diff mbox

[U-Boot,2/2] imx: mx6ul/sx: fix mmdc_ch0 clk calculation

Message ID 1451887842-3747-2-git-send-email-peng.fan@nxp.com
State Changes Requested
Delegated to: Stefano Babic
Headers show

Commit Message

Peng Fan Jan. 4, 2016, 6:10 a.m. UTC
Check "Figure 19-5. BUS clock generation" of i.MX 6SoloX Applications
Processor Reference Manual and "Figure 18-5. BUS clock generation" of
i.MX 6UltraLite Applications Processor Reference Manual. If mmdc clk
sources from pll4_main_clk(pll_audio), the calculation is wrong.

Fix mmdc_ch0 clk calculation. Also add PLL_AUDIO/VIDEO support
for decode_pll.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
Cc: Stefano Babic <sbabic@denx.de>
---
 arch/arm/cpu/armv7/mx6/clock.c | 63 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 4 deletions(-)

Comments

Eric Nelson Jan. 5, 2016, 7:06 p.m. UTC | #1
Hi Peng,

On 01/03/2016 11:10 PM, Peng Fan wrote:
> Check "Figure 19-5. BUS clock generation" of i.MX 6SoloX Applications
> Processor Reference Manual and "Figure 18-5. BUS clock generation" of
> i.MX 6UltraLite Applications Processor Reference Manual. If mmdc clk
> sources from pll4_main_clk(pll_audio), the calculation is wrong.
> 
> Fix mmdc_ch0 clk calculation. Also add PLL_AUDIO/VIDEO support
> for decode_pll.
> 
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> Cc: Stefano Babic <sbabic@denx.de>
> ---
>  arch/arm/cpu/armv7/mx6/clock.c | 63 +++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 59 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c
> index 64514b1..1506c04 100644
> --- a/arch/arm/cpu/armv7/mx6/clock.c
> +++ b/arch/arm/cpu/armv7/mx6/clock.c
> @@ -18,6 +18,8 @@ enum pll_clocks {
>  	PLL_BUS,	/* System Bus PLL*/
>  	PLL_USBOTG,	/* OTG USB PLL */
>  	PLL_ENET,	/* ENET PLL */
> +	PLL_AUDIO,	/* AUDIO PLL */
> +	PLL_VIDEO,	/* AUDIO PLL */
>  };
>  
>  struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
> @@ -204,7 +206,7 @@ int enable_spi_clk(unsigned char enable, unsigned spi_num)
>  }
>  static u32 decode_pll(enum pll_clocks pll, u32 infreq)
>  {
> -	u32 div;
> +	u32 div, test_div, pll_num, pll_denom;
>  
>  	switch (pll) {
>  	case PLL_SYS:
> @@ -227,6 +229,44 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq)
>  		div &= BM_ANADIG_PLL_ENET_DIV_SELECT;
>  
>  		return 25000000 * (div + (div >> 1) + 1);
> +	case PLL_AUDIO:
> +		div = __raw_readl(&imx_ccm->analog_pll_audio);
> +		if (!(div & BM_ANADIG_PLL_AUDIO_ENABLE))
> +			return 0;
> +		/* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
> +		if (div & BM_ANADIG_PLL_AUDIO_BYPASS)
> +			return MXC_HCLK;
> +		pll_num = __raw_readl(&imx_ccm->analog_pll_audio_num);
> +		pll_denom = __raw_readl(&imx_ccm->analog_pll_audio_denom);
> +		test_div = (div & BM_ANADIG_PLL_AUDIO_TEST_DIV_SELECT) >>
> +			BP_ANADIG_PLL_AUDIO_TEST_DIV_SELECT;
> +		div &= BM_ANADIG_PLL_AUDIO_DIV_SELECT;
> +		if (test_div == 3) {
> +			debug("Error test_div\n");
> +			return 0;
> +		}
> +		test_div = 1 << (2 - test_div);
> +
> +		return infreq * (div + pll_num / pll_denom) / test_div;
> +	case PLL_VIDEO:
> +		div = __raw_readl(&imx_ccm->analog_pll_video);
> +		if (!(div & BM_ANADIG_PLL_VIDEO_ENABLE))
> +			return 0;
> +		/* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
> +		if (div & BM_ANADIG_PLL_VIDEO_BYPASS)
> +			return MXC_HCLK;
> +		pll_num = __raw_readl(&imx_ccm->analog_pll_video_num);
> +		pll_denom = __raw_readl(&imx_ccm->analog_pll_video_denom);
> +		test_div = (div & BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT) >>
> +			BP_ANADIG_PLL_VIDEO_POST_DIV_SELECT;
> +		div &= BM_ANADIG_PLL_VIDEO_DIV_SELECT;
> +		if (test_div == 3) {
> +			debug("Error test_div\n");
> +			return 0;
> +		}
> +		test_div = 1 << (2 - test_div);
> +
> +		return infreq * (div + pll_num / pll_denom) / test_div;
>  	default:
>  		return 0;
>  	}
> @@ -437,7 +477,7 @@ static u32 get_mmdc_ch0_clk(void)
>  	u32 cbcmr = __raw_readl(&imx_ccm->cbcmr);
>  	u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
>  
> -	u32 freq, podf, per2_clk2_podf;
> +	u32 freq, podf, per2_clk2_podf, misc2_audio_div;
>  
>  	if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL) ||
>  	    is_cpu_type(MXC_CPU_MX6SL)) {
> @@ -472,9 +512,24 @@ static u32 get_mmdc_ch0_clk(void)
>  				freq = mxc_get_pll_pfd(PLL_BUS, 0);
>  				break;
>  			case 3:
> -				/* static / 2 divider */
> -				freq =  mxc_get_pll_pfd(PLL_BUS, 2) / 2;

Your indentation is off here (1 tab too shallow):

Finding the register would also have been easier if this were named
pmu_misc2.

> +			misc2_audio_div = ((__raw_readl(&imx_ccm->ana_misc2)
> +					    >> 22) & 2) |
> +					   ((__raw_readl(&imx_ccm->ana_misc2)
> +					    >> 15) & 1);
> +			switch (misc2_audio_div) {
> +			case 0:
> +			case 2:
> +				misc2_audio_div = 1;
> +				break;
> +			case 1:
> +				misc2_audio_div = 2;
>  				break;
> +			case 3:
> +				misc2_audio_div = 4;
> +				break;
> +			}
> +			freq = decode_pll(PLL_AUDIO, MXC_HCLK) / misc2_audio_div;
> +			break;
>  			}
>  		}
>  		return freq / (podf + 1) / (per2_clk2_podf + 1);
>
Peng Fan Jan. 6, 2016, 1:47 a.m. UTC | #2
Hi Eric,
On Tue, Jan 05, 2016 at 12:06:52PM -0700, Eric Nelson wrote:
>Hi Peng,
>
>On 01/03/2016 11:10 PM, Peng Fan wrote:
>> Check "Figure 19-5. BUS clock generation" of i.MX 6SoloX Applications
>> Processor Reference Manual and "Figure 18-5. BUS clock generation" of
>> i.MX 6UltraLite Applications Processor Reference Manual. If mmdc clk
>> sources from pll4_main_clk(pll_audio), the calculation is wrong.
>> 
>> Fix mmdc_ch0 clk calculation. Also add PLL_AUDIO/VIDEO support
>> for decode_pll.
>> 
>> Signed-off-by: Peng Fan <peng.fan@nxp.com>
>> Cc: Stefano Babic <sbabic@denx.de>
>> ---
>>  arch/arm/cpu/armv7/mx6/clock.c | 63 +++++++++++++++++++++++++++++++++++++++---
>>  1 file changed, 59 insertions(+), 4 deletions(-)
>> 
>> diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c
>> index 64514b1..1506c04 100644
>> --- a/arch/arm/cpu/armv7/mx6/clock.c
>> +++ b/arch/arm/cpu/armv7/mx6/clock.c
>> @@ -18,6 +18,8 @@ enum pll_clocks {
>>  	PLL_BUS,	/* System Bus PLL*/
>>  	PLL_USBOTG,	/* OTG USB PLL */
>>  	PLL_ENET,	/* ENET PLL */
>> +	PLL_AUDIO,	/* AUDIO PLL */
>> +	PLL_VIDEO,	/* AUDIO PLL */
>>  };
>>  
>>  struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
>> @@ -204,7 +206,7 @@ int enable_spi_clk(unsigned char enable, unsigned spi_num)
>>  }
>>  static u32 decode_pll(enum pll_clocks pll, u32 infreq)
>>  {
>> -	u32 div;
>> +	u32 div, test_div, pll_num, pll_denom;
>>  
>>  	switch (pll) {
>>  	case PLL_SYS:
>> @@ -227,6 +229,44 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq)
>>  		div &= BM_ANADIG_PLL_ENET_DIV_SELECT;
>>  
>>  		return 25000000 * (div + (div >> 1) + 1);
>> +	case PLL_AUDIO:
>> +		div = __raw_readl(&imx_ccm->analog_pll_audio);
>> +		if (!(div & BM_ANADIG_PLL_AUDIO_ENABLE))
>> +			return 0;
>> +		/* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
>> +		if (div & BM_ANADIG_PLL_AUDIO_BYPASS)
>> +			return MXC_HCLK;
>> +		pll_num = __raw_readl(&imx_ccm->analog_pll_audio_num);
>> +		pll_denom = __raw_readl(&imx_ccm->analog_pll_audio_denom);
>> +		test_div = (div & BM_ANADIG_PLL_AUDIO_TEST_DIV_SELECT) >>
>> +			BP_ANADIG_PLL_AUDIO_TEST_DIV_SELECT;
>> +		div &= BM_ANADIG_PLL_AUDIO_DIV_SELECT;
>> +		if (test_div == 3) {
>> +			debug("Error test_div\n");
>> +			return 0;
>> +		}
>> +		test_div = 1 << (2 - test_div);
>> +
>> +		return infreq * (div + pll_num / pll_denom) / test_div;
>> +	case PLL_VIDEO:
>> +		div = __raw_readl(&imx_ccm->analog_pll_video);
>> +		if (!(div & BM_ANADIG_PLL_VIDEO_ENABLE))
>> +			return 0;
>> +		/* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
>> +		if (div & BM_ANADIG_PLL_VIDEO_BYPASS)
>> +			return MXC_HCLK;
>> +		pll_num = __raw_readl(&imx_ccm->analog_pll_video_num);
>> +		pll_denom = __raw_readl(&imx_ccm->analog_pll_video_denom);
>> +		test_div = (div & BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT) >>
>> +			BP_ANADIG_PLL_VIDEO_POST_DIV_SELECT;
>> +		div &= BM_ANADIG_PLL_VIDEO_DIV_SELECT;
>> +		if (test_div == 3) {
>> +			debug("Error test_div\n");
>> +			return 0;
>> +		}
>> +		test_div = 1 << (2 - test_div);
>> +
>> +		return infreq * (div + pll_num / pll_denom) / test_div;
>>  	default:
>>  		return 0;
>>  	}
>> @@ -437,7 +477,7 @@ static u32 get_mmdc_ch0_clk(void)
>>  	u32 cbcmr = __raw_readl(&imx_ccm->cbcmr);
>>  	u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
>>  
>> -	u32 freq, podf, per2_clk2_podf;
>> +	u32 freq, podf, per2_clk2_podf, misc2_audio_div;
>>  
>>  	if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL) ||
>>  	    is_cpu_type(MXC_CPU_MX6SL)) {
>> @@ -472,9 +512,24 @@ static u32 get_mmdc_ch0_clk(void)
>>  				freq = mxc_get_pll_pfd(PLL_BUS, 0);
>>  				break;
>>  			case 3:
>> -				/* static / 2 divider */
>> -				freq =  mxc_get_pll_pfd(PLL_BUS, 2) / 2;
>
>Your indentation is off here (1 tab too shallow):

oh. Thanks for pointing this out.

>
>Finding the register would also have been easier if this were named
>pmu_misc2.

CCM_ANALOG_MISCx is same to PMU_MISCx, they have same address.

Thanks
Peng.

>
>> +			misc2_audio_div = ((__raw_readl(&imx_ccm->ana_misc2)
>> +					    >> 22) & 2) |
>> +					   ((__raw_readl(&imx_ccm->ana_misc2)
>> +					    >> 15) & 1);
>> +			switch (misc2_audio_div) {
>> +			case 0:
>> +			case 2:
>> +				misc2_audio_div = 1;
>> +				break;
>> +			case 1:
>> +				misc2_audio_div = 2;
>>  				break;
>> +			case 3:
>> +				misc2_audio_div = 4;
>> +				break;
>> +			}
>> +			freq = decode_pll(PLL_AUDIO, MXC_HCLK) / misc2_audio_div;
>> +			break;
>>  			}
>>  		}
>>  		return freq / (podf + 1) / (per2_clk2_podf + 1);
>> 
>
diff mbox

Patch

diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c
index 64514b1..1506c04 100644
--- a/arch/arm/cpu/armv7/mx6/clock.c
+++ b/arch/arm/cpu/armv7/mx6/clock.c
@@ -18,6 +18,8 @@  enum pll_clocks {
 	PLL_BUS,	/* System Bus PLL*/
 	PLL_USBOTG,	/* OTG USB PLL */
 	PLL_ENET,	/* ENET PLL */
+	PLL_AUDIO,	/* AUDIO PLL */
+	PLL_VIDEO,	/* AUDIO PLL */
 };
 
 struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
@@ -204,7 +206,7 @@  int enable_spi_clk(unsigned char enable, unsigned spi_num)
 }
 static u32 decode_pll(enum pll_clocks pll, u32 infreq)
 {
-	u32 div;
+	u32 div, test_div, pll_num, pll_denom;
 
 	switch (pll) {
 	case PLL_SYS:
@@ -227,6 +229,44 @@  static u32 decode_pll(enum pll_clocks pll, u32 infreq)
 		div &= BM_ANADIG_PLL_ENET_DIV_SELECT;
 
 		return 25000000 * (div + (div >> 1) + 1);
+	case PLL_AUDIO:
+		div = __raw_readl(&imx_ccm->analog_pll_audio);
+		if (!(div & BM_ANADIG_PLL_AUDIO_ENABLE))
+			return 0;
+		/* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
+		if (div & BM_ANADIG_PLL_AUDIO_BYPASS)
+			return MXC_HCLK;
+		pll_num = __raw_readl(&imx_ccm->analog_pll_audio_num);
+		pll_denom = __raw_readl(&imx_ccm->analog_pll_audio_denom);
+		test_div = (div & BM_ANADIG_PLL_AUDIO_TEST_DIV_SELECT) >>
+			BP_ANADIG_PLL_AUDIO_TEST_DIV_SELECT;
+		div &= BM_ANADIG_PLL_AUDIO_DIV_SELECT;
+		if (test_div == 3) {
+			debug("Error test_div\n");
+			return 0;
+		}
+		test_div = 1 << (2 - test_div);
+
+		return infreq * (div + pll_num / pll_denom) / test_div;
+	case PLL_VIDEO:
+		div = __raw_readl(&imx_ccm->analog_pll_video);
+		if (!(div & BM_ANADIG_PLL_VIDEO_ENABLE))
+			return 0;
+		/* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
+		if (div & BM_ANADIG_PLL_VIDEO_BYPASS)
+			return MXC_HCLK;
+		pll_num = __raw_readl(&imx_ccm->analog_pll_video_num);
+		pll_denom = __raw_readl(&imx_ccm->analog_pll_video_denom);
+		test_div = (div & BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT) >>
+			BP_ANADIG_PLL_VIDEO_POST_DIV_SELECT;
+		div &= BM_ANADIG_PLL_VIDEO_DIV_SELECT;
+		if (test_div == 3) {
+			debug("Error test_div\n");
+			return 0;
+		}
+		test_div = 1 << (2 - test_div);
+
+		return infreq * (div + pll_num / pll_denom) / test_div;
 	default:
 		return 0;
 	}
@@ -437,7 +477,7 @@  static u32 get_mmdc_ch0_clk(void)
 	u32 cbcmr = __raw_readl(&imx_ccm->cbcmr);
 	u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
 
-	u32 freq, podf, per2_clk2_podf;
+	u32 freq, podf, per2_clk2_podf, misc2_audio_div;
 
 	if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL) ||
 	    is_cpu_type(MXC_CPU_MX6SL)) {
@@ -472,9 +512,24 @@  static u32 get_mmdc_ch0_clk(void)
 				freq = mxc_get_pll_pfd(PLL_BUS, 0);
 				break;
 			case 3:
-				/* static / 2 divider */
-				freq =  mxc_get_pll_pfd(PLL_BUS, 2) / 2;
+			misc2_audio_div = ((__raw_readl(&imx_ccm->ana_misc2)
+					    >> 22) & 2) |
+					   ((__raw_readl(&imx_ccm->ana_misc2)
+					    >> 15) & 1);
+			switch (misc2_audio_div) {
+			case 0:
+			case 2:
+				misc2_audio_div = 1;
+				break;
+			case 1:
+				misc2_audio_div = 2;
 				break;
+			case 3:
+				misc2_audio_div = 4;
+				break;
+			}
+			freq = decode_pll(PLL_AUDIO, MXC_HCLK) / misc2_audio_div;
+			break;
 			}
 		}
 		return freq / (podf + 1) / (per2_clk2_podf + 1);