ARM: imx6: fix up buggy CCM_CSCMR1 register
Subsystems (3)
cover ARM: imx6: fix up buggy CCM_CSCMR1 register
There is a defect in bits 22 and 21 of i.MX6 CCM_CSCMR1 register. These two bits are inverted between read and write. That said, bit field CCM_CSCMR1[22-20] (aclk/emi_podf on imx6q/dl and lcdif_pix_podf on imx6sl) will be something as below between read and write.
read write divider
000 110 1 001 111 2 010 100 3 011 101 4 100 010 5 101 011 6 110 000 7 111 001 8
To work around this hardware defect, every single read/modify/write sequence on the register will require a fix-up (invert bits 22 and 21) before writing the value into register. As there are dividers and multiplexers defined in the register, we choose to inherit the basic clk-divider and clk-mux and override the functions which writes register with a fix-up hooked in.
Shawn
Liu Ying (3):
ARM: imx: add common clock support for fixup div
ARM: imx: add common clock support for fixup mux
ARM: imx6: change some clocks to fixup clocks
arch/arm/mach-imx/Makefile | 3 +- arch/arm/mach-imx/clk-fixup-div.c | 129 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk-fixup-mux.c | 107 ++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk-imx6q.c | 24 +++---- arch/arm/mach-imx/clk-imx6sl.c | 20 +++--- arch/arm/mach-imx/clk.c | 26 ++++++++ arch/arm/mach-imx/clk.h | 10 +++ 7 files changed, 296 insertions(+), 23 deletions(-) create mode 100644 arch/arm/mach-imx/clk-fixup-div.c create mode 100644 arch/arm/mach-imx/clk-fixup-mux.c
Signature · 1 line
1.7.9.5
PATCH 1/3 ARM: imx: add common clock support for fixup div
From: Liu Ying <[email protected]>
One register may have several fields to control some clocks. It is possible that the read/write values of some fields may map to different real functional values, so writing to the other fields in the same register may break a working clock tree. A real case is the aclk_podf field in the register 'CCM Serial Clock Multiplexer Register 1' of i.MX6Q/SDL SoC. This patch introduces a fixup hook for divider clock which is called before writing a value to clock registers to support this kind of divider clocks.
--- arch/arm/mach-imx/Makefile | 3 +- arch/arm/mach-imx/clk-fixup-div.c | 129 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk.h | 4 ++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/clk-fixup-div.c
arch/arm/mach-imx/Makefile +2 -1
@@ -15,7 +15,8 @@ imx5-pm-$(CONFIG_PM) += pm-imx5.o obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o $(imx5-pm-y) obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ - clk-pfd.o clk-busy.o clk.o + clk-pfd.o clk-busy.o clk.o \ + clk-fixup-div.o obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
arch/arm/mach-imx/clk-fixup-div.c new file +129 -0
129 lines not on this page · raw message
arch/arm/mach-imx/clk.h +4 -0
@@ -49,6 +49,10 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, const char **parent_names, int num_parents); +struct clk *imx_clk_fixup_divider (const char *name,const char *parent, +void __iomem *reg,u8 shift,u8 width, +void (*fixup)(u32 *val)); +static inline struct clk *imx_clk_fixed (const char *name,int rate) {return clk_register_fixed_rate (NULL , name,NULL ,CLK_IS_ROOT , rate);
Signature · 1 line
1.7.9.5
PATCH 2/3 ARM: imx: add common clock support for fixup mux
In reply to Shawn GuoFrom: Liu Ying <[email protected]>
One register may have several fields to control some clocks. It is possible that the read/write values of some fields may map to different real functional values, so writing to the other fields in the same register may break a working clock tree. A real case is the aclk_podf field in the register 'CCM Serial Clock Multiplexer Register 1' of i.MX6Q/SDL SoC. This patch introduces a fixup hook for multiplexer clock which is called before writing a value to clock registers to support this kind of multiplexer clocks.
--- arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/clk-fixup-mux.c | 107 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk.h | 4 ++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/clk-fixup-mux.c
arch/arm/mach-imx/Makefile +1 -1
@@ -16,7 +16,7 @@ obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o $(i obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ clk-pfd.o clk-busy.o clk.o \ - clk-fixup-div.o + clk-fixup-div.o clk-fixup-mux.o obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
arch/arm/mach-imx/clk-fixup-mux.c new file +107 -0
107 lines not on this page · raw message
arch/arm/mach-imx/clk.h +4 -0
@@ -53,6 +53,10 @@ struct clk *imx_clk_fixup_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, void (*fixup)(u32 *val)); +struct clk *imx_clk_fixup_mux (const char *name,void __iomem *reg, +u8 shift,u8 width,const char **parents, +int num_parents,void (*fixup)(u32 *val)); +static inline struct clk *imx_clk_fixed (const char *name,int rate) {return clk_register_fixed_rate (NULL , name,NULL ,CLK_IS_ROOT , rate);
Signature · 1 line
1.7.9.5
PATCH 3/3 ARM: imx6: change some clocks to fixup clocks
In reply to Shawn GuoFrom: Liu Ying <[email protected]>
All the clocks controlled by the register 'CCM Serial Clock Multiplexer Register 1' should be fixup clocks. This patch changes those clocks from basic multiplexer or divider clocks to fixup clocks.
--- arch/arm/mach-imx/clk-imx6q.c | 24 ++++++++++++------------ arch/arm/mach-imx/clk-imx6sl.c | 20 ++++++++++---------- arch/arm/mach-imx/clk.c | 26 ++++++++++++++++++++++++++ arch/arm/mach-imx/clk.h | 2 ++ 4 files changed, 50 insertions(+), 22 deletions(-)
arch/arm/mach-imx/clk-imx6q.c +12 -12
@@ -384,16 +384,16 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[ipu2_di1_sel] =imx_clk_mux ("ipu2_di1_sel" , base +0x38 ,9 ,3 , ipu2_di1_sels,ARRAY_SIZE (ipu2_di1_sels)); clk[hsi_tx_sel] =imx_clk_mux ("hsi_tx_sel" , base +0x30 ,28 ,1 , hsi_tx_sels,ARRAY_SIZE (hsi_tx_sels)); clk[pcie_axi_sel] =imx_clk_mux ("pcie_axi_sel" , base +0x18 ,10 ,1 , pcie_axi_sels,ARRAY_SIZE (pcie_axi_sels)); - clk[ssi1_sel] =imx_clk_mux ("ssi1_sel" , base +0x1c ,10 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels)); - clk[ssi2_sel] =imx_clk_mux ("ssi2_sel" , base +0x1c ,12 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels)); - clk[ssi3_sel] =imx_clk_mux ("ssi3_sel" , base +0x1c ,14 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels)); - clk[usdhc1_sel] =imx_clk_mux ("usdhc1_sel" , base +0x1c ,16 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels)); - clk[usdhc2_sel] =imx_clk_mux ("usdhc2_sel" , base +0x1c ,17 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels)); - clk[usdhc3_sel] =imx_clk_mux ("usdhc3_sel" , base +0x1c ,18 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels)); - clk[usdhc4_sel] =imx_clk_mux ("usdhc4_sel" , base +0x1c ,19 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels)); + clk[ssi1_sel] =imx_clk_fixup_mux ("ssi1_sel" , base +0x1c ,10 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels), imx_cscmr1_fixup); + clk[ssi2_sel] =imx_clk_fixup_mux ("ssi2_sel" , base +0x1c ,12 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels), imx_cscmr1_fixup); + clk[ssi3_sel] =imx_clk_fixup_mux ("ssi3_sel" , base +0x1c ,14 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels), imx_cscmr1_fixup); + clk[usdhc1_sel] =imx_clk_fixup_mux ("usdhc1_sel" , base +0x1c ,16 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels), imx_cscmr1_fixup); + clk[usdhc2_sel] =imx_clk_fixup_mux ("usdhc2_sel" , base +0x1c ,17 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels), imx_cscmr1_fixup); + clk[usdhc3_sel] =imx_clk_fixup_mux ("usdhc3_sel" , base +0x1c ,18 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels), imx_cscmr1_fixup); + clk[usdhc4_sel] =imx_clk_fixup_mux ("usdhc4_sel" , base +0x1c ,19 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels), imx_cscmr1_fixup); clk[enfc_sel] =imx_clk_mux ("enfc_sel" , base +0x2c ,16 ,2 , enfc_sels,ARRAY_SIZE (enfc_sels)); - clk[emi_sel] =imx_clk_mux ("emi_sel" , base +0x1c ,27 ,2 , emi_sels,ARRAY_SIZE (emi_sels)); - clk[emi_slow_sel] =imx_clk_mux ("emi_slow_sel" , base +0x1c ,29 ,2 , emi_slow_sels,ARRAY_SIZE (emi_slow_sels)); + clk[emi_sel] =imx_clk_fixup_mux ("emi_sel" , base +0x1c ,27 ,2 , emi_sels,ARRAY_SIZE (emi_sels), imx_cscmr1_fixup); + clk[emi_slow_sel] =imx_clk_fixup_mux ("emi_slow_sel" , base +0x1c ,29 ,2 , emi_slow_sels,ARRAY_SIZE (emi_slow_sels), imx_cscmr1_fixup); clk[vdo_axi_sel] =imx_clk_mux ("vdo_axi_sel" , base +0x18 ,11 ,1 , vdo_axi_sels,ARRAY_SIZE (vdo_axi_sels)); clk[vpu_axi_sel] =imx_clk_mux ("vpu_axi_sel" , base +0x18 ,14 ,2 , vpu_axi_sels,ARRAY_SIZE (vpu_axi_sels)); clk[cko1_sel] =imx_clk_mux ("cko1_sel" , base +0x60 ,0 ,4 , cko1_sels,ARRAY_SIZE (cko1_sels));
@@ -406,7 +406,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[periph_clk2] =imx_clk_divider ("periph_clk2" ,"periph_clk2_sel" , base +0x14 ,27 ,3 ); clk[periph2_clk2] =imx_clk_divider ("periph2_clk2" ,"periph2_clk2_sel" , base +0x14 ,0 ,3 ); clk[ipg] =imx_clk_divider ("ipg" ,"ahb" , base +0x14 ,8 ,2 ); - clk[ipg_per] =imx_clk_divider ("ipg_per" ,"ipg" , base +0x1c ,0 ,6 ); + clk[ipg_per] =imx_clk_fixup_divider ("ipg_per" ,"ipg" , base +0x1c ,0 ,6 , imx_cscmr1_fixup); clk[esai_pred] =imx_clk_divider ("esai_pred" ,"esai_sel" , base +0x28 ,9 ,3 ); clk[esai_podf] =imx_clk_divider ("esai_podf" ,"esai_pred" , base +0x28 ,25 ,3 ); clk[asrc_pred] =imx_clk_divider ("asrc_pred" ,"asrc_sel" , base +0x30 ,12 ,3 );
@@ -442,8 +442,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[usdhc4_podf] =imx_clk_divider ("usdhc4_podf" ,"usdhc4_sel" , base +0x24 ,22 ,3 ); clk[enfc_pred] =imx_clk_divider ("enfc_pred" ,"enfc_sel" , base +0x2c ,18 ,3 ); clk[enfc_podf] =imx_clk_divider ("enfc_podf" ,"enfc_pred" , base +0x2c ,21 ,6 ); - clk[emi_podf] =imx_clk_divider ("emi_podf" ,"emi_sel" , base +0x1c ,20 ,3 ); - clk[emi_slow_podf] =imx_clk_divider ("emi_slow_podf" ,"emi_slow_sel" , base +0x1c ,23 ,3 ); + clk[emi_podf] =imx_clk_fixup_divider ("emi_podf" ,"emi_sel" , base +0x1c ,20 ,3 , imx_cscmr1_fixup); + clk[emi_slow_podf] =imx_clk_fixup_divider ("emi_slow_podf" ,"emi_slow_sel" , base +0x1c ,23 ,3 , imx_cscmr1_fixup); clk[vpu_axi_podf] =imx_clk_divider ("vpu_axi_podf" ,"vpu_axi_sel" , base +0x24 ,25 ,3 ); clk[cko1_podf] =imx_clk_divider ("cko1_podf" ,"cko1_sel" , base +0x60 ,4 ,3 );
arch/arm/mach-imx/clk-imx6sl.c +10 -10
@@ -138,14 +138,14 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) clks[IMX6SL_CLK_PERIPH_CLK2_SEL ] =imx_clk_mux ("periph_clk2_sel" , base +0x18 ,12 ,2 , periph_clk2_sels,ARRAY_SIZE (periph_clk2_sels)); clks[IMX6SL_CLK_CSI_SEL ] =imx_clk_mux ("csi_sel" , base +0x3c ,9 ,2 , csi_lcdif_sels,ARRAY_SIZE (csi_lcdif_sels)); clks[IMX6SL_CLK_LCDIF_AXI_SEL ] =imx_clk_mux ("lcdif_axi_sel" , base +0x3c ,14 ,2 , csi_lcdif_sels,ARRAY_SIZE (csi_lcdif_sels)); - clks[IMX6SL_CLK_USDHC1_SEL ] =imx_clk_mux ("usdhc1_sel" , base +0x1c ,16 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels)); - clks[IMX6SL_CLK_USDHC2_SEL ] =imx_clk_mux ("usdhc2_sel" , base +0x1c ,17 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels)); - clks[IMX6SL_CLK_USDHC3_SEL ] =imx_clk_mux ("usdhc3_sel" , base +0x1c ,18 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels)); - clks[IMX6SL_CLK_USDHC4_SEL ] =imx_clk_mux ("usdhc4_sel" , base +0x1c ,19 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels)); - clks[IMX6SL_CLK_SSI1_SEL ] =imx_clk_mux ("ssi1_sel" , base +0x1c ,10 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels)); - clks[IMX6SL_CLK_SSI2_SEL ] =imx_clk_mux ("ssi2_sel" , base +0x1c ,12 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels)); - clks[IMX6SL_CLK_SSI3_SEL ] =imx_clk_mux ("ssi3_sel" , base +0x1c ,14 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels)); - clks[IMX6SL_CLK_PERCLK_SEL ] =imx_clk_mux ("perclk_sel" , base +0x1c ,6 ,1 , perclk_sels,ARRAY_SIZE (perclk_sels)); + clks[IMX6SL_CLK_USDHC1_SEL ] =imx_clk_fixup_mux ("usdhc1_sel" , base +0x1c ,16 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_USDHC2_SEL ] =imx_clk_fixup_mux ("usdhc2_sel" , base +0x1c ,17 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_USDHC3_SEL ] =imx_clk_fixup_mux ("usdhc3_sel" , base +0x1c ,18 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_USDHC4_SEL ] =imx_clk_fixup_mux ("usdhc4_sel" , base +0x1c ,19 ,1 , usdhc_sels,ARRAY_SIZE (usdhc_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_SSI1_SEL ] =imx_clk_fixup_mux ("ssi1_sel" , base +0x1c ,10 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_SSI2_SEL ] =imx_clk_fixup_mux ("ssi2_sel" , base +0x1c ,12 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_SSI3_SEL ] =imx_clk_fixup_mux ("ssi3_sel" , base +0x1c ,14 ,2 , ssi_sels,ARRAY_SIZE (ssi_sels), imx_cscmr1_fixup); + clks[IMX6SL_CLK_PERCLK_SEL ] =imx_clk_fixup_mux ("perclk_sel" , base +0x1c ,6 ,1 , perclk_sels,ARRAY_SIZE (perclk_sels), imx_cscmr1_fixup); clks[IMX6SL_CLK_PXP_AXI_SEL ] =imx_clk_mux ("pxp_axi_sel" , base +0x34 ,6 ,3 , epdc_pxp_sels,ARRAY_SIZE (epdc_pxp_sels)); clks[IMX6SL_CLK_EPDC_AXI_SEL ] =imx_clk_mux ("epdc_axi_sel" , base +0x34 ,15 ,3 , epdc_pxp_sels,ARRAY_SIZE (epdc_pxp_sels)); clks[IMX6SL_CLK_GPU2D_OVG_SEL ] =imx_clk_mux ("gpu2d_ovg_sel" , base +0x18 ,4 ,2 , gpu2d_ovg_sels,ARRAY_SIZE (gpu2d_ovg_sels));
@@ -179,14 +179,14 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) clks[IMX6SL_CLK_SSI2_PODF ] =imx_clk_divider ("ssi2_podf" ,"ssi2_pred" , base +0x2c ,0 ,6 ); clks[IMX6SL_CLK_SSI3_PRED ] =imx_clk_divider ("ssi3_pred" ,"ssi3_sel" , base +0x28 ,22 ,3 ); clks[IMX6SL_CLK_SSI3_PODF ] =imx_clk_divider ("ssi3_podf" ,"ssi3_pred" , base +0x28 ,16 ,6 ); - clks[IMX6SL_CLK_PERCLK ] =imx_clk_divider ("perclk" ,"perclk_sel" , base +0x1c ,0 ,6 ); + clks[IMX6SL_CLK_PERCLK ] =imx_clk_fixup_divider ("perclk" ,"perclk_sel" , base +0x1c ,0 ,6 , imx_cscmr1_fixup); clks[IMX6SL_CLK_PXP_AXI_PODF ] =imx_clk_divider ("pxp_axi_podf" ,"pxp_axi_sel" , base +0x34 ,3 ,3 ); clks[IMX6SL_CLK_EPDC_AXI_PODF ] =imx_clk_divider ("epdc_axi_podf" ,"epdc_axi_sel" , base +0x34 ,12 ,3 ); clks[IMX6SL_CLK_GPU2D_OVG_PODF ] =imx_clk_divider ("gpu2d_ovg_podf" ,"gpu2d_ovg_sel" , base +0x18 ,26 ,3 ); clks[IMX6SL_CLK_GPU2D_PODF ] =imx_clk_divider ("gpu2d_podf" ,"gpu2d_sel" , base +0x18 ,29 ,3 ); clks[IMX6SL_CLK_LCDIF_PIX_PRED ] =imx_clk_divider ("lcdif_pix_pred" ,"lcdif_pix_sel" , base +0x38 ,3 ,3 ); clks[IMX6SL_CLK_EPDC_PIX_PRED ] =imx_clk_divider ("epdc_pix_pred" ,"epdc_pix_sel" , base +0x38 ,12 ,3 ); - clks[IMX6SL_CLK_LCDIF_PIX_PODF ] =imx_clk_divider ("lcdif_pix_podf" ,"lcdif_pix_pred" , base +0x1c ,20 ,3 ); + clks[IMX6SL_CLK_LCDIF_PIX_PODF ] =imx_clk_fixup_divider ("lcdif_pix_podf" ,"lcdif_pix_pred" , base +0x1c ,20 ,3 , imx_cscmr1_fixup); clks[IMX6SL_CLK_EPDC_PIX_PODF ] =imx_clk_divider ("epdc_pix_podf" ,"epdc_pix_pred" , base +0x18 ,23 ,3 ); clks[IMX6SL_CLK_SPDIF0_PRED ] =imx_clk_divider ("spdif0_pred" ,"spdif0_sel" , base +0x30 ,25 ,3 ); clks[IMX6SL_CLK_SPDIF0_PODF ] =imx_clk_divider ("spdif0_podf" ,"spdif0_pred" , base +0x30 ,22 ,3 );
arch/arm/mach-imx/clk.c +26 -0
@@ -37,3 +37,29 @@ struct clk * __init imx_obtain_fixed_clock( clk =imx_clk_fixed (name, rate);return clk; } + +/* +* This fixups the register CCM_CSCMR1 write value. +* The write/read/divider values of the aclk_podf field +* of that register have the relationship described by +* the following table: +* +* write value read value divider +* 3b'000 3b'110 7 +* 3b'001 3b'111 8 +* 3b'010 3b'100 5 +* 3b'011 3b'101 6 +* 3b'100 3b'010 3 +* 3b'101 3b'011 4 +* 3b'110 3b'000 1 +* 3b'111 3b'001 2(default) +* +* That's why we do the xor operation below. +*/ +#define CSCMR1_FIXUP 0x00600000 + +void imx_cscmr1_fixup (u32 *val) +{ + *val ^=CSCMR1_FIXUP ; +return ; +}
arch/arm/mach-imx/clk.h +2 -0
@@ -6,6 +6,8 @@extern spinlock_t imx_ccm_lock; +extern void imx_cscmr1_fixup (u32 *val); +struct clk *imx_clk_pllv1 (const char *name,const char *parent,void __iomem *base);
Signature · 1 line
1.7.9.5
cover ARM: imx6: fix up buggy CCM_CSCMR1 register
In reply to Shawn GuoQuoted 37 lines · Shawn Guo
There is a defect in bits 22 and 21 of i.MX6
CCM_CSCMR1register. These two bits are inverted between read and write. That said, bit field CCM_CSCMR1[22-20] (aclk/emi_podf on imx6q/dl andlcdif_pix_podfon imx6sl) will be something as below between read and write.read write divider 000 110 1 001 111 2 010 100 3 011 101 4 100 010 5 101 011 6 110 000 7 111 001 8To work around this hardware defect, every single read/modify/write sequence on the register will require a fix-up (invert bits 22 and 21) before writing the value into register. As there are dividers and multiplexers defined in the register, we choose to inherit the basic clk-divider and clk-mux and override the functions which writes register with a fix-up hooked in.
Shawn
Liu Ying (3):
ARM: imx: add common clock support for fixup div
ARM: imx: add common clock support for fixup mux
ARM: imx6: change some clocks to fixup clocksarch/arm/mach-imx/Makefile | 3 +- arch/arm/mach-imx/clk-fixup-div.c | 129 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk-fixup-mux.c | 107 ++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk-imx6q.c | 24 +++---- arch/arm/mach-imx/clk-imx6sl.c | 20 +++--- arch/arm/mach-imx/clk.c | 26 ++++++++ arch/arm/mach-imx/clk.h | 10 +++ 7 files changed, 296 insertions(+), 23 deletions(-)
Quoted 2 lines
create mode 100644
arch/arm/mach-imx/clk-fixup-div.ccreate mode 100644arch/arm/mach-imx/clk-fixup-mux.c
For the whole series:
Thanks
Dirk