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