12ecf1726SCédric Le Goater /* 22ecf1726SCédric Le Goater * ASPEED LPC Controller 32ecf1726SCédric Le Goater * 42ecf1726SCédric Le Goater * Copyright (C) 2017-2018 IBM Corp. 52ecf1726SCédric Le Goater * 62ecf1726SCédric Le Goater * This code is licensed under the GPL version 2 or later. See 72ecf1726SCédric Le Goater * the COPYING file in the top-level directory. 82ecf1726SCédric Le Goater */ 92ecf1726SCédric Le Goater 102ecf1726SCédric Le Goater #include "qemu/osdep.h" 112ecf1726SCédric Le Goater #include "qemu/log.h" 122ecf1726SCédric Le Goater #include "qemu/error-report.h" 132ecf1726SCédric Le Goater #include "hw/misc/aspeed_lpc.h" 142ecf1726SCédric Le Goater #include "qapi/error.h" 15*c59f781eSAndrew Jeffery #include "qapi/visitor.h" 16*c59f781eSAndrew Jeffery #include "hw/irq.h" 172ecf1726SCédric Le Goater #include "hw/qdev-properties.h" 182ecf1726SCédric Le Goater #include "migration/vmstate.h" 192ecf1726SCédric Le Goater 202ecf1726SCédric Le Goater #define TO_REG(offset) ((offset) >> 2) 212ecf1726SCédric Le Goater 222ecf1726SCédric Le Goater #define HICR0 TO_REG(0x00) 23*c59f781eSAndrew Jeffery #define HICR0_LPC3E BIT(7) 24*c59f781eSAndrew Jeffery #define HICR0_LPC2E BIT(6) 25*c59f781eSAndrew Jeffery #define HICR0_LPC1E BIT(5) 262ecf1726SCédric Le Goater #define HICR1 TO_REG(0x04) 272ecf1726SCédric Le Goater #define HICR2 TO_REG(0x08) 28*c59f781eSAndrew Jeffery #define HICR2_IBFIE3 BIT(3) 29*c59f781eSAndrew Jeffery #define HICR2_IBFIE2 BIT(2) 30*c59f781eSAndrew Jeffery #define HICR2_IBFIE1 BIT(1) 312ecf1726SCédric Le Goater #define HICR3 TO_REG(0x0C) 322ecf1726SCédric Le Goater #define HICR4 TO_REG(0x10) 33*c59f781eSAndrew Jeffery #define HICR4_KCSENBL BIT(2) 34*c59f781eSAndrew Jeffery #define IDR1 TO_REG(0x24) 35*c59f781eSAndrew Jeffery #define IDR2 TO_REG(0x28) 36*c59f781eSAndrew Jeffery #define IDR3 TO_REG(0x2C) 37*c59f781eSAndrew Jeffery #define ODR1 TO_REG(0x30) 38*c59f781eSAndrew Jeffery #define ODR2 TO_REG(0x34) 39*c59f781eSAndrew Jeffery #define ODR3 TO_REG(0x38) 40*c59f781eSAndrew Jeffery #define STR1 TO_REG(0x3C) 41*c59f781eSAndrew Jeffery #define STR_OBF BIT(0) 42*c59f781eSAndrew Jeffery #define STR_IBF BIT(1) 43*c59f781eSAndrew Jeffery #define STR_CMD_DATA BIT(3) 44*c59f781eSAndrew Jeffery #define STR2 TO_REG(0x40) 45*c59f781eSAndrew Jeffery #define STR3 TO_REG(0x44) 462ecf1726SCédric Le Goater #define HICR5 TO_REG(0x80) 472ecf1726SCédric Le Goater #define HICR6 TO_REG(0x84) 482ecf1726SCédric Le Goater #define HICR7 TO_REG(0x88) 492ecf1726SCédric Le Goater #define HICR8 TO_REG(0x8C) 50*c59f781eSAndrew Jeffery #define HICRB TO_REG(0x100) 51*c59f781eSAndrew Jeffery #define HICRB_IBFIE4 BIT(1) 52*c59f781eSAndrew Jeffery #define HICRB_LPC4E BIT(0) 53*c59f781eSAndrew Jeffery #define IDR4 TO_REG(0x114) 54*c59f781eSAndrew Jeffery #define ODR4 TO_REG(0x118) 55*c59f781eSAndrew Jeffery #define STR4 TO_REG(0x11C) 56*c59f781eSAndrew Jeffery 57*c59f781eSAndrew Jeffery enum aspeed_kcs_channel_id { 58*c59f781eSAndrew Jeffery kcs_channel_1 = 0, 59*c59f781eSAndrew Jeffery kcs_channel_2, 60*c59f781eSAndrew Jeffery kcs_channel_3, 61*c59f781eSAndrew Jeffery kcs_channel_4, 62*c59f781eSAndrew Jeffery }; 63*c59f781eSAndrew Jeffery 64*c59f781eSAndrew Jeffery static const enum aspeed_lpc_subdevice aspeed_kcs_subdevice_map[] = { 65*c59f781eSAndrew Jeffery [kcs_channel_1] = aspeed_lpc_kcs_1, 66*c59f781eSAndrew Jeffery [kcs_channel_2] = aspeed_lpc_kcs_2, 67*c59f781eSAndrew Jeffery [kcs_channel_3] = aspeed_lpc_kcs_3, 68*c59f781eSAndrew Jeffery [kcs_channel_4] = aspeed_lpc_kcs_4, 69*c59f781eSAndrew Jeffery }; 70*c59f781eSAndrew Jeffery 71*c59f781eSAndrew Jeffery struct aspeed_kcs_channel { 72*c59f781eSAndrew Jeffery enum aspeed_kcs_channel_id id; 73*c59f781eSAndrew Jeffery 74*c59f781eSAndrew Jeffery int idr; 75*c59f781eSAndrew Jeffery int odr; 76*c59f781eSAndrew Jeffery int str; 77*c59f781eSAndrew Jeffery }; 78*c59f781eSAndrew Jeffery 79*c59f781eSAndrew Jeffery static const struct aspeed_kcs_channel aspeed_kcs_channel_map[] = { 80*c59f781eSAndrew Jeffery [kcs_channel_1] = { 81*c59f781eSAndrew Jeffery .id = kcs_channel_1, 82*c59f781eSAndrew Jeffery .idr = IDR1, 83*c59f781eSAndrew Jeffery .odr = ODR1, 84*c59f781eSAndrew Jeffery .str = STR1 85*c59f781eSAndrew Jeffery }, 86*c59f781eSAndrew Jeffery 87*c59f781eSAndrew Jeffery [kcs_channel_2] = { 88*c59f781eSAndrew Jeffery .id = kcs_channel_2, 89*c59f781eSAndrew Jeffery .idr = IDR2, 90*c59f781eSAndrew Jeffery .odr = ODR2, 91*c59f781eSAndrew Jeffery .str = STR2 92*c59f781eSAndrew Jeffery }, 93*c59f781eSAndrew Jeffery 94*c59f781eSAndrew Jeffery [kcs_channel_3] = { 95*c59f781eSAndrew Jeffery .id = kcs_channel_3, 96*c59f781eSAndrew Jeffery .idr = IDR3, 97*c59f781eSAndrew Jeffery .odr = ODR3, 98*c59f781eSAndrew Jeffery .str = STR3 99*c59f781eSAndrew Jeffery }, 100*c59f781eSAndrew Jeffery 101*c59f781eSAndrew Jeffery [kcs_channel_4] = { 102*c59f781eSAndrew Jeffery .id = kcs_channel_4, 103*c59f781eSAndrew Jeffery .idr = IDR4, 104*c59f781eSAndrew Jeffery .odr = ODR4, 105*c59f781eSAndrew Jeffery .str = STR4 106*c59f781eSAndrew Jeffery }, 107*c59f781eSAndrew Jeffery }; 108*c59f781eSAndrew Jeffery 109*c59f781eSAndrew Jeffery struct aspeed_kcs_register_data { 110*c59f781eSAndrew Jeffery const char *name; 111*c59f781eSAndrew Jeffery int reg; 112*c59f781eSAndrew Jeffery const struct aspeed_kcs_channel *chan; 113*c59f781eSAndrew Jeffery }; 114*c59f781eSAndrew Jeffery 115*c59f781eSAndrew Jeffery static const struct aspeed_kcs_register_data aspeed_kcs_registers[] = { 116*c59f781eSAndrew Jeffery { 117*c59f781eSAndrew Jeffery .name = "idr1", 118*c59f781eSAndrew Jeffery .reg = IDR1, 119*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_1], 120*c59f781eSAndrew Jeffery }, 121*c59f781eSAndrew Jeffery { 122*c59f781eSAndrew Jeffery .name = "odr1", 123*c59f781eSAndrew Jeffery .reg = ODR1, 124*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_1], 125*c59f781eSAndrew Jeffery }, 126*c59f781eSAndrew Jeffery { 127*c59f781eSAndrew Jeffery .name = "str1", 128*c59f781eSAndrew Jeffery .reg = STR1, 129*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_1], 130*c59f781eSAndrew Jeffery }, 131*c59f781eSAndrew Jeffery { 132*c59f781eSAndrew Jeffery .name = "idr2", 133*c59f781eSAndrew Jeffery .reg = IDR2, 134*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_2], 135*c59f781eSAndrew Jeffery }, 136*c59f781eSAndrew Jeffery { 137*c59f781eSAndrew Jeffery .name = "odr2", 138*c59f781eSAndrew Jeffery .reg = ODR2, 139*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_2], 140*c59f781eSAndrew Jeffery }, 141*c59f781eSAndrew Jeffery { 142*c59f781eSAndrew Jeffery .name = "str2", 143*c59f781eSAndrew Jeffery .reg = STR2, 144*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_2], 145*c59f781eSAndrew Jeffery }, 146*c59f781eSAndrew Jeffery { 147*c59f781eSAndrew Jeffery .name = "idr3", 148*c59f781eSAndrew Jeffery .reg = IDR3, 149*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_3], 150*c59f781eSAndrew Jeffery }, 151*c59f781eSAndrew Jeffery { 152*c59f781eSAndrew Jeffery .name = "odr3", 153*c59f781eSAndrew Jeffery .reg = ODR3, 154*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_3], 155*c59f781eSAndrew Jeffery }, 156*c59f781eSAndrew Jeffery { 157*c59f781eSAndrew Jeffery .name = "str3", 158*c59f781eSAndrew Jeffery .reg = STR3, 159*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_3], 160*c59f781eSAndrew Jeffery }, 161*c59f781eSAndrew Jeffery { 162*c59f781eSAndrew Jeffery .name = "idr4", 163*c59f781eSAndrew Jeffery .reg = IDR4, 164*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_4], 165*c59f781eSAndrew Jeffery }, 166*c59f781eSAndrew Jeffery { 167*c59f781eSAndrew Jeffery .name = "odr4", 168*c59f781eSAndrew Jeffery .reg = ODR4, 169*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_4], 170*c59f781eSAndrew Jeffery }, 171*c59f781eSAndrew Jeffery { 172*c59f781eSAndrew Jeffery .name = "str4", 173*c59f781eSAndrew Jeffery .reg = STR4, 174*c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_4], 175*c59f781eSAndrew Jeffery }, 176*c59f781eSAndrew Jeffery { }, 177*c59f781eSAndrew Jeffery }; 178*c59f781eSAndrew Jeffery 179*c59f781eSAndrew Jeffery static const struct aspeed_kcs_register_data * 180*c59f781eSAndrew Jeffery aspeed_kcs_get_register_data_by_name(const char *name) 181*c59f781eSAndrew Jeffery { 182*c59f781eSAndrew Jeffery const struct aspeed_kcs_register_data *pos = aspeed_kcs_registers; 183*c59f781eSAndrew Jeffery 184*c59f781eSAndrew Jeffery while (pos->name) { 185*c59f781eSAndrew Jeffery if (!strcmp(pos->name, name)) { 186*c59f781eSAndrew Jeffery return pos; 187*c59f781eSAndrew Jeffery } 188*c59f781eSAndrew Jeffery pos++; 189*c59f781eSAndrew Jeffery } 190*c59f781eSAndrew Jeffery 191*c59f781eSAndrew Jeffery return NULL; 192*c59f781eSAndrew Jeffery } 193*c59f781eSAndrew Jeffery 194*c59f781eSAndrew Jeffery static const struct aspeed_kcs_channel * 195*c59f781eSAndrew Jeffery aspeed_kcs_get_channel_by_register(int reg) 196*c59f781eSAndrew Jeffery { 197*c59f781eSAndrew Jeffery const struct aspeed_kcs_register_data *pos = aspeed_kcs_registers; 198*c59f781eSAndrew Jeffery 199*c59f781eSAndrew Jeffery while (pos->name) { 200*c59f781eSAndrew Jeffery if (pos->reg == reg) { 201*c59f781eSAndrew Jeffery return pos->chan; 202*c59f781eSAndrew Jeffery } 203*c59f781eSAndrew Jeffery pos++; 204*c59f781eSAndrew Jeffery } 205*c59f781eSAndrew Jeffery 206*c59f781eSAndrew Jeffery return NULL; 207*c59f781eSAndrew Jeffery } 208*c59f781eSAndrew Jeffery 209*c59f781eSAndrew Jeffery static void aspeed_kcs_get_register_property(Object *obj, 210*c59f781eSAndrew Jeffery Visitor *v, 211*c59f781eSAndrew Jeffery const char *name, 212*c59f781eSAndrew Jeffery void *opaque, 213*c59f781eSAndrew Jeffery Error **errp) 214*c59f781eSAndrew Jeffery { 215*c59f781eSAndrew Jeffery const struct aspeed_kcs_register_data *data; 216*c59f781eSAndrew Jeffery AspeedLPCState *s = ASPEED_LPC(obj); 217*c59f781eSAndrew Jeffery uint32_t val; 218*c59f781eSAndrew Jeffery 219*c59f781eSAndrew Jeffery data = aspeed_kcs_get_register_data_by_name(name); 220*c59f781eSAndrew Jeffery if (!data) { 221*c59f781eSAndrew Jeffery return; 222*c59f781eSAndrew Jeffery } 223*c59f781eSAndrew Jeffery 224*c59f781eSAndrew Jeffery if (!strncmp("odr", name, 3)) { 225*c59f781eSAndrew Jeffery s->regs[data->chan->str] &= ~STR_OBF; 226*c59f781eSAndrew Jeffery } 227*c59f781eSAndrew Jeffery 228*c59f781eSAndrew Jeffery val = s->regs[data->reg]; 229*c59f781eSAndrew Jeffery 230*c59f781eSAndrew Jeffery visit_type_uint32(v, name, &val, errp); 231*c59f781eSAndrew Jeffery } 232*c59f781eSAndrew Jeffery 233*c59f781eSAndrew Jeffery static bool aspeed_kcs_channel_enabled(AspeedLPCState *s, 234*c59f781eSAndrew Jeffery const struct aspeed_kcs_channel *channel) 235*c59f781eSAndrew Jeffery { 236*c59f781eSAndrew Jeffery switch (channel->id) { 237*c59f781eSAndrew Jeffery case kcs_channel_1: return s->regs[HICR0] & HICR0_LPC1E; 238*c59f781eSAndrew Jeffery case kcs_channel_2: return s->regs[HICR0] & HICR0_LPC2E; 239*c59f781eSAndrew Jeffery case kcs_channel_3: 240*c59f781eSAndrew Jeffery return (s->regs[HICR0] & HICR0_LPC3E) && 241*c59f781eSAndrew Jeffery (s->regs[HICR4] & HICR4_KCSENBL); 242*c59f781eSAndrew Jeffery case kcs_channel_4: return s->regs[HICRB] & HICRB_LPC4E; 243*c59f781eSAndrew Jeffery default: return false; 244*c59f781eSAndrew Jeffery } 245*c59f781eSAndrew Jeffery } 246*c59f781eSAndrew Jeffery 247*c59f781eSAndrew Jeffery static bool 248*c59f781eSAndrew Jeffery aspeed_kcs_channel_ibf_irq_enabled(AspeedLPCState *s, 249*c59f781eSAndrew Jeffery const struct aspeed_kcs_channel *channel) 250*c59f781eSAndrew Jeffery { 251*c59f781eSAndrew Jeffery if (!aspeed_kcs_channel_enabled(s, channel)) { 252*c59f781eSAndrew Jeffery return false; 253*c59f781eSAndrew Jeffery } 254*c59f781eSAndrew Jeffery 255*c59f781eSAndrew Jeffery switch (channel->id) { 256*c59f781eSAndrew Jeffery case kcs_channel_1: return s->regs[HICR2] & HICR2_IBFIE1; 257*c59f781eSAndrew Jeffery case kcs_channel_2: return s->regs[HICR2] & HICR2_IBFIE2; 258*c59f781eSAndrew Jeffery case kcs_channel_3: return s->regs[HICR2] & HICR2_IBFIE3; 259*c59f781eSAndrew Jeffery case kcs_channel_4: return s->regs[HICRB] & HICRB_IBFIE4; 260*c59f781eSAndrew Jeffery default: return false; 261*c59f781eSAndrew Jeffery } 262*c59f781eSAndrew Jeffery } 263*c59f781eSAndrew Jeffery 264*c59f781eSAndrew Jeffery static void aspeed_kcs_set_register_property(Object *obj, 265*c59f781eSAndrew Jeffery Visitor *v, 266*c59f781eSAndrew Jeffery const char *name, 267*c59f781eSAndrew Jeffery void *opaque, 268*c59f781eSAndrew Jeffery Error **errp) 269*c59f781eSAndrew Jeffery { 270*c59f781eSAndrew Jeffery const struct aspeed_kcs_register_data *data; 271*c59f781eSAndrew Jeffery AspeedLPCState *s = ASPEED_LPC(obj); 272*c59f781eSAndrew Jeffery uint32_t val; 273*c59f781eSAndrew Jeffery 274*c59f781eSAndrew Jeffery data = aspeed_kcs_get_register_data_by_name(name); 275*c59f781eSAndrew Jeffery if (!data) { 276*c59f781eSAndrew Jeffery return; 277*c59f781eSAndrew Jeffery } 278*c59f781eSAndrew Jeffery 279*c59f781eSAndrew Jeffery if (!visit_type_uint32(v, name, &val, errp)) { 280*c59f781eSAndrew Jeffery return; 281*c59f781eSAndrew Jeffery } 282*c59f781eSAndrew Jeffery 283*c59f781eSAndrew Jeffery if (strncmp("str", name, 3)) { 284*c59f781eSAndrew Jeffery s->regs[data->reg] = val; 285*c59f781eSAndrew Jeffery } 286*c59f781eSAndrew Jeffery 287*c59f781eSAndrew Jeffery if (!strncmp("idr", name, 3)) { 288*c59f781eSAndrew Jeffery s->regs[data->chan->str] |= STR_IBF; 289*c59f781eSAndrew Jeffery if (aspeed_kcs_channel_ibf_irq_enabled(s, data->chan)) { 290*c59f781eSAndrew Jeffery enum aspeed_lpc_subdevice subdev; 291*c59f781eSAndrew Jeffery 292*c59f781eSAndrew Jeffery subdev = aspeed_kcs_subdevice_map[data->chan->id]; 293*c59f781eSAndrew Jeffery qemu_irq_raise(s->subdevice_irqs[subdev]); 294*c59f781eSAndrew Jeffery } 295*c59f781eSAndrew Jeffery } 296*c59f781eSAndrew Jeffery } 297*c59f781eSAndrew Jeffery 298*c59f781eSAndrew Jeffery static void aspeed_lpc_set_irq(void *opaque, int irq, int level) 299*c59f781eSAndrew Jeffery { 300*c59f781eSAndrew Jeffery AspeedLPCState *s = (AspeedLPCState *)opaque; 301*c59f781eSAndrew Jeffery 302*c59f781eSAndrew Jeffery if (level) { 303*c59f781eSAndrew Jeffery s->subdevice_irqs_pending |= BIT(irq); 304*c59f781eSAndrew Jeffery } else { 305*c59f781eSAndrew Jeffery s->subdevice_irqs_pending &= ~BIT(irq); 306*c59f781eSAndrew Jeffery } 307*c59f781eSAndrew Jeffery 308*c59f781eSAndrew Jeffery qemu_set_irq(s->irq, !!s->subdevice_irqs_pending); 309*c59f781eSAndrew Jeffery } 3102ecf1726SCédric Le Goater 3112ecf1726SCédric Le Goater static uint64_t aspeed_lpc_read(void *opaque, hwaddr offset, unsigned size) 3122ecf1726SCédric Le Goater { 3132ecf1726SCédric Le Goater AspeedLPCState *s = ASPEED_LPC(opaque); 3142ecf1726SCédric Le Goater int reg = TO_REG(offset); 3152ecf1726SCédric Le Goater 3162ecf1726SCédric Le Goater if (reg >= ARRAY_SIZE(s->regs)) { 3172ecf1726SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, 3182ecf1726SCédric Le Goater "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 3192ecf1726SCédric Le Goater __func__, offset); 3202ecf1726SCédric Le Goater return 0; 3212ecf1726SCédric Le Goater } 3222ecf1726SCédric Le Goater 323*c59f781eSAndrew Jeffery switch (reg) { 324*c59f781eSAndrew Jeffery case IDR1: 325*c59f781eSAndrew Jeffery case IDR2: 326*c59f781eSAndrew Jeffery case IDR3: 327*c59f781eSAndrew Jeffery case IDR4: 328*c59f781eSAndrew Jeffery { 329*c59f781eSAndrew Jeffery const struct aspeed_kcs_channel *channel; 330*c59f781eSAndrew Jeffery 331*c59f781eSAndrew Jeffery channel = aspeed_kcs_get_channel_by_register(reg); 332*c59f781eSAndrew Jeffery if (s->regs[channel->str] & STR_IBF) { 333*c59f781eSAndrew Jeffery enum aspeed_lpc_subdevice subdev; 334*c59f781eSAndrew Jeffery 335*c59f781eSAndrew Jeffery subdev = aspeed_kcs_subdevice_map[channel->id]; 336*c59f781eSAndrew Jeffery qemu_irq_lower(s->subdevice_irqs[subdev]); 337*c59f781eSAndrew Jeffery } 338*c59f781eSAndrew Jeffery 339*c59f781eSAndrew Jeffery s->regs[channel->str] &= ~STR_IBF; 340*c59f781eSAndrew Jeffery break; 341*c59f781eSAndrew Jeffery } 342*c59f781eSAndrew Jeffery default: 343*c59f781eSAndrew Jeffery break; 344*c59f781eSAndrew Jeffery } 345*c59f781eSAndrew Jeffery 3462ecf1726SCédric Le Goater return s->regs[reg]; 3472ecf1726SCédric Le Goater } 3482ecf1726SCédric Le Goater 3492ecf1726SCédric Le Goater static void aspeed_lpc_write(void *opaque, hwaddr offset, uint64_t data, 3502ecf1726SCédric Le Goater unsigned int size) 3512ecf1726SCédric Le Goater { 3522ecf1726SCédric Le Goater AspeedLPCState *s = ASPEED_LPC(opaque); 3532ecf1726SCédric Le Goater int reg = TO_REG(offset); 3542ecf1726SCédric Le Goater 3552ecf1726SCédric Le Goater if (reg >= ARRAY_SIZE(s->regs)) { 3562ecf1726SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, 3572ecf1726SCédric Le Goater "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 3582ecf1726SCédric Le Goater __func__, offset); 3592ecf1726SCédric Le Goater return; 3602ecf1726SCédric Le Goater } 3612ecf1726SCédric Le Goater 362*c59f781eSAndrew Jeffery 363*c59f781eSAndrew Jeffery switch (reg) { 364*c59f781eSAndrew Jeffery case ODR1: 365*c59f781eSAndrew Jeffery case ODR2: 366*c59f781eSAndrew Jeffery case ODR3: 367*c59f781eSAndrew Jeffery case ODR4: 368*c59f781eSAndrew Jeffery s->regs[aspeed_kcs_get_channel_by_register(reg)->str] |= STR_OBF; 369*c59f781eSAndrew Jeffery break; 370*c59f781eSAndrew Jeffery default: 371*c59f781eSAndrew Jeffery break; 372*c59f781eSAndrew Jeffery } 373*c59f781eSAndrew Jeffery 3742ecf1726SCédric Le Goater s->regs[reg] = data; 3752ecf1726SCédric Le Goater } 3762ecf1726SCédric Le Goater 3772ecf1726SCédric Le Goater static const MemoryRegionOps aspeed_lpc_ops = { 3782ecf1726SCédric Le Goater .read = aspeed_lpc_read, 3792ecf1726SCédric Le Goater .write = aspeed_lpc_write, 3802ecf1726SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 3812ecf1726SCédric Le Goater .valid = { 3822ecf1726SCédric Le Goater .min_access_size = 1, 3832ecf1726SCédric Le Goater .max_access_size = 4, 3842ecf1726SCédric Le Goater }, 3852ecf1726SCédric Le Goater }; 3862ecf1726SCédric Le Goater 3872ecf1726SCédric Le Goater static void aspeed_lpc_reset(DeviceState *dev) 3882ecf1726SCédric Le Goater { 3892ecf1726SCédric Le Goater struct AspeedLPCState *s = ASPEED_LPC(dev); 3902ecf1726SCédric Le Goater 391*c59f781eSAndrew Jeffery s->subdevice_irqs_pending = 0; 392*c59f781eSAndrew Jeffery 3932ecf1726SCédric Le Goater memset(s->regs, 0, sizeof(s->regs)); 3942ecf1726SCédric Le Goater 3952ecf1726SCédric Le Goater s->regs[HICR7] = s->hicr7; 3962ecf1726SCédric Le Goater } 3972ecf1726SCédric Le Goater 3982ecf1726SCédric Le Goater static void aspeed_lpc_realize(DeviceState *dev, Error **errp) 3992ecf1726SCédric Le Goater { 4002ecf1726SCédric Le Goater AspeedLPCState *s = ASPEED_LPC(dev); 4012ecf1726SCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 4022ecf1726SCédric Le Goater 4032ecf1726SCédric Le Goater sysbus_init_irq(sbd, &s->irq); 404*c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_kcs_1]); 405*c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_kcs_2]); 406*c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_kcs_3]); 407*c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_kcs_4]); 408*c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_ibt]); 4092ecf1726SCédric Le Goater 4102ecf1726SCédric Le Goater memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_lpc_ops, s, 4112ecf1726SCédric Le Goater TYPE_ASPEED_LPC, 0x1000); 4122ecf1726SCédric Le Goater 4132ecf1726SCédric Le Goater sysbus_init_mmio(sbd, &s->iomem); 414*c59f781eSAndrew Jeffery 415*c59f781eSAndrew Jeffery qdev_init_gpio_in(dev, aspeed_lpc_set_irq, ASPEED_LPC_NR_SUBDEVS); 416*c59f781eSAndrew Jeffery } 417*c59f781eSAndrew Jeffery 418*c59f781eSAndrew Jeffery static void aspeed_lpc_init(Object *obj) 419*c59f781eSAndrew Jeffery { 420*c59f781eSAndrew Jeffery object_property_add(obj, "idr1", "uint32", aspeed_kcs_get_register_property, 421*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 422*c59f781eSAndrew Jeffery object_property_add(obj, "odr1", "uint32", aspeed_kcs_get_register_property, 423*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 424*c59f781eSAndrew Jeffery object_property_add(obj, "str1", "uint32", aspeed_kcs_get_register_property, 425*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 426*c59f781eSAndrew Jeffery object_property_add(obj, "idr2", "uint32", aspeed_kcs_get_register_property, 427*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 428*c59f781eSAndrew Jeffery object_property_add(obj, "odr2", "uint32", aspeed_kcs_get_register_property, 429*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 430*c59f781eSAndrew Jeffery object_property_add(obj, "str2", "uint32", aspeed_kcs_get_register_property, 431*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 432*c59f781eSAndrew Jeffery object_property_add(obj, "idr3", "uint32", aspeed_kcs_get_register_property, 433*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 434*c59f781eSAndrew Jeffery object_property_add(obj, "odr3", "uint32", aspeed_kcs_get_register_property, 435*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 436*c59f781eSAndrew Jeffery object_property_add(obj, "str3", "uint32", aspeed_kcs_get_register_property, 437*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 438*c59f781eSAndrew Jeffery object_property_add(obj, "idr4", "uint32", aspeed_kcs_get_register_property, 439*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 440*c59f781eSAndrew Jeffery object_property_add(obj, "odr4", "uint32", aspeed_kcs_get_register_property, 441*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 442*c59f781eSAndrew Jeffery object_property_add(obj, "str4", "uint32", aspeed_kcs_get_register_property, 443*c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 4442ecf1726SCédric Le Goater } 4452ecf1726SCédric Le Goater 4462ecf1726SCédric Le Goater static const VMStateDescription vmstate_aspeed_lpc = { 4472ecf1726SCédric Le Goater .name = TYPE_ASPEED_LPC, 448*c59f781eSAndrew Jeffery .version_id = 2, 449*c59f781eSAndrew Jeffery .minimum_version_id = 2, 4502ecf1726SCédric Le Goater .fields = (VMStateField[]) { 4512ecf1726SCédric Le Goater VMSTATE_UINT32_ARRAY(regs, AspeedLPCState, ASPEED_LPC_NR_REGS), 452*c59f781eSAndrew Jeffery VMSTATE_UINT32(subdevice_irqs_pending, AspeedLPCState), 4532ecf1726SCédric Le Goater VMSTATE_END_OF_LIST(), 4542ecf1726SCédric Le Goater } 4552ecf1726SCédric Le Goater }; 4562ecf1726SCédric Le Goater 4572ecf1726SCédric Le Goater static Property aspeed_lpc_properties[] = { 4582ecf1726SCédric Le Goater DEFINE_PROP_UINT32("hicr7", AspeedLPCState, hicr7, 0), 4592ecf1726SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 4602ecf1726SCédric Le Goater }; 4612ecf1726SCédric Le Goater 4622ecf1726SCédric Le Goater static void aspeed_lpc_class_init(ObjectClass *klass, void *data) 4632ecf1726SCédric Le Goater { 4642ecf1726SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 4652ecf1726SCédric Le Goater 4662ecf1726SCédric Le Goater dc->realize = aspeed_lpc_realize; 4672ecf1726SCédric Le Goater dc->reset = aspeed_lpc_reset; 4682ecf1726SCédric Le Goater dc->desc = "Aspeed LPC Controller", 4692ecf1726SCédric Le Goater dc->vmsd = &vmstate_aspeed_lpc; 4702ecf1726SCédric Le Goater device_class_set_props(dc, aspeed_lpc_properties); 4712ecf1726SCédric Le Goater } 4722ecf1726SCédric Le Goater 4732ecf1726SCédric Le Goater static const TypeInfo aspeed_lpc_info = { 4742ecf1726SCédric Le Goater .name = TYPE_ASPEED_LPC, 4752ecf1726SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 4762ecf1726SCédric Le Goater .instance_size = sizeof(AspeedLPCState), 4772ecf1726SCédric Le Goater .class_init = aspeed_lpc_class_init, 478*c59f781eSAndrew Jeffery .instance_init = aspeed_lpc_init, 4792ecf1726SCédric Le Goater }; 4802ecf1726SCédric Le Goater 4812ecf1726SCédric Le Goater static void aspeed_lpc_register_types(void) 4822ecf1726SCédric Le Goater { 4832ecf1726SCédric Le Goater type_register_static(&aspeed_lpc_info); 4842ecf1726SCédric Le Goater } 4852ecf1726SCédric Le Goater 4862ecf1726SCédric Le Goater type_init(aspeed_lpc_register_types); 487