Loading drivers/mtd/nand/Kconfig +2 −3 Original line number Diff line number Diff line Loading @@ -461,13 +461,12 @@ config MTD_NAND_GPMI_NAND the GPMI. config MTD_NAND_BCM47XXNFLASH tristate "R/O support for NAND flash on BCMA bus" tristate "Support for NAND flash on BCM4706 BCMA bus" depends on BCMA_NFLASH help BCMA bus can have various flash memories attached, they are registered by bcma as platform devices. This enables driver for NAND flash memories. For now only read mode for BCM4706 is implemented. NAND flash memories. For now only BCM4706 is supported. config MTD_NAND_PLATFORM tristate "Support for generic platform NAND driver" Loading drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +77 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #define NCTL_CMD0 0x00010000 #define NCTL_CMD1W 0x00080000 #define NCTL_READ 0x00100000 #define NCTL_WRITE 0x00200000 #define NCTL_SPECADDR 0x01000000 #define NCTL_READY 0x04000000 #define NCTL_ERR 0x08000000 Loading Loading @@ -132,6 +133,36 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, } } static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, const uint8_t *buf, int len) { struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; struct bcma_drv_cc *cc = b47n->cc; u32 ctlcode; const u32 *data = (u32 *)buf; int i; BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); /* Don't validate column using nand_chip->page_shift, it may be bigger * when accessing OOB */ for (i = 0; i < len; i += 4, data++) { bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data); ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE; if (i == len - 4) /* Last read goes without that */ ctlcode &= ~NCTL_CSA; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) { pr_err("%s ctl_cmd didn't work!\n", __func__); return; } } b47n->curr_column += len; } /************************************************** * NAND chip ops **************************************************/ Loading Loading @@ -208,6 +239,36 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, if (page_addr != -1) b47n->curr_column += mtd->writesize; break; case NAND_CMD_ERASE1: bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, b47n->curr_page_addr); ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 | NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8); if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("ERASE1 failed\n"); break; case NAND_CMD_ERASE2: break; case NAND_CMD_SEQIN: /* Set page and column */ bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR, b47n->curr_column); bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, b47n->curr_page_addr); /* Prepare to write */ ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000; ctlcode |= NAND_CMD_SEQIN; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("SEQIN failed\n"); break; case NAND_CMD_PAGEPROG: if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 | NAND_CMD_PAGEPROG)) pr_err("PAGEPROG failed\n"); if (bcm47xxnflash_ops_bcm4706_poll(cc)) pr_err("PAGEPROG not ready\n"); break; default: pr_err("Command 0x%X unsupported\n", command); break; Loading Loading @@ -259,6 +320,21 @@ static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd, pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); } static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; switch (b47n->curr_command) { case NAND_CMD_SEQIN: bcm47xxnflash_ops_bcm4706_write(mtd, buf, len); return; } pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command); } /************************************************** * Init **************************************************/ Loading @@ -278,6 +354,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ Loading Loading
drivers/mtd/nand/Kconfig +2 −3 Original line number Diff line number Diff line Loading @@ -461,13 +461,12 @@ config MTD_NAND_GPMI_NAND the GPMI. config MTD_NAND_BCM47XXNFLASH tristate "R/O support for NAND flash on BCMA bus" tristate "Support for NAND flash on BCM4706 BCMA bus" depends on BCMA_NFLASH help BCMA bus can have various flash memories attached, they are registered by bcma as platform devices. This enables driver for NAND flash memories. For now only read mode for BCM4706 is implemented. NAND flash memories. For now only BCM4706 is supported. config MTD_NAND_PLATFORM tristate "Support for generic platform NAND driver" Loading
drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +77 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #define NCTL_CMD0 0x00010000 #define NCTL_CMD1W 0x00080000 #define NCTL_READ 0x00100000 #define NCTL_WRITE 0x00200000 #define NCTL_SPECADDR 0x01000000 #define NCTL_READY 0x04000000 #define NCTL_ERR 0x08000000 Loading Loading @@ -132,6 +133,36 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, } } static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, const uint8_t *buf, int len) { struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; struct bcma_drv_cc *cc = b47n->cc; u32 ctlcode; const u32 *data = (u32 *)buf; int i; BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); /* Don't validate column using nand_chip->page_shift, it may be bigger * when accessing OOB */ for (i = 0; i < len; i += 4, data++) { bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data); ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE; if (i == len - 4) /* Last read goes without that */ ctlcode &= ~NCTL_CSA; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) { pr_err("%s ctl_cmd didn't work!\n", __func__); return; } } b47n->curr_column += len; } /************************************************** * NAND chip ops **************************************************/ Loading Loading @@ -208,6 +239,36 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, if (page_addr != -1) b47n->curr_column += mtd->writesize; break; case NAND_CMD_ERASE1: bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, b47n->curr_page_addr); ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 | NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8); if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("ERASE1 failed\n"); break; case NAND_CMD_ERASE2: break; case NAND_CMD_SEQIN: /* Set page and column */ bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR, b47n->curr_column); bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, b47n->curr_page_addr); /* Prepare to write */ ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000; ctlcode |= NAND_CMD_SEQIN; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("SEQIN failed\n"); break; case NAND_CMD_PAGEPROG: if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 | NAND_CMD_PAGEPROG)) pr_err("PAGEPROG failed\n"); if (bcm47xxnflash_ops_bcm4706_poll(cc)) pr_err("PAGEPROG not ready\n"); break; default: pr_err("Command 0x%X unsupported\n", command); break; Loading Loading @@ -259,6 +320,21 @@ static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd, pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); } static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; switch (b47n->curr_command) { case NAND_CMD_SEQIN: bcm47xxnflash_ops_bcm4706_write(mtd, buf, len); return; } pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command); } /************************************************** * Init **************************************************/ Loading @@ -278,6 +354,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ Loading