1
0
Fork 0

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>
hifive-unleashed-5.1
Uwe Kleine-König 2012-04-23 11:23:35 +02:00 committed by David Woodhouse
parent 8556958af4
commit e4303b25f4
1 changed files with 104 additions and 66 deletions

View File

@ -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;