Skip to content

Commit 033d716

Browse files
jbrun3tstorulf
authored andcommitted
mmc: meson-gx: use CCF to handle the clock phases
Several phases can be controlled on the meson-gx controller, the core, tx and rx clock phase. The tx and rx uses delays to allow more fine grained setting of the phase. To properly compute the phase using delays, accessing the clock rate is necessary. Instead of ad-hoc functions, use the common clock framework to set the clock phases (and access the clock rate while doing it). Acked-by: Kevin Hilman <[email protected]> Signed-off-by: Jerome Brunet <[email protected]> Signed-off-by: Ulf Hansson <[email protected]>
1 parent 186cd8b commit 033d716

File tree

1 file changed

+176
-41
lines changed

1 file changed

+176
-41
lines changed

drivers/mmc/host/meson-gx-mmc.c

Lines changed: 176 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,9 @@
4646
#define CLK_CORE_PHASE_MASK GENMASK(9, 8)
4747
#define CLK_TX_PHASE_MASK GENMASK(11, 10)
4848
#define CLK_RX_PHASE_MASK GENMASK(13, 12)
49-
#define CLK_PHASE_0 0
50-
#define CLK_PHASE_90 1
51-
#define CLK_PHASE_180 2
52-
#define CLK_PHASE_270 3
49+
#define CLK_TX_DELAY_MASK GENMASK(19, 16)
50+
#define CLK_RX_DELAY_MASK GENMASK(23, 20)
51+
#define CLK_DELAY_STEP_PS 200
5352
#define CLK_ALWAYS_ON BIT(24)
5453

5554
#define SD_EMMC_DELAY 0x4
@@ -121,9 +120,9 @@
121120
#define MUX_CLK_NUM_PARENTS 2
122121

123122
struct meson_tuning_params {
124-
u8 core_phase;
125-
u8 tx_phase;
126-
u8 rx_phase;
123+
unsigned int core_phase;
124+
unsigned int tx_phase;
125+
unsigned int rx_phase;
127126
};
128127

129128
struct sd_emmc_desc {
@@ -142,6 +141,8 @@ struct meson_host {
142141
void __iomem *regs;
143142
struct clk *core_clk;
144143
struct clk *mmc_clk;
144+
struct clk *rx_clk;
145+
struct clk *tx_clk;
145146
unsigned long req_rate;
146147

147148
struct pinctrl *pinctrl;
@@ -181,6 +182,90 @@ struct meson_host {
181182
#define CMD_RESP_MASK GENMASK(31, 1)
182183
#define CMD_RESP_SRAM BIT(0)
183184

185+
struct meson_mmc_phase {
186+
struct clk_hw hw;
187+
void __iomem *reg;
188+
unsigned long phase_mask;
189+
unsigned long delay_mask;
190+
unsigned int delay_step_ps;
191+
};
192+
193+
#define to_meson_mmc_phase(_hw) container_of(_hw, struct meson_mmc_phase, hw)
194+
195+
static int meson_mmc_clk_get_phase(struct clk_hw *hw)
196+
{
197+
struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw);
198+
unsigned int phase_num = 1 << hweight_long(mmc->phase_mask);
199+
unsigned long period_ps, p, d;
200+
int degrees;
201+
u32 val;
202+
203+
val = readl(mmc->reg);
204+
p = (val & mmc->phase_mask) >> __bf_shf(mmc->phase_mask);
205+
degrees = p * 360 / phase_num;
206+
207+
if (mmc->delay_mask) {
208+
period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000,
209+
clk_get_rate(hw->clk));
210+
d = (val & mmc->delay_mask) >> __bf_shf(mmc->delay_mask);
211+
degrees += d * mmc->delay_step_ps * 360 / period_ps;
212+
degrees %= 360;
213+
}
214+
215+
return degrees;
216+
}
217+
218+
static void meson_mmc_apply_phase_delay(struct meson_mmc_phase *mmc,
219+
unsigned int phase,
220+
unsigned int delay)
221+
{
222+
u32 val;
223+
224+
val = readl(mmc->reg);
225+
val &= ~mmc->phase_mask;
226+
val |= phase << __bf_shf(mmc->phase_mask);
227+
228+
if (mmc->delay_mask) {
229+
val &= ~mmc->delay_mask;
230+
val |= delay << __bf_shf(mmc->delay_mask);
231+
}
232+
233+
writel(val, mmc->reg);
234+
}
235+
236+
static int meson_mmc_clk_set_phase(struct clk_hw *hw, int degrees)
237+
{
238+
struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw);
239+
unsigned int phase_num = 1 << hweight_long(mmc->phase_mask);
240+
unsigned long period_ps, d = 0, r;
241+
uint64_t p;
242+
243+
p = degrees % 360;
244+
245+
if (!mmc->delay_mask) {
246+
p = DIV_ROUND_CLOSEST_ULL(p, 360 / phase_num);
247+
} else {
248+
period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000,
249+
clk_get_rate(hw->clk));
250+
251+
/* First compute the phase index (p), the remainder (r) is the
252+
* part we'll try to acheive using the delays (d).
253+
*/
254+
r = do_div(p, 360 / phase_num);
255+
d = DIV_ROUND_CLOSEST(r * period_ps,
256+
360 * mmc->delay_step_ps);
257+
d = min(d, mmc->delay_mask >> __bf_shf(mmc->delay_mask));
258+
}
259+
260+
meson_mmc_apply_phase_delay(mmc, p, d);
261+
return 0;
262+
}
263+
264+
static const struct clk_ops meson_mmc_clk_phase_ops = {
265+
.get_phase = meson_mmc_clk_get_phase,
266+
.set_phase = meson_mmc_clk_set_phase,
267+
};
268+
184269
static unsigned int meson_mmc_get_timeout_msecs(struct mmc_data *data)
185270
{
186271
unsigned int timeout = data->timeout_ns / NSEC_PER_MSEC;
@@ -373,6 +458,13 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios)
373458
return 0;
374459
}
375460

461+
static void meson_mmc_set_phase_params(struct meson_host *host)
462+
{
463+
clk_set_phase(host->mmc_clk, host->tp.core_phase);
464+
clk_set_phase(host->tx_clk, host->tp.tx_phase);
465+
clk_set_phase(host->rx_clk, host->tp.rx_phase);
466+
}
467+
376468
/*
377469
* The SD/eMMC IP block has an internal mux and divider used for
378470
* generating the MMC clock. Use the clock framework to create and
@@ -383,6 +475,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
383475
struct clk_init_data init;
384476
struct clk_mux *mux;
385477
struct clk_divider *div;
478+
struct meson_mmc_phase *core, *tx, *rx;
386479
struct clk *clk;
387480
char clk_name[32];
388481
int i, ret = 0;
@@ -394,9 +487,6 @@ static int meson_mmc_clk_init(struct meson_host *host)
394487
clk_reg = 0;
395488
clk_reg |= CLK_ALWAYS_ON;
396489
clk_reg |= CLK_DIV_MASK;
397-
clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, host->tp.core_phase);
398-
clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, host->tp.tx_phase);
399-
clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, host->tp.rx_phase);
400490
writel(clk_reg, host->regs + SD_EMMC_CLOCK);
401491

402492
/* get the mux parents */
@@ -456,10 +546,80 @@ static int meson_mmc_clk_init(struct meson_host *host)
456546
div->flags = (CLK_DIVIDER_ONE_BASED |
457547
CLK_DIVIDER_ROUND_CLOSEST);
458548

459-
host->mmc_clk = devm_clk_register(host->dev, &div->hw);
549+
clk = devm_clk_register(host->dev, &div->hw);
550+
if (WARN_ON(IS_ERR(clk)))
551+
return PTR_ERR(clk);
552+
553+
/* create the mmc core clock */
554+
core = devm_kzalloc(host->dev, sizeof(*core), GFP_KERNEL);
555+
if (!core)
556+
return -ENOMEM;
557+
558+
snprintf(clk_name, sizeof(clk_name), "%s#core", dev_name(host->dev));
559+
init.name = clk_name;
560+
init.ops = &meson_mmc_clk_phase_ops;
561+
init.flags = CLK_SET_RATE_PARENT;
562+
clk_parent[0] = __clk_get_name(clk);
563+
init.parent_names = clk_parent;
564+
init.num_parents = 1;
565+
566+
core->reg = host->regs + SD_EMMC_CLOCK;
567+
core->phase_mask = CLK_CORE_PHASE_MASK;
568+
core->hw.init = &init;
569+
570+
host->mmc_clk = devm_clk_register(host->dev, &core->hw);
460571
if (WARN_ON(PTR_ERR_OR_ZERO(host->mmc_clk)))
461572
return PTR_ERR(host->mmc_clk);
462573

574+
/* create the mmc tx clock */
575+
tx = devm_kzalloc(host->dev, sizeof(*tx), GFP_KERNEL);
576+
if (!tx)
577+
return -ENOMEM;
578+
579+
snprintf(clk_name, sizeof(clk_name), "%s#tx", dev_name(host->dev));
580+
init.name = clk_name;
581+
init.ops = &meson_mmc_clk_phase_ops;
582+
init.flags = 0;
583+
clk_parent[0] = __clk_get_name(host->mmc_clk);
584+
init.parent_names = clk_parent;
585+
init.num_parents = 1;
586+
587+
tx->reg = host->regs + SD_EMMC_CLOCK;
588+
tx->phase_mask = CLK_TX_PHASE_MASK;
589+
tx->delay_mask = CLK_TX_DELAY_MASK;
590+
tx->delay_step_ps = CLK_DELAY_STEP_PS;
591+
tx->hw.init = &init;
592+
593+
host->tx_clk = devm_clk_register(host->dev, &tx->hw);
594+
if (WARN_ON(PTR_ERR_OR_ZERO(host->tx_clk)))
595+
return PTR_ERR(host->tx_clk);
596+
597+
/* create the mmc rx clock */
598+
rx = devm_kzalloc(host->dev, sizeof(*rx), GFP_KERNEL);
599+
if (!rx)
600+
return -ENOMEM;
601+
602+
snprintf(clk_name, sizeof(clk_name), "%s#rx", dev_name(host->dev));
603+
init.name = clk_name;
604+
init.ops = &meson_mmc_clk_phase_ops;
605+
init.flags = 0;
606+
clk_parent[0] = __clk_get_name(host->mmc_clk);
607+
init.parent_names = clk_parent;
608+
init.num_parents = 1;
609+
610+
rx->reg = host->regs + SD_EMMC_CLOCK;
611+
rx->phase_mask = CLK_RX_PHASE_MASK;
612+
rx->delay_mask = CLK_RX_DELAY_MASK;
613+
rx->delay_step_ps = CLK_DELAY_STEP_PS;
614+
rx->hw.init = &init;
615+
616+
host->rx_clk = devm_clk_register(host->dev, &rx->hw);
617+
if (WARN_ON(PTR_ERR_OR_ZERO(host->rx_clk)))
618+
return PTR_ERR(host->rx_clk);
619+
620+
/* Set the initial phase parameters */
621+
meson_mmc_set_phase_params(host);
622+
463623
/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
464624
host->mmc->f_min = clk_round_rate(host->mmc_clk, 400000);
465625
ret = clk_set_rate(host->mmc_clk, host->mmc->f_min);
@@ -469,31 +629,6 @@ static int meson_mmc_clk_init(struct meson_host *host)
469629
return clk_prepare_enable(host->mmc_clk);
470630
}
471631

472-
static void meson_mmc_set_tuning_params(struct mmc_host *mmc)
473-
{
474-
struct meson_host *host = mmc_priv(mmc);
475-
u32 regval;
476-
477-
/* stop clock */
478-
regval = readl(host->regs + SD_EMMC_CFG);
479-
regval |= CFG_STOP_CLOCK;
480-
writel(regval, host->regs + SD_EMMC_CFG);
481-
482-
regval = readl(host->regs + SD_EMMC_CLOCK);
483-
regval &= ~CLK_CORE_PHASE_MASK;
484-
regval |= FIELD_PREP(CLK_CORE_PHASE_MASK, host->tp.core_phase);
485-
regval &= ~CLK_TX_PHASE_MASK;
486-
regval |= FIELD_PREP(CLK_TX_PHASE_MASK, host->tp.tx_phase);
487-
regval &= ~CLK_RX_PHASE_MASK;
488-
regval |= FIELD_PREP(CLK_RX_PHASE_MASK, host->tp.rx_phase);
489-
writel(regval, host->regs + SD_EMMC_CLOCK);
490-
491-
/* start clock */
492-
regval = readl(host->regs + SD_EMMC_CFG);
493-
regval &= ~CFG_STOP_CLOCK;
494-
writel(regval, host->regs + SD_EMMC_CFG);
495-
}
496-
497632
static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
498633
{
499634
struct meson_host *host = mmc_priv(mmc);
@@ -862,13 +997,13 @@ static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
862997

863998
dev_info(mmc_dev(mmc), "(re)tuning...\n");
864999

865-
for (i = CLK_PHASE_0; i <= CLK_PHASE_270; i++) {
1000+
for (i = 0; i < 360; i += 90) {
8661001
host->tp.rx_phase = i;
8671002
/* exclude the active parameter set if retuning */
8681003
if (!memcmp(&tp_old, &host->tp, sizeof(tp_old)) &&
8691004
mmc->doing_retune)
8701005
continue;
871-
meson_mmc_set_tuning_params(mmc);
1006+
meson_mmc_set_phase_params(host);
8721007
ret = mmc_send_tuning(mmc, opcode, &cmd_error);
8731008
if (!ret)
8741009
break;
@@ -999,9 +1134,9 @@ static int meson_mmc_probe(struct platform_device *pdev)
9991134
if (ret)
10001135
goto free_host;
10011136

1002-
host->tp.core_phase = CLK_PHASE_180;
1003-
host->tp.tx_phase = CLK_PHASE_0;
1004-
host->tp.rx_phase = CLK_PHASE_0;
1137+
host->tp.core_phase = 180;
1138+
host->tp.tx_phase = 0;
1139+
host->tp.rx_phase = 0;
10051140

10061141
ret = meson_mmc_clk_init(host);
10071142
if (ret)

0 commit comments

Comments
 (0)