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