diff options
Diffstat (limited to 'drivers/misc/swap_case.c')
-rw-r--r-- | drivers/misc/swap_case.c | 102 |
1 files changed, 101 insertions, 1 deletions
diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index fa608cec1b..6afc6d9466 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -61,11 +61,63 @@ static int sandbox_swap_case_get_devfn(struct udevice *dev) return plat->devfn; } +static int sandbox_swap_case_use_ea(struct udevice *dev) +{ + return !!ofnode_get_property(dev->node, "use-ea", NULL); +} + +/* Please keep these macros in sync with ea_regs below */ +#define PCI_CAP_ID_EA_SIZE (sizeof(ea_regs) + 4) +#define PCI_CAP_ID_EA_ENTRY_CNT 4 +/* Hardcoded EA structure, excluding 1st DW. */ +static const u32 ea_regs[] = { + /* BEI=0, ES=2, BAR0 32b Base + 32b MaxOffset, I/O space */ + (2 << 8) | 2, + PCI_CAP_EA_BASE_LO0, + 0, + /* BEI=1, ES=2, BAR1 32b Base + 32b MaxOffset */ + (1 << 4) | 2, + PCI_CAP_EA_BASE_LO1, + MEM_TEXT_SIZE - 1, + /* BEI=2, ES=3, BAR2 64b Base + 32b MaxOffset */ + (2 << 4) | 3, + PCI_CAP_EA_BASE_LO2 | PCI_EA_IS_64, + PCI_CAP_EA_SIZE_LO, + PCI_CAP_EA_BASE_HI2, + /* BEI=4, ES=4, BAR4 64b Base + 64b MaxOffset */ + (4 << 4) | 4, + PCI_CAP_EA_BASE_LO4 | PCI_EA_IS_64, + PCI_CAP_EA_SIZE_LO | PCI_EA_IS_64, + PCI_CAP_EA_BASE_HI4, + PCI_CAP_EA_SIZE_HI, +}; + +static int sandbox_swap_case_read_ea(struct udevice *emul, uint offset, + ulong *valuep, enum pci_size_t size) +{ + u32 reg; + + offset = offset - PCI_CAP_ID_EA_OFFSET - 4; + reg = ea_regs[offset >> 2]; + reg >>= (offset % 4) * 8; + + *valuep = reg; + return 0; +} + static int sandbox_swap_case_read_config(struct udevice *emul, uint offset, ulong *valuep, enum pci_size_t size) { struct swap_case_platdata *plat = dev_get_platdata(emul); + /* + * The content of the EA capability structure is handled elsewhere to + * keep the switch/case below sane + */ + if (offset > PCI_CAP_ID_EA_OFFSET + PCI_CAP_LIST_NEXT && + offset < PCI_CAP_ID_EA_OFFSET + PCI_CAP_ID_EA_SIZE) + return sandbox_swap_case_read_ea(emul, offset, valuep, size); + switch (offset) { case PCI_COMMAND: *valuep = plat->command; @@ -134,9 +186,21 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset, *valuep = PCI_CAP_ID_MSIX_OFFSET; break; case PCI_CAP_ID_MSIX_OFFSET: - *valuep = PCI_CAP_ID_MSIX; + if (sandbox_swap_case_use_ea(emul)) + *valuep = (PCI_CAP_ID_EA_OFFSET << 8) | PCI_CAP_ID_MSIX; + else + *valuep = PCI_CAP_ID_MSIX; break; case PCI_CAP_ID_MSIX_OFFSET + PCI_CAP_LIST_NEXT: + if (sandbox_swap_case_use_ea(emul)) + *valuep = PCI_CAP_ID_EA_OFFSET; + else + *valuep = 0; + break; + case PCI_CAP_ID_EA_OFFSET: + *valuep = (PCI_CAP_ID_EA_ENTRY_CNT << 16) | PCI_CAP_ID_EA; + break; + case PCI_CAP_ID_EA_OFFSET + PCI_CAP_LIST_NEXT: *valuep = 0; break; case PCI_EXT_CAP_ID_ERR_OFFSET: @@ -257,6 +321,9 @@ int sandbox_swap_case_write_io(struct udevice *dev, unsigned int addr, return 0; } +static int pci_ea_bar2_magic = PCI_EA_BAR2_MAGIC; +static int pci_ea_bar4_magic = PCI_EA_BAR4_MAGIC; + static int sandbox_swap_case_map_physmem(struct udevice *dev, phys_addr_t addr, unsigned long *lenp, void **ptrp) { @@ -265,9 +332,42 @@ static int sandbox_swap_case_map_physmem(struct udevice *dev, int barnum; int ret; + if (sandbox_swap_case_use_ea(dev)) { + /* + * only support mapping base address in EA test for now, we + * don't handle mapping an offset inside a BAR. Seems good + * enough for the current test. + */ + switch (addr) { + case (phys_addr_t)PCI_CAP_EA_BASE_LO0: + *ptrp = &priv->op; + *lenp = 4; + break; + case (phys_addr_t)PCI_CAP_EA_BASE_LO1: + *ptrp = priv->mem_text; + *lenp = barinfo[1].size - 1; + break; + case (phys_addr_t)((PCI_CAP_EA_BASE_HI2 << 32) | + PCI_CAP_EA_BASE_LO2): + *ptrp = &pci_ea_bar2_magic; + *lenp = PCI_CAP_EA_SIZE_LO; + break; + case (phys_addr_t)((PCI_CAP_EA_BASE_HI4 << 32) | + PCI_CAP_EA_BASE_LO4): + *ptrp = &pci_ea_bar4_magic; + *lenp = (PCI_CAP_EA_SIZE_HI << 32) | + PCI_CAP_EA_SIZE_LO; + break; + default: + return -ENOENT; + } + return 0; + } + ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset); if (ret) return ret; + if (barnum == 1) { *ptrp = priv->mem_text + offset; avail = barinfo[1].size - offset; |