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