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 <console/console.h>
4 #include <device/device.h>
5 #include <device/pci.h>
6 #include <device/pci_def.h>
7 #include <device/pci_ops.h>
8 #include <device/pciexp.h>
9 #include <device/pci_ids.h>
11 #include <assert.h>
12 
13 #include "chip.h"
14 #include "pch.h"
15 
16 static const char *pch_pcie_acpi_name(const struct device *dev)
17 {
18  ASSERT(dev);
19 
20  if (PCI_SLOT(dev->path.pci.devfn) == 0x1c) {
21  static const char *names[] = { "RP01",
22  "RP02",
23  "RP03",
24  "RP04",
25  "RP05",
26  "RP06",
27  "RP07",
28  "RP08"};
29 
30  return names[PCI_FUNC(dev->path.pci.devfn)];
31  }
32 
33  return NULL;
34 }
35 
36 static void pch_pcie_pm_early(struct device *dev)
37 {
38  u16 link_width_p0, link_width_p4;
39  u8 slot_power_limit = 10; /* 10W for x1 */
40  u32 reg32;
41  u8 reg8;
42 
43  reg32 = RCBA32(RPC);
44 
45  /* Port 0-3 link aggregation from PCIEPCS1[1:0] soft strap */
46  switch (reg32 & 3) {
47  case 3:
48  link_width_p0 = 4;
49  break;
50  case 1:
51  case 2:
52  link_width_p0 = 2;
53  break;
54  case 0:
55  default:
56  link_width_p0 = 1;
57  }
58 
59  /* Port 4-7 link aggregation from PCIEPCS2[1:0] soft strap */
60  switch ((reg32 >> 2) & 3) {
61  case 3:
62  link_width_p4 = 4;
63  break;
64  case 1:
65  case 2:
66  link_width_p4 = 2;
67  break;
68  case 0:
69  default:
70  link_width_p4 = 1;
71  }
72 
73  /* Enable dynamic clock gating where needed */
74  reg8 = pci_read_config8(dev, 0xe1);
75  switch (PCI_FUNC(dev->path.pci.devfn)) {
76  case 0: /* Port 0 */
77  if (link_width_p0 == 4)
78  slot_power_limit = 40; /* 40W for x4 */
79  else if (link_width_p0 == 2)
80  slot_power_limit = 20; /* 20W for x2 */
81  reg8 |= 0x3f;
82  break;
83  case 4: /* Port 4 */
84  if (link_width_p4 == 4)
85  slot_power_limit = 40; /* 40W for x4 */
86  else if (link_width_p4 == 2)
87  slot_power_limit = 20; /* 20W for x2 */
88  reg8 |= 0x3f;
89  break;
90  case 1: /* Port 1 only if Port 0 is x1 */
91  if (link_width_p0 == 1)
92  reg8 |= 0x3;
93  break;
94  case 2: /* Port 2 only if Port 0 is x1 or x2 */
95  case 3: /* Port 3 only if Port 0 is x1 or x2 */
96  if (link_width_p0 <= 2)
97  reg8 |= 0x3;
98  break;
99  case 5: /* Port 5 only if Port 4 is x1 */
100  if (link_width_p4 == 1)
101  reg8 |= 0x3;
102  break;
103  case 6: /* Port 7 only if Port 4 is x1 or x2 */
104  case 7: /* Port 7 only if Port 4 is x1 or x2 */
105  if (link_width_p4 <= 2)
106  reg8 |= 0x3;
107  break;
108  }
109  pci_write_config8(dev, 0xe1, reg8);
110 
111  /* Set 0xE8[0] = 1 */
112  pci_or_config32(dev, 0xe8, 1);
113 
114  /* Adjust Common Clock exit latency */
115  reg32 = pci_read_config32(dev, 0xd8);
116  reg32 &= ~(1 << 17);
117  reg32 |= (1 << 16) | (1 << 15);
118  reg32 &= ~(1 << 31); /* Disable PME# SCI for native PME handling */
119  pci_write_config32(dev, 0xd8, reg32);
120 
121  /* Adjust ASPM L1 exit latency */
122  reg32 = pci_read_config32(dev, 0x4c);
123  reg32 &= ~((1 << 17) | (1 << 16) | (1 << 15));
124  if (RCBA32(CIR9) & (1 << 16)) {
125  /* If RCBA+2320[15]=1 set ASPM L1 to 8-16us */
126  reg32 |= (1 << 17);
127  } else {
128  /* Else set ASPM L1 to 2-4us */
129  reg32 |= (1 << 16);
130  }
131  pci_write_config32(dev, 0x4c, reg32);
132 
133  /* Set slot power limit as configured above */
134  reg32 = pci_read_config32(dev, 0x54);
135  reg32 &= ~((1 << 15) | (1 << 16)); /* 16:15 = Slot power scale */
136  reg32 &= ~(0xff << 7); /* 14:7 = Slot power limit */
137  reg32 |= (slot_power_limit << 7);
138  pci_write_config32(dev, 0x54, reg32);
139 }
140 
141 static void pch_pcie_pm_late(struct device *dev)
142 {
144  enum aspm_type apmc = 0;
145 
146  /* Set 0x314 = 0x743a361b */
147  pci_write_config32(dev, 0x314, 0x743a361b);
148 
149  /* Set 0x318[31:16] = 0x1414 */
150  pci_update_config32(dev, 0x318, 0x0000ffff, 0x14140000);
151 
152  /* Set 0x324[5] = 1 */
153  pci_or_config32(dev, 0x324, 1 << 5);
154 
155  /* Set 0x330[7:0] = 0x40 */
156  pci_update_config32(dev, 0x330, ~0xff, 0x40);
157 
158  /* Set 0x33C[24:0] = 0x854c74 */
159  pci_update_config32(dev, 0x33c, 0xff000000, 0x00854c74);
160 
161  /* No IO-APIC, Disable EOI forwarding */
162  pci_or_config32(dev, 0xd4, 1 << 1);
163 
164  /* Check for a rootport ASPM override */
165  apmc = config->pcie_aspm[PCI_FUNC(dev->path.pci.devfn)];
166 
167  /* Setup the override or get the real ASPM setting */
168  if (apmc) {
169  pci_or_config32(dev, 0xd4, (apmc << 2) | (1 << 4));
170 
171  } else {
172  apmc = pci_read_config32(dev, 0x50) & 3;
173  }
174 
175  /* If both L0s and L1 enabled then set root port 0xE8[1]=1 */
176  if (apmc == PCIE_ASPM_BOTH)
177  pci_or_config32(dev, 0xe8, 1 << 1);
178 }
179 
180 static void pci_init(struct device *dev)
181 {
182  u16 reg16;
184 
185  printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
186 
187  /* Enable Bus Master */
189 
190  /* Set Cache Line Size to 0x10 */
191  // This has no effect but the OS might expect it
192  pci_write_config8(dev, 0x0c, 0x10);
193 
195 
196  /* Clear errors in status registers. FIXME: Do something? */
197  reg16 = pci_read_config16(dev, 0x06);
198  //reg16 |= 0xf900;
199  pci_write_config16(dev, 0x06, reg16);
200 
201  reg16 = pci_read_config16(dev, 0x1e);
202  //reg16 |= 0xf900;
203  pci_write_config16(dev, 0x1e, reg16);
204 
205  /* Enable expresscard hotplug events. */
206  if (config->pcie_hotplug_map[PCI_FUNC(dev->path.pci.devfn)]) {
207  pci_or_config32(dev, 0xd8, 1 << 30);
208  pci_write_config16(dev, 0x42, 0x142);
209  }
210 }
211 
212 static void pch_pcie_enable(struct device *dev)
213 {
214  /* Power Management init before enumeration */
215  pch_pcie_pm_early(dev);
216 }
217 
218 static void pch_pciexp_scan_bridge(struct device *dev)
219 {
221 
222  if (CONFIG(PCIEXP_HOTPLUG) && config->pcie_hotplug_map[PCI_FUNC(dev->path.pci.devfn)]) {
224  } else {
225  /* Normal PCIe Scan */
226  pciexp_scan_bridge(dev);
227  }
228 
229  /* Late Power Management init after bridge device enumeration */
230  pch_pcie_pm_late(dev);
231 }
232 
233 static struct device_operations device_ops = {
235  .set_resources = pci_dev_set_resources,
236  .enable_resources = pci_bus_enable_resources,
237  .init = pci_init,
238  .enable = pch_pcie_enable,
239  .scan_bus = pch_pciexp_scan_bridge,
240  .acpi_name = pch_pcie_acpi_name,
241  .ops_pci = &pci_dev_ops_pci,
242 };
243 
244 static const unsigned short pci_device_ids[] = { 0x1c10, 0x1c12, 0x1c14, 0x1c16,
245  0x1c18, 0x1c1a, 0x1c1c, 0x1c1e,
246  0x1e10, 0x1e12, 0x1e14, 0x1e16,
247  0x1e18, 0x1e1a, 0x1e1c, 0x1e1e,
248  0 };
249 
250 static const struct pci_driver pch_pcie __pci_driver = {
251  .ops = &device_ops,
252  .vendor = PCI_VID_INTEL,
253  .devices = pci_device_ids,
254 };
#define ASSERT(x)
Definition: assert.h:44
#define printk(level,...)
Definition: stdlib.h:16
@ CONFIG
Definition: dsi_common.h:201
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_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 u16 pci_read_config16(const struct device *dev, u16 reg)
Definition: pci_ops.h:52
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_write_config16(const struct device *dev, u16 reg, u16 val)
Definition: pci_ops.h:70
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
enum board_config config
Definition: memory.c:448
#define PCI_BRIDGE_CTL_PARITY
Definition: pci_def.h:136
#define PCI_BRIDGE_CONTROL
Definition: pci_def.h:134
#define PCI_COMMAND_MASTER
Definition: pci_def.h:13
#define PCI_FUNC(devfn)
Definition: pci_def.h:550
#define PCI_COMMAND
Definition: pci_def.h:10
#define PCI_SLOT(devfn)
Definition: pci_def.h:549
void pci_bus_enable_resources(struct device *dev)
Definition: pci_device.c:758
void pci_bus_read_resources(struct device *dev)
Definition: pci_device.c:540
struct pci_operations pci_dev_ops_pci
Default device operation for PCI devices.
Definition: pci_device.c:911
void pci_dev_set_resources(struct device *dev)
Definition: pci_device.c:691
#define PCI_VID_INTEL
Definition: pci_ids.h:2157
aspm_type
Definition: pciexp.h:5
@ PCIE_ASPM_BOTH
Definition: pciexp.h:9
void pciexp_hotplug_scan_bridge(struct device *dev)
void pciexp_scan_bridge(struct device *dev)
#define RPC
Definition: rcba.h:8
#define CIR9
Definition: pch.h:258
static struct device_operations device_ops
Definition: pcie.c:233
static const char * pch_pcie_acpi_name(const struct device *dev)
Definition: pcie.c:16
static void pch_pcie_pm_early(struct device *dev)
Definition: pcie.c:36
static void pch_pcie_pm_late(struct device *dev)
Definition: pcie.c:141
static void pci_init(struct device *dev)
Definition: pcie.c:180
static void pch_pcie_enable(struct device *dev)
Definition: pcie.c:212
static const unsigned short pci_device_ids[]
Definition: pcie.c:244
static void pch_pciexp_scan_bridge(struct device *dev)
Definition: pcie.c:218
static const struct pci_driver pch_pcie __pci_driver
Definition: pcie.c:250
#define RCBA32(x)
Definition: rcba.h:14
#define NULL
Definition: stddef.h:19
uint32_t u32
Definition: stdint.h:51
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
void(* read_resources)(struct device *dev)
Definition: device.h:39
struct pci_path pci
Definition: path.h:116
Definition: device.h:107
struct device_path path
Definition: device.h:115
DEVTREE_CONST void * chip_info
Definition: device.h:164
unsigned int devfn
Definition: path.h:54