Patch for AMD RS690 chipset.
[coreboot.git] / src / southbridge / amd / rs690 / rs690_pcie.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2008 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 <console/console.h>
21 #include <device/device.h>
22 #include <device/pci.h>
23 #include <device/pci_ids.h>
24 #include <device/pci_ops.h>
25 #include <delay.h>
26 #include "rs690.h"
27
28 /*------------------------------------------------
29 * Global variable
30 ------------------------------------------------*/
31 PCIE_CFG AtiPcieCfg = {
32         PCIE_ENABLE_STATIC_DEV_REMAP,   /* Config */
33         0,                      /* ResetReleaseDelay */
34         0,                      /* Gfx0Width */
35         0,                      /* Gfx1Width */
36         0,                      /* GfxPayload */
37         0,                      /* GppPayload */
38         0,                      /* PortDetect, filled by GppSbInit */
39         0,                      /* PortHp */
40         0,                      /* DbgConfig */
41         0,                      /* DbgConfig2 */
42         0,                      /* GfxLx */
43         0,                      /* GppLx */
44         0,                      /* NBSBLx */
45         0,                      /* PortSlotInit */
46         0,                      /* Gfx0Pwr */
47         0,                      /* Gfx1Pwr */
48         0                       /* GppPwr */
49 };
50
51 static void PciePowerOffGppPorts(device_t nb_dev, device_t dev, u32 port);
52 static void ValidatePortEn(device_t nb_dev);
53
54 static void ValidatePortEn(device_t nb_dev)
55 {
56 }
57
58
59 /*****************************************************************
60 * Compliant with CIM_33's PCIEPowerOffGppPorts
61 * Power off unused GPP lines
62 *****************************************************************/
63 static void PciePowerOffGppPorts(device_t nb_dev, device_t dev, u32 port)
64 {
65         u32 reg;
66         u16 state_save;
67         struct southbridge_amd_rs690_config *cfg =
68             (struct southbridge_amd_rs690_config *)nb_dev->chip_info;
69         u8 state = cfg->port_enable;
70
71         if (!(AtiPcieCfg.Config & PCIE_DISABLE_HIDE_UNUSED_PORTS))
72                 state &= AtiPcieCfg.PortDetect;
73         state = ~state;
74         state &= (1 << 4) + (1 << 5) + (1 << 6) + (1 << 7);
75         state_save = state << 17;
76         state &= !(AtiPcieCfg.PortHp);
77         reg = nbmisc_read_index(nb_dev, 0x0c);
78         reg |= state;
79         nbmisc_write_index(nb_dev, 0x0c, reg);
80
81         reg = nbmisc_read_index(nb_dev, 0x08);
82         reg |= state_save;
83         nbmisc_write_index(nb_dev, 0x08, reg);
84
85         if ((AtiPcieCfg.Config & PCIE_OFF_UNUSED_GPP_LANES)
86             && !(AtiPcieCfg.
87                  Config & (PCIE_DISABLE_HIDE_UNUSED_PORTS +
88                            PCIE_GFX_COMPLIANCE))) {
89         }
90         /* step 3 Power Down Control for Southbridge */
91         reg = nbpcie_p_read_index(dev, 0xa2);
92
93         switch ((reg >> 4) & 0x7) {     /* get bit 4-6, LC_LINK_WIDTH_RD */
94         case 1:
95                 nbpcie_ind_write_index(nb_dev, 0x65, 0x0e0e);
96                 break;
97         case 2:
98                 nbpcie_ind_write_index(nb_dev, 0x65, 0x0c0c);
99                 break;
100         default:
101                 break;
102         }
103 }
104
105 static void pcie_init(struct device *dev)
106 {
107         /* Enable pci error detecting */
108         u32 dword;
109
110         printk_debug("pcie_init in rs690_pcie.c\n");
111
112         /* System error enable */
113         dword = pci_read_config32(dev, 0x04);
114         dword |= (1 << 8);      /* System error enable */
115         dword |= (1 << 30);     /* Clear possible errors */
116         pci_write_config32(dev, 0x04, dword);
117 }
118
119 static struct pci_operations lops_pci = {
120         .set_subsystem = 0,
121 };
122
123 static struct device_operations pcie_ops = {
124         .read_resources = pci_bus_read_resources,
125         .set_resources = pci_dev_set_resources,
126         .enable_resources = pci_bus_enable_resources,
127         .init = pcie_init,
128         .scan_bus = pci_scan_bridge,
129         /*.enable           = rs690_enable, */
130         .ops_pci = &lops_pci,
131 };
132
133 static struct pci_driver pcie_driver __pci_driver = {
134         .ops = &pcie_ops,
135         .vendor = PCI_VENDOR_ID_ATI,
136         .device = PCI_DEVICE_ID_ATI_RS690_PCIE,
137 };
138
139 static struct pci_driver pcie_driver_dev7 __pci_driver = {
140         .ops = &pcie_ops,
141         .vendor = PCI_VENDOR_ID_ATI,
142         .device = PCI_DEVICE_ID_ATI_RS690_PCIE_DEV7,
143 };
144 static struct pci_driver pcie_driver_dev8 __pci_driver = {
145         .ops = &pcie_ops,
146         .vendor = PCI_VENDOR_ID_ATI,
147         .device = PCI_DEVICE_ID_ATI_RS690_PCIE_DEV8,
148 };
149
150 /**********************************************************************
151 **********************************************************************/
152 static void switching_gpp_configurations(device_t nb_dev, device_t sb_dev)
153 {
154         u32 reg;
155         struct southbridge_amd_rs690_config *cfg =
156             (struct southbridge_amd_rs690_config *)nb_dev->chip_info;
157
158         /* enables GPP reconfiguration */
159         reg = nbmisc_read_index(nb_dev, PCIE_NBCFG_REG7);
160         reg |=
161             (RECONFIG_GPPSB_EN + RECONFIG_GPPSB_LINK_CONFIG +
162              RECONFIG_GPPSB_ATOMIC_RESET);
163         nbmisc_write_index(nb_dev, PCIE_NBCFG_REG7, reg);
164
165         /* sets desired GPPSB configurations, bit4-7 */
166         reg = nbmisc_read_index(nb_dev, 0x67);
167         reg &= 0xff0f;          /* clean */
168         reg |= cfg->gpp_configuration;
169         nbmisc_write_index(nb_dev, 0x67, reg);
170
171         /* read bit14 and write back its inverst value */
172         reg = nbmisc_read_index(nb_dev, PCIE_NBCFG_REG7);
173         reg ^= RECONFIG_GPPSB_GPPSB;
174         nbmisc_write_index(nb_dev, PCIE_NBCFG_REG7, reg);
175
176         /* delay 1ms */
177         mdelay(1);
178
179         /* waits until SB has trained to L0, poll for bit0-5 = 0x10 */
180         do {
181                 reg = nbpcie_p_read_index(sb_dev, PCIE_LC_STATE0);
182                 reg &= 0x1f;    /* remain LSB 5 bits */
183         } while (LC_STATE_RECONFIG_GPPSB != reg);
184
185         /* ensures that virtual channel negotiation is completed. poll for bit1 = 0 */
186         do {
187                 reg =
188                     pci_ext_read_config32(nb_dev, sb_dev,
189                                           PCIE_VC0_RESOURCE_STATUS);
190         } while (reg & VC_NEGOTIATION_PENDING);
191 }
192
193 /*****************************************************************
194 * The rs690 uses NBCONFIG:0x1c (BAR3) to map the PCIE Extended Configuration
195 * Space to a 256MB range within the first 4GB of addressable memory.
196 *****************************************************************/
197 void enable_pcie_bar3(device_t nb_dev)
198 {
199         printk_debug("enable_pcie_bar3()\n");
200         set_nbcfg_enable_bits(nb_dev, 0x7C, 1 << 30, 1 << 30);  /* Enables writes to the BAR3 register. */
201         set_nbcfg_enable_bits(nb_dev, 0x84, 7 << 16, 0 << 16);
202
203         pci_write_config32(nb_dev, 0x1C, EXT_CONF_BASE_ADDRESS);        /* PCIEMiscInit */
204         pci_write_config32(nb_dev, 0x20, 0x00000000);
205         set_htiu_enable_bits(nb_dev, 0x32, 1 << 28, 1 << 28);   /* PCIEMiscInit */
206         ProgK8TempMmioBase(1, EXT_CONF_BASE_ADDRESS, TEMP_MMIO_BASE_ADDRESS);
207 }
208
209 /*****************************************************************
210 * We should disable bar3 when we want to exit rs690_enable, because bar3 will be
211 * remapped in set_resource later.
212 *****************************************************************/
213 void disable_pcie_bar3(device_t nb_dev)
214 {
215         printk_debug("disable_pcie_bar3()\n");
216         set_nbcfg_enable_bits(nb_dev, 0x7C, 1 << 30, 0 << 30);  /* Disable writes to the BAR3. */
217         pci_write_config32(nb_dev, 0x1C, 0);    /* clear BAR3 address */
218         ProgK8TempMmioBase(0, EXT_CONF_BASE_ADDRESS, TEMP_MMIO_BASE_ADDRESS);
219 }
220
221 /*****************************************
222 * Compliant with CIM_33's PCIEGPPInit
223 * nb_dev:
224 *       root bridge struct
225 * dev:
226 *       p2p bridge struct
227 * port:
228 *       p2p bridge number, 4-8
229 *****************************************/
230 void rs690_gpp_sb_init(device_t nb_dev, device_t dev, u32 port)
231 {
232         u8 reg8;
233         u16 reg16;
234         device_t sb_dev;
235         struct southbridge_amd_rs690_config *cfg =
236             (struct southbridge_amd_rs690_config *)nb_dev->chip_info;
237         printk_debug("gpp_sb_init nb_dev=0x%x, dev=0x%x, port=0x%x\n", nb_dev, dev, port);
238
239         /* init GPP core */
240         set_pcie_enable_bits(nb_dev, 0x20 | PCIE_CORE_INDEX_GPPSB, 1 << 8,
241                              1 << 8);
242         /* PCIE initialization 5.10.2: rpr 2.12*/
243         set_pcie_enable_bits(nb_dev, 0x02 | PCIE_CORE_INDEX_GPPSB, 1 << 0, 1 << 0);     /* no description in datasheet. */
244
245         /* init GPPSB port */
246         /* Sets RCB timeout to be 100ms by setting bits[18:16] to 3 b101 and shortens the enumeration timer by setting bit[19] to 0*/
247         set_pcie_enable_bits(dev, 0x70, 7 << 16, 0xd << 16);
248         /* PCIE initialization 5.10.2: rpr 2.4 */
249         set_pcie_enable_bits(dev, 0x02, ~0xffffffff, 1 << 14);
250         /* Do not gate the electrical idle from the PHY and enables the escape from L1L23 */
251         set_pcie_enable_bits(dev, 0xA0, ~0xffffffbf, (3 << 30) | (3 << 12) | (3 << 4));
252         /* PCIE initialization 5.10.2: rpr 2.13 */
253         set_pcie_enable_bits(dev, 0x02, ~0xffffffff, 1 << 6);
254
255         /* SLOT_IMPLEMENTED in pcieConfig space */
256         reg8 = pci_read_config8(dev, 0x5b);
257         reg8 |= 1 << 0;
258         pci_write_config8(dev, 0x5b, reg8);
259
260         reg16 = pci_read_config16(dev, 0x5a);
261         reg16 |= 0x100;
262         pci_write_config16(dev, 0x5a, reg16);
263         nbmisc_write_index(nb_dev, 0x34, 0);
264
265         /* check compliance rpr step 2.1*/
266         if (AtiPcieCfg.Config & PCIE_GPP_COMPLIANCE) {
267                 u32 tmp;
268                 tmp = nbmisc_read_index(nb_dev, 0x67);
269                 tmp |= 1 << 3;
270                 nbmisc_write_index(nb_dev, 0x67, tmp);
271         }
272
273         /* step 5: dynamic slave CPL buffer allocation */
274         set_pcie_enable_bits(dev, 0x20, 1 << 11, 1 << 11);
275
276         /* step 5a: Training for GPP devices */
277         /* init GPP */
278         switch (port) {
279         case 4:         /* GPP */
280         case 5:
281         case 6:
282         case 7:
283                 /* Blocks DMA traffic during C3 state */
284                 set_pcie_enable_bits(dev, 0x10, 1 << 0, 0 << 0);
285                 /* Enabels TLP flushing */
286                 set_pcie_enable_bits(dev, 0x20, 1 << 19, 0 << 19);
287
288                 /* check port enable */
289                 if (cfg->port_enable & (1 << port)) {
290                         PcieReleasePortTraining(nb_dev, dev, port);
291                         if (!(AtiPcieCfg.Config & PCIE_GPP_COMPLIANCE)) {
292                                 u8 res = PcieTrainPort(nb_dev, dev, port);
293                                 printk_debug("PcieTrainPort port=0x%x result=%d\n", port, res);
294                                 if (res) {
295                                         AtiPcieCfg.PortDetect |= 1 << port;
296                                 }
297                         }
298                 }
299                 break;
300         case 8:         /* SB */
301                 break;
302         }
303         PciePowerOffGppPorts(nb_dev, dev, port);
304
305         /* step 5b: GFX devices in a GPP slot */
306
307         /* step 6a: VCI */
308         sb_dev = dev_find_slot(0, PCI_DEVFN(8, 0));
309         if (port == 8) {
310                 /* Clear bits 7:1 */
311                 pci_ext_write_config32(nb_dev, sb_dev, 0x114, 0x3f << 1, 0 << 1);
312                 /* Maps Traffic Class 1-7 to VC1 */
313                 pci_ext_write_config32(nb_dev, sb_dev, 0x120, 0x7f << 1, 0x7f << 1);
314                 /* Assigns VC ID to 1 */
315                 pci_ext_write_config32(nb_dev, sb_dev, 0x120, 7 << 24, 1 << 24);
316                 /* Enables VC1 */
317                 pci_ext_write_config32(nb_dev, sb_dev, 0x120, 1 << 31, 1 << 31);
318 #if 0
319                 do {
320                         reg16 = pci_ext_read_config32(nb_dev, sb_dev, 0x124);
321                         reg16 &= 0x2;
322                 } while (reg16); /*bit[1] = 0 means VC1 flow control initialization is successful */
323 #endif
324         }
325
326         /* step 6b: L0s for the southbridge link */
327         /* To enalbe L0s in the southbridage*/
328
329         /* step 6c: L0s for the GPP link(s) */
330         /* To eable L0s in the RS690 for the GPP port(s) */
331         set_pcie_enable_bits(nb_dev, 0xf9, 3 << 13, 2 << 13);
332         set_pcie_enable_bits(dev, 0xa0, 0xf << 8, 0x9 << 8);
333         reg16 = pci_read_config16(dev, 0x68);
334         reg16 |= 1 << 0;
335         pci_write_config16(dev, 0x68, reg16);
336
337         /* step 6d: ASPM L1 for the southbridge link */
338         /* To enalbe L1s in the southbridage*/
339
340         /* step 6e: ASPM L1 for GPP link(s) */;
341         set_pcie_enable_bits(nb_dev, 0xf9, 3 << 13, 2 << 13);
342         set_pcie_enable_bits(dev, 0xa0, 3 << 12, 3 << 12);
343         set_pcie_enable_bits(dev, 0xa0, 0xf << 4, 3 << 4);
344         reg16 = pci_read_config16(dev, 0x68);
345         reg16 &= ~0xff;
346         reg16 |= 1 << 1;
347         pci_write_config16(dev, 0x68, reg16);
348
349         /* step 6f: Turning off PLL during L1/L23 */
350         set_pcie_enable_bits(nb_dev, 0x40, 1 << 3, 1 << 3);
351         set_pcie_enable_bits(nb_dev, 0x40, 1 << 9, 1 << 9);
352
353         /* step 6g: TXCLK clock gating */
354         set_nbmisc_enable_bits(nb_dev, 0x7, 3 << 4, 3 << 4);
355         set_nbmisc_enable_bits(nb_dev, 0x7, 1 << 22, 1 << 22);
356         set_pcie_enable_bits(nb_dev, 0x11, 0xf << 4, 0xc << 4);
357
358         /* step 6h: LCLK clock gating, done in rs690_config_misc_clk() */
359 }
360
361 /*****************************************
362 * Compliant with CIM_33's PCIEConfigureGPPCore
363 *****************************************/
364 void config_gpp_core(device_t nb_dev, device_t sb_dev)
365 {
366         u32 reg;
367         struct southbridge_amd_rs690_config *cfg =
368             (struct southbridge_amd_rs690_config *)nb_dev->chip_info;
369
370         reg = nbmisc_read_index(nb_dev, 0x20);
371         if (AtiPcieCfg.Config & PCIE_ENABLE_STATIC_DEV_REMAP)
372                 reg &= 0xfffffffd;      /* set bit1 = 0 */
373         else
374                 reg |= 0x2;     /* set bit1 = 1 */
375         nbmisc_write_index(nb_dev, 0x20, reg);
376
377         reg = nbmisc_read_index(nb_dev, 0x67);  /* get STRAP_BIF_LINK_CONFIG_GPPSB at bit 4-7 */
378         if (cfg->gpp_configuration != ((reg >> 4) & 0xf))
379                 switching_gpp_configurations(nb_dev, sb_dev);
380         ValidatePortEn(nb_dev);
381 }
382
383 /*****************************************
384 * Compliant with CIM_33's PCIEMiscClkProg
385 *****************************************/
386 void pcie_config_misc_clk(device_t nb_dev)
387 {
388         u32 reg;
389         struct bus pbus; /* fake bus for dev0 fun1 */
390
391         reg = pci_read_config32(nb_dev, 0x4c);
392         reg |= 1 << 0;
393         pci_write_config32(nb_dev, 0x4c, reg);
394
395         if (AtiPcieCfg.Config & PCIE_GFX_CLK_GATING) {
396                 /* TXCLK Clock Gating */
397                 set_nbmisc_enable_bits(nb_dev, 0x07, 3 << 0, 3 << 0);
398                 set_nbmisc_enable_bits(nb_dev, 0x07, 1 << 22, 1 << 22);
399                 set_pcie_enable_bits(nb_dev, 0x11 | PCIE_CORE_INDEX_GFX, (3 << 6) | (~0xf), 3 << 6);
400
401                 /* LCLK Clock Gating */
402                 reg =  pci_cf8_conf1.read32(&pbus, 0, 1, 0x94);
403                 reg &= ~(1 << 16);
404                 pci_cf8_conf1.write32(&pbus, 0, 1, 0x94, reg);
405         }
406
407         if (AtiPcieCfg.Config & PCIE_GPP_CLK_GATING) {
408                 /* TXCLK Clock Gating */
409                 set_nbmisc_enable_bits(nb_dev, 0x07, 3 << 4, 3 << 4);
410                 set_nbmisc_enable_bits(nb_dev, 0x07, 1 << 22, 1 << 22);
411                 set_pcie_enable_bits(nb_dev, 0x11 | PCIE_CORE_INDEX_GPPSB, (3 << 6) | (~0xf), 3 << 6);
412
413                 /* LCLK Clock Gating */
414                 reg =  pci_cf8_conf1.read32(&pbus, 0, 1, 0x94);
415                 reg &= ~(1 << 24);
416                 pci_cf8_conf1.write32(&pbus, 0, 1, 0x94, reg);
417         }
418
419         reg = pci_read_config32(nb_dev, 0x4c);
420         reg &= ~(1 << 0);
421         pci_write_config32(nb_dev, 0x4c, reg);
422 }