1*162abf1aSKONRAD Frederic /* 2*162abf1aSKONRAD Frederic * GRLIB AHB APB PNP 3*162abf1aSKONRAD Frederic * 4*162abf1aSKONRAD Frederic * Copyright (C) 2019 AdaCore 5*162abf1aSKONRAD Frederic * 6*162abf1aSKONRAD Frederic * Developed by : 7*162abf1aSKONRAD Frederic * Frederic Konrad <frederic.konrad@adacore.com> 8*162abf1aSKONRAD Frederic * 9*162abf1aSKONRAD Frederic * This program is free software; you can redistribute it and/or modify 10*162abf1aSKONRAD Frederic * it under the terms of the GNU General Public License as published by 11*162abf1aSKONRAD Frederic * the Free Software Foundation, either version 2 of the License, or 12*162abf1aSKONRAD Frederic * (at your option) any later version. 13*162abf1aSKONRAD Frederic * 14*162abf1aSKONRAD Frederic * This program is distributed in the hope that it will be useful, 15*162abf1aSKONRAD Frederic * but WITHOUT ANY WARRANTY; without even the implied warranty of 16*162abf1aSKONRAD Frederic * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17*162abf1aSKONRAD Frederic * GNU General Public License for more details. 18*162abf1aSKONRAD Frederic * 19*162abf1aSKONRAD Frederic * You should have received a copy of the GNU General Public License along 20*162abf1aSKONRAD Frederic * with this program; if not, see <http://www.gnu.org/licenses/>. 21*162abf1aSKONRAD Frederic * 22*162abf1aSKONRAD Frederic */ 23*162abf1aSKONRAD Frederic 24*162abf1aSKONRAD Frederic #include "qemu/osdep.h" 25*162abf1aSKONRAD Frederic #include "hw/sysbus.h" 26*162abf1aSKONRAD Frederic #include "hw/misc/grlib_ahb_apb_pnp.h" 27*162abf1aSKONRAD Frederic 28*162abf1aSKONRAD Frederic #define GRLIB_PNP_VENDOR_SHIFT (24) 29*162abf1aSKONRAD Frederic #define GRLIB_PNP_VENDOR_SIZE (8) 30*162abf1aSKONRAD Frederic #define GRLIB_PNP_DEV_SHIFT (12) 31*162abf1aSKONRAD Frederic #define GRLIB_PNP_DEV_SIZE (12) 32*162abf1aSKONRAD Frederic #define GRLIB_PNP_VER_SHIFT (5) 33*162abf1aSKONRAD Frederic #define GRLIB_PNP_VER_SIZE (5) 34*162abf1aSKONRAD Frederic #define GRLIB_PNP_IRQ_SHIFT (0) 35*162abf1aSKONRAD Frederic #define GRLIB_PNP_IRQ_SIZE (5) 36*162abf1aSKONRAD Frederic #define GRLIB_PNP_ADDR_SHIFT (20) 37*162abf1aSKONRAD Frederic #define GRLIB_PNP_ADDR_SIZE (12) 38*162abf1aSKONRAD Frederic #define GRLIB_PNP_MASK_SHIFT (4) 39*162abf1aSKONRAD Frederic #define GRLIB_PNP_MASK_SIZE (12) 40*162abf1aSKONRAD Frederic 41*162abf1aSKONRAD Frederic #define GRLIB_AHB_DEV_ADDR_SHIFT (20) 42*162abf1aSKONRAD Frederic #define GRLIB_AHB_DEV_ADDR_SIZE (12) 43*162abf1aSKONRAD Frederic #define GRLIB_AHB_ENTRY_SIZE (0x20) 44*162abf1aSKONRAD Frederic #define GRLIB_AHB_MAX_DEV (64) 45*162abf1aSKONRAD Frederic #define GRLIB_AHB_SLAVE_OFFSET (0x800) 46*162abf1aSKONRAD Frederic 47*162abf1aSKONRAD Frederic #define GRLIB_APB_DEV_ADDR_SHIFT (8) 48*162abf1aSKONRAD Frederic #define GRLIB_APB_DEV_ADDR_SIZE (12) 49*162abf1aSKONRAD Frederic #define GRLIB_APB_ENTRY_SIZE (0x08) 50*162abf1aSKONRAD Frederic #define GRLIB_APB_MAX_DEV (512) 51*162abf1aSKONRAD Frederic 52*162abf1aSKONRAD Frederic #define GRLIB_PNP_MAX_REGS (0x1000) 53*162abf1aSKONRAD Frederic 54*162abf1aSKONRAD Frederic typedef struct AHBPnp { 55*162abf1aSKONRAD Frederic SysBusDevice parent_obj; 56*162abf1aSKONRAD Frederic MemoryRegion iomem; 57*162abf1aSKONRAD Frederic 58*162abf1aSKONRAD Frederic uint32_t regs[GRLIB_PNP_MAX_REGS >> 2]; 59*162abf1aSKONRAD Frederic uint8_t master_count; 60*162abf1aSKONRAD Frederic uint8_t slave_count; 61*162abf1aSKONRAD Frederic } AHBPnp; 62*162abf1aSKONRAD Frederic 63*162abf1aSKONRAD Frederic void grlib_ahb_pnp_add_entry(AHBPnp *dev, uint32_t address, uint32_t mask, 64*162abf1aSKONRAD Frederic uint8_t vendor, uint16_t device, int slave, 65*162abf1aSKONRAD Frederic int type) 66*162abf1aSKONRAD Frederic { 67*162abf1aSKONRAD Frederic unsigned int reg_start; 68*162abf1aSKONRAD Frederic 69*162abf1aSKONRAD Frederic /* 70*162abf1aSKONRAD Frederic * AHB entries look like this: 71*162abf1aSKONRAD Frederic * 72*162abf1aSKONRAD Frederic * 31 -------- 23 -------- 11 ----- 9 -------- 4 --- 0 73*162abf1aSKONRAD Frederic * | VENDOR ID | DEVICE ID | IRQ ? | VERSION | IRQ | 74*162abf1aSKONRAD Frederic * -------------------------------------------------- 75*162abf1aSKONRAD Frederic * | USER | 76*162abf1aSKONRAD Frederic * -------------------------------------------------- 77*162abf1aSKONRAD Frederic * | USER | 78*162abf1aSKONRAD Frederic * -------------------------------------------------- 79*162abf1aSKONRAD Frederic * | USER | 80*162abf1aSKONRAD Frederic * -------------------------------------------------- 81*162abf1aSKONRAD Frederic * | USER | 82*162abf1aSKONRAD Frederic * -------------------------------------------------- 83*162abf1aSKONRAD Frederic * 31 ----------- 20 --- 15 ----------------- 3 ---- 0 84*162abf1aSKONRAD Frederic * | ADDR[31..12] | 00PC | MASK | TYPE | 85*162abf1aSKONRAD Frederic * -------------------------------------------------- 86*162abf1aSKONRAD Frederic * 31 ----------- 20 --- 15 ----------------- 3 ---- 0 87*162abf1aSKONRAD Frederic * | ADDR[31..12] | 00PC | MASK | TYPE | 88*162abf1aSKONRAD Frederic * -------------------------------------------------- 89*162abf1aSKONRAD Frederic * 31 ----------- 20 --- 15 ----------------- 3 ---- 0 90*162abf1aSKONRAD Frederic * | ADDR[31..12] | 00PC | MASK | TYPE | 91*162abf1aSKONRAD Frederic * -------------------------------------------------- 92*162abf1aSKONRAD Frederic * 31 ----------- 20 --- 15 ----------------- 3 ---- 0 93*162abf1aSKONRAD Frederic * | ADDR[31..12] | 00PC | MASK | TYPE | 94*162abf1aSKONRAD Frederic * -------------------------------------------------- 95*162abf1aSKONRAD Frederic */ 96*162abf1aSKONRAD Frederic 97*162abf1aSKONRAD Frederic if (slave) { 98*162abf1aSKONRAD Frederic assert(dev->slave_count < GRLIB_AHB_MAX_DEV); 99*162abf1aSKONRAD Frederic reg_start = (GRLIB_AHB_SLAVE_OFFSET 100*162abf1aSKONRAD Frederic + (dev->slave_count * GRLIB_AHB_ENTRY_SIZE)) >> 2; 101*162abf1aSKONRAD Frederic dev->slave_count++; 102*162abf1aSKONRAD Frederic } else { 103*162abf1aSKONRAD Frederic assert(dev->master_count < GRLIB_AHB_MAX_DEV); 104*162abf1aSKONRAD Frederic reg_start = (dev->master_count * GRLIB_AHB_ENTRY_SIZE) >> 2; 105*162abf1aSKONRAD Frederic dev->master_count++; 106*162abf1aSKONRAD Frederic } 107*162abf1aSKONRAD Frederic 108*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 109*162abf1aSKONRAD Frederic GRLIB_PNP_VENDOR_SHIFT, 110*162abf1aSKONRAD Frederic GRLIB_PNP_VENDOR_SIZE, 111*162abf1aSKONRAD Frederic vendor); 112*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 113*162abf1aSKONRAD Frederic GRLIB_PNP_DEV_SHIFT, 114*162abf1aSKONRAD Frederic GRLIB_PNP_DEV_SIZE, 115*162abf1aSKONRAD Frederic device); 116*162abf1aSKONRAD Frederic reg_start += 4; 117*162abf1aSKONRAD Frederic /* AHB Memory Space */ 118*162abf1aSKONRAD Frederic dev->regs[reg_start] = type; 119*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 120*162abf1aSKONRAD Frederic GRLIB_PNP_ADDR_SHIFT, 121*162abf1aSKONRAD Frederic GRLIB_PNP_ADDR_SIZE, 122*162abf1aSKONRAD Frederic extract32(address, 123*162abf1aSKONRAD Frederic GRLIB_AHB_DEV_ADDR_SHIFT, 124*162abf1aSKONRAD Frederic GRLIB_AHB_DEV_ADDR_SIZE)); 125*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 126*162abf1aSKONRAD Frederic GRLIB_PNP_MASK_SHIFT, 127*162abf1aSKONRAD Frederic GRLIB_PNP_MASK_SIZE, 128*162abf1aSKONRAD Frederic mask); 129*162abf1aSKONRAD Frederic } 130*162abf1aSKONRAD Frederic 131*162abf1aSKONRAD Frederic static uint64_t grlib_ahb_pnp_read(void *opaque, hwaddr offset, unsigned size) 132*162abf1aSKONRAD Frederic { 133*162abf1aSKONRAD Frederic AHBPnp *ahb_pnp = GRLIB_AHB_PNP(opaque); 134*162abf1aSKONRAD Frederic 135*162abf1aSKONRAD Frederic return ahb_pnp->regs[offset >> 2]; 136*162abf1aSKONRAD Frederic } 137*162abf1aSKONRAD Frederic 138*162abf1aSKONRAD Frederic static const MemoryRegionOps grlib_ahb_pnp_ops = { 139*162abf1aSKONRAD Frederic .read = grlib_ahb_pnp_read, 140*162abf1aSKONRAD Frederic .endianness = DEVICE_BIG_ENDIAN, 141*162abf1aSKONRAD Frederic }; 142*162abf1aSKONRAD Frederic 143*162abf1aSKONRAD Frederic static void grlib_ahb_pnp_realize(DeviceState *dev, Error **errp) 144*162abf1aSKONRAD Frederic { 145*162abf1aSKONRAD Frederic AHBPnp *ahb_pnp = GRLIB_AHB_PNP(dev); 146*162abf1aSKONRAD Frederic SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 147*162abf1aSKONRAD Frederic 148*162abf1aSKONRAD Frederic memory_region_init_io(&ahb_pnp->iomem, OBJECT(dev), &grlib_ahb_pnp_ops, 149*162abf1aSKONRAD Frederic ahb_pnp, TYPE_GRLIB_AHB_PNP, GRLIB_PNP_MAX_REGS); 150*162abf1aSKONRAD Frederic sysbus_init_mmio(sbd, &ahb_pnp->iomem); 151*162abf1aSKONRAD Frederic } 152*162abf1aSKONRAD Frederic 153*162abf1aSKONRAD Frederic static void grlib_ahb_pnp_class_init(ObjectClass *klass, void *data) 154*162abf1aSKONRAD Frederic { 155*162abf1aSKONRAD Frederic DeviceClass *dc = DEVICE_CLASS(klass); 156*162abf1aSKONRAD Frederic 157*162abf1aSKONRAD Frederic dc->realize = grlib_ahb_pnp_realize; 158*162abf1aSKONRAD Frederic } 159*162abf1aSKONRAD Frederic 160*162abf1aSKONRAD Frederic static const TypeInfo grlib_ahb_pnp_info = { 161*162abf1aSKONRAD Frederic .name = TYPE_GRLIB_AHB_PNP, 162*162abf1aSKONRAD Frederic .parent = TYPE_SYS_BUS_DEVICE, 163*162abf1aSKONRAD Frederic .instance_size = sizeof(AHBPnp), 164*162abf1aSKONRAD Frederic .class_init = grlib_ahb_pnp_class_init, 165*162abf1aSKONRAD Frederic }; 166*162abf1aSKONRAD Frederic 167*162abf1aSKONRAD Frederic /* APBPnp */ 168*162abf1aSKONRAD Frederic 169*162abf1aSKONRAD Frederic typedef struct APBPnp { 170*162abf1aSKONRAD Frederic SysBusDevice parent_obj; 171*162abf1aSKONRAD Frederic MemoryRegion iomem; 172*162abf1aSKONRAD Frederic 173*162abf1aSKONRAD Frederic uint32_t regs[GRLIB_PNP_MAX_REGS >> 2]; 174*162abf1aSKONRAD Frederic uint32_t entry_count; 175*162abf1aSKONRAD Frederic } APBPnp; 176*162abf1aSKONRAD Frederic 177*162abf1aSKONRAD Frederic void grlib_apb_pnp_add_entry(APBPnp *dev, uint32_t address, uint32_t mask, 178*162abf1aSKONRAD Frederic uint8_t vendor, uint16_t device, uint8_t version, 179*162abf1aSKONRAD Frederic uint8_t irq, int type) 180*162abf1aSKONRAD Frederic { 181*162abf1aSKONRAD Frederic unsigned int reg_start; 182*162abf1aSKONRAD Frederic 183*162abf1aSKONRAD Frederic /* 184*162abf1aSKONRAD Frederic * APB entries look like this: 185*162abf1aSKONRAD Frederic * 186*162abf1aSKONRAD Frederic * 31 -------- 23 -------- 11 ----- 9 ------- 4 --- 0 187*162abf1aSKONRAD Frederic * | VENDOR ID | DEVICE ID | IRQ ? | VERSION | IRQ | 188*162abf1aSKONRAD Frederic * 189*162abf1aSKONRAD Frederic * 31 ---------- 20 --- 15 ----------------- 3 ---- 0 190*162abf1aSKONRAD Frederic * | ADDR[20..8] | 0000 | MASK | TYPE | 191*162abf1aSKONRAD Frederic */ 192*162abf1aSKONRAD Frederic 193*162abf1aSKONRAD Frederic assert(dev->entry_count < GRLIB_APB_MAX_DEV); 194*162abf1aSKONRAD Frederic reg_start = (dev->entry_count * GRLIB_APB_ENTRY_SIZE) >> 2; 195*162abf1aSKONRAD Frederic dev->entry_count++; 196*162abf1aSKONRAD Frederic 197*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 198*162abf1aSKONRAD Frederic GRLIB_PNP_VENDOR_SHIFT, 199*162abf1aSKONRAD Frederic GRLIB_PNP_VENDOR_SIZE, 200*162abf1aSKONRAD Frederic vendor); 201*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 202*162abf1aSKONRAD Frederic GRLIB_PNP_DEV_SHIFT, 203*162abf1aSKONRAD Frederic GRLIB_PNP_DEV_SIZE, 204*162abf1aSKONRAD Frederic device); 205*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 206*162abf1aSKONRAD Frederic GRLIB_PNP_VER_SHIFT, 207*162abf1aSKONRAD Frederic GRLIB_PNP_VER_SIZE, 208*162abf1aSKONRAD Frederic version); 209*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 210*162abf1aSKONRAD Frederic GRLIB_PNP_IRQ_SHIFT, 211*162abf1aSKONRAD Frederic GRLIB_PNP_IRQ_SIZE, 212*162abf1aSKONRAD Frederic irq); 213*162abf1aSKONRAD Frederic reg_start += 1; 214*162abf1aSKONRAD Frederic dev->regs[reg_start] = type; 215*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 216*162abf1aSKONRAD Frederic GRLIB_PNP_ADDR_SHIFT, 217*162abf1aSKONRAD Frederic GRLIB_PNP_ADDR_SIZE, 218*162abf1aSKONRAD Frederic extract32(address, 219*162abf1aSKONRAD Frederic GRLIB_APB_DEV_ADDR_SHIFT, 220*162abf1aSKONRAD Frederic GRLIB_APB_DEV_ADDR_SIZE)); 221*162abf1aSKONRAD Frederic dev->regs[reg_start] = deposit32(dev->regs[reg_start], 222*162abf1aSKONRAD Frederic GRLIB_PNP_MASK_SHIFT, 223*162abf1aSKONRAD Frederic GRLIB_PNP_MASK_SIZE, 224*162abf1aSKONRAD Frederic mask); 225*162abf1aSKONRAD Frederic } 226*162abf1aSKONRAD Frederic 227*162abf1aSKONRAD Frederic static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size) 228*162abf1aSKONRAD Frederic { 229*162abf1aSKONRAD Frederic APBPnp *apb_pnp = GRLIB_APB_PNP(opaque); 230*162abf1aSKONRAD Frederic 231*162abf1aSKONRAD Frederic return apb_pnp->regs[offset >> 2]; 232*162abf1aSKONRAD Frederic } 233*162abf1aSKONRAD Frederic 234*162abf1aSKONRAD Frederic static const MemoryRegionOps grlib_apb_pnp_ops = { 235*162abf1aSKONRAD Frederic .read = grlib_apb_pnp_read, 236*162abf1aSKONRAD Frederic .endianness = DEVICE_BIG_ENDIAN, 237*162abf1aSKONRAD Frederic }; 238*162abf1aSKONRAD Frederic 239*162abf1aSKONRAD Frederic static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp) 240*162abf1aSKONRAD Frederic { 241*162abf1aSKONRAD Frederic APBPnp *apb_pnp = GRLIB_APB_PNP(dev); 242*162abf1aSKONRAD Frederic SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 243*162abf1aSKONRAD Frederic 244*162abf1aSKONRAD Frederic memory_region_init_io(&apb_pnp->iomem, OBJECT(dev), &grlib_apb_pnp_ops, 245*162abf1aSKONRAD Frederic apb_pnp, TYPE_GRLIB_APB_PNP, GRLIB_PNP_MAX_REGS); 246*162abf1aSKONRAD Frederic sysbus_init_mmio(sbd, &apb_pnp->iomem); 247*162abf1aSKONRAD Frederic } 248*162abf1aSKONRAD Frederic 249*162abf1aSKONRAD Frederic static void grlib_apb_pnp_class_init(ObjectClass *klass, void *data) 250*162abf1aSKONRAD Frederic { 251*162abf1aSKONRAD Frederic DeviceClass *dc = DEVICE_CLASS(klass); 252*162abf1aSKONRAD Frederic 253*162abf1aSKONRAD Frederic dc->realize = grlib_apb_pnp_realize; 254*162abf1aSKONRAD Frederic } 255*162abf1aSKONRAD Frederic 256*162abf1aSKONRAD Frederic static const TypeInfo grlib_apb_pnp_info = { 257*162abf1aSKONRAD Frederic .name = TYPE_GRLIB_APB_PNP, 258*162abf1aSKONRAD Frederic .parent = TYPE_SYS_BUS_DEVICE, 259*162abf1aSKONRAD Frederic .instance_size = sizeof(APBPnp), 260*162abf1aSKONRAD Frederic .class_init = grlib_apb_pnp_class_init, 261*162abf1aSKONRAD Frederic }; 262*162abf1aSKONRAD Frederic 263*162abf1aSKONRAD Frederic static void grlib_ahb_apb_pnp_register_types(void) 264*162abf1aSKONRAD Frederic { 265*162abf1aSKONRAD Frederic type_register_static(&grlib_ahb_pnp_info); 266*162abf1aSKONRAD Frederic type_register_static(&grlib_apb_pnp_info); 267*162abf1aSKONRAD Frederic } 268*162abf1aSKONRAD Frederic 269*162abf1aSKONRAD Frederic type_init(grlib_ahb_apb_pnp_register_types) 270