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>
13 #include <power/acpi_pmc.h>
16 * struct pmc_emul_platdata - platform data for this device
18 * @command: Current PCI command value
19 * @bar: Current base address values
21 struct pmc_emul_platdata {
30 static struct pci_bar {
34 { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
38 { PCI_BASE_ADDRESS_SPACE_IO, 256 },
41 struct pmc_emul_priv {
45 static int sandbox_pmc_emul_read_config(struct udevice *emul, uint offset,
46 ulong *valuep, enum pci_size_t size)
48 struct pmc_emul_platdata *plat = dev_get_platdata(emul);
52 *valuep = plat->command;
58 *valuep = SANDBOX_PCI_VENDOR_ID;
61 *valuep = SANDBOX_PCI_PMC_EMUL_ID;
63 case PCI_CLASS_DEVICE:
64 if (size == PCI_SIZE_8) {
65 *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
67 *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
68 SANDBOX_PCI_CLASS_SUB_CODE;
72 *valuep = SANDBOX_PCI_CLASS_CODE;
74 case PCI_BASE_ADDRESS_0:
75 case PCI_BASE_ADDRESS_1:
76 case PCI_BASE_ADDRESS_2:
77 case PCI_BASE_ADDRESS_3:
78 case PCI_BASE_ADDRESS_4:
79 case PCI_BASE_ADDRESS_5: {
83 barnum = pci_offset_to_barnum(offset);
84 bar = &plat->bar[barnum];
86 *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
87 barinfo[barnum].size);
90 case PCI_CAPABILITY_LIST:
91 *valuep = PCI_CAP_ID_PM_OFFSET;
98 static int sandbox_pmc_emul_write_config(struct udevice *emul, uint offset,
99 ulong value, enum pci_size_t size)
101 struct pmc_emul_platdata *plat = dev_get_platdata(emul);
105 plat->command = value;
107 case PCI_BASE_ADDRESS_0:
108 case PCI_BASE_ADDRESS_1: {
112 barnum = pci_offset_to_barnum(offset);
113 bar = &plat->bar[barnum];
115 debug("w bar %d=%lx\n", barnum, value);
117 /* space indicator (bit#0) is read-only */
118 *bar |= barinfo[barnum].type;
126 static int sandbox_pmc_emul_find_bar(struct udevice *emul, unsigned int addr,
127 int *barnump, unsigned int *offsetp)
129 struct pmc_emul_platdata *plat = dev_get_platdata(emul);
132 for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
133 unsigned int size = barinfo[barnum].size;
134 u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
136 if (addr >= base && addr < base + size) {
138 *offsetp = addr - base;
147 static int sandbox_pmc_emul_read_io(struct udevice *dev, unsigned int addr,
148 ulong *valuep, enum pci_size_t size)
154 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
160 else if (barnum == 0)
166 static int sandbox_pmc_emul_write_io(struct udevice *dev, unsigned int addr,
167 ulong value, enum pci_size_t size)
173 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
180 static int sandbox_pmc_emul_map_physmem(struct udevice *dev,
181 phys_addr_t addr, unsigned long *lenp,
184 struct pmc_emul_priv *priv = dev_get_priv(dev);
185 unsigned int offset, avail;
189 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
194 *ptrp = priv->regs + offset;
195 avail = barinfo[0].size - offset;
196 if (avail > barinfo[0].size)
199 *lenp = min(*lenp, (ulong)avail);
207 static int sandbox_pmc_probe(struct udevice *dev)
209 struct pmc_emul_priv *priv = dev_get_priv(dev);
212 for (i = 0; i < MEMMAP_SIZE; i++)
218 static struct dm_pci_emul_ops sandbox_pmc_emul_emul_ops = {
219 .read_config = sandbox_pmc_emul_read_config,
220 .write_config = sandbox_pmc_emul_write_config,
221 .read_io = sandbox_pmc_emul_read_io,
222 .write_io = sandbox_pmc_emul_write_io,
223 .map_physmem = sandbox_pmc_emul_map_physmem,
226 static const struct udevice_id sandbox_pmc_emul_ids[] = {
227 { .compatible = "sandbox,pmc-emul" },
231 U_BOOT_DRIVER(sandbox_pmc_emul_emul) = {
232 .name = "sandbox_pmc_emul_emul",
233 .id = UCLASS_PCI_EMUL,
234 .of_match = sandbox_pmc_emul_ids,
235 .ops = &sandbox_pmc_emul_emul_ops,
236 .probe = sandbox_pmc_probe,
237 .priv_auto_alloc_size = sizeof(struct pmc_emul_priv),
238 .platdata_auto_alloc_size = sizeof(struct pmc_emul_platdata),
241 static struct pci_device_id sandbox_pmc_emul_supported[] = {
242 { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
246 U_BOOT_PCI_DEVICE(sandbox_pmc_emul_emul, sandbox_pmc_emul_supported);