| /* | 
 |  * QEMU Allwinner AHCI Emulation | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU General Public License | 
 |  * as published by the Free Software Foundation; either version 2 | 
 |  * of the License, or (at your option) any later version. | 
 |  * | 
 |  * This program is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |  * GNU General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU General Public License | 
 |  * along with this program; if not, see <http://www.gnu.org/licenses/>. | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 | #include "qemu/error-report.h" | 
 | #include "qemu/module.h" | 
 | #include "sysemu/dma.h" | 
 | #include "hw/ide/internal.h" | 
 | #include "migration/vmstate.h" | 
 | #include "ahci_internal.h" | 
 |  | 
 | #include "trace.h" | 
 |  | 
 | #define ALLWINNER_AHCI_BISTAFR    ((0xa0 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_BISTCR     ((0xa4 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_BISTFCTR   ((0xa8 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_BISTSR     ((0xac - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_BISTDECR   ((0xb0 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_DIAGNR0    ((0xb4 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_DIAGNR1    ((0xb8 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_OOBR       ((0xbc - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_PHYCS0R    ((0xc0 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_PHYCS1R    ((0xc4 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_PHYCS2R    ((0xc8 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_TIMER1MS   ((0xe0 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_GPARAM1R   ((0xe8 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_GPARAM2R   ((0xec - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_PPARAMR    ((0xf0 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_TESTR      ((0xf4 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_VERSIONR   ((0xf8 - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_IDR        ((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 | #define ALLWINNER_AHCI_RWCR       ((0xfc - ALLWINNER_AHCI_MMIO_OFF) / 4) | 
 |  | 
 | static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr, | 
 |                                         unsigned size) | 
 | { | 
 |     AllwinnerAHCIState *a = opaque; | 
 |     AHCIState *s = &(SYSBUS_AHCI(a)->ahci); | 
 |     uint64_t val = a->regs[addr / 4]; | 
 |  | 
 |     switch (addr / 4) { | 
 |     case ALLWINNER_AHCI_PHYCS0R: | 
 |         val |= 0x2 << 28; | 
 |         break; | 
 |     case ALLWINNER_AHCI_PHYCS2R: | 
 |         val &= ~(0x1 << 24); | 
 |         break; | 
 |     } | 
 |     trace_allwinner_ahci_mem_read(s, a, addr, val, size); | 
 |     return  val; | 
 | } | 
 |  | 
 | static void allwinner_ahci_mem_write(void *opaque, hwaddr addr, | 
 |                                      uint64_t val, unsigned size) | 
 | { | 
 |     AllwinnerAHCIState *a = opaque; | 
 |     AHCIState *s = &(SYSBUS_AHCI(a)->ahci); | 
 |  | 
 |     trace_allwinner_ahci_mem_write(s, a, addr, val, size); | 
 |     a->regs[addr / 4] = val; | 
 | } | 
 |  | 
 | static const MemoryRegionOps allwinner_ahci_mem_ops = { | 
 |     .read = allwinner_ahci_mem_read, | 
 |     .write = allwinner_ahci_mem_write, | 
 |     .valid.min_access_size = 4, | 
 |     .valid.max_access_size = 4, | 
 |     .endianness = DEVICE_LITTLE_ENDIAN, | 
 | }; | 
 |  | 
 | static void allwinner_ahci_init(Object *obj) | 
 | { | 
 |     SysbusAHCIState *s = SYSBUS_AHCI(obj); | 
 |     AllwinnerAHCIState *a = ALLWINNER_AHCI(obj); | 
 |  | 
 |     memory_region_init_io(&a->mmio, obj, &allwinner_ahci_mem_ops, a, | 
 |                           "allwinner-ahci", ALLWINNER_AHCI_MMIO_SIZE); | 
 |     memory_region_add_subregion(&s->ahci.mem, ALLWINNER_AHCI_MMIO_OFF, | 
 |                                 &a->mmio); | 
 | } | 
 |  | 
 | static const VMStateDescription vmstate_allwinner_ahci = { | 
 |     .name = "allwinner-ahci", | 
 |     .version_id = 1, | 
 |     .minimum_version_id = 1, | 
 |     .fields = (VMStateField[]) { | 
 |         VMSTATE_UINT32_ARRAY(regs, AllwinnerAHCIState, | 
 |                              ALLWINNER_AHCI_MMIO_SIZE / 4), | 
 |         VMSTATE_END_OF_LIST() | 
 |     } | 
 | }; | 
 |  | 
 | static void allwinner_ahci_class_init(ObjectClass *klass, void *data) | 
 | { | 
 |     DeviceClass *dc = DEVICE_CLASS(klass); | 
 |  | 
 |     dc->vmsd = &vmstate_allwinner_ahci; | 
 | } | 
 |  | 
 | static const TypeInfo allwinner_ahci_info = { | 
 |     .name          = TYPE_ALLWINNER_AHCI, | 
 |     .parent        = TYPE_SYSBUS_AHCI, | 
 |     .instance_size = sizeof(AllwinnerAHCIState), | 
 |     .instance_init = allwinner_ahci_init, | 
 |     .class_init    = allwinner_ahci_class_init, | 
 | }; | 
 |  | 
 | static void sysbus_ahci_register_types(void) | 
 | { | 
 |     type_register_static(&allwinner_ahci_info); | 
 | } | 
 |  | 
 | type_init(sysbus_ahci_register_types) |