From 62cbde4c4e462e5147d07cf1424492bb39e7bf94 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 19 Dec 2019 17:58:18 -0700 Subject: serial: ns16550: Support run-time configuration At present this driver uses an assortment of CONFIG options to control how it accesses the hardware. This is painful for platforms that are supposed to be controlled by a device tree or a previous-stage bootloader. Add a new CONFIG option to enable fully dynamic configuration. This controls register spacing, size, offset and endianness. Signed-off-by: Simon Glass Reviewed-by: Aiden Park Tested-by: Aiden Park Reviewed-by: Bin Meng [bmeng: squashed in http://patchwork.ozlabs.org/patch/1232929/] Signed-off-by: Bin Meng --- drivers/serial/Kconfig | 21 +++++++++++++ drivers/serial/ns16550.c | 79 +++++++++++++++++++++++++++++++++++++++++++----- include/ns16550.h | 16 +++++++++- 3 files changed, 107 insertions(+), 9 deletions(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bd95f70b61..1147654082 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -601,6 +601,27 @@ config SYS_NS16550 be used. It can be a constant or a function to get clock, eg, get_serial_clock(). +config NS16550_DYNAMIC + bool "Allow NS16550 to be configured at runtime" + default y if SYS_COREBOOT || SYS_SLIMBOOTLOADER + help + Enable this option to allow device-tree control of the driver. + + Normally this driver is controlled by the following options: + + CONFIG_SYS_NS16550_PORT_MAPPED - indicates that port I/O is used for + access. If not enabled, then the UART is memory-mapped. + CONFIG_SYS_NS16550_MEM32 - if memory-mapped, indicates that 32-bit + access should be used (instead of 8-bit) + CONFIG_SYS_NS16550_REG_SIZE - indicates register width and also + endianness. If positive, big-endian access is used. If negative, + little-endian is used. + + It is not a good practice for a driver to be statically configured, + since it prevents the same driver being used for different types of + UARTs in a system. This option avoids this problem at the cost of a + slightly increased code size. + config INTEL_MID_SERIAL bool "Intel MID platform UART support" depends on DM_SERIAL && OF_CONTROL diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 9851663dc5..31f6cfe421 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -93,19 +93,79 @@ static inline int serial_in_shift(void *addr, int shift) #define CONFIG_SYS_NS16550_CLK 0 #endif +/* + * Use this #ifdef for now since many platforms don't define in(), out(), + * out_le32(), etc. but we don't have #defines to indicate this. + * + * TODO(sjg@chromium.org): Add CONFIG options to indicate what I/O is available + * on a platform + */ +#ifdef CONFIG_NS16550_DYNAMIC +static void serial_out_dynamic(struct ns16550_platdata *plat, u8 *addr, + int value) +{ + if (plat->flags & NS16550_FLAG_IO) { + outb(value, addr); + } else if (plat->reg_width == 4) { + if (plat->flags & NS16550_FLAG_ENDIAN) { + if (plat->flags & NS16550_FLAG_BE) + out_be32(addr, value); + else + out_le32(addr, value); + } else { + writel(value, addr); + } + } else if (plat->flags & NS16550_FLAG_BE) { + writeb(value, addr + (1 << plat->reg_shift) - 1); + } else { + writeb(value, addr); + } +} + +static int serial_in_dynamic(struct ns16550_platdata *plat, u8 *addr) +{ + if (plat->flags & NS16550_FLAG_IO) { + return inb(addr); + } else if (plat->reg_width == 4) { + if (plat->flags & NS16550_FLAG_ENDIAN) { + if (plat->flags & NS16550_FLAG_BE) + return in_be32(addr); + else + return in_le32(addr); + } else { + return readl(addr); + } + } else if (plat->flags & NS16550_FLAG_BE) { + return readb(addr + (1 << plat->reg_shift) - 1); + } else { + return readb(addr); + } +} +#else +static inline void serial_out_dynamic(struct ns16550_platdata *plat, u8 *addr, + int value) +{ +} + +static inline int serial_in_dynamic(struct ns16550_platdata *plat, u8 *addr) +{ + return 0; +} + +#endif /* CONFIG_NS16550_DYNAMIC */ + static void ns16550_writeb(NS16550_t port, int offset, int value) { struct ns16550_platdata *plat = port->plat; unsigned char *addr; offset *= 1 << plat->reg_shift; - addr = (unsigned char *)plat->base + offset; + addr = (unsigned char *)plat->base + offset + plat->reg_offset; - /* - * As far as we know it doesn't make sense to support selection of - * these options at run-time, so use the existing CONFIG options. - */ - serial_out_shift(addr + plat->reg_offset, plat->reg_shift, value); + if (IS_ENABLED(CONFIG_NS16550_DYNAMIC)) + serial_out_dynamic(plat, addr, value); + else + serial_out_shift(addr, plat->reg_shift, value); } static int ns16550_readb(NS16550_t port, int offset) @@ -114,9 +174,12 @@ static int ns16550_readb(NS16550_t port, int offset) unsigned char *addr; offset *= 1 << plat->reg_shift; - addr = (unsigned char *)plat->base + offset; + addr = (unsigned char *)plat->base + offset + plat->reg_offset; - return serial_in_shift(addr + plat->reg_offset, plat->reg_shift); + if (IS_ENABLED(CONFIG_NS16550_DYNAMIC)) + return serial_in_dynamic(plat, addr); + else + return serial_in_shift(addr, plat->reg_shift); } static u32 ns16550_getfcr(NS16550_t port) diff --git a/include/ns16550.h b/include/ns16550.h index 701efeea85..18c9077755 100644 --- a/include/ns16550.h +++ b/include/ns16550.h @@ -31,6 +31,9 @@ #define CONFIG_SYS_NS16550_REG_SIZE (-1) #endif +#ifdef CONFIG_NS16550_DYNAMIC +#define UART_REG(x) unsigned char x +#else #if !defined(CONFIG_SYS_NS16550_REG_SIZE) || (CONFIG_SYS_NS16550_REG_SIZE == 0) #error "Please define NS16550 registers size." #elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_DM_SERIAL) @@ -44,14 +47,24 @@ unsigned char x; \ unsigned char postpad_##x[-CONFIG_SYS_NS16550_REG_SIZE - 1]; #endif +#endif /* CONFIG_NS16550_DYNAMIC */ + +enum ns16550_flags { + NS16550_FLAG_IO = 1 << 0, /* Use I/O access (else mem-mapped) */ + NS16550_FLAG_ENDIAN = 1 << 1, /* Use out_le/be_32() */ + NS16550_FLAG_BE = 1 << 2, /* Big-endian access (else little) */ +}; /** * struct ns16550_platdata - information about a NS16550 port * * @base: Base register address - * @reg_width: IO accesses size of registers (in bytes) + * @reg_width: IO accesses size of registers (in bytes, 1 or 4) * @reg_shift: Shift size of registers (0=byte, 1=16bit, 2=32bit...) + * @reg_offset: Offset to start of registers (normally 0) * @clock: UART base clock speed in Hz + * @fcr: Offset of FCR register (normally UART_FCR_DEFVAL) + * @flags: A few flags (enum ns16550_flags) * @bdf: PCI slot/function (pci_dev_t) */ struct ns16550_platdata { @@ -61,6 +74,7 @@ struct ns16550_platdata { int reg_offset; int clock; u32 fcr; + int flags; #if defined(CONFIG_PCI) && defined(CONFIG_SPL) int bdf; #endif -- cgit From 8c3ccb3f6d5602e47536fa83d1a8b938cae06f11 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 19 Dec 2019 17:58:19 -0700 Subject: x86: Update coreboot serial table struct Since mid 2016, coreboot has additional fields in the serial struct that it passes down to U-Boot. Add these so we are in sync. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/include/asm/coreboot_tables.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/x86/include/asm/coreboot_tables.h b/arch/x86/include/asm/coreboot_tables.h index 2c54e24e02..61de0077d7 100644 --- a/arch/x86/include/asm/coreboot_tables.h +++ b/arch/x86/include/asm/coreboot_tables.h @@ -97,6 +97,25 @@ struct cb_serial { u32 type; u32 baseaddr; u32 baud; + u32 regwidth; + + /* + * Crystal or input frequency to the chip containing the UART. + * Provide the board specific details to allow the payload to + * initialize the chip containing the UART and make independent + * decisions as to which dividers to select and their values + * to eventually arrive at the desired console baud-rate. + */ + u32 input_hertz; + + /* + * UART PCI address: bus, device, function + * 1 << 31 - Valid bit, PCI UART in use + * Bus << 20 + * Device << 15 + * Function << 12 + */ + u32 uart_pci_addr; }; #define CB_TAG_CONSOLE 0x0010 -- cgit From 44482e8a2a33835563c17d49dac4004d4da0a7ea Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 19 Dec 2019 17:58:20 -0700 Subject: x86: serial: Add a coreboot serial driver Coreboot can provide information about the serial device in use on a platform. Add a driver that uses this information to produce a working UART. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/serial/Kconfig | 11 ++++++++++ drivers/serial/Makefile | 1 + drivers/serial/serial_coreboot.c | 46 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 drivers/serial/serial_coreboot.c diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 1147654082..cd2e098883 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -542,6 +542,17 @@ config BCM6345_SERIAL help Select this to enable UART on BCM6345 SoCs. +config COREBOOT_SERIAL + bool "Coreboot UART support" + depends on DM_SERIAL + default y if SYS_COREBOOT + select SYS_NS16550 + help + Select this to enable a ns16550-style UART where the platform data + comes from the coreboot 'sysinfo' tables. This allows U-Boot to have + a serial console on any platform without needing to change the + device tree, etc. + config FSL_LINFLEXUART bool "Freescale Linflex UART support" depends on DM_SERIAL diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 06ee30697d..76b1811510 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_AR933X_UART) += serial_ar933x.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o +obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o diff --git a/drivers/serial/serial_coreboot.c b/drivers/serial/serial_coreboot.c new file mode 100644 index 0000000000..ccab347514 --- /dev/null +++ b/drivers/serial/serial_coreboot.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UART support for U-Boot when launched from Coreboot + * + * Copyright 2019 Google LLC + */ + +#include +#include +#include +#include +#include + +static int coreboot_ofdata_to_platdata(struct udevice *dev) +{ + struct ns16550_platdata *plat = dev_get_platdata(dev); + struct cb_serial *cb_info = lib_sysinfo.serial; + + plat->base = cb_info->baseaddr; + plat->reg_shift = cb_info->regwidth == 4 ? 2 : 0; + plat->reg_width = cb_info->regwidth; + plat->clock = cb_info->input_hertz; + plat->fcr = UART_FCR_DEFVAL; + plat->flags = 0; + if (cb_info->type == CB_SERIAL_TYPE_IO_MAPPED) + plat->flags |= NS16550_FLAG_IO; + + return 0; +} + +static const struct udevice_id coreboot_serial_ids[] = { + { .compatible = "coreboot-serial" }, + { }, +}; + +U_BOOT_DRIVER(coreboot_uart) = { + .name = "coreboot_uart", + .id = UCLASS_SERIAL, + .of_match = coreboot_serial_ids, + .priv_auto_alloc_size = sizeof(struct NS16550), + .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), + .ofdata_to_platdata = coreboot_ofdata_to_platdata, + .probe = ns16550_serial_probe, + .ops = &ns16550_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; -- cgit From b7c1e67a70b13fb8dbcb3b00532c2d2236afff49 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 19 Dec 2019 17:58:21 -0700 Subject: x86: Move coreboot over to use the coreboot UART Use this UART to improve the compatibility of U-Boot when used as a coreboot payload. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/dts/coreboot.dts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/dts/coreboot.dts b/arch/x86/dts/coreboot.dts index a88da6eafd..38ddaafa19 100644 --- a/arch/x86/dts/coreboot.dts +++ b/arch/x86/dts/coreboot.dts @@ -8,7 +8,6 @@ /dts-v1/; /include/ "skeleton.dtsi" -/include/ "serial.dtsi" /include/ "keyboard.dtsi" /include/ "pcspkr.dtsi" /include/ "reset.dtsi" @@ -40,6 +39,11 @@ u-boot,dm-pre-reloc; }; + serial: serial { + u-boot,dm-pre-reloc; + compatible = "coreboot-serial"; + }; + coreboot-fb { compatible = "coreboot-fb"; }; -- cgit From 18416ba1198afaae10b91552e8b0024cb84de2fa Mon Sep 17 00:00:00 2001 From: "Park, Aiden" Date: Wed, 18 Dec 2019 05:56:23 +0000 Subject: x86: serial: Use NS16550_DYNAMIC in Slim Bootloader Slim Bootloader provides serial port info in its HOB to support both IO or MMIO serial ports, but it's controlled by SYS_NS16550_MEM32 or SYS_NS16550_PORT_MAPPED in U-Boot. To support both serial port configurations dynamically at runtime, Slim Bootloader serial driver leverages NS16550_DYNAMIC. Signed-off-by: Aiden Park Reviewed-by: Bin Meng [bmeng: remove the obsolete comments for data->type] Signed-off-by: Bin Meng --- arch/x86/cpu/slimbootloader/serial.c | 13 +++++-------- include/configs/slimbootloader.h | 13 ------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/arch/x86/cpu/slimbootloader/serial.c b/arch/x86/cpu/slimbootloader/serial.c index 7b44a59bff..bab54b18df 100644 --- a/arch/x86/cpu/slimbootloader/serial.c +++ b/arch/x86/cpu/slimbootloader/serial.c @@ -34,18 +34,15 @@ static int slimbootloader_serial_ofdata_to_platdata(struct udevice *dev) data->stride, data->clk); - /* - * The data->type provides port io or mmio access type info, - * but the access type will be controlled by - * CONFIG_SYS_NS16550_PORT_MAPPED or CONFIG_SYS_NS16550_MEM32. - * - * TBD: ns16550 access type configuration in runtime. - * ex) plat->access_type = data->type - */ plat->base = data->base; /* ns16550 uses reg_shift, then covert stride to shift */ plat->reg_shift = data->stride >> 1; + plat->reg_width = data->stride; plat->clock = data->clk; + plat->fcr = UART_FCR_DEFVAL; + plat->flags = 0; + if (data->type == 1) + plat->flags |= NS16550_FLAG_IO; return 0; } diff --git a/include/configs/slimbootloader.h b/include/configs/slimbootloader.h index e0011ed446..b8169072cc 100644 --- a/include/configs/slimbootloader.h +++ b/include/configs/slimbootloader.h @@ -8,19 +8,6 @@ #include -/* - * By default, CONFIG_SYS_NS16550_PORT_MAPPED is enabled for port io serial. - * To use mmio base serial, enable CONFIG_SYS_NS16550_MEM32 and disable - * CONFIG_SYS_NS16550_PORT_MAPPED until ns16550 driver supports serial port - * configuration in run-time. - * - * #define CONFIG_SYS_NS16550_MEM32 - * #undef CONFIG_SYS_NS16550_PORT_MAPPED - */ -#ifdef CONFIG_SYS_NS16550_MEM32 -#undef CONFIG_SYS_NS16550_PORT_MAPPED -#endif - #define CONFIG_STD_DEVICES_SETTINGS \ "stdin=serial,i8042-kbd,usbkbd\0" \ "stdout=serial\0" \ -- cgit From a6302b7085ce12cb967234e19f2ac2c2320528f1 Mon Sep 17 00:00:00 2001 From: "Park, Aiden" Date: Wed, 18 Dec 2019 05:56:29 +0000 Subject: doc: intel: Update serial driver changes in slimbootloader.rst Now, Slim Bootloader uses NS16550_DYNAMIC to support serial port configuration at runtime, so no more code change is required. Therefore, remove unnecessary steps and fix minor typo. Signed-off-by: Aiden Park Reviewed-by: Bin Meng --- doc/board/intel/slimbootloader.rst | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/doc/board/intel/slimbootloader.rst b/doc/board/intel/slimbootloader.rst index 375e676804..a8c41b1aa7 100644 --- a/doc/board/intel/slimbootloader.rst +++ b/doc/board/intel/slimbootloader.rst @@ -111,35 +111,16 @@ Download it from http://downloads.yoctoproject.org/releases/yocto/yocto-2.0/mach Build Instruction for Slim Bootloader for LeafHill (APL) target --------------------------------------------------------------- -LeafHill is using PCI UART2 device as a serial port. -For MEM32 serial port, CONFIG_SYS_NS16550_MEM32 needs to be enabled in U-Boot. +Prepare U-Boot and Slim Bootloader as described at the beginning of this page. +Also, the PayloadId needs to be set for APL board. -1. Enable CONFIG_SYS_NS16550_MEM32 in U-Boot:: - - $ vi include/configs/slimbootloader.h - +#define CONFIG_SYS_NS16550_MEM32 - #ifdef CONFIG_SYS_NS16550_MEM3 - -2. Build U-Boot:: - - $ make disclean - $ make slimbootloader_defconfig - $ make all - -3. Copy u-boot-dtb.bin to Slim Bootloader. - Slim Bootloader looks for a payload from the specific location. - Copy the build u-boot-dtb.bin to the expected location:: - - $ mkdir -p /PayloadPkg/PayloadBins/ - $ cp /u-boot-dtb.bin /PayloadPkg/PayloadBins/u-boot-dtb.bin - -4. Update PayloadId. Let's use 'U-BT' as an example:: +1. Update PayloadId. Let's use 'U-BT' as an example:: $ vi Platform/ApollolakeBoardPkg/CfgData/CfgData_Int_LeafHill.dlt -GEN_CFG_DATA.PayloadId | 'AUTO +GEN_CFG_DATA.PayloadId | 'U-BT' -5. Update payload text base. +2. Update payload text base. * PAYLOAD_EXE_BASE must be the same as U-Boot CONFIG_SYS_TEXT_BASE in board/intel/slimbootloader/Kconfig. @@ -149,18 +130,18 @@ For MEM32 serial port, CONFIG_SYS_NS16550_MEM32 needs to be enabled in U-Boot. + self.PAYLOAD_LOAD_HIGH = 0 + self.PAYLOAD_EXE_BASE = 0x00100000 -6. Build APL target. Make sure u-boot-dtb.bin and U-BT PayloadId +3. Build APL target. Make sure u-boot-dtb.bin and U-BT PayloadId in build command. The output is Outputs/apl/Stitch_Components.zip:: $ python BuildLoader.py build apl -p "OsLoader.efi:LLDR:Lz4;u-boot-dtb.bin:U-BT:Lzma" -7. Stitch IFWI. +4. Stitch IFWI. Refer to Apollolake_ page in Slim Bootloader document site:: $ python Platform/ApollolakeBoardPkg/Script/StitchLoader.py -i -s Outputs/apl/Stitch_Components.zip -o -8. Flash IFWI. +5. Flash IFWI. Use DediProg to flash IFWI. You should reach at U-Boot serial console. @@ -175,7 +156,7 @@ Build Instruction to use ELF U-Boot 2. Build U-Boot:: - $ make disclean + $ make distclean $ make slimbootloader_defconfig $ make all $ strip u-boot (removing symbol for reduced size) -- cgit From 0d67fac29f3187e67f4fd3ef15f73e91be2fad12 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 8 Jan 2020 20:08:44 +0900 Subject: x86: use invd instead of wbinvd in real mode start code I do not know why the boot code immediately after the system reset should write-back the cache content. I think the cache invalidation should be enough. I tested this commit with qemu-x86_defconfig, and it worked for me. Signed-off-by: Masahiro Yamada Reviewed-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng --- arch/x86/cpu/start.S | 2 +- arch/x86/cpu/start16.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 01524635e9..26cf995db2 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -50,7 +50,7 @@ _x86boot_start: movl %cr0, %eax orl $(X86_CR0_NW | X86_CR0_CD), %eax movl %eax, %cr0 - wbinvd + invd /* * Zero the BIST (Built-In Self Test) value since we don't have it. diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 54f4ff6662..292e750508 100644 --- a/arch/x86/cpu/start16.S +++ b/arch/x86/cpu/start16.S @@ -28,7 +28,7 @@ start16: movl %cr0, %eax orl $(X86_CR0_NW | X86_CR0_CD), %eax movl %eax, %cr0 - wbinvd + invd /* load the temporary Global Descriptor Table */ data32 cs lidt idt_ptr -- cgit From 2fa863e9aa4e9d5638c6a8555a7d71dc38e79b90 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 8 Jan 2020 20:13:42 +0900 Subject: x86: limit the fs segment to the pointer size The fs segment is only used to get the global data pointer. If it is accessed beyond sizeof(new_gd->arch.gd_addr), it is a bug. To specify the byte-granule limit size, drop the G bit, so the flag field is 0x8093 instead of 0xc093, and set the limit field to sizeof(new_gd->arch.gd_addr) - 1. Signed-off-by: Masahiro Yamada Reviewed-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng [bmeng: fixed the comments about FS segement] Signed-off-by: Bin Meng --- arch/x86/cpu/i386/cpu.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index 1592b2c9d3..c8da7f10e9 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -136,10 +136,14 @@ void arch_setup_gd(gd_t *new_gd) /* DS: data, read/write, 4 GB, base 0 */ gdt_addr[X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff); - /* FS: data, read/write, 4 GB, base (Global Data Pointer) */ + /* + * FS: data, read/write, sizeof (Global Data Pointer), + * base (Global Data Pointer) + */ new_gd->arch.gd_addr = new_gd; - gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0xc093, - (ulong)&new_gd->arch.gd_addr, 0xfffff); + gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0x8093, + (ulong)&new_gd->arch.gd_addr, + sizeof(new_gd->arch.gd_addr) - 1); /* 16-bit CS: code, read/execute, 64 kB, base 0 */ gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff); -- cgit From d88030a83b6e48e39361b22818c93be602f32802 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 9 Jan 2020 20:33:32 +0100 Subject: doc: Chromebook Coral: fix build warnings Use valid restructured text to avoid warnings like WARNING: Title underline too short. WARNING: Block quote ends without a blank line; unexpected unindent. when building with `make htmldocs`. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng --- doc/board/google/chromebook_coral.rst | 90 ++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/doc/board/google/chromebook_coral.rst b/doc/board/google/chromebook_coral.rst index 515fd06d76..5dc3c97c3d 100644 --- a/doc/board/google/chromebook_coral.rst +++ b/doc/board/google/chromebook_coral.rst @@ -112,7 +112,7 @@ U-Boot then shuts down CAR and jumps to its relocated version. Boot flow - U-Boot post-relocation ---------------------------------- +---------------------------------- U-Boot starts up normally, running near the top of RAM. After driver model is running, arch_fsp_init_r() is called which loads and runs the FSP-S binary. @@ -142,54 +142,56 @@ Performance ----------- Bootstage is used through all phases of U-Boot to keep accurate timimgs for -boot. Use 'bootstage report' in U-Boot to see the report, e.g.: - -Timer summary in microseconds (16 records): - Mark Elapsed Stage - 0 0 reset - 155,325 155,325 TPL - 204,014 48,689 end TPL - 204,385 371 SPL - 738,633 534,248 end SPL - 739,161 528 board_init_f - 842,764 103,603 board_init_r - 1,166,233 323,469 main_loop - 1,166,283 50 id=175 - -Accumulated time: - 62 fast_spi - 202 dm_r - 7,779 dm_spl - 15,555 dm_f - 208,357 fsp-m - 239,847 fsp-s - 292,143 mmap_spi - -CPU performance is about 3500 DMIPS: - -=> dhry -1000000 iterations in 161 ms: 6211180/s, 3535 DMIPS +boot. Use 'bootstage report' in U-Boot to see the report, e.g.:: + + Timer summary in microseconds (16 records): + Mark Elapsed Stage + 0 0 reset + 155,325 155,325 TPL + 204,014 48,689 end TPL + 204,385 371 SPL + 738,633 534,248 end SPL + 739,161 528 board_init_f + 842,764 103,603 board_init_r + 1,166,233 323,469 main_loop + 1,166,283 50 id=175 + + Accumulated time: + 62 fast_spi + 202 dm_r + 7,779 dm_spl + 15,555 dm_f + 208,357 fsp-m + 239,847 fsp-s + 292,143 mmap_spi + +CPU performance is about 3500 DMIPS:: + + => dhry + 1000000 iterations in 161 ms: 6211180/s, 3535 DMIPS Partial memory map ------------------ -ffffffff Top of ROM (and last byte of 32-bit address space) -ffff8000 TPL loaded here (from IFWI) -ff000000 Bottom of ROM -fefc000 Top of CAR region -fef96000 Stack for FSP-M -fef40000 59000 FSP-M -fef11000 SPL loaded here -fef10000 CONFIG_BLOBLIST_ADDR -fef10000 Stack top in TPL, SPL and U-Boot before relocation -fef00000 1000 CONFIG_BOOTSTAGE_STASH_ADDR -fef00000 Base of CAR region - - f0000 CONFIG_ROM_TABLE_ADDR - 120000 BSS (defined in u-boot-spl.lds) - 200000 FSP-S (which is run after U-Boot is relocated) - 1110000 CONFIG_SYS_TEXT_BASE +:: + + ffffffff Top of ROM (and last byte of 32-bit address space) + ffff8000 TPL loaded here (from IFWI) + ff000000 Bottom of ROM + fefc000 Top of CAR region + fef96000 Stack for FSP-M + fef40000 59000 FSP-M + fef11000 SPL loaded here + fef10000 CONFIG_BLOBLIST_ADDR + fef10000 Stack top in TPL, SPL and U-Boot before relocation + fef00000 1000 CONFIG_BOOTSTAGE_STASH_ADDR + fef00000 Base of CAR region + + f0000 CONFIG_ROM_TABLE_ADDR + 120000 BSS (defined in u-boot-spl.lds) + 200000 FSP-S (which is run after U-Boot is relocated) + 1110000 CONFIG_SYS_TEXT_BASE Supported peripherals -- cgit From 42fddfc9d8551de51e6220e8119d418af9851f94 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 9 Jan 2020 23:12:34 +0200 Subject: x86: edison: Enable command line editing Enable command line editing, because it is extremely convenient. Signed-off-by: Marek Vasut Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- configs/edison_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/configs/edison_defconfig b/configs/edison_defconfig index 14b2eec3ba..124f0f628f 100644 --- a/configs/edison_defconfig +++ b/configs/edison_defconfig @@ -9,7 +9,6 @@ CONFIG_SMP=y CONFIG_BOARD_EARLY_INIT_R=y CONFIG_LAST_STAGE_INIT=y CONFIG_HUSH_PARSER=y -# CONFIG_CMDLINE_EDITING is not set CONFIG_CMD_CPU=y CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y -- cgit From b58d85363ff5bcd4293387e9e18e12e1add69e4a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 9 Jan 2020 23:12:35 +0200 Subject: x86: edison: Switch to ACPI mode SFI is quite poor and useless resource provider. Moreover it makes hard to develop and extend functionality in the Linux kernel. Enable a necessary minimum to use ACPI on Intel Edison. Linux kernel have been prepared for this change since v5.4, where the last crucial driver, i.e. for Basin Cove PMIC, has been submitted. Note, that stock image won't suffer by this change since it doesn't have ACPI enabled on the kernel level. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- configs/edison_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/edison_defconfig b/configs/edison_defconfig index 124f0f628f..58707d619a 100644 --- a/configs/edison_defconfig +++ b/configs/edison_defconfig @@ -6,6 +6,7 @@ CONFIG_NR_DRAM_BANKS=3 CONFIG_VENDOR_INTEL=y CONFIG_TARGET_EDISON=y CONFIG_SMP=y +CONFIG_GENERATE_ACPI_TABLE=y CONFIG_BOARD_EARLY_INIT_R=y CONFIG_LAST_STAGE_INIT=y CONFIG_HUSH_PARSER=y -- cgit From 5e579cc0044b8660fff7fbc043982ff80ff7be7a Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Tue, 14 Jan 2020 14:05:48 +0100 Subject: spi: ich: Drop while loop in hardware sequencing erase case When ich_spi_exec_op_hwseq() is called to erase a 4k block (opcode = SPINOR_OP_BE_4K), it expects to find a length value in op->data.nbytes, but that value is always 0. As a result, the while loop is never executed and no erase is carried out. Fix this by dropping the loop code entirely, only keeping the relevant parts of the loop body. See http://patchwork.ozlabs.org/patch/1222779/ for more detailed background information and discussion. Signed-off-by: Wolfgang Wallner Reviewed-by: Simon Glass Signed-off-by: Bin Meng --- drivers/spi/ich.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 133b25b72e..a9d7715a55 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -562,16 +562,8 @@ static int ich_spi_exec_op_hwseq(struct spi_slave *slave, return 0; /* ignore */ case SPINOR_OP_BE_4K: cycle = HSFSTS_CYCLE_4K_ERASE; - while (len) { - uint xfer_len = 0x1000; - - ret = exec_sync_hwseq_xfer(regs, cycle, offset, 0); - if (ret) - return ret; - offset += xfer_len; - len -= xfer_len; - } - return 0; + ret = exec_sync_hwseq_xfer(regs, cycle, offset, 0); + return ret; default: debug("Unknown cycle %x\n", op->cmd.opcode); return -EINVAL; -- cgit From 7d53b5a4ceaf86ecfe1bee097f27b49557e7cf7a Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Wed, 22 Jan 2020 16:01:44 +0100 Subject: x86: apl: Add the term "Interrupt Timer Subsystem" to ITSS files ITSS stands for "Interrupt Timer Subsystem", so add that term to the description of the relevant files. Signed-off-by: Wolfgang Wallner Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/apollolake/itss.c | 2 +- arch/x86/include/asm/arch-apollolake/itss.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/cpu/apollolake/itss.c b/arch/x86/cpu/apollolake/itss.c index 8789f8e6bb..95c9ebddc1 100644 --- a/arch/x86/cpu/apollolake/itss.c +++ b/arch/x86/cpu/apollolake/itss.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Something to do with Interrupts, but I don't know what ITSS stands for + * Interrupt Timer Subsystem * * Copyright (C) 2017 Intel Corporation. * Copyright (C) 2017 Siemens AG diff --git a/arch/x86/include/asm/arch-apollolake/itss.h b/arch/x86/include/asm/arch-apollolake/itss.h index 1e29503974..c75d8fe8c2 100644 --- a/arch/x86/include/asm/arch-apollolake/itss.h +++ b/arch/x86/include/asm/arch-apollolake/itss.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* + * Interrupt Timer Subsystem + * * Copyright (C) 2017 Intel Corporation. * Copyright 2019 Google LLC * -- cgit From 142c9751a6cb7e2f9d18847570bc01c5e991aeeb Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Wed, 22 Jan 2020 16:01:45 +0100 Subject: x86: Move itss.h from Apollo Lake to the generic x86 include directory The code in this file is not specific to Apollo Lake. According to coreboot sources (where this code comes from), it is common to at least: * Apollo Lake * Cannon Lake * Ice Lake * Skylake Signed-off-by: Wolfgang Wallner Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/apollolake/itss.c | 2 +- arch/x86/include/asm/arch-apollolake/itss.h | 45 ----------------------------- arch/x86/include/asm/itss.h | 45 +++++++++++++++++++++++++++++ drivers/pinctrl/intel/pinctrl.c | 2 +- 4 files changed, 47 insertions(+), 47 deletions(-) delete mode 100644 arch/x86/include/asm/arch-apollolake/itss.h create mode 100644 arch/x86/include/asm/itss.h diff --git a/arch/x86/cpu/apollolake/itss.c b/arch/x86/cpu/apollolake/itss.c index 95c9ebddc1..ff7a83d618 100644 --- a/arch/x86/cpu/apollolake/itss.c +++ b/arch/x86/cpu/apollolake/itss.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include struct apl_itss_platdata { #if CONFIG_IS_ENABLED(OF_PLATDATA) diff --git a/arch/x86/include/asm/arch-apollolake/itss.h b/arch/x86/include/asm/arch-apollolake/itss.h deleted file mode 100644 index c75d8fe8c2..0000000000 --- a/arch/x86/include/asm/arch-apollolake/itss.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Interrupt Timer Subsystem - * - * Copyright (C) 2017 Intel Corporation. - * Copyright 2019 Google LLC - * - * Modified from coreboot itss.h - */ - -#ifndef _ASM_ARCH_ITSS_H -#define _ASM_ARCH_ITSS_H - -#define GPIO_IRQ_START 50 -#define GPIO_IRQ_END ITSS_MAX_IRQ - -#define ITSS_MAX_IRQ 119 -#define IRQS_PER_IPC 32 -#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1) / IRQS_PER_IPC) - -/* Max PXRC registers in ITSS */ -#define MAX_PXRC_CONFIG (PCR_ITSS_PIRQH_ROUT - PCR_ITSS_PIRQA_ROUT + 1) - -/* PIRQA Routing Control Register */ -#define PCR_ITSS_PIRQA_ROUT 0x3100 -/* PIRQB Routing Control Register */ -#define PCR_ITSS_PIRQB_ROUT 0x3101 -/* PIRQC Routing Control Register */ -#define PCR_ITSS_PIRQC_ROUT 0x3102 -/* PIRQD Routing Control Register */ -#define PCR_ITSS_PIRQD_ROUT 0x3103 -/* PIRQE Routing Control Register */ -#define PCR_ITSS_PIRQE_ROUT 0x3104 -/* PIRQF Routing Control Register */ -#define PCR_ITSS_PIRQF_ROUT 0x3105 -/* PIRQG Routing Control Register */ -#define PCR_ITSS_PIRQG_ROUT 0x3106 -/* PIRQH Routing Control Register */ -#define PCR_ITSS_PIRQH_ROUT 0x3107 -/* ITSS Interrupt polarity control */ -#define PCR_ITSS_IPC0_CONF 0x3200 -/* ITSS Power reduction control */ -#define PCR_ITSS_ITSSPRC 0x3300 - -#endif /* _ASM_ARCH_ITSS_H */ diff --git a/arch/x86/include/asm/itss.h b/arch/x86/include/asm/itss.h new file mode 100644 index 0000000000..c75d8fe8c2 --- /dev/null +++ b/arch/x86/include/asm/itss.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Interrupt Timer Subsystem + * + * Copyright (C) 2017 Intel Corporation. + * Copyright 2019 Google LLC + * + * Modified from coreboot itss.h + */ + +#ifndef _ASM_ARCH_ITSS_H +#define _ASM_ARCH_ITSS_H + +#define GPIO_IRQ_START 50 +#define GPIO_IRQ_END ITSS_MAX_IRQ + +#define ITSS_MAX_IRQ 119 +#define IRQS_PER_IPC 32 +#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1) / IRQS_PER_IPC) + +/* Max PXRC registers in ITSS */ +#define MAX_PXRC_CONFIG (PCR_ITSS_PIRQH_ROUT - PCR_ITSS_PIRQA_ROUT + 1) + +/* PIRQA Routing Control Register */ +#define PCR_ITSS_PIRQA_ROUT 0x3100 +/* PIRQB Routing Control Register */ +#define PCR_ITSS_PIRQB_ROUT 0x3101 +/* PIRQC Routing Control Register */ +#define PCR_ITSS_PIRQC_ROUT 0x3102 +/* PIRQD Routing Control Register */ +#define PCR_ITSS_PIRQD_ROUT 0x3103 +/* PIRQE Routing Control Register */ +#define PCR_ITSS_PIRQE_ROUT 0x3104 +/* PIRQF Routing Control Register */ +#define PCR_ITSS_PIRQF_ROUT 0x3105 +/* PIRQG Routing Control Register */ +#define PCR_ITSS_PIRQG_ROUT 0x3106 +/* PIRQH Routing Control Register */ +#define PCR_ITSS_PIRQH_ROUT 0x3107 +/* ITSS Interrupt polarity control */ +#define PCR_ITSS_IPC0_CONF 0x3200 +/* ITSS Power reduction control */ +#define PCR_ITSS_ITSSPRC 0x3300 + +#endif /* _ASM_ARCH_ITSS_H */ diff --git a/drivers/pinctrl/intel/pinctrl.c b/drivers/pinctrl/intel/pinctrl.c index 4875a3b0b5..5bf5d8b0e2 100644 --- a/drivers/pinctrl/intel/pinctrl.c +++ b/drivers/pinctrl/intel/pinctrl.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include -- cgit From 43709fa0888cc80648939ae1588307334e6cc267 Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Wed, 22 Jan 2020 16:01:46 +0100 Subject: x86: Move itss.c from Apollo Lake to a more generic location The Interrupt Timer Subsystem (ITSS) is not specific to Apollo Lake, so move it to a common location within arch/x86. Signed-off-by: Wolfgang Wallner Reviewed-by: Simon Glass Reviewed-by: Bin Meng [bmeng: conditionally build itss.c] Signed-off-by: Bin Meng --- arch/x86/cpu/apollolake/Makefile | 1 - arch/x86/cpu/apollolake/itss.c | 214 ------------------------------------- arch/x86/cpu/intel_common/Makefile | 3 + arch/x86/cpu/intel_common/itss.c | 214 +++++++++++++++++++++++++++++++++++++ 4 files changed, 217 insertions(+), 215 deletions(-) delete mode 100644 arch/x86/cpu/apollolake/itss.c create mode 100644 arch/x86/cpu/intel_common/itss.c diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile index 1760df54d8..f99f2c6473 100644 --- a/arch/x86/cpu/apollolake/Makefile +++ b/arch/x86/cpu/apollolake/Makefile @@ -19,7 +19,6 @@ obj-y += fsp_s.o endif obj-y += hostbridge.o -obj-y += itss.o obj-y += lpc.o obj-y += p2sb.o obj-y += pch.o diff --git a/arch/x86/cpu/apollolake/itss.c b/arch/x86/cpu/apollolake/itss.c deleted file mode 100644 index ff7a83d618..0000000000 --- a/arch/x86/cpu/apollolake/itss.c +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Interrupt Timer Subsystem - * - * Copyright (C) 2017 Intel Corporation. - * Copyright (C) 2017 Siemens AG - * Copyright 2019 Google LLC - * - * Taken from coreboot itss.c - */ - -#include -#include -#include -#include -#include -#include -#include - -struct apl_itss_platdata { -#if CONFIG_IS_ENABLED(OF_PLATDATA) - /* Put this first since driver model will copy the data here */ - struct dtd_intel_apl_itss dtplat; -#endif -}; - -/* struct pmc_route - Routing for PMC to GPIO */ -struct pmc_route { - u32 pmc; - u32 gpio; -}; - -struct apl_itss_priv { - struct pmc_route *route; - uint route_count; - u32 irq_snapshot[NUM_IPC_REGS]; -}; - -static int apl_set_polarity(struct udevice *dev, uint irq, bool active_low) -{ - u32 mask; - uint reg; - - if (irq > ITSS_MAX_IRQ) - return -EINVAL; - - reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * (irq / IRQS_PER_IPC); - mask = 1 << (irq % IRQS_PER_IPC); - - pcr_clrsetbits32(dev, reg, mask, active_low ? mask : 0); - - return 0; -} - -#ifndef CONFIG_TPL_BUILD -static int apl_snapshot_polarities(struct udevice *dev) -{ - struct apl_itss_priv *priv = dev_get_priv(dev); - const int start = GPIO_IRQ_START; - const int end = GPIO_IRQ_END; - int reg_start; - int reg_end; - int i; - - reg_start = start / IRQS_PER_IPC; - reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC; - - for (i = reg_start; i < reg_end; i++) { - uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; - - priv->irq_snapshot[i] = pcr_read32(dev, reg); - } - - return 0; -} - -static void show_polarities(struct udevice *dev, const char *msg) -{ - int i; - - log_info("ITSS IRQ Polarities %s:\n", msg); - for (i = 0; i < NUM_IPC_REGS; i++) { - uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; - - log_info("IPC%d: 0x%08x\n", i, pcr_read32(dev, reg)); - } -} - -static int apl_restore_polarities(struct udevice *dev) -{ - struct apl_itss_priv *priv = dev_get_priv(dev); - const int start = GPIO_IRQ_START; - const int end = GPIO_IRQ_END; - int reg_start; - int reg_end; - int i; - - show_polarities(dev, "Before"); - - reg_start = start / IRQS_PER_IPC; - reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC; - - for (i = reg_start; i < reg_end; i++) { - u32 mask; - u16 reg; - int irq_start; - int irq_end; - - irq_start = i * IRQS_PER_IPC; - irq_end = min(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ); - - if (start > irq_end) - continue; - if (end < irq_start) - break; - - /* Track bits within the bounds of of the register */ - irq_start = max(start, irq_start) % IRQS_PER_IPC; - irq_end = min(end, irq_end) % IRQS_PER_IPC; - - /* Create bitmask of the inclusive range of start and end */ - mask = (((1U << irq_end) - 1) | (1U << irq_end)); - mask &= ~((1U << irq_start) - 1); - - reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; - pcr_clrsetbits32(dev, reg, mask, mask & priv->irq_snapshot[i]); - } - - show_polarities(dev, "After"); - - return 0; -} -#endif - -static int apl_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) -{ - struct apl_itss_priv *priv = dev_get_priv(dev); - struct pmc_route *route; - int i; - - for (i = 0, route = priv->route; i < priv->route_count; i++, route++) { - if (pmc_gpe_num == route->pmc) - return route->gpio; - } - - return -ENOENT; -} - -static int apl_itss_ofdata_to_platdata(struct udevice *dev) -{ - struct apl_itss_priv *priv = dev_get_priv(dev); - int ret; - -#if CONFIG_IS_ENABLED(OF_PLATDATA) - struct apl_itss_platdata *plat = dev_get_platdata(dev); - struct dtd_intel_apl_itss *dtplat = &plat->dtplat; - - /* - * It would be nice to do this in the bind() method, but with - * of-platdata binding happens in the order that DM finds things in the - * linker list (i.e. alphabetical order by driver name). So the GPIO - * device may well be bound before its parent (p2sb), and this call - * will fail if p2sb is not bound yet. - * - * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc - */ - ret = p2sb_set_port_id(dev, dtplat->intel_p2sb_port_id); - if (ret) - return log_msg_ret("Could not set port id", ret); - priv->route = (struct pmc_route *)dtplat->intel_pmc_routes; - priv->route_count = ARRAY_SIZE(dtplat->intel_pmc_routes) / - sizeof(struct pmc_route); -#else - int size; - - size = dev_read_size(dev, "intel,pmc-routes"); - if (size < 0) - return size; - priv->route = malloc(size); - if (!priv->route) - return -ENOMEM; - ret = dev_read_u32_array(dev, "intel,pmc-routes", (u32 *)priv->route, - size / sizeof(fdt32_t)); - if (ret) - return log_msg_ret("Cannot read pmc-routes", ret); - priv->route_count = size / sizeof(struct pmc_route); -#endif - - return 0; -} - -static const struct irq_ops apl_itss_ops = { - .route_pmc_gpio_gpe = apl_route_pmc_gpio_gpe, - .set_polarity = apl_set_polarity, -#ifndef CONFIG_TPL_BUILD - .snapshot_polarities = apl_snapshot_polarities, - .restore_polarities = apl_restore_polarities, -#endif -}; - -static const struct udevice_id apl_itss_ids[] = { - { .compatible = "intel,apl-itss"}, - { } -}; - -U_BOOT_DRIVER(apl_itss_drv) = { - .name = "intel_apl_itss", - .id = UCLASS_IRQ, - .of_match = apl_itss_ids, - .ops = &apl_itss_ops, - .ofdata_to_platdata = apl_itss_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct apl_itss_platdata), - .priv_auto_alloc_size = sizeof(struct apl_itss_priv), -}; diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index cc4e1c962b..1e7a72f2ba 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -27,6 +27,9 @@ obj-y += microcode.o endif endif obj-y += pch.o +ifdef CONFIG_INTEL_APOLLOLAKE +obj-y += itss.o +endif ifdef CONFIG_SPL ifndef CONFIG_SPL_BUILD diff --git a/arch/x86/cpu/intel_common/itss.c b/arch/x86/cpu/intel_common/itss.c new file mode 100644 index 0000000000..ff7a83d618 --- /dev/null +++ b/arch/x86/cpu/intel_common/itss.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Interrupt Timer Subsystem + * + * Copyright (C) 2017 Intel Corporation. + * Copyright (C) 2017 Siemens AG + * Copyright 2019 Google LLC + * + * Taken from coreboot itss.c + */ + +#include +#include +#include +#include +#include +#include +#include + +struct apl_itss_platdata { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + /* Put this first since driver model will copy the data here */ + struct dtd_intel_apl_itss dtplat; +#endif +}; + +/* struct pmc_route - Routing for PMC to GPIO */ +struct pmc_route { + u32 pmc; + u32 gpio; +}; + +struct apl_itss_priv { + struct pmc_route *route; + uint route_count; + u32 irq_snapshot[NUM_IPC_REGS]; +}; + +static int apl_set_polarity(struct udevice *dev, uint irq, bool active_low) +{ + u32 mask; + uint reg; + + if (irq > ITSS_MAX_IRQ) + return -EINVAL; + + reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * (irq / IRQS_PER_IPC); + mask = 1 << (irq % IRQS_PER_IPC); + + pcr_clrsetbits32(dev, reg, mask, active_low ? mask : 0); + + return 0; +} + +#ifndef CONFIG_TPL_BUILD +static int apl_snapshot_polarities(struct udevice *dev) +{ + struct apl_itss_priv *priv = dev_get_priv(dev); + const int start = GPIO_IRQ_START; + const int end = GPIO_IRQ_END; + int reg_start; + int reg_end; + int i; + + reg_start = start / IRQS_PER_IPC; + reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC; + + for (i = reg_start; i < reg_end; i++) { + uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; + + priv->irq_snapshot[i] = pcr_read32(dev, reg); + } + + return 0; +} + +static void show_polarities(struct udevice *dev, const char *msg) +{ + int i; + + log_info("ITSS IRQ Polarities %s:\n", msg); + for (i = 0; i < NUM_IPC_REGS; i++) { + uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; + + log_info("IPC%d: 0x%08x\n", i, pcr_read32(dev, reg)); + } +} + +static int apl_restore_polarities(struct udevice *dev) +{ + struct apl_itss_priv *priv = dev_get_priv(dev); + const int start = GPIO_IRQ_START; + const int end = GPIO_IRQ_END; + int reg_start; + int reg_end; + int i; + + show_polarities(dev, "Before"); + + reg_start = start / IRQS_PER_IPC; + reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC; + + for (i = reg_start; i < reg_end; i++) { + u32 mask; + u16 reg; + int irq_start; + int irq_end; + + irq_start = i * IRQS_PER_IPC; + irq_end = min(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ); + + if (start > irq_end) + continue; + if (end < irq_start) + break; + + /* Track bits within the bounds of of the register */ + irq_start = max(start, irq_start) % IRQS_PER_IPC; + irq_end = min(end, irq_end) % IRQS_PER_IPC; + + /* Create bitmask of the inclusive range of start and end */ + mask = (((1U << irq_end) - 1) | (1U << irq_end)); + mask &= ~((1U << irq_start) - 1); + + reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i; + pcr_clrsetbits32(dev, reg, mask, mask & priv->irq_snapshot[i]); + } + + show_polarities(dev, "After"); + + return 0; +} +#endif + +static int apl_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) +{ + struct apl_itss_priv *priv = dev_get_priv(dev); + struct pmc_route *route; + int i; + + for (i = 0, route = priv->route; i < priv->route_count; i++, route++) { + if (pmc_gpe_num == route->pmc) + return route->gpio; + } + + return -ENOENT; +} + +static int apl_itss_ofdata_to_platdata(struct udevice *dev) +{ + struct apl_itss_priv *priv = dev_get_priv(dev); + int ret; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct apl_itss_platdata *plat = dev_get_platdata(dev); + struct dtd_intel_apl_itss *dtplat = &plat->dtplat; + + /* + * It would be nice to do this in the bind() method, but with + * of-platdata binding happens in the order that DM finds things in the + * linker list (i.e. alphabetical order by driver name). So the GPIO + * device may well be bound before its parent (p2sb), and this call + * will fail if p2sb is not bound yet. + * + * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc + */ + ret = p2sb_set_port_id(dev, dtplat->intel_p2sb_port_id); + if (ret) + return log_msg_ret("Could not set port id", ret); + priv->route = (struct pmc_route *)dtplat->intel_pmc_routes; + priv->route_count = ARRAY_SIZE(dtplat->intel_pmc_routes) / + sizeof(struct pmc_route); +#else + int size; + + size = dev_read_size(dev, "intel,pmc-routes"); + if (size < 0) + return size; + priv->route = malloc(size); + if (!priv->route) + return -ENOMEM; + ret = dev_read_u32_array(dev, "intel,pmc-routes", (u32 *)priv->route, + size / sizeof(fdt32_t)); + if (ret) + return log_msg_ret("Cannot read pmc-routes", ret); + priv->route_count = size / sizeof(struct pmc_route); +#endif + + return 0; +} + +static const struct irq_ops apl_itss_ops = { + .route_pmc_gpio_gpe = apl_route_pmc_gpio_gpe, + .set_polarity = apl_set_polarity, +#ifndef CONFIG_TPL_BUILD + .snapshot_polarities = apl_snapshot_polarities, + .restore_polarities = apl_restore_polarities, +#endif +}; + +static const struct udevice_id apl_itss_ids[] = { + { .compatible = "intel,apl-itss"}, + { } +}; + +U_BOOT_DRIVER(apl_itss_drv) = { + .name = "intel_apl_itss", + .id = UCLASS_IRQ, + .of_match = apl_itss_ids, + .ops = &apl_itss_ops, + .ofdata_to_platdata = apl_itss_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct apl_itss_platdata), + .priv_auto_alloc_size = sizeof(struct apl_itss_priv), +}; -- cgit From 1d5bf32f0feaac806f85f128befd619cc81e7e08 Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Mon, 3 Feb 2020 14:06:45 +0100 Subject: x86: itss: Add a Kconfig option to enable/disable ITSS driver Add a Kconfig option to support enabling/disabling the inclusion of the ITSS driver depending on the platform. Atuomatically select the ITSS driver when building for Apollo Lake. Signed-off-by: Wolfgang Wallner Reviewed-by: Simon Glass Reviewed-by: Bin Meng [bmeng: squashed in http://patchwork.ozlabs.org/patch/1232761/] Signed-off-by: Bin Meng --- arch/x86/Kconfig | 6 ++++++ arch/x86/cpu/apollolake/Kconfig | 1 + arch/x86/cpu/intel_common/Makefile | 4 +--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 89b93e5de2..b733d2264e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -709,6 +709,12 @@ config ROM_TABLE_SIZE hex default 0x10000 +config HAVE_ITSS + bool "Enable ITSS" + help + Select this to include the driver for the Interrupt Timer + Subsystem (ITSS) which is found on several Intel devices. + menu "System tables" depends on !EFI && !SYS_COREBOOT diff --git a/arch/x86/cpu/apollolake/Kconfig b/arch/x86/cpu/apollolake/Kconfig index fcff176c27..a760e0ac68 100644 --- a/arch/x86/cpu/apollolake/Kconfig +++ b/arch/x86/cpu/apollolake/Kconfig @@ -39,6 +39,7 @@ config INTEL_APOLLOLAKE imply HAVE_X86_FIT imply INTEL_GPIO imply SMP + imply HAVE_ITSS if INTEL_APOLLOLAKE diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 1e7a72f2ba..e22c70781d 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -27,9 +27,7 @@ obj-y += microcode.o endif endif obj-y += pch.o -ifdef CONFIG_INTEL_APOLLOLAKE -obj-y += itss.o -endif +obj-$(CONFIG_HAVE_ITSS) += itss.o ifdef CONFIG_SPL ifndef CONFIG_SPL_BUILD -- cgit From 03fe85a27b23c609233100ccbab1617d78a73d84 Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Wed, 22 Jan 2020 16:01:47 +0100 Subject: x86: itss: Remove apl-prefix The Interrupt Timer Subsystem (ITSS) is not specific to Apollo Lake, so remove the apl-prefix of the implemented functions/structures/... Signed-off-by: Wolfgang Wallner Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/intel_common/itss.c | 56 +++++++++++++++++++-------------------- arch/x86/dts/chromebook_coral.dts | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/arch/x86/cpu/intel_common/itss.c b/arch/x86/cpu/intel_common/itss.c index ff7a83d618..9df51adecc 100644 --- a/arch/x86/cpu/intel_common/itss.c +++ b/arch/x86/cpu/intel_common/itss.c @@ -17,10 +17,10 @@ #include #include -struct apl_itss_platdata { +struct itss_platdata { #if CONFIG_IS_ENABLED(OF_PLATDATA) /* Put this first since driver model will copy the data here */ - struct dtd_intel_apl_itss dtplat; + struct dtd_intel_itss dtplat; #endif }; @@ -30,13 +30,13 @@ struct pmc_route { u32 gpio; }; -struct apl_itss_priv { +struct itss_priv { struct pmc_route *route; uint route_count; u32 irq_snapshot[NUM_IPC_REGS]; }; -static int apl_set_polarity(struct udevice *dev, uint irq, bool active_low) +static int set_polarity(struct udevice *dev, uint irq, bool active_low) { u32 mask; uint reg; @@ -53,9 +53,9 @@ static int apl_set_polarity(struct udevice *dev, uint irq, bool active_low) } #ifndef CONFIG_TPL_BUILD -static int apl_snapshot_polarities(struct udevice *dev) +static int snapshot_polarities(struct udevice *dev) { - struct apl_itss_priv *priv = dev_get_priv(dev); + struct itss_priv *priv = dev_get_priv(dev); const int start = GPIO_IRQ_START; const int end = GPIO_IRQ_END; int reg_start; @@ -86,9 +86,9 @@ static void show_polarities(struct udevice *dev, const char *msg) } } -static int apl_restore_polarities(struct udevice *dev) +static int restore_polarities(struct udevice *dev) { - struct apl_itss_priv *priv = dev_get_priv(dev); + struct itss_priv *priv = dev_get_priv(dev); const int start = GPIO_IRQ_START; const int end = GPIO_IRQ_END; int reg_start; @@ -132,9 +132,9 @@ static int apl_restore_polarities(struct udevice *dev) } #endif -static int apl_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) +static int route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) { - struct apl_itss_priv *priv = dev_get_priv(dev); + struct itss_priv *priv = dev_get_priv(dev); struct pmc_route *route; int i; @@ -146,14 +146,14 @@ static int apl_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) return -ENOENT; } -static int apl_itss_ofdata_to_platdata(struct udevice *dev) +static int itss_ofdata_to_platdata(struct udevice *dev) { - struct apl_itss_priv *priv = dev_get_priv(dev); + struct itss_priv *priv = dev_get_priv(dev); int ret; #if CONFIG_IS_ENABLED(OF_PLATDATA) - struct apl_itss_platdata *plat = dev_get_platdata(dev); - struct dtd_intel_apl_itss *dtplat = &plat->dtplat; + struct itss_platdata *plat = dev_get_platdata(dev); + struct dtd_intel_itss *dtplat = &plat->dtplat; /* * It would be nice to do this in the bind() method, but with @@ -189,26 +189,26 @@ static int apl_itss_ofdata_to_platdata(struct udevice *dev) return 0; } -static const struct irq_ops apl_itss_ops = { - .route_pmc_gpio_gpe = apl_route_pmc_gpio_gpe, - .set_polarity = apl_set_polarity, +static const struct irq_ops itss_ops = { + .route_pmc_gpio_gpe = route_pmc_gpio_gpe, + .set_polarity = set_polarity, #ifndef CONFIG_TPL_BUILD - .snapshot_polarities = apl_snapshot_polarities, - .restore_polarities = apl_restore_polarities, + .snapshot_polarities = snapshot_polarities, + .restore_polarities = restore_polarities, #endif }; -static const struct udevice_id apl_itss_ids[] = { - { .compatible = "intel,apl-itss"}, +static const struct udevice_id itss_ids[] = { + { .compatible = "intel,itss"}, { } }; -U_BOOT_DRIVER(apl_itss_drv) = { - .name = "intel_apl_itss", +U_BOOT_DRIVER(itss_drv) = { + .name = "intel_itss", .id = UCLASS_IRQ, - .of_match = apl_itss_ids, - .ops = &apl_itss_ops, - .ofdata_to_platdata = apl_itss_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct apl_itss_platdata), - .priv_auto_alloc_size = sizeof(struct apl_itss_priv), + .of_match = itss_ids, + .ops = &itss_ops, + .ofdata_to_platdata = itss_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct itss_platdata), + .priv_auto_alloc_size = sizeof(struct itss_priv), }; diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts index 24fcbb5063..a1820fa187 100644 --- a/arch/x86/dts/chromebook_coral.dts +++ b/arch/x86/dts/chromebook_coral.dts @@ -171,7 +171,7 @@ itss { u-boot,dm-pre-reloc; - compatible = "intel,apl-itss"; + compatible = "intel,itss"; intel,p2sb-port-id = ; intel,pmc-routes = < PMC_GPE_SW_31_0 GPIO_GPE_SW_31_0 -- cgit From b840c395c64fd2dfadb96717bb6898a3069239a0 Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Mon, 3 Feb 2020 11:38:04 +0100 Subject: gpio: intel_gpio: Pass pinctrl device to pcr_clrsetbits32() The function pcr_clrsetbits32() expects a device with a P2SB parent device. In intel_gpio_direction_output() and intel_gpio_set_value() the device 'dev' is passed to pcr_clrsetbits32(), which is a gpio-controller with a device 'pinctrl' as parent. This does not match the expectations of pcr_clrsetbits32(). But the 'pinctrl' device has a P2SB as parent. Pass the 'pinctrl' device instead of the 'dev' device to pcr_clrsetbits32(). Signed-off-by: Wolfgang Wallner Reviewed-by: Bin Meng --- drivers/gpio/intel_gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c index 4bf1c9ddc4..b05cfc4aed 100644 --- a/drivers/gpio/intel_gpio.c +++ b/drivers/gpio/intel_gpio.c @@ -39,7 +39,7 @@ static int intel_gpio_direction_output(struct udevice *dev, uint offset, struct udevice *pinctrl = dev_get_parent(dev); uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset); - pcr_clrsetbits32(dev, config_offset, + pcr_clrsetbits32(pinctrl, config_offset, PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE | PAD_CFG0_TX_DISABLE, PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE | @@ -72,7 +72,7 @@ static int intel_gpio_set_value(struct udevice *dev, unsigned offset, int value) struct udevice *pinctrl = dev_get_parent(dev); uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset); - pcr_clrsetbits32(dev, config_offset, PAD_CFG0_TX_STATE, + pcr_clrsetbits32(pinctrl, config_offset, PAD_CFG0_TX_STATE, value ? PAD_CFG0_TX_STATE : 0); return 0; -- cgit From 28c626804dee51dd89a5a400e0cb663ee9cc77ed Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Mon, 3 Feb 2020 11:38:05 +0100 Subject: gpio: intel_gpio: Clear tx state bit when setting output Add missing 'PAD_CFG0_TX_STATE' to the clear mask for pcr_clrsetbits32(). Otherwise this bit cannot be cleared again after it has been set once. Signed-off-by: Wolfgang Wallner Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- drivers/gpio/intel_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c index b05cfc4aed..be91626cc5 100644 --- a/drivers/gpio/intel_gpio.c +++ b/drivers/gpio/intel_gpio.c @@ -41,7 +41,7 @@ static int intel_gpio_direction_output(struct udevice *dev, uint offset, pcr_clrsetbits32(pinctrl, config_offset, PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE | - PAD_CFG0_TX_DISABLE, + PAD_CFG0_TX_DISABLE | PAD_CFG0_TX_STATE, PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE | (value ? PAD_CFG0_TX_STATE : 0)); -- cgit From ea86e725d4c363232047126f1c84b03f13de7840 Mon Sep 17 00:00:00 2001 From: Wolfgang Wallner Date: Mon, 3 Feb 2020 11:38:06 +0100 Subject: gpio: intel_gpio: Fix register/bit offsets intel_gpio_get_value() Fix the following in intel_gpio_get_value(): * The value of the register is contained in the variable 'reg', not in 'mode'. The variable 'mode' contains only the configuration whether the gpio is currently an input or an output. * The correct bitmasks for the input and output value are PAD_CFG0_RX_STATE and PAD_CFG0_TX_STATE. Use them instead of the currently used PAD_CFG0_RX_STATE_BIT and PAD_CFG0_TX_STATE_BIT. Signed-off-by: Wolfgang Wallner Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- drivers/gpio/intel_gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c index be91626cc5..67b8b80b9d 100644 --- a/drivers/gpio/intel_gpio.c +++ b/drivers/gpio/intel_gpio.c @@ -59,9 +59,9 @@ static int intel_gpio_get_value(struct udevice *dev, uint offset) if (!mode) { rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE); if (rx_tx == PAD_CFG0_TX_DISABLE) - return mode & PAD_CFG0_RX_STATE_BIT ? 1 : 0; + return reg & PAD_CFG0_RX_STATE ? 1 : 0; else if (rx_tx == PAD_CFG0_RX_DISABLE) - return mode & PAD_CFG0_TX_STATE_BIT ? 1 : 0; + return reg & PAD_CFG0_TX_STATE ? 1 : 0; } return 0; -- cgit From 9e0c131a32028547cc4834f238c614af2675c66d Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Mon, 27 Jan 2020 16:23:29 -0500 Subject: azure: Move to vs2017-win2016 platform build host Azure is moving to remove the vs2015-win2012r2 platform build host. The two suggested new platforms to use are vs2017-win2016 and windows-2019. For now, move up to vs2017-win2016. Cc: Bin Meng Signed-off-by: Tom Rini Reviewed-by: Bin Meng Tested-by: Bin Meng --- .azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 916ab84ea0..a0713dd66c 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -1,5 +1,5 @@ variables: - windows_vm: vs2015-win2012r2 + windows_vm: vs2017-win2016 ubuntu_vm: ubuntu-18.04 ci_runner_image: trini/u-boot-gitlab-ci-runner:bionic-20200112-17Jan2020 # Add '-u 0' options for Azure pipelines, otherwise we get "permission -- cgit