From 6c71b6f45474e58cb85370951f4c144495778e0b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 15 Sep 2017 21:43:19 +0900 Subject: [PATCH] mtd: nand: denali: allow to override corrupted revision register The Denali IP does not update the revision register properly. Allow to override it with SoC data associated with compatible. Linux had already finished big surgery of this driver, but I need to prepare the NAND core before the full sync of the driver. For now, I am fixing the most fatal problem on UniPhier platform. Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 27 +++++++++++++++------------ drivers/mtd/nand/denali.h | 7 +++++-- drivers/mtd/nand/denali_dt.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 47cf37d1d9..54718f418c 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "denali.h" @@ -433,17 +433,13 @@ static void find_valid_banks(struct denali_nand_info *denali) */ static void detect_max_banks(struct denali_nand_info *denali) { - uint32_t features = readl(denali->flash_reg + FEATURES); - /* - * Read the revision register, so we can calculate the max_banks - * properly: the encoding changed from rev 5.0 to 5.1 - */ - u32 revision = MAKE_COMPARABLE_REVISION( - readl(denali->flash_reg + REVISION)); - if (revision < REVISION_5_1) - denali->max_banks = 2 << (features & FEATURES__N_BANKS); - else - denali->max_banks = 1 << (features & FEATURES__N_BANKS); + uint32_t features = ioread32(denali->flash_reg + FEATURES); + + denali->max_banks = 1 << (features & FEATURES__N_BANKS); + + /* the encoding changed from rev 5.0 to 5.1 */ + if (denali->revision < 0x0501) + denali->max_banks <<= 1; } static void detect_partition_feature(struct denali_nand_info *denali) @@ -1153,6 +1149,13 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, /* Initialization code to bring the device up to a known good state */ static void denali_hw_init(struct denali_nand_info *denali) { + /* + * The REVISION register may not be reliable. Platforms are allowed to + * override it. + */ + if (!denali->revision) + denali->revision = swab16(ioread32(denali->flash_reg + REVISION)); + /* * tell driver how many bit controller will skip before writing * ECC code in OOB. This is normally used for bad block marker diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 694bce53a9..08db48843d 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -166,8 +166,6 @@ #define REVISION 0x370 #define REVISION__VALUE 0xffff -#define MAKE_COMPARABLE_REVISION(x) swab16((x) & REVISION__VALUE) -#define REVISION_5_1 0x00000501 #define ONFI_DEVICE_FEATURES 0x380 #define ONFI_DEVICE_FEATURES__VALUE 0x003f @@ -462,8 +460,13 @@ struct denali_nand_info { uint32_t blksperchip; uint32_t bbtskipbytes; uint32_t max_banks; + unsigned int revision; + unsigned int caps; }; +#define DENALI_CAP_HW_ECC_FIXUP BIT(0) +#define DENALI_CAP_DMA_64BIT BIT(1) + int denali_init(struct denali_nand_info *denali); #endif /* __DENALI_H__ */ diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 0a6155c748..4afd679a04 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -12,15 +12,38 @@ #include "denali.h" +struct denali_dt_data { + unsigned int revision; + unsigned int caps; +}; + +static const struct denali_dt_data denali_socfpga_data = { + .caps = DENALI_CAP_HW_ECC_FIXUP, +}; + +static const struct denali_dt_data denali_uniphier_v5a_data = { + .caps = DENALI_CAP_HW_ECC_FIXUP | + DENALI_CAP_DMA_64BIT, +}; + +static const struct denali_dt_data denali_uniphier_v5b_data = { + .revision = 0x0501, + .caps = DENALI_CAP_HW_ECC_FIXUP | + DENALI_CAP_DMA_64BIT, +}; + static const struct udevice_id denali_nand_dt_ids[] = { { .compatible = "altr,socfpga-denali-nand", + .data = (unsigned long)&denali_socfpga_data, }, { .compatible = "socionext,uniphier-denali-nand-v5a", + .data = (unsigned long)&denali_uniphier_v5a_data, }, { .compatible = "socionext,uniphier-denali-nand-v5b", + .data = (unsigned long)&denali_uniphier_v5b_data, }, { /* sentinel */ } }; @@ -28,9 +51,16 @@ static const struct udevice_id denali_nand_dt_ids[] = { static int denali_dt_probe(struct udevice *dev) { struct denali_nand_info *denali = dev_get_priv(dev); + const struct denali_dt_data *data; struct resource res; int ret; + data = (void *)dev_get_driver_data(dev); + if (data) { + denali->revision = data->revision; + denali->caps = data->caps; + } + ret = dev_read_resource_byname(dev, "denali_reg", &res); if (ret) return ret; -- 2.25.1