summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2019-12-18 07:20:19 -0500
committerTom Rini <trini@konsulko.com>2019-12-18 07:20:19 -0500
commitc0912f9bbfb26dd03d189953678691b799d35b6e (patch)
treef879600cd26b8d4678a174854b623941e5dc2ada /drivers
parent533c9f5714bdba79dc6f2629284d4c1a08a611d1 (diff)
parenta1d6dc3f84071f05574044f337dbdca70fae495d (diff)
Merge branch 'next' of https://gitlab.denx.de/u-boot/custodians/u-boot-x86 into next
- Various x86 common codes updated for TPL/SPL - I2C designware driver updated for PCI - ICH SPI driver updated to support Apollo Lake - Add Intel FSP2 base support - Intel Apollo Lake platform specific drivers support - Add a new board Google Chromebook Coral
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/core/util.c20
-rw-r--r--drivers/gpio/Kconfig31
-rw-r--r--drivers/gpio/Makefile5
-rw-r--r--drivers/gpio/at91_gpio.c6
-rw-r--r--drivers/gpio/atmel_pio4.c2
-rw-r--r--drivers/gpio/da8xx_gpio.c7
-rw-r--r--drivers/gpio/da8xx_gpio.h2
-rw-r--r--drivers/gpio/intel_gpio.c161
-rw-r--r--drivers/gpio/mxc_gpio.c4
-rw-r--r--drivers/gpio/mxs_gpio.c4
-rw-r--r--drivers/gpio/omap_gpio.c6
-rw-r--r--drivers/gpio/sunxi_gpio.c8
-rw-r--r--drivers/i2c/Makefile3
-rw-r--r--drivers/i2c/designware_i2c.c106
-rw-r--r--drivers/i2c/designware_i2c.h35
-rw-r--r--drivers/i2c/designware_i2c_pci.c144
-rw-r--r--drivers/i2c/i2c-uclass.c6
-rw-r--r--drivers/i2c/muxes/pca954x.c4
-rw-r--r--drivers/misc/Kconfig42
-rw-r--r--drivers/misc/Makefile5
-rw-r--r--drivers/misc/irq-uclass.c53
-rw-r--r--drivers/misc/irq_sandbox.c55
-rw-r--r--drivers/misc/p2sb-uclass.c216
-rw-r--r--drivers/misc/p2sb_emul.c272
-rw-r--r--drivers/misc/p2sb_sandbox.c39
-rw-r--r--drivers/misc/sandbox_adder.c60
-rw-r--r--drivers/mmc/fsl_esdhc_imx.c13
-rw-r--r--drivers/mmc/omap_hsmmc.c2
-rw-r--r--drivers/mtd/spi/sf_probe.c2
-rw-r--r--drivers/net/designware.c10
-rw-r--r--drivers/net/designware.h4
-rw-r--r--drivers/net/fec_mxc.c6
-rw-r--r--drivers/net/fec_mxc.h2
-rw-r--r--drivers/net/mvneta.c4
-rw-r--r--drivers/net/mvpp2.c9
-rw-r--r--drivers/net/sun8i_emac.c12
-rw-r--r--drivers/pch/Kconfig18
-rw-r--r--drivers/pch/Makefile4
-rw-r--r--drivers/pci/pci-aardvark.c4
-rw-r--r--drivers/pci/pci-uclass.c31
-rw-r--r--drivers/pci/pcie_dw_mvebu.c4
-rw-r--r--drivers/pinctrl/Kconfig23
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/intel/Kconfig26
-rw-r--r--drivers/pinctrl/intel/Makefile6
-rw-r--r--drivers/pinctrl/intel/pinctrl.c636
-rw-r--r--drivers/pinctrl/intel/pinctrl_apl.c192
-rw-r--r--drivers/power/Kconfig2
-rw-r--r--drivers/power/acpi_pmc/Kconfig34
-rw-r--r--drivers/power/acpi_pmc/Makefile6
-rw-r--r--drivers/power/acpi_pmc/acpi-pmc-uclass.c244
-rw-r--r--drivers/power/acpi_pmc/pmc_emul.c246
-rw-r--r--drivers/power/acpi_pmc/sandbox.c97
-rw-r--r--drivers/spi/Kconfig1
-rw-r--r--drivers/spi/atmel_spi.c10
-rw-r--r--drivers/spi/designware_spi.c4
-rw-r--r--drivers/spi/ich.c534
-rw-r--r--drivers/spi/ich.h46
-rw-r--r--drivers/spi/spi-uclass.c5
-rw-r--r--drivers/timer/Kconfig23
-rw-r--r--drivers/timer/tsc_timer.c10
-rw-r--r--drivers/tpm/tpm2_tis_spi.c2
63 files changed, 3263 insertions, 307 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index e977f19af6..cb8c215e76 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/
obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/
obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/
+obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += power/acpi_pmc/
ifndef CONFIG_TPL_BUILD
ifdef CONFIG_SPL_BUILD
diff --git a/drivers/core/util.c b/drivers/core/util.c
index 7dc1a2af02..69f83755f0 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -4,7 +4,9 @@
*/
#include <common.h>
+#include <dm/device.h>
#include <dm/ofnode.h>
+#include <dm/read.h>
#include <dm/util.h>
#include <linux/libfdt.h>
#include <vsprintf.h>
@@ -58,3 +60,21 @@ bool dm_ofnode_pre_reloc(ofnode node)
#endif
}
#endif
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+int pci_get_devfn(struct udevice *dev)
+{
+ struct fdt_pci_addr addr;
+ int ret;
+
+ /* Extract the devfn from fdt_pci_addr */
+ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
+ "reg", &addr);
+ if (ret) {
+ if (ret != -ENOENT)
+ return -EINVAL;
+ }
+
+ return addr.phys_hi & 0xff00;
+}
+#endif
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index c1ad5d64a3..1de6f5225e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -14,6 +14,28 @@ config DM_GPIO
particular GPIOs that they provide. The uclass interface
is defined in include/asm-generic/gpio.h.
+config SPL_DM_GPIO
+ bool "Enable Driver Model for GPIO drivers in SPL"
+ depends on DM_GPIO && SPL_DM && SPL_GPIO_SUPPORT
+ default y
+ help
+ Enable driver model for GPIO access in SPL. The standard GPIO
+ interface (gpio_get_value(), etc.) is then implemented by
+ the GPIO uclass. Drivers provide methods to query the
+ particular GPIOs that they provide. The uclass interface
+ is defined in include/asm-generic/gpio.h.
+
+config TPL_DM_GPIO
+ bool "Enable Driver Model for GPIO drivers in TPL"
+ depends on DM_GPIO && TPL_DM && TPL_GPIO_SUPPORT
+ default y
+ help
+ Enable driver model for GPIO access in TPL. The standard GPIO
+ interface (gpio_get_value(), etc.) is then implemented by
+ the GPIO uclass. Drivers provide methods to query the
+ particular GPIOs that they provide. The uclass interface
+ is defined in include/asm-generic/gpio.h.
+
config GPIO_HOG
bool "Enable GPIO hog support"
depends on DM_GPIO
@@ -82,6 +104,15 @@ config INTEL_BROADWELL_GPIO
driver from the common Intel ICH6 driver. It supports a total of
95 GPIOs which can be configured from the device tree.
+config INTEL_GPIO
+ bool "Intel generic GPIO driver"
+ depends on DM_GPIO
+ help
+ Say yes here to select Intel generic GPIO driver. This controller
+ supports recent chips (e.g. Apollo Lake). It permits basic GPIO
+ control including setting pins to input/output. It makes use of its
+ parent pinctrl driver to actually effect changes.
+
config INTEL_ICH6_GPIO
bool "Intel ICH6 compatible legacy GPIO driver"
depends on DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index ccc49e2eb0..449046b64c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -7,14 +7,17 @@ ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_DWAPB_GPIO) += dwapb_gpio.o
obj-$(CONFIG_AXP_GPIO) += axp_gpio.o
endif
-obj-$(CONFIG_DM_GPIO) += gpio-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)DM_GPIO) += gpio-uclass.o
obj-$(CONFIG_$(SPL_)DM_PCA953X) += pca953x_gpio.o
+ifdef CONFIG_$(SPL_TPL_)GPIO
obj-$(CONFIG_DM_74X164) += 74x164_gpio.o
+endif
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
obj-$(CONFIG_BCM6345_GPIO) += bcm6345_gpio.o
+obj-$(CONFIG_INTEL_GPIO) += intel_gpio.o
obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o
obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o
diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index dbfed72c61..5ea3e77b2d 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -210,7 +210,7 @@ int at91_pio3_set_d_periph(unsigned port, unsigned pin, int use_pullup)
return 0;
}
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
static bool at91_get_port_output(struct at91_port *at91_port, int offset)
{
u32 mask, val;
@@ -457,7 +457,7 @@ int at91_get_pio_value(unsigned port, unsigned pin)
return 0;
}
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
/* Common GPIO API */
int gpio_request(unsigned gpio, const char *label)
@@ -499,7 +499,7 @@ int gpio_set_value(unsigned gpio, int value)
}
#endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct at91_port_priv {
struct at91_port *regs;
diff --git a/drivers/gpio/atmel_pio4.c b/drivers/gpio/atmel_pio4.c
index 95a189a50f..8e6f32de1f 100644
--- a/drivers/gpio/atmel_pio4.c
+++ b/drivers/gpio/atmel_pio4.c
@@ -168,7 +168,7 @@ int atmel_pio4_get_pio_input(u32 port, u32 pin)
return (readl(&port_base->pdsr) & mask) ? 1 : 0;
}
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct atmel_pioctrl_data {
u32 nbanks;
diff --git a/drivers/gpio/da8xx_gpio.c b/drivers/gpio/da8xx_gpio.c
index 0a50c68d72..bd5a366aef 100644
--- a/drivers/gpio/da8xx_gpio.c
+++ b/drivers/gpio/da8xx_gpio.c
@@ -15,7 +15,7 @@
#include "da8xx_gpio.h"
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
#include <asm/arch/hardware.h>
#include <asm/arch/davinci_misc.h>
@@ -377,7 +377,8 @@ static int _gpio_direction_output(struct davinci_gpio *bank, unsigned int gpio,
_gpio_set_value(bank, gpio, value);
return 0;
}
-#ifndef CONFIG_DM_GPIO
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
void gpio_info(void)
{
@@ -428,7 +429,7 @@ int gpio_set_value(unsigned int gpio, int value)
return _gpio_set_value(bank, gpio, value);
}
-#else /* CONFIG_DM_GPIO */
+#else /* DM_GPIO */
static struct davinci_gpio *davinci_get_gpio_bank(struct udevice *dev, unsigned int offset)
{
diff --git a/drivers/gpio/da8xx_gpio.h b/drivers/gpio/da8xx_gpio.h
index 1de9ec7f6f..849e8d2dcf 100644
--- a/drivers/gpio/da8xx_gpio.h
+++ b/drivers/gpio/da8xx_gpio.h
@@ -28,7 +28,7 @@ struct davinci_gpio_bank {
#define MAX_NUM_GPIOS 144
#define GPIO_BIT(gp) ((gp) & 0x1F)
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
/* Information about a GPIO bank */
struct davinci_gpio_platdata {
diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c
new file mode 100644
index 0000000000..4bf1c9ddc4
--- /dev/null
+++ b/drivers/gpio/intel_gpio.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <p2sb.h>
+#include <pch.h>
+#include <pci.h>
+#include <syscon.h>
+#include <asm/cpu.h>
+#include <asm/gpio.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/intel_pinctrl_defs.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/arch/gpio.h>
+#include <dt-bindings/gpio/x86-gpio.h>
+
+static int intel_gpio_direction_input(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(pinctrl, config_offset,
+ PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
+ PAD_CFG0_RX_DISABLE,
+ PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE);
+
+ return 0;
+}
+
+static int intel_gpio_direction_output(struct udevice *dev, uint 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_MODE_MASK | PAD_CFG0_RX_STATE |
+ PAD_CFG0_TX_DISABLE,
+ PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE |
+ (value ? PAD_CFG0_TX_STATE : 0));
+
+ return 0;
+}
+
+static int intel_gpio_get_value(struct udevice *dev, uint offset)
+{
+ struct udevice *pinctrl = dev_get_parent(dev);
+ uint mode, rx_tx;
+ u32 reg;
+
+ reg = intel_pinctrl_get_config_reg(pinctrl, offset);
+ mode = (reg & PAD_CFG0_MODE_MASK) >> PAD_CFG0_MODE_SHIFT;
+ 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;
+ else if (rx_tx == PAD_CFG0_RX_DISABLE)
+ return mode & PAD_CFG0_TX_STATE_BIT ? 1 : 0;
+ }
+
+ return 0;
+}
+
+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,
+ value ? PAD_CFG0_TX_STATE : 0);
+
+ return 0;
+}
+
+static int intel_gpio_get_function(struct udevice *dev, uint offset)
+{
+ struct udevice *pinctrl = dev_get_parent(dev);
+ uint mode, rx_tx;
+ u32 reg;
+
+ reg = intel_pinctrl_get_config_reg(pinctrl, offset);
+ mode = (reg & PAD_CFG0_MODE_MASK) >> PAD_CFG0_MODE_SHIFT;
+ if (!mode) {
+ rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE);
+ if (rx_tx == PAD_CFG0_TX_DISABLE)
+ return GPIOF_INPUT;
+ else if (rx_tx == PAD_CFG0_RX_DISABLE)
+ return GPIOF_OUTPUT;
+ }
+
+ return GPIOF_FUNC;
+}
+
+static int intel_gpio_xlate(struct udevice *orig_dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ struct udevice *pinctrl, *dev;
+ int gpio, ret;
+
+ /*
+ * GPIO numbers are global in the device tree so it doesn't matter
+ * which one is used
+ */
+ gpio = args->args[0];
+ ret = intel_pinctrl_get_pad(gpio, &pinctrl, &desc->offset);
+ if (ret)
+ return log_msg_ret("bad", ret);
+ device_find_first_child(pinctrl, &dev);
+ if (!dev)
+ return log_msg_ret("no child", -ENOENT);
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+ desc->dev = dev;
+
+ return 0;
+}
+
+static int intel_gpio_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static int intel_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+ struct gpio_dev_priv *upriv = dev_get_uclass_priv(dev);
+ struct intel_pinctrl_priv *pinctrl_priv = dev_get_priv(dev->parent);
+ const struct pad_community *comm = pinctrl_priv->comm;
+
+ upriv->gpio_count = comm->last_pad - comm->first_pad + 1;
+ upriv->bank_name = dev->name;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_intel_ops = {
+ .direction_input = intel_gpio_direction_input,
+ .direction_output = intel_gpio_direction_output,
+ .get_value = intel_gpio_get_value,
+ .set_value = intel_gpio_set_value,
+ .get_function = intel_gpio_get_function,
+ .xlate = intel_gpio_xlate,
+};
+
+static const struct udevice_id intel_intel_gpio_ids[] = {
+ { .compatible = "intel,gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_intel) = {
+ .name = "gpio_intel",
+ .id = UCLASS_GPIO,
+ .of_match = intel_intel_gpio_ids,
+ .ops = &gpio_intel_ops,
+ .ofdata_to_platdata = intel_gpio_ofdata_to_platdata,
+ .probe = intel_gpio_probe,
+};
diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index 64ab7a303f..6592d141d3 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -30,7 +30,7 @@ struct mxc_bank_info {
struct gpio_regs *regs;
};
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
#define GPIO_TO_PORT(n) ((n) / 32)
/* GPIO port description */
@@ -161,7 +161,7 @@ int gpio_direction_output(unsigned gpio, int value)
}
#endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
#include <fdtdec.h>
static int mxc_gpio_is_output(struct gpio_regs *regs, int offset)
{
diff --git a/drivers/gpio/mxs_gpio.c b/drivers/gpio/mxs_gpio.c
index 5795155e3e..77778e9ce5 100644
--- a/drivers/gpio/mxs_gpio.c
+++ b/drivers/gpio/mxs_gpio.c
@@ -128,7 +128,7 @@ int name_to_gpio(const char *name)
return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT);
}
-#else /* CONFIG_DM_GPIO */
+#else /* DM_GPIO */
#include <dm.h>
#include <asm/gpio.h>
#include <dt-structs.h>
@@ -312,4 +312,4 @@ U_BOOT_DRIVER(gpio_mxs) = {
.ofdata_to_platdata = mxs_ofdata_to_platdata,
#endif
};
-#endif /* CONFIG_DM_GPIO */
+#endif /* DM_GPIO */
diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c
index 0031415d03..4249850f4b 100644
--- a/drivers/gpio/omap_gpio.c
+++ b/drivers/gpio/omap_gpio.c
@@ -30,7 +30,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define OMAP_GPIO_DIR_OUT 0
#define OMAP_GPIO_DIR_IN 1
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
#define GPIO_PER_BANK 32
@@ -121,7 +121,7 @@ static int _get_gpio_value(const struct gpio_bank *bank, int gpio)
return (__raw_readl(reg) & (1 << gpio)) != 0;
}
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
static inline const struct gpio_bank *get_gpio_bank(int gpio)
{
@@ -377,4 +377,4 @@ U_BOOT_DRIVER(gpio_omap) = {
#endif
};
-#endif /* CONFIG_DM_GPIO */
+#endif /* !DM_GPIO */
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index 719efc2cef..9c3a4428e1 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -28,7 +28,7 @@ struct sunxi_gpio_platdata {
int gpio_count;
};
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
static int sunxi_gpio_output(u32 pin, u32 val)
{
u32 dat;
@@ -116,7 +116,7 @@ int sunxi_name_to_gpio(const char *name)
return -1;
return group * 32 + pin;
}
-#endif
+#endif /* DM_GPIO */
int sunxi_name_to_gpio_bank(const char *name)
{
@@ -132,7 +132,7 @@ int sunxi_name_to_gpio_bank(const char *name)
return -1;
}
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
/* TODO(sjg@chromium.org): Remove this function and use device tree */
int sunxi_name_to_gpio(const char *name)
{
@@ -373,4 +373,4 @@ U_BOOT_DRIVER(gpio_sunxi) = {
.bind = gpio_sunxi_bind,
.probe = gpio_sunxi_probe,
};
-#endif
+#endif /* DM_GPIO */
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index c2f75d8755..f5a471f887 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -14,6 +14,9 @@ obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
+ifdef CONFIG_DM_PCI
+obj-$(CONFIG_SYS_I2C_DW) += designware_i2c_pci.o
+endif
obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 6daa90e744..b8cdd1c661 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -13,34 +13,6 @@
#include <asm/io.h>
#include "designware_i2c.h"
-struct dw_scl_sda_cfg {
- u32 ss_hcnt;
- u32 fs_hcnt;
- u32 ss_lcnt;
- u32 fs_lcnt;
- u32 sda_hold;
-};
-
-#ifdef CONFIG_X86
-/* BayTrail HCNT/LCNT/SDA hold time */
-static struct dw_scl_sda_cfg byt_config = {
- .ss_hcnt = 0x200,
- .fs_hcnt = 0x55,
- .ss_lcnt = 0x200,
- .fs_lcnt = 0x99,
- .sda_hold = 0x6,
-};
-#endif
-
-struct dw_i2c {
- struct i2c_regs *regs;
- struct dw_scl_sda_cfg *scl_sda_cfg;
- struct reset_ctl_bulk resets;
-#if CONFIG_IS_ENABLED(CLK)
- struct clk clk;
-#endif
-};
-
#ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
{
@@ -90,7 +62,9 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
unsigned int ena;
int i2c_spd;
- if (speed >= I2C_MAX_SPEED)
+ /* Allow max speed if there is no config, or the config allows it */
+ if (speed >= I2C_MAX_SPEED &&
+ (!scl_sda_cfg || scl_sda_cfg->has_max_speed))
i2c_spd = IC_SPEED_MODE_MAX;
else if (speed >= I2C_FAST_SPEED)
i2c_spd = IC_SPEED_MODE_FAST;
@@ -106,7 +80,6 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
switch (i2c_spd) {
-#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */
case IC_SPEED_MODE_MAX:
cntl |= IC_CON_SPD_SS;
if (scl_sda_cfg) {
@@ -119,7 +92,6 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
writel(hcnt, &i2c_base->ic_hs_scl_hcnt);
writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
break;
-#endif
case IC_SPEED_MODE_STANDARD:
cntl |= IC_CON_SPD_SS;
@@ -565,24 +537,19 @@ static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
return ret;
}
-static int designware_i2c_probe(struct udevice *bus)
+static int designware_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct dw_i2c *priv = dev_get_priv(bus);
- int ret;
- if (device_is_on_pci_bus(bus)) {
-#ifdef CONFIG_DM_PCI
- /* Save base address from PCI BAR */
- priv->regs = (struct i2c_regs *)
- dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
-#ifdef CONFIG_X86
- /* Use BayTrail specific timing values */
- priv->scl_sda_cfg = &byt_config;
-#endif
-#endif
- } else {
- priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
- }
+ priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
+
+ return 0;
+}
+
+int designware_i2c_probe(struct udevice *bus)
+{
+ struct dw_i2c *priv = dev_get_priv(bus);
+ int ret;
ret = reset_get_bulk(bus, &priv->resets);
if (ret)
@@ -606,7 +573,7 @@ static int designware_i2c_probe(struct udevice *bus)
return __dw_i2c_init(priv->regs, 0, 0);
}
-static int designware_i2c_remove(struct udevice *dev)
+int designware_i2c_remove(struct udevice *dev)
{
struct dw_i2c *priv = dev_get_priv(dev);
@@ -618,30 +585,7 @@ static int designware_i2c_remove(struct udevice *dev)
return reset_release_bulk(&priv->resets);
}
-static int designware_i2c_bind(struct udevice *dev)
-{
- static int num_cards;
- char name[20];
-
- /* Create a unique device name for PCI type devices */
- if (device_is_on_pci_bus(dev)) {
- /*
- * ToDo:
- * Setting req_seq in the driver is probably not recommended.
- * But without a DT alias the number is not configured. And
- * using this driver is impossible for PCIe I2C devices.
- * This can be removed, once a better (correct) way for this
- * is found and implemented.
- */
- dev->req_seq = num_cards;
- sprintf(name, "i2c_designware#%u", num_cards++);
- device_set_name(dev, name);
- }
-
- return 0;
-}
-
-static const struct dm_i2c_ops designware_i2c_ops = {
+const struct dm_i2c_ops designware_i2c_ops = {
.xfer = designware_i2c_xfer,
.probe_chip = designware_i2c_probe_chip,
.set_bus_speed = designware_i2c_set_bus_speed,
@@ -656,28 +600,12 @@ U_BOOT_DRIVER(i2c_designware) = {
.name = "i2c_designware",
.id = UCLASS_I2C,
.of_match = designware_i2c_ids,
- .bind = designware_i2c_bind,
+ .ofdata_to_platdata = designware_i2c_ofdata_to_platdata,
.probe = designware_i2c_probe,
.priv_auto_alloc_size = sizeof(struct dw_i2c),
.remove = designware_i2c_remove,
- .flags = DM_FLAG_OS_PREPARE,
+ .flags = DM_FLAG_OS_PREPARE,
.ops = &designware_i2c_ops,
};
-#ifdef CONFIG_X86
-static struct pci_device_id designware_pci_supported[] = {
- /* Intel BayTrail has 7 I2C controller located on the PCI bus */
- { PCI_VDEVICE(INTEL, 0x0f41) },
- { PCI_VDEVICE(INTEL, 0x0f42) },
- { PCI_VDEVICE(INTEL, 0x0f43) },
- { PCI_VDEVICE(INTEL, 0x0f44) },
- { PCI_VDEVICE(INTEL, 0x0f45) },
- { PCI_VDEVICE(INTEL, 0x0f46) },
- { PCI_VDEVICE(INTEL, 0x0f47) },
- {},
-};
-
-U_BOOT_PCI_DEVICE(i2c_designware, designware_pci_supported);
-#endif
-
#endif /* CONFIG_DM_I2C */
diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h
index 20ff20d9b8..48766d0806 100644
--- a/drivers/i2c/designware_i2c.h
+++ b/drivers/i2c/designware_i2c.h
@@ -7,6 +7,8 @@
#ifndef __DW_I2C_H_
#define __DW_I2C_H_
+#include <reset.h>
+
struct i2c_regs {
u32 ic_con; /* 0x00 */
u32 ic_tar; /* 0x04 */
@@ -131,4 +133,37 @@ struct i2c_regs {
#define I2C_FAST_SPEED 400000
#define I2C_STANDARD_SPEED 100000
+/**
+ * struct dw_scl_sda_cfg - I2C timing configuration
+ *
+ * @has_max_speed: Support maximum speed (1Mbps)
+ * @ss_hcnt: Standard speed high time in ns
+ * @fs_hcnt: Fast speed high time in ns
+ * @ss_lcnt: Standard speed low time in ns
+ * @fs_lcnt: Fast speed low time in ns
+ * @sda_hold: SDA hold time
+ */
+struct dw_scl_sda_cfg {
+ bool has_max_speed;
+ u32 ss_hcnt;
+ u32 fs_hcnt;
+ u32 ss_lcnt;
+ u32 fs_lcnt;
+ u32 sda_hold;
+};
+
+struct dw_i2c {
+ struct i2c_regs *regs;
+ struct dw_scl_sda_cfg *scl_sda_cfg;
+ struct reset_ctl_bulk resets;
+#if CONFIG_IS_ENABLED(CLK)
+ struct clk clk;
+#endif
+};
+
+extern const struct dm_i2c_ops designware_i2c_ops;
+
+int designware_i2c_probe(struct udevice *bus);
+int designware_i2c_remove(struct udevice *dev);
+
#endif /* __DW_I2C_H_ */
diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c
new file mode 100644
index 0000000000..7f0625df66
--- /dev/null
+++ b/drivers/i2c/designware_i2c_pci.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ * Copyright 2019 Google Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spl.h>
+#include <asm/lpss.h>
+#include "designware_i2c.h"
+
+enum {
+ VANILLA = 0, /* standard I2C with no tweaks */
+ INTEL_APL, /* Apollo Lake I2C */
+};
+
+/* BayTrail HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg byt_config = {
+ .ss_hcnt = 0x200,
+ .fs_hcnt = 0x55,
+ .ss_lcnt = 0x200,
+ .fs_lcnt = 0x99,
+ .sda_hold = 0x6,
+};
+
+/* Have a weak function for now - possibly should be a new uclass */
+__weak void lpss_reset_release(void *regs);
+
+static int designware_i2c_pci_ofdata_to_platdata(struct udevice *dev)
+{
+ struct dw_i2c *priv = dev_get_priv(dev);
+
+ if (spl_phase() < PHASE_SPL) {
+ u32 base;
+ int ret;
+
+ ret = dev_read_u32(dev, "early-regs", &base);
+ if (ret)
+ return log_msg_ret("early-regs", ret);
+
+ /* Set i2c base address */
+ dm_pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
+
+ /* Enable memory access and bus master */
+ dm_pci_write_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER);
+ }
+
+ if (spl_phase() < PHASE_BOARD_F) {
+ /* Handle early, fixed mapping into a different address space */
+ priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0);
+ } else {
+ priv->regs = (struct i2c_regs *)
+ dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ }
+ if (!priv->regs)
+ return -EINVAL;
+
+ /* Save base address from PCI BAR */
+ if (IS_ENABLED(CONFIG_INTEL_BAYTRAIL))
+ /* Use BayTrail specific timing values */
+ priv->scl_sda_cfg = &byt_config;
+
+ return 0;
+}
+
+static int designware_i2c_pci_probe(struct udevice *dev)
+{
+ struct dw_i2c *priv = dev_get_priv(dev);
+
+ if (dev_get_driver_data(dev) == INTEL_APL) {
+ /* Ensure controller is in D0 state */
+ lpss_set_power_state(dev, STATE_D0);
+
+ lpss_reset_release(priv->regs);
+ }
+
+ return designware_i2c_probe(dev);
+}
+
+static int designware_i2c_pci_bind(struct udevice *dev)
+{
+ char name[20];
+
+ /*
+ * Create a unique device name for PCI type devices
+ * ToDo:
+ * Setting req_seq in the driver is probably not recommended.
+ * But without a DT alias the number is not configured. And
+ * using this driver is impossible for PCIe I2C devices.
+ * This can be removed, once a better (correct) way for this
+ * is found and implemented.
+ *
+ * TODO(sjg@chromium.org): Perhaps if uclasses had platdata this would
+ * be possible. We cannot use static data in drivers since they may be
+ * used in SPL or before relocation.
+ */
+ dev->req_seq = gd->arch.dw_i2c_num_cards++;
+ sprintf(name, "i2c_designware#%u", dev->req_seq);
+ device_set_name(dev, name);
+
+ return 0;
+}
+
+static const struct udevice_id designware_i2c_pci_ids[] = {
+ { .compatible = "snps,designware-i2c-pci" },
+ { .compatible = "intel,apl-i2c", .data = INTEL_APL },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_designware_pci) = {
+ .name = "i2c_designware_pci",
+ .id = UCLASS_I2C,
+ .of_match = designware_i2c_pci_ids,
+ .bind = designware_i2c_pci_bind,
+ .ofdata_to_platdata = designware_i2c_pci_ofdata_to_platdata,
+ .probe = designware_i2c_pci_probe,
+ .priv_auto_alloc_size = sizeof(struct dw_i2c),
+ .remove = designware_i2c_remove,
+ .flags = DM_FLAG_OS_PREPARE,
+ .ops = &designware_i2c_ops,
+};
+
+static struct pci_device_id designware_pci_supported[] = {
+ /* Intel BayTrail has 7 I2C controller located on the PCI bus */
+ { PCI_VDEVICE(INTEL, 0x0f41) },
+ { PCI_VDEVICE(INTEL, 0x0f42) },
+ { PCI_VDEVICE(INTEL, 0x0f43) },
+ { PCI_VDEVICE(INTEL, 0x0f44) },
+ { PCI_VDEVICE(INTEL, 0x0f45) },
+ { PCI_VDEVICE(INTEL, 0x0f46) },
+ { PCI_VDEVICE(INTEL, 0x0f47) },
+ { PCI_VDEVICE(INTEL, 0x5aac), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5aae), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5ab0), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5ab2), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5ab4), .driver_data = INTEL_APL },
+ { PCI_VDEVICE(INTEL, 0x5ab6), .driver_data = INTEL_APL },
+ {},
+};
+
+U_BOOT_PCI_DEVICE(i2c_designware_pci, designware_pci_supported);
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 44aace3a36..fe77e64619 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -11,7 +11,7 @@
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
#include <asm/gpio.h>
#endif
@@ -485,7 +485,7 @@ uint i2c_get_chip_addr_offset_mask(struct udevice *dev)
return chip->chip_addr_offset_mask;
}
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit)
{
if (bit)
@@ -581,7 +581,7 @@ static int i2c_deblock_gpio(struct udevice *bus)
{
return -ENOSYS;
}
-#endif // CONFIG_DM_GPIO
+#endif /* DM_GPIO */
int i2c_deblock(struct udevice *bus)
{
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
index a630ce991d..bb2935f8ec 100644
--- a/drivers/i2c/muxes/pca954x.c
+++ b/drivers/i2c/muxes/pca954x.c
@@ -125,7 +125,7 @@ static int pca954x_ofdata_to_platdata(struct udevice *dev)
static int pca954x_probe(struct udevice *dev)
{
- if (IS_ENABLED(CONFIG_DM_GPIO)) {
+ if (CONFIG_IS_ENABLED(DM_GPIO)) {
struct pca954x_priv *priv = dev_get_priv(dev);
int err;
@@ -146,7 +146,7 @@ static int pca954x_probe(struct udevice *dev)
static int pca954x_remove(struct udevice *dev)
{
- if (IS_ENABLED(CONFIG_DM_GPIO)) {
+ if (CONFIG_IS_ENABLED(DM_GPIO)) {
struct pca954x_priv *priv = dev_get_priv(dev);
if (dm_gpio_is_valid(&priv->gpio_mux_reset))
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 82bb093c56..f18aa8f7ba 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -203,6 +203,15 @@ config FSL_SEC_MON
Security Monitor can be transitioned on any security failures,
like software violations or hardware security violations.
+config IRQ
+ bool "Intel Interrupt controller"
+ depends on X86 || SANDBOX
+ help
+ This enables support for Intel interrupt controllers, including ITSS.
+ Some devices have extra features, such as Apollo Lake. The
+ device has its own uclass since there are several operations
+ involved.
+
config JZ4780_EFUSE
bool "Ingenic JZ4780 eFUSE support"
depends on ARCH_JZ47XX
@@ -226,6 +235,39 @@ config NUVOTON_NCT6102D
disable the legacy UART, the watchdog or other devices
in the Nuvoton Super IO chips on X86 platforms.
+config P2SB
+ bool "Intel Primary-to-Sideband Bus"
+ depends on X86 || SANDBOX
+ help
+ This enables support for the Intel Primary-to-Sideband bus,
+ abbreviated to P2SB. The P2SB is used to access various peripherals
+ such as eSPI, GPIO, through memory-mapped I/O in a large chunk of PCI
+ space. The space is segmented into different channels and peripherals
+ are accessed by device-specific means within those channels. Devices
+ should be added in the device tree as subnodes of the P2SB. A
+ Peripheral Channel Register? (PCR) API is provided to access those
+ devices - see pcr_readl(), etc.
+
+config SPL_P2SB
+ bool "Intel Primary-to-Sideband Bus in SPL"
+ depends on SPL && (X86 || SANDBOX)
+ help
+ The Primary-to-Sideband bus is used to access various peripherals
+ through memory-mapped I/O in a large chunk of PCI space. The space is
+ segmented into different channels and peripherals are accessed by
+ device-specific means within those channels. Devices should be added
+ in the device tree as subnodes of the p2sb.
+
+config TPL_P2SB
+ bool "Intel Primary-to-Sideband Bus in TPL"
+ depends on TPL && (X86 || SANDBOX)
+ help
+ The Primary-to-Sideband bus is used to access various peripherals
+ through memory-mapped I/O in a large chunk of PCI space. The space is
+ segmented into different channels and peripherals are accessed by
+ device-specific means within those channels. Devices should be added
+ in the device tree as subnodes of the p2sb.
+
config PWRSEQ
bool "Enable power-sequencing drivers"
depends on DM
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 55976d6be5..d4e8638dea 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -10,8 +10,10 @@ obj-$(CONFIG_$(SPL_TPL_)CROS_EC_SANDBOX) += cros_ec_sandbox.o
obj-$(CONFIG_$(SPL_TPL_)CROS_EC_LPC) += cros_ec_lpc.o
ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_SANDBOX) += sandbox_adder.o
obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
+obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o
obj-$(CONFIG_SANDBOX) += swap_case.o
endif
@@ -39,6 +41,8 @@ obj-$(CONFIG_FS_LOADER) += fs_loader.o
obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
+obj-$(CONFIG_IRQ) += irq-uclass.o
+obj-$(CONFIG_SANDBOX) += irq_sandbox.o
obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
obj-$(CONFIG_IMX8) += imx8/
@@ -49,6 +53,7 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
obj-$(CONFIG_NS87308) += ns87308.o
obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
+obj-$(CONFIG_P2SB) += p2sb-uclass.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
obj-$(CONFIG_QFW) += qfw.o
diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
new file mode 100644
index 0000000000..d5182cf149
--- /dev/null
+++ b/drivers/misc/irq-uclass.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <irq.h>
+
+int irq_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
+{
+ const struct irq_ops *ops = irq_get_ops(dev);
+
+ if (!ops->route_pmc_gpio_gpe)
+ return -ENOSYS;
+
+ return ops->route_pmc_gpio_gpe(dev, pmc_gpe_num);
+}
+
+int irq_set_polarity(struct udevice *dev, uint irq, bool active_low)
+{
+ const struct irq_ops *ops = irq_get_ops(dev);
+
+ if (!ops->set_polarity)
+ return -ENOSYS;
+
+ return ops->set_polarity(dev, irq, active_low);
+}
+
+int irq_snapshot_polarities(struct udevice *dev)
+{
+ const struct irq_ops *ops = irq_get_ops(dev);
+
+ if (!ops->snapshot_polarities)
+ return -ENOSYS;
+
+ return ops->snapshot_polarities(dev);
+}
+
+int irq_restore_polarities(struct udevice *dev)
+{
+ const struct irq_ops *ops = irq_get_ops(dev);
+
+ if (!ops->restore_polarities)
+ return -ENOSYS;
+
+ return ops->restore_polarities(dev);
+}
+
+UCLASS_DRIVER(irq) = {
+ .id = UCLASS_IRQ,
+ .name = "irq",
+};
diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c
new file mode 100644
index 0000000000..6dda1a4c44
--- /dev/null
+++ b/drivers/misc/irq_sandbox.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox driver for interrupts
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <irq.h>
+
+static int sandbox_set_polarity(struct udevice *dev, uint irq, bool active_low)
+{
+ if (irq > 10)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sandbox_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
+{
+ if (pmc_gpe_num > 10)
+ return -ENOENT;
+
+ return pmc_gpe_num + 1;
+}
+
+static int sandbox_snapshot_polarities(struct udevice *dev)
+{
+ return 0;
+}
+
+static int sandbox_restore_polarities(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct irq_ops sandbox_irq_ops = {
+ .route_pmc_gpio_gpe = sandbox_route_pmc_gpio_gpe,
+ .set_polarity = sandbox_set_polarity,
+ .snapshot_polarities = sandbox_snapshot_polarities,
+ .restore_polarities = sandbox_restore_polarities,
+};
+
+static const struct udevice_id sandbox_irq_ids[] = {
+ { .compatible = "sandbox,irq"},
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_irq_drv) = {
+ .name = "sandbox_irq",
+ .id = UCLASS_IRQ,
+ .of_match = sandbox_irq_ids,
+ .ops = &sandbox_irq_ops,
+};
diff --git a/drivers/misc/p2sb-uclass.c b/drivers/misc/p2sb-uclass.c
new file mode 100644
index 0000000000..a198700b5f
--- /dev/null
+++ b/drivers/misc/p2sb-uclass.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Uclass for Primary-to-sideband bus, used to access various peripherals
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <p2sb.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <dm/uclass-internal.h>
+
+#define PCR_COMMON_IOSF_1_0 1
+
+static void *_pcr_reg_address(struct udevice *dev, uint offset)
+{
+ struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+ struct udevice *p2sb = dev_get_parent(dev);
+ struct p2sb_uc_priv *upriv = dev_get_uclass_priv(p2sb);
+ uintptr_t reg_addr;
+
+ /* Create an address based off of port id and offset */
+ reg_addr = upriv->mmio_base;
+ reg_addr += pplat->pid << PCR_PORTID_SHIFT;
+ reg_addr += offset;
+
+ return map_sysmem(reg_addr, 4);
+}
+
+/*
+ * The mapping of addresses via the SBREG_BAR assumes the IOSF-SB
+ * agents are using 32-bit aligned accesses for their configuration
+ * registers. For IOSF versions greater than 1_0, IOSF-SB
+ * agents can use any access (8/16/32 bit aligned) for their
+ * configuration registers
+ */
+static inline void check_pcr_offset_align(uint offset, uint size)
+{
+ const size_t align = PCR_COMMON_IOSF_1_0 ? sizeof(uint32_t) : size;
+
+ assert(IS_ALIGNED(offset, align));
+}
+
+uint pcr_read32(struct udevice *dev, uint offset)
+{
+ void *ptr;
+ uint val;
+
+ /* Ensure the PCR offset is correctly aligned */
+ assert(IS_ALIGNED(offset, sizeof(uint32_t)));
+
+ ptr = _pcr_reg_address(dev, offset);
+ val = readl(ptr);
+ unmap_sysmem(ptr);
+
+ return val;
+}
+
+uint pcr_read16(struct udevice *dev, uint offset)
+{
+ /* Ensure the PCR offset is correctly aligned */
+ check_pcr_offset_align(offset, sizeof(uint16_t));
+
+ return readw(_pcr_reg_address(dev, offset));
+}
+
+uint pcr_read8(struct udevice *dev, uint offset)
+{
+ /* Ensure the PCR offset is correctly aligned */
+ check_pcr_offset_align(offset, sizeof(uint8_t));
+
+ return readb(_pcr_reg_address(dev, offset));
+}
+
+/*
+ * After every write one needs to perform a read an innocuous register to
+ * ensure the writes are completed for certain ports. This is done for
+ * all ports so that the callers don't need the per-port knowledge for
+ * each transaction.
+ */
+static void write_completion(struct udevice *dev, uint offset)
+{
+ readl(_pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
+}
+
+void pcr_write32(struct udevice *dev, uint offset, uint indata)
+{
+ /* Ensure the PCR offset is correctly aligned */
+ assert(IS_ALIGNED(offset, sizeof(indata)));
+
+ writel(indata, _pcr_reg_address(dev, offset));
+ /* Ensure the writes complete */
+ write_completion(dev, offset);
+}
+
+void pcr_write16(struct udevice *dev, uint offset, uint indata)
+{
+ /* Ensure the PCR offset is correctly aligned */
+ check_pcr_offset_align(offset, sizeof(uint16_t));
+
+ writew(indata, _pcr_reg_address(dev, offset));
+ /* Ensure the writes complete */
+ write_completion(dev, offset);
+}
+
+void pcr_write8(struct udevice *dev, uint offset, uint indata)
+{
+ /* Ensure the PCR offset is correctly aligned */
+ check_pcr_offset_align(offset, sizeof(uint8_t));
+
+ writeb(indata, _pcr_reg_address(dev, offset));
+ /* Ensure the writes complete */
+ write_completion(dev, offset);
+}
+
+void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set)
+{
+ uint data32;
+
+ data32 = pcr_read32(dev, offset);
+ data32 &= ~clr;
+ data32 |= set;
+ pcr_write32(dev, offset, data32);
+}
+
+void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set)
+{
+ uint data16;
+
+ data16 = pcr_read16(dev, offset);
+ data16 &= ~clr;
+ data16 |= set;
+ pcr_write16(dev, offset, data16);
+}
+
+void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set)
+{
+ uint data8;
+
+ data8 = pcr_read8(dev, offset);
+ data8 &= ~clr;
+ data8 |= set;
+ pcr_write8(dev, offset, data8);
+}
+
+int p2sb_get_port_id(struct udevice *dev)
+{
+ struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+
+ return pplat->pid;
+}
+
+int p2sb_set_port_id(struct udevice *dev, int portid)
+{
+ struct udevice *ps2b;
+ struct p2sb_child_platdata *pplat;
+
+ if (!CONFIG_IS_ENABLED(OF_PLATDATA))
+ return -ENOSYS;
+
+ uclass_find_first_device(UCLASS_P2SB, &ps2b);
+ if (!ps2b)
+ return -EDEADLK;
+ dev->parent = ps2b;
+
+ /*
+ * We must allocate this, since when the device was bound it did not
+ * have a parent.
+ * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
+ */
+ dev->parent_platdata = malloc(sizeof(*pplat));
+ if (!dev->parent_platdata)
+ return -ENOMEM;
+ pplat = dev_get_parent_platdata(dev);
+ pplat->pid = portid;
+
+ return 0;
+}
+
+static int p2sb_child_post_bind(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+ int ret;
+ u32 pid;
+
+ ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
+ if (ret)
+ return ret;
+ pplat->pid = pid;
+#endif
+
+ return 0;
+}
+
+static int p2sb_post_bind(struct udevice *dev)
+{
+ if (spl_phase() > PHASE_TPL && !CONFIG_IS_ENABLED(OF_PLATDATA))
+ return dm_scan_fdt_dev(dev);
+
+ return 0;
+}
+
+UCLASS_DRIVER(p2sb) = {
+ .id = UCLASS_P2SB,
+ .name = "p2sb",
+ .per_device_auto_alloc_size = sizeof(struct p2sb_uc_priv),
+ .post_bind = p2sb_post_bind,
+ .child_post_bind = p2sb_child_post_bind,
+ .per_child_platdata_auto_alloc_size =
+ sizeof(struct p2sb_child_platdata),
+};
diff --git a/drivers/misc/p2sb_emul.c b/drivers/misc/p2sb_emul.c
new file mode 100644
index 0000000000..c3795c59c0
--- /dev/null
+++ b/drivers/misc/p2sb_emul.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI emulation device for an x86 Primary-to-Sideband bus
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY UCLASS_MISC
+#define LOG_DEBUG
+
+#include <common.h>
+#include <axi.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/test.h>
+#include <p2sb.h>
+
+/**
+ * struct p2sb_emul_platdata - platform data for this device
+ *
+ * @command: Current PCI command value
+ * @bar: Current base address values
+ */
+struct p2sb_emul_platdata {
+ u16 command;
+ u32 bar[6];
+};
+
+enum {
+ /* This emulator supports 16 different devices */
+ MEMMAP_SIZE = 16 << PCR_PORTID_SHIFT,
+};
+
+static struct pci_bar {
+ int type;
+ u32 size;
+} barinfo[] = {
+ { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+};
+
+struct p2sb_emul_priv {
+ u8 regs[16];
+};
+
+static int sandbox_p2sb_emul_read_config(struct udevice *emul, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ *valuep = plat->command;
+ break;
+ case PCI_HEADER_TYPE:
+ *valuep = PCI_HEADER_TYPE_NORMAL;
+ break;
+ case PCI_VENDOR_ID:
+ *valuep = SANDBOX_PCI_VENDOR_ID;
+ break;
+ case PCI_DEVICE_ID:
+ *valuep = SANDBOX_PCI_P2SB_EMUL_ID;
+ break;
+ case PCI_CLASS_DEVICE:
+ if (size == PCI_SIZE_8) {
+ *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
+ } else {
+ *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
+ SANDBOX_PCI_CLASS_SUB_CODE;
+ }
+ break;
+ case PCI_CLASS_CODE:
+ *valuep = SANDBOX_PCI_CLASS_CODE;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1:
+ case PCI_BASE_ADDRESS_2:
+ case PCI_BASE_ADDRESS_3:
+ case PCI_BASE_ADDRESS_4:
+ case PCI_BASE_ADDRESS_5: {
+ int barnum;
+ u32 *bar;
+
+ barnum = pci_offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
+ barinfo[barnum].size);
+ break;
+ }
+ case PCI_CAPABILITY_LIST:
+ *valuep = PCI_CAP_ID_PM_OFFSET;
+ break;
+ }
+
+ return 0;
+}
+
+static int sandbox_p2sb_emul_write_config(struct udevice *emul, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ plat->command = value;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1: {
+ int barnum;
+ u32 *bar;
+
+ barnum = pci_offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ log_debug("w bar %d=%lx\n", barnum, value);
+ *bar = value;
+ /* space indicator (bit#0) is read-only */
+ *bar |= barinfo[barnum].type;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_p2sb_emul_find_bar(struct udevice *emul, unsigned int addr,
+ int *barnump, unsigned int *offsetp)
+{
+ struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
+ int barnum;
+
+ for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
+ unsigned int size = barinfo[barnum].size;
+ u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
+
+ if (addr >= base && addr < base + size) {
+ *barnump = barnum;
+ *offsetp = addr - base;
+ return 0;
+ }
+ }
+ *barnump = -1;
+
+ return -ENOENT;
+}
+
+static int sandbox_p2sb_emul_read_io(struct udevice *dev, unsigned int addr,
+ ulong *valuep, enum pci_size_t size)
+{
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ if (barnum == 4)
+ *valuep = offset;
+ else if (barnum == 0)
+ *valuep = offset;
+
+ return 0;
+}
+
+static int sandbox_p2sb_emul_write_io(struct udevice *dev, unsigned int addr,
+ ulong value, enum pci_size_t size)
+{
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int find_p2sb_channel(struct udevice *emul, uint offset,
+ struct udevice **devp)
+{
+ uint pid = offset >> PCR_PORTID_SHIFT;
+ struct udevice *p2sb, *dev;
+ int ret;
+
+ ret = sandbox_pci_get_client(emul, &p2sb);
+ if (ret)
+ return log_msg_ret("No client", ret);
+
+ device_foreach_child(dev, p2sb) {
+ struct p2sb_child_platdata *pplat =
+ dev_get_parent_platdata(dev);
+
+ log_debug(" - child %s, pid %d, want %d\n", dev->name,
+ pplat->pid, pid);
+ if (pid == pplat->pid) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int sandbox_p2sb_emul_map_physmem(struct udevice *dev,
+ phys_addr_t addr, unsigned long *lenp,
+ void **ptrp)
+{
+ struct p2sb_emul_priv *priv = dev_get_priv(dev);
+ struct udevice *child;
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ log_debug("map %x: ", (uint)addr);
+ ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return log_msg_ret("Cannot find bar", ret);
+ log_debug("bar %d, offset %x\n", barnum, offset);
+
+ if (barnum != 0)
+ return log_msg_ret("Unknown BAR", -EINVAL);
+
+ ret = find_p2sb_channel(dev, offset, &child);
+ if (ret)
+ return log_msg_ret("Cannot find channel", ret);
+
+ offset &= ((1 << PCR_PORTID_SHIFT) - 1);
+ ret = axi_read(child, offset, priv->regs, AXI_SIZE_32);
+ if (ret)
+ return log_msg_ret("Child read failed", ret);
+ *ptrp = priv->regs + (offset & 3);
+ *lenp = 4;
+
+ return 0;
+}
+
+static struct dm_pci_emul_ops sandbox_p2sb_emul_emul_ops = {
+ .read_config = sandbox_p2sb_emul_read_config,
+ .write_config = sandbox_p2sb_emul_write_config,
+ .read_io = sandbox_p2sb_emul_read_io,
+ .write_io = sandbox_p2sb_emul_write_io,
+ .map_physmem = sandbox_p2sb_emul_map_physmem,
+};
+
+static const struct udevice_id sandbox_p2sb_emul_ids[] = {
+ { .compatible = "sandbox,p2sb-emul" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_p2sb_emul_emul) = {
+ .name = "sandbox_p2sb_emul_emul",
+ .id = UCLASS_PCI_EMUL,
+ .of_match = sandbox_p2sb_emul_ids,
+ .ops = &sandbox_p2sb_emul_emul_ops,
+ .priv_auto_alloc_size = sizeof(struct p2sb_emul_priv),
+ .platdata_auto_alloc_size = sizeof(struct p2sb_emul_platdata),
+};
+
+static struct pci_device_id sandbox_p2sb_emul_supported[] = {
+ { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
+ {},
+};
+
+U_BOOT_PCI_DEVICE(sandbox_p2sb_emul_emul, sandbox_p2sb_emul_supported);
diff --git a/drivers/misc/p2sb_sandbox.c b/drivers/misc/p2sb_sandbox.c
new file mode 100644
index 0000000000..ce50a9732e
--- /dev/null
+++ b/drivers/misc/p2sb_sandbox.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox P2SB for testing
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_P2SB
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <p2sb.h>
+
+struct sandbox_p2sb_priv {
+ ulong base;
+};
+
+static int sandbox_p2sb_probe(struct udevice *dev)
+{
+ struct p2sb_uc_priv *upriv = dev_get_uclass_priv(dev);
+
+ upriv->mmio_base = dm_pci_read_bar32(dev, 0);
+
+ return 0;
+}
+
+static const struct udevice_id sandbox_p2sb_ids[] = {
+ { .compatible = "sandbox,p2sb" },
+ { }
+};
+
+U_BOOT_DRIVER(p2sb_sandbox) = {
+ .name = "p2sb_sandbox",
+ .id = UCLASS_P2SB,
+ .of_match = sandbox_p2sb_ids,
+ .probe = sandbox_p2sb_probe,
+ .priv_auto_alloc_size = sizeof(struct sandbox_p2sb_priv),
+};
diff --git a/drivers/misc/sandbox_adder.c b/drivers/misc/sandbox_adder.c
new file mode 100644
index 0000000000..df262e6255
--- /dev/null
+++ b/drivers/misc/sandbox_adder.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox adder for p2sb testing
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_MISC
+
+#include <common.h>
+#include <axi.h>
+#include <dm.h>
+#include <misc.h>
+#include <p2sb.h>
+#include <asm/io.h>
+
+struct sandbox_adder_priv {
+ ulong base;
+};
+
+int sandbox_adder_read(struct udevice *dev, ulong address, void *data,
+ enum axi_size_t size)
+{
+ struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+ u32 *val = data;
+
+ *val = pplat->pid << 24 | address;
+
+ return 0;
+}
+
+int sandbox_adder_write(struct udevice *dev, ulong address, void *data,
+ enum axi_size_t size)
+{
+ return 0;
+}
+
+static int sandbox_adder_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static struct axi_ops sandbox_adder_ops = {
+ .read = sandbox_adder_read,
+ .write = sandbox_adder_write,
+};
+
+static const struct udevice_id sandbox_adder_ids[] = {
+ { .compatible = "sandbox,adder" },
+ { }
+};
+
+U_BOOT_DRIVER(adder_sandbox) = {
+ .name = "sandbox_adder",
+ .id = UCLASS_AXI,
+ .of_match = sandbox_adder_ids,
+ .probe = sandbox_adder_probe,
+ .ops = &sandbox_adder_ops,
+ .priv_auto_alloc_size = sizeof(struct sandbox_adder_priv),
+};
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c
index f1afab742d..f7b754bd9d 100644
--- a/drivers/mmc/fsl_esdhc_imx.c
+++ b/drivers/mmc/fsl_esdhc_imx.c
@@ -150,7 +150,7 @@ struct fsl_esdhc_priv {
struct udevice *vqmmc_dev;
struct udevice *vmmc_dev;
#endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc cd_gpio;
struct gpio_desc wp_gpio;
#endif
@@ -303,8 +303,9 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
return -ETIMEDOUT;
}
} else {
-#ifdef CONFIG_DM_GPIO
- if (dm_gpio_is_valid(&priv->wp_gpio) && dm_gpio_get_value(&priv->wp_gpio)) {
+#if CONFIG_IS_ENABLED(DM_GPIO)
+ if (dm_gpio_is_valid(&priv->wp_gpio) &&
+ dm_gpio_get_value(&priv->wp_gpio)) {
printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
return -ETIMEDOUT;
}
@@ -1092,7 +1093,7 @@ static int esdhc_getcd_common(struct fsl_esdhc_priv *priv)
#if CONFIG_IS_ENABLED(DM_MMC)
if (priv->non_removable)
return 1;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
if (dm_gpio_is_valid(&priv->cd_gpio))
return dm_gpio_get_value(&priv->cd_gpio);
#endif
@@ -1454,7 +1455,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
priv->non_removable = 1;
} else {
priv->non_removable = 0;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
GPIOD_IS_IN);
#endif
@@ -1464,7 +1465,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
priv->wp_enable = 1;
} else {
priv->wp_enable = 0;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio,
GPIOD_IS_IN);
#endif
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index dab3425e97..5d0cfb2ebd 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -184,7 +184,7 @@ static int omap_mmc_setup_gpio_in(int gpio, const char *label)
{
int ret;
-#ifndef CONFIG_DM_GPIO
+#if !CONFIG_IS_ENABLED(DM_GPIO)
if (!gpio_is_valid(gpio))
return -1;
#endif
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index f051e473ff..72b6ee702d 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -137,7 +137,7 @@ static int spi_flash_std_get_sw_write_prot(struct udevice *dev)
return spi_flash_cmd_get_sw_write_prot(flash);
}
-static int spi_flash_std_probe(struct udevice *dev)
+int spi_flash_std_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parent_priv(dev);
struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 5c2d5e5a79..19fc34f771 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -82,7 +82,7 @@ static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
return ret;
}
-#if defined(CONFIG_DM_ETH) && defined(CONFIG_DM_GPIO)
+#if defined(CONFIG_DM_ETH) && CONFIG_IS_ENABLED(DM_GPIO)
static int dw_mdio_reset(struct mii_dev *bus)
{
struct udevice *dev = bus->priv;
@@ -128,7 +128,7 @@ static int dw_mdio_init(const char *name, void *priv)
bus->read = dw_mdio_read;
bus->write = dw_mdio_write;
snprintf(bus->name, sizeof(bus->name), "%s", name);
-#if defined(CONFIG_DM_ETH) && defined(CONFIG_DM_GPIO)
+#if defined(CONFIG_DM_ETH) && CONFIG_IS_ENABLED(DM_GPIO)
bus->reset = dw_mdio_reset;
#endif
@@ -807,12 +807,12 @@ const struct eth_ops designware_eth_ops = {
int designware_eth_ofdata_to_platdata(struct udevice *dev)
{
struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct dw_eth_dev *priv = dev_get_priv(dev);
#endif
struct eth_pdata *pdata = &dw_pdata->eth_pdata;
const char *phy_mode;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
int reset_flags = GPIOD_IS_OUT;
#endif
int ret = 0;
@@ -829,7 +829,7 @@ int designware_eth_ofdata_to_platdata(struct udevice *dev)
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
if (dev_read_bool(dev, "snps,reset-active-low"))
reset_flags |= GPIOD_ACTIVE_LOW;
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index dea12b7048..3519a4167a 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -7,7 +7,7 @@
#ifndef _DW_ETH_H
#define _DW_ETH_H
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
#include <asm-generic/gpio.h>
#endif
@@ -235,7 +235,7 @@ struct dw_eth_dev {
#ifndef CONFIG_DM_ETH
struct eth_device *dev;
#endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc reset_gpio;
#endif
#ifdef CONFIG_CLK
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index 2aa1029d42..bc5b63d788 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -1309,7 +1309,7 @@ static int fec_phy_init(struct fec_priv *priv, struct udevice *dev)
return 0;
}
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
/* FEC GPIO reset */
static void fec_gpio_reset(struct fec_priv *priv)
{
@@ -1402,7 +1402,7 @@ static int fecmxc_probe(struct udevice *dev)
}
#endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
fec_gpio_reset(priv);
#endif
/* Reset chip. */
@@ -1508,7 +1508,7 @@ static int fecmxc_ofdata_to_platdata(struct udevice *dev)
device_get_supply_regulator(dev, "phy-supply", &priv->phy_supply);
#endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
ret = gpio_request_by_name(dev, "phy-reset-gpios", 0,
&priv->phy_reset_gpio, GPIOD_IS_OUT);
if (ret < 0)
diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h
index 723b06a651..159aec8967 100644
--- a/drivers/net/fec_mxc.h
+++ b/drivers/net/fec_mxc.h
@@ -255,7 +255,7 @@ struct fec_priv {
#ifdef CONFIG_DM_REGULATOR
struct udevice *phy_supply;
#endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc phy_reset_gpio;
uint32_t reset_delay;
uint32_t reset_post_delay;
diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c
index 6f76a6b0dc..5fe8500199 100644
--- a/drivers/net/mvneta.c
+++ b/drivers/net/mvneta.c
@@ -276,7 +276,7 @@ struct mvneta_port {
int init;
int phyaddr;
struct phy_device *phydev;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc phy_reset_gpio;
#endif
struct mii_dev *bus;
@@ -1754,7 +1754,7 @@ static int mvneta_probe(struct udevice *dev)
if (ret)
return ret;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
gpio_request_by_name(dev, "phy-reset-gpios", 0,
&pp->phy_reset_gpio, GPIOD_IS_OUT);
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index c5d1f9cf9f..917d06b6e0 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -959,7 +959,8 @@ struct mvpp2_port {
phy_interface_t phy_interface;
int phyaddr;
struct udevice *mdio_dev;
-#ifdef CONFIG_DM_GPIO
+ struct mii_dev *bus;
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc phy_reset_gpio;
struct gpio_desc phy_tx_disable_gpio;
#endif
@@ -4742,7 +4743,7 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
return -EINVAL;
}
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
gpio_request_by_name(dev, "phy-reset-gpios", 0,
&port->phy_reset_gpio, GPIOD_IS_OUT);
gpio_request_by_name(dev, "marvell,sfp-tx-disable-gpio", 0,
@@ -4769,7 +4770,7 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
return 0;
}
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
/* Port GPIO initialization */
static void mvpp2_gpio_init(struct mvpp2_port *port)
{
@@ -4802,7 +4803,7 @@ static int mvpp2_port_probe(struct udevice *dev,
}
mvpp2_port_power_up(port);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
mvpp2_gpio_init(port);
#endif
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 9551918796..6f10578c88 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -24,7 +24,7 @@
#include <net.h>
#include <reset.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
#include <asm-generic/gpio.h>
#endif
@@ -142,7 +142,7 @@ struct emac_eth_dev {
struct clk ephy_clk;
struct reset_ctl tx_rst;
struct reset_ctl ephy_rst;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc reset_gpio;
#endif
};
@@ -696,7 +696,7 @@ err_tx_clk:
return ret;
}
-#if defined(CONFIG_DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
static int sun8i_mdio_reset(struct mii_dev *bus)
{
struct udevice *dev = bus->priv;
@@ -743,7 +743,7 @@ static int sun8i_mdio_init(const char *name, struct udevice *priv)
bus->write = sun8i_mdio_write;
snprintf(bus->name, sizeof(bus->name), name);
bus->priv = (void *)priv;
-#if defined(CONFIG_DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
bus->reset = sun8i_mdio_reset;
#endif
@@ -905,7 +905,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
const fdt32_t *reg;
int node = dev_of_offset(dev);
int offset = 0;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
int reset_flags = GPIOD_IS_OUT;
#endif
int ret;
@@ -999,7 +999,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
printf("%s: Invalid RX delay value %d\n", __func__,
sun8i_pdata->rx_delay_ps);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
"snps,reset-active-low"))
reset_flags |= GPIOD_ACTIVE_LOW;
diff --git a/drivers/pch/Kconfig b/drivers/pch/Kconfig
index 18f006de24..c49a92885a 100644
--- a/drivers/pch/Kconfig
+++ b/drivers/pch/Kconfig
@@ -7,3 +7,21 @@ config PCH
northbridge / southbridge architecture that was previously used. The
PCH allows for higher performance since the memory functions are
handled in the CPU.
+
+config X86_PCH7
+ bool "Add support for Intel PCH7"
+ default y if X86
+ help
+ Enable this if your SoC uses Platform Controller Hub 7 (PCH7). This
+ dates from about 2011 and is used on baytrail, for example. The
+ PCH provides access to the GPIO and SPI base addresses, among other
+ functions.
+
+config X86_PCH9
+ bool "Add support for Intel PCH9"
+ default y if X86
+ help
+ Enable this if your SoC uses Platform Controller Hub 9 (PCH9). This
+ dates from about 2015 and is used on baytrail, for example. The
+ PCH provides access to the GPIO and SPI base addresses, among other
+ functions.
diff --git a/drivers/pch/Makefile b/drivers/pch/Makefile
index 8ea6b7852a..d5de3e48be 100644
--- a/drivers/pch/Makefile
+++ b/drivers/pch/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += pch-uclass.o
-obj-y += pch7.o
-obj-y += pch9.o
+obj-$(CONFIG_X86_PCH7) += pch7.o
+obj-$(CONFIG_X86_PCH9) += pch9.o
obj-$(CONFIG_SANDBOX) += sandbox_pch.o
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c
index 864ac16f57..aa0b4bc845 100644
--- a/drivers/pci/pci-aardvark.c
+++ b/drivers/pci/pci-aardvark.c
@@ -610,7 +610,7 @@ static int pcie_advk_probe(struct udevice *dev)
{
struct pcie_advk *pcie = dev_get_priv(dev);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc reset_gpio;
gpio_request_by_name(dev, "reset-gpio", 0, &reset_gpio,
@@ -636,7 +636,7 @@ static int pcie_advk_probe(struct udevice *dev)
}
#else
dev_dbg(pcie->dev, "PCIE Reset on GPIO support is missing\n");
-#endif /* CONFIG_DM_GPIO */
+#endif /* DM_GPIO */
pcie->first_busno = dev->seq;
pcie->dev = pci_get_controller(dev);
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index fab20fc60e..7308f612b6 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -975,12 +975,15 @@ static int pci_uclass_pre_probe(struct udevice *bus)
hose->bus = bus;
hose->first_busno = bus->seq;
hose->last_busno = bus->seq;
+ hose->skip_auto_config_until_reloc =
+ dev_read_bool(bus, "u-boot,skip-auto-config-until-reloc");
return 0;
}
static int pci_uclass_post_probe(struct udevice *bus)
{
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
int ret;
debug("%s: probing bus %d\n", __func__, bus->seq);
@@ -988,11 +991,13 @@ static int pci_uclass_post_probe(struct udevice *bus)
if (ret)
return ret;
-#if CONFIG_IS_ENABLED(PCI_PNP)
- ret = pci_auto_config_devices(bus);
- if (ret < 0)
- return ret;
-#endif
+ if (CONFIG_IS_ENABLED(PCI_PNP) &&
+ (!hose->skip_auto_config_until_reloc ||
+ (gd->flags & GD_FLG_RELOC))) {
+ ret = pci_auto_config_devices(bus);
+ if (ret < 0)
+ return log_msg_ret("pci auto-config", ret);
+ }
#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
/*
@@ -1018,22 +1023,6 @@ static int pci_uclass_post_probe(struct udevice *bus)
return 0;
}
-int pci_get_devfn(struct udevice *dev)
-{
- struct fdt_pci_addr addr;
- int ret;
-
- /* Extract the devfn from fdt_pci_addr */
- ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
- "reg", &addr);
- if (ret) {
- if (ret != -ENOENT)
- return -EINVAL;
- }
-
- return addr.phys_hi & 0xff00;
-}
-
static int pci_uclass_child_post_bind(struct udevice *dev)
{
struct pci_child_platdata *pplat;
diff --git a/drivers/pci/pcie_dw_mvebu.c b/drivers/pci/pcie_dw_mvebu.c
index 95fb41966f..693591e375 100644
--- a/drivers/pci/pcie_dw_mvebu.c
+++ b/drivers/pci/pcie_dw_mvebu.c
@@ -476,7 +476,7 @@ static int pcie_dw_mvebu_probe(struct udevice *dev)
struct pcie_dw_mvebu *pcie = dev_get_priv(dev);
struct udevice *ctlr = pci_get_controller(dev);
struct pci_controller *hose = dev_get_uclass_priv(ctlr);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc reset_gpio;
gpio_request_by_name(dev, "marvell,reset-gpio", 0, &reset_gpio,
@@ -496,7 +496,7 @@ static int pcie_dw_mvebu_probe(struct udevice *dev)
}
#else
debug("PCIE Reset on GPIO support is missing\n");
-#endif /* CONFIG_DM_GPIO */
+#endif /* DM_GPIO */
pcie->first_busno = dev->seq;
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index eadcfd6652..83e39b9de3 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -82,6 +82,13 @@ config SPL_PINCTRL
This option is an SPL-variant of the PINCTRL option.
See the help of PINCTRL for details.
+config TPL_PINCTRL
+ bool "Support pin controllers in TPL"
+ depends on TPL && TPL_DM
+ help
+ This option is an TPL variant of the PINCTRL option.
+ See the help of PINCTRL for details.
+
config SPL_PINCTRL_FULL
bool "Support full pin controllers in SPL"
depends on SPL_PINCTRL && SPL_OF_CONTROL
@@ -91,6 +98,13 @@ config SPL_PINCTRL_FULL
This option is an SPL-variant of the PINCTRL_FULL option.
See the help of PINCTRL_FULL for details.
+config TPL_PINCTRL_FULL
+ bool "Support full pin controllers in TPL"
+ depends on TPL_PINCTRL && TPL_OF_CONTROL
+ help
+ This option is an TPL-variant of the PINCTRL_FULL option.
+ See the help of PINCTRL_FULL for details.
+
config SPL_PINCTRL_GENERIC
bool "Support generic pin controllers in SPL"
depends on SPL_PINCTRL_FULL
@@ -163,6 +177,14 @@ config PINCTRL_AT91PIO4
This option is to enable the AT91 pinctrl driver for AT91 PIO4
controller which is available on SAMA5D2 SoC.
+config PINCTRL_INTEL
+ bool "Standard Intel pin-control and pin-mux driver"
+ help
+ Recent Intel chips such as Apollo Lake (APL) use a common pin control
+ and GPIO scheme. The settings for this come from an SoC-specific
+ driver which must be separately enabled. The driver supports setting
+ pins on start-up and changing the GPIO attributes.
+
config PINCTRL_PIC32
bool "Microchip PIC32 pin-control and pin-mux driver"
depends on DM && MACH_PIC32
@@ -266,6 +288,7 @@ endif
source "drivers/pinctrl/broadcom/Kconfig"
source "drivers/pinctrl/exynos/Kconfig"
+source "drivers/pinctrl/intel/Kconfig"
source "drivers/pinctrl/mediatek/Kconfig"
source "drivers/pinctrl/meson/Kconfig"
source "drivers/pinctrl/mscc/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index ce0879a2b7..4f662c4f6d 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -9,6 +9,7 @@ obj-y += nxp/
obj-$(CONFIG_$(SPL_)PINCTRL_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
obj-$(CONFIG_ARCH_ATH79) += ath79/
+obj-$(CONFIG_PINCTRL_INTEL) += intel/
obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
obj-$(CONFIG_ARCH_RMOBILE) += renesas/
obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig
new file mode 100644
index 0000000000..e62a2e0349
--- /dev/null
+++ b/drivers/pinctrl/intel/Kconfig
@@ -0,0 +1,26 @@
+#
+# Intel PINCTRL drivers
+#
+
+if PINCTRL_INTEL
+
+config INTEL_PINCTRL_DUAL_ROUTE_SUPPORT
+ bool
+ default y
+
+config INTEL_PINCTRL_PADCFG_PADTOL
+ bool n
+
+config INTEL_PINCTRL_IOSTANDBY
+ bool
+ default y
+
+config PINCTRL_INTEL_APL
+ bool "Support Intel Apollo Lake (APL)"
+ help
+ Add support for Intel Apollo Lake pin-control and pin-mux settings.
+ These are mostly read from the device tree, with the early-pads
+ property in the host bridge and the pads property in the fsp-s
+ subnode of the host bridge.
+
+endif
diff --git a/drivers/pinctrl/intel/Makefile b/drivers/pinctrl/intel/Makefile
new file mode 100644
index 0000000000..3aed8e9663
--- /dev/null
+++ b/drivers/pinctrl/intel/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-y += pinctrl.o
+obj-$(CONFIG_PINCTRL_INTEL_APL) += pinctrl_apl.o
diff --git a/drivers/pinctrl/intel/pinctrl.c b/drivers/pinctrl/intel/pinctrl.c
new file mode 100644
index 0000000000..4875a3b0b5
--- /dev/null
+++ b/drivers/pinctrl/intel/pinctrl.c
@@ -0,0 +1,636 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Intel Corp.
+ * Copyright 2019 Google LLC
+ *
+ * Taken partly from coreboot gpio.c
+ *
+ * Pinctrl is modelled as a separate device-tree node and device for each
+ * 'community' (basically a set of GPIOs). The separate devices work together
+ * and many functions permit any PINCTRL device to be provided as a parameter,
+ * since the pad numbering is unique across all devices.
+ *
+ * Each pinctrl has a single child GPIO device to handle GPIO access and
+ * therefore there is a simple GPIO driver included in this file.
+ */
+
+#define LOG_CATEGORY UCLASS_GPIO
+
+#include <common.h>
+#include <dm.h>
+#include <irq.h>
+#include <p2sb.h>
+#include <spl.h>
+#include <asm-generic/gpio.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/intel_pinctrl_defs.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/itss.h>
+#include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#define GPIO_DW_SIZE(x) (sizeof(u32) * (x))
+#define PAD_CFG_OFFSET(x, dw_num) ((x) + GPIO_DW_SIZE(dw_num))
+#define PAD_CFG0_OFFSET(x) PAD_CFG_OFFSET(x, 0)
+#define PAD_CFG1_OFFSET(x) PAD_CFG_OFFSET(x, 1)
+
+#define MISCCFG_GPE0_DW0_SHIFT 8
+#define MISCCFG_GPE0_DW0_MASK (0xf << MISCCFG_GPE0_DW0_SHIFT)
+#define MISCCFG_GPE0_DW1_SHIFT 12
+#define MISCCFG_GPE0_DW1_MASK (0xf << MISCCFG_GPE0_DW1_SHIFT)
+#define MISCCFG_GPE0_DW2_SHIFT 16
+#define MISCCFG_GPE0_DW2_MASK (0xf << MISCCFG_GPE0_DW2_SHIFT)
+
+#define GPI_SMI_STS_OFFSET(comm, group) ((comm)->gpi_smi_sts_reg_0 + \
+ ((group) * sizeof(u32)))
+#define GPI_SMI_EN_OFFSET(comm, group) ((comm)->gpi_smi_en_reg_0 + \
+ ((group) * sizeof(u32)))
+#define GPI_IS_OFFSET(comm, group) ((comm)->gpi_int_sts_reg_0 + \
+ ((group) * sizeof(uint32_t)))
+#define GPI_IE_OFFSET(comm, group) ((comm)->gpi_int_en_reg_0 + \
+ ((group) * sizeof(uint32_t)))
+
+/**
+ * relative_pad_in_comm() - Get the relative position of a GPIO
+ *
+ * This finds the position of a GPIO within a community
+ *
+ * @comm: Community to search
+ * @gpio: Pad number to look up (assumed to be valid)
+ * @return offset, 0 for first GPIO in community
+ */
+static size_t relative_pad_in_comm(const struct pad_community *comm,
+ uint gpio)
+{
+ return gpio - comm->first_pad;
+}
+
+/**
+ * pinctrl_group_index() - Find group for a a pad
+ *
+ * Find the group within the community that the pad is a part of
+ *
+ * @comm: Community to search
+ * @relative_pad: Pad to look up
+ * @return group number if found (see community_n_groups, etc.), or
+ * -ESPIPE if no groups, or -ENOENT if not found
+ */
+static int pinctrl_group_index(const struct pad_community *comm,
+ uint relative_pad)
+{
+ int i;
+
+ if (!comm->groups)
+ return -ESPIPE;
+
+ /* find the base pad number for this pad's group */
+ for (i = 0; i < comm->num_groups; i++) {
+ if (relative_pad >= comm->groups[i].first_pad &&
+ relative_pad < comm->groups[i].first_pad +
+ comm->groups[i].size)
+ return i;
+ }
+
+ return -ENOENT;
+}
+
+static int pinctrl_group_index_scaled(const struct pad_community *comm,
+ uint relative_pad, size_t scale)
+{
+ int ret;
+
+ ret = pinctrl_group_index(comm, relative_pad);
+ if (ret < 0)
+ return ret;
+
+ return ret * scale;
+}
+
+static int pinctrl_within_group(const struct pad_community *comm,
+ uint relative_pad)
+{
+ int ret;
+
+ ret = pinctrl_group_index(comm, relative_pad);
+ if (ret < 0)
+ return ret;
+
+ return relative_pad - comm->groups[ret].first_pad;
+}
+
+static u32 pinctrl_bitmask_within_group(const struct pad_community *comm,
+ uint relative_pad)
+{
+ return 1U << pinctrl_within_group(comm, relative_pad);
+}
+
+/**
+ * pinctrl_get_device() - Find the device for a particular pad
+ *
+ * Each pinctr, device is attached to one community and this supports a number
+ * of pads. This function finds the device which controls a particular pad.
+ *
+ * @pad: Pad to check
+ * @devp: Returns the device for that pad
+ * @return 0 if OK, -ENOTBLK if no device was found for the given pin
+ */
+static int pinctrl_get_device(uint pad, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ /*
+ * We have to probe each one of these since the community link is only
+ * attached in intel_pinctrl_ofdata_to_platdata().
+ */
+ uclass_foreach_dev_probe(UCLASS_PINCTRL, dev) {
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct pad_community *comm = priv->comm;
+
+ if (pad >= comm->first_pad && pad <= comm->last_pad) {
+ *devp = dev;
+ return 0;
+ }
+ }
+ printf("pad %d not found\n", pad);
+
+ return -ENOTBLK;
+}
+
+int intel_pinctrl_get_pad(uint pad, struct udevice **devp, uint *offsetp)
+{
+ const struct pad_community *comm;
+ struct intel_pinctrl_priv *priv;
+ struct udevice *dev;
+ int ret;
+
+ ret = pinctrl_get_device(pad, &dev);
+ if (ret)
+ return log_msg_ret("pad", ret);
+ priv = dev_get_priv(dev);
+ comm = priv->comm;
+ *devp = dev;
+ *offsetp = relative_pad_in_comm(comm, pad);
+
+ return 0;
+}
+
+static int pinctrl_configure_owner(struct udevice *dev,
+ const struct pad_config *cfg,
+ const struct pad_community *comm)
+{
+ u32 hostsw_own;
+ u16 hostsw_own_offset;
+ int pin;
+ int ret;
+
+ pin = relative_pad_in_comm(comm, cfg->pad);
+
+ /*
+ * Based on the gpio pin number configure the corresponding bit in
+ * HOSTSW_OWN register. Value of 0x1 indicates GPIO Driver onwership.
+ */
+ hostsw_own_offset = comm->host_own_reg_0;
+ ret = pinctrl_group_index_scaled(comm, pin, sizeof(u32));
+ if (ret < 0)
+ return ret;
+ hostsw_own_offset += ret;
+
+ hostsw_own = pcr_read32(dev, hostsw_own_offset);
+
+ /*
+ *The 4th bit in pad_config 1 (RO) is used to indicate if the pad
+ * needs GPIO driver ownership. Set the bit if GPIO driver ownership
+ * requested, otherwise clear the bit.
+ */
+ if (cfg->pad_config[1] & PAD_CFG1_GPIO_DRIVER)
+ hostsw_own |= pinctrl_bitmask_within_group(comm, pin);
+ else
+ hostsw_own &= ~pinctrl_bitmask_within_group(comm, pin);
+
+ pcr_write32(dev, hostsw_own_offset, hostsw_own);
+
+ return 0;
+}
+
+static int gpi_enable_smi(struct udevice *dev, const struct pad_config *cfg,
+ const struct pad_community *comm)
+{
+ u32 value;
+ u16 sts_reg;
+ u16 en_reg;
+ int group;
+ int pin;
+ int ret;
+
+ if ((cfg->pad_config[0] & PAD_CFG0_ROUTE_SMI) != PAD_CFG0_ROUTE_SMI)
+ return 0;
+
+ pin = relative_pad_in_comm(comm, cfg->pad);
+ ret = pinctrl_group_index(comm, pin);
+ if (ret < 0)
+ return ret;
+ group = ret;
+
+ sts_reg = GPI_SMI_STS_OFFSET(comm, group);
+ value = pcr_read32(dev, sts_reg);
+ /* Write back 1 to reset the sts bits */
+ pcr_write32(dev, sts_reg, value);
+
+ /* Set enable bits */
+ en_reg = GPI_SMI_EN_OFFSET(comm, group);
+ pcr_setbits32(dev, en_reg, pinctrl_bitmask_within_group(comm, pin));
+
+ return 0;
+}
+
+static int pinctrl_configure_itss(struct udevice *dev,
+ const struct pad_config *cfg,
+ uint pad_cfg_offset)
+{
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+
+ if (!priv->itss_pol_cfg)
+ return -ENOSYS;
+
+ int irq;
+
+ /*
+ * Set up ITSS polarity if pad is routed to APIC.
+ *
+ * The ITSS takes only active high interrupt signals. Therefore,
+ * if the pad configuration indicates an inversion assume the
+ * intent is for the ITSS polarity. Before forwarding on the
+ * request to the APIC there's an inversion setting for how the
+ * signal is forwarded to the APIC. Honor the inversion setting
+ * in the GPIO pad configuration so that a hardware active low
+ * signal looks that way to the APIC (double inversion).
+ */
+ if (!(cfg->pad_config[0] & PAD_CFG0_ROUTE_IOAPIC))
+ return 0;
+
+ irq = pcr_read32(dev, PAD_CFG1_OFFSET(pad_cfg_offset));
+ irq &= PAD_CFG1_IRQ_MASK;
+ if (!irq) {
+ log_err("GPIO %u doesn't support APIC routing\n", cfg->pad);
+
+ return -EPROTONOSUPPORT;
+ }
+ irq_set_polarity(priv->itss, irq,
+ cfg->pad_config[0] & PAD_CFG0_RX_POL_INVERT);
+
+ return 0;
+}
+
+/* Number of DWx config registers can be different for different SOCs */
+static uint pad_config_offset(struct intel_pinctrl_priv *priv, uint pad)
+{
+ const struct pad_community *comm = priv->comm;
+ size_t offset;
+
+ offset = relative_pad_in_comm(comm, pad);
+ offset *= GPIO_DW_SIZE(priv->num_cfgs);
+
+ return offset + comm->pad_cfg_base;
+}
+
+static int pinctrl_pad_reset_config_override(const struct pad_community *comm,
+ u32 config_value)
+{
+ const struct reset_mapping *rst_map = comm->reset_map;
+ int i;
+
+ /* Logical reset values equal chipset values */
+ if (!rst_map || !comm->num_reset_vals)
+ return config_value;
+
+ for (i = 0; i < comm->num_reset_vals; i++, rst_map++) {
+ if ((config_value & PAD_CFG0_RESET_MASK) == rst_map->logical) {
+ config_value &= ~PAD_CFG0_RESET_MASK;
+ config_value |= rst_map->chipset;
+
+ return config_value;
+ }
+ }
+ log_err("Logical-to-Chipset mapping not found\n");
+
+ return -ENOENT;
+}
+
+static const int mask[4] = {
+ PAD_CFG0_TX_STATE |
+ PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE | PAD_CFG0_MODE_MASK |
+ PAD_CFG0_ROUTE_MASK | PAD_CFG0_RXTENCFG_MASK |
+ PAD_CFG0_RXINV_MASK | PAD_CFG0_PREGFRXSEL |
+ PAD_CFG0_TRIG_MASK | PAD_CFG0_RXRAW1_MASK |
+ PAD_CFG0_RXPADSTSEL_MASK | PAD_CFG0_RESET_MASK,
+
+#ifdef CONFIG_INTEL_PINCTRL_IOSTANDBY
+ PAD_CFG1_IOSTERM_MASK | PAD_CFG1_PULL_MASK | PAD_CFG1_IOSSTATE_MASK,
+#else
+ PAD_CFG1_IOSTERM_MASK | PAD_CFG1_PULL_MASK,
+#endif
+
+ PAD_CFG2_DEBOUNCE_MASK,
+
+ 0,
+};
+
+/**
+ * pinctrl_configure_pad() - Configure a pad
+ *
+ * @dev: Pinctrl device containing the pad (see pinctrl_get_device())
+ * @cfg: Configuration to apply
+ * @return 0 if OK, -ve on error
+ */
+static int pinctrl_configure_pad(struct udevice *dev,
+ const struct pad_config *cfg)
+{
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct pad_community *comm = priv->comm;
+ uint config_offset;
+ u32 pad_conf, soc_pad_conf;
+ int ret;
+ int i;
+
+ if (IS_ERR(comm))
+ return PTR_ERR(comm);
+ config_offset = pad_config_offset(priv, cfg->pad);
+ for (i = 0; i < priv->num_cfgs; i++) {
+ pad_conf = pcr_read32(dev, PAD_CFG_OFFSET(config_offset, i));
+
+ soc_pad_conf = cfg->pad_config[i];
+ if (i == 0) {
+ ret = pinctrl_pad_reset_config_override(comm,
+ soc_pad_conf);
+ if (ret < 0)
+ return ret;
+ soc_pad_conf = ret;
+ }
+ soc_pad_conf &= mask[i];
+ soc_pad_conf |= pad_conf & ~mask[i];
+
+ log_debug("pinctrl_padcfg [0x%02x, %02zd] DW%d [0x%08x : 0x%08x : 0x%08x]\n",
+ comm->port, relative_pad_in_comm(comm, cfg->pad), i,
+ pad_conf,/* old value */
+ /* value passed from pinctrl table */
+ cfg->pad_config[i],
+ soc_pad_conf); /*new value*/
+ pcr_write32(dev, PAD_CFG_OFFSET(config_offset, i),
+ soc_pad_conf);
+ }
+ ret = pinctrl_configure_itss(dev, cfg, config_offset);
+ if (ret && ret != -ENOSYS)
+ return log_msg_ret("itss config failed", ret);
+ ret = pinctrl_configure_owner(dev, cfg, comm);
+ if (ret)
+ return ret;
+ ret = gpi_enable_smi(dev, cfg, comm);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+u32 intel_pinctrl_get_config_reg_addr(struct udevice *dev, uint offset)
+{
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct pad_community *comm = priv->comm;
+ uint config_offset;
+
+ assert(device_get_uclass_id(dev) == UCLASS_PINCTRL);
+ config_offset = comm->pad_cfg_base + offset *
+ GPIO_DW_SIZE(priv->num_cfgs);
+
+ return config_offset;
+}
+
+u32 intel_pinctrl_get_config_reg(struct udevice *dev, uint offset)
+{
+ uint config_offset = intel_pinctrl_get_config_reg_addr(dev, offset);
+
+ return pcr_read32(dev, config_offset);
+}
+
+int intel_pinctrl_get_acpi_pin(struct udevice *dev, uint offset)
+{
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct pad_community *comm = priv->comm;
+ int group;
+
+ group = pinctrl_group_index(comm, offset);
+
+ /* If pad base is not set then use GPIO number as ACPI pin number */
+ if (comm->groups[group].acpi_pad_base == PAD_BASE_NONE)
+ return comm->first_pad + offset;
+
+ /*
+ * If this group has a non-zero pad base then compute the ACPI pin
+ * number from the pad base and the relative pad in the group.
+ */
+ return comm->groups[group].acpi_pad_base +
+ pinctrl_within_group(comm, offset);
+}
+
+int pinctrl_route_gpe(struct udevice *itss, uint gpe0b, uint gpe0c, uint gpe0d)
+{
+ struct udevice *pinctrl_dev;
+ u32 misccfg_value;
+ u32 misccfg_clr;
+ int ret;
+
+ /*
+ * Get the group here for community specific MISCCFG register.
+ * If any of these returns -1 then there is some error in devicetree
+ * where the group is probably hardcoded and does not comply with the
+ * PMC group defines. So we return from here and MISCFG is set to
+ * default.
+ */
+ ret = irq_route_pmc_gpio_gpe(itss, gpe0b);
+ if (ret)
+ return ret;
+ gpe0b = ret;
+
+ ret = irq_route_pmc_gpio_gpe(itss, gpe0c);
+ if (ret)
+ return ret;
+ gpe0c = ret;
+
+ ret = irq_route_pmc_gpio_gpe(itss, gpe0d);
+ if (ret)
+ return ret;
+ gpe0d = ret;
+
+ misccfg_value = gpe0b << MISCCFG_GPE0_DW0_SHIFT;
+ misccfg_value |= gpe0c << MISCCFG_GPE0_DW1_SHIFT;
+ misccfg_value |= gpe0d << MISCCFG_GPE0_DW2_SHIFT;
+
+ /* Program GPIO_MISCCFG */
+ misccfg_clr = MISCCFG_GPE0_DW2_MASK | MISCCFG_GPE0_DW1_MASK |
+ MISCCFG_GPE0_DW0_MASK;
+
+ log_debug("misccfg_clr:%x misccfg_value:%x\n", misccfg_clr,
+ misccfg_value);
+ uclass_foreach_dev_probe(UCLASS_PINCTRL, pinctrl_dev) {
+ pcr_clrsetbits32(pinctrl_dev, GPIO_MISCCFG, misccfg_clr,
+ misccfg_value);
+ }
+
+ return 0;
+}
+
+int pinctrl_gpi_clear_int_cfg(void)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_PINCTRL, &uc);
+ if (ret)
+ return log_msg_ret("pinctrl uc", ret);
+ uclass_foreach_dev(dev, uc) {
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ const struct pad_community *comm = priv->comm;
+ uint sts_value;
+ int group;
+
+ for (group = 0; group < comm->num_gpi_regs; group++) {
+ /* Clear the enable register */
+ pcr_write32(dev, GPI_IE_OFFSET(comm, group), 0);
+
+ /* Read and clear the set status register bits*/
+ sts_value = pcr_read32(dev,
+ GPI_IS_OFFSET(comm, group));
+ pcr_write32(dev, GPI_IS_OFFSET(comm, group), sts_value);
+ }
+ }
+
+ return 0;
+}
+
+int pinctrl_config_pads(struct udevice *dev, u32 *pads, int pads_count)
+{
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ const u32 *ptr;
+ int i;
+
+ log_debug("%s: pads_count=%d\n", __func__, pads_count);
+ for (ptr = pads, i = 0; i < pads_count;
+ ptr += 1 + priv->num_cfgs, i++) {
+ struct udevice *pad_dev = NULL;
+ struct pad_config *cfg;
+ int ret;
+
+ cfg = (struct pad_config *)ptr;
+ ret = pinctrl_get_device(cfg->pad, &pad_dev);
+ if (ret)
+ return ret;
+ ret = pinctrl_configure_pad(pad_dev, cfg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int pinctrl_read_pads(struct udevice *dev, ofnode node, const char *prop,
+ u32 **padsp, int *pad_countp)
+{
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ u32 *pads;
+ int size;
+ int ret;
+
+ *padsp = NULL;
+ *pad_countp = 0;
+ size = ofnode_read_size(node, prop);
+ if (size < 0)
+ return 0;
+
+ pads = malloc(size);
+ if (!pads)
+ return -ENOMEM;
+ size /= sizeof(fdt32_t);
+ ret = ofnode_read_u32_array(node, prop, pads, size);
+ if (ret) {
+ free(pads);
+ return ret;
+ }
+ *pad_countp = size / (1 + priv->num_cfgs);
+ *padsp = pads;
+
+ return 0;
+}
+
+int pinctrl_count_pads(struct udevice *dev, u32 *pads, int size)
+{
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ int count = 0;
+ int i;
+
+ for (i = 0; i < size;) {
+ u32 val;
+ int j;
+
+ for (val = j = 0; j < priv->num_cfgs + 1; j++)
+ val |= pads[i + j];
+ if (!val)
+ break;
+ count++;
+ i += priv->num_cfgs + 1;
+ }
+
+ return count;
+}
+
+int pinctrl_config_pads_for_node(struct udevice *dev, ofnode node)
+{
+ int pads_count;
+ u32 *pads;
+ int ret;
+
+ if (device_get_uclass_id(dev) != UCLASS_PINCTRL)
+ return log_msg_ret("uclass", -EPROTONOSUPPORT);
+ ret = pinctrl_read_pads(dev, node, "pads", &pads, &pads_count);
+ if (ret)
+ return log_msg_ret("no pads", ret);
+ ret = pinctrl_config_pads(dev, pads, pads_count);
+ free(pads);
+ if (ret)
+ return log_msg_ret("pad config", ret);
+
+ return 0;
+}
+
+int intel_pinctrl_ofdata_to_platdata(struct udevice *dev,
+ const struct pad_community *comm,
+ int num_cfgs)
+{
+ struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (!comm) {
+ log_err("Cannot find community for pid %d\n", pplat->pid);
+ return -EDOM;
+ }
+ ret = uclass_first_device_err(UCLASS_IRQ, &priv->itss);
+ if (ret)
+ return log_msg_ret("Cannot find ITSS", ret);
+ priv->comm = comm;
+ priv->num_cfgs = num_cfgs;
+
+ return 0;
+}
+
+int intel_pinctrl_probe(struct udevice *dev)
+{
+ struct intel_pinctrl_priv *priv = dev_get_priv(dev);
+
+ priv->itss_pol_cfg = true;
+
+ return 0;
+}
+
+const struct pinctrl_ops intel_pinctrl_ops = {
+ /* No operations are supported, but DM expects this to be present */
+};
diff --git a/drivers/pinctrl/intel/pinctrl_apl.c b/drivers/pinctrl/intel/pinctrl_apl.c
new file mode 100644
index 0000000000..bd80435ffa
--- /dev/null
+++ b/drivers/pinctrl/intel/pinctrl_apl.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Intel Corp.
+ * Copyright 2019 Google LLC
+ *
+ * Taken partly from coreboot gpio.c
+ */
+
+#define LOG_CATEGORY UCLASS_GPIO
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <p2sb.h>
+#include <asm/intel_pinctrl.h>
+#include <asm-generic/gpio.h>
+#include <asm/intel_pinctrl_defs.h>
+
+/**
+ * struct apl_gpio_platdata - platform data for each device
+ *
+ * @dtplat: of-platdata data from C struct
+ */
+struct apl_gpio_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ /* Put this first since driver model will copy the data here */
+ struct dtd_intel_apl_pinctrl dtplat;
+#endif
+};
+
+static const struct reset_mapping rst_map[] = {
+ { .logical = PAD_CFG0_LOGICAL_RESET_PWROK, .chipset = 0U << 30 },
+ { .logical = PAD_CFG0_LOGICAL_RESET_DEEP, .chipset = 1U << 30 },
+ { .logical = PAD_CFG0_LOGICAL_RESET_PLTRST, .chipset = 2U << 30 },
+};
+
+/* Groups for each community */
+static const struct pad_group apl_community_n_groups[] = {
+ INTEL_GPP(N_OFFSET, N_OFFSET, GPIO_31), /* NORTH 0 */
+ INTEL_GPP(N_OFFSET, GPIO_32, JTAG_TRST_B), /* NORTH 1 */
+ INTEL_GPP(N_OFFSET, JTAG_TMS, SVID0_CLK), /* NORTH 2 */
+};
+
+static const struct pad_group apl_community_w_groups[] = {
+ INTEL_GPP(W_OFFSET, W_OFFSET, OSC_CLK_OUT_1), /* WEST 0 */
+ INTEL_GPP(W_OFFSET, OSC_CLK_OUT_2, SUSPWRDNACK),/* WEST 1 */
+};
+
+static const struct pad_group apl_community_sw_groups[] = {
+ INTEL_GPP(SW_OFFSET, SW_OFFSET, SMB_ALERTB), /* SOUTHWEST 0 */
+ INTEL_GPP(SW_OFFSET, SMB_CLK, LPC_FRAMEB), /* SOUTHWEST 1 */
+};
+
+static const struct pad_group apl_community_nw_groups[] = {
+ INTEL_GPP(NW_OFFSET, NW_OFFSET, PROCHOT_B), /* NORTHWEST 0 */
+ INTEL_GPP(NW_OFFSET, PMIC_I2C_SCL, GPIO_106), /* NORTHWEST 1 */
+ INTEL_GPP(NW_OFFSET, GPIO_109, GPIO_123), /* NORTHWEST 2 */
+};
+
+/* TODO(sjg@chromium.org): Consider moving this to device tree */
+static const struct pad_community apl_gpio_communities[] = {
+ {
+ .port = PID_GPIO_N,
+ .first_pad = N_OFFSET,
+ .last_pad = SVID0_CLK,
+ .num_gpi_regs = NUM_N_GPI_REGS,
+ .gpi_status_offset = NUM_NW_GPI_REGS + NUM_W_GPI_REGS
+ + NUM_SW_GPI_REGS,
+ .pad_cfg_base = PAD_CFG_BASE,
+ .host_own_reg_0 = HOSTSW_OWN_REG_0,
+ .gpi_int_sts_reg_0 = GPI_INT_STS_0,
+ .gpi_int_en_reg_0 = GPI_INT_EN_0,
+ .gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+ .gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+ .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+ .name = "GPIO_GPE_N",
+ .acpi_path = "\\_SB.GPO0",
+ .reset_map = rst_map,
+ .num_reset_vals = ARRAY_SIZE(rst_map),
+ .groups = apl_community_n_groups,
+ .num_groups = ARRAY_SIZE(apl_community_n_groups),
+ }, {
+ .port = PID_GPIO_NW,
+ .first_pad = NW_OFFSET,
+ .last_pad = GPIO_123,
+ .num_gpi_regs = NUM_NW_GPI_REGS,
+ .gpi_status_offset = NUM_W_GPI_REGS + NUM_SW_GPI_REGS,
+ .pad_cfg_base = PAD_CFG_BASE,
+ .host_own_reg_0 = HOSTSW_OWN_REG_0,
+ .gpi_int_sts_reg_0 = GPI_INT_STS_0,
+ .gpi_int_en_reg_0 = GPI_INT_EN_0,
+ .gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+ .gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+ .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+ .name = "GPIO_GPE_NW",
+ .acpi_path = "\\_SB.GPO1",
+ .reset_map = rst_map,
+ .num_reset_vals = ARRAY_SIZE(rst_map),
+ .groups = apl_community_nw_groups,
+ .num_groups = ARRAY_SIZE(apl_community_nw_groups),
+ }, {
+ .port = PID_GPIO_W,
+ .first_pad = W_OFFSET,
+ .last_pad = SUSPWRDNACK,
+ .num_gpi_regs = NUM_W_GPI_REGS,
+ .gpi_status_offset = NUM_SW_GPI_REGS,
+ .pad_cfg_base = PAD_CFG_BASE,
+ .host_own_reg_0 = HOSTSW_OWN_REG_0,
+ .gpi_int_sts_reg_0 = GPI_INT_STS_0,
+ .gpi_int_en_reg_0 = GPI_INT_EN_0,
+ .gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+ .gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+ .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+ .name = "GPIO_GPE_W",
+ .acpi_path = "\\_SB.GPO2",
+ .reset_map = rst_map,
+ .num_reset_vals = ARRAY_SIZE(rst_map),
+ .groups = apl_community_w_groups,
+ .num_groups = ARRAY_SIZE(apl_community_w_groups),
+ }, {
+ .port = PID_GPIO_SW,
+ .first_pad = SW_OFFSET,
+ .last_pad = LPC_FRAMEB,
+ .num_gpi_regs = NUM_SW_GPI_REGS,
+ .gpi_status_offset = 0,
+ .pad_cfg_base = PAD_CFG_BASE,
+ .host_own_reg_0 = HOSTSW_OWN_REG_0,
+ .gpi_int_sts_reg_0 = GPI_INT_STS_0,
+ .gpi_int_en_reg_0 = GPI_INT_EN_0,
+ .gpi_smi_sts_reg_0 = GPI_SMI_STS_0,
+ .gpi_smi_en_reg_0 = GPI_SMI_EN_0,
+ .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP,
+ .name = "GPIO_GPE_SW",
+ .acpi_path = "\\_SB.GPO3",
+ .reset_map = rst_map,
+ .num_reset_vals = ARRAY_SIZE(rst_map),
+ .groups = apl_community_sw_groups,
+ .num_groups = ARRAY_SIZE(apl_community_sw_groups),
+ },
+};
+
+static int apl_pinctrl_ofdata_to_platdata(struct udevice *dev)
+{
+ struct p2sb_child_platdata *pplat;
+ const struct pad_community *comm = NULL;
+ int i;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct apl_gpio_platdata *plat = dev_get_platdata(dev);
+ int ret;
+
+ /*
+ * 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, plat->dtplat.intel_p2sb_port_id);
+ if (ret)
+ return log_msg_ret("Could not set port id", ret);
+#endif
+ /* Attach this device to its community structure */
+ pplat = dev_get_parent_platdata(dev);
+ for (i = 0; i < ARRAY_SIZE(apl_gpio_communities); i++) {
+ if (apl_gpio_communities[i].port == pplat->pid)
+ comm = &apl_gpio_communities[i];
+ }
+
+ return intel_pinctrl_ofdata_to_platdata(dev, comm, 2);
+}
+
+static const struct udevice_id apl_gpio_ids[] = {
+ { .compatible = "intel,apl-pinctrl"},
+ { }
+};
+
+U_BOOT_DRIVER(apl_pinctrl_drv) = {
+ .name = "intel_apl_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = apl_gpio_ids,
+ .probe = intel_pinctrl_probe,
+ .ops = &intel_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .bind = dm_scan_fdt_dev,
+#endif
+ .ofdata_to_platdata = apl_pinctrl_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct intel_pinctrl_priv),
+ .platdata_auto_alloc_size = sizeof(struct apl_gpio_platdata),
+};
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 9495dca33b..cb2c6fe3eb 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -1,5 +1,7 @@
menu "Power"
+source "drivers/power/acpi_pmc/Kconfig"
+
source "drivers/power/domain/Kconfig"
source "drivers/power/pmic/Kconfig"
diff --git a/drivers/power/acpi_pmc/Kconfig b/drivers/power/acpi_pmc/Kconfig
new file mode 100644
index 0000000000..fcd50e36ca
--- /dev/null
+++ b/drivers/power/acpi_pmc/Kconfig
@@ -0,0 +1,34 @@
+config ACPI_PMC
+ bool "Power Manager (x86 PMC) support"
+ help
+ Enable support for an x86-style power-management controller which
+ provides features including checking whether the system started from
+ resume, powering off the system and enabling/disabling the reset
+ mechanism.
+
+config SPL_ACPI_PMC
+ bool "Power Manager (x86 PMC) support in SPL"
+ default y if ACPI_PMC
+ help
+ Enable support for an x86-style power-management controller which
+ provides features including checking whether the system started from
+ resume, powering off the system and enabling/disabling the reset
+ mechanism.
+
+config TPL_ACPI_PMC
+ bool "Power Manager (x86 PMC) support in TPL"
+ default y if ACPI_PMC
+ help
+ Enable support for an x86-style power-management controller which
+ provides features including checking whether the system started from
+ resume, powering off the system and enabling/disabling the reset
+ mechanism.
+
+config ACPI_PMC_SANDBOX
+ bool "Test power manager (PMC) for sandbox"
+ depends on ACPI_PMC && SANDBOX
+ help
+ This driver emulates a PMC (Power-Management Controller) so that
+ the uclass logic can be tested. You can use the 'pmc' command to
+ access information from the driver. It uses I/O access to read
+ from the PMC.
diff --git a/drivers/power/acpi_pmc/Makefile b/drivers/power/acpi_pmc/Makefile
new file mode 100644
index 0000000000..115788f109
--- /dev/null
+++ b/drivers/power/acpi_pmc/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += acpi-pmc-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC_SANDBOX) += sandbox.o pmc_emul.o
diff --git a/drivers/power/acpi_pmc/acpi-pmc-uclass.c b/drivers/power/acpi_pmc/acpi-pmc-uclass.c
new file mode 100644
index 0000000000..d43de87126
--- /dev/null
+++ b/drivers/power/acpi_pmc/acpi-pmc-uclass.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_ACPI_PMC
+
+#include <common.h>
+#include <acpi_s3.h>
+#include <dm.h>
+#include <log.h>
+#ifdef CONFIG_X86
+#include <asm/intel_pinctrl.h>
+#endif
+#include <asm/io.h>
+#include <power/acpi_pmc.h>
+
+enum {
+ PM1_STS = 0x00,
+ PM1_EN = 0x02,
+ PM1_CNT = 0x04,
+
+ GPE0_STS = 0x20,
+ GPE0_EN = 0x30,
+};
+
+struct tco_regs {
+ u32 tco_rld;
+ u32 tco_sts;
+ u32 tco1_cnt;
+ u32 tco_tmr;
+};
+
+enum {
+ TCO_STS_TIMEOUT = 1 << 3,
+ TCO_STS_SECOND_TO_STS = 1 << 17,
+ TCO1_CNT_HLT = 1 << 11,
+};
+
+#ifdef CONFIG_X86
+static int gpe0_shift(struct acpi_pmc_upriv *upriv, int regnum)
+{
+ return upriv->gpe0_dwx_shift_base + regnum * 4;
+}
+
+int pmc_gpe_init(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ struct udevice *itss;
+ u32 *dw;
+ u32 gpio_cfg_mask;
+ u32 gpio_cfg;
+ int ret, i;
+ u32 mask;
+
+ if (device_get_uclass_id(dev) != UCLASS_ACPI_PMC)
+ return log_msg_ret("uclass", -EPROTONOSUPPORT);
+ dw = upriv->gpe0_dw;
+ mask = upriv->gpe0_dwx_mask;
+ gpio_cfg_mask = 0;
+ for (i = 0; i < upriv->gpe0_count; i++) {
+ gpio_cfg_mask |= mask << gpe0_shift(upriv, i);
+ if (dw[i] & ~mask)
+ return log_msg_ret("Base GPE0 value", -EINVAL);
+ }
+
+ /*
+ * Route the GPIOs to the GPE0 block. Determine that all values
+ * are different and if they aren't, use the reset values.
+ */
+ if (dw[0] == dw[1] || dw[1] == dw[2]) {
+ log_info("PMC: Using default GPE route");
+ gpio_cfg = readl(upriv->gpe_cfg);
+ for (i = 0; i < upriv->gpe0_count; i++)
+ dw[i] = gpio_cfg >> gpe0_shift(upriv, i);
+ } else {
+ gpio_cfg = 0;
+ for (i = 0; i < upriv->gpe0_count; i++)
+ gpio_cfg |= dw[i] << gpe0_shift(upriv, i);
+ clrsetbits_le32(upriv->gpe_cfg, gpio_cfg_mask, gpio_cfg);
+ }
+
+ /* Set the routes in the GPIO communities as well */
+ ret = uclass_first_device_err(UCLASS_IRQ, &itss);
+ if (ret)
+ return log_msg_ret("Cannot find itss", ret);
+ pinctrl_route_gpe(itss, dw[0], dw[1], dw[2]);
+
+ return 0;
+}
+#endif /* CONFIG_X86 */
+
+static void pmc_fill_pm_reg_info(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ int i;
+
+ upriv->pm1_sts = inw(upriv->acpi_base + PM1_STS);
+ upriv->pm1_en = inw(upriv->acpi_base + PM1_EN);
+ upriv->pm1_cnt = inw(upriv->acpi_base + PM1_CNT);
+
+ log_debug("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
+ upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
+
+ for (i = 0; i < GPE0_REG_MAX; i++) {
+ upriv->gpe0_sts[i] = inl(upriv->acpi_base + GPE0_STS + i * 4);
+ upriv->gpe0_en[i] = inl(upriv->acpi_base + GPE0_EN + i * 4);
+ log_debug("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
+ upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
+ }
+}
+
+int pmc_disable_tco_base(ulong tco_base)
+{
+ struct tco_regs *regs = (struct tco_regs *)tco_base;
+
+ debug("tco_base %lx = %x\n", (ulong)&regs->tco1_cnt, TCO1_CNT_HLT);
+ setio_32(&regs->tco1_cnt, TCO1_CNT_HLT);
+
+ return 0;
+}
+
+int pmc_init(struct udevice *dev)
+{
+ const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+ int ret;
+
+ pmc_fill_pm_reg_info(dev);
+ if (!ops->init)
+ return -ENOSYS;
+
+ ret = ops->init(dev);
+ if (ret)
+ return log_msg_ret("Failed to init pmc", ret);
+
+#ifdef DEBUG
+ pmc_dump_info(dev);
+#endif
+
+ return 0;
+}
+
+int pmc_prev_sleep_state(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+ int prev_sleep_state = ACPI_S0; /* Default to S0 */
+
+ if (upriv->pm1_sts & WAK_STS) {
+ switch (acpi_sleep_from_pm1(upriv->pm1_cnt)) {
+ case ACPI_S3:
+ if (IS_ENABLED(HAVE_ACPI_RESUME))
+ prev_sleep_state = ACPI_S3;
+ break;
+ case ACPI_S5:
+ prev_sleep_state = ACPI_S5;
+ break;
+ default:
+ break;
+ }
+
+ /* Clear SLP_TYP */
+ outl(upriv->pm1_cnt & ~SLP_TYP, upriv->acpi_base + PM1_CNT);
+ }
+
+ if (!ops->prev_sleep_state)
+ return prev_sleep_state;
+
+ return ops->prev_sleep_state(dev, prev_sleep_state);
+}
+
+int pmc_disable_tco(struct udevice *dev)
+{
+ const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+
+ pmc_fill_pm_reg_info(dev);
+ if (!ops->disable_tco)
+ return -ENOSYS;
+
+ return ops->disable_tco(dev);
+}
+
+int pmc_global_reset_set_enable(struct udevice *dev, bool enable)
+{
+ const struct acpi_pmc_ops *ops = acpi_pmc_get_ops(dev);
+
+ if (!ops->global_reset_set_enable)
+ return -ENOSYS;
+
+ return ops->global_reset_set_enable(dev, enable);
+}
+
+void pmc_dump_info(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ int i;
+
+ printf("Device: %s\n", dev->name);
+ printf("ACPI base %x, pmc_bar0 %p, pmc_bar2 %p, gpe_cfg %p\n",
+ upriv->acpi_base, upriv->pmc_bar0, upriv->pmc_bar2,
+ upriv->gpe_cfg);
+ printf("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
+ upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
+
+ for (i = 0; i < GPE0_REG_MAX; i++) {
+ printf("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
+ upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
+ }
+
+ printf("prsts: %08x\n", upriv->prsts);
+ printf("tco_sts: %04x %04x\n", upriv->tco1_sts, upriv->tco2_sts);
+ printf("gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n",
+ upriv->gen_pmcon1, upriv->gen_pmcon2, upriv->gen_pmcon3);
+}
+
+int pmc_ofdata_to_uc_platdata(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ int ret;
+
+ ret = dev_read_u32(dev, "gpe0-dwx-mask", &upriv->gpe0_dwx_mask);
+ if (ret)
+ return log_msg_ret("no gpe0-dwx-mask", ret);
+ ret = dev_read_u32(dev, "gpe0-dwx-shift-base",
+ &upriv->gpe0_dwx_shift_base);
+ if (ret)
+ return log_msg_ret("no gpe0-dwx-shift-base", ret);
+ ret = dev_read_u32(dev, "gpe0-sts", &upriv->gpe0_sts_reg);
+ if (ret)
+ return log_msg_ret("no gpe0-sts", ret);
+ upriv->gpe0_sts_reg += upriv->acpi_base;
+ ret = dev_read_u32(dev, "gpe0-en", &upriv->gpe0_en_reg);
+ if (ret)
+ return log_msg_ret("no gpe0-en", ret);
+ upriv->gpe0_en_reg += upriv->acpi_base;
+
+ return 0;
+}
+
+UCLASS_DRIVER(acpi_pmc) = {
+ .id = UCLASS_ACPI_PMC,
+ .name = "power-mgr",
+ .per_device_auto_alloc_size = sizeof(struct acpi_pmc_upriv),
+};
diff --git a/drivers/power/acpi_pmc/pmc_emul.c b/drivers/power/acpi_pmc/pmc_emul.c
new file mode 100644
index 0000000000..15cc7acaf3
--- /dev/null
+++ b/drivers/power/acpi_pmc/pmc_emul.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI emulation device for an x86 Power-Management Controller (PMC)
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pci.h>
+#include <asm/test.h>
+#include <power/acpi_pmc.h>
+
+/**
+ * struct pmc_emul_platdata - platform data for this device
+ *
+ * @command: Current PCI command value
+ * @bar: Current base address values
+ */
+struct pmc_emul_platdata {
+ u16 command;
+ u32 bar[6];
+};
+
+enum {
+ MEMMAP_SIZE = 0x80,
+};
+
+static struct pci_bar {
+ int type;
+ u32 size;
+} barinfo[] = {
+ { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { PCI_BASE_ADDRESS_SPACE_IO, 256 },
+};
+
+struct pmc_emul_priv {
+ u8 regs[MEMMAP_SIZE];
+};
+
+static int sandbox_pmc_emul_read_config(struct udevice *emul, uint offset,
+ ulong *valuep, enum pci_size_t size)
+{
+ struct pmc_emul_platdata *plat = dev_get_platdata(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ *valuep = plat->command;
+ break;
+ case PCI_HEADER_TYPE:
+ *valuep = 0;
+ break;
+ case PCI_VENDOR_ID:
+ *valuep = SANDBOX_PCI_VENDOR_ID;
+ break;
+ case PCI_DEVICE_ID:
+ *valuep = SANDBOX_PCI_PMC_EMUL_ID;
+ break;
+ case PCI_CLASS_DEVICE:
+ if (size == PCI_SIZE_8) {
+ *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
+ } else {
+ *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
+ SANDBOX_PCI_CLASS_SUB_CODE;
+ }
+ break;
+ case PCI_CLASS_CODE:
+ *valuep = SANDBOX_PCI_CLASS_CODE;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1:
+ case PCI_BASE_ADDRESS_2:
+ case PCI_BASE_ADDRESS_3:
+ case PCI_BASE_ADDRESS_4:
+ case PCI_BASE_ADDRESS_5: {
+ int barnum;
+ u32 *bar;
+
+ barnum = pci_offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
+ barinfo[barnum].size);
+ break;
+ }
+ case PCI_CAPABILITY_LIST:
+ *valuep = PCI_CAP_ID_PM_OFFSET;
+ break;
+ }
+
+ return 0;
+}
+
+static int sandbox_pmc_emul_write_config(struct udevice *emul, uint offset,
+ ulong value, enum pci_size_t size)
+{
+ struct pmc_emul_platdata *plat = dev_get_platdata(emul);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ plat->command = value;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1: {
+ int barnum;
+ u32 *bar;
+
+ barnum = pci_offset_to_barnum(offset);
+ bar = &plat->bar[barnum];
+
+ debug("w bar %d=%lx\n", barnum, value);
+ *bar = value;
+ /* space indicator (bit#0) is read-only */
+ *bar |= barinfo[barnum].type;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int sandbox_pmc_emul_find_bar(struct udevice *emul, unsigned int addr,
+ int *barnump, unsigned int *offsetp)
+{
+ struct pmc_emul_platdata *plat = dev_get_platdata(emul);
+ int barnum;
+
+ for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
+ unsigned int size = barinfo[barnum].size;
+ u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
+
+ if (addr >= base && addr < base + size) {
+ *barnump = barnum;
+ *offsetp = addr - base;
+ return 0;
+ }
+ }
+ *barnump = -1;
+
+ return -ENOENT;
+}
+
+static int sandbox_pmc_emul_read_io(struct udevice *dev, unsigned int addr,
+ ulong *valuep, enum pci_size_t size)
+{
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ if (barnum == 4)
+ *valuep = offset;
+ else if (barnum == 0)
+ *valuep = offset;
+
+ return 0;
+}
+
+static int sandbox_pmc_emul_write_io(struct udevice *dev, unsigned int addr,
+ ulong value, enum pci_size_t size)
+{
+ unsigned int offset;
+ int barnum;
+ int ret;
+
+ ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sandbox_pmc_emul_map_physmem(struct udevice *dev,
+ phys_addr_t addr, unsigned long *lenp,
+ void **ptrp)
+{
+ struct pmc_emul_priv *priv = dev_get_priv(dev);
+ unsigned int offset, avail;
+ int barnum;
+ int ret;
+
+ ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
+ if (ret)
+ return ret;
+
+ if (barnum == 0) {
+ *ptrp = priv->regs + offset;
+ avail = barinfo[0].size - offset;
+ if (avail > barinfo[0].size)
+ *lenp = 0;
+ else
+ *lenp = min(*lenp, (ulong)avail);
+
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static int sandbox_pmc_probe(struct udevice *dev)
+{
+ struct pmc_emul_priv *priv = dev_get_priv(dev);
+ int i;
+
+ for (i = 0; i < MEMMAP_SIZE; i++)
+ priv->regs[i] = i;
+
+ return 0;
+}
+
+static struct dm_pci_emul_ops sandbox_pmc_emul_emul_ops = {
+ .read_config = sandbox_pmc_emul_read_config,
+ .write_config = sandbox_pmc_emul_write_config,
+ .read_io = sandbox_pmc_emul_read_io,
+ .write_io = sandbox_pmc_emul_write_io,
+ .map_physmem = sandbox_pmc_emul_map_physmem,
+};
+
+static const struct udevice_id sandbox_pmc_emul_ids[] = {
+ { .compatible = "sandbox,pmc-emul" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_pmc_emul_emul) = {
+ .name = "sandbox_pmc_emul_emul",
+ .id = UCLASS_PCI_EMUL,
+ .of_match = sandbox_pmc_emul_ids,
+ .ops = &sandbox_pmc_emul_emul_ops,
+ .probe = sandbox_pmc_probe,
+ .priv_auto_alloc_size = sizeof(struct pmc_emul_priv),
+ .platdata_auto_alloc_size = sizeof(struct pmc_emul_platdata),
+};
+
+static struct pci_device_id sandbox_pmc_emul_supported[] = {
+ { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
+ {},
+};
+
+U_BOOT_PCI_DEVICE(sandbox_pmc_emul_emul, sandbox_pmc_emul_supported);
diff --git a/drivers/power/acpi_pmc/sandbox.c b/drivers/power/acpi_pmc/sandbox.c
new file mode 100644
index 0000000000..7fbbf97b45
--- /dev/null
+++ b/drivers/power/acpi_pmc/sandbox.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox PMC for testing
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#define LOG_CATEGORY UCLASS_ACPI_PMC
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <power/acpi_pmc.h>
+
+#define GPIO_GPE_CFG 0x1050
+
+/* Memory mapped IO registers behind PMC_BASE_ADDRESS */
+#define PRSTS 0x1000
+#define GEN_PMCON1 0x1020
+#define GEN_PMCON2 0x1024
+#define GEN_PMCON3 0x1028
+
+/* Offset of TCO registers from ACPI base I/O address */
+#define TCO_REG_OFFSET 0x60
+#define TCO1_STS 0x64
+#define TCO2_STS 0x66
+#define TCO1_CNT 0x68
+#define TCO2_CNT 0x6a
+
+struct sandbox_pmc_priv {
+ ulong base;
+};
+
+static int sandbox_pmc_fill_power_state(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+ upriv->tco1_sts = inw(upriv->acpi_base + TCO1_STS);
+ upriv->tco2_sts = inw(upriv->acpi_base + TCO2_STS);
+
+ upriv->prsts = readl(upriv->pmc_bar0 + PRSTS);
+ upriv->gen_pmcon1 = readl(upriv->pmc_bar0 + GEN_PMCON1);
+ upriv->gen_pmcon2 = readl(upriv->pmc_bar0 + GEN_PMCON2);
+ upriv->gen_pmcon3 = readl(upriv->pmc_bar0 + GEN_PMCON3);
+
+ return 0;
+}
+
+static int sandbox_prev_sleep_state(struct udevice *dev, int prev_sleep_state)
+{
+ return prev_sleep_state;
+}
+
+static int sandbox_disable_tco(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+
+ pmc_disable_tco_base(upriv->acpi_base + TCO_REG_OFFSET);
+
+ return 0;
+}
+
+static int sandbox_pmc_probe(struct udevice *dev)
+{
+ struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev);
+ struct udevice *bus;
+ ulong base;
+
+ uclass_first_device(UCLASS_PCI, &bus);
+ base = dm_pci_read_bar32(dev, 0);
+ if (base == FDT_ADDR_T_NONE)
+ return log_msg_ret("No base address", -EINVAL);
+ upriv->pmc_bar0 = map_sysmem(base, 0x2000);
+ upriv->gpe_cfg = (u32 *)(upriv->pmc_bar0 + GPIO_GPE_CFG);
+
+ return pmc_ofdata_to_uc_platdata(dev);
+}
+
+static struct acpi_pmc_ops sandbox_pmc_ops = {
+ .init = sandbox_pmc_fill_power_state,
+ .prev_sleep_state = sandbox_prev_sleep_state,
+ .disable_tco = sandbox_disable_tco,
+};
+
+static const struct udevice_id sandbox_pmc_ids[] = {
+ { .compatible = "sandbox,pmc" },
+ { }
+};
+
+U_BOOT_DRIVER(pmc_sandbox) = {
+ .name = "pmc_sandbox",
+ .id = UCLASS_ACPI_PMC,
+ .of_match = sandbox_pmc_ids,
+ .probe = sandbox_pmc_probe,
+ .ops = &sandbox_pmc_ops,
+ .priv_auto_alloc_size = sizeof(struct sandbox_pmc_priv),
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 8588866489..fae2040af8 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -142,7 +142,6 @@ config FSL_DSPI
config ICH_SPI
bool "Intel ICH SPI driver"
- imply SPI_FLASH_BAR
help
Enable the Intel ICH SPI driver. This driver can be used to
access the SPI NOR flash on platforms embedding this Intel
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index cf4de9ee1a..f076e92a93 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -17,7 +17,7 @@
#ifdef CONFIG_DM_SPI
#include <asm/arch/at91_spi.h>
#endif
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
#include <asm/gpio.h>
#endif
@@ -228,7 +228,7 @@ struct atmel_spi_priv {
unsigned int freq; /* Default frequency */
unsigned int mode;
ulong bus_clk_rate;
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc cs_gpios[MAX_CS_COUNT];
#endif
};
@@ -285,7 +285,7 @@ static int atmel_spi_release_bus(struct udevice *dev)
static void atmel_spi_cs_activate(struct udevice *dev)
{
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct udevice *bus = dev_get_parent(dev);
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
@@ -300,7 +300,7 @@ static void atmel_spi_cs_activate(struct udevice *dev)
static void atmel_spi_cs_deactivate(struct udevice *dev)
{
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct udevice *bus = dev_get_parent(dev);
struct atmel_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
@@ -468,7 +468,7 @@ static int atmel_spi_probe(struct udevice *bus)
bus_plat->regs = (struct at91_spi *)devfdt_get_addr(bus);
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct atmel_spi_priv *priv = dev_get_priv(bus);
int i;
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 91e613e9cd..66ff8eeccd 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -126,7 +126,7 @@ static inline void dw_write(struct dw_spi_priv *priv, u32 offset, u32 val)
static int request_gpio_cs(struct udevice *bus)
{
-#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(DM_GPIO) && !defined(CONFIG_SPL_BUILD)
struct dw_spi_priv *priv = dev_get_priv(bus);
int ret;
@@ -373,7 +373,7 @@ static int poll_transfer(struct dw_spi_priv *priv)
*/
__weak void external_cs_manage(struct udevice *dev, bool on)
{
-#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(DM_GPIO) && !defined(CONFIG_SPL_BUILD)
struct dw_spi_priv *priv = dev_get_priv(dev->parent);
if (!dm_gpio_is_valid(&priv->cs_gpio))
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index fbb58c783e..133b25b72e 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -5,28 +5,45 @@
* This file is derived from the flashrom project.
*/
+#define LOG_CATEGORY UCLASS_SPI
+
#include <common.h>
+#include <div64.h>
#include <dm.h>
+#include <dt-structs.h>
#include <errno.h>
#include <malloc.h>
#include <pch.h>
#include <pci.h>
#include <pci_ids.h>
#include <spi.h>
-#include <asm/io.h>
+#include <spi_flash.h>
#include <spi-mem.h>
-#include <div64.h>
+#include <spl.h>
+#include <asm/fast_spi.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <linux/sizes.h>
#include "ich.h"
-DECLARE_GLOBAL_DATA_PTR;
-
#ifdef DEBUG_TRACE
#define debug_trace(fmt, args...) debug(fmt, ##args)
#else
#define debug_trace(x, args...)
#endif
+struct ich_spi_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dtd_intel_fast_spi dtplat;
+#endif
+ enum ich_version ich_version; /* Controller version, 7 or 9 */
+ bool lockdown; /* lock down controller settings? */
+ ulong mmio_base; /* Base of MMIO registers */
+ pci_dev_t bdf; /* PCI address used by of-platdata */
+ bool hwseq; /* Use hardware sequencing (not s/w) */
+};
+
static u8 ich_readb(struct ich_spi_priv *priv, int reg)
{
u8 value = readb(priv->base + reg);
@@ -89,22 +106,27 @@ static void ich_set_bbar(struct ich_spi_priv *ctlr, uint32_t minaddr)
const uint32_t bbar_mask = 0x00ffff00;
uint32_t ichspi_bbar;
- minaddr &= bbar_mask;
- ichspi_bbar = ich_readl(ctlr, ctlr->bbar) & ~bbar_mask;
- ichspi_bbar |= minaddr;
- ich_writel(ctlr, ichspi_bbar, ctlr->bbar);
+ if (ctlr->bbar) {
+ minaddr &= bbar_mask;
+ ichspi_bbar = ich_readl(ctlr, ctlr->bbar) & ~bbar_mask;
+ ichspi_bbar |= minaddr;
+ ich_writel(ctlr, ichspi_bbar, ctlr->bbar);
+ }
}
/* @return 1 if the SPI flash supports the 33MHz speed */
-static int ich9_can_do_33mhz(struct udevice *dev)
+static bool ich9_can_do_33mhz(struct udevice *dev)
{
+ struct ich_spi_priv *priv = dev_get_priv(dev);
u32 fdod, speed;
+ if (!CONFIG_IS_ENABLED(PCI))
+ return false;
/* Observe SPI Descriptor Component Section 0 */
- dm_pci_write_config32(dev->parent, 0xb0, 0x1000);
+ dm_pci_write_config32(priv->pch, 0xb0, 0x1000);
/* Extract the Write/Erase SPI Frequency from descriptor */
- dm_pci_read_config32(dev->parent, 0xb4, &fdod);
+ dm_pci_read_config32(priv->pch, 0xb4, &fdod);
/* Bits 23:21 have the fast read clock frequency, 0=20MHz, 1=33MHz */
speed = (fdod >> 21) & 7;
@@ -112,67 +134,6 @@ static int ich9_can_do_33mhz(struct udevice *dev)
return speed == 1;
}
-static int ich_init_controller(struct udevice *dev,
- struct ich_spi_platdata *plat,
- struct ich_spi_priv *ctlr)
-{
- ulong sbase_addr;
- void *sbase;
-
- /* SBASE is similar */
- pch_get_spi_base(dev->parent, &sbase_addr);
- sbase = (void *)sbase_addr;
- debug("%s: sbase=%p\n", __func__, sbase);
-
- if (plat->ich_version == ICHV_7) {
- struct ich7_spi_regs *ich7_spi = sbase;
-
- ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu);
- ctlr->menubytes = sizeof(ich7_spi->opmenu);
- ctlr->optype = offsetof(struct ich7_spi_regs, optype);
- ctlr->addr = offsetof(struct ich7_spi_regs, spia);
- ctlr->data = offsetof(struct ich7_spi_regs, spid);
- ctlr->databytes = sizeof(ich7_spi->spid);
- ctlr->status = offsetof(struct ich7_spi_regs, spis);
- ctlr->control = offsetof(struct ich7_spi_regs, spic);
- ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
- ctlr->preop = offsetof(struct ich7_spi_regs, preop);
- ctlr->base = ich7_spi;
- } else if (plat->ich_version == ICHV_9) {
- struct ich9_spi_regs *ich9_spi = sbase;
-
- ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu);
- ctlr->menubytes = sizeof(ich9_spi->opmenu);
- ctlr->optype = offsetof(struct ich9_spi_regs, optype);
- ctlr->addr = offsetof(struct ich9_spi_regs, faddr);
- ctlr->data = offsetof(struct ich9_spi_regs, fdata);
- ctlr->databytes = sizeof(ich9_spi->fdata);
- ctlr->status = offsetof(struct ich9_spi_regs, ssfs);
- ctlr->control = offsetof(struct ich9_spi_regs, ssfc);
- ctlr->speed = ctlr->control + 2;
- ctlr->bbar = offsetof(struct ich9_spi_regs, bbar);
- ctlr->preop = offsetof(struct ich9_spi_regs, preop);
- ctlr->bcr = offsetof(struct ich9_spi_regs, bcr);
- ctlr->pr = &ich9_spi->pr[0];
- ctlr->base = ich9_spi;
- } else {
- debug("ICH SPI: Unrecognised ICH version %d\n",
- plat->ich_version);
- return -EINVAL;
- }
-
- /* Work out the maximum speed we can support */
- ctlr->max_speed = 20000000;
- if (plat->ich_version == ICHV_9 && ich9_can_do_33mhz(dev))
- ctlr->max_speed = 33000000;
- debug("ICH SPI: Version ID %d detected at %p, speed %ld\n",
- plat->ich_version, ctlr->base, ctlr->max_speed);
-
- ich_set_bbar(ctlr, 0);
-
- return 0;
-}
-
static void spi_lock_down(struct ich_spi_platdata *plat, void *sbase)
{
if (plat->ich_version == ICHV_7) {
@@ -233,8 +194,7 @@ static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans,
}
if (opcode_index == ctlr->menubytes) {
- printf("ICH SPI: Opcode %x not found\n",
- trans->opcode);
+ debug("ICH SPI: Opcode %x not found\n", trans->opcode);
return -EINVAL;
}
@@ -242,8 +202,8 @@ static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans,
optype = (optypes >> (opcode_index * 2)) & 0x3;
if (optype != trans->type) {
- printf("ICH SPI: Transaction doesn't fit type %d\n",
- optype);
+ debug("ICH SPI: Transaction doesn't fit type %d\n",
+ optype);
return -ENOSPC;
}
return opcode_index;
@@ -274,9 +234,9 @@ static int ich_status_poll(struct ich_spi_priv *ctlr, u16 bitmask,
}
udelay(10);
}
+ debug("ICH SPI: SCIP timeout, read %x, expected %x, wts %x %x\n",
+ status, bitmask, wait_til_set, status & bitmask);
- printf("ICH SPI: SCIP timeout, read %x, expected %x\n",
- status, bitmask);
return -ETIMEDOUT;
}
@@ -295,7 +255,8 @@ static void ich_spi_config_opcode(struct udevice *dev)
ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32));
}
-static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
+static int ich_spi_exec_op_swseq(struct spi_slave *slave,
+ const struct spi_mem_op *op)
{
struct udevice *bus = dev_get_parent(slave->dev);
struct ich_spi_platdata *plat = dev_get_platdata(bus);
@@ -466,6 +427,228 @@ static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
return 0;
}
+/*
+ * Ensure read/write xfer len is not greater than SPIBAR_FDATA_FIFO_SIZE and
+ * that the operation does not cross page boundary.
+ */
+static uint get_xfer_len(u32 offset, int len, int page_size)
+{
+ uint xfer_len = min(len, SPIBAR_FDATA_FIFO_SIZE);
+ uint bytes_left = ALIGN(offset, page_size) - offset;
+
+ if (bytes_left)
+ xfer_len = min(xfer_len, bytes_left);
+
+ return xfer_len;
+}
+
+/* Fill FDATAn FIFO in preparation for a write transaction */
+static void fill_xfer_fifo(struct fast_spi_regs *regs, const void *data,
+ uint len)
+{
+ memcpy(regs->fdata, data, len);
+}
+
+/* Drain FDATAn FIFO after a read transaction populates data */
+static void drain_xfer_fifo(struct fast_spi_regs *regs, void *dest, uint len)
+{
+ memcpy(dest, regs->fdata, len);
+}
+
+/* Fire up a transfer using the hardware sequencer */
+static void start_hwseq_xfer(struct fast_spi_regs *regs, uint hsfsts_cycle,
+ uint offset, uint len)
+{
+ /* Make sure all W1C status bits get cleared */
+ u32 hsfsts;
+
+ hsfsts = readl(&regs->hsfsts_ctl);
+ hsfsts &= ~(HSFSTS_FCYCLE_MASK | HSFSTS_FDBC_MASK);
+ hsfsts |= HSFSTS_AEL | HSFSTS_FCERR | HSFSTS_FDONE;
+
+ /* Set up transaction parameters */
+ hsfsts |= hsfsts_cycle << HSFSTS_FCYCLE_SHIFT;
+ hsfsts |= ((len - 1) << HSFSTS_FDBC_SHIFT) & HSFSTS_FDBC_MASK;
+ hsfsts |= HSFSTS_FGO;
+
+ writel(offset, &regs->faddr);
+ writel(hsfsts, &regs->hsfsts_ctl);
+}
+
+static int wait_for_hwseq_xfer(struct fast_spi_regs *regs, uint offset)
+{
+ ulong start;
+ u32 hsfsts;
+
+ start = get_timer(0);
+ do {
+ hsfsts = readl(&regs->hsfsts_ctl);
+ if (hsfsts & HSFSTS_FCERR) {
+ debug("SPI transaction error at offset %x HSFSTS = %08x\n",
+ offset, hsfsts);
+ return -EIO;
+ }
+ if (hsfsts & HSFSTS_AEL)
+ return -EPERM;
+
+ if (hsfsts & HSFSTS_FDONE)
+ return 0;
+ } while (get_timer(start) < SPIBAR_HWSEQ_XFER_TIMEOUT_MS);
+
+ debug("SPI transaction timeout at offset %x HSFSTS = %08x, timer %d\n",
+ offset, hsfsts, (uint)get_timer(start));
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * exec_sync_hwseq_xfer() - Execute flash transfer by hardware sequencing
+ *
+ * This waits until complete or timeout
+ *
+ * @regs: SPI registers
+ * @hsfsts_cycle: Cycle type (enum hsfsts_cycle_t)
+ * @offset: Offset to access
+ * @len: Number of bytes to transfer (can be 0)
+ * @return 0 if OK, -EIO on flash-cycle error (FCERR), -EPERM on access error
+ * (AEL), -ETIMEDOUT on timeout
+ */
+static int exec_sync_hwseq_xfer(struct fast_spi_regs *regs, uint hsfsts_cycle,
+ uint offset, uint len)
+{
+ start_hwseq_xfer(regs, hsfsts_cycle, offset, len);
+
+ return wait_for_hwseq_xfer(regs, offset);
+}
+
+static int ich_spi_exec_op_hwseq(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ struct spi_flash *flash = dev_get_uclass_priv(slave->dev);
+ struct udevice *bus = dev_get_parent(slave->dev);
+ struct ich_spi_priv *priv = dev_get_priv(bus);
+ struct fast_spi_regs *regs = priv->base;
+ uint page_size;
+ uint offset;
+ int cycle;
+ uint len;
+ bool out;
+ int ret;
+ u8 *buf;
+
+ offset = op->addr.val;
+ len = op->data.nbytes;
+
+ switch (op->cmd.opcode) {
+ case SPINOR_OP_RDID:
+ cycle = HSFSTS_CYCLE_RDID;
+ break;
+ case SPINOR_OP_READ_FAST:
+ cycle = HSFSTS_CYCLE_READ;
+ break;
+ case SPINOR_OP_PP:
+ cycle = HSFSTS_CYCLE_WRITE;
+ break;
+ case SPINOR_OP_WREN:
+ /* Nothing needs to be done */
+ return 0;
+ case SPINOR_OP_WRSR:
+ cycle = HSFSTS_CYCLE_WR_STATUS;
+ break;
+ case SPINOR_OP_RDSR:
+ cycle = HSFSTS_CYCLE_RD_STATUS;
+ break;
+ case SPINOR_OP_WRDI:
+ 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;
+ default:
+ debug("Unknown cycle %x\n", op->cmd.opcode);
+ return -EINVAL;
+ };
+
+ out = op->data.dir == SPI_MEM_DATA_OUT;
+ buf = out ? (u8 *)op->data.buf.out : op->data.buf.in;
+ page_size = flash->page_size ? : 256;
+
+ while (len) {
+ uint xfer_len = get_xfer_len(offset, len, page_size);
+
+ if (out)
+ fill_xfer_fifo(regs, buf, xfer_len);
+
+ ret = exec_sync_hwseq_xfer(regs, cycle, offset, xfer_len);
+ if (ret)
+ return ret;
+
+ if (!out)
+ drain_xfer_fifo(regs, buf, xfer_len);
+
+ offset += xfer_len;
+ buf += xfer_len;
+ len -= xfer_len;
+ }
+
+ return 0;
+}
+
+static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
+{
+ struct udevice *bus = dev_get_parent(slave->dev);
+ struct ich_spi_platdata *plat = dev_get_platdata(bus);
+ int ret;
+
+ bootstage_start(BOOTSTAGE_ID_ACCUM_SPI, "fast_spi");
+ if (plat->hwseq)
+ ret = ich_spi_exec_op_hwseq(slave, op);
+ else
+ ret = ich_spi_exec_op_swseq(slave, op);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_SPI);
+
+ return ret;
+}
+
+static int ich_get_mmap_bus(struct udevice *bus, ulong *map_basep,
+ uint *map_sizep, uint *offsetp)
+{
+ pci_dev_t spi_bdf;
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct pci_child_platdata *pplat = dev_get_parent_platdata(bus);
+
+ spi_bdf = pplat->devfn;
+#else
+ struct ich_spi_platdata *plat = dev_get_platdata(bus);
+
+ /*
+ * We cannot rely on plat->bdf being set up yet since this method can
+ * be called before the device is probed. Use the of-platdata directly
+ * instead.
+ */
+ spi_bdf = pci_ofplat_get_devfn(plat->dtplat.reg[0]);
+#endif
+
+ return fast_spi_get_bios_mmap(spi_bdf, map_basep, map_sizep, offsetp);
+}
+
+static int ich_get_mmap(struct udevice *dev, ulong *map_basep, uint *map_sizep,
+ uint *offsetp)
+{
+ struct udevice *bus = dev_get_parent(dev);
+
+ return ich_get_mmap_bus(bus, map_basep, map_sizep, offsetp);
+}
+
static int ich_spi_adjust_size(struct spi_slave *slave, struct spi_mem_op *op)
{
unsigned int page_offset;
@@ -480,9 +663,11 @@ static int ich_spi_adjust_size(struct spi_slave *slave, struct spi_mem_op *op)
page_offset = do_div(aux, ICH_BOUNDARY);
}
- if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size) {
- op->data.nbytes = min(ICH_BOUNDARY - page_offset,
- slave->max_read_size);
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ if (slave->max_read_size) {
+ op->data.nbytes = min(ICH_BOUNDARY - page_offset,
+ slave->max_read_size);
+ }
} else if (slave->max_write_size) {
op->data.nbytes = min(ICH_BOUNDARY - page_offset,
slave->max_write_size);
@@ -493,26 +678,18 @@ static int ich_spi_adjust_size(struct spi_slave *slave, struct spi_mem_op *op)
return 0;
}
-static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
-{
- printf("ICH SPI: Only supports memory operations\n");
- return -1;
-}
-
-static int ich_spi_probe(struct udevice *dev)
+static int ich_protect_lockdown(struct udevice *dev)
{
struct ich_spi_platdata *plat = dev_get_platdata(dev);
struct ich_spi_priv *priv = dev_get_priv(dev);
- uint8_t bios_cntl;
- int ret;
+ int ret = -ENOSYS;
- ret = ich_init_controller(dev, plat, priv);
- if (ret)
- return ret;
/* Disable the BIOS write protect so write commands are allowed */
- ret = pch_set_spi_protect(dev->parent, false);
+ if (priv->pch)
+ ret = pch_set_spi_protect(priv->pch, false);
if (ret == -ENOSYS) {
+ u8 bios_cntl;
+
bios_cntl = ich_readb(priv, priv->bcr);
bios_cntl &= ~BIT(5); /* clear Enable InSMM_STS (EISS) */
bios_cntl |= 1; /* Write Protect Disable (WPD) */
@@ -529,6 +706,111 @@ static int ich_spi_probe(struct udevice *dev)
spi_lock_down(plat, priv->base);
}
+ return 0;
+}
+
+static int ich_init_controller(struct udevice *dev,
+ struct ich_spi_platdata *plat,
+ struct ich_spi_priv *ctlr)
+{
+ if (spl_phase() == PHASE_TPL) {
+ struct ich_spi_platdata *plat = dev_get_platdata(dev);
+ int ret;
+
+ ret = fast_spi_early_init(plat->bdf, plat->mmio_base);
+ if (ret)
+ return ret;
+ }
+
+ ctlr->base = (void *)plat->mmio_base;
+ if (plat->ich_version == ICHV_7) {
+ struct ich7_spi_regs *ich7_spi = ctlr->base;
+
+ ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu);
+ ctlr->menubytes = sizeof(ich7_spi->opmenu);
+ ctlr->optype = offsetof(struct ich7_spi_regs, optype);
+ ctlr->addr = offsetof(struct ich7_spi_regs, spia);
+ ctlr->data = offsetof(struct ich7_spi_regs, spid);
+ ctlr->databytes = sizeof(ich7_spi->spid);
+ ctlr->status = offsetof(struct ich7_spi_regs, spis);
+ ctlr->control = offsetof(struct ich7_spi_regs, spic);
+ ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
+ ctlr->preop = offsetof(struct ich7_spi_regs, preop);
+ } else if (plat->ich_version == ICHV_9) {
+ struct ich9_spi_regs *ich9_spi = ctlr->base;
+
+ ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu);
+ ctlr->menubytes = sizeof(ich9_spi->opmenu);
+ ctlr->optype = offsetof(struct ich9_spi_regs, optype);
+ ctlr->addr = offsetof(struct ich9_spi_regs, faddr);
+ ctlr->data = offsetof(struct ich9_spi_regs, fdata);
+ ctlr->databytes = sizeof(ich9_spi->fdata);
+ ctlr->status = offsetof(struct ich9_spi_regs, ssfs);
+ ctlr->control = offsetof(struct ich9_spi_regs, ssfc);
+ ctlr->speed = ctlr->control + 2;
+ ctlr->bbar = offsetof(struct ich9_spi_regs, bbar);
+ ctlr->preop = offsetof(struct ich9_spi_regs, preop);
+ ctlr->bcr = offsetof(struct ich9_spi_regs, bcr);
+ ctlr->pr = &ich9_spi->pr[0];
+ } else if (plat->ich_version == ICHV_APL) {
+ } else {
+ debug("ICH SPI: Unrecognised ICH version %d\n",
+ plat->ich_version);
+ return -EINVAL;
+ }
+
+ /* Work out the maximum speed we can support */
+ ctlr->max_speed = 20000000;
+ if (plat->ich_version == ICHV_9 && ich9_can_do_33mhz(dev))
+ ctlr->max_speed = 33000000;
+ debug("ICH SPI: Version ID %d detected at %lx, speed %ld\n",
+ plat->ich_version, plat->mmio_base, ctlr->max_speed);
+
+ ich_set_bbar(ctlr, 0);
+
+ return 0;
+}
+
+static int ich_cache_bios_region(struct udevice *dev)
+{
+ ulong map_base;
+ uint map_size;
+ uint offset;
+ ulong base;
+ int ret;
+
+ ret = ich_get_mmap_bus(dev, &map_base, &map_size, &offset);
+ if (ret)
+ return ret;
+
+ /* Don't use WRBACK since we are not supposed to write to SPI flash */
+ base = SZ_4G - map_size;
+ mtrr_set_next_var(MTRR_TYPE_WRPROT, base, map_size);
+ log_debug("BIOS cache base=%lx, size=%x\n", base, (uint)map_size);
+
+ return 0;
+}
+
+static int ich_spi_probe(struct udevice *dev)
+{
+ struct ich_spi_platdata *plat = dev_get_platdata(dev);
+ struct ich_spi_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = ich_init_controller(dev, plat, priv);
+ if (ret)
+ return ret;
+
+ if (spl_phase() == PHASE_TPL) {
+ /* Cache the BIOS to speed things up */
+ ret = ich_cache_bios_region(dev);
+ if (ret)
+ return ret;
+ } else {
+ ret = ich_protect_lockdown(dev);
+ if (ret)
+ return ret;
+ }
priv->cur_speed = priv->max_speed;
return 0;
@@ -570,9 +852,11 @@ static int ich_spi_child_pre_probe(struct udevice *dev)
/*
* Yes this controller can only write a small number of bytes at
- * once! The limit is typically 64 bytes.
+ * once! The limit is typically 64 bytes. For hardware sequencing a
+ * a loop is used to get around this.
*/
- slave->max_write_size = priv->databytes;
+ if (!plat->hwseq)
+ slave->max_write_size = priv->databytes;
/*
* ICH 7 SPI controller only supports array read command
* and byte program command for SST flash
@@ -586,23 +870,37 @@ static int ich_spi_child_pre_probe(struct udevice *dev)
static int ich_spi_ofdata_to_platdata(struct udevice *dev)
{
struct ich_spi_platdata *plat = dev_get_platdata(dev);
- int node = dev_of_offset(dev);
- int ret;
- ret = fdt_node_check_compatible(gd->fdt_blob, node, "intel,ich7-spi");
- if (ret == 0) {
- plat->ich_version = ICHV_7;
- } else {
- ret = fdt_node_check_compatible(gd->fdt_blob, node,
- "intel,ich9-spi");
- if (ret == 0)
- plat->ich_version = ICHV_9;
- }
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct ich_spi_priv *priv = dev_get_priv(dev);
- plat->lockdown = fdtdec_get_bool(gd->fdt_blob, node,
- "intel,spi-lock-down");
+ /* Find a PCH if there is one */
+ uclass_first_device(UCLASS_PCH, &priv->pch);
+ if (!priv->pch)
+ priv->pch = dev_get_parent(dev);
+
+ plat->ich_version = dev_get_driver_data(dev);
+ plat->lockdown = dev_read_bool(dev, "intel,spi-lock-down");
+ if (plat->ich_version == ICHV_APL) {
+ plat->mmio_base = dm_pci_read_bar32(dev, 0);
+ } else {
+ /* SBASE is similar */
+ pch_get_spi_base(priv->pch, &plat->mmio_base);
+ }
+ /*
+ * Use an int so that the property is present in of-platdata even
+ * when false.
+ */
+ plat->hwseq = dev_read_u32_default(dev, "intel,hardware-seq", 0);
+#else
+ plat->ich_version = ICHV_APL;
+ plat->mmio_base = plat->dtplat.early_regs[0];
+ plat->bdf = pci_ofplat_get_devfn(plat->dtplat.reg[0]);
+ plat->hwseq = plat->dtplat.intel_hardware_seq;
+#endif
+ debug("%s: mmio_base=%lx\n", __func__, plat->mmio_base);
- return ret;
+ return 0;
}
static const struct spi_controller_mem_ops ich_controller_mem_ops = {
@@ -612,10 +910,11 @@ static const struct spi_controller_mem_ops ich_controller_mem_ops = {
};
static const struct dm_spi_ops ich_spi_ops = {
- .xfer = ich_spi_xfer,
+ /* xfer is not supported */
.set_speed = ich_spi_set_speed,
.set_mode = ich_spi_set_mode,
.mem_ops = &ich_controller_mem_ops,
+ .get_mmap = ich_get_mmap,
/*
* cs_info is not needed, since we require all chip selects to be
* in the device tree explicitly
@@ -623,13 +922,14 @@ static const struct dm_spi_ops ich_spi_ops = {
};
static const struct udevice_id ich_spi_ids[] = {
- { .compatible = "intel,ich7-spi" },
- { .compatible = "intel,ich9-spi" },
+ { .compatible = "intel,ich7-spi", ICHV_7 },
+ { .compatible = "intel,ich9-spi", ICHV_9 },
+ { .compatible = "intel,fast-spi", ICHV_APL },
{ }
};
-U_BOOT_DRIVER(ich_spi) = {
- .name = "ich_spi",
+U_BOOT_DRIVER(intel_fast_spi) = {
+ .name = "intel_fast_spi",
.id = UCLASS_SPI,
.of_match = ich_spi_ids,
.ops = &ich_spi_ops,
diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h
index 3dfb2aaff1..d7f1ffdf37 100644
--- a/drivers/spi/ich.h
+++ b/drivers/spi/ich.h
@@ -163,14 +163,49 @@ struct spi_trans {
#define ICH_BOUNDARY 0x1000
+#define HSFSTS_FDBC_SHIFT 24
+#define HSFSTS_FDBC_MASK (0x3f << HSFSTS_FDBC_SHIFT)
+#define HSFSTS_WET BIT(21)
+#define HSFSTS_FCYCLE_SHIFT 17
+#define HSFSTS_FCYCLE_MASK (0xf << HSFSTS_FCYCLE_SHIFT)
+
+/* Supported flash cycle types */
+enum hsfsts_cycle_t {
+ HSFSTS_CYCLE_READ = 0,
+ HSFSTS_CYCLE_WRITE = 2,
+ HSFSTS_CYCLE_4K_ERASE,
+ HSFSTS_CYCLE_64K_ERASE,
+ HSFSTS_CYCLE_RDSFDP,
+ HSFSTS_CYCLE_RDID,
+ HSFSTS_CYCLE_WR_STATUS,
+ HSFSTS_CYCLE_RD_STATUS,
+};
+
+#define HSFSTS_FGO BIT(16)
+#define HSFSTS_FLOCKDN BIT(15)
+#define HSFSTS_FDV BIT(14)
+#define HSFSTS_FDOPSS BIT(13)
+#define HSFSTS_WRSDIS BIT(11)
+#define HSFSTS_SAF_CE BIT(8)
+#define HSFSTS_SAF_ACTIVE BIT(7)
+#define HSFSTS_SAF_LE BIT(6)
+#define HSFSTS_SCIP BIT(5)
+#define HSFSTS_SAF_DLE BIT(4)
+#define HSFSTS_SAF_ERROR BIT(3)
+#define HSFSTS_AEL BIT(2)
+#define HSFSTS_FCERR BIT(1)
+#define HSFSTS_FDONE BIT(0)
+#define HSFSTS_W1C_BITS 0xff
+
+/* Maximum bytes of data that can fit in FDATAn (0x10) registers */
+#define SPIBAR_FDATA_FIFO_SIZE 0x40
+
+#define SPIBAR_HWSEQ_XFER_TIMEOUT_MS 5000
+
enum ich_version {
ICHV_7,
ICHV_9,
-};
-
-struct ich_spi_platdata {
- enum ich_version ich_version; /* Controller version, 7 or 9 */
- bool lockdown; /* lock down controller settings? */
+ ICHV_APL,
};
struct ich_spi_priv {
@@ -191,6 +226,7 @@ struct ich_spi_priv {
ulong max_speed; /* Maximum bus speed in MHz */
ulong cur_speed; /* Current bus speed */
struct spi_trans trans; /* current transaction in progress */
+ struct udevice *pch; /* PCH, used to control SPI access */
};
#endif /* _ICH_H_ */
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 665611f7e2..af910e9efc 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -85,11 +85,14 @@ int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
struct udevice *bus = dev->parent;
+ struct dm_spi_ops *ops = spi_get_ops(bus);
if (bus->uclass->uc_drv->id != UCLASS_SPI)
return -EOPNOTSUPP;
+ if (!ops->xfer)
+ return -ENOSYS;
- return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
+ return ops->xfer(dev, bitlen, dout, din, flags);
}
int dm_spi_get_mmap(struct udevice *dev, ulong *map_basep, uint *map_sizep,
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 5f4bc6edb6..96cc49273f 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -174,6 +174,29 @@ config X86_TSC_TIMER
help
Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config X86_TSC_READ_BASE
+ bool "Read the TSC timer base on start-up"
+ depends on X86_TSC_TIMER
+ help
+ On x86 platforms the TSC timer tick starts at the value 0 on reset.
+ This it makes no sense to read the timer on boot and use that as the
+ base, since we will miss some time taken to load U-Boot, etc. This
+ delay is controlled by the SoC and we cannot reduce it, but for
+ bootstage we want to record the time since reset as accurately as
+ possible.
+
+ The only exception is when U-Boot is used as a secondary bootloader,
+ where this option should be enabled.
+
+config TPL_X86_TSC_TIMER_NATIVE
+ bool "x86 TSC timer uses native calibration"
+ depends on TPL && X86_TSC_TIMER
+ help
+ Selects native timer calibration for TPL and don't include the other
+ methods in the code. This helps to reduce code size in TPL and works
+ on fairly modern Intel chips. Code-size reductions is about 700
+ bytes.
+
config MTK_TIMER
bool "MediaTek timer support"
depends on TIMER
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c
index 0df551f94c..43cb2d820e 100644
--- a/drivers/timer/tsc_timer.c
+++ b/drivers/timer/tsc_timer.c
@@ -50,8 +50,7 @@ static unsigned long native_calibrate_tsc(void)
return 0;
crystal_freq = tsc_info.ecx / 1000;
-
- if (!crystal_freq) {
+ if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) {
switch (gd->arch.x86_model) {
case INTEL_FAM6_SKYLAKE_MOBILE:
case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -397,7 +396,8 @@ static void tsc_timer_ensure_setup(bool early)
{
if (gd->arch.tsc_inited)
return;
- gd->arch.tsc_base = rdtsc();
+ if (IS_ENABLED(CONFIG_X86_TSC_READ_BASE))
+ gd->arch.tsc_base = rdtsc();
if (!gd->arch.clock_rate) {
unsigned long fast_calibrate;
@@ -406,6 +406,10 @@ static void tsc_timer_ensure_setup(bool early)
if (fast_calibrate)
goto done;
+ /* Reduce code size by dropping other methods */
+ if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
+ panic("no timer");
+
fast_calibrate = cpu_mhz_from_cpuid();
if (fast_calibrate)
goto done;
diff --git a/drivers/tpm/tpm2_tis_spi.c b/drivers/tpm/tpm2_tis_spi.c
index 3d105fddba..713111f6c3 100644
--- a/drivers/tpm/tpm2_tis_spi.c
+++ b/drivers/tpm/tpm2_tis_spi.c
@@ -587,7 +587,7 @@ static int tpm_tis_spi_probe(struct udevice *dev)
/* Use the TPM v2 stack */
priv->version = TPM_V2;
- if (IS_ENABLED(CONFIG_DM_GPIO)) {
+ if (CONFIG_IS_ENABLED(DM_GPIO)) {
struct gpio_desc reset_gpio;
ret = gpio_request_by_name(dev, "gpio-reset", 0,