xref: /openbmc/qemu/hw/misc/arm_l2x0.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * ARM dummy L210, L220, PL310 cache controller.
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2010-2012 Calxeda
549ab747fSPaolo Bonzini  *
649ab747fSPaolo Bonzini  * This program is free software; you can redistribute it and/or modify it
749ab747fSPaolo Bonzini  * under the terms and conditions of the GNU General Public License,
849ab747fSPaolo Bonzini  * version 2 or any later version, as published by the Free Software
949ab747fSPaolo Bonzini  * Foundation.
1049ab747fSPaolo Bonzini  *
1149ab747fSPaolo Bonzini  * This program is distributed in the hope it will be useful, but WITHOUT
1249ab747fSPaolo Bonzini  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1349ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1449ab747fSPaolo Bonzini  * more details.
1549ab747fSPaolo Bonzini  *
1649ab747fSPaolo Bonzini  * You should have received a copy of the GNU General Public License along with
1749ab747fSPaolo Bonzini  * this program.  If not, see <http://www.gnu.org/licenses/>.
1849ab747fSPaolo Bonzini  *
1949ab747fSPaolo Bonzini  */
2049ab747fSPaolo Bonzini 
210d1c9782SPeter Maydell #include "qemu/osdep.h"
22a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
2349ab747fSPaolo 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"
2849ab747fSPaolo Bonzini 
2949ab747fSPaolo Bonzini /* L2C-310 r3p2 */
3049ab747fSPaolo Bonzini #define CACHE_ID 0x410000c8
3149ab747fSPaolo Bonzini 
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 
3849ab747fSPaolo Bonzini     MemoryRegion iomem;
3949ab747fSPaolo Bonzini     uint32_t cache_type;
4049ab747fSPaolo Bonzini     uint32_t ctrl;
4149ab747fSPaolo Bonzini     uint32_t aux_ctrl;
4249ab747fSPaolo Bonzini     uint32_t data_ctrl;
4349ab747fSPaolo Bonzini     uint32_t tag_ctrl;
4449ab747fSPaolo Bonzini     uint32_t filter_start;
4549ab747fSPaolo Bonzini     uint32_t filter_end;
46db1015e9SEduardo Habkost };
4749ab747fSPaolo Bonzini 
4849ab747fSPaolo Bonzini static const VMStateDescription vmstate_l2x0 = {
4949ab747fSPaolo Bonzini     .name = "l2x0",
5049ab747fSPaolo Bonzini     .version_id = 1,
5149ab747fSPaolo Bonzini     .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),
5949ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
6049ab747fSPaolo Bonzini     }
6149ab747fSPaolo Bonzini };
6249ab747fSPaolo Bonzini 
6349ab747fSPaolo Bonzini 
l2x0_priv_read(void * opaque,hwaddr offset,unsigned size)6449ab747fSPaolo Bonzini static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
6549ab747fSPaolo Bonzini                                unsigned size)
6649ab747fSPaolo Bonzini {
6749ab747fSPaolo Bonzini     uint32_t cache_data;
68ae1953d0SAndreas Färber     L2x0State *s = (L2x0State *)opaque;
6949ab747fSPaolo Bonzini     offset &= 0xfff;
7049ab747fSPaolo Bonzini     if (offset >= 0x730 && offset < 0x800) {
7149ab747fSPaolo Bonzini         return 0; /* cache ops complete */
7249ab747fSPaolo Bonzini     }
7349ab747fSPaolo Bonzini     switch (offset) {
7449ab747fSPaolo Bonzini     case 0:
7549ab747fSPaolo Bonzini         return CACHE_ID;
7649ab747fSPaolo Bonzini     case 0x4:
7749ab747fSPaolo Bonzini         /* aux_ctrl values affect cache_type values */
7849ab747fSPaolo Bonzini         cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
7949ab747fSPaolo Bonzini         cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
8049ab747fSPaolo Bonzini         return s->cache_type |= (cache_data << 18) | (cache_data << 6);
8149ab747fSPaolo Bonzini     case 0x100:
8249ab747fSPaolo Bonzini         return s->ctrl;
8349ab747fSPaolo Bonzini     case 0x104:
8449ab747fSPaolo Bonzini         return s->aux_ctrl;
8549ab747fSPaolo Bonzini     case 0x108:
8649ab747fSPaolo Bonzini         return s->tag_ctrl;
8749ab747fSPaolo Bonzini     case 0x10C:
8849ab747fSPaolo Bonzini         return s->data_ctrl;
8949ab747fSPaolo Bonzini     case 0xC00:
9049ab747fSPaolo Bonzini         return s->filter_start;
9149ab747fSPaolo Bonzini     case 0xC04:
9249ab747fSPaolo Bonzini         return s->filter_end;
9349ab747fSPaolo Bonzini     case 0xF40:
9449ab747fSPaolo Bonzini         return 0;
9549ab747fSPaolo Bonzini     case 0xF60:
9649ab747fSPaolo Bonzini         return 0;
9749ab747fSPaolo Bonzini     case 0xF80:
9849ab747fSPaolo Bonzini         return 0;
9949ab747fSPaolo Bonzini     default:
10049ab747fSPaolo Bonzini         qemu_log_mask(LOG_GUEST_ERROR,
10149ab747fSPaolo Bonzini                       "l2x0_priv_read: Bad offset %x\n", (int)offset);
10249ab747fSPaolo Bonzini         break;
10349ab747fSPaolo Bonzini     }
10449ab747fSPaolo Bonzini     return 0;
10549ab747fSPaolo Bonzini }
10649ab747fSPaolo Bonzini 
l2x0_priv_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)10749ab747fSPaolo Bonzini static void l2x0_priv_write(void *opaque, hwaddr offset,
10849ab747fSPaolo Bonzini                             uint64_t value, unsigned size)
10949ab747fSPaolo Bonzini {
110ae1953d0SAndreas Färber     L2x0State *s = (L2x0State *)opaque;
11149ab747fSPaolo Bonzini     offset &= 0xfff;
11249ab747fSPaolo Bonzini     if (offset >= 0x730 && offset < 0x800) {
11349ab747fSPaolo Bonzini         /* ignore */
11449ab747fSPaolo Bonzini         return;
11549ab747fSPaolo Bonzini     }
11649ab747fSPaolo Bonzini     switch (offset) {
11749ab747fSPaolo Bonzini     case 0x100:
11849ab747fSPaolo Bonzini         s->ctrl = value & 1;
11949ab747fSPaolo Bonzini         break;
12049ab747fSPaolo Bonzini     case 0x104:
12149ab747fSPaolo Bonzini         s->aux_ctrl = value;
12249ab747fSPaolo Bonzini         break;
12349ab747fSPaolo Bonzini     case 0x108:
12449ab747fSPaolo Bonzini         s->tag_ctrl = value;
12549ab747fSPaolo Bonzini         break;
12649ab747fSPaolo Bonzini     case 0x10C:
12749ab747fSPaolo Bonzini         s->data_ctrl = value;
12849ab747fSPaolo Bonzini         break;
12949ab747fSPaolo Bonzini     case 0xC00:
13049ab747fSPaolo Bonzini         s->filter_start = value;
13149ab747fSPaolo Bonzini         break;
13249ab747fSPaolo Bonzini     case 0xC04:
13349ab747fSPaolo Bonzini         s->filter_end = value;
13449ab747fSPaolo Bonzini         break;
13549ab747fSPaolo Bonzini     case 0xF40:
13649ab747fSPaolo Bonzini         return;
13749ab747fSPaolo Bonzini     case 0xF60:
13849ab747fSPaolo Bonzini         return;
13949ab747fSPaolo Bonzini     case 0xF80:
14049ab747fSPaolo Bonzini         return;
14149ab747fSPaolo Bonzini     default:
14249ab747fSPaolo Bonzini         qemu_log_mask(LOG_GUEST_ERROR,
14349ab747fSPaolo Bonzini                       "l2x0_priv_write: Bad offset %x\n", (int)offset);
14449ab747fSPaolo Bonzini         break;
14549ab747fSPaolo Bonzini     }
14649ab747fSPaolo Bonzini }
14749ab747fSPaolo Bonzini 
l2x0_priv_reset(DeviceState * dev)14849ab747fSPaolo Bonzini static void l2x0_priv_reset(DeviceState *dev)
14949ab747fSPaolo Bonzini {
1500e8982e9SAndreas Färber     L2x0State *s = ARM_L2X0(dev);
15149ab747fSPaolo Bonzini 
15249ab747fSPaolo Bonzini     s->ctrl = 0;
15349ab747fSPaolo Bonzini     s->aux_ctrl = 0x02020000;
15449ab747fSPaolo Bonzini     s->tag_ctrl = 0;
15549ab747fSPaolo Bonzini     s->data_ctrl = 0;
15649ab747fSPaolo Bonzini     s->filter_start = 0;
15749ab747fSPaolo Bonzini     s->filter_end = 0;
15849ab747fSPaolo Bonzini }
15949ab747fSPaolo Bonzini 
16049ab747fSPaolo Bonzini static const MemoryRegionOps l2x0_mem_ops = {
16149ab747fSPaolo Bonzini     .read = l2x0_priv_read,
16249ab747fSPaolo Bonzini     .write = l2x0_priv_write,
16349ab747fSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
16449ab747fSPaolo Bonzini  };
16549ab747fSPaolo Bonzini 
l2x0_priv_init(Object * obj)166da8060bfSxiaoqiang zhao static void l2x0_priv_init(Object *obj)
16749ab747fSPaolo Bonzini {
168da8060bfSxiaoqiang zhao     L2x0State *s = ARM_L2X0(obj);
169da8060bfSxiaoqiang zhao     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
17049ab747fSPaolo Bonzini 
171da8060bfSxiaoqiang zhao     memory_region_init_io(&s->iomem, obj, &l2x0_mem_ops, s,
1723c161542SPaolo Bonzini                           "l2x0_cc", 0x1000);
17349ab747fSPaolo Bonzini     sysbus_init_mmio(dev, &s->iomem);
17449ab747fSPaolo Bonzini }
17549ab747fSPaolo Bonzini 
17649ab747fSPaolo Bonzini static Property l2x0_properties[] = {
177ae1953d0SAndreas Färber     DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100),
17849ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
17949ab747fSPaolo Bonzini };
18049ab747fSPaolo Bonzini 
l2x0_class_init(ObjectClass * klass,void * data)18149ab747fSPaolo Bonzini static void l2x0_class_init(ObjectClass *klass, void *data)
18249ab747fSPaolo Bonzini {
18349ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
18449ab747fSPaolo Bonzini 
18549ab747fSPaolo Bonzini     dc->vmsd = &vmstate_l2x0;
1864f67d30bSMarc-André Lureau     device_class_set_props(dc, l2x0_properties);
187*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, l2x0_priv_reset);
18849ab747fSPaolo Bonzini }
18949ab747fSPaolo Bonzini 
19049ab747fSPaolo Bonzini static const TypeInfo l2x0_info = {
1910e8982e9SAndreas Färber     .name = TYPE_ARM_L2X0,
19249ab747fSPaolo Bonzini     .parent = TYPE_SYS_BUS_DEVICE,
193ae1953d0SAndreas Färber     .instance_size = sizeof(L2x0State),
194da8060bfSxiaoqiang zhao     .instance_init = l2x0_priv_init,
19549ab747fSPaolo Bonzini     .class_init = l2x0_class_init,
19649ab747fSPaolo Bonzini };
19749ab747fSPaolo Bonzini 
l2x0_register_types(void)19849ab747fSPaolo Bonzini static void l2x0_register_types(void)
19949ab747fSPaolo Bonzini {
20049ab747fSPaolo Bonzini     type_register_static(&l2x0_info);
20149ab747fSPaolo Bonzini }
20249ab747fSPaolo Bonzini 
20349ab747fSPaolo Bonzini type_init(l2x0_register_types)
204