mtd: mxc_nand: move function pointers to a per-SOC struct
This prepares switching to platform ids and of-tree probing. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
parent
8556958af4
commit
e4303b25f4
|
@ -140,6 +140,19 @@
|
|||
|
||||
#define NFC_V3_DELAY_LINE (host->regs_ip + 0x34)
|
||||
|
||||
struct mxc_nand_host;
|
||||
|
||||
struct mxc_nand_devtype_data {
|
||||
void (*preset)(struct mtd_info *);
|
||||
void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
|
||||
void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
|
||||
void (*send_page)(struct mtd_info *, unsigned int);
|
||||
void (*send_read_id)(struct mxc_nand_host *);
|
||||
uint16_t (*get_dev_status)(struct mxc_nand_host *);
|
||||
int (*check_int)(struct mxc_nand_host *);
|
||||
void (*irq_control)(struct mxc_nand_host *, int);
|
||||
};
|
||||
|
||||
struct mxc_nand_host {
|
||||
struct mtd_info mtd;
|
||||
struct nand_chip nand;
|
||||
|
@ -165,14 +178,7 @@ struct mxc_nand_host {
|
|||
unsigned int buf_start;
|
||||
int spare_len;
|
||||
|
||||
void (*preset)(struct mtd_info *);
|
||||
void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
|
||||
void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
|
||||
void (*send_page)(struct mtd_info *, unsigned int);
|
||||
void (*send_read_id)(struct mxc_nand_host *);
|
||||
uint16_t (*get_dev_status)(struct mxc_nand_host *);
|
||||
int (*check_int)(struct mxc_nand_host *);
|
||||
void (*irq_control)(struct mxc_nand_host *, int);
|
||||
const struct mxc_nand_devtype_data *devtype_data;
|
||||
|
||||
/*
|
||||
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
|
||||
|
@ -315,7 +321,7 @@ static void irq_control(struct mxc_nand_host *host, int activate)
|
|||
else
|
||||
disable_irq_nosync(host->irq);
|
||||
} else {
|
||||
host->irq_control(host, activate);
|
||||
host->devtype_data->irq_control(host, activate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,7 +329,7 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
|
|||
{
|
||||
struct mxc_nand_host *host = dev_id;
|
||||
|
||||
if (!host->check_int(host))
|
||||
if (!host->devtype_data->check_int(host))
|
||||
return IRQ_NONE;
|
||||
|
||||
irq_control(host, 0);
|
||||
|
@ -341,14 +347,14 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq)
|
|||
int max_retries = 8000;
|
||||
|
||||
if (useirq) {
|
||||
if (!host->check_int(host)) {
|
||||
if (!host->devtype_data->check_int(host)) {
|
||||
INIT_COMPLETION(host->op_completion);
|
||||
irq_control(host, 1);
|
||||
wait_for_completion(&host->op_completion);
|
||||
}
|
||||
} else {
|
||||
while (max_retries-- > 0) {
|
||||
if (host->check_int(host))
|
||||
if (host->devtype_data->check_int(host))
|
||||
break;
|
||||
|
||||
udelay(1);
|
||||
|
@ -621,7 +627,7 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
|
|||
|
||||
/* Check for status request */
|
||||
if (host->status_request)
|
||||
return host->get_dev_status(host) & 0xFF;
|
||||
return host->devtype_data->get_dev_status(host) & 0xFF;
|
||||
|
||||
ret = *(uint8_t *)(host->data_buf + host->buf_start);
|
||||
host->buf_start++;
|
||||
|
@ -756,34 +762,44 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
|
|||
* perform a read/write buf operation, the saved column
|
||||
* address is used to index into the full page.
|
||||
*/
|
||||
host->send_addr(host, 0, page_addr == -1);
|
||||
host->devtype_data->send_addr(host, 0, page_addr == -1);
|
||||
if (mtd->writesize > 512)
|
||||
/* another col addr cycle for 2k page */
|
||||
host->send_addr(host, 0, false);
|
||||
host->devtype_data->send_addr(host, 0, false);
|
||||
}
|
||||
|
||||
/* Write out page address, if necessary */
|
||||
if (page_addr != -1) {
|
||||
/* paddr_0 - p_addr_7 */
|
||||
host->send_addr(host, (page_addr & 0xff), false);
|
||||
host->devtype_data->send_addr(host, (page_addr & 0xff), false);
|
||||
|
||||
if (mtd->writesize > 512) {
|
||||
if (mtd->size >= 0x10000000) {
|
||||
/* paddr_8 - paddr_15 */
|
||||
host->send_addr(host, (page_addr >> 8) & 0xff, false);
|
||||
host->send_addr(host, (page_addr >> 16) & 0xff, true);
|
||||
host->devtype_data->send_addr(host,
|
||||
(page_addr >> 8) & 0xff,
|
||||
false);
|
||||
host->devtype_data->send_addr(host,
|
||||
(page_addr >> 16) & 0xff,
|
||||
true);
|
||||
} else
|
||||
/* paddr_8 - paddr_15 */
|
||||
host->send_addr(host, (page_addr >> 8) & 0xff, true);
|
||||
host->devtype_data->send_addr(host,
|
||||
(page_addr >> 8) & 0xff, true);
|
||||
} else {
|
||||
/* One more address cycle for higher density devices */
|
||||
if (mtd->size >= 0x4000000) {
|
||||
/* paddr_8 - paddr_15 */
|
||||
host->send_addr(host, (page_addr >> 8) & 0xff, false);
|
||||
host->send_addr(host, (page_addr >> 16) & 0xff, true);
|
||||
host->devtype_data->send_addr(host,
|
||||
(page_addr >> 8) & 0xff,
|
||||
false);
|
||||
host->devtype_data->send_addr(host,
|
||||
(page_addr >> 16) & 0xff,
|
||||
true);
|
||||
} else
|
||||
/* paddr_8 - paddr_15 */
|
||||
host->send_addr(host, (page_addr >> 8) & 0xff, true);
|
||||
host->devtype_data->send_addr(host,
|
||||
(page_addr >> 8) & 0xff, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -942,15 +958,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
|||
/* Command pre-processing step */
|
||||
switch (command) {
|
||||
case NAND_CMD_RESET:
|
||||
host->preset(mtd);
|
||||
host->send_cmd(host, command, false);
|
||||
host->devtype_data->preset(mtd);
|
||||
host->devtype_data->send_cmd(host, command, false);
|
||||
break;
|
||||
|
||||
case NAND_CMD_STATUS:
|
||||
host->buf_start = 0;
|
||||
host->status_request = true;
|
||||
|
||||
host->send_cmd(host, command, true);
|
||||
host->devtype_data->send_cmd(host, command, true);
|
||||
mxc_do_addr_cycle(mtd, column, page_addr);
|
||||
break;
|
||||
|
||||
|
@ -963,13 +979,14 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
|||
|
||||
command = NAND_CMD_READ0; /* only READ0 is valid */
|
||||
|
||||
host->send_cmd(host, command, false);
|
||||
host->devtype_data->send_cmd(host, command, false);
|
||||
mxc_do_addr_cycle(mtd, column, page_addr);
|
||||
|
||||
if (mtd->writesize > 512)
|
||||
host->send_cmd(host, NAND_CMD_READSTART, true);
|
||||
host->devtype_data->send_cmd(host,
|
||||
NAND_CMD_READSTART, true);
|
||||
|
||||
host->send_page(mtd, NFC_OUTPUT);
|
||||
host->devtype_data->send_page(mtd, NFC_OUTPUT);
|
||||
|
||||
memcpy(host->data_buf, host->main_area0, mtd->writesize);
|
||||
copy_spare(mtd, true);
|
||||
|
@ -982,28 +999,28 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
|||
|
||||
host->buf_start = column;
|
||||
|
||||
host->send_cmd(host, command, false);
|
||||
host->devtype_data->send_cmd(host, command, false);
|
||||
mxc_do_addr_cycle(mtd, column, page_addr);
|
||||
break;
|
||||
|
||||
case NAND_CMD_PAGEPROG:
|
||||
memcpy(host->main_area0, host->data_buf, mtd->writesize);
|
||||
copy_spare(mtd, false);
|
||||
host->send_page(mtd, NFC_INPUT);
|
||||
host->send_cmd(host, command, true);
|
||||
host->devtype_data->send_page(mtd, NFC_INPUT);
|
||||
host->devtype_data->send_cmd(host, command, true);
|
||||
mxc_do_addr_cycle(mtd, column, page_addr);
|
||||
break;
|
||||
|
||||
case NAND_CMD_READID:
|
||||
host->send_cmd(host, command, true);
|
||||
host->devtype_data->send_cmd(host, command, true);
|
||||
mxc_do_addr_cycle(mtd, column, page_addr);
|
||||
host->send_read_id(host);
|
||||
host->devtype_data->send_read_id(host);
|
||||
host->buf_start = column;
|
||||
break;
|
||||
|
||||
case NAND_CMD_ERASE1:
|
||||
case NAND_CMD_ERASE2:
|
||||
host->send_cmd(host, command, false);
|
||||
host->devtype_data->send_cmd(host, command, false);
|
||||
mxc_do_addr_cycle(mtd, column, page_addr);
|
||||
|
||||
break;
|
||||
|
@ -1037,6 +1054,42 @@ static struct nand_bbt_descr bbt_mirror_descr = {
|
|||
.pattern = mirror_pattern,
|
||||
};
|
||||
|
||||
/* v1: i.MX21, i.MX27, i.MX31 */
|
||||
static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
|
||||
.preset = preset_v1_v2,
|
||||
.send_cmd = send_cmd_v1_v2,
|
||||
.send_addr = send_addr_v1_v2,
|
||||
.send_page = send_page_v1_v2,
|
||||
.send_read_id = send_read_id_v1_v2,
|
||||
.get_dev_status = get_dev_status_v1_v2,
|
||||
.check_int = check_int_v1_v2,
|
||||
.irq_control = irq_control_v1_v2,
|
||||
};
|
||||
|
||||
/* v21: i.MX25, i.MX35 */
|
||||
static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
|
||||
.preset = preset_v1_v2,
|
||||
.send_cmd = send_cmd_v1_v2,
|
||||
.send_addr = send_addr_v1_v2,
|
||||
.send_page = send_page_v1_v2,
|
||||
.send_read_id = send_read_id_v1_v2,
|
||||
.get_dev_status = get_dev_status_v1_v2,
|
||||
.check_int = check_int_v1_v2,
|
||||
.irq_control = irq_control_v1_v2,
|
||||
};
|
||||
|
||||
/* v3: i.MX51, i.MX53 */
|
||||
static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
|
||||
.preset = preset_v3,
|
||||
.send_cmd = send_cmd_v3,
|
||||
.send_addr = send_addr_v3,
|
||||
.send_page = send_page_v3,
|
||||
.send_read_id = send_read_id_v3,
|
||||
.get_dev_status = get_dev_status_v3,
|
||||
.check_int = check_int_v3,
|
||||
.irq_control = irq_control_v3,
|
||||
};
|
||||
|
||||
static int __init mxcnd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct nand_chip *this;
|
||||
|
@ -1100,27 +1153,10 @@ static int __init mxcnd_probe(struct platform_device *pdev)
|
|||
|
||||
host->main_area0 = host->base;
|
||||
|
||||
if (nfc_is_v1() || nfc_is_v21()) {
|
||||
host->preset = preset_v1_v2;
|
||||
host->send_cmd = send_cmd_v1_v2;
|
||||
host->send_addr = send_addr_v1_v2;
|
||||
host->send_page = send_page_v1_v2;
|
||||
host->send_read_id = send_read_id_v1_v2;
|
||||
host->get_dev_status = get_dev_status_v1_v2;
|
||||
host->check_int = check_int_v1_v2;
|
||||
host->irq_control = irq_control_v1_v2;
|
||||
if (nfc_is_v1()) {
|
||||
host->devtype_data = &imx21_nand_devtype_data;
|
||||
if (cpu_is_mx21())
|
||||
host->irqpending_quirk = 1;
|
||||
}
|
||||
|
||||
if (nfc_is_v21()) {
|
||||
host->regs = host->base + 0x1e00;
|
||||
host->spare0 = host->base + 0x1000;
|
||||
host->spare_len = 64;
|
||||
oob_smallpage = &nandv2_hw_eccoob_smallpage;
|
||||
oob_largepage = &nandv2_hw_eccoob_largepage;
|
||||
this->ecc.bytes = 9;
|
||||
} else if (nfc_is_v1()) {
|
||||
host->regs = host->base + 0xe00;
|
||||
host->spare0 = host->base + 0x800;
|
||||
host->spare_len = 16;
|
||||
|
@ -1128,7 +1164,16 @@ static int __init mxcnd_probe(struct platform_device *pdev)
|
|||
oob_largepage = &nandv1_hw_eccoob_largepage;
|
||||
this->ecc.bytes = 3;
|
||||
host->eccsize = 1;
|
||||
} else if (nfc_is_v21()) {
|
||||
host->devtype_data = &imx25_nand_devtype_data;
|
||||
host->regs = host->base + 0x1e00;
|
||||
host->spare0 = host->base + 0x1000;
|
||||
host->spare_len = 64;
|
||||
oob_smallpage = &nandv2_hw_eccoob_smallpage;
|
||||
oob_largepage = &nandv2_hw_eccoob_largepage;
|
||||
this->ecc.bytes = 9;
|
||||
} else if (nfc_is_v3_2()) {
|
||||
host->devtype_data = &imx51_nand_devtype_data;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
err = -ENODEV;
|
||||
|
@ -1142,14 +1187,6 @@ static int __init mxcnd_probe(struct platform_device *pdev)
|
|||
host->regs_axi = host->base + 0x1e00;
|
||||
host->spare0 = host->base + 0x1000;
|
||||
host->spare_len = 64;
|
||||
host->preset = preset_v3;
|
||||
host->send_cmd = send_cmd_v3;
|
||||
host->send_addr = send_addr_v3;
|
||||
host->send_page = send_page_v3;
|
||||
host->send_read_id = send_read_id_v3;
|
||||
host->check_int = check_int_v3;
|
||||
host->get_dev_status = get_dev_status_v3;
|
||||
host->irq_control = irq_control_v3;
|
||||
oob_smallpage = &nandv2_hw_eccoob_smallpage;
|
||||
oob_largepage = &nandv2_hw_eccoob_largepage;
|
||||
} else
|
||||
|
@ -1186,10 +1223,11 @@ static int __init mxcnd_probe(struct platform_device *pdev)
|
|||
host->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
/*
|
||||
* Use host->irq_control here instead of irq_control because we must not
|
||||
* disable_irq_nosync without having requested the irq
|
||||
* Use host->devtype_data->irq_control() here instead of irq_control()
|
||||
* because we must not disable_irq_nosync without having requested the
|
||||
* irq.
|
||||
*/
|
||||
host->irq_control(host, 0);
|
||||
host->devtype_data->irq_control(host, 0);
|
||||
|
||||
err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
|
||||
if (err)
|
||||
|
@ -1202,7 +1240,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
|
|||
*/
|
||||
if (host->irqpending_quirk) {
|
||||
disable_irq_nosync(host->irq);
|
||||
host->irq_control(host, 1);
|
||||
host->devtype_data->irq_control(host, 1);
|
||||
}
|
||||
|
||||
/* first scan to find the device and get the page size */
|
||||
|
@ -1212,7 +1250,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* Call preset again, with correct writesize this time */
|
||||
host->preset(mtd);
|
||||
host->devtype_data->preset(mtd);
|
||||
|
||||
if (mtd->writesize == 2048)
|
||||
this->ecc.layout = oob_largepage;
|
||||
|
|
Loading…
Reference in a new issue