qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

ppc-uic.c (8507B)


      1 /*
      2  * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
      3  *
      4  * Copyright (c) 2007 Jocelyn Mayer
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "hw/intc/ppc-uic.h"
     27 #include "hw/irq.h"
     28 #include "hw/qdev-properties.h"
     29 #include "migration/vmstate.h"
     30 
     31 enum {
     32     DCR_UICSR  = 0x000,
     33     DCR_UICSRS = 0x001,
     34     DCR_UICER  = 0x002,
     35     DCR_UICCR  = 0x003,
     36     DCR_UICPR  = 0x004,
     37     DCR_UICTR  = 0x005,
     38     DCR_UICMSR = 0x006,
     39     DCR_UICVR  = 0x007,
     40     DCR_UICVCR = 0x008,
     41     DCR_UICMAX = 0x009,
     42 };
     43 
     44 /*#define DEBUG_UIC*/
     45 
     46 #ifdef DEBUG_UIC
     47 #  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
     48 #else
     49 #  define LOG_UIC(...) do { } while (0)
     50 #endif
     51 
     52 static void ppcuic_trigger_irq(PPCUIC *uic)
     53 {
     54     uint32_t ir, cr;
     55     int start, end, inc, i;
     56 
     57     /* Trigger interrupt if any is pending */
     58     ir = uic->uicsr & uic->uicer & (~uic->uiccr);
     59     cr = uic->uicsr & uic->uicer & uic->uiccr;
     60     LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
     61                 " uiccr %08" PRIx32 "\n"
     62                 "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
     63                 __func__, uic->uicsr, uic->uicer, uic->uiccr,
     64                 uic->uicsr & uic->uicer, ir, cr);
     65     if (ir != 0x0000000) {
     66         LOG_UIC("Raise UIC interrupt\n");
     67         qemu_irq_raise(uic->output_int);
     68     } else {
     69         LOG_UIC("Lower UIC interrupt\n");
     70         qemu_irq_lower(uic->output_int);
     71     }
     72     /* Trigger critical interrupt if any is pending and update vector */
     73     if (cr != 0x0000000) {
     74         qemu_irq_raise(uic->output_cint);
     75         if (uic->use_vectors) {
     76             /* Compute critical IRQ vector */
     77             if (uic->uicvcr & 1) {
     78                 start = 31;
     79                 end = 0;
     80                 inc = -1;
     81             } else {
     82                 start = 0;
     83                 end = 31;
     84                 inc = 1;
     85             }
     86             uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
     87             for (i = start; i <= end; i += inc) {
     88                 if (cr & (1 << i)) {
     89                     uic->uicvr += (i - start) * 512 * inc;
     90                     break;
     91                 }
     92             }
     93         }
     94         LOG_UIC("Raise UIC critical interrupt - "
     95                     "vector %08" PRIx32 "\n", uic->uicvr);
     96     } else {
     97         LOG_UIC("Lower UIC critical interrupt\n");
     98         qemu_irq_lower(uic->output_cint);
     99         uic->uicvr = 0x00000000;
    100     }
    101 }
    102 
    103 static void ppcuic_set_irq(void *opaque, int irq_num, int level)
    104 {
    105     PPCUIC *uic = opaque;
    106     uint32_t mask, sr;
    107 
    108     mask = 1U << (31 - irq_num);
    109     LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
    110                 " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
    111                 __func__, irq_num, level,
    112                 uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
    113     if (irq_num < 0 || irq_num > 31) {
    114         return;
    115     }
    116     sr = uic->uicsr;
    117 
    118     /* Update status register */
    119     if (uic->uictr & mask) {
    120         /* Edge sensitive interrupt */
    121         if (level == 1) {
    122             uic->uicsr |= mask;
    123         }
    124     } else {
    125         /* Level sensitive interrupt */
    126         if (level == 1) {
    127             uic->uicsr |= mask;
    128             uic->level |= mask;
    129         } else {
    130             uic->uicsr &= ~mask;
    131             uic->level &= ~mask;
    132         }
    133     }
    134     LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
    135                 "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
    136     if (sr != uic->uicsr) {
    137         ppcuic_trigger_irq(uic);
    138     }
    139 }
    140 
    141 static uint32_t dcr_read_uic(void *opaque, int dcrn)
    142 {
    143     PPCUIC *uic = opaque;
    144     uint32_t ret;
    145 
    146     dcrn -= uic->dcr_base;
    147     switch (dcrn) {
    148     case DCR_UICSR:
    149     case DCR_UICSRS:
    150         ret = uic->uicsr;
    151         break;
    152     case DCR_UICER:
    153         ret = uic->uicer;
    154         break;
    155     case DCR_UICCR:
    156         ret = uic->uiccr;
    157         break;
    158     case DCR_UICPR:
    159         ret = uic->uicpr;
    160         break;
    161     case DCR_UICTR:
    162         ret = uic->uictr;
    163         break;
    164     case DCR_UICMSR:
    165         ret = uic->uicsr & uic->uicer;
    166         break;
    167     case DCR_UICVR:
    168         if (!uic->use_vectors) {
    169             goto no_read;
    170         }
    171         ret = uic->uicvr;
    172         break;
    173     case DCR_UICVCR:
    174         if (!uic->use_vectors) {
    175             goto no_read;
    176         }
    177         ret = uic->uicvcr;
    178         break;
    179     default:
    180     no_read:
    181         ret = 0x00000000;
    182         break;
    183     }
    184 
    185     return ret;
    186 }
    187 
    188 static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
    189 {
    190     PPCUIC *uic = opaque;
    191 
    192     dcrn -= uic->dcr_base;
    193     LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
    194     switch (dcrn) {
    195     case DCR_UICSR:
    196         uic->uicsr &= ~val;
    197         uic->uicsr |= uic->level;
    198         ppcuic_trigger_irq(uic);
    199         break;
    200     case DCR_UICSRS:
    201         uic->uicsr |= val;
    202         ppcuic_trigger_irq(uic);
    203         break;
    204     case DCR_UICER:
    205         uic->uicer = val;
    206         ppcuic_trigger_irq(uic);
    207         break;
    208     case DCR_UICCR:
    209         uic->uiccr = val;
    210         ppcuic_trigger_irq(uic);
    211         break;
    212     case DCR_UICPR:
    213         uic->uicpr = val;
    214         break;
    215     case DCR_UICTR:
    216         uic->uictr = val;
    217         ppcuic_trigger_irq(uic);
    218         break;
    219     case DCR_UICMSR:
    220         break;
    221     case DCR_UICVR:
    222         break;
    223     case DCR_UICVCR:
    224         uic->uicvcr = val & 0xFFFFFFFD;
    225         ppcuic_trigger_irq(uic);
    226         break;
    227     }
    228 }
    229 
    230 static void ppc_uic_reset(DeviceState *dev)
    231 {
    232     PPCUIC *uic = PPC_UIC(dev);
    233 
    234     uic->uiccr = 0x00000000;
    235     uic->uicer = 0x00000000;
    236     uic->uicpr = 0x00000000;
    237     uic->uicsr = 0x00000000;
    238     uic->uictr = 0x00000000;
    239     if (uic->use_vectors) {
    240         uic->uicvcr = 0x00000000;
    241         uic->uicvr = 0x0000000;
    242     }
    243 }
    244 
    245 static void ppc_uic_realize(DeviceState *dev, Error **errp)
    246 {
    247     PPCUIC *uic = PPC_UIC(dev);
    248     Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
    249     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    250     int i;
    251 
    252     for (i = 0; i < DCR_UICMAX; i++) {
    253         ppc4xx_dcr_register(dcr, uic->dcr_base + i, uic,
    254                          &dcr_read_uic, &dcr_write_uic);
    255     }
    256 
    257     sysbus_init_irq(sbd, &uic->output_int);
    258     sysbus_init_irq(sbd, &uic->output_cint);
    259     qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
    260 }
    261 
    262 static Property ppc_uic_properties[] = {
    263     DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0xc0),
    264     DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
    265     DEFINE_PROP_END_OF_LIST()
    266 };
    267 
    268 static const VMStateDescription ppc_uic_vmstate = {
    269     .name = "ppc-uic",
    270     .version_id = 1,
    271     .minimum_version_id = 1,
    272     .fields = (VMStateField[]) {
    273         VMSTATE_UINT32(level, PPCUIC),
    274         VMSTATE_UINT32(uicsr, PPCUIC),
    275         VMSTATE_UINT32(uicer, PPCUIC),
    276         VMSTATE_UINT32(uiccr, PPCUIC),
    277         VMSTATE_UINT32(uicpr, PPCUIC),
    278         VMSTATE_UINT32(uictr, PPCUIC),
    279         VMSTATE_UINT32(uicvcr, PPCUIC),
    280         VMSTATE_UINT32(uicvr, PPCUIC),
    281         VMSTATE_END_OF_LIST()
    282     },
    283 };
    284 
    285 static void ppc_uic_class_init(ObjectClass *klass, void *data)
    286 {
    287     DeviceClass *dc = DEVICE_CLASS(klass);
    288 
    289     dc->reset = ppc_uic_reset;
    290     dc->realize = ppc_uic_realize;
    291     dc->vmsd = &ppc_uic_vmstate;
    292     device_class_set_props(dc, ppc_uic_properties);
    293 }
    294 
    295 static const TypeInfo ppc_uic_info = {
    296     .name = TYPE_PPC_UIC,
    297     .parent = TYPE_PPC4xx_DCR_DEVICE,
    298     .instance_size = sizeof(PPCUIC),
    299     .class_init = ppc_uic_class_init,
    300 };
    301 
    302 static void ppc_uic_register_types(void)
    303 {
    304     type_register_static(&ppc_uic_info);
    305 }
    306 
    307 type_init(ppc_uic_register_types);