From 49bbdae318e31758cab7ed15aa29abd8ad18de13 Mon Sep 17 00:00:00 2001 From: Tony Wu Date: Sat, 30 May 2015 15:02:39 +0800 Subject: MIPS: fix missing semicolon in cacheops.h Fix missing semicolon in cacheops.h introduced in commit 2b8bcc5a2 (MIPS: avoid .set ISA for cache operations) Signed-off-by: Tony Wu Cc: Paul Burton --- arch/mips/include/asm/cacheops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/mips/include/asm/cacheops.h b/arch/mips/include/asm/cacheops.h index 75ec380980..af2adc701e 100644 --- a/arch/mips/include/asm/cacheops.h +++ b/arch/mips/include/asm/cacheops.h @@ -18,7 +18,7 @@ static inline void mips_cache(int op, const volatile void *addr) #ifdef __GCC_HAVE_BUILTIN_MIPS_CACHE __builtin_mips_cache(op, addr); #else - __asm__ __volatile__("cache %0, %1" : : "i"(op), "R"(addr)) + __asm__ __volatile__("cache %0, %1" : : "i"(op), "R"(addr)); #endif } -- cgit From b11c5d1dc29e81326d1215011d19377737082aeb Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Wed, 1 Jul 2015 16:36:43 +0200 Subject: MIPS: change 'extern inline' to 'static inline' The kernel changed it a long time ago. Also this is now broken on gcc-5.x. Reported-by: Andy Kennedy Signed-off-by: Daniel Schwierzeck --- arch/mips/include/asm/io.h | 12 ++++++------ arch/mips/include/asm/system.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 3fa37f5dd2..a7ab087c0d 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -117,7 +117,7 @@ static inline void set_io_port_base(unsigned long base) * Change virtual addresses to physical addresses and vv. * These are trivial on the 1:1 Linux/MIPS mapping */ -extern inline phys_addr_t virt_to_phys(volatile void * address) +static inline phys_addr_t virt_to_phys(volatile void * address) { #ifndef CONFIG_64BIT return CPHYSADDR(address); @@ -126,7 +126,7 @@ extern inline phys_addr_t virt_to_phys(volatile void * address) #endif } -extern inline void * phys_to_virt(unsigned long address) +static inline void * phys_to_virt(unsigned long address) { #ifndef CONFIG_64BIT return (void *)KSEG0ADDR(address); @@ -138,7 +138,7 @@ extern inline void * phys_to_virt(unsigned long address) /* * IO bus memory addresses are also 1:1 with the physical address */ -extern inline unsigned long virt_to_bus(volatile void * address) +static inline unsigned long virt_to_bus(volatile void * address) { #ifndef CONFIG_64BIT return CPHYSADDR(address); @@ -147,7 +147,7 @@ extern inline unsigned long virt_to_bus(volatile void * address) #endif } -extern inline void * bus_to_virt(unsigned long address) +static inline void * bus_to_virt(unsigned long address) { #ifndef CONFIG_64BIT return (void *)KSEG0ADDR(address); @@ -165,12 +165,12 @@ extern unsigned long isa_slot_offset; extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); #if 0 -extern inline void *ioremap(unsigned long offset, unsigned long size) +static inline void *ioremap(unsigned long offset, unsigned long size) { return __ioremap(offset, size, _CACHE_UNCACHED); } -extern inline void *ioremap_nocache(unsigned long offset, unsigned long size) +static inline void *ioremap_nocache(unsigned long offset, unsigned long size) { return __ioremap(offset, size, _CACHE_UNCACHED); } diff --git a/arch/mips/include/asm/system.h b/arch/mips/include/asm/system.h index 7a2895284e..d56f73b8b8 100644 --- a/arch/mips/include/asm/system.h +++ b/arch/mips/include/asm/system.h @@ -22,7 +22,7 @@ #include #endif -extern __inline__ void +static __inline__ void __sti(void) { __asm__ __volatile__( @@ -46,7 +46,7 @@ __sti(void) * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs * no nops at all. */ -extern __inline__ void +static __inline__ void __cli(void) { __asm__ __volatile__( @@ -207,7 +207,7 @@ do { \ * For 32 and 64 bit operands we can take advantage of ll and sc. * FIXME: This doesn't work for R3000 machines. */ -extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) +static __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) { #ifdef CONFIG_CPU_HAS_LLSC unsigned long dummy; -- cgit From 54afb5002514f88c41f3d462d1e14715a40f4107 Mon Sep 17 00:00:00 2001 From: Vikas Manocha Date: Thu, 2 Jul 2015 18:29:40 -0700 Subject: stv0991: configure clock & pad muxing for qspi stv0991 has cadence qspi controller for flash interfacing, this patch configures the device pads & clock for the controller. Signed-off-by: Vikas Manocha Reviewed-by: Jagannadh Teki --- arch/arm/cpu/armv7/stv0991/clock.c | 4 +++- arch/arm/cpu/armv7/stv0991/pinmux.c | 5 +++++ arch/arm/include/asm/arch-stv0991/stv0991_cgu.h | 15 +++++++++++++++ arch/arm/include/asm/arch-stv0991/stv0991_creg.h | 9 +++++++++ arch/arm/include/asm/arch-stv0991/stv0991_periph.h | 2 ++ 5 files changed, 34 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/cpu/armv7/stv0991/clock.c b/arch/arm/cpu/armv7/stv0991/clock.c index 70b8a8d984..26c0d3637d 100644 --- a/arch/arm/cpu/armv7/stv0991/clock.c +++ b/arch/arm/cpu/armv7/stv0991/clock.c @@ -33,7 +33,9 @@ void clock_setup(int peripheral) /* Clock selection for ethernet tx_clk & rx_clk*/ writel((readl(&stv0991_cgu_regs->eth_ctrl) & ETH_CLK_MASK) | ETH_CLK_CTRL, &stv0991_cgu_regs->eth_ctrl); - + break; + case QSPI_CLOCK_CFG: + writel(QSPI_CLK_CTRL, &stv0991_cgu_regs->qspi_freq); break; default: break; diff --git a/arch/arm/cpu/armv7/stv0991/pinmux.c b/arch/arm/cpu/armv7/stv0991/pinmux.c index 1d086a235d..24c67faaea 100644 --- a/arch/arm/cpu/armv7/stv0991/pinmux.c +++ b/arch/arm/cpu/armv7/stv0991/pinmux.c @@ -55,6 +55,11 @@ int stv0991_pinmux_config(int peripheral) ETH_M_VDD_CFG, &stv0991_creg->vdd_pad1); break; + case QSPI_CS_CLK_PAD: + writel((readl(&stv0991_creg->mux13) & FLASH_CS_NC_MASK) | + CFG_FLASH_CS_NC, &stv0991_creg->mux13); + writel((readl(&stv0991_creg->mux13) & FLASH_CLK_MASK) | + CFG_FLASH_CLK, &stv0991_creg->mux13); default: break; } diff --git a/arch/arm/include/asm/arch-stv0991/stv0991_cgu.h b/arch/arm/include/asm/arch-stv0991/stv0991_cgu.h index ddcbb57a92..f0045f3e04 100644 --- a/arch/arm/include/asm/arch-stv0991/stv0991_cgu.h +++ b/arch/arm/include/asm/arch-stv0991/stv0991_cgu.h @@ -113,4 +113,19 @@ struct stv0991_cgu_regs { #define ETH_CLK_CTRL (ETH_CLK_RX_EXT_PHY << RX_CLK_SHIFT \ | ETH_CLK_TX_EXT_PHY) +/* CGU qspi clock */ +#define DIV_HCLK1_SHIFT 9 +#define DIV_CRYP_SHIFT 6 +#define MDIV_QSPI_SHIFT 3 + +#define CLK_QSPI_OSC 0 +#define CLK_QSPI_MCLK 1 +#define CLK_QSPI_PLL1 2 +#define CLK_QSPI_PLL2 3 + +#define QSPI_CLK_CTRL (3 << DIV_HCLK1_SHIFT \ + | 1 << DIV_CRYP_SHIFT \ + | 0 << MDIV_QSPI_SHIFT \ + | CLK_QSPI_OSC) + #endif diff --git a/arch/arm/include/asm/arch-stv0991/stv0991_creg.h b/arch/arm/include/asm/arch-stv0991/stv0991_creg.h index c804eb5e4c..737c95253b 100644 --- a/arch/arm/include/asm/arch-stv0991/stv0991_creg.h +++ b/arch/arm/include/asm/arch-stv0991/stv0991_creg.h @@ -49,6 +49,15 @@ struct stv0991_creg { u32 vdd_comp1; /* offset 0x400 */ }; +/* CREG MUX 13 register */ +#define FLASH_CS_NC_SHIFT 4 +#define FLASH_CS_NC_MASK ~(7 << FLASH_CS_NC_SHIFT) +#define CFG_FLASH_CS_NC (0 << FLASH_CS_NC_SHIFT) + +#define FLASH_CLK_SHIFT 0 +#define FLASH_CLK_MASK ~(7 << FLASH_CLK_SHIFT) +#define CFG_FLASH_CLK (0 << FLASH_CLK_SHIFT) + /* CREG MUX 12 register */ #define GPIOC_30_MUX_SHIFT 24 #define GPIOC_30_MUX_MASK ~(1 << GPIOC_30_MUX_SHIFT) diff --git a/arch/arm/include/asm/arch-stv0991/stv0991_periph.h b/arch/arm/include/asm/arch-stv0991/stv0991_periph.h index f728c83cb7..725da838b8 100644 --- a/arch/arm/include/asm/arch-stv0991/stv0991_periph.h +++ b/arch/arm/include/asm/arch-stv0991/stv0991_periph.h @@ -18,6 +18,7 @@ enum periph_id { UART_GPIOC_30_31 = 0, UART_GPIOB_16_17, ETH_GPIOB_10_31_C_0_4, + QSPI_CS_CLK_PAD, PERIPH_ID_I2C0, PERIPH_ID_I2C1, PERIPH_ID_I2C2, @@ -39,6 +40,7 @@ enum periph_id { enum periph_clock { UART_CLOCK_CFG = 0, ETH_CLOCK_CFG, + QSPI_CLOCK_CFG, }; #endif /* __ASM_ARM_ARCH_PERIPH_H */ -- cgit From e67abcaacb8271a58c1a5e5afb17475bd8c3deaf Mon Sep 17 00:00:00 2001 From: Vikas Manocha Date: Thu, 2 Jul 2015 18:29:41 -0700 Subject: stv0991: enable cadence qspi controller & spi flash This patch does all the board configurations required to use the qspi controller & attached spi flash memory. Signed-off-by: Vikas Manocha Reviewed-by: Jagannadh Teki --- arch/arm/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 192d9cf3f0..0d2a808fe2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -227,6 +227,9 @@ config TARGET_STV0991 select CPU_V7 select DM select DM_SERIAL + select DM_SPI + select DM_SPI_FLASH + select SPI_FLASH config TARGET_X600 bool "Support x600" -- cgit From 51d558392bc71f9cfb58ce5ea70975dee6bf6292 Mon Sep 17 00:00:00 2001 From: Vikas Manocha Date: Thu, 2 Jul 2015 18:29:42 -0700 Subject: stv0991: configure device tree for cadence qspi & flash This patch add the device tree entry for qspi controller & spi flash memory. Signed-off-by: Vikas Manocha Reviewed-by: Jagannadh Teki --- arch/arm/dts/stv0991.dts | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'arch') diff --git a/arch/arm/dts/stv0991.dts b/arch/arm/dts/stv0991.dts index b25c48bcec..3b1efca373 100644 --- a/arch/arm/dts/stv0991.dts +++ b/arch/arm/dts/stv0991.dts @@ -20,4 +20,38 @@ reg = <0x80406000 0x1000>; clock = <2700000>; }; + + aliases { + spi0 = "/spi@80203000"; /* QSPI */ + }; + + qspi: spi@80203000 { + compatible = "cadence,qspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x80203000 0x100>, + <0x40000000 0x1000000>; + clocks = <3750000>; + ext-decoder = <0>; /* external decoder */ + num-cs = <4>; + fifo-depth = <256>; + bus-num = <0>; + status = "okay"; + + flash0: n25q32@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-flash"; + reg = <0>; /* chip select */ + spi-max-frequency = <50000000>; + m25p,fast-read; + page-size = <256>; + block-size = <16>; /* 2^16, 64KB */ + read-delay = <4>; /* delay value in read data capture register */ + tshsl-ns = <50>; + tsd2d-ns = <50>; + tchsh-ns = <4>; + tslch-ns = <4>; + }; + }; }; -- cgit From 90a2f7171182f3b96c28b2dcff67b02a3164cdb1 Mon Sep 17 00:00:00 2001 From: Vikas Manocha Date: Thu, 2 Jul 2015 18:29:44 -0700 Subject: spi: cadence_qspi: get sram size from device tree sram size could be different on different socs, e.g. on stv0991 it is 256 while on altera platform it is 128. It is better to receive it from device tree. Signed-off-by: Vikas Manocha Tested-by: Stefan Roese Reviewed-by: Jagannadh Teki --- arch/arm/dts/socfpga.dtsi | 1 + arch/arm/dts/stv0991.dts | 1 + 2 files changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/dts/socfpga.dtsi b/arch/arm/dts/socfpga.dtsi index bf791c5dde..9b1242025d 100644 --- a/arch/arm/dts/socfpga.dtsi +++ b/arch/arm/dts/socfpga.dtsi @@ -639,6 +639,7 @@ ext-decoder = <0>; /* external decoder */ num-cs = <4>; fifo-depth = <128>; + sram-size = <128>; bus-num = <2>; status = "disabled"; }; diff --git a/arch/arm/dts/stv0991.dts b/arch/arm/dts/stv0991.dts index 3b1efca373..556df821e4 100644 --- a/arch/arm/dts/stv0991.dts +++ b/arch/arm/dts/stv0991.dts @@ -35,6 +35,7 @@ ext-decoder = <0>; /* external decoder */ num-cs = <4>; fifo-depth = <256>; + sram-size = <256>; bus-num = <0>; status = "okay"; -- cgit From 8097cba809d8c40d8fe72f792c7dc0644c845a32 Mon Sep 17 00:00:00 2001 From: Vikas Manocha Date: Thu, 2 Jul 2015 18:29:46 -0700 Subject: spi: cadence_qspi: add device tree binding doc This patch adds the device tree binding doc for the cadence qspi controller & also removes the not needed properties from the stv0991 device tree. Signed-off-by: Vikas Manocha Reviewed-by: Jagannadh Teki --- arch/arm/dts/stv0991.dts | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/dts/stv0991.dts b/arch/arm/dts/stv0991.dts index 556df821e4..fa3fd641b2 100644 --- a/arch/arm/dts/stv0991.dts +++ b/arch/arm/dts/stv0991.dts @@ -32,11 +32,7 @@ reg = <0x80203000 0x100>, <0x40000000 0x1000000>; clocks = <3750000>; - ext-decoder = <0>; /* external decoder */ - num-cs = <4>; - fifo-depth = <256>; sram-size = <256>; - bus-num = <0>; status = "okay"; flash0: n25q32@0 { @@ -48,7 +44,6 @@ m25p,fast-read; page-size = <256>; block-size = <16>; /* 2^16, 64KB */ - read-delay = <4>; /* delay value in read data capture register */ tshsl-ns = <50>; tsd2d-ns = <50>; tchsh-ns = <4>; -- cgit From 7f1adcd74f9d0dcff8759bd2262ad40c44e1a99d Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 29 Jun 2015 14:58:10 +0200 Subject: arm: mvebu: Add SDIO/SDHCI support for Armada A38x Armada A38x implements an SDHCI compatible SDIO controller. This patch enables the Marvell driver to support this SoC. And enables the SDIO controller if selected by the board configuration. Tested on Marvell DB-88F6820-GP board. Signed-off-by: Stefan Roese Cc: Pantelis Antoniou Cc: Luka Perkov --- arch/arm/mach-mvebu/cpu.c | 11 +++++++++++ arch/arm/mach-mvebu/include/mach/cpu.h | 2 ++ arch/arm/mach-mvebu/include/mach/gpio.h | 10 ++++++++++ arch/arm/mach-mvebu/include/mach/soc.h | 1 + 4 files changed, 24 insertions(+) create mode 100644 arch/arm/mach-mvebu/include/mach/gpio.h (limited to 'arch') diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 0121db8bb5..531d0fb44c 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -10,6 +10,7 @@ #include #include #include +#include #define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) #define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3)) @@ -245,6 +246,16 @@ int cpu_eth_init(bd_t *bis) } #endif +#ifdef CONFIG_MV_SDHCI +int board_mmc_init(bd_t *bis) +{ + mv_sdh_init(MVEBU_SDIO_BASE, 0, 0, + SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD); + + return 0; +} +#endif + #ifndef CONFIG_SYS_DCACHE_OFF void enable_caches(void) { diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h index 3b48460a0b..4bdb6331e1 100644 --- a/arch/arm/mach-mvebu/include/mach/cpu.h +++ b/arch/arm/mach-mvebu/include/mach/cpu.h @@ -114,6 +114,8 @@ void mvebu_sdram_size_adjust(enum memory_bank bank); int mvebu_mbus_probe(struct mbus_win windows[], int count); int mvebu_soc_family(void); +int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks); + /* * Highspeed SERDES PHY config init, ported from bin_hdr * to mainline U-Boot diff --git a/arch/arm/mach-mvebu/include/mach/gpio.h b/arch/arm/mach-mvebu/include/mach/gpio.h new file mode 100644 index 0000000000..09e3c503dd --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/gpio.h @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __MACH_MVEBU_GPIO_H +#define __MACH_MVEBU_GPIO_H + +/* Empty file - sdhci requires this. */ + +#endif diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index 0a9307c8ce..1aeec27aec 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -51,6 +51,7 @@ #define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000)) #define MVEBU_EGIGA0_BASE (MVEBU_REGISTER(0x70000)) #define MVEBU_EGIGA1_BASE (MVEBU_REGISTER(0x74000)) +#define MVEBU_SDIO_BASE (MVEBU_REGISTER(0xd8000)) #define SDRAM_MAX_CS 4 #define SDRAM_ADDR_MASK 0xFF000000 -- cgit From 4d991cb3c74f1aa7742022c37e6627401b9ac030 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 29 Jun 2015 14:58:13 +0200 Subject: arm: mvebu: Add SATA/SCSI (AHCI) support for Armada A38x This patch adds support for the common AHCI controller on the Marvell Armada 38x. Tested on the Marvell DB-88F6820-GP eval board. Signed-off-by: Stefan Roese Cc: Luka Perkov --- arch/arm/mach-mvebu/cpu.c | 55 ++++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/soc.h | 1 + 2 files changed, 56 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c index 531d0fb44c..9bc9f002d8 100644 --- a/arch/arm/mach-mvebu/cpu.c +++ b/arch/arm/mach-mvebu/cpu.c @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include #include @@ -256,6 +258,59 @@ int board_mmc_init(bd_t *bis) } #endif +#ifdef CONFIG_SCSI_AHCI_PLAT +#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0 +#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4 + +#define AHCI_WINDOW_CTRL(win) (0x60 + ((win) << 4)) +#define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4)) +#define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4)) + +static void ahci_mvebu_mbus_config(void __iomem *base) +{ + const struct mbus_dram_target_info *dram; + int i; + + dram = mvebu_mbus_dram_info(); + + for (i = 0; i < 4; i++) { + writel(0, base + AHCI_WINDOW_CTRL(i)); + writel(0, base + AHCI_WINDOW_BASE(i)); + writel(0, base + AHCI_WINDOW_SIZE(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + + writel((cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + base + AHCI_WINDOW_CTRL(i)); + writel(cs->base >> 16, base + AHCI_WINDOW_BASE(i)); + writel(((cs->size - 1) & 0xffff0000), + base + AHCI_WINDOW_SIZE(i)); + } +} + +static void ahci_mvebu_regret_option(void __iomem *base) +{ + /* + * Enable the regret bit to allow the SATA unit to regret a + * request that didn't receive an acknowlegde and avoid a + * deadlock + */ + writel(0x4, base + AHCI_VENDOR_SPECIFIC_0_ADDR); + writel(0x80, base + AHCI_VENDOR_SPECIFIC_0_DATA); +} + +void scsi_init(void) +{ + printf("MVEBU SATA INIT\n"); + ahci_mvebu_mbus_config((void __iomem *)MVEBU_SATA0_BASE); + ahci_mvebu_regret_option((void __iomem *)MVEBU_SATA0_BASE); + ahci_init((void __iomem *)MVEBU_SATA0_BASE); +} +#endif + #ifndef CONFIG_SYS_DCACHE_OFF void enable_caches(void) { diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index 1aeec27aec..e6bfbc25ee 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -51,6 +51,7 @@ #define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000)) #define MVEBU_EGIGA0_BASE (MVEBU_REGISTER(0x70000)) #define MVEBU_EGIGA1_BASE (MVEBU_REGISTER(0x74000)) +#define MVEBU_SATA0_BASE (MVEBU_REGISTER(0xa8000)) #define MVEBU_SDIO_BASE (MVEBU_REGISTER(0xd8000)) #define SDRAM_MAX_CS 4 -- cgit From fe11ae2437e67509b0a0697d932bba10aa686756 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 29 Jun 2015 14:58:15 +0200 Subject: usb: Add EHCI support for Armada 38x (mvebu) This patch adds USB EHCI host support for the common mvebu platform. Including the Armada 38x. Tested on DB-88F6280-GP eval board. Signed-off-by: Stefan Roese Reviewed-by: Marek Vasut Cc: Luka Perkov --- arch/arm/mach-mvebu/include/mach/soc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-mvebu/include/mach/soc.h b/arch/arm/mach-mvebu/include/mach/soc.h index e6bfbc25ee..1aaea672ee 100644 --- a/arch/arm/mach-mvebu/include/mach/soc.h +++ b/arch/arm/mach-mvebu/include/mach/soc.h @@ -49,6 +49,7 @@ #define MVEBU_EGIGA2_BASE (MVEBU_REGISTER(0x30000)) #define MVEBU_EGIGA3_BASE (MVEBU_REGISTER(0x34000)) #define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000)) +#define MVEBU_USB20_BASE (MVEBU_REGISTER(0x58000)) #define MVEBU_EGIGA0_BASE (MVEBU_REGISTER(0x70000)) #define MVEBU_EGIGA1_BASE (MVEBU_REGISTER(0x74000)) #define MVEBU_SATA0_BASE (MVEBU_REGISTER(0xa8000)) -- cgit From 343fb990646cc3d552711bff30bda743de392f08 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 7 Jun 2015 11:33:12 +0800 Subject: x86: Add Kconfig options to be used by arch/x86/cpu/config.mk Add RESET_SEG_START, RESET_SEG_SIZE and RESET_VEC_LOC Kconfig options and make arch/x86/cpu/config.mk use these options. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Andrew Bradford Tested-by: Simon Glass --- arch/x86/Kconfig | 15 +++++++++++++++ arch/x86/cpu/config.mk | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 20083e68c3..e35ae1d9ec 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -69,6 +69,21 @@ config X86_RESET_VECTOR bool default n +config RESET_SEG_START + hex + depends on X86_RESET_VECTOR + default 0xffff0000 + +config RESET_SEG_SIZE + hex + depends on X86_RESET_VECTOR + default 0x10000 + +config RESET_VEC_LOC + hex + depends on X86_RESET_VECTOR + default 0xfffffff0 + config SYS_X86_START16 hex depends on X86_RESET_VECTOR diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk index 4c4d0c7cd2..1263221e69 100644 --- a/arch/x86/cpu/config.mk +++ b/arch/x86/cpu/config.mk @@ -10,8 +10,8 @@ CROSS_COMPILE ?= i386-linux- PLATFORM_CPPFLAGS += -D__I386__ # DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! -LDPPFLAGS += -DRESET_SEG_START=0xffff0000 -LDPPFLAGS += -DRESET_SEG_SIZE=0x10000 -LDPPFLAGS += -DRESET_VEC_LOC=0xfffffff0 +LDPPFLAGS += -DRESET_SEG_START=$(CONFIG_RESET_SEG_START) +LDPPFLAGS += -DRESET_SEG_SIZE=$(CONFIG_RESET_SEG_SIZE) +LDPPFLAGS += -DRESET_VEC_LOC=$(CONFIG_RESET_VEC_LOC) LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16) LDPPFLAGS += -DRESET_BASE="CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE)" -- cgit From 002610f620553bec06e5724052fc5cc5f34eb1e8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 7 Jun 2015 11:33:13 +0800 Subject: x86: fsp: Load GDT before calling FspInitEntry Currently the FSP execution environment GDT is setup by U-Boot in arch/x86/cpu/start16.S, which works pretty well. But if we try to move the FspInitEntry call a little bit later to better fit into U-Boot's initialization sequence, FSP will fail to bring up the AP due to #GP fault as AP's GDT is duplicated from BSP whose GDT is now moved into CAR, and unfortunately FSP calls AP initialization after it disables the CAR. So basically the BSP's GDT still refers to the one in the CAR, whose content is no longer available, so when AP starts up and loads its segment register, it blows up. To resolve this, we load GDT before calling into FspInitEntry. The GDT is the same one used in arch/x86/cpu/start16.S, which is in the ROM and exists forever. Signed-off-by: Bin Meng Tested-by: Andrew Bradford Tested-by: Simon Glass Acked-by: Simon Glass --- arch/x86/cpu/cpu.c | 20 ++++++++++++++++++++ arch/x86/cpu/start16.S | 5 +++-- arch/x86/include/asm/u-boot-x86.h | 7 +++++++ arch/x86/lib/fsp/fsp_support.c | 3 +++ 4 files changed, 33 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index bb4a110c00..b6c585a28f 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -164,6 +164,26 @@ void setup_gdt(gd_t *id, u64 *gdt_addr) load_fs(X86_GDT_ENTRY_32BIT_FS); } +#ifdef CONFIG_HAVE_FSP +/* + * Setup FSP execution environment GDT + * + * Per Intel FSP external architecture specification, before calling any FSP + * APIs, we need make sure the system is in flat 32-bit mode and both the code + * and data selectors should have full 4GB access range. Here we reuse the one + * we used in arch/x86/cpu/start16.S, and reload the segement registers. + */ +void setup_fsp_gdt(void) +{ + load_gdt((const u64 *)(gdt_rom + CONFIG_RESET_SEG_START), 4); + load_ds(X86_GDT_ENTRY_32BIT_DS); + load_ss(X86_GDT_ENTRY_32BIT_DS); + load_es(X86_GDT_ENTRY_32BIT_DS); + load_fs(X86_GDT_ENTRY_32BIT_DS); + load_gs(X86_GDT_ENTRY_32BIT_DS); +} +#endif + int __weak x86_cleanup_before_linux(void) { #ifdef CONFIG_BOOTSTAGE_STASH diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 826e2b4361..5eb17f15c9 100644 --- a/arch/x86/cpu/start16.S +++ b/arch/x86/cpu/start16.S @@ -71,11 +71,12 @@ idt_ptr: */ gdt_ptr: .word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */ - .long BOOT_SEG + gdt /* base */ + .long BOOT_SEG + gdt_rom /* base */ /* Some CPUs are picky about GDT alignment... */ .align 16 -gdt: +.globl gdt_rom +gdt_rom: /* * The GDT table ... * diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index d1d21ed660..3c6ee2914b 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -8,12 +8,19 @@ #ifndef _U_BOOT_I386_H_ #define _U_BOOT_I386_H_ 1 +extern char gdt_rom[]; + /* cpu/.../cpu.c */ int arch_cpu_init(void); int x86_cpu_init_f(void); int cpu_init_f(void); void init_gd(gd_t *id, u64 *gdt_addr); void setup_gdt(gd_t *id, u64 *gdt_addr); +/* + * Setup FSP execution environment GDT to use the one we used in + * arch/x86/cpu/start16.S and reload the segment registers. + */ +void setup_fsp_gdt(void); int init_cache(void); int cleanup_before_linux(void); diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c index 5809235b10..4585166083 100644 --- a/arch/x86/lib/fsp/fsp_support.c +++ b/arch/x86/lib/fsp/fsp_support.c @@ -173,6 +173,9 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) post_code(POST_PRE_MRC); + /* Load GDT for FSP */ + setup_fsp_gdt(); + /* * Use ASM code to ensure the register value in EAX & ECX * will be passed into BlContinuationFunc -- cgit From aefaff8ed83472da5ba96e179231eee665e2d843 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 7 Jun 2015 11:33:14 +0800 Subject: x86: fsp: Move FspInitEntry call to board_init_f() The call to FspInitEntry is done in arch/x86/lib/fsp/fsp_car.S so far. It worked pretty well but looks not that good. Apart from doing too much work than just enabling CAR, it cannot read the configuration data from device tree at that time. Now we want to move it a little bit later as part of init_sequence_f[] being called by board_init_f(). This way it looks and works better in the U-Boot initialization path. Due to FSP's design, after calling FspInitEntry it will not return to its caller, instead it jumps to a continuation function which is given by bootloader with a new stack in system memory. The original stack in the CAR is gone, but its content is perserved by FSP and described by a bootloader temporary memory HOB. Technically we can recover anything we had before in the previous stack, but that is way too complicated. To make life much easier, in the FSP continuation routine we just simply call fsp_init_done() and jump back to car_init_ret() to redo the whole board_init_f() initialization, but this time with a non-zero HOB list pointer saved in U-Boot's global data so that we can bypass the FspInitEntry for the second time. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Andrew Bradford Tested-by: Simon Glass --- arch/x86/cpu/start.S | 6 +++++- arch/x86/include/asm/u-boot-x86.h | 3 +++ arch/x86/lib/fsp/fsp_car.S | 26 +++++--------------------- arch/x86/lib/fsp/fsp_common.c | 8 ++++++++ 4 files changed, 21 insertions(+), 22 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 2e5f9da756..00e585e19b 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -116,12 +116,16 @@ car_init_ret: rep stosb #ifdef CONFIG_HAVE_FSP + test %esi, %esi + jz skip_hob + /* Store HOB list */ movl %esp, %edx addl $GD_HOB_LIST, %edx movl %esi, (%edx) -#endif +skip_hob: +#endif /* Setup first parameter to setup_gdt, pointer to global_data */ movl %esp, %eax diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 3c6ee2914b..4dae365a12 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -56,6 +56,9 @@ u32 isa_map_rom(u32 bus_addr, int size); /* arch/x86/lib/... */ int video_bios_init(void); +/* arch/x86/lib/fsp/... */ +int x86_fsp_init(void); + void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); void board_init_f_r(void) __attribute__ ((noreturn)); diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S index 5e09568b85..afbf3f9baa 100644 --- a/arch/x86/lib/fsp/fsp_car.S +++ b/arch/x86/lib/fsp/fsp_car.S @@ -56,28 +56,10 @@ temp_ram_init_ret: /* stack grows down from top of CAR */ movl %edx, %esp + subl $4, %esp - /* - * TODO: - * - * According to FSP architecture spec, the fsp_init() will not return - * to its caller, instead it requires the bootloader to provide a - * so-called continuation function to pass into the FSP as a parameter - * of fsp_init, and fsp_init() will call that continuation function - * directly. - * - * The call to fsp_init() may need to be moved out of the car_init() - * to cpu_init_f() with the help of some inline assembly codes. - * Note there is another issue that fsp_init() will setup another stack - * using the fsp_init parameter stack_top after DRAM is initialized, - * which means any data on the previous stack (on the CAR) gets lost - * (ie: U-Boot global_data). FSP is supposed to support such scenario, - * however it does not work. This should be revisited in the future. - */ - movl $CONFIG_FSP_TEMP_RAM_ADDR, %eax - xorl %edx, %edx - xorl %ecx, %ecx - call fsp_init + xor %esi, %esi + jmp car_init_done .global fsp_init_done fsp_init_done: @@ -86,6 +68,8 @@ fsp_init_done: * Save eax to esi temporarily. */ movl %eax, %esi + +car_init_done: /* * Re-initialize the ebp (BIST) to zero, as we already reach here * which means we passed BIST testing before. diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 001494d97d..5b256324e1 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -46,3 +46,11 @@ void board_final_cleanup(void) return; } + +int x86_fsp_init(void) +{ + if (!gd->arch.hob_list) + fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, BOOT_FULL_CONFIG, NULL); + + return 0; +} -- cgit From be3f06bcc47e04bfc5fb7c900958918e2d019ef4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 12 Jun 2015 14:52:20 +0800 Subject: x86: dm: Clean up cpu drivers This commit does the following to clean up x86 cpu dm drivers: - Move cpu_x86 driver codes from arch/x86/cpu/cpu.c to a dedicated file arch/x86/cpu/cpu_x86.c - Rename x86_cpu_get_desc() to cpu_x86_get_desc() to keep consistent naming with other dm drivers - Add a new cpu_x86_bind() in the cpu_x86 driver which does exactly the same as the one in the intel baytrail cpu driver - Update intel baytrail cpu driver to use cpu_x86_get_desc() and cpu_x86_bind() Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/Makefile | 2 +- arch/x86/cpu/baytrail/cpu.c | 15 +++---------- arch/x86/cpu/cpu.c | 28 ------------------------ arch/x86/cpu/cpu_x86.c | 48 ++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu.h | 14 ------------ arch/x86/include/asm/cpu_x86.h | 34 ++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 55 deletions(-) create mode 100644 arch/x86/cpu/cpu_x86.c create mode 100644 arch/x86/include/asm/cpu_x86.h (limited to 'arch') diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 7ff05e6628..48197fb0fa 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -10,7 +10,7 @@ extra-y = start.o obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o -obj-y += interrupts.o cpu.o call64.o +obj-y += interrupts.o cpu.o cpu_x86.o call64.o obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c index 1d482064b2..05156a5a7b 100644 --- a/arch/x86/cpu/baytrail/cpu.c +++ b/arch/x86/cpu/baytrail/cpu.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -175,18 +176,8 @@ static int baytrail_get_info(struct udevice *dev, struct cpu_info *info) return 0; } -static int cpu_x86_baytrail_bind(struct udevice *dev) -{ - struct cpu_platdata *plat = dev_get_parent_platdata(dev); - - plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "intel,apic-id", -1); - - return 0; -} - static const struct cpu_ops cpu_x86_baytrail_ops = { - .get_desc = x86_cpu_get_desc, + .get_desc = cpu_x86_get_desc, .get_info = baytrail_get_info, }; @@ -199,7 +190,7 @@ U_BOOT_DRIVER(cpu_x86_baytrail_drv) = { .name = "cpu_x86_baytrail", .id = UCLASS_CPU, .of_match = cpu_x86_baytrail_ids, - .bind = cpu_x86_baytrail_bind, + .bind = cpu_x86_bind, .probe = cpu_x86_baytrail_probe, .ops = &cpu_x86_baytrail_ops, }; diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index b6c585a28f..1dfd9e6d27 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -21,8 +21,6 @@ #include #include -#include -#include #include #include #include @@ -540,16 +538,6 @@ char *cpu_get_name(char *name) return ptr; } -int x86_cpu_get_desc(struct udevice *dev, char *buf, int size) -{ - if (size < CPU_MAX_NAME_LEN) - return -ENOSPC; - - cpu_get_name(buf); - - return 0; -} - int default_print_cpuinfo(void) { printf("CPU: %s, vendor %s, device %xh\n", @@ -642,19 +630,3 @@ int cpu_init_r(void) { return x86_init_cpus(); } - -static const struct cpu_ops cpu_x86_ops = { - .get_desc = x86_cpu_get_desc, -}; - -static const struct udevice_id cpu_x86_ids[] = { - { .compatible = "cpu-x86" }, - { } -}; - -U_BOOT_DRIVER(cpu_x86_drv) = { - .name = "cpu_x86", - .id = UCLASS_CPU, - .of_match = cpu_x86_ids, - .ops = &cpu_x86_ops, -}; diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c new file mode 100644 index 0000000000..d32ba6614e --- /dev/null +++ b/arch/x86/cpu/cpu_x86.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +int cpu_x86_bind(struct udevice *dev) +{ + struct cpu_platdata *plat = dev_get_parent_platdata(dev); + + plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "intel,apic-id", -1); + + return 0; +} + +int cpu_x86_get_desc(struct udevice *dev, char *buf, int size) +{ + if (size < CPU_MAX_NAME_LEN) + return -ENOSPC; + + cpu_get_name(buf); + + return 0; +} + +static const struct cpu_ops cpu_x86_ops = { + .get_desc = cpu_x86_get_desc, +}; + +static const struct udevice_id cpu_x86_ids[] = { + { .compatible = "cpu-x86" }, + { } +}; + +U_BOOT_DRIVER(cpu_x86_drv) = { + .name = "cpu_x86", + .id = UCLASS_CPU, + .of_match = cpu_x86_ids, + .bind = cpu_x86_bind, + .ops = &cpu_x86_ops, +}; diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index ebc74adbc3..08284ee295 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -196,20 +196,6 @@ const char *cpu_vendor_name(int vendor); */ char *cpu_get_name(char *name); -/** - * -* x86_cpu_get_desc() - Get a description string for an x86 CPU -* -* This uses cpu_get_name() and is suitable to use as the get_desc() method for -* the CPU uclass. -* -* @dev: Device to check (UCLASS_CPU) -* @buf: Buffer to place string -* @size: Size of string space -* @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error -*/ -int x86_cpu_get_desc(struct udevice *dev, char *buf, int size); - /** * cpu_call64() - Jump to a 64-bit Linux kernel (internal function) * diff --git a/arch/x86/include/asm/cpu_x86.h b/arch/x86/include/asm/cpu_x86.h new file mode 100644 index 0000000000..19404805c5 --- /dev/null +++ b/arch/x86/include/asm/cpu_x86.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_CPU_X86_H +#define _ASM_CPU_X86_H + +/** + * cpu_x86_bind() - Bind an x86 CPU with the driver + * + * This updates cpu device's platform data with information from device tree, + * like the processor local apic id. + * + * @dev: Device to check (UCLASS_CPU) + * @return 0 always + */ +int cpu_x86_bind(struct udevice *dev); + +/** + * cpu_x86_get_desc() - Get a description string for an x86 CPU + * + * This uses cpu_get_name() and is suitable to use as the get_desc() method for + * the CPU uclass. + * + * @dev: Device to check (UCLASS_CPU) + * @buf: Buffer to place string + * @size: Size of string space + * @return: 0 if OK, -ENOSPC if buffer is too small, other -ve on error + */ +int cpu_x86_get_desc(struct udevice *dev, char *buf, int size); + +#endif /* _ASM_CPU_X86_H */ -- cgit From 063374d2f698162d0cc2d6ea44c8e332c639db0a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 12 Jun 2015 14:52:22 +0800 Subject: x86: kconfig: Make MAX_CPUS and AP_STACK_SIZE depend on SMP MAX_CPUS and AP_STACK_SIZE are only meaningful when SMP is on. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e35ae1d9ec..984a917819 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -237,6 +237,7 @@ config FSP_TEMP_RAM_ADDR config MAX_CPUS int "Maximum number of CPUs permitted" + depends on SMP default 4 help When using multi-CPU chips it is possible for U-Boot to start up @@ -258,6 +259,7 @@ config SMP config AP_STACK_SIZE hex + depends on SMP default 0x1000 help Each additional CPU started by U-Boot requires its own stack. This -- cgit From 4c71322b41a657596ee5e5777393ed83e80139c6 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 12 Jun 2015 14:52:23 +0800 Subject: x86: kconfig: Fix minor nits in MAX_CPUS Move MAX_CPUS definition after SMP so that it shows below SMP in the menuconfig. Also replace the leading spaces in the MAX_CPUS section with tabs to conform coding standard. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/Kconfig | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'arch') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 984a917819..36e97c8048 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -235,18 +235,6 @@ config FSP_TEMP_RAM_ADDR Stack top address which is used in FspInit after DRAM is ready and CAR is disabled. -config MAX_CPUS - int "Maximum number of CPUs permitted" - depends on SMP - default 4 - help - When using multi-CPU chips it is possible for U-Boot to start up - more than one CPU. The stack memory used by all of these CPUs is - pre-allocated so at present U-Boot wants to know the maximum - number of CPUs that may be present. Set this to at least as high - as the number of CPUs in your system (it uses about 4KB of RAM for - each CPU). - config SMP bool "Enable Symmetric Multiprocessing" default n @@ -257,6 +245,18 @@ config SMP only one CPU will be enabled regardless of the number of CPUs available. +config MAX_CPUS + int "Maximum number of CPUs permitted" + depends on SMP + default 4 + help + When using multi-CPU chips it is possible for U-Boot to start up + more than one CPU. The stack memory used by all of these CPUs is + pre-allocated so at present U-Boot wants to know the maximum + number of CPUs that may be present. Set this to at least as high + as the number of CPUs in your system (it uses about 4KB of RAM for + each CPU). + config AP_STACK_SIZE hex depends on SMP -- cgit From 946c2b5259823ca6935a62e1a68b6e29a74e33f0 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:35 +0800 Subject: x86: ivybridge: Remove SMP from CPU_SPECIFIC_OPTIONS Ivybridge is not ready for U-Boot MP initialization yet. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/ivybridge/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/x86/cpu/ivybridge/Kconfig b/arch/x86/cpu/ivybridge/Kconfig index e4595be3ae..0e249a40a6 100644 --- a/arch/x86/cpu/ivybridge/Kconfig +++ b/arch/x86/cpu/ivybridge/Kconfig @@ -95,7 +95,6 @@ config CPU_SPECIFIC_OPTIONS select ARCH_BOOTBLOCK_X86_32 select ARCH_ROMSTAGE_X86_32 select ARCH_RAMSTAGE_X86_32 - select SMP select SSE2 select UDELAY_LAPIC select CPU_MICROCODE_IN_CBFS -- cgit From 6e6f4ce4f82501e35301322872152fe28846d743 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:36 +0800 Subject: x86: Move MP initialization codes into a common place Most of the MP initialization codes in arch/x86/cpu/baytrail/cpu.c is common to all x86 processors, except detect_num_cpus() which varies from cpu to cpu. Move these to arch/x86/cpu/cpu.c and implement the new 'get_count' method for baytrail and cpu_x86 drivers. Now we call cpu_get_count() in mp_init() to get the number of CPUs. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/baytrail/cpu.c | 98 ++++++++++++++------------------------------- arch/x86/cpu/cpu.c | 40 ++++++++++++++++++ arch/x86/cpu/cpu_x86.c | 28 +++++++++++++ arch/x86/cpu/mp_init.c | 18 +++++++-- arch/x86/include/asm/mp.h | 1 - 5 files changed, 112 insertions(+), 73 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c index 05156a5a7b..a0117308ae 100644 --- a/arch/x86/cpu/baytrail/cpu.c +++ b/arch/x86/cpu/baytrail/cpu.c @@ -12,78 +12,9 @@ #include #include #include -#include #include #include -#ifdef CONFIG_SMP -static int enable_smis(struct udevice *cpu, void *unused) -{ - return 0; -} - -static struct mp_flight_record mp_steps[] = { - MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), - /* Wait for APs to finish initialization before proceeding. */ - MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), -}; - -static int detect_num_cpus(void) -{ - int ecx = 0; - - /* - * Use the algorithm described in Intel 64 and IA-32 Architectures - * Software Developer's Manual Volume 3 (3A, 3B & 3C): System - * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping - * of CPUID Extended Topology Leaf. - */ - while (1) { - struct cpuid_result leaf_b; - - leaf_b = cpuid_ext(0xb, ecx); - - /* - * Bay Trail doesn't have hyperthreading so just determine the - * number of cores by from level type (ecx[15:8] == * 2) - */ - if ((leaf_b.ecx & 0xff00) == 0x0200) - return leaf_b.ebx & 0xffff; - ecx++; - } -} - -static int baytrail_init_cpus(void) -{ - struct mp_params mp_params; - - lapic_setup(); - - mp_params.num_cpus = detect_num_cpus(); - mp_params.parallel_microcode_load = 0, - mp_params.flight_plan = &mp_steps[0]; - mp_params.num_records = ARRAY_SIZE(mp_steps); - mp_params.microcode_pointer = 0; - - if (mp_init(&mp_params)) { - printf("Warning: MP init failure\n"); - return -EIO; - } - - return 0; -} -#endif - -int x86_init_cpus(void) -{ -#ifdef CONFIG_SMP - debug("Init additional CPUs\n"); - baytrail_init_cpus(); -#endif - - return 0; -} - static void set_max_freq(void) { msr_t perf_ctl; @@ -176,9 +107,38 @@ static int baytrail_get_info(struct udevice *dev, struct cpu_info *info) return 0; } +static int baytrail_get_count(struct udevice *dev) +{ + int ecx = 0; + + /* + * Use the algorithm described in Intel 64 and IA-32 Architectures + * Software Developer's Manual Volume 3 (3A, 3B & 3C): System + * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping + * of CPUID Extended Topology Leaf. + */ + while (1) { + struct cpuid_result leaf_b; + + leaf_b = cpuid_ext(0xb, ecx); + + /* + * Bay Trail doesn't have hyperthreading so just determine the + * number of cores by from level type (ecx[15:8] == * 2) + */ + if ((leaf_b.ecx & 0xff00) == 0x0200) + return leaf_b.ebx & 0xffff; + + ecx++; + } + + return 0; +} + static const struct cpu_ops cpu_x86_baytrail_ops = { .get_desc = cpu_x86_get_desc, .get_info = baytrail_get_info, + .get_count = baytrail_get_count, }; static const struct udevice_id cpu_x86_baytrail_ids[] = { diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 1dfd9e6d27..a6e88cfe19 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -21,10 +21,13 @@ #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -621,8 +624,45 @@ int last_stage_init(void) } #endif +#ifdef CONFIG_SMP +static int enable_smis(struct udevice *cpu, void *unused) +{ + return 0; +} + +static struct mp_flight_record mp_steps[] = { + MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), + /* Wait for APs to finish initialization before proceeding */ + MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), +}; + +static int x86_mp_init(void) +{ + struct mp_params mp_params; + + lapic_setup(); + + mp_params.parallel_microcode_load = 0, + mp_params.flight_plan = &mp_steps[0]; + mp_params.num_records = ARRAY_SIZE(mp_steps); + mp_params.microcode_pointer = 0; + + if (mp_init(&mp_params)) { + printf("Warning: MP init failure\n"); + return -EIO; + } + + return 0; +} +#endif + __weak int x86_init_cpus(void) { +#ifdef CONFIG_SMP + debug("Init additional CPUs\n"); + x86_mp_init(); +#endif + return 0; } diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c index d32ba6614e..09410416a1 100644 --- a/arch/x86/cpu/cpu_x86.c +++ b/arch/x86/cpu/cpu_x86.c @@ -10,6 +10,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + int cpu_x86_bind(struct udevice *dev) { struct cpu_platdata *plat = dev_get_parent_platdata(dev); @@ -30,8 +32,34 @@ int cpu_x86_get_desc(struct udevice *dev, char *buf, int size) return 0; } +static int cpu_x86_get_count(struct udevice *dev) +{ + int node, cpu; + int num = 0; + + node = fdt_path_offset(gd->fdt_blob, "/cpus"); + if (node < 0) + return -ENOENT; + + for (cpu = fdt_first_subnode(gd->fdt_blob, node); + cpu >= 0; + cpu = fdt_next_subnode(gd->fdt_blob, cpu)) { + const char *device_type; + + device_type = fdt_getprop(gd->fdt_blob, cpu, + "device_type", NULL); + if (!device_type) + continue; + if (strcmp(device_type, "cpu") == 0) + num++; + } + + return num; +} + static const struct cpu_ops cpu_x86_ops = { .get_desc = cpu_x86_get_desc, + .get_count = cpu_x86_get_count, }; static const struct udevice_id cpu_x86_ids[] = { diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index ac5753a1fd..5564d84e17 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -22,6 +22,9 @@ #include #include +/* Total CPUs include BSP */ +static int num_cpus; + /* This also needs to match the sipi.S assembly code for saved MSR encoding */ struct saved_msr { uint32_t index; @@ -383,7 +386,7 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params) int ret = 0; const int timeout_us = 100000; const int step_us = 100; - int num_aps = mp_params->num_cpus - 1; + int num_aps = num_cpus - 1; for (i = 0; i < mp_params->num_records; i++) { struct mp_flight_record *rec = &mp_params->flight_plan[i]; @@ -451,7 +454,16 @@ int mp_init(struct mp_params *p) return -1; } - ret = check_cpu_devices(p->num_cpus); + num_cpus = cpu_get_count(cpu); + if (num_cpus < 0) { + debug("Cannot get number of CPUs: err=%d\n", num_cpus); + return num_cpus; + } + + if (num_cpus < 2) + debug("Warning: Only 1 CPU is detected\n"); + + ret = check_cpu_devices(num_cpus); if (ret) debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n"); @@ -471,7 +483,7 @@ int mp_init(struct mp_params *p) wbinvd(); /* Start the APs providing number of APs and the cpus_entered field */ - num_aps = p->num_cpus - 1; + num_aps = num_cpus - 1; ret = start_aps(num_aps, ap_count); if (ret) { mdelay(1000); diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index c0930fd0c6..2e6c3120c7 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -59,7 +59,6 @@ struct mp_flight_record { * SMM support. */ struct mp_params { - int num_cpus; /* Total cpus include BSP */ int parallel_microcode_load; const void *microcode_pointer; /* Flight plan for APs and BSP */ -- cgit From 61788e468ebe4a7b8c852ab4e761e084a7975a93 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:37 +0800 Subject: x86: Move lapic_setup() call into init_bsp() Currently lapic_setup() is called before calling mp_init(), which then calls init_bsp() where it calls enable_lapic(), which was already enabled in lapic_setup(). Hence move lapic_setup() call into init_bsp() to avoid the duplication. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/cpu.c | 2 -- arch/x86/cpu/mp_init.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index a6e88cfe19..d108ee5c4e 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -640,8 +640,6 @@ static int x86_mp_init(void) { struct mp_params mp_params; - lapic_setup(); - mp_params.parallel_microcode_load = 0, mp_params.flight_plan = &mp_steps[0]; mp_params.num_records = ARRAY_SIZE(mp_steps); diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 5564d84e17..e8bc9b6d04 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -418,7 +418,7 @@ static int init_bsp(struct udevice **devp) cpu_get_name(processor_name); debug("CPU: %s.\n", processor_name); - enable_lapic(); + lapic_setup(); apic_id = lapicid(); ret = find_cpu_by_apid_id(apic_id, devp); -- cgit From 63d54a67051e3e03b8a46b5442b65323d18ddb98 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:38 +0800 Subject: x86: Clean up lapic codes This commit cleans up the lapic codes: - Delete arch/x86/include/asm/lapic_def.h, and move register and bit defines into arch/x86/include/asm/lapic.h - Use MSR defines from msr-index.h in enable_lapic() and disable_lapic() - Remove unnecessary stuff like NEED_LAPIC, X86_GOOD_APIC and CONFIG_AP_IN_SIPI_WAIT - Move struct x86_cpu_priv defines to asm/arch-ivybridge/bd82x6x.h, as it is not apic related and only used by ivybridge - Fix coding convention issues Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/ivybridge/model_206ax.c | 2 +- arch/x86/cpu/lapic.c | 38 ++++---- arch/x86/include/asm/arch-ivybridge/bd82x6x.h | 14 ++- arch/x86/include/asm/lapic.h | 131 ++++++++++++++------------ arch/x86/include/asm/lapic_def.h | 101 -------------------- 5 files changed, 103 insertions(+), 183 deletions(-) delete mode 100644 arch/x86/include/asm/lapic_def.h (limited to 'arch') diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 8b08c40bcb..fd7db97cbd 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -13,12 +13,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include static void enable_vmx(void) diff --git a/arch/x86/cpu/lapic.c b/arch/x86/cpu/lapic.c index 4690603c75..6769ae53ae 100644 --- a/arch/x86/cpu/lapic.c +++ b/arch/x86/cpu/lapic.c @@ -8,50 +8,46 @@ */ #include -#include -#include #include #include void lapic_setup(void) { -#if NEED_LAPIC == 1 +#ifdef CONFIG_SMP /* Only Pentium Pro and later have those MSR stuff */ debug("Setting up local apic: "); /* Enable the local apic */ enable_lapic(); - /* - * Set Task Priority to 'accept all'. - */ + /* Set Task Priority to 'accept all' */ lapic_write_around(LAPIC_TASKPRI, lapic_read_around(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); /* Put the local apic in virtual wire mode */ lapic_write_around(LAPIC_SPIV, (lapic_read_around(LAPIC_SPIV) & - ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); + ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); lapic_write_around(LAPIC_LVT0, (lapic_read_around(LAPIC_LVT0) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_EXTINT)); + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_EXTINT)); lapic_write_around(LAPIC_LVT1, (lapic_read_around(LAPIC_LVT1) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_NMI)); + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_NMI)); debug("apic_id: 0x%02lx, ", lapicid()); -#else /* !NEED_LLAPIC */ +#else /* !CONFIG_SMP */ /* Only Pentium Pro and later have those MSR stuff */ debug("Disabling local apic: "); disable_lapic(); -#endif /* !NEED_LAPIC */ +#endif /* CONFIG_SMP */ debug("done.\n"); post_code(POST_LAPIC); } diff --git a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h index 5ae32f7883..7786493be7 100644 --- a/arch/x86/include/asm/arch-ivybridge/bd82x6x.h +++ b/arch/x86/include/asm/arch-ivybridge/bd82x6x.h @@ -16,7 +16,19 @@ int gma_func0_init(pci_dev_t dev, struct pci_controller *hose, const void *blob, int node); int bd82x6x_init(void); -struct x86_cpu_priv; +/** + * struct x86_cpu_priv - Information about a single CPU + * + * @apic_id: Advanced Programmable Interrupt Controller Identifier, which is + * just a number representing the CPU core + * + * TODO: Move this to driver model once lifecycle is understood + */ +struct x86_cpu_priv { + int apic_id; + int start_err; +}; + int model_206ax_init(struct x86_cpu_priv *cpu); #endif diff --git a/arch/x86/include/asm/lapic.h b/arch/x86/include/asm/lapic.h index 0a7f443195..f60974a878 100644 --- a/arch/x86/include/asm/lapic.h +++ b/arch/x86/include/asm/lapic.h @@ -1,5 +1,5 @@ /* - * From Coreboot file of same name + * From coreboot file of same name * * Copyright (C) 2014 Google, Inc * @@ -10,16 +10,61 @@ #define _ARCH_ASM_LAPIC_H #include -#include #include +#include #include -/* See if I need to initialize the local apic */ -#if CONFIG_SMP || CONFIG_IOAPIC -# define NEED_LAPIC 1 -#else -# define NEED_LAPIC 0 -#endif +#define LAPIC_DEFAULT_BASE 0xfee00000 + +#define LAPIC_ID 0x020 +#define LAPIC_LVR 0x030 + +#define LAPIC_TASKPRI 0x080 +#define LAPIC_TPRI_MASK 0xff + +#define LAPIC_RRR 0x0c0 + +#define LAPIC_SPIV 0x0f0 +#define LAPIC_SPIV_ENABLE 0x100 + +#define LAPIC_ICR 0x300 +#define LAPIC_DEST_SELF 0x40000 +#define LAPIC_DEST_ALLINC 0x80000 +#define LAPIC_DEST_ALLBUT 0xc0000 +#define LAPIC_ICR_RR_MASK 0x30000 +#define LAPIC_ICR_RR_INVALID 0x00000 +#define LAPIC_ICR_RR_INPROG 0x10000 +#define LAPIC_ICR_RR_VALID 0x20000 +#define LAPIC_INT_LEVELTRIG 0x08000 +#define LAPIC_INT_ASSERT 0x04000 +#define LAPIC_ICR_BUSY 0x01000 +#define LAPIC_DEST_LOGICAL 0x00800 +#define LAPIC_DM_FIXED 0x00000 +#define LAPIC_DM_LOWEST 0x00100 +#define LAPIC_DM_SMI 0x00200 +#define LAPIC_DM_REMRD 0x00300 +#define LAPIC_DM_NMI 0x00400 +#define LAPIC_DM_INIT 0x00500 +#define LAPIC_DM_STARTUP 0x00600 +#define LAPIC_DM_EXTINT 0x00700 +#define LAPIC_VECTOR_MASK 0x000ff + +#define LAPIC_ICR2 0x310 +#define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xff) +#define SET_LAPIC_DEST_FIELD(x) ((x) << 24) + +#define LAPIC_LVT0 0x350 +#define LAPIC_LVT1 0x360 +#define LAPIC_LVT_MASKED (1 << 16) +#define LAPIC_LVT_LEVEL_TRIGGER (1 << 15) +#define LAPIC_LVT_REMOTE_IRR (1 << 14) +#define LAPIC_INPUT_POLARITY (1 << 13) +#define LAPIC_SEND_PENDING (1 << 12) +#define LAPIC_LVT_RESERVED_1 (1 << 11) +#define LAPIC_DELIVERY_MODE_MASK (7 << 8) +#define LAPIC_DELIVERY_MODE_FIXED (0 << 8) +#define LAPIC_DELIVERY_MODE_NMI (4 << 8) +#define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) static inline __attribute__((always_inline)) unsigned long lapic_read(unsigned long reg) @@ -42,21 +87,21 @@ static inline void enable_lapic(void) { msr_t msr; - msr = msr_read(LAPIC_BASE_MSR); + msr = msr_read(MSR_IA32_APICBASE); msr.hi &= 0xffffff00; - msr.lo |= LAPIC_BASE_MSR_ENABLE; - msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK; + msr.lo |= MSR_IA32_APICBASE_ENABLE; + msr.lo &= ~MSR_IA32_APICBASE_BASE; msr.lo |= LAPIC_DEFAULT_BASE; - msr_write(LAPIC_BASE_MSR, msr); + msr_write(MSR_IA32_APICBASE, msr); } static inline void disable_lapic(void) { msr_t msr; - msr = msr_read(LAPIC_BASE_MSR); - msr.lo &= ~(1 << 11); - msr_write(LAPIC_BASE_MSR, msr); + msr = msr_read(MSR_IA32_APICBASE); + msr.lo &= ~MSR_IA32_APICBASE_ENABLE; + msr_write(MSR_IA32_APICBASE, msr); } static inline __attribute__((always_inline)) unsigned long lapicid(void) @@ -64,30 +109,24 @@ static inline __attribute__((always_inline)) unsigned long lapicid(void) return lapic_read(LAPIC_ID) >> 24; } -#if !CONFIG_AP_IN_SIPI_WAIT -/* If we need to go back to sipi wait, we use the long non-inlined version of - * this function in lapic_cpu_init.c - */ static inline __attribute__((always_inline)) void stop_this_cpu(void) { /* Called by an AP when it is ready to halt and wait for a new task */ for (;;) cpu_hlt(); } -#else -void stop_this_cpu(void); -#endif -#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ - sizeof(*(ptr)))) +#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ + sizeof(*(ptr)))) -struct __xchg_dummy { unsigned long a[100]; }; -#define __xg(x) ((struct __xchg_dummy *)(x)) +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) /* - * Note: no "lock" prefix even on SMP: xchg always implies lock anyway + * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. + * * Note 2: xchg has side effect, so that attribute volatile is necessary, - * but generally the primitive is invalid, *ptr is output argument. --ANK + * but generally the primitive is invalid, *ptr is output argument. */ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) @@ -121,25 +160,19 @@ static inline void lapic_write_atomic(unsigned long reg, unsigned long v) (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); } - -#ifdef X86_GOOD_APIC -# define FORCE_READ_AROUND_WRITE 0 -# define lapic_read_around(x) lapic_read(x) -# define lapic_write_around(x, y) lapic_write((x), (y)) -#else -# define FORCE_READ_AROUND_WRITE 1 -# define lapic_read_around(x) lapic_read(x) -# define lapic_write_around(x, y) lapic_write_atomic((x), (y)) -#endif +#define lapic_read_around(x) lapic_read(x) +#define lapic_write_around(x, y) lapic_write_atomic((x), (y)) static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) { int timeout; unsigned long status; int result; + lapic_wait_icr_idle(); lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); + timeout = 0; do { status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; @@ -150,30 +183,10 @@ static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) *pvalue = lapic_read(LAPIC_RRR); result = 0; } + return result; } - void lapic_setup(void); -#if CONFIG_SMP -struct device; -int start_cpu(struct device *cpu); -#endif /* CONFIG_SMP */ - -int boot_cpu(void); - -/** - * struct x86_cpu_priv - Information about a single CPU - * - * @apic_id: Advanced Programmable Interrupt Controller Identifier, which is - * just a number representing the CPU core - * - * TODO: Move this to driver model once lifecycle is understood - */ -struct x86_cpu_priv { - int apic_id; - int start_err; -}; - #endif diff --git a/arch/x86/include/asm/lapic_def.h b/arch/x86/include/asm/lapic_def.h deleted file mode 100644 index 722ceadaa4..0000000000 --- a/arch/x86/include/asm/lapic_def.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Taken from the Coreboot file of the same name - * - * (C) Copyright 2014 Google, Inc - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#ifndef _ASM_LAPIC_DEF_H -#define _ASM_LAPIC_DEF_H - -#define LAPIC_BASE_MSR 0x1B -#define LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8) -#define LAPIC_BASE_MSR_ENABLE (1 << 11) -#define LAPIC_BASE_MSR_ADDR_MASK 0xFFFFF000 - -#define LOCAL_APIC_ADDR 0xfee00000 -#define LAPIC_DEFAULT_BASE LOCAL_APIC_ADDR - -#define LAPIC_ID 0x020 -#define LAPIC_LVR 0x030 -#define LAPIC_TASKPRI 0x80 -#define LAPIC_TPRI_MASK 0xFF -#define LAPIC_ARBID 0x090 -#define LAPIC_RRR 0x0C0 -#define LAPIC_SVR 0x0f0 -#define LAPIC_SPIV 0x0f0 -#define LAPIC_SPIV_ENABLE 0x100 -#define LAPIC_ESR 0x280 -#define LAPIC_ESR_SEND_CS 0x00001 -#define LAPIC_ESR_RECV_CS 0x00002 -#define LAPIC_ESR_SEND_ACC 0x00004 -#define LAPIC_ESR_RECV_ACC 0x00008 -#define LAPIC_ESR_SENDILL 0x00020 -#define LAPIC_ESR_RECVILL 0x00040 -#define LAPIC_ESR_ILLREGA 0x00080 -#define LAPIC_ICR 0x300 -#define LAPIC_DEST_SELF 0x40000 -#define LAPIC_DEST_ALLINC 0x80000 -#define LAPIC_DEST_ALLBUT 0xC0000 -#define LAPIC_ICR_RR_MASK 0x30000 -#define LAPIC_ICR_RR_INVALID 0x00000 -#define LAPIC_ICR_RR_INPROG 0x10000 -#define LAPIC_ICR_RR_VALID 0x20000 -#define LAPIC_INT_LEVELTRIG 0x08000 -#define LAPIC_INT_ASSERT 0x04000 -#define LAPIC_ICR_BUSY 0x01000 -#define LAPIC_DEST_LOGICAL 0x00800 -#define LAPIC_DM_FIXED 0x00000 -#define LAPIC_DM_LOWEST 0x00100 -#define LAPIC_DM_SMI 0x00200 -#define LAPIC_DM_REMRD 0x00300 -#define LAPIC_DM_NMI 0x00400 -#define LAPIC_DM_INIT 0x00500 -#define LAPIC_DM_STARTUP 0x00600 -#define LAPIC_DM_EXTINT 0x00700 -#define LAPIC_VECTOR_MASK 0x000FF -#define LAPIC_ICR2 0x310 -#define GET_LAPIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) -#define SET_LAPIC_DEST_FIELD(x) ((x) << 24) -#define LAPIC_LVTT 0x320 -#define LAPIC_LVTPC 0x340 -#define LAPIC_LVT0 0x350 -#define LAPIC_LVT_TIMER_BASE_MASK (0x3 << 18) -#define GET_LAPIC_TIMER_BASE(x) (((x) >> 18) & 0x3) -#define SET_LAPIC_TIMER_BASE(x) (((x) << 18)) -#define LAPIC_TIMER_BASE_CLKIN 0x0 -#define LAPIC_TIMER_BASE_TMBASE 0x1 -#define LAPIC_TIMER_BASE_DIV 0x2 -#define LAPIC_LVT_TIMER_PERIODIC (1 << 17) -#define LAPIC_LVT_MASKED (1 << 16) -#define LAPIC_LVT_LEVEL_TRIGGER (1 << 15) -#define LAPIC_LVT_REMOTE_IRR (1 << 14) -#define LAPIC_INPUT_POLARITY (1 << 13) -#define LAPIC_SEND_PENDING (1 << 12) -#define LAPIC_LVT_RESERVED_1 (1 << 11) -#define LAPIC_DELIVERY_MODE_MASK (7 << 8) -#define LAPIC_DELIVERY_MODE_FIXED (0 << 8) -#define LAPIC_DELIVERY_MODE_NMI (4 << 8) -#define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) -#define GET_LAPIC_DELIVERY_MODE(x) (((x) >> 8) & 0x7) -#define SET_LAPIC_DELIVERY_MODE(x, y) (((x) & ~0x700)|((y) << 8)) -#define LAPIC_MODE_FIXED 0x0 -#define LAPIC_MODE_NMI 0x4 -#define LAPIC_MODE_EXINT 0x7 -#define LAPIC_LVT1 0x360 -#define LAPIC_LVTERR 0x370 -#define LAPIC_TMICT 0x380 -#define LAPIC_TMCCT 0x390 -#define LAPIC_TDCR 0x3E0 -#define LAPIC_TDR_DIV_TMBASE (1 << 2) -#define LAPIC_TDR_DIV_1 0xB -#define LAPIC_TDR_DIV_2 0x0 -#define LAPIC_TDR_DIV_4 0x1 -#define LAPIC_TDR_DIV_8 0x2 -#define LAPIC_TDR_DIV_16 0x3 -#define LAPIC_TDR_DIV_32 0x8 -#define LAPIC_TDR_DIV_64 0x9 -#define LAPIC_TDR_DIV_128 0xA - -#endif -- cgit From 990acd0d5165c3ca36716e01c5c182423bdfc16a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 17 Jun 2015 11:15:39 +0800 Subject: x86: crownbay: Add MP initialization Intel Crown Bay board has a TunnelCreek processor which supports hyper-threading. Add /cpus node in the crownbay.dts and enable the MP initialization. Signed-off-by: Bin Meng Acked-by: Simon Glass Signed-off-by: Simon Glass (modified to remove error: overriding the value of OF_CONTROL. Old value: "y", new value: "y") --- arch/x86/dts/crownbay.dts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'arch') diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index d68efda8df..1ec90cda18 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -23,6 +23,26 @@ silent_console = <0>; }; + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "cpu-x86"; + reg = <0>; + intel,apic-id = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "cpu-x86"; + reg = <1>; + intel,apic-id = <1>; + }; + + }; + gpioa { compatible = "intel,ich6-gpio"; u-boot,dm-pre-reloc; -- cgit From b0014b6423574780cdcb9a76478be0c1f83f7990 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:43 +0800 Subject: x86: crownbay: Enable DM RTC support Add a RTC node in the device tree to enable DM RTC support. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/dts/crownbay.dts | 1 + arch/x86/dts/rtc.dtsi | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 arch/x86/dts/rtc.dtsi (limited to 'arch') diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index 1ec90cda18..87ed0f4f19 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -10,6 +10,7 @@ /include/ "skeleton.dtsi" /include/ "serial.dtsi" +/include/ "rtc.dtsi" / { model = "Intel Crown Bay"; diff --git a/arch/x86/dts/rtc.dtsi b/arch/x86/dts/rtc.dtsi new file mode 100644 index 0000000000..93dacd7307 --- /dev/null +++ b/arch/x86/dts/rtc.dtsi @@ -0,0 +1,6 @@ +/ { + rtc { + compatible = "motorola,mc146818"; + reg = <0x70 2>; + }; +}; -- cgit From d402f922b291bb76e7e3b5c15dda7abf1ce33b85 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:44 +0800 Subject: x86: queensbay: Correct Topcliff device irqs There are 4 usb ports on the Intel Crown Bay board, 2 of which are connected to Topcliff usb host 0 and the other 2 connected to usb host 1. USB devices inserted in the ports connected to usb host 1 cannot get detected due to wrong IRQ assigned to the controller. Actually we need apply the PCI interrupt pin swizzling logic to all devices on the Topcliff chipset when configuring the PIRQ routing. This was observed on usb ports, but device 6 and 10 irqs are also wrong. Correct them all together. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/dts/crownbay.dts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'arch') diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index 87ed0f4f19..b77c65a463 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -180,29 +180,29 @@ * Note on the Crown Bay board, Topcliff chipset * is connected to TunnelCreek PCIe port 0, so * its bus number is 1 for its PCIe port and 2 - * for its PCI devices per U-Boot currnet PCI + * for its PCI devices per U-Boot current PCI * bus enumeration algorithm. */ PCI_BDF(1, 0, 0) INTA PIRQA PCI_BDF(2, 0, 1) INTA PIRQA PCI_BDF(2, 0, 2) INTA PIRQA - PCI_BDF(2, 2, 0) INTB PIRQB - PCI_BDF(2, 2, 1) INTB PIRQB - PCI_BDF(2, 2, 2) INTB PIRQB - PCI_BDF(2, 2, 3) INTB PIRQB - PCI_BDF(2, 2, 4) INTB PIRQB + PCI_BDF(2, 2, 0) INTB PIRQD + PCI_BDF(2, 2, 1) INTB PIRQD + PCI_BDF(2, 2, 2) INTB PIRQD + PCI_BDF(2, 2, 3) INTB PIRQD + PCI_BDF(2, 2, 4) INTB PIRQD PCI_BDF(2, 4, 0) INTC PIRQC PCI_BDF(2, 4, 1) INTC PIRQC - PCI_BDF(2, 6, 0) INTD PIRQD + PCI_BDF(2, 6, 0) INTD PIRQB PCI_BDF(2, 8, 0) INTA PIRQA PCI_BDF(2, 8, 1) INTA PIRQA PCI_BDF(2, 8, 2) INTA PIRQA PCI_BDF(2, 8, 3) INTA PIRQA - PCI_BDF(2, 10, 0) INTB PIRQB - PCI_BDF(2, 10, 1) INTB PIRQB - PCI_BDF(2, 10, 2) INTB PIRQB - PCI_BDF(2, 10, 3) INTB PIRQB - PCI_BDF(2, 10, 4) INTB PIRQB + PCI_BDF(2, 10, 0) INTB PIRQD + PCI_BDF(2, 10, 1) INTB PIRQD + PCI_BDF(2, 10, 2) INTB PIRQD + PCI_BDF(2, 10, 3) INTB PIRQD + PCI_BDF(2, 10, 4) INTB PIRQD PCI_BDF(2, 12, 0) INTC PIRQC PCI_BDF(2, 12, 1) INTC PIRQC PCI_BDF(2, 12, 2) INTC PIRQC -- cgit From 9c235436a3fbc8d6959c0acee276b7060e61f2e5 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:45 +0800 Subject: x86: Write correct bus number for the irq router We should write correct bus number to the PIRQ routing table for the irq router from device tree, instead of hard-coded zero. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 74b89ad2ff..7d5ccc1c65 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -161,7 +161,7 @@ static int create_pirq_routing_table(void) /* Populate the PIRQ table fields */ rt->signature = PIRQ_SIGNATURE; rt->version = PIRQ_VERSION; - rt->rtr_bus = 0; + rt->rtr_bus = PCI_BUS(irq_router.bdf); rt->rtr_devfn = (PCI_DEV(irq_router.bdf) << 3) | PCI_FUNC(irq_router.bdf); rt->rtr_vendor = PCI_VENDOR_ID_INTEL; -- cgit From 8c38e4d0b8d37dcd3bfd2293481e220b1b4a3a42 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:46 +0800 Subject: x86: Ignore function number when writing PIRQ routing table In fill_irq_info() pci device's function number is written into the table, however this is not really necessary. The function number can be anything as OS doesn't care about this field, neither does the PIRQ routing specification. Change to always writing 0 as the function number. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/irq.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 7d5ccc1c65..df4300c230 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -59,12 +59,12 @@ void pirq_assign_irq(int link, u8 irq) } static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus, - u8 device, u8 func, u8 pin, u8 pirq) + u8 device, u8 pin, u8 pirq) { struct irq_info *slot = *slotp; slot->bus = bus; - slot->devfn = (device << 3) | func; + slot->devfn = (device << 3) | 0; slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base); slot->irq[pin - 1].bitmap = irq_router.irq_mask; (*entries)++; @@ -182,8 +182,7 @@ static int create_pirq_routing_table(void) PCI_FUNC(pr.bdf), 'A' + pr.pin - 1, 'A' + pr.pirq); fill_irq_info(&slot, &irq_entries, PCI_BUS(pr.bdf), - PCI_DEV(pr.bdf), PCI_FUNC(pr.bdf), - pr.pin, pr.pirq); + PCI_DEV(pr.bdf), pr.pin, pr.pirq); cell += sizeof(struct pirq_routing) / sizeof(u32); } -- cgit From df81749db7d7303508be41503e4c8d1229a07d4c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:47 +0800 Subject: x86: Reduce PIRQ routing table size There is no need to populate multiple irq info entries with the same bus number and device number, but with different interrupt pin. We can use the same entry to store all the 4 interrupt pin (INT A/B/C/D) routing information to reduce the whole PIRQ routing table size. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/irq.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index df4300c230..97dd000039 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -58,17 +58,28 @@ void pirq_assign_irq(int link, u8 irq) writeb(irq, irq_router.ibase + LINK_N2V(link, base)); } -static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus, - u8 device, u8 pin, u8 pirq) +static struct irq_info *check_dup_entry(struct irq_info *slot_base, + int entry_num, int bus, int device) { - struct irq_info *slot = *slotp; + struct irq_info *slot = slot_base; + int i; + + for (i = 0; i < entry_num; i++) { + if (slot->bus == bus && slot->devfn == (device << 3)) + break; + slot++; + } + return (i == entry_num) ? NULL : slot; +} + +static inline void fill_irq_info(struct irq_info *slot, int bus, int device, + int pin, int pirq) +{ slot->bus = bus; slot->devfn = (device << 3) | 0; slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base); slot->irq[pin - 1].bitmap = irq_router.irq_mask; - (*entries)++; - (*slotp)++; } __weak void cpu_irq_init(void) @@ -84,7 +95,7 @@ static int create_pirq_routing_table(void) int len, count; const u32 *cell; struct irq_routing_table *rt; - struct irq_info *slot; + struct irq_info *slot, *slot_base; int irq_entries = 0; int i; int ret; @@ -167,7 +178,7 @@ static int create_pirq_routing_table(void) rt->rtr_vendor = PCI_VENDOR_ID_INTEL; rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31; - slot = rt->slots; + slot_base = rt->slots; /* Now fill in the irq_info entries in the PIRQ table */ for (i = 0; i < count; i++) { @@ -181,8 +192,44 @@ static int create_pirq_routing_table(void) i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), PCI_FUNC(pr.bdf), 'A' + pr.pin - 1, 'A' + pr.pirq); - fill_irq_info(&slot, &irq_entries, PCI_BUS(pr.bdf), - PCI_DEV(pr.bdf), pr.pin, pr.pirq); + + slot = check_dup_entry(slot_base, irq_entries, + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf)); + if (slot) { + debug("found entry for bus %d device %d, ", + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf)); + + if (slot->irq[pr.pin - 1].link) { + debug("skipping\n"); + + /* + * Sanity test on the routed PIRQ pin + * + * If they don't match, show a warning to tell + * there might be something wrong with the PIRQ + * routing information in the device tree. + */ + if (slot->irq[pr.pin - 1].link != + LINK_N2V(pr.pirq, irq_router.link_base)) + debug("WARNING: Inconsistent PIRQ routing information\n"); + + cell += sizeof(struct pirq_routing) / + sizeof(u32); + continue; + } else { + debug("writing INT%c\n", 'A' + pr.pin - 1); + fill_irq_info(slot, PCI_BUS(pr.bdf), + PCI_DEV(pr.bdf), pr.pin, pr.pirq); + cell += sizeof(struct pirq_routing) / + sizeof(u32); + continue; + } + } + + slot = slot_base + irq_entries; + fill_irq_info(slot, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), + pr.pin, pr.pirq); + irq_entries++; cell += sizeof(struct pirq_routing) / sizeof(u32); } -- cgit From ba9091f55d68fc3d7b65a710f9d47c0be15e816d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:48 +0800 Subject: x86: Clean up ioapic header file Remove all the dead/unused macros from asm/ioapic.h. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/include/asm/ioapic.h | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) (limited to 'arch') diff --git a/arch/x86/include/asm/ioapic.h b/arch/x86/include/asm/ioapic.h index 699160f9f7..f5d69dbf97 100644 --- a/arch/x86/include/asm/ioapic.h +++ b/arch/x86/include/asm/ioapic.h @@ -10,29 +10,9 @@ #define __ASM_IOAPIC_H #define IO_APIC_ADDR 0xfec00000 -#define IO_APIC_INDEX IO_APIC_ADDR -#define IO_APIC_DATA (IO_APIC_ADDR + 0x10) -#define IO_APIC_INTERRUPTS 24 - -#define ALL (0xff << 24) -#define NONE 0 -#define DISABLED (1 << 16) -#define ENABLED (0 << 16) -#define TRIGGER_EDGE (0 << 15) -#define TRIGGER_LEVEL (1 << 15) -#define POLARITY_HIGH (0 << 13) -#define POLARITY_LOW (1 << 13) -#define PHYSICAL_DEST (0 << 11) -#define LOGICAL_DEST (1 << 11) -#define ExtINT (7 << 8) -#define NMI (4 << 8) -#define SMI (2 << 8) -#define INT (1 << 8) -u32 io_apic_read(u32 ioapic_base, u32 reg); -void io_apic_write(u32 ioapic_base, u32 reg, u32 value); -void set_ioapic_id(u32 ioapic_base, u8 ioapic_id); -void setup_ioapic(u32 ioapic_base, u8 ioapic_id); -void clear_ioapic(u32 ioapic_base); +/* Direct addressed register */ +#define IO_APIC_INDEX (IO_APIC_ADDR + 0x00) +#define IO_APIC_DATA (IO_APIC_ADDR + 0x10) #endif -- cgit From 3d232878289bf59e83c6b152407a01f6e0fb790b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:49 +0800 Subject: x86: Add I/O APIC register access routines I/O APIC registers are addressed indirectly. Add io_apic_read() and io_apic_write() routines to help register access. Two macros for I/O APIC ID and version register offset are also added. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/Makefile | 2 +- arch/x86/cpu/ioapic.c | 21 +++++++++++++++++++++ arch/x86/include/asm/ioapic.h | 24 ++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 arch/x86/cpu/ioapic.c (limited to 'arch') diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 48197fb0fa..8a8e63e1d3 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_INTEL_QUARK) += quark/ obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/ -obj-y += irq.o lapic.o +obj-y += irq.o lapic.o ioapic.o obj-$(CONFIG_SMP) += mp_init.o obj-y += mtrr.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/ioapic.c b/arch/x86/cpu/ioapic.c new file mode 100644 index 0000000000..112a9c63b4 --- /dev/null +++ b/arch/x86/cpu/ioapic.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +u32 io_apic_read(u32 reg) +{ + writel(reg, IO_APIC_INDEX); + return readl(IO_APIC_DATA); +} + +void io_apic_write(u32 reg, u32 val) +{ + writel(reg, IO_APIC_INDEX); + writel(val, IO_APIC_DATA); +} diff --git a/arch/x86/include/asm/ioapic.h b/arch/x86/include/asm/ioapic.h index f5d69dbf97..77c443e9f5 100644 --- a/arch/x86/include/asm/ioapic.h +++ b/arch/x86/include/asm/ioapic.h @@ -15,4 +15,28 @@ #define IO_APIC_INDEX (IO_APIC_ADDR + 0x00) #define IO_APIC_DATA (IO_APIC_ADDR + 0x10) +/* Indirect addressed register offset */ +#define IO_APIC_ID 0x00 +#define IO_APIC_VER 0x01 + +/** + * io_apic_read() - Read I/O APIC register + * + * This routine reads I/O APIC indirect addressed register. + * + * @reg: address of indirect addressed register + * @return: register value to read + */ +u32 io_apic_read(u32 reg); + +/** + * io_apic_write() - Write I/O APIC register + * + * This routine writes I/O APIC indirect addressed register. + * + * @reg: address of indirect addressed register + * @val: register value to write + */ +void io_apic_write(u32 reg, u32 val); + #endif -- cgit From a2d73fdba638233253c14b31f3befb9099d76774 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:50 +0800 Subject: x86: Remove inline for lapic access routines Remove inline for lapic access routines and expose lapic_read() & lapic_write() as APIs to read/write lapic registers. Also move stop_this_cpu() to mp_init.c as it has nothing to do with lapic. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/lapic.c | 143 +++++++++++++++++++++++++++++++++++++------ arch/x86/cpu/mp_init.c | 27 +++++--- arch/x86/include/asm/lapic.h | 134 +++------------------------------------- 3 files changed, 153 insertions(+), 151 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/lapic.c b/arch/x86/cpu/lapic.c index 6769ae53ae..30d23130eb 100644 --- a/arch/x86/cpu/lapic.c +++ b/arch/x86/cpu/lapic.c @@ -8,9 +8,116 @@ */ #include +#include #include +#include +#include #include +unsigned long lapic_read(unsigned long reg) +{ + return readl(LAPIC_DEFAULT_BASE + reg); +} + +#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ + sizeof(*(ptr)))) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) + +/* + * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. + * + * Note 2: xchg has side effect, so that attribute volatile is necessary, + * but generally the primitive is invalid, *ptr is output argument. + */ +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + switch (size) { + case 1: + __asm__ __volatile__("xchgb %b0,%1" + : "=q" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 2: + __asm__ __volatile__("xchgw %w0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + case 4: + __asm__ __volatile__("xchgl %0,%1" + : "=r" (x) + : "m" (*__xg(ptr)), "0" (x) + : "memory"); + break; + } + + return x; +} + +void lapic_write(unsigned long reg, unsigned long v) +{ + (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); +} + +void enable_lapic(void) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_APICBASE); + msr.hi &= 0xffffff00; + msr.lo |= MSR_IA32_APICBASE_ENABLE; + msr.lo &= ~MSR_IA32_APICBASE_BASE; + msr.lo |= LAPIC_DEFAULT_BASE; + msr_write(MSR_IA32_APICBASE, msr); +} + +void disable_lapic(void) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_APICBASE); + msr.lo &= ~MSR_IA32_APICBASE_ENABLE; + msr_write(MSR_IA32_APICBASE, msr); +} + +unsigned long lapicid(void) +{ + return lapic_read(LAPIC_ID) >> 24; +} + +static void lapic_wait_icr_idle(void) +{ + do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY); +} + +int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) +{ + int timeout; + unsigned long status; + int result; + + lapic_wait_icr_idle(); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); + lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); + + timeout = 0; + do { + status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; + } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); + + result = -1; + if (status == LAPIC_ICR_RR_VALID) { + *pvalue = lapic_read(LAPIC_RRR); + result = 0; + } + + return result; +} + void lapic_setup(void) { #ifdef CONFIG_SMP @@ -21,26 +128,26 @@ void lapic_setup(void) enable_lapic(); /* Set Task Priority to 'accept all' */ - lapic_write_around(LAPIC_TASKPRI, - lapic_read_around(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); + lapic_write(LAPIC_TASKPRI, + lapic_read(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); /* Put the local apic in virtual wire mode */ - lapic_write_around(LAPIC_SPIV, (lapic_read_around(LAPIC_SPIV) & - ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); - lapic_write_around(LAPIC_LVT0, (lapic_read_around(LAPIC_LVT0) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_EXTINT)); - lapic_write_around(LAPIC_LVT1, (lapic_read_around(LAPIC_LVT1) & - ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | - LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | - LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | - LAPIC_DELIVERY_MODE_MASK)) | - (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | - LAPIC_DELIVERY_MODE_NMI)); + lapic_write(LAPIC_SPIV, (lapic_read(LAPIC_SPIV) & + ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); + lapic_write(LAPIC_LVT0, (lapic_read(LAPIC_LVT0) & + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_EXTINT)); + lapic_write(LAPIC_LVT1, (lapic_read(LAPIC_LVT1) & + ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | + LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | + LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | + LAPIC_DELIVERY_MODE_MASK)) | + (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | + LAPIC_DELIVERY_MODE_NMI)); debug("apic_id: 0x%02lx, ", lapicid()); #else /* !CONFIG_SMP */ diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index e8bc9b6d04..e686b28c9c 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -59,6 +61,13 @@ static inline void release_barrier(atomic_t *b) atomic_set(b, 1); } +static inline void stop_this_cpu(void) +{ + /* Called by an AP when it is ready to halt and wait for a new task */ + for (;;) + cpu_hlt(); +} + /* Returns 1 if timeout waiting for APs. 0 if target APs found */ static int wait_for_aps(atomic_t *val, int target, int total_delay, int delay_step) @@ -317,9 +326,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } /* Send INIT IPI to all but self */ - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_INIT); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_INIT); debug("Waiting for 10ms after sending INIT.\n"); mdelay(10); @@ -334,9 +343,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } } - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_STARTUP | sipi_vector); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_STARTUP | sipi_vector); debug("Waiting for 1st SIPI to complete..."); if (apic_wait_timeout(10000, 50)) { debug("timed out.\n"); @@ -359,9 +368,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) } } - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_STARTUP | sipi_vector); + lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_STARTUP | sipi_vector); debug("Waiting for 2nd SIPI to complete..."); if (apic_wait_timeout(10000, 50)) { debug("timed out.\n"); diff --git a/arch/x86/include/asm/lapic.h b/arch/x86/include/asm/lapic.h index f60974a878..bc2b2d1520 100644 --- a/arch/x86/include/asm/lapic.h +++ b/arch/x86/include/asm/lapic.h @@ -9,11 +9,6 @@ #ifndef _ARCH_ASM_LAPIC_H #define _ARCH_ASM_LAPIC_H -#include -#include -#include -#include - #define LAPIC_DEFAULT_BASE 0xfee00000 #define LAPIC_ID 0x020 @@ -66,126 +61,17 @@ #define LAPIC_DELIVERY_MODE_NMI (4 << 8) #define LAPIC_DELIVERY_MODE_EXTINT (7 << 8) -static inline __attribute__((always_inline)) - unsigned long lapic_read(unsigned long reg) -{ - return readl(LAPIC_DEFAULT_BASE + reg); -} - -static inline __attribute__((always_inline)) - void lapic_write(unsigned long reg, unsigned long val) -{ - writel(val, LAPIC_DEFAULT_BASE + reg); -} - -static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void) -{ - do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY); -} - -static inline void enable_lapic(void) -{ - msr_t msr; - - msr = msr_read(MSR_IA32_APICBASE); - msr.hi &= 0xffffff00; - msr.lo |= MSR_IA32_APICBASE_ENABLE; - msr.lo &= ~MSR_IA32_APICBASE_BASE; - msr.lo |= LAPIC_DEFAULT_BASE; - msr_write(MSR_IA32_APICBASE, msr); -} - -static inline void disable_lapic(void) -{ - msr_t msr; - - msr = msr_read(MSR_IA32_APICBASE); - msr.lo &= ~MSR_IA32_APICBASE_ENABLE; - msr_write(MSR_IA32_APICBASE, msr); -} - -static inline __attribute__((always_inline)) unsigned long lapicid(void) -{ - return lapic_read(LAPIC_ID) >> 24; -} - -static inline __attribute__((always_inline)) void stop_this_cpu(void) -{ - /* Called by an AP when it is ready to halt and wait for a new task */ - for (;;) - cpu_hlt(); -} - -#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ - sizeof(*(ptr)))) - -struct __xchg_dummy { unsigned long a[100]; }; -#define __xg(x) ((struct __xchg_dummy *)(x)) +unsigned long lapic_read(unsigned long reg); -/* - * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. - * - * Note 2: xchg has side effect, so that attribute volatile is necessary, - * but generally the primitive is invalid, *ptr is output argument. - */ -static inline unsigned long __xchg(unsigned long x, volatile void *ptr, - int size) -{ - switch (size) { - case 1: - __asm__ __volatile__("xchgb %b0,%1" - : "=q" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - case 2: - __asm__ __volatile__("xchgw %w0,%1" - : "=r" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - case 4: - __asm__ __volatile__("xchgl %0,%1" - : "=r" (x) - : "m" (*__xg(ptr)), "0" (x) - : "memory"); - break; - } - - return x; -} - -static inline void lapic_write_atomic(unsigned long reg, unsigned long v) -{ - (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); -} - -#define lapic_read_around(x) lapic_read(x) -#define lapic_write_around(x, y) lapic_write_atomic((x), (y)) - -static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) -{ - int timeout; - unsigned long status; - int result; - - lapic_wait_icr_idle(); - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); - lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); - - timeout = 0; - do { - status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; - } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); - - result = -1; - if (status == LAPIC_ICR_RR_VALID) { - *pvalue = lapic_read(LAPIC_RRR); - result = 0; - } - - return result; -} +void lapic_write(unsigned long reg, unsigned long v); + +void enable_lapic(void); + +void disable_lapic(void); + +unsigned long lapicid(void); + +int lapic_remote_read(int apicid, int reg, unsigned long *pvalue); void lapic_setup(void); -- cgit From 7f5df8d42d8eb0fbdb6bf168fd530aa0f01b99c7 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:51 +0800 Subject: x86: Add MultiProcessor (MP) table APIs The MP table provides a way for the operating system to support for symmetric multiprocessing as well as symmetric I/O interrupt handling with the local APIC and I/O APIC. We provide a bunch of APIs for U-Boot to write the floating table, configuration table header as well as base and extended table entries. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/include/asm/mpspec.h | 434 ++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/tables.h | 14 ++ arch/x86/lib/Makefile | 1 + arch/x86/lib/mpspec.c | 225 ++++++++++++++++++++++ arch/x86/lib/tables.c | 14 ++ 5 files changed, 688 insertions(+) create mode 100644 arch/x86/include/asm/mpspec.h create mode 100644 arch/x86/lib/mpspec.c (limited to 'arch') diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h new file mode 100644 index 0000000000..849113a940 --- /dev/null +++ b/arch/x86/include/asm/mpspec.h @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * Adapted from coreboot src/arch/x86/include/arch/smp/mpspec.h + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_MPSPEC_H +#define __ASM_MPSPEC_H + +/* + * Structure definitions for SMP machines following the + * Intel MultiProcessor Specification 1.4 + */ + +#define MPSPEC_V14 4 + +#define MPF_SIGNATURE "_MP_" + +struct mp_floating_table { + char mpf_signature[4]; /* "_MP_" */ + u32 mpf_physptr; /* Configuration table address */ + u8 mpf_length; /* Our length (paragraphs) */ + u8 mpf_spec; /* Specification version */ + u8 mpf_checksum; /* Checksum (makes sum 0) */ + u8 mpf_feature1; /* Predefined or Unique configuration? */ + u8 mpf_feature2; /* Bit7 set for IMCR/PIC */ + u8 mpf_feature3; /* Unused (0) */ + u8 mpf_feature4; /* Unused (0) */ + u8 mpf_feature5; /* Unused (0) */ +}; + +#define MPC_SIGNATURE "PCMP" + +struct mp_config_table { + char mpc_signature[4]; /* "PCMP" */ + u16 mpc_length; /* Size of table */ + u8 mpc_spec; /* Specification version */ + u8 mpc_checksum; /* Checksum (makes sum 0) */ + char mpc_oem[8]; /* OEM ID */ + char mpc_product[12]; /* Product ID */ + u32 mpc_oemptr; /* OEM table address */ + u16 mpc_oemsize; /* OEM table size */ + u16 mpc_entry_count; /* Number of entries in the table */ + u32 mpc_lapic; /* Local APIC address */ + u16 mpe_length; /* Extended table size */ + u8 mpe_checksum; /* Extended table checksum */ + u8 reserved; +}; + +/* Base MP configuration table entry types */ + +enum mp_base_config_entry_type { + MP_PROCESSOR, + MP_BUS, + MP_IOAPIC, + MP_INTSRC, + MP_LINTSRC +}; + +#define MPC_CPU_EN (1 << 0) +#define MPC_CPU_BP (1 << 1) + +struct mpc_config_processor { + u8 mpc_type; + u8 mpc_apicid; + u8 mpc_apicver; + u8 mpc_cpuflag; + u32 mpc_cpusignature; + u32 mpc_cpufeature; + u32 mpc_reserved[2]; +}; + +#define BUSTYPE_CBUS "CBUS " +#define BUSTYPE_CBUSII "CBUSII" +#define BUSTYPE_EISA "EISA " +#define BUSTYPE_FUTURE "FUTURE" +#define BUSTYPE_INTERN "INTERN" +#define BUSTYPE_ISA "ISA " +#define BUSTYPE_MBI "MBI " +#define BUSTYPE_MBII "MBII " +#define BUSTYPE_MCA "MCA " +#define BUSTYPE_MPI "MPI " +#define BUSTYPE_MPSA "MPSA " +#define BUSTYPE_NUBUS "NUBUS " +#define BUSTYPE_PCI "PCI " +#define BUSTYPE_PCMCIA "PCMCIA" +#define BUSTYPE_TC "TC " +#define BUSTYPE_VL "VL " +#define BUSTYPE_VME "VME " +#define BUSTYPE_XPRESS "XPRESS" + +struct mpc_config_bus { + u8 mpc_type; + u8 mpc_busid; + u8 mpc_bustype[6]; +}; + +#define MPC_APIC_USABLE (1 << 0) + +struct mpc_config_ioapic { + u8 mpc_type; + u8 mpc_apicid; + u8 mpc_apicver; + u8 mpc_flags; + u32 mpc_apicaddr; +}; + +enum mp_irq_source_types { + MP_INT, + MP_NMI, + MP_SMI, + MP_EXTINT +}; + +#define MP_IRQ_POLARITY_DEFAULT 0x0 +#define MP_IRQ_POLARITY_HIGH 0x1 +#define MP_IRQ_POLARITY_LOW 0x3 +#define MP_IRQ_POLARITY_MASK 0x3 +#define MP_IRQ_TRIGGER_DEFAULT 0x0 +#define MP_IRQ_TRIGGER_EDGE 0x4 +#define MP_IRQ_TRIGGER_LEVEL 0xc +#define MP_IRQ_TRIGGER_MASK 0xc + +#define MP_APIC_ALL 0xff + +struct mpc_config_intsrc { + u8 mpc_type; + u8 mpc_irqtype; + u16 mpc_irqflag; + u8 mpc_srcbus; + u8 mpc_srcbusirq; + u8 mpc_dstapic; + u8 mpc_dstirq; +}; + +struct mpc_config_lintsrc { + u8 mpc_type; + u8 mpc_irqtype; + u16 mpc_irqflag; + u8 mpc_srcbusid; + u8 mpc_srcbusirq; + u8 mpc_destapic; + u8 mpc_destlint; +}; + +/* Extended MP configuration table entry types */ + +enum mp_ext_config_entry_type { + MPE_SYSTEM_ADDRESS_SPACE = 128, + MPE_BUS_HIERARCHY, + MPE_COMPAT_ADDRESS_SPACE +}; + +struct mp_ext_config { + u8 mpe_type; + u8 mpe_length; +}; + +#define ADDRESS_TYPE_IO 0 +#define ADDRESS_TYPE_MEM 1 +#define ADDRESS_TYPE_PREFETCH 2 + +struct mp_ext_system_address_space { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_addr_type; + u32 mpe_addr_base_low; + u32 mpe_addr_base_high; + u32 mpe_addr_length_low; + u32 mpe_addr_length_high; +}; + +#define BUS_SUBTRACTIVE_DECODE (1 << 0) + +struct mp_ext_bus_hierarchy { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_bus_info; + u8 mpe_parent_busid; + u8 reserved[3]; +}; + +#define ADDRESS_RANGE_ADD 0 +#define ADDRESS_RANGE_SUBTRACT 1 + +/* + * X100 - X3FF + * X500 - X7FF + * X900 - XBFF + * XD00 - XFFF + */ +#define RANGE_LIST_IO_ISA 0 +/* + * X3B0 - X3BB + * X3C0 - X3DF + * X7B0 - X7BB + * X7C0 - X7DF + * XBB0 - XBBB + * XBC0 - XBDF + * XFB0 - XFBB + * XFC0 - XCDF + */ +#define RANGE_LIST_IO_VGA 1 + +struct mp_ext_compat_address_space { + u8 mpe_type; + u8 mpe_length; + u8 mpe_busid; + u8 mpe_addr_modifier; + u32 mpe_range_list; +}; + +/** + * mp_next_mpc_entry() - Compute MP configuration table end to be used as + * next base table entry start address + * + * This computes the end address of current MP configuration table, without + * counting any extended configuration table entry. + * + * @mc: configuration table header address + * @return: configuration table end address + */ +static inline u32 mp_next_mpc_entry(struct mp_config_table *mc) +{ + return (u32)mc + mc->mpc_length; +} + +/** + * mp_add_mpc_entry() - Add a base MP configuration table entry + * + * This adds the base MP configuration table entry size with + * added base table entry length and increases entry count by 1. + * + * @mc: configuration table header address + * @length: length of the added table entry + */ +static inline void mp_add_mpc_entry(struct mp_config_table *mc, uint length) +{ + mc->mpc_length += length; + mc->mpc_entry_count++; +} + +/** + * mp_next_mpe_entry() - Compute MP configuration table end to be used as + * next extended table entry start address + * + * This computes the end address of current MP configuration table, + * including any extended configuration table entry. + * + * @mc: configuration table header address + * @return: configuration table end address + */ +static inline u32 mp_next_mpe_entry(struct mp_config_table *mc) +{ + return (u32)mc + mc->mpc_length + mc->mpe_length; +} + +/** + * mp_add_mpe_entry() - Add an extended MP configuration table entry + * + * This adds the extended MP configuration table entry size with + * added extended table entry length. + * + * @mc: configuration table header address + * @mpe: extended table entry base address + */ +static inline void mp_add_mpe_entry(struct mp_config_table *mc, + struct mp_ext_config *mpe) +{ + mc->mpe_length += mpe->mpe_length; +} + +/** + * mp_write_floating_table() - Write the MP floating table + * + * This writes the MP floating table, and points MP configuration table + * to its end address so that MP configuration table follows immediately + * after the floating table. + * + * @mf: MP floating table base address + * @return: MP configuration table header address + */ +struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf); + +/** + * mp_config_table_init() - Initialize the MP configuration table header + * + * This populates the MP configuration table header with valid bits. + * + * @mc: MP configuration table header address + */ +void mp_config_table_init(struct mp_config_table *mc); + +/** + * mp_write_processor() - Write a processor entry + * + * This writes a processor entry to the configuration table. + * + * @mc: MP configuration table header address + */ +void mp_write_processor(struct mp_config_table *mc); + +/** + * mp_write_bus() - Write a bus entry + * + * This writes a bus entry to the configuration table. + * + * @mc: MP configuration table header address + * @id: bus id + * @bustype: bus type name + */ +void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype); + +/** + * mp_write_ioapic() - Write an I/O APIC entry + * + * This writes an I/O APIC entry to the configuration table. + * + * @mc: MP configuration table header address + * @id: I/O APIC id + * @ver: I/O APIC version + * @apicaddr: I/O APIC address + */ +void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr); + +/** + * mp_write_intsrc() - Write an I/O interrupt assignment entry + * + * This writes an I/O interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @irqflag: IRQ flag (level/trigger) + * @srcbus: source bus id where the interrupt comes from + * @srcbusirq: IRQ number mapped on the source bus + * @dstapic: destination I/O APIC id where the interrupt goes to + * @dstirq: destination I/O APIC pin where the interrupt goes to + */ +void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int dstapic, int dstirq); + +/** + * mp_write_pci_intsrc() - Write a PCI interrupt assignment entry + * + * This writes a PCI interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @srcbus: PCI bus number where the interrupt comes from + * @dev: device number on the PCI bus + * @pin: PCI interrupt pin (INT A/B/C/D) + * @dstapic: destination I/O APIC id where the interrupt goes to + * @dstirq: destination I/O APIC pin where the interrupt goes to + */ +void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, + int srcbus, int dev, int pin, int dstapic, int dstirq); + +/** + * mp_write_lintsrc() - Write a local interrupt assignment entry + * + * This writes a local interrupt assignment entry to the configuration table. + * + * @mc: MP configuration table header address + * @irqtype: IRQ type (INT/NMI/SMI/ExtINT) + * @irqflag: IRQ flag (level/trigger) + * @srcbus: PCI bus number where the interrupt comes from + * @srcbusirq: IRQ number mapped on the source bus + * @dstapic: destination local APIC id where the interrupt goes to + * @destlint: destination local APIC pin where the interrupt goes to + */ +void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int destapic, int destlint); + + +/** + * mp_write_address_space() - Write a system address space entry + * + * This writes a system address space entry to the configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id for the bus where system address space is mapped + * @addr_type: system address type + * @addr_base_low: starting address low + * @addr_base_high: starting address high + * @addr_length_low: address length low + * @addr_length_high: address length high + */ +void mp_write_address_space(struct mp_config_table *mc, + int busid, int addr_type, + u32 addr_base_low, u32 addr_base_high, + u32 addr_length_low, u32 addr_length_high); + +/** + * mp_write_bus_hierarchy() - Write a bus hierarchy descriptor entry + * + * This writes a bus hierarchy descriptor entry to the configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id + * @bus_info: bit0 indicates if the bus is a subtractive decode bus + * @parent_busid: parent bus id + */ +void mp_write_bus_hierarchy(struct mp_config_table *mc, + int busid, int bus_info, int parent_busid); + +/** + * mp_write_compat_address_space() - Write a compat bus address space entry + * + * This writes a compatibility bus address space modifier entry to the + * configuration table. + * + * @mc: MP configuration table header address + * @busid: bus id + * @addr_modifier: add or subtract to predefined address range list + * @range_list: list of predefined address space ranges + */ +void mp_write_compat_address_space(struct mp_config_table *mc, int busid, + int addr_modifier, u32 range_list); + +/** + * mptable_finalize() - Finalize the MP table + * + * This finalizes the MP table by calculating required checksums. + * + * @mc: MP configuration table header address + * @return: MP table end address + */ +u32 mptable_finalize(struct mp_config_table *mc); + +#endif /* __ASM_MPSPEC_H */ diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h index 8146ba39b2..0aa6d9b33e 100644 --- a/arch/x86/include/asm/tables.h +++ b/arch/x86/include/asm/tables.h @@ -27,6 +27,20 @@ */ u8 table_compute_checksum(void *v, int len); +/** + * table_fill_string() - Fill a string with pad in the configuration table + * + * This fills a string in the configuration table. It copies number of bytes + * from the source string, and if source string length is shorter than the + * required size to copy, pad the table string with the given pad character. + * + * @dest: where to fill a string + * @src: where to copy from + * @n: number of bytes to copy + * @pad: character to pad the remaining bytes + */ +void table_fill_string(char *dest, const char *src, size_t n, char pad); + /** * write_tables() - Write x86 configuration tables * diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 70ad19b263..43489fdc1f 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -15,6 +15,7 @@ obj-y += gcc.o obj-y += init_helpers.o obj-y += interrupts.o obj-y += lpc-uclass.o +obj-y += mpspec.o obj-y += cmd_mtrr.o obj-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o obj-$(CONFIG_SYS_PCAT_TIMER) += pcat_timer.o diff --git a/arch/x86/lib/mpspec.c b/arch/x86/lib/mpspec.c new file mode 100644 index 0000000000..26d102544d --- /dev/null +++ b/arch/x86/lib/mpspec.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * Adapted from coreboot src/arch/x86/boot/mpspec.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) +{ + u32 mc; + + memcpy(mf->mpf_signature, MPF_SIGNATURE, 4); + mf->mpf_physptr = (u32)mf + sizeof(struct mp_floating_table); + mf->mpf_length = 1; + mf->mpf_spec = MPSPEC_V14; + mf->mpf_checksum = 0; + /* We don't use the default configuration table */ + mf->mpf_feature1 = 0; + /* Indicate that virtual wire mode is always implemented */ + mf->mpf_feature2 = 0; + mf->mpf_feature3 = 0; + mf->mpf_feature4 = 0; + mf->mpf_feature5 = 0; + mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16); + + mc = (u32)mf + sizeof(struct mp_floating_table); + return (struct mp_config_table *)mc; +} + +void mp_config_table_init(struct mp_config_table *mc) +{ + memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); + mc->mpc_length = sizeof(struct mp_config_table); + mc->mpc_spec = MPSPEC_V14; + mc->mpc_checksum = 0; + mc->mpc_oemptr = 0; + mc->mpc_oemsize = 0; + mc->mpc_entry_count = 0; + mc->mpc_lapic = LAPIC_DEFAULT_BASE; + mc->mpe_length = 0; + mc->mpe_checksum = 0; + mc->reserved = 0; + + /* The oem/product id fields are exactly 8/12 bytes long */ + table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' '); + table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' '); +} + +void mp_write_processor(struct mp_config_table *mc) +{ + struct mpc_config_processor *mpc; + struct udevice *dev; + u8 boot_apicid, apicver; + u32 cpusignature, cpufeature; + struct cpuid_result result; + + boot_apicid = lapicid(); + apicver = lapic_read(LAPIC_LVR) & 0xff; + result = cpuid(1); + cpusignature = result.eax; + cpufeature = result.edx; + + for (uclass_find_first_device(UCLASS_CPU, &dev); + dev; + uclass_find_next_device(&dev)) { + struct cpu_platdata *plat = dev_get_parent_platdata(dev); + u8 cpuflag = MPC_CPU_EN; + + if (!device_active(dev)) + continue; + + mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_PROCESSOR; + mpc->mpc_apicid = plat->cpu_id; + mpc->mpc_apicver = apicver; + if (boot_apicid == plat->cpu_id) + cpuflag |= MPC_CPU_BP; + mpc->mpc_cpuflag = cpuflag; + mpc->mpc_cpusignature = cpusignature; + mpc->mpc_cpufeature = cpufeature; + mpc->mpc_reserved[0] = 0; + mpc->mpc_reserved[1] = 0; + mp_add_mpc_entry(mc, sizeof(*mpc)); + } +} + +void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype) +{ + struct mpc_config_bus *mpc; + + mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_BUS; + mpc->mpc_busid = id; + memcpy(mpc->mpc_bustype, bustype, 6); + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr) +{ + struct mpc_config_ioapic *mpc; + + mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_IOAPIC; + mpc->mpc_apicid = id; + mpc->mpc_apicver = ver; + mpc->mpc_flags = MPC_APIC_USABLE; + mpc->mpc_apicaddr = apicaddr; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int dstapic, int dstirq) +{ + struct mpc_config_intsrc *mpc; + + mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_INTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbus = srcbus; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_dstapic = dstapic; + mpc->mpc_dstirq = dstirq; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, + int srcbus, int dev, int pin, int dstapic, int dstirq) +{ + u8 srcbusirq = (dev << 2) | (pin - 1); + + mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, + srcbus, srcbusirq, dstapic, dstirq); +} + +void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, + int srcbus, int srcbusirq, int destapic, int destlint) +{ + struct mpc_config_lintsrc *mpc; + + mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc); + mpc->mpc_type = MP_LINTSRC; + mpc->mpc_irqtype = irqtype; + mpc->mpc_irqflag = irqflag; + mpc->mpc_srcbusid = srcbus; + mpc->mpc_srcbusirq = srcbusirq; + mpc->mpc_destapic = destapic; + mpc->mpc_destlint = destlint; + mp_add_mpc_entry(mc, sizeof(*mpc)); +} + +void mp_write_address_space(struct mp_config_table *mc, + int busid, int addr_type, + u32 addr_base_low, u32 addr_base_high, + u32 addr_length_low, u32 addr_length_high) +{ + struct mp_ext_system_address_space *mpe; + + mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_addr_type = addr_type; + mpe->mpe_addr_base_low = addr_base_low; + mpe->mpe_addr_base_high = addr_base_high; + mpe->mpe_addr_length_low = addr_length_low; + mpe->mpe_addr_length_high = addr_length_high; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +void mp_write_bus_hierarchy(struct mp_config_table *mc, + int busid, int bus_info, int parent_busid) +{ + struct mp_ext_bus_hierarchy *mpe; + + mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_BUS_HIERARCHY; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_bus_info = bus_info; + mpe->mpe_parent_busid = parent_busid; + mpe->reserved[0] = 0; + mpe->reserved[1] = 0; + mpe->reserved[2] = 0; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +void mp_write_compat_address_space(struct mp_config_table *mc, int busid, + int addr_modifier, u32 range_list) +{ + struct mp_ext_compat_address_space *mpe; + + mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc); + mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE; + mpe->mpe_length = sizeof(*mpe); + mpe->mpe_busid = busid; + mpe->mpe_addr_modifier = addr_modifier; + mpe->mpe_range_list = range_list; + mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); +} + +u32 mptable_finalize(struct mp_config_table *mc) +{ + u32 end; + + mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc), + mc->mpe_length); + mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length); + end = mp_next_mpe_entry(mc); + + debug("Write the MP table at: %x - %x\n", (u32)mc, end); + + return end; +} diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 8031201a49..41c50bc876 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -20,6 +20,20 @@ u8 table_compute_checksum(void *v, int len) return checksum; } +void table_fill_string(char *dest, const char *src, size_t n, char pad) +{ + int start, len; + int i; + + strncpy(dest, src, n); + + /* Fill the remaining bytes with pad */ + len = strlen(src); + start = len < n ? len : n; + for (i = start; i < n; i++) + dest[i] = pad; +} + void write_tables(void) { u32 __maybe_unused rom_table_end = ROM_TABLE_ADDR; -- cgit From 07545d861ccc54aecbeaa51b264258b90912b856 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:52 +0800 Subject: x86: Generate a valid MultiProcessor (MP) table Implement write_mp_table() to create a minimal working MP table. This includes an MP floating table, a configuration table header and all of the 5 base configuration table entries. The I/O interrupt assignment table entry is created based on the same information used in the creation of PIRQ routing table from device tree. A check duplicated entry logic is applied to prevent writing multiple I/O interrupt entries with the same information. Use a Kconfig option GENERATE_MP_TABLE to tell U-Boot whether we need actually write the MP table at the F seg, just like we did for PIRQ routing and SFI tables. With MP table existence, linux kernel will switch to I/O APIC and local APIC to process all the peripheral interrupts instead of 8259 PICs. This takes full advantage of the multicore hardware and the SMP kernel. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/Kconfig | 9 +++ arch/x86/include/asm/mpspec.h | 10 +++ arch/x86/lib/mpspec.c | 157 ++++++++++++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 ++ 4 files changed, 181 insertions(+) (limited to 'arch') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 36e97c8048..b52a80e1c2 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -313,6 +313,15 @@ config GENERATE_SFI_TABLE For more information, see http://simplefirmware.org +config GENERATE_MP_TABLE + bool "Generate an MP (Multi-Processor) table" + default n + help + Generate an MP (Multi-Processor) table for this board. The MP table + provides a way for the operating system to support for symmetric + multiprocessing as well as symmetric I/O interrupt handling with + the local APIC and I/O APIC. + endmenu config MAX_PIRQ_LINKS diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h index 849113a940..efa9231f92 100644 --- a/arch/x86/include/asm/mpspec.h +++ b/arch/x86/include/asm/mpspec.h @@ -431,4 +431,14 @@ void mp_write_compat_address_space(struct mp_config_table *mc, int busid, */ u32 mptable_finalize(struct mp_config_table *mc); +/** + * write_mp_table() - Write MP table + * + * This writes MP table at a given address. + * + * @addr: start address to write MP table + * @return: end address of MP table + */ +u32 write_mp_table(u32 addr); + #endif /* __ASM_MPSPEC_H */ diff --git a/arch/x86/lib/mpspec.c b/arch/x86/lib/mpspec.c index 26d102544d..f16fbcbb0d 100644 --- a/arch/x86/lib/mpspec.c +++ b/arch/x86/lib/mpspec.c @@ -9,13 +9,18 @@ #include #include #include +#include +#include #include +#include #include #include #include #include #include +DECLARE_GLOBAL_DATA_PTR; + struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) { u32 mc; @@ -223,3 +228,155 @@ u32 mptable_finalize(struct mp_config_table *mc) return end; } + +static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa, + int apicid, int external_int2) +{ + int i; + + mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, apicid, 0); + mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 1, apicid, 1); + mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, apicid, 2); + + for (i = 3; i < 16; i++) + mp_write_intsrc(mc, MP_INT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, i, apicid, i); +} + +/* + * Check duplicated I/O interrupt assignment table entry, to make sure + * there is only one entry with the given bus, device and interrupt pin. + */ +static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base, + int entry_num, int bus, int device, int pin) +{ + struct mpc_config_intsrc *intsrc = intsrc_base; + int i; + + for (i = 0; i < entry_num; i++) { + if (intsrc->mpc_srcbus == bus && + intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1))) + break; + intsrc++; + } + + return (i == entry_num) ? false : true; +} + +static int mptable_add_intsrc(struct mp_config_table *mc, + int bus_isa, int apicid) +{ + struct mpc_config_intsrc *intsrc_base; + int intsrc_entries = 0; + const void *blob = gd->fdt_blob; + int node; + int len, count; + const u32 *cell; + int i; + + /* Legacy Interrupts */ + debug("Writing ISA IRQs\n"); + mptable_add_isa_interrupts(mc, bus_isa, apicid, 0); + + /* Get I/O interrupt information from device tree */ + node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); + if (node < 0) { + debug("%s: Cannot find irq router node\n", __func__); + return -ENOENT; + } + + cell = fdt_getprop(blob, node, "intel,pirq-routing", &len); + if (!cell) + return -ENOENT; + + if ((len % sizeof(struct pirq_routing)) == 0) + count = len / sizeof(struct pirq_routing); + else + return -EINVAL; + + intsrc_base = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); + + for (i = 0; i < count; i++) { + struct pirq_routing pr; + + pr.bdf = fdt_addr_to_cpu(cell[0]); + pr.pin = fdt_addr_to_cpu(cell[1]); + pr.pirq = fdt_addr_to_cpu(cell[2]); + + if (check_dup_entry(intsrc_base, intsrc_entries, + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin)) { + debug("found entry for bus %d device %d INT%c, skipping\n", + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), + 'A' + pr.pin - 1); + cell += sizeof(struct pirq_routing) / sizeof(u32); + continue; + } + + /* PIRQ[A-H] are always connected to I/O APIC INTPIN#16-23 */ + mp_write_pci_intsrc(mc, MP_INT, PCI_BUS(pr.bdf), + PCI_DEV(pr.bdf), pr.pin, apicid, + pr.pirq + 16); + intsrc_entries++; + cell += sizeof(struct pirq_routing) / sizeof(u32); + } + + return 0; +} + +static void mptable_add_lintsrc(struct mp_config_table *mc, int bus_isa) +{ + mp_write_lintsrc(mc, MP_EXTINT, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, MP_APIC_ALL, 0); + mp_write_lintsrc(mc, MP_NMI, + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, + bus_isa, 0, MP_APIC_ALL, 1); +} + +u32 write_mp_table(u32 addr) +{ + struct mp_config_table *mc; + int ioapic_id, ioapic_ver; + int bus_isa = 0xff; + int ret; + u32 end; + + /* 16 byte align the table address */ + addr = ALIGN(addr, 16); + + /* Write floating table */ + mc = mp_write_floating_table((struct mp_floating_table *)addr); + + /* Write configuration table header */ + mp_config_table_init(mc); + + /* Write processor entry */ + mp_write_processor(mc); + + /* Write bus entry */ + mp_write_bus(mc, bus_isa, BUSTYPE_ISA); + + /* Write I/O APIC entry */ + ioapic_id = io_apic_read(IO_APIC_ID) >> 24; + ioapic_ver = io_apic_read(IO_APIC_VER) & 0xff; + mp_write_ioapic(mc, ioapic_id, ioapic_ver, IO_APIC_ADDR); + + /* Write I/O interrupt assignment entry */ + ret = mptable_add_intsrc(mc, bus_isa, ioapic_id); + if (ret) + debug("Failed to write I/O interrupt assignment table\n"); + + /* Write local interrupt assignment entry */ + mptable_add_lintsrc(mc, bus_isa); + + /* Finalize the MP table */ + end = mptable_finalize(mc); + + return end; +} diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 41c50bc876..75ffbc1b22 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -6,6 +6,7 @@ #include #include +#include #include u8 table_compute_checksum(void *v, int len) @@ -46,4 +47,8 @@ void write_tables(void) rom_table_end = write_sfi_table(rom_table_end); rom_table_end = ALIGN(rom_table_end, 1024); #endif +#ifdef CONFIG_GENERATE_MP_TABLE + rom_table_end = write_mp_table(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); +#endif } -- cgit From cdb6babec6422ad4b89e447b1b468f625deaea79 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 23 Jun 2015 12:18:55 +0800 Subject: x86: queensbay: Change PCIe root ports' interrupt routing So far interrupt routing works pretty well for any on-chip devices on Intel Crown Bay. When inserting any PCIe card to any PCIe slot, Linux kernel is smart enough to do interrupt swizzling and figure out device's irq using its parent bridge's interrupt routing info all the way up to its root port. In U-Boot all PCIe root ports' interrupts were routed to PIRQ E/F/G/H before, while actually all PCIe downstream ports received INTx are routed to PIRQ A/B/C/D directly and not configurable. Now we change this mapping so that any external PCIe device can work correctly. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/queensbay/tnc.c | 13 +++++++------ arch/x86/dts/crownbay.dts | 20 ++++++++++++++++---- 2 files changed, 23 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/queensbay/tnc.c b/arch/x86/cpu/queensbay/tnc.c index 873de7be9d..d27b2d9ec6 100644 --- a/arch/x86/cpu/queensbay/tnc.c +++ b/arch/x86/cpu/queensbay/tnc.c @@ -69,17 +69,18 @@ void cpu_irq_init(void) * 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 route internal PCI - * device's INTx to PIRQ E/F/G/H. + * 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(PIRQE, &rcba->d23ir); - writew(PIRQF, &rcba->d24ir); - writew(PIRQG, &rcba->d25ir); - writew(PIRQH, &rcba->d26ir); + writew(PIRQA, &rcba->d23ir); + writew(PIRQB, &rcba->d24ir); + writew(PIRQC, &rcba->d25ir); + writew(PIRQD, &rcba->d26ir); } int arch_misc_init(void) diff --git a/arch/x86/dts/crownbay.dts b/arch/x86/dts/crownbay.dts index b77c65a463..60da1f544b 100644 --- a/arch/x86/dts/crownbay.dts +++ b/arch/x86/dts/crownbay.dts @@ -169,10 +169,22 @@ /* TunnelCreek PCI devices */ PCI_BDF(0, 2, 0) INTA PIRQE PCI_BDF(0, 3, 0) INTA PIRQF - PCI_BDF(0, 23, 0) INTA PIRQE - PCI_BDF(0, 24, 0) INTA PIRQF - PCI_BDF(0, 25, 0) INTA PIRQG - PCI_BDF(0, 26, 0) INTA PIRQH + PCI_BDF(0, 23, 0) INTA PIRQA + PCI_BDF(0, 23, 0) INTB PIRQB + PCI_BDF(0, 23, 0) INTC PIRQC + PCI_BDF(0, 23, 0) INTD PIRQD + PCI_BDF(0, 24, 0) INTA PIRQB + PCI_BDF(0, 24, 0) INTB PIRQC + PCI_BDF(0, 24, 0) INTC PIRQD + PCI_BDF(0, 24, 0) INTD PIRQA + PCI_BDF(0, 25, 0) INTA PIRQC + PCI_BDF(0, 25, 0) INTB PIRQD + PCI_BDF(0, 25, 0) INTC PIRQA + PCI_BDF(0, 25, 0) INTD PIRQB + PCI_BDF(0, 26, 0) INTA PIRQD + PCI_BDF(0, 26, 0) INTB PIRQA + PCI_BDF(0, 26, 0) INTC PIRQB + PCI_BDF(0, 26, 0) INTD PIRQC PCI_BDF(0, 27, 0) INTA PIRQG /* * Topcliff PCI devices -- cgit From 7b5c3498901712dbd6503bf81c03bb6ea8e3b516 Mon Sep 17 00:00:00 2001 From: Jian Luo Date: Mon, 6 Jul 2015 16:42:06 +0800 Subject: x86: bios: Synchronize stack between real and protected mode PCI option rom may use different SS during its execution, so it is not safe to assume esp pointed to the same location in the protected mode. Signed-off-by: Jian Luo Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/lib/bios_asm.S | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'arch') diff --git a/arch/x86/lib/bios_asm.S b/arch/x86/lib/bios_asm.S index 4faa70e314..9dbf969373 100644 --- a/arch/x86/lib/bios_asm.S +++ b/arch/x86/lib/bios_asm.S @@ -246,6 +246,9 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) push %fs push %gs + /* Save real mode SS */ + movw %ss, %cs:__realmode_ss + /* Clear DF to not break ABI assumptions */ cld @@ -258,12 +261,29 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) enter_protected_mode + /* + * Now we are in protected mode. We need compute the right ESP based + * on saved real mode SS otherwise interrupt_handler() won't get + * correct parameters from the stack. + */ + movzwl %cs:__realmode_ss, %ecx + shll $4, %ecx + addl %ecx, %esp + /* Call the C interrupt handler */ movl $interrupt_handler, %eax call *%eax + /* Restore real mode ESP based on saved SS */ + movzwl %cs:__realmode_ss, %ecx + shll $4, %ecx + subl %ecx, %esp + enter_real_mode + /* Restore real mode SS */ + movw %cs:__realmode_ss, %ss + /* * Restore all registers, including those manipulated by the C * handler @@ -276,6 +296,9 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.) popal iret +__realmode_ss = PTR_TO_REAL_MODE(.) + .word 0 + .globl asm_realmode_code_size asm_realmode_code_size: .long . - asm_realmode_code -- cgit From 1441d81a793507745603c4c3b9481930ebd53822 Mon Sep 17 00:00:00 2001 From: Jian Luo Date: Mon, 6 Jul 2015 16:31:28 +0800 Subject: x86: bios: Allow pci config read/write to host bridge in int1a_handler We should allow pci config read/write to host bridge (b.d.f = 0.0.0) in the int1a_handler() which is a valid pci device. Signed-off-by: Jian Luo Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/lib/bios_interrupts.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/x86/lib/bios_interrupts.c b/arch/x86/lib/bios_interrupts.c index 290990a8bd..47d9f599a3 100644 --- a/arch/x86/lib/bios_interrupts.c +++ b/arch/x86/lib/bios_interrupts.c @@ -161,15 +161,7 @@ int int1a_handler(void) bus = M.x86.R_EBX >> 8; reg = M.x86.R_EDI; dev = PCI_BDF(bus, devfn >> 3, devfn & 7); - if (!dev) { - debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, - bus, devfn); - /* Or are we supposed to return PCIBIOS_NODEV? */ - M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ - M.x86.R_EAX |= PCIBIOS_BADREG; - retval = 0; - return retval; - } + switch (func) { case 0xb108: /* Read Config Byte */ byte = x86_pci_read_config8(dev, reg); -- cgit From 43dd22f5fc4c368616721a69e5ea0769abf292dc Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:30 +0800 Subject: x86: Setup fixed range MTRRs for legacy regions We should setup fixed range MTRRs for some legacy regions like VGA RAM and PCI ROM areas as uncacheable. Note FSP may setup these to other cache settings, but we can override this in x86_cpu_init_f(). Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/cpu.c | 22 ++++++++++++++++++++++ arch/x86/include/asm/mtrr.h | 27 ++++++++++++++++----------- 2 files changed, 38 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index d108ee5c4e..9afdafb17e 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -352,6 +354,26 @@ int x86_cpu_init_f(void) gd->arch.has_mtrr = has_mtrr(); } + /* Configure fixed range MTRRs for some legacy regions */ + if (gd->arch.has_mtrr) { + u64 mtrr_cap; + + mtrr_cap = native_read_msr(MTRR_CAP_MSR); + if (mtrr_cap & MTRR_CAP_FIX) { + /* Mark the VGA RAM area as uncacheable */ + native_write_msr(MTRR_FIX_16K_A0000_MSR, 0, 0); + + /* Mark the PCI ROM area as uncacheable */ + native_write_msr(MTRR_FIX_4K_C0000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_C8000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_D0000_MSR, 0, 0); + native_write_msr(MTRR_FIX_4K_D8000_MSR, 0, 0); + + /* Enable the fixed range MTRRs */ + msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); + } + } + return 0; } diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 3ad617cb4a..70762eed10 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -21,6 +21,11 @@ #define MTRR_CAP_MSR 0x0fe #define MTRR_DEF_TYPE_MSR 0x2ff +#define MTRR_CAP_SMRR (1 << 11) +#define MTRR_CAP_WC (1 << 10) +#define MTRR_CAP_FIX (1 << 8) +#define MTRR_CAP_VCNT_MASK 0xff + #define MTRR_DEF_TYPE_EN (1 << 11) #define MTRR_DEF_TYPE_FIX_EN (1 << 10) @@ -38,17 +43,17 @@ #define RANGES_PER_FIXED_MTRR 8 #define NUM_FIXED_RANGES (NUM_FIXED_MTRRS * RANGES_PER_FIXED_MTRR) -#define MTRR_FIX_64K_00000_MSR 0x250 -#define MTRR_FIX_16K_80000_MSR 0x258 -#define MTRR_FIX_16K_A0000_MSR 0x259 -#define MTRR_FIX_4K_C0000_MSR 0x268 -#define MTRR_FIX_4K_C8000_MSR 0x269 -#define MTRR_FIX_4K_D0000_MSR 0x26a -#define MTRR_FIX_4K_D8000_MSR 0x26b -#define MTRR_FIX_4K_E0000_MSR 0x26c -#define MTRR_FIX_4K_E8000_MSR 0x26d -#define MTRR_FIX_4K_F0000_MSR 0x26e -#define MTRR_FIX_4K_F8000_MSR 0x26f +#define MTRR_FIX_64K_00000_MSR 0x250 +#define MTRR_FIX_16K_80000_MSR 0x258 +#define MTRR_FIX_16K_A0000_MSR 0x259 +#define MTRR_FIX_4K_C0000_MSR 0x268 +#define MTRR_FIX_4K_C8000_MSR 0x269 +#define MTRR_FIX_4K_D0000_MSR 0x26a +#define MTRR_FIX_4K_D8000_MSR 0x26b +#define MTRR_FIX_4K_E0000_MSR 0x26c +#define MTRR_FIX_4K_E8000_MSR 0x26d +#define MTRR_FIX_4K_F0000_MSR 0x26e +#define MTRR_FIX_4K_F8000_MSR 0x26f #if !defined(__ASSEMBLER__) -- cgit From 92587b364b1750612739438810f17c5b98f406fb Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:31 +0800 Subject: x86: queensbay: Change CPU_ADDR_BITS to 32 Per CPUID:80000008h result, the maximum physical address bits of TunnelCreek processor is 32 instead of default 36. This will fix the incorrect decoding of MTRR range mask. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/queensbay/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/x86/cpu/queensbay/Kconfig b/arch/x86/cpu/queensbay/Kconfig index 397e599f93..fbf85f233f 100644 --- a/arch/x86/cpu/queensbay/Kconfig +++ b/arch/x86/cpu/queensbay/Kconfig @@ -38,4 +38,8 @@ config CMC_ADDR The default base address of 0xfffb0000 indicates that the binary must be located at offset 0xb0000 from the beginning of a 1MB flash device. +config CPU_ADDR_BITS + int + default 32 + endif -- cgit From df07d91956162c55f948cf150c14d678eca3b838 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:32 +0800 Subject: x86: cmd_mtrr: Improve MTRR list information Print the meaningful base address and mask of an MTRR range without showing the memory type encoding or valid bit. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/lib/cmd_mtrr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86/lib/cmd_mtrr.c b/arch/x86/lib/cmd_mtrr.c index 7e0506b75d..f632f495ed 100644 --- a/arch/x86/lib/cmd_mtrr.c +++ b/arch/x86/lib/cmd_mtrr.c @@ -37,7 +37,8 @@ static int do_mtrr_list(void) valid = mask & MTRR_PHYS_MASK_VALID; type = mtrr_type_name[base & MTRR_BASE_TYPE_MASK]; printf("%d %-5s %-12s %016llx %016llx %016llx\n", i, - valid ? "Y" : "N", type, base, mask, size); + valid ? "Y" : "N", type, base & ~MTRR_BASE_TYPE_MASK, + mask & ~MTRR_PHYS_MASK_VALID, size); } return 0; -- cgit From 786a08e0dd3d0505e10cc93622ce5db696c627e9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:33 +0800 Subject: x86: Move VGA option rom macros to Kconfig Move X86_OPTION_ROM_FILE & X86_OPTION_ROM_ADDR to arch/x86/Kconfig and rename them to VGA_BIOS_FILE & VGA_BIOS_ADDR which depend on HAVE_VGA_BIOS. The new names are consistent with other x86 binary blob options like HAVE_FSP/FSP_FILE/FSP_ADDR. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/Kconfig | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'arch') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b52a80e1c2..8381a3be6e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -287,6 +287,28 @@ config TSC_FREQ_IN_MHZ help The running frequency in MHz of Time-Stamp Counter (TSC). +config HAVE_VGA_BIOS + bool "Add a VGA BIOS image" + help + Select this option if you have a VGA BIOS image that you would + like to add to your ROM. + +config VGA_BIOS_FILE + string "VGA BIOS image filename" + depends on HAVE_VGA_BIOS + default "vga.bin" + help + The filename of the VGA BIOS image in the board directory. + +config VGA_BIOS_ADDR + hex "VGA BIOS image location" + depends on HAVE_VGA_BIOS + default 0xfff90000 + help + The location of VGA BIOS image in the SPI flash. For example, base + address of 0xfff90000 indicates that the image will be put at offset + 0x90000 from the beginning of a 1MB flash device. + menu "System tables" config GENERATE_PIRQ_TABLE -- cgit From 9e3a7c9bac35d47b7a021e311147ba0b5a128b08 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:34 +0800 Subject: x86: Remove MARK_GRAPHICS_MEM_WRCOMB MARK_GRAPHICS_MEM_WRCOMB is not referenced anywhere in the code, hence remove it. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/Kconfig | 8 -------- 1 file changed, 8 deletions(-) (limited to 'arch') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 8381a3be6e..cbbaa4f2ce 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -188,14 +188,6 @@ config X86_RAMTEST to work correctly. It is not exhaustive but can save time by detecting obvious failures. -config MARK_GRAPHICS_MEM_WRCOMB - bool "Mark graphics memory as write-combining" - default n - help - The graphics performance may increase if the graphics - memory is set as write-combining cache type. This option - enables marking the graphics memory as write-combining. - config HAVE_FSP bool "Add an Firmware Support Package binary" help -- cgit From a452002259e172c93277dbe5752817e0732afe78 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 6 Jul 2015 16:31:36 +0800 Subject: x86: Configure VESA parameters before loading Linux kernel Store VESA parameters to Linux setup header so that vesafb driver in the kernel could work. Signed-off-by: Bin Meng Acked-by: Simon Glass Tested-by: Jian Luo --- arch/x86/include/asm/zimage.h | 1 + arch/x86/lib/zimage.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'arch') diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 8e7dd424ca..bf351ed3b6 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -38,5 +38,6 @@ struct boot_params *load_zimage(char *image, unsigned long kernel_size, ulong *load_addressp); int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, unsigned long initrd_addr, unsigned long initrd_size); +void setup_video(struct screen_info *screen_info); #endif diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index c3f8a7308f..144471c5bb 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -273,6 +273,8 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, build_command_line(cmd_line, auto_boot); } + setup_video(&setup_base->screen_info); + return 0; } -- cgit From 945cae79e1b547d6edcce53aae68be2e3679a364 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:25 -0600 Subject: x86: pci: Tidy up the generic x86 PCI driver This driver should use the x86 PCI configuration functions. Also adjust its compatible string to something generic (i.e. without a vendor name). Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/coreboot/pci.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'arch') diff --git a/arch/x86/cpu/coreboot/pci.c b/arch/x86/cpu/coreboot/pci.c index 67eb14ce99..41e29a6086 100644 --- a/arch/x86/cpu/coreboot/pci.c +++ b/arch/x86/cpu/coreboot/pci.c @@ -11,29 +11,7 @@ #include #include -#include #include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -static const struct dm_pci_ops pci_x86_ops = { - .read_config = pci_x86_read_config, - .write_config = pci_x86_write_config, -}; - -static const struct udevice_id pci_x86_ids[] = { - { .compatible = "pci-x86" }, - { } -}; - -U_BOOT_DRIVER(pci_x86_drv) = { - .name = "pci_x86", - .id = UCLASS_PCI, - .of_match = pci_x86_ids, - .ops = &pci_x86_ops, -}; static const struct udevice_id generic_pch_ids[] = { { .compatible = "intel,pch" }, -- cgit From b71f9dca89013b8b100006029c98d04b495ebdf7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:26 -0600 Subject: dm: x86: minnowmax: Move PCI to use driver model Adjust minnowmax to use driver model for PCI. This requires adding a device tree node to specify the ranges, removing the board-specific PCI code and ensuring that the host bridge is configured. Reviewed-by: Bin Meng Signed-off-by: Simon Glass --- arch/x86/cpu/baytrail/Makefile | 1 - arch/x86/cpu/baytrail/pci.c | 46 ------------------------------------------ arch/x86/dts/minnowmax.dts | 10 +++++++++ 3 files changed, 10 insertions(+), 47 deletions(-) delete mode 100644 arch/x86/cpu/baytrail/pci.c (limited to 'arch') diff --git a/arch/x86/cpu/baytrail/Makefile b/arch/x86/cpu/baytrail/Makefile index c78b644eb7..5be5491643 100644 --- a/arch/x86/cpu/baytrail/Makefile +++ b/arch/x86/cpu/baytrail/Makefile @@ -7,5 +7,4 @@ obj-y += cpu.o obj-y += early_uart.o obj-y += fsp_configs.o -obj-y += pci.o obj-y += valleyview.o diff --git a/arch/x86/cpu/baytrail/pci.c b/arch/x86/cpu/baytrail/pci.c deleted file mode 100644 index 48409de5c4..0000000000 --- a/arch/x86/cpu/baytrail/pci.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2014, Bin Meng - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -void board_pci_setup_hose(struct pci_controller *hose) -{ - hose->first_busno = 0; - hose->last_busno = 0; - - /* PCI memory space */ - pci_set_region(hose->regions + 0, - CONFIG_PCI_MEM_BUS, - CONFIG_PCI_MEM_PHYS, - CONFIG_PCI_MEM_SIZE, - PCI_REGION_MEM); - - /* PCI IO space */ - pci_set_region(hose->regions + 1, - CONFIG_PCI_IO_BUS, - CONFIG_PCI_IO_PHYS, - CONFIG_PCI_IO_SIZE, - PCI_REGION_IO); - - pci_set_region(hose->regions + 2, - CONFIG_PCI_PREF_BUS, - CONFIG_PCI_PREF_PHYS, - CONFIG_PCI_PREF_SIZE, - PCI_REGION_PREFETCH); - - pci_set_region(hose->regions + 3, - 0, - 0, - gd->ram_size < 0x80000000 ? gd->ram_size : 0x80000000, - PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); - - hose->region_count = 4; -} diff --git a/arch/x86/dts/minnowmax.dts b/arch/x86/dts/minnowmax.dts index bd21bfb0b4..0e59b18d34 100644 --- a/arch/x86/dts/minnowmax.dts +++ b/arch/x86/dts/minnowmax.dts @@ -111,6 +111,16 @@ }; + pci { + compatible = "intel,pci-baytrail", "pci-x86"; + #address-cells = <3>; + #size-cells = <2>; + u-boot,dm-pre-reloc; + ranges = <0x02000000 0x0 0xd0000000 0xd0000000 0 0x10000000 + 0x42000000 0x0 0xc0000000 0xc0000000 0 0x10000000 + 0x01000000 0x0 0x2000 0x2000 0 0xe000>; + }; + spi { #address-cells = <1>; #size-cells = <0>; -- cgit From b9da5086b88a1565c7aede14e68bef2456c44475 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 3 Jul 2015 18:28:27 -0600 Subject: dm: x86: baytrail: Correct PCI region 3 when driver model is used Commit afbbd413a fixed this for non-driver-model. Make sure that the driver model code handles this also. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/cpu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9afdafb17e..af927b94e0 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -353,6 +353,8 @@ int x86_cpu_init_f(void) gd->arch.has_mtrr = has_mtrr(); } + /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ + gd->pci_ram_top = 0x80000000U; /* Configure fixed range MTRRs for some legacy regions */ if (gd->arch.has_mtrr) { -- cgit