From 4123ea34aac754cdbd0a5e482c29be433c311d67 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 15 Sep 2016 10:32:52 +0200 Subject: mtd: nand: mxc: implement onfi get/set features To be able to support different ONFI timing modes we have to implement the onfi_set_features and onfi_get_features. Tested on an i.MX25 SoC. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'drivers/mtd/nand/mxc_nand.c') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 5173fadc9a4e..8bd8108066ea 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1239,6 +1239,59 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, } } +static int mxc_nand_onfi_set_features(struct mtd_info *mtd, + struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + int i; + + if (!chip->onfi_version || + !(le16_to_cpu(chip->onfi_params.opt_cmd) + & ONFI_OPT_CMD_SET_GET_FEATURES)) + return -EINVAL; + + host->buf_start = 0; + + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + chip->write_byte(mtd, subfeature_param[i]); + + memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize); + host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false); + mxc_do_addr_cycle(mtd, addr, -1); + host->devtype_data->send_page(mtd, NFC_INPUT); + + return 0; +} + +static int mxc_nand_onfi_get_features(struct mtd_info *mtd, + struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + int i; + + if (!chip->onfi_version || + !(le16_to_cpu(chip->onfi_params.opt_cmd) + & ONFI_OPT_CMD_SET_GET_FEATURES)) + return -EINVAL; + + *(uint32_t *)host->main_area0 = 0xdeadbeef; + + host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false); + mxc_do_addr_cycle(mtd, addr, -1); + host->devtype_data->send_page(mtd, NFC_OUTPUT); + memcpy32_fromio(host->data_buf, host->main_area0, 512); + host->buf_start = 0; + + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + *subfeature_param++ = chip->read_byte(mtd); + + return 0; +} + /* * The generic flash bbt decriptors overlap with our ecc * hardware, so define some i.MX specific ones. @@ -1513,6 +1566,8 @@ static int mxcnd_probe(struct platform_device *pdev) this->read_word = mxc_nand_read_word; this->write_buf = mxc_nand_write_buf; this->read_buf = mxc_nand_read_buf; + this->onfi_set_features = mxc_nand_onfi_set_features; + this->onfi_get_features = mxc_nand_onfi_get_features; host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) -- cgit v1.2.3 From 8283079696aba905367297cf80287980eb34c14c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 15 Sep 2016 10:32:53 +0200 Subject: mtd: nand: mxc: Add timing setup for v2 controllers So far we relied on reset default or the bootloader to configure a suitable clk rate for the Nand controller. This works but we can optimize the timing for better performance. This sets the clk rate for v2 controllers (i.MX25/35) based on the timing mode read from the ONFI parameter page. This may also enable the symmetric mode (aks EDO mode) if necessary which reads one word per clock cycle. Tested on an i.MX25 with a Micron MT29F4G08ABBDAHC attached. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 84 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/nand/mxc_nand.c') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 8bd8108066ea..75c0c0eb52ae 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -152,6 +152,9 @@ struct mxc_nand_devtype_data { void (*select_chip)(struct mtd_info *mtd, int chip); int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); + int (*setup_data_interface)(struct mtd_info *mtd, + const struct nand_data_interface *conf, + bool check_only); /* * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked @@ -1012,6 +1015,82 @@ static void preset_v1(struct mtd_info *mtd) writew(0x4, NFC_V1_V2_WRPROT); } +static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, + const struct nand_data_interface *conf, + bool check_only) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + int tRC_min_ns, tRC_ps, ret; + unsigned long rate, rate_round; + const struct nand_sdr_timings *timings; + u16 config1; + + timings = nand_get_sdr_timings(conf); + if (IS_ERR(timings)) + return -ENOTSUPP; + + config1 = readw(NFC_V1_V2_CONFIG1); + + tRC_min_ns = timings->tRC_min / 1000; + rate = 1000000000 / tRC_min_ns; + + /* + * For tRC < 30ns we have to use EDO mode. In this case the controller + * does one access per clock cycle. Otherwise the controller does one + * access in two clock cycles, thus we have to double the rate to the + * controller. + */ + if (tRC_min_ns < 30) { + rate_round = clk_round_rate(host->clk, rate); + config1 |= NFC_V2_CONFIG1_ONE_CYCLE; + tRC_ps = 1000000000 / (rate_round / 1000); + } else { + rate *= 2; + rate_round = clk_round_rate(host->clk, rate); + config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE; + tRC_ps = 1000000000 / (rate_round / 1000 / 2); + } + + /* + * The timing values compared against are from the i.MX25 Automotive + * datasheet, Table 50. NFC Timing Parameters + */ + if (timings->tCLS_min > tRC_ps - 1000 || + timings->tCLH_min > tRC_ps - 2000 || + timings->tCS_min > tRC_ps - 1000 || + timings->tCH_min > tRC_ps - 2000 || + timings->tWP_min > tRC_ps - 1500 || + timings->tALS_min > tRC_ps || + timings->tALH_min > tRC_ps - 3000 || + timings->tDS_min > tRC_ps || + timings->tDH_min > tRC_ps - 5000 || + timings->tWC_min > 2 * tRC_ps || + timings->tWH_min > tRC_ps - 2500 || + timings->tRR_min > 6 * tRC_ps || + timings->tRP_min > 3 * tRC_ps / 2 || + timings->tRC_min > 2 * tRC_ps || + timings->tREH_min > (tRC_ps / 2) - 2500) { + dev_dbg(host->dev, "Timing out of bounds\n"); + return -EINVAL; + } + + if (check_only) + return 0; + + ret = clk_set_rate(host->clk, rate); + if (ret) + return ret; + + writew(config1, NFC_V1_V2_CONFIG1); + + dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round, + config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" : + "normal"); + + return 0; +} + static void preset_v2(struct mtd_info *mtd) { struct nand_chip *nand_chip = mtd_to_nand(mtd); @@ -1278,8 +1357,6 @@ static int mxc_nand_onfi_get_features(struct mtd_info *mtd, & ONFI_OPT_CMD_SET_GET_FEATURES)) return -EINVAL; - *(uint32_t *)host->main_area0 = 0xdeadbeef; - host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false); mxc_do_addr_cycle(mtd, addr, -1); host->devtype_data->send_page(mtd, NFC_OUTPUT); @@ -1380,6 +1457,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { .ooblayout = &mxc_v2_ooblayout_ops, .select_chip = mxc_nand_select_chip_v2, .correct_data = mxc_nand_correct_data_v2_v3, + .setup_data_interface = mxc_nand_v2_setup_data_interface, .irqpending_quirk = 0, .needs_ip = 0, .regs_offset = 0x1e00, @@ -1588,6 +1666,8 @@ static int mxcnd_probe(struct platform_device *pdev) if (err < 0) return err; + this->setup_data_interface = host->devtype_data->setup_data_interface; + if (host->devtype_data->needs_ip) { res = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->regs_ip = devm_ioremap_resource(&pdev->dev, res); -- cgit v1.2.3 From ba52b4dd653088cb936b94c447f0a4dd20814629 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sat, 17 Sep 2016 19:44:43 +0200 Subject: mtd: nand: mxc: Test CONFIG_OF instead of CONFIG_OF_MTD We are about to drop the OF_MTD Kconfig option. Test CONFIG_OF activation instead of CONFIG_OF_MTD. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand/mxc_nand.c') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 75c0c0eb52ae..d68314c8c399 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1565,7 +1565,7 @@ static const struct platform_device_id mxcnd_devtype[] = { }; MODULE_DEVICE_TABLE(platform, mxcnd_devtype); -#ifdef CONFIG_OF_MTD +#ifdef CONFIG_OF static const struct of_device_id mxcnd_dt_ids[] = { { .compatible = "fsl,imx21-nand", -- cgit v1.2.3