pwm: Add driver for Amlogic Meson PWM controller
[platform/kernel/u-boot.git] / drivers / misc / p2sb_emul.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * PCI emulation device for an x86 Primary-to-Sideband bus
4  *
5  * Copyright 2019 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8
9 #define LOG_CATEGORY UCLASS_MISC
10 #define LOG_DEBUG
11
12 #include <common.h>
13 #include <axi.h>
14 #include <dm.h>
15 #include <log.h>
16 #include <pci.h>
17 #include <asm/test.h>
18 #include <p2sb.h>
19
20 /**
21  * struct p2sb_emul_platdata - platform data for this device
22  *
23  * @command:    Current PCI command value
24  * @bar:        Current base address values
25  */
26 struct p2sb_emul_platdata {
27         u16 command;
28         u32 bar[6];
29 };
30
31 enum {
32         /* This emulator supports 16 different devices */
33         MEMMAP_SIZE     = 16 << PCR_PORTID_SHIFT,
34 };
35
36 static struct pci_bar {
37         int type;
38         u32 size;
39 } barinfo[] = {
40         { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE },
41         { 0, 0 },
42         { 0, 0 },
43         { 0, 0 },
44         { 0, 0 },
45         { 0, 0 },
46 };
47
48 struct p2sb_emul_priv {
49         u8 regs[16];
50 };
51
52 static int sandbox_p2sb_emul_read_config(const struct udevice *emul,
53                                          uint offset, ulong *valuep,
54                                          enum pci_size_t size)
55 {
56         struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
57
58         switch (offset) {
59         case PCI_COMMAND:
60                 *valuep = plat->command;
61                 break;
62         case PCI_HEADER_TYPE:
63                 *valuep = PCI_HEADER_TYPE_NORMAL;
64                 break;
65         case PCI_VENDOR_ID:
66                 *valuep = SANDBOX_PCI_VENDOR_ID;
67                 break;
68         case PCI_DEVICE_ID:
69                 *valuep = SANDBOX_PCI_P2SB_EMUL_ID;
70                 break;
71         case PCI_CLASS_DEVICE:
72                 if (size == PCI_SIZE_8) {
73                         *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
74                 } else {
75                         *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
76                                         SANDBOX_PCI_CLASS_SUB_CODE;
77                 }
78                 break;
79         case PCI_CLASS_CODE:
80                 *valuep = SANDBOX_PCI_CLASS_CODE;
81                 break;
82         case PCI_BASE_ADDRESS_0:
83         case PCI_BASE_ADDRESS_1:
84         case PCI_BASE_ADDRESS_2:
85         case PCI_BASE_ADDRESS_3:
86         case PCI_BASE_ADDRESS_4:
87         case PCI_BASE_ADDRESS_5: {
88                 int barnum;
89                 u32 *bar;
90
91                 barnum = pci_offset_to_barnum(offset);
92                 bar = &plat->bar[barnum];
93
94                 *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
95                                                barinfo[barnum].size);
96                 break;
97         }
98         case PCI_CAPABILITY_LIST:
99                 *valuep = PCI_CAP_ID_PM_OFFSET;
100                 break;
101         }
102
103         return 0;
104 }
105
106 static int sandbox_p2sb_emul_write_config(struct udevice *emul, uint offset,
107                                           ulong value, enum pci_size_t size)
108 {
109         struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
110
111         switch (offset) {
112         case PCI_COMMAND:
113                 plat->command = value;
114                 break;
115         case PCI_BASE_ADDRESS_0:
116         case PCI_BASE_ADDRESS_1: {
117                 int barnum;
118                 u32 *bar;
119
120                 barnum = pci_offset_to_barnum(offset);
121                 bar = &plat->bar[barnum];
122
123                 log_debug("w bar %d=%lx\n", barnum, value);
124                 *bar = value;
125                 /* space indicator (bit#0) is read-only */
126                 *bar |= barinfo[barnum].type;
127                 break;
128         }
129         }
130
131         return 0;
132 }
133
134 static int sandbox_p2sb_emul_find_bar(struct udevice *emul, unsigned int addr,
135                                       int *barnump, unsigned int *offsetp)
136 {
137         struct p2sb_emul_platdata *plat = dev_get_platdata(emul);
138         int barnum;
139
140         for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
141                 unsigned int size = barinfo[barnum].size;
142                 u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE;
143
144                 if (addr >= base && addr < base + size) {
145                         *barnump = barnum;
146                         *offsetp = addr - base;
147                         return 0;
148                 }
149         }
150         *barnump = -1;
151
152         return -ENOENT;
153 }
154
155 static int sandbox_p2sb_emul_read_io(struct udevice *dev, unsigned int addr,
156                                      ulong *valuep, enum pci_size_t size)
157 {
158         unsigned int offset;
159         int barnum;
160         int ret;
161
162         ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
163         if (ret)
164                 return ret;
165
166         if (barnum == 4)
167                 *valuep = offset;
168         else if (barnum == 0)
169                 *valuep = offset;
170
171         return 0;
172 }
173
174 static int sandbox_p2sb_emul_write_io(struct udevice *dev, unsigned int addr,
175                                       ulong value, enum pci_size_t size)
176 {
177         unsigned int offset;
178         int barnum;
179         int ret;
180
181         ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
182         if (ret)
183                 return ret;
184
185         return 0;
186 }
187
188 static int find_p2sb_channel(struct udevice *emul, uint offset,
189                              struct udevice **devp)
190 {
191         uint pid = offset >> PCR_PORTID_SHIFT;
192         struct udevice *p2sb, *dev;
193         int ret;
194
195         ret = sandbox_pci_get_client(emul, &p2sb);
196         if (ret)
197                 return log_msg_ret("No client", ret);
198
199         device_foreach_child(dev, p2sb) {
200                 struct p2sb_child_platdata *pplat =
201                          dev_get_parent_platdata(dev);
202
203                 log_debug("   - child %s, pid %d, want %d\n", dev->name,
204                           pplat->pid, pid);
205                 if (pid == pplat->pid) {
206                         *devp = dev;
207                         return 0;
208                 }
209         }
210
211         return -ENOENT;
212 }
213
214 static int sandbox_p2sb_emul_map_physmem(struct udevice *dev,
215                                          phys_addr_t addr, unsigned long *lenp,
216                                          void **ptrp)
217 {
218         struct p2sb_emul_priv *priv = dev_get_priv(dev);
219         struct udevice *child = NULL;  /* Silence compiler warning */
220         unsigned int offset;
221         int barnum;
222         int ret;
223
224         log_debug("map %x: ", (uint)addr);
225         ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset);
226         if (ret)
227                 return log_msg_ret("Cannot find bar", ret);
228         log_debug("bar %d, offset %x\n", barnum, offset);
229
230         if (barnum != 0)
231                 return log_msg_ret("Unknown BAR", -EINVAL);
232
233         ret = find_p2sb_channel(dev, offset, &child);
234         if (ret)
235                 return log_msg_ret("Cannot find channel", ret);
236
237         offset &= ((1 << PCR_PORTID_SHIFT) - 1);
238         ret = axi_read(child, offset, priv->regs, AXI_SIZE_32);
239         if (ret)
240                 return log_msg_ret("Child read failed", ret);
241         *ptrp = priv->regs + (offset & 3);
242         *lenp = 4;
243
244         return 0;
245 }
246
247 static struct dm_pci_emul_ops sandbox_p2sb_emul_emul_ops = {
248         .read_config = sandbox_p2sb_emul_read_config,
249         .write_config = sandbox_p2sb_emul_write_config,
250         .read_io = sandbox_p2sb_emul_read_io,
251         .write_io = sandbox_p2sb_emul_write_io,
252         .map_physmem = sandbox_p2sb_emul_map_physmem,
253 };
254
255 static const struct udevice_id sandbox_p2sb_emul_ids[] = {
256         { .compatible = "sandbox,p2sb-emul" },
257         { }
258 };
259
260 U_BOOT_DRIVER(sandbox_p2sb_emul_emul) = {
261         .name           = "sandbox_p2sb_emul_emul",
262         .id             = UCLASS_PCI_EMUL,
263         .of_match       = sandbox_p2sb_emul_ids,
264         .ops            = &sandbox_p2sb_emul_emul_ops,
265         .priv_auto_alloc_size = sizeof(struct p2sb_emul_priv),
266         .platdata_auto_alloc_size = sizeof(struct p2sb_emul_platdata),
267 };
268
269 static struct pci_device_id sandbox_p2sb_emul_supported[] = {
270         { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) },
271         {},
272 };
273
274 U_BOOT_PCI_DEVICE(sandbox_p2sb_emul_emul, sandbox_p2sb_emul_supported);