mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-09-09 00:07:57 -06:00
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:
parent
89f640bc04
commit
d4220389ff
5 changed files with 103 additions and 81 deletions
|
@ -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;
|
||||||
|
|
14
hw/flash.h
14
hw/flash.h
|
@ -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
164
hw/nand.c
|
@ -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;
|
|
||||||
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)
|
device_init(nand_create_device)
|
||||||
{
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue