1b2123a48SRob Herring /*
2b2123a48SRob Herring * ARM dummy L210, L220, PL310 cache controller.
3b2123a48SRob Herring *
4b2123a48SRob Herring * Copyright (c) 2010-2012 Calxeda
5b2123a48SRob Herring *
6b2123a48SRob Herring * This program is free software; you can redistribute it and/or modify it
7b2123a48SRob Herring * under the terms and conditions of the GNU General Public License,
8b2123a48SRob Herring * version 2 or any later version, as published by the Free Software
9b2123a48SRob Herring * Foundation.
10b2123a48SRob Herring *
11b2123a48SRob Herring * This program is distributed in the hope it will be useful, but WITHOUT
12b2123a48SRob Herring * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13b2123a48SRob Herring * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14b2123a48SRob Herring * more details.
15b2123a48SRob Herring *
16b2123a48SRob Herring * You should have received a copy of the GNU General Public License along with
17b2123a48SRob Herring * this program. If not, see <http://www.gnu.org/licenses/>.
18b2123a48SRob Herring *
19b2123a48SRob Herring */
20b2123a48SRob Herring
210d1c9782SPeter Maydell #include "qemu/osdep.h"
22a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
2383c9f4caSPaolo Bonzini #include "hw/sysbus.h"
24d6454270SMarkus Armbruster #include "migration/vmstate.h"
2503dd024fSPaolo Bonzini #include "qemu/log.h"
260b8fa32fSMarkus Armbruster #include "qemu/module.h"
27db1015e9SEduardo Habkost #include "qom/object.h"
28b2123a48SRob Herring
29b2123a48SRob Herring /* L2C-310 r3p2 */
30b2123a48SRob Herring #define CACHE_ID 0x410000c8
31b2123a48SRob Herring
320e8982e9SAndreas Färber #define TYPE_ARM_L2X0 "l2x0"
338063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(L2x0State, ARM_L2X0)
340e8982e9SAndreas Färber
35db1015e9SEduardo Habkost struct L2x0State {
360e8982e9SAndreas Färber SysBusDevice parent_obj;
370e8982e9SAndreas Färber
38b2123a48SRob Herring MemoryRegion iomem;
39b2123a48SRob Herring uint32_t cache_type;
40b2123a48SRob Herring uint32_t ctrl;
41b2123a48SRob Herring uint32_t aux_ctrl;
42b2123a48SRob Herring uint32_t data_ctrl;
43b2123a48SRob Herring uint32_t tag_ctrl;
44b2123a48SRob Herring uint32_t filter_start;
45b2123a48SRob Herring uint32_t filter_end;
46db1015e9SEduardo Habkost };
47b2123a48SRob Herring
48b2123a48SRob Herring static const VMStateDescription vmstate_l2x0 = {
49b2123a48SRob Herring .name = "l2x0",
50b2123a48SRob Herring .version_id = 1,
51b2123a48SRob Herring .minimum_version_id = 1,
52e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
53ae1953d0SAndreas Färber VMSTATE_UINT32(ctrl, L2x0State),
54ae1953d0SAndreas Färber VMSTATE_UINT32(aux_ctrl, L2x0State),
55ae1953d0SAndreas Färber VMSTATE_UINT32(data_ctrl, L2x0State),
56ae1953d0SAndreas Färber VMSTATE_UINT32(tag_ctrl, L2x0State),
57ae1953d0SAndreas Färber VMSTATE_UINT32(filter_start, L2x0State),
58ae1953d0SAndreas Färber VMSTATE_UINT32(filter_end, L2x0State),
59b2123a48SRob Herring VMSTATE_END_OF_LIST()
60b2123a48SRob Herring }
61b2123a48SRob Herring };
62b2123a48SRob Herring
63b2123a48SRob Herring
l2x0_priv_read(void * opaque,hwaddr offset,unsigned size)64a8170e5eSAvi Kivity static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
65b2123a48SRob Herring unsigned size)
66b2123a48SRob Herring {
67b2123a48SRob Herring uint32_t cache_data;
68ae1953d0SAndreas Färber L2x0State *s = (L2x0State *)opaque;
69b2123a48SRob Herring offset &= 0xfff;
70b2123a48SRob Herring if (offset >= 0x730 && offset < 0x800) {
71b2123a48SRob Herring return 0; /* cache ops complete */
72b2123a48SRob Herring }
73b2123a48SRob Herring switch (offset) {
74b2123a48SRob Herring case 0:
75b2123a48SRob Herring return CACHE_ID;
76b2123a48SRob Herring case 0x4:
77b2123a48SRob Herring /* aux_ctrl values affect cache_type values */
78b2123a48SRob Herring cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
79b2123a48SRob Herring cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
80b2123a48SRob Herring return s->cache_type |= (cache_data << 18) | (cache_data << 6);
81b2123a48SRob Herring case 0x100:
82b2123a48SRob Herring return s->ctrl;
83b2123a48SRob Herring case 0x104:
84b2123a48SRob Herring return s->aux_ctrl;
85b2123a48SRob Herring case 0x108:
86b2123a48SRob Herring return s->tag_ctrl;
87b2123a48SRob Herring case 0x10C:
88b2123a48SRob Herring return s->data_ctrl;
89b2123a48SRob Herring case 0xC00:
90b2123a48SRob Herring return s->filter_start;
91b2123a48SRob Herring case 0xC04:
92b2123a48SRob Herring return s->filter_end;
93b2123a48SRob Herring case 0xF40:
94b2123a48SRob Herring return 0;
95b2123a48SRob Herring case 0xF60:
96b2123a48SRob Herring return 0;
97b2123a48SRob Herring case 0xF80:
98b2123a48SRob Herring return 0;
99b2123a48SRob Herring default:
100a35d4e42SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
101a35d4e42SPeter Maydell "l2x0_priv_read: Bad offset %x\n", (int)offset);
102b2123a48SRob Herring break;
103b2123a48SRob Herring }
104b2123a48SRob Herring return 0;
105b2123a48SRob Herring }
106b2123a48SRob Herring
l2x0_priv_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)107a8170e5eSAvi Kivity static void l2x0_priv_write(void *opaque, hwaddr offset,
108b2123a48SRob Herring uint64_t value, unsigned size)
109b2123a48SRob Herring {
110ae1953d0SAndreas Färber L2x0State *s = (L2x0State *)opaque;
111b2123a48SRob Herring offset &= 0xfff;
112b2123a48SRob Herring if (offset >= 0x730 && offset < 0x800) {
113b2123a48SRob Herring /* ignore */
114b2123a48SRob Herring return;
115b2123a48SRob Herring }
116b2123a48SRob Herring switch (offset) {
117b2123a48SRob Herring case 0x100:
118b2123a48SRob Herring s->ctrl = value & 1;
119b2123a48SRob Herring break;
120b2123a48SRob Herring case 0x104:
121b2123a48SRob Herring s->aux_ctrl = value;
122b2123a48SRob Herring break;
123b2123a48SRob Herring case 0x108:
124b2123a48SRob Herring s->tag_ctrl = value;
125b2123a48SRob Herring break;
126b2123a48SRob Herring case 0x10C:
127b2123a48SRob Herring s->data_ctrl = value;
128b2123a48SRob Herring break;
129b2123a48SRob Herring case 0xC00:
130b2123a48SRob Herring s->filter_start = value;
131b2123a48SRob Herring break;
132b2123a48SRob Herring case 0xC04:
133b2123a48SRob Herring s->filter_end = value;
134b2123a48SRob Herring break;
135b2123a48SRob Herring case 0xF40:
136b2123a48SRob Herring return;
137b2123a48SRob Herring case 0xF60:
138b2123a48SRob Herring return;
139b2123a48SRob Herring case 0xF80:
140b2123a48SRob Herring return;
141b2123a48SRob Herring default:
142a35d4e42SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
143a35d4e42SPeter Maydell "l2x0_priv_write: Bad offset %x\n", (int)offset);
144b2123a48SRob Herring break;
145b2123a48SRob Herring }
146b2123a48SRob Herring }
147b2123a48SRob Herring
l2x0_priv_reset(DeviceState * dev)148b2123a48SRob Herring static void l2x0_priv_reset(DeviceState *dev)
149b2123a48SRob Herring {
1500e8982e9SAndreas Färber L2x0State *s = ARM_L2X0(dev);
151b2123a48SRob Herring
152b2123a48SRob Herring s->ctrl = 0;
153b2123a48SRob Herring s->aux_ctrl = 0x02020000;
154b2123a48SRob Herring s->tag_ctrl = 0;
155b2123a48SRob Herring s->data_ctrl = 0;
156b2123a48SRob Herring s->filter_start = 0;
157b2123a48SRob Herring s->filter_end = 0;
158b2123a48SRob Herring }
159b2123a48SRob Herring
160b2123a48SRob Herring static const MemoryRegionOps l2x0_mem_ops = {
161b2123a48SRob Herring .read = l2x0_priv_read,
162b2123a48SRob Herring .write = l2x0_priv_write,
163b2123a48SRob Herring .endianness = DEVICE_NATIVE_ENDIAN,
164b2123a48SRob Herring };
165b2123a48SRob Herring
l2x0_priv_init(Object * obj)166da8060bfSxiaoqiang zhao static void l2x0_priv_init(Object *obj)
167b2123a48SRob Herring {
168da8060bfSxiaoqiang zhao L2x0State *s = ARM_L2X0(obj);
169da8060bfSxiaoqiang zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj);
170b2123a48SRob Herring
171da8060bfSxiaoqiang zhao memory_region_init_io(&s->iomem, obj, &l2x0_mem_ops, s,
1723c161542SPaolo Bonzini "l2x0_cc", 0x1000);
173b2123a48SRob Herring sysbus_init_mmio(dev, &s->iomem);
174b2123a48SRob Herring }
175b2123a48SRob Herring
17630029973SRichard Henderson static const Property l2x0_properties[] = {
177ae1953d0SAndreas Färber DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100),
17839bffca2SAnthony Liguori };
17939bffca2SAnthony Liguori
l2x0_class_init(ObjectClass * klass,const void * data)180*12d1a768SPhilippe Mathieu-Daudé static void l2x0_class_init(ObjectClass *klass, const void *data)
181999e12bbSAnthony Liguori {
18239bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass);
183999e12bbSAnthony Liguori
18439bffca2SAnthony Liguori dc->vmsd = &vmstate_l2x0;
1854f67d30bSMarc-André Lureau device_class_set_props(dc, l2x0_properties);
186e3d08143SPeter Maydell device_class_set_legacy_reset(dc, l2x0_priv_reset);
187999e12bbSAnthony Liguori }
188999e12bbSAnthony Liguori
1898c43a6f0SAndreas Färber static const TypeInfo l2x0_info = {
1900e8982e9SAndreas Färber .name = TYPE_ARM_L2X0,
19139bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE,
192ae1953d0SAndreas Färber .instance_size = sizeof(L2x0State),
193da8060bfSxiaoqiang zhao .instance_init = l2x0_priv_init,
194999e12bbSAnthony Liguori .class_init = l2x0_class_init,
195b2123a48SRob Herring };
196b2123a48SRob Herring
l2x0_register_types(void)19783f7d43aSAndreas Färber static void l2x0_register_types(void)
198b2123a48SRob Herring {
19939bffca2SAnthony Liguori type_register_static(&l2x0_info);
200b2123a48SRob Herring }
201b2123a48SRob Herring
20283f7d43aSAndreas Färber type_init(l2x0_register_types)
203