• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/io.h>
4 #include <device/pci_ops.h>
5 #include <device/device.h>
6 #include <device/pci.h>
7 #include <console/console.h>
8 #include "chip.h"
9 #include "i82801jx.h"
10 
11 typedef struct southbridge_intel_i82801jx_config config_t;
12 
i82801jx_enable_device(struct device * dev)13 static void i82801jx_enable_device(struct device *dev)
14 {
15 	/* Enable SERR */
16 	pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_SERR);
17 }
18 
i82801jx_early_settings(const config_t * const info)19 static void i82801jx_early_settings(const config_t *const info)
20 {
21 	/* Program FERR# as processor break event indicator. */
22 	RCBA32(GCS) |= (1 << 6);
23 	/* BIOS must program... */
24 	RCBA32(RCBA_CIR8) = (RCBA32(RCBA_CIR8) & ~(0x3 <<  0)) | (0x2 <<  0);
25 	RCBA32(RCBA_FD) |= (1 << 0);
26 	RCBA32(RCBA_CIR9) = (RCBA32(RCBA_CIR9) & ~(0x3 << 26)) | (0x2 << 26);
27 	RCBA32(RCBA_CIR7) = (RCBA32(RCBA_CIR7) & ~(0xf << 16)) | (0x5 << 16);
28 	RCBA32(RCBA_CIR13) = (RCBA32(RCBA_CIR13) & ~(0xf << 16)) | (0x5 << 16);
29 	/* RCBA32(RCBA_CIR5) |= (1 << 0); cf. Specification Update */
30 	RCBA32(RCBA_CIR10) |= (3 << 16);
31 }
32 
i82801jx_pcie_init(const config_t * const info)33 static void i82801jx_pcie_init(const config_t *const info)
34 {
35 	struct device *pciePort[6];
36 	int i, slot_number = 1; /* Reserve slot number 0 for nb's PEG. */
37 
38 	/* PCIe - BIOS must program... */
39 	for (i = 0; i < 6; ++i) {
40 		pciePort[i] = pcidev_on_root(0x1c, i);
41 		if (!pciePort[i]) {
42 			printk(BIOS_EMERG, "PCIe port 00:1c.%x", i);
43 			die(" is not listed in devicetree.\n");
44 		}
45 		pci_or_config32(pciePort[i], 0x300, 1 << 21);
46 		pci_write_config8(pciePort[i], 0x324, 0x40);
47 	}
48 
49 	for (i = 5; (i >= 0) && !pciePort[i]->enabled; --i) {
50 		/* Only for the top disabled ports. */
51 		pci_or_config32(pciePort[i], 0x300, 0x3 << 16);
52 	}
53 
54 	/* Set slot implemented, slot number and slot power limits. */
55 	for (i = 0; i < 6; ++i) {
56 		struct device *const dev = pciePort[i];
57 		u32 xcap = pci_read_config32(dev, D28Fx_XCAP);
58 		if (info->pcie_slot_implemented & (1 << i))
59 			xcap |=  PCI_EXP_FLAGS_SLOT;
60 		else
61 			xcap &= ~PCI_EXP_FLAGS_SLOT;
62 		pci_write_config32(dev, D28Fx_XCAP, xcap);
63 
64 		if (info->pcie_slot_implemented & (1 << i)) {
65 			u32 slcap = pci_read_config32(dev, D28Fx_SLCAP);
66 			slcap &= ~(0x1fff << 19);
67 			slcap |=  (slot_number++ << 19);
68 			slcap &= ~(0x0003 << 16);
69 			slcap |=  (info->pcie_power_limits[i].scale << 16);
70 			slcap &= ~(0x00ff <<  7);
71 			slcap |=  (info->pcie_power_limits[i].value <<  7);
72 			pci_write_config32(dev, D28Fx_SLCAP, slcap);
73 		}
74 	}
75 
76 	/* Lock R/WO ASPM support bits. */
77 	for (i = 0; i < 6; ++i)
78 		pci_update_config32(pciePort[i], 0x4c, ~0, 0);
79 }
80 
i82801jx_ehci_init(void)81 static void i82801jx_ehci_init(void)
82 {
83 	struct device *const pciEHCI1 = pcidev_on_root(0x1d, 7);
84 	if (!pciEHCI1)
85 		die("EHCI controller (00:1d.7) not listed in devicetree.\n");
86 	struct device *const pciEHCI2 = pcidev_on_root(0x1a, 7);
87 	if (!pciEHCI2)
88 		die("EHCI controller (00:1a.7) not listed in devicetree.\n");
89 
90 	u32 reg32;
91 
92 	/* TODO: Maybe we have to save and
93 		 restore these settings across S3. */
94 	reg32 = pci_read_config32(pciEHCI1, 0xfc);
95 	pci_write_config32(pciEHCI1, 0xfc, (reg32 & ~(3 << 2)) |
96 					   (1 << 29) | (1 << 17) | (2 << 2));
97 	reg32 = pci_read_config32(pciEHCI2, 0xfc);
98 	pci_write_config32(pciEHCI2, 0xfc, (reg32 & ~(3 << 2)) |
99 					   (1 << 29) | (1 << 17) | (2 << 2));
100 }
101 
i82801jx_function_disabled(const unsigned int devfn)102 static int i82801jx_function_disabled(const unsigned int devfn)
103 {
104 	struct device *const dev = pcidev_path_on_root(devfn);
105 	if (!dev) {
106 		printk(BIOS_EMERG,
107 		       "PCI device 00:%x.%x",
108 		       PCI_SLOT(devfn), PCI_FUNC(devfn));
109 		die(" is not listed in devicetree.\n");
110 	}
111 	return !dev->enabled;
112 }
113 
i82801jx_hide_functions(void)114 static void i82801jx_hide_functions(void)
115 {
116 	int i;
117 	u32 reg32;
118 
119 	/* FIXME: This works pretty good if the devicetree is consistent. But
120 	          some functions have to be disabled in right order and/or have
121 		  other constraints. */
122 
123 	if (i82801jx_function_disabled(PCI_DEVFN(0x19, 0)))
124 		RCBA32(RCBA_BUC) |= BUC_LAND;
125 
126 	reg32 = RCBA32(RCBA_FD);
127 	struct {
128 		int devfn;
129 		u32 mask;
130 	} functions[] = {
131 		{ PCI_DEVFN(0x1a, 0), FD_U4D },		/* UHCI #4 */
132 		{ PCI_DEVFN(0x1a, 1), FD_U5D },		/* UHCI #5 */
133 		{ PCI_DEVFN(0x1a, 2), FD_U6D },		/* UHCI #6 */
134 		{ PCI_DEVFN(0x1a, 7), FD_EHCI2D },	/* EHCI #2 */
135 		{ PCI_DEVFN(0x1b, 0), FD_HDAD },	/* HD Audio */
136 		{ PCI_DEVFN(0x1c, 0), FD_PE1D },	/* PCIe #1 */
137 		{ PCI_DEVFN(0x1c, 1), FD_PE2D },	/* PCIe #2 */
138 		{ PCI_DEVFN(0x1c, 2), FD_PE3D },	/* PCIe #3 */
139 		{ PCI_DEVFN(0x1c, 3), FD_PE4D },	/* PCIe #4 */
140 		{ PCI_DEVFN(0x1c, 4), FD_PE5D },	/* PCIe #5 */
141 		{ PCI_DEVFN(0x1c, 5), FD_PE6D },	/* PCIe #6 */
142 		{ PCI_DEVFN(0x1d, 0), FD_U1D },		/* UHCI #1 */
143 		{ PCI_DEVFN(0x1d, 1), FD_U2D },		/* UHCI #2 */
144 		{ PCI_DEVFN(0x1d, 2), FD_U3D },		/* UHCI #3 */
145 		{ PCI_DEVFN(0x1d, 7), FD_EHCI1D },	/* EHCI #1 */
146 		{ PCI_DEVFN(0x1f, 0), FD_LBD },		/* LPC */
147 		{ PCI_DEVFN(0x1f, 2), FD_SAD1 },	/* SATA #1 */
148 		{ PCI_DEVFN(0x1f, 3), FD_SD },		/* SMBus */
149 		{ PCI_DEVFN(0x1f, 5), FD_SAD2 },	/* SATA #2 */
150 		{ PCI_DEVFN(0x1f, 6), FD_TTD },		/* Thermal Throttle */
151 	};
152 	for (i = 0; i < ARRAY_SIZE(functions); ++i) {
153 		if (i82801jx_function_disabled(functions[i].devfn))
154 			reg32 |= functions[i].mask;
155 	}
156 	RCBA32(RCBA_FD) = reg32;
157 	RCBA32(RCBA_FD) |= (1 << 0); /* BIOS must write this... */
158 	RCBA32(RCBA_FDSW) |= (1 << 7); /* Lock function-disable? */
159 
160 	/* Hide PCIe root port PCI functions. RPFN is partially R/WO. */
161 	reg32 = RCBA32(RCBA_RPFN);
162 	for (i = 0; i < 6; ++i) {
163 		if (i82801jx_function_disabled(PCI_DEVFN(0x1c, i)))
164 			reg32 |= (1 << ((i * 4) + 3));
165 	}
166 	RCBA32(RCBA_RPFN) = reg32;
167 
168 	/* Lock R/WO UHCI controller #6 remapping. */
169 	RCBA32(RCBA_MAP) = RCBA32(RCBA_MAP);
170 }
171 
i82801jx_init(void * chip_info)172 static void i82801jx_init(void *chip_info)
173 {
174 	const config_t *const info = (config_t *)chip_info;
175 
176 	printk(BIOS_DEBUG, "Initializing i82801jx southbridge...\n");
177 
178 	i82801jx_early_settings(info);
179 
180 	/* PCI Express setup. */
181 	i82801jx_pcie_init(info);
182 
183 	/* EHCI configuration. */
184 	i82801jx_ehci_init();
185 
186 	/* Now hide internal functions. We can't access them after this. */
187 	i82801jx_hide_functions();
188 
189 	/* Reset watchdog timer. */
190 #if !CONFIG(HAVE_SMI_HANDLER)
191 	outw(0x0008, DEFAULT_TCOBASE + 0x12); /* Set higher timer value. */
192 #endif
193 	outw(0x0000, DEFAULT_TCOBASE + 0x00); /* Update timer. */
194 }
195 
196 struct chip_operations southbridge_intel_i82801jx_ops = {
197 	.name = "Intel ICH10 (82801Jx) Series Southbridge",
198 	.enable_dev	= i82801jx_enable_device,
199 	.init		= i82801jx_init,
200 };
201