* [Qemu-devel] [PATCH 01/15] hw/omap_l4.c: Add helper function omap_l4_region_base
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 02/15] hw/omap_gpio.c: Don't complain about some writes to r/o registers Peter Maydell
` (13 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Add helper function omap_l4_region_base() to return the base address
of a particular region of an L4 target agent.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/omap.h | 2 ++
hw/omap_l4.c | 6 ++++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/hw/omap.h b/hw/omap.h
index c227a82..00a0ea9 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -93,6 +93,8 @@ struct omap_target_agent_s *omap_l4ta_get(
int cs);
target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
int iotype);
+target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta,
+ int region);
int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
CPUWriteMemoryFunc * const *mem_write, void *opaque);
diff --git a/hw/omap_l4.c b/hw/omap_l4.c
index 4af0ca8..59c84b1 100644
--- a/hw/omap_l4.c
+++ b/hw/omap_l4.c
@@ -146,6 +146,12 @@ struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num)
return bus;
}
+target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta,
+ int region)
+{
+ return ta->bus->base + ta->start[region].offset;
+}
+
static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr)
{
struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 02/15] hw/omap_gpio.c: Don't complain about some writes to r/o registers
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 01/15] hw/omap_l4.c: Add helper function omap_l4_region_base Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-30 4:53 ` andrzej zaborowski
2011-07-29 15:35 ` [Qemu-devel] [PATCH 03/15] hw/omap_clk: Add the clock for the OMAP2430-specific fifth GPIO module Peter Maydell
` (12 subsequent siblings)
14 siblings, 1 reply; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
Don't complain about some writes to r/o OMAP2 GPIO registers, because the
kernel will do them anyway.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/omap_gpio.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 478f7d9..b53b13b 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -385,7 +385,7 @@ static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr,
case 0x00: /* GPIO_REVISION */
case 0x14: /* GPIO_SYSSTATUS */
case 0x38: /* GPIO_DATAIN */
- OMAP_RO_REG(addr);
+ /* read-only, ignore quietly */
break;
case 0x10: /* GPIO_SYSCONFIG */
@@ -531,7 +531,7 @@ static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr,
case 0x00: /* GPIO_REVISION */
case 0x14: /* GPIO_SYSSTATUS */
case 0x38: /* GPIO_DATAIN */
- OMAP_RO_REG(addr);
+ /* read-only, ignore quietly */
break;
case 0x10: /* GPIO_SYSCONFIG */
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 02/15] hw/omap_gpio.c: Don't complain about some writes to r/o registers
2011-07-29 15:35 ` [Qemu-devel] [PATCH 02/15] hw/omap_gpio.c: Don't complain about some writes to r/o registers Peter Maydell
@ 2011-07-30 4:53 ` andrzej zaborowski
2011-07-30 12:44 ` Peter Maydell
0 siblings, 1 reply; 19+ messages in thread
From: andrzej zaborowski @ 2011-07-30 4:53 UTC (permalink / raw)
To: Peter Maydell; +Cc: Anthony Liguori, qemu-devel
Hi,
I went ahead and pushed the series with the exception of this patch
and 14/15 because I think these are the types of patches that should
remain in downstream as a reminder, is there an argument for not
fixing these things in Linux?
In patch 04 I renamed omap2_gpio_module_set to omap2_gpio_set because
the parameter is no longer the module pointer. By the way I think we
should also pass the target agent pointer on creation the same way
clocks are passed and use omap_l4_attach.
In patch 07 I bumped the vmstate version because the structure seems
to have changed.
In patch 12 I removed the
else {
s->bdrv_cur = s->bdrv;
} part because there seemed to be no reason to add it, please check
that I haven't broken something.
Cheers
On 29 July 2011 17:35, Peter Maydell <peter.maydell@linaro.org> wrote:
> Don't complain about some writes to r/o OMAP2 GPIO registers, because the
> kernel will do them anyway.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/omap_gpio.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
> index 478f7d9..b53b13b 100644
> --- a/hw/omap_gpio.c
> +++ b/hw/omap_gpio.c
> @@ -385,7 +385,7 @@ static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr,
> case 0x00: /* GPIO_REVISION */
> case 0x14: /* GPIO_SYSSTATUS */
> case 0x38: /* GPIO_DATAIN */
> - OMAP_RO_REG(addr);
> + /* read-only, ignore quietly */
> break;
>
> case 0x10: /* GPIO_SYSCONFIG */
> @@ -531,7 +531,7 @@ static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr,
> case 0x00: /* GPIO_REVISION */
> case 0x14: /* GPIO_SYSSTATUS */
> case 0x38: /* GPIO_DATAIN */
> - OMAP_RO_REG(addr);
> + /* read-only, ignore quietly */
> break;
>
> case 0x10: /* GPIO_SYSCONFIG */
> --
> 1.7.1
>
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 02/15] hw/omap_gpio.c: Don't complain about some writes to r/o registers
2011-07-30 4:53 ` andrzej zaborowski
@ 2011-07-30 12:44 ` Peter Maydell
0 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-30 12:44 UTC (permalink / raw)
To: andrzej zaborowski; +Cc: Anthony Liguori, qemu-devel
On 30 July 2011 05:53, andrzej zaborowski <balrogg@gmail.com> wrote:
> I went ahead and pushed the series
Thanks.
> with the exception of this patch
> and 14/15 because I think these are the types of patches that should
> remain in downstream as a reminder, is there an argument for not
> fixing these things in Linux?
I think the only arguments are "it's too hard" and "I'd like to
run legacy images without having qemu constantly complaining and
making '-serial stdio' unusable" :-) [have you seen how much chatter
you get out of n810 running a meego image?] I think I've said before
that really we ought to have this kind of message more consistently
and conveniently enablable/disablable.
I'll leave this sort of change out of future patches; when I get
down to the point where they're the only thing left in my patch
stack (a) I'll be very happy and (b) I might look at a nicer way
to handle them.
> In patch 04 I renamed omap2_gpio_module_set to omap2_gpio_set because
> the parameter is no longer the module pointer. By the way I think we
> should also pass the target agent pointer on creation the same way
> clocks are passed and use omap_l4_attach.
The clock passing thing is (as per comments) a bit nasty; at
the moment sysbus is the closest we have to a nice way of exposing
"I have some MMIO regions" so I'm a bit reluctant to hide it behind
another magic pointer property. I'll have a think about this, though.
> In patch 07 I bumped the vmstate version because the structure seems
> to have changed.
Oops, yes. I had a note at some point to look more carefully at
the vmstate change but I must have forgotten about it :-(
I agree we can just bump the version.
> In patch 12 I removed the
> else {
> s->bdrv_cur = s->bdrv;
> } part because there seemed to be no reason to add it, please check
> that I haven't broken something.
That looks like it should be OK, we'll always call onenand_reset()
which will set bdrv_cur to bdrv.
-- PMM
^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 03/15] hw/omap_clk: Add the clock for the OMAP2430-specific fifth GPIO module
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 01/15] hw/omap_l4.c: Add helper function omap_l4_region_base Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 02/15] hw/omap_gpio.c: Don't complain about some writes to r/o registers Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 04/15] hw/omap_gpio.c: Convert to qdev Peter Maydell
` (11 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
The OMAP2430 has a fifth GPIO module which earlier OMAP2 models lack; add
the clock definition for it.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/omap_clk.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/hw/omap_clk.c b/hw/omap_clk.c
index 6bcabef..577b326 100644
--- a/hw/omap_clk.c
+++ b/hw/omap_clk.c
@@ -836,7 +836,7 @@ static struct clk i2c2_iclk = {
.parent = &core_l4_iclk,
};
-static struct clk gpio_dbclk[4] = {
+static struct clk gpio_dbclk[5] = {
{
.name = "gpio1_dbclk",
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
@@ -853,6 +853,10 @@ static struct clk gpio_dbclk[4] = {
.name = "gpio4_dbclk",
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.parent = &wu_32k_clk,
+ }, {
+ .name = "gpio5_dbclk",
+ .flags = CLOCK_IN_OMAP243X,
+ .parent = &wu_32k_clk,
},
};
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 04/15] hw/omap_gpio.c: Convert to qdev
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (2 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 03/15] hw/omap_clk: Add the clock for the OMAP2430-specific fifth GPIO module Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 05/15] lm832x: Take DeviceState pointer in lm832x_key_event() Peter Maydell
` (10 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Convert the OMAP GPIO module to qdev.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/nseries.c | 47 +++++-----
hw/omap.h | 20 +----
hw/omap1.c | 10 ++-
hw/omap2.c | 34 ++++++--
hw/omap_gpio.c | 259 ++++++++++++++++++++++++++++++++-----------------------
hw/palm.c | 26 +++---
6 files changed, 220 insertions(+), 176 deletions(-)
diff --git a/hw/nseries.c b/hw/nseries.c
index 2f84f53..32f2f53 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -134,9 +134,9 @@ static void n800_mmc_cs_cb(void *opaque, int line, int level)
static void n8x0_gpio_setup(struct n800_s *s)
{
qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_MMC_CS_GPIO, mmc_cs[0]);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]);
- qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N800_BAT_COVER_GPIO)[0]);
+ qemu_irq_lower(qdev_get_gpio_in(s->cpu->gpio, N800_BAT_COVER_GPIO));
}
#define MAEMO_CAL_HEADER(...) \
@@ -168,8 +168,8 @@ static void n8x0_nand_setup(struct n800_s *s)
omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
onenand_base_unmap,
(s->nand = onenand_init(0xec4800, 1,
- omap2_gpio_in_get(s->cpu->gpif,
- N8X0_ONENAND_GPIO)[0])));
+ qdev_get_gpio_in(s->cpu->gpio,
+ N8X0_ONENAND_GPIO))));
otp_region = onenand_raw_otp(s->nand);
memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
@@ -180,7 +180,7 @@ static void n8x0_nand_setup(struct n800_s *s)
static void n8x0_i2c_setup(struct n800_s *s)
{
DeviceState *dev;
- qemu_irq tmp_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TMP105_GPIO)[0];
+ qemu_irq tmp_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TMP105_GPIO);
/* Attach the CPU on one end of our I2C bus. */
s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
@@ -249,8 +249,8 @@ static void n800_tsc_kbd_setup(struct n800_s *s)
/* XXX: are the three pins inverted inside the chip between the
* tsc and the cpu (N4111)? */
qemu_irq penirq = NULL; /* NC */
- qemu_irq kbirq = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_KP_IRQ_GPIO)[0];
- qemu_irq dav = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_TS_GPIO)[0];
+ qemu_irq kbirq = qdev_get_gpio_in(s->cpu->gpio, N800_TSC_KP_IRQ_GPIO);
+ qemu_irq dav = qdev_get_gpio_in(s->cpu->gpio, N800_TSC_TS_GPIO);
s->ts.chip = tsc2301_init(penirq, kbirq, dav);
s->ts.opaque = s->ts.chip->opaque;
@@ -269,7 +269,7 @@ static void n800_tsc_kbd_setup(struct n800_s *s)
static void n810_tsc_setup(struct n800_s *s)
{
- qemu_irq pintdav = omap2_gpio_in_get(s->cpu->gpif, N810_TSC_TS_GPIO)[0];
+ qemu_irq pintdav = qdev_get_gpio_in(s->cpu->gpio, N810_TSC_TS_GPIO);
s->ts.opaque = tsc2005_init(pintdav);
s->ts.txrx = tsc2005_txrx;
@@ -361,7 +361,7 @@ static int n810_keys[0x80] = {
static void n810_kbd_setup(struct n800_s *s)
{
- qemu_irq kbd_irq = omap2_gpio_in_get(s->cpu->gpif, N810_KEYBOARD_GPIO)[0];
+ qemu_irq kbd_irq = qdev_get_gpio_in(s->cpu->gpio, N810_KEYBOARD_GPIO);
DeviceState *dev;
int i;
@@ -726,15 +726,15 @@ static void n8x0_dss_setup(struct n800_s *s)
static void n8x0_cbus_setup(struct n800_s *s)
{
- qemu_irq dat_out = omap2_gpio_in_get(s->cpu->gpif, N8X0_CBUS_DAT_GPIO)[0];
- qemu_irq retu_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_RETU_GPIO)[0];
- qemu_irq tahvo_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TAHVO_GPIO)[0];
+ qemu_irq dat_out = qdev_get_gpio_in(s->cpu->gpio, N8X0_CBUS_DAT_GPIO);
+ qemu_irq retu_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_RETU_GPIO);
+ qemu_irq tahvo_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TAHVO_GPIO);
CBus *cbus = cbus_init(dat_out);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_CLK_GPIO, cbus->clk);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_DAT_GPIO, cbus->dat);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_SEL_GPIO, cbus->sel);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
@@ -743,13 +743,12 @@ static void n8x0_cbus_setup(struct n800_s *s)
static void n8x0_uart_setup(struct n800_s *s)
{
CharDriverState *radio = uart_hci_init(
- omap2_gpio_in_get(s->cpu->gpif,
- N8X0_BT_HOST_WKUP_GPIO)[0]);
+ qdev_get_gpio_in(s->cpu->gpio, N8X0_BT_HOST_WKUP_GPIO));
- omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_RESET_GPIO,
- csrhci_pins_get(radio)[csrhci_pin_reset]);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_WKUP_GPIO,
- csrhci_pins_get(radio)[csrhci_pin_wakeup]);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_RESET_GPIO,
+ csrhci_pins_get(radio)[csrhci_pin_reset]);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_WKUP_GPIO,
+ csrhci_pins_get(radio)[csrhci_pin_wakeup]);
omap_uart_attach(s->cpu->uart[BT_UART], radio);
}
@@ -763,7 +762,7 @@ static void n8x0_usb_power_cb(void *opaque, int line, int level)
static void n8x0_usb_setup(struct n800_s *s)
{
- qemu_irq tusb_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TUSB_INT_GPIO)[0];
+ qemu_irq tusb_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TUSB_INT_GPIO);
qemu_irq tusb_pwr = qemu_allocate_irqs(n8x0_usb_power_cb, s, 1)[0];
TUSBState *tusb = tusb6010_init(tusb_irq);
@@ -774,7 +773,7 @@ static void n8x0_usb_setup(struct n800_s *s)
tusb6010_sync_io(tusb), NULL, NULL, tusb);
s->usb = tusb;
- omap2_gpio_out_set(s->cpu->gpif, N8X0_TUSB_ENABLE_GPIO, tusb_pwr);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_TUSB_ENABLE_GPIO, tusb_pwr);
}
/* Setup done before the main bootloader starts by some early setup code
@@ -1020,7 +1019,7 @@ static void n8x0_boot_init(void *opaque)
/* If the machine has a slided keyboard, open it */
if (s->kbd)
- qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N810_SLIDE_GPIO)[0]);
+ qemu_irq_raise(qdev_get_gpio_in(s->cpu->gpio, N810_SLIDE_GPIO));
}
#define OMAP_TAG_NOKIA_BT 0x4e01
diff --git a/hw/omap.h b/hw/omap.h
index 00a0ea9..a064353 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -683,22 +683,6 @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
-/* omap1 gpio module interface */
-struct omap_gpio_s;
-struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
- qemu_irq irq, omap_clk clk);
-void omap_gpio_reset(struct omap_gpio_s *s);
-qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s);
-void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler);
-
-/* omap2 gpio interface */
-struct omap_gpif_s;
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
- qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules);
-void omap_gpif_reset(struct omap_gpif_s *s);
-qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start);
-void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler);
-
struct uWireSlave {
uint16_t (*receive)(void *opaque);
void (*send)(void *opaque, uint16_t data);
@@ -852,7 +836,7 @@ struct omap_mpu_state_s {
/* MPUI-TIPB peripherals */
struct omap_uart_s *uart[3];
- struct omap_gpio_s *gpio;
+ DeviceState *gpio;
struct omap_mcbsp_s *mcbsp1;
struct omap_mcbsp_s *mcbsp3;
@@ -950,8 +934,6 @@ struct omap_mpu_state_s {
struct omap_gpmc_s *gpmc;
struct omap_sysctl_s *sysc;
- struct omap_gpif_s *gpif;
-
struct omap_mcspi_s *mcspi[2];
struct omap_dss_s *dss;
diff --git a/hw/omap1.c b/hw/omap1.c
index 364c26f..4c3d43f 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -27,6 +27,7 @@
#include "pc.h"
#include "blockdev.h"
#include "range.h"
+#include "sysbus.h"
/* Should signal the TCMI/GPMC */
uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr)
@@ -3585,7 +3586,6 @@ static void omap1_mpu_reset(void *opaque)
omap_uart_reset(mpu->uart[2]);
omap_mmc_reset(mpu->mmc);
omap_mpuio_reset(mpu->mpuio);
- omap_gpio_reset(mpu->gpio);
omap_uwire_reset(mpu->microwire);
omap_pwl_reset(mpu);
omap_pwt_reset(mpu);
@@ -3845,8 +3845,12 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO],
s->wakeup, omap_findclk(s, "clk32-kHz"));
- s->gpio = omap_gpio_init(0xfffce000, s->irq[0][OMAP_INT_GPIO_BANK1],
- omap_findclk(s, "arm_gpio_ck"));
+ s->gpio = qdev_create(NULL, "omap-gpio");
+ qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
+ qdev_init_nofail(s->gpio);
+ sysbus_connect_irq(sysbus_from_qdev(s->gpio), 0,
+ s->irq[0][OMAP_INT_GPIO_BANK1]);
+ sysbus_mmio_map(sysbus_from_qdev(s->gpio), 0, 0xfffce000);
s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX],
s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
diff --git a/hw/omap2.c b/hw/omap2.c
index 0f13272..c9b3540 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -27,6 +27,7 @@
#include "qemu-char.h"
#include "flash.h"
#include "soc_dma.h"
+#include "sysbus.h"
#include "audio/audio.h"
/* Enhanced Audio Controller (CODEC only) */
@@ -2203,7 +2204,6 @@ static void omap2_mpu_reset(void *opaque)
omap_uart_reset(mpu->uart[1]);
omap_uart_reset(mpu->uart[2]);
omap_mmc_reset(mpu->mmc);
- omap_gpif_reset(mpu->gpif);
omap_mcspi_reset(mpu->mcspi[0]);
omap_mcspi_reset(mpu->mcspi[1]);
omap_i2c_reset(mpu->i2c[0]);
@@ -2232,9 +2232,10 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
ram_addr_t sram_base, q2_base;
qemu_irq *cpu_irq;
qemu_irq dma_irqs[4];
- omap_clk gpio_clks[4];
DriveInfo *dinfo;
int i;
+ SysBusDevice *busdev;
+ struct omap_target_agent_s *ta;
/* Core */
s->mpu_model = omap2420;
@@ -2377,13 +2378,28 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
omap_findclk(s, "i2c2.fclk"),
omap_findclk(s, "i2c2.iclk"));
- gpio_clks[0] = omap_findclk(s, "gpio1_dbclk");
- gpio_clks[1] = omap_findclk(s, "gpio2_dbclk");
- gpio_clks[2] = omap_findclk(s, "gpio3_dbclk");
- gpio_clks[3] = omap_findclk(s, "gpio4_dbclk");
- s->gpif = omap2_gpio_init(omap_l4ta(s->l4, 3),
- &s->irq[0][OMAP_INT_24XX_GPIO_BANK1],
- gpio_clks, omap_findclk(s, "gpio_iclk"), 4);
+ s->gpio = qdev_create(NULL, "omap2-gpio");
+ qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
+ qdev_prop_set_ptr(s->gpio, "iclk", omap_findclk(s, "gpio_iclk"));
+ qdev_prop_set_ptr(s->gpio, "fclk0", omap_findclk(s, "gpio1_dbclk"));
+ qdev_prop_set_ptr(s->gpio, "fclk1", omap_findclk(s, "gpio2_dbclk"));
+ qdev_prop_set_ptr(s->gpio, "fclk2", omap_findclk(s, "gpio3_dbclk"));
+ qdev_prop_set_ptr(s->gpio, "fclk3", omap_findclk(s, "gpio4_dbclk"));
+ if (s->mpu_model == omap2430) {
+ qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk"));
+ }
+ qdev_init_nofail(s->gpio);
+ busdev = sysbus_from_qdev(s->gpio);
+ sysbus_connect_irq(busdev, 0, s->irq[0][OMAP_INT_24XX_GPIO_BANK1]);
+ sysbus_connect_irq(busdev, 3, s->irq[0][OMAP_INT_24XX_GPIO_BANK2]);
+ sysbus_connect_irq(busdev, 6, s->irq[0][OMAP_INT_24XX_GPIO_BANK3]);
+ sysbus_connect_irq(busdev, 9, s->irq[0][OMAP_INT_24XX_GPIO_BANK4]);
+ ta = omap_l4ta(s->l4, 3);
+ sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
+ sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
+ sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2));
+ sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4));
+ sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5));
s->sdrc = omap_sdrc_init(0x68009000);
s->gpmc = omap_gpmc_init(0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]);
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index b53b13b..a4280d2 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -20,10 +20,10 @@
#include "hw.h"
#include "omap.h"
-/* General-Purpose I/O */
+#include "sysbus.h"
+
struct omap_gpio_s {
qemu_irq irq;
- qemu_irq *in;
qemu_irq handler[16];
uint16_t inputs;
@@ -35,9 +35,17 @@ struct omap_gpio_s {
uint16_t pins;
};
+struct omap_gpif_s {
+ SysBusDevice busdev;
+ int mpu_model;
+ void *clk;
+ struct omap_gpio_s omap1;
+};
+
+/* General-Purpose I/O of OMAP1 */
static void omap_gpio_set(void *opaque, int line, int level)
{
- struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+ struct omap_gpio_s *s = &((struct omap_gpif_s *)opaque)->omap1;
uint16_t prev = s->inputs;
if (level)
@@ -160,7 +168,7 @@ static CPUWriteMemoryFunc * const omap_gpio_writefn[] = {
omap_badwidth_write16,
};
-void omap_gpio_reset(struct omap_gpio_s *s)
+static void omap_gpio_reset(struct omap_gpio_s *s)
{
s->inputs = 0;
s->outputs = ~0;
@@ -171,43 +179,12 @@ void omap_gpio_reset(struct omap_gpio_s *s)
s->pins = ~0;
}
-struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
- qemu_irq irq, omap_clk clk)
-{
- int iomemtype;
- struct omap_gpio_s *s = (struct omap_gpio_s *)
- qemu_mallocz(sizeof(struct omap_gpio_s));
-
- s->irq = irq;
- s->in = qemu_allocate_irqs(omap_gpio_set, s, 16);
- omap_gpio_reset(s);
-
- iomemtype = cpu_register_io_memory(omap_gpio_readfn,
- omap_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(base, 0x1000, iomemtype);
-
- return s;
-}
-
-qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s)
-{
- return s->in;
-}
-
-void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler)
-{
- if (line >= 16 || line < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
- s->handler[line] = handler;
-}
-
-/* General-Purpose Interface of OMAP2 */
struct omap2_gpio_s {
qemu_irq irq[2];
qemu_irq wkup;
- qemu_irq *in;
- qemu_irq handler[32];
+ qemu_irq *handler;
+ uint8_t revision;
uint8_t config[2];
uint32_t inputs;
uint32_t outputs;
@@ -221,8 +198,21 @@ struct omap2_gpio_s {
uint8_t delay;
};
+struct omap2_gpif_s {
+ SysBusDevice busdev;
+ int mpu_model;
+ void *iclk;
+ void *fclk[6];
+ int modulecount;
+ struct omap2_gpio_s *modules;
+ qemu_irq *handler;
+ int autoidle;
+ int gpo;
+};
+
+/* General-Purpose Interface of OMAP2/3 */
static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
- int line)
+ int line)
{
qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
}
@@ -271,8 +261,9 @@ static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
static void omap2_gpio_module_set(void *opaque, int line, int level)
{
- struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
-
+ struct omap2_gpif_s *p = opaque;
+ struct omap2_gpio_s *s = &p->modules[line >> 5];
+ line &= 31;
if (level) {
if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
omap2_gpio_module_int(s, line);
@@ -308,7 +299,7 @@ static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr)
switch (addr) {
case 0x00: /* GPIO_REVISION */
- return 0x18;
+ return s->revision;
case 0x10: /* GPIO_SYSCONFIG */
return s->config[0];
@@ -583,45 +574,28 @@ static CPUWriteMemoryFunc * const omap2_gpio_module_writefn[] = {
omap2_gpio_module_write,
};
-static void omap2_gpio_module_init(struct omap2_gpio_s *s,
- struct omap_target_agent_s *ta, int region,
- qemu_irq mpu, qemu_irq dsp, qemu_irq wkup,
- omap_clk fclk, omap_clk iclk)
+static void omap_gpif_reset(DeviceState *dev)
{
- int iomemtype;
-
- s->irq[0] = mpu;
- s->irq[1] = dsp;
- s->wkup = wkup;
- s->in = qemu_allocate_irqs(omap2_gpio_module_set, s, 32);
-
- iomemtype = l4_register_io_memory(omap2_gpio_module_readfn,
- omap2_gpio_module_writefn, s);
- omap_l4_attach(ta, region, iomemtype);
+ struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s,
+ sysbus_from_qdev(dev));
+ omap_gpio_reset(&s->omap1);
}
-struct omap_gpif_s {
- struct omap2_gpio_s module[5];
- int modules;
-
- int autoidle;
- int gpo;
-};
-
-void omap_gpif_reset(struct omap_gpif_s *s)
+static void omap2_gpif_reset(DeviceState *dev)
{
int i;
-
- for (i = 0; i < s->modules; i ++)
- omap2_gpio_module_reset(s->module + i);
-
+ struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s,
+ sysbus_from_qdev(dev));
+ for (i = 0; i < s->modulecount; i++) {
+ omap2_gpio_module_reset(&s->modules[i]);
+ }
s->autoidle = 0;
s->gpo = 0;
}
-static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
+static uint32_t omap2_gpif_top_read(void *opaque, target_phys_addr_t addr)
{
- struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+ struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
switch (addr) {
case 0x00: /* IPGENERICOCPSPL_REVISION */
@@ -647,10 +621,10 @@ static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
return 0;
}
-static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
- uint32_t value)
+static void omap2_gpif_top_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
{
- struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+ struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
switch (addr) {
case 0x00: /* IPGENERICOCPSPL_REVISION */
@@ -662,7 +636,7 @@ static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
if (value & (1 << 1)) /* SOFTRESET */
- omap_gpif_reset(s);
+ omap2_gpif_reset(&s->busdev.qdev);
s->autoidle = value & 1;
break;
@@ -676,50 +650,119 @@ static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
}
}
-static CPUReadMemoryFunc * const omap_gpif_top_readfn[] = {
- omap_gpif_top_read,
- omap_gpif_top_read,
- omap_gpif_top_read,
+static CPUReadMemoryFunc * const omap2_gpif_top_readfn[] = {
+ omap2_gpif_top_read,
+ omap2_gpif_top_read,
+ omap2_gpif_top_read,
};
-static CPUWriteMemoryFunc * const omap_gpif_top_writefn[] = {
- omap_gpif_top_write,
- omap_gpif_top_write,
- omap_gpif_top_write,
+static CPUWriteMemoryFunc * const omap2_gpif_top_writefn[] = {
+ omap2_gpif_top_write,
+ omap2_gpif_top_write,
+ omap2_gpif_top_write,
};
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
- qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules)
+static int omap_gpio_init(SysBusDevice *dev)
{
- int iomemtype, i;
- struct omap_gpif_s *s = (struct omap_gpif_s *)
- qemu_mallocz(sizeof(struct omap_gpif_s));
- int region[4] = { 0, 2, 4, 5 };
+ struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev);
+ if (!s->clk) {
+ hw_error("omap-gpio: clk not connected\n");
+ }
+ qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16);
+ qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16);
+ sysbus_init_irq(dev, &s->omap1.irq);
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap_gpio_readfn,
+ omap_gpio_writefn,
+ &s->omap1,
+ DEVICE_NATIVE_ENDIAN));
+ return 0;
+}
- s->modules = modules;
- for (i = 0; i < modules; i ++)
- omap2_gpio_module_init(s->module + i, ta, region[i],
- irq[i], NULL, NULL, fclk[i], iclk);
+static int omap2_gpio_init(SysBusDevice *dev)
+{
+ int i;
+ struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev);
+ if (!s->iclk) {
+ hw_error("omap2-gpio: iclk not connected\n");
+ }
+ if (s->mpu_model < omap3430) {
+ s->modulecount = (s->mpu_model < omap2430) ? 4 : 5;
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap2_gpif_top_readfn,
+ omap2_gpif_top_writefn, s,
+ DEVICE_NATIVE_ENDIAN));
+ } else {
+ s->modulecount = 6;
+ }
+ s->modules = qemu_mallocz(s->modulecount * sizeof(struct omap2_gpio_s));
+ s->handler = qemu_mallocz(s->modulecount * 32 * sizeof(qemu_irq));
+ qdev_init_gpio_in(&dev->qdev, omap2_gpio_module_set, s->modulecount * 32);
+ qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32);
+ for (i = 0; i < s->modulecount; i++) {
+ struct omap2_gpio_s *m = &s->modules[i];
+ if (!s->fclk[i]) {
+ hw_error("omap2-gpio: fclk%d not connected\n", i);
+ }
+ m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
+ m->handler = &s->handler[i * 32];
+ sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */
+ sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */
+ sysbus_init_irq(dev, &m->wkup);
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap2_gpio_module_readfn,
+ omap2_gpio_module_writefn,
+ m, DEVICE_NATIVE_ENDIAN));
+ }
+ return 0;
+}
- omap_gpif_reset(s);
+/* Using qdev pointer properties for the clocks is not ideal.
+ * qdev should support a generic means of defining a 'port' with
+ * an arbitrary interface for connecting two devices. Then we
+ * could reframe the omap clock API in terms of clock ports,
+ * and get some type safety. For now the best qdev provides is
+ * passing an arbitrary pointer.
+ * (It's not possible to pass in the string which is the clock
+ * name, because this device does not have the necessary information
+ * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
+ * translation.)
+ */
- iomemtype = l4_register_io_memory(omap_gpif_top_readfn,
- omap_gpif_top_writefn, s);
- omap_l4_attach(ta, 1, iomemtype);
+static SysBusDeviceInfo omap_gpio_info = {
+ .init = omap_gpio_init,
+ .qdev.name = "omap-gpio",
+ .qdev.size = sizeof(struct omap_gpif_s),
+ .qdev.reset = omap_gpif_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
- return s;
-}
+static SysBusDeviceInfo omap2_gpio_info = {
+ .init = omap2_gpio_init,
+ .qdev.name = "omap2-gpio",
+ .qdev.size = sizeof(struct omap2_gpif_s),
+ .qdev.reset = omap2_gpif_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
+ DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
+ DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
+ DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
+ DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
+ DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
+ DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
-qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start)
+static void omap_gpio_register_device(void)
{
- if (start >= s->modules * 32 || start < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, start);
- return s->module[start >> 5].in + (start & 31);
+ sysbus_register_withprop(&omap_gpio_info);
+ sysbus_register_withprop(&omap2_gpio_info);
}
-void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler)
-{
- if (line >= s->modules * 32 || line < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
- s->module[line >> 5].handler[line & 31] = handler;
-}
+device_init(omap_gpio_register_device)
diff --git a/hw/palm.c b/hw/palm.c
index f22d777..1c97394 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -94,7 +94,7 @@ static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
{
uWireSlave *tsc;
- tsc = tsc2102_init(omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]);
+ tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
omap_uwire_attach(cpu->microwire, tsc, 0);
omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
@@ -163,24 +163,24 @@ static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
qemu_irq *misc_gpio;
omap_mmc_handlers(cpu->mmc,
- omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO],
- qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
- [PALMTE_MMC_SWITCH_GPIO]));
+ qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
+ qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
+ [PALMTE_MMC_SWITCH_GPIO]));
misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7);
- omap_gpio_out_set(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]);
- omap_gpio_out_set(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]);
- omap_gpio_out_set(cpu->gpio, 11, misc_gpio[2]);
- omap_gpio_out_set(cpu->gpio, 12, misc_gpio[3]);
- omap_gpio_out_set(cpu->gpio, 13, misc_gpio[4]);
+ qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]);
+ qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]);
+ qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]);
+ qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]);
+ qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]);
omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]);
omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]);
/* Reset some inputs to initial state. */
- qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USBDETECT_GPIO]);
- qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USB_OR_DC_GPIO]);
- qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[4]);
- qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_HEADPHONES_GPIO]);
+ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
+ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
+ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
+ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 05/15] lm832x: Take DeviceState pointer in lm832x_key_event()
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (3 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 04/15] hw/omap_gpio.c: Convert to qdev Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 06/15] hw/nand: Pass block device state to init function Peter Maydell
` (9 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
Since lm832x has been qdev'ified, its users will generally
have a DeviceState pointer rather than an i2c_slave pointer,
so adjust lm832x_key_event's prototype to suit.
This allows the n810 (its only user) to actually pass a correct
pointer to it rather than NULL. The effect is that we no longer
segfault when a key is pressed.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/i2c.h | 2 +-
hw/lm832x.c | 4 ++--
hw/nseries.c | 7 +++----
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/hw/i2c.h b/hw/i2c.h
index 5514402..9381d01 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -72,6 +72,6 @@ void wm8750_set_bclk_in(void *opaque, int new_hz);
void tmp105_set(i2c_slave *i2c, int temp);
/* lm832x.c */
-void lm832x_key_event(i2c_slave *i2c, int key, int state);
+void lm832x_key_event(DeviceState *dev, int key, int state);
#endif
diff --git a/hw/lm832x.c b/hw/lm832x.c
index 590a4cc..992ce49 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -474,9 +474,9 @@ static int lm8323_init(i2c_slave *i2c)
return 0;
}
-void lm832x_key_event(struct i2c_slave *i2c, int key, int state)
+void lm832x_key_event(DeviceState *dev, int key, int state)
{
- LM823KbdState *s = (LM823KbdState *) i2c;
+ LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE_FROM_QDEV(dev));
if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
return;
diff --git a/hw/nseries.c b/hw/nseries.c
index 32f2f53..45b52bb 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -45,7 +45,7 @@ struct n800_s {
i2c_bus *i2c;
int keymap[0x80];
- i2c_slave *kbd;
+ DeviceState *kbd;
TUSBState *usb;
void *retu;
@@ -362,7 +362,6 @@ static int n810_keys[0x80] = {
static void n810_kbd_setup(struct n800_s *s)
{
qemu_irq kbd_irq = qdev_get_gpio_in(s->cpu->gpio, N810_KEYBOARD_GPIO);
- DeviceState *dev;
int i;
for (i = 0; i < 0x80; i ++)
@@ -375,8 +374,8 @@ static void n810_kbd_setup(struct n800_s *s)
/* Attach the LM8322 keyboard to the I2C bus,
* should happen in n8x0_i2c_setup and s->kbd be initialised here. */
- dev = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR);
- qdev_connect_gpio_out(dev, 0, kbd_irq);
+ s->kbd = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR);
+ qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
}
/* LCD MIPI DBI-C controller (URAL) */
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 06/15] hw/nand: Pass block device state to init function
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (4 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 05/15] lm832x: Take DeviceState pointer in lm832x_key_event() Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 07/15] hw/nand: Support large NAND devices Peter Maydell
` (8 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
Pass the BlockDeviceState to the nand_init() function rather
than having it look it up via drive_get() itself.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/axis_dev88.c | 6 +++++-
hw/flash.h | 2 +-
hw/nand.c | 8 ++------
hw/spitz.c | 4 +++-
hw/tc6393xb.c | 5 ++++-
5 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 0e2135a..de1f5a5 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -30,6 +30,7 @@
#include "loader.h"
#include "elf.h"
#include "cris-boot.h"
+#include "blockdev.h"
#define D(x)
#define DNAND(x)
@@ -251,6 +252,7 @@ void axisdev88_init (ram_addr_t ram_size,
CPUState *env;
DeviceState *dev;
SysBusDevice *s;
+ DriveInfo *nand;
qemu_irq irq[30], nmi[2], *cpu_irq;
void *etraxfs_dmac;
struct etraxfs_dma_client *eth[2] = {NULL, NULL};
@@ -278,7 +280,9 @@ void axisdev88_init (ram_addr_t ram_size,
/* Attach a NAND flash to CS1. */
- nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
+ nand = drive_get(IF_MTD, 0, 0);
+ nand_state.nand = nand_init(nand ? nand->bdrv : NULL,
+ NAND_MFR_STMICRO, 0x39);
nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state,
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);
diff --git a/hw/flash.h b/hw/flash.h
index c22e1a9..a992bb8 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -19,7 +19,7 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
/* nand.c */
typedef struct NANDFlashState NANDFlashState;
-NANDFlashState *nand_init(int manf_id, int chip_id);
+NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
void nand_done(NANDFlashState *s);
void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd);
diff --git a/hw/nand.c b/hw/nand.c
index 37e51d7..d6204d9 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -14,7 +14,6 @@
# include "hw.h"
# include "flash.h"
# include "blockdev.h"
-/* FIXME: Pass block device as an argument. */
# define NAND_CMD_READ0 0x00
# define NAND_CMD_READ1 0x01
@@ -451,20 +450,17 @@ uint8_t nand_getio(NANDFlashState *s)
return *(s->ioaddr ++);
}
-NANDFlashState *nand_init(int manf_id, int chip_id)
+NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
{
int pagesize;
NANDFlashState *s;
- DriveInfo *dinfo;
if (nand_flash_ids[chip_id].size == 0) {
hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
}
s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
- dinfo = drive_get(IF_MTD, 0, 0);
- if (dinfo)
- s->bdrv = dinfo->bdrv;
+ s->bdrv = bdrv;
s->manf_id = manf_id;
s->chip_id = chip_id;
s->size = nand_flash_ids[s->chip_id].size << 20;
diff --git a/hw/spitz.c b/hw/spitz.c
index 006f7a9..78e9c34 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -169,11 +169,13 @@ static void sl_flash_register(PXA2xxState *cpu, int size)
static int sl_nand_init(SysBusDevice *dev) {
int iomemtype;
SLNANDState *s;
+ DriveInfo *nand;
s = FROM_SYSBUS(SLNANDState, dev);
s->ctl = 0;
- s->nand = nand_init(s->manf_id, s->chip_id);
+ nand = drive_get(IF_MTD, 0, 0);
+ s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
iomemtype = cpu_register_io_memory(sl_readfn,
sl_writefn, s, DEVICE_NATIVE_ENDIAN);
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index ed49e94..4de0819 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -12,6 +12,7 @@
#include "flash.h"
#include "console.h"
#include "pixel_ops.h"
+#include "blockdev.h"
#define IRQ_TC6393_NAND 0
#define IRQ_TC6393_MMC 1
@@ -566,6 +567,7 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
{
int iomemtype;
TC6393xbState *s;
+ DriveInfo *nand;
CPUReadMemoryFunc * const tc6393xb_readfn[] = {
tc6393xb_readb,
tc6393xb_readw,
@@ -586,7 +588,8 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
- s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76);
+ nand = drive_get(IF_MTD, 0, 0);
+ s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
iomemtype = cpu_register_io_memory(tc6393xb_readfn,
tc6393xb_writefn, s, DEVICE_NATIVE_ENDIAN);
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 07/15] hw/nand: Support large NAND devices
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (5 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 06/15] hw/nand: Pass block device state to init function Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 08/15] hw/nand: Support devices wider than 8 bits Peter Maydell
` (7 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Add support for NAND devices of over 1Gb.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/nand.c | 48 +++++++++++++++++++++++++++---------------------
1 files changed, 27 insertions(+), 21 deletions(-)
diff --git a/hw/nand.c b/hw/nand.c
index d6204d9..18aa226 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -6,6 +6,10 @@
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
+ * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
+ * datasheet from Micron Technology and "NAND02G-B2C" datasheet
+ * from ST Microelectronics.
+ *
* This code is licensed under the GNU GPL v2.
*/
@@ -57,14 +61,15 @@ struct NANDFlashState {
uint8_t *ioaddr;
int iolen;
- uint32_t cmd, addr;
+ uint32_t cmd;
+ uint64_t addr;
int addrlen;
int status;
int offset;
void (*blk_write)(NANDFlashState *s);
void (*blk_erase)(NANDFlashState *s);
- void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset);
+ void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
uint32_t ioaddr_vmstate;
};
@@ -318,7 +323,7 @@ static const VMStateDescription vmstate_nand = {
VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
VMSTATE_INT32(iolen, NANDFlashState),
VMSTATE_UINT32(cmd, NANDFlashState),
- VMSTATE_UINT32(addr, NANDFlashState),
+ VMSTATE_UINT64(addr, NANDFlashState),
VMSTATE_INT32(addrlen, NANDFlashState),
VMSTATE_INT32(status, NANDFlashState),
VMSTATE_INT32(offset, NANDFlashState),
@@ -432,7 +437,7 @@ uint8_t nand_getio(NANDFlashState *s)
/* Allow sequential reading */
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
- offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+ offset = (int)(s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
s->offset = 0;
s->blk_load(s, s->addr, offset);
@@ -526,7 +531,7 @@ void nand_done(NANDFlashState *s)
/* Program a single page */
static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
{
- uint32_t off, page, sector, soff;
+ uint64_t off, page, sector, soff;
uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
if (PAGE(s->addr) >= s->pages)
return;
@@ -539,7 +544,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
off = (s->addr & PAGE_MASK) + s->offset;
soff = SECTOR_OFFSET(s->addr);
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
- printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
@@ -551,20 +556,20 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
}
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
} else {
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
sector = off >> 9;
soff = off & 0x1ff;
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
- printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
memcpy(iobuf + soff, s->io, s->iolen);
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
}
s->offset = 0;
}
@@ -572,7 +577,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
/* Erase a single block */
static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
{
- uint32_t i, page, addr;
+ uint64_t i, page, addr;
uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
@@ -589,34 +594,35 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
for (; i < page; i ++)
if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, i);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
} else {
addr = PAGE_START(addr);
page = addr >> 9;
if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: read error in sector %i\n", __FUNCTION__, page);
+ printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, page);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
memset(iobuf, 0xff, 0x200);
i = (addr & ~0x1ff) + 0x200;
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
i < addr; i += 0x200)
if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+ printf("%s: write error in sector %" PRIu64 "\n",
+ __func__, i >> 9);
page = i >> 9;
if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: read error in sector %i\n", __FUNCTION__, page);
+ printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, page);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
}
}
static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
- uint32_t addr, int offset)
+ uint64_t addr, int offset)
{
if (PAGE(addr) >= s->pages)
return;
@@ -624,8 +630,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
if (s->bdrv) {
if (s->mem_oob) {
if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
- printf("%s: read error in sector %i\n",
- __FUNCTION__, SECTOR(addr));
+ printf("%s: read error in sector %" PRIu64 "\n",
+ __func__, SECTOR(addr));
memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
s->storage + (PAGE(s->addr) << OOB_SHIFT),
OOB_SIZE);
@@ -633,8 +639,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
} else {
if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
s->io, (PAGE_SECTORS + 2)) == -1)
- printf("%s: read error in sector %i\n",
- __FUNCTION__, PAGE_START(addr) >> 9);
+ printf("%s: read error in sector %" PRIu64 "\n",
+ __func__, PAGE_START(addr) >> 9);
s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
}
} else {
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 08/15] hw/nand: Support devices wider than 8 bits
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (6 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 07/15] hw/nand: Support large NAND devices Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 09/15] hw/nand: Support multiple reads following READ STATUS Peter Maydell
` (6 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Support NAND devices which are wider than 8 bits.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/flash.h | 5 ++-
hw/nand.c | 119 +++++++++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 89 insertions(+), 35 deletions(-)
diff --git a/hw/flash.h b/hw/flash.h
index a992bb8..132ad29 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -24,8 +24,9 @@ void nand_done(NANDFlashState *s);
void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd);
void nand_getpins(NANDFlashState *s, int *rb);
-void nand_setio(NANDFlashState *s, uint8_t value);
-uint8_t nand_getio(NANDFlashState *s);
+void nand_setio(NANDFlashState *s, uint32_t value);
+uint32_t nand_getio(NANDFlashState *s);
+uint32_t nand_getbuswidth(NANDFlashState *s);
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
diff --git a/hw/nand.c b/hw/nand.c
index 18aa226..2e98f25 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -49,6 +49,7 @@
struct NANDFlashState {
uint8_t manf_id, chip_id;
+ uint8_t buswidth; /* in BYTES */
int size, pages;
int page_shift, oob_shift, erase_shift, addr_shift;
uint8_t *storage;
@@ -215,6 +216,14 @@ static void nand_reset(NANDFlashState *s)
s->status &= NAND_IOSTATUS_UNPROTCT;
}
+static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
+{
+ s->ioaddr[s->iolen++] = value;
+ for (value = s->buswidth; --value;) {
+ s->ioaddr[s->iolen++] = 0;
+ }
+}
+
static void nand_command(NANDFlashState *s)
{
unsigned int offset;
@@ -224,15 +233,19 @@ static void nand_command(NANDFlashState *s)
break;
case NAND_CMD_READID:
- s->io[0] = s->manf_id;
- s->io[1] = s->chip_id;
- s->io[2] = 'Q'; /* Don't-care byte (often 0xa5) */
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
- s->io[3] = 0x15; /* Page Size, Block Size, Spare Size.. */
- else
- s->io[3] = 0xc0; /* Multi-plane */
s->ioaddr = s->io;
- s->iolen = 4;
+ s->iolen = 0;
+ nand_pushio_byte(s, s->manf_id);
+ nand_pushio_byte(s, s->chip_id);
+ nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
+ if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+ /* Page Size, Block Size, Spare Size; bit 6 indicates
+ * 8 vs 16 bit width NAND.
+ */
+ nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
+ } else {
+ nand_pushio_byte(s, 0xc0); /* Multi-plane */
+ }
break;
case NAND_CMD_RANDOMREAD2:
@@ -277,9 +290,9 @@ static void nand_command(NANDFlashState *s)
break;
case NAND_CMD_READSTATUS:
- s->io[0] = s->status;
s->ioaddr = s->io;
- s->iolen = 1;
+ s->iolen = 0;
+ nand_pushio_byte(s, s->status);
break;
default:
@@ -357,8 +370,10 @@ void nand_getpins(NANDFlashState *s, int *rb)
*rb = 1;
}
-void nand_setio(NANDFlashState *s, uint8_t value)
+void nand_setio(NANDFlashState *s, uint32_t value)
{
+ int i;
+
if (!s->ce && s->cle) {
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
@@ -404,36 +419,64 @@ void nand_setio(NANDFlashState *s, uint8_t value)
s->addr = (s->addr & mask) | v;
s->addrlen ++;
- if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
- nand_command(s);
-
- if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- s->addrlen == 3 && (
- s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1))
- nand_command(s);
- if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- s->addrlen == 4 && (
- s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1))
- nand_command(s);
+ switch (s->addrlen) {
+ case 1:
+ if (s->cmd == NAND_CMD_READID) {
+ nand_command(s);
+ }
+ break;
+ case 2: /* fix cache address as a byte address */
+ s->addr <<= (s->buswidth - 1);
+ break;
+ case 3:
+ if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+ && (s->cmd == NAND_CMD_READ0
+ || s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+ nand_command(s);
+ }
+ break;
+ case 4:
+ if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+ && nand_flash_ids[s->chip_id].size < 256 /* 1Gb or less */
+ && (s->cmd == NAND_CMD_READ0 ||
+ s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+ nand_command(s);
+ }
+ break;
+ case 5:
+ if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+ && nand_flash_ids[s->chip_id].size >= 256 /* 2Gb or more */
+ && (s->cmd == NAND_CMD_READ0 ||
+ s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+ nand_command(s);
+ }
+ break;
+ default:
+ break;
+ }
}
if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
- if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
- s->io[s->iolen ++] = value;
+ if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
+ for (i = s->buswidth; i--; value >>= 8) {
+ s->io[s->iolen++] = (uint8_t)(value & 0xff);
+ }
+ }
} else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
if ((s->addr & ((1 << s->addr_shift) - 1)) <
- (1 << s->page_shift) + (1 << s->oob_shift)) {
- s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
- s->addr ++;
+ (1 << s->page_shift) + (1 << s->oob_shift)) {
+ for (i = s->buswidth; i--; s->addr++, value >>= 8) {
+ s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
+ (uint8_t)(value & 0xff);
+ }
}
}
}
-uint8_t nand_getio(NANDFlashState *s)
+uint32_t nand_getio(NANDFlashState *s)
{
int offset;
+ uint32_t x = 0;
/* Allow sequential reading */
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
@@ -450,9 +493,18 @@ uint8_t nand_getio(NANDFlashState *s)
if (s->ce || s->iolen <= 0)
return 0;
- s->iolen --;
- s->addr++;
- return *(s->ioaddr ++);
+ for (offset = s->buswidth; offset--;) {
+ x |= s->ioaddr[offset] << (offset << 3);
+ }
+ s->addr += s->buswidth;
+ s->ioaddr += s->buswidth;
+ s->iolen -= s->buswidth;
+ return x;
+}
+
+uint32_t nand_getbuswidth(NANDFlashState *s)
+{
+ return s->buswidth << 3;
}
NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
@@ -468,6 +520,7 @@ NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
s->bdrv = bdrv;
s->manf_id = manf_id;
s->chip_id = chip_id;
+ s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
s->size = nand_flash_ids[s->chip_id].size << 20;
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
s->page_shift = 11;
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 09/15] hw/nand: Support multiple reads following READ STATUS
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (7 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 08/15] hw/nand: Support devices wider than 8 bits Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 10/15] hw/nand: Writing to NAND can only clear bits Peter Maydell
` (5 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
After receiving READ STATUS command all subsequent IO reads should return
the status register value until another command is issued.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/nand.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/hw/nand.c b/hw/nand.c
index 2e98f25..e6c551d 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -496,9 +496,14 @@ uint32_t nand_getio(NANDFlashState *s)
for (offset = s->buswidth; offset--;) {
x |= s->ioaddr[offset] << (offset << 3);
}
- s->addr += s->buswidth;
- s->ioaddr += s->buswidth;
- s->iolen -= s->buswidth;
+ /* after receiving READ STATUS command all subsequent reads will
+ * return the status register value until another command is issued
+ */
+ if (s->cmd != NAND_CMD_READSTATUS) {
+ s->addr += s->buswidth;
+ s->ioaddr += s->buswidth;
+ s->iolen -= s->buswidth;
+ }
return x;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 10/15] hw/nand: Writing to NAND can only clear bits
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (8 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 09/15] hw/nand: Support multiple reads following READ STATUS Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 11/15] hw/nand: qdevify Peter Maydell
` (4 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
Writing to a NAND device cannot set bits, it can only clear them;
implement this rather than simply copying the data.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/nand.c | 17 +++++++++++++----
1 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/hw/nand.c b/hw/nand.c
index e6c551d..d068eb6 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -75,6 +75,15 @@ struct NANDFlashState {
uint32_t ioaddr_vmstate;
};
+static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
+{
+ /* Like memcpy() but we logical-AND the data into the destination */
+ int i;
+ for (i = 0; i < n; i++) {
+ dest[i] &= src[i];
+ }
+}
+
# define NAND_NO_AUTOINCR 0x00000001
# define NAND_BUSWIDTH_16 0x00000002
# define NAND_NO_PADDING 0x00000004
@@ -595,7 +604,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
return;
if (!s->bdrv) {
- memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
+ mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
s->offset, s->io, s->iolen);
} else if (s->mem_oob) {
sector = SECTOR(s->addr);
@@ -606,10 +615,10 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
return;
}
- memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
+ mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
if (off + s->iolen > PAGE_SIZE) {
page = PAGE(s->addr);
- memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
+ mem_and(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
}
@@ -624,7 +633,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
return;
}
- memcpy(iobuf + soff, s->io, s->iolen);
+ mem_and(iobuf + soff, s->io, s->iolen);
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 11/15] hw/nand: qdevify
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (9 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 10/15] hw/nand: Writing to NAND can only clear bits Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 12/15] onenand: Pass BlockDriverState to init function Peter Maydell
` (3 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Qdevify the NAND device.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/axis_dev88.c | 2 +-
hw/flash.h | 14 ++---
hw/nand.c | 164 +++++++++++++++++++++++++++++++------------------------
hw/spitz.c | 2 +-
hw/tc6393xb.c | 2 +-
5 files changed, 102 insertions(+), 82 deletions(-)
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index de1f5a5..e0a8c14 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -37,7 +37,7 @@
struct nand_state_t
{
- NANDFlashState *nand;
+ DeviceState *nand;
unsigned int rdy:1;
unsigned int ale:1;
unsigned int cle:1;
diff --git a/hw/flash.h b/hw/flash.h
index 132ad29..43260ce 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -18,15 +18,13 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
int be);
/* nand.c */
-typedef struct NANDFlashState NANDFlashState;
-NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
-void nand_done(NANDFlashState *s);
-void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd);
-void nand_getpins(NANDFlashState *s, int *rb);
-void nand_setio(NANDFlashState *s, uint32_t value);
-uint32_t nand_getio(NANDFlashState *s);
-uint32_t nand_getbuswidth(NANDFlashState *s);
+void nand_getpins(DeviceState *dev, int *rb);
+void nand_setio(DeviceState *dev, uint32_t value);
+uint32_t nand_getio(DeviceState *dev);
+uint32_t nand_getbuswidth(DeviceState *dev);
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
diff --git a/hw/nand.c b/hw/nand.c
index d068eb6..2f5a40e 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -18,6 +18,7 @@
# include "hw.h"
# include "flash.h"
# include "blockdev.h"
+# include "sysbus.h"
# define NAND_CMD_READ0 0x00
# define NAND_CMD_READ1 0x01
@@ -47,7 +48,9 @@
# define MAX_PAGE 0x800
# define MAX_OOB 0x40
+typedef struct NANDFlashState NANDFlashState;
struct NANDFlashState {
+ SysBusDevice busdev;
uint8_t manf_id, chip_id;
uint8_t buswidth; /* in BYTES */
int size, pages;
@@ -215,8 +218,9 @@ static const struct {
[0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 },
};
-static void nand_reset(NANDFlashState *s)
+static void nand_reset(DeviceState *dev)
{
+ NANDFlashState *s = FROM_SYSBUS(NANDFlashState, sysbus_from_qdev(dev));
s->cmd = NAND_CMD_READ0;
s->addr = 0;
s->addrlen = 0;
@@ -270,7 +274,7 @@ static void nand_command(NANDFlashState *s)
break;
case NAND_CMD_RESET:
- nand_reset(s);
+ nand_reset(&s->busdev.qdev);
break;
case NAND_CMD_PAGEPROGRAM1:
@@ -354,15 +358,84 @@ static const VMStateDescription vmstate_nand = {
}
};
+static int nand_device_init(SysBusDevice *dev)
+{
+ int pagesize;
+ NANDFlashState *s = FROM_SYSBUS(NANDFlashState, dev);
+ s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
+ s->size = nand_flash_ids[s->chip_id].size << 20;
+ if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+ s->page_shift = 11;
+ s->erase_shift = 6;
+ } else {
+ s->page_shift = nand_flash_ids[s->chip_id].page_shift;
+ s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+ }
+
+ switch (1 << s->page_shift) {
+ case 256:
+ nand_init_256(s);
+ break;
+ case 512:
+ nand_init_512(s);
+ break;
+ case 2048:
+ nand_init_2048(s);
+ break;
+ default:
+ hw_error("%s: Unsupported NAND block size.\n", __func__);
+ }
+
+ pagesize = 1 << s->oob_shift;
+ s->mem_oob = 1;
+ if (s->bdrv && bdrv_getlength(s->bdrv) >=
+ (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
+ pagesize = 0;
+ s->mem_oob = 0;
+ }
+
+ if (!s->bdrv) {
+ pagesize += 1 << s->page_shift;
+ }
+ if (pagesize) {
+ s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
+ 0xff, s->pages * pagesize);
+ }
+ /* Give s->ioaddr a sane value in case we save state before it is used. */
+ s->ioaddr = s->io;
+
+ return 0;
+}
+
+static SysBusDeviceInfo nand_info = {
+ .init = nand_device_init,
+ .qdev.name = "nand",
+ .qdev.size = sizeof(NANDFlashState),
+ .qdev.reset = nand_reset,
+ .qdev.vmsd = &vmstate_nand,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
+ DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
+ DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
+
+static void nand_create_device(void)
+{
+ sysbus_register_withprop(&nand_info);
+}
+
/*
* Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip
* outputs are R/B and eight I/O pins.
*
* CE, WP and R/B are active low.
*/
-void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd)
{
+ NANDFlashState *s = (NANDFlashState *)dev;
s->cle = cle;
s->ale = ale;
s->ce = ce;
@@ -374,15 +447,15 @@ void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
s->status &= ~NAND_IOSTATUS_UNPROTCT;
}
-void nand_getpins(NANDFlashState *s, int *rb)
+void nand_getpins(DeviceState *dev, int *rb)
{
*rb = 1;
}
-void nand_setio(NANDFlashState *s, uint32_t value)
+void nand_setio(DeviceState *dev, uint32_t value)
{
int i;
-
+ NANDFlashState *s = (NANDFlashState *)dev;
if (!s->ce && s->cle) {
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
@@ -482,10 +555,11 @@ void nand_setio(NANDFlashState *s, uint32_t value)
}
}
-uint32_t nand_getio(NANDFlashState *s)
+uint32_t nand_getio(DeviceState *dev)
{
int offset;
uint32_t x = 0;
+ NANDFlashState *s = (NANDFlashState *)dev;
/* Allow sequential reading */
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
@@ -516,82 +590,30 @@ uint32_t nand_getio(NANDFlashState *s)
return x;
}
-uint32_t nand_getbuswidth(NANDFlashState *s)
+uint32_t nand_getbuswidth(DeviceState *dev)
{
+ NANDFlashState *s = (NANDFlashState *)dev;
return s->buswidth << 3;
}
-NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
{
- int pagesize;
- NANDFlashState *s;
-
+ DeviceState *dev;
if (nand_flash_ids[chip_id].size == 0) {
hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
}
-
- s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
- s->bdrv = bdrv;
- s->manf_id = manf_id;
- s->chip_id = chip_id;
- s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
- s->size = nand_flash_ids[s->chip_id].size << 20;
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- s->page_shift = 11;
- s->erase_shift = 6;
- } else {
- s->page_shift = nand_flash_ids[s->chip_id].page_shift;
- s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+ dev = qdev_create(NULL, "nand");
+ qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
+ qdev_prop_set_uint8(dev, "chip_id", chip_id);
+ if (bdrv) {
+ qdev_prop_set_drive_nofail(dev, "drive", bdrv);
}
- switch (1 << s->page_shift) {
- case 256:
- nand_init_256(s);
- break;
- case 512:
- nand_init_512(s);
- break;
- case 2048:
- nand_init_2048(s);
- break;
- default:
- hw_error("%s: Unsupported NAND block size.\n", __FUNCTION__);
- }
-
- pagesize = 1 << s->oob_shift;
- s->mem_oob = 1;
- if (s->bdrv && bdrv_getlength(s->bdrv) >=
- (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
- pagesize = 0;
- s->mem_oob = 0;
- }
-
- if (!s->bdrv)
- pagesize += 1 << s->page_shift;
- if (pagesize)
- s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
- 0xff, s->pages * pagesize);
- /* Give s->ioaddr a sane value in case we save state before it
- is used. */
- s->ioaddr = s->io;
-
- vmstate_register(NULL, -1, &vmstate_nand, s);
-
- return s;
+ qdev_init_nofail(dev);
+ return dev;
}
-void nand_done(NANDFlashState *s)
-{
- if (s->bdrv) {
- bdrv_close(s->bdrv);
- bdrv_delete(s->bdrv);
- }
-
- if (!s->bdrv || s->mem_oob)
- qemu_free(s->storage);
-
- qemu_free(s);
-}
+device_init(nand_create_device)
#else
diff --git a/hw/spitz.c b/hw/spitz.c
index 78e9c34..c05b5f7 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -48,7 +48,7 @@
typedef struct {
SysBusDevice busdev;
- NANDFlashState *nand;
+ DeviceState *nand;
uint8_t ctl;
uint8_t manf_id;
uint8_t chip_id;
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index 4de0819..a1c48bf 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -118,7 +118,7 @@ struct TC6393xbState {
} nand;
int nand_enable;
uint32_t nand_phys;
- NANDFlashState *flash;
+ DeviceState *flash;
ECCState ecc;
DisplayState *ds;
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 12/15] onenand: Pass BlockDriverState to init function
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (10 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 11/15] hw/nand: qdevify Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 13/15] onenand: Handle various ID fields separately Peter Maydell
` (2 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
Pass the BlockDriverState to the onenand init function so it doesn't
need to look up the drive itself.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/flash.h | 3 ++-
hw/nseries.c | 10 ++++++----
hw/onenand.c | 14 ++++++++------
3 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/hw/flash.h b/hw/flash.h
index 43260ce..1aae43d 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -38,7 +38,8 @@ uint32_t nand_getbuswidth(DeviceState *dev);
/* onenand.c */
void onenand_base_update(void *opaque, target_phys_addr_t new);
void onenand_base_unmap(void *opaque);
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq);
+void *onenand_init(BlockDriverState *bdrv, uint32_t id,
+ int regshift, qemu_irq irq);
void *onenand_raw_otp(void *opaque);
/* ecc.c */
diff --git a/hw/nseries.c b/hw/nseries.c
index 45b52bb..96cc490 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -31,6 +31,7 @@
#include "hw.h"
#include "bt.h"
#include "loader.h"
+#include "blockdev.h"
/* Nokia N8x0 support */
struct n800_s {
@@ -163,13 +164,14 @@ static const uint8_t n8x0_cal_bt_id[] = {
static void n8x0_nand_setup(struct n800_s *s)
{
char *otp_region;
+ DriveInfo *dinfo;
+ dinfo = drive_get(IF_MTD, 0, 0);
/* Either ec40xx or ec48xx are OK for the ID */
+ s->nand = onenand_init(dinfo ? dinfo->bdrv : 0, 0xec4800, 1,
+ qdev_get_gpio_in(s->cpu->gpio, N8X0_ONENAND_GPIO));
omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
- onenand_base_unmap,
- (s->nand = onenand_init(0xec4800, 1,
- qdev_get_gpio_in(s->cpu->gpio,
- N8X0_ONENAND_GPIO))));
+ onenand_base_unmap, s->nand);
otp_region = onenand_raw_otp(s->nand);
memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
diff --git a/hw/onenand.c b/hw/onenand.c
index 71c1ab4..3a19d7f 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -615,10 +615,10 @@ static CPUWriteMemoryFunc * const onenand_writefn[] = {
onenand_write,
};
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
+void *onenand_init(BlockDriverState *bdrv, uint32_t id,
+ int regshift, qemu_irq irq)
{
OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
- DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
uint32_t size = 1 << (24 + ((id >> 12) & 7));
void *ram;
@@ -632,11 +632,13 @@ void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
s->iomemtype = cpu_register_io_memory(onenand_readfn,
onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
- if (!dinfo)
+ s->bdrv = bdrv;
+ if (!s->bdrv) {
s->image = memset(qemu_malloc(size + (size >> 5)),
- 0xff, size + (size >> 5));
- else
- s->bdrv = dinfo->bdrv;
+ 0xff, size + (size >> 5));
+ } else {
+ s->bdrv_cur = s->bdrv;
+ }
s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
0xff, (64 + 2) << PAGE_SHIFT);
s->ram = qemu_ram_alloc(NULL, "onenand.ram", 0xc000 << s->shift);
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 13/15] onenand: Handle various ID fields separately
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (11 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 12/15] onenand: Pass BlockDriverState to init function Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 14/15] onenand: Ignore zero writes to boot command space Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 15/15] hw/onenand: program actions can only clear bits Peter Maydell
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Handle the manufacturer, device and version IDs separately rather than
smooshing them all together into a single uint32_t. Note that the ID
registers are actually 16 bit, even though typically the top bits are 0
and the Read Identification Data command only returns the bottom 8 bits.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/flash.h | 3 ++-
hw/nseries.c | 5 +++--
hw/onenand.c | 29 ++++++++++++++++++-----------
3 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/hw/flash.h b/hw/flash.h
index 1aae43d..1064fd0 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -38,7 +38,8 @@ uint32_t nand_getbuswidth(DeviceState *dev);
/* onenand.c */
void onenand_base_update(void *opaque, target_phys_addr_t new);
void onenand_base_unmap(void *opaque);
-void *onenand_init(BlockDriverState *bdrv, uint32_t id,
+void *onenand_init(BlockDriverState *bdrv,
+ uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
int regshift, qemu_irq irq);
void *onenand_raw_otp(void *opaque);
diff --git a/hw/nseries.c b/hw/nseries.c
index 96cc490..7cdba25 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -167,8 +167,9 @@ static void n8x0_nand_setup(struct n800_s *s)
DriveInfo *dinfo;
dinfo = drive_get(IF_MTD, 0, 0);
- /* Either ec40xx or ec48xx are OK for the ID */
- s->nand = onenand_init(dinfo ? dinfo->bdrv : 0, 0xec4800, 1,
+ /* Either 0x40 or 0x48 are OK for the device ID */
+ s->nand = onenand_init(dinfo ? dinfo->bdrv : 0,
+ NAND_MFR_SAMSUNG, 0x48, 0, 1,
qdev_get_gpio_in(s->cpu->gpio, N8X0_ONENAND_GPIO));
omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
onenand_base_unmap, s->nand);
diff --git a/hw/onenand.c b/hw/onenand.c
index 3a19d7f..9f02736 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -31,7 +31,11 @@
#define BLOCK_SHIFT (PAGE_SHIFT + 6)
typedef struct {
- uint32_t id;
+ struct {
+ uint16_t man;
+ uint16_t dev;
+ uint16_t ver;
+ } id;
int shift;
target_phys_addr_t base;
qemu_irq intr;
@@ -453,12 +457,12 @@ static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
return lduw_le_p(s->boot[0] + addr);
case 0xf000: /* Manufacturer ID */
- return (s->id >> 16) & 0xff;
+ return s->id.man;
case 0xf001: /* Device ID */
- return (s->id >> 8) & 0xff;
- /* TODO: get the following values from a real chip! */
+ return s->id.dev;
case 0xf002: /* Version ID */
- return (s->id >> 0) & 0xff;
+ return s->id.ver;
+ /* TODO: get the following values from a real chip! */
case 0xf003: /* Data Buffer size */
return 1 << PAGE_SHIFT;
case 0xf004: /* Boot Buffer size */
@@ -541,8 +545,8 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
case 0x0090: /* Read Identification Data */
memset(s->boot[0], 0, 3 << s->shift);
- s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff;
- s->boot[0][1 << s->shift] = (s->id >> 8) & 0xff;
+ s->boot[0][0 << s->shift] = s->id.man & 0xff;
+ s->boot[0][1 << s->shift] = s->id.dev & 0xff;
s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
break;
@@ -615,21 +619,24 @@ static CPUWriteMemoryFunc * const onenand_writefn[] = {
onenand_write,
};
-void *onenand_init(BlockDriverState *bdrv, uint32_t id,
+void *onenand_init(BlockDriverState *bdrv,
+ uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
int regshift, qemu_irq irq)
{
OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
- uint32_t size = 1 << (24 + ((id >> 12) & 7));
+ uint32_t size = 1 << (24 + ((dev_id >> 4) & 7));
void *ram;
s->shift = regshift;
s->intr = irq;
s->rdy = NULL;
- s->id = id;
+ s->id.man = man_id;
+ s->id.dev = dev_id;
+ s->id.ver = ver_id;
s->blocks = size >> BLOCK_SHIFT;
s->secs = size >> 9;
s->blockwp = qemu_malloc(s->blocks);
- s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
+ s->density_mask = (dev_id & 0x08) ? (1 << (6 + ((dev_id >> 4) & 7))) : 0;
s->iomemtype = cpu_register_io_memory(onenand_readfn,
onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
s->bdrv = bdrv;
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 14/15] onenand: Ignore zero writes to boot command space
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (12 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 13/15] onenand: Handle various ID fields separately Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-29 15:35 ` [Qemu-devel] [PATCH 15/15] hw/onenand: program actions can only clear bits Peter Maydell
14 siblings, 0 replies; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
Ignore zero writes to the boot command space; Linux will issue
these in the powerdown/reset sequence.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/onenand.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/hw/onenand.c b/hw/onenand.c
index 9f02736..0edcfe2 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -550,6 +550,13 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
break;
+ case 0x0000:
+ /* ignore zero writes without error messages,
+ * linux omap2/3 kernel will issue these upon
+ * powerdown/reset sequence.
+ */
+ break;
+
default:
fprintf(stderr, "%s: unknown OneNAND boot command %x\n",
__FUNCTION__, value);
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 15/15] hw/onenand: program actions can only clear bits
2011-07-29 15:35 [Qemu-devel] [PULL 00/15] omap patches (gpio, nand, onenand, lm832x) Peter Maydell
` (13 preceding siblings ...)
2011-07-29 15:35 ` [Qemu-devel] [PATCH 14/15] onenand: Ignore zero writes to boot command space Peter Maydell
@ 2011-07-29 15:35 ` Peter Maydell
2011-07-30 5:19 ` andrzej zaborowski
14 siblings, 1 reply; 19+ messages in thread
From: Peter Maydell @ 2011-07-29 15:35 UTC (permalink / raw)
To: qemu-devel, Anthony Liguori
From: Juha Riihimäki <juha.riihimaki@nokia.com>
The program actions onenand_prog_main() and onenand_prog_spare()
can only set bits.
This implies a rewrite of onenand_erase() to not use the program
functions, since erase does need to set bits.
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/onenand.c | 135 +++++++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 106 insertions(+), 29 deletions(-)
diff --git a/hw/onenand.c b/hw/onenand.c
index 0edcfe2..981d23c 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -179,14 +179,39 @@ static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
void *src)
{
- if (s->bdrv_cur)
- return bdrv_write(s->bdrv_cur, sec, src, secn) < 0;
- else if (sec + secn > s->secs_cur)
- return 1;
-
- memcpy(s->current + (sec << 9), src, secn << 9);
+ int result = 0;
+
+ if (secn > 0) {
+ uint32_t size = (uint32_t)secn * 512;
+ const uint8_t *sp = (const uint8_t *)src;
+ uint8_t *dp = 0;
+ if (s->bdrv_cur) {
+ dp = qemu_malloc(size);
+ if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
+ result = 1;
+ }
+ } else {
+ if (sec + secn > s->secs_cur) {
+ result = 1;
+ } else {
+ dp = (uint8_t *)s->current + (sec << 9);
+ }
+ }
+ if (!result) {
+ uint32_t i;
+ for (i = 0; i < size; i++) {
+ dp[i] &= sp[i];
+ }
+ if (s->bdrv_cur) {
+ result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
+ }
+ }
+ if (dp && s->bdrv_cur) {
+ qemu_free(dp);
+ }
+ }
- return 0;
+ return result;
}
static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
@@ -209,35 +234,87 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
void *src)
{
- uint8_t buf[512];
-
- if (s->bdrv_cur) {
- if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
- return 1;
- memcpy(buf + ((sec & 31) << 4), src, secn << 4);
- return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0;
- } else if (sec + secn > s->secs_cur)
- return 1;
-
- memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4);
-
- return 0;
+ int result = 0;
+ if (secn > 0) {
+ const uint8_t *sp = (const uint8_t *)src;
+ uint8_t *dp = 0, *dpp = 0;
+ if (s->bdrv_cur) {
+ dp = qemu_malloc(512);
+ if (!dp || bdrv_read(s->bdrv_cur,
+ s->secs_cur + (sec >> 5),
+ dp, 1) < 0) {
+ result = 1;
+ } else {
+ dpp = dp + ((sec & 31) << 4);
+ }
+ } else {
+ if (sec + secn > s->secs_cur) {
+ result = 1;
+ } else {
+ dpp = s->current + (s->secs_cur << 9) + (sec << 4);
+ }
+ }
+ if (!result) {
+ uint32_t i;
+ for (i = 0; i < (secn << 4); i++) {
+ dpp[i] &= sp[i];
+ }
+ if (s->bdrv_cur) {
+ result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
+ dp, 1) < 0;
+ }
+ }
+ if (dp) {
+ qemu_free(dp);
+ }
+ }
+ return result;
}
static inline int onenand_erase(OneNANDState *s, int sec, int num)
{
- /* TODO: optimise */
- uint8_t buf[512];
-
- memset(buf, 0xff, sizeof(buf));
- for (; num > 0; num --, sec ++) {
- if (onenand_prog_main(s, sec, 1, buf))
- return 1;
- if (onenand_prog_spare(s, sec, 1, buf))
- return 1;
+ uint8_t *blankbuf, *tmpbuf;
+ blankbuf = qemu_malloc(512);
+ if (!blankbuf) {
+ return 1;
+ }
+ tmpbuf = qemu_malloc(512);
+ if (!tmpbuf) {
+ qemu_free(blankbuf);
+ return 1;
+ }
+ memset(blankbuf, 0xff, 512);
+ for (; num > 0; num--, sec++) {
+ if (s->bdrv_cur) {
+ int erasesec = s->secs_cur + (sec >> 5);
+ if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1)) {
+ goto fail;
+ }
+ if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+ goto fail;
+ }
+ memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
+ if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+ goto fail;
+ }
+ } else {
+ if (sec + 1 > s->secs_cur) {
+ goto fail;
+ }
+ memcpy(s->current + (sec << 9), blankbuf, 512);
+ memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
+ blankbuf, 1 << 4);
+ }
}
+ qemu_free(tmpbuf);
+ qemu_free(blankbuf);
return 0;
+
+fail:
+ qemu_free(tmpbuf);
+ qemu_free(blankbuf);
+ return 1;
}
static void onenand_command(OneNANDState *s, int cmd)
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 15/15] hw/onenand: program actions can only clear bits
2011-07-29 15:35 ` [Qemu-devel] [PATCH 15/15] hw/onenand: program actions can only clear bits Peter Maydell
@ 2011-07-30 5:19 ` andrzej zaborowski
0 siblings, 0 replies; 19+ messages in thread
From: andrzej zaborowski @ 2011-07-30 5:19 UTC (permalink / raw)
To: Peter Maydell; +Cc: Anthony Liguori, qemu-devel
On 29 July 2011 17:35, Peter Maydell <peter.maydell@linaro.org> wrote:
> From: Juha Riihimäki <juha.riihimaki@nokia.com>
>
> The program actions onenand_prog_main() and onenand_prog_spare()
> can only set bits.
>
> This implies a rewrite of onenand_erase() to not use the program
> functions, since erase does need to set bits.
>
> Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
> [Riku Voipio: Fixes and restructuring patchset]
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> [Peter Maydell: More fixes and cleanups for upstream submission]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/onenand.c | 135 +++++++++++++++++++++++++++++++++++++++++++++------------
> 1 files changed, 106 insertions(+), 29 deletions(-)
>
> diff --git a/hw/onenand.c b/hw/onenand.c
...
> static inline int onenand_erase(OneNANDState *s, int sec, int num)
> {
> - /* TODO: optimise */
> - uint8_t buf[512];
> -
> - memset(buf, 0xff, sizeof(buf));
> - for (; num > 0; num --, sec ++) {
> - if (onenand_prog_main(s, sec, 1, buf))
> - return 1;
> - if (onenand_prog_spare(s, sec, 1, buf))
> - return 1;
> + uint8_t *blankbuf, *tmpbuf;
> + blankbuf = qemu_malloc(512);
> + if (!blankbuf) {
> + return 1;
> + }
> + tmpbuf = qemu_malloc(512);
> + if (!tmpbuf) {
> + qemu_free(blankbuf);
> + return 1;
> + }
> + memset(blankbuf, 0xff, 512);
> + for (; num > 0; num--, sec++) {
> + if (s->bdrv_cur) {
> + int erasesec = s->secs_cur + (sec >> 5);
> + if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1)) {
> + goto fail;
> + }
> + if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
> + goto fail;
> + }
> + memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
> + if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
> + goto fail;
> + }
By the way it seems that this can be optimised to require just one
read for the entire erase.
Cheers
^ permalink raw reply [flat|nested] 19+ messages in thread