blob: 8015031da85926d6dc8d2bde3aeabdcdd41447b7 [file] [log] [blame]
Simon Glass8c501022019-12-06 21:41:54 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * PCI emulation device for an x86 Power-Management Controller (PMC)
4 *
5 * Copyright 2019 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#include <common.h>
10#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass8c501022019-12-06 21:41:54 -070012#include <pci.h>
13#include <asm/test.h>
14#include <power/acpi_pmc.h>
15
16/**
Simon Glassb75b15b2020-12-03 16:55:23 -070017 * struct pmc_emul_plat - platform data for this device
Simon Glass8c501022019-12-06 21:41:54 -070018 *
19 * @command: Current PCI command value
20 * @bar: Current base address values
21 */
Simon Glassb75b15b2020-12-03 16:55:23 -070022struct pmc_emul_plat {
Simon Glass8c501022019-12-06 21:41:54 -070023 u16 command;
24 u32 bar[6];
25};
26
27enum {
28 MEMMAP_SIZE = 0x80,
29};
30
31static struct pci_bar {
32 int type;
33 u32 size;
34} barinfo[] = {
35 { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
36 { 0, 0 },
37 { 0, 0 },
38 { 0, 0 },
39 { PCI_BASE_ADDRESS_SPACE_IO, 256 },
Andrew Sculla7c9d8b2022-04-03 10:39:10 +000040 { 0, 0 },
Simon Glass8c501022019-12-06 21:41:54 -070041};
42
43struct pmc_emul_priv {
44 u8 regs[MEMMAP_SIZE];
45};
46
Simon Glass2a311e82020-01-27 08:49:37 -070047static int sandbox_pmc_emul_read_config(const struct udevice *emul, uint offset,
Simon Glass8c501022019-12-06 21:41:54 -070048 ulong *valuep, enum pci_size_t size)
49{
Simon Glassb75b15b2020-12-03 16:55:23 -070050 struct pmc_emul_plat *plat = dev_get_plat(emul);
Simon Glass8c501022019-12-06 21:41:54 -070051
52 switch (offset) {
53 case PCI_COMMAND:
54 *valuep = plat->command;
55 break;
56 case PCI_HEADER_TYPE:
57 *valuep = 0;
58 break;
59 case PCI_VENDOR_ID:
60 *valuep = SANDBOX_PCI_VENDOR_ID;
61 break;
62 case PCI_DEVICE_ID:
63 *valuep = SANDBOX_PCI_PMC_EMUL_ID;
64 break;
65 case PCI_CLASS_DEVICE:
66 if (size == PCI_SIZE_8) {
67 *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
68 } else {
69 *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
70 SANDBOX_PCI_CLASS_SUB_CODE;
71 }
72 break;
73 case PCI_CLASS_CODE:
74 *valuep = SANDBOX_PCI_CLASS_CODE;
75 break;
76 case PCI_BASE_ADDRESS_0:
77 case PCI_BASE_ADDRESS_1:
78 case PCI_BASE_ADDRESS_2:
79 case PCI_BASE_ADDRESS_3:
80 case PCI_BASE_ADDRESS_4:
81 case PCI_BASE_ADDRESS_5: {
82 int barnum;
83 u32 *bar;
84
85 barnum = pci_offset_to_barnum(offset);
86 bar = &plat->bar[barnum];
87
88 *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
89 barinfo[barnum].size);
90 break;
91 }
92 case PCI_CAPABILITY_LIST:
93 *valuep = PCI_CAP_ID_PM_OFFSET;
94 break;
95 }
96
97 return 0;
98}
99
100static int sandbox_pmc_emul_write_config(struct udevice *emul, uint offset,
101 ulong value, enum pci_size_t size)
102{
Simon Glassb75b15b2020-12-03 16:55:23 -0700103 struct pmc_emul_plat *plat = dev_get_plat(emul);
Simon Glass8c501022019-12-06 21:41:54 -0700104
105 switch (offset) {
106 case PCI_COMMAND:
107 plat->command = value;
108 break;
109 case PCI_BASE_ADDRESS_0:
110 case PCI_BASE_ADDRESS_1: {
111 int barnum;
112 u32 *bar;
113
114 barnum = pci_offset_to_barnum(offset);
115 bar = &plat->bar[barnum];
116
117 debug("w bar %d=%lx\n", barnum, value);
118 *bar = value;
119 /* space indicator (bit#0) is read-only */
120 *bar |= barinfo[barnum].type;
121 break;
122 }
123 }
124
125 return 0;
126}
127
128static int sandbox_pmc_emul_find_bar(struct udevice *emul, unsigned int addr,
129 int *barnump, unsigned int *offsetp)
130{
Simon Glassb75b15b2020-12-03 16:55:23 -0700131 struct pmc_emul_plat *plat = dev_get_plat(emul);
Simon Glass8c501022019-12-06 21:41:54 -0700132 int barnum;
133
134 for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
135 unsigned int size = barinfo[barnum].size;
136 u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
137
138 if (addr >= base && addr < base + size) {
139 *barnump = barnum;
140 *offsetp = addr - base;
141 return 0;
142 }
143 }
144 *barnump = -1;
145
146 return -ENOENT;
147}
148
149static int sandbox_pmc_emul_read_io(struct udevice *dev, unsigned int addr,
150 ulong *valuep, enum pci_size_t size)
151{
152 unsigned int offset;
153 int barnum;
154 int ret;
155
156 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
157 if (ret)
158 return ret;
159
160 if (barnum == 4)
161 *valuep = offset;
162 else if (barnum == 0)
163 *valuep = offset;
164
165 return 0;
166}
167
168static int sandbox_pmc_emul_write_io(struct udevice *dev, unsigned int addr,
169 ulong value, enum pci_size_t size)
170{
171 unsigned int offset;
172 int barnum;
173 int ret;
174
175 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
176 if (ret)
177 return ret;
178
179 return 0;
180}
181
182static int sandbox_pmc_emul_map_physmem(struct udevice *dev,
183 phys_addr_t addr, unsigned long *lenp,
184 void **ptrp)
185{
186 struct pmc_emul_priv *priv = dev_get_priv(dev);
187 unsigned int offset, avail;
188 int barnum;
189 int ret;
190
191 ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
192 if (ret)
193 return ret;
194
195 if (barnum == 0) {
196 *ptrp = priv->regs + offset;
197 avail = barinfo[0].size - offset;
198 if (avail > barinfo[0].size)
199 *lenp = 0;
200 else
201 *lenp = min(*lenp, (ulong)avail);
202
203 return 0;
204 }
205
206 return -ENOENT;
207}
208
209static int sandbox_pmc_probe(struct udevice *dev)
210{
211 struct pmc_emul_priv *priv = dev_get_priv(dev);
212 int i;
213
214 for (i = 0; i < MEMMAP_SIZE; i++)
215 priv->regs[i] = i;
216
217 return 0;
218}
219
220static struct dm_pci_emul_ops sandbox_pmc_emul_emul_ops = {
221 .read_config = sandbox_pmc_emul_read_config,
222 .write_config = sandbox_pmc_emul_write_config,
223 .read_io = sandbox_pmc_emul_read_io,
224 .write_io = sandbox_pmc_emul_write_io,
225 .map_physmem = sandbox_pmc_emul_map_physmem,
226};
227
228static const struct udevice_id sandbox_pmc_emul_ids[] = {
229 { .compatible = "sandbox,pmc-emul" },
230 { }
231};
232
233U_BOOT_DRIVER(sandbox_pmc_emul_emul) = {
234 .name = "sandbox_pmc_emul_emul",
235 .id = UCLASS_PCI_EMUL,
236 .of_match = sandbox_pmc_emul_ids,
237 .ops = &sandbox_pmc_emul_emul_ops,
238 .probe = sandbox_pmc_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700239 .priv_auto = sizeof(struct pmc_emul_priv),
Simon Glassb75b15b2020-12-03 16:55:23 -0700240 .plat_auto = sizeof(struct pmc_emul_plat),
Simon Glass8c501022019-12-06 21:41:54 -0700241};
242
243static struct pci_device_id sandbox_pmc_emul_supported[] = {
244 { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
245 {},
246};
247
248U_BOOT_PCI_DEVICE(sandbox_pmc_emul_emul, sandbox_pmc_emul_supported);