Add a simple PMC for sandbox to permit tests to run.

Signed-off-by: Simon Glass <s...@chromium.org>
---

Changes in v5: None
Changes in v4: None
Changes in v3:
- Rename power-mgr uclass to acpi-pmc
- Tidy up Makefile rules to reduce duplication

Changes in v2: None

 arch/Kconfig                      |   2 +
 arch/sandbox/dts/sandbox.dtsi     |  14 ++
 arch/sandbox/dts/test.dts         |  14 ++
 arch/sandbox/include/asm/test.h   |   1 +
 drivers/Makefile                  |   1 +
 drivers/power/acpi_pmc/Kconfig    |   9 ++
 drivers/power/acpi_pmc/Makefile   |   1 +
 drivers/power/acpi_pmc/pmc_emul.c | 246 ++++++++++++++++++++++++++++++
 drivers/power/acpi_pmc/sandbox.c  |  97 ++++++++++++
 test/dm/Makefile                  |   1 +
 test/dm/pmc.c                     |  33 ++++
 11 files changed, 419 insertions(+)
 create mode 100644 drivers/power/acpi_pmc/pmc_emul.c
 create mode 100644 drivers/power/acpi_pmc/sandbox.c
 create mode 100644 test/dm/pmc.c

diff --git a/arch/Kconfig b/arch/Kconfig
index 141e48bc43..8094e18663 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -133,6 +133,8 @@ config SANDBOX
        imply PHYLIB
        imply DM_MDIO
        imply DM_MDIO_MUX
+       imply ACPI_PMC
+       imply ACPI_PMC_SANDBOX
 
 config SH
        bool "SuperH architecture"
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index f09bc70b0d..7bf144f532 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -100,6 +100,17 @@
        };
 
        pci-controller {
+               pci@1e,0 {
+                       compatible = "sandbox,pmc";
+                       reg = <0xf000 0 0 0 0>;
+                       sandbox,emul = <&pmc_emul>;
+                       gpe0-dwx-mask = <0xf>;
+                       gpe0-dwx-shift-base = <4>;
+                       gpe0-dw = <6 7 9>;
+                       gpe0-sts = <0x20>;
+                       gpe0-en = <0x30>;
+               };
+
                pci@1f,0 {
                        compatible = "pci-generic";
                        reg = <0xf800 0 0 0 0>;
@@ -109,6 +120,9 @@
 
        emul {
                compatible = "sandbox,pci-emul-parent";
+               pmc_emul: emul@1e,0 {
+                       compatible = "sandbox,pmc-emul";
+               };
                swap_case_emul: emul@1f,0 {
                        compatible = "sandbox,swap-case";
                };
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index fdb08f2111..99905677ab 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -471,6 +471,17 @@
                               0x01000810 0 0 0 0>;
                        sandbox,emul = <&swap_case_emul0_1>;
                };
+               pci@1e,0 {
+                       compatible = "sandbox,pmc";
+                       reg = <0xf000 0 0 0 0>;
+                       sandbox,emul = <&pmc_emul1e>;
+                       acpi-base = <0x400>;
+                       gpe0-dwx-mask = <0xf>;
+                       gpe0-dwx-shift-base = <4>;
+                       gpe0-dw = <6 7 9>;
+                       gpe0-sts = <0x20>;
+                       gpe0-en = <0x30>;
+               };
                pci@1f,0 {
                        compatible = "pci-generic";
                        /* reg 0 is at 0x10, using FDT_PCI_SPACE_IO */
@@ -491,6 +502,9 @@
                swap_case_emul0_1f: emul0@1f,0 {
                        compatible = "sandbox,swap-case";
                };
+               pmc_emul1e: emul@1e,0 {
+                       compatible = "sandbox,pmc-emul";
+               };
        };
 
        pci1: pci-controller1 {
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index b885e1a14f..fa40d21f3f 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -13,6 +13,7 @@
 
 #define SANDBOX_PCI_VENDOR_ID          0x1234
 #define SANDBOX_PCI_SWAP_CASE_EMUL_ID  0x5678
+#define SANDBOX_PCI_PMC_EMUL_ID                0x5677
 #define SANDBOX_PCI_CLASS_CODE         PCI_CLASS_CODE_COMM
 #define SANDBOX_PCI_CLASS_SUB_CODE     PCI_CLASS_SUB_CODE_COMM_SERIAL
 
diff --git a/drivers/Makefile b/drivers/Makefile
index 0befeddfcb..4f460edc95 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -26,6 +26,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/power/acpi_pmc/Kconfig b/drivers/power/acpi_pmc/Kconfig
index 472a61a9fd..fcd50e36ca 100644
--- a/drivers/power/acpi_pmc/Kconfig
+++ b/drivers/power/acpi_pmc/Kconfig
@@ -23,3 +23,12 @@ config TPL_ACPI_PMC
          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
index 7c1ba05c9f..115788f109 100644
--- a/drivers/power/acpi_pmc/Makefile
+++ b/drivers/power/acpi_pmc/Makefile
@@ -3,3 +3,4 @@
 # 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/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 <s...@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/test/dm/Makefile b/test/dm/Makefile
index 0c2fd5cb5e..10a19a00c9 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PCI_ENDPOINT) += pci_ep.o
 obj-$(CONFIG_PCH) += pch.o
 obj-$(CONFIG_PHY) += phy.o
 obj-$(CONFIG_POWER_DOMAIN) += power-domain.o
+obj-$(CONFIG_ACPI_PMC) += pmc.o
 obj-$(CONFIG_DM_PWM) += pwm.o
 obj-$(CONFIG_RAM) += ram.o
 obj-y += regmap.o
diff --git a/test/dm/pmc.c b/test/dm/pmc.c
new file mode 100644
index 0000000000..1a222838ab
--- /dev/null
+++ b/test/dm/pmc.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test for power-management controller uclass (PMC)
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <power/acpi_pmc.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Base test of the PMC uclass */
+static int dm_test_pmc_base(struct unit_test_state *uts)
+{
+       struct acpi_pmc_upriv *upriv;
+       struct udevice *dev;
+
+       ut_assertok(uclass_first_device_err(UCLASS_ACPI_PMC, &dev));
+
+       ut_assertok(pmc_disable_tco(dev));
+       ut_assertok(pmc_init(dev));
+       ut_assertok(pmc_prev_sleep_state(dev));
+
+       /* Check some values to see that I/O works */
+       upriv = dev_get_uclass_priv(dev);
+       ut_asserteq(0x24, upriv->gpe0_sts[1]);
+       ut_asserteq(0x64, upriv->tco1_sts);
+
+       return 0;
+}
+DM_TEST(dm_test_pmc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.24.0.432.g9d3f5f5b63-goog

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to