dm: pci: Update the PCI read_config() method to const dev *
[oweals/u-boot.git] / drivers / power / acpi_pmc / pmc_emul.c
1 // 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>
11 #include <pci.h>
12 #include <asm/test.h>
13 #include <power/acpi_pmc.h>
14
15 /**
16  * struct pmc_emul_platdata - platform data for this device
17  *
18  * @command:    Current PCI command value
19  * @bar:        Current base address values
20  */
21 struct pmc_emul_platdata {
22         u16 command;
23         u32 bar[6];
24 };
25
26 enum {
27         MEMMAP_SIZE     = 0x80,
28 };
29
30 static struct pci_bar {
31         int type;
32         u32 size;
33 } barinfo[] = {
34         { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
35         { 0, 0 },
36         { 0, 0 },
37         { 0, 0 },
38         { PCI_BASE_ADDRESS_SPACE_IO, 256 },
39 };
40
41 struct pmc_emul_priv {
42         u8 regs[MEMMAP_SIZE];
43 };
44
45 static int sandbox_pmc_emul_read_config(const struct udevice *emul, uint offset,
46                                         ulong *valuep, enum pci_size_t size)
47 {
48         struct pmc_emul_platdata *plat = dev_get_platdata(emul);
49
50         switch (offset) {
51         case PCI_COMMAND:
52                 *valuep = plat->command;
53                 break;
54         case PCI_HEADER_TYPE:
55                 *valuep = 0;
56                 break;
57         case PCI_VENDOR_ID:
58                 *valuep = SANDBOX_PCI_VENDOR_ID;
59                 break;
60         case PCI_DEVICE_ID:
61                 *valuep = SANDBOX_PCI_PMC_EMUL_ID;
62                 break;
63         case PCI_CLASS_DEVICE:
64                 if (size == PCI_SIZE_8) {
65                         *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
66                 } else {
67                         *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
68                                         SANDBOX_PCI_CLASS_SUB_CODE;
69                 }
70                 break;
71         case PCI_CLASS_CODE:
72                 *valuep = SANDBOX_PCI_CLASS_CODE;
73                 break;
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: {
80                 int barnum;
81                 u32 *bar;
82
83                 barnum = pci_offset_to_barnum(offset);
84                 bar = &plat->bar[barnum];
85
86                 *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
87                                                barinfo[barnum].size);
88                 break;
89         }
90         case PCI_CAPABILITY_LIST:
91                 *valuep = PCI_CAP_ID_PM_OFFSET;
92                 break;
93         }
94
95         return 0;
96 }
97
98 static int sandbox_pmc_emul_write_config(struct udevice *emul, uint offset,
99                                          ulong value, enum pci_size_t size)
100 {
101         struct pmc_emul_platdata *plat = dev_get_platdata(emul);
102
103         switch (offset) {
104         case PCI_COMMAND:
105                 plat->command = value;
106                 break;
107         case PCI_BASE_ADDRESS_0:
108         case PCI_BASE_ADDRESS_1: {
109                 int barnum;
110                 u32 *bar;
111
112                 barnum = pci_offset_to_barnum(offset);
113                 bar = &plat->bar[barnum];
114
115                 debug("w bar %d=%lx\n", barnum, value);
116                 *bar = value;
117                 /* space indicator (bit#0) is read-only */
118                 *bar |= barinfo[barnum].type;
119                 break;
120         }
121         }
122
123         return 0;
124 }
125
126 static int sandbox_pmc_emul_find_bar(struct udevice *emul, unsigned int addr,
127                                      int *barnump, unsigned int *offsetp)
128 {
129         struct pmc_emul_platdata *plat = dev_get_platdata(emul);
130         int barnum;
131
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;
135
136                 if (addr >= base && addr < base + size) {
137                         *barnump = barnum;
138                         *offsetp = addr - base;
139                         return 0;
140                 }
141         }
142         *barnump = -1;
143
144         return -ENOENT;
145 }
146
147 static int sandbox_pmc_emul_read_io(struct udevice *dev, unsigned int addr,
148                                     ulong *valuep, enum pci_size_t size)
149 {
150         unsigned int offset;
151         int barnum;
152         int ret;
153
154         ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
155         if (ret)
156                 return ret;
157
158         if (barnum == 4)
159                 *valuep = offset;
160         else if (barnum == 0)
161                 *valuep = offset;
162
163         return 0;
164 }
165
166 static int sandbox_pmc_emul_write_io(struct udevice *dev, unsigned int addr,
167                                      ulong value, enum pci_size_t size)
168 {
169         unsigned int offset;
170         int barnum;
171         int ret;
172
173         ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
174         if (ret)
175                 return ret;
176
177         return 0;
178 }
179
180 static int sandbox_pmc_emul_map_physmem(struct udevice *dev,
181                                         phys_addr_t addr, unsigned long *lenp,
182                                         void **ptrp)
183 {
184         struct pmc_emul_priv *priv = dev_get_priv(dev);
185         unsigned int offset, avail;
186         int barnum;
187         int ret;
188
189         ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset);
190         if (ret)
191                 return ret;
192
193         if (barnum == 0) {
194                 *ptrp = priv->regs + offset;
195                 avail = barinfo[0].size - offset;
196                 if (avail > barinfo[0].size)
197                         *lenp = 0;
198                 else
199                         *lenp = min(*lenp, (ulong)avail);
200
201                 return 0;
202         }
203
204         return -ENOENT;
205 }
206
207 static int sandbox_pmc_probe(struct udevice *dev)
208 {
209         struct pmc_emul_priv *priv = dev_get_priv(dev);
210         int i;
211
212         for (i = 0; i < MEMMAP_SIZE; i++)
213                 priv->regs[i] = i;
214
215         return 0;
216 }
217
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,
224 };
225
226 static const struct udevice_id sandbox_pmc_emul_ids[] = {
227         { .compatible = "sandbox,pmc-emul" },
228         { }
229 };
230
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),
239 };
240
241 static struct pci_device_id sandbox_pmc_emul_supported[] = {
242         { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
243         {},
244 };
245
246 U_BOOT_PCI_DEVICE(sandbox_pmc_emul_emul, sandbox_pmc_emul_supported);