1 // SPDX-License-Identifier: GPL-2.0+
3 * PCI emulation device for an x86 Power-Management Controller (PMC)
5 * Copyright 2019 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
14 #include <power/acpi_pmc.h>
17 * struct pmc_emul_platdata - platform data for this device
19 * @command: Current PCI command value
20 * @bar: Current base address values
22 struct pmc_emul_platdata {
31 static struct pci_bar {
35 { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
39 { PCI_BASE_ADDRESS_SPACE_IO, 256 },
42 struct pmc_emul_priv {
46 static int sandbox_pmc_emul_read_config(const struct udevice *emul, uint offset,
47 ulong *valuep, enum pci_size_t size)
49 struct pmc_emul_platdata *plat = dev_get_plat(emul);
53 *valuep = plat->command;
59 *valuep = SANDBOX_PCI_VENDOR_ID;
62 *valuep = SANDBOX_PCI_PMC_EMUL_ID;
64 case PCI_CLASS_DEVICE:
65 if (size == PCI_SIZE_8) {
66 *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
68 *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
69 SANDBOX_PCI_CLASS_SUB_CODE;
73 *valuep = SANDBOX_PCI_CLASS_CODE;
75 case PCI_BASE_ADDRESS_0:
76 case PCI_BASE_ADDRESS_1:
77 case PCI_BASE_ADDRESS_2:
78 case PCI_BASE_ADDRESS_3:
79 case PCI_BASE_ADDRESS_4:
80 case PCI_BASE_ADDRESS_5: {
84 barnum = pci_offset_to_barnum(offset);
85 bar = &plat->bar[barnum];
87 *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
88 barinfo[barnum].size);
91 case PCI_CAPABILITY_LIST:
92 *valuep = PCI_CAP_ID_PM_OFFSET;
99 static int sandbox_pmc_emul_write_config(struct udevice *emul, uint offset,
100 ulong value, enum pci_size_t size)
102 struct pmc_emul_platdata *plat = dev_get_plat(emul);
106 plat->command = value;
108 case PCI_BASE_ADDRESS_0:
109 case PCI_BASE_ADDRESS_1: {
113 barnum = pci_offset_to_barnum(offset);
114 bar = &plat->bar[barnum];
116 debug("w bar %d=%lx\n", barnum, value);
118 /* space indicator (bit#0) is read-only */
119 *bar |= barinfo[barnum].type;
127 static int sandbox_pmc_emul_find_bar(struct udevice *emul, unsigned int addr,
128 int *barnump, unsigned int *offsetp)
130 struct pmc_emul_platdata *plat = dev_get_plat(emul);
133 for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
134 unsigned int size = barinfo[barnum].size;
135 u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
137 if (addr >= base && addr < base + size) {
139 *offsetp = addr - base;
148 static int sandbox_pmc_emul_read_io(struct udevice *dev, unsigned int addr,
149 ulong *valuep, enum pci_size_t size)
155 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
161 else if (barnum == 0)
167 static int sandbox_pmc_emul_write_io(struct udevice *dev, unsigned int addr,
168 ulong value, enum pci_size_t size)
174 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
181 static int sandbox_pmc_emul_map_physmem(struct udevice *dev,
182 phys_addr_t addr, unsigned long *lenp,
185 struct pmc_emul_priv *priv = dev_get_priv(dev);
186 unsigned int offset, avail;
190 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
195 *ptrp = priv->regs + offset;
196 avail = barinfo[0].size - offset;
197 if (avail > barinfo[0].size)
200 *lenp = min(*lenp, (ulong)avail);
208 static int sandbox_pmc_probe(struct udevice *dev)
210 struct pmc_emul_priv *priv = dev_get_priv(dev);
213 for (i = 0; i < MEMMAP_SIZE; i++)
219 static struct dm_pci_emul_ops sandbox_pmc_emul_emul_ops = {
220 .read_config = sandbox_pmc_emul_read_config,
221 .write_config = sandbox_pmc_emul_write_config,
222 .read_io = sandbox_pmc_emul_read_io,
223 .write_io = sandbox_pmc_emul_write_io,
224 .map_physmem = sandbox_pmc_emul_map_physmem,
227 static const struct udevice_id sandbox_pmc_emul_ids[] = {
228 { .compatible = "sandbox,pmc-emul" },
232 U_BOOT_DRIVER(sandbox_pmc_emul_emul) = {
233 .name = "sandbox_pmc_emul_emul",
234 .id = UCLASS_PCI_EMUL,
235 .of_match = sandbox_pmc_emul_ids,
236 .ops = &sandbox_pmc_emul_emul_ops,
237 .probe = sandbox_pmc_probe,
238 .priv_auto = sizeof(struct pmc_emul_priv),
239 .plat_auto = sizeof(struct pmc_emul_platdata),
242 static struct pci_device_id sandbox_pmc_emul_supported[] = {
243 { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
247 U_BOOT_PCI_DEVICE(sandbox_pmc_emul_emul, sandbox_pmc_emul_supported);