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 }; 150 151 static void grlib_ahb_pnp_realize(DeviceState *dev, Error **errp) 152 { 153 AHBPnp *ahb_pnp = GRLIB_AHB_PNP(dev); 154 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 155 156 memory_region_init_io(&ahb_pnp->iomem, OBJECT(dev), &grlib_ahb_pnp_ops, 157 ahb_pnp, TYPE_GRLIB_AHB_PNP, GRLIB_PNP_MAX_REGS); 158 sysbus_init_mmio(sbd, &ahb_pnp->iomem); 159 } 160 161 static void grlib_ahb_pnp_class_init(ObjectClass *klass, void *data) 162 { 163 DeviceClass *dc = DEVICE_CLASS(klass); 164 165 dc->realize = grlib_ahb_pnp_realize; 166 } 167 168 static const TypeInfo grlib_ahb_pnp_info = { 169 .name = TYPE_GRLIB_AHB_PNP, 170 .parent = TYPE_SYS_BUS_DEVICE, 171 .instance_size = sizeof(AHBPnp), 172 .class_init = grlib_ahb_pnp_class_init, 173 }; 174 175 /* APBPnp */ 176 177 typedef struct APBPnp { 178 SysBusDevice parent_obj; 179 MemoryRegion iomem; 180 181 uint32_t regs[GRLIB_PNP_MAX_REGS >> 2]; 182 uint32_t entry_count; 183 } APBPnp; 184 185 void grlib_apb_pnp_add_entry(APBPnp *dev, uint32_t address, uint32_t mask, 186 uint8_t vendor, uint16_t device, uint8_t version, 187 uint8_t irq, int type) 188 { 189 unsigned int reg_start; 190 191 /* 192 * APB entries look like this: 193 * 194 * 31 -------- 23 -------- 11 ----- 9 ------- 4 --- 0 195 * | VENDOR ID | DEVICE ID | IRQ ? | VERSION | IRQ | 196 * 197 * 31 ---------- 20 --- 15 ----------------- 3 ---- 0 198 * | ADDR[20..8] | 0000 | MASK | TYPE | 199 */ 200 201 assert(dev->entry_count < GRLIB_APB_MAX_DEV); 202 reg_start = (dev->entry_count * GRLIB_APB_ENTRY_SIZE) >> 2; 203 dev->entry_count++; 204 205 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 206 GRLIB_PNP_VENDOR_SHIFT, 207 GRLIB_PNP_VENDOR_SIZE, 208 vendor); 209 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 210 GRLIB_PNP_DEV_SHIFT, 211 GRLIB_PNP_DEV_SIZE, 212 device); 213 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 214 GRLIB_PNP_VER_SHIFT, 215 GRLIB_PNP_VER_SIZE, 216 version); 217 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 218 GRLIB_PNP_IRQ_SHIFT, 219 GRLIB_PNP_IRQ_SIZE, 220 irq); 221 reg_start += 1; 222 dev->regs[reg_start] = type; 223 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 224 GRLIB_PNP_ADDR_SHIFT, 225 GRLIB_PNP_ADDR_SIZE, 226 extract32(address, 227 GRLIB_APB_DEV_ADDR_SHIFT, 228 GRLIB_APB_DEV_ADDR_SIZE)); 229 dev->regs[reg_start] = deposit32(dev->regs[reg_start], 230 GRLIB_PNP_MASK_SHIFT, 231 GRLIB_PNP_MASK_SIZE, 232 mask); 233 } 234 235 static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size) 236 { 237 APBPnp *apb_pnp = GRLIB_APB_PNP(opaque); 238 239 return apb_pnp->regs[offset >> 2]; 240 } 241 242 static void grlib_apb_pnp_write(void *opaque, hwaddr addr, 243 uint64_t val, unsigned size) 244 { 245 qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__); 246 } 247 248 static const MemoryRegionOps grlib_apb_pnp_ops = { 249 .read = grlib_apb_pnp_read, 250 .write = grlib_apb_pnp_write, 251 .endianness = DEVICE_BIG_ENDIAN, 252 .impl = { 253 .min_access_size = 4, 254 .max_access_size = 4, 255 }, 256 }; 257 258 static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp) 259 { 260 APBPnp *apb_pnp = GRLIB_APB_PNP(dev); 261 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 262 263 memory_region_init_io(&apb_pnp->iomem, OBJECT(dev), &grlib_apb_pnp_ops, 264 apb_pnp, TYPE_GRLIB_APB_PNP, GRLIB_PNP_MAX_REGS); 265 sysbus_init_mmio(sbd, &apb_pnp->iomem); 266 } 267 268 static void grlib_apb_pnp_class_init(ObjectClass *klass, void *data) 269 { 270 DeviceClass *dc = DEVICE_CLASS(klass); 271 272 dc->realize = grlib_apb_pnp_realize; 273 } 274 275 static const TypeInfo grlib_apb_pnp_info = { 276 .name = TYPE_GRLIB_APB_PNP, 277 .parent = TYPE_SYS_BUS_DEVICE, 278 .instance_size = sizeof(APBPnp), 279 .class_init = grlib_apb_pnp_class_init, 280 }; 281 282 static void grlib_ahb_apb_pnp_register_types(void) 283 { 284 type_register_static(&grlib_ahb_pnp_info); 285 type_register_static(&grlib_apb_pnp_info); 286 } 287 288 type_init(grlib_ahb_apb_pnp_register_types) 289