From 627151b4966fe68029cd14aa5fd81f5f0c67fa26 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Nov 2021 20:15:53 +0100 Subject: mmc: renesas_sdhi: Flag non-standard SDnH handling for V3M V3M handles SDnH differently than other Gen3 SoCs, so let's add a separate entry for that. This will allow better SDnH handling in the future. Signed-off-by: Wolfram Sang Acked-by: Ulf Hansson Link: https://lore.kernel.org/r/20211110191610.5664-5-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- drivers/mmc/host/renesas_sdhi.h | 3 +++ drivers/mmc/host/renesas_sdhi_internal_dmac.c | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 0c45e82ff0de..cd82420677cc 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -18,6 +18,8 @@ struct renesas_sdhi_scc { u32 tap_hs400_4tap; /* sampling clock position for HS400 (4 TAP) */ }; +#define SDHI_FLAG_NEED_CLKH_FALLBACK BIT(0) + struct renesas_sdhi_of_data { unsigned long tmio_flags; u32 tmio_ocr_mask; @@ -31,6 +33,7 @@ struct renesas_sdhi_of_data { int taps_num; unsigned int max_blk_count; unsigned short max_segs; + unsigned long sdhi_flags; }; #define SDHI_CALIB_TABLE_MAX 32 diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 7660f7ea74dd..9d2c600fd4ce 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -125,6 +125,22 @@ static const struct renesas_sdhi_of_data of_data_rcar_gen3 = { /* DMAC can handle 32bit blk count but only 1 segment */ .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, .max_segs = 1, + .sdhi_flags = SDHI_FLAG_NEED_CLKH_FALLBACK, +}; + +static const struct renesas_sdhi_of_data of_data_rcar_gen3_no_fallback = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | + MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE, + .bus_shift = 2, + .scc_offset = 0x1000, + .taps = rcar_gen3_scc_taps, + .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), + /* DMAC can handle 32bit blk count but only 1 segment */ + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, + .max_segs = 1, }; static const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = { @@ -214,6 +230,10 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77965_compatible = { .quirks = &sdhi_quirks_r8a77965, }; +static const struct renesas_sdhi_of_data_with_quirks of_r8a77970_compatible = { + .of_data = &of_data_rcar_gen3_no_fallback, +}; + static const struct renesas_sdhi_of_data_with_quirks of_r8a77980_compatible = { .of_data = &of_data_rcar_gen3, .quirks = &sdhi_quirks_nohs400, @@ -235,6 +255,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, }, { .compatible = "renesas,sdhi-r8a77965", .data = &of_r8a77965_compatible, }, + { .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, }, { .compatible = "renesas,sdhi-r8a77980", .data = &of_r8a77980_compatible, }, { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, -- cgit v1.2.3 From bb6d3fa98a418b071c5f735e75558604f5f4af66 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Nov 2021 20:15:54 +0100 Subject: clk: renesas: rcar-gen3: Switch to new SD clock handling The old SD handling code was huge and could not handle all the details which showed up on R-Car Gen3 SoCs meanwhile. It is time to switch to another design. Have SDnH a separate clock, use the existing divider clocks and move the errata handling from the clock driver to the SDHI driver where it belongs. This patch removes the old SD handling code and switch to the new one. This updates the SDHI driver at the same time. Because the SDHI driver can only communicate with the clock driver via clk_set_rate(), I don't see an alternative to this flag-day-approach, so we cross subsystems here. The patch sadly looks messy for the CPG lib, but it is basically a huge chunk of code removed and smaller chunks added. It looks much better when you just view the resulting source file. Signed-off-by: Wolfram Sang Acked-by: Ulf Hansson # For MMC Link: https://lore.kernel.org/r/20211110191610.5664-6-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779a0-cpg-mssr.c | 6 +- drivers/clk/renesas/rcar-cpg-lib.c | 220 ++++---------------------------- drivers/clk/renesas/rcar-cpg-lib.h | 3 +- drivers/clk/renesas/rcar-gen3-cpg.c | 5 +- drivers/mmc/host/renesas_sdhi.h | 1 + drivers/mmc/host/renesas_sdhi_core.c | 28 +++- 6 files changed, 56 insertions(+), 207 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index 935eaaf567cf..b89075f5fa89 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -479,10 +479,8 @@ static struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev, __clk_get_name(parent), notifiers); case CLK_TYPE_R8A779A0_SD: - return cpg_sd_clk_register(core->name, base, core->offset, - __clk_get_name(parent), notifiers, - false); - break; + return cpg_sd_clk_register(core->name, base + core->offset, + __clk_get_name(parent)); case CLK_TYPE_R8A779A0_MDSEL: /* diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c index de8d21e4c6c5..e2e0447de190 100644 --- a/drivers/clk/renesas/rcar-cpg-lib.c +++ b/drivers/clk/renesas/rcar-cpg-lib.c @@ -66,214 +66,48 @@ void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, * SDn Clock */ -struct clk * __init cpg_sdh_clk_register(const char *name, - void __iomem *sdnckcr, const char *parent_name, - struct raw_notifier_head *notifiers) -{ - /* placeholder during transition */ - return clk_register_fixed_factor(NULL, name, parent_name, 0, 1, 1); -} - -#define CPG_SD_STP_HCK BIT(9) -#define CPG_SD_STP_CK BIT(8) - -#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK) -#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0) - -#define CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) \ -{ \ - .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \ - ((sd_srcfc) << 2) | \ - ((sd_fc) << 0), \ - .div = (sd_div), \ -} - -struct sd_div_table { - u32 val; - unsigned int div; -}; +#define SDnSRCFC_SHIFT 2 +#define STPnHCK BIT(9 - SDnSRCFC_SHIFT) -struct sd_clock { - struct clk_hw hw; - const struct sd_div_table *div_table; - struct cpg_simple_notifier csn; - unsigned int div_num; - unsigned int cur_div_idx; -}; - -/* SDn divider - * sd_srcfc sd_fc div - * stp_hck (div) (div) = sd_srcfc x sd_fc - *--------------------------------------------------------- - * 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP) - * 0 1 (2) 1 (4) 8 : SDR50 - * 1 2 (4) 1 (4) 16 : HS / SDR25 - * 1 3 (8) 1 (4) 32 : NS / SDR12 - * 1 4 (16) 1 (4) 64 - * 0 0 (1) 0 (2) 2 - * 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP) - * 1 2 (4) 0 (2) 8 - * 1 3 (8) 0 (2) 16 - * 1 4 (16) 0 (2) 32 - * - * NOTE: There is a quirk option to ignore the first row of the dividers - * table when searching for suitable settings. This is because HS400 on - * early ES versions of H3 and M3-W requires a specific setting to work. - */ -static const struct sd_div_table cpg_sd_div_table[] = { -/* CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) */ - CPG_SD_DIV_TABLE_DATA(0, 0, 1, 4), - CPG_SD_DIV_TABLE_DATA(0, 1, 1, 8), - CPG_SD_DIV_TABLE_DATA(1, 2, 1, 16), - CPG_SD_DIV_TABLE_DATA(1, 3, 1, 32), - CPG_SD_DIV_TABLE_DATA(1, 4, 1, 64), - CPG_SD_DIV_TABLE_DATA(0, 0, 0, 2), - CPG_SD_DIV_TABLE_DATA(0, 1, 0, 4), - CPG_SD_DIV_TABLE_DATA(1, 2, 0, 8), - CPG_SD_DIV_TABLE_DATA(1, 3, 0, 16), - CPG_SD_DIV_TABLE_DATA(1, 4, 0, 32), +static const struct clk_div_table cpg_sdh_div_table[] = { + { 0, 1 }, { 1, 2 }, { STPnHCK | 2, 4 }, { STPnHCK | 3, 8 }, + { STPnHCK | 4, 16 }, { 0, 0 }, }; -#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw) - -static int cpg_sd_clock_enable(struct clk_hw *hw) -{ - struct sd_clock *clock = to_sd_clock(hw); - - cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK, - clock->div_table[clock->cur_div_idx].val & - CPG_SD_STP_MASK); - - return 0; -} - -static void cpg_sd_clock_disable(struct clk_hw *hw) -{ - struct sd_clock *clock = to_sd_clock(hw); - - cpg_reg_modify(clock->csn.reg, 0, CPG_SD_STP_MASK); -} - -static int cpg_sd_clock_is_enabled(struct clk_hw *hw) +struct clk * __init cpg_sdh_clk_register(const char *name, + void __iomem *sdnckcr, const char *parent_name, + struct raw_notifier_head *notifiers) { - struct sd_clock *clock = to_sd_clock(hw); - - return !(readl(clock->csn.reg) & CPG_SD_STP_MASK); -} + struct cpg_simple_notifier *csn; + struct clk *clk; -static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct sd_clock *clock = to_sd_clock(hw); + csn = kzalloc(sizeof(*csn), GFP_KERNEL); + if (!csn) + return ERR_PTR(-ENOMEM); - return DIV_ROUND_CLOSEST(parent_rate, - clock->div_table[clock->cur_div_idx].div); -} + csn->reg = sdnckcr; -static int cpg_sd_clock_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - unsigned long best_rate = ULONG_MAX, diff_min = ULONG_MAX; - struct sd_clock *clock = to_sd_clock(hw); - unsigned long calc_rate, diff; - unsigned int i; - - for (i = 0; i < clock->div_num; i++) { - calc_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, - clock->div_table[i].div); - if (calc_rate < req->min_rate || calc_rate > req->max_rate) - continue; - - diff = calc_rate > req->rate ? calc_rate - req->rate - : req->rate - calc_rate; - if (diff < diff_min) { - best_rate = calc_rate; - diff_min = diff; - } + clk = clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr, + SDnSRCFC_SHIFT, 8, 0, cpg_sdh_div_table, + &cpg_lock); + if (IS_ERR(clk)) { + kfree(csn); + return clk; } - if (best_rate == ULONG_MAX) - return -EINVAL; - - req->rate = best_rate; - return 0; -} - -static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct sd_clock *clock = to_sd_clock(hw); - unsigned int i; - - for (i = 0; i < clock->div_num; i++) - if (rate == DIV_ROUND_CLOSEST(parent_rate, - clock->div_table[i].div)) - break; - - if (i >= clock->div_num) - return -EINVAL; - - clock->cur_div_idx = i; - - cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK | CPG_SD_FC_MASK, - clock->div_table[i].val & - (CPG_SD_STP_MASK | CPG_SD_FC_MASK)); - - return 0; + cpg_simple_notifier_register(notifiers, csn); + return clk; } -static const struct clk_ops cpg_sd_clock_ops = { - .enable = cpg_sd_clock_enable, - .disable = cpg_sd_clock_disable, - .is_enabled = cpg_sd_clock_is_enabled, - .recalc_rate = cpg_sd_clock_recalc_rate, - .determine_rate = cpg_sd_clock_determine_rate, - .set_rate = cpg_sd_clock_set_rate, +static const struct clk_div_table cpg_sd_div_table[] = { + { 0, 2 }, { 1, 4 }, { 0, 0 }, }; struct clk * __init cpg_sd_clk_register(const char *name, - void __iomem *base, unsigned int offset, const char *parent_name, - struct raw_notifier_head *notifiers, bool skip_first) + void __iomem *sdnckcr, const char *parent_name) { - struct clk_init_data init = {}; - struct sd_clock *clock; - struct clk *clk; - u32 val; - - clock = kzalloc(sizeof(*clock), GFP_KERNEL); - if (!clock) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &cpg_sd_clock_ops; - init.flags = CLK_SET_RATE_PARENT; - init.parent_names = &parent_name; - init.num_parents = 1; - - clock->csn.reg = base + offset; - clock->hw.init = &init; - clock->div_table = cpg_sd_div_table; - clock->div_num = ARRAY_SIZE(cpg_sd_div_table); - - if (skip_first) { - clock->div_table++; - clock->div_num--; - } - - val = readl(clock->csn.reg) & ~CPG_SD_FC_MASK; - val |= CPG_SD_STP_MASK | (clock->div_table[0].val & CPG_SD_FC_MASK); - writel(val, clock->csn.reg); - - clk = clk_register(NULL, &clock->hw); - if (IS_ERR(clk)) - goto free_clock; - - cpg_simple_notifier_register(notifiers, &clock->csn); - return clk; - -free_clock: - kfree(clock); - return clk; + return clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr, + 0, 2, 0, cpg_sd_div_table, &cpg_lock); } struct rpc_clock { diff --git a/drivers/clk/renesas/rcar-cpg-lib.h b/drivers/clk/renesas/rcar-cpg-lib.h index d001722ec13f..94627df1c94c 100644 --- a/drivers/clk/renesas/rcar-cpg-lib.h +++ b/drivers/clk/renesas/rcar-cpg-lib.h @@ -31,8 +31,7 @@ struct clk * __init cpg_sdh_clk_register(const char *name, struct raw_notifier_head *notifiers); struct clk * __init cpg_sd_clk_register(const char *name, - void __iomem *base, unsigned int offset, const char *parent_name, - struct raw_notifier_head *notifiers, bool skip_first); + void __iomem *sdnckcr, const char *parent_name); struct clk * __init cpg_rpc_clk_register(const char *name, void __iomem *rpcckcr, const char *parent_name, diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 0c815684dd47..941dadf07230 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -406,9 +406,8 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, __clk_get_name(parent), notifiers); case CLK_TYPE_GEN3_SD: - return cpg_sd_clk_register(core->name, base, core->offset, - __clk_get_name(parent), notifiers, - cpg_quirks & SD_SKIP_FIRST); + return cpg_sd_clk_register(core->name, base + core->offset, + __clk_get_name(parent)); case CLK_TYPE_GEN3_R: if (cpg_quirks & RCKCR_CKSEL) { diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index cd82420677cc..66d308e73e17 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -60,6 +60,7 @@ struct tmio_mmc_dma { struct renesas_sdhi { struct clk *clk; + struct clk *clkh; struct clk *clk_cd; struct tmio_mmc_data mmc_data; struct tmio_mmc_dma dma_priv; diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index a4407f391f66..31e232bcb5e8 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -127,10 +127,12 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host) } static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, - unsigned int new_clock) + unsigned int wanted_clock) { struct renesas_sdhi *priv = host_to_priv(host); + struct clk *ref_clk = priv->clk; unsigned int freq, diff, best_freq = 0, diff_min = ~0; + unsigned int new_clock, clkh_shift = 0; int i; /* @@ -141,6 +143,16 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2) || mmc_doing_tune(host->mmc)) return clk_get_rate(priv->clk); + if (priv->clkh) { + bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; + bool need_slow_clkh = (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) || + (host->mmc->ios.timing == MMC_TIMING_MMC_HS400); + clkh_shift = use_4tap && need_slow_clkh ? 1 : 2; + ref_clk = priv->clkh; + } + + new_clock = wanted_clock << clkh_shift; + /* * We want the bus clock to be as close as possible to, but no * greater than, new_clock. As we can divide by 1 << i for @@ -148,11 +160,10 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, * possible, but no greater than, new_clock << i. */ for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) { - freq = clk_round_rate(priv->clk, new_clock << i); + freq = clk_round_rate(ref_clk, new_clock << i); if (freq > (new_clock << i)) { /* Too fast; look for a slightly slower option */ - freq = clk_round_rate(priv->clk, - (new_clock << i) / 4 * 3); + freq = clk_round_rate(ref_clk, (new_clock << i) / 4 * 3); if (freq > (new_clock << i)) continue; } @@ -164,7 +175,10 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, } } - clk_set_rate(priv->clk, best_freq); + clk_set_rate(ref_clk, best_freq); + + if (priv->clkh) + clk_set_rate(priv->clk, best_freq >> clkh_shift); return clk_get_rate(priv->clk); } @@ -947,6 +961,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, mmc_data->max_segs = of_data->max_segs; dma_priv->dma_buswidth = of_data->dma_buswidth; host->bus_shift = of_data->bus_shift; + /* Fallback for old DTs */ + if (of_data->sdhi_flags & SDHI_FLAG_NEED_CLKH_FALLBACK) + priv->clkh = clk_get_parent(clk_get_parent(priv->clk)); + } host->write16_hook = renesas_sdhi_write16_hook; -- cgit v1.2.3 From 079e83b958a3c3d9c84e24b28478d57adc1cd7fe Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Nov 2021 20:16:08 +0100 Subject: mmc: renesas_sdhi: Use dev_err_probe when getting clock fails This is to improve deferred probe in this driver and to keep consistent with an up-to-date handling of a soon to be added second clock. Signed-off-by: Wolfram Sang Acked-by: Ulf Hansson Link: https://lore.kernel.org/r/20211110191610.5664-20-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- drivers/mmc/host/renesas_sdhi_core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 31e232bcb5e8..7f842fd306a3 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -918,11 +918,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, dma_priv = &priv->dma_priv; priv->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "cannot get clock: %d\n", ret); - return ret; - } + if (IS_ERR(priv->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), "cannot get clock"); /* * Some controllers provide a 2nd clock just to run the internal card -- cgit v1.2.3 From e5f7e81ee430acb6d1fa9a6323fe645bd52e0b9c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Nov 2021 20:16:09 +0100 Subject: mmc: renesas_sdhi: Parse DT for SDnH If there is a SDnH clock provided in DT, let's use it instead of relying on the fallback. Signed-off-by: Wolfram Sang Acked-by: Ulf Hansson Link: https://lore.kernel.org/r/20211110191610.5664-21-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- drivers/mmc/host/renesas_sdhi_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 7f842fd306a3..2f5e22e539a3 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -921,6 +921,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (IS_ERR(priv->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), "cannot get clock"); + priv->clkh = devm_clk_get_optional(&pdev->dev, "clkh"); + if (IS_ERR(priv->clkh)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clkh), "cannot get clkh"); + /* * Some controllers provide a 2nd clock just to run the internal card * detection logic. Unfortunately, the existing driver architecture does @@ -959,7 +963,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, dma_priv->dma_buswidth = of_data->dma_buswidth; host->bus_shift = of_data->bus_shift; /* Fallback for old DTs */ - if (of_data->sdhi_flags & SDHI_FLAG_NEED_CLKH_FALLBACK) + if (!priv->clkh && of_data->sdhi_flags & SDHI_FLAG_NEED_CLKH_FALLBACK) priv->clkh = clk_get_parent(clk_get_parent(priv->clk)); } -- cgit v1.2.3 From 91389c390521a02ecfb91270f5b9d7fae4312ae5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 18 Nov 2021 21:33:37 -0600 Subject: clk: sunxi-ng: Allow the CCU core to be built as a module Like the individual CCU drivers, it can be beneficial for memory consumption of cross-platform configurations to only load the CCU core on the relevant platform. For example, a generic arm64 kernel sees the following improvement when building the CCU core and drivers as modules: before: text data bss dec hex filename 13882360 5251670 360800 19494830 12977ae vmlinux after: text data bss dec hex filename 13734787 5086442 360800 19182029 124b1cd vmlinux So the result is a 390KB total reduction in kernel image size. The one early clock provider (sun5i) requires the core to be built in. Now that loading the MMC driver will trigger loading the CCU core, the MMC timing mode functions do not need a compile-time fallback. Signed-off-by: Samuel Holland Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20211119033338.25486-5-samuel@sholland.org --- drivers/clk/Makefile | 2 +- drivers/clk/sunxi-ng/Kconfig | 3 ++- drivers/clk/sunxi-ng/Makefile | 33 ++++++++++++++++++--------------- drivers/clk/sunxi-ng/ccu_common.c | 3 +++ drivers/mmc/host/Kconfig | 1 + include/linux/clk/sunxi-ng.h | 15 --------------- 6 files changed, 25 insertions(+), 32 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e42312121e51..6afe36bd2c0a 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -110,7 +110,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-y += sprd/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ -obj-$(CONFIG_SUNXI_CCU) += sunxi-ng/ +obj-y += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index de88b6e0ec69..727ff755eca4 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config SUNXI_CCU - bool "Clock support for Allwinner SoCs" + tristate "Clock support for Allwinner SoCs" depends on ARCH_SUNXI || COMPILE_TEST select RESET_CONTROLLER default ARCH_SUNXI @@ -52,6 +52,7 @@ config SUN5I_CCU bool "Support for the Allwinner sun5i family CCM" default MACH_SUN5I depends on MACH_SUN5I || COMPILE_TEST + depends on SUNXI_CCU=y config SUN6I_A31_CCU tristate "Support for the Allwinner A31/A31s CCU" diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 1020ed49a588..659d55150c32 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -1,24 +1,27 @@ # SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SUNXI_CCU) += sunxi-ccu.o + # Common objects -obj-y += ccu_common.o -obj-y += ccu_mmc_timing.o -obj-y += ccu_reset.o +sunxi-ccu-y += ccu_common.o +sunxi-ccu-y += ccu_mmc_timing.o +sunxi-ccu-y += ccu_reset.o # Base clock types -obj-y += ccu_div.o -obj-y += ccu_frac.o -obj-y += ccu_gate.o -obj-y += ccu_mux.o -obj-y += ccu_mult.o -obj-y += ccu_phase.o -obj-y += ccu_sdm.o +sunxi-ccu-y += ccu_div.o +sunxi-ccu-y += ccu_frac.o +sunxi-ccu-y += ccu_gate.o +sunxi-ccu-y += ccu_mux.o +sunxi-ccu-y += ccu_mult.o +sunxi-ccu-y += ccu_phase.o +sunxi-ccu-y += ccu_sdm.o # Multi-factor clocks -obj-y += ccu_nk.o -obj-y += ccu_nkm.o -obj-y += ccu_nkmp.o -obj-y += ccu_nm.o -obj-y += ccu_mp.o +sunxi-ccu-y += ccu_nk.o +sunxi-ccu-y += ccu_nkm.o +sunxi-ccu-y += ccu_nkmp.o +sunxi-ccu-y += ccu_nm.o +sunxi-ccu-y += ccu_mp.o # SoC support obj-$(CONFIG_SUNIV_F1C100S_CCU) += suniv-f1c100s-ccu.o diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index 6afdedbce6a2..8d28a7a079d0 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "ccu_common.h" @@ -214,3 +215,5 @@ void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg, kfree(ccu); } } + +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 5af8494c31b5..52b0b27a6839 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -966,6 +966,7 @@ config MMC_REALTEK_USB config MMC_SUNXI tristate "Allwinner sunxi SD/MMC Host Controller support" depends on ARCH_SUNXI || COMPILE_TEST + depends on SUNXI_CCU help This selects support for the SD/MMC Host Controller on Allwinner sunxi SoCs. diff --git a/include/linux/clk/sunxi-ng.h b/include/linux/clk/sunxi-ng.h index 3cd14acde0a1..cf32123b39f5 100644 --- a/include/linux/clk/sunxi-ng.h +++ b/include/linux/clk/sunxi-ng.h @@ -6,22 +6,7 @@ #ifndef _LINUX_CLK_SUNXI_NG_H_ #define _LINUX_CLK_SUNXI_NG_H_ -#include - -#ifdef CONFIG_SUNXI_CCU int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode); int sunxi_ccu_get_mmc_timing_mode(struct clk *clk); -#else -static inline int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, - bool new_mode) -{ - return -ENOTSUPP; -} - -static inline int sunxi_ccu_get_mmc_timing_mode(struct clk *clk) -{ - return -ENOTSUPP; -} -#endif #endif -- cgit v1.2.3 From 366df82fc68a9db22ab9de890a372d79662e397c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 16 Nov 2021 14:36:07 +0100 Subject: mmc: renesas_sdhi: Use devm_clk_get_optional() to obtain CD clock Use the existing devm_clk_get_optional() helper to obtain the optional Card Detect clock, instead of open-coding the same operation. a side effect, real errors will now be handled correctly instead of being ignored. Signed-off-by: Geert Uytterhoeven Acked-by: Ulf Hansson Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/540d803d31bf9aa1d0f78f431cae0ccd05387edc.1637069733.git.geert+renesas@glider.be --- drivers/mmc/host/renesas_sdhi_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 2f5e22e539a3..61cde437f317 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -936,9 +936,9 @@ int renesas_sdhi_probe(struct platform_device *pdev, * to the card detect circuit. That leaves us with if separate clocks * are presented, we must treat them both as virtually 1 clock. */ - priv->clk_cd = devm_clk_get(&pdev->dev, "cd"); + priv->clk_cd = devm_clk_get_optional(&pdev->dev, "cd"); if (IS_ERR(priv->clk_cd)) - priv->clk_cd = NULL; + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk_cd), "cannot get cd clock"); priv->pinctrl = devm_pinctrl_get(&pdev->dev); if (!IS_ERR(priv->pinctrl)) { -- cgit v1.2.3 From 45177fc641f9de58180af158d1fac8defa99afca Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 17 Nov 2021 11:38:50 +0100 Subject: mmc: renesas_sdhi: Simplify an expression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have 'quirks', no need to go via 'priv'. Signed-off-by: Wolfram Sang Acked-by: Ulf Hansson Reviewed-by: Niklas Söderlund Link: https://lore.kernel.org/r/20211117103850.28397-1-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- drivers/mmc/host/renesas_sdhi_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 61cde437f317..415911e96f34 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -1063,7 +1063,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) { const struct renesas_sdhi_scc *taps = of_data->taps; - bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; + bool use_4tap = quirks && quirks->hs400_4taps; bool hit = false; for (i = 0; i < of_data->taps_num; i++) { -- cgit v1.2.3