xref: /openbmc/u-boot/arch/mips/mach-ath79/ar933x/clk.c (revision cf0bcd7d)
1 /*
2  * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
3  *
4  * SPDX-License-Identifier: GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <asm/io.h>
9 #include <asm/addrspace.h>
10 #include <asm/types.h>
11 #include <mach/ar71xx_regs.h>
12 #include <mach/ath79.h>
13 
14 DECLARE_GLOBAL_DATA_PTR;
15 
16 static u32 ar933x_get_xtal(void)
17 {
18 	u32 val;
19 
20 	val = ath79_get_bootstrap();
21 	if (val & AR933X_BOOTSTRAP_REF_CLK_40)
22 		return 40000000;
23 	else
24 		return 25000000;
25 }
26 
27 int get_serial_clock(void)
28 {
29 	return ar933x_get_xtal();
30 }
31 
32 int get_clocks(void)
33 {
34 	void __iomem *regs;
35 	u32 val, xtal, pll, div;
36 
37 	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
38 			   MAP_NOCACHE);
39 	xtal = ar933x_get_xtal();
40 	val = readl(regs + AR933X_PLL_CPU_CONFIG_REG);
41 
42 	/* VCOOUT = XTAL * DIV_INT */
43 	div = (val >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT)
44 			& AR933X_PLL_CPU_CONFIG_REFDIV_MASK;
45 	pll = xtal / div;
46 
47 	/* PLLOUT = VCOOUT * (1/2^OUTDIV) */
48 	div = (val >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT)
49 			& AR933X_PLL_CPU_CONFIG_NINT_MASK;
50 	pll *= div;
51 	div = (val >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT)
52 			& AR933X_PLL_CPU_CONFIG_OUTDIV_MASK;
53 	if (!div)
54 		div = 1;
55 	pll >>= div;
56 
57 	val = readl(regs + AR933X_PLL_CLK_CTRL_REG);
58 
59 	/* CPU_CLK = PLLOUT / CPU_POST_DIV */
60 	div = ((val >> AR933X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT)
61 			& AR933X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1;
62 	gd->cpu_clk = pll / div;
63 
64 	/* DDR_CLK = PLLOUT / DDR_POST_DIV */
65 	div = ((val >> AR933X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT)
66 			& AR933X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1;
67 	gd->mem_clk = pll / div;
68 
69 	/* AHB_CLK = PLLOUT / AHB_POST_DIV */
70 	div = ((val >> AR933X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT)
71 			& AR933X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1;
72 	gd->bus_clk = pll / div;
73 
74 	return 0;
75 }
76 
77 ulong get_bus_freq(ulong dummy)
78 {
79 	if (!gd->bus_clk)
80 		get_clocks();
81 	return gd->bus_clk;
82 }
83 
84 ulong get_ddr_freq(ulong dummy)
85 {
86 	if (!gd->mem_clk)
87 		get_clocks();
88 	return gd->mem_clk;
89 }
90