blob: 33da2b403af2e58c022c7d3c7bd258f849df37c4 [file] [log] [blame]
Kerry Sheh6b909f22012-02-07 20:31:40 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <stdint.h>
21#include <console/console.h>
22#include <device/device.h>
23#include <arch/ioapic.h>
24#include <device/pci.h>
25#include <device/pci_ids.h>
26#include "NbPlatform.h"
27#include "nb_cimx.h"
28#include "rd890_cfg.h"
29
30
31/**
32 * Global RD890 CIMX Configuration structure
33 */
34static NB_CONFIG nb_cfg[MAX_NB_COUNT];
35static HT_CONFIG ht_cfg[MAX_NB_COUNT];
36static PCIE_CONFIG pcie_cfg[MAX_NB_COUNT];
37static AMD_NB_CONFIG_BLOCK gConfig;
38
39
40/**
41 * Reset PCIE Cores, Training the Ports selected by port_enable of devicetree
42 * After this call EP are fully operational on particular NB
43 */
44void nb_Pcie_Early_Init(void)
45{
46 LibSystemApiCall(AmdPcieEarlyInit, &gConfig); //AmdPcieEarlyInit(&gConfig);
47}
48
49void nb_Pcie_Late_Init(void)
50{
51 LibSystemApiCall(AmdPcieLateInit, &gConfig);
52}
53
54void nb_Early_Post_Init(void)
55{
56 LibSystemApiCall(AmdEarlyPostInit, &gConfig);
57}
58
59void nb_Mid_Post_Init(void)
60{
61 LibSystemApiCall(AmdMidPostInit, &gConfig);
62}
63
64void nb_Late_Post_Init(void)
65{
66 LibSystemApiCall(AmdLatePostInit, &gConfig);
67}
68
69static void rd890_enable(device_t dev)
70{
71 u32 address = 0;
72 u32 mask;
73 u32 val;
74 u32 devfn;
75 u32 port;
76 AMD_NB_CONFIG *NbConfigPtr = NULL;
77
78 u8 nb_index = 0; /* The first IO Hub, TODO: other NBs */
79 address = MAKE_SBDFO(0, 0x0, 0x0, 0x0, 0x0);
80 NbConfigPtr = &(gConfig.Northbridges[nb_index]);
81
82 devfn = dev->path.pci.devfn;
83 port = devfn >> 3;
84 printk(BIOS_INFO, "rd890_enable ");
85 printk(BIOS_INFO, "Bus-%x Dev-%X Fun-%X, enable=%x\n",
86 0, (devfn >> 3), (devfn & 0x07), dev->enabled);
87 if (port != 0) {
88 if (dev->enabled) {
89 NbConfigPtr->pPcieConfig->PortConfiguration[port].ForcePortDisable = OFF;
90 } else {
91 NbConfigPtr->pPcieConfig->PortConfiguration[port].ForcePortDisable = ON;
92 }
93 }
94
95 switch (port) {
96 case 0x0: /* Root Complex, and ClkConfig */
97
98 if ((devfn & 0x07) == 1) { /* skip dev-0 fun-1 */
99 break;
100 }
101
102 /* CIMX configuration defualt initialize */
103 rd890_cimx_config(&gConfig, &nb_cfg[0], &ht_cfg[0], &pcie_cfg[0]);
104 if (gConfig.StandardHeader.CalloutPtr != NULL) {
105 /* NOTE: not use LibNbCallBack */
106 gConfig.StandardHeader.CalloutPtr(CB_AmdSetPcieEarlyConfig, (u32)dev, (VOID*)NbConfigPtr);
107 }
108 /* Reset PCIE Cores, Training the Ports selected by port_enable of devicetree
109 * After this call EP are fully operational on particular NB
110 */
111 nb_Pcie_Early_Init();
112 break;
113
114 case 0x2: /* Gpp1 Port0 */
115 case 0x3: /* Gpp1 Port1 */
116 mask = ~(1 << port);
117 val = (dev->enabled ? 0 : 1) << port;
118 LibNbPciIndexRMW(address | NB_MISC_INDEX, NB_MISC_REG0C, AccessS3SaveWidth32, mask, val, NbConfigPtr);
119 break;
120
121 case 0x4: /* Gpp3a Port0 */
122 case 0x5: /* Gpp3a Port1 */
123 case 0x6: /* Gpp3a Port2 */
124 case 0x7: /* Gpp3a Port3 */
125 mask = ~(1 << port);
126 val = (dev->enabled ? 0 : 1) << port;
127 LibNbPciIndexRMW(address | NB_MISC_INDEX, NB_MISC_REG0C, AccessS3SaveWidth32, mask, val, NbConfigPtr);
128 break;
129
130 case 0x8: /* SB ALink */
131 mask = ~(1 << 6);
132 val = (dev->enabled ? 1 : 0) << 6;
133 LibNbPciIndexRMW(address | NB_MISC_INDEX, NB_MISC_REG0C, AccessS3SaveWidth32, mask, val, NbConfigPtr);
134 break;
135
136 case 0x9: /* Gpp3a Port4 */
137 case 0xa: /* Gpp3a Port5 */
138 mask = ~(1 << (7 + port));
139 val = (dev->enabled ? 0 : 1) << (7 + port);
140 LibNbPciIndexRMW(address | NB_MISC_INDEX, NB_MISC_REG0C, AccessS3SaveWidth32, mask, val, NbConfigPtr);
141 break;
142
143 case 0xb: /* Gpp2 Port0 */
144 case 0xc: /* Gpp2 Port1 */
145 mask = ~(1 << (7 + port));
146 val = (dev->enabled ? 0 : 1) << (7 + port);
147 LibNbPciIndexRMW(address | NB_MISC_INDEX, NB_MISC_REG0C, AccessS3SaveWidth32, mask, val, NbConfigPtr);
148 break;
149
150 case 0xd: /* Gpp3b */
151 mask = ~(1 << (7 + port));
152 val = (dev->enabled ? 0 : 1) << (7 + port);
153 LibNbPciIndexRMW(address | NB_MISC_INDEX, NB_MISC_REG0C, AccessS3SaveWidth32, mask, val, NbConfigPtr);
154
155 /* Init NB at Early Post */
156 if (gConfig.StandardHeader.CalloutPtr != NULL) {
157 gConfig.StandardHeader.CalloutPtr(CB_AmdSetEarlyPostConfig, 0, (VOID*)NbConfigPtr);
158 }
159 nb_Early_Post_Init();//
160 if (gConfig.StandardHeader.CalloutPtr != NULL) {
161 gConfig.StandardHeader.CalloutPtr(CB_AmdSetMidPostConfig, 0, (VOID*)NbConfigPtr);
162 }
163 nb_Mid_Post_Init();
164 nb_Pcie_Late_Init();
165 if (gConfig.StandardHeader.CalloutPtr != NULL) {
166 gConfig.StandardHeader.CalloutPtr(CB_AmdSetLatePostConfig, 0, (VOID*)NbConfigPtr);
167 }
168 nb_Late_Post_Init();
169 break;
170
171 default:
172 printk(BIOS_INFO, "Buggy Device Tree\n");
173 break;
174 }
175}
176
177struct chip_operations northbridge_amd_cimx_rd890_ops = {
178 CHIP_NAME("ATI rd890")
179 .enable_dev = rd890_enable,
180};
181
182
183static void ioapic_init(struct device *dev)
184{
185 u32 ioapic_base;
186
187 pci_write_config32(dev, 0xF8, 0x1);
188 ioapic_base = pci_read_config32(dev, 0xFC) & 0xfffffff0;
189 setup_ioapic(ioapic_base, 1);
190}
191
192static void rd890_read_resource(struct device *dev)
193{
194 pci_dev_read_resources(dev);
195
196 /* rpr6.2.(1). Write the Base Address Register (BAR) */
197 pci_write_config32(dev, 0xF8, 0x1); /* set IOAPIC's index as 1 and make sure no one changes it. */
198 pci_get_resource(dev, 0xFC); /* APIC located in sr5690 */
199
200 compact_resources(dev);
201}
202
203/* If IOAPIC's index changes, we should replace the pci_dev_set_resource(). */
204static void rd890_set_resources(struct device *dev)
205{
206 pci_write_config32(dev, 0xF8, 0x1); /* set IOAPIC's index as 1 and make sure no one changes it. */
207 pci_dev_set_resources(dev);
208}
209
210static struct pci_operations lops_pci = {
211 .set_subsystem = pci_dev_set_subsystem,
212};
213
214static struct device_operations ht_ops = {
215 .read_resources = rd890_read_resource,
216 .set_resources = rd890_set_resources,
217 .enable_resources = pci_dev_enable_resources,
218 .init = ioapic_init,
219 .scan_bus = 0,
220 .ops_pci = &lops_pci,
221};
222
Patrick Georgiefff7332012-07-26 19:48:23 +0200223static const unsigned short driver_ids[] = {
224 PCI_DEVICE_ID_AMD_SR5690_HT,
225 PCI_DEVICE_ID_AMD_SR5670_HT,
226 PCI_DEVICE_ID_AMD_SR5650_HT,
227 PCI_DEVICE_ID_AMD_RD890TV_HT,
228 PCI_DEVICE_ID_AMD_RD890_HT,
229 PCI_DEVICE_ID_AMD_990FX_HT,
230 0
231};
232
Kerry Sheh6b909f22012-02-07 20:31:40 +0800233static const struct pci_driver ht_driver_sr5690 __pci_driver = {
234 .ops = &ht_ops,
235 .vendor = PCI_VENDOR_ID_ATI,
Patrick Georgiefff7332012-07-26 19:48:23 +0200236 .devices= driver_ids,
Kerry Sheh6b909f22012-02-07 20:31:40 +0800237};