| 
									
										
										
										
											2017-10-31 13:48:59 -04:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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"
 | 
					
						
							| 
									
										
										
										
											2019-05-23 16:35:07 +02:00
										 |  |  | #include "qemu/module.h"
 | 
					
						
							| 
									
										
										
										
											2017-10-31 13:48:59 -04:00
										 |  |  | #include "sysemu/dma.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:45 +02:00
										 |  |  | #include "migration/vmstate.h"
 | 
					
						
							| 
									
										
										
										
											2024-02-13 06:15:13 +01:00
										 |  |  | #include "hw/ide/ahci-sysbus.h"
 | 
					
						
							| 
									
										
										
										
											2017-10-31 13:48:59 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | #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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-12 09:00:19 +02:00
										 |  |  |     memory_region_init_io(&a->mmio, obj, &allwinner_ahci_mem_ops, a, | 
					
						
							| 
									
										
										
										
											2017-10-31 13:48:59 -04:00
										 |  |  |                           "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, | 
					
						
							| 
									
										
										
										
											2023-12-21 14:16:13 +11:00
										 |  |  |     .fields = (const VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2017-10-31 13:48:59 -04:00
										 |  |  |         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) |