12585c679SThomas Huth /* 22585c679SThomas Huth * QEMU Allwinner AHCI Emulation 32585c679SThomas Huth * 42585c679SThomas Huth * This program is free software; you can redistribute it and/or 52585c679SThomas Huth * modify it under the terms of the GNU General Public License 62585c679SThomas Huth * as published by the Free Software Foundation; either version 2 72585c679SThomas Huth * of the License, or (at your option) any later version. 82585c679SThomas Huth * 92585c679SThomas Huth * This program is distributed in the hope that it will be useful, 102585c679SThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 112585c679SThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 122585c679SThomas Huth * GNU General Public License for more details. 132585c679SThomas Huth * 142585c679SThomas Huth * You should have received a copy of the GNU General Public License 152585c679SThomas Huth * along with this program; if not, see <http://www.gnu.org/licenses/>. 162585c679SThomas Huth */ 172585c679SThomas Huth 182585c679SThomas Huth #include "qemu/osdep.h" 192585c679SThomas Huth #include "qemu/error-report.h" 200b8fa32fSMarkus Armbruster #include "qemu/module.h" 212585c679SThomas Huth #include "sysemu/dma.h" 222585c679SThomas Huth #include "hw/ide/internal.h" 23d6454270SMarkus Armbruster #include "migration/vmstate.h" 249314b859SMichael S. Tsirkin #include "ahci_internal.h" 252585c679SThomas Huth 262585c679SThomas Huth #include "trace.h" 272585c679SThomas Huth 282585c679SThomas Huth #define ALLWINNER_AHCI_BISTAFR ((0xa0 - ALLWINNER_AHCI_MMIO_OFF) / 4) 292585c679SThomas Huth #define ALLWINNER_AHCI_BISTCR ((0xa4 - ALLWINNER_AHCI_MMIO_OFF) / 4) 302585c679SThomas Huth #define ALLWINNER_AHCI_BISTFCTR ((0xa8 - ALLWINNER_AHCI_MMIO_OFF) / 4) 312585c679SThomas Huth #define ALLWINNER_AHCI_BISTSR ((0xac - ALLWINNER_AHCI_MMIO_OFF) / 4) 322585c679SThomas Huth #define ALLWINNER_AHCI_BISTDECR ((0xb0 - ALLWINNER_AHCI_MMIO_OFF) / 4) 332585c679SThomas Huth #define ALLWINNER_AHCI_DIAGNR0 ((0xb4 - ALLWINNER_AHCI_MMIO_OFF) / 4) 342585c679SThomas Huth #define ALLWINNER_AHCI_DIAGNR1 ((0xb8 - ALLWINNER_AHCI_MMIO_OFF) / 4) 352585c679SThomas Huth #define ALLWINNER_AHCI_OOBR ((0xbc - ALLWINNER_AHCI_MMIO_OFF) / 4) 362585c679SThomas Huth #define ALLWINNER_AHCI_PHYCS0R ((0xc0 - ALLWINNER_AHCI_MMIO_OFF) / 4) 372585c679SThomas Huth #define ALLWINNER_AHCI_PHYCS1R ((0xc4 - ALLWINNER_AHCI_MMIO_OFF) / 4) 382585c679SThomas Huth #define ALLWINNER_AHCI_PHYCS2R ((0xc8 - ALLWINNER_AHCI_MMIO_OFF) / 4) 392585c679SThomas Huth #define ALLWINNER_AHCI_TIMER1MS ((0xe0 - ALLWINNER_AHCI_MMIO_OFF) / 4) 402585c679SThomas Huth #define ALLWINNER_AHCI_GPARAM1R ((0xe8 - ALLWINNER_AHCI_MMIO_OFF) / 4) 412585c679SThomas Huth #define ALLWINNER_AHCI_GPARAM2R ((0xec - ALLWINNER_AHCI_MMIO_OFF) / 4) 422585c679SThomas Huth #define ALLWINNER_AHCI_PPARAMR ((0xf0 - ALLWINNER_AHCI_MMIO_OFF) / 4) 432585c679SThomas Huth #define ALLWINNER_AHCI_TESTR ((0xf4 - ALLWINNER_AHCI_MMIO_OFF) / 4) 442585c679SThomas Huth #define ALLWINNER_AHCI_VERSIONR ((0xf8 - ALLWINNER_AHCI_MMIO_OFF) / 4) 452585c679SThomas Huth #define ALLWINNER_AHCI_IDR ((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4) 462585c679SThomas Huth #define ALLWINNER_AHCI_RWCR ((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4) 472585c679SThomas Huth 482585c679SThomas Huth static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr, 492585c679SThomas Huth unsigned size) 502585c679SThomas Huth { 512585c679SThomas Huth AllwinnerAHCIState *a = opaque; 522585c679SThomas Huth AHCIState *s = &(SYSBUS_AHCI(a)->ahci); 532585c679SThomas Huth uint64_t val = a->regs[addr / 4]; 542585c679SThomas Huth 552585c679SThomas Huth switch (addr / 4) { 562585c679SThomas Huth case ALLWINNER_AHCI_PHYCS0R: 572585c679SThomas Huth val |= 0x2 << 28; 582585c679SThomas Huth break; 592585c679SThomas Huth case ALLWINNER_AHCI_PHYCS2R: 602585c679SThomas Huth val &= ~(0x1 << 24); 612585c679SThomas Huth break; 622585c679SThomas Huth } 632585c679SThomas Huth trace_allwinner_ahci_mem_read(s, a, addr, val, size); 642585c679SThomas Huth return val; 652585c679SThomas Huth } 662585c679SThomas Huth 672585c679SThomas Huth static void allwinner_ahci_mem_write(void *opaque, hwaddr addr, 682585c679SThomas Huth uint64_t val, unsigned size) 692585c679SThomas Huth { 702585c679SThomas Huth AllwinnerAHCIState *a = opaque; 712585c679SThomas Huth AHCIState *s = &(SYSBUS_AHCI(a)->ahci); 722585c679SThomas Huth 732585c679SThomas Huth trace_allwinner_ahci_mem_write(s, a, addr, val, size); 742585c679SThomas Huth a->regs[addr / 4] = val; 752585c679SThomas Huth } 762585c679SThomas Huth 772585c679SThomas Huth static const MemoryRegionOps allwinner_ahci_mem_ops = { 782585c679SThomas Huth .read = allwinner_ahci_mem_read, 792585c679SThomas Huth .write = allwinner_ahci_mem_write, 802585c679SThomas Huth .valid.min_access_size = 4, 812585c679SThomas Huth .valid.max_access_size = 4, 822585c679SThomas Huth .endianness = DEVICE_LITTLE_ENDIAN, 832585c679SThomas Huth }; 842585c679SThomas Huth 852585c679SThomas Huth static void allwinner_ahci_init(Object *obj) 862585c679SThomas Huth { 872585c679SThomas Huth SysbusAHCIState *s = SYSBUS_AHCI(obj); 882585c679SThomas Huth AllwinnerAHCIState *a = ALLWINNER_AHCI(obj); 892585c679SThomas Huth 90688ffbb4SPhilippe Mathieu-Daudé memory_region_init_io(&a->mmio, obj, &allwinner_ahci_mem_ops, a, 912585c679SThomas Huth "allwinner-ahci", ALLWINNER_AHCI_MMIO_SIZE); 922585c679SThomas Huth memory_region_add_subregion(&s->ahci.mem, ALLWINNER_AHCI_MMIO_OFF, 932585c679SThomas Huth &a->mmio); 942585c679SThomas Huth } 952585c679SThomas Huth 962585c679SThomas Huth static const VMStateDescription vmstate_allwinner_ahci = { 972585c679SThomas Huth .name = "allwinner-ahci", 982585c679SThomas Huth .version_id = 1, 992585c679SThomas Huth .minimum_version_id = 1, 100*8595c054SRichard Henderson .fields = (const VMStateField[]) { 1012585c679SThomas Huth VMSTATE_UINT32_ARRAY(regs, AllwinnerAHCIState, 1022585c679SThomas Huth ALLWINNER_AHCI_MMIO_SIZE / 4), 1032585c679SThomas Huth VMSTATE_END_OF_LIST() 1042585c679SThomas Huth } 1052585c679SThomas Huth }; 1062585c679SThomas Huth 1072585c679SThomas Huth static void allwinner_ahci_class_init(ObjectClass *klass, void *data) 1082585c679SThomas Huth { 1092585c679SThomas Huth DeviceClass *dc = DEVICE_CLASS(klass); 1102585c679SThomas Huth 1112585c679SThomas Huth dc->vmsd = &vmstate_allwinner_ahci; 1122585c679SThomas Huth } 1132585c679SThomas Huth 1142585c679SThomas Huth static const TypeInfo allwinner_ahci_info = { 1152585c679SThomas Huth .name = TYPE_ALLWINNER_AHCI, 1162585c679SThomas Huth .parent = TYPE_SYSBUS_AHCI, 1172585c679SThomas Huth .instance_size = sizeof(AllwinnerAHCIState), 1182585c679SThomas Huth .instance_init = allwinner_ahci_init, 1192585c679SThomas Huth .class_init = allwinner_ahci_class_init, 1202585c679SThomas Huth }; 1212585c679SThomas Huth 1222585c679SThomas Huth static void sysbus_ahci_register_types(void) 1232585c679SThomas Huth { 1242585c679SThomas Huth type_register_static(&allwinner_ahci_info); 1252585c679SThomas Huth } 1262585c679SThomas Huth 1272585c679SThomas Huth type_init(sysbus_ahci_register_types) 128