Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/512x: clk: enforce even SDHC divider values

the SDHC clock is derived from CSB with a fractional divider which can
address "quarters"; the implementation multiplies CSB by 4 and divides
it by the (integer) divider value

a bug in the clock domain synchronisation requires that only even
divider values get setup; we achieve this by
- multiplying CSB by 2 only instead of 4
- registering with CCF the divider's bit field without bit0
- the divider's lowest bit remains clear as this is the reset value
and later operations won't touch it

this change keeps fully utilizing common clock primitives (needs no
additional support logic, and avoids an excessive divider table) and
satisfies the hardware's constraint of only supporting even divider
values

Signed-off-by: Gerhard Sittig <gsi@denx.de>
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Anatolij Gustschin <agust@denx.de>

authored by

Gerhard Sittig and committed by
Anatolij Gustschin
76922ebb 2a2b9ff8

+14 -2
+14 -2
arch/powerpc/platforms/512x/clock-commonclk.c
··· 560 560 /* now setup anything below SYS and CSB and IPS */ 561 561 562 562 clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2); 563 - clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 4, 1); 563 + 564 + /* 565 + * the Reference Manual discusses that for SDHC only even divide 566 + * ratios are supported because clock domain synchronization 567 + * between 'per' and 'ipg' is broken; 568 + * keep the divider's bit 0 cleared (per reset value), and only 569 + * allow to setup the divider's bits 7:1, which results in that 570 + * only even divide ratios can get configured upon rate changes; 571 + * keep the "x4" name because this bit shift hack is an internal 572 + * implementation detail, the "fractional divider with quarters" 573 + * semantics remains 574 + */ 575 + clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 2, 1); 564 576 clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0, 565 - &clkregs->scfr2, 0, 8, 577 + &clkregs->scfr2, 1, 7, 566 578 CLK_DIVIDER_ONE_BASED); 567 579 clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1); 568 580 clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,