coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
pch.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <delay.h>
5 #include <device/device.h>
6 #include <device/pci.h>
7 #include <device/pci_def.h>
8 #include <device/pci_ops.h>
9 #include <string.h>
10 
11 #include "chip.h"
12 #include "pch.h"
13 
15 {
16  static int pch_revision_id = -1;
17 
18 #ifdef __SIMPLE_DEVICE__
19  pci_devfn_t dev = PCI_DEV(0, 0x1f, 0);
20 #else
21  struct device *dev = pcidev_on_root(0x1f, 0);
22 #endif
23 
24  if (pch_revision_id < 0)
25  pch_revision_id = pci_read_config8(dev, PCI_REVISION_ID);
26  return pch_revision_id;
27 }
28 
30 {
31  static int pch_type = -1;
32 
33 #ifdef __SIMPLE_DEVICE__
34  pci_devfn_t dev = PCI_DEV(0, 0x1f, 0);
35 #else
36  struct device *dev = pcidev_on_root(0x1f, 0);
37 #endif
38 
39  if (pch_type < 0)
41  return pch_type;
42 }
43 
44 static int pch_silicon_supported(int type, int rev)
45 {
46  int cur_type = pch_silicon_type();
47  int cur_rev = pch_silicon_revision();
48 
49  switch (type) {
50  case PCH_TYPE_CPT:
51  /* CougarPoint minimum revision */
52  if (cur_type == PCH_TYPE_CPT && cur_rev >= rev)
53  return 1;
54  /* PantherPoint any revision */
55  if (cur_type == PCH_TYPE_PPT)
56  return 1;
57  break;
58 
59  case PCH_TYPE_PPT:
60  /* PantherPoint minimum revision */
61  if (cur_type == PCH_TYPE_PPT && cur_rev >= rev)
62  return 1;
63  break;
64  }
65 
66  return 0;
67 }
68 
69 #define IOBP_RETRY 1000
70 static inline int iobp_poll(void)
71 {
72  unsigned int try = IOBP_RETRY;
73  u32 data;
74 
75  while (try--) {
76  data = RCBA32(IOBPS);
77  if ((data & 1) == 0)
78  return 1;
79  udelay(10);
80  }
81 
82  printk(BIOS_ERR, "IOBP timeout\n");
83  return 0;
84 }
85 
86 void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
87 {
88  u32 data;
89 
90  /* Set the address */
92 
93  /* READ OPCODE */
96  else
98  if (!iobp_poll())
99  return;
100 
101  /* Read IOBP data */
102  data = RCBA32(IOBPD);
103  if (!iobp_poll())
104  return;
105 
106  /* Check for successful transaction */
107  if ((RCBA32(IOBPS) & 0x6) != 0) {
108  printk(BIOS_ERR, "IOBP read 0x%08x failed\n", address);
109  return;
110  }
111 
112  /* Update the data */
113  data &= andvalue;
114  data |= orvalue;
115 
116  /* WRITE OPCODE */
119  else
121  if (!iobp_poll())
122  return;
123 
124  /* Write IOBP data */
125  RCBA32(IOBPD) = data;
126  if (!iobp_poll())
127  return;
128 }
129 
130 #ifndef __SIMPLE_DEVICE__
131 /* Set bit in function disable register to hide this device */
132 static void pch_hide_devfn(unsigned int devfn)
133 {
134  switch (devfn) {
135  case PCI_DEVFN(20, 0): /* xHCI */
136  if (pch_silicon_type() == PCH_TYPE_PPT) {
137  /* on CPT this bit is reserved */
139  }
140  break;
141  case PCI_DEVFN(22, 0): /* MEI #1 */
143  break;
144  case PCI_DEVFN(22, 1): /* MEI #2 */
146  break;
147  case PCI_DEVFN(22, 2): /* IDE-R */
149  break;
150  case PCI_DEVFN(22, 3): /* KT */
152  break;
153  case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
154  /* BUC is already handled in `early_pch.c`. */
155  break;
156  case PCI_DEVFN(26, 0): /* EHCI #2 */
158  break;
159  case PCI_DEVFN(27, 0): /* HD Audio Controller */
161  break;
162  case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
163  case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
164  case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
165  case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
166  case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
167  case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
168  case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
169  case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
171  break;
172  case PCI_DEVFN(29, 0): /* EHCI #1 */
174  break;
175  case PCI_DEVFN(30, 0): /* PCI-to-PCI Bridge */
177  break;
178  case PCI_DEVFN(31, 0): /* LPC */
180  break;
181  case PCI_DEVFN(31, 2): /* SATA #1 */
183  break;
184  case PCI_DEVFN(31, 3): /* SMBUS */
186  break;
187  case PCI_DEVFN(31, 5): /* SATA #22 */
189  break;
190  case PCI_DEVFN(31, 6): /* Thermal Subsystem */
192  break;
193  }
194 }
195 
196 /* Check if any port in set X to X+3 is enabled */
197 static int pch_pcie_check_set_enabled(struct device *dev)
198 {
199  struct device *port;
200  int port_func;
201  int dev_func = PCI_FUNC(dev->path.pci.devfn);
202 
203  printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
204 
205  /* Go through static device tree list of devices
206  * because enumeration is still in progress */
207  for (port = all_devices; port; port = port->next) {
208  /* Only care about PCIe root ports */
209  if (PCI_SLOT(port->path.pci.devfn) !=
210  PCI_SLOT(dev->path.pci.devfn))
211  continue;
212 
213  /* Check if port is in range and enabled */
214  port_func = PCI_FUNC(port->path.pci.devfn);
215  if (port_func >= dev_func &&
216  port_func < (dev_func + 4) &&
217  port->enabled)
218  return 1;
219  }
220 
221  /* None of the ports in this set are enabled */
222  return 0;
223 }
224 
225 /* RPFN is a write-once register so keep a copy until it is written */
226 static u32 new_rpfn;
227 
228 /* Swap function numbers assigned to two PCIe Root Ports */
229 static void pch_pcie_function_swap(u8 old_fn, u8 new_fn)
230 {
231  u32 old_rpfn = new_rpfn;
232 
233  printk(BIOS_DEBUG, "PCH: Remap PCIe function %d to %d\n",
234  old_fn, new_fn);
235 
236  new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn));
237 
238  /* Old function set to new function and disabled */
239  new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn));
240  new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn));
241 }
242 
243 /* Update devicetree with new Root Port function number assignment */
246 {
247  struct device *dev;
248 
249  /*
250  * hotplug map should also be updated along with their
251  * corresponding port
252  */
253  u8 new_hotplug_map[sizeof(config->pcie_hotplug_map)];
254 
255  /*
256  * Slots that didn't move need the hotplug setting copied too,
257  * so "new_hotplug_map" is initialized with the values of the old map.
258  */
259  memcpy(new_hotplug_map, config->pcie_hotplug_map,
260  sizeof(new_hotplug_map));
261 
262  /* Update the function numbers in the static devicetree */
263  for (dev = all_devices; dev; dev = dev->next) {
264  u8 new_devfn;
265 
266  /* Only care about PCH PCIe root ports */
267  if (PCI_SLOT(dev->path.pci.devfn) !=
269  continue;
270 
271  /* Determine the new devfn for this port */
272  new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT,
274  PCI_FUNC(dev->path.pci.devfn)));
275 
276  if (dev->path.pci.devfn != new_devfn) {
278  "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
279  PCI_SLOT(dev->path.pci.devfn),
280  PCI_FUNC(dev->path.pci.devfn),
281  PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
282 
283  /*
284  * Copy the flag to its new position along with
285  * the corresponding port
286  */
287  new_hotplug_map[PCI_FUNC(new_devfn)] =
288  config->pcie_hotplug_map
289  [PCI_FUNC(dev->path.pci.devfn)];
290 
291  dev->path.pci.devfn = new_devfn;
292  }
293  }
294 
295  /* Copy the updated map back to its place */
296  memcpy(config->pcie_hotplug_map, new_hotplug_map,
297  sizeof(new_hotplug_map));
298 }
299 
300 /* Special handling for PCIe Root Port devices */
301 static void pch_pcie_enable(struct device *dev)
302 {
304 
305  if (!config)
306  return;
307 
308  /*
309  * Save a copy of the Root Port Function Number map when
310  * starting to walk the list of PCIe Root Ports so it can
311  * be updated locally and written out when the last port
312  * has been processed.
313  */
314  if (PCI_FUNC(dev->path.pci.devfn) == 0) {
315  new_rpfn = RCBA32(RPFN);
316 
317  /*
318  * Enable Root Port coalescing if the first port is disabled
319  * or the other devices will not be enumerated by the OS.
320  */
321  if (!dev->enabled)
322  config->pcie_port_coalesce = true;
323 
324  if (config->pcie_port_coalesce)
326  "PCH: PCIe Root Port coalescing is enabled\n");
327  }
328 
329  if (!dev->enabled) {
330  printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
331 
332  /*
333  * PCIE Power Savings for PantherPoint and CougarPoint/B1+
334  *
335  * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
336  * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
337  *
338  * This check is done here instead of PCIe driver
339  * because the PCIe driver enable() handler is not
340  * called unless the device is enabled.
341  */
342  if ((PCI_FUNC(dev->path.pci.devfn) == 0 ||
343  PCI_FUNC(dev->path.pci.devfn) == 4)) {
344  /* Handle workaround for PPT and CPT/B1+ */
347  pci_or_config8(dev, 0xe2, 1);
348  }
349 
350  /*
351  * Enable Clock Gating for shared PCIe resources
352  * before disabling this particular port.
353  */
354  pci_write_config8(dev, 0xe1, 0x3c);
355  }
356 
357  /* Ensure memory, io, and bus master are all disabled */
360 
361  /* Do not claim downstream transactions for PCIe ports */
363 
364  /* Hide this device if possible */
366  } else {
367  int fn;
368 
369  /*
370  * Check if there is a lower disabled port to swap with this
371  * port in order to maintain linear order starting at zero.
372  */
373  if (config->pcie_port_coalesce) {
374  for (fn=0; fn < PCI_FUNC(dev->path.pci.devfn); fn++) {
375  if (!(new_rpfn & RPFN_HIDE(fn)))
376  continue;
377 
378  /* Swap places with this function */
380  PCI_FUNC(dev->path.pci.devfn), fn);
381  break;
382  }
383  }
384 
385  /* Enable SERR */
387  }
388 
389  /*
390  * When processing the last PCIe root port we can now
391  * update the Root Port Function Number and Hide register.
392  */
393  if (PCI_FUNC(dev->path.pci.devfn) == 7) {
394  printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
395  RCBA32(RPFN), new_rpfn);
396  RCBA32(RPFN) = new_rpfn;
397 
398  /* Update static devictree with new function numbers */
399  if (config->pcie_port_coalesce)
401  }
402 }
403 
404 void pch_enable(struct device *dev)
405 {
406  /* PCH PCIe Root Ports get special handling */
407  if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
408  return pch_pcie_enable(dev);
409 
410  if (!dev->enabled) {
411  printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
412 
413  /* Ensure memory, io, and bus master are all disabled */
416 
417  /* Hide this device if possible */
419  } else {
420  /* Enable SERR */
422  }
423 }
424 
426  CHIP_NAME("Intel Series 6/7 (Cougar Point/Panther Point) Southbridge")
427  .enable_dev = pch_enable,
428 };
429 #endif
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
#define printk(level,...)
Definition: stdlib.h:16
DEVTREE_CONST struct device *DEVTREE_CONST all_devices
Linked list of ALL devices.
Definition: device_const.c:13
DEVTREE_CONST struct device * pcidev_on_root(uint8_t dev, uint8_t fn)
Definition: device_const.c:260
const char * dev_path(const struct device *dev)
Definition: device_util.c:149
uint64_t address
Definition: fw_cfg_if.h:0
port
Definition: i915.h:29
#define CHIP_NAME(X)
Definition: device.h:32
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_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 u8 pci_read_config8(const struct device *dev, u16 reg)
Definition: pci_ops.h:46
static __always_inline void pci_write_config8(const struct device *dev, u16 reg, u8 val)
Definition: pci_ops.h:64
unsigned int type
Definition: edid.c:57
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_SPEW
BIOS_SPEW - Excessively verbose output.
Definition: loglevel.h:142
enum board_config config
Definition: memory.c:448
#define PCI_COMMAND_SERR
Definition: pci_def.h:19
#define PCI_DEVFN(slot, func)
Definition: pci_def.h:548
#define PCI_COMMAND_IO
Definition: pci_def.h:11
#define PCI_COMMAND_MASTER
Definition: pci_def.h:13
#define PCI_COMMAND_MEMORY
Definition: pci_def.h:12
#define PCI_FUNC(devfn)
Definition: pci_def.h:550
#define PCI_COMMAND
Definition: pci_def.h:10
#define PCI_DEVICE_ID
Definition: pci_def.h:9
#define PCI_REVISION_ID
Definition: pci_def.h:41
#define PCI_SLOT(devfn)
Definition: pci_def.h:549
#define PCI_DEV(SEGBUS, DEV, FN)
Definition: pci_type.h:14
u32 pci_devfn_t
Definition: pci_type.h:8
#define PCH_DISABLE_HD_AUDIO
Definition: rcba.h:136
#define PCH_DISABLE_KT
Definition: rcba.h:146
#define PCH_DISABLE_MEI1
Definition: rcba.h:149
#define RPFN_FNGET(reg, port)
Definition: rcba.h:14
#define PCH_DISABLE_XHCI
Definition: rcba.h:143
#define PCH_DISABLE_SMBUS
Definition: rcba.h:135
#define IOBPD
Definition: rcba.h:44
#define RPFN_FNSET(port, func)
Definition: rcba.h:16
#define PCH_DISABLE_EHCI1
Definition: rcba.h:139
#define PCH_DISABLE_SATA2
Definition: rcba.h:142
#define PCH_DISABLE_LPC
Definition: rcba.h:138
#define PCH_DISABLE_EHCI2
Definition: rcba.h:137
#define FD2
Definition: rcba.h:128
#define RPFN_HIDE(port)
Definition: rcba.h:12
#define RPFN
Definition: rcba.h:9
#define FD
Definition: rcba.h:125
#define PCH_DISABLE_IDER
Definition: rcba.h:147
#define PCH_DISABLE_SATA1
Definition: rcba.h:134
#define PCH_DISABLE_THERMAL
Definition: rcba.h:141
#define IOBPIRI
Definition: rcba.h:43
#define PCH_DISABLE_PCIE(x)
Definition: rcba.h:140
#define RPFN_FNMASK(port)
Definition: rcba.h:18
#define IOBPS
Definition: rcba.h:45
#define PCH_DISABLE_MEI2
Definition: rcba.h:148
u16 pch_type(void)
Definition: pch.c:20
static int iobp_poll(void)
Definition: pch.c:70
struct chip_operations southbridge_intel_bd82x6x_ops
Definition: pch.c:425
static void pch_pcie_function_swap(u8 old_fn, u8 new_fn)
Definition: pch.c:229
void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
Definition: pch.c:86
static void pch_pcie_enable(struct device *dev)
Definition: pch.c:301
void pch_enable(struct device *dev)
Definition: pch.c:404
static int pch_pcie_check_set_enabled(struct device *dev)
Definition: pch.c:197
static u32 new_rpfn
Definition: pch.c:226
static int pch_silicon_supported(int type, int rev)
Definition: pch.c:44
int pch_silicon_type(void)
Definition: pch.c:29
int pch_silicon_revision(void)
Definition: pch.c:14
static void pch_pcie_devicetree_update(struct southbridge_intel_bd82x6x_config *config)
Definition: pch.c:244
#define IOBP_RETRY
Definition: pch.c:69
static void pch_hide_devfn(unsigned int devfn)
Definition: pch.c:132
#define PCH_TYPE_CPT
Definition: pch.h:9
#define IOBPS_RW_BX
Definition: pch.h:265
#define IOBPS_READ_AX
Definition: pch.h:267
#define PCH_DISABLE_P2P
Definition: pch.h:349
#define PCH_STEP_B0
Definition: pch.h:15
#define PCH_STEP_B1
Definition: pch.h:16
#define PCH_TYPE_PPT
Definition: pch.h:10
#define IOBPS_WRITE_AX
Definition: pch.h:266
#define PCH_PCIE_DEV_SLOT
Definition: pch.h:81
#define RCBA32_OR(x, or)
Definition: rcba.h:22
#define RCBA32(x)
Definition: rcba.h:14
uint32_t u32
Definition: stdint.h:51
uint8_t u8
Definition: stdint.h:45
struct pci_path pci
Definition: path.h:116
Definition: device.h:107
struct device_path path
Definition: device.h:115
DEVTREE_CONST struct device * next
Definition: device.h:113
DEVTREE_CONST void * chip_info
Definition: device.h:164
unsigned int enabled
Definition: device.h:122
unsigned int devfn
Definition: path.h:54
void udelay(uint32_t us)
Definition: udelay.c:15