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:
Zhaoyifeng 2017-10-17 14:29:38 +08:00 committed by Kever Yang
parent afabcf8d2f
commit 441217e374
16 changed files with 24365 additions and 0 deletions

View File

@ -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

View File

@ -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

41
cmd/rknand.c Normal file
View File

@ -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'"
);

View File

@ -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;

28
doc/README.rknand Normal file
View File

@ -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

View File

@ -72,6 +72,8 @@ source "drivers/remoteproc/Kconfig"
source "drivers/reset/Kconfig"
source "drivers/rknand/Kconfig"
source "drivers/rtc/Kconfig"
source "drivers/scsi/Kconfig"

View File

@ -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/

View File

@ -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,
};

12
drivers/rknand/Kconfig Normal file
View File

@ -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.

7
drivers/rknand/Makefile Normal file
View File

@ -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

23971
drivers/rknand/rk_ftl_arm_v7.S Normal file

File diff suppressed because it is too large Load Diff

205
drivers/rknand/rknand.c Normal file
View File

@ -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),
};

62
drivers/rknand/rknand.h Normal file
View File

@ -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__ */

View File

@ -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 */
};

View File

@ -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 */

20
include/rknand.h Normal file
View File

@ -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__ */