2011-12-29 07:19:54 +01:00
|
|
|
/*
|
|
|
|
* ARM dummy L210, L220, PL310 cache controller.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2010-2012 Calxeda
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
|
|
* version 2 or any later version, as published by the Free Software
|
|
|
|
* Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2013-02-04 15:40:22 +01:00
|
|
|
#include "hw/sysbus.h"
|
2011-12-29 07:19:54 +01:00
|
|
|
|
|
|
|
/* L2C-310 r3p2 */
|
|
|
|
#define CACHE_ID 0x410000c8
|
|
|
|
|
2013-07-26 21:20:52 +02:00
|
|
|
#define TYPE_ARM_L2X0 "l2x0"
|
|
|
|
#define ARM_L2X0(obj) OBJECT_CHECK(L2x0State, (obj), TYPE_ARM_L2X0)
|
|
|
|
|
2013-07-26 21:18:35 +02:00
|
|
|
typedef struct L2x0State {
|
2013-07-26 21:20:52 +02:00
|
|
|
SysBusDevice parent_obj;
|
|
|
|
|
2011-12-29 07:19:54 +01:00
|
|
|
MemoryRegion iomem;
|
|
|
|
uint32_t cache_type;
|
|
|
|
uint32_t ctrl;
|
|
|
|
uint32_t aux_ctrl;
|
|
|
|
uint32_t data_ctrl;
|
|
|
|
uint32_t tag_ctrl;
|
|
|
|
uint32_t filter_start;
|
|
|
|
uint32_t filter_end;
|
2013-07-26 21:18:35 +02:00
|
|
|
} L2x0State;
|
2011-12-29 07:19:54 +01:00
|
|
|
|
|
|
|
static const VMStateDescription vmstate_l2x0 = {
|
|
|
|
.name = "l2x0",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.fields = (VMStateField[]) {
|
2013-07-26 21:18:35 +02:00
|
|
|
VMSTATE_UINT32(ctrl, L2x0State),
|
|
|
|
VMSTATE_UINT32(aux_ctrl, L2x0State),
|
|
|
|
VMSTATE_UINT32(data_ctrl, L2x0State),
|
|
|
|
VMSTATE_UINT32(tag_ctrl, L2x0State),
|
|
|
|
VMSTATE_UINT32(filter_start, L2x0State),
|
|
|
|
VMSTATE_UINT32(filter_end, L2x0State),
|
2011-12-29 07:19:54 +01:00
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-10-23 12:30:10 +02:00
|
|
|
static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
|
2011-12-29 07:19:54 +01:00
|
|
|
unsigned size)
|
|
|
|
{
|
|
|
|
uint32_t cache_data;
|
2013-07-26 21:18:35 +02:00
|
|
|
L2x0State *s = (L2x0State *)opaque;
|
2011-12-29 07:19:54 +01:00
|
|
|
offset &= 0xfff;
|
|
|
|
if (offset >= 0x730 && offset < 0x800) {
|
|
|
|
return 0; /* cache ops complete */
|
|
|
|
}
|
|
|
|
switch (offset) {
|
|
|
|
case 0:
|
|
|
|
return CACHE_ID;
|
|
|
|
case 0x4:
|
|
|
|
/* aux_ctrl values affect cache_type values */
|
|
|
|
cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
|
|
|
|
cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
|
|
|
|
return s->cache_type |= (cache_data << 18) | (cache_data << 6);
|
|
|
|
case 0x100:
|
|
|
|
return s->ctrl;
|
|
|
|
case 0x104:
|
|
|
|
return s->aux_ctrl;
|
|
|
|
case 0x108:
|
|
|
|
return s->tag_ctrl;
|
|
|
|
case 0x10C:
|
|
|
|
return s->data_ctrl;
|
|
|
|
case 0xC00:
|
|
|
|
return s->filter_start;
|
|
|
|
case 0xC04:
|
|
|
|
return s->filter_end;
|
|
|
|
case 0xF40:
|
|
|
|
return 0;
|
|
|
|
case 0xF60:
|
|
|
|
return 0;
|
|
|
|
case 0xF80:
|
|
|
|
return 0;
|
|
|
|
default:
|
2012-10-30 08:45:10 +01:00
|
|
|
qemu_log_mask(LOG_GUEST_ERROR,
|
|
|
|
"l2x0_priv_read: Bad offset %x\n", (int)offset);
|
2011-12-29 07:19:54 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-23 12:30:10 +02:00
|
|
|
static void l2x0_priv_write(void *opaque, hwaddr offset,
|
2011-12-29 07:19:54 +01:00
|
|
|
uint64_t value, unsigned size)
|
|
|
|
{
|
2013-07-26 21:18:35 +02:00
|
|
|
L2x0State *s = (L2x0State *)opaque;
|
2011-12-29 07:19:54 +01:00
|
|
|
offset &= 0xfff;
|
|
|
|
if (offset >= 0x730 && offset < 0x800) {
|
|
|
|
/* ignore */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (offset) {
|
|
|
|
case 0x100:
|
|
|
|
s->ctrl = value & 1;
|
|
|
|
break;
|
|
|
|
case 0x104:
|
|
|
|
s->aux_ctrl = value;
|
|
|
|
break;
|
|
|
|
case 0x108:
|
|
|
|
s->tag_ctrl = value;
|
|
|
|
break;
|
|
|
|
case 0x10C:
|
|
|
|
s->data_ctrl = value;
|
|
|
|
break;
|
|
|
|
case 0xC00:
|
|
|
|
s->filter_start = value;
|
|
|
|
break;
|
|
|
|
case 0xC04:
|
|
|
|
s->filter_end = value;
|
|
|
|
break;
|
|
|
|
case 0xF40:
|
|
|
|
return;
|
|
|
|
case 0xF60:
|
|
|
|
return;
|
|
|
|
case 0xF80:
|
|
|
|
return;
|
|
|
|
default:
|
2012-10-30 08:45:10 +01:00
|
|
|
qemu_log_mask(LOG_GUEST_ERROR,
|
|
|
|
"l2x0_priv_write: Bad offset %x\n", (int)offset);
|
2011-12-29 07:19:54 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void l2x0_priv_reset(DeviceState *dev)
|
|
|
|
{
|
2013-07-26 21:20:52 +02:00
|
|
|
L2x0State *s = ARM_L2X0(dev);
|
2011-12-29 07:19:54 +01:00
|
|
|
|
|
|
|
s->ctrl = 0;
|
|
|
|
s->aux_ctrl = 0x02020000;
|
|
|
|
s->tag_ctrl = 0;
|
|
|
|
s->data_ctrl = 0;
|
|
|
|
s->filter_start = 0;
|
|
|
|
s->filter_end = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MemoryRegionOps l2x0_mem_ops = {
|
|
|
|
.read = l2x0_priv_read,
|
|
|
|
.write = l2x0_priv_write,
|
|
|
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int l2x0_priv_init(SysBusDevice *dev)
|
|
|
|
{
|
2013-07-26 21:20:52 +02:00
|
|
|
L2x0State *s = ARM_L2X0(dev);
|
2011-12-29 07:19:54 +01:00
|
|
|
|
2013-06-07 03:25:08 +02:00
|
|
|
memory_region_init_io(&s->iomem, OBJECT(dev), &l2x0_mem_ops, s,
|
|
|
|
"l2x0_cc", 0x1000);
|
2011-12-29 07:19:54 +01:00
|
|
|
sysbus_init_mmio(dev, &s->iomem);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-08 04:34:16 +01:00
|
|
|
static Property l2x0_properties[] = {
|
2013-07-26 21:18:35 +02:00
|
|
|
DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100),
|
2011-12-08 04:34:16 +01:00
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
2012-01-24 20:12:29 +01:00
|
|
|
static void l2x0_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
2011-12-08 04:34:16 +01:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
2012-01-24 20:12:29 +01:00
|
|
|
|
|
|
|
k->init = l2x0_priv_init;
|
2011-12-08 04:34:16 +01:00
|
|
|
dc->vmsd = &vmstate_l2x0;
|
qdev: Replace no_user by cannot_instantiate_with_device_add_yet
In an ideal world, machines can be built by wiring devices together
with configuration, not code. Unfortunately, that's not the world we
live in right now. We still have quite a few devices that need to be
wired up by code. If you try to device_add such a device, it'll fail
in sometimes mysterious ways. If you're lucky, you get an
unmysterious immediate crash.
To protect users from such badness, DeviceClass member no_user used to
make device models unavailable with -device / device_add, but that
regressed in commit 18b6dad. The device model is still omitted from
help, but is available anyway.
Attempts to fix the regression have been rejected with the argument
that the purpose of no_user isn't clear, and it's prone to misuse.
This commit clarifies no_user's purpose. Anthony suggested to rename
it cannot_instantiate_with_device_add_yet_due_to_internal_bugs, which
I shorten somewhat to keep checkpatch happy. While there, make it
bool.
Every use of cannot_instantiate_with_device_add_yet gets a FIXME
comment asking for rationale. The next few commits will clean them
all up, either by providing a rationale, or by getting rid of the use.
With that done, the regression fix is hopefully acceptable.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Marcel Apfelbaum <marcel.a@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2013-11-28 17:26:54 +01:00
|
|
|
dc->cannot_instantiate_with_device_add_yet = true; /* FIXME explain why */
|
2011-12-08 04:34:16 +01:00
|
|
|
dc->props = l2x0_properties;
|
|
|
|
dc->reset = l2x0_priv_reset;
|
2012-01-24 20:12:29 +01:00
|
|
|
}
|
|
|
|
|
2013-01-10 16:19:07 +01:00
|
|
|
static const TypeInfo l2x0_info = {
|
2013-07-26 21:20:52 +02:00
|
|
|
.name = TYPE_ARM_L2X0,
|
2011-12-08 04:34:16 +01:00
|
|
|
.parent = TYPE_SYS_BUS_DEVICE,
|
2013-07-26 21:18:35 +02:00
|
|
|
.instance_size = sizeof(L2x0State),
|
2012-01-24 20:12:29 +01:00
|
|
|
.class_init = l2x0_class_init,
|
2011-12-29 07:19:54 +01:00
|
|
|
};
|
|
|
|
|
2012-02-09 15:20:55 +01:00
|
|
|
static void l2x0_register_types(void)
|
2011-12-29 07:19:54 +01:00
|
|
|
{
|
2011-12-08 04:34:16 +01:00
|
|
|
type_register_static(&l2x0_info);
|
2011-12-29 07:19:54 +01:00
|
|
|
}
|
|
|
|
|
2012-02-09 15:20:55 +01:00
|
|
|
type_init(l2x0_register_types)
|