qemu/hw/misc/grlib_ahb_apb_pnp.c
<<
>>
Prefs
   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)
 302