oxnas: backport upstream NAND driver
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
parent
ae21033e76
commit
5cde94d9ab
12 changed files with 5913 additions and 161 deletions
|
@ -243,8 +243,7 @@ CONFIG_MODULES_USE_ELF_REL=y
|
||||||
CONFIG_MTD_NAND=y
|
CONFIG_MTD_NAND=y
|
||||||
CONFIG_MTD_NAND_ECC=y
|
CONFIG_MTD_NAND_ECC=y
|
||||||
CONFIG_MTD_NAND_OXNAS=y
|
CONFIG_MTD_NAND_OXNAS=y
|
||||||
CONFIG_MTD_NAND_PLATFORM=y
|
# CONFIG_MTD_SPLIT_FIRMWARE is not set
|
||||||
CONFIG_MTD_SPLIT_FIRMWARE=y
|
|
||||||
CONFIG_MTD_UBI=y
|
CONFIG_MTD_UBI=y
|
||||||
CONFIG_MTD_UBI_BEB_LIMIT=20
|
CONFIG_MTD_UBI_BEB_LIMIT=20
|
||||||
CONFIG_MTD_UBI_BLOCK=y
|
CONFIG_MTD_UBI_BLOCK=y
|
||||||
|
|
|
@ -34,15 +34,6 @@
|
||||||
nand@41000000 {
|
nand@41000000 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
||||||
partition@0 {
|
|
||||||
label = "boot";
|
|
||||||
reg = <0x0 0x26c0000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
partition@26c0000 {
|
|
||||||
label = "ubi";
|
|
||||||
reg = <0x26c0000 0xd940000>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ethernet@40400000 {
|
ethernet@40400000 {
|
||||||
|
@ -132,3 +123,24 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nandc {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
nand@0 {
|
||||||
|
reg = <0>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
nand-ecc-mode = "soft";
|
||||||
|
nand-ecc-algo = "hamming";
|
||||||
|
|
||||||
|
partition@0 {
|
||||||
|
label = "boot";
|
||||||
|
reg = <0x00000000 0x026c0000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
partition@26c0000 {
|
||||||
|
label = "ubi";
|
||||||
|
reg = <0x026c0000 0x0d940000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -31,37 +31,6 @@
|
||||||
nr-ports = <2>;
|
nr-ports = <2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
nand@41000000 {
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
partition@0 {
|
|
||||||
label = "stage1";
|
|
||||||
reg = <0x00000000 0x00040000>;
|
|
||||||
read-only;
|
|
||||||
};
|
|
||||||
|
|
||||||
partition@40000 {
|
|
||||||
label = "u-boot";
|
|
||||||
reg = <0x00040000 0x00200000>;
|
|
||||||
read-only;
|
|
||||||
};
|
|
||||||
|
|
||||||
partition@240000 {
|
|
||||||
label = "initrd";
|
|
||||||
reg = <0x00240000 0x00600000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
partition@840000 {
|
|
||||||
label = "kernel";
|
|
||||||
reg = <0x00840000 0x007C0000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
partition@e00000 {
|
|
||||||
label = "ubi";
|
|
||||||
reg = <0x01000000 0x07000000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ethernet@40400000 {
|
ethernet@40400000 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
snps,phy-addr = <1>;
|
snps,phy-addr = <1>;
|
||||||
|
@ -163,3 +132,42 @@
|
||||||
gpios = <&GPIOA 9 0>;
|
gpios = <&GPIOA 9 0>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nandc {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
nand@0 {
|
||||||
|
reg = <0>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
nand-ecc-mode = "soft";
|
||||||
|
nand-ecc-algo = "hamming";
|
||||||
|
|
||||||
|
partition@0 {
|
||||||
|
label = "stage1";
|
||||||
|
reg = <0x00000000 0x00040000>;
|
||||||
|
read-only;
|
||||||
|
};
|
||||||
|
|
||||||
|
partition@40000 {
|
||||||
|
label = "u-boot";
|
||||||
|
reg = <0x00040000 0x00200000>;
|
||||||
|
read-only;
|
||||||
|
};
|
||||||
|
|
||||||
|
partition@240000 {
|
||||||
|
label = "initrd";
|
||||||
|
reg = <0x00240000 0x00600000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
partition@840000 {
|
||||||
|
label = "kernel";
|
||||||
|
reg = <0x00840000 0x007C0000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
partition@e00000 {
|
||||||
|
label = "ubi";
|
||||||
|
reg = <0x01000000 0x07000000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -28,21 +28,6 @@
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
nand@41000000 {
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
partition@0 {
|
|
||||||
label = "boot";
|
|
||||||
reg = <0x00000000 0x00e00000>;
|
|
||||||
/*read-only;*/
|
|
||||||
};
|
|
||||||
|
|
||||||
partition@e00000 {
|
|
||||||
label = "ubi";
|
|
||||||
reg = <0x00e00000 0x07200000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ethernet@40400000 {
|
ethernet@40400000 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
@ -84,3 +69,26 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nandc {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
nand@0 {
|
||||||
|
reg = <0>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
nand-ecc-mode = "soft";
|
||||||
|
nand-ecc-algo = "hamming";
|
||||||
|
|
||||||
|
partition@0 {
|
||||||
|
label = "boot";
|
||||||
|
reg = <0x00000000 0x00e00000>;
|
||||||
|
/*read-only;*/
|
||||||
|
};
|
||||||
|
|
||||||
|
partition@e00000 {
|
||||||
|
label = "ubi";
|
||||||
|
reg = <0x00e00000 0x07200000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -25,21 +25,6 @@
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
nand@41000000 {
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
partition@0 {
|
|
||||||
label = "boot";
|
|
||||||
reg = <0x00000000 0x00e00000>;
|
|
||||||
/*read-only;*/
|
|
||||||
};
|
|
||||||
|
|
||||||
partition@e00000 {
|
|
||||||
label = "ubi";
|
|
||||||
reg = <0x00e00000 0x07200000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ethernet@40400000 {
|
ethernet@40400000 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
@ -81,3 +66,26 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nandc {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
nand@0 {
|
||||||
|
reg = <0>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
nand-ecc-mode = "soft";
|
||||||
|
nand-ecc-algo = "hamming";
|
||||||
|
|
||||||
|
partition@0 {
|
||||||
|
label = "boot";
|
||||||
|
reg = <0x00000000 0x00e00000>;
|
||||||
|
/*read-only;*/
|
||||||
|
};
|
||||||
|
|
||||||
|
partition@e00000 {
|
||||||
|
label = "ubi";
|
||||||
|
reg = <0x00e00000 0x07200000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -27,20 +27,6 @@
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
nand@41000000 {
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
partition@0 {
|
|
||||||
label = "boot";
|
|
||||||
reg = <0x00000000 0x00e00000>;
|
|
||||||
/*read-only;*/
|
|
||||||
};
|
|
||||||
|
|
||||||
partition@e00000 {
|
|
||||||
label = "ubi";
|
|
||||||
reg = <0x00e00000 0x07200000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ethernet@40400000 {
|
ethernet@40400000 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
@ -91,3 +77,26 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nandc {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
nand@0 {
|
||||||
|
reg = <0>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
nand-ecc-mode = "soft";
|
||||||
|
nand-ecc-algo = "hamming";
|
||||||
|
|
||||||
|
partition@0 {
|
||||||
|
label = "boot";
|
||||||
|
reg = <0x00000000 0x00e00000>;
|
||||||
|
read-only;
|
||||||
|
};
|
||||||
|
|
||||||
|
partition@e00000 {
|
||||||
|
label = "ubi";
|
||||||
|
reg = <0x00e00000 0x07200000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -298,16 +298,15 @@
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
nand@41000000 {
|
nandc: nand-controller@41000000 {
|
||||||
compatible = "plxtech,nand-nas782x", "gen_nand";
|
compatible = "oxsemi,ox820-nand";
|
||||||
reg = <0x41000000 0x100000>, <0x41C00000 0x20>;
|
reg = <0x41000000 0x100000>;
|
||||||
nand-ecc-mode = "soft";
|
|
||||||
clocks = <&stdclk 9>;
|
clocks = <&stdclk 9>;
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
pinctrl-0 = <&pinctrl_nand0>;
|
pinctrl-0 = <&pinctrl_nand0>;
|
||||||
resets = <&rst 15>;
|
resets = <&rst 15>;
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <1>;
|
#size-cells = <0>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,94 +1,211 @@
|
||||||
/*
|
/*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* Oxford Semiconductor OXNAS NAND driver
|
||||||
* under the terms of the GNU General Public License version 2 as published
|
|
||||||
* by the Free Software Foundation.
|
* Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
|
||||||
|
* Heavily based on plat_nand.c :
|
||||||
|
* Author: Vitaly Wool <vitalywool@gmail.com>
|
||||||
|
* Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
|
||||||
|
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
*
|
*
|
||||||
* based on xway_nand.c
|
|
||||||
* Copyright © 2012 John Crispin <blogic@openwrt.org>
|
|
||||||
* and oxnas_nand.c "NAND glue for Oxnas platforms"
|
|
||||||
* written by Ma Haijun <mahaijuns@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/mtd/nand.h>
|
#include <linux/err.h>
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/io.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
|
#include <linux/mtd/mtd.h>
|
||||||
|
#include <linux/mtd/nand.h>
|
||||||
|
#include <linux/mtd/partitions.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
/* nand commands */
|
/* Nand commands */
|
||||||
#define NAND_CMD_ALE BIT(18)
|
#define OXNAS_NAND_CMD_ALE BIT(18)
|
||||||
#define NAND_CMD_CLE BIT(19)
|
#define OXNAS_NAND_CMD_CLE BIT(19)
|
||||||
#define NAND_CMD_CS 0
|
|
||||||
#define NAND_CMD_RESET 0xff
|
|
||||||
#define NAND_CMD (NAND_CMD_CS | NAND_CMD_CLE)
|
|
||||||
#define NAND_ADDR (NAND_CMD_CS | NAND_CMD_ALE)
|
|
||||||
#define NAND_DATA (NAND_CMD_CS)
|
|
||||||
|
|
||||||
static void oxnas_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
#define OXNAS_NAND_MAX_CHIPS 1
|
||||||
|
|
||||||
|
struct oxnas_nand {
|
||||||
|
struct nand_hw_control base;
|
||||||
|
void __iomem *io_base;
|
||||||
|
struct clk *clk;
|
||||||
|
struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
|
||||||
|
unsigned long ctrl;
|
||||||
|
struct mtd_partition *partitions;
|
||||||
|
int nr_partitions;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
|
struct oxnas_nand *oxnas = nand_get_controller_data(chip);
|
||||||
|
|
||||||
|
return readb(oxnas->io_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
|
struct oxnas_nand *oxnas = nand_get_controller_data(chip);
|
||||||
|
|
||||||
|
ioread8_rep(oxnas->io_base, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oxnas_nand_write_buf(struct mtd_info *mtd,
|
||||||
|
const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
|
struct oxnas_nand *oxnas = nand_get_controller_data(chip);
|
||||||
|
|
||||||
|
iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single CS command control */
|
||||||
|
static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||||
|
unsigned int ctrl)
|
||||||
|
{
|
||||||
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
|
struct oxnas_nand *oxnas = nand_get_controller_data(chip);
|
||||||
|
|
||||||
if (ctrl & NAND_CTRL_CHANGE) {
|
if (ctrl & NAND_CTRL_CHANGE) {
|
||||||
nandaddr &= ~(NAND_CMD | NAND_ADDR);
|
|
||||||
if (ctrl & NAND_CLE)
|
if (ctrl & NAND_CLE)
|
||||||
nandaddr |= NAND_CMD;
|
oxnas->ctrl = OXNAS_NAND_CMD_CLE;
|
||||||
else if (ctrl & NAND_ALE)
|
else if (ctrl & NAND_ALE)
|
||||||
nandaddr |= NAND_ADDR;
|
oxnas->ctrl = OXNAS_NAND_CMD_ALE;
|
||||||
this->IO_ADDR_W = (void __iomem *) nandaddr;
|
else
|
||||||
|
oxnas->ctrl = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd != NAND_CMD_NONE)
|
if (cmd != NAND_CMD_NONE)
|
||||||
writeb(cmd, (void __iomem *) nandaddr);
|
writeb(cmd, oxnas->io_base + oxnas->ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oxnas_nand_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
/* enable clock and release static block reset */
|
|
||||||
struct clk *clk = of_clk_get(pdev->dev.of_node, 0);
|
|
||||||
|
|
||||||
if (IS_ERR(clk))
|
|
||||||
return PTR_ERR(clk);
|
|
||||||
|
|
||||||
clk_prepare_enable(clk);
|
|
||||||
device_reset(&pdev->dev);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allow users to override the partition in DT using the cmdline */
|
|
||||||
static const char * part_probes[] = { "cmdlinepart", "ofpart", NULL };
|
|
||||||
|
|
||||||
static struct platform_nand_data oxnas_nand_data = {
|
|
||||||
.chip = {
|
|
||||||
.nr_chips = 1,
|
|
||||||
.chip_delay = 30,
|
|
||||||
.part_probe_types = part_probes,
|
|
||||||
},
|
|
||||||
.ctrl = {
|
|
||||||
.probe = oxnas_nand_probe,
|
|
||||||
.cmd_ctrl = oxnas_cmd_ctrl,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to find the node inside the DT. If it is available attach out
|
* Probe for the NAND device.
|
||||||
* platform_nand_data
|
|
||||||
*/
|
*/
|
||||||
static int __init oxnas_register_nand(void)
|
static int oxnas_nand_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct platform_device *pdev;
|
struct device_node *nand_np;
|
||||||
|
struct oxnas_nand *oxnas;
|
||||||
|
struct nand_chip *chip;
|
||||||
|
struct mtd_info *mtd;
|
||||||
|
struct resource *res;
|
||||||
|
int nchips = 0;
|
||||||
|
int count = 0;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
node = of_find_compatible_node(NULL, NULL, "plxtech,nand-nas782x");
|
/* Allocate memory for the device structure (and zero it) */
|
||||||
if (!node)
|
oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
|
||||||
return -ENOENT;
|
GFP_KERNEL);
|
||||||
pdev = of_find_device_by_node(node);
|
if (!oxnas)
|
||||||
if (!pdev)
|
return -ENOMEM;
|
||||||
|
|
||||||
|
nand_hw_control_init(&oxnas->base);
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(oxnas->io_base))
|
||||||
|
return PTR_ERR(oxnas->io_base);
|
||||||
|
|
||||||
|
oxnas->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(oxnas->clk))
|
||||||
|
oxnas->clk = NULL;
|
||||||
|
|
||||||
|
/* Only a single chip node is supported */
|
||||||
|
count = of_get_child_count(np);
|
||||||
|
pr_info("########### count: %d\n", count);
|
||||||
|
if (count > 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
pdev->dev.platform_data = &oxnas_nand_data;
|
|
||||||
of_node_put(node);
|
clk_prepare_enable(oxnas->clk);
|
||||||
|
device_reset_optional(&pdev->dev);
|
||||||
|
|
||||||
|
for_each_child_of_node(np, nand_np) {
|
||||||
|
chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!chip)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
chip->controller = &oxnas->base;
|
||||||
|
|
||||||
|
nand_set_flash_node(chip, nand_np);
|
||||||
|
nand_set_controller_data(chip, oxnas);
|
||||||
|
|
||||||
|
mtd = nand_to_mtd(chip);
|
||||||
|
mtd->dev.parent = &pdev->dev;
|
||||||
|
mtd->priv = chip;
|
||||||
|
|
||||||
|
chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
|
||||||
|
chip->read_buf = oxnas_nand_read_buf;
|
||||||
|
chip->read_byte = oxnas_nand_read_byte;
|
||||||
|
chip->write_buf = oxnas_nand_write_buf;
|
||||||
|
chip->chip_delay = 30;
|
||||||
|
|
||||||
|
/* Scan to find existence of the device */
|
||||||
|
err = nand_scan(mtd, 1);
|
||||||
|
pr_info("########### nand_scan err: %d\n", err);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mtd_device_register(mtd, NULL, 0);
|
||||||
|
pr_info("########### mtd_device_register err: %d\n", err);
|
||||||
|
if (err) {
|
||||||
|
nand_release(mtd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
oxnas->chips[nchips] = chip;
|
||||||
|
++nchips;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("########### nchips: %d\n", nchips);
|
||||||
|
|
||||||
|
/* Exit if no chips found */
|
||||||
|
if (!nchips)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, oxnas);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
subsys_initcall(oxnas_register_nand);
|
static int oxnas_nand_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct oxnas_nand *oxnas = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
if (oxnas->chips[0])
|
||||||
|
nand_release(nand_to_mtd(oxnas->chips[0]));
|
||||||
|
|
||||||
|
clk_disable_unprepare(oxnas->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id oxnas_nand_match[] = {
|
||||||
|
{ .compatible = "oxsemi,ox820-nand" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, oxnas_nand_match);
|
||||||
|
|
||||||
|
static struct platform_driver oxnas_nand_driver = {
|
||||||
|
.probe = oxnas_nand_probe,
|
||||||
|
.remove = oxnas_nand_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "oxnas_nand",
|
||||||
|
.of_match_table = oxnas_nand_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(oxnas_nand_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||||
|
MODULE_DESCRIPTION("Oxnas NAND driver");
|
||||||
|
MODULE_ALIAS("platform:oxnas_nand");
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,91 @@
|
||||||
|
From 410a91f6efa1c4c3c4369d1dd2c31286749dff33 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||||
|
Date: Wed, 23 Mar 2016 11:19:01 +0100
|
||||||
|
Subject: [PATCH 073/102] of: mtd: prepare helper reading NAND ECC algo from
|
||||||
|
DT
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
NAND subsystem is being slightly reworked to store ECC details in
|
||||||
|
separated fields. In future we'll want to add support for more DT
|
||||||
|
properties as specifying every possible setup with a single
|
||||||
|
"nand-ecc-mode" is a pretty bad idea.
|
||||||
|
To allow this let's add a helper that will support something like
|
||||||
|
"nand-ecc-algo" in future. Right now we use it for keeping backward
|
||||||
|
compatibility.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||||
|
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||||
|
---
|
||||||
|
drivers/of/of_mtd.c | 36 ++++++++++++++++++++++++++++++++++++
|
||||||
|
include/linux/of_mtd.h | 6 ++++++
|
||||||
|
2 files changed, 42 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/of/of_mtd.c
|
||||||
|
+++ b/drivers/of/of_mtd.c
|
||||||
|
@@ -50,6 +50,42 @@ int of_get_nand_ecc_mode(struct device_n
|
||||||
|
EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
+ * of_get_nand_ecc_algo - Get nand ecc algorithm for given device_node
|
||||||
|
+ * @np: Pointer to the given device_node
|
||||||
|
+ *
|
||||||
|
+ * The function gets ecc algorithm and returns its enum value, or errno in error
|
||||||
|
+ * case.
|
||||||
|
+ */
|
||||||
|
+int of_get_nand_ecc_algo(struct device_node *np)
|
||||||
|
+{
|
||||||
|
+ const char *pm;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * TODO: Read ECC algo OF property and map it to enum nand_ecc_algo.
|
||||||
|
+ * It's not implemented yet as currently NAND subsystem ignores
|
||||||
|
+ * algorithm explicitly set this way. Once it's handled we should
|
||||||
|
+ * document & support new property.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * For backward compatibility we also read "nand-ecc-mode" checking
|
||||||
|
+ * for some obsoleted values that were specifying ECC algorithm.
|
||||||
|
+ */
|
||||||
|
+ err = of_property_read_string(np, "nand-ecc-mode", &pm);
|
||||||
|
+ if (err < 0)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ if (!strcasecmp(pm, "soft"))
|
||||||
|
+ return NAND_ECC_HAMMING;
|
||||||
|
+ else if (!strcasecmp(pm, "soft_bch"))
|
||||||
|
+ return NAND_ECC_BCH;
|
||||||
|
+
|
||||||
|
+ return -ENODEV;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_algo);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
* of_get_nand_ecc_step_size - Get ECC step size associated to
|
||||||
|
* the required ECC strength (see below).
|
||||||
|
* @np: Pointer to the given device_node
|
||||||
|
--- a/include/linux/of_mtd.h
|
||||||
|
+++ b/include/linux/of_mtd.h
|
||||||
|
@@ -13,6 +13,7 @@
|
||||||
|
|
||||||
|
#include <linux/of.h>
|
||||||
|
int of_get_nand_ecc_mode(struct device_node *np);
|
||||||
|
+int of_get_nand_ecc_algo(struct device_node *np);
|
||||||
|
int of_get_nand_ecc_step_size(struct device_node *np);
|
||||||
|
int of_get_nand_ecc_strength(struct device_node *np);
|
||||||
|
int of_get_nand_bus_width(struct device_node *np);
|
||||||
|
@@ -24,6 +25,11 @@ static inline int of_get_nand_ecc_mode(s
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+static inline int of_get_nand_ecc_algo(struct device_node *np)
|
||||||
|
+{
|
||||||
|
+ return -ENOSYS;
|
||||||
|
+}
|
||||||
|
|
||||||
|
static inline int of_get_nand_ecc_step_size(struct device_node *np)
|
||||||
|
{
|
|
@ -0,0 +1,202 @@
|
||||||
|
From d45bc58dd3bdcaabc1d7d8d9b0b8dee826635cc6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
|
||||||
|
Date: Wed, 27 Jul 2016 11:23:52 +0200
|
||||||
|
Subject: [PATCH] mtd: nand: import nand_hw_control_init()
|
||||||
|
|
||||||
|
The code to initialize a struct nand_hw_control is duplicated across
|
||||||
|
several drivers. Factorize it using an inline function.
|
||||||
|
|
||||||
|
Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
|
||||||
|
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||||
|
---
|
||||||
|
drivers/mtd/nand/bf5xx_nand.c | 3 +--
|
||||||
|
drivers/mtd/nand/brcmnand/brcmnand.c | 3 +--
|
||||||
|
drivers/mtd/nand/docg4.c | 3 +--
|
||||||
|
drivers/mtd/nand/fsl_elbc_nand.c | 3 +--
|
||||||
|
drivers/mtd/nand/fsl_ifc_nand.c | 3 +--
|
||||||
|
drivers/mtd/nand/jz4780_nand.c | 3 +--
|
||||||
|
drivers/mtd/nand/nand_base.c | 3 +--
|
||||||
|
drivers/mtd/nand/ndfc.c | 3 +--
|
||||||
|
drivers/mtd/nand/pxa3xx_nand.c | 3 +--
|
||||||
|
drivers/mtd/nand/qcom_nandc.c | 3 +--
|
||||||
|
drivers/mtd/nand/s3c2410.c | 3 +--
|
||||||
|
drivers/mtd/nand/sunxi_nand.c | 3 +--
|
||||||
|
drivers/mtd/nand/txx9ndfmc.c | 3 +--
|
||||||
|
include/linux/mtd/nand.h | 7 +++++++
|
||||||
|
14 files changed, 20 insertions(+), 26 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
|
||||||
|
index 37da423..3962f55 100644
|
||||||
|
--- a/drivers/mtd/nand/bf5xx_nand.c
|
||||||
|
+++ b/drivers/mtd/nand/bf5xx_nand.c
|
||||||
|
@@ -761,8 +761,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, info);
|
||||||
|
|
||||||
|
- spin_lock_init(&info->controller.lock);
|
||||||
|
- init_waitqueue_head(&info->controller.wq);
|
||||||
|
+ nand_hw_control_init(&info->controller);
|
||||||
|
|
||||||
|
info->device = &pdev->dev;
|
||||||
|
info->platform = plat;
|
||||||
|
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
|
||||||
|
index 8eb2c64..82ec36b 100644
|
||||||
|
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
|
||||||
|
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
|
||||||
|
@@ -2370,8 +2370,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
|
||||||
|
|
||||||
|
init_completion(&ctrl->done);
|
||||||
|
init_completion(&ctrl->dma_done);
|
||||||
|
- spin_lock_init(&ctrl->controller.lock);
|
||||||
|
- init_waitqueue_head(&ctrl->controller.wq);
|
||||||
|
+ nand_hw_control_init(&ctrl->controller);
|
||||||
|
INIT_LIST_HEAD(&ctrl->host_list);
|
||||||
|
|
||||||
|
/* NAND register range */
|
||||||
|
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
|
||||||
|
index 4731699..7af2a3c 100644
|
||||||
|
--- a/drivers/mtd/nand/docg4.c
|
||||||
|
+++ b/drivers/mtd/nand/docg4.c
|
||||||
|
@@ -1249,8 +1249,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
|
||||||
|
nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
|
||||||
|
nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
|
||||||
|
nand->controller = &nand->hwcontrol;
|
||||||
|
- spin_lock_init(&nand->controller->lock);
|
||||||
|
- init_waitqueue_head(&nand->controller->wq);
|
||||||
|
+ nand_hw_control_init(nand->controller);
|
||||||
|
|
||||||
|
/* methods */
|
||||||
|
nand->cmdfunc = docg4_command;
|
||||||
|
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
|
||||||
|
index 60a88f2..113f76e 100644
|
||||||
|
--- a/drivers/mtd/nand/fsl_elbc_nand.c
|
||||||
|
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
|
||||||
|
@@ -879,8 +879,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
|
||||||
|
}
|
||||||
|
elbc_fcm_ctrl->counter++;
|
||||||
|
|
||||||
|
- spin_lock_init(&elbc_fcm_ctrl->controller.lock);
|
||||||
|
- init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
|
||||||
|
+ nand_hw_control_init(&elbc_fcm_ctrl->controller);
|
||||||
|
fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
|
||||||
|
} else {
|
||||||
|
elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
|
||||||
|
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
|
||||||
|
index 4e9e5fd..0a177b1 100644
|
||||||
|
--- a/drivers/mtd/nand/fsl_ifc_nand.c
|
||||||
|
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
|
||||||
|
@@ -987,8 +987,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
|
||||||
|
ifc_nand_ctrl->addr = NULL;
|
||||||
|
fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
|
||||||
|
|
||||||
|
- spin_lock_init(&ifc_nand_ctrl->controller.lock);
|
||||||
|
- init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
|
||||||
|
+ nand_hw_control_init(&ifc_nand_ctrl->controller);
|
||||||
|
} else {
|
||||||
|
ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
|
||||||
|
}
|
||||||
|
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
|
||||||
|
index 77533f7..53ea796 100644
|
||||||
|
--- a/drivers/mtd/nand/nand_base.c
|
||||||
|
+++ b/drivers/mtd/nand/nand_base.c
|
||||||
|
@@ -3191,8 +3191,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
|
||||||
|
|
||||||
|
if (!chip->controller) {
|
||||||
|
chip->controller = &chip->hwcontrol;
|
||||||
|
- spin_lock_init(&chip->controller->lock);
|
||||||
|
- init_waitqueue_head(&chip->controller->wq);
|
||||||
|
+ nand_hw_control_init(chip->controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
|
||||||
|
index 218c789..28e6118 100644
|
||||||
|
--- a/drivers/mtd/nand/ndfc.c
|
||||||
|
+++ b/drivers/mtd/nand/ndfc.c
|
||||||
|
@@ -218,8 +218,7 @@ static int ndfc_probe(struct platform_device *ofdev)
|
||||||
|
ndfc = &ndfc_ctrl[cs];
|
||||||
|
ndfc->chip_select = cs;
|
||||||
|
|
||||||
|
- spin_lock_init(&ndfc->ndfc_control.lock);
|
||||||
|
- init_waitqueue_head(&ndfc->ndfc_control.wq);
|
||||||
|
+ nand_hw_control_init(&ndfc->ndfc_control);
|
||||||
|
ndfc->ofdev = ofdev;
|
||||||
|
dev_set_drvdata(&ofdev->dev, ndfc);
|
||||||
|
|
||||||
|
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
|
||||||
|
index 436dd6d..b121bf4 100644
|
||||||
|
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||||||
|
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||||||
|
@@ -1810,8 +1810,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
|
||||||
|
chip->cmdfunc = nand_cmdfunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
- spin_lock_init(&chip->controller->lock);
|
||||||
|
- init_waitqueue_head(&chip->controller->wq);
|
||||||
|
+ nand_hw_control_init(chip->controller);
|
||||||
|
info->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(info->clk)) {
|
||||||
|
dev_err(&pdev->dev, "failed to get nand clock\n");
|
||||||
|
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
|
||||||
|
index d9309cf..b1734d7 100644
|
||||||
|
--- a/drivers/mtd/nand/s3c2410.c
|
||||||
|
+++ b/drivers/mtd/nand/s3c2410.c
|
||||||
|
@@ -977,8 +977,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, info);
|
||||||
|
|
||||||
|
- spin_lock_init(&info->controller.lock);
|
||||||
|
- init_waitqueue_head(&info->controller.wq);
|
||||||
|
+ nand_hw_control_init(&info->controller);
|
||||||
|
|
||||||
|
/* get the clock source and enable it */
|
||||||
|
|
||||||
|
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
|
||||||
|
index e414b31..8b5dadc 100644
|
||||||
|
--- a/drivers/mtd/nand/sunxi_nand.c
|
||||||
|
+++ b/drivers/mtd/nand/sunxi_nand.c
|
||||||
|
@@ -2175,8 +2175,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
nfc->dev = dev;
|
||||||
|
- spin_lock_init(&nfc->controller.lock);
|
||||||
|
- init_waitqueue_head(&nfc->controller.wq);
|
||||||
|
+ nand_hw_control_init(&nfc->controller);
|
||||||
|
INIT_LIST_HEAD(&nfc->chips);
|
||||||
|
|
||||||
|
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
|
||||||
|
index 04d63f5..0a14fda 100644
|
||||||
|
--- a/drivers/mtd/nand/txx9ndfmc.c
|
||||||
|
+++ b/drivers/mtd/nand/txx9ndfmc.c
|
||||||
|
@@ -303,8 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
|
||||||
|
dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
|
||||||
|
(gbusclk + 500000) / 1000000, hold, spw);
|
||||||
|
|
||||||
|
- spin_lock_init(&drvdata->hw_control.lock);
|
||||||
|
- init_waitqueue_head(&drvdata->hw_control.wq);
|
||||||
|
+ nand_hw_control_init(&drvdata->hw_control);
|
||||||
|
|
||||||
|
platform_set_drvdata(dev, drvdata);
|
||||||
|
txx9ndfmc_initialize(dev);
|
||||||
|
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
|
||||||
|
index 8dd6e01..f6a2d5e 100644
|
||||||
|
--- a/include/linux/mtd/nand.h
|
||||||
|
+++ b/include/linux/mtd/nand.h
|
||||||
|
@@ -460,6 +460,13 @@ struct nand_hw_control {
|
||||||
|
wait_queue_head_t wq;
|
||||||
|
};
|
||||||
|
|
||||||
|
+static inline void nand_hw_control_init(struct nand_hw_control *nfc)
|
||||||
|
+{
|
||||||
|
+ nfc->active = NULL;
|
||||||
|
+ spin_lock_init(&nfc->lock);
|
||||||
|
+ init_waitqueue_head(&nfc->wq);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* struct nand_ecc_ctrl - Control structure for ECC
|
||||||
|
* @mode: ECC mode
|
||||||
|
--
|
||||||
|
2.10.2
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
--- a/drivers/mtd/nand/Kconfig
|
--- a/drivers/mtd/nand/Kconfig
|
||||||
+++ b/drivers/mtd/nand/Kconfig
|
+++ b/drivers/mtd/nand/Kconfig
|
||||||
@@ -546,4 +546,12 @@ config MTD_NAND_HISI504
|
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
|
||||||
help
|
help
|
||||||
Enables support for NAND controller on Hisilicon SoC Hip04.
|
Enables support for NAND controller on Hisilicon SoC Hip04.
|
||||||
|
|
||||||
+config MTD_NAND_OXNAS
|
+config MTD_NAND_OXNAS
|
||||||
+ tristate "Support for NAND on Plxtech NAS782X SoC"
|
+ tristate "Support for NAND on Plxtech NAS782X SoC"
|
||||||
+ depends on ARCH_OXNAS
|
+ depends on ARCH_OXNAS
|
||||||
+ select MTD_NAND_PLATFORM
|
|
||||||
+ help
|
+ help
|
||||||
+ Enables support for NAND Flash chips on Plxtech NAS782X SoCs. NAND is attached
|
+ Enables support for NAND Flash chips on Plxtech NAS782X SoCs. NAND is attached
|
||||||
+ to the STATIC Unit.
|
+ to the STATIC Unit.
|
||||||
|
|
Loading…
Reference in a new issue