xref: /openbmc/qemu/hw/misc/arm_l2x0.c (revision 1b111dc1)
1 /*
2  * ARM dummy L210, L220, PL310 cache controller.
3  *
4  * Copyright (c) 2010-2012 Calxeda
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2 or any later version, as published by the Free Software
9  * Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "hw/sysbus.h"
22 
23 /* L2C-310 r3p2 */
24 #define CACHE_ID 0x410000c8
25 
26 #define TYPE_ARM_L2X0 "l2x0"
27 #define ARM_L2X0(obj) OBJECT_CHECK(L2x0State, (obj), TYPE_ARM_L2X0)
28 
29 typedef struct L2x0State {
30     SysBusDevice parent_obj;
31 
32     MemoryRegion iomem;
33     uint32_t cache_type;
34     uint32_t ctrl;
35     uint32_t aux_ctrl;
36     uint32_t data_ctrl;
37     uint32_t tag_ctrl;
38     uint32_t filter_start;
39     uint32_t filter_end;
40 } L2x0State;
41 
42 static const VMStateDescription vmstate_l2x0 = {
43     .name = "l2x0",
44     .version_id = 1,
45     .minimum_version_id = 1,
46     .fields = (VMStateField[]) {
47         VMSTATE_UINT32(ctrl, L2x0State),
48         VMSTATE_UINT32(aux_ctrl, L2x0State),
49         VMSTATE_UINT32(data_ctrl, L2x0State),
50         VMSTATE_UINT32(tag_ctrl, L2x0State),
51         VMSTATE_UINT32(filter_start, L2x0State),
52         VMSTATE_UINT32(filter_end, L2x0State),
53         VMSTATE_END_OF_LIST()
54     }
55 };
56 
57 
58 static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
59                                unsigned size)
60 {
61     uint32_t cache_data;
62     L2x0State *s = (L2x0State *)opaque;
63     offset &= 0xfff;
64     if (offset >= 0x730 && offset < 0x800) {
65         return 0; /* cache ops complete */
66     }
67     switch (offset) {
68     case 0:
69         return CACHE_ID;
70     case 0x4:
71         /* aux_ctrl values affect cache_type values */
72         cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
73         cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
74         return s->cache_type |= (cache_data << 18) | (cache_data << 6);
75     case 0x100:
76         return s->ctrl;
77     case 0x104:
78         return s->aux_ctrl;
79     case 0x108:
80         return s->tag_ctrl;
81     case 0x10C:
82         return s->data_ctrl;
83     case 0xC00:
84         return s->filter_start;
85     case 0xC04:
86         return s->filter_end;
87     case 0xF40:
88         return 0;
89     case 0xF60:
90         return 0;
91     case 0xF80:
92         return 0;
93     default:
94         qemu_log_mask(LOG_GUEST_ERROR,
95                       "l2x0_priv_read: Bad offset %x\n", (int)offset);
96         break;
97     }
98     return 0;
99 }
100 
101 static void l2x0_priv_write(void *opaque, hwaddr offset,
102                             uint64_t value, unsigned size)
103 {
104     L2x0State *s = (L2x0State *)opaque;
105     offset &= 0xfff;
106     if (offset >= 0x730 && offset < 0x800) {
107         /* ignore */
108         return;
109     }
110     switch (offset) {
111     case 0x100:
112         s->ctrl = value & 1;
113         break;
114     case 0x104:
115         s->aux_ctrl = value;
116         break;
117     case 0x108:
118         s->tag_ctrl = value;
119         break;
120     case 0x10C:
121         s->data_ctrl = value;
122         break;
123     case 0xC00:
124         s->filter_start = value;
125         break;
126     case 0xC04:
127         s->filter_end = value;
128         break;
129     case 0xF40:
130         return;
131     case 0xF60:
132         return;
133     case 0xF80:
134         return;
135     default:
136         qemu_log_mask(LOG_GUEST_ERROR,
137                       "l2x0_priv_write: Bad offset %x\n", (int)offset);
138         break;
139     }
140 }
141 
142 static void l2x0_priv_reset(DeviceState *dev)
143 {
144     L2x0State *s = ARM_L2X0(dev);
145 
146     s->ctrl = 0;
147     s->aux_ctrl = 0x02020000;
148     s->tag_ctrl = 0;
149     s->data_ctrl = 0;
150     s->filter_start = 0;
151     s->filter_end = 0;
152 }
153 
154 static const MemoryRegionOps l2x0_mem_ops = {
155     .read = l2x0_priv_read,
156     .write = l2x0_priv_write,
157     .endianness = DEVICE_NATIVE_ENDIAN,
158  };
159 
160 static int l2x0_priv_init(SysBusDevice *dev)
161 {
162     L2x0State *s = ARM_L2X0(dev);
163 
164     memory_region_init_io(&s->iomem, OBJECT(dev), &l2x0_mem_ops, s,
165                           "l2x0_cc", 0x1000);
166     sysbus_init_mmio(dev, &s->iomem);
167     return 0;
168 }
169 
170 static Property l2x0_properties[] = {
171     DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100),
172     DEFINE_PROP_END_OF_LIST(),
173 };
174 
175 static void l2x0_class_init(ObjectClass *klass, void *data)
176 {
177     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
178     DeviceClass *dc = DEVICE_CLASS(klass);
179 
180     k->init = l2x0_priv_init;
181     dc->vmsd = &vmstate_l2x0;
182     dc->props = l2x0_properties;
183     dc->reset = l2x0_priv_reset;
184 }
185 
186 static const TypeInfo l2x0_info = {
187     .name = TYPE_ARM_L2X0,
188     .parent = TYPE_SYS_BUS_DEVICE,
189     .instance_size = sizeof(L2x0State),
190     .class_init = l2x0_class_init,
191 };
192 
193 static void l2x0_register_types(void)
194 {
195     type_register_static(&l2x0_info);
196 }
197 
198 type_init(l2x0_register_types)
199