mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-01 01:32:34 +00:00
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
This commit is contained in:
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 += 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
|
||||
|
@ -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()
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
181
hw/arm_l2x0.c
Normal file
181
hw/arm_l2x0.c
Normal file
@ -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 "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)
|
||||
|
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
@ -833,8 +829,6 @@ struct omap_mpu_state_s {
|
||||
MemoryRegion tcmi_iomem;
|
||||
MemoryRegion clkm_iomem;
|
||||
MemoryRegion clkdsp_iomem;
|
||||
MemoryRegion pwl_iomem;
|
||||
MemoryRegion pwt_iomem;
|
||||
MemoryRegion mpui_io_iomem;
|
||||
MemoryRegion tap_iomem;
|
||||
MemoryRegion imif_ram;
|
||||
@ -871,20 +865,8 @@ struct omap_mpu_state_s {
|
||||
|
||||
struct omap_uwire_s *microwire;
|
||||
|
||||
struct {
|
||||
uint8_t output;
|
||||
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_pwl_s *pwl;
|
||||
struct omap_pwt_s *pwt;
|
||||
struct omap_i2c_s *i2c[2];
|
||||
|
||||
struct omap_rtc_s *rtc;
|
||||
@ -922,11 +904,7 @@ struct omap_mpu_state_s {
|
||||
|
||||
uint32_t tcmi_regs[17];
|
||||
|
||||
struct dpll_ctl_s {
|
||||
MemoryRegion iomem;
|
||||
uint16_t mode;
|
||||
omap_clk dpll;
|
||||
} dpll[3];
|
||||
struct dpll_ctl_s *dpll[3];
|
||||
|
||||
omap_clk clks;
|
||||
struct {
|
||||
|
153
hw/omap1.c
153
hw/omap1.c
@ -20,11 +20,7 @@
|
||||
#include "arm-misc.h"
|
||||
#include "omap.h"
|
||||
#include "sysemu.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "qemu-char.h"
|
||||
#include "soc_dma.h"
|
||||
/* We use pc-style serial ports. */
|
||||
#include "pc.h"
|
||||
#include "blockdev.h"
|
||||
#include "range.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 */
|
||||
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,
|
||||
unsigned size)
|
||||
{
|
||||
@ -1409,15 +1411,17 @@ static void omap_dpll_reset(struct dpll_ctl_s *s)
|
||||
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)
|
||||
{
|
||||
struct dpll_ctl_s *s = g_malloc0(sizeof(*s));
|
||||
memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100);
|
||||
|
||||
s->dpll = clk;
|
||||
omap_dpll_reset(s);
|
||||
|
||||
memory_region_add_subregion(memory, base, &s->iomem);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
|
||||
static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
|
||||
target_phys_addr_t base,
|
||||
qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
|
||||
omap_clk clk)
|
||||
@ -2289,12 +2293,20 @@ void omap_uwire_attach(struct omap_uwire_s *s,
|
||||
}
|
||||
|
||||
/* Pseudonoise Pulse-Width Light Modulator */
|
||||
static void omap_pwl_update(struct omap_mpu_state_s *s)
|
||||
{
|
||||
int output = (s->pwl.clk && s->pwl.enable) ? s->pwl.level : 0;
|
||||
struct omap_pwl_s {
|
||||
MemoryRegion iomem;
|
||||
uint8_t output;
|
||||
uint8_t level;
|
||||
uint8_t enable;
|
||||
int clk;
|
||||
};
|
||||
|
||||
if (output != s->pwl.output) {
|
||||
s->pwl.output = output;
|
||||
static void omap_pwl_update(struct omap_pwl_s *s)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
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;
|
||||
|
||||
if (size != 1) {
|
||||
@ -2311,9 +2323,9 @@ static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr,
|
||||
|
||||
switch (offset) {
|
||||
case 0x00: /* PWL_LEVEL */
|
||||
return s->pwl.level;
|
||||
return s->level;
|
||||
case 0x04: /* PWL_CTRL */
|
||||
return s->pwl.enable;
|
||||
return s->enable;
|
||||
}
|
||||
OMAP_BAD_REG(addr);
|
||||
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,
|
||||
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;
|
||||
|
||||
if (size != 1) {
|
||||
@ -2331,11 +2343,11 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
|
||||
|
||||
switch (offset) {
|
||||
case 0x00: /* PWL_LEVEL */
|
||||
s->pwl.level = value;
|
||||
s->level = value;
|
||||
omap_pwl_update(s);
|
||||
break;
|
||||
case 0x04: /* PWL_CTRL */
|
||||
s->pwl.enable = value & 1;
|
||||
s->enable = value & 1;
|
||||
omap_pwl_update(s);
|
||||
break;
|
||||
default:
|
||||
@ -2350,41 +2362,52 @@ static const MemoryRegionOps omap_pwl_ops = {
|
||||
.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->pwl.level = 0;
|
||||
s->pwl.enable = 0;
|
||||
s->pwl.clk = 1;
|
||||
s->output = 0;
|
||||
s->level = 0;
|
||||
s->enable = 0;
|
||||
s->clk = 1;
|
||||
omap_pwl_update(s);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void omap_pwl_init(MemoryRegion *system_memory,
|
||||
target_phys_addr_t base, struct omap_mpu_state_s *s,
|
||||
omap_clk clk)
|
||||
static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory,
|
||||
target_phys_addr_t base,
|
||||
omap_clk clk)
|
||||
{
|
||||
struct omap_pwl_s *s = g_malloc0(sizeof(*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);
|
||||
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]);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
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;
|
||||
|
||||
if (size != 1) {
|
||||
@ -2393,11 +2416,11 @@ static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr,
|
||||
|
||||
switch (offset) {
|
||||
case 0x00: /* FRC */
|
||||
return s->pwt.frc;
|
||||
return s->frc;
|
||||
case 0x04: /* VCR */
|
||||
return s->pwt.vrc;
|
||||
return s->vrc;
|
||||
case 0x08: /* GCR */
|
||||
return s->pwt.gcr;
|
||||
return s->gcr;
|
||||
}
|
||||
OMAP_BAD_REG(addr);
|
||||
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,
|
||||
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;
|
||||
|
||||
if (size != 1) {
|
||||
@ -2415,16 +2438,16 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
|
||||
|
||||
switch (offset) {
|
||||
case 0x00: /* FRC */
|
||||
s->pwt.frc = value & 0x3f;
|
||||
s->frc = value & 0x3f;
|
||||
break;
|
||||
case 0x04: /* VRC */
|
||||
if ((value ^ s->pwt.vrc) & 1) {
|
||||
if ((value ^ s->vrc) & 1) {
|
||||
if (value & 1)
|
||||
printf("%s: %iHz buzz on\n", __FUNCTION__, (int)
|
||||
/* 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 */
|
||||
((s->pwt.gcr & 2) ? 1 : 154) /
|
||||
((s->gcr & 2) ? 1 : 154) /
|
||||
/* Octave multiplexer */
|
||||
(2 << (value & 3)) *
|
||||
/* 101/107 divider */
|
||||
@ -2439,10 +2462,10 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
|
||||
else
|
||||
printf("%s: silence!\n", __FUNCTION__);
|
||||
}
|
||||
s->pwt.vrc = value & 0x7f;
|
||||
s->vrc = value & 0x7f;
|
||||
break;
|
||||
case 0x08: /* GCR */
|
||||
s->pwt.gcr = value & 3;
|
||||
s->gcr = value & 3;
|
||||
break;
|
||||
default:
|
||||
OMAP_BAD_REG(addr);
|
||||
@ -2456,23 +2479,25 @@ static const MemoryRegionOps omap_pwt_ops = {
|
||||
.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->pwt.vrc = 0;
|
||||
s->pwt.gcr = 0;
|
||||
s->frc = 0;
|
||||
s->vrc = 0;
|
||||
s->gcr = 0;
|
||||
}
|
||||
|
||||
static void omap_pwt_init(MemoryRegion *system_memory,
|
||||
target_phys_addr_t base, struct omap_mpu_state_s *s,
|
||||
omap_clk clk)
|
||||
static struct omap_pwt_s *omap_pwt_init(MemoryRegion *system_memory,
|
||||
target_phys_addr_t base,
|
||||
omap_clk clk)
|
||||
{
|
||||
s->pwt.clk = clk;
|
||||
struct omap_pwt_s *s = g_malloc0(sizeof(*s));
|
||||
s->clk = clk;
|
||||
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);
|
||||
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 */
|
||||
@ -3658,17 +3683,17 @@ static void omap1_mpu_reset(void *opaque)
|
||||
omap_mpui_reset(mpu);
|
||||
omap_tipb_bridge_reset(mpu->private_tipb);
|
||||
omap_tipb_bridge_reset(mpu->public_tipb);
|
||||
omap_dpll_reset(&mpu->dpll[0]);
|
||||
omap_dpll_reset(&mpu->dpll[1]);
|
||||
omap_dpll_reset(&mpu->dpll[2]);
|
||||
omap_dpll_reset(mpu->dpll[0]);
|
||||
omap_dpll_reset(mpu->dpll[1]);
|
||||
omap_dpll_reset(mpu->dpll[2]);
|
||||
omap_uart_reset(mpu->uart[0]);
|
||||
omap_uart_reset(mpu->uart[1]);
|
||||
omap_uart_reset(mpu->uart[2]);
|
||||
omap_mmc_reset(mpu->mmc);
|
||||
omap_mpuio_reset(mpu->mpuio);
|
||||
omap_uwire_reset(mpu->microwire);
|
||||
omap_pwl_reset(mpu);
|
||||
omap_pwt_reset(mpu);
|
||||
omap_pwl_reset(mpu->pwl);
|
||||
omap_pwt_reset(mpu->pwt);
|
||||
omap_i2c_reset(mpu->i2c[0]);
|
||||
omap_rtc_reset(mpu->rtc);
|
||||
omap_mcbsp_reset(mpu->mcbsp1);
|
||||
@ -3928,12 +3953,12 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
||||
"uart3",
|
||||
serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
|
||||
|
||||
omap_dpll_init(system_memory,
|
||||
&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
|
||||
omap_dpll_init(system_memory,
|
||||
&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
|
||||
omap_dpll_init(system_memory,
|
||||
&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
|
||||
s->dpll[0] = omap_dpll_init(system_memory, 0xfffecf00,
|
||||
omap_findclk(s, "dpll1"));
|
||||
s->dpll[1] = omap_dpll_init(system_memory, 0xfffed000,
|
||||
omap_findclk(s, "dpll2"));
|
||||
s->dpll[2] = omap_dpll_init(system_memory, 0xfffed100,
|
||||
omap_findclk(s, "dpll3"));
|
||||
|
||||
dinfo = drive_get(IF_SD, 0, 0);
|
||||
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),
|
||||
s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
|
||||
|
||||
omap_pwl_init(system_memory, 0xfffb5800, s, omap_findclk(s, "armxor_ck"));
|
||||
omap_pwt_init(system_memory, 0xfffb6000, s, omap_findclk(s, "armxor_ck"));
|
||||
s->pwl = omap_pwl_init(system_memory, 0xfffb5800,
|
||||
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,
|
||||
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->irqen = 0;
|
||||
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->config = 0xa00;
|
||||
s->prefetch.config1 = 0x00004000;
|
||||
@ -451,7 +457,6 @@ void omap_gpmc_reset(struct omap_gpmc_s *s)
|
||||
s->prefetch.fifopointer = 0;
|
||||
s->prefetch.count = 0;
|
||||
for (i = 0; i < 8; i ++) {
|
||||
omap_gpmc_cs_unmap(s, i);
|
||||
s->cs_file[i].config[1] = 0x101001;
|
||||
s->cs_file[i].config[2] = 0x020201;
|
||||
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 */
|
||||
if (!s->prefetch.startengine) {
|
||||
uint32_t oldconfig1 = s->prefetch.config1;
|
||||
uint32_t newconfig1 = value & 0x7f8f7fbf;
|
||||
uint32_t changed;
|
||||
s->prefetch.config1 = value & 0x7f8f7fbf;
|
||||
changed = oldconfig1 ^ s->prefetch.config1;
|
||||
changed = newconfig1 ^ s->prefetch.config1;
|
||||
if (changed & (0x80 | 0x7000000)) {
|
||||
/* Turning the engine on or off, or mapping it somewhere else.
|
||||
* cs_map() and cs_unmap() check the prefetch config and
|
||||
* 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 newcs = prefetch_cs(s->prefetch.config1);
|
||||
int oldcs = prefetch_cs(s->prefetch.config1);
|
||||
int newcs = prefetch_cs(newconfig1);
|
||||
omap_gpmc_cs_unmap(s, oldcs);
|
||||
omap_gpmc_cs_map(s, oldcs);
|
||||
if (newcs != oldcs) {
|
||||
if (oldcs != 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);
|
||||
}
|
||||
} else {
|
||||
s->prefetch.config1 = newconfig1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
11
hw/pl110.c
11
hw/pl110.c
@ -60,10 +60,13 @@ typedef struct {
|
||||
qemu_irq irq;
|
||||
} pl110_state;
|
||||
|
||||
static int vmstate_pl110_post_load(void *opaque, int version_id);
|
||||
|
||||
static const VMStateDescription vmstate_pl110 = {
|
||||
.name = "pl110",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = vmstate_pl110_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(version, pl110_state),
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 status;
|
||||
uint32_t mask[2];
|
||||
int fifo_pos;
|
||||
int fifo_len;
|
||||
int32_t fifo_pos;
|
||||
int32_t fifo_len;
|
||||
/* 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
|
||||
subsequent transfers until after the driver polls the status word.
|
||||
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];
|
||||
qemu_irq irq[2];
|
||||
/* GPIO outputs for 'card is readonly' and 'card inserted' */
|
||||
qemu_irq cardstatus[2];
|
||||
} 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_RESPONSE (1 << 6)
|
||||
#define PL181_CMD_LONGRESP (1 << 7)
|
||||
@ -420,9 +445,9 @@ static const MemoryRegionOps pl181_ops = {
|
||||
.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->cmdarg = 0;
|
||||
@ -459,15 +484,21 @@ static int pl181_init(SysBusDevice *dev)
|
||||
qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
|
||||
dinfo = drive_get_next(IF_SD);
|
||||
s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
|
||||
qemu_register_reset(pl181_reset, s);
|
||||
pl181_reset(s);
|
||||
/* ??? Save/restore. */
|
||||
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)
|
||||
{
|
||||
sysbus_register_dev("pl181", sizeof(pl181_state), pl181_init);
|
||||
sysbus_register_withprop(&pl181_info);
|
||||
}
|
||||
|
||||
device_init(pl181_register_devices)
|
||||
|
Loading…
x
Reference in New Issue
Block a user