From c04cf0a5717372f8546d07cdb6a13abcdcc5be85 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Mar 2017 13:51:53 +0200 Subject: [PATCH 01/10] x86: Remove unused option There is option which is not used: CONFIG_ZBOOT_32 Remove it from default x86 config and from whitelist. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- include/configs/x86-common.h | 1 - scripts/config_whitelist.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h index f7796cf63f..d69e609bd9 100644 --- a/include/configs/x86-common.h +++ b/include/configs/x86-common.h @@ -16,7 +16,6 @@ * (easy to change) */ #define CONFIG_SHOW_BOOT_PROGRESS -#define CONFIG_ZBOOT_32 #define CONFIG_PHYSMEM #define CONFIG_DISPLAY_BOARDINFO_LATE #define CONFIG_LAST_STAGE_INIT diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 04b6a95052..330bc5897a 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -6663,7 +6663,6 @@ CONFIG_YAFFS_WINCE CONFIG_YELLOWSTONE CONFIG_YELLOW_LED CONFIG_YOSEMITE -CONFIG_ZBOOT_32 CONFIG_ZC770_XM010 CONFIG_ZC770_XM011 CONFIG_ZC770_XM012 From d24c7fbcc5e530bb5a2b5326869aaa2d7a61d607 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 16 Mar 2017 07:26:27 -0700 Subject: [PATCH 02/10] dm: rtc: Add 16-bit read/write support At present there are only 8-bit and 32-bit read/write routines in the rtc uclass driver. This adds the 16-bit support. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/rtc/rtc-uclass.c | 30 ++++++++++++++++++++++++++++++ include/rtc.h | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c index 300e9b30ec..89312c51ff 100644 --- a/drivers/rtc/rtc-uclass.c +++ b/drivers/rtc/rtc-uclass.c @@ -60,6 +60,36 @@ int rtc_write8(struct udevice *dev, unsigned int reg, int val) return ops->write8(dev, reg, val); } +int rtc_read16(struct udevice *dev, unsigned int reg, u16 *valuep) +{ + u16 value = 0; + int ret; + int i; + + for (i = 0; i < sizeof(value); i++) { + ret = rtc_read8(dev, reg + i); + if (ret < 0) + return ret; + value |= ret << (i << 3); + } + + *valuep = value; + return 0; +} + +int rtc_write16(struct udevice *dev, unsigned int reg, u16 value) +{ + int i, ret; + + for (i = 0; i < sizeof(value); i++) { + ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff); + if (ret) + return ret; + } + + return 0; +} + int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep) { u32 value = 0; diff --git a/include/rtc.h b/include/rtc.h index 69fe8d4db0..49142b6e18 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -127,6 +127,26 @@ int rtc_read8(struct udevice *dev, unsigned int reg); */ int rtc_write8(struct udevice *dev, unsigned int reg, int val); +/** + * rtc_read16() - Read a 16-bit value from the RTC + * + * @dev: Device to read from + * @reg: Offset to start reading from + * @valuep: Place to put the value that is read + * @return 0 if OK, -ve on error + */ +int rtc_read16(struct udevice *dev, unsigned int reg, u16 *valuep); + +/** + * rtc_write16() - Write a 16-bit value to the RTC + * + * @dev: Device to write to + * @reg: Register to start writing to + * @value: Value to write + * @return 0 if OK, -ve on error + */ +int rtc_write16(struct udevice *dev, unsigned int reg, u16 value); + /** * rtc_read32() - Read a 32-bit value from the RTC * From 3dc0f8446aae39256c2259e948251e68f106919b Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 30 Mar 2017 12:58:10 +0200 Subject: [PATCH 03/10] x86: Kconfig: Add options to configure the descriptor.bin / me.bin filenames This introduces two Kconfig options to enable board specific filenames for the Intel binary blobs to be used to generate the SPI flash image. Signed-off-by: Stefan Roese Cc: Bin Meng Cc: Simon Glass Reviewed-by: Bin Meng --- arch/x86/Kconfig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index dfdd7564ea..6ce127a23c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -316,6 +316,22 @@ config X86_RAMTEST to work correctly. It is not exhaustive but can save time by detecting obvious failures. +config FLASH_DESCRIPTOR_FILE + string "Flash descriptor binary filename" + depends on HAVE_INTEL_ME + default "descriptor.bin" + help + The filename of the file to use as flash descriptor in the + board directory. + +config INTEL_ME_FILE + string "Intel Management Engine binary filename" + depends on HAVE_INTEL_ME + default "me.bin" + help + The filename of the file to use as Intel Management Engine in the + board directory. + config HAVE_FSP bool "Add an Firmware Support Package binary" depends on !EFI From cccab03a529ac1bf1a66ff75fb15784005ec8570 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 30 Mar 2017 12:58:11 +0200 Subject: [PATCH 04/10] x86: Add file names from Kconfig in descriptor/intel-me nodes in u-boot.dtsi Since we now have the file names configurable via Kconfig for the flash descriptor and intel-me files, add these from Kconfig in the corresponding dts nodes. Signed-off-by: Stefan Roese Cc: Bin Meng Cc: Simon Glass Reviewed-by: Bin Meng --- arch/x86/dts/u-boot.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 69c1c1d498..a4321d33de 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -17,8 +17,10 @@ size = ; #ifdef CONFIG_HAVE_INTEL_ME intel-descriptor { + filename = CONFIG_FLASH_DESCRIPTOR_FILE; }; intel-me { + filename = CONFIG_INTEL_ME_FILE; }; #endif #ifdef CONFIG_SPL From 2b4c65289698705d91e4c601ece3f079c71cf433 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 30 Mar 2017 12:58:12 +0200 Subject: [PATCH 05/10] binman: Remove hard-coded file name for x86 flash-descriptor & intel-me Now that we have added file names from Kconfig in x86 u-boot.dtsi, update binman to avoid using hard-coded names. Signed-off-by: Stefan Roese Cc: Bin Meng Cc: Simon Glass Reviewed-by: Bin Meng --- tools/binman/etype/intel_descriptor.py | 3 --- tools/binman/etype/intel_me.py | 3 --- 2 files changed, 6 deletions(-) diff --git a/tools/binman/etype/intel_descriptor.py b/tools/binman/etype/intel_descriptor.py index 7f4ea0b21b..6435749e7c 100644 --- a/tools/binman/etype/intel_descriptor.py +++ b/tools/binman/etype/intel_descriptor.py @@ -37,9 +37,6 @@ class Entry_intel_descriptor(Entry_blob): Entry_blob.__init__(self, image, etype, node) self._regions = [] - def GetDefaultFilename(self): - return 'descriptor.bin' - def GetPositions(self): pos = self.data.find(FD_SIGNATURE) if pos == -1: diff --git a/tools/binman/etype/intel_me.py b/tools/binman/etype/intel_me.py index 45ab50c1ec..5e1c7993b7 100644 --- a/tools/binman/etype/intel_me.py +++ b/tools/binman/etype/intel_me.py @@ -12,6 +12,3 @@ from blob import Entry_blob class Entry_intel_me(Entry_blob): def __init__(self, image, etype, node): Entry_blob.__init__(self, image, etype, node) - - def GetDefaultFilename(self): - return 'me.bin' From 13c531e52a09b4e6ffa8b5a1457199b0a574cb27 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 31 Mar 2017 08:09:39 +0200 Subject: [PATCH 06/10] x86: bootm: Fix FIT image booting on x86 Checking 'is_zimage' at this time will always fail and therefore booting a FIT style image will always lead to this error message: "## Kernel loading failed (missing x86 kernel setup) ..." This change now removes this check and booting of FIT images works just fine. Signed-off-by: Stefan Roese Cc: Simon Glass Cc: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/lib/bootm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 3c3d9e1e80..75bab90225 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -100,7 +100,7 @@ static int boot_prep_linux(bootm_headers_t *images) } is_zimage = 1; #if defined(CONFIG_FIT) - } else if (images->fit_uname_os && is_zimage) { + } else if (images->fit_uname_os) { ret = fit_image_get_data(images->fit_hdr_os, images->fit_noffset_os, (const void **)&data, &len); From ae5564d1aec8b39f55f283f8d187b7b1603533bf Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 4 Apr 2017 21:17:14 -0700 Subject: [PATCH 07/10] tools: binman: Add missing filenames for various x86 rom tests With recent changes, some x86-specific rom tests of binman fail to run. Fix it by adding missing filenames in corresponding entries. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- tools/binman/test/30_x86-rom-me-no-desc.dts | 1 + tools/binman/test/31_x86-rom-me.dts | 2 ++ tools/binman/test/32_intel-vga.dts | 1 + tools/binman/test/42_intel-fsp.dts | 1 + tools/binman/test/43_intel-cmc.dts | 1 + 5 files changed, 6 insertions(+) diff --git a/tools/binman/test/30_x86-rom-me-no-desc.dts b/tools/binman/test/30_x86-rom-me-no-desc.dts index 4578f660ac..68d3ce09ec 100644 --- a/tools/binman/test/30_x86-rom-me-no-desc.dts +++ b/tools/binman/test/30_x86-rom-me-no-desc.dts @@ -9,6 +9,7 @@ end-at-4gb; size = <16>; intel-me { + filename = "me.bin"; pos-unset; }; }; diff --git a/tools/binman/test/31_x86-rom-me.dts b/tools/binman/test/31_x86-rom-me.dts index b484ab31cf..ee3dac875a 100644 --- a/tools/binman/test/31_x86-rom-me.dts +++ b/tools/binman/test/31_x86-rom-me.dts @@ -9,9 +9,11 @@ end-at-4gb; size = <0x800000>; intel-descriptor { + filename = "descriptor.bin"; }; intel-me { + filename = "me.bin"; pos-unset; }; }; diff --git a/tools/binman/test/32_intel-vga.dts b/tools/binman/test/32_intel-vga.dts index 1790833238..9c532d03d3 100644 --- a/tools/binman/test/32_intel-vga.dts +++ b/tools/binman/test/32_intel-vga.dts @@ -8,6 +8,7 @@ size = <16>; intel-vga { + filename = "vga.bin"; }; }; }; diff --git a/tools/binman/test/42_intel-fsp.dts b/tools/binman/test/42_intel-fsp.dts index e0a1e76f13..8a7c889251 100644 --- a/tools/binman/test/42_intel-fsp.dts +++ b/tools/binman/test/42_intel-fsp.dts @@ -8,6 +8,7 @@ size = <16>; intel-fsp { + filename = "fsp.bin"; }; }; }; diff --git a/tools/binman/test/43_intel-cmc.dts b/tools/binman/test/43_intel-cmc.dts index 26c456def7..5a56c7d881 100644 --- a/tools/binman/test/43_intel-cmc.dts +++ b/tools/binman/test/43_intel-cmc.dts @@ -8,6 +8,7 @@ size = <16>; intel-cmc { + filename = "cmc.bin"; }; }; }; From c5f8dd482b4178cda30be7355085a70521cd4813 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Feb 2017 14:04:10 +0200 Subject: [PATCH 08/10] serial: Add serial driver for Intel MID Add a specific serial driver for Intel MID platforms. It has special fractional divider which can be programmed via UART_PS, UART_MUL, and UART_DIV registers. The UART clock is calculated as UART clock = XTAL * UART_MUL / UART_DIV The baudrate is calculated as baud rate = UART clock / UART_PS / DLAB Initialize fractional divider correctly for Intel Edison platform. For backward compatibility we have to set initial DLAB value to 16 and speed to 115200 baud, where initial frequency is 29491200Hz, and XTAL frequency is 38.4MHz. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass Reviewed-by: Kever Yang --- drivers/serial/Kconfig | 9 ++++ drivers/serial/Makefile | 1 + drivers/serial/serial_intel_mid.c | 69 +++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 drivers/serial/serial_intel_mid.c diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 0900cc8acb..c0ec2ec2e4 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -376,6 +376,15 @@ config SYS_NS16550 be used. It can be a constant or a function to get clock, eg, get_serial_clock(). +config INTEL_MID_SERIAL + bool "Intel MID platform UART support" + depends on DM_SERIAL && OF_CONTROL + depends on INTEL_MID + select SYS_NS16550 + help + Select this to enable a UART for Intel MID platforms. + This uses the ns16550 driver as a library. + config ROCKCHIP_SERIAL bool "Rockchip on-chip UART support" depends on DM_SERIAL && SPL_OF_PLATDATA diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 8ba15ce028..4382cf9329 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_S5P) += serial_s5p.o obj-$(CONFIG_MXC_UART) += serial_mxc.o obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o obj-$(CONFIG_MESON_SERIAL) += serial_meson.o +obj-$(CONFIG_INTEL_MID_SERIAL) += serial_intel_mid.o ifdef CONFIG_SPL_BUILD obj-$(CONFIG_ROCKCHIP_SERIAL) += serial_rockchip.o endif diff --git a/drivers/serial/serial_intel_mid.c b/drivers/serial/serial_intel_mid.c new file mode 100644 index 0000000000..777c09d6d2 --- /dev/null +++ b/drivers/serial/serial_intel_mid.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +/* + * The UART clock is calculated as + * + * UART clock = XTAL * UART_MUL / UART_DIV + * + * The baudrate is calculated as + * + * baud rate = UART clock / UART_PS / DLAB + */ +#define UART_PS 0x30 +#define UART_MUL 0x34 +#define UART_DIV 0x38 + +static void mid_writel(struct ns16550_platdata *plat, int offset, int value) +{ + unsigned char *addr; + + offset *= 1 << plat->reg_shift; + addr = (unsigned char *)plat->base + offset; + + writel(value, addr + plat->reg_offset); +} + +static int mid_serial_probe(struct udevice *dev) +{ + struct ns16550_platdata *plat = dev_get_platdata(dev); + + /* + * Initialize fractional divider correctly for Intel Edison + * platform. + * + * For backward compatibility we have to set initial DLAB value + * to 16 and speed to 115200 baud, where initial frequency is + * 29491200Hz, and XTAL frequency is 38.4MHz. + */ + mid_writel(plat, UART_MUL, 96); + mid_writel(plat, UART_DIV, 125); + mid_writel(plat, UART_PS, 16); + + return ns16550_serial_probe(dev); +} + +static const struct udevice_id mid_serial_ids[] = { + { .compatible = "intel,mid-uart" }, + {} +}; + +U_BOOT_DRIVER(serial_intel_mid) = { + .name = "serial_intel_mid", + .id = UCLASS_SERIAL, + .of_match = mid_serial_ids, + .ofdata_to_platdata = ns16550_serial_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), + .priv_auto_alloc_size = sizeof(struct NS16550), + .probe = mid_serial_probe, + .ops = &ns16550_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; From bb416465fde8393bcbf1f64847b5e3cb021d5c81 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sat, 1 Apr 2017 16:21:33 +0300 Subject: [PATCH 09/10] x86: Add SCU IPC driver for Intel MID platforms Intel MID platforms have few microcontrollers inside SoC, one of them is so called System Controller Unit (SCU). Here is the driver to communicate with microcontroller. Signed-off-by: Vincent Tinelli Signed-off-by: Felipe Balbi Signed-off-by: Andy Shevchenko Acked-by: Simon Glass --- arch/x86/Kconfig | 2 + arch/x86/include/asm/cpu.h | 1 + arch/x86/include/asm/scu.h | 28 +++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/scu.c | 168 +++++++++++++++++++++++++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 arch/x86/include/asm/scu.h create mode 100644 arch/x86/lib/scu.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6ce127a23c..9ead3ebccf 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -83,6 +83,8 @@ endchoice # subarchitectures-specific options below config INTEL_MID bool "Intel MID platform support" + select REGMAP + select SYSCON help Select to build a U-Boot capable of supporting Intel MID (Mobile Internet Device) platform systems which do not have diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index c651f2f594..0ee13b1eb1 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -54,6 +54,7 @@ enum { X86_NONE, X86_SYSCON_ME, /* Intel Management Engine */ X86_SYSCON_PINCONF, /* Intel x86 pin configuration */ + X86_SYSCON_SCU, /* System Controller Unit */ }; struct cpuid_result { diff --git a/arch/x86/include/asm/scu.h b/arch/x86/include/asm/scu.h new file mode 100644 index 0000000000..4d40e495bb --- /dev/null +++ b/arch/x86/include/asm/scu.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _X86_ASM_SCU_IPC_H_ +#define _X86_ASM_SCU_IPC_H_ + +/* IPC defines the following message types */ +#define IPCMSG_WARM_RESET 0xf0 +#define IPCMSG_COLD_RESET 0xf1 +#define IPCMSG_SOFT_RESET 0xf2 +#define IPCMSG_COLD_BOOT 0xf3 +#define IPCMSG_GET_FW_REVISION 0xf4 +#define IPCMSG_WATCHDOG_TIMER 0xf8 /* Set Kernel Watchdog Threshold */ + +struct ipc_ifwi_version { + u16 minor; + u8 major; + u8 hardware_id; + u32 reserved[3]; +}; + +/* Issue commands to the SCU with or without data */ +int scu_ipc_simple_command(u32 cmd, u32 sub); +int scu_ipc_command(u32 cmd, u32 sub, u32 *in, int inlen, u32 *out, int outlen); + +#endif /* _X86_ASM_SCU_IPC_H_ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 1c2c085179..320e45e4a0 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -32,6 +32,7 @@ obj-y += pirq_routing.o obj-y += relocate.o obj-y += physmem.o obj-$(CONFIG_X86_RAMTEST) += ramtest.o +obj-$(CONFIG_INTEL_MID) += scu.o obj-y += sections.o obj-y += sfi.o obj-y += string.o diff --git a/arch/x86/lib/scu.c b/arch/x86/lib/scu.c new file mode 100644 index 0000000000..bb23d0b829 --- /dev/null +++ b/arch/x86/lib/scu.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * Intel Mobile Internet Devices (MID) based on Intel Atom SoCs have few + * microcontrollers inside to do some auxiliary tasks. One of such + * microcontroller is System Controller Unit (SCU) which, in particular, + * is servicing watchdog and controlling system reset function. + * + * This driver enables IPC channel to SCU. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SCU register map */ +struct ipc_regs { + u32 cmd; + u32 status; + u32 sptr; + u32 dptr; + u32 reserved[28]; + u32 wbuf[4]; + u32 rbuf[4]; +}; + +struct scu { + struct ipc_regs *regs; +}; + +/** + * scu_ipc_send_command() - send command to SCU + * @regs: register map of SCU + * @cmd: command + * + * Command Register (Write Only): + * A write to this register results in an interrupt to the SCU core processor + * Format: + * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)| + */ +static void scu_ipc_send_command(struct ipc_regs *regs, u32 cmd) +{ + writel(cmd, ®s->cmd); +} + +/** + * scu_ipc_check_status() - check status of last command + * @regs: register map of SCU + * + * Status Register (Read Only): + * Driver will read this register to get the ready/busy status of the IPC + * block and error status of the IPC command that was just processed by SCU + * Format: + * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)| + */ +static int scu_ipc_check_status(struct ipc_regs *regs) +{ + int loop_count = 100000; + int status; + + do { + status = readl(®s->status); + if (!(status & BIT(0))) + break; + + udelay(1); + } while (--loop_count); + if (!loop_count) + return -ETIMEDOUT; + + if (status & BIT(1)) { + printf("%s() status=0x%08x\n", __func__, status); + return -EIO; + } + + return 0; +} + +static int scu_ipc_cmd(struct ipc_regs *regs, u32 cmd, u32 sub, + u32 *in, int inlen, u32 *out, int outlen) +{ + int i, err; + + for (i = 0; i < inlen; i++) + writel(*in++, ®s->wbuf[i]); + + scu_ipc_send_command(regs, (inlen << 16) | (sub << 12) | cmd); + err = scu_ipc_check_status(regs); + + if (!err) { + for (i = 0; i < outlen; i++) + *out++ = readl(®s->rbuf[i]); + } + + return err; +} + +/** + * scu_ipc_simple_command() - send a simple command + * @cmd: command + * @sub: sub type + * + * Issue a simple command to the SCU. Do not use this interface if + * you must then access data as any data values may be overwritten + * by another SCU access by the time this function returns. + * + * This function may sleep. Locking for SCU accesses is handled for + * the caller. + */ +int scu_ipc_simple_command(u32 cmd, u32 sub) +{ + struct scu *scu; + struct udevice *dev; + int ret; + + ret = syscon_get_by_driver_data(X86_SYSCON_SCU, &dev); + if (ret) + return ret; + + scu = dev_get_priv(dev); + + scu_ipc_send_command(scu->regs, sub << 12 | cmd); + return scu_ipc_check_status(scu->regs); +} + +int scu_ipc_command(u32 cmd, u32 sub, u32 *in, int inlen, u32 *out, int outlen) +{ + struct scu *scu; + struct udevice *dev; + int ret; + + ret = syscon_get_by_driver_data(X86_SYSCON_SCU, &dev); + if (ret) + return ret; + + scu = dev_get_priv(dev); + + return scu_ipc_cmd(scu->regs, cmd, sub, in, inlen, out, outlen); +} + +static int scu_ipc_probe(struct udevice *dev) +{ + struct scu *scu = dev_get_priv(dev); + + scu->regs = syscon_get_first_range(X86_SYSCON_SCU); + + return 0; +} + +static const struct udevice_id scu_ipc_match[] = { + { .compatible = "intel,scu-ipc", .data = X86_SYSCON_SCU }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(scu_ipc) = { + .name = "scu_ipc", + .id = UCLASS_SYSCON, + .of_match = scu_ipc_match, + .probe = scu_ipc_probe, + .priv_auto_alloc_size = sizeof(struct scu), +}; From ca0d29e4f06095fd39f3125aef8f427aa1728ee5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 1 Apr 2017 16:21:34 +0300 Subject: [PATCH 10/10] x86: Introduce minimal PMU driver for Intel MID platforms This simple PMU driver allows to tyrn power on and off for selected devices. In particularly Intel Tangier needs to power on SDHCI controllers in order to access to them during board initialization. In the future it might be expanded to cover other Intel MID platforms, that's why it's located under arch/x86/lib and called pmu.c. Signed-off-by: Felipe Balbi Signed-off-by: Andy Shevchenko Reviewed-by: Simon Glass --- arch/x86/include/asm/cpu.h | 1 + arch/x86/include/asm/pmu.h | 11 ++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/pmu.c | 117 +++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 arch/x86/include/asm/pmu.h create mode 100644 arch/x86/lib/pmu.c diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 0ee13b1eb1..c00687a20a 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -54,6 +54,7 @@ enum { X86_NONE, X86_SYSCON_ME, /* Intel Management Engine */ X86_SYSCON_PINCONF, /* Intel x86 pin configuration */ + X86_SYSCON_PMU, /* Power Management Unit */ X86_SYSCON_SCU, /* System Controller Unit */ }; diff --git a/arch/x86/include/asm/pmu.h b/arch/x86/include/asm/pmu.h new file mode 100644 index 0000000000..96b968ff8f --- /dev/null +++ b/arch/x86/include/asm/pmu.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _X86_ASM_PMU_IPC_H_ +#define _X86_ASM_PMU_IPC_H_ + +int pmu_turn_power(unsigned int lss, bool on); + +#endif /* _X86_ASM_PMU_IPC_H_ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 320e45e4a0..d1ad37af64 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -31,6 +31,7 @@ obj-y += pinctrl_ich6.o obj-y += pirq_routing.o obj-y += relocate.o obj-y += physmem.o +obj-$(CONFIG_INTEL_MID) += pmu.o obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-$(CONFIG_INTEL_MID) += scu.o obj-y += sections.o diff --git a/arch/x86/lib/pmu.c b/arch/x86/lib/pmu.c new file mode 100644 index 0000000000..4ceab8dc64 --- /dev/null +++ b/arch/x86/lib/pmu.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers */ +struct pmu_regs { + u32 sts; + u32 cmd; + u32 ics; + u32 reserved; + u32 wkc[4]; + u32 wks[4]; + u32 ssc[4]; + u32 sss[4]; +}; + +/* Bits in PMU_REGS_STS */ +#define PMU_REGS_STS_BUSY (1 << 8) + +struct pmu_mid { + struct pmu_regs *regs; +}; + +static int pmu_read_status(struct pmu_regs *regs) +{ + int retry = 500000; + u32 val; + + do { + val = readl(®s->sts); + if (!(val & PMU_REGS_STS_BUSY)) + return 0; + + udelay(1); + } while (--retry); + + printf("WARNING: PMU still busy\n"); + return -EBUSY; +} + +static int pmu_power_lss(struct pmu_regs *regs, unsigned int lss, bool on) +{ + unsigned int offset = (lss * 2) / 32; + unsigned int shift = (lss * 2) % 32; + u32 ssc; + int ret; + + /* Check PMU status */ + ret = pmu_read_status(regs); + if (ret) + return ret; + + /* Read PMU values */ + ssc = readl(®s->sss[offset]); + + /* Modify PMU values */ + if (on) + ssc &= ~(0x3 << shift); /* D0 */ + else + ssc |= 0x3 << shift; /* D3hot */ + + /* Write modified PMU values */ + writel(ssc, ®s->ssc[offset]); + + /* Update modified PMU values */ + writel(0x00002201, ®s->cmd); + + /* Check PMU status */ + return pmu_read_status(regs); +} + +int pmu_turn_power(unsigned int lss, bool on) +{ + struct pmu_mid *pmu; + struct udevice *dev; + int ret; + + ret = syscon_get_by_driver_data(X86_SYSCON_PMU, &dev); + if (ret) + return ret; + + pmu = dev_get_priv(dev); + + return pmu_power_lss(pmu->regs, lss, on); +} + +static int pmu_mid_probe(struct udevice *dev) +{ + struct pmu_mid *pmu = dev_get_priv(dev); + + pmu->regs = syscon_get_first_range(X86_SYSCON_PMU); + + return 0; +} + +static const struct udevice_id pmu_mid_match[] = { + { .compatible = "intel,pmu-mid", .data = X86_SYSCON_PMU }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(intel_mid_pmu) = { + .name = "pmu_mid", + .id = UCLASS_SYSCON, + .of_match = pmu_mid_match, + .probe = pmu_mid_probe, + .priv_auto_alloc_size = sizeof(struct pmu_mid), +};