coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
pcie.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <stdint.h>
4 #include <device/pci_ops.h>
5 #include <device/pci_def.h>
6 #include <console/console.h>
8 
9 #include "gm45.h"
10 
11 static void init_egress(void)
12 {
13  /* VC0: TC0 only */
16 
17  /* VC1: isoch */
18  epbar_write32(EPVC1MTS, 0x0a0a0a0a);
19  epbar_clrsetbits32(EPVC1RCAP, 127 << 16, 0x0a << 16);
20 
21  /* VC1: ID1, TC7 */
22  epbar_clrsetbits32(EPVC1RCTL, 7 << 24, 1 << 24);
23  epbar_clrsetbits8(EPVC1RCTL, ~1, 1 << 7);
24 
25  /* VC1 ARB table: setup and enable */
26  epbar_write32(EP_PORTARB(0), 0x55555555);
27  epbar_write32(EP_PORTARB(1), 0x55555555);
28  epbar_write32(EP_PORTARB(2), 0x55555555);
29  epbar_write32(EP_PORTARB(3), 0x55555555);
30  epbar_write32(EP_PORTARB(4), 0x55555555);
31  epbar_write32(EP_PORTARB(5), 0x55555555);
32  epbar_write32(EP_PORTARB(6), 0x55555555);
33  epbar_write32(EP_PORTARB(7), 0x00005555);
34  epbar_setbits32(EPVC1RCTL, 1 << 16);
35 
36  while ((epbar_read8(EPVC1RSTS) & 1) != 0);
37 
38  /* VC1: enable */
39  epbar_setbits32(EPVC1RCTL, 1 << 31);
40 
41  while ((epbar_read8(EPVC1RSTS) & 2) != 0);
42 }
43 
44 /* MCH side */
45 /* b2step: b2 stepping or higher */
46 static void init_dmi(int b2step)
47 {
48  /* VC0: TC0 only */
51 
52  /* VC1: ID1, TC7 */
53  dmibar_clrsetbits32(DMIVC1RCTL, 7 << 24, 1 << 24);
54  dmibar_clrsetbits8(DMIVC1RCTL, ~1, 1 << 7);
55 
56  /* VC1: enable */
57  dmibar_setbits32(DMIVC1RCTL, 1 << 31);
58 
59  while ((dmibar_read8(DMIVC1RSTS) & VC1NP) != 0);
60 
61  /* additional configuration. */
62  dmibar_setbits32(0x200, 3 << 13);
63  dmibar_clrbits32(0x200, 1 << 21);
64  dmibar_clrsetbits32(0x200, 3 << 26, 2 << 26);
65  dmibar_write32(0x2c, 0x86000040);
66  dmibar_setbits32(0xfc, 1 << 0);
67  dmibar_setbits32(0xfc, 1 << 1);
68  dmibar_setbits32(0xfc, 1 << 4);
69  if (!b2step) {
70  dmibar_setbits32(0xfc, 1 << 11);
71  } else {
72  dmibar_clrbits32(0xfc, 1 << 11);
73  }
74  dmibar_clrbits32(0x204, 3 << 10);
75  dmibar_clrbits32(0xf4, 1 << 4);
76  dmibar_setbits32(0xf0, 3 << 24);
77  dmibar_write32(0xf04, 0x07050880);
78  dmibar_write32(0xf44, 0x07050880);
79  dmibar_write32(0xf84, 0x07050880);
80  dmibar_write32(0xfc4, 0x07050880);
81 
82  /* lock down write-once registers
83  DMIBAR32(0x84) will be set in setup_aspm(). */
84  dmibar_setbits32(0x308, 0);
85  dmibar_setbits32(0x314, 0);
86  dmibar_setbits32(0x324, 0);
87  dmibar_setbits32(0x328, 0);
88  dmibar_setbits32(0x334, 0);
89  dmibar_setbits32(0x338, 0);
90 }
91 
92 static void init_pcie(const int peg_enabled,
93  const int sdvo_enabled,
94  const int peg_x16)
95 {
96  const pci_devfn_t mch = PCI_DEV(0, 0, 0);
97  const pci_devfn_t pciex = PCI_DEV(0, 1, 0);
98 
99  printk(BIOS_DEBUG, "PEG x%d %s, SDVO %s\n", peg_x16?16:1,
100  peg_enabled?"enabled":"disabled",
101  sdvo_enabled?"enabled":"disabled");
102 
103  if (peg_enabled) {
104  pci_or_config8(mch, D0F0_DEVEN, 1 << 1);
105 
106  pci_write_config8(pciex, 0x224,
107  (pci_read_config8(pciex, 0x224) & ~31) | (peg_x16 ? 16 : 0) | 1);
108 
109  pci_and_config16(pciex, 0x224, ~(1 << 8));
110 
111  /* FIXME: fill in: slot or fixed? -> devicetree */
112  int peg_is_slot = 0;
113  if (peg_is_slot) {
114  pci_or_config16(pciex, PEG_CAP, 1 << 8);
115  }
116 
117  /* FIXME: fill in: slot number, slot power -> devicetree */
118  /* Use slot number 0 by now, slots on sb count from 1. */
119  int peg_slot = 0; /* unique within chassis */
120  /* peg_power := val * 10^-exp */
121  int peg_power_val = 75;
122  int peg_power_exp = 0; /* 0..3 */
123  const u32 tmp = (peg_slot << 17) | (peg_power_exp << 15) | (peg_power_val << 7);
124  pci_write_config32(pciex, SLOTCAP, tmp);
125 
126  /* GPEs */
127  pci_or_config8(pciex, PEGLC, 7);
128 
129  /* VC0: TC0 only, VC0 only */
130  pci_and_config8(pciex, D1F0_VC0RCTL, 1);
131 
132  pci_and_config8(pciex, D1F0_VCCAP, ~7);
133  }
134 }
135 
136 static void setup_aspm(const stepping_t stepping, const int peg_enabled)
137 {
138  u32 tmp32;
139  const pci_devfn_t pciex = PCI_DEV(0, 1, 0);
140 
141  /* Prerequisites for ASPM: */
142  if (peg_enabled) {
143  pci_or_config32(pciex, 0x200, 3 << 13);
144 
145  pci_and_config32(pciex, 0x0f0, ~((1 << 27) | (1 << 26)));
146 
147  pci_or_config32(pciex, 0x0f0, 3 << 24);
148 
149  pci_and_config32(pciex, 0x0f4, ~(1 << 4));
150 
151  pci_or_config32(pciex, 0x0fc, 1 << 0);
152 
153  pci_or_config32(pciex, 0x0fc, 1 << 1);
154 
155  pci_or_config32(pciex, 0x0fc, 1 << 4);
156 
157  pci_and_config32(pciex, 0x0fc, ~(7 << 5));
158 
159  /* Set L0s, L1 supported in LCTL? */
160  pci_or_config32(pciex, 0x0b0, 3 << 0);
161 
162  pci_or_config32(pciex, 0x0f0, 3 << 24);
163 
164  tmp32 = pci_read_config32(pciex, 0x0f0);
165  if ((stepping >= STEPPING_B0) && (stepping <= STEPPING_B1))
166  tmp32 |= (1 << 31);
167  else if (stepping >= STEPPING_B2)
168  tmp32 &= ~(1 << 31);
169  pci_write_config32(pciex, 0x0f0, tmp32);
170 
171  tmp32 = pci_read_config32(pciex, 0x0fc);
172  if ((stepping >= STEPPING_B0) && (stepping <= STEPPING_B1))
173  tmp32 |= (1 << 10);
174  else if (stepping >= STEPPING_B2)
175  tmp32 &= ~(1 << 10);
176  pci_write_config32(pciex, 0x0fc, tmp32);
177 
178  tmp32 = pci_read_config32(pciex, 0x0fc);
179  if (stepping >= STEPPING_B2)
180  tmp32 |= (1 << 14);
181  pci_write_config32(pciex, 0x0fc, tmp32);
182 
183  tmp32 = pci_read_config32(pciex, 0x0fc);
184  if (stepping >= STEPPING_B1)
185  tmp32 &= ~(1 << 13);
186  pci_write_config32(pciex, 0x0fc, tmp32);
187  }
188  dmibar_setbits8(0x0e1c, 1 << 0);
189  dmibar_setbits16(0x0f00, 3 << 8);
190  dmibar_setbits16(0x0f00, 7 << 3);
191  dmibar_clrbits32(0x0f14, 1 << 17);
192  dmibar_clrbits16(0x0e1c, 1 << 8);
193  if (stepping >= STEPPING_B0) {
194  dmibar_clrsetbits32(0x0e28 + 4, 0xf << (52 - 32), 0xd << (52 - 32));
195  dmibar_write32(0x0e2c, 0x88d07333);
196  }
197  if (peg_enabled) {
198  pci_and_config32(pciex, 0xa08, ~(1 << 15));
199 
200  pci_or_config32(pciex, 0xa84, 1 << 8);
201 
202  pci_and_config32(pciex, 0xb14, ~(1 << 17));
203 
204  pci_or_config32(pciex, 0xb00, 3 << 8);
205 
206  pci_or_config32(pciex, 0xb00, 7 << 3);
207 
208  pci_and_config32(pciex, 0xa84, ~(1 << 8));
209 
210  pci_or_config32(pciex, 0xa84, 1 << 8);
211 
212  pci_update_config32(pciex, 0xb04, ~(0x1f << 23), 0x0e << 23);
213 
214  pci_or_config32(pciex, 0xb04, 1 << 31);
215 
216  pci_update_config32(pciex, 0xb04, ~(0x03 << 29), 0x01 << 29);
217  }
218 
219  /*\ Setup ASPM on DMI \*/
220 
221  /* Exit latencies should be checked to be supported by
222  the endpoint (ICH), but ICH doesn't give any limits. */
223 
224  if (LPC_IS_MOBILE(PCI_DEV(0, 0x1f, 0)))
225  dmibar_setbits8(DMILCTL, 3 << 0); // enable ASPM L0s, L1 (write-once)
226  else
227  dmibar_setbits8(DMILCTL, 1 << 0); // enable ASPM L0s (write-once)
228  /* timing */
229  dmibar_clrsetbits32(DMILCAP, 63 << 12, 2 << 12 | 2 << 15);
230  dmibar_write8(0x208 + 3, 0);
231  dmibar_clrbits32(0x208, 3 << 20);
232 
233  /*\ Setup ASPM on PEG \*/
234  /*
235  * Maybe we just have to advertise ASPM through LCAP[11:10]
236  * (LCAP[17:15] == 010b is the default, will be locked, as it's R/WO),
237  * set 0x208[31:24,23:22] to zero, 0x224[24:21] = 1 and let the
238  * generic ASPM code do the rest? - Nico
239  */
240  /* TODO: Prepare PEG for ASPM. */
241 }
242 
243 static void setup_rcrb(const int peg_enabled)
244 {
245  /*\ RCRB setup: Egress Port \*/
246 
247  /* Set component ID of MCH (1). */
248  epbar_write8(EPESD + 2, 1);
249 
250  /* Link1: component ID 1, link valid. */
251  epbar_clrsetbits32(EPLE1D, 0xffffff, 1 << 16 | 1 << 0);
252  epbar_write32(EPLE1A, CONFIG_FIXED_DMIBAR_MMIO_BASE);
253 
254  if (peg_enabled)
255  /* Link2: link_valid. */
256  epbar_setbits8(EPLE2D, 1 << 0); /* link valid */
257 
258  /*\ RCRB setup: DMI Port \*/
259 
260  /* Set component ID of MCH (1). */
261  dmibar_write8(DMIESD + 2, 1);
262 
263  /* Link1: target port 0, component id 2 (ICH), link valid. */
264  dmibar_write32(DMILE1D, 0 << 24 | 2 << 16 | 1 << 0);
265  dmibar_write32(DMILE1A, CONFIG_FIXED_RCBA_MMIO_BASE);
266 
267  /* Link2: component ID 1 (MCH), link valid */
268  dmibar_clrsetbits32(DMILE2D, 0xffffff, 1 << 16 | 1 << 0);
269  dmibar_write32(DMILE2A, CONFIG_FIXED_MCHBAR_MMIO_BASE);
270 }
271 
273 {
274  const pci_devfn_t mch = PCI_DEV(0, 0, 0);
275  const int peg_enabled = (pci_read_config8(mch, D0F0_DEVEN) >> 1) & 1;
276  const int sdvo_enabled = mchbar_read16(0x40) >> 8 & 1;
277  const int peg_x16 = (peg_enabled && !sdvo_enabled);
278 
279  init_egress();
281  init_pcie(peg_enabled, sdvo_enabled, peg_x16);
282 
283  setup_aspm(stepping, peg_enabled);
284  setup_rcrb(peg_enabled);
285 }
#define printk(level,...)
Definition: stdlib.h:16
#define epbar_clrbits8(addr, clear)
Definition: fixed_bars.h:170
#define epbar_setbits8(addr, set)
Definition: fixed_bars.h:166
static __always_inline void dmibar_write8(const uintptr_t offset, const uint8_t value)
Definition: fixed_bars.h:81
static __always_inline void epbar_clrsetbits32(uintptr_t offset, uint32_t clear, uint32_t set)
Definition: fixed_bars.h:161
#define dmibar_clrbits32(addr, clear)
Definition: fixed_bars.h:117
static __always_inline void epbar_clrsetbits8(uintptr_t offset, uint8_t clear, uint8_t set)
Definition: fixed_bars.h:151
#define dmibar_clrbits8(addr, clear)
Definition: fixed_bars.h:115
#define dmibar_setbits8(addr, set)
Definition: fixed_bars.h:111
static __always_inline void dmibar_write32(const uintptr_t offset, const uint32_t value)
Definition: fixed_bars.h:91
#define dmibar_setbits32(addr, set)
Definition: fixed_bars.h:113
static __always_inline void dmibar_clrsetbits8(uintptr_t offset, uint8_t clear, uint8_t set)
Definition: fixed_bars.h:96
static __always_inline void epbar_write8(const uintptr_t offset, const uint8_t value)
Definition: fixed_bars.h:136
#define dmibar_clrbits16(addr, clear)
Definition: fixed_bars.h:116
static __always_inline uint16_t mchbar_read16(const uintptr_t offset)
Definition: fixed_bars.h:16
static __always_inline uint8_t dmibar_read8(const uintptr_t offset)
Definition: fixed_bars.h:66
static __always_inline uint8_t epbar_read8(const uintptr_t offset)
Definition: fixed_bars.h:121
#define dmibar_setbits16(addr, set)
Definition: fixed_bars.h:112
static __always_inline void dmibar_clrsetbits32(uintptr_t offset, uint32_t clear, uint32_t set)
Definition: fixed_bars.h:106
static __always_inline void epbar_write32(const uintptr_t offset, const uint32_t value)
Definition: fixed_bars.h:146
#define epbar_setbits32(addr, set)
Definition: fixed_bars.h:168
#define SLOTCAP
Definition: gm45.h:198
#define EPVC0RCTL
Definition: gm45.h:375
#define PEGLC
Definition: gm45.h:199
#define EPLE1A
Definition: gm45.h:390
#define VC1NP
Definition: gm45.h:354
#define D1F0_VCCAP
Definition: gm45.h:200
#define DMIVC0RCTL
Definition: gm45.h:347
#define EPPVCCAP1
Definition: gm45.h:371
#define DMIESD
Definition: gm45.h:356
#define DMIPVCCAP1
Definition: gm45.h:344
#define PEG_CAP
Definition: gm45.h:197
stepping_t
Definition: gm45.h:14
@ STEPPING_B1
Definition: gm45.h:22
@ STEPPING_B0
Definition: gm45.h:21
@ STEPPING_B2
Definition: gm45.h:23
#define DMIVC1RSTS
Definition: gm45.h:353
#define DMILE1D
Definition: gm45.h:358
#define EPVC1RCTL
Definition: gm45.h:379
#define DMILCTL
Definition: gm45.h:364
#define DMILE2D
Definition: gm45.h:360
#define DMIVC1RCTL
Definition: gm45.h:352
#define EPESD
Definition: gm45.h:387
#define DMILCAP
Definition: gm45.h:363
#define DMILE2A
Definition: gm45.h:361
#define EPVC1RCAP
Definition: gm45.h:378
#define EPVC1MTS
Definition: gm45.h:382
#define DMILE1A
Definition: gm45.h:359
#define EP_PORTARB(x)
Definition: gm45.h:394
#define D0F0_DEVEN
Definition: gm45.h:177
#define D1F0_VC0RCTL
Definition: gm45.h:201
#define EPLE2D
Definition: gm45.h:391
#define EPLE1D
Definition: gm45.h:389
#define EPVC1RSTS
Definition: gm45.h:380
#define LPC_IS_MOBILE(dev)
Definition: i82801ix.h:159
static __always_inline void pci_or_config32(const struct device *dev, u16 reg, u32 ormask)
Definition: pci_ops.h:191
static __always_inline void pci_write_config32(const struct device *dev, u16 reg, u32 val)
Definition: pci_ops.h:76
static __always_inline void pci_and_config16(const struct device *dev, u16 reg, u16 andmask)
Definition: pci_ops.h:147
static __always_inline void pci_and_config8(const struct device *dev, u16 reg, u8 andmask)
Definition: pci_ops.h:136
static __always_inline void pci_update_config32(const struct device *dev, u16 reg, u32 mask, u32 or)
Definition: pci_ops.h:120
static __always_inline void pci_or_config16(const struct device *dev, u16 reg, u16 ormask)
Definition: pci_ops.h:180
static __always_inline void pci_or_config8(const struct device *dev, u16 reg, u8 ormask)
Definition: pci_ops.h:169
static __always_inline u32 pci_read_config32(const struct device *dev, u16 reg)
Definition: pci_ops.h:58
static __always_inline u8 pci_read_config8(const struct device *dev, u16 reg)
Definition: pci_ops.h:46
static __always_inline void pci_and_config32(const struct device *dev, u16 reg, u32 andmask)
Definition: pci_ops.h:158
static __always_inline void pci_write_config8(const struct device *dev, u16 reg, u8 val)
Definition: pci_ops.h:64
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
static void init_pcie(const int peg_enabled, const int sdvo_enabled, const int peg_x16)
Definition: pcie.c:92
void gm45_late_init(const stepping_t stepping)
Definition: pcie.c:272
static void setup_rcrb(const int peg_enabled)
Definition: pcie.c:243
static void init_egress(void)
Definition: pcie.c:11
static void setup_aspm(const stepping_t stepping, const int peg_enabled)
Definition: pcie.c:136
static void init_dmi(int b2step)
Definition: pcie.c:46
#define PCI_DEV(SEGBUS, DEV, FN)
Definition: pci_type.h:14
u32 pci_devfn_t
Definition: pci_type.h:8
const char * stepping
uint32_t u32
Definition: stdint.h:51