blob: 6ea2ea9aae3acf0ad2061a4f42ad9bd9000f1ecd [file] [log] [blame]
Lee Leahy77ff0b12015-05-05 15:07:29 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 * Copyright (C) 2013 Google Inc.
Lee Leahy32471722015-04-20 15:20:28 -07006 * Copyright (C) 2015 Intel Corp.
Frans Hendriksbd5233e2018-12-05 15:24:48 +01007 * Copyright (C) 2018 Eltan B.V.
Lee Leahy77ff0b12015-05-05 15:07:29 -07008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Lee Leahy77ff0b12015-05-05 15:07:29 -070017 */
18
Lee Leahy77ff0b12015-05-05 15:07:29 -070019#include <arch/io.h>
20#include <arch/acpi.h>
Lee Leahy2bc9cee2015-06-30 15:25:44 -070021#include <arch/acpigen.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070022#include <bootstate.h>
Lee Leahy32471722015-04-20 15:20:28 -070023#include "chip.h"
Lee Leahy77ff0b12015-05-05 15:07:29 -070024#include <console/console.h>
25#include <cpu/x86/smm.h>
26#include <device/device.h>
27#include <device/pci.h>
28#include <device/pci_ids.h>
Frans Hendriksbd5233e2018-12-05 15:24:48 +010029#include <pc80/i8254.h>
Lee Leahy32471722015-04-20 15:20:28 -070030#include <romstage_handoff.h>
Lee Leahy2bc9cee2015-06-30 15:25:44 -070031#include <soc/acpi.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070032#include <soc/iomap.h>
33#include <soc/irq.h>
34#include <soc/lpc.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070035#include <soc/pci_devs.h>
Lee Leahy32471722015-04-20 15:20:28 -070036#include <soc/pm.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070037#include <soc/ramstage.h>
38#include <soc/spi.h>
Lee Leahy32471722015-04-20 15:20:28 -070039#include <spi-generic.h>
40#include <stdint.h>
Hannah Williams3fa80a92017-03-22 16:33:36 -070041#include <reg_script.h>
42
43static const struct reg_script ops[] = {
44 REG_MMIO_RMW32(ILB_BASE_ADDRESS + SCNT,
45 ~SCNT_MODE, 0), /* put LPC SERIRQ in Quiet Mode */
46 REG_SCRIPT_END
47};
48
49static void enable_serirq_quiet_mode(void)
50{
51 reg_script_run(ops);
52}
Lee Leahy77ff0b12015-05-05 15:07:29 -070053
54static inline void
Elyes HAOUASb13fac32018-05-24 22:29:44 +020055add_mmio_resource(struct device *dev, int i, unsigned long addr,
56 unsigned long size)
Lee Leahy77ff0b12015-05-05 15:07:29 -070057{
Elyes HAOUASa342f392018-10-17 10:56:26 +020058 printk(BIOS_SPEW, "%s/%s (%s, 0x%016lx, 0x%016lx)\n",
Lee Leahy32471722015-04-20 15:20:28 -070059 __FILE__, __func__, dev_name(dev), addr, size);
Lee Leahy77ff0b12015-05-05 15:07:29 -070060 mmio_resource(dev, i, addr >> 10, size >> 10);
61}
62
Elyes HAOUASb13fac32018-05-24 22:29:44 +020063static void sc_add_mmio_resources(struct device *dev)
Lee Leahy77ff0b12015-05-05 15:07:29 -070064{
Elyes HAOUASa342f392018-10-17 10:56:26 +020065 printk(BIOS_SPEW, "%s/%s (%s)\n",
Lee Leahy32471722015-04-20 15:20:28 -070066 __FILE__, __func__, dev_name(dev));
Lee Leahy77ff0b12015-05-05 15:07:29 -070067 add_mmio_resource(dev, 0xfeb, ABORT_BASE_ADDRESS, ABORT_BASE_SIZE);
68 add_mmio_resource(dev, PBASE, PMC_BASE_ADDRESS, PMC_BASE_SIZE);
69 add_mmio_resource(dev, IOBASE, IO_BASE_ADDRESS, IO_BASE_SIZE);
70 add_mmio_resource(dev, IBASE, ILB_BASE_ADDRESS, ILB_BASE_SIZE);
71 add_mmio_resource(dev, SBASE, SPI_BASE_ADDRESS, SPI_BASE_SIZE);
72 add_mmio_resource(dev, MPBASE, MPHY_BASE_ADDRESS, MPHY_BASE_SIZE);
73 add_mmio_resource(dev, PUBASE, PUNIT_BASE_ADDRESS, PUNIT_BASE_SIZE);
74 add_mmio_resource(dev, RCBA, RCBA_BASE_ADDRESS, RCBA_BASE_SIZE);
75}
76
77/* Default IO range claimed by the LPC device. The upper bound is exclusive. */
78#define LPC_DEFAULT_IO_RANGE_LOWER 0
79#define LPC_DEFAULT_IO_RANGE_UPPER 0x1000
80
81static inline int io_range_in_default(int base, int size)
82{
83 /* Does it start above the range? */
84 if (base >= LPC_DEFAULT_IO_RANGE_UPPER)
85 return 0;
86
87 /* Is it entirely contained? */
88 if (base >= LPC_DEFAULT_IO_RANGE_LOWER &&
89 (base + size) < LPC_DEFAULT_IO_RANGE_UPPER)
90 return 1;
91
92 /* This will return not in range for partial overlaps. */
93 return 0;
94}
95
96/*
97 * Note: this function assumes there is no overlap with the default LPC device's
98 * claimed range: LPC_DEFAULT_IO_RANGE_LOWER -> LPC_DEFAULT_IO_RANGE_UPPER.
99 */
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200100static void sc_add_io_resource(struct device *dev, int base, int size,
101 int index)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700102{
103 struct resource *res;
104
Elyes HAOUASa342f392018-10-17 10:56:26 +0200105 printk(BIOS_SPEW, "%s/%s (%s, 0x%08x, 0x%08x, 0x%08x)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700106 __FILE__, __func__, dev_name(dev), base, size, index);
107
Lee Leahy77ff0b12015-05-05 15:07:29 -0700108 if (io_range_in_default(base, size))
109 return;
110
111 res = new_resource(dev, index);
112 res->base = base;
113 res->size = size;
114 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
115}
116
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200117static void sc_add_io_resources(struct device *dev)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700118{
119 struct resource *res;
120
Elyes HAOUASa342f392018-10-17 10:56:26 +0200121 printk(BIOS_SPEW, "%s/%s (%s)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700122 __FILE__, __func__, dev_name(dev));
123
Lee Leahy77ff0b12015-05-05 15:07:29 -0700124 /* Add the default claimed IO range for the LPC device. */
125 res = new_resource(dev, 0);
126 res->base = LPC_DEFAULT_IO_RANGE_LOWER;
127 res->size = LPC_DEFAULT_IO_RANGE_UPPER - LPC_DEFAULT_IO_RANGE_LOWER;
128 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
129
130 /* GPIO */
Frans Hendriks4b2c12f2018-11-22 07:52:38 +0100131 sc_add_io_resource(dev, GPIO_BASE_ADDRESS, GPIO_BASE_SIZE, GBASE);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700132
133 /* ACPI */
Frans Hendriks4b2c12f2018-11-22 07:52:38 +0100134 sc_add_io_resource(dev, ACPI_BASE_ADDRESS, ACPI_BASE_SIZE, ABASE);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700135}
136
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200137static void sc_read_resources(struct device *dev)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700138{
Elyes HAOUASa342f392018-10-17 10:56:26 +0200139 printk(BIOS_SPEW, "%s/%s (%s)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700140 __FILE__, __func__, dev_name(dev));
141
Lee Leahy77ff0b12015-05-05 15:07:29 -0700142 /* Get the normal PCI resources of this device. */
143 pci_dev_read_resources(dev);
144
145 /* Add non-standard MMIO resources. */
146 sc_add_mmio_resources(dev);
147
148 /* Add IO resources. */
149 sc_add_io_resources(dev);
150}
151
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200152static void sc_init(struct device *dev)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700153{
154 int i;
Lee Leahy32471722015-04-20 15:20:28 -0700155 const unsigned long pr_base = ILB_BASE_ADDRESS + 0x08;
156 const unsigned long ir_base = ILB_BASE_ADDRESS + 0x20;
157 void *gen_pmcon1 = (void *)(PMC_BASE_ADDRESS + GEN_PMCON1);
158 void *actl = (void *)(ILB_BASE_ADDRESS + ACTL);
159 const struct soc_irq_route *ir = &global_soc_irq_route;
160 struct soc_intel_braswell_config *config = dev->chip_info;
161
Elyes HAOUASa342f392018-10-17 10:56:26 +0200162 printk(BIOS_SPEW, "%s/%s (%s)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700163 __FILE__, __func__, dev_name(dev));
Lee Leahy77ff0b12015-05-05 15:07:29 -0700164
165 /* Set up the PIRQ PIC routing based on static config. */
Lee Leahy32471722015-04-20 15:20:28 -0700166 for (i = 0; i < NUM_PIRQS; i++)
167 write8((void *)(pr_base + i*sizeof(ir->pic[i])),
168 ir->pic[i]);
169
Lee Leahy77ff0b12015-05-05 15:07:29 -0700170 /* Set up the per device PIRQ routing base on static config. */
Lee Leahy32471722015-04-20 15:20:28 -0700171 for (i = 0; i < NUM_IR_DEVS; i++)
172 write16((void *)(ir_base + i*sizeof(ir->pcidev[i])),
173 ir->pcidev[i]);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700174
175 /* Route SCI to IRQ9 */
176 write32(actl, (read32(actl) & ~SCIS_MASK) | SCIS_IRQ9);
177
Lee Leahy77ff0b12015-05-05 15:07:29 -0700178 if (config->disable_slp_x_stretch_sus_fail) {
179 printk(BIOS_DEBUG, "Disabling slp_x stretching.\n");
180 write32(gen_pmcon1,
181 read32(gen_pmcon1) | DIS_SLP_X_STRCH_SUS_UP);
182 } else {
183 write32(gen_pmcon1,
184 read32(gen_pmcon1) & ~DIS_SLP_X_STRCH_SUS_UP);
185 }
186
Frans Hendriksbd5233e2018-12-05 15:24:48 +0100187 /* Initialize i8254 timers */
188 setup_i8254();
Lee Leahy77ff0b12015-05-05 15:07:29 -0700189}
190
191/*
192 * Common code for the south cluster devices.
193 */
194
Lee Leahy32471722015-04-20 15:20:28 -0700195/* Set bit in function disble register to hide this device. */
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200196static void sc_disable_devfn(struct device *dev)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700197{
Lee Leahy32471722015-04-20 15:20:28 -0700198 void *func_dis = (void *)(PMC_BASE_ADDRESS + FUNC_DIS);
199 void *func_dis2 = (void *)(PMC_BASE_ADDRESS + FUNC_DIS2);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700200 uint32_t mask = 0;
201 uint32_t mask2 = 0;
202
Elyes HAOUASa342f392018-10-17 10:56:26 +0200203 printk(BIOS_SPEW, "%s/%s (%s)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700204 __FILE__, __func__, dev_name(dev));
205
206#define SET_DIS_MASK(name_) \
207 case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC): \
208 mask |= name_ ## _DIS
209#define SET_DIS_MASK2(name_) \
210 case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC): \
211 mask2 |= name_ ## _DIS
212
Lee Leahy77ff0b12015-05-05 15:07:29 -0700213 switch (dev->path.pci.devfn) {
Lee Leahy32471722015-04-20 15:20:28 -0700214 SET_DIS_MASK(SDIO);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700215 break;
Lee Leahy32471722015-04-20 15:20:28 -0700216 SET_DIS_MASK(SD);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700217 break;
Lee Leahy32471722015-04-20 15:20:28 -0700218 SET_DIS_MASK(SATA);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700219 break;
Lee Leahy32471722015-04-20 15:20:28 -0700220 SET_DIS_MASK(XHCI);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700221 /* Disable super speed PHY when XHCI is not available. */
222 mask2 |= USH_SS_PHY_DIS;
223 break;
Lee Leahy32471722015-04-20 15:20:28 -0700224 SET_DIS_MASK(LPE);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700225 break;
Lee Leahy32471722015-04-20 15:20:28 -0700226 SET_DIS_MASK(MMC);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700227 break;
Lee Leahy32471722015-04-20 15:20:28 -0700228 SET_DIS_MASK(SIO_DMA1);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700229 break;
Lee Leahy32471722015-04-20 15:20:28 -0700230 SET_DIS_MASK(I2C1);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700231 break;
Lee Leahy32471722015-04-20 15:20:28 -0700232 SET_DIS_MASK(I2C2);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700233 break;
Lee Leahy32471722015-04-20 15:20:28 -0700234 SET_DIS_MASK(I2C3);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700235 break;
Lee Leahy32471722015-04-20 15:20:28 -0700236 SET_DIS_MASK(I2C4);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700237 break;
Lee Leahy32471722015-04-20 15:20:28 -0700238 SET_DIS_MASK(I2C5);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700239 break;
Lee Leahy32471722015-04-20 15:20:28 -0700240 SET_DIS_MASK(I2C6);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700241 break;
Lee Leahy32471722015-04-20 15:20:28 -0700242 SET_DIS_MASK(I2C7);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700243 break;
Lee Leahy32471722015-04-20 15:20:28 -0700244 SET_DIS_MASK(TXE);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700245 break;
Lee Leahy32471722015-04-20 15:20:28 -0700246 SET_DIS_MASK(HDA);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700247 break;
Lee Leahy32471722015-04-20 15:20:28 -0700248 SET_DIS_MASK(PCIE_PORT1);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700249 break;
Lee Leahy32471722015-04-20 15:20:28 -0700250 SET_DIS_MASK(PCIE_PORT2);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700251 break;
Lee Leahy32471722015-04-20 15:20:28 -0700252 SET_DIS_MASK(PCIE_PORT3);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700253 break;
Lee Leahy32471722015-04-20 15:20:28 -0700254 SET_DIS_MASK(PCIE_PORT4);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700255 break;
Lee Leahy32471722015-04-20 15:20:28 -0700256 SET_DIS_MASK(SIO_DMA2);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700257 break;
Lee Leahy32471722015-04-20 15:20:28 -0700258 SET_DIS_MASK(PWM1);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700259 break;
Lee Leahy32471722015-04-20 15:20:28 -0700260 SET_DIS_MASK(PWM2);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700261 break;
Lee Leahy32471722015-04-20 15:20:28 -0700262 SET_DIS_MASK(HSUART1);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700263 break;
Lee Leahy32471722015-04-20 15:20:28 -0700264 SET_DIS_MASK(HSUART2);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700265 break;
Lee Leahy32471722015-04-20 15:20:28 -0700266 SET_DIS_MASK(SPI);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700267 break;
Lee Leahy32471722015-04-20 15:20:28 -0700268 SET_DIS_MASK2(SMBUS);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700269 break;
270 }
271
272 if (mask != 0) {
273 write32(func_dis, read32(func_dis) | mask);
274 /* Ensure posted write hits. */
275 read32(func_dis);
276 }
277
278 if (mask2 != 0) {
279 write32(func_dis2, read32(func_dis2) | mask2);
280 /* Ensure posted write hits. */
281 read32(func_dis2);
282 }
283}
284
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200285static inline void set_d3hot_bits(struct device *dev, int offset)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700286{
287 uint32_t reg8;
Lee Leahy32471722015-04-20 15:20:28 -0700288
Elyes HAOUASa342f392018-10-17 10:56:26 +0200289 printk(BIOS_SPEW, "%s/%s (%s, 0x%08x)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700290 __FILE__, __func__, dev_name(dev), offset);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700291 printk(BIOS_DEBUG, "Power management CAP offset 0x%x.\n", offset);
292 reg8 = pci_read_config8(dev, offset + 4);
293 reg8 |= 0x3;
294 pci_write_config8(dev, offset + 4, reg8);
295}
296
Lee Leahy32471722015-04-20 15:20:28 -0700297/*
298 * Parts of the audio subsystem are powered by the HDA device. Therefore, one
Lee Leahy77ff0b12015-05-05 15:07:29 -0700299 * cannot put HDA into D3Hot. Instead perform this workaround to make some of
Lee Leahy32471722015-04-20 15:20:28 -0700300 * the audio paths work for LPE audio.
301 */
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200302static void hda_work_around(struct device *dev)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700303{
Lee Leahy32471722015-04-20 15:20:28 -0700304 void *gctl = (void *)(TEMP_BASE_ADDRESS + 0x8);
305
Elyes HAOUASa342f392018-10-17 10:56:26 +0200306 printk(BIOS_SPEW, "%s/%s (%s)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700307 __FILE__, __func__, dev_name(dev));
Lee Leahy77ff0b12015-05-05 15:07:29 -0700308
309 /* Need to set magic register 0x43 to 0xd7 in config space. */
310 pci_write_config8(dev, 0x43, 0xd7);
311
Lee Leahy32471722015-04-20 15:20:28 -0700312 /*
313 * Need to set bit 0 of GCTL to take the device out of reset. However,
314 * that requires setting up the 64-bit BAR.
315 */
Lee Leahy77ff0b12015-05-05 15:07:29 -0700316 pci_write_config32(dev, PCI_BASE_ADDRESS_0, TEMP_BASE_ADDRESS);
317 pci_write_config32(dev, PCI_BASE_ADDRESS_1, 0);
318 pci_write_config8(dev, PCI_COMMAND, PCI_COMMAND_MEMORY);
319 write32(gctl, read32(gctl) | 0x1);
320 pci_write_config8(dev, PCI_COMMAND, 0);
321 pci_write_config32(dev, PCI_BASE_ADDRESS_0, 0);
322}
323
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200324static int place_device_in_d3hot(struct device *dev)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700325{
Lee Leahy1072e7d2017-03-16 17:35:32 -0700326 unsigned int offset;
Lee Leahy77ff0b12015-05-05 15:07:29 -0700327
Elyes HAOUASa342f392018-10-17 10:56:26 +0200328 printk(BIOS_SPEW, "%s/%s (%s)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700329 __FILE__, __func__, dev_name(dev));
330
331 /*
332 * Parts of the HDA block are used for LPE audio as well.
333 * Therefore assume the HDA will never be put into D3Hot.
334 */
Lee Leahy77ff0b12015-05-05 15:07:29 -0700335 if (dev->path.pci.devfn == PCI_DEVFN(HDA_DEV, HDA_FUNC)) {
336 hda_work_around(dev);
337 return 0;
338 }
339
340 offset = pci_find_capability(dev, PCI_CAP_ID_PM);
341
342 if (offset != 0) {
343 set_d3hot_bits(dev, offset);
344 return 0;
345 }
346
Lee Leahy32471722015-04-20 15:20:28 -0700347 /*
348 * For some reason some of the devices don't have the capability
349 * pointer set correctly. Work around this by hard coding the offset.
350 */
351#define DEV_CASE(name_) \
352 case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC)
353
Lee Leahy77ff0b12015-05-05 15:07:29 -0700354 switch (dev->path.pci.devfn) {
Lee Leahy32471722015-04-20 15:20:28 -0700355 DEV_CASE(SDIO) :
356 DEV_CASE(SD) :
357 DEV_CASE(MMC) :
358 DEV_CASE(LPE) :
359 DEV_CASE(SIO_DMA1) :
360 DEV_CASE(I2C1) :
361 DEV_CASE(I2C2) :
362 DEV_CASE(I2C3) :
363 DEV_CASE(I2C4) :
364 DEV_CASE(I2C5) :
365 DEV_CASE(I2C6) :
366 DEV_CASE(I2C7) :
367 DEV_CASE(SIO_DMA2) :
368 DEV_CASE(PWM1) :
369 DEV_CASE(PWM2) :
370 DEV_CASE(HSUART1) :
371 DEV_CASE(HSUART2) :
372 DEV_CASE(SPI) :
Lee Leahy77ff0b12015-05-05 15:07:29 -0700373 offset = 0x80;
374 break;
Lee Leahy32471722015-04-20 15:20:28 -0700375 DEV_CASE(SATA) :
376 DEV_CASE(XHCI) :
Lee Leahy77ff0b12015-05-05 15:07:29 -0700377 offset = 0x70;
378 break;
Lee Leahy32471722015-04-20 15:20:28 -0700379 DEV_CASE(HDA) :
380 DEV_CASE(SMBUS) :
Lee Leahy77ff0b12015-05-05 15:07:29 -0700381 offset = 0x50;
382 break;
Lee Leahy32471722015-04-20 15:20:28 -0700383 DEV_CASE(TXE) :
Lee Leahy77ff0b12015-05-05 15:07:29 -0700384 /* TXE cannot be placed in D3Hot. */
385 return 0;
Lee Leahy32471722015-04-20 15:20:28 -0700386 DEV_CASE(PCIE_PORT1) :
387 DEV_CASE(PCIE_PORT2) :
388 DEV_CASE(PCIE_PORT3) :
389 DEV_CASE(PCIE_PORT4) :
Lee Leahy77ff0b12015-05-05 15:07:29 -0700390 offset = 0xa0;
391 break;
392 }
393
394 if (offset != 0) {
395 set_d3hot_bits(dev, offset);
396 return 0;
397 }
398
399 return -1;
400}
401
402/* Common PCI device function disable. */
Elyes HAOUASb13fac32018-05-24 22:29:44 +0200403void southcluster_enable_dev(struct device *dev)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700404{
405 uint32_t reg32;
406
Elyes HAOUASa342f392018-10-17 10:56:26 +0200407 printk(BIOS_SPEW, "%s/%s (%s)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700408 __FILE__, __func__, dev_name(dev));
Lee Leahy77ff0b12015-05-05 15:07:29 -0700409 if (!dev->enabled) {
410 int slot = PCI_SLOT(dev->path.pci.devfn);
411 int func = PCI_FUNC(dev->path.pci.devfn);
412 printk(BIOS_DEBUG, "%s: Disabling device: %02x.%01x\n",
413 dev_path(dev), slot, func);
414
415 /* Ensure memory, io, and bus master are all disabled */
416 reg32 = pci_read_config32(dev, PCI_COMMAND);
417 reg32 &= ~(PCI_COMMAND_MASTER |
418 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
419 pci_write_config32(dev, PCI_COMMAND, reg32);
420
421 /* Place device in D3Hot */
422 if (place_device_in_d3hot(dev) < 0) {
423 printk(BIOS_WARNING,
424 "Could not place %02x.%01x into D3Hot. "
425 "Keeping device visible.\n", slot, func);
426 return;
427 }
428 /* Disable this device if possible */
429 sc_disable_devfn(dev);
430 } else {
431 /* Enable SERR */
432 reg32 = pci_read_config32(dev, PCI_COMMAND);
433 reg32 |= PCI_COMMAND_SERR;
434 pci_write_config32(dev, PCI_COMMAND, reg32);
435 }
436}
437
438static struct device_operations device_ops = {
439 .read_resources = sc_read_resources,
440 .set_resources = pci_dev_set_resources,
441 .enable_resources = NULL,
Lee Leahy2bc9cee2015-06-30 15:25:44 -0700442 .acpi_inject_dsdt_generator = southcluster_inject_dsdt,
443 .write_acpi_tables = southcluster_write_acpi_tables,
Lee Leahy77ff0b12015-05-05 15:07:29 -0700444 .init = sc_init,
445 .enable = southcluster_enable_dev,
Lee Leahy32471722015-04-20 15:20:28 -0700446 .scan_bus = scan_lpc_bus,
Lee Leahy77ff0b12015-05-05 15:07:29 -0700447 .ops_pci = &soc_pci_ops,
448};
449
450static const struct pci_driver southcluster __pci_driver = {
451 .ops = &device_ops,
452 .vendor = PCI_VENDOR_ID_INTEL,
453 .device = LPC_DEVID,
454};
455
Aaron Durbin64031672018-04-21 14:45:32 -0600456int __weak mainboard_get_spi_config(struct spi_config *cfg)
Lee Leahy77ff0b12015-05-05 15:07:29 -0700457{
Elyes HAOUASa342f392018-10-17 10:56:26 +0200458 printk(BIOS_SPEW, "%s/%s (0x%p)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700459 __FILE__, __func__, (void *)cfg);
Lee Leahy77ff0b12015-05-05 15:07:29 -0700460 return -1;
461}
462
463static void finalize_chipset(void *unused)
464{
Lee Leahy32471722015-04-20 15:20:28 -0700465 void *bcr = (void *)(SPI_BASE_ADDRESS + BCR);
466 void *gcs = (void *)(RCBA_BASE_ADDRESS + GCS);
467 void *gen_pmcon2 = (void *)(PMC_BASE_ADDRESS + GEN_PMCON2);
468 void *etr = (void *)(PMC_BASE_ADDRESS + ETR);
469 uint8_t *spi = (uint8_t *)SPI_BASE_ADDRESS;
Lee Leahy77ff0b12015-05-05 15:07:29 -0700470 struct spi_config cfg;
471
Elyes HAOUASa342f392018-10-17 10:56:26 +0200472 printk(BIOS_SPEW, "%s/%s (0x%p)\n",
Lee Leahy32471722015-04-20 15:20:28 -0700473 __FILE__, __func__, unused);
474
Lee Leahy77ff0b12015-05-05 15:07:29 -0700475 /* Set the lock enable on the BIOS control register. */
476 write32(bcr, read32(bcr) | BCR_LE);
477
478 /* Set BIOS lock down bit controlling boot block size and swapping. */
479 write32(gcs, read32(gcs) | BILD);
480
481 /* Lock sleep stretching policy and set SMI lock. */
482 write32(gen_pmcon2, read32(gen_pmcon2) | SLPSX_STR_POL_LOCK | SMI_LOCK);
483
484 /* Set the CF9 lock. */
485 write32(etr, read32(etr) | CF9LOCK);
486
487 if (mainboard_get_spi_config(&cfg) < 0) {
488 printk(BIOS_DEBUG, "No SPI lockdown configuration.\n");
489 } else {
490 write16(spi + PREOP, cfg.preop);
491 write16(spi + OPTYPE, cfg.optype);
492 write32(spi + OPMENU0, cfg.opmenu[0]);
493 write32(spi + OPMENU1, cfg.opmenu[1]);
494 write16(spi + HSFSTS, read16(spi + HSFSTS) | FLOCKDN);
495 write32(spi + UVSCC, cfg.uvscc);
496 write32(spi + LVSCC, cfg.lvscc | VCL);
497 }
Lee Leahy32471722015-04-20 15:20:28 -0700498 spi_init();
Hannah Williams3fa80a92017-03-22 16:33:36 -0700499 enable_serirq_quiet_mode();
Lee Leahy77ff0b12015-05-05 15:07:29 -0700500
501 printk(BIOS_DEBUG, "Finalizing SMM.\n");
502 outb(APM_CNT_FINALIZE, APM_CNT);
503}
504
Hannah Williams2cfdde72015-04-15 19:48:07 -0700505BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, finalize_chipset, NULL);