mirror of https://github.com/proxmox/mirror_qemu
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 supportmaster
commit
c47f322365
|
@ -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 += 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 += versatile_pci.o
|
||||||
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.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 += arm_mptimer.o
|
||||||
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
|
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
|
||||||
obj-arm-y += pl061.o
|
obj-arm-y += pl061.o
|
||||||
|
|
|
@ -29,6 +29,7 @@ gic_get_current_cpu(void)
|
||||||
typedef struct a9mp_priv_state {
|
typedef struct a9mp_priv_state {
|
||||||
gic_state gic;
|
gic_state gic;
|
||||||
uint32_t scu_control;
|
uint32_t scu_control;
|
||||||
|
uint32_t scu_status;
|
||||||
uint32_t old_timer_status[8];
|
uint32_t old_timer_status[8];
|
||||||
uint32_t num_cpu;
|
uint32_t num_cpu;
|
||||||
qemu_irq *timer_irq;
|
qemu_irq *timer_irq;
|
||||||
|
@ -48,7 +49,13 @@ static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
|
||||||
case 0x04: /* Configuration */
|
case 0x04: /* Configuration */
|
||||||
return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
|
return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
|
||||||
case 0x08: /* CPU Power Status */
|
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 */
|
case 0x0c: /* Invalidate All Registers In Secure State */
|
||||||
return 0;
|
return 0;
|
||||||
case 0x40: /* Filtering Start Address Register */
|
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)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
a9mp_priv_state *s = (a9mp_priv_state *)opaque;
|
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) {
|
switch (offset) {
|
||||||
case 0x00: /* Control */
|
case 0x00: /* Control */
|
||||||
s->scu_control = value & 1;
|
s->scu_control = value & 1;
|
||||||
break;
|
break;
|
||||||
case 0x4: /* Configuration: RO */
|
case 0x4: /* Configuration: RO */
|
||||||
break;
|
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 */
|
case 0x0c: /* Invalidate All Registers In Secure State */
|
||||||
/* no-op as we do not implement caches */
|
/* no-op as we do not implement caches */
|
||||||
break;
|
break;
|
||||||
|
@ -80,7 +110,6 @@ static void a9_scu_write(void *opaque, target_phys_addr_t offset,
|
||||||
case 0x44: /* Filtering End Address Register */
|
case 0x44: /* Filtering End Address Register */
|
||||||
/* RAZ/WI, like an implementation with only one AXI master */
|
/* RAZ/WI, like an implementation with only one AXI master */
|
||||||
break;
|
break;
|
||||||
case 0x8: /* CPU Power Status */
|
|
||||||
case 0x50: /* SCU Access Control Register */
|
case 0x50: /* SCU Access Control Register */
|
||||||
case 0x54: /* SCU Non-secure Access Control Register */
|
case 0x54: /* SCU Non-secure Access Control Register */
|
||||||
/* unimplemented, fall through */
|
/* unimplemented, fall through */
|
||||||
|
@ -169,11 +198,12 @@ static int a9mp_priv_init(SysBusDevice *dev)
|
||||||
|
|
||||||
static const VMStateDescription vmstate_a9mp_priv = {
|
static const VMStateDescription vmstate_a9mp_priv = {
|
||||||
.name = "a9mpcore_priv",
|
.name = "a9mpcore_priv",
|
||||||
.version_id = 1,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(scu_control, a9mp_priv_state),
|
VMSTATE_UINT32(scu_control, a9mp_priv_state),
|
||||||
VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
|
VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
|
||||||
|
VMSTATE_UINT32_V(scu_status, a9mp_priv_state, 2),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
|
||||||
if (offset < 0x08)
|
if (offset < 0x08)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (offset >= 0x80) {
|
||||||
|
/* Interrupt Security , RAZ/WI */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
} else if (offset < 0x200) {
|
} 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");
|
DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
|
||||||
} else if (offset < 4) {
|
} else if (offset < 4) {
|
||||||
/* ignored. */
|
/* ignored. */
|
||||||
|
} else if (offset >= 0x80) {
|
||||||
|
/* Interrupt Security Registers, RAZ/WI */
|
||||||
} else {
|
} else {
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
/*
|
||||||
|
* 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)
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include "sysbus.h"
|
#include "sysbus.h"
|
||||||
#include "qemu-timer.h"
|
#include "qemu-timer.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "qdev.h"
|
||||||
|
|
||||||
/* Common timer implementation. */
|
/* Common timer implementation. */
|
||||||
|
|
||||||
|
@ -178,6 +180,7 @@ typedef struct {
|
||||||
SysBusDevice busdev;
|
SysBusDevice busdev;
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
arm_timer_state *timer[2];
|
arm_timer_state *timer[2];
|
||||||
|
uint32_t freq0, freq1;
|
||||||
int level[2];
|
int level[2];
|
||||||
qemu_irq irq;
|
qemu_irq irq;
|
||||||
} sp804_state;
|
} sp804_state;
|
||||||
|
@ -269,10 +272,11 @@ static int sp804_init(SysBusDevice *dev)
|
||||||
|
|
||||||
qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
|
qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
|
||||||
sysbus_init_irq(dev, &s->irq);
|
sysbus_init_irq(dev, &s->irq);
|
||||||
/* ??? The timers are actually configurable between 32kHz and 1MHz, but
|
/* The timers are configurable between 32kHz and 1MHz
|
||||||
we don't implement that. */
|
* defaulting to 1MHz but overrideable as individual properties */
|
||||||
s->timer[0] = arm_timer_init(1000000);
|
s->timer[0] = arm_timer_init(s->freq0);
|
||||||
s->timer[1] = arm_timer_init(1000000);
|
s->timer[1] = arm_timer_init(s->freq1);
|
||||||
|
|
||||||
s->timer[0]->irq = qi[0];
|
s->timer[0]->irq = qi[0];
|
||||||
s->timer[1]->irq = qi[1];
|
s->timer[1]->irq = qi[1];
|
||||||
memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
|
memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
|
||||||
|
@ -281,6 +285,16 @@ static int sp804_init(SysBusDevice *dev)
|
||||||
return 0;
|
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. */
|
/* Integrator/CP timer module. */
|
||||||
|
|
||||||
|
@ -349,7 +363,7 @@ static int icp_pit_init(SysBusDevice *dev)
|
||||||
static void arm_timer_register_devices(void)
|
static void arm_timer_register_devices(void)
|
||||||
{
|
{
|
||||||
sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
|
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)
|
device_init(arm_timer_register_devices)
|
||||||
|
|
28
hw/omap.h
28
hw/omap.h
|
@ -672,10 +672,6 @@ void omap_uart_reset(struct omap_uart_s *s);
|
||||||
void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
|
void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
|
||||||
|
|
||||||
struct omap_mpuio_s;
|
struct omap_mpuio_s;
|
||||||
struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *system_memory,
|
|
||||||
target_phys_addr_t base,
|
|
||||||
qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
|
|
||||||
omap_clk clk);
|
|
||||||
qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
|
qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
|
||||||
void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
|
void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
|
||||||
void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
|
void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
|
||||||
|
@ -833,8 +829,6 @@ struct omap_mpu_state_s {
|
||||||
MemoryRegion tcmi_iomem;
|
MemoryRegion tcmi_iomem;
|
||||||
MemoryRegion clkm_iomem;
|
MemoryRegion clkm_iomem;
|
||||||
MemoryRegion clkdsp_iomem;
|
MemoryRegion clkdsp_iomem;
|
||||||
MemoryRegion pwl_iomem;
|
|
||||||
MemoryRegion pwt_iomem;
|
|
||||||
MemoryRegion mpui_io_iomem;
|
MemoryRegion mpui_io_iomem;
|
||||||
MemoryRegion tap_iomem;
|
MemoryRegion tap_iomem;
|
||||||
MemoryRegion imif_ram;
|
MemoryRegion imif_ram;
|
||||||
|
@ -871,20 +865,8 @@ struct omap_mpu_state_s {
|
||||||
|
|
||||||
struct omap_uwire_s *microwire;
|
struct omap_uwire_s *microwire;
|
||||||
|
|
||||||
struct {
|
struct omap_pwl_s *pwl;
|
||||||
uint8_t output;
|
struct omap_pwt_s *pwt;
|
||||||
uint8_t level;
|
|
||||||
uint8_t enable;
|
|
||||||
int clk;
|
|
||||||
} pwl;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint8_t frc;
|
|
||||||
uint8_t vrc;
|
|
||||||
uint8_t gcr;
|
|
||||||
omap_clk clk;
|
|
||||||
} pwt;
|
|
||||||
|
|
||||||
struct omap_i2c_s *i2c[2];
|
struct omap_i2c_s *i2c[2];
|
||||||
|
|
||||||
struct omap_rtc_s *rtc;
|
struct omap_rtc_s *rtc;
|
||||||
|
@ -922,11 +904,7 @@ struct omap_mpu_state_s {
|
||||||
|
|
||||||
uint32_t tcmi_regs[17];
|
uint32_t tcmi_regs[17];
|
||||||
|
|
||||||
struct dpll_ctl_s {
|
struct dpll_ctl_s *dpll[3];
|
||||||
MemoryRegion iomem;
|
|
||||||
uint16_t mode;
|
|
||||||
omap_clk dpll;
|
|
||||||
} dpll[3];
|
|
||||||
|
|
||||||
omap_clk clks;
|
omap_clk clks;
|
||||||
struct {
|
struct {
|
||||||
|
|
153
hw/omap1.c
153
hw/omap1.c
|
@ -20,11 +20,7 @@
|
||||||
#include "arm-misc.h"
|
#include "arm-misc.h"
|
||||||
#include "omap.h"
|
#include "omap.h"
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
#include "qemu-timer.h"
|
|
||||||
#include "qemu-char.h"
|
|
||||||
#include "soc_dma.h"
|
#include "soc_dma.h"
|
||||||
/* We use pc-style serial ports. */
|
|
||||||
#include "pc.h"
|
|
||||||
#include "blockdev.h"
|
#include "blockdev.h"
|
||||||
#include "range.h"
|
#include "range.h"
|
||||||
#include "sysbus.h"
|
#include "sysbus.h"
|
||||||
|
@ -1344,6 +1340,12 @@ static void omap_tcmi_init(MemoryRegion *memory, target_phys_addr_t base,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Digital phase-locked loops control */
|
/* Digital phase-locked loops control */
|
||||||
|
struct dpll_ctl_s {
|
||||||
|
MemoryRegion iomem;
|
||||||
|
uint16_t mode;
|
||||||
|
omap_clk dpll;
|
||||||
|
};
|
||||||
|
|
||||||
static uint64_t omap_dpll_read(void *opaque, target_phys_addr_t addr,
|
static uint64_t omap_dpll_read(void *opaque, target_phys_addr_t addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
|
@ -1409,15 +1411,17 @@ static void omap_dpll_reset(struct dpll_ctl_s *s)
|
||||||
omap_clk_setrate(s->dpll, 1, 1);
|
omap_clk_setrate(s->dpll, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_dpll_init(MemoryRegion *memory, struct dpll_ctl_s *s,
|
static struct dpll_ctl_s *omap_dpll_init(MemoryRegion *memory,
|
||||||
target_phys_addr_t base, omap_clk clk)
|
target_phys_addr_t base, omap_clk clk)
|
||||||
{
|
{
|
||||||
|
struct dpll_ctl_s *s = g_malloc0(sizeof(*s));
|
||||||
memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100);
|
memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100);
|
||||||
|
|
||||||
s->dpll = clk;
|
s->dpll = clk;
|
||||||
omap_dpll_reset(s);
|
omap_dpll_reset(s);
|
||||||
|
|
||||||
memory_region_add_subregion(memory, base, &s->iomem);
|
memory_region_add_subregion(memory, base, &s->iomem);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MPU Clock/Reset/Power Mode Control */
|
/* MPU Clock/Reset/Power Mode Control */
|
||||||
|
@ -2066,7 +2070,7 @@ static void omap_mpuio_onoff(void *opaque, int line, int on)
|
||||||
omap_mpuio_kbd_update(s);
|
omap_mpuio_kbd_update(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
|
static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
|
||||||
target_phys_addr_t base,
|
target_phys_addr_t base,
|
||||||
qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
|
qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
|
||||||
omap_clk clk)
|
omap_clk clk)
|
||||||
|
@ -2289,12 +2293,20 @@ void omap_uwire_attach(struct omap_uwire_s *s,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pseudonoise Pulse-Width Light Modulator */
|
/* Pseudonoise Pulse-Width Light Modulator */
|
||||||
static void omap_pwl_update(struct omap_mpu_state_s *s)
|
struct omap_pwl_s {
|
||||||
{
|
MemoryRegion iomem;
|
||||||
int output = (s->pwl.clk && s->pwl.enable) ? s->pwl.level : 0;
|
uint8_t output;
|
||||||
|
uint8_t level;
|
||||||
|
uint8_t enable;
|
||||||
|
int clk;
|
||||||
|
};
|
||||||
|
|
||||||
if (output != s->pwl.output) {
|
static void omap_pwl_update(struct omap_pwl_s *s)
|
||||||
s->pwl.output = output;
|
{
|
||||||
|
int output = (s->clk && s->enable) ? s->level : 0;
|
||||||
|
|
||||||
|
if (output != s->output) {
|
||||||
|
s->output = output;
|
||||||
printf("%s: Backlight now at %i/256\n", __FUNCTION__, output);
|
printf("%s: Backlight now at %i/256\n", __FUNCTION__, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2302,7 +2314,7 @@ static void omap_pwl_update(struct omap_mpu_state_s *s)
|
||||||
static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr,
|
static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
|
struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
|
||||||
int offset = addr & OMAP_MPUI_REG_MASK;
|
int offset = addr & OMAP_MPUI_REG_MASK;
|
||||||
|
|
||||||
if (size != 1) {
|
if (size != 1) {
|
||||||
|
@ -2311,9 +2323,9 @@ static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr,
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 0x00: /* PWL_LEVEL */
|
case 0x00: /* PWL_LEVEL */
|
||||||
return s->pwl.level;
|
return s->level;
|
||||||
case 0x04: /* PWL_CTRL */
|
case 0x04: /* PWL_CTRL */
|
||||||
return s->pwl.enable;
|
return s->enable;
|
||||||
}
|
}
|
||||||
OMAP_BAD_REG(addr);
|
OMAP_BAD_REG(addr);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2322,7 +2334,7 @@ static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr,
|
||||||
static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
|
static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
|
||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
|
struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
|
||||||
int offset = addr & OMAP_MPUI_REG_MASK;
|
int offset = addr & OMAP_MPUI_REG_MASK;
|
||||||
|
|
||||||
if (size != 1) {
|
if (size != 1) {
|
||||||
|
@ -2331,11 +2343,11 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 0x00: /* PWL_LEVEL */
|
case 0x00: /* PWL_LEVEL */
|
||||||
s->pwl.level = value;
|
s->level = value;
|
||||||
omap_pwl_update(s);
|
omap_pwl_update(s);
|
||||||
break;
|
break;
|
||||||
case 0x04: /* PWL_CTRL */
|
case 0x04: /* PWL_CTRL */
|
||||||
s->pwl.enable = value & 1;
|
s->enable = value & 1;
|
||||||
omap_pwl_update(s);
|
omap_pwl_update(s);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -2350,41 +2362,52 @@ static const MemoryRegionOps omap_pwl_ops = {
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void omap_pwl_reset(struct omap_mpu_state_s *s)
|
static void omap_pwl_reset(struct omap_pwl_s *s)
|
||||||
{
|
{
|
||||||
s->pwl.output = 0;
|
s->output = 0;
|
||||||
s->pwl.level = 0;
|
s->level = 0;
|
||||||
s->pwl.enable = 0;
|
s->enable = 0;
|
||||||
s->pwl.clk = 1;
|
s->clk = 1;
|
||||||
omap_pwl_update(s);
|
omap_pwl_update(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_pwl_clk_update(void *opaque, int line, int on)
|
static void omap_pwl_clk_update(void *opaque, int line, int on)
|
||||||
{
|
{
|
||||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
|
struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
|
||||||
|
|
||||||
s->pwl.clk = on;
|
s->clk = on;
|
||||||
omap_pwl_update(s);
|
omap_pwl_update(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_pwl_init(MemoryRegion *system_memory,
|
static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory,
|
||||||
target_phys_addr_t base, struct omap_mpu_state_s *s,
|
target_phys_addr_t base,
|
||||||
omap_clk clk)
|
omap_clk clk)
|
||||||
{
|
{
|
||||||
|
struct omap_pwl_s *s = g_malloc0(sizeof(*s));
|
||||||
|
|
||||||
omap_pwl_reset(s);
|
omap_pwl_reset(s);
|
||||||
|
|
||||||
memory_region_init_io(&s->pwl_iomem, &omap_pwl_ops, s,
|
memory_region_init_io(&s->iomem, &omap_pwl_ops, s,
|
||||||
"omap-pwl", 0x800);
|
"omap-pwl", 0x800);
|
||||||
memory_region_add_subregion(system_memory, base, &s->pwl_iomem);
|
memory_region_add_subregion(system_memory, base, &s->iomem);
|
||||||
|
|
||||||
omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]);
|
omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pulse-Width Tone module */
|
/* Pulse-Width Tone module */
|
||||||
|
struct omap_pwt_s {
|
||||||
|
MemoryRegion iomem;
|
||||||
|
uint8_t frc;
|
||||||
|
uint8_t vrc;
|
||||||
|
uint8_t gcr;
|
||||||
|
omap_clk clk;
|
||||||
|
};
|
||||||
|
|
||||||
static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr,
|
static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
|
struct omap_pwt_s *s = (struct omap_pwt_s *) opaque;
|
||||||
int offset = addr & OMAP_MPUI_REG_MASK;
|
int offset = addr & OMAP_MPUI_REG_MASK;
|
||||||
|
|
||||||
if (size != 1) {
|
if (size != 1) {
|
||||||
|
@ -2393,11 +2416,11 @@ static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr,
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 0x00: /* FRC */
|
case 0x00: /* FRC */
|
||||||
return s->pwt.frc;
|
return s->frc;
|
||||||
case 0x04: /* VCR */
|
case 0x04: /* VCR */
|
||||||
return s->pwt.vrc;
|
return s->vrc;
|
||||||
case 0x08: /* GCR */
|
case 0x08: /* GCR */
|
||||||
return s->pwt.gcr;
|
return s->gcr;
|
||||||
}
|
}
|
||||||
OMAP_BAD_REG(addr);
|
OMAP_BAD_REG(addr);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2406,7 +2429,7 @@ static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr,
|
||||||
static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
|
static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
|
||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
|
struct omap_pwt_s *s = (struct omap_pwt_s *) opaque;
|
||||||
int offset = addr & OMAP_MPUI_REG_MASK;
|
int offset = addr & OMAP_MPUI_REG_MASK;
|
||||||
|
|
||||||
if (size != 1) {
|
if (size != 1) {
|
||||||
|
@ -2415,16 +2438,16 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 0x00: /* FRC */
|
case 0x00: /* FRC */
|
||||||
s->pwt.frc = value & 0x3f;
|
s->frc = value & 0x3f;
|
||||||
break;
|
break;
|
||||||
case 0x04: /* VRC */
|
case 0x04: /* VRC */
|
||||||
if ((value ^ s->pwt.vrc) & 1) {
|
if ((value ^ s->vrc) & 1) {
|
||||||
if (value & 1)
|
if (value & 1)
|
||||||
printf("%s: %iHz buzz on\n", __FUNCTION__, (int)
|
printf("%s: %iHz buzz on\n", __FUNCTION__, (int)
|
||||||
/* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */
|
/* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */
|
||||||
((omap_clk_getrate(s->pwt.clk) >> 3) /
|
((omap_clk_getrate(s->clk) >> 3) /
|
||||||
/* Pre-multiplexer divider */
|
/* Pre-multiplexer divider */
|
||||||
((s->pwt.gcr & 2) ? 1 : 154) /
|
((s->gcr & 2) ? 1 : 154) /
|
||||||
/* Octave multiplexer */
|
/* Octave multiplexer */
|
||||||
(2 << (value & 3)) *
|
(2 << (value & 3)) *
|
||||||
/* 101/107 divider */
|
/* 101/107 divider */
|
||||||
|
@ -2439,10 +2462,10 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
|
||||||
else
|
else
|
||||||
printf("%s: silence!\n", __FUNCTION__);
|
printf("%s: silence!\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
s->pwt.vrc = value & 0x7f;
|
s->vrc = value & 0x7f;
|
||||||
break;
|
break;
|
||||||
case 0x08: /* GCR */
|
case 0x08: /* GCR */
|
||||||
s->pwt.gcr = value & 3;
|
s->gcr = value & 3;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
OMAP_BAD_REG(addr);
|
OMAP_BAD_REG(addr);
|
||||||
|
@ -2456,23 +2479,25 @@ static const MemoryRegionOps omap_pwt_ops = {
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void omap_pwt_reset(struct omap_mpu_state_s *s)
|
static void omap_pwt_reset(struct omap_pwt_s *s)
|
||||||
{
|
{
|
||||||
s->pwt.frc = 0;
|
s->frc = 0;
|
||||||
s->pwt.vrc = 0;
|
s->vrc = 0;
|
||||||
s->pwt.gcr = 0;
|
s->gcr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_pwt_init(MemoryRegion *system_memory,
|
static struct omap_pwt_s *omap_pwt_init(MemoryRegion *system_memory,
|
||||||
target_phys_addr_t base, struct omap_mpu_state_s *s,
|
target_phys_addr_t base,
|
||||||
omap_clk clk)
|
omap_clk clk)
|
||||||
{
|
{
|
||||||
s->pwt.clk = clk;
|
struct omap_pwt_s *s = g_malloc0(sizeof(*s));
|
||||||
|
s->clk = clk;
|
||||||
omap_pwt_reset(s);
|
omap_pwt_reset(s);
|
||||||
|
|
||||||
memory_region_init_io(&s->pwt_iomem, &omap_pwt_ops, s,
|
memory_region_init_io(&s->iomem, &omap_pwt_ops, s,
|
||||||
"omap-pwt", 0x800);
|
"omap-pwt", 0x800);
|
||||||
memory_region_add_subregion(system_memory, base, &s->pwt_iomem);
|
memory_region_add_subregion(system_memory, base, &s->iomem);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Real-time Clock module */
|
/* Real-time Clock module */
|
||||||
|
@ -3658,17 +3683,17 @@ static void omap1_mpu_reset(void *opaque)
|
||||||
omap_mpui_reset(mpu);
|
omap_mpui_reset(mpu);
|
||||||
omap_tipb_bridge_reset(mpu->private_tipb);
|
omap_tipb_bridge_reset(mpu->private_tipb);
|
||||||
omap_tipb_bridge_reset(mpu->public_tipb);
|
omap_tipb_bridge_reset(mpu->public_tipb);
|
||||||
omap_dpll_reset(&mpu->dpll[0]);
|
omap_dpll_reset(mpu->dpll[0]);
|
||||||
omap_dpll_reset(&mpu->dpll[1]);
|
omap_dpll_reset(mpu->dpll[1]);
|
||||||
omap_dpll_reset(&mpu->dpll[2]);
|
omap_dpll_reset(mpu->dpll[2]);
|
||||||
omap_uart_reset(mpu->uart[0]);
|
omap_uart_reset(mpu->uart[0]);
|
||||||
omap_uart_reset(mpu->uart[1]);
|
omap_uart_reset(mpu->uart[1]);
|
||||||
omap_uart_reset(mpu->uart[2]);
|
omap_uart_reset(mpu->uart[2]);
|
||||||
omap_mmc_reset(mpu->mmc);
|
omap_mmc_reset(mpu->mmc);
|
||||||
omap_mpuio_reset(mpu->mpuio);
|
omap_mpuio_reset(mpu->mpuio);
|
||||||
omap_uwire_reset(mpu->microwire);
|
omap_uwire_reset(mpu->microwire);
|
||||||
omap_pwl_reset(mpu);
|
omap_pwl_reset(mpu->pwl);
|
||||||
omap_pwt_reset(mpu);
|
omap_pwt_reset(mpu->pwt);
|
||||||
omap_i2c_reset(mpu->i2c[0]);
|
omap_i2c_reset(mpu->i2c[0]);
|
||||||
omap_rtc_reset(mpu->rtc);
|
omap_rtc_reset(mpu->rtc);
|
||||||
omap_mcbsp_reset(mpu->mcbsp1);
|
omap_mcbsp_reset(mpu->mcbsp1);
|
||||||
|
@ -3928,12 +3953,12 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
||||||
"uart3",
|
"uart3",
|
||||||
serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
|
serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
|
||||||
|
|
||||||
omap_dpll_init(system_memory,
|
s->dpll[0] = omap_dpll_init(system_memory, 0xfffecf00,
|
||||||
&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
|
omap_findclk(s, "dpll1"));
|
||||||
omap_dpll_init(system_memory,
|
s->dpll[1] = omap_dpll_init(system_memory, 0xfffed000,
|
||||||
&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
|
omap_findclk(s, "dpll2"));
|
||||||
omap_dpll_init(system_memory,
|
s->dpll[2] = omap_dpll_init(system_memory, 0xfffed100,
|
||||||
&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
|
omap_findclk(s, "dpll3"));
|
||||||
|
|
||||||
dinfo = drive_get(IF_SD, 0, 0);
|
dinfo = drive_get(IF_SD, 0, 0);
|
||||||
if (!dinfo) {
|
if (!dinfo) {
|
||||||
|
@ -3963,8 +3988,10 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
||||||
qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX),
|
qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX),
|
||||||
s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
|
s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
|
||||||
|
|
||||||
omap_pwl_init(system_memory, 0xfffb5800, s, omap_findclk(s, "armxor_ck"));
|
s->pwl = omap_pwl_init(system_memory, 0xfffb5800,
|
||||||
omap_pwt_init(system_memory, 0xfffb6000, s, omap_findclk(s, "armxor_ck"));
|
omap_findclk(s, "armxor_ck"));
|
||||||
|
s->pwt = omap_pwt_init(system_memory, 0xfffb6000,
|
||||||
|
omap_findclk(s, "armxor_ck"));
|
||||||
|
|
||||||
s->i2c[0] = omap_i2c_init(system_memory, 0xfffb3800,
|
s->i2c[0] = omap_i2c_init(system_memory, 0xfffb3800,
|
||||||
qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C),
|
qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C),
|
||||||
|
|
|
@ -443,6 +443,12 @@ void omap_gpmc_reset(struct omap_gpmc_s *s)
|
||||||
s->irqst = 0;
|
s->irqst = 0;
|
||||||
s->irqen = 0;
|
s->irqen = 0;
|
||||||
omap_gpmc_int_update(s);
|
omap_gpmc_int_update(s);
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
/* This has to happen before we change any of the config
|
||||||
|
* used to determine which memory regions are mapped or unmapped.
|
||||||
|
*/
|
||||||
|
omap_gpmc_cs_unmap(s, i);
|
||||||
|
}
|
||||||
s->timeout = 0;
|
s->timeout = 0;
|
||||||
s->config = 0xa00;
|
s->config = 0xa00;
|
||||||
s->prefetch.config1 = 0x00004000;
|
s->prefetch.config1 = 0x00004000;
|
||||||
|
@ -451,7 +457,6 @@ void omap_gpmc_reset(struct omap_gpmc_s *s)
|
||||||
s->prefetch.fifopointer = 0;
|
s->prefetch.fifopointer = 0;
|
||||||
s->prefetch.count = 0;
|
s->prefetch.count = 0;
|
||||||
for (i = 0; i < 8; i ++) {
|
for (i = 0; i < 8; i ++) {
|
||||||
omap_gpmc_cs_unmap(s, i);
|
|
||||||
s->cs_file[i].config[1] = 0x101001;
|
s->cs_file[i].config[1] = 0x101001;
|
||||||
s->cs_file[i].config[2] = 0x020201;
|
s->cs_file[i].config[2] = 0x020201;
|
||||||
s->cs_file[i].config[3] = 0x10031003;
|
s->cs_file[i].config[3] = 0x10031003;
|
||||||
|
@ -716,24 +721,31 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
|
||||||
|
|
||||||
case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
|
case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
|
||||||
if (!s->prefetch.startengine) {
|
if (!s->prefetch.startengine) {
|
||||||
uint32_t oldconfig1 = s->prefetch.config1;
|
uint32_t newconfig1 = value & 0x7f8f7fbf;
|
||||||
uint32_t changed;
|
uint32_t changed;
|
||||||
s->prefetch.config1 = value & 0x7f8f7fbf;
|
changed = newconfig1 ^ s->prefetch.config1;
|
||||||
changed = oldconfig1 ^ s->prefetch.config1;
|
|
||||||
if (changed & (0x80 | 0x7000000)) {
|
if (changed & (0x80 | 0x7000000)) {
|
||||||
/* Turning the engine on or off, or mapping it somewhere else.
|
/* Turning the engine on or off, or mapping it somewhere else.
|
||||||
* cs_map() and cs_unmap() check the prefetch config and
|
* cs_map() and cs_unmap() check the prefetch config and
|
||||||
* overall CSVALID bits, so it is sufficient to unmap-and-map
|
* overall CSVALID bits, so it is sufficient to unmap-and-map
|
||||||
* both the old cs and the new one.
|
* both the old cs and the new one. Note that we adhere to
|
||||||
|
* the "unmap/change config/map" order (and not unmap twice
|
||||||
|
* if newcs == oldcs), otherwise we'll try to delete the wrong
|
||||||
|
* memory region.
|
||||||
*/
|
*/
|
||||||
int oldcs = prefetch_cs(oldconfig1);
|
int oldcs = prefetch_cs(s->prefetch.config1);
|
||||||
int newcs = prefetch_cs(s->prefetch.config1);
|
int newcs = prefetch_cs(newconfig1);
|
||||||
omap_gpmc_cs_unmap(s, oldcs);
|
omap_gpmc_cs_unmap(s, oldcs);
|
||||||
omap_gpmc_cs_map(s, oldcs);
|
if (oldcs != newcs) {
|
||||||
if (newcs != oldcs) {
|
|
||||||
omap_gpmc_cs_unmap(s, newcs);
|
omap_gpmc_cs_unmap(s, newcs);
|
||||||
|
}
|
||||||
|
s->prefetch.config1 = newconfig1;
|
||||||
|
omap_gpmc_cs_map(s, oldcs);
|
||||||
|
if (oldcs != newcs) {
|
||||||
omap_gpmc_cs_map(s, newcs);
|
omap_gpmc_cs_map(s, newcs);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
s->prefetch.config1 = newconfig1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
11
hw/pl110.c
11
hw/pl110.c
|
@ -60,10 +60,13 @@ typedef struct {
|
||||||
qemu_irq irq;
|
qemu_irq irq;
|
||||||
} pl110_state;
|
} pl110_state;
|
||||||
|
|
||||||
|
static int vmstate_pl110_post_load(void *opaque, int version_id);
|
||||||
|
|
||||||
static const VMStateDescription vmstate_pl110 = {
|
static const VMStateDescription vmstate_pl110 = {
|
||||||
.name = "pl110",
|
.name = "pl110",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
|
.post_load = vmstate_pl110_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_INT32(version, pl110_state),
|
VMSTATE_INT32(version, pl110_state),
|
||||||
VMSTATE_UINT32_ARRAY(timing, pl110_state, 4),
|
VMSTATE_UINT32_ARRAY(timing, pl110_state, 4),
|
||||||
|
@ -430,6 +433,14 @@ static void pl110_mux_ctrl_set(void *opaque, int line, int level)
|
||||||
s->mux_ctrl = level;
|
s->mux_ctrl = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vmstate_pl110_post_load(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
pl110_state *s = opaque;
|
||||||
|
/* Make sure we redraw, and at the right size */
|
||||||
|
pl110_invalidate_display(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int pl110_init(SysBusDevice *dev)
|
static int pl110_init(SysBusDevice *dev)
|
||||||
{
|
{
|
||||||
pl110_state *s = FROM_SYSBUS(pl110_state, dev);
|
pl110_state *s = FROM_SYSBUS(pl110_state, dev);
|
||||||
|
|
49
hw/pl181.c
49
hw/pl181.c
|
@ -38,20 +38,45 @@ typedef struct {
|
||||||
uint32_t datacnt;
|
uint32_t datacnt;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
uint32_t mask[2];
|
uint32_t mask[2];
|
||||||
int fifo_pos;
|
int32_t fifo_pos;
|
||||||
int fifo_len;
|
int32_t fifo_len;
|
||||||
/* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
|
/* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
|
||||||
while it is reading the FIFO. We hack around this be defering
|
while it is reading the FIFO. We hack around this be defering
|
||||||
subsequent transfers until after the driver polls the status word.
|
subsequent transfers until after the driver polls the status word.
|
||||||
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
|
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
|
||||||
*/
|
*/
|
||||||
int linux_hack;
|
int32_t linux_hack;
|
||||||
uint32_t fifo[PL181_FIFO_LEN];
|
uint32_t fifo[PL181_FIFO_LEN];
|
||||||
qemu_irq irq[2];
|
qemu_irq irq[2];
|
||||||
/* GPIO outputs for 'card is readonly' and 'card inserted' */
|
/* GPIO outputs for 'card is readonly' and 'card inserted' */
|
||||||
qemu_irq cardstatus[2];
|
qemu_irq cardstatus[2];
|
||||||
} pl181_state;
|
} pl181_state;
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_pl181 = {
|
||||||
|
.name = "pl181",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(clock, pl181_state),
|
||||||
|
VMSTATE_UINT32(power, pl181_state),
|
||||||
|
VMSTATE_UINT32(cmdarg, pl181_state),
|
||||||
|
VMSTATE_UINT32(cmd, pl181_state),
|
||||||
|
VMSTATE_UINT32(datatimer, pl181_state),
|
||||||
|
VMSTATE_UINT32(datalength, pl181_state),
|
||||||
|
VMSTATE_UINT32(respcmd, pl181_state),
|
||||||
|
VMSTATE_UINT32_ARRAY(response, pl181_state, 4),
|
||||||
|
VMSTATE_UINT32(datactrl, pl181_state),
|
||||||
|
VMSTATE_UINT32(datacnt, pl181_state),
|
||||||
|
VMSTATE_UINT32(status, pl181_state),
|
||||||
|
VMSTATE_UINT32_ARRAY(mask, pl181_state, 2),
|
||||||
|
VMSTATE_INT32(fifo_pos, pl181_state),
|
||||||
|
VMSTATE_INT32(fifo_len, pl181_state),
|
||||||
|
VMSTATE_INT32(linux_hack, pl181_state),
|
||||||
|
VMSTATE_UINT32_ARRAY(fifo, pl181_state, PL181_FIFO_LEN),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#define PL181_CMD_INDEX 0x3f
|
#define PL181_CMD_INDEX 0x3f
|
||||||
#define PL181_CMD_RESPONSE (1 << 6)
|
#define PL181_CMD_RESPONSE (1 << 6)
|
||||||
#define PL181_CMD_LONGRESP (1 << 7)
|
#define PL181_CMD_LONGRESP (1 << 7)
|
||||||
|
@ -420,9 +445,9 @@ static const MemoryRegionOps pl181_ops = {
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pl181_reset(void *opaque)
|
static void pl181_reset(DeviceState *d)
|
||||||
{
|
{
|
||||||
pl181_state *s = (pl181_state *)opaque;
|
pl181_state *s = DO_UPCAST(pl181_state, busdev.qdev, d);
|
||||||
|
|
||||||
s->power = 0;
|
s->power = 0;
|
||||||
s->cmdarg = 0;
|
s->cmdarg = 0;
|
||||||
|
@ -459,15 +484,21 @@ static int pl181_init(SysBusDevice *dev)
|
||||||
qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
|
qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
|
||||||
dinfo = drive_get_next(IF_SD);
|
dinfo = drive_get_next(IF_SD);
|
||||||
s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
|
s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
|
||||||
qemu_register_reset(pl181_reset, s);
|
|
||||||
pl181_reset(s);
|
|
||||||
/* ??? Save/restore. */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SysBusDeviceInfo pl181_info = {
|
||||||
|
.init = pl181_init,
|
||||||
|
.qdev.name = "pl181",
|
||||||
|
.qdev.size = sizeof(pl181_state),
|
||||||
|
.qdev.vmsd = &vmstate_pl181,
|
||||||
|
.qdev.reset = pl181_reset,
|
||||||
|
.qdev.no_user = 1,
|
||||||
|
};
|
||||||
|
|
||||||
static void pl181_register_devices(void)
|
static void pl181_register_devices(void)
|
||||||
{
|
{
|
||||||
sysbus_register_dev("pl181", sizeof(pl181_state), pl181_init);
|
sysbus_register_withprop(&pl181_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
device_init(pl181_register_devices)
|
device_init(pl181_register_devices)
|
||||||
|
|
Loading…
Reference in New Issue