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 <yamada.masahiro@socionext.com>
This commit is contained in:
Masahiro Yamada 2017-09-15 21:43:19 +09:00
parent 08cebeeaad
commit 6c71b6f454
3 changed files with 50 additions and 14 deletions

View File

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

View File

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

View File

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