* [Qemu-devel] [PULL 00/24] arm-devs queue
@ 2013-06-03 16:29 Peter Maydell
2013-06-03 16:29 ` [Qemu-devel] [PULL 01/24] xilinx_spips: seperate SPI and QSPI as two classes Peter Maydell
` (24 more replies)
0 siblings, 25 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
Hi; here's the latest arm-devs pullreq. I had a lot of
cc'd mail to wade through putting this together so I wouldn't
be surprised if I missed a patch somewhere; if so please
ping the relevant patch.
Please pull.
thanks
-- PMM
The following changes since commit 8b779b368b3b45d5ed3160173499eeafee4d567c:
po/hu.po: Hungarian translation for the GTK+ interface (2013-06-03 08:39:11 -0500)
are available in the git repository at:
git://git.linaro.org/people/pmaydell/qemu-arm.git arm-devs.next
for you to fetch changes up to 95669e69848eda87861e1ec3016562101542f543:
i.MX: Improve EPIT timer code. (2013-06-03 17:17:46 +0100)
----------------------------------------------------------------
Igor Mitsyanko (2):
hw/arm/exynos4210.c: convert chipid_and_omr to an mmio region
exynos4210.c: register rom_mem for memory migration
Jean-Christophe DUBOIS (2):
i.MX: split GPT and EPIT timer implementation
i.MX: Improve EPIT timer code.
Peter Crosthwaite (20):
xilinx_spips: seperate SPI and QSPI as two classes
xilinx_spips: Make interrupts clear on read
xilinx_spips: Inhibit interrupts in LQSPI mode
xilinx_spips: Add verbose LQSPI debug output
xilinx_spips: Fix QSPI FIFO size
xilinx_spips: Trash LQ page cache on mode change
xilinx_spips: Add automatic start support
xilinx_spips: Implement automatic CS
xilinx_spips: lqspi: Dont touch config register
xilinx_spips: Fix CTRL register RW bits
xilinx_spips: Fix striping behaviour
xilinx_spips: Debug msgs for Snoop state
xilinx_spips: Multiple debug verbosity levels
xilinx_spips: lqspi: Push more data to tx-fifo
xilinx_spips: lqspi: Fix byte/misaligned access
sd/sdhci.c: Only reset data_count on new commands
sd/sdhci: Fix Buffer Write Ready interrupt
sd/sdhci.c: Fix bdata_read DPRINT message
sd/sdhci:ADMA: fix interrupt
sd/sd.c: Fix "inquiry" ACMD41
hw/arm/exynos4210.c | 28 ++-
hw/arm/xilinx_zynq.c | 2 +-
hw/sd/sd.c | 11 +-
hw/sd/sdhci.c | 28 +--
hw/ssi/xilinx_spips.c | 320 ++++++++++++++++++++------
hw/timer/Makefile.objs | 3 +-
hw/timer/imx_epit.c | 432 +++++++++++++++++++++++++++++++++++
hw/timer/{imx_timer.c => imx_gpt.c} | 366 +----------------------------
8 files changed, 735 insertions(+), 455 deletions(-)
create mode 100644 hw/timer/imx_epit.c
rename hw/timer/{imx_timer.c => imx_gpt.c} (58%)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 01/24] xilinx_spips: seperate SPI and QSPI as two classes
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
@ 2013-06-03 16:29 ` Peter Maydell
2013-06-03 16:29 ` [Qemu-devel] [PULL 02/24] xilinx_spips: Make interrupts clear on read Peter Maydell
` (23 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Make SPI and QSPI different classes. QSPIPS is setup as a child of SPIPS.
Only QSPI has the LQSPI functionality, so move all that to the child class.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 2cdd0cadb5ba77ca02fde5cae627852dc9a64c71.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/xilinx_zynq.c | 2 +-
hw/ssi/xilinx_spips.c | 69 +++++++++++++++++++++++++++++++++++++++----------
2 files changed, 56 insertions(+), 15 deletions(-)
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 41505c3..4602a6f 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -66,7 +66,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1;
int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES;
- dev = qdev_create(NULL, "xilinx,spips");
+ dev = qdev_create(NULL, is_qspi ? "xlnx.ps7-qspi" : "xlnx.ps7-spi");
qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1);
qdev_prop_set_uint8(dev, "num-ss-bits", num_ss);
qdev_prop_set_uint8(dev, "num-busses", num_busses);
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index b2397f4..734adf0 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -129,7 +129,8 @@ typedef enum {
} FlashCMD;
typedef struct {
- SysBusDevice busdev;
+ SysBusDevice parent_obj;
+
MemoryRegion iomem;
MemoryRegion mmlqspi;
@@ -149,15 +150,23 @@ typedef struct {
uint8_t num_txrx_bytes;
uint32_t regs[R_MAX];
+} XilinxSPIPS;
+
+typedef struct {
+ XilinxSPIPS parent_obj;
uint32_t lqspi_buf[LQSPI_CACHE_SIZE];
hwaddr lqspi_cached_addr;
-} XilinxSPIPS;
+} XilinxQSPIPS;
+
-#define TYPE_XILINX_SPIPS "xilinx,spips"
+#define TYPE_XILINX_SPIPS "xlnx.ps7-spi"
+#define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi"
#define XILINX_SPIPS(obj) \
OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
+#define XILINX_QSPIPS(obj) \
+ OBJECT_CHECK(XilinxQSPIPS, (obj), TYPE_XILINX_QSPIPS)
static inline int num_effective_busses(XilinxSPIPS *s)
{
@@ -436,11 +445,12 @@ static uint64_t
lqspi_read(void *opaque, hwaddr addr, unsigned int size)
{
int i;
+ XilinxQSPIPS *q = opaque;
XilinxSPIPS *s = opaque;
- if (addr >= s->lqspi_cached_addr &&
- addr <= s->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
- return s->lqspi_buf[(addr - s->lqspi_cached_addr) >> 2];
+ if (addr >= q->lqspi_cached_addr &&
+ addr <= q->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
+ return q->lqspi_buf[(addr - q->lqspi_cached_addr) >> 2];
} else {
int flash_addr = (addr / num_effective_busses(s));
int slave = flash_addr >> LQSPI_ADDRESS_BITS;
@@ -484,14 +494,14 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) {
tx_data_bytes(s, 0, 4);
xilinx_spips_flush_txfifo(s);
- rx_data_bytes(s, &s->lqspi_buf[cache_entry], 4);
+ rx_data_bytes(s, &q->lqspi_buf[cache_entry], 4);
cache_entry++;
}
s->regs[R_CONFIG] |= CS;
xilinx_spips_update_cs_lines(s);
- s->lqspi_cached_addr = addr;
+ q->lqspi_cached_addr = addr;
return lqspi_read(opaque, addr, size);
}
}
@@ -511,7 +521,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
int i;
- DB_PRINT("inited device model\n");
+ DB_PRINT("realized spips\n");
s->spi = g_new(SSIBus *, s->num_busses);
for (i = 0; i < s->num_busses; ++i) {
@@ -531,17 +541,32 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4);
sysbus_init_mmio(sbd, &s->iomem);
- memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi",
- (1 << LQSPI_ADDRESS_BITS) * 2);
- sysbus_init_mmio(sbd, &s->mmlqspi);
-
s->irqline = -1;
- s->lqspi_cached_addr = ~0ULL;
fifo8_create(&s->rx_fifo, RXFF_A);
fifo8_create(&s->tx_fifo, TXFF_A);
}
+static void xilinx_qspips_realize(DeviceState *dev, Error **errp)
+{
+ XilinxSPIPS *s = XILINX_SPIPS(dev);
+ XilinxQSPIPS *q = XILINX_QSPIPS(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ DB_PRINT("realized qspips\n");
+
+ s->num_busses = 2;
+ s->num_cs = 2;
+ s->num_txrx_bytes = 4;
+
+ xilinx_spips_realize(dev, errp);
+ memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi",
+ (1 << LQSPI_ADDRESS_BITS) * 2);
+ sysbus_init_mmio(sbd, &s->mmlqspi);
+
+ q->lqspi_cached_addr = ~0ULL;
+}
+
static int xilinx_spips_post_load(void *opaque, int version_id)
{
xilinx_spips_update_ixr((XilinxSPIPS *)opaque);
@@ -570,6 +595,14 @@ static Property xilinx_spips_properties[] = {
DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1),
DEFINE_PROP_END_OF_LIST(),
};
+
+static void xilinx_qspips_class_init(ObjectClass *klass, void * data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = xilinx_qspips_realize;
+}
+
static void xilinx_spips_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -587,9 +620,17 @@ static const TypeInfo xilinx_spips_info = {
.class_init = xilinx_spips_class_init,
};
+static const TypeInfo xilinx_qspips_info = {
+ .name = TYPE_XILINX_QSPIPS,
+ .parent = TYPE_XILINX_SPIPS,
+ .instance_size = sizeof(XilinxQSPIPS),
+ .class_init = xilinx_qspips_class_init,
+};
+
static void xilinx_spips_register_types(void)
{
type_register_static(&xilinx_spips_info);
+ type_register_static(&xilinx_qspips_info);
}
type_init(xilinx_spips_register_types)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 02/24] xilinx_spips: Make interrupts clear on read
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
2013-06-03 16:29 ` [Qemu-devel] [PULL 01/24] xilinx_spips: seperate SPI and QSPI as two classes Peter Maydell
@ 2013-06-03 16:29 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 03/24] xilinx_spips: Inhibit interrupts in LQSPI mode Peter Maydell
` (22 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
By default these interrupts are clear on read.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 999ff0091ed3cc3969a431bf55c00ef934cecc8e.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 734adf0..261d948 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -330,6 +330,10 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
mask = 0x0002FFFF;
break;
case R_INTR_STATUS:
+ ret = s->regs[addr] & IXR_ALL;
+ s->regs[addr] = 0;
+ DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+ return ret;
case R_INTR_MASK:
mask = IXR_ALL;
break;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 03/24] xilinx_spips: Inhibit interrupts in LQSPI mode
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
2013-06-03 16:29 ` [Qemu-devel] [PULL 01/24] xilinx_spips: seperate SPI and QSPI as two classes Peter Maydell
2013-06-03 16:29 ` [Qemu-devel] [PULL 02/24] xilinx_spips: Make interrupts clear on read Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 04/24] xilinx_spips: Add verbose LQSPI debug output Peter Maydell
` (21 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The real hardware does not produce interrupts in LQSPI mode. Inhibit
generation of interrupts when the LQ_MODE bit is set.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: dff794a06872009ea7e5733ce6adcff94d18bbd0.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 261d948..a8691d5 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -204,6 +204,9 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
static void xilinx_spips_update_ixr(XilinxSPIPS *s)
{
+ if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE) {
+ return;
+ }
/* These are set/cleared as they occur */
s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW |
IXR_TX_FIFO_MODE_FAIL);
@@ -256,7 +259,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
for (i = 0; i < num_effective_busses(s); ++i) {
if (!i || s->snoop_state == SNOOP_STRIPING) {
if (fifo8_is_empty(&s->tx_fifo)) {
- s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
+ if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
+ s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
+ }
xilinx_spips_update_ixr(s);
return;
} else {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 04/24] xilinx_spips: Add verbose LQSPI debug output
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (2 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 03/24] xilinx_spips: Inhibit interrupts in LQSPI mode Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 05/24] xilinx_spips: Fix QSPI FIFO size Peter Maydell
` (20 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
You really need this is you want to track a guest banging on LQSPI.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 26e508da4af11058d37daa777064c9e5c2a69abb.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index a8691d5..29636ce 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -456,10 +456,13 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
int i;
XilinxQSPIPS *q = opaque;
XilinxSPIPS *s = opaque;
+ uint32_t ret;
if (addr >= q->lqspi_cached_addr &&
addr <= q->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
- return q->lqspi_buf[(addr - q->lqspi_cached_addr) >> 2];
+ ret = q->lqspi_buf[(addr - q->lqspi_cached_addr) >> 2];
+ DB_PRINT("addr: %08x, data: %08x\n", (unsigned)addr, (unsigned)ret);
+ return ret;
} else {
int flash_addr = (addr / num_effective_busses(s));
int slave = flash_addr >> LQSPI_ADDRESS_BITS;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 05/24] xilinx_spips: Fix QSPI FIFO size
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (3 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 04/24] xilinx_spips: Add verbose LQSPI debug output Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 06/24] xilinx_spips: Trash LQ page cache on mode change Peter Maydell
` (19 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
QSPI has a bigger FIFO than the regular SPI controller. Differentiate
between the two with correct FIFO sizes for each.
This is the first piece of class data for SPIPS, so this patch sees
the creation of the XilinxSPIPSClass definition and assoicated QOM
constructs.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: acee25dd5e203215cbc15ca5d3cb5d5b2efebe7b.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 29636ce..86f33ef 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -106,6 +106,9 @@
#define RXFF_A 32
#define TXFF_A 32
+#define RXFF_A_Q (64 * 4)
+#define TXFF_A_Q (64 * 4)
+
/* 16MB per linear region */
#define LQSPI_ADDRESS_BITS 24
/* Bite off 4k chunks at a time */
@@ -159,12 +162,23 @@ typedef struct {
hwaddr lqspi_cached_addr;
} XilinxQSPIPS;
+typedef struct XilinxSPIPSClass {
+ SysBusDeviceClass parent_class;
+
+ uint32_t rx_fifo_size;
+ uint32_t tx_fifo_size;
+} XilinxSPIPSClass;
#define TYPE_XILINX_SPIPS "xlnx.ps7-spi"
#define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi"
#define XILINX_SPIPS(obj) \
OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
+#define XILINX_SPIPS_CLASS(klass) \
+ OBJECT_CLASS_CHECK(XilinxSPIPSClass, (klass), TYPE_XILINX_SPIPS)
+#define XILINX_SPIPS_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XilinxSPIPSClass, (obj), TYPE_XILINX_SPIPS)
+
#define XILINX_QSPIPS(obj) \
OBJECT_CHECK(XilinxQSPIPS, (obj), TYPE_XILINX_QSPIPS)
@@ -531,6 +545,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
{
XilinxSPIPS *s = XILINX_SPIPS(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s);
int i;
DB_PRINT("realized spips\n");
@@ -555,8 +570,8 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
s->irqline = -1;
- fifo8_create(&s->rx_fifo, RXFF_A);
- fifo8_create(&s->tx_fifo, TXFF_A);
+ fifo8_create(&s->rx_fifo, xsc->rx_fifo_size);
+ fifo8_create(&s->tx_fifo, xsc->tx_fifo_size);
}
static void xilinx_qspips_realize(DeviceState *dev, Error **errp)
@@ -611,18 +626,25 @@ static Property xilinx_spips_properties[] = {
static void xilinx_qspips_class_init(ObjectClass *klass, void * data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
dc->realize = xilinx_qspips_realize;
+ xsc->rx_fifo_size = RXFF_A_Q;
+ xsc->tx_fifo_size = TXFF_A_Q;
}
static void xilinx_spips_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
dc->realize = xilinx_spips_realize;
dc->reset = xilinx_spips_reset;
dc->props = xilinx_spips_properties;
dc->vmsd = &vmstate_xilinx_spips;
+
+ xsc->rx_fifo_size = RXFF_A;
+ xsc->tx_fifo_size = TXFF_A;
}
static const TypeInfo xilinx_spips_info = {
@@ -630,6 +652,7 @@ static const TypeInfo xilinx_spips_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(XilinxSPIPS),
.class_init = xilinx_spips_class_init,
+ .class_size = sizeof(XilinxSPIPSClass),
};
static const TypeInfo xilinx_qspips_info = {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 06/24] xilinx_spips: Trash LQ page cache on mode change
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (4 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 05/24] xilinx_spips: Fix QSPI FIFO size Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 07/24] xilinx_spips: Add automatic start support Peter Maydell
` (18 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Invalidate the LQSPI cached page when transitioning into LQSPI mode.
Otherwise there is a possibility that the controller will return stale
data to the guest when transitioning back to LQ_MODE after a page
program.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 677490a6ee1953fe5d366e599d665de645ac84db.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 86f33ef..cf4c43e 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -165,6 +165,8 @@ typedef struct {
typedef struct XilinxSPIPSClass {
SysBusDeviceClass parent_class;
+ const MemoryRegionOps *reg_ops;
+
uint32_t rx_fifo_size;
uint32_t tx_fifo_size;
} XilinxSPIPSClass;
@@ -462,6 +464,25 @@ static const MemoryRegionOps spips_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static void xilinx_qspips_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ XilinxQSPIPS *q = XILINX_QSPIPS(opaque);
+
+ xilinx_spips_write(opaque, addr, value, size);
+ addr >>= 2;
+
+ if (addr == R_LQSPI_CFG) {
+ q->lqspi_cached_addr = ~0ULL;
+ }
+}
+
+static const MemoryRegionOps qspips_ops = {
+ .read = xilinx_spips_read,
+ .write = xilinx_qspips_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
#define LQSPI_CACHE_SIZE 1024
static uint64_t
@@ -565,7 +586,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->cs_lines[i]);
}
- memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4);
+ memory_region_init_io(&s->iomem, xsc->reg_ops, s, "spi", R_MAX*4);
sysbus_init_mmio(sbd, &s->iomem);
s->irqline = -1;
@@ -629,6 +650,7 @@ static void xilinx_qspips_class_init(ObjectClass *klass, void * data)
XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
dc->realize = xilinx_qspips_realize;
+ xsc->reg_ops = &qspips_ops;
xsc->rx_fifo_size = RXFF_A_Q;
xsc->tx_fifo_size = TXFF_A_Q;
}
@@ -643,6 +665,7 @@ static void xilinx_spips_class_init(ObjectClass *klass, void *data)
dc->props = xilinx_spips_properties;
dc->vmsd = &vmstate_xilinx_spips;
+ xsc->reg_ops = &spips_ops;
xsc->rx_fifo_size = RXFF_A;
xsc->tx_fifo_size = TXFF_A;
}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 07/24] xilinx_spips: Add automatic start support
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (5 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 06/24] xilinx_spips: Trash LQ page cache on mode change Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 08/24] xilinx_spips: Implement automatic CS Peter Maydell
` (17 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
SPI has a mode where it automatically starts based on tx fifo
occupancy. Implemented.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: f4e9accb5de87b526fff6ed937f63278db76533b.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index cf4c43e..0c04ec9 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -451,7 +451,8 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
}
s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
no_reg_update:
- if (man_start_com) {
+ if ((man_start_com && s->regs[R_CONFIG] & MAN_START_EN) ||
+ (fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG] & MAN_START_EN)) {
xilinx_spips_flush_txfifo(s);
}
xilinx_spips_update_ixr(s);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 08/24] xilinx_spips: Implement automatic CS
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (6 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 07/24] xilinx_spips: Add automatic start support Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 09/24] xilinx_spips: lqspi: Dont touch config register Peter Maydell
` (16 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Implement the automatic CS control feature. If the MANUAL_CS bit is
cleared then the chip select stay de-asserted as long as the tx FIFO
is empty.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 1d67383adc42761af715a93f161344b9284dfc9a.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 0c04ec9..631d010 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -190,6 +190,12 @@ static inline int num_effective_busses(XilinxSPIPS *s)
s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
}
+static inline bool xilinx_spips_cs_is_set(XilinxSPIPS *s, int i, int field)
+{
+ return ~field & (1 << i) && (s->regs[R_CONFIG] & MANUAL_CS
+ || !fifo8_is_empty(&s->tx_fifo));
+}
+
static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
{
int i, j;
@@ -202,14 +208,15 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
int cs_to_set = (j * s->num_cs + i + upage) %
(s->num_cs * s->num_busses);
- if (~field & (1 << i) && !found) {
+ if (xilinx_spips_cs_is_set(s, i, field) && !found) {
DB_PRINT("selecting slave %d\n", i);
qemu_set_irq(s->cs_lines[cs_to_set], 0);
} else {
+ DB_PRINT("deselecting slave %d\n", i);
qemu_set_irq(s->cs_lines[cs_to_set], 1);
}
}
- if (~field & (1 << i)) {
+ if (xilinx_spips_cs_is_set(s, i, field)) {
found = true;
}
}
@@ -451,12 +458,13 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
}
s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
no_reg_update:
+ xilinx_spips_update_cs_lines(s);
if ((man_start_com && s->regs[R_CONFIG] & MAN_START_EN) ||
(fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG] & MAN_START_EN)) {
xilinx_spips_flush_txfifo(s);
}
- xilinx_spips_update_ixr(s);
xilinx_spips_update_cs_lines(s);
+ xilinx_spips_update_ixr(s);
}
static const MemoryRegionOps spips_ops = {
@@ -510,7 +518,7 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
fifo8_reset(&s->rx_fifo);
s->regs[R_CONFIG] &= ~CS;
- s->regs[R_CONFIG] |= (~(1 << slave) << CS_SHIFT) & CS;
+ s->regs[R_CONFIG] |= ((~(1 << slave) << CS_SHIFT) & CS) | MANUAL_CS;
xilinx_spips_update_cs_lines(s);
/* instruction */
@@ -534,6 +542,7 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
DB_PRINT("pushing dummy byte\n");
fifo8_push(&s->tx_fifo, 0);
}
+ xilinx_spips_update_cs_lines(s);
xilinx_spips_flush_txfifo(s);
fifo8_reset(&s->rx_fifo);
@@ -545,6 +554,7 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
rx_data_bytes(s, &q->lqspi_buf[cache_entry], 4);
cache_entry++;
}
+ xilinx_spips_update_cs_lines(s);
s->regs[R_CONFIG] |= CS;
xilinx_spips_update_cs_lines(s);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 09/24] xilinx_spips: lqspi: Dont touch config register
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (7 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 08/24] xilinx_spips: Implement automatic CS Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 10/24] xilinx_spips: Fix CTRL register RW bits Peter Maydell
` (15 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The LQSPI mode is supposed to work via the automatic CS mode feature
rather than manipulate CS lines itself. Now that auto CS is implemented
remove LQSPIs CS mode override logic. There is still a need to
manipulate the U_PAGE bit in LQSPI config register to implement
dual-stack mode however.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 000c8dd54df09523f17052638100722ef0f5a3af.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 631d010..ea8a593 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -511,16 +511,16 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
int flash_addr = (addr / num_effective_busses(s));
int slave = flash_addr >> LQSPI_ADDRESS_BITS;
int cache_entry = 0;
+ uint32_t u_page_save = s->regs[R_LQSPI_STS] & ~LQSPI_CFG_U_PAGE;
+
+ s->regs[R_LQSPI_STS] &= ~LQSPI_CFG_U_PAGE;
+ s->regs[R_LQSPI_STS] |= slave ? LQSPI_CFG_U_PAGE : 0;
DB_PRINT("config reg status: %08x\n", s->regs[R_LQSPI_CFG]);
fifo8_reset(&s->tx_fifo);
fifo8_reset(&s->rx_fifo);
- s->regs[R_CONFIG] &= ~CS;
- s->regs[R_CONFIG] |= ((~(1 << slave) << CS_SHIFT) & CS) | MANUAL_CS;
- xilinx_spips_update_cs_lines(s);
-
/* instruction */
DB_PRINT("pushing read instruction: %02x\n",
(uint8_t)(s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE));
@@ -554,9 +554,9 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
rx_data_bytes(s, &q->lqspi_buf[cache_entry], 4);
cache_entry++;
}
- xilinx_spips_update_cs_lines(s);
- s->regs[R_CONFIG] |= CS;
+ s->regs[R_LQSPI_STS] &= ~LQSPI_CFG_U_PAGE;
+ s->regs[R_LQSPI_STS] |= u_page_save;
xilinx_spips_update_cs_lines(s);
q->lqspi_cached_addr = addr;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 10/24] xilinx_spips: Fix CTRL register RW bits
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (8 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 09/24] xilinx_spips: lqspi: Dont touch config register Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 11/24] xilinx_spips: Fix striping behaviour Peter Maydell
` (14 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The CTRL register was RAZ/WI on some of the RW bits. Even though the
function behind these bits is invalid in QEMU, they should still be
guest accessible. Fix.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: b7aaad93163ce4af0c428635804ac7b77a567b25.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index ea8a593..3e9e76c 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -56,6 +56,7 @@
#define CLK_PH (1 << 2)
#define CLK_POL (1 << 1)
#define MODE_SEL (1 << 0)
+#define R_CONFIG_RSVD (0x7bf40000)
/* interrupt mechanism */
#define R_INTR_STATUS (0x04 / 4)
@@ -355,7 +356,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
addr >>= 2;
switch (addr) {
case R_CONFIG:
- mask = 0x0002FFFF;
+ mask = ~(R_CONFIG_RSVD | MAN_START_COM);
break;
case R_INTR_STATUS:
ret = s->regs[addr] & IXR_ALL;
@@ -415,7 +416,7 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
addr >>= 2;
switch (addr) {
case R_CONFIG:
- mask = 0x0002FFFF;
+ mask = ~(R_CONFIG_RSVD | MAN_START_COM);
if (value & MAN_START_COM) {
man_start_com = 1;
}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 11/24] xilinx_spips: Fix striping behaviour
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (9 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 10/24] xilinx_spips: Fix CTRL register RW bits Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 12/24] xilinx_spips: Debug msgs for Snoop state Peter Maydell
` (13 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The QSPI controller was using byte-wide stripes when striping across
the two flashes in dual parallel mode. The real hardware however uses
individual bit striping. QEMU misbehaves in the (corner) case where
data is written/read in dual-parallel mode and read/written back in
single mode.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 718a61df1bf746ec06f6da44d12f8317af7b08ce.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 84 ++++++++++++++++++++++++++++++++++++-------------
1 file changed, 63 insertions(+), 21 deletions(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 3e9e76c..7222e15 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -273,35 +273,77 @@ static void xilinx_spips_reset(DeviceState *d)
xilinx_spips_update_cs_lines(s);
}
+/* N way (num) in place bit striper. Lay out row wise bits (LSB to MSB)
+ * column wise (from element 0 to N-1). num is the length of x, and dir
+ * reverses the direction of the transform. Best illustrated by example:
+ * Each digit in the below array is a single bit (num == 3):
+ *
+ * {{ 76543210, } ----- stripe (dir == false) -----> {{ FCheb630, }
+ * { hgfedcba, } { GDAfc741, }
+ * { HGFEDCBA, }} <---- upstripe (dir == true) ----- { HEBgda52, }}
+ */
+
+static inline void stripe8(uint8_t *x, int num, bool dir)
+{
+ uint8_t r[num];
+ memset(r, 0, sizeof(uint8_t) * num);
+ int idx[2] = {0, 0};
+ int bit[2] = {0, 0};
+ int d = dir;
+
+ for (idx[0] = 0; idx[0] < num; ++idx[0]) {
+ for (bit[0] = 0; bit[0] < 8; ++bit[0]) {
+ r[idx[d]] |= x[idx[!d]] & 1 << bit[!d] ? 1 << bit[d] : 0;
+ idx[1] = (idx[1] + 1) % num;
+ if (!idx[1]) {
+ bit[1]++;
+ }
+ }
+ }
+ memcpy(x, r, sizeof(uint8_t) * num);
+}
+
static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
{
for (;;) {
int i;
- uint8_t rx;
uint8_t tx = 0;
+ uint8_t tx_rx[num_effective_busses(s)];
- for (i = 0; i < num_effective_busses(s); ++i) {
- if (!i || s->snoop_state == SNOOP_STRIPING) {
- if (fifo8_is_empty(&s->tx_fifo)) {
- if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
- s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
- }
- xilinx_spips_update_ixr(s);
- return;
- } else {
- tx = fifo8_pop(&s->tx_fifo);
- }
+ if (fifo8_is_empty(&s->tx_fifo)) {
+ if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) {
+ s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
}
- rx = ssi_transfer(s->spi[i], (uint32_t)tx);
- DB_PRINT("tx = %02x rx = %02x\n", tx, rx);
- if (!i || s->snoop_state == SNOOP_STRIPING) {
- if (fifo8_is_full(&s->rx_fifo)) {
- s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
- DB_PRINT("rx FIFO overflow");
- } else {
- fifo8_push(&s->rx_fifo, (uint8_t)rx);
- }
+ xilinx_spips_update_ixr(s);
+ return;
+ } else if (s->snoop_state == SNOOP_STRIPING) {
+ for (i = 0; i < num_effective_busses(s); ++i) {
+ tx_rx[i] = fifo8_pop(&s->tx_fifo);
}
+ stripe8(tx_rx, num_effective_busses(s), false);
+ } else {
+ tx = fifo8_pop(&s->tx_fifo);
+ for (i = 0; i < num_effective_busses(s); ++i) {
+ tx_rx[i] = tx;
+ }
+ }
+
+ for (i = 0; i < num_effective_busses(s); ++i) {
+ DB_PRINT("tx = %02x\n", tx_rx[i]);
+ tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]);
+ DB_PRINT("rx = %02x\n", tx_rx[i]);
+ }
+
+ if (fifo8_is_full(&s->rx_fifo)) {
+ s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
+ DB_PRINT("rx FIFO overflow");
+ } else if (s->snoop_state == SNOOP_STRIPING) {
+ stripe8(tx_rx, num_effective_busses(s), true);
+ for (i = 0; i < num_effective_busses(s); ++i) {
+ fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]);
+ }
+ } else {
+ fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]);
}
switch (s->snoop_state) {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 12/24] xilinx_spips: Debug msgs for Snoop state
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (10 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 11/24] xilinx_spips: Fix striping behaviour Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 13/24] xilinx_spips: Multiple debug verbosity levels Peter Maydell
` (12 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
This is worth keeping track of when debugging the device model.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: d3b44ecf23d671798b062eee5dc362c716ea54cd.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 7222e15..8fbbd24 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -223,6 +223,7 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
}
if (!found) {
s->snoop_state = SNOOP_CHECKING;
+ DB_PRINT("moving to snoop check state\n");
}
}
@@ -346,6 +347,7 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]);
}
+ DB_PRINT("initial snoop state: %x\n", (unsigned)s->snoop_state);
switch (s->snoop_state) {
case (SNOOP_CHECKING):
switch (tx) { /* new instruction code */
@@ -374,6 +376,7 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
default:
s->snoop_state--;
}
+ DB_PRINT("final snoop state: %x\n", (unsigned)s->snoop_state);
}
}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 13/24] xilinx_spips: Multiple debug verbosity levels
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (11 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 12/24] xilinx_spips: Debug msgs for Snoop state Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 14/24] xilinx_spips: lqspi: Push more data to tx-fifo Peter Maydell
` (11 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The debug printfs on every SPI operation is extremely verbose. Add
a second level of debug for this.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: f63478b8e5b29cc011cdc10e29f8537bb2fc2b5e.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 70 +++++++++++++++++++++++++++++--------------------
1 file changed, 42 insertions(+), 28 deletions(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 8fbbd24..665f471 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -30,15 +30,17 @@
#include "hw/ssi.h"
#include "qemu/bitops.h"
-#ifdef XILINX_SPIPS_ERR_DEBUG
-#define DB_PRINT(...) do { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } while (0);
-#else
- #define DB_PRINT(...)
+#ifndef XILINX_SPIPS_ERR_DEBUG
+#define XILINX_SPIPS_ERR_DEBUG 0
#endif
+#define DB_PRINT_L(level, ...) do { \
+ if (XILINX_SPIPS_ERR_DEBUG > (level)) { \
+ fprintf(stderr, ": %s: ", __func__); \
+ fprintf(stderr, ## __VA_ARGS__); \
+ } \
+} while (0);
+
/* config register */
#define R_CONFIG (0x00 / 4)
#define IFMODE (1 << 31)
@@ -210,10 +212,10 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
(s->num_cs * s->num_busses);
if (xilinx_spips_cs_is_set(s, i, field) && !found) {
- DB_PRINT("selecting slave %d\n", i);
+ DB_PRINT_L(0, "selecting slave %d\n", i);
qemu_set_irq(s->cs_lines[cs_to_set], 0);
} else {
- DB_PRINT("deselecting slave %d\n", i);
+ DB_PRINT_L(0, "deselecting slave %d\n", i);
qemu_set_irq(s->cs_lines[cs_to_set], 1);
}
}
@@ -223,7 +225,7 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
}
if (!found) {
s->snoop_state = SNOOP_CHECKING;
- DB_PRINT("moving to snoop check state\n");
+ DB_PRINT_L(1, "moving to snoop check state\n");
}
}
@@ -306,6 +308,8 @@ static inline void stripe8(uint8_t *x, int num, bool dir)
static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
{
+ int debug_level = 0;
+
for (;;) {
int i;
uint8_t tx = 0;
@@ -330,14 +334,14 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
}
for (i = 0; i < num_effective_busses(s); ++i) {
- DB_PRINT("tx = %02x\n", tx_rx[i]);
+ DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]);
- DB_PRINT("rx = %02x\n", tx_rx[i]);
+ DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
}
if (fifo8_is_full(&s->rx_fifo)) {
s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
- DB_PRINT("rx FIFO overflow");
+ DB_PRINT_L(0, "rx FIFO overflow");
} else if (s->snoop_state == SNOOP_STRIPING) {
stripe8(tx_rx, num_effective_busses(s), true);
for (i = 0; i < num_effective_busses(s); ++i) {
@@ -347,7 +351,8 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]);
}
- DB_PRINT("initial snoop state: %x\n", (unsigned)s->snoop_state);
+ DB_PRINT_L(debug_level, "initial snoop state: %x\n",
+ (unsigned)s->snoop_state);
switch (s->snoop_state) {
case (SNOOP_CHECKING):
switch (tx) { /* new instruction code */
@@ -372,11 +377,17 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
break;
case (SNOOP_STRIPING):
case (SNOOP_NONE):
+ /* Once we hit the boring stuff - squelch debug noise */
+ if (!debug_level) {
+ DB_PRINT_L(0, "squelching debug info ....\n");
+ debug_level = 1;
+ }
break;
default:
s->snoop_state--;
}
- DB_PRINT("final snoop state: %x\n", (unsigned)s->snoop_state);
+ DB_PRINT_L(debug_level, "final snoop state: %x\n",
+ (unsigned)s->snoop_state);
}
}
@@ -406,7 +417,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
case R_INTR_STATUS:
ret = s->regs[addr] & IXR_ALL;
s->regs[addr] = 0;
- DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+ DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
return ret;
case R_INTR_MASK:
mask = IXR_ALL;
@@ -427,11 +438,12 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
break;
case R_RX_DATA:
rx_data_bytes(s, &ret, s->num_txrx_bytes);
- DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+ DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
xilinx_spips_update_ixr(s);
return ret;
}
- DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask);
+ DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4,
+ s->regs[addr] & mask);
return s->regs[addr] & mask;
}
@@ -457,7 +469,7 @@ static void xilinx_spips_write(void *opaque, hwaddr addr,
int man_start_com = 0;
XilinxSPIPS *s = opaque;
- DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
+ DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
addr >>= 2;
switch (addr) {
case R_CONFIG:
@@ -551,7 +563,8 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
if (addr >= q->lqspi_cached_addr &&
addr <= q->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
ret = q->lqspi_buf[(addr - q->lqspi_cached_addr) >> 2];
- DB_PRINT("addr: %08x, data: %08x\n", (unsigned)addr, (unsigned)ret);
+ DB_PRINT_L(1, "addr: %08x, data: %08x\n", (unsigned)addr,
+ (unsigned)ret);
return ret;
} else {
int flash_addr = (addr / num_effective_busses(s));
@@ -562,17 +575,18 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
s->regs[R_LQSPI_STS] &= ~LQSPI_CFG_U_PAGE;
s->regs[R_LQSPI_STS] |= slave ? LQSPI_CFG_U_PAGE : 0;
- DB_PRINT("config reg status: %08x\n", s->regs[R_LQSPI_CFG]);
+ DB_PRINT_L(0, "config reg status: %08x\n", s->regs[R_LQSPI_CFG]);
fifo8_reset(&s->tx_fifo);
fifo8_reset(&s->rx_fifo);
/* instruction */
- DB_PRINT("pushing read instruction: %02x\n",
- (uint8_t)(s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE));
+ DB_PRINT_L(0, "pushing read instruction: %02x\n",
+ (unsigned)(uint8_t)(s->regs[R_LQSPI_CFG] &
+ LQSPI_CFG_INST_CODE));
fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
/* read address */
- DB_PRINT("pushing read address %06x\n", flash_addr);
+ DB_PRINT_L(0, "pushing read address %06x\n", flash_addr);
fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16));
fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
@@ -585,14 +599,14 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
/* dummy bytes */
for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT,
LQSPI_CFG_DUMMY_WIDTH)); ++i) {
- DB_PRINT("pushing dummy byte\n");
+ DB_PRINT_L(0, "pushing dummy byte\n");
fifo8_push(&s->tx_fifo, 0);
}
xilinx_spips_update_cs_lines(s);
xilinx_spips_flush_txfifo(s);
fifo8_reset(&s->rx_fifo);
- DB_PRINT("starting QSPI data read\n");
+ DB_PRINT_L(0, "starting QSPI data read\n");
for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) {
tx_data_bytes(s, 0, 4);
@@ -626,7 +640,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s);
int i;
- DB_PRINT("realized spips\n");
+ DB_PRINT_L(0, "realized spips\n");
s->spi = g_new(SSIBus *, s->num_busses);
for (i = 0; i < s->num_busses; ++i) {
@@ -658,7 +672,7 @@ static void xilinx_qspips_realize(DeviceState *dev, Error **errp)
XilinxQSPIPS *q = XILINX_QSPIPS(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- DB_PRINT("realized qspips\n");
+ DB_PRINT_L(0, "realized qspips\n");
s->num_busses = 2;
s->num_cs = 2;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 14/24] xilinx_spips: lqspi: Push more data to tx-fifo
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (12 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 13/24] xilinx_spips: Multiple debug verbosity levels Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 15/24] xilinx_spips: lqspi: Fix byte/misaligned access Peter Maydell
` (10 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Do 16 words per fifo flush. Increases performance and decreases
debug verbosity. This data depth has no real hardware analogue,
so just go with something that has reasonable performance.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 5621ee4621941d3639b5cacfdec26bd3148f31d5.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 665f471..e975a87 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -608,11 +608,14 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
DB_PRINT_L(0, "starting QSPI data read\n");
- for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) {
- tx_data_bytes(s, 0, 4);
+ while (cache_entry < LQSPI_CACHE_SIZE / 4) {
+ for (i = 0; i < 16; ++i) {
+ tx_data_bytes(s, 0, 4);
+ }
xilinx_spips_flush_txfifo(s);
- rx_data_bytes(s, &q->lqspi_buf[cache_entry], 4);
- cache_entry++;
+ for (i = 0; i < 16; ++i) {
+ rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 4);
+ }
}
s->regs[R_LQSPI_STS] &= ~LQSPI_CFG_U_PAGE;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 15/24] xilinx_spips: lqspi: Fix byte/misaligned access
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (13 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 14/24] xilinx_spips: lqspi: Push more data to tx-fifo Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 16/24] sd/sdhci.c: Only reset data_count on new commands Peter Maydell
` (9 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The LQSPI bus attachment supports byte/halfword and misaligned
accesses. Fixed. Refactored the LQSPI cache to be byte-wise
instead of word wise accordingly.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Message-id: 5ec47b13563ad2d22105a1f26186d7756718394b.1369117359.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/ssi/xilinx_spips.c | 31 +++++++++++++++++--------------
1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index e975a87..05a3ada 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -161,7 +161,7 @@ typedef struct {
typedef struct {
XilinxSPIPS parent_obj;
- uint32_t lqspi_buf[LQSPI_CACHE_SIZE];
+ uint8_t lqspi_buf[LQSPI_CACHE_SIZE];
hwaddr lqspi_cached_addr;
} XilinxQSPIPS;
@@ -391,14 +391,12 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
}
}
-static inline void rx_data_bytes(XilinxSPIPS *s, uint32_t *value, int max)
+static inline void rx_data_bytes(XilinxSPIPS *s, uint8_t *value, int max)
{
int i;
- *value = 0;
for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) {
- uint32_t next = fifo8_pop(&s->rx_fifo) & 0xFF;
- *value |= next << 8 * (s->regs[R_CONFIG] & ENDIAN ? 3-i : i);
+ value[i] = fifo8_pop(&s->rx_fifo);
}
}
@@ -408,6 +406,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
XilinxSPIPS *s = opaque;
uint32_t mask = ~0;
uint32_t ret;
+ uint8_t rx_buf[4];
addr >>= 2;
switch (addr) {
@@ -437,7 +436,10 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
mask = 0;
break;
case R_RX_DATA:
- rx_data_bytes(s, &ret, s->num_txrx_bytes);
+ memset(rx_buf, 0, sizeof(rx_buf));
+ rx_data_bytes(s, rx_buf, s->num_txrx_bytes);
+ ret = s->regs[R_CONFIG] & ENDIAN ? cpu_to_be32(*(uint32_t *)rx_buf)
+ : cpu_to_le32(*(uint32_t *)rx_buf);
DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
xilinx_spips_update_ixr(s);
return ret;
@@ -562,7 +564,8 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
if (addr >= q->lqspi_cached_addr &&
addr <= q->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
- ret = q->lqspi_buf[(addr - q->lqspi_cached_addr) >> 2];
+ uint8_t *retp = &q->lqspi_buf[addr - q->lqspi_cached_addr];
+ ret = cpu_to_le32(*(uint32_t *)retp);
DB_PRINT_L(1, "addr: %08x, data: %08x\n", (unsigned)addr,
(unsigned)ret);
return ret;
@@ -608,13 +611,13 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
DB_PRINT_L(0, "starting QSPI data read\n");
- while (cache_entry < LQSPI_CACHE_SIZE / 4) {
- for (i = 0; i < 16; ++i) {
- tx_data_bytes(s, 0, 4);
+ while (cache_entry < LQSPI_CACHE_SIZE) {
+ for (i = 0; i < 64; ++i) {
+ tx_data_bytes(s, 0, 1);
}
xilinx_spips_flush_txfifo(s);
- for (i = 0; i < 16; ++i) {
- rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 4);
+ for (i = 0; i < 64; ++i) {
+ rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 1);
}
}
@@ -622,7 +625,7 @@ lqspi_read(void *opaque, hwaddr addr, unsigned int size)
s->regs[R_LQSPI_STS] |= u_page_save;
xilinx_spips_update_cs_lines(s);
- q->lqspi_cached_addr = addr;
+ q->lqspi_cached_addr = flash_addr * num_effective_busses(s);
return lqspi_read(opaque, addr, size);
}
}
@@ -631,7 +634,7 @@ static const MemoryRegionOps lqspi_ops = {
.read = lqspi_read,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = {
- .min_access_size = 4,
+ .min_access_size = 1,
.max_access_size = 4
}
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 16/24] sd/sdhci.c: Only reset data_count on new commands
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (14 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 15/24] xilinx_spips: lqspi: Fix byte/misaligned access Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 17/24] sd/sdhci: Fix Buffer Write Ready interrupt Peter Maydell
` (8 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The data_count variable was being reset on every transfer, including
DMA transfer resumptions. This is incorrect, it should only be set
on a new command.
Manifests as a bug when using ADMA and there is a timer delay between
ADMA frames where the fifo is left in a non empty state.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Igor Mitsyanko <i.mitsyanko@gmail.com>
Message-id: 15a98609cc32315211b0963091a8efd67522e160.1369370934.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/sd/sdhci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 91dc9b0..0a84540 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -260,6 +260,7 @@ static void sdhci_send_command(SDHCIState *s)
sdhci_update_irq(s);
if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) {
+ s->data_count = 0;
sdhci_do_data_transfer(s);
}
}
@@ -773,7 +774,6 @@ static void sdhci_do_adma(SDHCIState *s)
static void sdhci_data_transfer(SDHCIState *s)
{
SDHCIClass *k = SDHCI_GET_CLASS(s);
- s->data_count = 0;
if (s->trnmod & SDHC_TRNS_DMA) {
switch (SDHC_DMA_TYPE(s->hostctl)) {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 17/24] sd/sdhci: Fix Buffer Write Ready interrupt
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (15 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 16/24] sd/sdhci.c: Only reset data_count on new commands Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 18/24] sd/sdhci.c: Fix bdata_read DPRINT message Peter Maydell
` (7 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
This interrupt is not risen after the last block is written to sd. It
is mutually exclusive with the end of transfer conditions. Fix.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Igor Mitsyanko <i.mitsyanko@gmail.com>
Message-id: 7ca9fd3e03ce1bec94aff08f607c15a0ec3d3371.1369370934.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/sd/sdhci.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 0a84540..ea510b5 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -405,15 +405,14 @@ static void sdhci_write_block_to_card(SDHCIState *s)
/* Next data can be written through BUFFER DATORT register */
s->prnsts |= SDHC_SPACE_AVAILABLE;
- if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
- s->norintsts |= SDHC_NIS_WBUFRDY;
- }
/* Finish transfer if that was the last block of data */
if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
((s->trnmod & SDHC_TRNS_MULTI) &&
(s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0))) {
SDHCI_GET_CLASS(s)->end_data_transfer(s);
+ } else if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
+ s->norintsts |= SDHC_NIS_WBUFRDY;
}
/* Generate Block Gap Event if requested and if not the last block */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 18/24] sd/sdhci.c: Fix bdata_read DPRINT message
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (16 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 17/24] sd/sdhci: Fix Buffer Write Ready interrupt Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 19/24] sd/sdhci:ADMA: fix interrupt Peter Maydell
` (6 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
This message was printing out the data in decimal only, which is not
very friendly to the debugging developer. Add hex variant in
parenthesis to make it consistent with other similar messages in this
module.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Igor Mitsyanko <i.mitsyanko@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: d624179649137832eaa8caa263ef9589b4395d5e.1369370934.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/sd/sdhci.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index ea510b5..15345dc 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -880,7 +880,8 @@ static uint32_t sdhci_read(SDHCIState *s, unsigned int offset, unsigned size)
case SDHC_BDATA:
if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) {
ret = SDHCI_GET_CLASS(s)->bdata_read(s, size);
- DPRINT_L2("read %ub: addr[0x%04x] -> %u\n", size, offset, ret);
+ DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, offset,
+ ret, ret);
return ret;
}
break;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 19/24] sd/sdhci:ADMA: fix interrupt
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (17 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 18/24] sd/sdhci.c: Fix bdata_read DPRINT message Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 20/24] sd/sd.c: Fix "inquiry" ACMD41 Peter Maydell
` (5 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The end of transfer check was occurring and potentially returning before
the interrupt flag was checked. This means the interrupt will be missed
if it occurs on the last packet. Fix by checking for the interrupt
before checking for the end of transfer.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Igor Mitsyanko <i.mitsyanko@gmail.com>
Message-id: 9969ec154777957ec738fc4e539d68e7494d0081.1369370934.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/sd/sdhci.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 15345dc..e64899c 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -730,6 +730,15 @@ static void sdhci_do_adma(SDHCIState *s)
break;
}
+ if (dscr.attr & SDHC_ADMA_ATTR_INT) {
+ DPRINT_L1("ADMA interrupt: admasysaddr=0x%lx\n", s->admasysaddr);
+ if (s->norintstsen & SDHC_NISEN_DMA) {
+ s->norintsts |= SDHC_NIS_DMA;
+ }
+
+ sdhci_update_irq(s);
+ }
+
/* ADMA transfer terminates if blkcnt == 0 or by END attribute */
if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
(s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) {
@@ -752,15 +761,6 @@ static void sdhci_do_adma(SDHCIState *s)
return;
}
- if (dscr.attr & SDHC_ADMA_ATTR_INT) {
- DPRINT_L1("ADMA interrupt: admasysaddr=0x%lx\n", s->admasysaddr);
- if (s->norintstsen & SDHC_NISEN_DMA) {
- s->norintsts |= SDHC_NIS_DMA;
- }
-
- sdhci_update_irq(s);
- return;
- }
}
/* we have unfinished business - reschedule to continue ADMA */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 20/24] sd/sd.c: Fix "inquiry" ACMD41
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (18 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 19/24] sd/sdhci:ADMA: fix interrupt Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 21/24] i.MX: split GPT and EPIT timer implementation Peter Maydell
` (4 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
QEMU models two (of the three) ACMD41 has two modes, "inquiry" and
"first". The selection logic for which of the two is incorrect - it
compares != 0 for the entire argument value rather than only bits 23:0
as per the spec. Fix.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 3ef0a7fd1b2f3ebb23b4fdeabcc14caf3fad6d71.1369622254.git.peter.crosthwaite@xilinx.com
Reviewed-by: Igor Mitsyanko <i.mitsyanko@gmail.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/sd/sd.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 2e0ef3e..346d86f 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -43,6 +43,8 @@ do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0)
#define DPRINTF(fmt, ...) do {} while(0)
#endif
+#define ACMD41_ENQUIRY_MASK 0x00ffffff
+
typedef enum {
sd_r0 = 0, /* no response */
sd_r1, /* normal response command */
@@ -1277,9 +1279,14 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
}
switch (sd->state) {
case sd_idle_state:
- /* We accept any voltage. 10000 V is nothing. */
- if (req.arg)
+ /* We accept any voltage. 10000 V is nothing.
+ *
+ * We don't model init delay so just advance straight to ready state
+ * unless it's an enquiry ACMD41 (bits 23:0 == 0).
+ */
+ if (req.arg & ACMD41_ENQUIRY_MASK) {
sd->state = sd_ready_state;
+ }
return sd_r3;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 21/24] i.MX: split GPT and EPIT timer implementation
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (19 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 20/24] sd/sd.c: Fix "inquiry" ACMD41 Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 22/24] hw/arm/exynos4210.c: convert chipid_and_omr to an mmio region Peter Maydell
` (3 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Jean-Christophe DUBOIS <jcd@tribudubois.net>
There is no common code between these 2 timer implementation.
So it is better to split them.
Signed-off-by: Jean-Christophe DUBOIS <jcd@tribudubois.net>
Message-id: 1368990197-19694-1-git-send-email-jcd@tribudubois.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/timer/Makefile.objs | 3 +-
hw/timer/imx_epit.c | 404 ++++++++++++++++++++++++
hw/timer/imx_gpt.c | 465 +++++++++++++++++++++++++++
hw/timer/imx_timer.c | 823 ------------------------------------------------
4 files changed, 871 insertions(+), 824 deletions(-)
create mode 100644 hw/timer/imx_epit.c
create mode 100644 hw/timer/imx_gpt.c
delete mode 100644 hw/timer/imx_timer.c
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index e4bd17f..32b5c1a 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -11,7 +11,8 @@ common-obj-$(CONFIG_XILINX) += xilinx_timer.o
common-obj-$(CONFIG_SLAVIO) += slavio_timer.o
common-obj-$(CONFIG_ETRAXFS) += etraxfs_timer.o
common-obj-$(CONFIG_GRLIB) += grlib_gptimer.o
-common-obj-$(CONFIG_IMX) += imx_timer.o
+common-obj-$(CONFIG_IMX) += imx_epit.o
+common-obj-$(CONFIG_IMX) += imx_gpt.o
common-obj-$(CONFIG_LM32) += lm32_timer.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
new file mode 100644
index 0000000..451e646
--- /dev/null
+++ b/hw/timer/imx_epit.c
@@ -0,0 +1,404 @@
+/*
+ * IMX EPIT Timer
+ *
+ * Copyright (c) 2008 OK Labs
+ * Copyright (c) 2011 NICTA Pty Ltd
+ * Originally written by Hans Jiang
+ * Updated by Peter Chubb
+ *
+ * This code is licensed under GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/hw.h"
+#include "qemu/bitops.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "hw/sysbus.h"
+#include "hw/arm/imx.h"
+
+//#define DEBUG_TIMER 1
+#ifdef DEBUG_TIMER
+# define DPRINTF(fmt, args...) \
+ do { printf("imx_timer: " fmt , ##args); } while (0)
+#else
+# define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+# define IPRINTF(fmt, args...) \
+ do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
+#else
+# define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * EPIT: Enhanced periodic interrupt timer
+ */
+
+#define CR_EN (1 << 0)
+#define CR_ENMOD (1 << 1)
+#define CR_OCIEN (1 << 2)
+#define CR_RLD (1 << 3)
+#define CR_PRESCALE_SHIFT (4)
+#define CR_PRESCALE_MASK (0xfff)
+#define CR_SWR (1 << 16)
+#define CR_IOVW (1 << 17)
+#define CR_DBGEN (1 << 18)
+#define CR_WAITEN (1 << 19)
+#define CR_DOZEN (1 << 20)
+#define CR_STOPEN (1 << 21)
+#define CR_CLKSRC_SHIFT (24)
+#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
+
+#define TIMER_MAX 0XFFFFFFFFUL
+
+/*
+ * Exact clock frequencies vary from board to board.
+ * These are typical.
+ */
+static const IMXClk imx_timerp_clocks[] = {
+ 0, /* 00 disabled */
+ IPG, /* 01 ipg_clk, ~532MHz */
+ IPG, /* 10 ipg_clk_highfreq */
+ CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */
+};
+
+typedef struct {
+ SysBusDevice busdev;
+ ptimer_state *timer_reload;
+ ptimer_state *timer_cmp;
+ MemoryRegion iomem;
+ DeviceState *ccm;
+
+ uint32_t cr;
+ uint32_t sr;
+ uint32_t lr;
+ uint32_t cmp;
+ uint32_t cnt;
+
+ uint32_t freq;
+ qemu_irq irq;
+} IMXTimerPState;
+
+/*
+ * Update interrupt status
+ */
+static void imx_timerp_update(IMXTimerPState *s)
+{
+ if (s->sr && (s->cr & CR_OCIEN)) {
+ qemu_irq_raise(s->irq);
+ } else {
+ qemu_irq_lower(s->irq);
+ }
+}
+
+static void set_timerp_freq(IMXTimerPState *s)
+{
+ unsigned clksrc;
+ unsigned prescaler;
+ uint32_t freq;
+
+ clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
+ prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
+
+ freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
+
+ s->freq = freq;
+ DPRINTF("Setting ptimer frequency to %u\n", freq);
+
+ if (freq) {
+ ptimer_set_freq(s->timer_reload, freq);
+ ptimer_set_freq(s->timer_cmp, freq);
+ }
+}
+
+static void imx_timerp_reset(DeviceState *dev)
+{
+ IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev);
+
+ /*
+ * Soft reset doesn't touch some bits; hard reset clears them
+ */
+ s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
+ s->sr = 0;
+ s->lr = TIMER_MAX;
+ s->cmp = 0;
+ s->cnt = 0;
+ /* stop both timers */
+ ptimer_stop(s->timer_cmp);
+ ptimer_stop(s->timer_reload);
+ /* compute new frequency */
+ set_timerp_freq(s);
+ /* init both timers to TIMER_MAX */
+ ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
+ ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
+ if (s->freq && (s->cr & CR_EN)) {
+ /* if the timer is still enabled, restart it */
+ ptimer_run(s->timer_reload, 1);
+ }
+}
+
+static uint32_t imx_timerp_update_counts(IMXTimerPState *s)
+{
+ s->cnt = ptimer_get_count(s->timer_reload);
+
+ return s->cnt;
+}
+
+static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ IMXTimerPState *s = (IMXTimerPState *)opaque;
+
+ DPRINTF("p-read(offset=%x)", (unsigned int)(offset >> 2));
+ switch (offset >> 2) {
+ case 0: /* Control Register */
+ DPRINTF("cr %x\n", s->cr);
+ return s->cr;
+
+ case 1: /* Status Register */
+ DPRINTF("sr %x\n", s->sr);
+ return s->sr;
+
+ case 2: /* LR - ticks*/
+ DPRINTF("lr %x\n", s->lr);
+ return s->lr;
+
+ case 3: /* CMP */
+ DPRINTF("cmp %x\n", s->cmp);
+ return s->cmp;
+
+ case 4: /* CNT */
+ imx_timerp_update_counts(s);
+ DPRINTF(" cnt = %x\n", s->cnt);
+ return s->cnt;
+ }
+
+ IPRINTF("imx_timerp_read: Bad offset %x\n",
+ (int)offset >> 2);
+ return 0;
+}
+
+static void imx_reload_compare_timer(IMXTimerPState *s)
+{
+ if ((s->cr & CR_OCIEN) && s->cmp) {
+ /* if the compare feature is on */
+ uint32_t tmp = imx_timerp_update_counts(s);
+ if (tmp > s->cmp) {
+ /* reinit the cmp timer if required */
+ ptimer_set_count(s->timer_cmp, tmp - s->cmp);
+ if ((s->cr & CR_EN)) {
+ /* Restart the cmp timer if required */
+ ptimer_run(s->timer_cmp, 0);
+ }
+ }
+ }
+}
+
+static void imx_timerp_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IMXTimerPState *s = (IMXTimerPState *)opaque;
+ DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
+ (unsigned int)value);
+
+ switch (offset >> 2) {
+ case 0: /* CR */
+ s->cr = value & 0x03ffffff;
+ if (s->cr & CR_SWR) {
+ /* handle the reset */
+ imx_timerp_reset(&s->busdev.qdev);
+ } else {
+ set_timerp_freq(s);
+ }
+
+ if (s->freq && (s->cr & CR_EN)) {
+ if (s->cr & CR_ENMOD) {
+ if (s->cr & CR_RLD) {
+ ptimer_set_limit(s->timer_reload, s->lr, 1);
+ } else {
+ ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
+ }
+ }
+
+ imx_reload_compare_timer(s);
+
+ ptimer_run(s->timer_reload, 1);
+ } else {
+ /* stop both timers */
+ ptimer_stop(s->timer_reload);
+ ptimer_stop(s->timer_cmp);
+ }
+ break;
+
+ case 1: /* SR - ACK*/
+ /* writing 1 to OCIF clear the OCIF bit */
+ if (value & 0x01) {
+ s->sr = 0;
+ imx_timerp_update(s);
+ }
+ break;
+
+ case 2: /* LR - set ticks */
+ s->lr = value;
+
+ if (s->cr & CR_RLD) {
+ /* Also set the limit if the LRD bit is set */
+ /* If IOVW bit is set then set the timer value */
+ ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
+ } else if (s->cr & CR_IOVW) {
+ /* If IOVW bit is set then set the timer value */
+ ptimer_set_count(s->timer_reload, s->lr);
+ }
+
+ imx_reload_compare_timer(s);
+
+ break;
+
+ case 3: /* CMP */
+ s->cmp = value;
+
+ imx_reload_compare_timer(s);
+
+ break;
+
+ default:
+ IPRINTF("imx_timerp_write: Bad offset %x\n",
+ (int)offset >> 2);
+ }
+}
+
+static void imx_timerp_reload(void *opaque)
+{
+ IMXTimerPState *s = (IMXTimerPState *)opaque;
+
+ DPRINTF("imxp reload\n");
+
+ if (!(s->cr & CR_EN)) {
+ return;
+ }
+
+ if (s->cr & CR_RLD) {
+ ptimer_set_limit(s->timer_reload, s->lr, 1);
+ } else {
+ ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
+ }
+
+ if (s->cr & CR_OCIEN) {
+ /* if compare register is 0 then we handle the interrupt here */
+ if (s->cmp == 0) {
+ s->sr = 1;
+ imx_timerp_update(s);
+ } else if (s->cmp <= s->lr) {
+ /* We should launch the compare register */
+ ptimer_set_count(s->timer_cmp, s->lr - s->cmp);
+ ptimer_run(s->timer_cmp, 0);
+ } else {
+ IPRINTF("imxp reload: s->lr < s->cmp\n");
+ }
+ }
+}
+
+static void imx_timerp_cmp(void *opaque)
+{
+ IMXTimerPState *s = (IMXTimerPState *)opaque;
+
+ DPRINTF("imxp compare\n");
+
+ ptimer_stop(s->timer_cmp);
+
+ /* compare register is not 0 */
+ if (s->cmp) {
+ s->sr = 1;
+ imx_timerp_update(s);
+ }
+}
+
+void imx_timerp_create(const hwaddr addr,
+ qemu_irq irq,
+ DeviceState *ccm)
+{
+ IMXTimerPState *pp;
+ DeviceState *dev;
+
+ dev = sysbus_create_simple("imx_timerp", addr, irq);
+ pp = container_of(dev, IMXTimerPState, busdev.qdev);
+ pp->ccm = ccm;
+}
+
+static const MemoryRegionOps imx_timerp_ops = {
+ .read = imx_timerp_read,
+ .write = imx_timerp_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_imx_timerp = {
+ .name = "imx-timerp",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(cr, IMXTimerPState),
+ VMSTATE_UINT32(sr, IMXTimerPState),
+ VMSTATE_UINT32(lr, IMXTimerPState),
+ VMSTATE_UINT32(cmp, IMXTimerPState),
+ VMSTATE_UINT32(cnt, IMXTimerPState),
+ VMSTATE_UINT32(freq, IMXTimerPState),
+ VMSTATE_PTIMER(timer_reload, IMXTimerPState),
+ VMSTATE_PTIMER(timer_cmp, IMXTimerPState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int imx_timerp_init(SysBusDevice *dev)
+{
+ IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev);
+ QEMUBH *bh;
+
+ DPRINTF("imx_timerp_init\n");
+ sysbus_init_irq(dev, &s->irq);
+ memory_region_init_io(&s->iomem, &imx_timerp_ops,
+ s, "imxp-timer",
+ 0x00001000);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ bh = qemu_bh_new(imx_timerp_reload, s);
+ s->timer_reload = ptimer_init(bh);
+
+ bh = qemu_bh_new(imx_timerp_cmp, s);
+ s->timer_cmp = ptimer_init(bh);
+
+ return 0;
+}
+
+
+static void imx_timerp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ k->init = imx_timerp_init;
+ dc->vmsd = &vmstate_imx_timerp;
+ dc->reset = imx_timerp_reset;
+ dc->desc = "i.MX periodic timer";
+}
+
+static const TypeInfo imx_timerp_info = {
+ .name = "imx_timerp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXTimerPState),
+ .class_init = imx_timerp_class_init,
+};
+
+static void imx_timer_register_types(void)
+{
+ type_register_static(&imx_timerp_info);
+}
+
+type_init(imx_timer_register_types)
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
new file mode 100644
index 0000000..d8c4f0b
--- /dev/null
+++ b/hw/timer/imx_gpt.c
@@ -0,0 +1,465 @@
+/*
+ * IMX GPT Timer
+ *
+ * Copyright (c) 2008 OK Labs
+ * Copyright (c) 2011 NICTA Pty Ltd
+ * Originally written by Hans Jiang
+ * Updated by Peter Chubb
+ *
+ * This code is licensed under GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/hw.h"
+#include "qemu/bitops.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "hw/sysbus.h"
+#include "hw/arm/imx.h"
+
+//#define DEBUG_TIMER 1
+#ifdef DEBUG_TIMER
+# define DPRINTF(fmt, args...) \
+ do { printf("imx_timer: " fmt , ##args); } while (0)
+#else
+# define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+# define IPRINTF(fmt, args...) \
+ do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
+#else
+# define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * GPT : General purpose timer
+ *
+ * This timer counts up continuously while it is enabled, resetting itself
+ * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
+ * reaches the value of ocr1 (in periodic mode). WE simulate this using a
+ * QEMU ptimer counting down from ocr1 and reloading from ocr1 in
+ * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1.
+ * waiting_rov is set when counting from TIMER_MAX.
+ *
+ * In the real hardware, there are three comparison registers that can
+ * trigger interrupts, and compare channel 1 can be used to
+ * force-reset the timer. However, this is a `bare-bones'
+ * implementation: only what Linux 3.x uses has been implemented
+ * (free-running timer from 0 to OCR1 or TIMER_MAX) .
+ */
+
+#define TIMER_MAX 0XFFFFFFFFUL
+
+/* Control register. Not all of these bits have any effect (yet) */
+#define GPT_CR_EN (1 << 0) /* GPT Enable */
+#define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */
+#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */
+#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */
+#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */
+#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */
+#define GPT_CR_CLKSRC_SHIFT (6)
+#define GPT_CR_CLKSRC_MASK (0x7)
+
+#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */
+#define GPT_CR_SWR (1 << 15) /* Software Reset */
+#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */
+#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */
+#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
+#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
+#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
+#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */
+#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */
+#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */
+
+#define GPT_SR_OF1 (1 << 0)
+#define GPT_SR_ROV (1 << 5)
+
+#define GPT_IR_OF1IE (1 << 0)
+#define GPT_IR_ROVIE (1 << 5)
+
+typedef struct {
+ SysBusDevice busdev;
+ ptimer_state *timer;
+ MemoryRegion iomem;
+ DeviceState *ccm;
+
+ uint32_t cr;
+ uint32_t pr;
+ uint32_t sr;
+ uint32_t ir;
+ uint32_t ocr1;
+ uint32_t ocr2;
+ uint32_t ocr3;
+ uint32_t icr1;
+ uint32_t icr2;
+ uint32_t cnt;
+
+ uint32_t waiting_rov;
+ qemu_irq irq;
+} IMXTimerGState;
+
+static const VMStateDescription vmstate_imx_timerg = {
+ .name = "imx-timerg",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(cr, IMXTimerGState),
+ VMSTATE_UINT32(pr, IMXTimerGState),
+ VMSTATE_UINT32(sr, IMXTimerGState),
+ VMSTATE_UINT32(ir, IMXTimerGState),
+ VMSTATE_UINT32(ocr1, IMXTimerGState),
+ VMSTATE_UINT32(ocr2, IMXTimerGState),
+ VMSTATE_UINT32(ocr3, IMXTimerGState),
+ VMSTATE_UINT32(icr1, IMXTimerGState),
+ VMSTATE_UINT32(icr2, IMXTimerGState),
+ VMSTATE_UINT32(cnt, IMXTimerGState),
+ VMSTATE_UINT32(waiting_rov, IMXTimerGState),
+ VMSTATE_PTIMER(timer, IMXTimerGState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const IMXClk imx_timerg_clocks[] = {
+ NOCLK, /* 000 No clock source */
+ IPG, /* 001 ipg_clk, 532MHz*/
+ IPG, /* 010 ipg_clk_highfreq */
+ NOCLK, /* 011 not defined */
+ CLK_32k, /* 100 ipg_clk_32k */
+ NOCLK, /* 101 not defined */
+ NOCLK, /* 110 not defined */
+ NOCLK, /* 111 not defined */
+};
+
+
+static void imx_timerg_set_freq(IMXTimerGState *s)
+{
+ int clksrc;
+ uint32_t freq;
+
+ clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK;
+ freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr);
+
+ DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq);
+
+ if (freq) {
+ ptimer_set_freq(s->timer, freq);
+ }
+}
+
+static void imx_timerg_update(IMXTimerGState *s)
+{
+ uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
+
+ DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n",
+ s->sr & GPT_SR_OF1 ? "OF1" : "",
+ s->sr & GPT_SR_ROV ? "ROV" : "",
+ s->ir & GPT_SR_OF1 ? "OF1" : "",
+ s->ir & GPT_SR_ROV ? "ROV" : "",
+ s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled");
+
+ qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags);
+}
+
+static uint32_t imx_timerg_update_counts(IMXTimerGState *s)
+{
+ uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1;
+ uint64_t cnt = ptimer_get_count(s->timer);
+ s->cnt = target - cnt;
+ return s->cnt;
+}
+
+static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout)
+{
+ uint64_t diff_cnt;
+
+ if (!(s->cr & GPT_CR_FRR)) {
+ IPRINTF("IMX_timerg_reload --- called in reset-mode\n");
+ return;
+ }
+
+ /*
+ * For small timeouts, qemu sometimes runs too slow.
+ * Better deliver a late interrupt than none.
+ *
+ * In Reset mode (FRR bit clear)
+ * the ptimer reloads itself from OCR1;
+ * in free-running mode we need to fake
+ * running from 0 to ocr1 to TIMER_MAX
+ */
+ if (timeout > s->cnt) {
+ diff_cnt = timeout - s->cnt;
+ } else {
+ diff_cnt = 0;
+ }
+ ptimer_set_count(s->timer, diff_cnt);
+}
+
+static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ IMXTimerGState *s = (IMXTimerGState *)opaque;
+
+ DPRINTF("g-read(offset=%x)", (unsigned int)(offset >> 2));
+ switch (offset >> 2) {
+ case 0: /* Control Register */
+ DPRINTF(" cr = %x\n", s->cr);
+ return s->cr;
+
+ case 1: /* prescaler */
+ DPRINTF(" pr = %x\n", s->pr);
+ return s->pr;
+
+ case 2: /* Status Register */
+ DPRINTF(" sr = %x\n", s->sr);
+ return s->sr;
+
+ case 3: /* Interrupt Register */
+ DPRINTF(" ir = %x\n", s->ir);
+ return s->ir;
+
+ case 4: /* Output Compare Register 1 */
+ DPRINTF(" ocr1 = %x\n", s->ocr1);
+ return s->ocr1;
+
+ case 5: /* Output Compare Register 2 */
+ DPRINTF(" ocr2 = %x\n", s->ocr2);
+ return s->ocr2;
+
+ case 6: /* Output Compare Register 3 */
+ DPRINTF(" ocr3 = %x\n", s->ocr3);
+ return s->ocr3;
+
+ case 7: /* input Capture Register 1 */
+ DPRINTF(" icr1 = %x\n", s->icr1);
+ return s->icr1;
+
+ case 8: /* input Capture Register 2 */
+ DPRINTF(" icr2 = %x\n", s->icr2);
+ return s->icr2;
+
+ case 9: /* cnt */
+ imx_timerg_update_counts(s);
+ DPRINTF(" cnt = %x\n", s->cnt);
+ return s->cnt;
+ }
+
+ IPRINTF("imx_timerg_read: Bad offset %x\n",
+ (int)offset >> 2);
+
+ return 0;
+}
+
+static void imx_timerg_reset(DeviceState *dev)
+{
+ IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev);
+
+ /*
+ * Soft reset doesn't touch some bits; hard reset clears them
+ */
+ s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN|
+ GPT_CR_WAITEN|GPT_CR_DBGEN);
+ s->sr = 0;
+ s->pr = 0;
+ s->ir = 0;
+ s->cnt = 0;
+ s->ocr1 = TIMER_MAX;
+ s->ocr2 = TIMER_MAX;
+ s->ocr3 = TIMER_MAX;
+ s->icr1 = 0;
+ s->icr2 = 0;
+ ptimer_stop(s->timer);
+ ptimer_set_limit(s->timer, TIMER_MAX, 1);
+ ptimer_set_count(s->timer, TIMER_MAX);
+ imx_timerg_set_freq(s);
+}
+
+static void imx_timerg_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IMXTimerGState *s = (IMXTimerGState *)opaque;
+ DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2,
+ (unsigned int)value);
+
+ switch (offset >> 2) {
+ case 0: {
+ uint32_t oldcr = s->cr;
+ /* CR */
+ if (value & GPT_CR_SWR) { /* force reset */
+ value &= ~GPT_CR_SWR;
+ imx_timerg_reset(&s->busdev.qdev);
+ imx_timerg_update(s);
+ }
+
+ s->cr = value & ~0x7c00;
+ imx_timerg_set_freq(s);
+ if ((oldcr ^ value) & GPT_CR_EN) {
+ if (value & GPT_CR_EN) {
+ if (value & GPT_CR_ENMOD) {
+ ptimer_set_count(s->timer, s->ocr1);
+ s->cnt = 0;
+ }
+ ptimer_run(s->timer,
+ (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX));
+ } else {
+ ptimer_stop(s->timer);
+ };
+ }
+ return;
+ }
+
+ case 1: /* Prescaler */
+ s->pr = value & 0xfff;
+ imx_timerg_set_freq(s);
+ return;
+
+ case 2: /* SR */
+ /*
+ * No point in implementing the status register bits to do with
+ * external interrupt sources.
+ */
+ value &= GPT_SR_OF1 | GPT_SR_ROV;
+ s->sr &= ~value;
+ imx_timerg_update(s);
+ return;
+
+ case 3: /* IR -- interrupt register */
+ s->ir = value & 0x3f;
+ imx_timerg_update(s);
+ return;
+
+ case 4: /* OCR1 -- output compare register */
+ /* In non-freerun mode, reset count when this register is written */
+ if (!(s->cr & GPT_CR_FRR)) {
+ s->waiting_rov = 0;
+ ptimer_set_limit(s->timer, value, 1);
+ } else {
+ imx_timerg_update_counts(s);
+ if (value > s->cnt) {
+ s->waiting_rov = 0;
+ imx_timerg_reload(s, value);
+ } else {
+ s->waiting_rov = 1;
+ imx_timerg_reload(s, TIMER_MAX - s->cnt);
+ }
+ }
+ s->ocr1 = value;
+ return;
+
+ case 5: /* OCR2 -- output compare register */
+ case 6: /* OCR3 -- output compare register */
+ default:
+ IPRINTF("imx_timerg_write: Bad offset %x\n",
+ (int)offset >> 2);
+ }
+}
+
+static void imx_timerg_timeout(void *opaque)
+{
+ IMXTimerGState *s = (IMXTimerGState *)opaque;
+
+ DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov);
+ if (s->cr & GPT_CR_FRR) {
+ /*
+ * Free running timer from 0 -> TIMERMAX
+ * Generates interrupt at TIMER_MAX and at cnt==ocr1
+ * If ocr1 == TIMER_MAX, then no need to reload timer.
+ */
+ if (s->ocr1 == TIMER_MAX) {
+ DPRINTF("s->ocr1 == TIMER_MAX, FRR\n");
+ s->sr |= GPT_SR_OF1 | GPT_SR_ROV;
+ imx_timerg_update(s);
+ return;
+ }
+
+ if (s->waiting_rov) {
+ /*
+ * We were waiting for cnt==TIMER_MAX
+ */
+ s->sr |= GPT_SR_ROV;
+ s->waiting_rov = 0;
+ s->cnt = 0;
+ imx_timerg_reload(s, s->ocr1);
+ } else {
+ /* Must have got a cnt==ocr1 timeout. */
+ s->sr |= GPT_SR_OF1;
+ s->cnt = s->ocr1;
+ s->waiting_rov = 1;
+ imx_timerg_reload(s, TIMER_MAX);
+ }
+ imx_timerg_update(s);
+ return;
+ }
+
+ s->sr |= GPT_SR_OF1;
+ imx_timerg_update(s);
+}
+
+static const MemoryRegionOps imx_timerg_ops = {
+ .read = imx_timerg_read,
+ .write = imx_timerg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+
+static int imx_timerg_init(SysBusDevice *dev)
+{
+ IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev);
+ QEMUBH *bh;
+
+ sysbus_init_irq(dev, &s->irq);
+ memory_region_init_io(&s->iomem, &imx_timerg_ops,
+ s, "imxg-timer",
+ 0x00001000);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ bh = qemu_bh_new(imx_timerg_timeout, s);
+ s->timer = ptimer_init(bh);
+
+ /* Hard reset resets extra bits in CR */
+ s->cr = 0;
+ return 0;
+}
+
+void imx_timerg_create(const hwaddr addr,
+ qemu_irq irq,
+ DeviceState *ccm)
+{
+ IMXTimerGState *pp;
+ DeviceState *dev;
+
+ dev = sysbus_create_simple("imx_timerg", addr, irq);
+ pp = container_of(dev, IMXTimerGState, busdev.qdev);
+ pp->ccm = ccm;
+}
+
+static void imx_timerg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ k->init = imx_timerg_init;
+ dc->vmsd = &vmstate_imx_timerg;
+ dc->reset = imx_timerg_reset;
+ dc->desc = "i.MX general timer";
+}
+
+static const TypeInfo imx_timerg_info = {
+ .name = "imx_timerg",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXTimerGState),
+ .class_init = imx_timerg_class_init,
+};
+
+static void imx_timer_register_types(void)
+{
+ type_register_static(&imx_timerg_info);
+}
+
+type_init(imx_timer_register_types)
diff --git a/hw/timer/imx_timer.c b/hw/timer/imx_timer.c
deleted file mode 100644
index 7693bb7..0000000
--- a/hw/timer/imx_timer.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * IMX31 Timer
- *
- * Copyright (c) 2008 OK Labs
- * Copyright (c) 2011 NICTA Pty Ltd
- * Originally written by Hans Jiang
- * Updated by Peter Chubb
- *
- * This code is licensed under GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "hw/sysbus.h"
-#include "hw/arm/imx.h"
-
-//#define DEBUG_TIMER 1
-#ifdef DEBUG_TIMER
-# define DPRINTF(fmt, args...) \
- do { printf("imx_timer: " fmt , ##args); } while (0)
-#else
-# define DPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * Define to 1 for messages about attempts to
- * access unimplemented registers or similar.
- */
-#define DEBUG_IMPLEMENTATION 1
-#if DEBUG_IMPLEMENTATION
-# define IPRINTF(fmt, args...) \
- do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
-#else
-# define IPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * GPT : General purpose timer
- *
- * This timer counts up continuously while it is enabled, resetting itself
- * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
- * reaches the value of ocr1 (in periodic mode). WE simulate this using a
- * QEMU ptimer counting down from ocr1 and reloading from ocr1 in
- * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1.
- * waiting_rov is set when counting from TIMER_MAX.
- *
- * In the real hardware, there are three comparison registers that can
- * trigger interrupts, and compare channel 1 can be used to
- * force-reset the timer. However, this is a `bare-bones'
- * implementation: only what Linux 3.x uses has been implemented
- * (free-running timer from 0 to OCR1 or TIMER_MAX) .
- */
-
-
-#define TIMER_MAX 0XFFFFFFFFUL
-
-/* Control register. Not all of these bits have any effect (yet) */
-#define GPT_CR_EN (1 << 0) /* GPT Enable */
-#define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */
-#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */
-#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */
-#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */
-#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */
-#define GPT_CR_CLKSRC_SHIFT (6)
-#define GPT_CR_CLKSRC_MASK (0x7)
-
-#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */
-#define GPT_CR_SWR (1 << 15) /* Software Reset */
-#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */
-#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */
-#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
-#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
-#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
-#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */
-#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */
-#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */
-
-#define GPT_SR_OF1 (1 << 0)
-#define GPT_SR_ROV (1 << 5)
-
-#define GPT_IR_OF1IE (1 << 0)
-#define GPT_IR_ROVIE (1 << 5)
-
-typedef struct {
- SysBusDevice busdev;
- ptimer_state *timer;
- MemoryRegion iomem;
- DeviceState *ccm;
-
- uint32_t cr;
- uint32_t pr;
- uint32_t sr;
- uint32_t ir;
- uint32_t ocr1;
- uint32_t ocr2;
- uint32_t ocr3;
- uint32_t icr1;
- uint32_t icr2;
- uint32_t cnt;
-
- uint32_t waiting_rov;
- qemu_irq irq;
-} IMXTimerGState;
-
-static const VMStateDescription vmstate_imx_timerg = {
- .name = "imx-timerg",
- .version_id = 2,
- .minimum_version_id = 2,
- .minimum_version_id_old = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cr, IMXTimerGState),
- VMSTATE_UINT32(pr, IMXTimerGState),
- VMSTATE_UINT32(sr, IMXTimerGState),
- VMSTATE_UINT32(ir, IMXTimerGState),
- VMSTATE_UINT32(ocr1, IMXTimerGState),
- VMSTATE_UINT32(ocr2, IMXTimerGState),
- VMSTATE_UINT32(ocr3, IMXTimerGState),
- VMSTATE_UINT32(icr1, IMXTimerGState),
- VMSTATE_UINT32(icr2, IMXTimerGState),
- VMSTATE_UINT32(cnt, IMXTimerGState),
- VMSTATE_UINT32(waiting_rov, IMXTimerGState),
- VMSTATE_PTIMER(timer, IMXTimerGState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const IMXClk imx_timerg_clocks[] = {
- NOCLK, /* 000 No clock source */
- IPG, /* 001 ipg_clk, 532MHz*/
- IPG, /* 010 ipg_clk_highfreq */
- NOCLK, /* 011 not defined */
- CLK_32k, /* 100 ipg_clk_32k */
- NOCLK, /* 101 not defined */
- NOCLK, /* 110 not defined */
- NOCLK, /* 111 not defined */
-};
-
-
-static void imx_timerg_set_freq(IMXTimerGState *s)
-{
- int clksrc;
- uint32_t freq;
-
- clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK;
- freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr);
-
- DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq);
- if (freq) {
- ptimer_set_freq(s->timer, freq);
- }
-}
-
-static void imx_timerg_update(IMXTimerGState *s)
-{
- uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
-
- DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n",
- s->sr & GPT_SR_OF1 ? "OF1" : "",
- s->sr & GPT_SR_ROV ? "ROV" : "",
- s->ir & GPT_SR_OF1 ? "OF1" : "",
- s->ir & GPT_SR_ROV ? "ROV" : "",
- s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled");
-
- qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags);
-}
-
-static uint32_t imx_timerg_update_counts(IMXTimerGState *s)
-{
- uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1;
- uint64_t cnt = ptimer_get_count(s->timer);
- s->cnt = target - cnt;
- return s->cnt;
-}
-
-static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout)
-{
- uint64_t diff_cnt;
-
- if (!(s->cr & GPT_CR_FRR)) {
- IPRINTF("IMX_timerg_reload --- called in reset-mode\n");
- return;
- }
-
- /*
- * For small timeouts, qemu sometimes runs too slow.
- * Better deliver a late interrupt than none.
- *
- * In Reset mode (FRR bit clear)
- * the ptimer reloads itself from OCR1;
- * in free-running mode we need to fake
- * running from 0 to ocr1 to TIMER_MAX
- */
- if (timeout > s->cnt) {
- diff_cnt = timeout - s->cnt;
- } else {
- diff_cnt = 0;
- }
- ptimer_set_count(s->timer, diff_cnt);
-}
-
-static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- IMXTimerGState *s = (IMXTimerGState *)opaque;
-
- DPRINTF("g-read(offset=%x)", offset >> 2);
- switch (offset >> 2) {
- case 0: /* Control Register */
- DPRINTF(" cr = %x\n", s->cr);
- return s->cr;
-
- case 1: /* prescaler */
- DPRINTF(" pr = %x\n", s->pr);
- return s->pr;
-
- case 2: /* Status Register */
- DPRINTF(" sr = %x\n", s->sr);
- return s->sr;
-
- case 3: /* Interrupt Register */
- DPRINTF(" ir = %x\n", s->ir);
- return s->ir;
-
- case 4: /* Output Compare Register 1 */
- DPRINTF(" ocr1 = %x\n", s->ocr1);
- return s->ocr1;
-
- case 5: /* Output Compare Register 2 */
- DPRINTF(" ocr2 = %x\n", s->ocr2);
- return s->ocr2;
-
- case 6: /* Output Compare Register 3 */
- DPRINTF(" ocr3 = %x\n", s->ocr3);
- return s->ocr3;
-
- case 7: /* input Capture Register 1 */
- DPRINTF(" icr1 = %x\n", s->icr1);
- return s->icr1;
-
- case 8: /* input Capture Register 2 */
- DPRINTF(" icr2 = %x\n", s->icr2);
- return s->icr2;
-
- case 9: /* cnt */
- imx_timerg_update_counts(s);
- DPRINTF(" cnt = %x\n", s->cnt);
- return s->cnt;
- }
-
- IPRINTF("imx_timerg_read: Bad offset %x\n",
- (int)offset >> 2);
-
- return 0;
-}
-
-static void imx_timerg_reset(DeviceState *dev)
-{
- IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev);
-
- /*
- * Soft reset doesn't touch some bits; hard reset clears them
- */
- s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN|
- GPT_CR_WAITEN|GPT_CR_DBGEN);
- s->sr = 0;
- s->pr = 0;
- s->ir = 0;
- s->cnt = 0;
- s->ocr1 = TIMER_MAX;
- s->ocr2 = TIMER_MAX;
- s->ocr3 = TIMER_MAX;
- s->icr1 = 0;
- s->icr2 = 0;
- ptimer_stop(s->timer);
- ptimer_set_limit(s->timer, TIMER_MAX, 1);
- ptimer_set_count(s->timer, TIMER_MAX);
- imx_timerg_set_freq(s);
-}
-
-static void imx_timerg_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- IMXTimerGState *s = (IMXTimerGState *)opaque;
- DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2,
- (unsigned int)value);
-
- switch (offset >> 2) {
- case 0: {
- uint32_t oldcr = s->cr;
- /* CR */
- if (value & GPT_CR_SWR) { /* force reset */
- value &= ~GPT_CR_SWR;
- imx_timerg_reset(&s->busdev.qdev);
- imx_timerg_update(s);
- }
-
- s->cr = value & ~0x7c00;
- imx_timerg_set_freq(s);
- if ((oldcr ^ value) & GPT_CR_EN) {
- if (value & GPT_CR_EN) {
- if (value & GPT_CR_ENMOD) {
- ptimer_set_count(s->timer, s->ocr1);
- s->cnt = 0;
- }
- ptimer_run(s->timer,
- (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX));
- } else {
- ptimer_stop(s->timer);
- };
- }
- return;
- }
-
- case 1: /* Prescaler */
- s->pr = value & 0xfff;
- imx_timerg_set_freq(s);
- return;
-
- case 2: /* SR */
- /*
- * No point in implementing the status register bits to do with
- * external interrupt sources.
- */
- value &= GPT_SR_OF1 | GPT_SR_ROV;
- s->sr &= ~value;
- imx_timerg_update(s);
- return;
-
- case 3: /* IR -- interrupt register */
- s->ir = value & 0x3f;
- imx_timerg_update(s);
- return;
-
- case 4: /* OCR1 -- output compare register */
- /* In non-freerun mode, reset count when this register is written */
- if (!(s->cr & GPT_CR_FRR)) {
- s->waiting_rov = 0;
- ptimer_set_limit(s->timer, value, 1);
- } else {
- imx_timerg_update_counts(s);
- if (value > s->cnt) {
- s->waiting_rov = 0;
- imx_timerg_reload(s, value);
- } else {
- s->waiting_rov = 1;
- imx_timerg_reload(s, TIMER_MAX - s->cnt);
- }
- }
- s->ocr1 = value;
- return;
-
- case 5: /* OCR2 -- output compare register */
- case 6: /* OCR3 -- output compare register */
- default:
- IPRINTF("imx_timerg_write: Bad offset %x\n",
- (int)offset >> 2);
- }
-}
-
-static void imx_timerg_timeout(void *opaque)
-{
- IMXTimerGState *s = (IMXTimerGState *)opaque;
-
- DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov);
- if (s->cr & GPT_CR_FRR) {
- /*
- * Free running timer from 0 -> TIMERMAX
- * Generates interrupt at TIMER_MAX and at cnt==ocr1
- * If ocr1 == TIMER_MAX, then no need to reload timer.
- */
- if (s->ocr1 == TIMER_MAX) {
- DPRINTF("s->ocr1 == TIMER_MAX, FRR\n");
- s->sr |= GPT_SR_OF1 | GPT_SR_ROV;
- imx_timerg_update(s);
- return;
- }
-
- if (s->waiting_rov) {
- /*
- * We were waiting for cnt==TIMER_MAX
- */
- s->sr |= GPT_SR_ROV;
- s->waiting_rov = 0;
- s->cnt = 0;
- imx_timerg_reload(s, s->ocr1);
- } else {
- /* Must have got a cnt==ocr1 timeout. */
- s->sr |= GPT_SR_OF1;
- s->cnt = s->ocr1;
- s->waiting_rov = 1;
- imx_timerg_reload(s, TIMER_MAX);
- }
- imx_timerg_update(s);
- return;
- }
-
- s->sr |= GPT_SR_OF1;
- imx_timerg_update(s);
-}
-
-static const MemoryRegionOps imx_timerg_ops = {
- .read = imx_timerg_read,
- .write = imx_timerg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-
-static int imx_timerg_init(SysBusDevice *dev)
-{
- IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev);
- QEMUBH *bh;
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->iomem, &imx_timerg_ops,
- s, "imxg-timer",
- 0x00001000);
- sysbus_init_mmio(dev, &s->iomem);
-
- bh = qemu_bh_new(imx_timerg_timeout, s);
- s->timer = ptimer_init(bh);
-
- /* Hard reset resets extra bits in CR */
- s->cr = 0;
- return 0;
-}
-
-
-
-/*
- * EPIT: Enhanced periodic interrupt timer
- */
-
-#define CR_EN (1 << 0)
-#define CR_ENMOD (1 << 1)
-#define CR_OCIEN (1 << 2)
-#define CR_RLD (1 << 3)
-#define CR_PRESCALE_SHIFT (4)
-#define CR_PRESCALE_MASK (0xfff)
-#define CR_SWR (1 << 16)
-#define CR_IOVW (1 << 17)
-#define CR_DBGEN (1 << 18)
-#define CR_WAITEN (1 << 19)
-#define CR_DOZEN (1 << 20)
-#define CR_STOPEN (1 << 21)
-#define CR_CLKSRC_SHIFT (24)
-#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
-
-
-/*
- * Exact clock frequencies vary from board to board.
- * These are typical.
- */
-static const IMXClk imx_timerp_clocks[] = {
- 0, /* 00 disabled */
- IPG, /* 01 ipg_clk, ~532MHz */
- IPG, /* 10 ipg_clk_highfreq */
- CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */
-};
-
-typedef struct {
- SysBusDevice busdev;
- ptimer_state *timer_reload;
- ptimer_state *timer_cmp;
- MemoryRegion iomem;
- DeviceState *ccm;
-
- uint32_t cr;
- uint32_t sr;
- uint32_t lr;
- uint32_t cmp;
- uint32_t cnt;
-
- uint32_t freq;
- qemu_irq irq;
-} IMXTimerPState;
-
-/*
- * Update interrupt status
- */
-static void imx_timerp_update(IMXTimerPState *s)
-{
- if (s->sr && (s->cr & CR_OCIEN)) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static void set_timerp_freq(IMXTimerPState *s)
-{
- int clksrc;
- unsigned prescaler;
- uint32_t freq;
-
- clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT;
- prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK);
- freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
-
- s->freq = freq;
- DPRINTF("Setting ptimer frequency to %u\n", freq);
-
- if (freq) {
- ptimer_set_freq(s->timer_reload, freq);
- ptimer_set_freq(s->timer_cmp, freq);
- }
-}
-
-static void imx_timerp_reset(DeviceState *dev)
-{
- IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev);
-
- /*
- * Soft reset doesn't touch some bits; hard reset clears them
- */
- s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
- s->sr = 0;
- s->lr = TIMER_MAX;
- s->cmp = 0;
- s->cnt = 0;
- /* stop both timers */
- ptimer_stop(s->timer_cmp);
- ptimer_stop(s->timer_reload);
- /* compute new frequency */
- set_timerp_freq(s);
- /* init both timers to TIMER_MAX */
- ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
- ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
- if (s->freq && (s->cr & CR_EN)) {
- /* if the timer is still enabled, restart it */
- ptimer_run(s->timer_reload, 1);
- }
-}
-
-static uint32_t imx_timerp_update_counts(IMXTimerPState *s)
-{
- s->cnt = ptimer_get_count(s->timer_reload);
-
- return s->cnt;
-}
-
-static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- IMXTimerPState *s = (IMXTimerPState *)opaque;
-
- DPRINTF("p-read(offset=%x)", offset >> 2);
- switch (offset >> 2) {
- case 0: /* Control Register */
- DPRINTF("cr %x\n", s->cr);
- return s->cr;
-
- case 1: /* Status Register */
- DPRINTF("sr %x\n", s->sr);
- return s->sr;
-
- case 2: /* LR - ticks*/
- DPRINTF("lr %x\n", s->lr);
- return s->lr;
-
- case 3: /* CMP */
- DPRINTF("cmp %x\n", s->cmp);
- return s->cmp;
-
- case 4: /* CNT */
- imx_timerp_update_counts(s);
- DPRINTF(" cnt = %x\n", s->cnt);
- return s->cnt;
- }
-
- IPRINTF("imx_timerp_read: Bad offset %x\n",
- (int)offset >> 2);
- return 0;
-}
-
-static void imx_reload_compare_timer(IMXTimerPState *s)
-{
- if ((s->cr & CR_OCIEN) && s->cmp) {
- /* if the compare feature is on */
- uint32_t tmp = imx_timerp_update_counts(s);
- if (tmp > s->cmp) {
- /* reinit the cmp timer if required */
- ptimer_set_count(s->timer_cmp, tmp - s->cmp);
- if ((s->cr & CR_EN)) {
- /* Restart the cmp timer if required */
- ptimer_run(s->timer_cmp, 0);
- }
- }
- }
-}
-
-static void imx_timerp_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- IMXTimerPState *s = (IMXTimerPState *)opaque;
- DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
- (unsigned int)value);
-
- switch (offset >> 2) {
- case 0: /* CR */
- s->cr = value & 0x03ffffff;
- if (s->cr & CR_SWR) {
- /* handle the reset */
- imx_timerp_reset(&s->busdev.qdev);
- } else {
- set_timerp_freq(s);
- }
-
- if (s->freq && (s->cr & CR_EN)) {
- if (s->cr & CR_ENMOD) {
- if (s->cr & CR_RLD) {
- ptimer_set_limit(s->timer_reload, s->lr, 1);
- } else {
- ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
- }
- }
-
- imx_reload_compare_timer(s);
-
- ptimer_run(s->timer_reload, 1);
- } else {
- /* stop both timers */
- ptimer_stop(s->timer_reload);
- ptimer_stop(s->timer_cmp);
- }
- break;
-
- case 1: /* SR - ACK*/
- /* writing 1 to OCIF clear the OCIF bit */
- if (value & 0x01) {
- s->sr = 0;
- imx_timerp_update(s);
- }
- break;
-
- case 2: /* LR - set ticks */
- s->lr = value;
-
- if (s->cr & CR_RLD) {
- /* Also set the limit if the LRD bit is set */
- /* If IOVW bit is set then set the timer value */
- ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
- } else if (s->cr & CR_IOVW) {
- /* If IOVW bit is set then set the timer value */
- ptimer_set_count(s->timer_reload, s->lr);
- }
-
- imx_reload_compare_timer(s);
-
- break;
-
- case 3: /* CMP */
- s->cmp = value;
-
- imx_reload_compare_timer(s);
-
- break;
-
- default:
- IPRINTF("imx_timerp_write: Bad offset %x\n",
- (int)offset >> 2);
- }
-}
-
-static void imx_timerp_reload(void *opaque)
-{
- IMXTimerPState *s = (IMXTimerPState *)opaque;
-
- DPRINTF("imxp reload\n");
-
- if (!(s->cr & CR_EN)) {
- return;
- }
-
- if (s->cr & CR_RLD) {
- ptimer_set_limit(s->timer_reload, s->lr, 1);
- } else {
- ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
- }
-
- if (s->cr & CR_OCIEN) {
- /* if compare register is 0 then we handle the interrupt here */
- if (s->cmp == 0) {
- s->sr = 1;
- imx_timerp_update(s);
- } else if (s->cmp <= s->lr) {
- /* We should launch the compare register */
- ptimer_set_count(s->timer_cmp, s->lr - s->cmp);
- ptimer_run(s->timer_cmp, 0);
- } else {
- IPRINTF("imxp reload: s->lr < s->cmp\n");
- }
- }
-}
-
-static void imx_timerp_cmp(void *opaque)
-{
- IMXTimerPState *s = (IMXTimerPState *)opaque;
-
- DPRINTF("imxp compare\n");
-
- ptimer_stop(s->timer_cmp);
-
- /* compare register is not 0 */
- if (s->cmp) {
- s->sr = 1;
- imx_timerp_update(s);
- }
-}
-
-void imx_timerp_create(const hwaddr addr,
- qemu_irq irq,
- DeviceState *ccm)
-{
- IMXTimerPState *pp;
- DeviceState *dev;
-
- dev = sysbus_create_simple("imx_timerp", addr, irq);
- pp = container_of(dev, IMXTimerPState, busdev.qdev);
- pp->ccm = ccm;
-}
-
-static const MemoryRegionOps imx_timerp_ops = {
- .read = imx_timerp_read,
- .write = imx_timerp_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_imx_timerp = {
- .name = "imx-timerp",
- .version_id = 2,
- .minimum_version_id = 2,
- .minimum_version_id_old = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(cr, IMXTimerPState),
- VMSTATE_UINT32(sr, IMXTimerPState),
- VMSTATE_UINT32(lr, IMXTimerPState),
- VMSTATE_UINT32(cmp, IMXTimerPState),
- VMSTATE_UINT32(cnt, IMXTimerPState),
- VMSTATE_UINT32(freq, IMXTimerPState),
- VMSTATE_PTIMER(timer_reload, IMXTimerPState),
- VMSTATE_PTIMER(timer_cmp, IMXTimerPState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int imx_timerp_init(SysBusDevice *dev)
-{
- IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev);
- QEMUBH *bh;
-
- DPRINTF("imx_timerp_init\n");
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->iomem, &imx_timerp_ops,
- s, "imxp-timer",
- 0x00001000);
- sysbus_init_mmio(dev, &s->iomem);
-
- bh = qemu_bh_new(imx_timerp_reload, s);
- s->timer_reload = ptimer_init(bh);
-
- bh = qemu_bh_new(imx_timerp_cmp, s);
- s->timer_cmp = ptimer_init(bh);
-
- return 0;
-}
-
-
-void imx_timerg_create(const hwaddr addr,
- qemu_irq irq,
- DeviceState *ccm)
-{
- IMXTimerGState *pp;
- DeviceState *dev;
-
- dev = sysbus_create_simple("imx_timerg", addr, irq);
- pp = container_of(dev, IMXTimerGState, busdev.qdev);
- pp->ccm = ccm;
-}
-
-static void imx_timerg_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = imx_timerg_init;
- dc->vmsd = &vmstate_imx_timerg;
- dc->reset = imx_timerg_reset;
- dc->desc = "i.MX general timer";
-}
-
-static void imx_timerp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = imx_timerp_init;
- dc->vmsd = &vmstate_imx_timerp;
- dc->reset = imx_timerp_reset;
- dc->desc = "i.MX periodic timer";
-}
-
-static const TypeInfo imx_timerp_info = {
- .name = "imx_timerp",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXTimerPState),
- .class_init = imx_timerp_class_init,
-};
-
-static const TypeInfo imx_timerg_info = {
- .name = "imx_timerg",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXTimerGState),
- .class_init = imx_timerg_class_init,
-};
-
-static void imx_timer_register_types(void)
-{
- type_register_static(&imx_timerp_info);
- type_register_static(&imx_timerg_info);
-}
-
-type_init(imx_timer_register_types)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 22/24] hw/arm/exynos4210.c: convert chipid_and_omr to an mmio region
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (20 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 21/24] i.MX: split GPT and EPIT timer implementation Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 23/24] exynos4210.c: register rom_mem for memory migration Peter Maydell
` (2 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Igor Mitsyanko <i.mitsyanko@samsung.com>
Exynos SoC was misusing memory_region_init_ram_ptr(): this interface can safely
be used only for memory regions which size is a multiple of target page size.
Change chipid_and_omr memory to an mmio region to fix this.
Signed-off-by: Igor Mitsyanko <i.mitsyanko@samsung.com>
Message-id: 1368199981-45292-2-git-send-email-i.mitsyanko@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/exynos4210.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index c8101d3..502b106 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -79,6 +79,28 @@
static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
0x09, 0x00, 0x00, 0x00 };
+static uint64_t exynos4210_chipid_and_omr_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ assert(offset < sizeof(chipid_and_omr));
+ return chipid_and_omr[offset];
+}
+
+static void exynos4210_chipid_and_omr_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ return;
+}
+
+static const MemoryRegionOps exynos4210_chipid_and_omr_ops = {
+ .read = exynos4210_chipid_and_omr_read,
+ .write = exynos4210_chipid_and_omr_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .max_access_size = 1,
+ }
+};
+
void exynos4210_write_secondary(ARMCPU *cpu,
const struct arm_boot_info *info)
{
@@ -219,9 +241,8 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
/*** Memory ***/
/* Chip-ID and OMR */
- memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid",
- sizeof(chipid_and_omr), chipid_and_omr);
- memory_region_set_readonly(&s->chipid_mem, true);
+ memory_region_init_io(&s->chipid_mem, &exynos4210_chipid_and_omr_ops,
+ NULL, "exynos4210.chipid", sizeof(chipid_and_omr));
memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
&s->chipid_mem);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 23/24] exynos4210.c: register rom_mem for memory migration
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (21 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 22/24] hw/arm/exynos4210.c: convert chipid_and_omr to an mmio region Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 24/24] i.MX: Improve EPIT timer code Peter Maydell
2013-06-17 21:17 ` [Qemu-devel] [PULL 00/24] arm-devs queue Anthony Liguori
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Igor Mitsyanko <i.mitsyanko@samsung.com>
Even if we do not register newly created RAM MemoryRegion for migration with
vmstate_register_ram_global() function, ram_save_setup() still saves this region
to snapshot file with empty idstr=="". Consequently this results in error during
VM loading in ram_load().
Register rom_mem for migration.
Signed-off-by: Igor Mitsyanko <i.mitsyanko@samsung.com>
Message-id: 1368199981-45292-3-git-send-email-i.mitsyanko@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/exynos4210.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 502b106..8186f14 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -249,6 +249,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
/* Internal ROM */
memory_region_init_ram(&s->irom_mem, "exynos4210.irom",
EXYNOS4210_IROM_SIZE);
+ vmstate_register_ram_global(&s->irom_mem);
memory_region_set_readonly(&s->irom_mem, true);
memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
&s->irom_mem);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [Qemu-devel] [PULL 24/24] i.MX: Improve EPIT timer code.
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (22 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 23/24] exynos4210.c: register rom_mem for memory migration Peter Maydell
@ 2013-06-03 16:30 ` Peter Maydell
2013-06-17 21:17 ` [Qemu-devel] [PULL 00/24] arm-devs queue Anthony Liguori
24 siblings, 0 replies; 26+ messages in thread
From: Peter Maydell @ 2013-06-03 16:30 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel, Paul Brook
From: Jean-Christophe DUBOIS <jcd@tribudubois.net>
* Unify function and type naming
* use dynamic cast whenever possible
* simplify Debug printf.
* use new style device intialization.
Signed-off-by: Jean-Christophe DUBOIS <jcd@tribudubois.net>
Reviewed-by: Peter Chubb <peter.chubb@nicta.com.au>
Message-id: 1369839656-24466-1-git-send-email-jcd@tribudubois.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/timer/imx_epit.c | 236 ++++++++++++++++++++++++++++-----------------------
1 file changed, 132 insertions(+), 104 deletions(-)
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index 451e646..7cdb006 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -5,6 +5,7 @@
* Copyright (c) 2011 NICTA Pty Ltd
* Originally written by Hans Jiang
* Updated by Peter Chubb
+ * Updated by Jean-Christophe Dubois
*
* This code is licensed under GPL version 2 or later. See
* the COPYING file in the top-level directory.
@@ -18,10 +19,31 @@
#include "hw/sysbus.h"
#include "hw/arm/imx.h"
-//#define DEBUG_TIMER 1
-#ifdef DEBUG_TIMER
+#define TYPE_IMX_EPIT "imx.epit"
+
+#define DEBUG_TIMER 0
+#if DEBUG_TIMER
+
+static char const *imx_epit_reg_name(uint32_t reg)
+{
+ switch (reg) {
+ case 0:
+ return "CR";
+ case 1:
+ return "SR";
+ case 2:
+ return "LR";
+ case 3:
+ return "CMP";
+ case 4:
+ return "CNT";
+ default:
+ return "[?]";
+ }
+}
+
# define DPRINTF(fmt, args...) \
- do { printf("imx_timer: " fmt , ##args); } while (0)
+ do { printf("%s: " fmt , __func__, ##args); } while (0)
#else
# define DPRINTF(fmt, args...) do {} while (0)
#endif
@@ -32,12 +54,15 @@
*/
#define DEBUG_IMPLEMENTATION 1
#if DEBUG_IMPLEMENTATION
-# define IPRINTF(fmt, args...) \
- do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
+# define IPRINTF(fmt, args...) \
+ do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0)
#else
# define IPRINTF(fmt, args...) do {} while (0)
#endif
+#define IMX_EPIT(obj) \
+ OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT)
+
/*
* EPIT: Enhanced periodic interrupt timer
*/
@@ -63,7 +88,7 @@
* Exact clock frequencies vary from board to board.
* These are typical.
*/
-static const IMXClk imx_timerp_clocks[] = {
+static const IMXClk imx_epit_clocks[] = {
0, /* 00 disabled */
IPG, /* 01 ipg_clk, ~532MHz */
IPG, /* 10 ipg_clk_highfreq */
@@ -85,32 +110,33 @@ typedef struct {
uint32_t freq;
qemu_irq irq;
-} IMXTimerPState;
+} IMXEPITState;
/*
* Update interrupt status
*/
-static void imx_timerp_update(IMXTimerPState *s)
+static void imx_epit_update_int(IMXEPITState *s)
{
- if (s->sr && (s->cr & CR_OCIEN)) {
+ if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
qemu_irq_raise(s->irq);
} else {
qemu_irq_lower(s->irq);
}
}
-static void set_timerp_freq(IMXTimerPState *s)
+static void imx_epit_set_freq(IMXEPITState *s)
{
- unsigned clksrc;
- unsigned prescaler;
+ uint32_t clksrc;
+ uint32_t prescaler;
uint32_t freq;
clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
- freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
+ freq = imx_clock_frequency(s->ccm, imx_epit_clocks[clksrc]) / prescaler;
s->freq = freq;
+
DPRINTF("Setting ptimer frequency to %u\n", freq);
if (freq) {
@@ -119,9 +145,9 @@ static void set_timerp_freq(IMXTimerPState *s)
}
}
-static void imx_timerp_reset(DeviceState *dev)
+static void imx_epit_reset(DeviceState *dev)
{
- IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev);
+ IMXEPITState *s = IMX_EPIT(dev);
/*
* Soft reset doesn't touch some bits; hard reset clears them
@@ -135,7 +161,7 @@ static void imx_timerp_reset(DeviceState *dev)
ptimer_stop(s->timer_cmp);
ptimer_stop(s->timer_reload);
/* compute new frequency */
- set_timerp_freq(s);
+ imx_epit_set_freq(s);
/* init both timers to TIMER_MAX */
ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
@@ -145,52 +171,56 @@ static void imx_timerp_reset(DeviceState *dev)
}
}
-static uint32_t imx_timerp_update_counts(IMXTimerPState *s)
+static uint32_t imx_epit_update_count(IMXEPITState *s)
{
s->cnt = ptimer_get_count(s->timer_reload);
return s->cnt;
}
-static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
- unsigned size)
+static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
{
- IMXTimerPState *s = (IMXTimerPState *)opaque;
+ IMXEPITState *s = IMX_EPIT(opaque);
+ uint32_t reg_value = 0;
+ uint32_t reg = offset >> 2;
- DPRINTF("p-read(offset=%x)", (unsigned int)(offset >> 2));
- switch (offset >> 2) {
+ switch (reg) {
case 0: /* Control Register */
- DPRINTF("cr %x\n", s->cr);
- return s->cr;
+ reg_value = s->cr;
+ break;
case 1: /* Status Register */
- DPRINTF("sr %x\n", s->sr);
- return s->sr;
+ reg_value = s->sr;
+ break;
case 2: /* LR - ticks*/
- DPRINTF("lr %x\n", s->lr);
- return s->lr;
+ reg_value = s->lr;
+ break;
case 3: /* CMP */
- DPRINTF("cmp %x\n", s->cmp);
- return s->cmp;
+ reg_value = s->cmp;
+ break;
case 4: /* CNT */
- imx_timerp_update_counts(s);
- DPRINTF(" cnt = %x\n", s->cnt);
- return s->cnt;
+ imx_epit_update_count(s);
+ reg_value = s->cnt;
+ break;
+
+ default:
+ IPRINTF("Bad offset %x\n", reg);
+ break;
}
- IPRINTF("imx_timerp_read: Bad offset %x\n",
- (int)offset >> 2);
- return 0;
+ DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(reg), reg_value);
+
+ return reg_value;
}
-static void imx_reload_compare_timer(IMXTimerPState *s)
+static void imx_epit_reload_compare_timer(IMXEPITState *s)
{
if ((s->cr & CR_OCIEN) && s->cmp) {
/* if the compare feature is on */
- uint32_t tmp = imx_timerp_update_counts(s);
+ uint32_t tmp = imx_epit_update_count(s);
if (tmp > s->cmp) {
/* reinit the cmp timer if required */
ptimer_set_count(s->timer_cmp, tmp - s->cmp);
@@ -202,21 +232,22 @@ static void imx_reload_compare_timer(IMXTimerPState *s)
}
}
-static void imx_timerp_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
+static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
{
- IMXTimerPState *s = (IMXTimerPState *)opaque;
- DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
- (unsigned int)value);
+ IMXEPITState *s = IMX_EPIT(opaque);
+ uint32_t reg = offset >> 2;
+
+ DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value);
- switch (offset >> 2) {
+ switch (reg) {
case 0: /* CR */
s->cr = value & 0x03ffffff;
if (s->cr & CR_SWR) {
/* handle the reset */
- imx_timerp_reset(&s->busdev.qdev);
+ imx_epit_reset(DEVICE(s));
} else {
- set_timerp_freq(s);
+ imx_epit_set_freq(s);
}
if (s->freq && (s->cr & CR_EN)) {
@@ -228,7 +259,7 @@ static void imx_timerp_write(void *opaque, hwaddr offset,
}
}
- imx_reload_compare_timer(s);
+ imx_epit_reload_compare_timer(s);
ptimer_run(s->timer_reload, 1);
} else {
@@ -242,7 +273,7 @@ static void imx_timerp_write(void *opaque, hwaddr offset,
/* writing 1 to OCIF clear the OCIF bit */
if (value & 0x01) {
s->sr = 0;
- imx_timerp_update(s);
+ imx_epit_update_int(s);
}
break;
@@ -258,28 +289,29 @@ static void imx_timerp_write(void *opaque, hwaddr offset,
ptimer_set_count(s->timer_reload, s->lr);
}
- imx_reload_compare_timer(s);
+ imx_epit_reload_compare_timer(s);
break;
case 3: /* CMP */
s->cmp = value;
- imx_reload_compare_timer(s);
+ imx_epit_reload_compare_timer(s);
break;
default:
- IPRINTF("imx_timerp_write: Bad offset %x\n",
- (int)offset >> 2);
+ IPRINTF("Bad offset %x\n", reg);
+
+ break;
}
}
-static void imx_timerp_reload(void *opaque)
+static void imx_epit_timeout(void *opaque)
{
- IMXTimerPState *s = (IMXTimerPState *)opaque;
+ IMXEPITState *s = IMX_EPIT(opaque);
- DPRINTF("imxp reload\n");
+ DPRINTF("\n");
if (!(s->cr & CR_EN)) {
return;
@@ -295,110 +327,106 @@ static void imx_timerp_reload(void *opaque)
/* if compare register is 0 then we handle the interrupt here */
if (s->cmp == 0) {
s->sr = 1;
- imx_timerp_update(s);
+ imx_epit_update_int(s);
} else if (s->cmp <= s->lr) {
/* We should launch the compare register */
ptimer_set_count(s->timer_cmp, s->lr - s->cmp);
ptimer_run(s->timer_cmp, 0);
} else {
- IPRINTF("imxp reload: s->lr < s->cmp\n");
+ IPRINTF("s->lr < s->cmp\n");
}
}
}
-static void imx_timerp_cmp(void *opaque)
+static void imx_epit_cmp(void *opaque)
{
- IMXTimerPState *s = (IMXTimerPState *)opaque;
+ IMXEPITState *s = IMX_EPIT(opaque);
- DPRINTF("imxp compare\n");
+ DPRINTF("\n");
ptimer_stop(s->timer_cmp);
/* compare register is not 0 */
if (s->cmp) {
s->sr = 1;
- imx_timerp_update(s);
+ imx_epit_update_int(s);
}
}
-void imx_timerp_create(const hwaddr addr,
- qemu_irq irq,
- DeviceState *ccm)
+void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
{
- IMXTimerPState *pp;
+ IMXEPITState *pp;
DeviceState *dev;
- dev = sysbus_create_simple("imx_timerp", addr, irq);
- pp = container_of(dev, IMXTimerPState, busdev.qdev);
+ dev = sysbus_create_simple(TYPE_IMX_EPIT, addr, irq);
+ pp = IMX_EPIT(dev);
pp->ccm = ccm;
}
-static const MemoryRegionOps imx_timerp_ops = {
- .read = imx_timerp_read,
- .write = imx_timerp_write,
+static const MemoryRegionOps imx_epit_ops = {
+ .read = imx_epit_read,
+ .write = imx_epit_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static const VMStateDescription vmstate_imx_timerp = {
- .name = "imx-timerp",
+static const VMStateDescription vmstate_imx_timer_epit = {
+ .name = TYPE_IMX_EPIT,
.version_id = 2,
.minimum_version_id = 2,
.minimum_version_id_old = 2,
.fields = (VMStateField[]) {
- VMSTATE_UINT32(cr, IMXTimerPState),
- VMSTATE_UINT32(sr, IMXTimerPState),
- VMSTATE_UINT32(lr, IMXTimerPState),
- VMSTATE_UINT32(cmp, IMXTimerPState),
- VMSTATE_UINT32(cnt, IMXTimerPState),
- VMSTATE_UINT32(freq, IMXTimerPState),
- VMSTATE_PTIMER(timer_reload, IMXTimerPState),
- VMSTATE_PTIMER(timer_cmp, IMXTimerPState),
+ VMSTATE_UINT32(cr, IMXEPITState),
+ VMSTATE_UINT32(sr, IMXEPITState),
+ VMSTATE_UINT32(lr, IMXEPITState),
+ VMSTATE_UINT32(cmp, IMXEPITState),
+ VMSTATE_UINT32(cnt, IMXEPITState),
+ VMSTATE_UINT32(freq, IMXEPITState),
+ VMSTATE_PTIMER(timer_reload, IMXEPITState),
+ VMSTATE_PTIMER(timer_cmp, IMXEPITState),
VMSTATE_END_OF_LIST()
}
};
-static int imx_timerp_init(SysBusDevice *dev)
+static void imx_epit_realize(DeviceState *dev, Error **errp)
{
- IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev);
+ IMXEPITState *s = IMX_EPIT(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
QEMUBH *bh;
- DPRINTF("imx_timerp_init\n");
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->iomem, &imx_timerp_ops,
- s, "imxp-timer",
+ DPRINTF("\n");
+
+ sysbus_init_irq(sbd, &s->irq);
+ memory_region_init_io(&s->iomem, &imx_epit_ops, s, TYPE_IMX_EPIT,
0x00001000);
- sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_mmio(sbd, &s->iomem);
- bh = qemu_bh_new(imx_timerp_reload, s);
+ bh = qemu_bh_new(imx_epit_timeout, s);
s->timer_reload = ptimer_init(bh);
- bh = qemu_bh_new(imx_timerp_cmp, s);
+ bh = qemu_bh_new(imx_epit_cmp, s);
s->timer_cmp = ptimer_init(bh);
-
- return 0;
}
-
-static void imx_timerp_class_init(ObjectClass *klass, void *data)
+static void imx_epit_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = imx_timerp_init;
- dc->vmsd = &vmstate_imx_timerp;
- dc->reset = imx_timerp_reset;
+
+ dc->realize = imx_epit_realize;
+ dc->reset = imx_epit_reset;
+ dc->vmsd = &vmstate_imx_timer_epit;
dc->desc = "i.MX periodic timer";
}
-static const TypeInfo imx_timerp_info = {
- .name = "imx_timerp",
+static const TypeInfo imx_epit_info = {
+ .name = TYPE_IMX_EPIT,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXTimerPState),
- .class_init = imx_timerp_class_init,
+ .instance_size = sizeof(IMXEPITState),
+ .class_init = imx_epit_class_init,
};
-static void imx_timer_register_types(void)
+static void imx_epit_register_types(void)
{
- type_register_static(&imx_timerp_info);
+ type_register_static(&imx_epit_info);
}
-type_init(imx_timer_register_types)
+type_init(imx_epit_register_types)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [Qemu-devel] [PULL 00/24] arm-devs queue
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
` (23 preceding siblings ...)
2013-06-03 16:30 ` [Qemu-devel] [PULL 24/24] i.MX: Improve EPIT timer code Peter Maydell
@ 2013-06-17 21:17 ` Anthony Liguori
24 siblings, 0 replies; 26+ messages in thread
From: Anthony Liguori @ 2013-06-17 21:17 UTC (permalink / raw)
To: Peter Maydell, Anthony Liguori; +Cc: qemu-devel, Paul Brook
Pulled. Thanks.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2013-06-17 21:19 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-03 16:29 [Qemu-devel] [PULL 00/24] arm-devs queue Peter Maydell
2013-06-03 16:29 ` [Qemu-devel] [PULL 01/24] xilinx_spips: seperate SPI and QSPI as two classes Peter Maydell
2013-06-03 16:29 ` [Qemu-devel] [PULL 02/24] xilinx_spips: Make interrupts clear on read Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 03/24] xilinx_spips: Inhibit interrupts in LQSPI mode Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 04/24] xilinx_spips: Add verbose LQSPI debug output Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 05/24] xilinx_spips: Fix QSPI FIFO size Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 06/24] xilinx_spips: Trash LQ page cache on mode change Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 07/24] xilinx_spips: Add automatic start support Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 08/24] xilinx_spips: Implement automatic CS Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 09/24] xilinx_spips: lqspi: Dont touch config register Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 10/24] xilinx_spips: Fix CTRL register RW bits Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 11/24] xilinx_spips: Fix striping behaviour Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 12/24] xilinx_spips: Debug msgs for Snoop state Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 13/24] xilinx_spips: Multiple debug verbosity levels Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 14/24] xilinx_spips: lqspi: Push more data to tx-fifo Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 15/24] xilinx_spips: lqspi: Fix byte/misaligned access Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 16/24] sd/sdhci.c: Only reset data_count on new commands Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 17/24] sd/sdhci: Fix Buffer Write Ready interrupt Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 18/24] sd/sdhci.c: Fix bdata_read DPRINT message Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 19/24] sd/sdhci:ADMA: fix interrupt Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 20/24] sd/sd.c: Fix "inquiry" ACMD41 Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 21/24] i.MX: split GPT and EPIT timer implementation Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 22/24] hw/arm/exynos4210.c: convert chipid_and_omr to an mmio region Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 23/24] exynos4210.c: register rom_mem for memory migration Peter Maydell
2013-06-03 16:30 ` [Qemu-devel] [PULL 24/24] i.MX: Improve EPIT timer code Peter Maydell
2013-06-17 21:17 ` [Qemu-devel] [PULL 00/24] arm-devs queue Anthony Liguori
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).