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 "qemu/log.h" 26 #include "hw/sysbus.h" 27 #include "hw/misc/grlib_ahb_apb_pnp.h" 28 #include "trace.h" 29 30 #define GRLIB_PNP_VENDOR_SHIFT (24) 31 #define GRLIB_PNP_VENDOR_SIZE (8) 32 #define GRLIB_PNP_DEV_SHIFT (12) 33 #define GRLIB_PNP_DEV_SIZE (12) 34 #define GRLIB_PNP_VER_SHIFT (5) 35 #define GRLIB_PNP_VER_SIZE (5) 36 #define GRLIB_PNP_IRQ_SHIFT (0) 37 #define GRLIB_PNP_IRQ_SIZE (5) 38 #define GRLIB_PNP_ADDR_SHIFT (20) 39 #define GRLIB_PNP_ADDR_SIZE (12) 40 #define GRLIB_PNP_MASK_SHIFT (4) 41 #define GRLIB_PNP_MASK_SIZE (12) 42 43 #define GRLIB_AHB_DEV_ADDR_SHIFT (20) 44 #define GRLIB_AHB_DEV_ADDR_SIZE (12) 45 #define GRLIB_AHB_ENTRY_SIZE (0x20) 46 #define GRLIB_AHB_MAX_DEV (64) 47 #define GRLIB_AHB_SLAVE_OFFSET (0x800) 48 49 #define GRLIB_APB_DEV_ADDR_SHIFT (8) 50 #define GRLIB_APB_DEV_ADDR_SIZE (12) 51 #define GRLIB_APB_ENTRY_SIZE (0x08) 52 #define GRLIB_APB_MAX_DEV (512) 53 54 #define GRLIB_PNP_MAX_REGS (0x1000) 55 56 typedef struct AHBPnp { 57 SysBusDevice parent_obj; 58 MemoryRegion iomem; 59 60 uint32_t regs[GRLIB_PNP_MAX_REGS >> 2]; 61 uint8_t master_count; 62 uint8_t slave_count; 63 } AHBPnp; 64 65 void grlib_ahb_pnp_add_entry(AHBPnp *dev, uint32_t address, uint32_t mask, 66 uint8_t vendor, uint16_t device, int slave, 67 int type) 68 { 69 unsigned int reg_start; 70 71 /* 72 * AHB entries look like this: 73 * 74 * 31 -------- 23 -------- 11 ----- 9 -------- 4 --- 0 75 * | VENDOR ID | DEVICE ID | IRQ ? | VERSION | IRQ | 76 * -------------------------------------------------- 77 * | USER | 78 * -------------------------------------------------- 79 * | USER | 80 * -------------------------------------------------- 81 * | USER | 82 * -------------------------------------------------- 83 * | USER | 84 * -------------------------------------------------- 85 * 31 ----------- 20 --- 15 ----------------- 3 ---- 0 86 * | ADDR[31..12] | 00PC | MASK | TYPE | 87 * -------------------------------------------------- 88 * 31 ----------- 20 --- 15 ----------------- 3 ---- 0 89 * | ADDR[31..12] | 00PC | MASK | TYPE | 90 * -------------------------------------------------- 91 * 31 ----------- 20 --- 15 ----------------- 3 ---- 0 92 * | ADDR[31..12] | 00PC | MASK | TYPE | 93 * -------------------------------------------------- 94 * 31 ----------- 20 --- 15 ----------------- 3 ---- 0 95 * | ADDR[31..12] | 00PC | MASK | TYPE | 96 * -------------------------------------------------- 97 */ 98 99 if (slave) { 100 assert(dev->slave_count < GRLIB_AHB_MAX_DEV); 101 reg_start = (GRLIB_AHB_SLAVE_OFFSET 102 + (dev->slave_count * GRLIB_AHB_ENTRY_SIZE)) >> 2; 103 dev->slave_count++; 104 } else { 105 assert(dev->master_count < GRLIB_AHB_MAX_DEV); 106 reg_start = (dev->master_count * GRLIB_AHB_ENTRY_SIZE) >> 2; 107 dev->master_count++; 108 } 109 110 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 111 GRLIB_PNP_VENDOR_SHIFT, 112 GRLIB_PNP_VENDOR_SIZE, 113 vendor); 114 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 115 GRLIB_PNP_DEV_SHIFT, 116 GRLIB_PNP_DEV_SIZE, 117 device); 118 reg_start += 4; 119 /* AHB Memory Space */ 120 dev->regs[reg_start] = type; 121 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 122 GRLIB_PNP_ADDR_SHIFT, 123 GRLIB_PNP_ADDR_SIZE, 124 extract32(address, 125 GRLIB_AHB_DEV_ADDR_SHIFT, 126 GRLIB_AHB_DEV_ADDR_SIZE)); 127 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 128 GRLIB_PNP_MASK_SHIFT, 129 GRLIB_PNP_MASK_SIZE, 130 mask); 131 } 132 133 static uint64_t grlib_ahb_pnp_read(void *opaque, hwaddr offset, unsigned size) 134 { 135 AHBPnp *ahb_pnp = GRLIB_AHB_PNP(opaque); 136 uint32_t val; 137 138 val = ahb_pnp->regs[offset >> 2]; 139 val = extract32(val, (4 - (offset & 3) - size) * 8, size * 8); 140 trace_grlib_ahb_pnp_read(offset, size, val); 141 142 return val; 143 } 144 145 static void grlib_ahb_pnp_write(void *opaque, hwaddr addr, 146 uint64_t val, unsigned size) 147 { 148 qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); 149 } 150 151 static const MemoryRegionOps grlib_ahb_pnp_ops = { 152 .read = grlib_ahb_pnp_read, 153 .write = grlib_ahb_pnp_write, 154 .endianness = DEVICE_BIG_ENDIAN, 155 .impl = { 156 .min_access_size = 1, 157 .max_access_size = 4, 158 }, 159 }; 160 161 static void grlib_ahb_pnp_realize(DeviceState *dev, Error **errp) 162 { 163 AHBPnp *ahb_pnp = GRLIB_AHB_PNP(dev); 164 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 165 166 memory_region_init_io(&ahb_pnp->iomem, OBJECT(dev), &grlib_ahb_pnp_ops, 167 ahb_pnp, TYPE_GRLIB_AHB_PNP, GRLIB_PNP_MAX_REGS); 168 sysbus_init_mmio(sbd, &ahb_pnp->iomem); 169 } 170 171 static void grlib_ahb_pnp_class_init(ObjectClass *klass, void *data) 172 { 173 DeviceClass *dc = DEVICE_CLASS(klass); 174 175 dc->realize = grlib_ahb_pnp_realize; 176 } 177 178 static const TypeInfo grlib_ahb_pnp_info = { 179 .name = TYPE_GRLIB_AHB_PNP, 180 .parent = TYPE_SYS_BUS_DEVICE, 181 .instance_size = sizeof(AHBPnp), 182 .class_init = grlib_ahb_pnp_class_init, 183 }; 184 185 /* APBPnp */ 186 187 typedef struct APBPnp { 188 SysBusDevice parent_obj; 189 MemoryRegion iomem; 190 191 uint32_t regs[GRLIB_PNP_MAX_REGS >> 2]; 192 uint32_t entry_count; 193 } APBPnp; 194 195 void grlib_apb_pnp_add_entry(APBPnp *dev, uint32_t address, uint32_t mask, 196 uint8_t vendor, uint16_t device, uint8_t version, 197 uint8_t irq, int type) 198 { 199 unsigned int reg_start; 200 201 /* 202 * APB entries look like this: 203 * 204 * 31 -------- 23 -------- 11 ----- 9 ------- 4 --- 0 205 * | VENDOR ID | DEVICE ID | IRQ ? | VERSION | IRQ | 206 * 207 * 31 ---------- 20 --- 15 ----------------- 3 ---- 0 208 * | ADDR[20..8] | 0000 | MASK | TYPE | 209 */ 210 211 assert(dev->entry_count < GRLIB_APB_MAX_DEV); 212 reg_start = (dev->entry_count * GRLIB_APB_ENTRY_SIZE) >> 2; 213 dev->entry_count++; 214 215 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 216 GRLIB_PNP_VENDOR_SHIFT, 217 GRLIB_PNP_VENDOR_SIZE, 218 vendor); 219 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 220 GRLIB_PNP_DEV_SHIFT, 221 GRLIB_PNP_DEV_SIZE, 222 device); 223 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 224 GRLIB_PNP_VER_SHIFT, 225 GRLIB_PNP_VER_SIZE, 226 version); 227 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 228 GRLIB_PNP_IRQ_SHIFT, 229 GRLIB_PNP_IRQ_SIZE, 230 irq); 231 reg_start += 1; 232 dev->regs[reg_start] = type; 233 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 234 GRLIB_PNP_ADDR_SHIFT, 235 GRLIB_PNP_ADDR_SIZE, 236 extract32(address, 237 GRLIB_APB_DEV_ADDR_SHIFT, 238 GRLIB_APB_DEV_ADDR_SIZE)); 239 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 240 GRLIB_PNP_MASK_SHIFT, 241 GRLIB_PNP_MASK_SIZE, 242 mask); 243 } 244 245 static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size) 246 { 247 APBPnp *apb_pnp = GRLIB_APB_PNP(opaque); 248 uint32_t val; 249 250 val = apb_pnp->regs[offset >> 2]; 251 val = extract32(val, (4 - (offset & 3) - size) * 8, size * 8); 252 trace_grlib_apb_pnp_read(offset, size, val); 253 254 return val; 255 } 256 257 static void grlib_apb_pnp_write(void *opaque, hwaddr addr, 258 uint64_t val, unsigned size) 259 { 260 qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); 261 } 262 263 static const MemoryRegionOps grlib_apb_pnp_ops = { 264 .read = grlib_apb_pnp_read, 265 .write = grlib_apb_pnp_write, 266 .endianness = DEVICE_BIG_ENDIAN, 267 .impl = { 268 .min_access_size = 1, 269 .max_access_size = 4, 270 }, 271 }; 272 273 static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp) 274 { 275 APBPnp *apb_pnp = GRLIB_APB_PNP(dev); 276 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 277 278 memory_region_init_io(&apb_pnp->iomem, OBJECT(dev), &grlib_apb_pnp_ops, 279 apb_pnp, TYPE_GRLIB_APB_PNP, GRLIB_PNP_MAX_REGS); 280 sysbus_init_mmio(sbd, &apb_pnp->iomem); 281 } 282 283 static void grlib_apb_pnp_class_init(ObjectClass *klass, void *data) 284 { 285 DeviceClass *dc = DEVICE_CLASS(klass); 286 287 dc->realize = grlib_apb_pnp_realize; 288 } 289 290 static const TypeInfo grlib_apb_pnp_info = { 291 .name = TYPE_GRLIB_APB_PNP, 292 .parent = TYPE_SYS_BUS_DEVICE, 293 .instance_size = sizeof(APBPnp), 294 .class_init = grlib_apb_pnp_class_init, 295 }; 296 297 static void grlib_ahb_apb_pnp_register_types(void) 298 { 299 type_register_static(&grlib_ahb_pnp_info); 300 type_register_static(&grlib_apb_pnp_info); 301 } 302 303 type_init(grlib_ahb_apb_pnp_register_types) 304