xref: /openbmc/qemu/hw/misc/allwinner-sramc.c (revision 05def917e113ef95ef712ffd96d614203f5e8397)
1*05def917Sqianfan Zhao /*
2*05def917Sqianfan Zhao  * Allwinner R40 SRAM controller emulation
3*05def917Sqianfan Zhao  *
4*05def917Sqianfan Zhao  * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
5*05def917Sqianfan Zhao  *
6*05def917Sqianfan Zhao  * This program is free software: you can redistribute it and/or modify
7*05def917Sqianfan Zhao  * it under the terms of the GNU General Public License as published by
8*05def917Sqianfan Zhao  * the Free Software Foundation, either version 2 of the License, or
9*05def917Sqianfan Zhao  * (at your option) any later version.
10*05def917Sqianfan Zhao  *
11*05def917Sqianfan Zhao  * This program is distributed in the hope that it will be useful,
12*05def917Sqianfan Zhao  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*05def917Sqianfan Zhao  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*05def917Sqianfan Zhao  * GNU General Public License for more details.
15*05def917Sqianfan Zhao  *
16*05def917Sqianfan Zhao  * You should have received a copy of the GNU General Public License
17*05def917Sqianfan Zhao  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18*05def917Sqianfan Zhao  */
19*05def917Sqianfan Zhao 
20*05def917Sqianfan Zhao #include "qemu/osdep.h"
21*05def917Sqianfan Zhao #include "qemu/units.h"
22*05def917Sqianfan Zhao #include "hw/sysbus.h"
23*05def917Sqianfan Zhao #include "migration/vmstate.h"
24*05def917Sqianfan Zhao #include "qemu/log.h"
25*05def917Sqianfan Zhao #include "qemu/module.h"
26*05def917Sqianfan Zhao #include "qapi/error.h"
27*05def917Sqianfan Zhao #include "hw/qdev-properties.h"
28*05def917Sqianfan Zhao #include "hw/qdev-properties-system.h"
29*05def917Sqianfan Zhao #include "hw/misc/allwinner-sramc.h"
30*05def917Sqianfan Zhao #include "trace.h"
31*05def917Sqianfan Zhao 
32*05def917Sqianfan Zhao /*
33*05def917Sqianfan Zhao  * register offsets
34*05def917Sqianfan Zhao  * https://linux-sunxi.org/SRAM_Controller_Register_Guide
35*05def917Sqianfan Zhao  */
36*05def917Sqianfan Zhao enum {
37*05def917Sqianfan Zhao     REG_SRAM_CTL1_CFG               = 0x04, /* SRAM Control register 1 */
38*05def917Sqianfan Zhao     REG_SRAM_VER                    = 0x24, /* SRAM Version register */
39*05def917Sqianfan Zhao     REG_SRAM_R40_SOFT_ENTRY_REG0    = 0xbc,
40*05def917Sqianfan Zhao };
41*05def917Sqianfan Zhao 
42*05def917Sqianfan Zhao /* REG_SRAMC_VERSION bit defines */
43*05def917Sqianfan Zhao #define SRAM_VER_READ_ENABLE            (1 << 15)
44*05def917Sqianfan Zhao #define SRAM_VER_VERSION_SHIFT          16
45*05def917Sqianfan Zhao #define SRAM_VERSION_SUN8I_R40          0x1701
46*05def917Sqianfan Zhao 
47*05def917Sqianfan Zhao static uint64_t allwinner_sramc_read(void *opaque, hwaddr offset,
48*05def917Sqianfan Zhao                                      unsigned size)
49*05def917Sqianfan Zhao {
50*05def917Sqianfan Zhao     AwSRAMCState *s = AW_SRAMC(opaque);
51*05def917Sqianfan Zhao     AwSRAMCClass *sc = AW_SRAMC_GET_CLASS(s);
52*05def917Sqianfan Zhao     uint64_t val = 0;
53*05def917Sqianfan Zhao 
54*05def917Sqianfan Zhao     switch (offset) {
55*05def917Sqianfan Zhao     case REG_SRAM_CTL1_CFG:
56*05def917Sqianfan Zhao         val = s->sram_ctl1;
57*05def917Sqianfan Zhao         break;
58*05def917Sqianfan Zhao     case REG_SRAM_VER:
59*05def917Sqianfan Zhao         /* bit15: lock bit, set this bit before reading this register */
60*05def917Sqianfan Zhao         if (s->sram_ver & SRAM_VER_READ_ENABLE) {
61*05def917Sqianfan Zhao             val = SRAM_VER_READ_ENABLE |
62*05def917Sqianfan Zhao                     (sc->sram_version_code << SRAM_VER_VERSION_SHIFT);
63*05def917Sqianfan Zhao         }
64*05def917Sqianfan Zhao         break;
65*05def917Sqianfan Zhao     case REG_SRAM_R40_SOFT_ENTRY_REG0:
66*05def917Sqianfan Zhao         val = s->sram_soft_entry_reg0;
67*05def917Sqianfan Zhao         break;
68*05def917Sqianfan Zhao     default:
69*05def917Sqianfan Zhao         qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
70*05def917Sqianfan Zhao                       __func__, (uint32_t)offset);
71*05def917Sqianfan Zhao         return 0;
72*05def917Sqianfan Zhao     }
73*05def917Sqianfan Zhao 
74*05def917Sqianfan Zhao     trace_allwinner_sramc_read(offset, val);
75*05def917Sqianfan Zhao 
76*05def917Sqianfan Zhao     return val;
77*05def917Sqianfan Zhao }
78*05def917Sqianfan Zhao 
79*05def917Sqianfan Zhao static void allwinner_sramc_write(void *opaque, hwaddr offset,
80*05def917Sqianfan Zhao                                   uint64_t val, unsigned size)
81*05def917Sqianfan Zhao {
82*05def917Sqianfan Zhao     AwSRAMCState *s = AW_SRAMC(opaque);
83*05def917Sqianfan Zhao 
84*05def917Sqianfan Zhao     trace_allwinner_sramc_write(offset, val);
85*05def917Sqianfan Zhao 
86*05def917Sqianfan Zhao     switch (offset) {
87*05def917Sqianfan Zhao     case REG_SRAM_CTL1_CFG:
88*05def917Sqianfan Zhao         s->sram_ctl1 = val;
89*05def917Sqianfan Zhao         break;
90*05def917Sqianfan Zhao     case REG_SRAM_VER:
91*05def917Sqianfan Zhao         /* Only the READ_ENABLE bit is writeable */
92*05def917Sqianfan Zhao         s->sram_ver = val & SRAM_VER_READ_ENABLE;
93*05def917Sqianfan Zhao         break;
94*05def917Sqianfan Zhao     case REG_SRAM_R40_SOFT_ENTRY_REG0:
95*05def917Sqianfan Zhao         s->sram_soft_entry_reg0 = val;
96*05def917Sqianfan Zhao         break;
97*05def917Sqianfan Zhao     default:
98*05def917Sqianfan Zhao         qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
99*05def917Sqianfan Zhao                       __func__, (uint32_t)offset);
100*05def917Sqianfan Zhao         break;
101*05def917Sqianfan Zhao     }
102*05def917Sqianfan Zhao }
103*05def917Sqianfan Zhao 
104*05def917Sqianfan Zhao static const MemoryRegionOps allwinner_sramc_ops = {
105*05def917Sqianfan Zhao     .read = allwinner_sramc_read,
106*05def917Sqianfan Zhao     .write = allwinner_sramc_write,
107*05def917Sqianfan Zhao     .endianness = DEVICE_NATIVE_ENDIAN,
108*05def917Sqianfan Zhao     .valid = {
109*05def917Sqianfan Zhao         .min_access_size = 4,
110*05def917Sqianfan Zhao         .max_access_size = 4,
111*05def917Sqianfan Zhao     },
112*05def917Sqianfan Zhao     .impl.min_access_size = 4,
113*05def917Sqianfan Zhao };
114*05def917Sqianfan Zhao 
115*05def917Sqianfan Zhao static const VMStateDescription allwinner_sramc_vmstate = {
116*05def917Sqianfan Zhao     .name = "allwinner-sramc",
117*05def917Sqianfan Zhao     .version_id = 1,
118*05def917Sqianfan Zhao     .minimum_version_id = 1,
119*05def917Sqianfan Zhao     .fields = (VMStateField[]) {
120*05def917Sqianfan Zhao         VMSTATE_UINT32(sram_ver, AwSRAMCState),
121*05def917Sqianfan Zhao         VMSTATE_UINT32(sram_soft_entry_reg0, AwSRAMCState),
122*05def917Sqianfan Zhao         VMSTATE_END_OF_LIST()
123*05def917Sqianfan Zhao     }
124*05def917Sqianfan Zhao };
125*05def917Sqianfan Zhao 
126*05def917Sqianfan Zhao static void allwinner_sramc_reset(DeviceState *dev)
127*05def917Sqianfan Zhao {
128*05def917Sqianfan Zhao     AwSRAMCState *s = AW_SRAMC(dev);
129*05def917Sqianfan Zhao     AwSRAMCClass *sc = AW_SRAMC_GET_CLASS(s);
130*05def917Sqianfan Zhao 
131*05def917Sqianfan Zhao     switch (sc->sram_version_code) {
132*05def917Sqianfan Zhao     case SRAM_VERSION_SUN8I_R40:
133*05def917Sqianfan Zhao         s->sram_ctl1 = 0x1300;
134*05def917Sqianfan Zhao         break;
135*05def917Sqianfan Zhao     }
136*05def917Sqianfan Zhao }
137*05def917Sqianfan Zhao 
138*05def917Sqianfan Zhao static void allwinner_sramc_class_init(ObjectClass *klass, void *data)
139*05def917Sqianfan Zhao {
140*05def917Sqianfan Zhao     DeviceClass *dc = DEVICE_CLASS(klass);
141*05def917Sqianfan Zhao 
142*05def917Sqianfan Zhao     dc->reset = allwinner_sramc_reset;
143*05def917Sqianfan Zhao     dc->vmsd = &allwinner_sramc_vmstate;
144*05def917Sqianfan Zhao }
145*05def917Sqianfan Zhao 
146*05def917Sqianfan Zhao static void allwinner_sramc_init(Object *obj)
147*05def917Sqianfan Zhao {
148*05def917Sqianfan Zhao     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
149*05def917Sqianfan Zhao     AwSRAMCState *s = AW_SRAMC(obj);
150*05def917Sqianfan Zhao 
151*05def917Sqianfan Zhao     /* Memory mapping */
152*05def917Sqianfan Zhao     memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_sramc_ops, s,
153*05def917Sqianfan Zhao                            TYPE_AW_SRAMC, 1 * KiB);
154*05def917Sqianfan Zhao     sysbus_init_mmio(sbd, &s->iomem);
155*05def917Sqianfan Zhao }
156*05def917Sqianfan Zhao 
157*05def917Sqianfan Zhao static const TypeInfo allwinner_sramc_info = {
158*05def917Sqianfan Zhao     .name          = TYPE_AW_SRAMC,
159*05def917Sqianfan Zhao     .parent        = TYPE_SYS_BUS_DEVICE,
160*05def917Sqianfan Zhao     .instance_init = allwinner_sramc_init,
161*05def917Sqianfan Zhao     .instance_size = sizeof(AwSRAMCState),
162*05def917Sqianfan Zhao     .class_init    = allwinner_sramc_class_init,
163*05def917Sqianfan Zhao };
164*05def917Sqianfan Zhao 
165*05def917Sqianfan Zhao static void allwinner_r40_sramc_class_init(ObjectClass *klass, void *data)
166*05def917Sqianfan Zhao {
167*05def917Sqianfan Zhao     AwSRAMCClass *sc = AW_SRAMC_CLASS(klass);
168*05def917Sqianfan Zhao 
169*05def917Sqianfan Zhao     sc->sram_version_code = SRAM_VERSION_SUN8I_R40;
170*05def917Sqianfan Zhao }
171*05def917Sqianfan Zhao 
172*05def917Sqianfan Zhao static const TypeInfo allwinner_r40_sramc_info = {
173*05def917Sqianfan Zhao     .name          = TYPE_AW_SRAMC_SUN8I_R40,
174*05def917Sqianfan Zhao     .parent        = TYPE_AW_SRAMC,
175*05def917Sqianfan Zhao     .class_init    = allwinner_r40_sramc_class_init,
176*05def917Sqianfan Zhao };
177*05def917Sqianfan Zhao 
178*05def917Sqianfan Zhao static void allwinner_sramc_register(void)
179*05def917Sqianfan Zhao {
180*05def917Sqianfan Zhao     type_register_static(&allwinner_sramc_info);
181*05def917Sqianfan Zhao     type_register_static(&allwinner_r40_sramc_info);
182*05def917Sqianfan Zhao }
183*05def917Sqianfan Zhao 
184*05def917Sqianfan Zhao type_init(allwinner_sramc_register)
185