1 /* 2 * ASPEED I3C Controller 3 * 4 * Copyright (C) 2021 ASPEED Technology Inc. 5 * Copyright (C) 2025 Google, LLC. 6 * 7 * This code is licensed under the GPL version 2 or later. See 8 * the COPYING file in the top-level directory. 9 */ 10 11 #include "qemu/osdep.h" 12 #include "qemu/log.h" 13 #include "qemu/error-report.h" 14 #include "hw/i3c/aspeed_i3c.h" 15 #include "hw/registerfields.h" 16 #include "hw/qdev-properties.h" 17 #include "qapi/error.h" 18 #include "migration/vmstate.h" 19 #include "trace.h" 20 21 /* I3C Controller Registers */ 22 REG32(I3C1_REG0, 0x10) 23 REG32(I3C1_REG1, 0x14) 24 FIELD(I3C1_REG1, I2C_MODE, 0, 1) 25 FIELD(I3C1_REG1, SA_EN, 15, 1) 26 REG32(I3C2_REG0, 0x20) 27 REG32(I3C2_REG1, 0x24) 28 FIELD(I3C2_REG1, I2C_MODE, 0, 1) 29 FIELD(I3C2_REG1, SA_EN, 15, 1) 30 REG32(I3C3_REG0, 0x30) 31 REG32(I3C3_REG1, 0x34) 32 FIELD(I3C3_REG1, I2C_MODE, 0, 1) 33 FIELD(I3C3_REG1, SA_EN, 15, 1) 34 REG32(I3C4_REG0, 0x40) 35 REG32(I3C4_REG1, 0x44) 36 FIELD(I3C4_REG1, I2C_MODE, 0, 1) 37 FIELD(I3C4_REG1, SA_EN, 15, 1) 38 REG32(I3C5_REG0, 0x50) 39 REG32(I3C5_REG1, 0x54) 40 FIELD(I3C5_REG1, I2C_MODE, 0, 1) 41 FIELD(I3C5_REG1, SA_EN, 15, 1) 42 REG32(I3C6_REG0, 0x60) 43 REG32(I3C6_REG1, 0x64) 44 FIELD(I3C6_REG1, I2C_MODE, 0, 1) 45 FIELD(I3C6_REG1, SA_EN, 15, 1) 46 47 static uint64_t aspeed_i3c_read(void *opaque, hwaddr addr, unsigned int size) 48 { 49 AspeedI3CState *s = ASPEED_I3C(opaque); 50 uint64_t val = 0; 51 52 val = s->regs[addr >> 2]; 53 54 trace_aspeed_i3c_read(addr, val); 55 56 return val; 57 } 58 59 static void aspeed_i3c_write(void *opaque, 60 hwaddr addr, 61 uint64_t data, 62 unsigned int size) 63 { 64 AspeedI3CState *s = ASPEED_I3C(opaque); 65 66 trace_aspeed_i3c_write(addr, data); 67 68 addr >>= 2; 69 70 /* I3C controller register */ 71 switch (addr) { 72 case R_I3C1_REG1: 73 case R_I3C2_REG1: 74 case R_I3C3_REG1: 75 case R_I3C4_REG1: 76 case R_I3C5_REG1: 77 case R_I3C6_REG1: 78 if (data & R_I3C1_REG1_I2C_MODE_MASK) { 79 qemu_log_mask(LOG_UNIMP, 80 "%s: Unsupported I2C mode [0x%08" HWADDR_PRIx 81 "]=%08" PRIx64 "\n", 82 __func__, addr << 2, data); 83 break; 84 } 85 if (data & R_I3C1_REG1_SA_EN_MASK) { 86 qemu_log_mask(LOG_UNIMP, 87 "%s: Unsupported slave mode [%08" HWADDR_PRIx 88 "]=0x%08" PRIx64 "\n", 89 __func__, addr << 2, data); 90 break; 91 } 92 s->regs[addr] = data; 93 break; 94 default: 95 s->regs[addr] = data; 96 break; 97 } 98 } 99 100 static const MemoryRegionOps aspeed_i3c_ops = { 101 .read = aspeed_i3c_read, 102 .write = aspeed_i3c_write, 103 .endianness = DEVICE_LITTLE_ENDIAN, 104 .valid = { 105 .min_access_size = 1, 106 .max_access_size = 4, 107 } 108 }; 109 110 static void aspeed_i3c_reset(DeviceState *dev) 111 { 112 AspeedI3CState *s = ASPEED_I3C(dev); 113 memset(s->regs, 0, sizeof(s->regs)); 114 } 115 116 static void aspeed_i3c_instance_init(Object *obj) 117 { 118 AspeedI3CState *s = ASPEED_I3C(obj); 119 int i; 120 121 for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) { 122 object_initialize_child(obj, "device[*]", &s->devices[i], 123 TYPE_DW_I3C); 124 } 125 } 126 127 static void aspeed_i3c_realize(DeviceState *dev, Error **errp) 128 { 129 int i; 130 AspeedI3CState *s = ASPEED_I3C(dev); 131 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 132 133 memory_region_init(&s->iomem_container, OBJECT(s), 134 TYPE_ASPEED_I3C ".container", 0x8000); 135 136 sysbus_init_mmio(sbd, &s->iomem_container); 137 138 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i3c_ops, s, 139 TYPE_ASPEED_I3C ".regs", ASPEED_I3C_NR_REGS << 2); 140 141 memory_region_add_subregion(&s->iomem_container, 0x0, &s->iomem); 142 143 for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) { 144 Object *i3c_dev = OBJECT(&s->devices[i]); 145 146 if (!object_property_set_uint(i3c_dev, "device-id", i, errp)) { 147 return; 148 } 149 150 if (!sysbus_realize(SYS_BUS_DEVICE(i3c_dev), errp)) { 151 return; 152 } 153 154 /* 155 * Register Address of I3CX Device = 156 * (Base Address of Global Register) + (Offset of I3CX) + Offset 157 * X = 0, 1, 2, 3, 4, 5 158 * Offset of I3C0 = 0x2000 159 * Offset of I3C1 = 0x3000 160 * Offset of I3C2 = 0x4000 161 * Offset of I3C3 = 0x5000 162 * Offset of I3C4 = 0x6000 163 * Offset of I3C5 = 0x7000 164 */ 165 memory_region_add_subregion(&s->iomem_container, 166 0x2000 + i * 0x1000, &s->devices[i].mr); 167 } 168 169 } 170 171 static const VMStateDescription vmstate_aspeed_i3c = { 172 .name = TYPE_ASPEED_I3C, 173 .version_id = 1, 174 .minimum_version_id = 1, 175 .fields = (const VMStateField[]) { 176 VMSTATE_UINT32_ARRAY(regs, AspeedI3CState, ASPEED_I3C_NR_REGS), 177 VMSTATE_STRUCT_ARRAY(devices, AspeedI3CState, ASPEED_I3C_NR_DEVICES, 1, 178 vmstate_dw_i3c, DWI3C), 179 VMSTATE_END_OF_LIST(), 180 } 181 }; 182 183 static void aspeed_i3c_class_init(ObjectClass *klass, const void *data) 184 { 185 DeviceClass *dc = DEVICE_CLASS(klass); 186 187 dc->realize = aspeed_i3c_realize; 188 device_class_set_legacy_reset(dc, aspeed_i3c_reset); 189 dc->desc = "Aspeed I3C Controller"; 190 dc->vmsd = &vmstate_aspeed_i3c; 191 } 192 193 static const TypeInfo aspeed_i3c_info = { 194 .name = TYPE_ASPEED_I3C, 195 .parent = TYPE_SYS_BUS_DEVICE, 196 .instance_init = aspeed_i3c_instance_init, 197 .instance_size = sizeof(AspeedI3CState), 198 .class_init = aspeed_i3c_class_init, 199 }; 200 201 static void aspeed_i3c_register_types(void) 202 { 203 type_register_static(&aspeed_i3c_info); 204 } 205 206 type_init(aspeed_i3c_register_types); 207