x86: sandbox: Add a PMC emulator and test
Add a simple PMC for sandbox to permit tests to run. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
parent
6c6d88e142
commit
3b65ee34b9
@ -133,6 +133,9 @@ config SANDBOX
|
|||||||
imply PHYLIB
|
imply PHYLIB
|
||||||
imply DM_MDIO
|
imply DM_MDIO
|
||||||
imply DM_MDIO_MUX
|
imply DM_MDIO_MUX
|
||||||
|
imply ACPI_PMC
|
||||||
|
imply ACPI_PMC_SANDBOX
|
||||||
|
imply CMD_PMC
|
||||||
|
|
||||||
config SH
|
config SH
|
||||||
bool "SuperH architecture"
|
bool "SuperH architecture"
|
||||||
|
@ -100,6 +100,17 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
pci-controller {
|
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 {
|
pci@1f,0 {
|
||||||
compatible = "pci-generic";
|
compatible = "pci-generic";
|
||||||
reg = <0xf800 0 0 0 0>;
|
reg = <0xf800 0 0 0 0>;
|
||||||
@ -109,6 +120,9 @@
|
|||||||
|
|
||||||
emul {
|
emul {
|
||||||
compatible = "sandbox,pci-emul-parent";
|
compatible = "sandbox,pci-emul-parent";
|
||||||
|
pmc_emul: emul@1e,0 {
|
||||||
|
compatible = "sandbox,pmc-emul";
|
||||||
|
};
|
||||||
swap_case_emul: emul@1f,0 {
|
swap_case_emul: emul@1f,0 {
|
||||||
compatible = "sandbox,swap-case";
|
compatible = "sandbox,swap-case";
|
||||||
};
|
};
|
||||||
|
@ -471,6 +471,17 @@
|
|||||||
0x01000810 0 0 0 0>;
|
0x01000810 0 0 0 0>;
|
||||||
sandbox,emul = <&swap_case_emul0_1>;
|
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 {
|
pci@1f,0 {
|
||||||
compatible = "pci-generic";
|
compatible = "pci-generic";
|
||||||
/* reg 0 is at 0x10, using FDT_PCI_SPACE_IO */
|
/* reg 0 is at 0x10, using FDT_PCI_SPACE_IO */
|
||||||
@ -491,6 +502,9 @@
|
|||||||
swap_case_emul0_1f: emul0@1f,0 {
|
swap_case_emul0_1f: emul0@1f,0 {
|
||||||
compatible = "sandbox,swap-case";
|
compatible = "sandbox,swap-case";
|
||||||
};
|
};
|
||||||
|
pmc_emul1e: emul@1e,0 {
|
||||||
|
compatible = "sandbox,pmc-emul";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pci1: pci-controller1 {
|
pci1: pci-controller1 {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#define SANDBOX_PCI_VENDOR_ID 0x1234
|
#define SANDBOX_PCI_VENDOR_ID 0x1234
|
||||||
#define SANDBOX_PCI_SWAP_CASE_EMUL_ID 0x5678
|
#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_CODE PCI_CLASS_CODE_COMM
|
||||||
#define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL
|
#define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL
|
||||||
|
|
||||||
|
@ -228,6 +228,14 @@ config CMD_LICENSE
|
|||||||
help
|
help
|
||||||
Print GPL license text
|
Print GPL license text
|
||||||
|
|
||||||
|
config CMD_PMC
|
||||||
|
bool "pmc"
|
||||||
|
help
|
||||||
|
Provides access to the Intel Power-Management Controller (PMC) so
|
||||||
|
that its state can be examined. This does not currently support
|
||||||
|
changing the state but it is still useful for debugging and seeing
|
||||||
|
what is going on.
|
||||||
|
|
||||||
config CMD_REGINFO
|
config CMD_REGINFO
|
||||||
bool "reginfo"
|
bool "reginfo"
|
||||||
depends on PPC
|
depends on PPC
|
||||||
|
@ -109,6 +109,7 @@ ifdef CONFIG_PCI
|
|||||||
obj-$(CONFIG_CMD_PCI) += pci.o
|
obj-$(CONFIG_CMD_PCI) += pci.o
|
||||||
endif
|
endif
|
||||||
obj-$(CONFIG_CMD_PINMUX) += pinmux.o
|
obj-$(CONFIG_CMD_PINMUX) += pinmux.o
|
||||||
|
obj-$(CONFIG_CMD_PMC) += pmc.o
|
||||||
obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o
|
obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o
|
||||||
obj-$(CONFIG_CMD_WOL) += wol.o
|
obj-$(CONFIG_CMD_WOL) += wol.o
|
||||||
obj-$(CONFIG_CMD_QFW) += qfw.o
|
obj-$(CONFIG_CMD_QFW) += qfw.o
|
||||||
|
81
cmd/pmc.c
Normal file
81
cmd/pmc.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Intel PMC command
|
||||||
|
*
|
||||||
|
* Copyright 2019 Google LLC
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <command.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <power/acpi_pmc.h>
|
||||||
|
|
||||||
|
static int get_pmc_dev(struct udevice **devp)
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = uclass_first_device_err(UCLASS_ACPI_PMC, &dev);
|
||||||
|
if (ret) {
|
||||||
|
printf("Could not find device (err=%d)\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = pmc_init(dev);
|
||||||
|
if (ret) {
|
||||||
|
printf("Could not init device (err=%d)\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
*devp = dev;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_pmc_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = get_pmc_dev(&dev);
|
||||||
|
if (ret)
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_pmc_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = get_pmc_dev(&dev);
|
||||||
|
if (ret)
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
pmc_dump_info(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cmd_tbl_t cmd_pmc_sub[] = {
|
||||||
|
U_BOOT_CMD_MKENT(init, 0, 1, do_pmc_init, "", ""),
|
||||||
|
U_BOOT_CMD_MKENT(info, 0, 1, do_pmc_info, "", ""),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_pmc(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||||
|
{
|
||||||
|
const cmd_tbl_t *cp;
|
||||||
|
|
||||||
|
if (argc < 2) /* no subcommand */
|
||||||
|
return cmd_usage(cmdtp);
|
||||||
|
|
||||||
|
cp = find_cmd_tbl(argv[1], &cmd_pmc_sub[0], ARRAY_SIZE(cmd_pmc_sub));
|
||||||
|
if (!cp)
|
||||||
|
return CMD_RET_USAGE;
|
||||||
|
|
||||||
|
return cp->cmd(cmdtp, flag, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
U_BOOT_CMD(
|
||||||
|
pmc, 2, 1, do_pmc, "Power-management controller info",
|
||||||
|
"info - read state and show info about the PMC\n"
|
||||||
|
"pmc init - read state from the PMC\n"
|
||||||
|
);
|
@ -25,6 +25,7 @@ obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/
|
|||||||
obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
|
obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
|
||||||
obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/
|
obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/
|
||||||
obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/
|
obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/
|
||||||
|
obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += power/acpi_pmc/
|
||||||
|
|
||||||
ifndef CONFIG_TPL_BUILD
|
ifndef CONFIG_TPL_BUILD
|
||||||
ifdef CONFIG_SPL_BUILD
|
ifdef CONFIG_SPL_BUILD
|
||||||
|
@ -23,3 +23,12 @@ config TPL_ACPI_PMC
|
|||||||
provides features including checking whether the system started from
|
provides features including checking whether the system started from
|
||||||
resume, powering off the system and enabling/disabling the reset
|
resume, powering off the system and enabling/disabling the reset
|
||||||
mechanism.
|
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.
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
# Copyright 2019 Google LLC
|
# Copyright 2019 Google LLC
|
||||||
|
|
||||||
obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += acpi-pmc-uclass.o
|
obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += acpi-pmc-uclass.o
|
||||||
|
obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC_SANDBOX) += sandbox.o pmc_emul.o
|
||||||
|
246
drivers/power/acpi_pmc/pmc_emul.c
Normal file
246
drivers/power/acpi_pmc/pmc_emul.c
Normal file
@ -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);
|
97
drivers/power/acpi_pmc/sandbox.c
Normal file
97
drivers/power/acpi_pmc/sandbox.c
Normal file
@ -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),
|
||||||
|
};
|
@ -36,6 +36,7 @@ obj-$(CONFIG_PCI_ENDPOINT) += pci_ep.o
|
|||||||
obj-$(CONFIG_PCH) += pch.o
|
obj-$(CONFIG_PCH) += pch.o
|
||||||
obj-$(CONFIG_PHY) += phy.o
|
obj-$(CONFIG_PHY) += phy.o
|
||||||
obj-$(CONFIG_POWER_DOMAIN) += power-domain.o
|
obj-$(CONFIG_POWER_DOMAIN) += power-domain.o
|
||||||
|
obj-$(CONFIG_ACPI_PMC) += pmc.o
|
||||||
obj-$(CONFIG_DM_PWM) += pwm.o
|
obj-$(CONFIG_DM_PWM) += pwm.o
|
||||||
obj-$(CONFIG_RAM) += ram.o
|
obj-$(CONFIG_RAM) += ram.o
|
||||||
obj-y += regmap.o
|
obj-y += regmap.o
|
||||||
|
33
test/dm/pmc.c
Normal file
33
test/dm/pmc.c
Normal file
@ -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);
|
Loading…
Reference in New Issue
Block a user