drivers: rknand: add nand flash drivers for Rockchip SoC
This patch add the nand flash support for Rockchip Soc(RK3128, RK3126x, RK3188, Rk3229 etc). Change-Id: I35ea09f0714b303b247a97ed13cc6e0e56675a0e Signed-off-by: Yifeng Zhao <zyf@rock-chips.com>
This commit is contained in:
parent
afabcf8d2f
commit
441217e374
|
|
@ -831,6 +831,13 @@ config CMD_REMOTEPROC
|
|||
help
|
||||
Support for Remote Processor control
|
||||
|
||||
config CMD_RKNAND
|
||||
bool "rknand"
|
||||
depends on RKNAND
|
||||
default y if RKNAND
|
||||
help
|
||||
Rockchip NAND FLASH device support
|
||||
|
||||
config CMD_ROCKUSB
|
||||
bool "rockusb"
|
||||
depends on USB_FUNCTION_ROCKUSB
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o
|
|||
obj-$(CONFIG_SANDBOX) += host.o
|
||||
obj-$(CONFIG_CMD_SATA) += sata.o
|
||||
obj-$(CONFIG_CMD_NVME) += nvme.o
|
||||
obj-$(CONFIG_CMD_RKNAND) += rknand.o
|
||||
obj-$(CONFIG_CMD_SF) += sf.o
|
||||
obj-$(CONFIG_CMD_SCSI) += scsi.o disk.o
|
||||
obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) (C) Copyright 2016-2017 Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <rknand.h>
|
||||
|
||||
static int rknand_curr_dev;
|
||||
static int do_rknand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (argc == 2) {
|
||||
if (strncmp(argv[1], "scan", 4) == 0) {
|
||||
ret = rknand_scan_namespace();
|
||||
if (ret)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return blk_common_cmd(argc, argv, IF_TYPE_RKNAND, &rknand_curr_dev);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
rknand, 8, 1, do_rknand,
|
||||
"rockchip nand flash sub-system",
|
||||
"scan - scan Nand devices\n"
|
||||
"rknand info - show all available Nand devices\n"
|
||||
"rknand device [dev] - show or set current Nand device\n"
|
||||
"rknand part [dev] - print partition table of one or all Nand devices\n"
|
||||
"rknand read addr blk# cnt - read `cnt' blocks starting at block\n"
|
||||
" `blk#' to memory address `addr'\n"
|
||||
"rknand write addr blk# cnt - write `cnt' blocks starting at block\n"
|
||||
" `blk#' from memory address `addr'"
|
||||
);
|
||||
|
|
@ -133,6 +133,7 @@ void dev_print (struct blk_desc *dev_desc)
|
|||
case IF_TYPE_MMC:
|
||||
case IF_TYPE_USB:
|
||||
case IF_TYPE_NVME:
|
||||
case IF_TYPE_RKNAND:
|
||||
printf ("Vendor: %s Rev: %s Prod: %s\n",
|
||||
dev_desc->vendor,
|
||||
dev_desc->revision,
|
||||
|
|
@ -269,6 +270,9 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc)
|
|||
case IF_TYPE_NVME:
|
||||
puts ("NVMe");
|
||||
break;
|
||||
case IF_TYPE_RKNAND:
|
||||
puts("RKNAND");
|
||||
break;
|
||||
default:
|
||||
puts ("UNKNOWN");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
rknand (Rockchip NAND FLASH drivers with FTL)
|
||||
=====================================================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The rknand is used for Rockchip Soc NAND FLASH devices.
|
||||
|
||||
Status
|
||||
------
|
||||
It supprot SLC and MLC NAND Flash with fully FTL.
|
||||
|
||||
Usage in U-Boot
|
||||
---------------
|
||||
|
||||
To list all of the rknand hard disks, try:
|
||||
|
||||
=> rknand info
|
||||
Device 0: Vendor: 0x2207 Rev: V1.00 Prod: rknand
|
||||
Type: Hard Disk
|
||||
Capacity: 7304.0 MB = 7.1 GB (14958592 x 512)
|
||||
|
||||
To find and initialize nand devices, try:
|
||||
=> rknand dev 0
|
||||
Device 0: Vendor: 0x2207 Rev: V1.00 Prod: rknand
|
||||
Type: Hard Disk
|
||||
Capacity: 7304.0 MB = 7.1 GB (14958592 x 512)
|
||||
... is now current device
|
||||
|
|
@ -72,6 +72,8 @@ source "drivers/remoteproc/Kconfig"
|
|||
|
||||
source "drivers/reset/Kconfig"
|
||||
|
||||
source "drivers/rknand/Kconfig"
|
||||
|
||||
source "drivers/rtc/Kconfig"
|
||||
|
||||
source "drivers/scsi/Kconfig"
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ obj-$(CONFIG_FPGA) += fpga/
|
|||
obj-y += misc/
|
||||
obj-$(CONFIG_MMC) += mmc/
|
||||
obj-$(CONFIG_NVME) += nvme/
|
||||
obj-$(CONFIG_RKNAND) += rknand/
|
||||
obj-y += pcmcia/
|
||||
obj-y += dfu/
|
||||
obj-$(CONFIG_X86) += pch/
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = {
|
|||
[IF_TYPE_HOST] = "host",
|
||||
[IF_TYPE_SYSTEMACE] = "ace",
|
||||
[IF_TYPE_NVME] = "nvme",
|
||||
[IF_TYPE_RKNAND] = "rknand",
|
||||
};
|
||||
|
||||
static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
|
||||
|
|
@ -36,6 +37,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
|
|||
[IF_TYPE_SATA] = UCLASS_AHCI,
|
||||
[IF_TYPE_HOST] = UCLASS_ROOT,
|
||||
[IF_TYPE_NVME] = UCLASS_NVME,
|
||||
[IF_TYPE_RKNAND] = UCLASS_RKNAND,
|
||||
[IF_TYPE_SYSTEMACE] = UCLASS_INVALID,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Copyright (C) (C) Copyright 2016-2017 Rockchip Electronics Co., Ltd
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
config RKNAND
|
||||
bool "Rockchip NAND FLASH device support"
|
||||
depends on BLK
|
||||
help
|
||||
This option enables support for Rockchip NAND FLASH devices.
|
||||
It supports block interface(with rk ftl) to read and write NAND FLASH.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# Copyright (C) (C) Copyright 2016-2017 Rockchip Electronics Co., Ltd
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += rknand.o rk_ftl_arm_v7.o
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright (C) (C) Copyright 2016-2017 Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dm/root.h>
|
||||
#include "rknand.h"
|
||||
|
||||
struct blk_desc *rknand_get_blk_desc(struct rknand_dev *ndev)
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
struct udevice *dev;
|
||||
|
||||
device_find_first_child(ndev->dev, &dev);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
desc = dev_get_uclass_platdata(dev);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
ulong rknand_bread(struct udevice *udev, lbaint_t start,
|
||||
lbaint_t blkcnt, void *dst)
|
||||
{
|
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
|
||||
struct rknand_dev *ndev = dev_get_priv(udev->parent);
|
||||
int err;
|
||||
|
||||
if (blkcnt == 0)
|
||||
return 0;
|
||||
|
||||
if ((start + blkcnt) > block_dev->lba)
|
||||
return 0;
|
||||
|
||||
if (ndev->read == NULL)
|
||||
return 0;
|
||||
|
||||
err = ndev->read(0, (u32)start, (u32)blkcnt, dst);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
ulong rknand_bwrite(struct udevice *udev, lbaint_t start,
|
||||
lbaint_t blkcnt, const void *src)
|
||||
{
|
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
|
||||
struct rknand_dev *ndev = dev_get_priv(udev->parent);
|
||||
int err;
|
||||
|
||||
if (blkcnt == 0)
|
||||
return 0;
|
||||
|
||||
if ((start + blkcnt) > block_dev->lba)
|
||||
return 0;
|
||||
|
||||
if (ndev->write == NULL)
|
||||
return 0;
|
||||
|
||||
err = ndev->write(0, (u32)start, (u32)blkcnt, src);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
ulong rknand_berase(struct udevice *udev, lbaint_t start,
|
||||
lbaint_t blkcnt)
|
||||
{
|
||||
struct blk_desc *block_dev = dev_get_uclass_platdata(udev);
|
||||
struct rknand_dev *ndev = dev_get_priv(udev->parent);
|
||||
int err;
|
||||
|
||||
if (blkcnt == 0)
|
||||
return 0;
|
||||
|
||||
if ((start + blkcnt) > block_dev->lba)
|
||||
return 0;
|
||||
|
||||
if (ndev->erase == NULL)
|
||||
return 0;
|
||||
|
||||
err = ndev->erase(0, (u32)start, (u32)blkcnt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
int rknand_scan_namespace(void)
|
||||
{
|
||||
struct uclass *uc;
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get(UCLASS_RKNAND, &uc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uclass_foreach_dev(dev, uc) {
|
||||
debug("%s %d %p\n", __func__, __LINE__, dev);
|
||||
ret = device_probe(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknand_blk_bind(struct udevice *udev)
|
||||
{
|
||||
struct udevice *bdev;
|
||||
int ret;
|
||||
|
||||
ret = blk_create_devicef(udev, "rknand_blk", "blk",
|
||||
IF_TYPE_RKNAND,
|
||||
0, 512, 0, &bdev);
|
||||
if (ret) {
|
||||
debug("Cannot create block device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknand_blk_probe(struct udevice *udev)
|
||||
{
|
||||
struct rknand_dev *ndev = dev_get_priv(udev->parent);
|
||||
struct blk_desc *desc = dev_get_uclass_platdata(udev);
|
||||
|
||||
debug("%s %d %p ndev = %p %p\n", __func__, __LINE__,
|
||||
udev, ndev, udev->parent);
|
||||
ndev->dev = udev;
|
||||
desc->if_type = IF_TYPE_RKNAND;
|
||||
desc->lba = ndev->density;
|
||||
desc->log2blksz = 9;
|
||||
desc->blksz = 512;
|
||||
desc->bdev = udev;
|
||||
desc->devnum = 0;
|
||||
sprintf(desc->vendor, "0x%.4x", 0x2207);
|
||||
memcpy(desc->product, "rknand", sizeof("rknand"));
|
||||
memcpy(desc->revision, "V1.00", sizeof("V1.00"));
|
||||
/* part_init(desc); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_nand_probe(struct udevice *udev)
|
||||
{
|
||||
int ret;
|
||||
struct rknand_dev *ndev = dev_get_priv(udev);
|
||||
|
||||
ndev->ioaddr = (void *)devfdt_get_addr(udev);
|
||||
ret = rk_ftl_init(ndev->ioaddr);
|
||||
if (!ret) {
|
||||
ndev->density = ftl_get_density(0);
|
||||
ndev->read = ftl_read;
|
||||
ndev->write = ftl_write;
|
||||
ndev->erase = ftl_discard;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct blk_ops rknand_blk_ops = {
|
||||
.read = rknand_bread,
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
.write = rknand_bwrite,
|
||||
.erase = rknand_berase,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct udevice_id rockchip_nand_ids[] = {
|
||||
{ .compatible = "rockchip,rk-nandc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rknand_blk) = {
|
||||
.name = "rknand_blk",
|
||||
.id = UCLASS_BLK,
|
||||
.ops = &rknand_blk_ops,
|
||||
.probe = rknand_blk_probe,
|
||||
};
|
||||
|
||||
UCLASS_DRIVER(rknand) = {
|
||||
.id = UCLASS_RKNAND,
|
||||
.name = "rknand",
|
||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||
.per_device_auto_alloc_size = sizeof(struct rknand_uclass_priv),
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rknand) = {
|
||||
.name = "rknand",
|
||||
.id = UCLASS_RKNAND,
|
||||
.of_match = rockchip_nand_ids,
|
||||
.bind = rknand_blk_bind,
|
||||
.probe = rockchip_nand_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct rknand_dev),
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) (C) Copyright 2016-2017 Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __DRIVER_RKNAND_H__
|
||||
#define __DRIVER_RKNAND_H__
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <clk.h>
|
||||
#include <asm/arch/clock.h>
|
||||
|
||||
/* Represents an NVM Express device. Each nvme_dev is a PCI function. */
|
||||
struct rknand_dev {
|
||||
void *ioaddr;
|
||||
struct clk nandc_clk;
|
||||
struct clk nandc_hclk;
|
||||
u32 density;
|
||||
struct udevice *dev;
|
||||
|
||||
/*
|
||||
* read() - read from a block device
|
||||
*
|
||||
* @start: Start block number to read (0=first)
|
||||
* @blkcnt: Number of blocks to read
|
||||
* @buffer: Destination buffer for data read
|
||||
* @return 0 is OK, -1 is error.
|
||||
*/
|
||||
u32 (*read)(u8 lun, u32 start, u32 blkcnt, void *buffer);
|
||||
/*
|
||||
* write() - write to a block device
|
||||
*
|
||||
* @dev: Device to write to
|
||||
* @start: Start block number to write (0=first)
|
||||
* @blkcnt: Number of blocks to write
|
||||
* @buffer: Source buffer for data to write
|
||||
* @return 0 is OK, -1 is error.
|
||||
*/
|
||||
u32 (*write)(u8 lun, u32 start, u32 blkcnt, const void *buffer);
|
||||
/*
|
||||
* erase() - erase a section of a block device
|
||||
*
|
||||
* @dev: Device to (partially) erase
|
||||
* @start: Start block number to erase (0=first)
|
||||
* @blkcnt: Number of blocks to erase
|
||||
* @return 0 is OK, -1 is error.
|
||||
*/
|
||||
u32 (*erase)(u8 lun, u32 start, u32 blkcnt);
|
||||
};
|
||||
|
||||
struct rknand_uclass_priv {
|
||||
struct rknand_dev *ndev;
|
||||
};
|
||||
|
||||
u32 ftl_write(u8 lun, u32 start, u32 blkcnt, const void *buffer);
|
||||
u32 ftl_read(u8 lun, u32 start, u32 blkcnt, void *buffer);
|
||||
u32 ftl_discard(u8 lun, u32 start, u32 blkcnt);
|
||||
u32 ftl_get_density(u8 lun);
|
||||
int rk_ftl_init(u32 *reg_base);
|
||||
|
||||
#endif /* __DRIVER_RKNAND_H__ */
|
||||
|
|
@ -32,6 +32,7 @@ enum if_type {
|
|||
IF_TYPE_HOST,
|
||||
IF_TYPE_SYSTEMACE,
|
||||
IF_TYPE_NVME,
|
||||
IF_TYPE_RKNAND,
|
||||
|
||||
IF_TYPE_COUNT, /* Number of interface types */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ enum uclass_id {
|
|||
UCLASS_REGULATOR, /* Regulator device */
|
||||
UCLASS_REMOTEPROC, /* Remote Processor device */
|
||||
UCLASS_RESET, /* Reset controller device */
|
||||
UCLASS_RKNAND, /* Rockchip nand device with ftl */
|
||||
UCLASS_RTC, /* Real time clock device */
|
||||
UCLASS_SCSI, /* SCSI device */
|
||||
UCLASS_SERIAL, /* Serial UART */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (C) (C) Copyright 2017 Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __RKNAND_H__
|
||||
#define __RKNAND_H__
|
||||
/**
|
||||
* rknand_scan_namespace - scan all namespaces attached to RK NAND
|
||||
* controllers
|
||||
*
|
||||
* This probes all registered RK NAND uclass device drivers in the
|
||||
* system,and tries to find all namespaces attached to the RK NAND
|
||||
* controllers.
|
||||
*
|
||||
* @return: 0 on success, -ve on error
|
||||
*/
|
||||
int rknand_scan_namespace(void);
|
||||
#endif /* __RKNAND_H__ */
|
||||
Loading…
Reference in New Issue