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" 15c59f781eSAndrew Jeffery #include "qapi/visitor.h" 16c59f781eSAndrew 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) 23c59f781eSAndrew Jeffery #define HICR0_LPC3E BIT(7) 24c59f781eSAndrew Jeffery #define HICR0_LPC2E BIT(6) 25c59f781eSAndrew Jeffery #define HICR0_LPC1E BIT(5) 262ecf1726SCédric Le Goater #define HICR1 TO_REG(0x04) 272ecf1726SCédric Le Goater #define HICR2 TO_REG(0x08) 28c59f781eSAndrew Jeffery #define HICR2_IBFIE3 BIT(3) 29c59f781eSAndrew Jeffery #define HICR2_IBFIE2 BIT(2) 30c59f781eSAndrew Jeffery #define HICR2_IBFIE1 BIT(1) 312ecf1726SCédric Le Goater #define HICR3 TO_REG(0x0C) 322ecf1726SCédric Le Goater #define HICR4 TO_REG(0x10) 33c59f781eSAndrew Jeffery #define HICR4_KCSENBL BIT(2) 34c59f781eSAndrew Jeffery #define IDR1 TO_REG(0x24) 35c59f781eSAndrew Jeffery #define IDR2 TO_REG(0x28) 36c59f781eSAndrew Jeffery #define IDR3 TO_REG(0x2C) 37c59f781eSAndrew Jeffery #define ODR1 TO_REG(0x30) 38c59f781eSAndrew Jeffery #define ODR2 TO_REG(0x34) 39c59f781eSAndrew Jeffery #define ODR3 TO_REG(0x38) 40c59f781eSAndrew Jeffery #define STR1 TO_REG(0x3C) 41c59f781eSAndrew Jeffery #define STR_OBF BIT(0) 42c59f781eSAndrew Jeffery #define STR_IBF BIT(1) 43c59f781eSAndrew Jeffery #define STR_CMD_DATA BIT(3) 44c59f781eSAndrew Jeffery #define STR2 TO_REG(0x40) 45c59f781eSAndrew 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) 50c59f781eSAndrew Jeffery #define HICRB TO_REG(0x100) 51c59f781eSAndrew Jeffery #define HICRB_IBFIE4 BIT(1) 52c59f781eSAndrew Jeffery #define HICRB_LPC4E BIT(0) 53c59f781eSAndrew Jeffery #define IDR4 TO_REG(0x114) 54c59f781eSAndrew Jeffery #define ODR4 TO_REG(0x118) 55c59f781eSAndrew Jeffery #define STR4 TO_REG(0x11C) 56c59f781eSAndrew Jeffery 57c59f781eSAndrew Jeffery enum aspeed_kcs_channel_id { 58c59f781eSAndrew Jeffery kcs_channel_1 = 0, 59c59f781eSAndrew Jeffery kcs_channel_2, 60c59f781eSAndrew Jeffery kcs_channel_3, 61c59f781eSAndrew Jeffery kcs_channel_4, 62c59f781eSAndrew Jeffery }; 63c59f781eSAndrew Jeffery 64c59f781eSAndrew Jeffery static const enum aspeed_lpc_subdevice aspeed_kcs_subdevice_map[] = { 65c59f781eSAndrew Jeffery [kcs_channel_1] = aspeed_lpc_kcs_1, 66c59f781eSAndrew Jeffery [kcs_channel_2] = aspeed_lpc_kcs_2, 67c59f781eSAndrew Jeffery [kcs_channel_3] = aspeed_lpc_kcs_3, 68c59f781eSAndrew Jeffery [kcs_channel_4] = aspeed_lpc_kcs_4, 69c59f781eSAndrew Jeffery }; 70c59f781eSAndrew Jeffery 71c59f781eSAndrew Jeffery struct aspeed_kcs_channel { 72c59f781eSAndrew Jeffery enum aspeed_kcs_channel_id id; 73c59f781eSAndrew Jeffery 74c59f781eSAndrew Jeffery int idr; 75c59f781eSAndrew Jeffery int odr; 76c59f781eSAndrew Jeffery int str; 77c59f781eSAndrew Jeffery }; 78c59f781eSAndrew Jeffery 79c59f781eSAndrew Jeffery static const struct aspeed_kcs_channel aspeed_kcs_channel_map[] = { 80c59f781eSAndrew Jeffery [kcs_channel_1] = { 81c59f781eSAndrew Jeffery .id = kcs_channel_1, 82c59f781eSAndrew Jeffery .idr = IDR1, 83c59f781eSAndrew Jeffery .odr = ODR1, 84c59f781eSAndrew Jeffery .str = STR1 85c59f781eSAndrew Jeffery }, 86c59f781eSAndrew Jeffery 87c59f781eSAndrew Jeffery [kcs_channel_2] = { 88c59f781eSAndrew Jeffery .id = kcs_channel_2, 89c59f781eSAndrew Jeffery .idr = IDR2, 90c59f781eSAndrew Jeffery .odr = ODR2, 91c59f781eSAndrew Jeffery .str = STR2 92c59f781eSAndrew Jeffery }, 93c59f781eSAndrew Jeffery 94c59f781eSAndrew Jeffery [kcs_channel_3] = { 95c59f781eSAndrew Jeffery .id = kcs_channel_3, 96c59f781eSAndrew Jeffery .idr = IDR3, 97c59f781eSAndrew Jeffery .odr = ODR3, 98c59f781eSAndrew Jeffery .str = STR3 99c59f781eSAndrew Jeffery }, 100c59f781eSAndrew Jeffery 101c59f781eSAndrew Jeffery [kcs_channel_4] = { 102c59f781eSAndrew Jeffery .id = kcs_channel_4, 103c59f781eSAndrew Jeffery .idr = IDR4, 104c59f781eSAndrew Jeffery .odr = ODR4, 105c59f781eSAndrew Jeffery .str = STR4 106c59f781eSAndrew Jeffery }, 107c59f781eSAndrew Jeffery }; 108c59f781eSAndrew Jeffery 109c59f781eSAndrew Jeffery struct aspeed_kcs_register_data { 110c59f781eSAndrew Jeffery const char *name; 111c59f781eSAndrew Jeffery int reg; 112c59f781eSAndrew Jeffery const struct aspeed_kcs_channel *chan; 113c59f781eSAndrew Jeffery }; 114c59f781eSAndrew Jeffery 115c59f781eSAndrew Jeffery static const struct aspeed_kcs_register_data aspeed_kcs_registers[] = { 116c59f781eSAndrew Jeffery { 117c59f781eSAndrew Jeffery .name = "idr1", 118c59f781eSAndrew Jeffery .reg = IDR1, 119c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_1], 120c59f781eSAndrew Jeffery }, 121c59f781eSAndrew Jeffery { 122c59f781eSAndrew Jeffery .name = "odr1", 123c59f781eSAndrew Jeffery .reg = ODR1, 124c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_1], 125c59f781eSAndrew Jeffery }, 126c59f781eSAndrew Jeffery { 127c59f781eSAndrew Jeffery .name = "str1", 128c59f781eSAndrew Jeffery .reg = STR1, 129c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_1], 130c59f781eSAndrew Jeffery }, 131c59f781eSAndrew Jeffery { 132c59f781eSAndrew Jeffery .name = "idr2", 133c59f781eSAndrew Jeffery .reg = IDR2, 134c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_2], 135c59f781eSAndrew Jeffery }, 136c59f781eSAndrew Jeffery { 137c59f781eSAndrew Jeffery .name = "odr2", 138c59f781eSAndrew Jeffery .reg = ODR2, 139c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_2], 140c59f781eSAndrew Jeffery }, 141c59f781eSAndrew Jeffery { 142c59f781eSAndrew Jeffery .name = "str2", 143c59f781eSAndrew Jeffery .reg = STR2, 144c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_2], 145c59f781eSAndrew Jeffery }, 146c59f781eSAndrew Jeffery { 147c59f781eSAndrew Jeffery .name = "idr3", 148c59f781eSAndrew Jeffery .reg = IDR3, 149c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_3], 150c59f781eSAndrew Jeffery }, 151c59f781eSAndrew Jeffery { 152c59f781eSAndrew Jeffery .name = "odr3", 153c59f781eSAndrew Jeffery .reg = ODR3, 154c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_3], 155c59f781eSAndrew Jeffery }, 156c59f781eSAndrew Jeffery { 157c59f781eSAndrew Jeffery .name = "str3", 158c59f781eSAndrew Jeffery .reg = STR3, 159c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_3], 160c59f781eSAndrew Jeffery }, 161c59f781eSAndrew Jeffery { 162c59f781eSAndrew Jeffery .name = "idr4", 163c59f781eSAndrew Jeffery .reg = IDR4, 164c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_4], 165c59f781eSAndrew Jeffery }, 166c59f781eSAndrew Jeffery { 167c59f781eSAndrew Jeffery .name = "odr4", 168c59f781eSAndrew Jeffery .reg = ODR4, 169c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_4], 170c59f781eSAndrew Jeffery }, 171c59f781eSAndrew Jeffery { 172c59f781eSAndrew Jeffery .name = "str4", 173c59f781eSAndrew Jeffery .reg = STR4, 174c59f781eSAndrew Jeffery .chan = &aspeed_kcs_channel_map[kcs_channel_4], 175c59f781eSAndrew Jeffery }, 176c59f781eSAndrew Jeffery { }, 177c59f781eSAndrew Jeffery }; 178c59f781eSAndrew Jeffery 179c59f781eSAndrew Jeffery static const struct aspeed_kcs_register_data * 180c59f781eSAndrew Jeffery aspeed_kcs_get_register_data_by_name(const char *name) 181c59f781eSAndrew Jeffery { 182c59f781eSAndrew Jeffery const struct aspeed_kcs_register_data *pos = aspeed_kcs_registers; 183c59f781eSAndrew Jeffery 184c59f781eSAndrew Jeffery while (pos->name) { 185c59f781eSAndrew Jeffery if (!strcmp(pos->name, name)) { 186c59f781eSAndrew Jeffery return pos; 187c59f781eSAndrew Jeffery } 188c59f781eSAndrew Jeffery pos++; 189c59f781eSAndrew Jeffery } 190c59f781eSAndrew Jeffery 191c59f781eSAndrew Jeffery return NULL; 192c59f781eSAndrew Jeffery } 193c59f781eSAndrew Jeffery 194c59f781eSAndrew Jeffery static const struct aspeed_kcs_channel * 195c59f781eSAndrew Jeffery aspeed_kcs_get_channel_by_register(int reg) 196c59f781eSAndrew Jeffery { 197c59f781eSAndrew Jeffery const struct aspeed_kcs_register_data *pos = aspeed_kcs_registers; 198c59f781eSAndrew Jeffery 199c59f781eSAndrew Jeffery while (pos->name) { 200c59f781eSAndrew Jeffery if (pos->reg == reg) { 201c59f781eSAndrew Jeffery return pos->chan; 202c59f781eSAndrew Jeffery } 203c59f781eSAndrew Jeffery pos++; 204c59f781eSAndrew Jeffery } 205c59f781eSAndrew Jeffery 206c59f781eSAndrew Jeffery return NULL; 207c59f781eSAndrew Jeffery } 208c59f781eSAndrew Jeffery 209c59f781eSAndrew Jeffery static void aspeed_kcs_get_register_property(Object *obj, 210c59f781eSAndrew Jeffery Visitor *v, 211c59f781eSAndrew Jeffery const char *name, 212c59f781eSAndrew Jeffery void *opaque, 213c59f781eSAndrew Jeffery Error **errp) 214c59f781eSAndrew Jeffery { 215c59f781eSAndrew Jeffery const struct aspeed_kcs_register_data *data; 216c59f781eSAndrew Jeffery AspeedLPCState *s = ASPEED_LPC(obj); 217c59f781eSAndrew Jeffery uint32_t val; 218c59f781eSAndrew Jeffery 219c59f781eSAndrew Jeffery data = aspeed_kcs_get_register_data_by_name(name); 220c59f781eSAndrew Jeffery if (!data) { 221c59f781eSAndrew Jeffery return; 222c59f781eSAndrew Jeffery } 223c59f781eSAndrew Jeffery 224c59f781eSAndrew Jeffery if (!strncmp("odr", name, 3)) { 225c59f781eSAndrew Jeffery s->regs[data->chan->str] &= ~STR_OBF; 226c59f781eSAndrew Jeffery } 227c59f781eSAndrew Jeffery 228c59f781eSAndrew Jeffery val = s->regs[data->reg]; 229c59f781eSAndrew Jeffery 230c59f781eSAndrew Jeffery visit_type_uint32(v, name, &val, errp); 231c59f781eSAndrew Jeffery } 232c59f781eSAndrew Jeffery 233c59f781eSAndrew Jeffery static bool aspeed_kcs_channel_enabled(AspeedLPCState *s, 234c59f781eSAndrew Jeffery const struct aspeed_kcs_channel *channel) 235c59f781eSAndrew Jeffery { 236c59f781eSAndrew Jeffery switch (channel->id) { 237c59f781eSAndrew Jeffery case kcs_channel_1: return s->regs[HICR0] & HICR0_LPC1E; 238c59f781eSAndrew Jeffery case kcs_channel_2: return s->regs[HICR0] & HICR0_LPC2E; 239c59f781eSAndrew Jeffery case kcs_channel_3: 240c59f781eSAndrew Jeffery return (s->regs[HICR0] & HICR0_LPC3E) && 241c59f781eSAndrew Jeffery (s->regs[HICR4] & HICR4_KCSENBL); 242c59f781eSAndrew Jeffery case kcs_channel_4: return s->regs[HICRB] & HICRB_LPC4E; 243c59f781eSAndrew Jeffery default: return false; 244c59f781eSAndrew Jeffery } 245c59f781eSAndrew Jeffery } 246c59f781eSAndrew Jeffery 247c59f781eSAndrew Jeffery static bool 248c59f781eSAndrew Jeffery aspeed_kcs_channel_ibf_irq_enabled(AspeedLPCState *s, 249c59f781eSAndrew Jeffery const struct aspeed_kcs_channel *channel) 250c59f781eSAndrew Jeffery { 251c59f781eSAndrew Jeffery if (!aspeed_kcs_channel_enabled(s, channel)) { 252c59f781eSAndrew Jeffery return false; 253c59f781eSAndrew Jeffery } 254c59f781eSAndrew Jeffery 255c59f781eSAndrew Jeffery switch (channel->id) { 256c59f781eSAndrew Jeffery case kcs_channel_1: return s->regs[HICR2] & HICR2_IBFIE1; 257c59f781eSAndrew Jeffery case kcs_channel_2: return s->regs[HICR2] & HICR2_IBFIE2; 258c59f781eSAndrew Jeffery case kcs_channel_3: return s->regs[HICR2] & HICR2_IBFIE3; 259c59f781eSAndrew Jeffery case kcs_channel_4: return s->regs[HICRB] & HICRB_IBFIE4; 260c59f781eSAndrew Jeffery default: return false; 261c59f781eSAndrew Jeffery } 262c59f781eSAndrew Jeffery } 263c59f781eSAndrew Jeffery 264c59f781eSAndrew Jeffery static void aspeed_kcs_set_register_property(Object *obj, 265c59f781eSAndrew Jeffery Visitor *v, 266c59f781eSAndrew Jeffery const char *name, 267c59f781eSAndrew Jeffery void *opaque, 268c59f781eSAndrew Jeffery Error **errp) 269c59f781eSAndrew Jeffery { 270c59f781eSAndrew Jeffery const struct aspeed_kcs_register_data *data; 271c59f781eSAndrew Jeffery AspeedLPCState *s = ASPEED_LPC(obj); 272c59f781eSAndrew Jeffery uint32_t val; 273c59f781eSAndrew Jeffery 274c59f781eSAndrew Jeffery data = aspeed_kcs_get_register_data_by_name(name); 275c59f781eSAndrew Jeffery if (!data) { 276c59f781eSAndrew Jeffery return; 277c59f781eSAndrew Jeffery } 278c59f781eSAndrew Jeffery 279c59f781eSAndrew Jeffery if (!visit_type_uint32(v, name, &val, errp)) { 280c59f781eSAndrew Jeffery return; 281c59f781eSAndrew Jeffery } 282c59f781eSAndrew Jeffery 283c59f781eSAndrew Jeffery if (strncmp("str", name, 3)) { 284c59f781eSAndrew Jeffery s->regs[data->reg] = val; 285c59f781eSAndrew Jeffery } 286c59f781eSAndrew Jeffery 287c59f781eSAndrew Jeffery if (!strncmp("idr", name, 3)) { 288c59f781eSAndrew Jeffery s->regs[data->chan->str] |= STR_IBF; 289c59f781eSAndrew Jeffery if (aspeed_kcs_channel_ibf_irq_enabled(s, data->chan)) { 290c59f781eSAndrew Jeffery enum aspeed_lpc_subdevice subdev; 291c59f781eSAndrew Jeffery 292c59f781eSAndrew Jeffery subdev = aspeed_kcs_subdevice_map[data->chan->id]; 293c59f781eSAndrew Jeffery qemu_irq_raise(s->subdevice_irqs[subdev]); 294c59f781eSAndrew Jeffery } 295c59f781eSAndrew Jeffery } 296c59f781eSAndrew Jeffery } 297c59f781eSAndrew Jeffery 298c59f781eSAndrew Jeffery static void aspeed_lpc_set_irq(void *opaque, int irq, int level) 299c59f781eSAndrew Jeffery { 300c59f781eSAndrew Jeffery AspeedLPCState *s = (AspeedLPCState *)opaque; 301c59f781eSAndrew Jeffery 302c59f781eSAndrew Jeffery if (level) { 303c59f781eSAndrew Jeffery s->subdevice_irqs_pending |= BIT(irq); 304c59f781eSAndrew Jeffery } else { 305c59f781eSAndrew Jeffery s->subdevice_irqs_pending &= ~BIT(irq); 306c59f781eSAndrew Jeffery } 307c59f781eSAndrew Jeffery 308c59f781eSAndrew Jeffery qemu_set_irq(s->irq, !!s->subdevice_irqs_pending); 309c59f781eSAndrew 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 323c59f781eSAndrew Jeffery switch (reg) { 324c59f781eSAndrew Jeffery case IDR1: 325c59f781eSAndrew Jeffery case IDR2: 326c59f781eSAndrew Jeffery case IDR3: 327c59f781eSAndrew Jeffery case IDR4: 328c59f781eSAndrew Jeffery { 329c59f781eSAndrew Jeffery const struct aspeed_kcs_channel *channel; 330c59f781eSAndrew Jeffery 331c59f781eSAndrew Jeffery channel = aspeed_kcs_get_channel_by_register(reg); 332c59f781eSAndrew Jeffery if (s->regs[channel->str] & STR_IBF) { 333c59f781eSAndrew Jeffery enum aspeed_lpc_subdevice subdev; 334c59f781eSAndrew Jeffery 335c59f781eSAndrew Jeffery subdev = aspeed_kcs_subdevice_map[channel->id]; 336c59f781eSAndrew Jeffery qemu_irq_lower(s->subdevice_irqs[subdev]); 337c59f781eSAndrew Jeffery } 338c59f781eSAndrew Jeffery 339c59f781eSAndrew Jeffery s->regs[channel->str] &= ~STR_IBF; 340c59f781eSAndrew Jeffery break; 341c59f781eSAndrew Jeffery } 342c59f781eSAndrew Jeffery default: 343c59f781eSAndrew Jeffery break; 344c59f781eSAndrew Jeffery } 345c59f781eSAndrew 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 362c59f781eSAndrew Jeffery 363c59f781eSAndrew Jeffery switch (reg) { 364c59f781eSAndrew Jeffery case ODR1: 365c59f781eSAndrew Jeffery case ODR2: 366c59f781eSAndrew Jeffery case ODR3: 367c59f781eSAndrew Jeffery case ODR4: 368c59f781eSAndrew Jeffery s->regs[aspeed_kcs_get_channel_by_register(reg)->str] |= STR_OBF; 369c59f781eSAndrew Jeffery break; 370c59f781eSAndrew Jeffery default: 371c59f781eSAndrew Jeffery break; 372c59f781eSAndrew Jeffery } 373c59f781eSAndrew 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 391c59f781eSAndrew Jeffery s->subdevice_irqs_pending = 0; 392c59f781eSAndrew 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); 404c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_kcs_1]); 405c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_kcs_2]); 406c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_kcs_3]); 407c59f781eSAndrew Jeffery sysbus_init_irq(sbd, &s->subdevice_irqs[aspeed_lpc_kcs_4]); 408c59f781eSAndrew 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); 414c59f781eSAndrew Jeffery 415c59f781eSAndrew Jeffery qdev_init_gpio_in(dev, aspeed_lpc_set_irq, ASPEED_LPC_NR_SUBDEVS); 416c59f781eSAndrew Jeffery } 417c59f781eSAndrew Jeffery 418c59f781eSAndrew Jeffery static void aspeed_lpc_init(Object *obj) 419c59f781eSAndrew Jeffery { 420c59f781eSAndrew Jeffery object_property_add(obj, "idr1", "uint32", aspeed_kcs_get_register_property, 421c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 422c59f781eSAndrew Jeffery object_property_add(obj, "odr1", "uint32", aspeed_kcs_get_register_property, 423c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 424c59f781eSAndrew Jeffery object_property_add(obj, "str1", "uint32", aspeed_kcs_get_register_property, 425c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 426c59f781eSAndrew Jeffery object_property_add(obj, "idr2", "uint32", aspeed_kcs_get_register_property, 427c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 428c59f781eSAndrew Jeffery object_property_add(obj, "odr2", "uint32", aspeed_kcs_get_register_property, 429c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 430c59f781eSAndrew Jeffery object_property_add(obj, "str2", "uint32", aspeed_kcs_get_register_property, 431c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 432c59f781eSAndrew Jeffery object_property_add(obj, "idr3", "uint32", aspeed_kcs_get_register_property, 433c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 434c59f781eSAndrew Jeffery object_property_add(obj, "odr3", "uint32", aspeed_kcs_get_register_property, 435c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 436c59f781eSAndrew Jeffery object_property_add(obj, "str3", "uint32", aspeed_kcs_get_register_property, 437c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 438c59f781eSAndrew Jeffery object_property_add(obj, "idr4", "uint32", aspeed_kcs_get_register_property, 439c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 440c59f781eSAndrew Jeffery object_property_add(obj, "odr4", "uint32", aspeed_kcs_get_register_property, 441c59f781eSAndrew Jeffery aspeed_kcs_set_register_property, NULL, NULL); 442c59f781eSAndrew Jeffery object_property_add(obj, "str4", "uint32", aspeed_kcs_get_register_property, 443c59f781eSAndrew 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, 448c59f781eSAndrew Jeffery .version_id = 2, 449c59f781eSAndrew Jeffery .minimum_version_id = 2, 450*e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 4512ecf1726SCédric Le Goater VMSTATE_UINT32_ARRAY(regs, AspeedLPCState, ASPEED_LPC_NR_REGS), 452c59f781eSAndrew 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, 478c59f781eSAndrew 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