@@ -10,7 +10,7 @@
#include <malloc.h>
#include <nand.h>
#include <linux/errno.h>
-#include <asm/io.h>
+#include <linux/io.h>
#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)
@@ -1154,6 +1150,13 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
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
*/
@@ -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__ */
@@ -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;
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 <yamada.masahiro@socionext.com> --- 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(-)