spl: drivers: mtd: nand: raw: switch to the device model

Switch to the device model and support mtd.

Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
Change-Id: Idfb60cec7a375254a423677b1c3f1da4be954eb5
This commit is contained in:
Yifeng Zhao 2020-04-21 09:48:45 +08:00 committed by Jianhong Chen
parent 6a8fa29e04
commit e65bf00a8c
1 changed files with 191 additions and 9 deletions

View File

@ -5,6 +5,7 @@
*/
#include <common.h>
#include <dm.h>
#include <fdtdec.h>
#include <fdt_support.h>
#include <inttypes.h>
@ -80,6 +81,8 @@ struct rk_nand {
u8 chipnr;
u8 id[5];
u8 *databuf;
struct udevice *dev;
struct mtd_info *mtd;
};
struct rk_nand *g_rk_nand;
@ -248,10 +251,175 @@ static void read_flash_id(struct rk_nand *rknand, uint8_t *id)
id[3] = readb(bank_base);
id[4] = readb(bank_base);
rockchip_nand_select_chip(rknand->regs, -1);
printf("%s %x %x %x %x %x\n", __func__, id[0], id[1], id[2], id[3],
id[4]);
if (id[0] != 0xFF && id[0] != 0x00)
printf("NAND:%x %x\n", id[0], id[1]);
}
#ifdef CONFIG_NAND_ROCKCHIP_DT
static const struct udevice_id rockchip_nandc_ids[] = {
{ .compatible = "rockchip,rk-nandc" },
{ }
};
static int spl_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
return is_badblock(ofs / CONFIG_SYS_NAND_PAGE_SIZE);
}
static int spl_nand_read_page(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
int read_size, offset, read_len;
unsigned int page;
unsigned int max_pages = CONFIG_SYS_NAND_SIZE /
CONFIG_SYS_NAND_PAGE_SIZE;
/* Convert to page number */
page = from / CONFIG_SYS_NAND_PAGE_SIZE;
offset = from & (CONFIG_SYS_NAND_PAGE_SIZE - 1);
read_len = len;
*retlen = 0;
while (read_len) {
read_size = CONFIG_SYS_NAND_PAGE_SIZE - offset;
if (read_size > read_len)
read_size = read_len;
if (offset || read_size < CONFIG_SYS_NAND_PAGE_SIZE) {
if (nandc_read_page(page, g_rk_nand->databuf) < 0)
return -EIO;
memcpy(buf, g_rk_nand->databuf + offset, read_size);
offset = 0;
} else {
if (nandc_read_page(page, buf) < 0)
return -EIO;
}
page++;
read_len -= read_size;
buf += read_size;
if (page >= max_pages)
return -EIO;
}
*retlen = len;
return 0;
}
static int rockchip_nandc_probe(struct udevice *dev)
{
const void *blob = gd->fdt_blob;
struct rk_nand *rknand = dev_get_priv(dev);
struct mtd_info *mtd = dev_get_uclass_priv(dev);
fdt_addr_t regs;
int ret = -ENODEV;
int node;
g_rk_nand = rknand;
rknand->dev = dev;
node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC);
if (node < 0) {
printf("Nand node not found\n");
return -ENODEV;
}
if (!fdtdec_get_is_enabled(blob, node)) {
debug("Nand disabled in device tree\n");
return -ENODEV;
}
regs = fdt_get_base_address(blob, node);
if (!regs) {
debug("Nand address not found\n");
return -ENODEV;
}
rknand->regs = (void *)regs;
nandc_init(g_rk_nand);
read_flash_id(g_rk_nand, g_rk_nand->id);
if (g_rk_nand->id[0] == g_rk_nand->id[1])
return -ENODEV;
if (g_rk_nand->id[1] == 0xA1 || g_rk_nand->id[1] == 0xF1 ||
g_rk_nand->id[1] == 0xD1 || g_rk_nand->id[1] == 0xAA ||
g_rk_nand->id[1] == 0xDA || g_rk_nand->id[1] == 0xAC ||
g_rk_nand->id[1] == 0xDC || g_rk_nand->id[1] == 0xA3 ||
g_rk_nand->id[1] == 0xD3 || g_rk_nand->id[1] == 0x95 ||
g_rk_nand->id[1] == 0x48) {
g_rk_nand->chipnr = 1;
g_rk_nand->databuf = kzalloc(CONFIG_SYS_NAND_PAGE_SIZE,
GFP_KERNEL);
if (!g_rk_nand)
return -ENOMEM;
mtd->_block_isbad = spl_nand_block_isbad;
mtd->_read = spl_nand_read_page;
mtd->size = CONFIG_SYS_NAND_SIZE;
mtd->writesize = CONFIG_SYS_NAND_PAGE_SIZE;
mtd->type = MTD_NANDFLASH;
mtd->dev = rknand->dev;
mtd->priv = rknand;
add_mtd_device(mtd);
mtd->name = "rk-nand";
rknand->mtd = mtd;
ret = 0;
}
return ret;
}
static int rockchip_nandc_bind(struct udevice *udev)
{
int ret = 0;
#ifdef CONFIG_MTD_BLK
struct udevice *bdev;
ret = blk_create_devicef(udev, "mtd_blk", "blk", IF_TYPE_MTD,
BLK_MTD_NAND, 512, 0, &bdev);
if (ret)
printf("Cannot create block device\n");
#endif
return ret;
}
U_BOOT_DRIVER(rk_nandc_v6) = {
.name = "rk_nandc_v6",
.id = UCLASS_MTD,
.of_match = rockchip_nandc_ids,
.bind = rockchip_nandc_bind,
.probe = rockchip_nandc_probe,
.priv_auto_alloc_size = sizeof(struct rk_nand),
};
void board_nand_init(void)
{
struct udevice *dev;
int ret;
ret = uclass_get_device_by_driver(UCLASS_MTD,
DM_GET_DRIVER(rk_nandc_v6),
&dev);
if (ret && ret != -ENODEV)
pr_err("Failed to initialize NAND controller. (error %d)\n",
ret);
}
int nand_spl_load_image(u32 offs, u32 size, void *buf)
{
return -EIO;
}
void nand_init(void){};
int rk_nand_init(void)
{
return -ENODEV;
}
#else
void board_nand_init(void)
{
const void *blob = gd->fdt_blob;
@ -271,18 +439,18 @@ void board_nand_init(void)
if (node < 0) {
printf("Nand node not found\n");
goto err;
return;
}
if (!fdtdec_get_is_enabled(blob, node)) {
debug("Nand disabled in device tree\n");
goto err;
return;
}
regs = fdt_get_base_address(blob, node);
if (regs == FDT_ADDR_T_NONE) {
if (!regs) {
debug("Nand address not found\n");
goto err;
return;
}
g_rk_nand = kzalloc(sizeof(*g_rk_nand), GFP_KERNEL);
@ -290,12 +458,24 @@ void board_nand_init(void)
g_rk_nand->databuf = kzalloc(CONFIG_SYS_NAND_PAGE_SIZE, GFP_KERNEL);
nandc_init(g_rk_nand);
read_flash_id(g_rk_nand, g_rk_nand->id);
if (g_rk_nand->id[0] != 0xFF && g_rk_nand->id[1] != 0xFF &&
g_rk_nand->id[0] != 0x00 && g_rk_nand->id[1] != 0x00)
if (g_rk_nand->id[0] == g_rk_nand->id[1])
goto err;
if (g_rk_nand->id[1] == 0xA1 || g_rk_nand->id[1] == 0xF1 ||
g_rk_nand->id[1] == 0xD1 || g_rk_nand->id[1] == 0xAA ||
g_rk_nand->id[1] == 0xDA || g_rk_nand->id[1] == 0xAC ||
g_rk_nand->id[1] == 0xDC || g_rk_nand->id[1] == 0xA3 ||
g_rk_nand->id[1] == 0xD3 || g_rk_nand->id[1] == 0x95 ||
g_rk_nand->id[1] == 0x48) {
g_rk_nand->chipnr = 1;
return;
return;
}
err:
kfree(g_rk_nand->databuf);
kfree(g_rk_nand);
g_rk_nand = NULL;
}
int nand_spl_load_image(u32 offs, u32 size, void *buf)
@ -351,5 +531,7 @@ int rk_nand_init(void)
else
return -ENODEV;
}
#endif
void nand_deselect(void) {}