From 39c47d7f2e3a82c2f06ea659b046006111d8ceb2 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Thu, 29 Feb 2024 16:12:08 +0100 Subject: [PATCH] WIP: mtd: rawnand: Override automatic NAND timing mode from dts Makes it possible to use problematic combinations of flash chips and controllers like for example SMC on at91 SAM9X60 with S34ML02G1 by explicitly giving an ONFI timing mode in dts instead of finding the best mode automatically. --- drivers/mtd/nand/raw/nand_base.c | 56 ++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index d7dbbd469b8925..8f1162abe36721 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -916,6 +916,28 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr) return ret; } +static int of_get_nand_onfi_timing_mode(struct nand_chip *chip) +{ + struct device_node *dn = nand_get_flash_node(chip); + u32 val; + int ret; + + ret = of_property_read_u32(dn, "nand-onfi-timing-mode", &val); + +#if 0 + if (ret < 0) + { + pr_debug("Error (%d) reading property 'nand-onfi-timing-mode'.\n", ret); + return ret; + } else { + pr_debug("Got nand-onfi-timing-mode val %u\n", val); + return val; + } +#else + return (ret < 0) ? ret : val; +#endif +} + /** * nand_choose_best_sdr_timings - Pick up the best SDR timings that both the * NAND controller and the NAND chip support @@ -935,7 +957,15 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, iface->type = NAND_SDR_IFACE; - if (spec_timings) { + mode = of_get_nand_onfi_timing_mode(chip); + + if (mode >= 0) { + /* Optionally override best mode from device tree. */ + pr_debug("Overriding automatic NAND timing mode, trying ONFI mode %d on %s interface\n", + mode, "SDR"); + best_mode = mode; + } else if (spec_timings) { + pr_debug("Trying specific NAND timings on %s interface\n", "SDR"); iface->timings.sdr = *spec_timings; iface->timings.mode = onfi_find_closest_sdr_mode(spec_timings); @@ -943,6 +973,7 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, iface); if (!ret) { + pr_debug("Using specific NAND timings on %s interface\n", "SDR"); chip->best_interface_config = iface; return ret; } @@ -951,6 +982,7 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, best_mode = iface->timings.mode; } else if (chip->parameters.onfi) { best_mode = fls(chip->parameters.onfi->sdr_timing_modes) - 1; + pr_debug("Trying ONFI mode %d on %s interface\n", best_mode, "SDR"); } for (mode = best_mode; mode >= 0; mode--) { @@ -964,6 +996,11 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip, } } + if (ret) + pr_debug("No timing mode found for %s interface\n", "SDR"); + else + pr_debug("Using ONFI timing mode %d for %s interface\n", mode, "SDR"); + return ret; } @@ -986,7 +1023,15 @@ int nand_choose_best_nvddr_timings(struct nand_chip *chip, iface->type = NAND_NVDDR_IFACE; - if (spec_timings) { + mode = of_get_nand_onfi_timing_mode(chip); + + if (mode >= 0) { + /* Optionally override best mode from device tree. */ + pr_debug("Overriding automatic NAND timing mode, trying ONFI mode %d on %s interface\n", + mode, "NV-DDR"); + best_mode = mode; + } else if (spec_timings) { + pr_debug("Trying specific NAND timings on %s interface\n", "NV-DDR"); iface->timings.nvddr = *spec_timings; iface->timings.mode = onfi_find_closest_nvddr_mode(spec_timings); @@ -994,6 +1039,7 @@ int nand_choose_best_nvddr_timings(struct nand_chip *chip, ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, iface); if (!ret) { + pr_debug("Using specific NAND timings on %s interface\n", "NV-DDR"); chip->best_interface_config = iface; return ret; } @@ -1002,6 +1048,7 @@ int nand_choose_best_nvddr_timings(struct nand_chip *chip, best_mode = iface->timings.mode; } else if (chip->parameters.onfi) { best_mode = fls(chip->parameters.onfi->nvddr_timing_modes) - 1; + pr_debug("Trying ONFI mode %d on %s interface\n", best_mode, "NV-DDR"); } for (mode = best_mode; mode >= 0; mode--) { @@ -1015,6 +1062,11 @@ int nand_choose_best_nvddr_timings(struct nand_chip *chip, } } + if (ret) + pr_debug("No timing mode found for %s interface\n", "NV-DDR"); + else + pr_debug("Using ONFI timing mode %d for %s interface\n", mode, "NV-DDR"); + return ret; }