staticint bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
{ int i = 0;
bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code); for (i = 0; i < NFLASH_READY_RETRIES; i++) { if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) {
i = 0; break;
}
} if (i) {
pr_err("NFLASH control command not ready!\n"); return -EBUSY;
} return 0;
}
staticint bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
{ int i;
for (i = 0; i < NFLASH_READY_RETRIES; i++) { if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) { if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
BCMA_CC_NFLASH_CTL_ERR) {
pr_err("Error on polling\n"); return -EBUSY;
} else { return 0;
}
}
}
u32 ctlcode;
u32 *dest = (u32 *)buf; int i; int toread;
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 */
while (len) { /* We can read maximum of 0x200 bytes at once */
toread = min(len, 0x200);
/* Set page and column */
bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR,
b47n->curr_column);
bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR,
b47n->curr_page_addr);
/* Prepare to read */
ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL |
NCTL_CMD0;
ctlcode |= NAND_CMD_READSTART << 8; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) return; if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc)) return;
/* Eventually read some data :) */ for (i = 0; i < toread; i += 4, dest++) {
ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ; if (i == toread - 4) /* Last read goes without that */
ctlcode &= ~NCTL_CSA; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
ctlcode)) return;
*dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA);
}
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;
}
}
staticvoid bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct nand_chip *nand_chip, int cmd, unsignedint ctrl)
{ struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
u32 code = 0; int rc;
if (cmd == NAND_CMD_NONE) return;
if (cmd & NAND_CTRL_CLE)
code = cmd | NCTL_CMD0;
/* nCS is not needed for reset command */ if (cmd != NAND_CMD_RESET)
code |= NCTL_CSA;
rc = bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code); if (rc)
pr_err("ctl_cmd didn't work with error %d\n", rc);
}
/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */ staticvoid bcm47xxnflash_ops_bcm4706_select_chip(struct nand_chip *chip, int cs)
{ 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.
*/ staticvoid bcm47xxnflash_ops_bcm4706_cmdfunc(struct nand_chip *nand_chip, unsigned command, int column, int page_addr)
{ struct mtd_info *mtd = nand_to_mtd(nand_chip); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); struct bcma_drv_cc *cc = b47n->cc;
u32 ctlcode; int i;
if (column != -1)
b47n->curr_column = column; if (page_addr != -1)
b47n->curr_page_addr = page_addr;
switch (command) { case NAND_CMD_RESET:
nand_chip->legacy.cmd_ctrl(nand_chip, command, NAND_CTRL_CLE);
/* * Reading is specific, last one has to go without NCTL_CSA * 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 = NCTL_CSA | NCTL_READ; if (i == ARRAY_SIZE(b47n->id_data) - 1)
ctlcode &= ~NCTL_CSA; 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; case NAND_CMD_STATUS:
ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
pr_err("STATUS command error\n"); break; case NAND_CMD_READ0: break; case NAND_CMD_READOOB: 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 = NCTL_ROW | 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 | NCTL_ROW | NCTL_COL | NCTL_CMD0;
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, NCTL_CMD0 |
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;
}
b47n->curr_command = command;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.