qemu/hw/intc/rx_icu.c
<<
>>
Prefs
   1/*
   2 * RX Interrupt Control Unit
   3 *
   4 * Warning: Only ICUa is supported.
   5 *
   6 * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware
   7 *            (Rev.1.40 R01UH0033EJ0140)
   8 *
   9 * Copyright (c) 2019 Yoshinori Sato
  10 *
  11 * SPDX-License-Identifier: GPL-2.0-or-later
  12 *
  13 * This program is free software; you can redistribute it and/or modify it
  14 * under the terms and conditions of the GNU General Public License,
  15 * version 2 or later, as published by the Free Software Foundation.
  16 *
  17 * This program is distributed in the hope it will be useful, but WITHOUT
  18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  19 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  20 * more details.
  21 *
  22 * You should have received a copy of the GNU General Public License along with
  23 * this program.  If not, see <http://www.gnu.org/licenses/>.
  24 */
  25
  26#include "qemu/osdep.h"
  27#include "qemu/log.h"
  28#include "qemu/error-report.h"
  29#include "hw/irq.h"
  30#include "hw/registerfields.h"
  31#include "hw/qdev-properties.h"
  32#include "hw/intc/rx_icu.h"
  33#include "migration/vmstate.h"
  34
  35REG8(IR, 0)
  36  FIELD(IR, IR,  0, 1)
  37REG8(DTCER, 0x100)
  38  FIELD(DTCER, DTCE,  0, 1)
  39REG8(IER, 0x200)
  40REG8(SWINTR, 0x2e0)
  41  FIELD(SWINTR, SWINT, 0, 1)
  42REG16(FIR, 0x2f0)
  43  FIELD(FIR, FVCT, 0,  8)
  44  FIELD(FIR, FIEN, 15, 1)
  45REG8(IPR, 0x300)
  46  FIELD(IPR, IPR, 0, 4)
  47REG8(DMRSR, 0x400)
  48REG8(IRQCR, 0x500)
  49  FIELD(IRQCR, IRQMD, 2, 2)
  50REG8(NMISR, 0x580)
  51  FIELD(NMISR, NMIST, 0, 1)
  52  FIELD(NMISR, LVDST, 1, 1)
  53  FIELD(NMISR, OSTST, 2, 1)
  54REG8(NMIER, 0x581)
  55  FIELD(NMIER, NMIEN, 0, 1)
  56  FIELD(NMIER, LVDEN, 1, 1)
  57  FIELD(NMIER, OSTEN, 2, 1)
  58REG8(NMICLR, 0x582)
  59  FIELD(NMICLR, NMICLR, 0, 1)
  60  FIELD(NMICLR, OSTCLR, 2, 1)
  61REG8(NMICR, 0x583)
  62  FIELD(NMICR, NMIMD, 3, 1)
  63
  64static void set_irq(RXICUState *icu, int n_IRQ, int req)
  65{
  66    if ((icu->fir & R_FIR_FIEN_MASK) &&
  67        (icu->fir & R_FIR_FVCT_MASK) == n_IRQ) {
  68        qemu_set_irq(icu->_fir, req);
  69    } else {
  70        qemu_set_irq(icu->_irq, req);
  71    }
  72}
  73
  74static uint16_t rxicu_level(RXICUState *icu, unsigned n)
  75{
  76    return (icu->ipr[icu->map[n]] << 8) | n;
  77}
  78
  79static void rxicu_request(RXICUState *icu, int n_IRQ)
  80{
  81    int enable;
  82
  83    enable = icu->ier[n_IRQ / 8] & (1 << (n_IRQ & 7));
  84    if (n_IRQ > 0 && enable != 0 && qatomic_read(&icu->req_irq) < 0) {
  85        qatomic_set(&icu->req_irq, n_IRQ);
  86        set_irq(icu, n_IRQ, rxicu_level(icu, n_IRQ));
  87    }
  88}
  89
  90static void rxicu_set_irq(void *opaque, int n_IRQ, int level)
  91{
  92    RXICUState *icu = opaque;
  93    struct IRQSource *src;
  94    int issue;
  95
  96    if (n_IRQ >= NR_IRQS) {
  97        error_report("%s: IRQ %d out of range", __func__, n_IRQ);
  98        return;
  99    }
 100
 101    src = &icu->src[n_IRQ];
 102
 103    level = (level != 0);
 104    switch (src->sense) {
 105    case TRG_LEVEL:
 106        /* level-sensitive irq */
 107        issue = level;
 108        src->level = level;
 109        break;
 110    case TRG_NEDGE:
 111        issue = (level == 0 && src->level == 1);
 112        src->level = level;
 113        break;
 114    case TRG_PEDGE:
 115        issue = (level == 1 && src->level == 0);
 116        src->level = level;
 117        break;
 118    case TRG_BEDGE:
 119        issue = ((level ^ src->level) & 1);
 120        src->level = level;
 121        break;
 122    default:
 123        g_assert_not_reached();
 124    }
 125    if (issue == 0 && src->sense == TRG_LEVEL) {
 126        icu->ir[n_IRQ] = 0;
 127        if (qatomic_read(&icu->req_irq) == n_IRQ) {
 128            /* clear request */
 129            set_irq(icu, n_IRQ, 0);
 130            qatomic_set(&icu->req_irq, -1);
 131        }
 132        return;
 133    }
 134    if (issue) {
 135        icu->ir[n_IRQ] = 1;
 136        rxicu_request(icu, n_IRQ);
 137    }
 138}
 139
 140static void rxicu_ack_irq(void *opaque, int no, int level)
 141{
 142    RXICUState *icu = opaque;
 143    int i;
 144    int n_IRQ;
 145    int max_pri;
 146
 147    n_IRQ = qatomic_read(&icu->req_irq);
 148    if (n_IRQ < 0) {
 149        return;
 150    }
 151    qatomic_set(&icu->req_irq, -1);
 152    if (icu->src[n_IRQ].sense != TRG_LEVEL) {
 153        icu->ir[n_IRQ] = 0;
 154    }
 155
 156    max_pri = 0;
 157    n_IRQ = -1;
 158    for (i = 0; i < NR_IRQS; i++) {
 159        if (icu->ir[i]) {
 160            if (max_pri < icu->ipr[icu->map[i]]) {
 161                n_IRQ = i;
 162                max_pri = icu->ipr[icu->map[i]];
 163            }
 164        }
 165    }
 166
 167    if (n_IRQ >= 0) {
 168        rxicu_request(icu, n_IRQ);
 169    }
 170}
 171
 172static uint64_t icu_read(void *opaque, hwaddr addr, unsigned size)
 173{
 174    RXICUState *icu = opaque;
 175    int reg = addr & 0xff;
 176
 177    if ((addr != A_FIR && size != 1) ||
 178        (addr == A_FIR && size != 2)) {
 179        qemu_log_mask(LOG_GUEST_ERROR, "rx_icu: Invalid read size 0x%"
 180                                       HWADDR_PRIX "\n",
 181                      addr);
 182        return UINT64_MAX;
 183    }
 184    switch (addr) {
 185    case A_IR ... A_IR + 0xff:
 186        return icu->ir[reg] & R_IR_IR_MASK;
 187    case A_DTCER ... A_DTCER + 0xff:
 188        return icu->dtcer[reg] & R_DTCER_DTCE_MASK;
 189    case A_IER ... A_IER + 0x1f:
 190        return icu->ier[reg];
 191    case A_SWINTR:
 192        return 0;
 193    case A_FIR:
 194        return icu->fir & (R_FIR_FIEN_MASK | R_FIR_FVCT_MASK);
 195    case A_IPR ... A_IPR + 0x8f:
 196        return icu->ipr[reg] & R_IPR_IPR_MASK;
 197    case A_DMRSR:
 198    case A_DMRSR + 4:
 199    case A_DMRSR + 8:
 200    case A_DMRSR + 12:
 201        return icu->dmasr[reg >> 2];
 202    case A_IRQCR ... A_IRQCR + 0x1f:
 203        return icu->src[64 + reg].sense << R_IRQCR_IRQMD_SHIFT;
 204    case A_NMISR:
 205    case A_NMICLR:
 206        return 0;
 207    case A_NMIER:
 208        return icu->nmier;
 209    case A_NMICR:
 210        return icu->nmicr;
 211    default:
 212        qemu_log_mask(LOG_UNIMP, "rx_icu: Register 0x%" HWADDR_PRIX " "
 213                                 "not implemented.\n",
 214                      addr);
 215        break;
 216    }
 217    return UINT64_MAX;
 218}
 219
 220static void icu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
 221{
 222    RXICUState *icu = opaque;
 223    int reg = addr & 0xff;
 224
 225    if ((addr != A_FIR && size != 1) ||
 226        (addr == A_FIR && size != 2)) {
 227        qemu_log_mask(LOG_GUEST_ERROR, "rx_icu: Invalid write size at "
 228                                       "0x%" HWADDR_PRIX "\n",
 229                      addr);
 230        return;
 231    }
 232    switch (addr) {
 233    case A_IR ... A_IR + 0xff:
 234        if (icu->src[reg].sense != TRG_LEVEL && val == 0) {
 235            icu->ir[reg] = 0;
 236        }
 237        break;
 238    case A_DTCER ... A_DTCER + 0xff:
 239        icu->dtcer[reg] = val & R_DTCER_DTCE_MASK;
 240        qemu_log_mask(LOG_UNIMP, "rx_icu: DTC not implemented\n");
 241        break;
 242    case A_IER ... A_IER + 0x1f:
 243        icu->ier[reg] = val;
 244        break;
 245    case A_SWINTR:
 246        if (val & R_SWINTR_SWINT_MASK) {
 247            qemu_irq_pulse(icu->_swi);
 248        }
 249        break;
 250    case A_FIR:
 251        icu->fir = val & (R_FIR_FIEN_MASK | R_FIR_FVCT_MASK);
 252        break;
 253    case A_IPR ... A_IPR + 0x8f:
 254        icu->ipr[reg] = val & R_IPR_IPR_MASK;
 255        break;
 256    case A_DMRSR:
 257    case A_DMRSR + 4:
 258    case A_DMRSR + 8:
 259    case A_DMRSR + 12:
 260        icu->dmasr[reg >> 2] = val;
 261        qemu_log_mask(LOG_UNIMP, "rx_icu: DMAC not implemented\n");
 262        break;
 263    case A_IRQCR ... A_IRQCR + 0x1f:
 264        icu->src[64 + reg].sense = val >> R_IRQCR_IRQMD_SHIFT;
 265        break;
 266    case A_NMICLR:
 267        break;
 268    case A_NMIER:
 269        icu->nmier |= val & (R_NMIER_NMIEN_MASK |
 270                             R_NMIER_LVDEN_MASK |
 271                             R_NMIER_OSTEN_MASK);
 272        break;
 273    case A_NMICR:
 274        if ((icu->nmier & R_NMIER_NMIEN_MASK) == 0) {
 275            icu->nmicr = val & R_NMICR_NMIMD_MASK;
 276        }
 277        break;
 278    default:
 279        qemu_log_mask(LOG_UNIMP, "rx_icu: Register 0x%" HWADDR_PRIX " "
 280                                 "not implemented\n",
 281                      addr);
 282        break;
 283    }
 284}
 285
 286static const MemoryRegionOps icu_ops = {
 287    .write = icu_write,
 288    .read  = icu_read,
 289    .endianness = DEVICE_LITTLE_ENDIAN,
 290    .impl = {
 291        .min_access_size = 1,
 292        .max_access_size = 2,
 293    },
 294    .valid = {
 295        .min_access_size = 1,
 296        .max_access_size = 2,
 297    },
 298};
 299
 300static void rxicu_realize(DeviceState *dev, Error **errp)
 301{
 302    RXICUState *icu = RX_ICU(dev);
 303    int i;
 304
 305    if (icu->init_sense == NULL) {
 306        qemu_log_mask(LOG_GUEST_ERROR,
 307                      "rx_icu: trigger-level property must be set.");
 308        return;
 309    }
 310
 311    for (i = 0; i < NR_IRQS; i++) {
 312        icu->src[i].sense = TRG_PEDGE;
 313    }
 314    for (i = 0; i < icu->nr_sense; i++) {
 315        uint8_t irqno = icu->init_sense[i];
 316        icu->src[irqno].sense = TRG_LEVEL;
 317    }
 318    icu->req_irq = -1;
 319}
 320
 321static void rxicu_init(Object *obj)
 322{
 323    SysBusDevice *d = SYS_BUS_DEVICE(obj);
 324    RXICUState *icu = RX_ICU(obj);
 325
 326    memory_region_init_io(&icu->memory, OBJECT(icu), &icu_ops,
 327                          icu, "rx-icu", 0x600);
 328    sysbus_init_mmio(d, &icu->memory);
 329
 330    qdev_init_gpio_in(DEVICE(d), rxicu_set_irq, NR_IRQS);
 331    qdev_init_gpio_in_named(DEVICE(d), rxicu_ack_irq, "ack", 1);
 332    sysbus_init_irq(d, &icu->_irq);
 333    sysbus_init_irq(d, &icu->_fir);
 334    sysbus_init_irq(d, &icu->_swi);
 335}
 336
 337static void rxicu_fini(Object *obj)
 338{
 339    RXICUState *icu = RX_ICU(obj);
 340    g_free(icu->map);
 341    g_free(icu->init_sense);
 342}
 343
 344static const VMStateDescription vmstate_rxicu = {
 345    .name = "rx-icu",
 346    .version_id = 1,
 347    .minimum_version_id = 1,
 348    .fields = (VMStateField[]) {
 349        VMSTATE_UINT8_ARRAY(ir, RXICUState, NR_IRQS),
 350        VMSTATE_UINT8_ARRAY(dtcer, RXICUState, NR_IRQS),
 351        VMSTATE_UINT8_ARRAY(ier, RXICUState, NR_IRQS / 8),
 352        VMSTATE_UINT8_ARRAY(ipr, RXICUState, 142),
 353        VMSTATE_UINT8_ARRAY(dmasr, RXICUState, 4),
 354        VMSTATE_UINT16(fir, RXICUState),
 355        VMSTATE_UINT8(nmisr, RXICUState),
 356        VMSTATE_UINT8(nmier, RXICUState),
 357        VMSTATE_UINT8(nmiclr, RXICUState),
 358        VMSTATE_UINT8(nmicr, RXICUState),
 359        VMSTATE_INT16(req_irq, RXICUState),
 360        VMSTATE_END_OF_LIST()
 361    }
 362};
 363
 364static Property rxicu_properties[] = {
 365    DEFINE_PROP_ARRAY("ipr-map", RXICUState, nr_irqs, map,
 366                      qdev_prop_uint8, uint8_t),
 367    DEFINE_PROP_ARRAY("trigger-level", RXICUState, nr_sense, init_sense,
 368                      qdev_prop_uint8, uint8_t),
 369    DEFINE_PROP_END_OF_LIST(),
 370};
 371
 372static void rxicu_class_init(ObjectClass *klass, void *data)
 373{
 374    DeviceClass *dc = DEVICE_CLASS(klass);
 375
 376    dc->realize = rxicu_realize;
 377    dc->vmsd = &vmstate_rxicu;
 378    device_class_set_props(dc, rxicu_properties);
 379}
 380
 381static const TypeInfo rxicu_info = {
 382    .name = TYPE_RX_ICU,
 383    .parent = TYPE_SYS_BUS_DEVICE,
 384    .instance_size = sizeof(RXICUState),
 385    .instance_init = rxicu_init,
 386    .instance_finalize = rxicu_fini,
 387    .class_init = rxicu_class_init,
 388};
 389
 390static void rxicu_register_types(void)
 391{
 392    type_register_static(&rxicu_info);
 393}
 394
 395type_init(rxicu_register_types)
 396