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