From 68769ebcbc892c85e9a1ffff09bbc6e4877f2d1f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 21 Apr 2017 07:24:46 -0700 Subject: x86: pci: Allow conditionally run VGA rom in S3 Introduce a new CONFIG_S3_VGA_ROM_RUN option so that U-Boot can bypass executing VGA roms in S3. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Tested-by: Stefan Roese --- drivers/pci/pci_rom.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 57204c4f3f1..75fb0933371 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -35,8 +35,22 @@ #include #include +#ifdef CONFIG_X86 +#include +DECLARE_GLOBAL_DATA_PTR; +#endif + __weak bool board_should_run_oprom(struct udevice *dev) { +#if defined(CONFIG_X86) && defined(CONFIG_HAVE_ACPI_RESUME) + if (gd->arch.prev_sleep_state == ACPI_S3) { + if (IS_ENABLED(CONFIG_S3_VGA_ROM_RUN)) + return true; + else + return false; + } +#endif + return true; } -- cgit v1.3.1 From ddb3ac3c716f56cead695444e65a7ba7b0946555 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 9 Apr 2017 18:38:21 -0600 Subject: x86: Convert MMC to driver model Convert the pci_mmc driver over to driver model and migrate all x86 boards that use it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng --- arch/Kconfig | 1 + arch/x86/cpu/baytrail/valleyview.c | 12 ------ arch/x86/cpu/quark/quark.c | 10 ----- arch/x86/cpu/queensbay/Makefile | 2 +- arch/x86/cpu/queensbay/topcliff.c | 20 --------- drivers/mmc/pci_mmc.c | 86 ++++++++++++++++++++++++++------------ include/mmc.h | 12 ------ 7 files changed, 62 insertions(+), 81 deletions(-) delete mode 100644 arch/x86/cpu/queensbay/topcliff.c (limited to 'drivers') diff --git a/arch/Kconfig b/arch/Kconfig index 826e346f980..2528f50efa7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -85,6 +85,7 @@ config X86 select DM_SPI select DM_SPI_FLASH select USB_EHCI_HCD + select DM_MMC if MMC config XTENSA bool "Xtensa architecture" diff --git a/arch/x86/cpu/baytrail/valleyview.c b/arch/x86/cpu/baytrail/valleyview.c index 87ba849c1c4..c58f6a86a8f 100644 --- a/arch/x86/cpu/baytrail/valleyview.c +++ b/arch/x86/cpu/baytrail/valleyview.c @@ -11,18 +11,6 @@ #include #include -static struct pci_device_id mmc_supported[] = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SDIO }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SD }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_EMMC2 }, - {}, -}; - -int cpu_mmc_init(bd_t *bis) -{ - return pci_mmc_init("ValleyView SDHCI", mmc_supported); -} - #ifndef CONFIG_EFI_APP int arch_cpu_init(void) { diff --git a/arch/x86/cpu/quark/quark.c b/arch/x86/cpu/quark/quark.c index 0c2cea4ee9d..c36a5892d5f 100644 --- a/arch/x86/cpu/quark/quark.c +++ b/arch/x86/cpu/quark/quark.c @@ -16,11 +16,6 @@ #include #include -static struct pci_device_id mmc_supported[] = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_SDIO }, - {}, -}; - static void quark_setup_mtrr(void) { u32 base, mask; @@ -328,11 +323,6 @@ int arch_early_init_r(void) return 0; } -int cpu_mmc_init(bd_t *bis) -{ - return pci_mmc_init("Quark SDHCI", mmc_supported); -} - int arch_misc_init(void) { #ifdef CONFIG_ENABLE_MRC_CACHE diff --git a/arch/x86/cpu/queensbay/Makefile b/arch/x86/cpu/queensbay/Makefile index af3ffad3852..c0681995bdf 100644 --- a/arch/x86/cpu/queensbay/Makefile +++ b/arch/x86/cpu/queensbay/Makefile @@ -5,4 +5,4 @@ # obj-y += fsp_configs.o irq.o -obj-y += tnc.o topcliff.o +obj-y += tnc.o diff --git a/arch/x86/cpu/queensbay/topcliff.c b/arch/x86/cpu/queensbay/topcliff.c deleted file mode 100644 index b76dd7de697..00000000000 --- a/arch/x86/cpu/queensbay/topcliff.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2014, Bin Meng - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include - -static struct pci_device_id mmc_supported[] = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0 }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1 }, - {}, -}; - -int cpu_mmc_init(bd_t *bis) -{ - return pci_mmc_init("Topcliff SDHCI", mmc_supported); -} diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c index e39b476834e..6db89779ba3 100644 --- a/drivers/mmc/pci_mmc.c +++ b/drivers/mmc/pci_mmc.c @@ -6,37 +6,71 @@ */ #include +#include #include #include +#include #include #include -int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported) +struct pci_mmc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +struct pci_mmc_priv { + struct sdhci_host host; + void *base; +}; + +static int pci_mmc_probe(struct udevice *dev) { - struct sdhci_host *mmc_host; - u32 iobase; + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct pci_mmc_plat *plat = dev_get_platdata(dev); + struct pci_mmc_priv *priv = dev_get_priv(dev); + struct sdhci_host *host = &priv->host; + u32 ioaddr; int ret; - int i; - - for (i = 0; ; i++) { - struct udevice *dev; - - ret = pci_find_device_id(mmc_supported, i, &dev); - if (ret) - return ret; - mmc_host = malloc(sizeof(struct sdhci_host)); - if (!mmc_host) - return -ENOMEM; - - mmc_host->name = name; - dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase); - mmc_host->ioaddr = (void *)(ulong)iobase; - mmc_host->quirks = 0; - mmc_host->max_clk = 0; - ret = add_sdhci(mmc_host, 0, 0); - if (ret) - return ret; - } - - return 0; + + dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &ioaddr); + host->ioaddr = map_sysmem(ioaddr, 0); + host->name = dev->name; + ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); + if (ret) + return ret; + host->mmc = &plat->mmc; + host->mmc->priv = &priv->host; + host->mmc->dev = dev; + upriv->mmc = host->mmc; + + return sdhci_probe(dev); } + +static int pci_mmc_bind(struct udevice *dev) +{ + struct pci_mmc_plat *plat = dev_get_platdata(dev); + + return sdhci_bind(dev, &plat->mmc, &plat->cfg); +} + +U_BOOT_DRIVER(pci_mmc) = { + .name = "pci_mmc", + .id = UCLASS_MMC, + .bind = pci_mmc_bind, + .probe = pci_mmc_probe, + .ops = &sdhci_ops, + .priv_auto_alloc_size = sizeof(struct pci_mmc_priv), + .platdata_auto_alloc_size = sizeof(struct pci_mmc_plat), +}; + +static struct pci_device_id mmc_supported[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SDIO) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SD) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_EMMC2) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_SDIO) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1) }, + {}, +}; + +U_BOOT_PCI_DEVICE(pci_mmc, mmc_supported); diff --git a/include/mmc.h b/include/mmc.h index fad12d608ce..8346b0e19e2 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -585,18 +585,6 @@ int cpu_mmc_init(bd_t *bis); int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr); int mmc_get_env_dev(void); -struct pci_device_id; - -/** - * pci_mmc_init() - set up PCI MMC devices - * - * This finds all the matching PCI IDs and sets them up as MMC devices. - * - * @name: Name to use for devices - * @mmc_supported: PCI IDs to search for, terminated by {0, 0} - */ -int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported); - /* Set block count limit because of 16 bit register limit on some hardware*/ #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 -- cgit v1.3.1 From e98856fcff5adc64689c3d5597b0a36d867eec8f Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 24 Apr 2017 09:48:01 +0200 Subject: serial: serial-uclass: Use force parameter in stdio_deregister_dev() On my x86 platform I've noticed, that calling dm_uninit() or the new function dm_remove_devices_flags() does not remove the desired device at all. Debugging showed, that the serial uclass returns -EPERM in serial_pre_remove(). This patch sets the force parameter when calling stdio_deregister_dev() resulting in a removal of the device. Signed-off-by: Stefan Roese Cc: Simon Glass Cc: Bin Meng Reviewed-by: Simon Glass --- drivers/serial/serial-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 43c028ebe63..c2b9c5f12f5 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -349,7 +349,7 @@ static int serial_pre_remove(struct udevice *dev) #if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER) struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); - if (stdio_deregister_dev(upriv->sdev, 0)) + if (stdio_deregister_dev(upriv->sdev, true)) return -EPERM; #endif -- cgit v1.3.1 From 426f99fa98c3725fe0ca1eb8438d1215a2c6bd6b Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 24 Apr 2017 09:48:02 +0200 Subject: dm: core: Add DM_FLAG_OS_PREPARE flag This new flag can be added to DM device drivers, which need to do some final configuration before U-Boot exits and the OS (e.g. Linux) is started. The remove functions of those drivers will get called at this stage to do these last-stage configuration steps. Signed-off-by: Stefan Roese Reviewed-by: Simon Glass Cc: Bin Meng --- drivers/core/device-remove.c | 16 +++++++++++----- include/dm/device.h | 11 ++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index cc0043b990b..3c6ab42f7d6 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -152,6 +152,15 @@ void device_free(struct udevice *dev) devres_release_probe(dev); } +static bool flags_remove(uint flags, uint drv_flags) +{ + if ((flags & DM_REMOVE_NORMAL) || + (flags & (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE)))) + return true; + + return false; +} + int device_remove(struct udevice *dev, uint flags) { const struct driver *drv; @@ -178,9 +187,7 @@ int device_remove(struct udevice *dev, uint flags) * Remove the device if called with the "normal" remove flag set, * or if the remove flag matches any of the drivers remove flags */ - if (drv->remove && - ((flags & DM_REMOVE_NORMAL) || - (flags & (drv->flags & DM_FLAG_ACTIVE_DMA)))) { + if (drv->remove && flags_remove(flags, drv->flags)) { ret = drv->remove(dev); if (ret) goto err_remove; @@ -194,8 +201,7 @@ int device_remove(struct udevice *dev, uint flags) } } - if ((flags & DM_REMOVE_NORMAL) || - (flags & (drv->flags & DM_FLAG_ACTIVE_DMA))) { + if (flags_remove(flags, drv->flags)) { device_free(dev); dev->seq = -1; diff --git a/include/dm/device.h b/include/dm/device.h index 079ec570030..df02e41df3d 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -54,6 +54,12 @@ struct driver_info; */ #define DM_FLAG_ACTIVE_DMA (1 << 9) +/* + * Call driver remove function to do some final configuration, before + * U-Boot exits and the OS is started + */ +#define DM_FLAG_OS_PREPARE (1 << 10) + /* * One or multiple of these flags are passed to device_remove() so that * a selective device removal as specified by the remove-stage and the @@ -66,10 +72,13 @@ enum { /* Remove devices with active DMA */ DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA, + /* Remove devices which need some final OS preparation steps */ + DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE, + /* Add more use cases here */ /* Remove devices with any active flag */ - DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA, + DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE, }; /** -- cgit v1.3.1 From 4759dffe23460d39d8e92c01013b00a3587e2112 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 24 Apr 2017 09:48:04 +0200 Subject: spi: ich: Configure SPI BIOS parameters for Linux upon U-Boot exit This patch adds a remove function to the Intel ICH SPI driver, that will be called upon U-Boot exit, directly before the OS (Linux) is started. This function takes care of configuring the BIOS registers in the SPI controller (similar to what a "standard" BIOS or coreboot does), so that the Linux MTD device driver is able to correctly read/write to the SPI NOR chip. Without this, the chip is not detected at all. Signed-off-by: Stefan Roese Reviewed-by: Simon Glass Cc: Bin Meng Cc: Jagan Teki --- drivers/spi/ich.c | 18 ++++++++++++++++++ drivers/spi/ich.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 65 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 893fe33b66f..bf2e99b5ccb 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -617,6 +617,22 @@ static int ich_spi_probe(struct udevice *dev) return 0; } +static int ich_spi_remove(struct udevice *bus) +{ + struct ich_spi_priv *ctlr = dev_get_priv(bus); + + /* + * Configure SPI controller so that the Linux MTD driver can fully + * access the SPI NOR chip + */ + ich_writew(ctlr, SPI_OPPREFIX, ctlr->preop); + ich_writew(ctlr, SPI_OPTYPE, ctlr->optype); + ich_writel(ctlr, SPI_OPMENU_LOWER, ctlr->opmenu); + ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32)); + + return 0; +} + static int ich_spi_set_speed(struct udevice *bus, uint speed) { struct ich_spi_priv *priv = dev_get_priv(bus); @@ -700,4 +716,6 @@ U_BOOT_DRIVER(ich_spi) = { .priv_auto_alloc_size = sizeof(struct ich_spi_priv), .child_pre_probe = ich_spi_child_pre_probe, .probe = ich_spi_probe, + .remove = ich_spi_remove, + .flags = DM_FLAG_OS_PREPARE, }; diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h index bd0a8208096..dcb8a9048f8 100644 --- a/drivers/spi/ich.h +++ b/drivers/spi/ich.h @@ -101,13 +101,6 @@ enum { HSFC_FSMIE = 0x8000 }; -enum { - SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0, - SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1, - SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2, - SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3 -}; - enum { ICH_MAX_CMD_LEN = 5, }; @@ -124,8 +117,55 @@ struct spi_trans { uint32_t offset; }; +#define SPI_OPCODE_WRSR 0x01 +#define SPI_OPCODE_PAGE_PROGRAM 0x02 +#define SPI_OPCODE_READ 0x03 +#define SPI_OPCODE_WRDIS 0x04 +#define SPI_OPCODE_RDSR 0x05 #define SPI_OPCODE_WREN 0x06 #define SPI_OPCODE_FAST_READ 0x0b +#define SPI_OPCODE_ERASE_SECT 0x20 +#define SPI_OPCODE_READ_ID 0x9f +#define SPI_OPCODE_ERASE_BLOCK 0xd8 + +#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0 +#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1 +#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2 +#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3 + +#define SPI_OPMENU_0 SPI_OPCODE_WRSR +#define SPI_OPTYPE_0 SPI_OPCODE_TYPE_WRITE_NO_ADDRESS + +#define SPI_OPMENU_1 SPI_OPCODE_PAGE_PROGRAM +#define SPI_OPTYPE_1 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS + +#define SPI_OPMENU_2 SPI_OPCODE_READ +#define SPI_OPTYPE_2 SPI_OPCODE_TYPE_READ_WITH_ADDRESS + +#define SPI_OPMENU_3 SPI_OPCODE_RDSR +#define SPI_OPTYPE_3 SPI_OPCODE_TYPE_READ_NO_ADDRESS + +#define SPI_OPMENU_4 SPI_OPCODE_ERASE_SECT +#define SPI_OPTYPE_4 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS + +#define SPI_OPMENU_5 SPI_OPCODE_READ_ID +#define SPI_OPTYPE_5 SPI_OPCODE_TYPE_READ_NO_ADDRESS + +#define SPI_OPMENU_6 SPI_OPCODE_ERASE_BLOCK +#define SPI_OPTYPE_6 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS + +#define SPI_OPMENU_7 SPI_OPCODE_FAST_READ +#define SPI_OPTYPE_7 SPI_OPCODE_TYPE_READ_WITH_ADDRESS + +#define SPI_OPPREFIX ((SPI_OPCODE_WREN << 8) | SPI_OPCODE_WREN) +#define SPI_OPTYPE ((SPI_OPTYPE_7 << 14) | (SPI_OPTYPE_6 << 12) | \ + (SPI_OPTYPE_5 << 10) | (SPI_OPTYPE_4 << 8) | \ + (SPI_OPTYPE_3 << 6) | (SPI_OPTYPE_2 << 4) | \ + (SPI_OPTYPE_1 << 2) | (SPI_OPTYPE_0 << 0)) +#define SPI_OPMENU_UPPER ((SPI_OPMENU_7 << 24) | (SPI_OPMENU_6 << 16) | \ + (SPI_OPMENU_5 << 8) | (SPI_OPMENU_4 << 0)) +#define SPI_OPMENU_LOWER ((SPI_OPMENU_3 << 24) | (SPI_OPMENU_2 << 16) | \ + (SPI_OPMENU_1 << 8) | (SPI_OPMENU_0 << 0)) enum ich_version { ICHV_7, -- cgit v1.3.1 From 770ee0174223e824a721f5f164cc8b2bf7473189 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 7 May 2017 19:52:29 -0700 Subject: x86: ich6_gpio: Add use-lvl-write-cache for I/O access mode Add a device-tree property use-lvl-write-cache that will cause writes to lvl to be cached instead of read from lvl before each write. This is required on some platforms that have the register implemented as dual read/write (such as Baytrail). Prior to this fix the blue USB port on the Minnowboard Max was unusable since USB_HOST_EN0 was set high then immediately set low when USB_HOST_EN1 was written. This also resolves the 'gpio clear | set' command warning like: "Warning: value of pin is still 0" Signed-off-by: George McCollister Signed-off-by: Bin Meng Reviewed-by: Stefan Roese Reviewed-by: Simon Glass --- arch/x86/dts/bayleybay.dts | 6 ++++++ arch/x86/dts/baytrail_som-db5800-som-6867.dts | 6 ++++++ arch/x86/dts/conga-qeval20-qa3-e3845.dts | 6 ++++++ arch/x86/dts/dfi-bt700.dtsi | 6 ++++++ arch/x86/dts/minnowmax.dts | 6 ++++++ drivers/gpio/intel_ich6_gpio.c | 30 ++++++++++++++++++++++----- 6 files changed, 55 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/arch/x86/dts/bayleybay.dts b/arch/x86/dts/bayleybay.dts index 18b310d39e8..1ae058d7a94 100644 --- a/arch/x86/dts/bayleybay.dts +++ b/arch/x86/dts/bayleybay.dts @@ -189,6 +189,7 @@ u-boot,dm-pre-reloc; reg = <0 0x20>; bank-name = "A"; + use-lvl-write-cache; }; gpiob { @@ -196,6 +197,7 @@ u-boot,dm-pre-reloc; reg = <0x20 0x20>; bank-name = "B"; + use-lvl-write-cache; }; gpioc { @@ -203,6 +205,7 @@ u-boot,dm-pre-reloc; reg = <0x40 0x20>; bank-name = "C"; + use-lvl-write-cache; }; gpiod { @@ -210,6 +213,7 @@ u-boot,dm-pre-reloc; reg = <0x60 0x20>; bank-name = "D"; + use-lvl-write-cache; }; gpioe { @@ -217,6 +221,7 @@ u-boot,dm-pre-reloc; reg = <0x80 0x20>; bank-name = "E"; + use-lvl-write-cache; }; gpiof { @@ -224,6 +229,7 @@ u-boot,dm-pre-reloc; reg = <0xA0 0x20>; bank-name = "F"; + use-lvl-write-cache; }; }; }; diff --git a/arch/x86/dts/baytrail_som-db5800-som-6867.dts b/arch/x86/dts/baytrail_som-db5800-som-6867.dts index e1d81a7283a..aa8bfb86513 100644 --- a/arch/x86/dts/baytrail_som-db5800-som-6867.dts +++ b/arch/x86/dts/baytrail_som-db5800-som-6867.dts @@ -212,6 +212,7 @@ u-boot,dm-pre-reloc; reg = <0 0x20>; bank-name = "A"; + use-lvl-write-cache; }; gpiob { @@ -219,6 +220,7 @@ u-boot,dm-pre-reloc; reg = <0x20 0x20>; bank-name = "B"; + use-lvl-write-cache; }; gpioc { @@ -226,6 +228,7 @@ u-boot,dm-pre-reloc; reg = <0x40 0x20>; bank-name = "C"; + use-lvl-write-cache; }; gpiod { @@ -233,6 +236,7 @@ u-boot,dm-pre-reloc; reg = <0x60 0x20>; bank-name = "D"; + use-lvl-write-cache; }; gpioe { @@ -240,6 +244,7 @@ u-boot,dm-pre-reloc; reg = <0x80 0x20>; bank-name = "E"; + use-lvl-write-cache; }; gpiof { @@ -247,6 +252,7 @@ u-boot,dm-pre-reloc; reg = <0xA0 0x20>; bank-name = "F"; + use-lvl-write-cache; }; }; }; diff --git a/arch/x86/dts/conga-qeval20-qa3-e3845.dts b/arch/x86/dts/conga-qeval20-qa3-e3845.dts index f0efe908e2c..898e9c9b5f7 100644 --- a/arch/x86/dts/conga-qeval20-qa3-e3845.dts +++ b/arch/x86/dts/conga-qeval20-qa3-e3845.dts @@ -199,6 +199,7 @@ u-boot,dm-pre-reloc; reg = <0 0x20>; bank-name = "A"; + use-lvl-write-cache; }; gpiob { @@ -206,6 +207,7 @@ u-boot,dm-pre-reloc; reg = <0x20 0x20>; bank-name = "B"; + use-lvl-write-cache; }; gpioc { @@ -213,6 +215,7 @@ u-boot,dm-pre-reloc; reg = <0x40 0x20>; bank-name = "C"; + use-lvl-write-cache; }; gpiod { @@ -220,6 +223,7 @@ u-boot,dm-pre-reloc; reg = <0x60 0x20>; bank-name = "D"; + use-lvl-write-cache; }; gpioe { @@ -227,6 +231,7 @@ u-boot,dm-pre-reloc; reg = <0x80 0x20>; bank-name = "E"; + use-lvl-write-cache; }; gpiof { @@ -234,6 +239,7 @@ u-boot,dm-pre-reloc; reg = <0xA0 0x20>; bank-name = "F"; + use-lvl-write-cache; }; }; }; diff --git a/arch/x86/dts/dfi-bt700.dtsi b/arch/x86/dts/dfi-bt700.dtsi index 75ee6ade7c1..546981a9ac1 100644 --- a/arch/x86/dts/dfi-bt700.dtsi +++ b/arch/x86/dts/dfi-bt700.dtsi @@ -201,6 +201,7 @@ u-boot,dm-pre-reloc; reg = <0 0x20>; bank-name = "A"; + use-lvl-write-cache; }; gpiob { @@ -208,6 +209,7 @@ u-boot,dm-pre-reloc; reg = <0x20 0x20>; bank-name = "B"; + use-lvl-write-cache; }; gpioc { @@ -215,6 +217,7 @@ u-boot,dm-pre-reloc; reg = <0x40 0x20>; bank-name = "C"; + use-lvl-write-cache; }; gpiod { @@ -222,6 +225,7 @@ u-boot,dm-pre-reloc; reg = <0x60 0x20>; bank-name = "D"; + use-lvl-write-cache; }; gpioe { @@ -229,6 +233,7 @@ u-boot,dm-pre-reloc; reg = <0x80 0x20>; bank-name = "E"; + use-lvl-write-cache; }; gpiof { @@ -236,6 +241,7 @@ u-boot,dm-pre-reloc; reg = <0xA0 0x20>; bank-name = "F"; + use-lvl-write-cache; }; }; }; diff --git a/arch/x86/dts/minnowmax.dts b/arch/x86/dts/minnowmax.dts index d51318bdf60..bc382a89489 100644 --- a/arch/x86/dts/minnowmax.dts +++ b/arch/x86/dts/minnowmax.dts @@ -218,6 +218,7 @@ u-boot,dm-pre-reloc; reg = <0 0x20>; bank-name = "A"; + use-lvl-write-cache; }; gpiob { @@ -225,6 +226,7 @@ u-boot,dm-pre-reloc; reg = <0x20 0x20>; bank-name = "B"; + use-lvl-write-cache; }; gpioc { @@ -232,6 +234,7 @@ u-boot,dm-pre-reloc; reg = <0x40 0x20>; bank-name = "C"; + use-lvl-write-cache; }; gpiod { @@ -239,6 +242,7 @@ u-boot,dm-pre-reloc; reg = <0x60 0x20>; bank-name = "D"; + use-lvl-write-cache; }; gpioe { @@ -246,6 +250,7 @@ u-boot,dm-pre-reloc; reg = <0x80 0x20>; bank-name = "E"; + use-lvl-write-cache; }; gpiof { @@ -253,6 +258,7 @@ u-boot,dm-pre-reloc; reg = <0xA0 0x20>; bank-name = "F"; + use-lvl-write-cache; }; }; }; diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c index 8b782260bc3..0a9eb03fd05 100644 --- a/drivers/gpio/intel_ich6_gpio.c +++ b/drivers/gpio/intel_ich6_gpio.c @@ -46,22 +46,31 @@ struct ich6_bank_priv { uint16_t use_sel; uint16_t io_sel; uint16_t lvl; + u32 lvl_write_cache; + bool use_lvl_write_cache; }; #define GPIO_USESEL_OFFSET(x) (x) #define GPIO_IOSEL_OFFSET(x) (x + 4) #define GPIO_LVL_OFFSET(x) (x + 8) -static int _ich6_gpio_set_value(uint16_t base, unsigned offset, int value) +static int _ich6_gpio_set_value(struct ich6_bank_priv *bank, unsigned offset, + int value) { u32 val; - val = inl(base); + if (bank->use_lvl_write_cache) + val = bank->lvl_write_cache; + else + val = inl(bank->lvl); + if (value) val |= (1UL << offset); else val &= ~(1UL << offset); - outl(val, base); + outl(val, bank->lvl); + if (bank->use_lvl_write_cache) + bank->lvl_write_cache = val; return 0; } @@ -112,6 +121,7 @@ static int ich6_gpio_probe(struct udevice *dev) struct ich6_bank_platdata *plat = dev_get_platdata(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct ich6_bank_priv *bank = dev_get_priv(dev); + const void *prop; uc_priv->gpio_count = GPIO_PER_BANK; uc_priv->bank_name = plat->bank_name; @@ -119,6 +129,14 @@ static int ich6_gpio_probe(struct udevice *dev) bank->io_sel = plat->base_addr + 4; bank->lvl = plat->base_addr + 8; + prop = fdt_getprop(gd->fdt_blob, dev->of_offset, + "use-lvl-write-cache", NULL); + if (prop) + bank->use_lvl_write_cache = true; + else + bank->use_lvl_write_cache = false; + bank->lvl_write_cache = 0; + return 0; } @@ -160,7 +178,7 @@ static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset, if (ret) return ret; - return _ich6_gpio_set_value(bank->lvl, offset, value); + return _ich6_gpio_set_value(bank, offset, value); } static int ich6_gpio_get_value(struct udevice *dev, unsigned offset) @@ -170,6 +188,8 @@ static int ich6_gpio_get_value(struct udevice *dev, unsigned offset) int r; tmplong = inl(bank->lvl); + if (bank->use_lvl_write_cache) + tmplong |= bank->lvl_write_cache; r = (tmplong & (1UL << offset)) ? 1 : 0; return r; } @@ -178,7 +198,7 @@ static int ich6_gpio_set_value(struct udevice *dev, unsigned offset, int value) { struct ich6_bank_priv *bank = dev_get_priv(dev); - return _ich6_gpio_set_value(bank->lvl, offset, value); + return _ich6_gpio_set_value(bank, offset, value); } static int ich6_gpio_get_function(struct udevice *dev, unsigned offset) -- cgit v1.3.1