Commit d456882b authored by Lei Wen's avatar Lei Wen Committed by Artem Bityutskiy

mtd: pxa3xx_nand: sperate each chip individual info

For support two chip select, we seperate chip specific info in this
patch.
Signed-off-by: default avatarLei Wen <leiwen@marvell.com>
parent da675b4e
...@@ -110,6 +110,7 @@ enum { ...@@ -110,6 +110,7 @@ enum {
enum { enum {
STATE_IDLE = 0, STATE_IDLE = 0,
STATE_PREPARED,
STATE_CMD_HANDLE, STATE_CMD_HANDLE,
STATE_DMA_READING, STATE_DMA_READING,
STATE_DMA_WRITING, STATE_DMA_WRITING,
...@@ -120,21 +121,39 @@ enum { ...@@ -120,21 +121,39 @@ enum {
STATE_READY, STATE_READY,
}; };
struct pxa3xx_nand_info { struct pxa3xx_nand_host {
struct nand_chip nand_chip; struct nand_chip chip;
struct pxa3xx_nand_cmdset *cmdset;
struct mtd_info *mtd;
void *info_data;
/* page size of attached chip */
unsigned int page_size;
int use_ecc;
/* calculated from pxa3xx_nand_flash data */
unsigned int col_addr_cycles;
unsigned int row_addr_cycles;
size_t read_id_bytes;
/* cached register value */
uint32_t reg_ndcr;
uint32_t ndtr0cs0;
uint32_t ndtr1cs0;
};
struct pxa3xx_nand_info {
struct nand_hw_control controller; struct nand_hw_control controller;
struct platform_device *pdev; struct platform_device *pdev;
struct pxa3xx_nand_cmdset *cmdset;
struct clk *clk; struct clk *clk;
void __iomem *mmio_base; void __iomem *mmio_base;
unsigned long mmio_phys; unsigned long mmio_phys;
struct completion cmd_complete;
unsigned int buf_start; unsigned int buf_start;
unsigned int buf_count; unsigned int buf_count;
struct mtd_info *mtd;
/* DMA information */ /* DMA information */
int drcmr_dat; int drcmr_dat;
int drcmr_cmd; int drcmr_cmd;
...@@ -142,18 +161,11 @@ struct pxa3xx_nand_info { ...@@ -142,18 +161,11 @@ struct pxa3xx_nand_info {
unsigned char *data_buff; unsigned char *data_buff;
unsigned char *oob_buff; unsigned char *oob_buff;
dma_addr_t data_buff_phys; dma_addr_t data_buff_phys;
size_t data_buff_size;
int data_dma_ch; int data_dma_ch;
struct pxa_dma_desc *data_desc; struct pxa_dma_desc *data_desc;
dma_addr_t data_desc_addr; dma_addr_t data_desc_addr;
uint32_t reg_ndcr; struct pxa3xx_nand_host *host;
/* saved column/page_addr during CMD_SEQIN */
int seqin_column;
int seqin_page_addr;
/* relate to the command */
unsigned int state; unsigned int state;
int use_ecc; /* use HW ECC ? */ int use_ecc; /* use HW ECC ? */
...@@ -162,24 +174,13 @@ struct pxa3xx_nand_info { ...@@ -162,24 +174,13 @@ struct pxa3xx_nand_info {
unsigned int page_size; /* page size of attached chip */ unsigned int page_size; /* page size of attached chip */
unsigned int data_size; /* data size in FIFO */ unsigned int data_size; /* data size in FIFO */
unsigned int oob_size;
int retcode; int retcode;
struct completion cmd_complete;
/* generated NDCBx register values */ /* generated NDCBx register values */
uint32_t ndcb0; uint32_t ndcb0;
uint32_t ndcb1; uint32_t ndcb1;
uint32_t ndcb2; uint32_t ndcb2;
/* timing calcuted from setting */
uint32_t ndtr0cs0;
uint32_t ndtr1cs0;
/* calculated from pxa3xx_nand_flash data */
size_t oob_size;
size_t read_id_bytes;
unsigned int col_addr_cycles;
unsigned int row_addr_cycles;
}; };
static int use_dma = 1; static int use_dma = 1;
...@@ -241,9 +242,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; ...@@ -241,9 +242,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL};
/* convert nano-seconds to nand flash controller clock cycles */ /* convert nano-seconds to nand flash controller clock cycles */
#define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000)
static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
const struct pxa3xx_nand_timing *t) const struct pxa3xx_nand_timing *t)
{ {
struct pxa3xx_nand_info *info = host->info_data;
unsigned long nand_clk = clk_get_rate(info->clk); unsigned long nand_clk = clk_get_rate(info->clk);
uint32_t ndtr0, ndtr1; uint32_t ndtr0, ndtr1;
...@@ -258,23 +260,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, ...@@ -258,23 +260,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
info->ndtr0cs0 = ndtr0; host->ndtr0cs0 = ndtr0;
info->ndtr1cs0 = ndtr1; host->ndtr1cs0 = ndtr1;
nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR0CS0, ndtr0);
nand_writel(info, NDTR1CS0, ndtr1); nand_writel(info, NDTR1CS0, ndtr1);
} }
static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
{ {
int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; struct pxa3xx_nand_host *host = info->host;
int oob_enable = host->reg_ndcr & NDCR_SPARE_EN;
info->data_size = info->page_size; info->data_size = host->page_size;
if (!oob_enable) { if (!oob_enable) {
info->oob_size = 0; info->oob_size = 0;
return; return;
} }
switch (info->page_size) { switch (host->page_size) {
case 2048: case 2048:
info->oob_size = (info->use_ecc) ? 40 : 64; info->oob_size = (info->use_ecc) ? 40 : 64;
break; break;
...@@ -292,9 +295,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) ...@@ -292,9 +295,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
*/ */
static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
{ {
struct pxa3xx_nand_host *host = info->host;
uint32_t ndcr; uint32_t ndcr;
ndcr = info->reg_ndcr; ndcr = host->reg_ndcr;
ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
ndcr |= info->use_dma ? NDCR_DMA_EN : 0; ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
ndcr |= NDCR_ND_RUN; ndcr |= NDCR_ND_RUN;
...@@ -463,12 +467,6 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) ...@@ -463,12 +467,6 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int pxa3xx_nand_dev_ready(struct mtd_info *mtd)
{
struct pxa3xx_nand_info *info = mtd->priv;
return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0;
}
static inline int is_buf_blank(uint8_t *buf, size_t len) static inline int is_buf_blank(uint8_t *buf, size_t len)
{ {
for (; len > 0; len--) for (; len > 0; len--)
...@@ -481,10 +479,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -481,10 +479,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
uint16_t column, int page_addr) uint16_t column, int page_addr)
{ {
uint16_t cmd; uint16_t cmd;
int addr_cycle, exec_cmd, ndcb0; int addr_cycle, exec_cmd;
struct mtd_info *mtd = info->mtd; struct pxa3xx_nand_host *host = info->host;
struct mtd_info *mtd = host->mtd;
ndcb0 = 0;
addr_cycle = 0; addr_cycle = 0;
exec_cmd = 1; exec_cmd = 1;
...@@ -494,6 +492,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -494,6 +492,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
info->oob_size = 0; info->oob_size = 0;
info->use_ecc = 0; info->use_ecc = 0;
info->is_ready = 0; info->is_ready = 0;
info->ndcb0 = 0;
info->retcode = ERR_NONE; info->retcode = ERR_NONE;
switch (command) { switch (command) {
...@@ -512,20 +511,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -512,20 +511,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
break; break;
} }
info->ndcb0 = ndcb0; addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles + host->col_addr_cycles);
+ info->col_addr_cycles);
switch (command) { switch (command) {
case NAND_CMD_READOOB: case NAND_CMD_READOOB:
case NAND_CMD_READ0: case NAND_CMD_READ0:
cmd = info->cmdset->read1; cmd = host->cmdset->read1;
if (command == NAND_CMD_READOOB) if (command == NAND_CMD_READOOB)
info->buf_start = mtd->writesize + column; info->buf_start = mtd->writesize + column;
else else
info->buf_start = column; info->buf_start = column;
if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) if (unlikely(host->page_size < PAGE_CHUNK_SIZE))
info->ndcb0 |= NDCB0_CMD_TYPE(0) info->ndcb0 |= NDCB0_CMD_TYPE(0)
| addr_cycle | addr_cycle
| (cmd & NDCB0_CMD1_MASK); | (cmd & NDCB0_CMD1_MASK);
...@@ -537,7 +535,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -537,7 +535,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
case NAND_CMD_SEQIN: case NAND_CMD_SEQIN:
/* small page addr setting */ /* small page addr setting */
if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) {
info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
| (column & 0xFF); | (column & 0xFF);
...@@ -564,7 +562,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -564,7 +562,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
break; break;
} }
cmd = info->cmdset->program; cmd = host->cmdset->program;
info->ndcb0 |= NDCB0_CMD_TYPE(0x1) info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
| NDCB0_AUTO_RS | NDCB0_AUTO_RS
| NDCB0_ST_ROW_EN | NDCB0_ST_ROW_EN
...@@ -574,8 +572,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -574,8 +572,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
break; break;
case NAND_CMD_READID: case NAND_CMD_READID:
cmd = info->cmdset->read_id; cmd = host->cmdset->read_id;
info->buf_count = info->read_id_bytes; info->buf_count = host->read_id_bytes;
info->ndcb0 |= NDCB0_CMD_TYPE(3) info->ndcb0 |= NDCB0_CMD_TYPE(3)
| NDCB0_ADDR_CYC(1) | NDCB0_ADDR_CYC(1)
| cmd; | cmd;
...@@ -583,7 +581,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -583,7 +581,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
info->data_size = 8; info->data_size = 8;
break; break;
case NAND_CMD_STATUS: case NAND_CMD_STATUS:
cmd = info->cmdset->read_status; cmd = host->cmdset->read_status;
info->buf_count = 1; info->buf_count = 1;
info->ndcb0 |= NDCB0_CMD_TYPE(4) info->ndcb0 |= NDCB0_CMD_TYPE(4)
| NDCB0_ADDR_CYC(1) | NDCB0_ADDR_CYC(1)
...@@ -593,7 +591,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -593,7 +591,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
break; break;
case NAND_CMD_ERASE1: case NAND_CMD_ERASE1:
cmd = info->cmdset->erase; cmd = host->cmdset->erase;
info->ndcb0 |= NDCB0_CMD_TYPE(2) info->ndcb0 |= NDCB0_CMD_TYPE(2)
| NDCB0_AUTO_RS | NDCB0_AUTO_RS
| NDCB0_ADDR_CYC(3) | NDCB0_ADDR_CYC(3)
...@@ -604,7 +602,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -604,7 +602,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
break; break;
case NAND_CMD_RESET: case NAND_CMD_RESET:
cmd = info->cmdset->reset; cmd = host->cmdset->reset;
info->ndcb0 |= NDCB0_CMD_TYPE(5) info->ndcb0 |= NDCB0_CMD_TYPE(5)
| cmd; | cmd;
...@@ -627,7 +625,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, ...@@ -627,7 +625,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
int column, int page_addr) int column, int page_addr)
{ {
struct pxa3xx_nand_info *info = mtd->priv; struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
int ret, exec_cmd; int ret, exec_cmd;
/* /*
...@@ -635,9 +634,10 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, ...@@ -635,9 +634,10 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
* "byte" address into a "word" address appropriate * "byte" address into a "word" address appropriate
* for indexing a word-oriented device * for indexing a word-oriented device
*/ */
if (info->reg_ndcr & NDCR_DWIDTH_M) if (host->reg_ndcr & NDCR_DWIDTH_M)
column /= 2; column /= 2;
info->state = STATE_PREPARED;
exec_cmd = prepare_command_pool(info, command, column, page_addr); exec_cmd = prepare_command_pool(info, command, column, page_addr);
if (exec_cmd) { if (exec_cmd) {
init_completion(&info->cmd_complete); init_completion(&info->cmd_complete);
...@@ -650,8 +650,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, ...@@ -650,8 +650,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
/* Stop State Machine for next command cycle */ /* Stop State Machine for next command cycle */
pxa3xx_nand_stop(info); pxa3xx_nand_stop(info);
} }
info->state = STATE_IDLE;
} }
info->state = STATE_IDLE;
} }
static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
...@@ -664,7 +664,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, ...@@ -664,7 +664,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int page) struct nand_chip *chip, uint8_t *buf, int page)
{ {
struct pxa3xx_nand_info *info = mtd->priv; struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, buf, mtd->writesize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
...@@ -695,7 +696,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, ...@@ -695,7 +696,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
{ {
struct pxa3xx_nand_info *info = mtd->priv; struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
char retval = 0xFF; char retval = 0xFF;
if (info->buf_start < info->buf_count) if (info->buf_start < info->buf_count)
...@@ -707,7 +709,8 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) ...@@ -707,7 +709,8 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
{ {
struct pxa3xx_nand_info *info = mtd->priv; struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
u16 retval = 0xFFFF; u16 retval = 0xFFFF;
if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
...@@ -719,7 +722,8 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) ...@@ -719,7 +722,8 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{ {
struct pxa3xx_nand_info *info = mtd->priv; struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
int real_len = min_t(size_t, len, info->buf_count - info->buf_start); int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
memcpy(buf, info->data_buff + info->buf_start, real_len); memcpy(buf, info->data_buff + info->buf_start, real_len);
...@@ -729,7 +733,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) ...@@ -729,7 +733,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void pxa3xx_nand_write_buf(struct mtd_info *mtd, static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len) const uint8_t *buf, int len)
{ {
struct pxa3xx_nand_info *info = mtd->priv; struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
int real_len = min_t(size_t, len, info->buf_count - info->buf_start); int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
memcpy(info->data_buff + info->buf_start, buf, real_len); memcpy(info->data_buff + info->buf_start, buf, real_len);
...@@ -749,7 +754,8 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip) ...@@ -749,7 +754,8 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
{ {
struct pxa3xx_nand_info *info = mtd->priv; struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
/* pxa3xx_nand_send_command has waited for command complete */ /* pxa3xx_nand_send_command has waited for command complete */
if (this->state == FL_WRITING || this->state == FL_ERASING) { if (this->state == FL_WRITING || this->state == FL_ERASING) {
...@@ -772,6 +778,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, ...@@ -772,6 +778,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
{ {
struct platform_device *pdev = info->pdev; struct platform_device *pdev = info->pdev;
struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
struct pxa3xx_nand_host *host = info->host;
uint32_t ndcr = 0x0; /* enable all interrupts */ uint32_t ndcr = 0x0; /* enable all interrupts */
if (f->page_size != 2048 && f->page_size != 512) { if (f->page_size != 2048 && f->page_size != 512) {
...@@ -785,45 +792,52 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, ...@@ -785,45 +792,52 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
} }
/* calculate flash information */ /* calculate flash information */
info->cmdset = &default_cmdset; host->cmdset = &default_cmdset;
info->page_size = f->page_size; host->page_size = f->page_size;
info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
/* calculate addressing information */ /* calculate addressing information */
info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
if (f->num_blocks * f->page_per_block > 65536) if (f->num_blocks * f->page_per_block > 65536)
info->row_addr_cycles = 3; host->row_addr_cycles = 3;
else else
info->row_addr_cycles = 2; host->row_addr_cycles = 2;
ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0; ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes); ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);
ndcr |= NDCR_SPARE_EN; /* enable spare by default */ ndcr |= NDCR_SPARE_EN; /* enable spare by default */
info->reg_ndcr = ndcr; host->reg_ndcr = ndcr;
pxa3xx_nand_set_timing(info, f->timing); pxa3xx_nand_set_timing(host, f->timing);
return 0; return 0;
} }
static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
{ {
struct pxa3xx_nand_host *host = info->host;
uint32_t ndcr = nand_readl(info, NDCR); uint32_t ndcr = nand_readl(info, NDCR);
info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
/* set info fields needed to read id */
info->read_id_bytes = (info->page_size == 2048) ? 4 : 2;
info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
info->cmdset = &default_cmdset;
info->ndtr0cs0 = nand_readl(info, NDTR0CS0); if (ndcr & NDCR_PAGE_SZ) {
info->ndtr1cs0 = nand_readl(info, NDTR1CS0); host->page_size = 2048;
host->read_id_bytes = 4;
} else {
host->page_size = 512;
host->read_id_bytes = 2;
}
host->reg_ndcr = ndcr & ~NDCR_INT_MASK;
host->cmdset = &default_cmdset;
host->ndtr0cs0 = nand_readl(info, NDTR0CS0);
host->ndtr1cs0 = nand_readl(info, NDTR1CS0);
return 0; return 0;
} }
...@@ -853,7 +867,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) ...@@ -853,7 +867,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
return -ENOMEM; return -ENOMEM;
} }
info->data_buff_size = MAX_BUFF_SIZE;
info->data_desc = (void *)info->data_buff + data_desc_offset; info->data_desc = (void *)info->data_buff + data_desc_offset;
info->data_desc_addr = info->data_buff_phys + data_desc_offset; info->data_desc_addr = info->data_buff_phys + data_desc_offset;
...@@ -861,7 +874,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) ...@@ -861,7 +874,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
pxa3xx_nand_data_dma_irq, info); pxa3xx_nand_data_dma_irq, info);
if (info->data_dma_ch < 0) { if (info->data_dma_ch < 0) {
dev_err(&pdev->dev, "failed to request data dma\n"); dev_err(&pdev->dev, "failed to request data dma\n");
dma_free_coherent(&pdev->dev, info->data_buff_size, dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
info->data_buff, info->data_buff_phys); info->data_buff, info->data_buff_phys);
return info->data_dma_ch; return info->data_dma_ch;
} }
...@@ -871,21 +884,25 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) ...@@ -871,21 +884,25 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
{ {
struct mtd_info *mtd = info->mtd; struct mtd_info *mtd = info->host->mtd;
struct nand_chip *chip = mtd->priv; int ret;
/* use the common timing to make a try */ /* use the common timing to make a try */
pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); if (ret)
return ret;
pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
if (info->is_ready) if (info->is_ready)
return 1;
else
return 0; return 0;
return -ENODEV;
} }
static int pxa3xx_nand_scan(struct mtd_info *mtd) static int pxa3xx_nand_scan(struct mtd_info *mtd)
{ {
struct pxa3xx_nand_info *info = mtd->priv; struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
struct platform_device *pdev = info->pdev; struct platform_device *pdev = info->pdev;
struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
...@@ -899,12 +916,10 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) ...@@ -899,12 +916,10 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
goto KEEP_CONFIG; goto KEEP_CONFIG;
ret = pxa3xx_nand_sensing(info); ret = pxa3xx_nand_sensing(info);
if (!ret) { if (ret) {
kfree(mtd);
info->mtd = NULL;
dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n"); dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n");
return -EINVAL; return ret;
} }
chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0);
...@@ -912,8 +927,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) ...@@ -912,8 +927,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
if (id != 0) if (id != 0)
dev_info(&info->pdev->dev, "Detect a flash id %x\n", id); dev_info(&info->pdev->dev, "Detect a flash id %x\n", id);
else { else {
kfree(mtd);
info->mtd = NULL;
dev_warn(&info->pdev->dev, dev_warn(&info->pdev->dev,
"Read out ID 0, potential timing set wrong!!\n"); "Read out ID 0, potential timing set wrong!!\n");
...@@ -933,14 +946,17 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) ...@@ -933,14 +946,17 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
} }
if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
kfree(mtd);
info->mtd = NULL;
dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n"); dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
return -EINVAL; return -EINVAL;
} }
pxa3xx_nand_config_flash(info, f); ret = pxa3xx_nand_config_flash(info, f);
if (ret) {
dev_err(&info->pdev->dev, "ERROR! Configure failed\n");
return ret;
}
pxa3xx_flash_ids[0].name = f->name; pxa3xx_flash_ids[0].name = f->name;
pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff; pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff;
pxa3xx_flash_ids[0].pagesize = f->page_size; pxa3xx_flash_ids[0].pagesize = f->page_size;
...@@ -952,47 +968,56 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) ...@@ -952,47 +968,56 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
pxa3xx_flash_ids[1].name = NULL; pxa3xx_flash_ids[1].name = NULL;
def = pxa3xx_flash_ids; def = pxa3xx_flash_ids;
KEEP_CONFIG: KEEP_CONFIG:
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = host->page_size;
chip->options = NAND_NO_AUTOINCR;
chip->options |= NAND_NO_READRDY;
if (host->reg_ndcr & NDCR_DWIDTH_M)
chip->options |= NAND_BUSWIDTH_16;
if (nand_scan_ident(mtd, 1, def)) if (nand_scan_ident(mtd, 1, def))
return -ENODEV; return -ENODEV;
/* calculate addressing information */ /* calculate addressing information */
info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; if (mtd->writesize >= 2048)
host->col_addr_cycles = 2;
else
host->col_addr_cycles = 1;
info->oob_buff = info->data_buff + mtd->writesize; info->oob_buff = info->data_buff + mtd->writesize;
if ((mtd->size >> chip->page_shift) > 65536) if ((mtd->size >> chip->page_shift) > 65536)
info->row_addr_cycles = 3; host->row_addr_cycles = 3;
else else
info->row_addr_cycles = 2; host->row_addr_cycles = 2;
mtd->name = mtd_names[0];
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = info->page_size;
chip->options = (info->reg_ndcr & NDCR_DWIDTH_M) ? NAND_BUSWIDTH_16 : 0;
chip->options |= NAND_NO_AUTOINCR;
chip->options |= NAND_NO_READRDY;
mtd->name = mtd_names[0];
return nand_scan_tail(mtd); return nand_scan_tail(mtd);
} }
static static int alloc_nand_resource(struct platform_device *pdev)
struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
{ {
struct pxa3xx_nand_info *info; struct pxa3xx_nand_info *info;
struct pxa3xx_nand_host *host;
struct nand_chip *chip; struct nand_chip *chip;
struct mtd_info *mtd; struct mtd_info *mtd;
struct resource *r; struct resource *r;
int ret, irq; int ret, irq;
mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), info = kzalloc(sizeof(*info) + sizeof(*mtd) + sizeof(*host),
GFP_KERNEL); GFP_KERNEL);
if (!mtd) { if (!info) {
dev_err(&pdev->dev, "failed to allocate memory\n"); dev_err(&pdev->dev, "failed to allocate memory\n");
return NULL; return -ENOMEM;
} }
info = (struct pxa3xx_nand_info *)(&mtd[1]); mtd = (struct mtd_info *)(&info[1]);
chip = (struct nand_chip *)(&mtd[1]); chip = (struct nand_chip *)(&mtd[1]);
host = (struct pxa3xx_nand_host *)chip;
info->pdev = pdev; info->pdev = pdev;
info->mtd = mtd; info->host = host;
mtd->priv = info; host->mtd = mtd;
host->info_data = info;
mtd->priv = host;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
...@@ -1000,7 +1025,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) ...@@ -1000,7 +1025,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
chip->controller = &info->controller; chip->controller = &info->controller;
chip->waitfunc = pxa3xx_nand_waitfunc; chip->waitfunc = pxa3xx_nand_waitfunc;
chip->select_chip = pxa3xx_nand_select_chip; chip->select_chip = pxa3xx_nand_select_chip;
chip->dev_ready = pxa3xx_nand_dev_ready;
chip->cmdfunc = pxa3xx_nand_cmdfunc; chip->cmdfunc = pxa3xx_nand_cmdfunc;
chip->read_word = pxa3xx_nand_read_word; chip->read_word = pxa3xx_nand_read_word;
chip->read_byte = pxa3xx_nand_read_byte; chip->read_byte = pxa3xx_nand_read_byte;
...@@ -1079,13 +1103,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) ...@@ -1079,13 +1103,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
return info; return 0;
fail_free_buf: fail_free_buf:
free_irq(irq, info); free_irq(irq, info);
if (use_dma) { if (use_dma) {
pxa_free_dma(info->data_dma_ch); pxa_free_dma(info->data_dma_ch);
dma_free_coherent(&pdev->dev, info->data_buff_size, dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
info->data_buff, info->data_buff_phys); info->data_buff, info->data_buff_phys);
} else } else
kfree(info->data_buff); kfree(info->data_buff);
...@@ -1097,17 +1121,19 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) ...@@ -1097,17 +1121,19 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
clk_disable(info->clk); clk_disable(info->clk);
clk_put(info->clk); clk_put(info->clk);
fail_free_mtd: fail_free_mtd:
kfree(mtd); kfree(info);
return NULL; return ret;
} }
static int pxa3xx_nand_remove(struct platform_device *pdev) static int pxa3xx_nand_remove(struct platform_device *pdev)
{ {
struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
struct mtd_info *mtd = info->mtd;
struct resource *r; struct resource *r;
int irq; int irq;
if (!info)
return 0;
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
...@@ -1115,7 +1141,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) ...@@ -1115,7 +1141,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
free_irq(irq, info); free_irq(irq, info);
if (use_dma) { if (use_dma) {
pxa_free_dma(info->data_dma_ch); pxa_free_dma(info->data_dma_ch);
dma_free_writecombine(&pdev->dev, info->data_buff_size, dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,
info->data_buff, info->data_buff_phys); info->data_buff, info->data_buff_phys);
} else } else
kfree(info->data_buff); kfree(info->data_buff);
...@@ -1127,10 +1153,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) ...@@ -1127,10 +1153,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
clk_disable(info->clk); clk_disable(info->clk);
clk_put(info->clk); clk_put(info->clk);
if (mtd) { nand_release(info->host->mtd);
nand_release(mtd); kfree(info);
kfree(mtd);
}
return 0; return 0;
} }
...@@ -1138,6 +1162,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) ...@@ -1138,6 +1162,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
{ {
struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_platform_data *pdata;
struct pxa3xx_nand_info *info; struct pxa3xx_nand_info *info;
int ret;
pdata = pdev->dev.platform_data; pdata = pdev->dev.platform_data;
if (!pdata) { if (!pdata) {
...@@ -1145,17 +1170,20 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) ...@@ -1145,17 +1170,20 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
info = alloc_nand_resource(pdev); ret = alloc_nand_resource(pdev);
if (info == NULL) if (ret) {
return -ENOMEM; dev_err(&pdev->dev, "alloc nand resource failed\n");
return ret;
}
if (pxa3xx_nand_scan(info->mtd)) { info = platform_get_drvdata(pdev);
if (pxa3xx_nand_scan(info->host->mtd)) {
dev_err(&pdev->dev, "failed to scan nand\n"); dev_err(&pdev->dev, "failed to scan nand\n");
pxa3xx_nand_remove(pdev); pxa3xx_nand_remove(pdev);
return -ENODEV; return -ENODEV;
} }
return mtd_device_parse_register(info->mtd, NULL, 0, return mtd_device_parse_register(info->host->mtd, NULL, 0,
pdata->parts, pdata->nr_parts); pdata->parts, pdata->nr_parts);
} }
...@@ -1182,8 +1210,8 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) ...@@ -1182,8 +1210,8 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
/* We don't want to handle interrupt without calling mtd routine */ /* We don't want to handle interrupt without calling mtd routine */
disable_int(info, NDCR_INT_MASK); disable_int(info, NDCR_INT_MASK);
nand_writel(info, NDTR0CS0, info->ndtr0cs0); nand_writel(info, NDTR0CS0, info->host->ndtr0cs0);
nand_writel(info, NDTR1CS0, info->ndtr1cs0); nand_writel(info, NDTR1CS0, info->host->ndtr1cs0);
/* /*
* As the spec says, the NDSR would be updated to 0x1800 when * As the spec says, the NDSR would be updated to 0x1800 when
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment