1*0f4fcf18SXiaojuan Yang /* SPDX-License-Identifier: GPL-2.0-or-later */ 2*0f4fcf18SXiaojuan Yang /* 3*0f4fcf18SXiaojuan Yang * QEMU Loongson 7A1000 I/O interrupt controller. 4*0f4fcf18SXiaojuan Yang * 5*0f4fcf18SXiaojuan Yang * Copyright (C) 2021 Loongson Technology Corporation Limited 6*0f4fcf18SXiaojuan Yang */ 7*0f4fcf18SXiaojuan Yang 8*0f4fcf18SXiaojuan Yang #include "qemu/osdep.h" 9*0f4fcf18SXiaojuan Yang #include "hw/sysbus.h" 10*0f4fcf18SXiaojuan Yang #include "hw/loongarch/virt.h" 11*0f4fcf18SXiaojuan Yang #include "hw/irq.h" 12*0f4fcf18SXiaojuan Yang #include "hw/intc/loongarch_pch_pic.h" 13*0f4fcf18SXiaojuan Yang #include "migration/vmstate.h" 14*0f4fcf18SXiaojuan Yang #include "trace.h" 15*0f4fcf18SXiaojuan Yang 16*0f4fcf18SXiaojuan Yang static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) 17*0f4fcf18SXiaojuan Yang { 18*0f4fcf18SXiaojuan Yang unsigned long val; 19*0f4fcf18SXiaojuan Yang int irq; 20*0f4fcf18SXiaojuan Yang 21*0f4fcf18SXiaojuan Yang if (level) { 22*0f4fcf18SXiaojuan Yang val = mask & s->intirr & ~s->int_mask; 23*0f4fcf18SXiaojuan Yang if (val) { 24*0f4fcf18SXiaojuan Yang irq = find_first_bit(&val, 64); 25*0f4fcf18SXiaojuan Yang s->intisr |= 0x1ULL << irq; 26*0f4fcf18SXiaojuan Yang qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); 27*0f4fcf18SXiaojuan Yang } 28*0f4fcf18SXiaojuan Yang } else { 29*0f4fcf18SXiaojuan Yang val = mask & s->intisr; 30*0f4fcf18SXiaojuan Yang if (val) { 31*0f4fcf18SXiaojuan Yang irq = find_first_bit(&val, 64); 32*0f4fcf18SXiaojuan Yang s->intisr &= ~(0x1ULL << irq); 33*0f4fcf18SXiaojuan Yang qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); 34*0f4fcf18SXiaojuan Yang } 35*0f4fcf18SXiaojuan Yang } 36*0f4fcf18SXiaojuan Yang } 37*0f4fcf18SXiaojuan Yang 38*0f4fcf18SXiaojuan Yang static void pch_pic_irq_handler(void *opaque, int irq, int level) 39*0f4fcf18SXiaojuan Yang { 40*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 41*0f4fcf18SXiaojuan Yang uint64_t mask = 1ULL << irq; 42*0f4fcf18SXiaojuan Yang 43*0f4fcf18SXiaojuan Yang assert(irq < PCH_PIC_IRQ_NUM); 44*0f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_irq_handler(irq, level); 45*0f4fcf18SXiaojuan Yang 46*0f4fcf18SXiaojuan Yang if (s->intedge & mask) { 47*0f4fcf18SXiaojuan Yang /* Edge triggered */ 48*0f4fcf18SXiaojuan Yang if (level) { 49*0f4fcf18SXiaojuan Yang if ((s->last_intirr & mask) == 0) { 50*0f4fcf18SXiaojuan Yang s->intirr |= mask; 51*0f4fcf18SXiaojuan Yang } 52*0f4fcf18SXiaojuan Yang s->last_intirr |= mask; 53*0f4fcf18SXiaojuan Yang } else { 54*0f4fcf18SXiaojuan Yang s->last_intirr &= ~mask; 55*0f4fcf18SXiaojuan Yang } 56*0f4fcf18SXiaojuan Yang } else { 57*0f4fcf18SXiaojuan Yang /* Level triggered */ 58*0f4fcf18SXiaojuan Yang if (level) { 59*0f4fcf18SXiaojuan Yang s->intirr |= mask; 60*0f4fcf18SXiaojuan Yang s->last_intirr |= mask; 61*0f4fcf18SXiaojuan Yang } else { 62*0f4fcf18SXiaojuan Yang s->intirr &= ~mask; 63*0f4fcf18SXiaojuan Yang s->last_intirr &= ~mask; 64*0f4fcf18SXiaojuan Yang } 65*0f4fcf18SXiaojuan Yang } 66*0f4fcf18SXiaojuan Yang pch_pic_update_irq(s, mask, level); 67*0f4fcf18SXiaojuan Yang } 68*0f4fcf18SXiaojuan Yang 69*0f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, 70*0f4fcf18SXiaojuan Yang unsigned size) 71*0f4fcf18SXiaojuan Yang { 72*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 73*0f4fcf18SXiaojuan Yang uint64_t val = 0; 74*0f4fcf18SXiaojuan Yang uint32_t offset = addr & 0xfff; 75*0f4fcf18SXiaojuan Yang 76*0f4fcf18SXiaojuan Yang switch (offset) { 77*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_ID_LO: 78*0f4fcf18SXiaojuan Yang val = PCH_PIC_INT_ID_VAL; 79*0f4fcf18SXiaojuan Yang break; 80*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_ID_HI: 81*0f4fcf18SXiaojuan Yang val = PCH_PIC_INT_ID_NUM; 82*0f4fcf18SXiaojuan Yang break; 83*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_MASK_LO: 84*0f4fcf18SXiaojuan Yang val = (uint32_t)s->int_mask; 85*0f4fcf18SXiaojuan Yang break; 86*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_MASK_HI: 87*0f4fcf18SXiaojuan Yang val = s->int_mask >> 32; 88*0f4fcf18SXiaojuan Yang break; 89*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_EDGE_LO: 90*0f4fcf18SXiaojuan Yang val = (uint32_t)s->intedge; 91*0f4fcf18SXiaojuan Yang break; 92*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_EDGE_HI: 93*0f4fcf18SXiaojuan Yang val = s->intedge >> 32; 94*0f4fcf18SXiaojuan Yang break; 95*0f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_EN_LO: 96*0f4fcf18SXiaojuan Yang val = (uint32_t)s->htmsi_en; 97*0f4fcf18SXiaojuan Yang break; 98*0f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_EN_HI: 99*0f4fcf18SXiaojuan Yang val = s->htmsi_en >> 32; 100*0f4fcf18SXiaojuan Yang break; 101*0f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL0_LO: 102*0f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL0_HI: 103*0f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL1_LO: 104*0f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL1_HI: 105*0f4fcf18SXiaojuan Yang break; 106*0f4fcf18SXiaojuan Yang default: 107*0f4fcf18SXiaojuan Yang break; 108*0f4fcf18SXiaojuan Yang } 109*0f4fcf18SXiaojuan Yang 110*0f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_low_readw(size, addr, val); 111*0f4fcf18SXiaojuan Yang return val; 112*0f4fcf18SXiaojuan Yang } 113*0f4fcf18SXiaojuan Yang 114*0f4fcf18SXiaojuan Yang static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi) 115*0f4fcf18SXiaojuan Yang { 116*0f4fcf18SXiaojuan Yang uint64_t mask = 0xffffffff00000000; 117*0f4fcf18SXiaojuan Yang uint64_t data = target; 118*0f4fcf18SXiaojuan Yang 119*0f4fcf18SXiaojuan Yang return hi ? (value & ~mask) | (data << 32) : (value & mask) | data; 120*0f4fcf18SXiaojuan Yang } 121*0f4fcf18SXiaojuan Yang 122*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, 123*0f4fcf18SXiaojuan Yang uint64_t value, unsigned size) 124*0f4fcf18SXiaojuan Yang { 125*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 126*0f4fcf18SXiaojuan Yang uint32_t offset, old_valid, data = (uint32_t)value; 127*0f4fcf18SXiaojuan Yang uint64_t old, int_mask; 128*0f4fcf18SXiaojuan Yang offset = addr & 0xfff; 129*0f4fcf18SXiaojuan Yang 130*0f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_low_writew(size, addr, data); 131*0f4fcf18SXiaojuan Yang 132*0f4fcf18SXiaojuan Yang switch (offset) { 133*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_MASK_LO: 134*0f4fcf18SXiaojuan Yang old = s->int_mask; 135*0f4fcf18SXiaojuan Yang s->int_mask = get_writew_val(old, data, 0); 136*0f4fcf18SXiaojuan Yang old_valid = (uint32_t)old; 137*0f4fcf18SXiaojuan Yang if (old_valid & ~data) { 138*0f4fcf18SXiaojuan Yang pch_pic_update_irq(s, (old_valid & ~data), 1); 139*0f4fcf18SXiaojuan Yang } 140*0f4fcf18SXiaojuan Yang if (~old_valid & data) { 141*0f4fcf18SXiaojuan Yang pch_pic_update_irq(s, (~old_valid & data), 0); 142*0f4fcf18SXiaojuan Yang } 143*0f4fcf18SXiaojuan Yang break; 144*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_MASK_HI: 145*0f4fcf18SXiaojuan Yang old = s->int_mask; 146*0f4fcf18SXiaojuan Yang s->int_mask = get_writew_val(old, data, 1); 147*0f4fcf18SXiaojuan Yang old_valid = (uint32_t)(old >> 32); 148*0f4fcf18SXiaojuan Yang int_mask = old_valid & ~data; 149*0f4fcf18SXiaojuan Yang if (int_mask) { 150*0f4fcf18SXiaojuan Yang pch_pic_update_irq(s, int_mask << 32, 1); 151*0f4fcf18SXiaojuan Yang } 152*0f4fcf18SXiaojuan Yang int_mask = ~old_valid & data; 153*0f4fcf18SXiaojuan Yang if (int_mask) { 154*0f4fcf18SXiaojuan Yang pch_pic_update_irq(s, int_mask << 32, 0); 155*0f4fcf18SXiaojuan Yang } 156*0f4fcf18SXiaojuan Yang break; 157*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_EDGE_LO: 158*0f4fcf18SXiaojuan Yang s->intedge = get_writew_val(s->intedge, data, 0); 159*0f4fcf18SXiaojuan Yang break; 160*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_EDGE_HI: 161*0f4fcf18SXiaojuan Yang s->intedge = get_writew_val(s->intedge, data, 1); 162*0f4fcf18SXiaojuan Yang break; 163*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_CLEAR_LO: 164*0f4fcf18SXiaojuan Yang if (s->intedge & data) { 165*0f4fcf18SXiaojuan Yang s->intirr &= (~data); 166*0f4fcf18SXiaojuan Yang pch_pic_update_irq(s, data, 0); 167*0f4fcf18SXiaojuan Yang s->intisr &= (~data); 168*0f4fcf18SXiaojuan Yang } 169*0f4fcf18SXiaojuan Yang break; 170*0f4fcf18SXiaojuan Yang case PCH_PIC_INT_CLEAR_HI: 171*0f4fcf18SXiaojuan Yang value <<= 32; 172*0f4fcf18SXiaojuan Yang if (s->intedge & value) { 173*0f4fcf18SXiaojuan Yang s->intirr &= (~value); 174*0f4fcf18SXiaojuan Yang pch_pic_update_irq(s, value, 0); 175*0f4fcf18SXiaojuan Yang s->intisr &= (~value); 176*0f4fcf18SXiaojuan Yang } 177*0f4fcf18SXiaojuan Yang break; 178*0f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_EN_LO: 179*0f4fcf18SXiaojuan Yang s->htmsi_en = get_writew_val(s->htmsi_en, data, 0); 180*0f4fcf18SXiaojuan Yang break; 181*0f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_EN_HI: 182*0f4fcf18SXiaojuan Yang s->htmsi_en = get_writew_val(s->htmsi_en, data, 1); 183*0f4fcf18SXiaojuan Yang break; 184*0f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL0_LO: 185*0f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL0_HI: 186*0f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL1_LO: 187*0f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL1_HI: 188*0f4fcf18SXiaojuan Yang break; 189*0f4fcf18SXiaojuan Yang default: 190*0f4fcf18SXiaojuan Yang break; 191*0f4fcf18SXiaojuan Yang } 192*0f4fcf18SXiaojuan Yang } 193*0f4fcf18SXiaojuan Yang 194*0f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, 195*0f4fcf18SXiaojuan Yang unsigned size) 196*0f4fcf18SXiaojuan Yang { 197*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 198*0f4fcf18SXiaojuan Yang uint64_t val = 0; 199*0f4fcf18SXiaojuan Yang uint32_t offset = addr & 0xfff; 200*0f4fcf18SXiaojuan Yang 201*0f4fcf18SXiaojuan Yang switch (offset) { 202*0f4fcf18SXiaojuan Yang case STATUS_LO_START: 203*0f4fcf18SXiaojuan Yang val = (uint32_t)(s->intisr & (~s->int_mask)); 204*0f4fcf18SXiaojuan Yang break; 205*0f4fcf18SXiaojuan Yang case STATUS_HI_START: 206*0f4fcf18SXiaojuan Yang val = (s->intisr & (~s->int_mask)) >> 32; 207*0f4fcf18SXiaojuan Yang break; 208*0f4fcf18SXiaojuan Yang case POL_LO_START: 209*0f4fcf18SXiaojuan Yang val = (uint32_t)s->int_polarity; 210*0f4fcf18SXiaojuan Yang break; 211*0f4fcf18SXiaojuan Yang case POL_HI_START: 212*0f4fcf18SXiaojuan Yang val = s->int_polarity >> 32; 213*0f4fcf18SXiaojuan Yang break; 214*0f4fcf18SXiaojuan Yang default: 215*0f4fcf18SXiaojuan Yang break; 216*0f4fcf18SXiaojuan Yang } 217*0f4fcf18SXiaojuan Yang 218*0f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_high_readw(size, addr, val); 219*0f4fcf18SXiaojuan Yang return val; 220*0f4fcf18SXiaojuan Yang } 221*0f4fcf18SXiaojuan Yang 222*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, 223*0f4fcf18SXiaojuan Yang uint64_t value, unsigned size) 224*0f4fcf18SXiaojuan Yang { 225*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 226*0f4fcf18SXiaojuan Yang uint32_t offset, data = (uint32_t)value; 227*0f4fcf18SXiaojuan Yang offset = addr & 0xfff; 228*0f4fcf18SXiaojuan Yang 229*0f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_high_writew(size, addr, data); 230*0f4fcf18SXiaojuan Yang 231*0f4fcf18SXiaojuan Yang switch (offset) { 232*0f4fcf18SXiaojuan Yang case STATUS_LO_START: 233*0f4fcf18SXiaojuan Yang s->intisr = get_writew_val(s->intisr, data, 0); 234*0f4fcf18SXiaojuan Yang break; 235*0f4fcf18SXiaojuan Yang case STATUS_HI_START: 236*0f4fcf18SXiaojuan Yang s->intisr = get_writew_val(s->intisr, data, 1); 237*0f4fcf18SXiaojuan Yang break; 238*0f4fcf18SXiaojuan Yang case POL_LO_START: 239*0f4fcf18SXiaojuan Yang s->int_polarity = get_writew_val(s->int_polarity, data, 0); 240*0f4fcf18SXiaojuan Yang break; 241*0f4fcf18SXiaojuan Yang case POL_HI_START: 242*0f4fcf18SXiaojuan Yang s->int_polarity = get_writew_val(s->int_polarity, data, 1); 243*0f4fcf18SXiaojuan Yang break; 244*0f4fcf18SXiaojuan Yang default: 245*0f4fcf18SXiaojuan Yang break; 246*0f4fcf18SXiaojuan Yang } 247*0f4fcf18SXiaojuan Yang } 248*0f4fcf18SXiaojuan Yang 249*0f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, 250*0f4fcf18SXiaojuan Yang unsigned size) 251*0f4fcf18SXiaojuan Yang { 252*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 253*0f4fcf18SXiaojuan Yang uint64_t val = 0; 254*0f4fcf18SXiaojuan Yang uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; 255*0f4fcf18SXiaojuan Yang int64_t offset_tmp; 256*0f4fcf18SXiaojuan Yang 257*0f4fcf18SXiaojuan Yang switch (offset) { 258*0f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: 259*0f4fcf18SXiaojuan Yang offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; 260*0f4fcf18SXiaojuan Yang if (offset_tmp >= 0 && offset_tmp < 64) { 261*0f4fcf18SXiaojuan Yang val = s->htmsi_vector[offset_tmp]; 262*0f4fcf18SXiaojuan Yang } 263*0f4fcf18SXiaojuan Yang break; 264*0f4fcf18SXiaojuan Yang case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: 265*0f4fcf18SXiaojuan Yang offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; 266*0f4fcf18SXiaojuan Yang if (offset_tmp >= 0 && offset_tmp < 64) { 267*0f4fcf18SXiaojuan Yang val = s->route_entry[offset_tmp]; 268*0f4fcf18SXiaojuan Yang } 269*0f4fcf18SXiaojuan Yang break; 270*0f4fcf18SXiaojuan Yang default: 271*0f4fcf18SXiaojuan Yang break; 272*0f4fcf18SXiaojuan Yang } 273*0f4fcf18SXiaojuan Yang 274*0f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_readb(size, addr, val); 275*0f4fcf18SXiaojuan Yang return val; 276*0f4fcf18SXiaojuan Yang } 277*0f4fcf18SXiaojuan Yang 278*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, 279*0f4fcf18SXiaojuan Yang uint64_t data, unsigned size) 280*0f4fcf18SXiaojuan Yang { 281*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 282*0f4fcf18SXiaojuan Yang int32_t offset_tmp; 283*0f4fcf18SXiaojuan Yang uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; 284*0f4fcf18SXiaojuan Yang 285*0f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_writeb(size, addr, data); 286*0f4fcf18SXiaojuan Yang 287*0f4fcf18SXiaojuan Yang switch (offset) { 288*0f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: 289*0f4fcf18SXiaojuan Yang offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; 290*0f4fcf18SXiaojuan Yang if (offset_tmp >= 0 && offset_tmp < 64) { 291*0f4fcf18SXiaojuan Yang s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); 292*0f4fcf18SXiaojuan Yang } 293*0f4fcf18SXiaojuan Yang break; 294*0f4fcf18SXiaojuan Yang case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: 295*0f4fcf18SXiaojuan Yang offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; 296*0f4fcf18SXiaojuan Yang if (offset_tmp >= 0 && offset_tmp < 64) { 297*0f4fcf18SXiaojuan Yang s->route_entry[offset_tmp] = (uint8_t)(data & 0xff); 298*0f4fcf18SXiaojuan Yang } 299*0f4fcf18SXiaojuan Yang break; 300*0f4fcf18SXiaojuan Yang default: 301*0f4fcf18SXiaojuan Yang break; 302*0f4fcf18SXiaojuan Yang } 303*0f4fcf18SXiaojuan Yang } 304*0f4fcf18SXiaojuan Yang 305*0f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = { 306*0f4fcf18SXiaojuan Yang .read = loongarch_pch_pic_low_readw, 307*0f4fcf18SXiaojuan Yang .write = loongarch_pch_pic_low_writew, 308*0f4fcf18SXiaojuan Yang .valid = { 309*0f4fcf18SXiaojuan Yang .min_access_size = 4, 310*0f4fcf18SXiaojuan Yang .max_access_size = 8, 311*0f4fcf18SXiaojuan Yang }, 312*0f4fcf18SXiaojuan Yang .impl = { 313*0f4fcf18SXiaojuan Yang .min_access_size = 4, 314*0f4fcf18SXiaojuan Yang .max_access_size = 4, 315*0f4fcf18SXiaojuan Yang }, 316*0f4fcf18SXiaojuan Yang .endianness = DEVICE_LITTLE_ENDIAN, 317*0f4fcf18SXiaojuan Yang }; 318*0f4fcf18SXiaojuan Yang 319*0f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = { 320*0f4fcf18SXiaojuan Yang .read = loongarch_pch_pic_high_readw, 321*0f4fcf18SXiaojuan Yang .write = loongarch_pch_pic_high_writew, 322*0f4fcf18SXiaojuan Yang .valid = { 323*0f4fcf18SXiaojuan Yang .min_access_size = 4, 324*0f4fcf18SXiaojuan Yang .max_access_size = 8, 325*0f4fcf18SXiaojuan Yang }, 326*0f4fcf18SXiaojuan Yang .impl = { 327*0f4fcf18SXiaojuan Yang .min_access_size = 4, 328*0f4fcf18SXiaojuan Yang .max_access_size = 4, 329*0f4fcf18SXiaojuan Yang }, 330*0f4fcf18SXiaojuan Yang .endianness = DEVICE_LITTLE_ENDIAN, 331*0f4fcf18SXiaojuan Yang }; 332*0f4fcf18SXiaojuan Yang 333*0f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg8_ops = { 334*0f4fcf18SXiaojuan Yang .read = loongarch_pch_pic_readb, 335*0f4fcf18SXiaojuan Yang .write = loongarch_pch_pic_writeb, 336*0f4fcf18SXiaojuan Yang .valid = { 337*0f4fcf18SXiaojuan Yang .min_access_size = 1, 338*0f4fcf18SXiaojuan Yang .max_access_size = 1, 339*0f4fcf18SXiaojuan Yang }, 340*0f4fcf18SXiaojuan Yang .impl = { 341*0f4fcf18SXiaojuan Yang .min_access_size = 1, 342*0f4fcf18SXiaojuan Yang .max_access_size = 1, 343*0f4fcf18SXiaojuan Yang }, 344*0f4fcf18SXiaojuan Yang .endianness = DEVICE_LITTLE_ENDIAN, 345*0f4fcf18SXiaojuan Yang }; 346*0f4fcf18SXiaojuan Yang 347*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_reset(DeviceState *d) 348*0f4fcf18SXiaojuan Yang { 349*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d); 350*0f4fcf18SXiaojuan Yang int i; 351*0f4fcf18SXiaojuan Yang 352*0f4fcf18SXiaojuan Yang s->int_mask = -1; 353*0f4fcf18SXiaojuan Yang s->htmsi_en = 0x0; 354*0f4fcf18SXiaojuan Yang s->intedge = 0x0; 355*0f4fcf18SXiaojuan Yang s->intclr = 0x0; 356*0f4fcf18SXiaojuan Yang s->auto_crtl0 = 0x0; 357*0f4fcf18SXiaojuan Yang s->auto_crtl1 = 0x0; 358*0f4fcf18SXiaojuan Yang for (i = 0; i < 64; i++) { 359*0f4fcf18SXiaojuan Yang s->route_entry[i] = 0x1; 360*0f4fcf18SXiaojuan Yang s->htmsi_vector[i] = 0x0; 361*0f4fcf18SXiaojuan Yang } 362*0f4fcf18SXiaojuan Yang s->intirr = 0x0; 363*0f4fcf18SXiaojuan Yang s->intisr = 0x0; 364*0f4fcf18SXiaojuan Yang s->last_intirr = 0x0; 365*0f4fcf18SXiaojuan Yang s->int_polarity = 0x0; 366*0f4fcf18SXiaojuan Yang } 367*0f4fcf18SXiaojuan Yang 368*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_init(Object *obj) 369*0f4fcf18SXiaojuan Yang { 370*0f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj); 371*0f4fcf18SXiaojuan Yang SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 372*0f4fcf18SXiaojuan Yang 373*0f4fcf18SXiaojuan Yang memory_region_init_io(&s->iomem32_low, obj, 374*0f4fcf18SXiaojuan Yang &loongarch_pch_pic_reg32_low_ops, 375*0f4fcf18SXiaojuan Yang s, PCH_PIC_NAME(.reg32_part1), 0x100); 376*0f4fcf18SXiaojuan Yang memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops, 377*0f4fcf18SXiaojuan Yang s, PCH_PIC_NAME(.reg8), 0x2a0); 378*0f4fcf18SXiaojuan Yang memory_region_init_io(&s->iomem32_high, obj, 379*0f4fcf18SXiaojuan Yang &loongarch_pch_pic_reg32_high_ops, 380*0f4fcf18SXiaojuan Yang s, PCH_PIC_NAME(.reg32_part2), 0xc60); 381*0f4fcf18SXiaojuan Yang sysbus_init_mmio(sbd, &s->iomem32_low); 382*0f4fcf18SXiaojuan Yang sysbus_init_mmio(sbd, &s->iomem8); 383*0f4fcf18SXiaojuan Yang sysbus_init_mmio(sbd, &s->iomem32_high); 384*0f4fcf18SXiaojuan Yang 385*0f4fcf18SXiaojuan Yang qdev_init_gpio_out(DEVICE(obj), s->parent_irq, PCH_PIC_IRQ_NUM); 386*0f4fcf18SXiaojuan Yang qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM); 387*0f4fcf18SXiaojuan Yang } 388*0f4fcf18SXiaojuan Yang 389*0f4fcf18SXiaojuan Yang static const VMStateDescription vmstate_loongarch_pch_pic = { 390*0f4fcf18SXiaojuan Yang .name = TYPE_LOONGARCH_PCH_PIC, 391*0f4fcf18SXiaojuan Yang .version_id = 1, 392*0f4fcf18SXiaojuan Yang .minimum_version_id = 1, 393*0f4fcf18SXiaojuan Yang .fields = (VMStateField[]) { 394*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(int_mask, LoongArchPCHPIC), 395*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC), 396*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(intedge, LoongArchPCHPIC), 397*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(intclr, LoongArchPCHPIC), 398*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC), 399*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC), 400*0f4fcf18SXiaojuan Yang VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64), 401*0f4fcf18SXiaojuan Yang VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64), 402*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(last_intirr, LoongArchPCHPIC), 403*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(intirr, LoongArchPCHPIC), 404*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(intisr, LoongArchPCHPIC), 405*0f4fcf18SXiaojuan Yang VMSTATE_UINT64(int_polarity, LoongArchPCHPIC), 406*0f4fcf18SXiaojuan Yang VMSTATE_END_OF_LIST() 407*0f4fcf18SXiaojuan Yang } 408*0f4fcf18SXiaojuan Yang }; 409*0f4fcf18SXiaojuan Yang 410*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data) 411*0f4fcf18SXiaojuan Yang { 412*0f4fcf18SXiaojuan Yang DeviceClass *dc = DEVICE_CLASS(klass); 413*0f4fcf18SXiaojuan Yang 414*0f4fcf18SXiaojuan Yang dc->reset = loongarch_pch_pic_reset; 415*0f4fcf18SXiaojuan Yang dc->vmsd = &vmstate_loongarch_pch_pic; 416*0f4fcf18SXiaojuan Yang } 417*0f4fcf18SXiaojuan Yang 418*0f4fcf18SXiaojuan Yang static const TypeInfo loongarch_pch_pic_info = { 419*0f4fcf18SXiaojuan Yang .name = TYPE_LOONGARCH_PCH_PIC, 420*0f4fcf18SXiaojuan Yang .parent = TYPE_SYS_BUS_DEVICE, 421*0f4fcf18SXiaojuan Yang .instance_size = sizeof(LoongArchPCHPIC), 422*0f4fcf18SXiaojuan Yang .instance_init = loongarch_pch_pic_init, 423*0f4fcf18SXiaojuan Yang .class_init = loongarch_pch_pic_class_init, 424*0f4fcf18SXiaojuan Yang }; 425*0f4fcf18SXiaojuan Yang 426*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_register_types(void) 427*0f4fcf18SXiaojuan Yang { 428*0f4fcf18SXiaojuan Yang type_register_static(&loongarch_pch_pic_info); 429*0f4fcf18SXiaojuan Yang } 430*0f4fcf18SXiaojuan Yang 431*0f4fcf18SXiaojuan Yang type_init(loongarch_pch_pic_register_types) 432