105def917Sqianfan Zhao /* 205def917Sqianfan Zhao * Allwinner R40 SRAM controller emulation 305def917Sqianfan Zhao * 405def917Sqianfan Zhao * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com> 505def917Sqianfan Zhao * 605def917Sqianfan Zhao * This program is free software: you can redistribute it and/or modify 705def917Sqianfan Zhao * it under the terms of the GNU General Public License as published by 805def917Sqianfan Zhao * the Free Software Foundation, either version 2 of the License, or 905def917Sqianfan Zhao * (at your option) any later version. 1005def917Sqianfan Zhao * 1105def917Sqianfan Zhao * This program is distributed in the hope that it will be useful, 1205def917Sqianfan Zhao * but WITHOUT ANY WARRANTY; without even the implied warranty of 1305def917Sqianfan Zhao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1405def917Sqianfan Zhao * GNU General Public License for more details. 1505def917Sqianfan Zhao * 1605def917Sqianfan Zhao * You should have received a copy of the GNU General Public License 1705def917Sqianfan Zhao * along with this program. If not, see <http://www.gnu.org/licenses/>. 1805def917Sqianfan Zhao */ 1905def917Sqianfan Zhao 2005def917Sqianfan Zhao #include "qemu/osdep.h" 2105def917Sqianfan Zhao #include "qemu/units.h" 2205def917Sqianfan Zhao #include "hw/sysbus.h" 2305def917Sqianfan Zhao #include "migration/vmstate.h" 2405def917Sqianfan Zhao #include "qemu/log.h" 2505def917Sqianfan Zhao #include "qemu/module.h" 2605def917Sqianfan Zhao #include "qapi/error.h" 2705def917Sqianfan Zhao #include "hw/qdev-properties.h" 2805def917Sqianfan Zhao #include "hw/qdev-properties-system.h" 2905def917Sqianfan Zhao #include "hw/misc/allwinner-sramc.h" 3005def917Sqianfan Zhao #include "trace.h" 3105def917Sqianfan Zhao 3205def917Sqianfan Zhao /* 3305def917Sqianfan Zhao * register offsets 3405def917Sqianfan Zhao * https://linux-sunxi.org/SRAM_Controller_Register_Guide 3505def917Sqianfan Zhao */ 3605def917Sqianfan Zhao enum { 3705def917Sqianfan Zhao REG_SRAM_CTL1_CFG = 0x04, /* SRAM Control register 1 */ 3805def917Sqianfan Zhao REG_SRAM_VER = 0x24, /* SRAM Version register */ 3905def917Sqianfan Zhao REG_SRAM_R40_SOFT_ENTRY_REG0 = 0xbc, 4005def917Sqianfan Zhao }; 4105def917Sqianfan Zhao 4205def917Sqianfan Zhao /* REG_SRAMC_VERSION bit defines */ 4305def917Sqianfan Zhao #define SRAM_VER_READ_ENABLE (1 << 15) 4405def917Sqianfan Zhao #define SRAM_VER_VERSION_SHIFT 16 4505def917Sqianfan Zhao #define SRAM_VERSION_SUN8I_R40 0x1701 4605def917Sqianfan Zhao 4705def917Sqianfan Zhao static uint64_t allwinner_sramc_read(void *opaque, hwaddr offset, 4805def917Sqianfan Zhao unsigned size) 4905def917Sqianfan Zhao { 5005def917Sqianfan Zhao AwSRAMCState *s = AW_SRAMC(opaque); 5105def917Sqianfan Zhao AwSRAMCClass *sc = AW_SRAMC_GET_CLASS(s); 5205def917Sqianfan Zhao uint64_t val = 0; 5305def917Sqianfan Zhao 5405def917Sqianfan Zhao switch (offset) { 5505def917Sqianfan Zhao case REG_SRAM_CTL1_CFG: 5605def917Sqianfan Zhao val = s->sram_ctl1; 5705def917Sqianfan Zhao break; 5805def917Sqianfan Zhao case REG_SRAM_VER: 5905def917Sqianfan Zhao /* bit15: lock bit, set this bit before reading this register */ 6005def917Sqianfan Zhao if (s->sram_ver & SRAM_VER_READ_ENABLE) { 6105def917Sqianfan Zhao val = SRAM_VER_READ_ENABLE | 6205def917Sqianfan Zhao (sc->sram_version_code << SRAM_VER_VERSION_SHIFT); 6305def917Sqianfan Zhao } 6405def917Sqianfan Zhao break; 6505def917Sqianfan Zhao case REG_SRAM_R40_SOFT_ENTRY_REG0: 6605def917Sqianfan Zhao val = s->sram_soft_entry_reg0; 6705def917Sqianfan Zhao break; 6805def917Sqianfan Zhao default: 6905def917Sqianfan Zhao qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 7005def917Sqianfan Zhao __func__, (uint32_t)offset); 7105def917Sqianfan Zhao return 0; 7205def917Sqianfan Zhao } 7305def917Sqianfan Zhao 7405def917Sqianfan Zhao trace_allwinner_sramc_read(offset, val); 7505def917Sqianfan Zhao 7605def917Sqianfan Zhao return val; 7705def917Sqianfan Zhao } 7805def917Sqianfan Zhao 7905def917Sqianfan Zhao static void allwinner_sramc_write(void *opaque, hwaddr offset, 8005def917Sqianfan Zhao uint64_t val, unsigned size) 8105def917Sqianfan Zhao { 8205def917Sqianfan Zhao AwSRAMCState *s = AW_SRAMC(opaque); 8305def917Sqianfan Zhao 8405def917Sqianfan Zhao trace_allwinner_sramc_write(offset, val); 8505def917Sqianfan Zhao 8605def917Sqianfan Zhao switch (offset) { 8705def917Sqianfan Zhao case REG_SRAM_CTL1_CFG: 8805def917Sqianfan Zhao s->sram_ctl1 = val; 8905def917Sqianfan Zhao break; 9005def917Sqianfan Zhao case REG_SRAM_VER: 9105def917Sqianfan Zhao /* Only the READ_ENABLE bit is writeable */ 9205def917Sqianfan Zhao s->sram_ver = val & SRAM_VER_READ_ENABLE; 9305def917Sqianfan Zhao break; 9405def917Sqianfan Zhao case REG_SRAM_R40_SOFT_ENTRY_REG0: 9505def917Sqianfan Zhao s->sram_soft_entry_reg0 = val; 9605def917Sqianfan Zhao break; 9705def917Sqianfan Zhao default: 9805def917Sqianfan Zhao qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 9905def917Sqianfan Zhao __func__, (uint32_t)offset); 10005def917Sqianfan Zhao break; 10105def917Sqianfan Zhao } 10205def917Sqianfan Zhao } 10305def917Sqianfan Zhao 10405def917Sqianfan Zhao static const MemoryRegionOps allwinner_sramc_ops = { 10505def917Sqianfan Zhao .read = allwinner_sramc_read, 10605def917Sqianfan Zhao .write = allwinner_sramc_write, 10705def917Sqianfan Zhao .endianness = DEVICE_NATIVE_ENDIAN, 10805def917Sqianfan Zhao .valid = { 10905def917Sqianfan Zhao .min_access_size = 4, 11005def917Sqianfan Zhao .max_access_size = 4, 11105def917Sqianfan Zhao }, 11205def917Sqianfan Zhao .impl.min_access_size = 4, 11305def917Sqianfan Zhao }; 11405def917Sqianfan Zhao 11505def917Sqianfan Zhao static const VMStateDescription allwinner_sramc_vmstate = { 11605def917Sqianfan Zhao .name = "allwinner-sramc", 11705def917Sqianfan Zhao .version_id = 1, 11805def917Sqianfan Zhao .minimum_version_id = 1, 119*e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 12005def917Sqianfan Zhao VMSTATE_UINT32(sram_ver, AwSRAMCState), 12105def917Sqianfan Zhao VMSTATE_UINT32(sram_soft_entry_reg0, AwSRAMCState), 12205def917Sqianfan Zhao VMSTATE_END_OF_LIST() 12305def917Sqianfan Zhao } 12405def917Sqianfan Zhao }; 12505def917Sqianfan Zhao 12605def917Sqianfan Zhao static void allwinner_sramc_reset(DeviceState *dev) 12705def917Sqianfan Zhao { 12805def917Sqianfan Zhao AwSRAMCState *s = AW_SRAMC(dev); 12905def917Sqianfan Zhao AwSRAMCClass *sc = AW_SRAMC_GET_CLASS(s); 13005def917Sqianfan Zhao 13105def917Sqianfan Zhao switch (sc->sram_version_code) { 13205def917Sqianfan Zhao case SRAM_VERSION_SUN8I_R40: 13305def917Sqianfan Zhao s->sram_ctl1 = 0x1300; 13405def917Sqianfan Zhao break; 13505def917Sqianfan Zhao } 13605def917Sqianfan Zhao } 13705def917Sqianfan Zhao 13805def917Sqianfan Zhao static void allwinner_sramc_class_init(ObjectClass *klass, void *data) 13905def917Sqianfan Zhao { 14005def917Sqianfan Zhao DeviceClass *dc = DEVICE_CLASS(klass); 14105def917Sqianfan Zhao 14205def917Sqianfan Zhao dc->reset = allwinner_sramc_reset; 14305def917Sqianfan Zhao dc->vmsd = &allwinner_sramc_vmstate; 14405def917Sqianfan Zhao } 14505def917Sqianfan Zhao 14605def917Sqianfan Zhao static void allwinner_sramc_init(Object *obj) 14705def917Sqianfan Zhao { 14805def917Sqianfan Zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 14905def917Sqianfan Zhao AwSRAMCState *s = AW_SRAMC(obj); 15005def917Sqianfan Zhao 15105def917Sqianfan Zhao /* Memory mapping */ 15205def917Sqianfan Zhao memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_sramc_ops, s, 15305def917Sqianfan Zhao TYPE_AW_SRAMC, 1 * KiB); 15405def917Sqianfan Zhao sysbus_init_mmio(sbd, &s->iomem); 15505def917Sqianfan Zhao } 15605def917Sqianfan Zhao 15705def917Sqianfan Zhao static const TypeInfo allwinner_sramc_info = { 15805def917Sqianfan Zhao .name = TYPE_AW_SRAMC, 15905def917Sqianfan Zhao .parent = TYPE_SYS_BUS_DEVICE, 16005def917Sqianfan Zhao .instance_init = allwinner_sramc_init, 16105def917Sqianfan Zhao .instance_size = sizeof(AwSRAMCState), 1629057e5f7SAkihiko Odaki .class_size = sizeof(AwSRAMCClass), 16305def917Sqianfan Zhao .class_init = allwinner_sramc_class_init, 16405def917Sqianfan Zhao }; 16505def917Sqianfan Zhao 16605def917Sqianfan Zhao static void allwinner_r40_sramc_class_init(ObjectClass *klass, void *data) 16705def917Sqianfan Zhao { 16805def917Sqianfan Zhao AwSRAMCClass *sc = AW_SRAMC_CLASS(klass); 16905def917Sqianfan Zhao 17005def917Sqianfan Zhao sc->sram_version_code = SRAM_VERSION_SUN8I_R40; 17105def917Sqianfan Zhao } 17205def917Sqianfan Zhao 17305def917Sqianfan Zhao static const TypeInfo allwinner_r40_sramc_info = { 17405def917Sqianfan Zhao .name = TYPE_AW_SRAMC_SUN8I_R40, 17505def917Sqianfan Zhao .parent = TYPE_AW_SRAMC, 17605def917Sqianfan Zhao .class_init = allwinner_r40_sramc_class_init, 17705def917Sqianfan Zhao }; 17805def917Sqianfan Zhao 17905def917Sqianfan Zhao static void allwinner_sramc_register(void) 18005def917Sqianfan Zhao { 18105def917Sqianfan Zhao type_register_static(&allwinner_sramc_info); 18205def917Sqianfan Zhao type_register_static(&allwinner_r40_sramc_info); 18305def917Sqianfan Zhao } 18405def917Sqianfan Zhao 18505def917Sqianfan Zhao type_init(allwinner_sramc_register) 186