diff options
Diffstat (limited to 'arch/arm/mach-omap2/gpmc-nand.c')
| -rw-r--r-- | arch/arm/mach-omap2/gpmc-nand.c | 126 |
1 files changed, 61 insertions, 65 deletions
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index db969a5c499..93914d22006 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -43,85 +43,69 @@ static struct platform_device gpmc_nand_device = { .resource = gpmc_nand_resource, }; -static int omap2_nand_gpmc_retime( - struct omap_nand_platform_data *gpmc_nand_data, - struct gpmc_timings *gpmc_t) +static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) { - struct gpmc_timings t; - int err; - - memset(&t, 0, sizeof(t)); - t.sync_clk = gpmc_t->sync_clk; - t.cs_on = gpmc_t->cs_on; - t.adv_on = gpmc_t->adv_on; - - /* Read */ - t.adv_rd_off = gpmc_t->adv_rd_off; - t.oe_on = t.adv_on; - t.access = gpmc_t->access; - t.oe_off = gpmc_t->oe_off; - t.cs_rd_off = gpmc_t->cs_rd_off; - t.rd_cycle = gpmc_t->rd_cycle; - - /* Write */ - t.adv_wr_off = gpmc_t->adv_wr_off; - t.we_on = t.oe_on; - if (cpu_is_omap34xx()) { - t.wr_data_mux_bus = gpmc_t->wr_data_mux_bus; - t.wr_access = gpmc_t->wr_access; + /* platforms which support all ECC schemes */ + if (soc_is_am33xx() || soc_is_am43xx() || cpu_is_omap44xx() || + soc_is_omap54xx() || soc_is_dra7xx()) + return 1; + + if (ecc_opt == OMAP_ECC_BCH4_CODE_HW_DETECTION_SW || + ecc_opt == OMAP_ECC_BCH8_CODE_HW_DETECTION_SW) { + if (cpu_is_omap24xx()) + return 0; + else if (cpu_is_omap3630() && (GET_OMAP_REVISION() == 0)) + return 0; + else + return 1; } - t.we_off = gpmc_t->we_off; - t.cs_wr_off = gpmc_t->cs_wr_off; - t.wr_cycle = gpmc_t->wr_cycle; - /* Configure GPMC */ - if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 1); - else - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0); - gpmc_cs_configure(gpmc_nand_data->cs, - GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND); - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0); - err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); - if (err) - return err; + /* OMAP3xxx do not have ELM engine, so cannot support ECC schemes + * which require H/W based ECC error detection */ + if ((cpu_is_omap34xx() || cpu_is_omap3630()) && + ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) || + (ecc_opt == OMAP_ECC_BCH8_CODE_HW))) + return 0; - return 0; + /* legacy platforms support only HAM1 (1-bit Hamming) ECC scheme */ + if (ecc_opt == OMAP_ECC_HAM1_CODE_HW) + return 1; + else + return 0; } -static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) +/* This function will go away once the device-tree convertion is complete */ +static void gpmc_set_legacy(struct omap_nand_platform_data *gpmc_nand_data, + struct gpmc_settings *s) { - /* support only OMAP3 class */ - if (!cpu_is_omap34xx()) { - pr_err("BCH ecc is not supported on this CPU\n"); - return 0; - } - - /* - * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1. - * Other chips may be added if confirmed to work. - */ - if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) && - (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) { - pr_err("BCH 4-bit mode is not supported on this CPU\n"); - return 0; + /* Enable RD PIN Monitoring Reg */ + if (gpmc_nand_data->dev_ready) { + s->wait_on_read = true; + s->wait_on_write = true; } - return 1; + if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16) + s->device_width = GPMC_DEVWIDTH_16BIT; + else + s->device_width = GPMC_DEVWIDTH_8BIT; } -int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, - struct gpmc_timings *gpmc_t) +int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, + struct gpmc_timings *gpmc_t) { int err = 0; + struct gpmc_settings s; struct device *dev = &gpmc_nand_device.dev; + memset(&s, 0, sizeof(struct gpmc_settings)); + gpmc_nand_device.dev.platform_data = gpmc_nand_data; err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, (unsigned long *)&gpmc_nand_resource[0].start); if (err < 0) { - dev_err(dev, "Cannot request GPMC CS\n"); + dev_err(dev, "Cannot request GPMC CS %d, error %d\n", + gpmc_nand_data->cs, err); return err; } @@ -134,22 +118,34 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); if (gpmc_t) { - err = omap2_nand_gpmc_retime(gpmc_nand_data, gpmc_t); + err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t); if (err < 0) { dev_err(dev, "Unable to set gpmc timings: %d\n", err); return err; } } - /* Enable RD PIN Monitoring Reg */ - if (gpmc_nand_data->dev_ready) { - gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1); - } + if (gpmc_nand_data->of_node) + gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); + else + gpmc_set_legacy(gpmc_nand_data, &s); + + s.device_nand = true; + + err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s); + if (err < 0) + goto out_free_cs; + + err = gpmc_configure(GPMC_CONFIG_WP, 0); + if (err < 0) + goto out_free_cs; gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs); - if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) + if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) { + dev_err(dev, "Unsupported NAND ECC scheme selected\n"); return -EINVAL; + } err = platform_device_register(&gpmc_nand_device); if (err < 0) { |
