mirror of
https://github.com/torvalds/linux.git
synced 2024-11-19 18:41:48 +00:00
mtd: brcmnand: Add v7.2 controller support
The 7.2 controller differs in a few area compared to its predecssor (7.1): - NAND scrambler, which we are not using just yet - higher ECC levels (up to 120 bits) per 1KB data blocks, also not supported yet - up to 128B OOB This patch adds the necessary code to support such a controller generation and updates the Device Tree binding. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Acked-by: Kamal Dasu <kdasu.kdev@gmail.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
This commit is contained in:
parent
cabfeaa678
commit
decba6d478
@ -27,6 +27,7 @@ Required properties:
|
|||||||
brcm,brcmnand-v6.2
|
brcm,brcmnand-v6.2
|
||||||
brcm,brcmnand-v7.0
|
brcm,brcmnand-v7.0
|
||||||
brcm,brcmnand-v7.1
|
brcm,brcmnand-v7.1
|
||||||
|
brcm,brcmnand-v7.2
|
||||||
brcm,brcmnand
|
brcm,brcmnand
|
||||||
- reg : the register start and length for NAND register region.
|
- reg : the register start and length for NAND register region.
|
||||||
(optional) Flash DMA register range (if present)
|
(optional) Flash DMA register range (if present)
|
||||||
|
@ -340,6 +340,36 @@ static const u16 brcmnand_regs_v71[] = {
|
|||||||
[BRCMNAND_FC_BASE] = 0x400,
|
[BRCMNAND_FC_BASE] = 0x400,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* BRCMNAND v7.2 */
|
||||||
|
static const u16 brcmnand_regs_v72[] = {
|
||||||
|
[BRCMNAND_CMD_START] = 0x04,
|
||||||
|
[BRCMNAND_CMD_EXT_ADDRESS] = 0x08,
|
||||||
|
[BRCMNAND_CMD_ADDRESS] = 0x0c,
|
||||||
|
[BRCMNAND_INTFC_STATUS] = 0x14,
|
||||||
|
[BRCMNAND_CS_SELECT] = 0x18,
|
||||||
|
[BRCMNAND_CS_XOR] = 0x1c,
|
||||||
|
[BRCMNAND_LL_OP] = 0x20,
|
||||||
|
[BRCMNAND_CS0_BASE] = 0x50,
|
||||||
|
[BRCMNAND_CS1_BASE] = 0,
|
||||||
|
[BRCMNAND_CORR_THRESHOLD] = 0xdc,
|
||||||
|
[BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0,
|
||||||
|
[BRCMNAND_UNCORR_COUNT] = 0xfc,
|
||||||
|
[BRCMNAND_CORR_COUNT] = 0x100,
|
||||||
|
[BRCMNAND_CORR_EXT_ADDR] = 0x10c,
|
||||||
|
[BRCMNAND_CORR_ADDR] = 0x110,
|
||||||
|
[BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
|
||||||
|
[BRCMNAND_UNCORR_ADDR] = 0x118,
|
||||||
|
[BRCMNAND_SEMAPHORE] = 0x150,
|
||||||
|
[BRCMNAND_ID] = 0x194,
|
||||||
|
[BRCMNAND_ID_EXT] = 0x198,
|
||||||
|
[BRCMNAND_LL_RDATA] = 0x19c,
|
||||||
|
[BRCMNAND_OOB_READ_BASE] = 0x200,
|
||||||
|
[BRCMNAND_OOB_READ_10_BASE] = 0,
|
||||||
|
[BRCMNAND_OOB_WRITE_BASE] = 0x400,
|
||||||
|
[BRCMNAND_OOB_WRITE_10_BASE] = 0,
|
||||||
|
[BRCMNAND_FC_BASE] = 0x600,
|
||||||
|
};
|
||||||
|
|
||||||
enum brcmnand_cs_reg {
|
enum brcmnand_cs_reg {
|
||||||
BRCMNAND_CS_CFG_EXT = 0,
|
BRCMNAND_CS_CFG_EXT = 0,
|
||||||
BRCMNAND_CS_CFG,
|
BRCMNAND_CS_CFG,
|
||||||
@ -435,7 +465,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Register offsets */
|
/* Register offsets */
|
||||||
if (ctrl->nand_version >= 0x0701)
|
if (ctrl->nand_version >= 0x0702)
|
||||||
|
ctrl->reg_offsets = brcmnand_regs_v72;
|
||||||
|
else if (ctrl->nand_version >= 0x0701)
|
||||||
ctrl->reg_offsets = brcmnand_regs_v71;
|
ctrl->reg_offsets = brcmnand_regs_v71;
|
||||||
else if (ctrl->nand_version >= 0x0600)
|
else if (ctrl->nand_version >= 0x0600)
|
||||||
ctrl->reg_offsets = brcmnand_regs_v60;
|
ctrl->reg_offsets = brcmnand_regs_v60;
|
||||||
@ -480,7 +512,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Maximum spare area sector size (per 512B) */
|
/* Maximum spare area sector size (per 512B) */
|
||||||
if (ctrl->nand_version >= 0x0600)
|
if (ctrl->nand_version >= 0x0702)
|
||||||
|
ctrl->max_oob = 128;
|
||||||
|
else if (ctrl->nand_version >= 0x0600)
|
||||||
ctrl->max_oob = 64;
|
ctrl->max_oob = 64;
|
||||||
else if (ctrl->nand_version >= 0x0500)
|
else if (ctrl->nand_version >= 0x0500)
|
||||||
ctrl->max_oob = 32;
|
ctrl->max_oob = 32;
|
||||||
@ -583,14 +617,20 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
|
|||||||
enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
|
enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
|
||||||
int cs = host->cs;
|
int cs = host->cs;
|
||||||
|
|
||||||
if (ctrl->nand_version >= 0x0600)
|
if (ctrl->nand_version >= 0x0702)
|
||||||
|
bits = 7;
|
||||||
|
else if (ctrl->nand_version >= 0x0600)
|
||||||
bits = 6;
|
bits = 6;
|
||||||
else if (ctrl->nand_version >= 0x0500)
|
else if (ctrl->nand_version >= 0x0500)
|
||||||
bits = 5;
|
bits = 5;
|
||||||
else
|
else
|
||||||
bits = 4;
|
bits = 4;
|
||||||
|
|
||||||
if (ctrl->nand_version >= 0x0600) {
|
if (ctrl->nand_version >= 0x0702) {
|
||||||
|
if (cs >= 4)
|
||||||
|
reg = BRCMNAND_CORR_THRESHOLD_EXT;
|
||||||
|
shift = (cs % 4) * bits;
|
||||||
|
} else if (ctrl->nand_version >= 0x0600) {
|
||||||
if (cs >= 5)
|
if (cs >= 5)
|
||||||
reg = BRCMNAND_CORR_THRESHOLD_EXT;
|
reg = BRCMNAND_CORR_THRESHOLD_EXT;
|
||||||
shift = (cs % 5) * bits;
|
shift = (cs % 5) * bits;
|
||||||
@ -631,19 +671,28 @@ enum {
|
|||||||
|
|
||||||
static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
|
static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
|
||||||
{
|
{
|
||||||
if (ctrl->nand_version >= 0x0600)
|
if (ctrl->nand_version >= 0x0702)
|
||||||
|
return GENMASK(7, 0);
|
||||||
|
else if (ctrl->nand_version >= 0x0600)
|
||||||
return GENMASK(6, 0);
|
return GENMASK(6, 0);
|
||||||
else
|
else
|
||||||
return GENMASK(5, 0);
|
return GENMASK(5, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NAND_ACC_CONTROL_ECC_SHIFT 16
|
#define NAND_ACC_CONTROL_ECC_SHIFT 16
|
||||||
|
#define NAND_ACC_CONTROL_ECC_EXT_SHIFT 13
|
||||||
|
|
||||||
static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
|
static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
|
||||||
{
|
{
|
||||||
u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
|
u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
|
||||||
|
|
||||||
return mask << NAND_ACC_CONTROL_ECC_SHIFT;
|
mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
|
||||||
|
|
||||||
|
/* v7.2 includes additional ECC levels */
|
||||||
|
if (ctrl->nand_version >= 0x0702)
|
||||||
|
mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
|
||||||
|
|
||||||
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
|
static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
|
||||||
@ -667,7 +716,9 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
|
|||||||
|
|
||||||
static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
|
static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
|
||||||
{
|
{
|
||||||
if (ctrl->nand_version >= 0x0600)
|
if (ctrl->nand_version >= 0x0702)
|
||||||
|
return 9;
|
||||||
|
else if (ctrl->nand_version >= 0x0600)
|
||||||
return 7;
|
return 7;
|
||||||
else if (ctrl->nand_version >= 0x0500)
|
else if (ctrl->nand_version >= 0x0500)
|
||||||
return 6;
|
return 6;
|
||||||
@ -773,10 +824,16 @@ enum brcmnand_llop_type {
|
|||||||
* Internal support functions
|
* Internal support functions
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
|
static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
|
||||||
|
struct brcmnand_cfg *cfg)
|
||||||
{
|
{
|
||||||
return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
|
if (ctrl->nand_version <= 0x0701)
|
||||||
cfg->ecc_level == 15;
|
return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
|
||||||
|
cfg->ecc_level == 15;
|
||||||
|
else
|
||||||
|
return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
|
||||||
|
cfg->ecc_level == 15) ||
|
||||||
|
(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -931,7 +988,7 @@ static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
|
|||||||
if (p->sector_size_1k)
|
if (p->sector_size_1k)
|
||||||
ecc_level <<= 1;
|
ecc_level <<= 1;
|
||||||
|
|
||||||
if (is_hamming_ecc(p)) {
|
if (is_hamming_ecc(host->ctrl, p)) {
|
||||||
ecc->bytes = 3 * sectors;
|
ecc->bytes = 3 * sectors;
|
||||||
mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
|
mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
|
||||||
return 0;
|
return 0;
|
||||||
@ -1857,7 +1914,8 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
|
static void brcmnand_print_cfg(struct brcmnand_host *host,
|
||||||
|
char *buf, struct brcmnand_cfg *cfg)
|
||||||
{
|
{
|
||||||
buf += sprintf(buf,
|
buf += sprintf(buf,
|
||||||
"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
|
"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
|
||||||
@ -1868,7 +1926,7 @@ static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
|
|||||||
cfg->spare_area_size, cfg->device_width);
|
cfg->spare_area_size, cfg->device_width);
|
||||||
|
|
||||||
/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
|
/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
|
||||||
if (is_hamming_ecc(cfg))
|
if (is_hamming_ecc(host->ctrl, cfg))
|
||||||
sprintf(buf, ", Hamming ECC");
|
sprintf(buf, ", Hamming ECC");
|
||||||
else if (cfg->sector_size_1k)
|
else if (cfg->sector_size_1k)
|
||||||
sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
|
sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
|
||||||
@ -1987,7 +2045,7 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
|
|||||||
|
|
||||||
brcmnand_set_ecc_enabled(host, 1);
|
brcmnand_set_ecc_enabled(host, 1);
|
||||||
|
|
||||||
brcmnand_print_cfg(msg, cfg);
|
brcmnand_print_cfg(host, msg, cfg);
|
||||||
dev_info(ctrl->dev, "detected %s\n", msg);
|
dev_info(ctrl->dev, "detected %s\n", msg);
|
||||||
|
|
||||||
/* Configure ACC_CONTROL */
|
/* Configure ACC_CONTROL */
|
||||||
@ -1995,6 +2053,10 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
|
|||||||
tmp = nand_readreg(ctrl, offs);
|
tmp = nand_readreg(ctrl, offs);
|
||||||
tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
|
tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
|
||||||
tmp &= ~ACC_CONTROL_RD_ERASED;
|
tmp &= ~ACC_CONTROL_RD_ERASED;
|
||||||
|
|
||||||
|
/* We need to turn on Read from erased paged protected by ECC */
|
||||||
|
if (ctrl->nand_version >= 0x0702)
|
||||||
|
tmp |= ACC_CONTROL_RD_ERASED;
|
||||||
tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
|
tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
|
||||||
if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
|
if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
|
||||||
/*
|
/*
|
||||||
@ -2195,6 +2257,7 @@ static const struct of_device_id brcmnand_of_match[] = {
|
|||||||
{ .compatible = "brcm,brcmnand-v6.2" },
|
{ .compatible = "brcm,brcmnand-v6.2" },
|
||||||
{ .compatible = "brcm,brcmnand-v7.0" },
|
{ .compatible = "brcm,brcmnand-v7.0" },
|
||||||
{ .compatible = "brcm,brcmnand-v7.1" },
|
{ .compatible = "brcm,brcmnand-v7.1" },
|
||||||
|
{ .compatible = "brcm,brcmnand-v7.2" },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, brcmnand_of_match);
|
MODULE_DEVICE_TABLE(of, brcmnand_of_match);
|
||||||
|
Loading…
Reference in New Issue
Block a user