xref: /qemu/hw/misc/arm_l2x0.c (revision b65cb867)
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 "qemu/osdep.h"
22 #include "hw/qdev-properties.h"
23 #include "hw/sysbus.h"
24 #include "migration/vmstate.h"
25 #include "qemu/log.h"
26 #include "qemu/module.h"
27 
28 /* L2C-310 r3p2 */
29 #define CACHE_ID 0x410000c8
30 
31 #define TYPE_ARM_L2X0 "l2x0"
32 #define ARM_L2X0(obj) OBJECT_CHECK(L2x0State, (obj), TYPE_ARM_L2X0)
33 
34 typedef struct L2x0State {
35     SysBusDevice parent_obj;
36 
37     MemoryRegion iomem;
38     uint32_t cache_type;
39     uint32_t ctrl;
40     uint32_t aux_ctrl;
41     uint32_t data_ctrl;
42     uint32_t tag_ctrl;
43     uint32_t filter_start;
44     uint32_t filter_end;
45 } L2x0State;
46 
47 static const VMStateDescription vmstate_l2x0 = {
48     .name = "l2x0",
49     .version_id = 1,
50     .minimum_version_id = 1,
51     .fields = (VMStateField[]) {
52         VMSTATE_UINT32(ctrl, L2x0State),
53         VMSTATE_UINT32(aux_ctrl, L2x0State),
54         VMSTATE_UINT32(data_ctrl, L2x0State),
55         VMSTATE_UINT32(tag_ctrl, L2x0State),
56         VMSTATE_UINT32(filter_start, L2x0State),
57         VMSTATE_UINT32(filter_end, L2x0State),
58         VMSTATE_END_OF_LIST()
59     }
60 };
61 
62 
63 static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
64                                unsigned size)
65 {
66     uint32_t cache_data;
67     L2x0State *s = (L2x0State *)opaque;
68     offset &= 0xfff;
69     if (offset >= 0x730 && offset < 0x800) {
70         return 0; /* cache ops complete */
71     }
72     switch (offset) {
73     case 0:
74         return CACHE_ID;
75     case 0x4:
76         /* aux_ctrl values affect cache_type values */
77         cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
78         cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
79         return s->cache_type |= (cache_data << 18) | (cache_data << 6);
80     case 0x100:
81         return s->ctrl;
82     case 0x104:
83         return s->aux_ctrl;
84     case 0x108:
85         return s->tag_ctrl;
86     case 0x10C:
87         return s->data_ctrl;
88     case 0xC00:
89         return s->filter_start;
90     case 0xC04:
91         return s->filter_end;
92     case 0xF40:
93         return 0;
94     case 0xF60:
95         return 0;
96     case 0xF80:
97         return 0;
98     default:
99         qemu_log_mask(LOG_GUEST_ERROR,
100                       "l2x0_priv_read: Bad offset %x\n", (int)offset);
101         break;
102     }
103     return 0;
104 }
105 
106 static void l2x0_priv_write(void *opaque, hwaddr offset,
107                             uint64_t value, unsigned size)
108 {
109     L2x0State *s = (L2x0State *)opaque;
110     offset &= 0xfff;
111     if (offset >= 0x730 && offset < 0x800) {
112         /* ignore */
113         return;
114     }
115     switch (offset) {
116     case 0x100:
117         s->ctrl = value & 1;
118         break;
119     case 0x104:
120         s->aux_ctrl = value;
121         break;
122     case 0x108:
123         s->tag_ctrl = value;
124         break;
125     case 0x10C:
126         s->data_ctrl = value;
127         break;
128     case 0xC00:
129         s->filter_start = value;
130         break;
131     case 0xC04:
132         s->filter_end = value;
133         break;
134     case 0xF40:
135         return;
136     case 0xF60:
137         return;
138     case 0xF80:
139         return;
140     default:
141         qemu_log_mask(LOG_GUEST_ERROR,
142                       "l2x0_priv_write: Bad offset %x\n", (int)offset);
143         break;
144     }
145 }
146 
147 static void l2x0_priv_reset(DeviceState *dev)
148 {
149     L2x0State *s = ARM_L2X0(dev);
150 
151     s->ctrl = 0;
152     s->aux_ctrl = 0x02020000;
153     s->tag_ctrl = 0;
154     s->data_ctrl = 0;
155     s->filter_start = 0;
156     s->filter_end = 0;
157 }
158 
159 static const MemoryRegionOps l2x0_mem_ops = {
160     .read = l2x0_priv_read,
161     .write = l2x0_priv_write,
162     .endianness = DEVICE_NATIVE_ENDIAN,
163  };
164 
165 static void l2x0_priv_init(Object *obj)
166 {
167     L2x0State *s = ARM_L2X0(obj);
168     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
169 
170     memory_region_init_io(&s->iomem, obj, &l2x0_mem_ops, s,
171                           "l2x0_cc", 0x1000);
172     sysbus_init_mmio(dev, &s->iomem);
173 }
174 
175 static Property l2x0_properties[] = {
176     DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100),
177     DEFINE_PROP_END_OF_LIST(),
178 };
179 
180 static void l2x0_class_init(ObjectClass *klass, void *data)
181 {
182     DeviceClass *dc = DEVICE_CLASS(klass);
183 
184     dc->vmsd = &vmstate_l2x0;
185     dc->props = l2x0_properties;
186     dc->reset = l2x0_priv_reset;
187 }
188 
189 static const TypeInfo l2x0_info = {
190     .name = TYPE_ARM_L2X0,
191     .parent = TYPE_SYS_BUS_DEVICE,
192     .instance_size = sizeof(L2x0State),
193     .instance_init = l2x0_priv_init,
194     .class_init = l2x0_class_init,
195 };
196 
197 static void l2x0_register_types(void)
198 {
199     type_register_static(&l2x0_info);
200 }
201 
202 type_init(l2x0_register_types)
203