xref: /openbmc/qemu/hw/misc/grlib_ahb_apb_pnp.c (revision b15c0f7d)
1 /*
2  * GRLIB AHB APB PNP
3  *
4  *  Copyright (C) 2019 AdaCore
5  *
6  *  Developed by :
7  *  Frederic Konrad   <frederic.konrad@adacore.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23 
24 #include "qemu/osdep.h"
25 #include "hw/sysbus.h"
26 #include "hw/misc/grlib_ahb_apb_pnp.h"
27 
28 #define GRLIB_PNP_VENDOR_SHIFT (24)
29 #define GRLIB_PNP_VENDOR_SIZE   (8)
30 #define GRLIB_PNP_DEV_SHIFT    (12)
31 #define GRLIB_PNP_DEV_SIZE     (12)
32 #define GRLIB_PNP_VER_SHIFT     (5)
33 #define GRLIB_PNP_VER_SIZE      (5)
34 #define GRLIB_PNP_IRQ_SHIFT     (0)
35 #define GRLIB_PNP_IRQ_SIZE      (5)
36 #define GRLIB_PNP_ADDR_SHIFT   (20)
37 #define GRLIB_PNP_ADDR_SIZE    (12)
38 #define GRLIB_PNP_MASK_SHIFT    (4)
39 #define GRLIB_PNP_MASK_SIZE    (12)
40 
41 #define GRLIB_AHB_DEV_ADDR_SHIFT   (20)
42 #define GRLIB_AHB_DEV_ADDR_SIZE    (12)
43 #define GRLIB_AHB_ENTRY_SIZE       (0x20)
44 #define GRLIB_AHB_MAX_DEV          (64)
45 #define GRLIB_AHB_SLAVE_OFFSET     (0x800)
46 
47 #define GRLIB_APB_DEV_ADDR_SHIFT   (8)
48 #define GRLIB_APB_DEV_ADDR_SIZE    (12)
49 #define GRLIB_APB_ENTRY_SIZE       (0x08)
50 #define GRLIB_APB_MAX_DEV          (512)
51 
52 #define GRLIB_PNP_MAX_REGS         (0x1000)
53 
54 typedef struct AHBPnp {
55     SysBusDevice parent_obj;
56     MemoryRegion iomem;
57 
58     uint32_t regs[GRLIB_PNP_MAX_REGS >> 2];
59     uint8_t master_count;
60     uint8_t slave_count;
61 } AHBPnp;
62 
63 void grlib_ahb_pnp_add_entry(AHBPnp *dev, uint32_t address, uint32_t mask,
64                              uint8_t vendor, uint16_t device, int slave,
65                              int type)
66 {
67     unsigned int reg_start;
68 
69     /*
70      * AHB entries look like this:
71      *
72      * 31 -------- 23 -------- 11 ----- 9 -------- 4 --- 0
73      *  | VENDOR ID | DEVICE ID | IRQ ? | VERSION  | IRQ |
74      *  --------------------------------------------------
75      *  |                      USER                      |
76      *  --------------------------------------------------
77      *  |                      USER                      |
78      *  --------------------------------------------------
79      *  |                      USER                      |
80      *  --------------------------------------------------
81      *  |                      USER                      |
82      *  --------------------------------------------------
83      * 31 ----------- 20 --- 15 ----------------- 3 ---- 0
84      *  | ADDR[31..12] | 00PC |        MASK       | TYPE |
85      *  --------------------------------------------------
86      * 31 ----------- 20 --- 15 ----------------- 3 ---- 0
87      *  | ADDR[31..12] | 00PC |        MASK       | TYPE |
88      *  --------------------------------------------------
89      * 31 ----------- 20 --- 15 ----------------- 3 ---- 0
90      *  | ADDR[31..12] | 00PC |        MASK       | TYPE |
91      *  --------------------------------------------------
92      * 31 ----------- 20 --- 15 ----------------- 3 ---- 0
93      *  | ADDR[31..12] | 00PC |        MASK       | TYPE |
94      *  --------------------------------------------------
95      */
96 
97     if (slave) {
98         assert(dev->slave_count < GRLIB_AHB_MAX_DEV);
99         reg_start = (GRLIB_AHB_SLAVE_OFFSET
100                   + (dev->slave_count * GRLIB_AHB_ENTRY_SIZE)) >> 2;
101         dev->slave_count++;
102     } else {
103         assert(dev->master_count < GRLIB_AHB_MAX_DEV);
104         reg_start = (dev->master_count * GRLIB_AHB_ENTRY_SIZE) >> 2;
105         dev->master_count++;
106     }
107 
108     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
109                                      GRLIB_PNP_VENDOR_SHIFT,
110                                      GRLIB_PNP_VENDOR_SIZE,
111                                      vendor);
112     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
113                                      GRLIB_PNP_DEV_SHIFT,
114                                      GRLIB_PNP_DEV_SIZE,
115                                      device);
116     reg_start += 4;
117     /* AHB Memory Space */
118     dev->regs[reg_start] = type;
119     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
120                                      GRLIB_PNP_ADDR_SHIFT,
121                                      GRLIB_PNP_ADDR_SIZE,
122                                      extract32(address,
123                                                GRLIB_AHB_DEV_ADDR_SHIFT,
124                                                GRLIB_AHB_DEV_ADDR_SIZE));
125     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
126                                      GRLIB_PNP_MASK_SHIFT,
127                                      GRLIB_PNP_MASK_SIZE,
128                                      mask);
129 }
130 
131 static uint64_t grlib_ahb_pnp_read(void *opaque, hwaddr offset, unsigned size)
132 {
133     AHBPnp *ahb_pnp = GRLIB_AHB_PNP(opaque);
134 
135     return ahb_pnp->regs[offset >> 2];
136 }
137 
138 static const MemoryRegionOps grlib_ahb_pnp_ops = {
139     .read       = grlib_ahb_pnp_read,
140     .endianness = DEVICE_BIG_ENDIAN,
141 };
142 
143 static void grlib_ahb_pnp_realize(DeviceState *dev, Error **errp)
144 {
145     AHBPnp *ahb_pnp = GRLIB_AHB_PNP(dev);
146     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
147 
148     memory_region_init_io(&ahb_pnp->iomem, OBJECT(dev), &grlib_ahb_pnp_ops,
149                           ahb_pnp, TYPE_GRLIB_AHB_PNP, GRLIB_PNP_MAX_REGS);
150     sysbus_init_mmio(sbd, &ahb_pnp->iomem);
151 }
152 
153 static void grlib_ahb_pnp_class_init(ObjectClass *klass, void *data)
154 {
155     DeviceClass *dc = DEVICE_CLASS(klass);
156 
157     dc->realize = grlib_ahb_pnp_realize;
158 }
159 
160 static const TypeInfo grlib_ahb_pnp_info = {
161     .name          = TYPE_GRLIB_AHB_PNP,
162     .parent        = TYPE_SYS_BUS_DEVICE,
163     .instance_size = sizeof(AHBPnp),
164     .class_init    = grlib_ahb_pnp_class_init,
165 };
166 
167 /* APBPnp */
168 
169 typedef struct APBPnp {
170     SysBusDevice parent_obj;
171     MemoryRegion iomem;
172 
173     uint32_t regs[GRLIB_PNP_MAX_REGS >> 2];
174     uint32_t entry_count;
175 } APBPnp;
176 
177 void grlib_apb_pnp_add_entry(APBPnp *dev, uint32_t address, uint32_t mask,
178                              uint8_t vendor, uint16_t device, uint8_t version,
179                              uint8_t irq, int type)
180 {
181     unsigned int reg_start;
182 
183     /*
184      * APB entries look like this:
185      *
186      * 31 -------- 23 -------- 11 ----- 9 ------- 4 --- 0
187      *  | VENDOR ID | DEVICE ID | IRQ ? | VERSION | IRQ |
188      *
189      * 31 ---------- 20 --- 15 ----------------- 3 ---- 0
190      *  | ADDR[20..8] | 0000 |        MASK       | TYPE |
191      */
192 
193     assert(dev->entry_count < GRLIB_APB_MAX_DEV);
194     reg_start = (dev->entry_count * GRLIB_APB_ENTRY_SIZE) >> 2;
195     dev->entry_count++;
196 
197     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
198                                      GRLIB_PNP_VENDOR_SHIFT,
199                                      GRLIB_PNP_VENDOR_SIZE,
200                                      vendor);
201     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
202                                      GRLIB_PNP_DEV_SHIFT,
203                                      GRLIB_PNP_DEV_SIZE,
204                                      device);
205     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
206                                      GRLIB_PNP_VER_SHIFT,
207                                      GRLIB_PNP_VER_SIZE,
208                                      version);
209     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
210                                      GRLIB_PNP_IRQ_SHIFT,
211                                      GRLIB_PNP_IRQ_SIZE,
212                                      irq);
213     reg_start += 1;
214     dev->regs[reg_start] = type;
215     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
216                                      GRLIB_PNP_ADDR_SHIFT,
217                                      GRLIB_PNP_ADDR_SIZE,
218                                      extract32(address,
219                                                GRLIB_APB_DEV_ADDR_SHIFT,
220                                                GRLIB_APB_DEV_ADDR_SIZE));
221     dev->regs[reg_start] = deposit32(dev->regs[reg_start],
222                                      GRLIB_PNP_MASK_SHIFT,
223                                      GRLIB_PNP_MASK_SIZE,
224                                      mask);
225 }
226 
227 static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size)
228 {
229     APBPnp *apb_pnp = GRLIB_APB_PNP(opaque);
230 
231     return apb_pnp->regs[offset >> 2];
232 }
233 
234 static const MemoryRegionOps grlib_apb_pnp_ops = {
235     .read       = grlib_apb_pnp_read,
236     .endianness = DEVICE_BIG_ENDIAN,
237 };
238 
239 static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp)
240 {
241     APBPnp *apb_pnp = GRLIB_APB_PNP(dev);
242     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
243 
244     memory_region_init_io(&apb_pnp->iomem, OBJECT(dev), &grlib_apb_pnp_ops,
245                           apb_pnp, TYPE_GRLIB_APB_PNP, GRLIB_PNP_MAX_REGS);
246     sysbus_init_mmio(sbd, &apb_pnp->iomem);
247 }
248 
249 static void grlib_apb_pnp_class_init(ObjectClass *klass, void *data)
250 {
251     DeviceClass *dc = DEVICE_CLASS(klass);
252 
253     dc->realize = grlib_apb_pnp_realize;
254 }
255 
256 static const TypeInfo grlib_apb_pnp_info = {
257     .name          = TYPE_GRLIB_APB_PNP,
258     .parent        = TYPE_SYS_BUS_DEVICE,
259     .instance_size = sizeof(APBPnp),
260     .class_init    = grlib_apb_pnp_class_init,
261 };
262 
263 static void grlib_ahb_apb_pnp_register_types(void)
264 {
265     type_register_static(&grlib_ahb_pnp_info);
266     type_register_static(&grlib_apb_pnp_info);
267 }
268 
269 type_init(grlib_ahb_apb_pnp_register_types)
270