diff options
Diffstat (limited to 'arch/arm/cpu/armv7/exynos/clock.c')
| -rw-r--r-- | arch/arm/cpu/armv7/exynos/clock.c | 279 | 
1 files changed, 264 insertions, 15 deletions
| diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 84a50470a..5bde9d180 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -96,7 +96,7 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)  	freq = CONFIG_SYS_CLK_FREQ; -	if (pllreg == EPLL) { +	if (pllreg == EPLL || pllreg == RPLL) {  		k = k & 0xffff;  		/* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */  		fout = (m + k / PLL_DIV_65536) * (freq / (p * (1 << s))); @@ -117,7 +117,7 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)  			div = PLL_DIV_1024;  		else if (proid_is_exynos4412())  			div = PLL_DIV_65535; -		else if (proid_is_exynos5250()) +		else if (proid_is_exynos5250() || proid_is_exynos5420())  			div = PLL_DIV_65536;  		else  			return 0; @@ -362,6 +362,43 @@ unsigned long clock_get_periph_rate(int peripheral)  		return 0;  } +/* exynos5420: return pll clock frequency */ +static unsigned long exynos5420_get_pll_clk(int pllreg) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned long r, k = 0; + +	switch (pllreg) { +	case APLL: +		r = readl(&clk->apll_con0); +		break; +	case MPLL: +		r = readl(&clk->mpll_con0); +		break; +	case EPLL: +		r = readl(&clk->epll_con0); +		k = readl(&clk->epll_con1); +		break; +	case VPLL: +		r = readl(&clk->vpll_con0); +		k = readl(&clk->vpll_con1); +		break; +	case BPLL: +		r = readl(&clk->bpll_con0); +		break; +	case RPLL: +		r = readl(&clk->rpll_con0); +		k = readl(&clk->rpll_con1); +		break; +	default: +		printf("Unsupported PLL (%d)\n", pllreg); +		return 0; +	} + +	return exynos_get_pll_clk(pllreg, r, k); +} +  /* exynos4: return ARM clock frequency */  static unsigned long exynos4_get_arm_clk(void)  { @@ -485,6 +522,27 @@ static unsigned long exynos4x12_get_pwm_clk(void)  	return pclk;  } +/* exynos5420: return pwm clock frequency */ +static unsigned long exynos5420_get_pwm_clk(void) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned long pclk, sclk; +	unsigned int ratio; + +	/* +	 * CLK_DIV_PERIC0 +	 * PWM_RATIO [31:28] +	 */ +	ratio = readl(&clk->div_peric0); +	ratio = (ratio >> 28) & 0xf; +	sclk = get_pll_clk(MPLL); + +	pclk = sclk / (ratio + 1); + +	return pclk; +} +  /* exynos4: return uart clock frequency */  static unsigned long exynos4_get_uart_clk(int dev_index)  { @@ -624,6 +682,53 @@ static unsigned long exynos5_get_uart_clk(int dev_index)  	return uclk;  } +/* exynos5420: return uart clock frequency */ +static unsigned long exynos5420_get_uart_clk(int dev_index) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned long uclk, sclk; +	unsigned int sel; +	unsigned int ratio; + +	/* +	 * CLK_SRC_PERIC0 +	 * UART0_SEL [6:4] +	 * UART1_SEL [10:8] +	 * UART2_SEL [14:12] +	 * UART3_SEL [18:16] +	 * generalised calculation as follows +	 * sel = (sel >> ((dev_index * 4) + 4)) & mask; +	 */ +	sel = readl(&clk->src_peric0); +	sel = (sel >> ((dev_index * 4) + 4)) & 0x7; + +	if (sel == 0x3) +		sclk = get_pll_clk(MPLL); +	else if (sel == 0x6) +		sclk = get_pll_clk(EPLL); +	else if (sel == 0x7) +		sclk = get_pll_clk(RPLL); +	else +		return 0; + +	/* +	 * CLK_DIV_PERIC0 +	 * UART0_RATIO [11:8] +	 * UART1_RATIO [15:12] +	 * UART2_RATIO [19:16] +	 * UART3_RATIO [23:20] +	 * generalised calculation as follows +	 * ratio = (ratio >> ((dev_index * 4) + 8)) & mask; +	 */ +	ratio = readl(&clk->div_peric0); +	ratio = (ratio >> ((dev_index * 4) + 8)) & 0xf; + +	uclk = sclk / (ratio + 1); + +	return uclk; +} +  static unsigned long exynos4_get_mmc_clk(int dev_index)  {  	struct exynos4_clock *clk = @@ -718,6 +823,47 @@ static unsigned long exynos5_get_mmc_clk(int dev_index)  	return uclk;  } +static unsigned long exynos5420_get_mmc_clk(int dev_index) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned long uclk, sclk; +	unsigned int sel, ratio; + +	/* +	 * CLK_SRC_FSYS +	 * MMC0_SEL [10:8] +	 * MMC1_SEL [14:12] +	 * MMC2_SEL [18:16] +	 * generalised calculation as follows +	 * sel = (sel >> ((dev_index * 4) + 8)) & mask +	 */ +	sel = readl(&clk->src_fsys); +	sel = (sel >> ((dev_index * 4) + 8)) & 0x7; + +	if (sel == 0x3) +		sclk = get_pll_clk(MPLL); +	else if (sel == 0x6) +		sclk = get_pll_clk(EPLL); +	else +		return 0; + +	/* +	 * CLK_DIV_FSYS1 +	 * MMC0_RATIO [9:0] +	 * MMC1_RATIO [19:10] +	 * MMC2_RATIO [29:20] +	 * generalised calculation as follows +	 * ratio = (ratio >> (dev_index * 10)) & mask +	 */ +	ratio = readl(&clk->div_fsys1); +	ratio = (ratio >> (dev_index * 10)) & 0x3ff; + +	uclk = (sclk / (ratio + 1)); + +	return uclk; +} +  /* exynos4: set the mmc clock */  static void exynos4_set_mmc_clk(int dev_index, unsigned int div)  { @@ -804,6 +950,29 @@ static void exynos5_set_mmc_clk(int dev_index, unsigned int div)  	writel(val, addr);  } +/* exynos5: set the mmc clock */ +static void exynos5420_set_mmc_clk(int dev_index, unsigned int div) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned int addr; +	unsigned int val, shift; + +	/* +	 * CLK_DIV_FSYS1 +	 * MMC0_RATIO [9:0] +	 * MMC1_RATIO [19:10] +	 * MMC2_RATIO [29:20] +	 */ +	addr = (unsigned int)&clk->div_fsys1; +	shift = dev_index * 10; + +	val = readl(addr); +	val &= ~(0x3ff << shift); +	val |= (div & 0x3ff) << shift; +	writel(val, addr); +} +  /* get_lcd_clk: return lcd clock frequency */  static unsigned long exynos4_get_lcd_clk(void)  { @@ -1324,6 +1493,71 @@ static int exynos5_set_spi_clk(enum periph_id periph_id,  	return 0;  } +static int exynos5420_set_spi_clk(enum periph_id periph_id, +					unsigned int rate) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	int main; +	unsigned int fine; +	unsigned shift, pre_shift; +	unsigned div_mask = 0xf, pre_div_mask = 0xff; +	u32 *reg; +	u32 *pre_reg; + +	main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); +	if (main < 0) { +		debug("%s: Cannot set clock rate for periph %d", +		      __func__, periph_id); +		return -1; +	} +	main = main - 1; +	fine = fine - 1; + +	switch (periph_id) { +	case PERIPH_ID_SPI0: +		reg = &clk->div_peric1; +		shift = 20; +		pre_reg = &clk->div_peric4; +		pre_shift = 8; +		break; +	case PERIPH_ID_SPI1: +		reg = &clk->div_peric1; +		shift = 24; +		pre_reg = &clk->div_peric4; +		pre_shift = 16; +		break; +	case PERIPH_ID_SPI2: +		reg = &clk->div_peric1; +		shift = 28; +		pre_reg = &clk->div_peric4; +		pre_shift = 24; +		break; +	case PERIPH_ID_SPI3: +		reg = &clk->div_isp1; +		shift = 16; +		pre_reg = &clk->div_isp1; +		pre_shift = 0; +		break; +	case PERIPH_ID_SPI4: +		reg = &clk->div_isp1; +		shift = 20; +		pre_reg = &clk->div_isp1; +		pre_shift = 8; +		break; +	default: +		debug("%s: Unsupported peripheral ID %d\n", __func__, +		      periph_id); +		return -1; +	} + +	clrsetbits_le32(reg, div_mask << shift, (main & div_mask) << shift); +	clrsetbits_le32(pre_reg, pre_div_mask << pre_shift, +			(fine & pre_div_mask) << pre_shift); + +	return 0; +} +  static unsigned long exynos4_get_i2c_clk(void)  {  	struct exynos4_clock *clk = @@ -1341,9 +1575,11 @@ static unsigned long exynos4_get_i2c_clk(void)  unsigned long get_pll_clk(int pllreg)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_get_pll_clk(pllreg);  		return exynos5_get_pll_clk(pllreg); -	else { +	} else {  		if (proid_is_exynos4412())  			return exynos4x12_get_pll_clk(pllreg);  		return exynos4_get_pll_clk(pllreg); @@ -1375,9 +1611,11 @@ unsigned long get_i2c_clk(void)  unsigned long get_pwm_clk(void)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_get_pwm_clk();  		return clock_get_periph_rate(PERIPH_ID_PWM0); -	else { +	} else {  		if (proid_is_exynos4412())  			return exynos4x12_get_pwm_clk();  		return exynos4_get_pwm_clk(); @@ -1386,9 +1624,11 @@ unsigned long get_pwm_clk(void)  unsigned long get_uart_clk(int dev_index)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_get_uart_clk(dev_index);  		return exynos5_get_uart_clk(dev_index); -	else { +	} else {  		if (proid_is_exynos4412())  			return exynos4x12_get_uart_clk(dev_index);  		return exynos4_get_uart_clk(dev_index); @@ -1397,17 +1637,23 @@ unsigned long get_uart_clk(int dev_index)  unsigned long get_mmc_clk(int dev_index)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_get_mmc_clk(dev_index);  		return exynos5_get_mmc_clk(dev_index); -	else +	} else {  		return exynos4_get_mmc_clk(dev_index); +	}  }  void set_mmc_clk(int dev_index, unsigned int div)  { -	if (cpu_is_exynos5()) -		exynos5_set_mmc_clk(dev_index, div); -	else { +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			exynos5420_set_mmc_clk(dev_index, div); +		else +			exynos5_set_mmc_clk(dev_index, div); +	} else {  		if (proid_is_exynos4412())  			exynos4x12_set_mmc_clk(dev_index, div);  		else @@ -1439,10 +1685,13 @@ void set_mipi_clk(void)  int set_spi_clk(int periph_id, unsigned int rate)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_set_spi_clk(periph_id, rate);  		return exynos5_set_spi_clk(periph_id, rate); -	else +	} else {  		return 0; +	}  }  int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq, |