diff --git a/target/linux/imx/patches-6.6/400-gpmi-nand.patch b/target/linux/imx/patches-6.6/400-gpmi-nand.patch index ea268c3421e9f7..d02a1db28824d0 100644 --- a/target/linux/imx/patches-6.6/400-gpmi-nand.patch +++ b/target/linux/imx/patches-6.6/400-gpmi-nand.patch @@ -9,16 +9,114 @@ Signed-off-by: Alexey Sadkov --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c -@@ -943,7 +943,7 @@ - return ret; - } +@@ -14,12 +14,18 @@ + #include + #include + #include ++#include + #include ++#include ++#include + #include + #include "gpmi-nand.h" + #include "gpmi-regs.h" + #include "bch-regs.h" + ++/* export the bch geometry to dbgfs */ ++static struct debugfs_blob_wrapper dbg_bch_geo; ++ + /* Resource names for the GPMI NAND driver. */ + #define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand" + #define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch" +@@ -112,7 +118,7 @@ + return 0; + + error: +- pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); ++ pr_err("%s(%px): module reset timeout\n", __func__, reset_addr); + return -ETIMEDOUT; + } + +@@ -146,7 +152,7 @@ + static int gpmi_init(struct gpmi_nand_data *this) + { + struct resources *r = &this->resources; +- int ret; ++ int ret = 0; + + ret = pm_runtime_resume_and_get(this->dev); + if (ret < 0) +@@ -727,11 +733,40 @@ + return err; + } + ++int bch_create_debugfs(struct gpmi_nand_data *this) ++{ ++ struct bch_geometry *bch_geo = &this->bch_geometry; ++ struct dentry *dbg_root; ++ ++ dbg_root = debugfs_create_dir("gpmi-nand", NULL); ++ if (!dbg_root) { ++ dev_err(this->dev, "failed to create debug directory\n"); ++ return -EINVAL; ++ } ++ ++ dbg_bch_geo.data = (void *)bch_geo; ++ dbg_bch_geo.size = sizeof(struct bch_geometry); ++ if (!debugfs_create_blob("bch_geometry", S_IRUGO, ++ dbg_root, &dbg_bch_geo)) { ++ dev_err(this->dev, "failed to create debug bch geometry\n"); ++ return -EINVAL; ++ } ++ ++ /* create raw mode flag */ ++ if (!debugfs_create_file("raw_mode", S_IRUGO, ++ dbg_root, NULL, NULL)) { ++ dev_err(this->dev, "failed to create raw mode flag\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + /* Configures the geometry for BCH. */ + static int bch_set_geometry(struct gpmi_nand_data *this) + { + struct resources *r = &this->resources; +- int ret; ++ int ret = 0; + + ret = common_nfc_set_geometry(this); + if (ret) +@@ -755,7 +790,6 @@ + /* Set *all* chip selects to use layout 0. */ + writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT); + +- ret = 0; + err_out: + pm_runtime_mark_last_busy(this->dev); + pm_runtime_put_autosuspend(this->dev); +@@ -937,6 +971,9 @@ + if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this)) + clk_disable_unprepare(r->clock[0]); + ++ if (GPMI_IS_MX6SX(this) && hw->clk_rate > 88000000) ++ hw->clk_rate = 88000000; ++ + ret = clk_set_rate(r->clock[0], hw->clk_rate); + if (ret) { + dev_err(this->dev, "cannot set clock rate to %lu Hz: %d\n", hw->clk_rate, ret); +@@ -983,7 +1020,8 @@ + return PTR_ERR(sdr); + + /* Only MX28/MX6 GPMI controller can reach EDO timings */ +- if (sdr->tRC_min <= 25000 && !GPMI_IS_MX28(this) && !GPMI_IS_MX6(this)) ++ if (sdr->tRC_min <= 25000 && !GPMI_IS_MX28(this) && ++ !(GPMI_IS_MX6(this) || GPMI_IS_MX8(this))) + return -ENOTSUPP; -- if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this)) { -+ if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this) || GPMI_IS_MX6UL(this) || GPMI_IS_MX6ULL(this) || GPMI_IS_MX6QP(this)) { - ret = clk_prepare_enable(r->clock[0]); - if (ret) - return ret; -@@ -1157,6 +1157,14 @@ + /* Stop here if this call was just a check */ +@@ -1157,6 +1195,14 @@ .clks = gpmi_clks_for_mx6, .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), }; @@ -33,44 +131,241 @@ Signed-off-by: Alexey Sadkov static const struct gpmi_devdata gpmi_devdata_imx6sx = { .type = IS_MX6SX, -@@ -1165,6 +1173,22 @@ - .clks = gpmi_clks_for_mx6, - .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), +@@ -1177,6 +1223,17 @@ + .clks = gpmi_clks_for_mx7d, + .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d), }; -+ -+static const struct gpmi_devdata gpmi_devdata_imx6ul = { -+ .type = IS_MX6UL, -+ .bch_max_ecc_strength = 40, -+ .max_chain_delay = 12000, -+ .clks = gpmi_clks_for_mx6, -+ .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), ++static const char * gpmi_clks_for_mx8qxp[GPMI_CLK_MAX] = { ++ "gpmi_clk", "gpmi_apb_clk", "bch_clk", "bch_apb_clk", +}; + -+static const struct gpmi_devdata gpmi_devdata_imx6ull = { -+ .type = IS_MX6ULL, -+ .bch_max_ecc_strength = 40, ++static const struct gpmi_devdata gpmi_devdata_imx8qxp = { ++ .type = IS_MX8QXP, ++ .bch_max_ecc_strength = 62, + .max_chain_delay = 12000, -+ .clks = gpmi_clks_for_mx6, -+ .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), ++ .clks = gpmi_clks_for_mx8qxp, ++ .clks_count = ARRAY_SIZE(gpmi_clks_for_mx8qxp), +}; - static const char * const gpmi_clks_for_mx7d[] = { - "gpmi_io", "gpmi_bch_apb", -@@ -2719,8 +2743,11 @@ + static int acquire_register_block(struct gpmi_nand_data *this, + const char *res_name) +@@ -1284,10 +1341,6 @@ + if (ret) + goto exit_regs; + +- ret = acquire_dma_channels(this); +- if (ret) +- goto exit_regs; +- + ret = gpmi_get_clks(this); + if (ret) + goto exit_clock; +@@ -2190,7 +2243,7 @@ + */ + chipnr = block >> (chip->chip_shift - chip->phys_erase_shift); + page = block << (chip->phys_erase_shift - chip->page_shift); +- byte = block << chip->phys_erase_shift; ++ byte = (loff_t)block << chip->phys_erase_shift; + + /* Send the command to read the conventional block mark. */ + nand_select_target(chip, chipnr); +@@ -2262,6 +2315,11 @@ + if (ret) + return ret; + ++ /* Save the geometry to debugfs*/ ++ ret = bch_create_debugfs(this); ++ if (ret) ++ return ret; ++ + /* Init the nand_ecc_ctrl{} */ + ecc->read_page = gpmi_ecc_read_page; + ecc->write_page = gpmi_ecc_write_page; +@@ -2281,7 +2339,7 @@ + * (1) the chip is imx6, and + * (2) the size of the ECC parity is byte aligned. + */ +- if (GPMI_IS_MX6(this) && ++ if ((GPMI_IS_MX6(this) || GPMI_IS_MX8(this)) && + ((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) { + ecc->read_subpage = gpmi_ecc_read_subpage; + chip->options |= NAND_SUBPAGE_READ; +@@ -2567,11 +2625,11 @@ + &direct); + break; + } ++ } + +- if (!desc) { +- ret = -ENXIO; +- goto unmap; +- } ++ if (!desc) { ++ ret = -ENXIO; ++ goto unmap; + } + + dev_dbg(this->dev, "%s setup done\n", __func__); +@@ -2662,6 +2720,7 @@ + { + struct nand_chip *chip = &this->nand; + struct mtd_info *mtd = nand_to_mtd(chip); ++ u32 max_cs; + int ret; + + /* init the MTD data structures */ +@@ -2692,7 +2751,12 @@ + this->base.ops = &gpmi_nand_controller_ops; + chip->controller = &this->base; + +- ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1); ++ max_cs = (GPMI_IS_MX6(this) || GPMI_IS_MX8(this)) ? 2 : 1; ++ ++ /* override the max_cs if board has other limitations */ ++ of_property_read_u32(this->pdev->dev.of_node, "fsl,max-nand-cs", &max_cs); ++ ++ ret = nand_scan(chip, max_cs); + if (ret) + goto err_out; + +@@ -2719,8 +2783,10 @@ { .compatible = "fsl,imx23-gpmi-nand", .data = &gpmi_devdata_imx23, }, { .compatible = "fsl,imx28-gpmi-nand", .data = &gpmi_devdata_imx28, }, { .compatible = "fsl,imx6q-gpmi-nand", .data = &gpmi_devdata_imx6q, }, + { .compatible = "fsl,imx6qp-gpmi-nand", .data = &gpmi_devdata_imx6qp, }, { .compatible = "fsl,imx6sx-gpmi-nand", .data = &gpmi_devdata_imx6sx, }, - { .compatible = "fsl,imx7d-gpmi-nand", .data = &gpmi_devdata_imx7d,}, -+ { .compatible = "fsl,imx6ul-gpmi-nand", .data = &gpmi_devdata_imx6ul, }, -+ { .compatible = "fsl,imx6ull-gpmi-nand", .data = &gpmi_devdata_imx6ull, }, +- { .compatible = "fsl,imx7d-gpmi-nand", .data = &gpmi_devdata_imx7d,}, ++ { .compatible = "fsl,imx7d-gpmi-nand", .data = &gpmi_devdata_imx7d, }, ++ { .compatible = "fsl,imx8qxp-gpmi-nand", .data = &gpmi_devdata_imx8qxp, }, {} }; MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); +@@ -2743,15 +2809,9 @@ + if (ret) + goto exit_acquire_resources; + +- ret = __gpmi_enable_clk(this, true); +- if (ret) +- goto exit_acquire_resources; +- ++ pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 500); + pm_runtime_use_autosuspend(&pdev->dev); +- pm_runtime_set_active(&pdev->dev); +- pm_runtime_enable(&pdev->dev); +- pm_runtime_get_sync(&pdev->dev); + + ret = gpmi_init(this); + if (ret) +@@ -2761,15 +2821,12 @@ + if (ret) + goto exit_nfc_init; + +- pm_runtime_mark_last_busy(&pdev->dev); +- pm_runtime_put_autosuspend(&pdev->dev); +- + dev_info(this->dev, "driver registered.\n"); + + return 0; + + exit_nfc_init: +- pm_runtime_put(&pdev->dev); ++ pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + release_resources(this); + exit_acquire_resources: +@@ -2783,7 +2840,6 @@ + struct nand_chip *chip = &this->nand; + int ret; + +- pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + ret = mtd_device_unregister(nand_to_mtd(chip)); +@@ -2796,10 +2852,12 @@ + #ifdef CONFIG_PM_SLEEP + static int gpmi_pm_suspend(struct device *dev) + { +- struct gpmi_nand_data *this = dev_get_drvdata(dev); ++ int ret; + +- release_dma_channels(this); +- return 0; ++ pinctrl_pm_select_sleep_state(dev); ++ ret = pm_runtime_force_suspend(dev); ++ ++ return ret; + } + + static int gpmi_pm_resume(struct device *dev) +@@ -2807,9 +2865,13 @@ + struct gpmi_nand_data *this = dev_get_drvdata(dev); + int ret; + +- ret = acquire_dma_channels(this); +- if (ret < 0) ++ ret = pm_runtime_force_resume(dev); ++ if (ret) { ++ dev_err(this->dev, "Error in resume %d\n", ret); + return ret; ++ } ++ ++ pinctrl_pm_select_default_state(dev); + + /* re-init the GPMI registers */ + ret = gpmi_init(this); +@@ -2829,22 +2891,44 @@ + return ret; + } + ++ /* re-apply the timing setting */ ++ this->hw.must_apply_timings = true; ++ + return 0; + } + #endif /* CONFIG_PM_SLEEP */ + +-static int __maybe_unused gpmi_runtime_suspend(struct device *dev) ++#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true) ++#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false) ++ ++static int gpmi_runtime_suspend(struct device *dev) + { + struct gpmi_nand_data *this = dev_get_drvdata(dev); + +- return __gpmi_enable_clk(this, false); ++ gpmi_disable_clk(this); ++ release_bus_freq(BUS_FREQ_HIGH); ++ release_dma_channels(this); ++ ++ return 0; + } + +-static int __maybe_unused gpmi_runtime_resume(struct device *dev) ++static int gpmi_runtime_resume(struct device *dev) + { + struct gpmi_nand_data *this = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = gpmi_enable_clk(this); ++ if (ret) ++ return ret; ++ ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ ret = acquire_dma_channels(this); ++ if (ret < 0) ++ return ret; + +- return __gpmi_enable_clk(this, true); ++ return 0; ++ + } + + static const struct dev_pm_ops gpmi_pm_ops = { --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h -@@ -76,8 +76,11 @@ +@@ -76,8 +76,12 @@ IS_MX23, IS_MX28, IS_MX6Q, @@ -79,22 +374,22 @@ Signed-off-by: Alexey Sadkov IS_MX7D, + IS_MX6UL, + IS_MX6ULL, ++ IS_MX8QXP, }; struct gpmi_devdata { -@@ -170,10 +173,14 @@ +@@ -170,10 +174,13 @@ #define GPMI_IS_MX23(x) ((x)->devdata->type == IS_MX23) #define GPMI_IS_MX28(x) ((x)->devdata->type == IS_MX28) #define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q) +#define GPMI_IS_MX6QP(x) ((x)->devdata->type == IS_MX6QP) #define GPMI_IS_MX6SX(x) ((x)->devdata->type == IS_MX6SX) #define GPMI_IS_MX7D(x) ((x)->devdata->type == IS_MX7D) -+#define GPMI_IS_MX6UL(x) ((x)->devdata->type == IS_MX6UL) -+#define GPMI_IS_MX6ULL(x) ((x)->devdata->type == IS_MX6ULL) ++#define GPMI_IS_MX8QXP(x) ((x)->devdata->type == IS_MX8QXP) #define GPMI_IS_MX6(x) (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \ - GPMI_IS_MX7D(x)) -+ GPMI_IS_MX7D(x) || GPMI_IS_MX6UL(x) || \ -+ GPMI_IS_MX6ULL(x) || GPMI_IS_MX6QP(x)) ++ GPMI_IS_MX7D(x) || GPMI_IS_MX6QP(x)) ++#define GPMI_IS_MX8(x) (GPMI_IS_MX8QXP(x)) #define GPMI_IS_MXS(x) (GPMI_IS_MX23(x) || GPMI_IS_MX28(x)) #endif