|
@@ -16,6 +16,10 @@
|
|
|
|
|
|
#include "bcm47xxnflash.h"
|
|
|
|
|
|
+/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
|
|
|
+ * shown 164 retries as maxiumum. */
|
|
|
+#define NFLASH_READY_RETRIES 1000
|
|
|
+
|
|
|
/**************************************************
|
|
|
* Various helpers
|
|
|
**************************************************/
|
|
@@ -25,6 +29,24 @@ static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
|
|
|
return ((ns * 1000 * clock) / 1000000) + 1;
|
|
|
}
|
|
|
|
|
|
+static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
|
|
|
+{
|
|
|
+ int i = 0;
|
|
|
+
|
|
|
+ bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, 0x80000000 | code);
|
|
|
+ for (i = 0; i < NFLASH_READY_RETRIES; i++) {
|
|
|
+ if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & 0x80000000)) {
|
|
|
+ i = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (i) {
|
|
|
+ pr_err("NFLASH control command not ready!\n");
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**************************************************
|
|
|
* NAND chip ops
|
|
|
**************************************************/
|
|
@@ -36,6 +58,83 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
|
|
|
+ * For example, reading chip id is performed in a non-standard way.
|
|
|
+ * Setting column and page is also handled differently, we use a special
|
|
|
+ * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
|
|
|
+ * standard commands would be much more complicated.
|
|
|
+ */
|
|
|
+static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
|
|
+ unsigned command, int column,
|
|
|
+ int page_addr)
|
|
|
+{
|
|
|
+ struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
|
|
|
+ struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
|
|
|
+ u32 ctlcode;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (column != -1)
|
|
|
+ b47n->curr_column = column;
|
|
|
+
|
|
|
+ switch (command) {
|
|
|
+ case NAND_CMD_RESET:
|
|
|
+ pr_warn("Chip reset not implemented yet\n");
|
|
|
+ break;
|
|
|
+ case NAND_CMD_READID:
|
|
|
+ ctlcode = 0x40000000 | 0x01000000 | 0x00080000 | 0x00010000;
|
|
|
+ ctlcode |= NAND_CMD_READID;
|
|
|
+ if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) {
|
|
|
+ pr_err("READID error\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Reading is specific, last one has to go without 0x40000000
|
|
|
+ * bit. We don't know how many reads NAND subsystem is going
|
|
|
+ * to perform, so cache everything.
|
|
|
+ */
|
|
|
+ for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) {
|
|
|
+ ctlcode = 0x40000000 | 0x00100000;
|
|
|
+ if (i == ARRAY_SIZE(b47n->id_data) - 1)
|
|
|
+ ctlcode &= ~0x40000000;
|
|
|
+ if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
|
|
|
+ ctlcode)) {
|
|
|
+ pr_err("READID error\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ b47n->id_data[i] =
|
|
|
+ bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA)
|
|
|
+ & 0xFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ pr_err("Command 0x%X unsupported\n", command);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ b47n->curr_command = command;
|
|
|
+}
|
|
|
+
|
|
|
+static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
|
|
|
+{
|
|
|
+ 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_READID:
|
|
|
+ if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) {
|
|
|
+ pr_err("Requested invalid id_data: %d\n",
|
|
|
+ b47n->curr_column);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return b47n->id_data[b47n->curr_column++];
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**************************************************
|
|
|
* Init
|
|
|
**************************************************/
|
|
@@ -52,6 +151,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
|
|
|
u32 val;
|
|
|
|
|
|
b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
|
|
|
+ b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
|
|
|
+ b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
|
|
|
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
|
|
|
|
|
|
/* Enable NAND flash access */
|