Hi Simon, On Mon, Oct 21, 2019 at 11:40 AM Simon Glass <s...@chromium.org> wrote: > > Add a sandbox driver and PCI-device emulator for p2sb. Also add a test > which uses a simple 'adder' driver to test the p2sb functionality. > > Signed-off-by: Simon Glass <s...@chromium.org> > --- > > Changes in v3: > - Fix build errors in sandbox_spl, etc > > Changes in v2: None > > arch/sandbox/cpu/state.c | 1 + > arch/sandbox/dts/test.dts | 13 ++ > arch/sandbox/include/asm/test.h | 10 ++ > configs/sandbox64_defconfig | 2 + > configs/sandbox_flattree_defconfig | 3 + > configs/sandbox_spl_defconfig | 2 + > configs/tools-only_defconfig | 2 + > drivers/core/uclass.c | 4 +- > drivers/misc/Makefile | 2 + > drivers/misc/p2sb_emul.c | 272 +++++++++++++++++++++++++++++ > drivers/misc/p2sb_sandbox.c | 44 +++++ > drivers/misc/sandbox_adder.c | 60 +++++++ > test/dm/Makefile | 1 + > test/dm/p2sb.c | 28 +++ > 14 files changed, 442 insertions(+), 2 deletions(-) > create mode 100644 drivers/misc/p2sb_emul.c > create mode 100644 drivers/misc/p2sb_sandbox.c > create mode 100644 drivers/misc/sandbox_adder.c > create mode 100644 test/dm/p2sb.c > > diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c > index dee5fde4f73..cd46e000f5e 100644 > --- a/arch/sandbox/cpu/state.c > +++ b/arch/sandbox/cpu/state.c > @@ -356,6 +356,7 @@ void state_reset_for_test(struct sandbox_state *state) > /* No reset yet, so mark it as such. Always allow power reset */ > state->last_sysreset = SYSRESET_COUNT; > state->sysreset_allowed[SYSRESET_POWER_OFF] = true; > + state->allow_memio = false;
A separate patch? > > memset(&state->wdt, '\0', sizeof(state->wdt)); > memset(state->spi, '\0', sizeof(state->spi)); > diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts > index 5c1093df282..24631770544 100644 > --- a/arch/sandbox/dts/test.dts > +++ b/arch/sandbox/dts/test.dts > @@ -467,6 +467,16 @@ > 0x01000810 0 0 0 0>; > sandbox,emul = <&swap_case_emul0_1>; > }; > + p2sb-pci@2,0 { > + compatible = "sandbox,p2sb"; > + reg = <0x02001010 0 0 0 0>; > + sandbox,emul = <&p2sb_emul>; > + > + adder { > + intel,p2sb-port-id = <3>; > + compatible = "sandbox,adder"; > + }; > + }; > pci@1e,0 { > compatible = "sandbox,pmc"; > reg = <0xf000 0 0 0 0>; > @@ -498,6 +508,9 @@ > swap_case_emul0_1f: emul0@1f,0 { > compatible = "sandbox,swap-case"; > }; > + p2sb_emul: emul@2,0 { > + compatible = "sandbox,p2sb-emul"; > + }; > pmc_emul1e: emul@1e,0 { > compatible = "sandbox,pmc-emul"; > }; > diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h > index 7f9e7fc26f5..77fff529e19 100644 > --- a/arch/sandbox/include/asm/test.h > +++ b/arch/sandbox/include/asm/test.h > @@ -14,6 +14,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_P2SB_EMUL_ID 0x5676 > #define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM > #define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL > > @@ -214,4 +215,13 @@ int sandbox_get_pci_ep_irq_count(struct udevice *dev); > */ > uint sandbox_pci_read_bar(u32 barval, int type, uint size); > > +/** > + * sandbox_set_enable_memio() - Enable memory-mapped I/O read/write > + * > + * Normally readl(), writel() and the like are nops on sandbox. If this > function > + * is called with true, those function do real memory accesses. This is > useful > + * for certain tests. > + */ > +void sandbox_set_enable_memio(bool enable); > + A separate patch? > #endif > diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig > index 1fea683d892..4c86141ffb1 100644 > --- a/configs/sandbox64_defconfig > +++ b/configs/sandbox64_defconfig > @@ -81,6 +81,8 @@ CONFIG_DEVRES=y > CONFIG_DEBUG_DEVRES=y > CONFIG_ADC=y > CONFIG_ADC_SANDBOX=y > +CONFIG_AXI=y > +CONFIG_AXI_SANDBOX=y > CONFIG_CLK=y > CONFIG_CPU=y > CONFIG_DM_DEMO=y > diff --git a/configs/sandbox_flattree_defconfig > b/configs/sandbox_flattree_defconfig > index 898815fe531..230d65b14a7 100644 > --- a/configs/sandbox_flattree_defconfig > +++ b/configs/sandbox_flattree_defconfig > @@ -65,6 +65,8 @@ CONFIG_DEVRES=y > CONFIG_DEBUG_DEVRES=y > CONFIG_ADC=y > CONFIG_ADC_SANDBOX=y > +CONFIG_AXI=y > +CONFIG_AXI_SANDBOX=y > CONFIG_CLK=y > CONFIG_CLK_COMPOSITE_CCF=y > CONFIG_SANDBOX_CLK_CCF=y > @@ -116,6 +118,7 @@ CONFIG_PCI=y > CONFIG_DM_PCI=y > CONFIG_DM_PCI_COMPAT=y > CONFIG_PCI_SANDBOX=y > +CONFIG_P2SB=y > CONFIG_PHY=y > CONFIG_PHY_SANDBOX=y > CONFIG_PINCTRL=y > diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig > index c49e05ec319..405b6015474 100644 > --- a/configs/sandbox_spl_defconfig > +++ b/configs/sandbox_spl_defconfig > @@ -86,6 +86,8 @@ CONFIG_DEBUG_DEVRES=y > # CONFIG_SPL_SIMPLE_BUS is not set > CONFIG_ADC=y > CONFIG_ADC_SANDBOX=y > +CONFIG_AXI=y > +CONFIG_AXI_SANDBOX=y > CONFIG_CLK=y > CONFIG_CPU=y > CONFIG_DM_DEMO=y > diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig > index 4808b498502..35f5ca74065 100644 > --- a/configs/tools-only_defconfig > +++ b/configs/tools-only_defconfig > @@ -11,6 +11,8 @@ CONFIG_OF_HOSTFILE=y > CONFIG_DEFAULT_DEVICE_TREE="sandbox" > CONFIG_IP_DEFRAG=y > # CONFIG_UDP_FUNCTION_FASTBOOT is not set > +CONFIG_AXI=y > +CONFIG_AXI_SANDBOX=y > CONFIG_SANDBOX_GPIO=y > CONFIG_PCI=y > CONFIG_DM_PCI=y > diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c > index 36f4d1c289d..57f619cca3b 100644 > --- a/drivers/core/uclass.c > +++ b/drivers/core/uclass.c > @@ -56,8 +56,8 @@ static int uclass_add(enum uclass_id id, struct uclass > **ucp) > *ucp = NULL; > uc_drv = lists_uclass_lookup(id); > if (!uc_drv) { > - debug("Cannot find uclass for id %d: please add the > UCLASS_DRIVER() declaration for this UCLASS_... id\n", > - id); > + printf("Cannot find uclass for id %d: please add the > UCLASS_DRIVER() declaration for this UCLASS_... id\n", > + id); Looks unrelated to this patch. > /* > * Use a strange error to make this case easier to find. When > * a uclass is not available it can prevent driver model from > diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile > index 840d9fa5e39..363864454bd 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 > > diff --git a/drivers/misc/p2sb_emul.c b/drivers/misc/p2sb_emul.c > new file mode 100644 > index 00000000000..c3795c59c08 > --- /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 <s...@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 00000000000..2337df9951d > --- /dev/null > +++ b/drivers/misc/p2sb_sandbox.c > @@ -0,0 +1,44 @@ > +// 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); > + printf("mmio base %x\n", upriv->mmio_base); > + > + return 0; > +} > + > +static struct p2sb_ops sandbox_p2sb_ops = { > +}; Could this be dropped, since it's an empty struct? > + > +static const struct udevice_id sandbox_p2sb_ids[] = { > + { .compatible = "sandbox,p2sb" }, > + { } > +}; > + > +U_BOOT_DRIVER(p2sb_sandbox) = { > + .name = "pmic_pm8916", The name does not look correct. > + .id = UCLASS_P2SB, > + .of_match = sandbox_p2sb_ids, > + .probe = sandbox_p2sb_probe, > + .ops = &sandbox_p2sb_ops, > + .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 00000000000..df262e62555 > --- /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/test/dm/Makefile b/test/dm/Makefile > index 10a19a00c90..129ccb3b496 100644 > --- a/test/dm/Makefile > +++ b/test/dm/Makefile > @@ -32,6 +32,7 @@ obj-y += ofnode.o > obj-$(CONFIG_OSD) += osd.o > obj-$(CONFIG_DM_VIDEO) += panel.o > obj-$(CONFIG_DM_PCI) += pci.o > +obj-$(CONFIG_P2SB) += p2sb.o > obj-$(CONFIG_PCI_ENDPOINT) += pci_ep.o > obj-$(CONFIG_PCH) += pch.o > obj-$(CONFIG_PHY) += phy.o > diff --git a/test/dm/p2sb.c b/test/dm/p2sb.c > new file mode 100644 > index 00000000000..ccb75cf3753 > --- /dev/null > +++ b/test/dm/p2sb.c > @@ -0,0 +1,28 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Test for Primary-to-Sideband bus (P2SB) > + * > + * Copyright 2019 Google LLC > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <p2sb.h> > +#include <asm/test.h> > +#include <dm/test.h> > +#include <test/ut.h> > + > +/* Base test of the PMC uclass */ > +static int dm_test_p2sb_base(struct unit_test_state *uts) > +{ > + struct udevice *dev; > + > + sandbox_set_enable_memio(true); > + ut_assertok(uclass_get_device_by_name(UCLASS_AXI, "adder", &dev)); > + ut_asserteq(0x03000004, pcr_read32(dev, 4)); > + ut_asserteq(0x300, pcr_read16(dev, 6)); > + ut_asserteq(4, pcr_read8(dev, 4)); > + > + return 0; > +} > +DM_TEST(dm_test_p2sb_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); > -- Regards, Bin _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot