Commit c47f3223 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'pmaydell/arm-devs.for-upstream' into staging

* pmaydell/arm-devs.for-upstream:
  add L2x0/PL310 cache controller device
  arm: add dummy gic security registers
  arm: Set frequencies for arm_timer
  arm: add missing scu registers
  hw/omap_gpmc: Fix region map/unmap when configuring prefetch engine
  hw/omap1.c: Drop unused includes
  hw/omap1.c: Separate dpll_ctl from omap_mpu_state
  hw/omap1.c: Separate PWT from omap_mpu_state
  hw/omap1.c: Separate PWL from omap_mpu_state
  hw/omap1.c: omap_mpuio_init() need not be public
  hw/pl110.c: Add post-load hook to invalidate display
  hw/pl181.c: Add save/load support
parents 11c7ef0c b2123a48
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+33 −3
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ gic_get_current_cpu(void)
typedef struct a9mp_priv_state {
    gic_state gic;
    uint32_t scu_control;
    uint32_t scu_status;
    uint32_t old_timer_status[8];
    uint32_t num_cpu;
    qemu_irq *timer_irq;
@@ -48,7 +49,13 @@ static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
    case 0x04: /* Configuration */
        return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
    case 0x08: /* CPU Power Status */
        return 0;
        return s->scu_status;
    case 0x09: /* CPU status.  */
        return s->scu_status >> 8;
    case 0x0a: /* CPU status.  */
        return s->scu_status >> 16;
    case 0x0b: /* CPU status.  */
        return s->scu_status >> 24;
    case 0x0c: /* Invalidate All Registers In Secure State */
        return 0;
    case 0x40: /* Filtering Start Address Register */
@@ -67,12 +74,35 @@ static void a9_scu_write(void *opaque, target_phys_addr_t offset,
                         uint64_t value, unsigned size)
{
    a9mp_priv_state *s = (a9mp_priv_state *)opaque;
    uint32_t mask;
    uint32_t shift;
    switch (size) {
    case 1:
        mask = 0xff;
        break;
    case 2:
        mask = 0xffff;
        break;
    case 4:
        mask = 0xffffffff;
        break;
    default:
        fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
                size, offset);
        return;
    }

    switch (offset) {
    case 0x00: /* Control */
        s->scu_control = value & 1;
        break;
    case 0x4: /* Configuration: RO */
        break;
    case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
        shift = (offset - 0x8) * 8;
        s->scu_status &= ~(mask << shift);
        s->scu_status |= ((value & mask) << shift);
        break;
    case 0x0c: /* Invalidate All Registers In Secure State */
        /* no-op as we do not implement caches */
        break;
@@ -80,7 +110,6 @@ static void a9_scu_write(void *opaque, target_phys_addr_t offset,
    case 0x44: /* Filtering End Address Register */
        /* RAZ/WI, like an implementation with only one AXI master */
        break;
    case 0x8: /* CPU Power Status */
    case 0x50: /* SCU Access Control Register */
    case 0x54: /* SCU Non-secure Access Control Register */
        /* unimplemented, fall through */
@@ -169,11 +198,12 @@ static int a9mp_priv_init(SysBusDevice *dev)

static const VMStateDescription vmstate_a9mp_priv = {
    .name = "a9mpcore_priv",
    .version_id = 1,
    .version_id = 2,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32(scu_control, a9mp_priv_state),
        VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
        VMSTATE_UINT32_V(scu_status, a9mp_priv_state, 2),
        VMSTATE_END_OF_LIST()
    }
};
+6 −0
Original line number Diff line number Diff line
@@ -282,6 +282,10 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
            return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
        if (offset < 0x08)
            return 0;
        if (offset >= 0x80) {
            /* Interrupt Security , RAZ/WI */
            return 0;
        }
#endif
        goto bad_reg;
    } else if (offset < 0x200) {
@@ -413,6 +417,8 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
        } else if (offset < 4) {
            /* ignored.  */
        } else if (offset >= 0x80) {
            /* Interrupt Security Registers, RAZ/WI */
        } else {
            goto bad_reg;
        }

hw/arm_l2x0.c

0 → 100644
+181 −0
Original line number Diff line number Diff line
/*
 * 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/>.
 *
 */

#include "sysbus.h"

/* L2C-310 r3p2 */
#define CACHE_ID 0x410000c8

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)
{
    uint32_t cache_data;
    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:
        /* 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:
        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 void l2x0_priv_reset(DeviceState *dev)
{
    l2x0_state *s = DO_UPCAST(l2x0_state, busdev.qdev, dev);

    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)
{
    l2x0_state *s = FROM_SYSBUS(l2x0_state, 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, 0x1c100100),
        DEFINE_PROP_END_OF_LIST(),
    },
    .qdev.reset = l2x0_priv_reset,
};

static void l2x0_register_device(void)
{
    sysbus_register_withprop(&l2x0_info);
}

device_init(l2x0_register_device)
+19 −5
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@

#include "sysbus.h"
#include "qemu-timer.h"
#include "qemu-common.h"
#include "qdev.h"

/* Common timer implementation.  */

@@ -178,6 +180,7 @@ typedef struct {
    SysBusDevice busdev;
    MemoryRegion iomem;
    arm_timer_state *timer[2];
    uint32_t freq0, freq1;
    int level[2];
    qemu_irq irq;
} sp804_state;
@@ -269,10 +272,11 @@ static int sp804_init(SysBusDevice *dev)

    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
    sysbus_init_irq(dev, &s->irq);
    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
       we don't implement that.  */
    s->timer[0] = arm_timer_init(1000000);
    s->timer[1] = arm_timer_init(1000000);
    /* The timers are configurable between 32kHz and 1MHz
     * defaulting to 1MHz but overrideable as individual properties */
    s->timer[0] = arm_timer_init(s->freq0);
    s->timer[1] = arm_timer_init(s->freq1);

    s->timer[0]->irq = qi[0];
    s->timer[1]->irq = qi[1];
    memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
@@ -281,6 +285,16 @@ static int sp804_init(SysBusDevice *dev)
    return 0;
}

static SysBusDeviceInfo sp804_info = {
    .init = sp804_init,
    .qdev.name = "sp804",
    .qdev.size = sizeof(sp804_state),
    .qdev.props = (Property[]) {
        DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
        DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
        DEFINE_PROP_END_OF_LIST(),
    }
};

/* Integrator/CP timer module.  */

@@ -349,7 +363,7 @@ static int icp_pit_init(SysBusDevice *dev)
static void arm_timer_register_devices(void)
{
    sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
    sysbus_register_dev("sp804", sizeof(sp804_state), sp804_init);
    sysbus_register_withprop(&sp804_info);
}

device_init(arm_timer_register_devices)
Loading