RE: [PATCH 3/7] ARM: S5P6440: Clock and PLL support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Dec 11, 2009 at 19:35 +0900, Marc Zyngier wrote:
> -----Original Message-----
> From: linux-samsung-soc-owner@xxxxxxxxxxxxxxx [mailto:linux-samsung-soc-
> owner@xxxxxxxxxxxxxxx] On Behalf Of Marc Zyngier
> Sent: Friday, December 11, 2009 7:35 PM
> To: Kukjin Kim
> Cc: linux-samsung-soc@xxxxxxxxxxxxxxx; ben-linux@xxxxxxxxx; Kukjin Kim;
> Adityapratap Sharma; Thomas Abraham; Atul Dahiya
> Subject: Re: [PATCH 3/7] ARM: S5P6440: Clock and PLL support
> 
> On Fri, 11 Dec 2009 18:54:31 +0900
> Kukjin Kim <kgene.kim@xxxxxxxxxxx> wrote:
> 
> A few problems spotted here:

Hi Marc Zyngier,

Ok.

> > +static struct clk init_clocks_disable[] = {
> > +	{
> > +		.name		= "nand",
> > +		.id		= -1,
> > +		.parent		= &clk_h,
> > +		.enable		= s5p6440_mem_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_MEM0_HCLK_NFCON,
> > +	}, {
> > +		.name		= "adc",
> > +		.id		= -1,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_TSADC,
> > +	}, {
> > +		.name		= "i2c",
> > +		.id		= -1,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_IIC0,
> > +	}, {
> > +		.name		= "i2s_v40",
> > +		.id		= 0,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_IIS2,
> > +	}, {
> > +		.name		= "spi",
> > +		.id		= 0,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_SPI0,
> > +	}, {
> > +		.name		= "spi",
> > +		.id		= 1,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_SPI1,
> > +	}, {
> > +		.name		= "sclk_spi_48",
> > +		.id		= 0,
> > +		.parent		= &clk_48m,
> > +		.enable		= s5p6440_sclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_SCLK0_SPI0_48,
> > +	}, {
> > +		.name		= "sclk_spi_48",
> > +		.id		= 1,
> > +		.parent		= &clk_48m,
> > +		.enable		= s5p6440_sclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_SCLK0_SPI1_48,
> > +	}, {
> > +		.name		= "48m",
> > +		.id		= 0,
> > +		.parent		= &clk_48m,
> > +		.enable		= s5p6440_sclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_SCLK0_MMC0_48,
> > +	}, {
> > +		.name		= "48m",
> > +		.id		= 1,
> > +		.parent		= &clk_48m,
> > +		.enable		= s5p6440_sclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_SCLK0_MMC1_48,
> > +	}, {
> > +		.name		= "48m",
> > +		.id		= 2,
> > +		.parent		= &clk_48m,
> > +		.enable		= s5p6440_sclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_SCLK0_MMC2_48,
> > +	}, {
> > +		.name    	= "otg",
> > +		.id	   	= -1,
> > +		.parent  	= &clk_h,
> > +		.enable  	= s5p6440_hclk0_ctrl,
> > +		.ctrlbit 	= S5P_CLKCON_HCLK0_USB
> > +	}, {
> > +		.name    	= "post",
> > +		.id	   	= -1,
> > +		.parent  	= &clk_h,
> > +		.enable  	= s5p6440_hclk0_ctrl,
> > +		.ctrlbit 	= S5P_CLKCON_HCLK0_POST0
> > +	}, {
> > +		.name		= "lcd",
> > +		.id		= -1,
> > +		.parent		= &clk_h,
> > +		.enable		= s5p6440_hclk1_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_HCLK1_DISPCON,
> > +	}, {
> > +		.name		= "hsmmc",
> > +		.id		= 0,
> > +		.parent		= &clk_h,
> > +		.enable		= s5p6440_hclk0_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_HCLK0_HSMMC0,
> > +	}, {
> > +		.name		= "hsmmc",
> > +		.id		= 1,
> > +		.parent		= &clk_h,
> > +		.enable		= s5p6440_hclk0_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_HCLK0_HSMMC1,
> > +	}, {
> > +		.name		= "hsmmc",
> > +		.id		= 2,
> > +		.parent		= &clk_h,
> > +		.enable		= s5p6440_hclk0_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_HCLK0_HSMMC2,
> > +	}, {
> > +		.name		= "rtc",
> > +		.id		= -1,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_RTC,
> > +	}, {
> > +		.name		= "watchdog",
> > +		.id		= -1,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_WDT,
> > +	}
> > +};
> >
> > +/*
> > + * The following clocks will be enabled during clock initialization.
> > + */
> > +static struct clk init_clocks[] = {
> > +	{
> > +		.name		= "gpio",
> > +		.id		= -1,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_GPIO,
> > +	}, {
> > +		.name		= "timers",
> > +		.id		= -1,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_PWM,
> > +	}, {
> > +		.name		= "uart",
> > +		.id		= 0,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_UART0,
> > +	}, {
> > +		.name		= "uart",
> > +		.id		= 1,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_UART1,
> > +	}, {
> > +		.name		= "uart",
> > +		.id		= 2,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_UART2,
> > +	}, {
> > +		.name		= "uart",
> > +		.id		= 3,
> > +		.parent		= &clk_p,
> > +		.enable		= s5p6440_pclk_ctrl,
> > +		.ctrlbit	= S5P_CLKCON_PCLK_UART3,
> > +	}
> > +};
> The parent for most of these clocks are wrong. Looking at the user
> manual, they are connected to the low frequency domain (PCLK_LOW or
> HCLK_LOW). The parent must then be set to clk_p_low or clk_h_low.
Yes, you're right. I had thought that PCLK and HCLK were PCLK_LOW and
HCLK_LOW, respectively. However, it differs with user manual. I will change
it.

> Failure to do so leads to some "interesting" situations when HCLK and
> HCLK_LOW have different rates...
Yes, it works when HCLK and HCLK_LOW are same. But if they are different, it
doesn't work. I will change it.

> > +void __init_or_cpufreq s5p6440_setup_clocks(void)
> > +{
> > +	struct clk *xtal_clk;
> > +	unsigned long xtal;
> > +	unsigned long fclk;
> > +	unsigned long hclk;
> > +	unsigned long hclk_low;
> > +	unsigned long pclk;
> > +	unsigned long pclk_low;
> > +	unsigned long epll;
> > +	unsigned long apll;
> > +	unsigned long mpll;
> > +	unsigned int ptr;
> > +	u32 clkdiv0;
> > +	u32 clkdiv3;
> > +
> > +	/* Set S5P6440 functions for clk_fout_epll */
> > +	clk_fout_epll.enable = s5p6440_epll_enable;
> > +	clk_fout_epll.ops = &s5p6440_epll_ops;
> > +
> > +	/* Set S5P6440 functions for arm clock */
> > +	clk_arm.parent = &clk_mout_apll.clk;
> > +	clk_arm.ops = &s5p6440_clkarm_ops;
> > +
> > +	clkdiv0 = __raw_readl(S5P_CLK_DIV0);
> > +	clkdiv3 = __raw_readl(S5P_CLK_DIV3);
> > +
> > +	xtal_clk = clk_get(NULL, "ext_xtal");
> > +	BUG_ON(IS_ERR(xtal_clk));
> > +
> > +	xtal = clk_get_rate(xtal_clk);
> > +	clk_put(xtal_clk);
> > +
> > +	epll = s5p6440_get_epll(xtal);
> > +	mpll = s5p_get_pll(xtal, __raw_readl(S5P_MPLL_CON));
> > +	apll = s5p_get_pll(xtal, __raw_readl(S5P_APLL_CON));
> > +
> > +	printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz,
> M=%ld.%ldMHz," \
> > +			" E=%ld.%ldMHz\n",
> > +			print_mhz(apll), print_mhz(mpll), print_mhz(epll));
> > +
> > +	fclk = apll / GET_DIV(clkdiv0, S5P_CLKDIV0_ARM);
> > +	hclk = fclk / GET_DIV(clkdiv0, S5P_CLKDIV0_HCLK);
> > +	pclk = hclk / GET_DIV(clkdiv0, S5P_CLKDIV0_PCLK);
> > +
> > +	if (__raw_readl(S5P_OTHERS) & S5P_OTHERS_HCLK_LOW_SEL_MPLL) {
> > +		/* Synchronous mode */
> > +		hclk_low = apll / GET_DIV(clkdiv3, S5P_CLKDIV3_HCLK_LOW);
> > +	} else {
> > +		/* Asynchronous mode */
> > +		hclk_low = mpll / GET_DIV(clkdiv3, S5P_CLKDIV3_HCLK_LOW);
> > +	}
> 
> The test is inverted. S5P_OTHERS::S5P_OTHERS_HCLK_LOW_SEL_MPLL is set
> when MPLL is the source clock for HCLK_LOW.
Yes, you're right. They inverted. I will change them as follows :

+	if (__raw_readl(S5P_OTHERS) & S5P_OTHERS_HCLK_LOW_SEL_MPLL) {
+		hclk_low = mpll / GET_DIV(clkdiv3, S5P_CLKDIV3_HCLK_LOW);
+	} else {
+		hclk_low = apll / GET_DIV(clkdiv3, S5P_CLKDIV3_HCLK_LOW);
+	}

> > +	pclk_low = hclk_low / GET_DIV(clkdiv3, S5P_CLKDIV3_PCLK_LOW);
> > +
> > +	printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz,
> HCLK_LOW=%ld.%ldMHz," \
> > +			" PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
> > +			print_mhz(hclk), print_mhz(hclk_low),
> > +			print_mhz(pclk), print_mhz(pclk_low));
> > +
> > +	clk_fout_mpll.rate = mpll;
> > +	clk_fout_epll.rate = epll;
> > +	clk_fout_apll.rate = apll;
> > +
> > +	clk_f.rate = fclk;
> > +	clk_h.rate = hclk;
> > +	clk_p.rate = pclk;
> > +	clk_h_low.rate = hclk_low;
> > +	clk_p_low.rate = pclk_low;
> > +
> > +	for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
> > +		s3c_set_clksrc(init_parents[ptr]);
> > +
> > +	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
> > +		s3c_set_clksrc(&clksrcs[ptr]);
> > +}
> 
> --

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@xxxxxxxxxxx>, Senior Engineer,
System LSI Division, SAMSUNG ELECTRONICS CO., LTD.

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux SoC Development]     [Linux Rockchip Development]     [Linux USB Development]     [Video for Linux]     [Linux Audio Users]     [Linux SCSI]     [Yosemite News]

  Powered by Linux