#include "qemu/osdep.h"
#include "hw/hw.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/block/flash.h"
#include "sysemu/block-backend.h"
-#include "hw/qdev.h"
+#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "qom/object.h"
# define NAND_CMD_READ0 0x00
# define NAND_CMD_READ1 0x01
#define TYPE_NAND "nand"
-#define NAND(obj) \
- OBJECT_CHECK(NANDFlashState, (obj), TYPE_NAND)
+OBJECT_DECLARE_SIMPLE_TYPE(NANDFlashState, NAND)
static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
{
# define NAND_IO
# define PAGE(addr) ((addr) >> ADDR_SHIFT)
-# define PAGE_START(page) (PAGE(page) * (PAGE_SIZE + OOB_SIZE))
+# define PAGE_START(page) (PAGE(page) * (NAND_PAGE_SIZE + OOB_SIZE))
# define PAGE_MASK ((1 << ADDR_SHIFT) - 1)
# define OOB_SHIFT (PAGE_SHIFT - 5)
# define OOB_SIZE (1 << OOB_SHIFT)
# define SECTOR(addr) ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
# define SECTOR_OFFSET(addr) ((addr) & ((511 >> PAGE_SHIFT) << 8))
-# define PAGE_SIZE 256
+# define NAND_PAGE_SIZE 256
# define PAGE_SHIFT 8
# define PAGE_SECTORS 1
# define ADDR_SHIFT 8
# include "nand.c"
-# define PAGE_SIZE 512
+# define NAND_PAGE_SIZE 512
# define PAGE_SHIFT 9
# define PAGE_SECTORS 1
# define ADDR_SHIFT 8
# include "nand.c"
-# define PAGE_SIZE 2048
+# define NAND_PAGE_SIZE 2048
# define PAGE_SHIFT 11
# define PAGE_SECTORS 4
# define ADDR_SHIFT 16
# include "nand.c"
-/* Information based on Linux drivers/mtd/nand/nand_ids.c */
+/* Information based on Linux drivers/mtd/nand/raw/nand_ids.c */
static const struct {
int size;
int width;
} nand_flash_ids[0x100] = {
[0 ... 0xff] = { 0 },
- [0x6e] = { 1, 8, 8, 4, 0 },
- [0x64] = { 2, 8, 8, 4, 0 },
[0x6b] = { 4, 8, 9, 4, 0 },
- [0xe8] = { 1, 8, 8, 4, 0 },
- [0xec] = { 1, 8, 8, 4, 0 },
- [0xea] = { 2, 8, 8, 4, 0 },
- [0xd5] = { 4, 8, 9, 4, 0 },
[0xe3] = { 4, 8, 9, 4, 0 },
[0xe5] = { 4, 8, 9, 4, 0 },
[0xd6] = { 8, 8, 9, 4, 0 },
-
- [0x39] = { 8, 8, 9, 4, 0 },
[0xe6] = { 8, 8, 9, 4, 0 },
- [0x49] = { 8, 16, 9, 4, NAND_BUSWIDTH_16 },
- [0x59] = { 8, 16, 9, 4, NAND_BUSWIDTH_16 },
[0x33] = { 16, 8, 9, 5, 0 },
[0x73] = { 16, 8, 9, 5, 0 },
break;
default:
- printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd);
+ printf("%s: Unknown NAND command 0x%02x\n", __func__, s->cmd);
}
}
-static void nand_pre_save(void *opaque)
+static int nand_pre_save(void *opaque)
{
NANDFlashState *s = NAND(opaque);
s->ioaddr_vmstate = s->ioaddr - s->io;
+
+ return 0;
}
static int nand_post_load(void *opaque, int version_id)
{
int pagesize;
NANDFlashState *s = NAND(dev);
+ int ret;
+
s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
s->size = nand_flash_ids[s->chip_id].size << 20;
pagesize = 1 << s->oob_shift;
s->mem_oob = 1;
if (s->blk) {
- if (blk_is_read_only(s->blk)) {
+ if (!blk_supports_write_perm(s->blk)) {
error_setg(errp, "Can't use a read-only drive");
return;
}
+ ret = blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, errp);
+ if (ret < 0) {
+ return;
+ }
if (blk_getlength(s->blk) >=
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
pagesize = 0;
dc->realize = nand_realize;
dc->reset = nand_reset;
dc->vmsd = &vmstate_nand;
- dc->props = nand_properties;
+ device_class_set_props(dc, nand_properties);
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
static const TypeInfo nand_info = {
DeviceState *dev;
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", __func__);
}
- dev = DEVICE(object_new(TYPE_NAND));
+ dev = qdev_new(TYPE_NAND);
qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
qdev_prop_set_uint8(dev, "chip_id", chip_id);
if (blk) {
- qdev_prop_set_drive(dev, "drive", blk, &error_fatal);
+ qdev_prop_set_drive_err(dev, "drive", blk, &error_fatal);
}
- qdev_init_nofail(dev);
+ qdev_realize(dev, NULL, &error_fatal);
return dev;
}
#else
/* Program a single page */
-static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
+static void glue(nand_blk_write_, NAND_PAGE_SIZE)(NANDFlashState *s)
{
uint64_t off, page, sector, soff;
uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
sector = SECTOR(s->addr);
off = (s->addr & PAGE_MASK) + s->offset;
soff = SECTOR_OFFSET(s->addr);
- if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
- PAGE_SECTORS << BDRV_SECTOR_BITS) < 0) {
+ if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS,
+ PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
- mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
- if (off + s->iolen > PAGE_SIZE) {
+ mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, NAND_PAGE_SIZE - off));
+ if (off + s->iolen > NAND_PAGE_SIZE) {
page = PAGE(s->addr);
- mem_and(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
- MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
+ mem_and(s->storage + (page << OOB_SHIFT), s->io + NAND_PAGE_SIZE - off,
+ MIN(OOB_SIZE, off + s->iolen - NAND_PAGE_SIZE));
}
- if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
- PAGE_SECTORS << BDRV_SECTOR_BITS, 0) < 0) {
+ if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS,
+ PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
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 (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
- (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) {
+ if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS,
+ (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
mem_and(iobuf + soff, s->io, s->iolen);
- if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
- (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, 0) < 0) {
+ if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS,
+ (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
}
}
}
/* Erase a single block */
-static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
+static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s)
{
uint64_t i, page, addr;
uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
if (!s->blk) {
memset(s->storage + PAGE_START(addr),
- 0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
+ 0xff, (NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift);
} else if (s->mem_oob) {
memset(s->storage + (PAGE(addr) << OOB_SHIFT),
0xff, OOB_SIZE << s->erase_shift);
i = SECTOR(addr);
page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
for (; i < page; i ++)
- if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS, iobuf,
- BDRV_SECTOR_SIZE, 0) < 0) {
+ if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS,
+ BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
}
} else {
addr = PAGE_START(addr);
page = addr >> 9;
- if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf,
- BDRV_SECTOR_SIZE) < 0) {
+ if (blk_pread(s->blk, page << BDRV_SECTOR_BITS,
+ BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
}
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
- if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf,
- BDRV_SECTOR_SIZE, 0) < 0) {
+ if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS,
+ BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
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;
+ for (addr += ((NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
i < addr; i += 0x200) {
- if (blk_pwrite(s->blk, i, iobuf, BDRV_SECTOR_SIZE, 0) < 0) {
+ if (blk_pwrite(s->blk, i, BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n",
__func__, i >> 9);
}
}
page = i >> 9;
- if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf,
- BDRV_SECTOR_SIZE) < 0) {
+ if (blk_pread(s->blk, page << BDRV_SECTOR_BITS,
+ BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
}
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
- if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf,
- BDRV_SECTOR_SIZE, 0) < 0) {
+ if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS,
+ BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
}
}
}
-static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
+static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
uint64_t addr, int offset)
{
if (PAGE(addr) >= s->pages) {
if (s->blk) {
if (s->mem_oob) {
- if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS, s->io,
- PAGE_SECTORS << BDRV_SECTOR_BITS) < 0) {
+ if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS,
+ PAGE_SECTORS << BDRV_SECTOR_BITS, s->io, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n",
__func__, SECTOR(addr));
}
- memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
+ memcpy(s->io + SECTOR_OFFSET(s->addr) + NAND_PAGE_SIZE,
s->storage + (PAGE(s->addr) << OOB_SHIFT),
OOB_SIZE);
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
} else {
- if (blk_pread(s->blk, PAGE_START(addr), s->io,
- (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) {
+ if (blk_pread(s->blk, PAGE_START(addr),
+ (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, s->io, 0)
+ < 0) {
printf("%s: read error in sector %" PRIu64 "\n",
__func__, PAGE_START(addr) >> 9);
}
}
} else {
memcpy(s->io, s->storage + PAGE_START(s->addr) +
- offset, PAGE_SIZE + OOB_SIZE - offset);
+ offset, NAND_PAGE_SIZE + OOB_SIZE - offset);
s->ioaddr = s->io;
}
}
-static void glue(nand_init_, PAGE_SIZE)(NANDFlashState *s)
+static void glue(nand_init_, NAND_PAGE_SIZE)(NANDFlashState *s)
{
s->oob_shift = PAGE_SHIFT - 5;
s->pages = s->size >> PAGE_SHIFT;
s->addr_shift = ADDR_SHIFT;
- s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
- s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
- s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
+ s->blk_erase = glue(nand_blk_erase_, NAND_PAGE_SIZE);
+ s->blk_write = glue(nand_blk_write_, NAND_PAGE_SIZE);
+ s->blk_load = glue(nand_blk_load_, NAND_PAGE_SIZE);
}
-# undef PAGE_SIZE
+# undef NAND_PAGE_SIZE
# undef PAGE_SHIFT
# undef PAGE_SECTORS
# undef ADDR_SHIFT