hw/nand: qdevify

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>
Signed-off-by: Andrzej Zaborowski <andrew.zaborowski@intel.com>
This commit is contained in:
Juha Riihimäki 2011-07-29 16:35:24 +01:00 committed by Andrzej Zaborowski
parent 89f640bc04
commit d4220389ff
5 changed files with 103 additions and 81 deletions

View file

@ -37,7 +37,7 @@
struct nand_state_t struct nand_state_t
{ {
NANDFlashState *nand; DeviceState *nand;
unsigned int rdy:1; unsigned int rdy:1;
unsigned int ale:1; unsigned int ale:1;
unsigned int cle:1; unsigned int cle:1;

View file

@ -18,15 +18,13 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
int be); int be);
/* nand.c */ /* nand.c */
typedef struct NANDFlashState NANDFlashState; DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id); void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
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); uint8_t ce, uint8_t wp, uint8_t gnd);
void nand_getpins(NANDFlashState *s, int *rb); void nand_getpins(DeviceState *dev, int *rb);
void nand_setio(NANDFlashState *s, uint32_t value); void nand_setio(DeviceState *dev, uint32_t value);
uint32_t nand_getio(NANDFlashState *s); uint32_t nand_getio(DeviceState *dev);
uint32_t nand_getbuswidth(NANDFlashState *s); uint32_t nand_getbuswidth(DeviceState *dev);
#define NAND_MFR_TOSHIBA 0x98 #define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec #define NAND_MFR_SAMSUNG 0xec

164
hw/nand.c
View file

@ -18,6 +18,7 @@
# include "hw.h" # include "hw.h"
# include "flash.h" # include "flash.h"
# include "blockdev.h" # include "blockdev.h"
# include "sysbus.h"
# define NAND_CMD_READ0 0x00 # define NAND_CMD_READ0 0x00
# define NAND_CMD_READ1 0x01 # define NAND_CMD_READ1 0x01
@ -47,7 +48,9 @@
# define MAX_PAGE 0x800 # define MAX_PAGE 0x800
# define MAX_OOB 0x40 # define MAX_OOB 0x40
typedef struct NANDFlashState NANDFlashState;
struct NANDFlashState { struct NANDFlashState {
SysBusDevice busdev;
uint8_t manf_id, chip_id; uint8_t manf_id, chip_id;
uint8_t buswidth; /* in BYTES */ uint8_t buswidth; /* in BYTES */
int size, pages; int size, pages;
@ -215,8 +218,9 @@ static const struct {
[0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 }, [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->cmd = NAND_CMD_READ0;
s->addr = 0; s->addr = 0;
s->addrlen = 0; s->addrlen = 0;
@ -270,7 +274,7 @@ static void nand_command(NANDFlashState *s)
break; break;
case NAND_CMD_RESET: case NAND_CMD_RESET:
nand_reset(s); nand_reset(&s->busdev.qdev);
break; break;
case NAND_CMD_PAGEPROGRAM1: case NAND_CMD_PAGEPROGRAM1:
@ -354,15 +358,85 @@ 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 * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip
* outputs are R/B and eight I/O pins. * outputs are R/B and eight I/O pins.
* *
* CE, WP and R/B are active low. * 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) uint8_t ce, uint8_t wp, uint8_t gnd)
{ {
NANDFlashState *s = (NANDFlashState *) dev;
s->cle = cle; s->cle = cle;
s->ale = ale; s->ale = ale;
s->ce = ce; s->ce = ce;
@ -374,15 +448,15 @@ void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
s->status &= ~NAND_IOSTATUS_UNPROTCT; s->status &= ~NAND_IOSTATUS_UNPROTCT;
} }
void nand_getpins(NANDFlashState *s, int *rb) void nand_getpins(DeviceState *dev, int *rb)
{ {
*rb = 1; *rb = 1;
} }
void nand_setio(NANDFlashState *s, uint32_t value) void nand_setio(DeviceState *dev, uint32_t value)
{ {
int i; int i;
NANDFlashState *s = (NANDFlashState *) dev;
if (!s->ce && s->cle) { if (!s->ce && s->cle) {
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) { if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2) if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
@ -482,10 +556,11 @@ void nand_setio(NANDFlashState *s, uint32_t value)
} }
} }
uint32_t nand_getio(NANDFlashState *s) uint32_t nand_getio(DeviceState *dev)
{ {
int offset; int offset;
uint32_t x = 0; uint32_t x = 0;
NANDFlashState *s = (NANDFlashState *) dev;
/* Allow sequential reading */ /* Allow sequential reading */
if (!s->iolen && s->cmd == NAND_CMD_READ0) { if (!s->iolen && s->cmd == NAND_CMD_READ0) {
@ -516,82 +591,31 @@ uint32_t nand_getio(NANDFlashState *s)
return x; return x;
} }
uint32_t nand_getbuswidth(NANDFlashState *s) uint32_t nand_getbuswidth(DeviceState *dev)
{ {
NANDFlashState *s = (NANDFlashState *) dev;
return s->buswidth << 3; 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; DeviceState *dev;
NANDFlashState *s;
if (nand_flash_ids[chip_id].size == 0) { if (nand_flash_ids[chip_id].size == 0) {
hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__); hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
} }
dev = qdev_create(NULL, "nand");
s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState)); qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
s->bdrv = bdrv; qdev_prop_set_uint8(dev, "chip_id", chip_id);
s->manf_id = manf_id; if (bdrv) {
s->chip_id = chip_id; qdev_prop_set_drive_nofail(dev, "drive", bdrv);
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) { qdev_init_nofail(dev);
case 256: return dev;
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; device_init(nand_create_device)
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;
}
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);
}
#else #else

View file

@ -48,7 +48,7 @@
typedef struct { typedef struct {
SysBusDevice busdev; SysBusDevice busdev;
NANDFlashState *nand; DeviceState *nand;
uint8_t ctl; uint8_t ctl;
uint8_t manf_id; uint8_t manf_id;
uint8_t chip_id; uint8_t chip_id;

View file

@ -118,7 +118,7 @@ struct TC6393xbState {
} nand; } nand;
int nand_enable; int nand_enable;
uint32_t nand_phys; uint32_t nand_phys;
NANDFlashState *flash; DeviceState *flash;
ECCState ecc; ECCState ecc;
DisplayState *ds; DisplayState *ds;