diff options
Diffstat (limited to 'arch/x86/cpu')
38 files changed, 1749 insertions, 1076 deletions
diff --git a/arch/x86/cpu/baytrail/early_uart.c b/arch/x86/cpu/baytrail/early_uart.c index b64a3a90db..471d592b49 100644 --- a/arch/x86/cpu/baytrail/early_uart.c +++ b/arch/x86/cpu/baytrail/early_uart.c @@ -59,11 +59,15 @@ static void x86_pci_write_config32(int dev, unsigned int where, u32 value) } /* This can be called after memory-mapped PCI is working */ -int setup_early_uart(void) +int setup_internal_uart(int enable) { - /* Enable the legacy UART hardware. */ + /* Enable or disable the legacy UART hardware */ x86_pci_write_config32(PCI_DEV_CONFIG(0, LPC_DEV, LPC_FUNC), UART_CONT, - 1); + enable); + + /* All done for the disable part, so just return */ + if (!enable) + return 0; /* * Set up the pads to the UART function. This allows the signals to diff --git a/arch/x86/cpu/baytrail/fsp_configs.c b/arch/x86/cpu/baytrail/fsp_configs.c index a72d615f21..d49b8d2737 100644 --- a/arch/x86/cpu/baytrail/fsp_configs.c +++ b/arch/x86/cpu/baytrail/fsp_configs.c @@ -121,16 +121,23 @@ const struct pch_azalia_config azalia_config = { }; /** - * Override the FSP's UPD. + * Override the FSP's configuration data. * If the device tree does not specify an integer setting, use the default * provided in Intel's Baytrail_FSP_Gold4.tgz release FSP/BayleyBayFsp.bsf file. */ -void update_fsp_upd(struct upd_region *fsp_upd) +void update_fsp_configs(struct fsp_config_data *config, + struct fspinit_rtbuf *rt_buf) { + struct upd_region *fsp_upd = &config->fsp_upd; struct memory_down_data *mem; const void *blob = gd->fdt_blob; int node; + /* Initialize runtime buffer for fsp_init() */ + rt_buf->common.stack_top = config->common.stack_top - 32; + rt_buf->common.boot_mode = config->common.boot_mode; + rt_buf->common.upd_data = &config->fsp_upd; + fsp_upd->azalia_config_ptr = (uint32_t)&azalia_config; node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_BAYTRAIL_FSP); diff --git a/arch/x86/cpu/baytrail/valleyview.c b/arch/x86/cpu/baytrail/valleyview.c index 7299f2cddc..25382f9aab 100644 --- a/arch/x86/cpu/baytrail/valleyview.c +++ b/arch/x86/cpu/baytrail/valleyview.c @@ -50,7 +50,7 @@ int arch_misc_init(void) mrccache_save(); #endif - return pirq_init(); + return 0; } int reserve_arch(void) diff --git a/arch/x86/cpu/coreboot/pci.c b/arch/x86/cpu/coreboot/pci.c index 41e29a6086..7f5087a918 100644 --- a/arch/x86/cpu/coreboot/pci.c +++ b/arch/x86/cpu/coreboot/pci.c @@ -14,7 +14,8 @@ #include <pci.h> static const struct udevice_id generic_pch_ids[] = { - { .compatible = "intel,pch" }, + { .compatible = "intel,pch7" }, + { .compatible = "intel,pch9" }, { } }; diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 381d83526f..6c3a748f75 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -688,7 +688,7 @@ static int x86_mp_init(void) } #endif -__weak int x86_init_cpus(void) +static int x86_init_cpus(void) { #ifdef CONFIG_SMP debug("Init additional CPUs\n"); @@ -709,8 +709,24 @@ __weak int x86_init_cpus(void) int cpu_init_r(void) { - if (ll_boot_init()) - return x86_init_cpus(); + struct udevice *dev; + int ret; + + if (!ll_boot_init()) + return 0; + + ret = x86_init_cpus(); + if (ret) + return ret; + + /* + * Set up the northbridge, PCH and LPC if available. Note that these + * may have had some limited pre-relocation init if they were probed + * before relocation, but this is post relocation. + */ + uclass_first_device(UCLASS_NORTHBRIDGE, &dev); + uclass_first_device(UCLASS_PCH, &dev); + uclass_first_device(UCLASS_LPC, &dev); return 0; } diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index b00ddc0cb4..c40200bf85 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -12,6 +12,7 @@ */ #include <common.h> +#include <dm.h> #include <asm/cache.h> #include <asm/control_regs.h> #include <asm/interrupt.h> @@ -244,6 +245,14 @@ int disable_interrupts(void) int interrupt_init(void) { + struct udevice *dev; + int ret; + + /* Try to set up the interrupt router, but don't require one */ + ret = uclass_first_device(UCLASS_IRQ, &dev); + if (ret && ret != -ENODEV) + return ret; + /* * When running as an EFI application we are not in control of * interrupts and should leave them alone. diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 35b29f69d8..0b36ace091 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> @@ -82,12 +83,7 @@ static inline void fill_irq_info(struct irq_info *slot, int bus, int device, slot->irq[pin - 1].bitmap = irq_router.irq_mask; } -__weak void cpu_irq_init(void) -{ - return; -} - -static int create_pirq_routing_table(void) +static int create_pirq_routing_table(struct udevice *dev) { const void *blob = gd->fdt_blob; struct fdt_pci_addr addr; @@ -97,16 +93,13 @@ static int create_pirq_routing_table(void) struct irq_routing_table *rt; struct irq_info *slot, *slot_base; int irq_entries = 0; + int parent; int i; int ret; - node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); - if (node < 0) { - debug("%s: Cannot find irq router node\n", __func__); - return -EINVAL; - } - - ret = fdtdec_get_pci_addr(blob, node, FDT_PCI_SPACE_CONFIG, + node = dev->of_offset; + parent = dev->parent->of_offset; + ret = fdtdec_get_pci_addr(blob, parent, FDT_PCI_SPACE_CONFIG, "reg", &addr); if (ret) return ret; @@ -225,13 +218,11 @@ static int create_pirq_routing_table(void) return 0; } -int pirq_init(void) +int irq_router_common_init(struct udevice *dev) { int ret; - cpu_irq_init(); - - ret = create_pirq_routing_table(); + ret = create_pirq_routing_table(dev); if (ret) { debug("Failed to create pirq routing table\n"); return ret; @@ -243,6 +234,11 @@ int pirq_init(void) return 0; } +int irq_router_probe(struct udevice *dev) +{ + return irq_router_common_init(dev); +} + u32 write_pirq_routing_table(u32 addr) { if (!pirq_routing_table) @@ -250,3 +246,20 @@ u32 write_pirq_routing_table(u32 addr) return copy_pirq_routing_table(addr, pirq_routing_table); } + +static const struct udevice_id irq_router_ids[] = { + { .compatible = "intel,irq-router" }, + { } +}; + +U_BOOT_DRIVER(irq_router_drv) = { + .name = "intel_irq", + .id = UCLASS_IRQ, + .of_match = irq_router_ids, + .probe = irq_router_probe, +}; + +UCLASS_DRIVER(irq) = { + .id = UCLASS_IRQ, + .name = "irq", +}; diff --git a/arch/x86/cpu/ivybridge/Kconfig b/arch/x86/cpu/ivybridge/Kconfig index 56abd8fae3..1768a26a35 100644 --- a/arch/x86/cpu/ivybridge/Kconfig +++ b/arch/x86/cpu/ivybridge/Kconfig @@ -48,7 +48,6 @@ config DCACHE_RAM_MRC_VAR_SIZE config CPU_SPECIFIC_OPTIONS def_bool y select SMM_TSEG - select HAVE_INTEL_ME select X86_RAMTEST config SMM_TSEG_SIZE diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index 0c7efaec7c..45ef14187e 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -7,7 +7,6 @@ obj-y += bd82x6x.o obj-y += car.o obj-y += cpu.o -obj-y += early_init.o obj-y += early_me.o obj-y += gma.o obj-y += lpc.o @@ -15,10 +14,6 @@ obj-y += me_status.o obj-y += model_206ax.o obj-y += microcode_intel.o obj-y += northbridge.o -obj-y += pch.o -obj-y += pci.o obj-y += report_platform.o obj-y += sata.o obj-y += sdram.o -obj-y += usb_ehci.o -obj-y += usb_xhci.o diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index 434dfd649f..2b172d49ba 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -3,12 +3,15 @@ * * SPDX-License-Identifier: GPL-2.0+ */ - #include <common.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> +#include <pch.h> +#include <syscon.h> +#include <asm/cpu.h> +#include <asm/io.h> #include <asm/lapic.h> #include <asm/pci.h> #include <asm/arch/bd82x6x.h> @@ -16,106 +19,198 @@ #include <asm/arch/pch.h> #include <asm/arch/sandybridge.h> -void bd82x6x_pci_init(pci_dev_t dev) +#define BIOS_CTRL 0xdc + +static int pch_revision_id = -1; +static int pch_type = -1; + +/** + * pch_silicon_revision() - Read silicon revision ID from the PCH + * + * @dev: PCH device + * @return silicon revision ID + */ +static int pch_silicon_revision(struct udevice *dev) { - u16 reg16; - u8 reg8; - - debug("bd82x6x PCI init.\n"); - /* Enable Bus Master */ - reg16 = x86_pci_read_config16(dev, PCI_COMMAND); - reg16 |= PCI_COMMAND_MASTER; - x86_pci_write_config16(dev, PCI_COMMAND, reg16); - - /* This device has no interrupt */ - x86_pci_write_config8(dev, INTR, 0xff); - - /* disable parity error response and SERR */ - reg16 = x86_pci_read_config16(dev, BCTRL); - reg16 &= ~(1 << 0); - reg16 &= ~(1 << 1); - x86_pci_write_config16(dev, BCTRL, reg16); - - /* Master Latency Count must be set to 0x04! */ - reg8 = x86_pci_read_config8(dev, SMLT); - reg8 &= 0x07; - reg8 |= (0x04 << 3); - x86_pci_write_config8(dev, SMLT, reg8); - - /* Will this improve throughput of bus masters? */ - x86_pci_write_config8(dev, PCI_MIN_GNT, 0x06); - - /* Clear errors in status registers */ - reg16 = x86_pci_read_config16(dev, PSTS); - /* reg16 |= 0xf900; */ - x86_pci_write_config16(dev, PSTS, reg16); - - reg16 = x86_pci_read_config16(dev, SECSTS); - /* reg16 |= 0xf900; */ - x86_pci_write_config16(dev, SECSTS, reg16); + u8 val; + + if (pch_revision_id < 0) { + dm_pci_read_config8(dev, PCI_REVISION_ID, &val); + pch_revision_id = val; + } + + return pch_revision_id; } -static int bd82x6x_probe(struct udevice *dev) +int pch_silicon_type(struct udevice *dev) { - const void *blob = gd->fdt_blob; - struct pci_controller *hose; - struct x86_cpu_priv *cpu; - int sata_node, gma_node; - int ret; + u8 val; - hose = pci_bus_to_hose(0); - lpc_enable(PCH_LPC_DEV); - lpc_init(hose, PCH_LPC_DEV); - sata_node = fdtdec_next_compatible(blob, 0, - COMPAT_INTEL_PANTHERPOINT_AHCI); - if (sata_node < 0) { - debug("%s: Cannot find SATA node\n", __func__); - return -EINVAL; + if (pch_type < 0) { + dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val); + pch_type = val; } - bd82x6x_sata_init(PCH_SATA_DEV, blob, sata_node); - bd82x6x_usb_ehci_init(PCH_EHCI1_DEV); - bd82x6x_usb_ehci_init(PCH_EHCI2_DEV); - - cpu = calloc(1, sizeof(*cpu)); - if (!cpu) - return -ENOMEM; - model_206ax_init(cpu); - - gma_node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_GMA); - if (gma_node < 0) { - debug("%s: Cannot find GMA node\n", __func__); - return -EINVAL; + + return pch_type; +} + +/** + * pch_silicon_supported() - Check if a certain revision is supported + * + * @dev: PCH device + * @type: PCH type + * @rev: Minimum required resion + * @return 0 if not supported, 1 if supported + */ +static int pch_silicon_supported(struct udevice *dev, int type, int rev) +{ + int cur_type = pch_silicon_type(dev); + int cur_rev = pch_silicon_revision(dev); + + switch (type) { + case PCH_TYPE_CPT: + /* CougarPoint minimum revision */ + if (cur_type == PCH_TYPE_CPT && cur_rev >= rev) + return 1; + /* PantherPoint any revision */ + if (cur_type == PCH_TYPE_PPT) + return 1; + break; + + case PCH_TYPE_PPT: + /* PantherPoint minimum revision */ + if (cur_type == PCH_TYPE_PPT && cur_rev >= rev) + return 1; + break; + } + + return 0; +} + +#define IOBP_RETRY 1000 +static inline int iobp_poll(void) +{ + unsigned try = IOBP_RETRY; + u32 data; + + while (try--) { + data = readl(RCB_REG(IOBPS)); + if ((data & 1) == 0) + return 1; + udelay(10); } - ret = dm_pci_bus_find_bdf(PCH_VIDEO_DEV, &dev); + + printf("IOBP timeout\n"); + return 0; +} + +void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue, + u32 orvalue) +{ + u32 data; + + /* Set the address */ + writel(address, RCB_REG(IOBPIRI)); + + /* READ OPCODE */ + if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) + writel(IOBPS_RW_BX, RCB_REG(IOBPS)); + else + writel(IOBPS_READ_AX, RCB_REG(IOBPS)); + if (!iobp_poll()) + return; + + /* Read IOBP data */ + data = readl(RCB_REG(IOBPD)); + if (!iobp_poll()) + return; + + /* Check for successful transaction */ + if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) { + printf("IOBP read 0x%08x failed\n", address); + return; + } + + /* Update the data */ + data &= andvalue; + data |= orvalue; + + /* WRITE OPCODE */ + if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) + writel(IOBPS_RW_BX, RCB_REG(IOBPS)); + else + writel(IOBPS_WRITE_AX, RCB_REG(IOBPS)); + if (!iobp_poll()) + return; + + /* Write IOBP data */ + writel(data, RCB_REG(IOBPD)); + if (!iobp_poll()) + return; +} + +static int bd82x6x_probe(struct udevice *dev) +{ + struct udevice *gma_dev; + int ret; + + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + + /* Cause the SATA device to do its init */ + uclass_first_device(UCLASS_DISK, &dev); + + ret = syscon_get_by_driver_data(X86_SYSCON_GMA, &gma_dev); if (ret) return ret; - ret = gma_func0_init(dev, blob, gma_node); + ret = gma_func0_init(gma_dev); if (ret) return ret; return 0; } -int bd82x6x_init(void) +static int bd82x6x_pch_get_sbase(struct udevice *dev, ulong *sbasep) { - const void *blob = gd->fdt_blob; - int sata_node; - - sata_node = fdtdec_next_compatible(blob, 0, - COMPAT_INTEL_PANTHERPOINT_AHCI); - if (sata_node < 0) { - debug("%s: Cannot find SATA node\n", __func__); - return -EINVAL; - } + u32 rcba; + + dm_pci_read_config32(dev, PCH_RCBA, &rcba); + /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */ + rcba = rcba & 0xffffc000; + *sbasep = rcba + 0x3800; + + return 0; +} + +static enum pch_version bd82x6x_pch_get_version(struct udevice *dev) +{ + return PCHV_9; +} - bd82x6x_pci_init(PCH_DEV); - bd82x6x_sata_enable(PCH_SATA_DEV, blob, sata_node); - northbridge_enable(PCH_DEV); - northbridge_init(PCH_DEV); +static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect) +{ + uint8_t bios_cntl; + + /* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */ + dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl); + if (protect) { + bios_cntl &= ~BIOS_CTRL_BIOSWE; + bios_cntl |= BIT(5); + } else { + bios_cntl |= BIOS_CTRL_BIOSWE; + bios_cntl &= ~BIT(5); + } + dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl); return 0; } +static const struct pch_ops bd82x6x_pch_ops = { + .get_sbase = bd82x6x_pch_get_sbase, + .get_version = bd82x6x_pch_get_version, + .set_spi_protect = bd82x6x_set_spi_protect, +}; + static const struct udevice_id bd82x6x_ids[] = { { .compatible = "intel,bd82x6x" }, { } @@ -126,4 +221,5 @@ U_BOOT_DRIVER(bd82x6x_drv) = { .id = UCLASS_PCH, .of_match = bd82x6x_ids, .probe = bd82x6x_probe, + .ops = &bd82x6x_pch_ops, }; diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c index 343bfb4e98..948833c028 100644 --- a/arch/x86/cpu/ivybridge/cpu.c +++ b/arch/x86/cpu/ivybridge/cpu.c @@ -15,6 +15,7 @@ #include <dm.h> #include <errno.h> #include <fdtdec.h> +#include <pch.h> #include <asm/cpu.h> #include <asm/io.h> #include <asm/lapic.h> @@ -30,26 +31,6 @@ DECLARE_GLOBAL_DATA_PTR; -static void enable_port80_on_lpc(struct pci_controller *hose, pci_dev_t dev) -{ - /* Enable port 80 POST on LPC */ - pci_hose_write_config_dword(hose, dev, PCH_RCBA_BASE, DEFAULT_RCBA | 1); - clrbits_le32(RCB_REG(GCS), 4); -} - -/* - * Enable Prefetching and Caching. - */ -static void enable_spi_prefetch(struct pci_controller *hose, pci_dev_t dev) -{ - u8 reg8; - - pci_hose_read_config_byte(hose, dev, 0xdc, ®8); - reg8 &= ~(3 << 2); - reg8 |= (2 << 2); /* Prefetching and Caching Enabled */ - pci_hose_write_config_byte(hose, dev, 0xdc, reg8); -} - static int set_flex_ratio_to_tdp_nominal(void) { msr_t flex_ratio, msr; @@ -99,22 +80,6 @@ static int set_flex_ratio_to_tdp_nominal(void) return -EINVAL; } -static void set_spi_speed(void) -{ - u32 fdod; - - /* Observe SPI Descriptor Component Section 0 */ - writel(0x1000, RCB_REG(SPI_DESC_COMP0)); - - /* Extract the1 Write/Erase SPI Frequency from descriptor */ - fdod = readl(RCB_REG(SPI_FREQ_WR_ERA)); - fdod >>= 24; - fdod &= 7; - - /* Set Software Sequence frequency to match */ - clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod); -} - int arch_cpu_init(void) { post_code(POST_CPU_INIT); @@ -124,10 +89,8 @@ int arch_cpu_init(void) int arch_cpu_init_dm(void) { - const void *blob = gd->fdt_blob; struct pci_controller *hose; - struct udevice *bus; - int node; + struct udevice *bus, *dev; int ret; post_code(0x70); @@ -141,19 +104,9 @@ int arch_cpu_init_dm(void) /* TODO(sjg@chromium.org): Get rid of gd->hose */ gd->hose = hose; - node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_PCH); - if (node < 0) - return -ENOENT; - ret = lpc_early_init(gd->fdt_blob, node, PCH_LPC_DEV); - if (ret) - return ret; - - enable_spi_prefetch(hose, PCH_LPC_DEV); - - /* This is already done in start.S, but let's do it in C */ - enable_port80_on_lpc(hose, PCH_LPC_DEV); - - set_spi_speed(); + ret = uclass_first_device(UCLASS_LPC, &dev); + if (!dev) + return -ENODEV; /* * We should do as little as possible before the serial console is @@ -167,41 +120,6 @@ int arch_cpu_init_dm(void) return 0; } -static int enable_smbus(void) -{ - pci_dev_t dev; - uint16_t value; - - /* Set the SMBus device statically. */ - dev = PCI_BDF(0x0, 0x1f, 0x3); - - /* Check to make sure we've got the right device. */ - value = x86_pci_read_config16(dev, 0x0); - if (value != 0x8086) { - printf("SMBus controller not found\n"); - return -ENOSYS; - } - - /* Set SMBus I/O base. */ - x86_pci_write_config32(dev, SMB_BASE, - SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO); - - /* Set SMBus enable. */ - x86_pci_write_config8(dev, HOSTC, HST_EN); - - /* Set SMBus I/O space enable. */ - x86_pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO); - - /* Disable interrupt generation. */ - outb(0, SMBUS_IO_BASE + SMBHSTCTL); - - /* Clear any lingering errors, so transactions can run. */ - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); - debug("SMBus controller enabled\n"); - - return 0; -} - #define PCH_EHCI0_TEMP_BAR0 0xe8000000 #define PCH_EHCI1_TEMP_BAR0 0xe8000400 #define PCH_XHCI_TEMP_BAR0 0xe8001000 @@ -215,33 +133,33 @@ static int enable_smbus(void) * * This is used to speed up the resume path. */ -static void enable_usb_bar(void) +static void enable_usb_bar(struct udevice *bus) { pci_dev_t usb0 = PCH_EHCI1_DEV; pci_dev_t usb1 = PCH_EHCI2_DEV; pci_dev_t usb3 = PCH_XHCI_DEV; - u32 cmd; + ulong cmd; /* USB Controller 1 */ - x86_pci_write_config32(usb0, PCI_BASE_ADDRESS_0, - PCH_EHCI0_TEMP_BAR0); - cmd = x86_pci_read_config32(usb0, PCI_COMMAND); + pci_bus_write_config(bus, usb0, PCI_BASE_ADDRESS_0, + PCH_EHCI0_TEMP_BAR0, PCI_SIZE_32); + pci_bus_read_config(bus, usb0, PCI_COMMAND, &cmd, PCI_SIZE_32); cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; - x86_pci_write_config32(usb0, PCI_COMMAND, cmd); + pci_bus_write_config(bus, usb0, PCI_COMMAND, cmd, PCI_SIZE_32); - /* USB Controller 1 */ - x86_pci_write_config32(usb1, PCI_BASE_ADDRESS_0, - PCH_EHCI1_TEMP_BAR0); - cmd = x86_pci_read_config32(usb1, PCI_COMMAND); + /* USB Controller 2 */ + pci_bus_write_config(bus, usb1, PCI_BASE_ADDRESS_0, + PCH_EHCI1_TEMP_BAR0, PCI_SIZE_32); + pci_bus_read_config(bus, usb1, PCI_COMMAND, &cmd, PCI_SIZE_32); cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; - x86_pci_write_config32(usb1, PCI_COMMAND, cmd); + pci_bus_write_config(bus, usb1, PCI_COMMAND, cmd, PCI_SIZE_32); - /* USB3 Controller */ - x86_pci_write_config32(usb3, PCI_BASE_ADDRESS_0, - PCH_XHCI_TEMP_BAR0); - cmd = x86_pci_read_config32(usb3, PCI_COMMAND); + /* USB3 Controller 1 */ + pci_bus_write_config(bus, usb3, PCI_BASE_ADDRESS_0, + PCH_XHCI_TEMP_BAR0, PCI_SIZE_32); + pci_bus_read_config(bus, usb3, PCI_COMMAND, &cmd, PCI_SIZE_32); cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; - x86_pci_write_config32(usb3, PCI_COMMAND, cmd); + pci_bus_write_config(bus, usb3, PCI_COMMAND, cmd, PCI_SIZE_32); } static int report_bist_failure(void) @@ -259,6 +177,7 @@ int print_cpuinfo(void) { enum pei_boot_mode_t boot_mode = PEI_BOOT_NONE; char processor_name[CPU_MAX_NAME_LEN]; + struct udevice *dev, *lpc; const char *name; uint32_t pm1_cnt; uint16_t pm1_sts; @@ -289,7 +208,16 @@ int print_cpuinfo(void) } /* Early chipset init required before RAM init can work */ - sandybridge_early_init(SANDYBRIDGE_MOBILE); + uclass_first_device(UCLASS_NORTHBRIDGE, &dev); + + ret = uclass_first_device(UCLASS_LPC, &lpc); + if (ret) + return ret; + if (!dev) + return -ENODEV; + + /* Cause the SATA device to do its early init */ + uclass_first_device(UCLASS_DISK, &dev); /* Check PM1_STS[15] to see if we are waking from Sx */ pm1_sts = inw(DEFAULT_PMBASE + PM1_STS); @@ -308,20 +236,18 @@ int print_cpuinfo(void) post_code(POST_EARLY_INIT); /* Enable SPD ROMs and DDR-III DRAM */ - ret = enable_smbus(); + ret = uclass_first_device(UCLASS_I2C, &dev); if (ret) return ret; + if (!dev) + return -ENODEV; /* Prepare USB controller early in S3 resume */ if (boot_mode == PEI_BOOT_RESUME) - enable_usb_bar(); + enable_usb_bar(pci_get_controller(lpc->parent)); gd->arch.pei_boot_mode = boot_mode; - /* TODO: Move this to the board or driver */ - x86_pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE | 1); - x86_pci_write_config32(PCH_LPC_DEV, GPIO_CNTL, 0x10); - /* Print processor name */ name = cpu_get_name(processor_name); printf("CPU: %s\n", name); diff --git a/arch/x86/cpu/ivybridge/early_init.c b/arch/x86/cpu/ivybridge/early_init.c deleted file mode 100644 index 9ca008e345..0000000000 --- a/arch/x86/cpu/ivybridge/early_init.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * From Coreboot - * - * Copyright (C) 2007-2010 coresystems GmbH - * Copyright (C) 2011 Google Inc - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/pci.h> -#include <asm/arch/pch.h> -#include <asm/arch/sandybridge.h> - -static void sandybridge_setup_bars(pci_dev_t pch_dev, pci_dev_t lpc_dev) -{ - /* Setting up Southbridge. In the northbridge code. */ - debug("Setting up static southbridge registers\n"); - x86_pci_write_config32(lpc_dev, PCH_RCBA_BASE, DEFAULT_RCBA | 1); - - x86_pci_write_config32(lpc_dev, PMBASE, DEFAULT_PMBASE | 1); - x86_pci_write_config8(lpc_dev, ACPI_CNTL, 0x80); /* Enable ACPI BAR */ - - debug("Disabling watchdog reboot\n"); - setbits_le32(RCB_REG(GCS), 1 >> 5); /* No reset */ - outw(1 << 11, DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ - - /* Set up all hardcoded northbridge BARs */ - debug("Setting up static registers\n"); - x86_pci_write_config32(pch_dev, EPBAR, DEFAULT_EPBAR | 1); - x86_pci_write_config32(pch_dev, EPBAR + 4, (0LL + DEFAULT_EPBAR) >> 32); - x86_pci_write_config32(pch_dev, MCHBAR, DEFAULT_MCHBAR | 1); - x86_pci_write_config32(pch_dev, MCHBAR + 4, - (0LL + DEFAULT_MCHBAR) >> 32); - /* 64MB - busses 0-63 */ - x86_pci_write_config32(pch_dev, PCIEXBAR, DEFAULT_PCIEXBAR | 5); - x86_pci_write_config32(pch_dev, PCIEXBAR + 4, - (0LL + DEFAULT_PCIEXBAR) >> 32); - x86_pci_write_config32(pch_dev, DMIBAR, DEFAULT_DMIBAR | 1); - x86_pci_write_config32(pch_dev, DMIBAR + 4, - (0LL + DEFAULT_DMIBAR) >> 32); - - /* Set C0000-FFFFF to access RAM on both reads and writes */ - x86_pci_write_config8(pch_dev, PAM0, 0x30); - x86_pci_write_config8(pch_dev, PAM1, 0x33); - x86_pci_write_config8(pch_dev, PAM2, 0x33); - x86_pci_write_config8(pch_dev, PAM3, 0x33); - x86_pci_write_config8(pch_dev, PAM4, 0x33); - x86_pci_write_config8(pch_dev, PAM5, 0x33); - x86_pci_write_config8(pch_dev, PAM6, 0x33); -} - -static void sandybridge_setup_graphics(pci_dev_t pch_dev, pci_dev_t video_dev) -{ - u32 reg32; - u16 reg16; - u8 reg8; - - reg16 = x86_pci_read_config16(video_dev, PCI_DEVICE_ID); - switch (reg16) { - case 0x0102: /* GT1 Desktop */ - case 0x0106: /* GT1 Mobile */ - case 0x010a: /* GT1 Server */ - case 0x0112: /* GT2 Desktop */ - case 0x0116: /* GT2 Mobile */ - case 0x0122: /* GT2 Desktop >=1.3GHz */ - case 0x0126: /* GT2 Mobile >=1.3GHz */ - case 0x0156: /* IvyBridge */ - case 0x0166: /* IvyBridge */ - break; - default: - debug("Graphics not supported by this CPU/chipset\n"); - return; - } - - debug("Initialising Graphics\n"); - - /* Setup IGD memory by setting GGC[7:3] = 1 for 32MB */ - reg16 = x86_pci_read_config16(pch_dev, GGC); - reg16 &= ~0x00f8; - reg16 |= 1 << 3; - /* Program GTT memory by setting GGC[9:8] = 2MB */ - reg16 &= ~0x0300; - reg16 |= 2 << 8; - /* Enable VGA decode */ - reg16 &= ~0x0002; - x86_pci_write_config16(pch_dev, GGC, reg16); - - /* Enable 256MB aperture */ - reg8 = x86_pci_read_config8(video_dev, MSAC); - reg8 &= ~0x06; - reg8 |= 0x02; - x86_pci_write_config8(video_dev, MSAC, reg8); - - /* Erratum workarounds */ - reg32 = readl(MCHBAR_REG(0x5f00)); - reg32 |= (1 << 9) | (1 << 10); - writel(reg32, MCHBAR_REG(0x5f00)); - - /* Enable SA Clock Gating */ - reg32 = readl(MCHBAR_REG(0x5f00)); - writel(reg32 | 1, MCHBAR_REG(0x5f00)); - - /* GPU RC6 workaround for sighting 366252 */ - reg32 = readl(MCHBAR_REG(0x5d14)); - reg32 |= (1 << 31); - writel(reg32, MCHBAR_REG(0x5d14)); - - /* VLW */ - reg32 = readl(MCHBAR_REG(0x6120)); - reg32 &= ~(1 << 0); - writel(reg32, MCHBAR_REG(0x6120)); - - reg32 = readl(MCHBAR_REG(0x5418)); - reg32 |= (1 << 4) | (1 << 5); - writel(reg32, MCHBAR_REG(0x5418)); -} - -void sandybridge_early_init(int chipset_type) -{ - pci_dev_t pch_dev = PCH_DEV; - pci_dev_t video_dev = PCH_VIDEO_DEV; - pci_dev_t lpc_dev = PCH_LPC_DEV; - u32 capid0_a; - u8 reg8; - - /* Device ID Override Enable should be done very early */ - capid0_a = x86_pci_read_config32(pch_dev, 0xe4); - if (capid0_a & (1 << 10)) { - reg8 = x86_pci_read_config8(pch_dev, 0xf3); - reg8 &= ~7; /* Clear 2:0 */ - - if (chipset_type == SANDYBRIDGE_MOBILE) - reg8 |= 1; /* Set bit 0 */ - - x86_pci_write_config8(pch_dev, 0xf3, reg8); - } - - /* Setup all BARs required for early PCIe and raminit */ - sandybridge_setup_bars(pch_dev, lpc_dev); - - /* Device Enable */ - x86_pci_write_config32(pch_dev, DEVEN, DEVEN_HOST | DEVEN_IGD); - - sandybridge_setup_graphics(pch_dev, video_dev); -} diff --git a/arch/x86/cpu/ivybridge/early_me.c b/arch/x86/cpu/ivybridge/early_me.c index 711470f364..b1df77d571 100644 --- a/arch/x86/cpu/ivybridge/early_me.c +++ b/arch/x86/cpu/ivybridge/early_me.c @@ -7,8 +7,10 @@ */ #include <common.h> +#include <dm.h> #include <errno.h> #include <asm/pci.h> +#include <asm/cpu.h> #include <asm/processor.h> #include <asm/arch/me.h> #include <asm/arch/pch.h> @@ -25,33 +27,36 @@ static const char *const me_ack_values[] = { [ME_HFS_ACK_CONTINUE] = "Continue to boot" }; -static inline void pci_read_dword_ptr(void *ptr, int offset) +static inline void pci_read_dword_ptr(struct udevice *me_dev, void *ptr, + int offset) { u32 dword; - dword = x86_pci_read_config32(PCH_ME_DEV, offset); + dm_pci_read_config32(me_dev, offset, &dword); memcpy(ptr, &dword, sizeof(dword)); } -static inline void pci_write_dword_ptr(void *ptr, int offset) +static inline void pci_write_dword_ptr(struct udevice *me_dev, void *ptr, + int offset) { u32 dword = 0; + memcpy(&dword, ptr, sizeof(dword)); - x86_pci_write_config32(PCH_ME_DEV, offset, dword); + dm_pci_write_config32(me_dev, offset, dword); } -void intel_early_me_status(void) +void intel_early_me_status(struct udevice *me_dev) { struct me_hfs hfs; struct me_gmes gmes; - pci_read_dword_ptr(&hfs, PCI_ME_HFS); - pci_read_dword_ptr(&gmes, PCI_ME_GMES); + pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); + pci_read_dword_ptr(me_dev, &gmes, PCI_ME_GMES); intel_me_status(&hfs, &gmes); } -int intel_early_me_init(void) +int intel_early_me_init(struct udevice *me_dev) { int count; struct me_uma uma; @@ -61,7 +66,7 @@ int intel_early_me_init(void) /* Wait for ME UMA SIZE VALID bit to be set */ for (count = ME_RETRY; count > 0; --count) { - pci_read_dword_ptr(&uma, PCI_ME_UMA); + pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA); if (uma.valid) break; udelay(ME_DELAY); @@ -72,7 +77,7 @@ int intel_early_me_init(void) } /* Check for valid firmware */ - pci_read_dword_ptr(&hfs, PCI_ME_HFS); + pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); if (hfs.fpt_bad) { printf("WARNING: ME has bad firmware\n"); return -EBADF; @@ -83,11 +88,11 @@ int intel_early_me_init(void) return 0; } -int intel_early_me_uma_size(void) +int intel_early_me_uma_size(struct udevice *me_dev) { struct me_uma uma; - pci_read_dword_ptr(&uma, PCI_ME_UMA); + pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA); if (uma.valid) { debug("ME: Requested %uMB UMA\n", uma.size); return uma.size; @@ -97,11 +102,11 @@ int intel_early_me_uma_size(void) return -EINVAL; } -static inline void set_global_reset(int enable) +static inline void set_global_reset(struct udevice *dev, int enable) { u32 etr3; - etr3 = x86_pci_read_config32(PCH_LPC_DEV, ETR3); + dm_pci_read_config32(dev, ETR3, &etr3); /* Clear CF9 Without Resume Well Reset Enable */ etr3 &= ~ETR3_CWORWRE; @@ -112,10 +117,11 @@ static inline void set_global_reset(int enable) else etr3 &= ~ETR3_CF9GR; - x86_pci_write_config32(PCH_LPC_DEV, ETR3, etr3); + dm_pci_write_config32(dev, ETR3, etr3); } -int intel_early_me_init_done(u8 status) +int intel_early_me_init_done(struct udevice *dev, struct udevice *me_dev, + uint status) { int count; u32 mebase_l, mebase_h; @@ -126,8 +132,8 @@ int intel_early_me_init_done(u8 status) }; /* MEBASE from MESEG_BASE[35:20] */ - mebase_l = x86_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L); - mebase_h = x86_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H); + dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L, &mebase_l); + dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H, &mebase_h); mebase_h &= 0xf; did.uma_base = (mebase_l >> 20) | (mebase_h << 12); @@ -135,25 +141,25 @@ int intel_early_me_init_done(u8 status) debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n", status, did.uma_base); - pci_write_dword_ptr(&did, PCI_ME_H_GS); + pci_write_dword_ptr(me_dev, &did, PCI_ME_H_GS); /* Must wait for ME acknowledgement */ for (count = ME_RETRY; count > 0; --count) { - pci_read_dword_ptr(&hfs, PCI_ME_HFS); + pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); if (hfs.bios_msg_ack) break; udelay(ME_DELAY); } if (!count) { printf("ERROR: ME failed to respond\n"); - return -1; + return -ETIMEDOUT; } /* Return the requested BIOS action */ debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]); /* Check status after acknowledgement */ - intel_early_me_status(); + intel_early_me_status(me_dev); switch (hfs.ack_data) { case ME_HFS_ACK_CONTINUE: @@ -161,17 +167,17 @@ int intel_early_me_init_done(u8 status) return 0; case ME_HFS_ACK_RESET: /* Non-power cycle reset */ - set_global_reset(0); + set_global_reset(dev, 0); reset_cpu(0); break; case ME_HFS_ACK_PWR_CYCLE: /* Power cycle reset */ - set_global_reset(0); + set_global_reset(dev, 0); x86_full_reset(); break; case ME_HFS_ACK_GBL_RESET: /* Global reset */ - set_global_reset(1); + set_global_reset(dev, 1); x86_full_reset(); break; case ME_HFS_ACK_S3: @@ -180,5 +186,17 @@ int intel_early_me_init_done(u8 status) break; } - return -1; + return -EINVAL; } + +static const struct udevice_id ivybridge_syscon_ids[] = { + { .compatible = "intel,me", .data = X86_SYSCON_ME }, + { .compatible = "intel,gma", .data = X86_SYSCON_GMA }, + { } +}; + +U_BOOT_DRIVER(syscon_intel_me) = { + .name = "intel_me_syscon", + .id = UCLASS_SYSCON, + .of_match = ivybridge_syscon_ids, +}; diff --git a/arch/x86/cpu/ivybridge/gma.c b/arch/x86/cpu/ivybridge/gma.c index 85a09c64b6..3b6291e905 100644 --- a/arch/x86/cpu/ivybridge/gma.c +++ b/arch/x86/cpu/ivybridge/gma.c @@ -8,6 +8,7 @@ #include <common.h> #include <bios_emul.h> +#include <dm.h> #include <errno.h> #include <fdtdec.h> #include <pci_rom.h> @@ -352,14 +353,13 @@ static int gtt_poll(void *bar, u32 reg, u32 mask, u32 value) return 0; } -static int gma_pm_init_pre_vbios(void *gtt_bar) +static int gma_pm_init_pre_vbios(void *gtt_bar, int rev) { u32 reg32; - debug("GT Power Management Init, silicon = %#x\n", - bridge_silicon_revision()); + debug("GT Power Management Init, silicon = %#x\n", rev); - if (bridge_silicon_revision() < IVB_STEP_C0) { + if (rev < IVB_STEP_C0) { /* 1: Enable force wake */ gtt_write(gtt_bar, 0xa18c, 0x00000001); gtt_poll(gtt_bar, 0x130090, (1 << 0), (1 << 0)); @@ -369,14 +369,14 @@ static int gma_pm_init_pre_vbios(void *gtt_bar) gtt_poll(gtt_bar, 0x130040, (1 << 0), (1 << 0)); } - if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { + if ((rev & BASE_REV_MASK) == BASE_REV_SNB) { /* 1d: Set GTT+0x42004 [15:14]=11 (SnB C1+) */ reg32 = gtt_read(gtt_bar, 0x42004); reg32 |= (1 << 14) | (1 << 15); gtt_write(gtt_bar, 0x42004, reg32); } - if (bridge_silicon_revision() >= IVB_STEP_A0) { + if (rev >= IVB_STEP_A0) { /* Display Reset Acknowledge Settings */ reg32 = gtt_read(gtt_bar, 0x45010); reg32 |= (1 << 1) | (1 << 0); @@ -385,7 +385,7 @@ static int gma_pm_init_pre_vbios(void *gtt_bar) /* 2: Get GT SKU from GTT+0x911c[13] */ reg32 = gtt_read(gtt_bar, 0x911c); - if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { + if ((rev & BASE_REV_MASK) == BASE_REV_SNB) { if (reg32 & (1 << 13)) { debug("SNB GT1 Power Meter Weights\n"); gtt_write_powermeter(gtt_bar, snb_pm_gt1); @@ -434,13 +434,13 @@ static int gma_pm_init_pre_vbios(void *gtt_bar) reg32 = gtt_read(gtt_bar, 0xa180); reg32 |= (1 << 26) | (1 << 31); /* (bit 20=1 for SNB step D1+ / IVB A0+) */ - if (bridge_silicon_revision() >= SNB_STEP_D1) + if (rev >= SNB_STEP_D1) reg32 |= (1 << 20); gtt_write(gtt_bar, 0xa180, reg32); /* 6a: for SnB step D2+ only */ - if (((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) && - (bridge_silicon_revision() >= SNB_STEP_D2)) { + if (((rev & BASE_REV_MASK) == BASE_REV_SNB) && + (rev >= SNB_STEP_D2)) { reg32 = gtt_read(gtt_bar, 0x9400); reg32 |= (1 << 7); gtt_write(gtt_bar, 0x9400, reg32); @@ -452,7 +452,7 @@ static int gma_pm_init_pre_vbios(void *gtt_bar) gtt_poll(gtt_bar, 0x941c, (1 << 1), (0 << 1)); } - if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_IVB) { + if ((rev & BASE_REV_MASK) == BASE_REV_IVB) { reg32 = gtt_read(gtt_bar, 0x907c); reg32 |= (1 << 16); gtt_write(gtt_bar, 0x907c, reg32); @@ -504,7 +504,7 @@ static int gma_pm_init_pre_vbios(void *gtt_bar) gtt_write(gtt_bar, 0xa070, 0x0000000a); /* RP Idle Hysteresis */ /* 11a: Enable Render Standby (RC6) */ - if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_IVB) { + if ((rev & BASE_REV_MASK) == BASE_REV_IVB) { /* * IvyBridge should also support DeepRenderStandby. * @@ -538,14 +538,16 @@ static int gma_pm_init_pre_vbios(void *gtt_bar) return 0; } -int gma_pm_init_post_vbios(void *gtt_bar, const void *blob, int node) +int gma_pm_init_post_vbios(struct udevice *dev, int rev, void *gtt_bar) { + const void *blob = gd->fdt_blob; + int node = dev->of_offset; u32 reg32, cycle_delay; debug("GT Power Management Init (post VBIOS)\n"); /* 15: Deassert Force Wake */ - if (bridge_silicon_revision() < IVB_STEP_C0) { + if (rev < IVB_STEP_C0) { gtt_write(gtt_bar, 0xa18c, gtt_read(gtt_bar, 0xa18c) & ~1); gtt_poll(gtt_bar, 0x130090, (1 << 0), (0 << 0)); } else { @@ -728,15 +730,93 @@ static int int15_handler(void) return res; } -int gma_func0_init(struct udevice *dev, const void *blob, int node) +void sandybridge_setup_graphics(struct udevice *dev, struct udevice *video_dev) +{ + u32 reg32; + u16 reg16; + u8 reg8; + + dm_pci_read_config16(video_dev, PCI_DEVICE_ID, ®16); + switch (reg16) { + case 0x0102: /* GT1 Desktop */ + case 0x0106: /* GT1 Mobile */ + case 0x010a: /* GT1 Server */ + case 0x0112: /* GT2 Desktop */ + case 0x0116: /* GT2 Mobile */ + case 0x0122: /* GT2 Desktop >=1.3GHz */ + case 0x0126: /* GT2 Mobile >=1.3GHz */ + case 0x0156: /* IvyBridge */ + case 0x0166: /* IvyBridge */ + break; + default: + debug("Graphics not supported by this CPU/chipset\n"); + return; + } + + debug("Initialising Graphics\n"); + + /* Setup IGD memory by setting GGC[7:3] = 1 for 32MB */ + dm_pci_read_config16(dev, GGC, ®16); + reg16 &= ~0x00f8; + reg16 |= 1 << 3; + /* Program GTT memory by setting GGC[9:8] = 2MB */ + reg16 &= ~0x0300; + reg16 |= 2 << 8; + /* Enable VGA decode */ + reg16 &= ~0x0002; + dm_pci_write_config16(dev, GGC, reg16); + + /* Enable 256MB aperture */ + dm_pci_read_config8(video_dev, MSAC, ®8); + reg8 &= ~0x06; + reg8 |= 0x02; + dm_pci_write_config8(video_dev, MSAC, reg8); + + /* Erratum workarounds */ + reg32 = readl(MCHBAR_REG(0x5f00)); + reg32 |= (1 << 9) | (1 << 10); + writel(reg32, MCHBAR_REG(0x5f00)); + + /* Enable SA Clock Gating */ + reg32 = readl(MCHBAR_REG(0x5f00)); + writel(reg32 | 1, MCHBAR_REG(0x5f00)); + + /* GPU RC6 workaround for sighting 366252 */ + reg32 = readl(MCHBAR_REG(0x5d14)); + reg32 |= (1 << 31); + writel(reg32, MCHBAR_REG(0x5d14)); + + /* VLW */ + reg32 = readl(MCHBAR_REG(0x6120)); + reg32 &= ~(1 << 0); + writel(reg32, MCHBAR_REG(0x6120)); + + reg32 = readl(MCHBAR_REG(0x5418)); + reg32 |= (1 << 4) | (1 << 5); + writel(reg32, MCHBAR_REG(0x5418)); +} + +int gma_func0_init(struct udevice *dev) { #ifdef CONFIG_VIDEO ulong start; #endif + struct udevice *nbridge; void *gtt_bar; ulong base; u32 reg32; int ret; + int rev; + + /* Enable PCH Display Port */ + writew(0x0010, RCB_REG(DISPBDF)); + setbits_le32(RCB_REG(FD2), PCH_ENABLE_DBDF); + + ret = uclass_first_device(UCLASS_NORTHBRIDGE, &nbridge); + if (!nbridge) + return -ENODEV; + rev = bridge_silicon_revision(nbridge); + sandybridge_setup_graphics(nbridge, dev); /* IGD needs to be Bus Master */ dm_pci_read_config32(dev, PCI_COMMAND, ®32); @@ -750,7 +830,7 @@ int gma_func0_init(struct udevice *dev, const void *blob, int node) gtt_bar = (void *)dm_pci_read_bar32(dev, 0); debug("GT bar %p\n", gtt_bar); - ret = gma_pm_init_pre_vbios(gtt_bar); + ret = gma_pm_init_pre_vbios(gtt_bar, rev); if (ret) return ret; @@ -761,7 +841,7 @@ int gma_func0_init(struct udevice *dev, const void *blob, int node) debug("BIOS ran in %lums\n", get_timer(start)); #endif /* Post VBIOS init */ - ret = gma_pm_init_post_vbios(gtt_bar, blob, node); + ret = gma_pm_init_post_vbios(dev, rev, gtt_bar); if (ret) return ret; diff --git a/arch/x86/cpu/ivybridge/lpc.c b/arch/x86/cpu/ivybridge/lpc.c index af5d4a8908..9ab5ed3ff9 100644 --- a/arch/x86/cpu/ivybridge/lpc.c +++ b/arch/x86/cpu/ivybridge/lpc.c @@ -24,13 +24,13 @@ #define ENABLE_ACPI_MODE_IN_COREBOOT 0 #define TEST_SMM_FLASH_LOCKDOWN 0 -static int pch_enable_apic(pci_dev_t dev) +static int pch_enable_apic(struct udevice *pch) { u32 reg32; int i; /* Enable ACPI I/O and power management. Set SCI IRQ to IRQ9 */ - x86_pci_write_config8(dev, ACPI_CNTL, 0x80); + dm_pci_write_config8(pch, ACPI_CNTL, 0x80); writel(0, IO_APIC_INDEX); writel(1 << 25, IO_APIC_DATA); @@ -66,36 +66,36 @@ static int pch_enable_apic(pci_dev_t dev) return 0; } -static void pch_enable_serial_irqs(pci_dev_t dev) +static void pch_enable_serial_irqs(struct udevice *pch) { u32 value; /* Set packet length and toggle silent mode bit for one frame. */ value = (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0); #ifdef CONFIG_SERIRQ_CONTINUOUS_MODE - x86_pci_write_config8(dev, SERIRQ_CNTL, value); + dm_pci_write_config8(pch, SERIRQ_CNTL, value); #else - x86_pci_write_config8(dev, SERIRQ_CNTL, value | (1 << 6)); + dm_pci_write_config8(pch, SERIRQ_CNTL, value | (1 << 6)); #endif } -static int pch_pirq_init(const void *blob, int node, pci_dev_t dev) +static int pch_pirq_init(struct udevice *pch) { uint8_t route[8], *ptr; - if (fdtdec_get_byte_array(blob, node, "intel,pirq-routing", route, - sizeof(route))) + if (fdtdec_get_byte_array(gd->fdt_blob, pch->of_offset, + "intel,pirq-routing", route, sizeof(route))) return -EINVAL; ptr = route; - x86_pci_write_config8(dev, PIRQA_ROUT, *ptr++); - x86_pci_write_config8(dev, PIRQB_ROUT, *ptr++); - x86_pci_write_config8(dev, PIRQC_ROUT, *ptr++); - x86_pci_write_config8(dev, PIRQD_ROUT, *ptr++); + dm_pci_write_config8(pch, PIRQA_ROUT, *ptr++); + dm_pci_write_config8(pch, PIRQB_ROUT, *ptr++); + dm_pci_write_config8(pch, PIRQC_ROUT, *ptr++); + dm_pci_write_config8(pch, PIRQD_ROUT, *ptr++); - x86_pci_write_config8(dev, PIRQE_ROUT, *ptr++); - x86_pci_write_config8(dev, PIRQF_ROUT, *ptr++); - x86_pci_write_config8(dev, PIRQG_ROUT, *ptr++); - x86_pci_write_config8(dev, PIRQH_ROUT, *ptr++); + dm_pci_write_config8(pch, PIRQE_ROUT, *ptr++); + dm_pci_write_config8(pch, PIRQF_ROUT, *ptr++); + dm_pci_write_config8(pch, PIRQG_ROUT, *ptr++); + dm_pci_write_config8(pch, PIRQH_ROUT, *ptr++); /* * TODO(sjg@chromium.org): U-Boot does not set up the interrupts @@ -104,26 +104,28 @@ static int pch_pirq_init(const void *blob, int node, pci_dev_t dev) return 0; } -static int pch_gpi_routing(const void *blob, int node, pci_dev_t dev) +static int pch_gpi_routing(struct udevice *pch) { u8 route[16]; u32 reg; int gpi; - if (fdtdec_get_byte_array(blob, node, "intel,gpi-routing", route, - sizeof(route))) + if (fdtdec_get_byte_array(gd->fdt_blob, pch->of_offset, + "intel,gpi-routing", route, sizeof(route))) return -EINVAL; for (reg = 0, gpi = 0; gpi < ARRAY_SIZE(route); gpi++) reg |= route[gpi] << (gpi * 2); - x86_pci_write_config32(dev, 0xb8, reg); + dm_pci_write_config32(pch, 0xb8, reg); return 0; } -static int pch_power_options(const void *blob, int node, pci_dev_t dev) +static int pch_power_options(struct udevice *pch) { + const void *blob = gd->fdt_blob; + int node = pch->of_offset; u8 reg8; u16 reg16, pmbase; u32 reg32; @@ -142,7 +144,7 @@ static int pch_power_options(const void *blob, int node, pci_dev_t dev) */ pwr_on = MAINBOARD_POWER_ON; - reg16 = x86_pci_read_config16(dev, GEN_PMCON_3); + dm_pci_read_config16(pch, GEN_PMCON_3, ®16); reg16 &= 0xfffe; switch (pwr_on) { case MAINBOARD_POWER_OFF: @@ -169,7 +171,7 @@ static int pch_power_options(const void *blob, int node, pci_dev_t dev) reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */ - x86_pci_write_config16(dev, GEN_PMCON_3, reg16); + dm_pci_write_config16(pch, GEN_PMCON_3, reg16); debug("Set power %s after power failure.\n", state); /* Set up NMI on errors. */ @@ -193,21 +195,22 @@ static int pch_power_options(const void *blob, int node, pci_dev_t dev) outb(reg8, 0x70); /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */ - reg16 = x86_pci_read_config16(dev, GEN_PMCON_1); + dm_pci_read_config16(pch, GEN_PMCON_1, ®16); reg16 &= ~(3 << 0); /* SMI# rate 1 minute */ reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */ #if DEBUG_PERIODIC_SMIS /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using periodic SMIs */ reg16 |= (3 << 0); /* Periodic SMI every 8s */ #endif - x86_pci_write_config16(dev, GEN_PMCON_1, reg16); + dm_pci_write_config16(pch, GEN_PMCON_1, reg16); /* Set the board's GPI routing. */ - ret = pch_gpi_routing(blob, node, dev); + ret = pch_gpi_routing(pch); if (ret) return ret; - pmbase = x86_pci_read_config16(dev, 0x40) & 0xfffe; + dm_pci_read_config16(pch, 0x40, &pmbase); + pmbase &= 0xfffe; writel(pmbase + GPE0_EN, fdtdec_get_int(blob, node, "intel,gpe0-enable", 0)); @@ -227,16 +230,16 @@ static int pch_power_options(const void *blob, int node, pci_dev_t dev) return 0; } -static void pch_rtc_init(pci_dev_t dev) +static void pch_rtc_init(struct udevice *pch) { int rtc_failed; u8 reg8; - reg8 = x86_pci_read_config8(dev, GEN_PMCON_3); + dm_pci_read_config8(pch, GEN_PMCON_3, ®8); rtc_failed = reg8 & RTC_BATTERY_DEAD; if (rtc_failed) { reg8 &= ~RTC_BATTERY_DEAD; - x86_pci_write_config8(dev, GEN_PMCON_3, reg8); + dm_pci_write_config8(pch, GEN_PMCON_3, reg8); } debug("rtc_failed = 0x%x\n", rtc_failed); @@ -246,10 +249,10 @@ static void pch_rtc_init(pci_dev_t dev) } /* CougarPoint PCH Power Management init */ -static void cpt_pm_init(pci_dev_t dev) +static void cpt_pm_init(struct udevice *pch) { debug("CougarPoint PM init\n"); - x86_pci_write_config8(dev, 0xa9, 0x47); + dm_pci_write_config8(pch, 0xa9, 0x47); setbits_le32(RCB_REG(0x2238), (1 << 6) | (1 << 0)); setbits_le32(RCB_REG(0x228c), 1 << 0); @@ -290,10 +293,10 @@ static void cpt_pm_init(pci_dev_t dev) } /* PantherPoint PCH Power Management init */ -static void ppt_pm_init(pci_dev_t dev) +static void ppt_pm_init(struct udevice *pch) { debug("PantherPoint PM init\n"); - x86_pci_write_config8(dev, 0xa9, 0x47); + dm_pci_write_config8(pch, 0xa9, 0x47); setbits_le32(RCB_REG(0x2238), 1 << 0); setbits_le32(RCB_REG(0x228c), 1 << 0); setbits_le16(RCB_REG(0x1100), (1 << 13) | (1 << 14)); @@ -340,21 +343,21 @@ static void enable_hpet(void) clrsetbits_le32(RCB_REG(HPTC), 3 << 0, 1 << 7); } -static void enable_clock_gating(pci_dev_t dev) +static void enable_clock_gating(struct udevice *pch) { u32 reg32; u16 reg16; setbits_le32(RCB_REG(0x2234), 0xf); - reg16 = x86_pci_read_config16(dev, GEN_PMCON_1); + dm_pci_read_config16(pch, GEN_PMCON_1, ®16); reg16 |= (1 << 2) | (1 << 11); - x86_pci_write_config16(dev, GEN_PMCON_1, reg16); + dm_pci_write_config16(pch, GEN_PMCON_1, reg16); - pch_iobp_update(0xEB007F07, ~0UL, (1 << 31)); - pch_iobp_update(0xEB004000, ~0UL, (1 << 7)); - pch_iobp_update(0xEC007F07, ~0UL, (1 << 31)); - pch_iobp_update(0xEC004000, ~0UL, (1 << 7)); + pch_iobp_update(pch, 0xEB007F07, ~0UL, (1 << 31)); + pch_iobp_update(pch, 0xEB004000, ~0UL, (1 << 7)); + pch_iobp_update(pch, 0xEC007F07, ~0UL, (1 << 31)); + pch_iobp_update(pch, 0xEC004000, ~0UL, (1 << 7)); reg32 = readl(RCB_REG(CG)); reg32 |= (1 << 31); @@ -376,77 +379,24 @@ static void enable_clock_gating(pci_dev_t dev) setbits_le32(RCB_REG(0x3564), 0x3); } -#if CONFIG_HAVE_SMI_HANDLER -static void pch_lock_smm(pci_dev_t dev) -{ -#if TEST_SMM_FLASH_LOCKDOWN - u8 reg8; -#endif - - if (acpi_slp_type != 3) { -#if ENABLE_ACPI_MODE_IN_COREBOOT - debug("Enabling ACPI via APMC:\n"); - outb(0xe1, 0xb2); /* Enable ACPI mode */ - debug("done.\n"); -#else - debug("Disabling ACPI via APMC:\n"); - outb(0x1e, 0xb2); /* Disable ACPI mode */ - debug("done.\n"); -#endif - } - - /* Don't allow evil boot loaders, kernels, or - * userspace applications to deceive us: - */ - smm_lock(); - -#if TEST_SMM_FLASH_LOCKDOWN - /* Now try this: */ - debug("Locking BIOS to RO... "); - reg8 = x86_pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ - debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", - (reg8 & 1) ? "rw" : "ro"); - reg8 &= ~(1 << 0); /* clear BIOSWE */ - x86_pci_write_config8(dev, 0xdc, reg8); - reg8 |= (1 << 1); /* set BLE */ - x86_pci_write_config8(dev, 0xdc, reg8); - debug("ok.\n"); - reg8 = x86_pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ - debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", - (reg8 & 1) ? "rw" : "ro"); - - debug("Writing:\n"); - writeb(0, 0xfff00000); - debug("Testing:\n"); - reg8 |= (1 << 0); /* set BIOSWE */ - x86_pci_write_config8(dev, 0xdc, reg8); - - reg8 = x86_pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ - debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", - (reg8 & 1) ? "rw" : "ro"); - debug("Done.\n"); -#endif -} -#endif - -static void pch_disable_smm_only_flashing(pci_dev_t dev) +static void pch_disable_smm_only_flashing(struct udevice *pch) { u8 reg8; debug("Enabling BIOS updates outside of SMM... "); - reg8 = x86_pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ + dm_pci_read_config8(pch, 0xdc, ®8); /* BIOS_CNTL */ reg8 &= ~(1 << 5); - x86_pci_write_config8(dev, 0xdc, reg8); + dm_pci_write_config8(pch, 0xdc, reg8); } -static void pch_fixups(pci_dev_t dev) +static void pch_fixups(struct udevice *pch) { u8 gen_pmcon_2; /* Indicate DRAM init done for MRC S3 to know it can resume */ - gen_pmcon_2 = x86_pci_read_config8(dev, GEN_PMCON_2); + dm_pci_read_config8(pch, GEN_PMCON_2, &gen_pmcon_2); gen_pmcon_2 |= (1 << 7); - x86_pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2); + dm_pci_write_config8(pch, GEN_PMCON_2, gen_pmcon_2); /* Enable DMI ASPM in the PCH */ clrbits_le32(RCB_REG(0x2304), 1 << 10); @@ -454,7 +404,49 @@ static void pch_fixups(pci_dev_t dev) setbits_le32(RCB_REG(0x21a8), 0x3); } -int lpc_early_init(const void *blob, int node, pci_dev_t dev) +/* + * Enable Prefetching and Caching. + */ +static void enable_spi_prefetch(struct udevice *pch) +{ + u8 reg8; + + dm_pci_read_config8(pch, 0xdc, ®8); + reg8 &= ~(3 << 2); + reg8 |= (2 << 2); /* Prefetching and Caching Enabled */ + dm_pci_write_config8(pch, 0xdc, reg8); +} + +static void enable_port80_on_lpc(struct udevice *pch) +{ + /* Enable port 80 POST on LPC */ + dm_pci_write_config32(pch, PCH_RCBA_BASE, DEFAULT_RCBA | 1); + clrbits_le32(RCB_REG(GCS), 4); +} + +static void set_spi_speed(void) +{ + u32 fdod; + + /* Observe SPI Descriptor Component Section 0 */ + writel(0x1000, RCB_REG(SPI_DESC_COMP0)); + + /* Extract the1 Write/Erase SPI Frequency from descriptor */ + fdod = readl(RCB_REG(SPI_FREQ_WR_ERA)); + fdod >>= 24; + fdod &= 7; + + /* Set Software Sequence frequency to match */ + clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod); +} + +/** + * lpc_early_init() - set up LPC serial ports and other early things + * + * @dev: LPC device + * @return 0 if OK, -ve on error + */ +static int lpc_early_init(struct udevice *dev) { struct reg_info { u32 base; @@ -463,17 +455,18 @@ int lpc_early_init(const void *blob, int node, pci_dev_t dev) int count; int i; - count = fdtdec_get_int_array_count(blob, node, "intel,gen-dec", - (u32 *)values, sizeof(values) / sizeof(u32)); + count = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset, + "intel,gen-dec", (u32 *)values, + sizeof(values) / sizeof(u32)); if (count < 0) return -EINVAL; /* Set COM1/COM2 decode range */ - x86_pci_write_config16(dev, LPC_IO_DEC, 0x0010); + dm_pci_write_config16(dev->parent, LPC_IO_DEC, 0x0010); /* Enable PS/2 Keyboard/Mouse, EC areas and COM1 */ - x86_pci_write_config16(dev, LPC_EN, KBC_LPC_EN | MC_LPC_EN | - GAMEL_LPC_EN | COMA_LPC_EN); + dm_pci_write_config16(dev->parent, LPC_EN, KBC_LPC_EN | MC_LPC_EN | + GAMEL_LPC_EN | COMA_LPC_EN); /* Write all registers but use 0 if we run out of data */ count = count * sizeof(u32) / sizeof(values[0]); @@ -482,81 +475,114 @@ int lpc_early_init(const void *blob, int node, pci_dev_t dev) if (i < count) reg = ptr->base | PCI_COMMAND_IO | (ptr->size << 16); - x86_pci_write_config32(dev, LPC_GENX_DEC(i), reg); + dm_pci_write_config32(dev->parent, LPC_GENX_DEC(i), reg); } + enable_spi_prefetch(dev->parent); + + /* This is already done in start.S, but let's do it in C */ + enable_port80_on_lpc(dev->parent); + + set_spi_speed(); + return 0; } -int lpc_init(struct pci_controller *hose, pci_dev_t dev) +static int lpc_init_extra(struct udevice *dev) { + struct udevice *pch = dev->parent; const void *blob = gd->fdt_blob; int node; debug("pch: lpc_init\n"); - pci_write_bar32(hose, dev, 0, 0); - pci_write_bar32(hose, dev, 1, 0xff800000); - pci_write_bar32(hose, dev, 2, 0xfec00000); - pci_write_bar32(hose, dev, 3, 0x800); - pci_write_bar32(hose, dev, 4, 0x900); + dm_pci_write_bar32(pch, 0, 0); + dm_pci_write_bar32(pch, 1, 0xff800000); + dm_pci_write_bar32(pch, 2, 0xfec00000); + dm_pci_write_bar32(pch, 3, 0x800); + dm_pci_write_bar32(pch, 4, 0x900); node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_PCH); if (node < 0) return -ENOENT; /* Set the value for PCI command register. */ - x86_pci_write_config16(dev, PCI_COMMAND, 0x000f); + dm_pci_write_config16(pch, PCI_COMMAND, 0x000f); /* IO APIC initialization. */ - pch_enable_apic(dev); + pch_enable_apic(pch); - pch_enable_serial_irqs(dev); + pch_enable_serial_irqs(pch); /* Setup the PIRQ. */ - pch_pirq_init(blob, node, dev); + pch_pirq_init(pch); /* Setup power options. */ - pch_power_options(blob, node, dev); + pch_power_options(pch); /* Initialize power management */ - switch (pch_silicon_type()) { + switch (pch_silicon_type(pch)) { case PCH_TYPE_CPT: /* CougarPoint */ - cpt_pm_init(dev); + cpt_pm_init(pch); break; case PCH_TYPE_PPT: /* PantherPoint */ - ppt_pm_init(dev); + ppt_pm_init(pch); break; default: - printf("Unknown Chipset: %#02x.%dx\n", PCI_DEV(dev), - PCI_FUNC(dev)); + printf("Unknown Chipset: %s\n", pch->name); return -ENOSYS; } /* Initialize the real time clock. */ - pch_rtc_init(dev); + pch_rtc_init(pch); /* Initialize the High Precision Event Timers, if present. */ enable_hpet(); /* Initialize Clock Gating */ - enable_clock_gating(dev); + enable_clock_gating(pch); - pch_disable_smm_only_flashing(dev); + pch_disable_smm_only_flashing(pch); -#if CONFIG_HAVE_SMI_HANDLER - pch_lock_smm(dev); -#endif + pch_fixups(pch); - pch_fixups(dev); + return 0; +} + +static int bd82x6x_lpc_early_init(struct udevice *dev) +{ + /* Setting up Southbridge. In the northbridge code. */ + debug("Setting up static southbridge registers\n"); + dm_pci_write_config32(dev->parent, PCH_RCBA_BASE, DEFAULT_RCBA | 1); + dm_pci_write_config32(dev->parent, PMBASE, DEFAULT_PMBASE | 1); + + /* Enable ACPI BAR */ + dm_pci_write_config8(dev->parent, ACPI_CNTL, 0x80); + + debug("Disabling watchdog reboot\n"); + setbits_le32(RCB_REG(GCS), 1 >> 5); /* No reset */ + outw(1 << 11, DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ + + dm_pci_write_config32(dev->parent, GPIO_BASE, DEFAULT_GPIOBASE | 1); + dm_pci_write_config32(dev->parent, GPIO_CNTL, 0x10); return 0; } -void lpc_enable(pci_dev_t dev) +static int bd82x6x_lpc_probe(struct udevice *dev) { - /* Enable PCH Display Port */ - writew(0x0010, RCB_REG(DISPBDF)); - setbits_le32(RCB_REG(FD2), PCH_ENABLE_DBDF); + int ret; + + if (!(gd->flags & GD_FLG_RELOC)) { + ret = lpc_early_init(dev); + if (ret) { + debug("%s: lpc_early_init() failed\n", __func__); + return ret; + } + + return bd82x6x_lpc_early_init(dev); + } + + return lpc_init_extra(dev); } static const struct udevice_id bd82x6x_lpc_ids[] = { @@ -568,4 +594,5 @@ U_BOOT_DRIVER(bd82x6x_lpc_drv) = { .name = "lpc", .id = UCLASS_LPC, .of_match = bd82x6x_lpc_ids, + .probe = bd82x6x_lpc_probe, }; diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index fd7db97cbd..9654600cf1 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -8,10 +8,13 @@ */ #include <common.h> +#include <cpu.h> +#include <dm.h> #include <fdtdec.h> #include <malloc.h> #include <asm/acpi.h> #include <asm/cpu.h> +#include <asm/cpu_x86.h> #include <asm/lapic.h> #include <asm/msr.h> #include <asm/mtrr.h> @@ -280,18 +283,13 @@ static void configure_c_states(void) msr_write(MSR_PP1_CURRENT_CONFIG, msr); } -static int configure_thermal_target(void) +static int configure_thermal_target(struct udevice *dev) { int tcc_offset; msr_t msr; - int node; - /* Find pointer to CPU configuration */ - node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_INTEL_MODEL_206AX); - if (node < 0) - return -ENOENT; - tcc_offset = fdtdec_get_int(gd->fdt_blob, node, "tcc-offset", 0); + tcc_offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "tcc-offset", + 0); /* Set TCC activaiton offset if supported */ msr = msr_read(MSR_PLATFORM_INFO); @@ -400,56 +398,7 @@ static void configure_mca(void) static unsigned ehci_debug_addr; #endif -/* - * Initialize any extra cores/threads in this package. - */ -static int intel_cores_init(struct x86_cpu_priv *cpu) -{ - struct cpuid_result result; - unsigned threads_per_package, threads_per_core, i; - - /* Logical processors (threads) per core */ - result = cpuid_ext(0xb, 0); - threads_per_core = result.ebx & 0xffff; - - /* Logical processors (threads) per package */ - result = cpuid_ext(0xb, 1); - threads_per_package = result.ebx & 0xffff; - - debug("CPU: %u has %u cores, %u threads per core\n", - cpu->apic_id, threads_per_package / threads_per_core, - threads_per_core); - - for (i = 1; i < threads_per_package; ++i) { - struct x86_cpu_priv *new_cpu; - - new_cpu = calloc(1, sizeof(*new_cpu)); - if (!new_cpu) - return -ENOMEM; - - new_cpu->apic_id = cpu->apic_id + i; - - /* Update APIC ID if no hyperthreading */ - if (threads_per_core == 1) - new_cpu->apic_id <<= 1; - - debug("CPU: %u has core %u\n", cpu->apic_id, new_cpu->apic_id); - -#if 0 && CONFIG_SMP && CONFIG_MAX_CPUS > 1 - /* TODO(sjg@chromium.org): Start the new cpu */ - if (!start_cpu(new_cpu)) { - /* Record the error in cpu? */ - printk(BIOS_ERR, "CPU %u would not start!\n", - new_cpu->apic_id); - new_cpu->start_err = 1; - } -#endif - } - - return 0; -} - -int model_206ax_init(struct x86_cpu_priv *cpu) +static int model_206ax_init(struct udevice *dev) { int ret; @@ -463,16 +412,6 @@ int model_206ax_init(struct x86_cpu_priv *cpu) set_ehci_debug(0); #endif - /* Setup MTRRs based on physical address size */ -#if 0 /* TODO: Implement this */ - struct cpuid_result cpuid_regs; - - cpuid_regs = cpuid(0x80000008); - x86_setup_fixed_mtrrs(); - x86_setup_var_mtrrs(cpuid_regs.eax & 0xff, 2); - x86_mtrr_check(); -#endif - #if CONFIG_USBDEBUG set_ehci_debug(ehci_debug_addr); #endif @@ -491,9 +430,11 @@ int model_206ax_init(struct x86_cpu_priv *cpu) configure_misc(); /* Thermal throttle activation offset */ - ret = configure_thermal_target(); - if (ret) + ret = configure_thermal_target(dev); + if (ret) { + debug("Cannot set thermal target\n"); return ret; + } /* Enable Direct Cache Access */ configure_dca_cap(); @@ -507,8 +448,49 @@ int model_206ax_init(struct x86_cpu_priv *cpu) /* Enable Turbo */ turbo_enable(); - /* Start up extra cores */ - intel_cores_init(cpu); + return 0; +} + +static int model_206ax_get_info(struct udevice *dev, struct cpu_info *info) +{ + msr_t msr; + + msr = msr_read(IA32_PERF_CTL); + info->cpu_freq = ((msr.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK * 1000000; + info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU; + + return 0; +} + +static int model_206ax_get_count(struct udevice *dev) +{ + return 4; +} + +static int cpu_x86_model_206ax_probe(struct udevice *dev) +{ + if (dev->seq == 0) + model_206ax_init(dev); return 0; } + +static const struct cpu_ops cpu_x86_model_206ax_ops = { + .get_desc = cpu_x86_get_desc, + .get_info = model_206ax_get_info, + .get_count = model_206ax_get_count, +}; + +static const struct udevice_id cpu_x86_model_206ax_ids[] = { + { .compatible = "intel,core-gen3" }, + { } +}; + +U_BOOT_DRIVER(cpu_x86_model_206ax_drv) = { + .name = "cpu_x86_model_206ax", + .id = UCLASS_CPU, + .of_match = cpu_x86_model_206ax_ids, + .bind = cpu_x86_bind, + .probe = cpu_x86_model_206ax_probe, + .ops = &cpu_x86_model_206ax_ops, +}; diff --git a/arch/x86/cpu/ivybridge/northbridge.c b/arch/x86/cpu/ivybridge/northbridge.c index e3d8c139df..a066607a18 100644 --- a/arch/x86/cpu/ivybridge/northbridge.c +++ b/arch/x86/cpu/ivybridge/northbridge.c @@ -8,6 +8,7 @@ */ #include <common.h> +#include <dm.h> #include <asm/msr.h> #include <asm/acpi.h> #include <asm/cpu.h> @@ -18,23 +19,17 @@ #include <asm/arch/model_206ax.h> #include <asm/arch/sandybridge.h> -static int bridge_revision_id = -1; - -int bridge_silicon_revision(void) +int bridge_silicon_revision(struct udevice *dev) { - if (bridge_revision_id < 0) { - struct cpuid_result result; - uint8_t stepping, bridge_id; - pci_dev_t dev; - - result = cpuid(1); - stepping = result.eax & 0xf; - dev = PCI_BDF(0, 0, 0); - bridge_id = x86_pci_read_config16(dev, PCI_DEVICE_ID) & 0xf0; - bridge_revision_id = bridge_id | stepping; - } - - return bridge_revision_id; + struct cpuid_result result; + u16 bridge_id; + u8 stepping; + + result = cpuid(1); + stepping = result.eax & 0xf; + dm_pci_read_config16(dev, PCI_DEVICE_ID, &bridge_id); + bridge_id &= 0xf0; + return bridge_id | stepping; } /* @@ -47,15 +42,14 @@ int bridge_silicon_revision(void) static const int legacy_hole_base_k = 0xa0000 / 1024; static const int legacy_hole_size_k = 384; -static int get_pcie_bar(u32 *base, u32 *len) +static int get_pcie_bar(struct udevice *dev, u32 *base, u32 *len) { - pci_dev_t dev = PCI_BDF(0, 0, 0); u32 pciexbar_reg; *base = 0; *len = 0; - pciexbar_reg = x86_pci_read_config32(dev, PCIEXBAR); + dm_pci_read_config32(dev, PCIEXBAR, &pciexbar_reg); if (!(pciexbar_reg & (1 << 0))) return 0; @@ -81,55 +75,55 @@ static int get_pcie_bar(u32 *base, u32 *len) return 0; } -static void add_fixed_resources(pci_dev_t dev, int index) +static void add_fixed_resources(struct udevice *dev, int index) { u32 pcie_config_base, pcie_config_size; - if (get_pcie_bar(&pcie_config_base, &pcie_config_size)) { + if (get_pcie_bar(dev, &pcie_config_base, &pcie_config_size)) { debug("Adding PCIe config bar base=0x%08x size=0x%x\n", pcie_config_base, pcie_config_size); } } -static void northbridge_dmi_init(pci_dev_t dev) +static void northbridge_dmi_init(struct udevice *dev, int rev) { /* Clear error status bits */ writel(0xffffffff, DMIBAR_REG(0x1c4)); writel(0xffffffff, DMIBAR_REG(0x1d0)); /* Steps prior to DMI ASPM */ - if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { + if ((rev & BASE_REV_MASK) == BASE_REV_SNB) { clrsetbits_le32(DMIBAR_REG(0x250), (1 << 22) | (1 << 20), 1 << 21); } setbits_le32(DMIBAR_REG(0x238), 1 << 29); - if (bridge_silicon_revision() >= SNB_STEP_D0) { + if (rev >= SNB_STEP_D0) { setbits_le32(DMIBAR_REG(0x1f8), 1 << 16); - } else if (bridge_silicon_revision() >= SNB_STEP_D1) { + } else if (rev >= SNB_STEP_D1) { clrsetbits_le32(DMIBAR_REG(0x1f8), 1 << 26, 1 << 16); setbits_le32(DMIBAR_REG(0x1fc), (1 << 12) | (1 << 23)); } /* Enable ASPM on SNB link, should happen before PCH link */ - if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) + if ((rev & BASE_REV_MASK) == BASE_REV_SNB) setbits_le32(DMIBAR_REG(0xd04), 1 << 4); setbits_le32(DMIBAR_REG(0x88), (1 << 1) | (1 << 0)); } -void northbridge_init(pci_dev_t dev) +static void northbridge_init(struct udevice *dev, int rev) { u32 bridge_type; add_fixed_resources(dev, 6); - northbridge_dmi_init(dev); + northbridge_dmi_init(dev, rev); bridge_type = readl(MCHBAR_REG(0x5f10)); bridge_type &= ~0xff; - if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_IVB) { + if ((rev & BASE_REV_MASK) == BASE_REV_IVB) { /* Enable Power Aware Interrupt Routing - fixed priority */ clrsetbits_8(MCHBAR_REG(0x5418), 0xf, 0x4); @@ -167,6 +161,78 @@ void northbridge_init(pci_dev_t dev) writel(0x00100001, MCHBAR_REG(0x5500)); } -void northbridge_enable(pci_dev_t dev) +static void sandybridge_setup_northbridge_bars(struct udevice *dev) +{ + /* Set up all hardcoded northbridge BARs */ + debug("Setting up static registers\n"); + dm_pci_write_config32(dev, EPBAR, DEFAULT_EPBAR | 1); + dm_pci_write_config32(dev, EPBAR + 4, (0LL + DEFAULT_EPBAR) >> 32); + dm_pci_write_config32(dev, MCHBAR, DEFAULT_MCHBAR | 1); + dm_pci_write_config32(dev, MCHBAR + 4, (0LL + DEFAULT_MCHBAR) >> 32); + /* 64MB - busses 0-63 */ + dm_pci_write_config32(dev, PCIEXBAR, DEFAULT_PCIEXBAR | 5); + dm_pci_write_config32(dev, PCIEXBAR + 4, + (0LL + DEFAULT_PCIEXBAR) >> 32); + dm_pci_write_config32(dev, DMIBAR, DEFAULT_DMIBAR | 1); + dm_pci_write_config32(dev, DMIBAR + 4, (0LL + DEFAULT_DMIBAR) >> 32); + + /* Set C0000-FFFFF to access RAM on both reads and writes */ + dm_pci_write_config8(dev, PAM0, 0x30); + dm_pci_write_config8(dev, PAM1, 0x33); + dm_pci_write_config8(dev, PAM2, 0x33); + dm_pci_write_config8(dev, PAM3, 0x33); + dm_pci_write_config8(dev, PAM4, 0x33); + dm_pci_write_config8(dev, PAM5, 0x33); + dm_pci_write_config8(dev, PAM6, 0x33); +} + +static int bd82x6x_northbridge_early_init(struct udevice *dev) +{ + const int chipset_type = SANDYBRIDGE_MOBILE; + u32 capid0_a; + u8 reg8; + + /* Device ID Override Enable should be done very early */ + dm_pci_read_config32(dev, 0xe4, &capid0_a); + if (capid0_a & (1 << 10)) { + dm_pci_read_config8(dev, 0xf3, ®8); + reg8 &= ~7; /* Clear 2:0 */ + + if (chipset_type == SANDYBRIDGE_MOBILE) + reg8 |= 1; /* Set bit 0 */ + + dm_pci_write_config8(dev, 0xf3, reg8); + } + + sandybridge_setup_northbridge_bars(dev); + + /* Device Enable */ + dm_pci_write_config32(dev, DEVEN, DEVEN_HOST | DEVEN_IGD); + + return 0; +} + +static int bd82x6x_northbridge_probe(struct udevice *dev) { + int rev; + + if (!(gd->flags & GD_FLG_RELOC)) + return bd82x6x_northbridge_early_init(dev); + + rev = bridge_silicon_revision(dev); + northbridge_init(dev, rev); + + return 0; } + +static const struct udevice_id bd82x6x_northbridge_ids[] = { + { .compatible = "intel,bd82x6x-northbridge" }, + { } +}; + +U_BOOT_DRIVER(bd82x6x_northbridge_drv) = { + .name = "bd82x6x_northbridge", + .id = UCLASS_NORTHBRIDGE, + .of_match = bd82x6x_northbridge_ids, + .probe = bd82x6x_northbridge_probe, +}; diff --git a/arch/x86/cpu/ivybridge/pch.c b/arch/x86/cpu/ivybridge/pch.c deleted file mode 100644 index bbab64699e..0000000000 --- a/arch/x86/cpu/ivybridge/pch.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * From Coreboot - * Copyright (C) 2008-2009 coresystems GmbH - * Copyright (C) 2012 The Chromium OS Authors. - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/pci.h> -#include <asm/arch/pch.h> - -static int pch_revision_id = -1; -static int pch_type = -1; - -int pch_silicon_revision(void) -{ - pci_dev_t dev; - - dev = PCH_LPC_DEV; - - if (pch_revision_id < 0) - pch_revision_id = x86_pci_read_config8(dev, PCI_REVISION_ID); - return pch_revision_id; -} - -int pch_silicon_type(void) -{ - pci_dev_t dev; - - dev = PCH_LPC_DEV; - - if (pch_type < 0) - pch_type = x86_pci_read_config8(dev, PCI_DEVICE_ID + 1); - return pch_type; -} - -int pch_silicon_supported(int type, int rev) -{ - int cur_type = pch_silicon_type(); - int cur_rev = pch_silicon_revision(); - - switch (type) { - case PCH_TYPE_CPT: - /* CougarPoint minimum revision */ - if (cur_type == PCH_TYPE_CPT && cur_rev >= rev) - return 1; - /* PantherPoint any revision */ - if (cur_type == PCH_TYPE_PPT) - return 1; - break; - - case PCH_TYPE_PPT: - /* PantherPoint minimum revision */ - if (cur_type == PCH_TYPE_PPT && cur_rev >= rev) - return 1; - break; - } - - return 0; -} - -#define IOBP_RETRY 1000 -static inline int iobp_poll(void) -{ - unsigned try = IOBP_RETRY; - u32 data; - - while (try--) { - data = readl(RCB_REG(IOBPS)); - if ((data & 1) == 0) - return 1; - udelay(10); - } - - printf("IOBP timeout\n"); - return 0; -} - -void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue) -{ - u32 data; - - /* Set the address */ - writel(address, RCB_REG(IOBPIRI)); - - /* READ OPCODE */ - if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B0)) - writel(IOBPS_RW_BX, RCB_REG(IOBPS)); - else - writel(IOBPS_READ_AX, RCB_REG(IOBPS)); - if (!iobp_poll()) - return; - - /* Read IOBP data */ - data = readl(RCB_REG(IOBPD)); - if (!iobp_poll()) - return; - - /* Check for successful transaction */ - if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) { - printf("IOBP read 0x%08x failed\n", address); - return; - } - - /* Update the data */ - data &= andvalue; - data |= orvalue; - - /* WRITE OPCODE */ - if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B0)) - writel(IOBPS_RW_BX, RCB_REG(IOBPS)); - else - writel(IOBPS_WRITE_AX, RCB_REG(IOBPS)); - if (!iobp_poll()) - return; - - /* Write IOBP data */ - writel(data, RCB_REG(IOBPD)); - if (!iobp_poll()) - return; -} diff --git a/arch/x86/cpu/ivybridge/pci.c b/arch/x86/cpu/ivybridge/pci.c deleted file mode 100644 index 5e90f30e08..0000000000 --- a/arch/x86/cpu/ivybridge/pci.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * (C) Copyright 2008,2009 - * Graeme Russ, <graeme.russ@gmail.com> - * - * (C) Copyright 2002 - * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <dm.h> -#include <pci.h> -#include <asm/pci.h> -#include <asm/post.h> -#include <asm/arch/bd82x6x.h> -#include <asm/arch/pch.h> - -static int pci_ivybridge_probe(struct udevice *bus) -{ - struct pci_controller *hose = dev_get_uclass_priv(bus); - pci_dev_t dev; - u16 reg16; - - if (!(gd->flags & GD_FLG_RELOC)) - return 0; - post_code(0x50); - bd82x6x_init(); - post_code(0x51); - - reg16 = 0xff; - dev = PCH_DEV; - reg16 = x86_pci_read_config16(dev, PCI_COMMAND); - reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; - x86_pci_write_config16(dev, PCI_COMMAND, reg16); - - /* - * Clear non-reserved bits in status register. - */ - pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff); - pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); - pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08); - - pci_write_bar32(hose, dev, 0, 0xf0000000); - post_code(0x52); - - return 0; -} - -static const struct dm_pci_ops pci_ivybridge_ops = { - .read_config = pci_x86_read_config, - .write_config = pci_x86_write_config, -}; - -static const struct udevice_id pci_ivybridge_ids[] = { - { .compatible = "intel,pci-ivybridge" }, - { } -}; - -U_BOOT_DRIVER(pci_ivybridge_drv) = { - .name = "pci_ivybridge", - .id = UCLASS_PCI, - .of_match = pci_ivybridge_ids, - .ops = &pci_ivybridge_ops, - .probe = pci_ivybridge_probe, -}; diff --git a/arch/x86/cpu/ivybridge/report_platform.c b/arch/x86/cpu/ivybridge/report_platform.c index 44938709c9..c78322aef9 100644 --- a/arch/x86/cpu/ivybridge/report_platform.c +++ b/arch/x86/cpu/ivybridge/report_platform.c @@ -10,6 +10,7 @@ #include <asm/cpu.h> #include <asm/pci.h> #include <asm/arch/pch.h> +#include <asm/arch/sandybridge.h> static void report_cpu_info(void) { @@ -63,27 +64,27 @@ static struct { {0x1E5F, "NM70"}, }; -static void report_pch_info(void) +static void report_pch_info(struct udevice *dev) { const char *pch_type = "Unknown"; int i; u16 dev_id; uint8_t rev_id; - dev_id = x86_pci_read_config16(PCH_LPC_DEV, 2); + dm_pci_read_config16(dev, 2, &dev_id); for (i = 0; i < ARRAY_SIZE(pch_table); i++) { if (pch_table[i].dev_id == dev_id) { pch_type = pch_table[i].dev_name; break; } } - rev_id = x86_pci_read_config8(PCH_LPC_DEV, 8); + dm_pci_read_config8(dev, 8, &rev_id); debug("PCH type: %s, device id: %x, rev id %x\n", pch_type, dev_id, rev_id); } -void report_platform_info(void) +void report_platform_info(struct udevice *dev) { report_cpu_info(); - report_pch_info(); + report_pch_info(dev); } diff --git a/arch/x86/cpu/ivybridge/sata.c b/arch/x86/cpu/ivybridge/sata.c index e7bf03c1dc..a59d9edce5 100644 --- a/arch/x86/cpu/ivybridge/sata.c +++ b/arch/x86/cpu/ivybridge/sata.c @@ -6,48 +6,56 @@ */ #include <common.h> +#include <dm.h> #include <fdtdec.h> #include <asm/io.h> #include <asm/pci.h> #include <asm/arch/pch.h> #include <asm/arch/bd82x6x.h> -static inline u32 sir_read(pci_dev_t dev, int idx) +DECLARE_GLOBAL_DATA_PTR; + +static inline u32 sir_read(struct udevice *dev, int idx) { - x86_pci_write_config32(dev, SATA_SIRI, idx); - return x86_pci_read_config32(dev, SATA_SIRD); + u32 data; + + dm_pci_write_config32(dev, SATA_SIRI, idx); + dm_pci_read_config32(dev, SATA_SIRD, &data); + + return data; } -static inline void sir_write(pci_dev_t dev, int idx, u32 value) +static inline void sir_write(struct udevice *dev, int idx, u32 value) { - x86_pci_write_config32(dev, SATA_SIRI, idx); - x86_pci_write_config32(dev, SATA_SIRD, value); + dm_pci_write_config32(dev, SATA_SIRI, idx); + dm_pci_write_config32(dev, SATA_SIRD, value); } -static void common_sata_init(pci_dev_t dev, unsigned int port_map) +static void common_sata_init(struct udevice *dev, unsigned int port_map) { u32 reg32; u16 reg16; /* Set IDE I/O Configuration */ reg32 = SIG_MODE_PRI_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0; - x86_pci_write_config32(dev, IDE_CONFIG, reg32); + dm_pci_write_config32(dev, IDE_CONFIG, reg32); /* Port enable */ - reg16 = x86_pci_read_config16(dev, 0x92); + dm_pci_read_config16(dev, 0x92, ®16); reg16 &= ~0x3f; reg16 |= port_map; - x86_pci_write_config16(dev, 0x92, reg16); + dm_pci_write_config16(dev, 0x92, reg16); /* SATA Initialization register */ port_map &= 0xff; - x86_pci_write_config32(dev, 0x94, ((port_map ^ 0x3f) << 24) | 0x183); + dm_pci_write_config32(dev, 0x94, ((port_map ^ 0x3f) << 24) | 0x183); } -void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node) +static void bd82x6x_sata_init(struct udevice *dev, struct udevice *pch) { unsigned int port_map, speed_support, port_tx; - struct pci_controller *hose = pci_bus_to_hose(0); + const void *blob = gd->fdt_blob; + int node = dev->of_offset; const char *mode; u32 reg32; u16 reg16; @@ -59,33 +67,27 @@ void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node) speed_support = fdtdec_get_int(blob, node, "sata_interface_speed_support", 0); - /* Enable BARs */ - x86_pci_write_config16(dev, PCI_COMMAND, 0x0007); - mode = fdt_getprop(blob, node, "intel,sata-mode", NULL); if (!mode || !strcmp(mode, "ahci")) { u32 abar; debug("SATA: Controller in AHCI mode\n"); - /* Set Interrupt Line, Interrupt Pin is set by D31IP.PIP */ - x86_pci_write_config8(dev, INTR_LN, 0x0a); - /* Set timings */ - x86_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | IDE_PPE0 | IDE_IE0 | IDE_TIME0); - x86_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | + dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); /* Sync DMA */ - x86_pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0); - x86_pci_write_config16(dev, IDE_SDMA_TIM, 0x0001); + dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_PSDE0); + dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0001); common_sata_init(dev, 0x8000 | port_map); /* Initialize AHCI memory-mapped space */ - abar = pci_read_bar32(hose, dev, 5); + abar = dm_pci_read_bar32(dev, 5); debug("ABAR: %08X\n", abar); /* CAP (HBA Capabilities) : enable power management */ reg32 = readl(abar + 0x00); @@ -113,59 +115,54 @@ void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node) debug("SATA: Controller in combined mode\n"); /* No AHCI: clear AHCI base */ - pci_write_bar32(hose, dev, 5, 0x00000000); + dm_pci_write_bar32(dev, 5, 0x00000000); /* And without AHCI BAR no memory decoding */ - reg16 = x86_pci_read_config16(dev, PCI_COMMAND); + dm_pci_read_config16(dev, PCI_COMMAND, ®16); reg16 &= ~PCI_COMMAND_MEMORY; - x86_pci_write_config16(dev, PCI_COMMAND, reg16); + dm_pci_write_config16(dev, PCI_COMMAND, reg16); - x86_pci_write_config8(dev, 0x09, 0x80); + dm_pci_write_config8(dev, 0x09, 0x80); /* Set timings */ - x86_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | IDE_ISP_5_CLOCKS | IDE_RCT_4_CLOCKS); - x86_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | + dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | IDE_PPE0 | IDE_IE0 | IDE_TIME0); /* Sync DMA */ - x86_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0); - x86_pci_write_config16(dev, IDE_SDMA_TIM, 0x0200); + dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0); + dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0200); common_sata_init(dev, port_map); } else { debug("SATA: Controller in plain-ide mode\n"); /* No AHCI: clear AHCI base */ - pci_write_bar32(hose, dev, 5, 0x00000000); + dm_pci_write_bar32(dev, 5, 0x00000000); /* And without AHCI BAR no memory decoding */ - reg16 = x86_pci_read_config16(dev, PCI_COMMAND); + dm_pci_read_config16(dev, PCI_COMMAND, ®16); reg16 &= ~PCI_COMMAND_MEMORY; - x86_pci_write_config16(dev, PCI_COMMAND, reg16); + dm_pci_write_config16(dev, PCI_COMMAND, reg16); /* * Native mode capable on both primary and secondary (0xa) * OR'ed with enabled (0x50) = 0xf */ - x86_pci_write_config8(dev, 0x09, 0x8f); - - /* Set Interrupt Line */ - /* Interrupt Pin is set by D31IP.PIP */ - x86_pci_write_config8(dev, INTR_LN, 0xff); + dm_pci_write_config8(dev, 0x09, 0x8f); /* Set timings */ - x86_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | + dm_pci_write_config16(dev, IDE_TIM_PRI, IDE_DECODE_ENABLE | IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | IDE_PPE0 | IDE_IE0 | IDE_TIME0); - x86_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | + dm_pci_write_config16(dev, IDE_TIM_SEC, IDE_DECODE_ENABLE | IDE_SITRE | IDE_ISP_3_CLOCKS | IDE_RCT_1_CLOCKS | IDE_IE0 | IDE_TIME0); /* Sync DMA */ - x86_pci_write_config16(dev, IDE_SDMA_CNT, - IDE_SSDE0 | IDE_PSDE0); - x86_pci_write_config16(dev, IDE_SDMA_TIM, 0x0201); + dm_pci_write_config16(dev, IDE_SDMA_CNT, IDE_SSDE0 | IDE_PSDE0); + dm_pci_write_config16(dev, IDE_SDMA_TIM, 0x0201); common_sata_init(dev, port_map); } @@ -173,11 +170,11 @@ void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node) /* Set Gen3 Transmitter settings if needed */ port_tx = fdtdec_get_int(blob, node, "intel,sata-port0-gen3-tx", 0); if (port_tx) - pch_iobp_update(SATA_IOBP_SP0G3IR, 0, port_tx); + pch_iobp_update(pch, SATA_IOBP_SP0G3IR, 0, port_tx); port_tx = fdtdec_get_int(blob, node, "intel,sata-port1-gen3-tx", 0); if (port_tx) - pch_iobp_update(SATA_IOBP_SP1G3IR, 0, port_tx); + pch_iobp_update(pch, SATA_IOBP_SP1G3IR, 0, port_tx); /* Additional Programming Requirements */ sir_write(dev, 0x04, 0x00001600); @@ -202,12 +199,14 @@ void bd82x6x_sata_init(pci_dev_t dev, const void *blob, int node) sir_write(dev, 0xc8, 0x0c0c0c0c); sir_write(dev, 0xd4, 0x10000000); - pch_iobp_update(0xea004001, 0x3fffffff, 0xc0000000); - pch_iobp_update(0xea00408a, 0xfffffcff, 0x00000100); + pch_iobp_update(pch, 0xea004001, 0x3fffffff, 0xc0000000); + pch_iobp_update(pch, 0xea00408a, 0xfffffcff, 0x00000100); } -void bd82x6x_sata_enable(pci_dev_t dev, const void *blob, int node) +static void bd82x6x_sata_enable(struct udevice *dev) { + const void *blob = gd->fdt_blob; + int node = dev->of_offset; unsigned port_map; const char *mode; u16 map = 0; @@ -222,5 +221,36 @@ void bd82x6x_sata_enable(pci_dev_t dev, const void *blob, int node) port_map = fdtdec_get_int(blob, node, "intel,sata-port-map", 0); map |= (port_map ^ 0x3f) << 8; - x86_pci_write_config16(dev, 0x90, map); + dm_pci_write_config16(dev, 0x90, map); } + +static int bd82x6x_sata_probe(struct udevice *dev) +{ + struct udevice *pch; + int ret; + + ret = uclass_first_device(UCLASS_PCH, &pch); + if (ret) + return ret; + if (!pch) + return -ENODEV; + + if (!(gd->flags & GD_FLG_RELOC)) + bd82x6x_sata_enable(dev); + else + bd82x6x_sata_init(dev, pch); + + return 0; +} + +static const struct udevice_id bd82x6x_ahci_ids[] = { + { .compatible = "intel,pantherpoint-ahci" }, + { } +}; + +U_BOOT_DRIVER(ahci_ivybridge_drv) = { + .name = "ahci_ivybridge", + .id = UCLASS_DISK, + .of_match = bd82x6x_ahci_ids, + .probe = bd82x6x_sata_probe, +}; diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c index 4372a5caf2..e23c422cd0 100644 --- a/arch/x86/cpu/ivybridge/sdram.c +++ b/arch/x86/cpu/ivybridge/sdram.c @@ -18,6 +18,8 @@ #include <rtc.h> #include <spi.h> #include <spi_flash.h> +#include <syscon.h> +#include <asm/cpu.h> #include <asm/processor.h> #include <asm/gpio.h> #include <asm/global_data.h> @@ -283,22 +285,24 @@ static int recovery_mode_enabled(void) /** * Find the PEI executable in the ROM and execute it. * - * @param pei_data: configuration data for UEFI PEI reference code + * @dev: Northbridge device + * @pei_data: configuration data for UEFI PEI reference code */ -int sdram_initialise(struct pei_data *pei_data) +int sdram_initialise(struct udevice *dev, struct udevice *me_dev, + struct pei_data *pei_data) { unsigned version; const char *data; uint16_t done; int ret; - report_platform_info(); + report_platform_info(dev); /* Wait for ME to be ready */ - ret = intel_early_me_init(); + ret = intel_early_me_init(me_dev); if (ret) return ret; - ret = intel_early_me_uma_size(); + ret = intel_early_me_uma_size(me_dev); if (ret < 0) return ret; @@ -374,12 +378,12 @@ int sdram_initialise(struct pei_data *pei_data) * Send ME init done for SandyBridge here. This is done inside the * SystemAgent binary on IvyBridge */ - done = x86_pci_read_config32(PCH_DEV, PCI_DEVICE_ID); + dm_pci_read_config16(dev, PCI_DEVICE_ID, &done); done &= BASE_REV_MASK; if (BASE_REV_SNB == done) - intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); + intel_early_me_init_done(dev, me_dev, ME_INIT_STATUS_SUCCESS); else - intel_early_me_status(); + intel_early_me_status(me_dev); post_system_agent_init(pei_data); report_memory_config(); @@ -495,8 +499,10 @@ static int add_memory_area(struct memory_info *info, * * This is a bit complicated since on x86 there are system memory holes all * over the place. We create a list of available memory blocks + * + * @dev: Northbridge device */ -static int sdram_find(pci_dev_t dev) +static int sdram_find(struct udevice *dev) { struct memory_info *info = &gd->arch.meminfo; uint32_t tseg_base, uma_size, tolud; @@ -505,6 +511,7 @@ static int sdram_find(pci_dev_t dev) uint64_t uma_memory_size; unsigned long long tomk; uint16_t ggc; + u32 val; /* Total Memory 2GB example: * @@ -533,24 +540,27 @@ static int sdram_find(pci_dev_t dev) */ /* Top of Upper Usable DRAM, including remap */ - touud = x86_pci_read_config32(dev, TOUUD+4); - touud <<= 32; - touud |= x86_pci_read_config32(dev, TOUUD); + dm_pci_read_config32(dev, TOUUD + 4, &val); + touud = (uint64_t)val << 32; + dm_pci_read_config32(dev, TOUUD, &val); + touud |= val; /* Top of Lower Usable DRAM */ - tolud = x86_pci_read_config32(dev, TOLUD); + dm_pci_read_config32(dev, TOLUD, &tolud); /* Top of Memory - does not account for any UMA */ - tom = x86_pci_read_config32(dev, 0xa4); - tom <<= 32; - tom |= x86_pci_read_config32(dev, 0xa0); + dm_pci_read_config32(dev, 0xa4, &val); + tom = (uint64_t)val << 32; + dm_pci_read_config32(dev, 0xa0, &val); + tom |= val; debug("TOUUD %llx TOLUD %08x TOM %llx\n", touud, tolud, tom); /* ME UMA needs excluding if total memory <4GB */ - me_base = x86_pci_read_config32(dev, 0x74); - me_base <<= 32; - me_base |= x86_pci_read_config32(dev, 0x70); + dm_pci_read_config32(dev, 0x74, &val); + me_base = (uint64_t)val << 32; + dm_pci_read_config32(dev, 0x70, &val); + me_base |= val; debug("MEBASE %llx\n", me_base); @@ -568,7 +578,7 @@ static int sdram_find(pci_dev_t dev) } /* Graphics memory comes next */ - ggc = x86_pci_read_config16(dev, GGC); + dm_pci_read_config16(dev, GGC, &ggc); if (!(ggc & 2)) { debug("IGD decoded, subtracting "); @@ -588,7 +598,7 @@ static int sdram_find(pci_dev_t dev) } /* Calculate TSEG size from its base which must be below GTT */ - tseg_base = x86_pci_read_config32(dev, 0xb8); + dm_pci_read_config32(dev, 0xb8, &tseg_base); uma_size = (uma_memory_base - tseg_base) >> 10; tomk -= uma_size; uma_memory_base = tomk * 1024ULL; @@ -723,15 +733,23 @@ int dram_init(void) { 0, 4, 0x0000 }, /* P13= Empty */ }, }; - pci_dev_t dev = PCI_BDF(0, 0, 0); + struct udevice *dev, *me_dev; int ret; + ret = uclass_first_device(UCLASS_NORTHBRIDGE, &dev); + if (ret) + return ret; + if (!dev) + return -ENODEV; + ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev); + if (ret) + return ret; debug("Boot mode %d\n", gd->arch.pei_boot_mode); debug("mrc_input %p\n", pei_data.mrc_input); pei_data.boot_mode = gd->arch.pei_boot_mode; ret = copy_spd(&pei_data); if (!ret) - ret = sdram_initialise(&pei_data); + ret = sdram_initialise(dev, me_dev, &pei_data); if (ret) return ret; diff --git a/arch/x86/cpu/ivybridge/usb_ehci.c b/arch/x86/cpu/ivybridge/usb_ehci.c deleted file mode 100644 index da11aee94d..0000000000 --- a/arch/x86/cpu/ivybridge/usb_ehci.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * From Coreboot - * Copyright (C) 2008-2009 coresystems GmbH - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/pci.h> -#include <asm/arch/pch.h> - -void bd82x6x_usb_ehci_init(pci_dev_t dev) -{ - u32 reg32; - - /* Disable Wake on Disconnect in RMH */ - reg32 = readl(RCB_REG(0x35b0)); - reg32 |= 0x22; - writel(reg32, RCB_REG(0x35b0)); - - debug("EHCI: Setting up controller.. "); - reg32 = x86_pci_read_config32(dev, PCI_COMMAND); - reg32 |= PCI_COMMAND_MASTER; - /* reg32 |= PCI_COMMAND_SERR; */ - x86_pci_write_config32(dev, PCI_COMMAND, reg32); - - debug("done.\n"); -} diff --git a/arch/x86/cpu/ivybridge/usb_xhci.c b/arch/x86/cpu/ivybridge/usb_xhci.c deleted file mode 100644 index f77b80489b..0000000000 --- a/arch/x86/cpu/ivybridge/usb_xhci.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * From Coreboot - * Copyright (C) 2008-2009 coresystems GmbH - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include <common.h> -#include <asm/pci.h> -#include <asm/arch/pch.h> - -void bd82x6x_usb_xhci_init(pci_dev_t dev) -{ - u32 reg32; - - debug("XHCI: Setting up controller.. "); - - /* lock overcurrent map */ - reg32 = x86_pci_read_config32(dev, 0x44); - reg32 |= 1; - x86_pci_write_config32(dev, 0x44, reg32); - - /* Enable clock gating */ - reg32 = x86_pci_read_config32(dev, 0x40); - reg32 &= ~((1 << 20) | (1 << 21)); - reg32 |= (1 << 19) | (1 << 18) | (1 << 17); - reg32 |= (1 << 10) | (1 << 9) | (1 << 8); - reg32 |= (1 << 31); /* lock */ - x86_pci_write_config32(dev, 0x40, reg32); - - debug("done.\n"); -} diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 4334f5b3e5..7917350bff 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -20,8 +20,11 @@ #include <asm/mtrr.h> #include <asm/processor.h> #include <asm/sipi.h> +#include <asm/fw_cfg.h> #include <dm/device-internal.h> #include <dm/uclass-internal.h> +#include <dm/lists.h> +#include <dm/root.h> #include <linux/linkage.h> DECLARE_GLOBAL_DATA_PTR; @@ -104,7 +107,7 @@ static void ap_do_flight_plan(struct udevice *cpu) } } -static int find_cpu_by_apid_id(int apic_id, struct udevice **devp) +static int find_cpu_by_apic_id(int apic_id, struct udevice **devp) { struct udevice *dev; @@ -137,7 +140,7 @@ static void ap_init(unsigned int cpu_index) enable_lapic(); apic_id = lapicid(); - ret = find_cpu_by_apid_id(apic_id, &dev); + ret = find_cpu_by_apic_id(apic_id, &dev); if (ret) { debug("Unknown CPU apic_id %x\n", apic_id); goto done; @@ -210,7 +213,7 @@ static int save_bsp_msrs(char *start, int size) return msr_count; } -static int load_sipi_vector(atomic_t **ap_countp) +static int load_sipi_vector(atomic_t **ap_countp, int num_cpus) { struct sipi_params_16bit *params16; struct sipi_params *params; @@ -239,7 +242,7 @@ static int load_sipi_vector(atomic_t **ap_countp) params->idt_ptr = (uint32_t)x86_get_idt(); params->stack_size = CONFIG_AP_STACK_SIZE; - size = params->stack_size * CONFIG_MAX_CPUS; + size = params->stack_size * num_cpus; stack = memalign(size, 4096); if (!stack) return -ENOMEM; @@ -432,7 +435,7 @@ static int init_bsp(struct udevice **devp) lapic_setup(); apic_id = lapicid(); - ret = find_cpu_by_apid_id(apic_id, devp); + ret = find_cpu_by_apic_id(apic_id, devp); if (ret) { printf("Cannot find boot CPU, APIC ID %d\n", apic_id); return ret; @@ -441,6 +444,69 @@ static int init_bsp(struct udevice **devp) return 0; } +#ifdef CONFIG_QEMU +static int qemu_cpu_fixup(void) +{ + int ret; + int cpu_num; + int cpu_online; + struct udevice *dev, *pdev; + struct cpu_platdata *plat; + char *cpu; + + /* first we need to find '/cpus' */ + for (device_find_first_child(dm_root(), &pdev); + pdev; + device_find_next_child(&pdev)) { + if (!strcmp(pdev->name, "cpus")) + break; + } + if (!pdev) { + printf("unable to find cpus device\n"); + return -ENODEV; + } + + /* calculate cpus that are already bound */ + cpu_num = 0; + for (uclass_find_first_device(UCLASS_CPU, &dev); + dev; + uclass_find_next_device(&dev)) { + cpu_num++; + } + + /* get actual cpu number */ + cpu_online = qemu_fwcfg_online_cpus(); + if (cpu_online < 0) { + printf("unable to get online cpu number: %d\n", cpu_online); + return cpu_online; + } + + /* bind addtional cpus */ + dev = NULL; + for (; cpu_num < cpu_online; cpu_num++) { + /* + * allocate device name here as device_bind_driver() does + * not copy device name, 8 bytes are enough for + * sizeof("cpu@") + 3 digits cpu number + '\0' + */ + cpu = malloc(8); + if (!cpu) { + printf("unable to allocate device name\n"); + return -ENOMEM; + } + sprintf(cpu, "cpu@%d", cpu_num); + ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev); + if (ret) { + printf("binding cpu@%d failed: %d\n", cpu_num, ret); + return ret; + } + plat = dev_get_parent_platdata(dev); + plat->cpu_id = cpu_num; + } + return 0; +} +#endif + int mp_init(struct mp_params *p) { int num_aps; @@ -454,6 +520,12 @@ int mp_init(struct mp_params *p) if (ret) return ret; +#ifdef CONFIG_QEMU + ret = qemu_cpu_fixup(); + if (ret) + return ret; +#endif + ret = init_bsp(&cpu); if (ret) { debug("Cannot init boot CPU: err=%d\n", ret); @@ -483,7 +555,7 @@ int mp_init(struct mp_params *p) mp_info.records = p->flight_plan; /* Load the SIPI vector */ - ret = load_sipi_vector(&ap_count); + ret = load_sipi_vector(&ap_count, num_cpus); if (ap_count == NULL) return -1; diff --git a/arch/x86/cpu/qemu/Kconfig b/arch/x86/cpu/qemu/Kconfig index 4f9862194a..6808c9a6b9 100644 --- a/arch/x86/cpu/qemu/Kconfig +++ b/arch/x86/cpu/qemu/Kconfig @@ -17,4 +17,11 @@ config SYS_CAR_SIZE hex default 0x10000 +config ACPI_PM1_BASE + hex + default 0xe400 + help + ACPI Power Managment 1 (PM1) i/o-mapped base address. + This device is defined in ACPI specification, with 16 bytes in size. + endif diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 3f3958aa8e..801413a1cb 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -7,5 +7,7 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif -obj-y += qemu.o +obj-y += cpu.o fw_cfg.o qemu.o +ifndef CONFIG_QEMU_ACPI_TABLE obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o +endif diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c new file mode 100644 index 0000000000..a1b70c6bde --- /dev/null +++ b/arch/x86/cpu/qemu/cpu.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015, Miao Yan <yanmiaobest@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <errno.h> +#include <asm/cpu.h> +#include <asm/fw_cfg.h> + +DECLARE_GLOBAL_DATA_PTR; + +int cpu_qemu_get_desc(struct udevice *dev, char *buf, int size) +{ + if (size < CPU_MAX_NAME_LEN) + return -ENOSPC; + + cpu_get_name(buf); + + return 0; +} + +static int cpu_qemu_get_count(struct udevice *dev) +{ + return qemu_fwcfg_online_cpus(); +} + +static const struct cpu_ops cpu_qemu_ops = { + .get_desc = cpu_qemu_get_desc, + .get_count = cpu_qemu_get_count, +}; + +static const struct udevice_id cpu_qemu_ids[] = { + { .compatible = "cpu-qemu" }, + { } +}; + +U_BOOT_DRIVER(cpu_qemu_drv) = { + .name = "cpu_qemu", + .id = UCLASS_CPU, + .of_match = cpu_qemu_ids, + .ops = &cpu_qemu_ops, +}; diff --git a/arch/x86/cpu/qemu/fw_cfg.c b/arch/x86/cpu/qemu/fw_cfg.c new file mode 100644 index 0000000000..5ea7a6e2e5 --- /dev/null +++ b/arch/x86/cpu/qemu/fw_cfg.c @@ -0,0 +1,571 @@ +/* + * (C) Copyright 2015 Miao Yan <yanmiaoebst@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <errno.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/fw_cfg.h> +#include <asm/tables.h> +#include <asm/e820.h> +#include <linux/list.h> +#include <memalign.h> + +static bool fwcfg_present; +static bool fwcfg_dma_present; + +static LIST_HEAD(fw_list); + +/* Read configuration item using fw_cfg PIO interface */ +static void qemu_fwcfg_read_entry_pio(uint16_t entry, + uint32_t size, void *address) +{ + uint32_t i = 0; + uint8_t *data = address; + + /* + * writting FW_CFG_INVALID will cause read operation to resume at + * last offset, otherwise read will start at offset 0 + */ + if (entry != FW_CFG_INVALID) + outw(entry, FW_CONTROL_PORT); + while (size--) + data[i++] = inb(FW_DATA_PORT); +} + +/* Read configuration item using fw_cfg DMA interface */ +static void qemu_fwcfg_read_entry_dma(uint16_t entry, + uint32_t size, void *address) +{ + struct fw_cfg_dma_access dma; + + dma.length = cpu_to_be32(size); + dma.address = cpu_to_be64((uintptr_t)address); + dma.control = cpu_to_be32(FW_CFG_DMA_READ); + + /* + * writting FW_CFG_INVALID will cause read operation to resume at + * last offset, otherwise read will start at offset 0 + */ + if (entry != FW_CFG_INVALID) + dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16)); + + barrier(); + + debug("qemu_fwcfg_dma_read_entry: addr %p, length %u control 0x%x\n", + address, size, be32_to_cpu(dma.control)); + + outl(cpu_to_be32((uint32_t)&dma), FW_DMA_PORT_HIGH); + + while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR) + __asm__ __volatile__ ("pause"); +} + +static bool qemu_fwcfg_present(void) +{ + uint32_t qemu; + + qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); + return be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE; +} + +static bool qemu_fwcfg_dma_present(void) +{ + uint8_t dma_enabled; + + qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); + if (dma_enabled & FW_CFG_DMA_ENABLED) + return true; + + return false; +} + +static void qemu_fwcfg_read_entry(uint16_t entry, + uint32_t length, void *address) +{ + if (fwcfg_dma_present) + qemu_fwcfg_read_entry_dma(entry, length, address); + else + qemu_fwcfg_read_entry_pio(entry, length, address); +} + +int qemu_fwcfg_online_cpus(void) +{ + uint16_t nb_cpus; + + if (!fwcfg_present) + return -ENODEV; + + qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus); + + return le16_to_cpu(nb_cpus); +} + +/* + * This function prepares kernel for zboot. It loads kernel data + * to 'load_addr', initrd to 'initrd_addr' and kernel command + * line using qemu fw_cfg interface. + */ +static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr) +{ + char *data_addr; + uint32_t setup_size, kernel_size, cmdline_size, initrd_size; + + qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, &setup_size); + qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, &kernel_size); + + if (setup_size == 0 || kernel_size == 0) { + printf("warning: no kernel available\n"); + return -1; + } + + data_addr = load_addr; + qemu_fwcfg_read_entry(FW_CFG_SETUP_DATA, + le32_to_cpu(setup_size), data_addr); + data_addr += le32_to_cpu(setup_size); + + qemu_fwcfg_read_entry(FW_CFG_KERNEL_DATA, + le32_to_cpu(kernel_size), data_addr); + data_addr += le32_to_cpu(kernel_size); + + data_addr = initrd_addr; + qemu_fwcfg_read_entry(FW_CFG_INITRD_SIZE, 4, &initrd_size); + if (initrd_size == 0) { + printf("warning: no initrd available\n"); + } else { + qemu_fwcfg_read_entry(FW_CFG_INITRD_DATA, + le32_to_cpu(initrd_size), data_addr); + data_addr += le32_to_cpu(initrd_size); + } + + qemu_fwcfg_read_entry(FW_CFG_CMDLINE_SIZE, 4, &cmdline_size); + if (cmdline_size) { + qemu_fwcfg_read_entry(FW_CFG_CMDLINE_DATA, + le32_to_cpu(cmdline_size), data_addr); + /* + * if kernel cmdline only contains '\0', (e.g. no -append + * when invoking qemu), do not update bootargs + */ + if (*data_addr != '\0') { + if (setenv("bootargs", data_addr) < 0) + printf("warning: unable to change bootargs\n"); + } + } + + printf("loading kernel to address %p size %x", load_addr, + le32_to_cpu(kernel_size)); + if (initrd_size) + printf(" initrd %p size %x\n", + initrd_addr, + le32_to_cpu(initrd_size)); + else + printf("\n"); + + return 0; +} + +static int qemu_fwcfg_read_firmware_list(void) +{ + int i; + uint32_t count; + struct fw_file *file; + struct list_head *entry; + + /* don't read it twice */ + if (!list_empty(&fw_list)) + return 0; + + qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count); + if (!count) + return 0; + + count = be32_to_cpu(count); + for (i = 0; i < count; i++) { + file = malloc(sizeof(*file)); + if (!file) { + printf("error: allocating resource\n"); + goto err; + } + qemu_fwcfg_read_entry(FW_CFG_INVALID, + sizeof(struct fw_cfg_file), &file->cfg); + file->addr = 0; + list_add_tail(&file->list, &fw_list); + } + + return 0; + +err: + list_for_each(entry, &fw_list) { + file = list_entry(entry, struct fw_file, list); + free(file); + } + + return -ENOMEM; +} + +#ifdef CONFIG_QEMU_ACPI_TABLE +static struct fw_file *qemu_fwcfg_find_file(const char *name) +{ + struct list_head *entry; + struct fw_file *file; + + list_for_each(entry, &fw_list) { + file = list_entry(entry, struct fw_file, list); + if (!strcmp(file->cfg.name, name)) + return file; + } + + return NULL; +} + +/* + * This function allocates memory for ACPI tables + * + * @entry : BIOS linker command entry which tells where to allocate memory + * (either high memory or low memory) + * @addr : The address that should be used for low memory allcation. If the + * memory allocation request is 'ZONE_HIGH' then this parameter will + * be ignored. + * @return: 0 on success, or negative value on failure + */ +static int bios_linker_allocate(struct bios_linker_entry *entry, + unsigned long *addr) +{ + uint32_t size, align; + struct fw_file *file; + unsigned long aligned_addr; + + align = le32_to_cpu(entry->alloc.align); + /* align must be power of 2 */ + if (align & (align - 1)) { + printf("error: wrong alignment %u\n", align); + return -EINVAL; + } + + file = qemu_fwcfg_find_file(entry->alloc.file); + if (!file) { + printf("error: can't find file %s\n", entry->alloc.file); + return -ENOENT; + } + + size = be32_to_cpu(file->cfg.size); + + /* + * ZONE_HIGH means we need to allocate from high memory, since + * malloc space is already at the end of RAM, so we directly use it. + * If allocation zone is ZONE_FSEG, then we use the 'addr' passed + * in which is low memory + */ + if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) { + aligned_addr = (unsigned long)memalign(align, size); + if (!aligned_addr) { + printf("error: allocating resource\n"); + return -ENOMEM; + } + } else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) { + aligned_addr = ALIGN(*addr, align); + } else { + printf("error: invalid allocation zone\n"); + return -EINVAL; + } + + debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n", + file->cfg.name, size, entry->alloc.zone, align, aligned_addr); + + qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select), + size, (void *)aligned_addr); + file->addr = aligned_addr; + + /* adjust address for low memory allocation */ + if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) + *addr = (aligned_addr + size); + + return 0; +} + +/* + * This function patches ACPI tables previously loaded + * by bios_linker_allocate() + * + * @entry : BIOS linker command entry which tells how to patch + * ACPI tables + * @return: 0 on success, or negative value on failure + */ +static int bios_linker_add_pointer(struct bios_linker_entry *entry) +{ + struct fw_file *dest, *src; + uint32_t offset = le32_to_cpu(entry->pointer.offset); + uint64_t pointer = 0; + + dest = qemu_fwcfg_find_file(entry->pointer.dest_file); + if (!dest || !dest->addr) + return -ENOENT; + src = qemu_fwcfg_find_file(entry->pointer.src_file); + if (!src || !src->addr) + return -ENOENT; + + debug("bios_linker_add_pointer: dest->addr 0x%lx, src->addr 0x%lx, offset 0x%x size %u, 0x%llx\n", + dest->addr, src->addr, offset, entry->pointer.size, pointer); + + memcpy(&pointer, (char *)dest->addr + offset, entry->pointer.size); + pointer = le64_to_cpu(pointer); + pointer += (unsigned long)src->addr; + pointer = cpu_to_le64(pointer); + memcpy((char *)dest->addr + offset, &pointer, entry->pointer.size); + + return 0; +} + +/* + * This function updates checksum fields of ACPI tables previously loaded + * by bios_linker_allocate() + * + * @entry : BIOS linker command entry which tells where to update ACPI table + * checksums + * @return: 0 on success, or negative value on failure + */ +static int bios_linker_add_checksum(struct bios_linker_entry *entry) +{ + struct fw_file *file; + uint8_t *data, cksum = 0; + uint8_t *cksum_start; + + file = qemu_fwcfg_find_file(entry->cksum.file); + if (!file || !file->addr) + return -ENOENT; + + data = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.offset)); + cksum_start = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.start)); + cksum = table_compute_checksum(cksum_start, + le32_to_cpu(entry->cksum.length)); + *data = cksum; + + return 0; +} + +unsigned install_e820_map(unsigned max_entries, struct e820entry *entries) +{ + entries[0].addr = 0; + entries[0].size = ISA_START_ADDRESS; + entries[0].type = E820_RAM; + + entries[1].addr = ISA_START_ADDRESS; + entries[1].size = ISA_END_ADDRESS - ISA_START_ADDRESS; + entries[1].type = E820_RESERVED; + + /* + * since we use memalign(malloc) to allocate high memory for + * storing ACPI tables, we need to reserve them in e820 tables, + * otherwise kernel will reclaim them and data will be corrupted + */ + entries[2].addr = ISA_END_ADDRESS; + entries[2].size = gd->relocaddr - TOTAL_MALLOC_LEN - ISA_END_ADDRESS; + entries[2].type = E820_RAM; + + /* for simplicity, reserve entire malloc space */ + entries[3].addr = gd->relocaddr - TOTAL_MALLOC_LEN; + entries[3].size = TOTAL_MALLOC_LEN; + entries[3].type = E820_RESERVED; + + entries[4].addr = gd->relocaddr; + entries[4].size = gd->ram_size - gd->relocaddr; + entries[4].type = E820_RESERVED; + + entries[5].addr = CONFIG_PCIE_ECAM_BASE; + entries[5].size = CONFIG_PCIE_ECAM_SIZE; + entries[5].type = E820_RESERVED; + + return 6; +} + +/* This function loads and patches ACPI tables provided by QEMU */ +unsigned long write_acpi_tables(unsigned long addr) +{ + int i, ret = 0; + struct fw_file *file; + struct bios_linker_entry *table_loader; + struct bios_linker_entry *entry; + uint32_t size; + struct list_head *list; + + /* make sure fw_list is loaded */ + ret = qemu_fwcfg_read_firmware_list(); + if (ret) { + printf("error: can't read firmware file list\n"); + return addr; + } + + file = qemu_fwcfg_find_file("etc/table-loader"); + if (!file) { + printf("error: can't find etc/table-loader\n"); + return addr; + } + + size = be32_to_cpu(file->cfg.size); + if ((size % sizeof(*entry)) != 0) { + printf("error: table-loader maybe corrupted\n"); + return addr; + } + + table_loader = malloc(size); + if (!table_loader) { + printf("error: no memory for table-loader\n"); + return addr; + } + + qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select), + size, table_loader); + + for (i = 0; i < (size / sizeof(*entry)); i++) { + entry = table_loader + i; + switch (le32_to_cpu(entry->command)) { + case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: + ret = bios_linker_allocate(entry, &addr); + if (ret) + goto out; + break; + case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: + ret = bios_linker_add_pointer(entry); + if (ret) + goto out; + break; + case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: + ret = bios_linker_add_checksum(entry); + if (ret) + goto out; + break; + default: + break; + } + } + +out: + if (ret) { + list_for_each(list, &fw_list) { + file = list_entry(list, struct fw_file, list); + if (file->addr) + free((void *)file->addr); + } + } + + free(table_loader); + return addr; +} +#endif + +static int qemu_fwcfg_list_firmware(void) +{ + int ret; + struct list_head *entry; + struct fw_file *file; + + /* make sure fw_list is loaded */ + ret = qemu_fwcfg_read_firmware_list(); + if (ret) + return ret; + + list_for_each(entry, &fw_list) { + file = list_entry(entry, struct fw_file, list); + printf("%-56s\n", file->cfg.name); + } + + return 0; +} + +void qemu_fwcfg_init(void) +{ + fwcfg_present = qemu_fwcfg_present(); + if (fwcfg_present) + fwcfg_dma_present = qemu_fwcfg_dma_present(); +} + +static int qemu_fwcfg_do_list(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + if (qemu_fwcfg_list_firmware() < 0) + return CMD_RET_FAILURE; + + return 0; +} + +static int qemu_fwcfg_do_cpus(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + int ret = qemu_fwcfg_online_cpus(); + if (ret < 0) { + printf("QEMU fw_cfg interface not found\n"); + return CMD_RET_FAILURE; + } + + printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus()); + + return 0; +} + +static int qemu_fwcfg_do_load(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + char *env; + void *load_addr; + void *initrd_addr; + + env = getenv("loadaddr"); + load_addr = env ? + (void *)simple_strtoul(env, NULL, 16) : + (void *)CONFIG_LOADADDR; + + env = getenv("ramdiskaddr"); + initrd_addr = env ? + (void *)simple_strtoul(env, NULL, 16) : + (void *)CONFIG_RAMDISK_ADDR; + + if (argc == 2) { + load_addr = (void *)simple_strtoul(argv[0], NULL, 16); + initrd_addr = (void *)simple_strtoul(argv[1], NULL, 16); + } else if (argc == 1) { + load_addr = (void *)simple_strtoul(argv[0], NULL, 16); + } + + return qemu_fwcfg_setup_kernel(load_addr, initrd_addr); +} + +static cmd_tbl_t fwcfg_commands[] = { + U_BOOT_CMD_MKENT(list, 0, 1, qemu_fwcfg_do_list, "", ""), + U_BOOT_CMD_MKENT(cpus, 0, 1, qemu_fwcfg_do_cpus, "", ""), + U_BOOT_CMD_MKENT(load, 2, 1, qemu_fwcfg_do_load, "", ""), +}; + +static int do_qemu_fw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret; + cmd_tbl_t *fwcfg_cmd; + + if (!fwcfg_present) { + printf("QEMU fw_cfg interface not found\n"); + return CMD_RET_USAGE; + } + + fwcfg_cmd = find_cmd_tbl(argv[1], fwcfg_commands, + ARRAY_SIZE(fwcfg_commands)); + argc -= 2; + argv += 2; + if (!fwcfg_cmd || argc > fwcfg_cmd->maxargs) + return CMD_RET_USAGE; + + ret = fwcfg_cmd->cmd(fwcfg_cmd, flag, argc, argv); + + return cmd_process_error(fwcfg_cmd, ret); +} + +U_BOOT_CMD( + qfw, 4, 1, do_qemu_fw, + "QEMU firmware interface", + "<command>\n" + " - list : print firmware(s) currently loaded\n" + " - cpus : print online cpu number\n" + " - load <kernel addr> <initrd addr> : load kernel and initrd (if any), and setup for zboot\n" +) diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 1f93f72dc8..f8af566dea 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -11,9 +11,35 @@ #include <asm/processor.h> #include <asm/arch/device.h> #include <asm/arch/qemu.h> +#include <asm/fw_cfg.h> static bool i440fx; +static void enable_pm_piix(void) +{ + u8 en; + u16 cmd; + + /* Set the PM I/O base */ + x86_pci_write_config32(PIIX_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1); + + /* Enable access to the PM I/O space */ + cmd = x86_pci_read_config16(PIIX_PM, PCI_COMMAND); + cmd |= PCI_COMMAND_IO; + x86_pci_write_config16(PIIX_PM, PCI_COMMAND, cmd); + + /* PM I/O Space Enable (PMIOSE) */ + en = x86_pci_read_config8(PIIX_PM, PMREGMISC); + en |= PMIOSE; + x86_pci_write_config8(PIIX_PM, PMREGMISC, en); +} + +static void enable_pm_ich9(void) +{ + /* Set the PM I/O base */ + x86_pci_write_config32(ICH9_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1); +} + static void qemu_chipset_init(void) { u16 device, xbcs; @@ -52,11 +78,17 @@ static void qemu_chipset_init(void) xbcs = x86_pci_read_config16(PIIX_ISA, XBCS); xbcs |= APIC_EN; x86_pci_write_config16(PIIX_ISA, XBCS, xbcs); + + enable_pm_piix(); } else { /* Configure PCIe ECAM base address */ x86_pci_write_config32(PCI_BDF(0, 0, 0), PCIEX_BAR, CONFIG_PCIE_ECAM_BASE | BAR_EN); + + enable_pm_ich9(); } + + qemu_fwcfg_init(); } int arch_cpu_init(void) @@ -93,11 +125,6 @@ int arch_early_init_r(void) return 0; } -int arch_misc_init(void) -{ - return pirq_init(); -} - #ifdef CONFIG_GENERATE_MP_TABLE int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq) { diff --git a/arch/x86/cpu/quark/Makefile b/arch/x86/cpu/quark/Makefile index 8f1d018fb6..6d670d75c1 100644 --- a/arch/x86/cpu/quark/Makefile +++ b/arch/x86/cpu/quark/Makefile @@ -4,5 +4,5 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += car.o dram.o msg_port.o quark.o +obj-y += car.o dram.o irq.o msg_port.o quark.o obj-y += mrc.o mrc_util.o hte.o smc.o diff --git a/arch/x86/cpu/quark/irq.c b/arch/x86/cpu/quark/irq.c new file mode 100644 index 0000000000..1f8f90923d --- /dev/null +++ b/arch/x86/cpu/quark/irq.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> + * Copyright (C) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <asm/irq.h> +#include <asm/arch/device.h> +#include <asm/arch/quark.h> + +int quark_irq_router_probe(struct udevice *dev) +{ + struct quark_rcba *rcba; + u32 base; + + qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, LB_RCBA, &base); + base &= ~MEM_BAR_EN; + rcba = (struct quark_rcba *)base; + + /* + * Route Quark PCI device interrupt pin to PIRQ + * + * Route device#23's INTA/B/C/D to PIRQA/B/C/D + * Route device#20,21's INTA/B/C/D to PIRQE/F/G/H + */ + writew(PIRQC, &rcba->rmu_ir); + writew(PIRQA | (PIRQB << 4) | (PIRQC << 8) | (PIRQD << 12), + &rcba->d23_ir); + writew(PIRQD, &rcba->core_ir); + writew(PIRQE | (PIRQF << 4) | (PIRQG << 8) | (PIRQH << 12), + &rcba->d20d21_ir); + + return irq_router_common_init(dev); +} + +static const struct udevice_id quark_irq_router_ids[] = { + { .compatible = "intel,quark-irq-router" }, + { } +}; + +U_BOOT_DRIVER(quark_irq_router_drv) = { + .name = "quark_intel_irq", + .id = UCLASS_IRQ, + .of_match = quark_irq_router_ids, + .probe = quark_irq_router_probe, +}; diff --git a/arch/x86/cpu/quark/quark.c b/arch/x86/cpu/quark/quark.c index 37ce3940b0..6e20930a4d 100644 --- a/arch/x86/cpu/quark/quark.c +++ b/arch/x86/cpu/quark/quark.c @@ -7,12 +7,10 @@ #include <common.h> #include <mmc.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/mrccache.h> #include <asm/mtrr.h> #include <asm/pci.h> #include <asm/post.h> -#include <asm/processor.h> #include <asm/arch/device.h> #include <asm/arch/msg_port.h> #include <asm/arch/quark.h> @@ -252,17 +250,6 @@ int arch_cpu_init(void) */ quark_setup_bars(); - /* - * Initialize PCIe controller - * - * Quark SoC holds the PCIe controller in reset following a power on. - * U-Boot needs to release the PCIe controller from reset. The PCIe - * controller (D23:F0/F1) will not be visible in PCI configuration - * space and any access to its PCI configuration registers will cause - * system hang while it is held in reset. - */ - quark_pcie_early_init(); - /* Initialize USB2 PHY */ quark_usb_early_init(); @@ -277,6 +264,22 @@ int arch_cpu_init(void) return 0; } +int arch_cpu_init_dm(void) +{ + /* + * Initialize PCIe controller + * + * Quark SoC holds the PCIe controller in reset following a power on. + * U-Boot needs to release the PCIe controller from reset. The PCIe + * controller (D23:F0/F1) will not be visible in PCI configuration + * space and any access to its PCI configuration registers will cause + * system hang while it is held in reset. + */ + quark_pcie_early_init(); + + return 0; +} + int print_cpuinfo(void) { post_code(POST_CPU_INFO); @@ -341,29 +344,6 @@ int cpu_mmc_init(bd_t *bis) return pci_mmc_init("Quark SDHCI", mmc_supported); } -void cpu_irq_init(void) -{ - struct quark_rcba *rcba; - u32 base; - - qrk_pci_read_config_dword(QUARK_LEGACY_BRIDGE, LB_RCBA, &base); - base &= ~MEM_BAR_EN; - rcba = (struct quark_rcba *)base; - - /* - * Route Quark PCI device interrupt pin to PIRQ - * - * Route device#23's INTA/B/C/D to PIRQA/B/C/D - * Route device#20,21's INTA/B/C/D to PIRQE/F/G/H - */ - writew(PIRQC, &rcba->rmu_ir); - writew(PIRQA | (PIRQB << 4) | (PIRQC << 8) | (PIRQD << 12), - &rcba->d23_ir); - writew(PIRQD, &rcba->core_ir); - writew(PIRQE | (PIRQF << 4) | (PIRQG << 8) | (PIRQH << 12), - &rcba->d20d21_ir); -} - int arch_misc_init(void) { #ifdef CONFIG_ENABLE_MRC_CACHE @@ -375,7 +355,7 @@ int arch_misc_init(void) mrccache_save(); #endif - return pirq_init(); + return 0; } void board_final_cleanup(void) diff --git a/arch/x86/cpu/queensbay/Makefile b/arch/x86/cpu/queensbay/Makefile index 660f9678bd..af3ffad385 100644 --- a/arch/x86/cpu/queensbay/Makefile +++ b/arch/x86/cpu/queensbay/Makefile @@ -4,5 +4,5 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += fsp_configs.o +obj-y += fsp_configs.o irq.o obj-y += tnc.o topcliff.o diff --git a/arch/x86/cpu/queensbay/fsp_configs.c b/arch/x86/cpu/queensbay/fsp_configs.c index 78bc966bbd..f83bb5f221 100644 --- a/arch/x86/cpu/queensbay/fsp_configs.c +++ b/arch/x86/cpu/queensbay/fsp_configs.c @@ -8,13 +8,13 @@ #include <common.h> #include <asm/fsp/fsp_support.h> -void update_fsp_upd(struct upd_region *fsp_upd) +void update_fsp_configs(struct fsp_config_data *config, + struct fspinit_rtbuf *rt_buf) { - /* Override any UPD setting if required */ - - /* Uncomment the line below to enable DEBUG message */ - /* fsp_upd->serial_dbgport_type = 1; */ + /* Initialize runtime buffer for fsp_init() */ + rt_buf->common.stack_top = config->common.stack_top - 32; + rt_buf->common.boot_mode = config->common.boot_mode; + rt_buf->common.upd_data = &config->fsp_upd; - /* Examples on how to initialize the pointers in UPD region */ - /* fsp_upd->pcd_example = (EXAMPLE_DATA *)&example; */ + /* Override any UPD setting if required */ } diff --git a/arch/x86/cpu/queensbay/irq.c b/arch/x86/cpu/queensbay/irq.c new file mode 100644 index 0000000000..44369f7ec7 --- /dev/null +++ b/arch/x86/cpu/queensbay/irq.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> + * Copyright (C) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pci.h> +#include <asm/arch/device.h> +#include <asm/arch/tnc.h> + +int queensbay_irq_router_probe(struct udevice *dev) +{ + struct tnc_rcba *rcba; + u32 base; + + base = x86_pci_read_config32(TNC_LPC, LPC_RCBA); + base &= ~MEM_BAR_EN; + rcba = (struct tnc_rcba *)base; + + /* Make sure all internal PCI devices are using INTA */ + writel(INTA, &rcba->d02ip); + writel(INTA, &rcba->d03ip); + writel(INTA, &rcba->d27ip); + writel(INTA, &rcba->d31ip); + writel(INTA, &rcba->d23ip); + writel(INTA, &rcba->d24ip); + writel(INTA, &rcba->d25ip); + writel(INTA, &rcba->d26ip); + + /* + * Route TunnelCreek PCI device interrupt pin to PIRQ + * + * Since PCIe downstream ports received INTx are routed to PIRQ + * A/B/C/D directly and not configurable, we have to route PCIe + * root ports' INTx to PIRQ A/B/C/D as well. For other devices + * on TunneCreek, route them to PIRQ E/F/G/H. + */ + writew(PIRQE, &rcba->d02ir); + writew(PIRQF, &rcba->d03ir); + writew(PIRQG, &rcba->d27ir); + writew(PIRQH, &rcba->d31ir); + writew(PIRQA, &rcba->d23ir); + writew(PIRQB, &rcba->d24ir); + writew(PIRQC, &rcba->d25ir); + writew(PIRQD, &rcba->d26ir); + + return irq_router_common_init(dev); +} + +static const struct udevice_id queensbay_irq_router_ids[] = { + { .compatible = "intel,queensbay-irq-router" }, + { } +}; + +U_BOOT_DRIVER(queensbay_irq_router_drv) = { + .name = "queensbay_intel_irq", + .id = UCLASS_IRQ, + .of_match = queensbay_irq_router_ids, + .probe = queensbay_irq_router_probe, +}; diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c index fb81919c21..75f7adb74c 100644 --- a/arch/x86/cpu/queensbay/tnc.c +++ b/arch/x86/cpu/queensbay/tnc.c @@ -69,46 +69,9 @@ int arch_early_init_r(void) return 0; } -void cpu_irq_init(void) -{ - struct tnc_rcba *rcba; - u32 base; - - base = x86_pci_read_config32(TNC_LPC, LPC_RCBA); - base &= ~MEM_BAR_EN; - rcba = (struct tnc_rcba *)base; - - /* Make sure all internal PCI devices are using INTA */ - writel(INTA, &rcba->d02ip); - writel(INTA, &rcba->d03ip); - writel(INTA, &rcba->d27ip); - writel(INTA, &rcba->d31ip); - writel(INTA, &rcba->d23ip); - writel(INTA, &rcba->d24ip); - writel(INTA, &rcba->d25ip); - writel(INTA, &rcba->d26ip); - - /* - * Route TunnelCreek PCI device interrupt pin to PIRQ - * - * Since PCIe downstream ports received INTx are routed to PIRQ - * A/B/C/D directly and not configurable, we have to route PCIe - * root ports' INTx to PIRQ A/B/C/D as well. For other devices - * on TunneCreek, route them to PIRQ E/F/G/H. - */ - writew(PIRQE, &rcba->d02ir); - writew(PIRQF, &rcba->d03ir); - writew(PIRQG, &rcba->d27ir); - writew(PIRQH, &rcba->d31ir); - writew(PIRQA, &rcba->d23ir); - writew(PIRQB, &rcba->d24ir); - writew(PIRQC, &rcba->d25ir); - writew(PIRQD, &rcba->d26ir); -} - int arch_misc_init(void) { unprotect_spi_flash(); - return pirq_init(); + return 0; } diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 5b4ee79d88..485868ff57 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -123,8 +123,9 @@ car_init_ret: #endif /* Set up global data */ mov %esp, %eax - call board_init_f_mem + call board_init_f_alloc_reserve mov %eax, %esp + call board_init_f_init_reserve #ifdef CONFIG_DEBUG_UART call debug_uart_init |