blob: ac6d4ca7c017fe583938de8d613198feeb059414 [file] [log] [blame]
Angel Pons4b429832020-04-02 23:48:50 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Chris Morgan5e5e7892020-02-07 09:40:42 -06002
3#include <console/console.h>
4#include <device/device.h>
5#include <device/pci.h>
6#include <device/pciexp.h>
7#include <device/pci_ids.h>
Angel Ponsae999502020-11-05 01:58:34 +01008#include <device/pci_ops.h>
Chris Morgan5e5e7892020-02-07 09:40:42 -06009#include <assert.h>
Angel Ponsae999502020-11-05 01:58:34 +010010#include <types.h>
11
12#include "chip.h"
13#include "haswell.h"
Chris Morgan5e5e7892020-02-07 09:40:42 -060014
Chris Morgan5e5e7892020-02-07 09:40:42 -060015#if CONFIG(HAVE_ACPI_TABLES)
16static const char *pcie_acpi_name(const struct device *dev)
17{
18 assert(dev);
19
20 if (dev->path.type != DEVICE_PATH_PCI)
21 return NULL;
22
23 assert(dev->bus);
24 if (dev->bus->secondary == 0)
25 switch (dev->path.pci.devfn) {
26 case PCI_DEVFN(1, 0):
27 return "PEGP";
28 case PCI_DEVFN(1, 1):
29 return "PEG1";
30 case PCI_DEVFN(1, 2):
31 return "PEG2";
32 };
33
34 struct device *const port = dev->bus->dev;
35 assert(port);
36 assert(port->bus);
37
38 if (dev->path.pci.devfn == PCI_DEVFN(0, 0) &&
39 port->bus->secondary == 0 &&
40 (port->path.pci.devfn == PCI_DEVFN(1, 0) ||
41 port->path.pci.devfn == PCI_DEVFN(1, 1) ||
42 port->path.pci.devfn == PCI_DEVFN(1, 2)))
43 return "DEV0";
44
45 return NULL;
46}
47#endif
48
Angel Ponsae999502020-11-05 01:58:34 +010049static void peg_enable(struct device *dev)
50{
51 const struct northbridge_intel_haswell_config *config = config_of(dev);
52
53 const uint8_t func = PCI_FUNC(PCI_BDF(dev));
54
55 assert(func < ARRAY_SIZE(config->peg_cfg));
56
57 const bool slot_implemented = !config->peg_cfg[func].is_onboard;
58
59 if (slot_implemented) {
60 /* Default is 1, but register is R/WO and needs to be written to once */
61 pci_or_config16(dev, PEG_CAP, 1 << 8);
62 } else {
63 pci_and_config16(dev, PEG_CAP, ~(1 << 8));
64 }
65
66 /* Note: this register is write-once */
67 uint32_t slotcap = pci_read_config32(dev, PEG_SLOTCAP);
68
69 /* Physical slot number (zero for ports connected to onboard devices) */
70 slotcap &= ~(0x1fff << 19);
71 if (slot_implemented) {
72 uint16_t slot_number = config->peg_cfg[func].phys_slot_number & 0x1fff;
73 if (slot_number == 0) {
74 /* Slot number must be non-zero and unique */
75 slot_number = func + 1;
76 }
77 slotcap |= slot_number << 19;
78 }
79
80 /* Default to 1.0 watt scale */
81 slotcap &= ~(3 << 15);
82 slotcap |= (config->peg_cfg[func].power_limit_scale & 3) << 15;
83
84 uint8_t power_limit_value = config->peg_cfg[func].power_limit_value;
85 if (power_limit_value == 0) {
86 /* Default to 75 watts */
87 power_limit_value = 75;
88 }
89 slotcap &= ~(0xff << 7);
90 slotcap |= power_limit_value << 7;
91
92 pci_write_config32(dev, PEG_SLOTCAP, slotcap);
93
94 /* Clear errors */
95 pci_write_config16(dev, PCI_STATUS, 0xffff);
96 pci_write_config16(dev, PCI_SEC_STATUS, 0xffff);
97 pci_write_config16(dev, PEG_DSTS, 0xffff);
98 pci_write_config32(dev, PEG_UESTS, 0xffffffff);
99 pci_write_config32(dev, PEG_CESTS, 0xffffffff);
100 pci_write_config32(dev, 0x1f0, 0xffffffff);
101
102 pci_or_config32(dev, PEG_VC0RCTL, 0x7f << 1);
103
104 /* Advertise OBFF support using WAKE# signaling only */
105 pci_or_config32(dev, PEG_DCAP2, 1 << 19);
106
107 pci_or_config32(dev, PEG_UESEV, 1 << 14);
108
109 /* Select -3.5 dB de-emphasis */
110 pci_or_config32(dev, PEG_LCTL2, 1 << 6);
111
112 pci_or_config32(dev, PEG_L0SLAT, 1 << 31);
113
114 pci_update_config32(dev, 0x250, ~(7 << 20), 2 << 20);
115
116 pci_or_config32(dev, 0x238, 1 << 29);
117
118 pci_or_config32(dev, 0x1f8, 1 << 16);
119
120 pci_update_config32(dev, PEG_AFE_PM_TMR, ~0x1f, 0x13);
121
122 /* Lock DCAP */
123 pci_update_config32(dev, PEG_DCAP, ~0, 0);
124
125 if (func == 0)
126 pci_or_config32(dev, 0xcd0, 1 << 11);
127
128 /* Enable support for L0s and L1 */
129 pci_or_config32(dev, PEG_LCAP, 3 << 10);
130
131 pci_and_config32(dev, 0x200, ~(3 << 26));
132
133 /* Other fields in this register must not be changed while writing this */
134 pci_or_config16(dev, 0x258, 1 << 2);
135}
136
Chris Morgan5e5e7892020-02-07 09:40:42 -0600137static struct device_operations device_ops = {
138 .read_resources = pci_bus_read_resources,
139 .set_resources = pci_dev_set_resources,
140 .enable_resources = pci_bus_enable_resources,
141 .scan_bus = pciexp_scan_bridge,
142 .reset_bus = pci_bus_reset,
Angel Ponsae999502020-11-05 01:58:34 +0100143 .enable = peg_enable,
Chris Morgan5e5e7892020-02-07 09:40:42 -0600144 .init = pci_dev_init,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200145 .ops_pci = &pci_dev_ops_pci,
Chris Morgan5e5e7892020-02-07 09:40:42 -0600146#if CONFIG(HAVE_ACPI_TABLES)
147 .acpi_name = pcie_acpi_name,
148#endif
149};
150
Iru Cai12a13e12020-05-22 22:57:03 +0800151static const unsigned short pci_device_ids[] = {
152 0x0c01, 0x0c05, 0x0c09, 0x0c0d,
153 0x0d01, 0x0d05, 0x0d09, /* Crystal Well */
154 0 };
Chris Morgan5e5e7892020-02-07 09:40:42 -0600155
156static const struct pci_driver pch_pcie __pci_driver = {
157 .ops = &device_ops,
158 .vendor = PCI_VENDOR_ID_INTEL,
159 .devices = pci_device_ids,
160};