diff mbox

[v2,7/9] add L2x0/PL310 cache controller device

Message ID 1324578014-24746-8-git-send-email-mark.langsdorf@calxeda.com
State New
Headers show

Commit Message

Mark Langsdorf Dec. 22, 2011, 6:20 p.m. UTC
From: Rob Herring <rob.herring@calxeda.com>

This is just a dummy device for ARM L2 cache controllers, based on the
pl310. The cache type parameter can be defined by a property value
and has a meaningful default.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v1
	Corrected formatting
	Clarified the copyrights
	Clarified GPL revision
	Clarified model version
	Removed hw_error() calls
	Added a reset function
	Restructed everything as switch/case statements
	Added a type cache property

 Makefile.target |    1 +
 hw/arm_l2x0.c   |  173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 174 insertions(+), 0 deletions(-)
 create mode 100644 hw/arm_l2x0.c

Comments

Peter Maydell Dec. 24, 2011, 12:53 a.m. UTC | #1
On 22 December 2011 18:20, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> From: Rob Herring <rob.herring@calxeda.com>
>
> This is just a dummy device for ARM L2 cache controllers, based on the
> pl310. The cache type parameter can be defined by a property value
> and has a meaningful default.
>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>

scripts/checkpatch.pl complains about a couple of overlong lines;
please fix.

> ---
> Changes from v1
>        Corrected formatting
>        Clarified the copyrights
>        Clarified GPL revision
>        Clarified model version
>        Removed hw_error() calls
>        Added a reset function
>        Restructed everything as switch/case statements
>        Added a type cache property
>
>  Makefile.target |    1 +
>  hw/arm_l2x0.c   |  173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 174 insertions(+), 0 deletions(-)
>  create mode 100644 hw/arm_l2x0.c
>
> diff --git a/Makefile.target b/Makefile.target
> index 3261383..db5e44c 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -336,6 +336,7 @@ obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
>  obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
>  obj-arm-y += versatile_pci.o
>  obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
> +obj-arm-y += arm_l2x0.o
>  obj-arm-y += arm_mptimer.o
>  obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
>  obj-arm-y += pl061.o
> diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
> new file mode 100644
> index 0000000..84f6c5a
> --- /dev/null
> +++ b/hw/arm_l2x0.c
> @@ -0,0 +1,173 @@
> +/*
> + * 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, as published by the Free Software Foundation.

"Or any later version". We're trying to avoid new v2-only code, please.

> + *
> + * 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/>.
> + *
> + */
> +
> +#include "sysbus.h"
> +
> +/* L2C-310 r3p1 */
> +#define CACHE_ID 0x410000c6

Why not r3p2 ?

> +#define DEFAULT_CACHE_TYPE 0x19080800
> +
> +typedef struct l2x0_state {
> +    SysBusDevice busdev;
> +    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;
> +} l2x0_state;
> +
> +static const VMStateDescription vmstate_l2x0 = {
> +    .name = "l2x0",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(ctrl, l2x0_state),
> +        VMSTATE_UINT32(aux_ctrl, l2x0_state),
> +        VMSTATE_UINT32(data_ctrl, l2x0_state),
> +        VMSTATE_UINT32(tag_ctrl, l2x0_state),
> +        VMSTATE_UINT32(filter_start, l2x0_state),
> +        VMSTATE_UINT32(filter_end, l2x0_state),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +
> +static uint64_t l2x0_priv_read(void *opaque, target_phys_addr_t offset, unsigned size)
> +{
> +    l2x0_state *s = (l2x0_state *)opaque;
> +    offset &= 0xfff;
> +    if (offset >= 0x730 && offset < 0x800) {
> +        return 0; /* cache ops complete */
> +    }
> +    switch (offset) {
> +    case 0:
> +        return CACHE_ID;
> +    case 0x4:
> +        return s->cache_type;
> +    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:
> +        fprintf(stderr, "l2x0_priv_read: Bad offset %x\n", (int)offset);
> +        break;
> +    }
> +    return 0;
> +}
> +
> +static void l2x0_priv_write(void *opaque, target_phys_addr_t offset, uint64_t value, unsigned size)
> +{
> +    l2x0_state *s = (l2x0_state *)opaque;
> +    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:
> +        fprintf(stderr, "l2x0_priv_write: Bad offset %x\n", (int)offset);
> +        break;
> +    }
> +}
> +
> +static int l2x0_priv_reset(SysBusDevice *dev)
> +{
> +    l2x0_state *s = FROM_SYSBUS(l2x0_state, dev);
> +
> +    s->aux_ctrl = 0x00020000;

TRM says the aux ctrl reset value is 0x02020000.
This should be a qdev reset function for the device
(registered via .qdev.reset in the SysBusDeviceInfo).
You'll need to reset the other registers too.

> +    return 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)
> +{
> +    l2x0_state *s = FROM_SYSBUS(l2x0_state, dev);
> +
> +    l2x0_priv_reset(dev);

If you make this a qdev reset function you don't need to
explicitly call it from your init function.

> +
> +    memory_region_init_io(&s->iomem, &l2x0_mem_ops, s, "l2x0_cc", 0x1000);
> +    sysbus_init_mmio(dev, &s->iomem);
> +    return 0;
> +}
> +
> +static SysBusDeviceInfo l2x0_info = {
> +    .init = l2x0_priv_init,
> +    .qdev.name = "l2x0",
> +    .qdev.size = sizeof(l2x0_state),
> +    .qdev.vmsd = &vmstate_l2x0,
> +    .qdev.no_user = 1,
> +    .qdev.props = (Property[]) {
> +        DEFINE_PROP_UINT32("type", l2x0_state, cache_type, DEFAULT_CACHE_TYPE),
> +        DEFINE_PROP_END_OF_LIST(),
> +    }
> +};
> +
> +static void l2x0_register_device(void)
> +{
> +    sysbus_register_withprop(&l2x0_info);
> +}
> +
> +device_init(l2x0_register_device)
> +
> --
> 1.7.5.4
>

-- PMM
diff mbox

Patch

diff --git a/Makefile.target b/Makefile.target
index 3261383..db5e44c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -336,6 +336,7 @@  obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
 obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
+obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
 obj-arm-y += pl061.o
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
new file mode 100644
index 0000000..84f6c5a
--- /dev/null
+++ b/hw/arm_l2x0.c
@@ -0,0 +1,173 @@ 
+/*
+ * 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, 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/>.
+ *
+ */
+
+#include "sysbus.h"
+
+/* L2C-310 r3p1 */
+#define CACHE_ID 0x410000c6
+#define DEFAULT_CACHE_TYPE 0x19080800
+
+typedef struct l2x0_state {
+    SysBusDevice busdev;
+    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;
+} l2x0_state;
+
+static const VMStateDescription vmstate_l2x0 = {
+    .name = "l2x0",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ctrl, l2x0_state),
+        VMSTATE_UINT32(aux_ctrl, l2x0_state),
+        VMSTATE_UINT32(data_ctrl, l2x0_state),
+        VMSTATE_UINT32(tag_ctrl, l2x0_state),
+        VMSTATE_UINT32(filter_start, l2x0_state),
+        VMSTATE_UINT32(filter_end, l2x0_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static uint64_t l2x0_priv_read(void *opaque, target_phys_addr_t offset, unsigned size)
+{
+    l2x0_state *s = (l2x0_state *)opaque;
+    offset &= 0xfff;
+    if (offset >= 0x730 && offset < 0x800) {
+        return 0; /* cache ops complete */
+    }
+    switch (offset) {
+    case 0:
+        return CACHE_ID;
+    case 0x4:
+        return s->cache_type;
+    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:
+        fprintf(stderr, "l2x0_priv_read: Bad offset %x\n", (int)offset);
+        break;
+    }
+    return 0;
+}
+
+static void l2x0_priv_write(void *opaque, target_phys_addr_t offset, uint64_t value, unsigned size)
+{
+    l2x0_state *s = (l2x0_state *)opaque;
+    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:
+        fprintf(stderr, "l2x0_priv_write: Bad offset %x\n", (int)offset);
+        break;
+    }
+}
+
+static int l2x0_priv_reset(SysBusDevice *dev)
+{
+    l2x0_state *s = FROM_SYSBUS(l2x0_state, dev);
+
+    s->aux_ctrl = 0x00020000;
+    return 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)
+{
+    l2x0_state *s = FROM_SYSBUS(l2x0_state, dev);
+
+    l2x0_priv_reset(dev);
+
+    memory_region_init_io(&s->iomem, &l2x0_mem_ops, s, "l2x0_cc", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static SysBusDeviceInfo l2x0_info = {
+    .init = l2x0_priv_init,
+    .qdev.name = "l2x0",
+    .qdev.size = sizeof(l2x0_state),
+    .qdev.vmsd = &vmstate_l2x0,
+    .qdev.no_user = 1,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("type", l2x0_state, cache_type, DEFAULT_CACHE_TYPE),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void l2x0_register_device(void)
+{
+    sysbus_register_withprop(&l2x0_info);
+}
+
+device_init(l2x0_register_device)
+