From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:14
Hi everyone,
Here is an attempt at improving the MMC clock support in the Allwinner
SoCs.
Until now, the MMC clocks were having a custom phase function that was
directly setting an obscure value in the right register, because we
were not really having any idea of what these values were.
Now that we have more informations, we can introduce a common function
call to get and set the phase of a particular clock, and use this in
both our provider and our client.
Thanks,
Maxime
Changes from v2:
- Reworked the get_phase operation handling to call it from
_clk_init instead of the ugly hack
- Added the clocks to the A23
- Modified the output and sample clock names to have a consistent
naming
Changes from v1:
- Dropped the patches to enforce rate boundaries on the clocks. This
is partly covered by the Tomeu, and should be based on this
whenever it will be merged.
- Fixed a few typos here and there
- Added a patch to include of.h from clk-provider.h
Maxime Ripard (11):
clk: Include of.h in clock-provider.h
clk: Add a function to retrieve phase
clk: sunxi: factors: Invert the probing logic
clk: sunxi: Introduce mbus compatible
ARM: sunxi: dt: Switch to the new mbus compatible
clk: sunxi: Move mod0 clock to a file of its own
clk: sunxi: Move mbus to mod0 file
ARM: sunxi: dt: Add sample and output mmc clocks
clk: sunxi: mod0: Introduce MMC proper phase handling
mmc: sunxi: Convert MMC driver to the standard clock phase API
clk: sunxi: Remove custom phase function
Mike Turquette (1):
clk: introduce clk_set_phase function & callback
Documentation/devicetree/bindings/clock/sunxi.txt | 3 +
.../devicetree/bindings/mmc/sunxi-mmc.txt | 8 +-
arch/arm/boot/dts/sun4i-a10.dtsi | 104 +++++++-
arch/arm/boot/dts/sun5i-a10s.dtsi | 81 +++++-
arch/arm/boot/dts/sun5i-a13.dtsi | 82 +++++-
arch/arm/boot/dts/sun6i-a31.dtsi | 104 +++++++-
arch/arm/boot/dts/sun7i-a20.dtsi | 106 +++++++-
arch/arm/boot/dts/sun8i-a23.dtsi | 78 +++++-
drivers/clk/clk.c | 95 ++++++-
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-factors.c | 101 +++++++-
drivers/clk/sunxi/clk-factors.h | 16 +-
drivers/clk/sunxi/clk-mod0.c | 283 +++++++++++++++++++++
drivers/clk/sunxi/clk-sunxi.c | 189 +-------------
drivers/mmc/host/sunxi-mmc.c | 72 ++++--
include/linux/clk-private.h | 1 +
include/linux/clk-provider.h | 11 +
include/linux/clk.h | 29 +++
include/linux/clk/sunxi.h | 22 --
19 files changed, 1090 insertions(+), 296 deletions(-)
create mode 100644 drivers/clk/sunxi/clk-mod0.c
delete mode 100644 include/linux/clk/sunxi.h
--
2.1.0
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:15
From: Mike Turquette <redacted>
A common operation for a clock signal generator is to shift the phase of
that signal. This patch introduces a new function to the clk.h API to
dynamically adjust the phase of a clock signal. Additionally this patch
introduces support for the new function in the common clock framework
via the .set_phase call back in struct clk_ops.
Signed-off-by: Mike Turquette <redacted>
Signed-off-by: Maxime Ripard <redacted>
---
drivers/clk/clk.c | 85 +++++++++++++++++++++++++++++++++++++++++---
include/linux/clk-private.h | 1 +
include/linux/clk-provider.h | 5 +++
include/linux/clk.h | 29 +++++++++++++++
4 files changed, 116 insertions(+), 4 deletions(-)
Am Donnerstag, 11. September 2014, 22:18:15 schrieb Maxime Ripard:
From: Mike Turquette <redacted>
A common operation for a clock signal generator is to shift the phase of
that signal. This patch introduces a new function to the clk.h API to
dynamically adjust the phase of a clock signal. Additionally this patch
introduces support for the new function in the common clock framework
via the .set_phase call back in struct clk_ops.
Signed-off-by: Mike Turquette <redacted>
Signed-off-by: Maxime Ripard <redacted>
This looks nice and would also be very useful for Rockchip SoCs I'm working
on. And the implementation looks very straightforward.
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
@@ -264,6 +265,11 @@ static int clk_debug_create_one(struct clk *clk, struct
dentry *pdentry) if (!d)
goto err_out;
+ d = debugfs_create_u32("clk_phase", S_IRUGO, clk->dentry,
+ (u32 *)&clk->phase);
+ if (!d)
+ goto err_out;
+
d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
(u32 *)&clk->flags);
if (!d)
@@ -1739,6 +1745,77 @@ out: EXPORT_SYMBOL_GPL(clk_set_parent); /**+ * clk_set_phase - adjust the phase shift of a clock signal+ * @clk: clock signal source+ * @degrees: number of degrees the signal is shifted+ *+ * Shifts the phase of a clock signal by the specified+ * degrees. Returns 0 on success, -EERROR otherwise.+ *+ * This function makes no distinction about the input or reference+ * signal that we adjust the clock signal phase against. For example+ * phase locked-loop clock signal generators we may shift phase with+ * respect to feedback clock signal input, but for other cases the+ * clock phase may be shifted with respect to some other, unspecified+ * signal.+ *+ * Additionally the concept of phase shift does not propagate through+ * the clock tree hierarchy, which sets it apart from clock rates and+ * clock accuracy. A parent clock phase attribute does not have an+ * impact on the phase attribute of a child clock.+ */+int clk_set_phase(struct clk *clk, int degrees)+{+ int ret = 0;++ if (!clk)+ goto out;++ /* sanity check degrees */+ degrees %= 360;+ if (degrees < 0)+ degrees += 360;++ clk_prepare_lock();++ if (!clk->ops->set_phase)+ goto out_unlock;++ ret = clk->ops->set_phase(clk->hw, degrees);++ if (!ret)+ clk->phase = degrees;++out_unlock:+ clk_prepare_unlock();++out:+ return ret;+}++/**+ * clk_get_phase - return the phase shift of a clock signal+ * @clk: clock signal source+ *+ * Returns the phase shift of a clock node in degrees, otherwise returns+ * -EERROR.+ */+int clk_get_phase(struct clk *clk)+{+ int ret = 0;++ if (!clk)+ goto out;++ clk_prepare_lock();+ ret = clk->phase;+ clk_prepare_unlock();++out:+ return ret;+}++/** * __clk_init - initialize the data structures in a struct clk * @dev: device initializing this clk, placeholder for now * @clk: clk being initialized
@@ -106,6 +106,25 @@ int clk_notifier_unregister(struct clk *clk, struct
notifier_block *nb); */
long clk_get_accuracy(struct clk *clk);
+/**
+ * clk_set_phase - adjust the phase shift of a clock signal
+ * @clk: clock signal source
+ * @degrees: number of degrees the signal is shifted
+ *
+ * Shifts the phase of a clock signal by the specified degrees. Returns 0
on + * success, -EERROR otherwise.
+ */
+int clk_set_phase(struct clk *clk, int degrees);
+
+/**
+ * clk_get_phase - return the phase shift of a clock signal
+ * @clk: clock signal source
+ *
+ * Returns the phase shift of a clock node in degrees, otherwise returns
+ * -EERROR.
+ */
+int clk_get_phase(struct clk *clk);
+
#else
static inline long clk_get_accuracy(struct clk *clk)
@@ -113,6 +132,16 @@ static inline long clk_get_accuracy(struct clk *clk) return -ENOTSUPP; }+static inline long clk_set_phase(struct clk *clk, int phase)+{+ return -ENOTSUPP;+}++static inline long clk_get_phase(struct clk *clk)+{+ return -ENOTSUPP;+}+ #endif /**
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:16
CLK_OF_DECLARE relies on OF_DECLARE_1 that is defined in of.h. Fixes build
errors when one use CLK_OF_DECLARE but doesn't include of.h
Signed-off-by: Maxime Ripard <redacted>
---
include/linux/clk-provider.h | 1 +
1 file changed, 1 insertion(+)
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:17
The current phase API doesn't look into the actual hardware to get the phase
value, but will rather get it from a variable only set by the set_phase
function.
This will cause issue when the client driver will never call the set_phase
function, where we can end up having a reported phase that will not match what
the hardware has been programmed to by the bootloader or what phase is
programmed out of reset.
Add a new get_phase function for the drivers to implement so that we can get
this value.
Signed-off-by: Maxime Ripard <redacted>
---
drivers/clk/clk.c | 10 ++++++++++
include/linux/clk-provider.h | 5 +++++
2 files changed, 15 insertions(+)
Am Donnerstag, 11. September 2014, 22:18:17 schrieb Maxime Ripard:
The current phase API doesn't look into the actual hardware to get the phase
value, but will rather get it from a variable only set by the set_phase
function.
This will cause issue when the client driver will never call the set_phase
function, where we can end up having a reported phase that will not match
what the hardware has been programmed to by the bootloader or what phase is
programmed out of reset.
Add a new get_phase function for the drivers to implement so that we can get
this value.
Signed-off-by: Maxime Ripard <redacted>
From: Mike Turquette <hidden> Date: 2014-09-28 00:17:32
Quoting Maxime Ripard (2014-09-11 13:18:17)
quoted hunk
The current phase API doesn't look into the actual hardware to get the phase
value, but will rather get it from a variable only set by the set_phase
function.
This will cause issue when the client driver will never call the set_phase
function, where we can end up having a reported phase that will not match what
the hardware has been programmed to by the bootloader or what phase is
programmed out of reset.
Add a new get_phase function for the drivers to implement so that we can get
this value.
Signed-off-by: Maxime Ripard <redacted>
---
drivers/clk/clk.c | 10 ++++++++++
include/linux/clk-provider.h | 5 +++++
2 files changed, 15 insertions(+)
I probably wasn't paying enough attention to this. Based on the
coverletter I thought that v3 would introduce something like
CLK_GET_PHASE_NOCACHE and stuff that logic into a __clk_get_phase
function? Looks like this version of the series doesn't handle phases
that can be changed by hardware (e.g. coming out of idle).
Correct me if I am wrong, but it looks like we retrieve the phase only
once at init and then never again? The rest of the time we rely on
clk->phase to always be accurate...
Regards,
Mike
quoted hunk
+
+ /*
* Set clk's rate. The preferred method is to use .recalc_rate. For
* simple clocks and lazy developers the default fallback is to use the
* parent's rate. If a clock doesn't have a parent (or is orphaned)
From: Maxime Ripard <hidden> Date: 2014-09-29 08:24:21
Hi Mike,
On Sat, Sep 27, 2014 at 05:17:32PM -0700, Mike Turquette wrote:
Quoting Maxime Ripard (2014-09-11 13:18:17)
quoted
The current phase API doesn't look into the actual hardware to get the phase
value, but will rather get it from a variable only set by the set_phase
function.
This will cause issue when the client driver will never call the set_phase
function, where we can end up having a reported phase that will not match what
the hardware has been programmed to by the bootloader or what phase is
programmed out of reset.
Add a new get_phase function for the drivers to implement so that we can get
this value.
Signed-off-by: Maxime Ripard <redacted>
---
drivers/clk/clk.c | 10 ++++++++++
include/linux/clk-provider.h | 5 +++++
2 files changed, 15 insertions(+)
I probably wasn't paying enough attention to this. Based on the
coverletter I thought that v3 would introduce something like
CLK_GET_PHASE_NOCACHE and stuff that logic into a __clk_get_phase
function? Looks like this version of the series doesn't handle phases
that can be changed by hardware (e.g. coming out of idle).
Correct me if I am wrong, but it looks like we retrieve the phase only
once at init and then never again? The rest of the time we rely on
clk->phase to always be accurate...
Yeah, I didn't have any use for it at the moment, and thought that if
someone ever needed it, it would be trivial to add, so I left it out.
If you want me to still do it, I can send an additional patch.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140929/fa5f33c9/attachment.sig>
From: Mike Turquette <hidden> Date: 2014-09-30 07:01:17
Quoting Maxime Ripard (2014-09-29 01:24:21)
Hi Mike,
On Sat, Sep 27, 2014 at 05:17:32PM -0700, Mike Turquette wrote:
quoted
Quoting Maxime Ripard (2014-09-11 13:18:17)
quoted
The current phase API doesn't look into the actual hardware to get the phase
value, but will rather get it from a variable only set by the set_phase
function.
This will cause issue when the client driver will never call the set_phase
function, where we can end up having a reported phase that will not match what
the hardware has been programmed to by the bootloader or what phase is
programmed out of reset.
Add a new get_phase function for the drivers to implement so that we can get
this value.
Signed-off-by: Maxime Ripard <redacted>
---
drivers/clk/clk.c | 10 ++++++++++
include/linux/clk-provider.h | 5 +++++
2 files changed, 15 insertions(+)
I probably wasn't paying enough attention to this. Based on the
coverletter I thought that v3 would introduce something like
CLK_GET_PHASE_NOCACHE and stuff that logic into a __clk_get_phase
function? Looks like this version of the series doesn't handle phases
that can be changed by hardware (e.g. coming out of idle).
Correct me if I am wrong, but it looks like we retrieve the phase only
once at init and then never again? The rest of the time we rely on
clk->phase to always be accurate...
Yeah, I didn't have any use for it at the moment, and thought that if
someone ever needed it, it would be trivial to add, so I left it out.
If you want me to still do it, I can send an additional patch.
No it is fine. A bit asymmetrical for my brain but it is dead code if no
one is using it (yet).
Regards,
Mike
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:19
Even though the mbus clock is a regular module clock, given its nature, it
needs to be enabled all the time.
Introduce a new compatible, to differentiate it from the other module clocks.
Signed-off-by: Maxime Ripard <redacted>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/clk-sunxi.c | 1 +
2 files changed, 2 insertions(+)
@@ -46,6 +46,7 @@ Required properties: "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23+ "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks "allwinner,sun7i-a20-out-clk" - for the external output clocks "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:21
Since we know have the ability to declare factors clock outside of clk-sunxi,
create a new mod0 driver to deal with the mod0 clocks.
Signed-off-by: Maxime Ripard <redacted>
---
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-mod0.c | 82 +++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sunxi/clk-sunxi.c | 1 -
3 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/sunxi/clk-mod0.c
@@ -0,0 +1,82 @@+/*+*Copyright2013EmilioL?pez+*+*EmilioL?pez<emilio@elopez.com.ar>+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;eitherversion2oftheLicense,or+*(atyouroption)anylaterversion.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/++#include<linux/clk-provider.h>+#include<linux/clkdev.h>++#include"clk-factors.h"++/**+*sun4i_get_mod0_factors()-calculatesm,nfactorsforMOD0-styleclocks+*MOD0rateiscalculatedasfollows+*rate=(parent_rate>>p)/(m+1);+*/++staticvoidsun4i_a10_get_mod0_factors(u32*freq,u32parent_rate,+u8*n,u8*k,u8*m,u8*p)+{+u8div,calcm,calcp;++/* These clocks can only divide, so we will never be able to achieve+*frequencieshigherthantheparentfrequency*/+if(*freq>parent_rate)+*freq=parent_rate;++div=DIV_ROUND_UP(parent_rate,*freq);++if(div<16)+calcp=0;+elseif(div/2<16)+calcp=1;+elseif(div/4<16)+calcp=2;+else+calcp=3;++calcm=DIV_ROUND_UP(div,1<<calcp);++*freq=(parent_rate>>calcp)/calcm;++/* we were called to round the frequency, we can now return */+if(n==NULL)+return;++*m=calcm-1;+*p=calcp;+}++/* user manual says "n" but it's really "p" */+staticstructclk_factors_configsun4i_a10_mod0_config={+.mshift=0,+.mwidth=4,+.pshift=16,+.pwidth=2,+};++staticconststructfactors_datasun4i_a10_mod0_data__initconst={+.enable=31,+.mux=24,+.table=&sun4i_a10_mod0_config,+.getter=sun4i_a10_get_mod0_factors,+};++staticDEFINE_SPINLOCK(sun4i_a10_mod0_lock);++staticvoid__initsun4i_a10_mod0_setup(structdevice_node*node)+{+sunxi_factors_register(node,&sun4i_a10_mod0_data,&sun4i_a10_mod0_lock);+}+CLK_OF_DECLARE(sun4i_a10_mod0,"allwinner,sun4i-a10-mod0-clk",sun4i_a10_mod0_setup);
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:22
Move the MBUS clock to the module clocks file. It's pretty trivial, but still
requires to enable the clocks to make sure it won't get disabled.
Signed-off-by: Maxime Ripard <redacted>
---
drivers/clk/sunxi/clk-mod0.c | 12 +++++++++
drivers/clk/sunxi/clk-sunxi.c | 57 -------------------------------------------
2 files changed, 12 insertions(+), 57 deletions(-)
@@ -320,46 +320,6 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate,-/**-*sun4i_get_mod0_factors()-calculatesm,nfactorsforMOD0-styleclocks-*MOD0rateiscalculatedasfollows-*rate=(parent_rate>>p)/(m+1);-*/--staticvoidsun4i_get_mod0_factors(u32*freq,u32parent_rate,-u8*n,u8*k,u8*m,u8*p)-{-u8div,calcm,calcp;--/* These clocks can only divide, so we will never be able to achieve-*frequencieshigherthantheparentfrequency*/-if(*freq>parent_rate)-*freq=parent_rate;--div=DIV_ROUND_UP(parent_rate,*freq);--if(div<16)-calcp=0;-elseif(div/2<16)-calcp=1;-elseif(div/4<16)-calcp=2;-else-calcp=3;--calcm=DIV_ROUND_UP(div,1<<calcp);--*freq=(parent_rate>>calcp)/calcm;--/* we were called to round the frequency, we can now return */-if(n==NULL)-return;--*m=calcm-1;-*p=calcp;-}--/***sun7i_a20_get_out_factors()-calculatesm,pfactorsforCLK_OUT_A/B
@@ -495,14 +455,6 @@ static struct clk_factors_config sun4i_apb1_config = {};/* user manual says "n" but it's really "p" */-staticstructclk_factors_configsun4i_mod0_config={-.mshift=0,-.mwidth=4,-.pshift=16,-.pwidth=2,-};--/* user manual says "n" but it's really "p" */staticstructclk_factors_configsun7i_a20_out_config={.mshift=8,.mwidth=5,
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:24
The MMC clock we thought we had until now are actually not one but three
different clocks.
The main one is unchanged, and will have three outputs:
- The clock fed into the MMC
- a sample and output clocks, to deal with when should we output/sample data
to/from the MMC bus
The phase control we had are actually controlling the two latter clocks, but
the main MMC one is unchanged.
We can adjust the phase with a 3 bits value, from 0 to 7, 0 meaning a 180 phase
shift, and the other values being the number of periods from the MMC parent
clock to outphase the clock of.
Signed-off-by: Maxime Ripard <redacted>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 2 +
drivers/clk/sunxi/clk-mod0.c | 189 ++++++++++++++++++++++
2 files changed, 191 insertions(+)
@@ -47,6 +47,8 @@ Required properties: "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13+ "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10+ "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10 "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks "allwinner,sun7i-a20-out-clk" - for the external output clocks "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
@@ -92,3 +93,191 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)clk_prepare_enable(mbus);}CLK_OF_DECLARE(sun5i_a13_mbus,"allwinner,sun5i-a13-mbus-clk",sun5i_a13_mbus_setup);++structmmc_phase_data{+u8offset;+};++structmmc_phase{+structclk_hwhw;+void__iomem*reg;+structmmc_phase_data*data;+spinlock_t*lock;+};++#define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)++staticintmmc_get_phase(structclk_hw*hw)+{+structclk*mmc,*mmc_parent,*clk=hw->clk;+structmmc_phase*phase=to_mmc_phase(hw);+unsignedintmmc_rate,mmc_parent_rate;+u16step,mmc_div;+u32value;+u8delay;++value=readl(phase->reg);+delay=(value>>phase->data->offset)&0x3;++if(!delay)+return180;++/* Get the main MMC clock */+mmc=clk_get_parent(clk);+if(!mmc)+return-EINVAL;++/* And its rate */+mmc_rate=clk_get_rate(mmc);+if(!mmc_rate)+return-EINVAL;++/* Now, get the MMC parent (most likely some PLL) */+mmc_parent=clk_get_parent(mmc);+if(!mmc_parent)+return-EINVAL;++/* And its rate */+mmc_parent_rate=clk_get_rate(mmc_parent);+if(!mmc_parent_rate)+return-EINVAL;++/* Get MMC clock divider */+mmc_div=mmc_parent_rate/mmc_rate;++step=DIV_ROUND_CLOSEST(360,mmc_div);+returndelay*step;+}++staticintmmc_set_phase(structclk_hw*hw,intdegrees)+{+structclk*mmc,*mmc_parent,*clk=hw->clk;+structmmc_phase*phase=to_mmc_phase(hw);+unsignedintmmc_rate,mmc_parent_rate;+unsignedlongflags;+u32value;+u8delay;++/* Get the main MMC clock */+mmc=clk_get_parent(clk);+if(!mmc)+return-EINVAL;++/* And its rate */+mmc_rate=clk_get_rate(mmc);+if(!mmc_rate)+return-EINVAL;++/* Now, get the MMC parent (most likely some PLL) */+mmc_parent=clk_get_parent(mmc);+if(!mmc_parent)+return-EINVAL;++/* And its rate */+mmc_parent_rate=clk_get_rate(mmc_parent);+if(!mmc_parent_rate)+return-EINVAL;++if(degrees!=180){+u16step,mmc_div;++/* Get MMC clock divider */+mmc_div=mmc_parent_rate/mmc_rate;++/*+*Wecanonlyoutphasetheclocksbymultipleofthe+*PLL'speriod.+*+*SincetheMMCclockinonlyadivider,andthe+*formulatogettheoutphasingindegreesisdeg=+*360*delta/period+*+*Ifwesimplifythisformula,wecanseethatthe+*onlythingthatwe'reconcernedaboutisthenumber+*ofperiodwewanttooutphaseourclockfrom,and+*thedividersetbytheMMCclock.+*/+step=DIV_ROUND_CLOSEST(360,mmc_div);+delay=DIV_ROUND_CLOSEST(degrees,step);+}else{+delay=0;+}++spin_lock_irqsave(phase->lock,flags);+value=readl(phase->reg);+value&=~GENMASK(phase->data->offset+3,phase->data->offset);+value|=delay<<phase->data->offset;+writel(value,phase->reg);+spin_unlock_irqrestore(phase->lock,flags);++return0;+}++staticconststructclk_opsmmc_clk_ops={+.get_phase=mmc_get_phase,+.set_phase=mmc_set_phase,+};++staticvoid__initsun4i_a10_mmc_phase_setup(structdevice_node*node,+structmmc_phase_data*data)+{+constchar*parent_names[1]={of_clk_get_parent_name(node,0)};+structclk_init_datainit={+.num_parents=1,+.parent_names=parent_names,+.ops=&mmc_clk_ops,+};++structmmc_phase*phase;+structclk*clk;++phase=kmalloc(sizeof(*phase),GFP_KERNEL);+if(!phase)+return;++phase->hw.init=&init;++phase->reg=of_iomap(node,0);+if(!phase->reg)+gotoerr_free;++phase->data=data;+phase->lock=&sun4i_a10_mod0_lock;++if(of_property_read_string(node,"clock-output-names",&init.name))+init.name=node->name;++clk=clk_register(NULL,&phase->hw);+if(IS_ERR(clk))+gotoerr_unmap;++of_clk_add_provider(node,of_clk_src_simple_get,clk);++return;++err_unmap:+iounmap(phase->reg);+err_free:+kfree(phase);+}+++staticstructmmc_phase_datammc_output_clk={+.offset=8,+};++staticstructmmc_phase_datammc_sample_clk={+.offset=20,+};++staticvoid__initsun4i_a10_mmc_output_setup(structdevice_node*node)+{+sun4i_a10_mmc_phase_setup(node,&mmc_output_clk);+}+CLK_OF_DECLARE(sun4i_a10_mmc_output,"allwinner,sun4i-a10-mmc-output-clk",sun4i_a10_mmc_output_setup);++staticvoid__initsun4i_a10_mmc_sample_setup(structdevice_node*node)+{+sun4i_a10_mmc_phase_setup(node,&mmc_sample_clk);+}+CLK_OF_DECLARE(sun4i_a10_mmc_sample,"allwinner,sun4i-a10-mmc-sample-clk",sun4i_a10_mmc_sample_setup);
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:25
Now that we have proper support to use the generic phase API in our clock
driver, switch the MMC driver to use it.
Signed-off-by: Maxime Ripard <redacted>
Acked-by: Ulf Hansson <redacted>
---
.../devicetree/bindings/mmc/sunxi-mmc.txt | 8 +--
drivers/mmc/host/sunxi-mmc.c | 72 +++++++++++++++-------
2 files changed, 53 insertions(+), 27 deletions(-)
@@ -10,8 +10,8 @@ Absolute maximum transfer rate is 200MB/s Required properties: - compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc" - reg : mmc controller base registers- - clocks : a list with 2 phandle + clock specifier pairs- - clock-names : must contain "ahb" and "mmc"+ - clocks : a list with 4 phandle + clock specifier pairs+ - clock-names : must contain "ahb", "mmc", "output" and "sample" - interrupts : mmc controller interrupt Optional properties:
@@ -909,6 +907,18 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,returnPTR_ERR(host->clk_mmc);}+host->clk_output=devm_clk_get(&pdev->dev,"output");+if(IS_ERR(host->clk_output)){+dev_err(&pdev->dev,"Could not get output clock\n");+returnPTR_ERR(host->clk_output);+}++host->clk_sample=devm_clk_get(&pdev->dev,"sample");+if(IS_ERR(host->clk_sample)){+dev_err(&pdev->dev,"Could not get sample clock\n");+returnPTR_ERR(host->clk_sample);+}+host->reset=devm_reset_control_get(&pdev->dev,"ahb");ret=clk_prepare_enable(host->clk_ahb);
From: David Lanzendörfer <hidden> Date: 2014-09-26 14:27:10
Hello
Now that we have proper support to use the generic phase API in our clock
driver, switch the MMC driver to use it.
[...]
/* determine delays */
if (rate <= 400000) {
- oclk_dly = 0;
- sclk_dly = 7;
+ oclk_dly = 180;
+ sclk_dly = 42;
[...]
How did you calculate the actual phase values from the original parameters?
greatings
--
David Lanzend?rfer
OpenSourceSupport GmbH
System engineer and supporter
http://www.o2s.ch/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140926/8bc39436/attachment.sig>
From: Maxime Ripard <hidden> Date: 2014-09-11 20:18:26
Now that we don't have any user left for our custom phase function, we can
safely remove this hack from the code.
Signed-off-by: Maxime Ripard <redacted>
---
drivers/clk/sunxi/clk-sunxi.c | 37 -------------------------------------
include/linux/clk/sunxi.h | 22 ----------------------
2 files changed, 59 deletions(-)
delete mode 100644 include/linux/clk/sunxi.h
@@ -1,22 +0,0 @@-/*- * Copyright 2013 - Hans de Goede <hdegoede@redhat.com>- *- * This program is free software; you can redistribute it and/or modify- * it under the terms of the GNU General Public License as published by- * the Free Software Foundation; either version 2 of the License, or- * (at your option) any later version.- *- * This program is distributed in the hope that it will be useful,- * but WITHOUT ANY WARRANTY; without even the implied warranty of- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- * GNU General Public License for more details.- */--#ifndef __LINUX_CLK_SUNXI_H_-#define __LINUX_CLK_SUNXI_H_--#include <linux/clk.h>--void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output);--#endif
From: Hans de Goede <hidden> Date: 2014-09-12 07:22:06
Hi,
On 09/11/2014 10:18 PM, Maxime Ripard wrote:
Hi everyone,
Here is an attempt at improving the MMC clock support in the Allwinner
SoCs.
Until now, the MMC clocks were having a custom phase function that was
directly setting an obscure value in the right register, because we
were not really having any idea of what these values were.
Now that we have more informations, we can introduce a common function
call to get and set the phase of a particular clock, and use this in
both our provider and our client.
Thanks,
Maxime
I've not done a full review this time around (-ENOTIME), but I've taken
a look at the changed bits, and those look good to me.
Regards,
Hans
From: Maxime Ripard <hidden> Date: 2014-09-22 11:31:33
Mike,
On Thu, Sep 11, 2014 at 10:18:14PM +0200, Maxime Ripard wrote:
Hi everyone,
Here is an attempt at improving the MMC clock support in the Allwinner
SoCs.
Until now, the MMC clocks were having a custom phase function that was
directly setting an obscure value in the right register, because we
were not really having any idea of what these values were.
Now that we have more informations, we can introduce a common function
call to get and set the phase of a particular clock, and use this in
both our provider and our client.
It would be great that we have that custom phase API out of the kernel
for 3.18, and you were one of the greatest supporters to that idea,
could we please have your view on this?
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140922/b6ddffc8/attachment.sig>
From: Mike Turquette <hidden> Date: 2014-09-26 00:42:18
Quoting Maxime Ripard (2014-09-22 04:31:33)
Mike,
On Thu, Sep 11, 2014 at 10:18:14PM +0200, Maxime Ripard wrote:
quoted
Hi everyone,
Here is an attempt at improving the MMC clock support in the Allwinner
SoCs.
Until now, the MMC clocks were having a custom phase function that was
directly setting an obscure value in the right register, because we
were not really having any idea of what these values were.
Now that we have more informations, we can introduce a common function
call to get and set the phase of a particular clock, and use this in
both our provider and our client.
It would be great that we have that custom phase API out of the kernel
for 3.18, and you were one of the greatest supporters to that idea,
could we please have your view on this?
Patches all look good to me. Did you want the whole series to go through
the clk tree? If so we'll need an Ack for the MMC patch and for the ARM
DTS patches as well.
Regards,
Mike
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
From: Maxime Ripard <hidden> Date: 2014-09-26 06:55:07
Hi Mike,
On Thu, Sep 25, 2014 at 05:42:18PM -0700, Mike Turquette wrote:
Quoting Maxime Ripard (2014-09-22 04:31:33)
quoted
Mike,
On Thu, Sep 11, 2014 at 10:18:14PM +0200, Maxime Ripard wrote:
quoted
Hi everyone,
Here is an attempt at improving the MMC clock support in the Allwinner
SoCs.
Until now, the MMC clocks were having a custom phase function that was
directly setting an obscure value in the right register, because we
were not really having any idea of what these values were.
Now that we have more informations, we can introduce a common function
call to get and set the phase of a particular clock, and use this in
both our provider and our client.
It would be great that we have that custom phase API out of the kernel
for 3.18, and you were one of the greatest supporters to that idea,
could we please have your view on this?
Patches all look good to me. Did you want the whole series to go through
the clk tree?
I guess it would be where it most make sense yes.
If so we'll need an Ack for the MMC patch and for the ARM DTS
patches as well.
We already have an Ack from Ulf on the MMC patch, and I'm the
maintainer of the DTS involved, so we should be ok :)
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140926/c3dd532a/attachment.sig>
From: Mike Turquette <hidden> Date: 2014-09-26 17:52:44
Quoting Maxime Ripard (2014-09-25 23:55:07)
Hi Mike,
On Thu, Sep 25, 2014 at 05:42:18PM -0700, Mike Turquette wrote:
quoted
Quoting Maxime Ripard (2014-09-22 04:31:33)
quoted
Mike,
On Thu, Sep 11, 2014 at 10:18:14PM +0200, Maxime Ripard wrote:
quoted
Hi everyone,
Here is an attempt at improving the MMC clock support in the Allwinner
SoCs.
Until now, the MMC clocks were having a custom phase function that was
directly setting an obscure value in the right register, because we
were not really having any idea of what these values were.
Now that we have more informations, we can introduce a common function
call to get and set the phase of a particular clock, and use this in
both our provider and our client.
It would be great that we have that custom phase API out of the kernel
for 3.18, and you were one of the greatest supporters to that idea,
could we please have your view on this?
Patches all look good to me. Did you want the whole series to go through
the clk tree?
I guess it would be where it most make sense yes.
quoted
If so we'll need an Ack for the MMC patch and for the ARM DTS
patches as well.
We already have an Ack from Ulf on the MMC patch, and I'm the
maintainer of the DTS involved, so we should be ok :)
Oops, I didn't notice Ulf's Ack. Will either your or Emilio be sending a
pull request for the sunxi clock changes?
Regards,
Mike
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com