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
allwinner_sramc_read(void * opaque,hwaddr offset,unsigned size)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
allwinner_sramc_write(void * opaque,hwaddr offset,uint64_t val,unsigned size)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,
119e4ea952fSRichard 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
allwinner_sramc_reset(DeviceState * dev)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
allwinner_sramc_class_init(ObjectClass * klass,void * data)13805def917Sqianfan Zhao static void allwinner_sramc_class_init(ObjectClass *klass, void *data)
13905def917Sqianfan Zhao {
14005def917Sqianfan Zhao DeviceClass *dc = DEVICE_CLASS(klass);
14105def917Sqianfan Zhao
142*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, allwinner_sramc_reset);
14305def917Sqianfan Zhao dc->vmsd = &allwinner_sramc_vmstate;
14405def917Sqianfan Zhao }
14505def917Sqianfan Zhao
allwinner_sramc_init(Object * obj)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
allwinner_r40_sramc_class_init(ObjectClass * klass,void * data)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
allwinner_sramc_register(void)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