• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  This program is free software; you can redistribute it and/or modify it
3  *  under the terms of the GNU General Public License version 2 as published
4  *  by the Free Software Foundation.
5  *
6  *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
7  */
8 
9 #include <linux/io.h>
10 #include <linux/export.h>
11 #include <linux/init.h>
12 #include <linux/clk.h>
13 
14 #include <asm/time.h>
15 #include <asm/irq.h>
16 #include <asm/div64.h>
17 
18 #include <lantiq_soc.h>
19 
20 static unsigned int ltq_ram_clocks[] = {
21 	CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
22 #define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3]
23 
24 #define BASIC_FREQUENCY_1	35328000
25 #define BASIC_FREQUENCY_2	36000000
26 #define BASIS_REQUENCY_USB	12000000
27 
28 #define GET_BITS(x, msb, lsb) \
29 	(((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
30 
31 #define LTQ_CGU_PLL0_CFG	0x0004
32 #define LTQ_CGU_PLL1_CFG	0x0008
33 #define LTQ_CGU_PLL2_CFG	0x000C
34 #define LTQ_CGU_SYS		0x0010
35 #define LTQ_CGU_UPDATE		0x0014
36 #define LTQ_CGU_IF_CLK		0x0018
37 #define LTQ_CGU_OSC_CON		0x001C
38 #define LTQ_CGU_SMD		0x0020
39 #define LTQ_CGU_CT1SR		0x0028
40 #define LTQ_CGU_CT2SR		0x002C
41 #define LTQ_CGU_PCMCR		0x0030
42 #define LTQ_CGU_PCI_CR		0x0034
43 #define LTQ_CGU_PD_PC		0x0038
44 #define LTQ_CGU_FMR		0x003C
45 
46 #define CGU_PLL0_PHASE_DIVIDER_ENABLE	\
47 	(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))
48 #define CGU_PLL0_BYPASS			\
49 	(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))
50 #define CGU_PLL0_CFG_DSMSEL		\
51 	(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))
52 #define CGU_PLL0_CFG_FRAC_EN		\
53 	(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))
54 #define CGU_PLL1_SRC			\
55 	(ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))
56 #define CGU_PLL2_PHASE_DIVIDER_ENABLE	\
57 	(ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))
58 #define CGU_SYS_FPI_SEL			(1 << 6)
59 #define CGU_SYS_DDR_SEL			0x3
60 #define CGU_PLL0_SRC			(1 << 29)
61 
62 #define CGU_PLL0_CFG_PLLK	GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17)
63 #define CGU_PLL0_CFG_PLLN	GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6)
64 #define CGU_PLL0_CFG_PLLM	GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2)
65 #define CGU_PLL2_SRC		GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17)
66 #define CGU_PLL2_CFG_INPUT_DIV	GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13)
67 
68 static unsigned int ltq_get_pll0_fdiv(void);
69 
get_input_clock(int pll)70 static inline unsigned int get_input_clock(int pll)
71 {
72 	switch (pll) {
73 	case 0:
74 		if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)
75 			return BASIS_REQUENCY_USB;
76 		else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
77 			return BASIC_FREQUENCY_1;
78 		else
79 			return BASIC_FREQUENCY_2;
80 	case 1:
81 		if (CGU_PLL1_SRC)
82 			return BASIS_REQUENCY_USB;
83 		else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
84 			return BASIC_FREQUENCY_1;
85 		else
86 			return BASIC_FREQUENCY_2;
87 	case 2:
88 		switch (CGU_PLL2_SRC) {
89 		case 0:
90 			return ltq_get_pll0_fdiv();
91 		case 1:
92 			return CGU_PLL2_PHASE_DIVIDER_ENABLE ?
93 				BASIC_FREQUENCY_1 :
94 				BASIC_FREQUENCY_2;
95 		case 2:
96 			return BASIS_REQUENCY_USB;
97 		}
98 	default:
99 		return 0;
100 	}
101 }
102 
cal_dsm(int pll,unsigned int num,unsigned int den)103 static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den)
104 {
105 	u64 res, clock = get_input_clock(pll);
106 
107 	res = num * clock;
108 	do_div(res, den);
109 	return res;
110 }
111 
mash_dsm(int pll,unsigned int M,unsigned int N,unsigned int K)112 static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N,
113 	unsigned int K)
114 {
115 	unsigned int num = ((N + 1) << 10) + K;
116 	unsigned int den = (M + 1) << 10;
117 
118 	return cal_dsm(pll, num, den);
119 }
120 
ssff_dsm_1(int pll,unsigned int M,unsigned int N,unsigned int K)121 static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N,
122 	unsigned int K)
123 {
124 	unsigned int num = ((N + 1) << 11) + K + 512;
125 	unsigned int den = (M + 1) << 11;
126 
127 	return cal_dsm(pll, num, den);
128 }
129 
ssff_dsm_2(int pll,unsigned int M,unsigned int N,unsigned int K)130 static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N,
131 	unsigned int K)
132 {
133 	unsigned int num = K >= 512 ?
134 		((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
135 	unsigned int den = (M + 1) << 12;
136 
137 	return cal_dsm(pll, num, den);
138 }
139 
dsm(int pll,unsigned int M,unsigned int N,unsigned int K,unsigned int dsmsel,unsigned int phase_div_en)140 static inline unsigned int dsm(int pll, unsigned int M, unsigned int N,
141 	unsigned int K, unsigned int dsmsel, unsigned int phase_div_en)
142 {
143 	if (!dsmsel)
144 		return mash_dsm(pll, M, N, K);
145 	else if (!phase_div_en)
146 		return mash_dsm(pll, M, N, K);
147 	else
148 		return ssff_dsm_2(pll, M, N, K);
149 }
150 
ltq_get_pll0_fosc(void)151 static inline unsigned int ltq_get_pll0_fosc(void)
152 {
153 	if (CGU_PLL0_BYPASS)
154 		return get_input_clock(0);
155 	else
156 		return !CGU_PLL0_CFG_FRAC_EN
157 			? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,
158 				CGU_PLL0_CFG_DSMSEL,
159 				CGU_PLL0_PHASE_DIVIDER_ENABLE)
160 			: dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,
161 				CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,
162 				CGU_PLL0_PHASE_DIVIDER_ENABLE);
163 }
164 
ltq_get_pll0_fdiv(void)165 static unsigned int ltq_get_pll0_fdiv(void)
166 {
167 	unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;
168 
169 	return (ltq_get_pll0_fosc() + (div >> 1)) / div;
170 }
171 
ltq_get_io_region_clock(void)172 unsigned int ltq_get_io_region_clock(void)
173 {
174 	unsigned int ret = ltq_get_pll0_fosc();
175 
176 	switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) {
177 	default:
178 	case 0:
179 		return (ret + 1) / 2;
180 	case 1:
181 		return (ret * 2 + 2) / 5;
182 	case 2:
183 		return (ret + 1) / 3;
184 	case 3:
185 		return (ret + 2) / 4;
186 	}
187 }
188 EXPORT_SYMBOL(ltq_get_io_region_clock);
189 
ltq_get_fpi_bus_clock(int fpi)190 unsigned int ltq_get_fpi_bus_clock(int fpi)
191 {
192 	unsigned int ret = ltq_get_io_region_clock();
193 
194 	if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))
195 		ret >>= 1;
196 	return ret;
197 }
198 EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
199 
ltq_get_cpu_hz(void)200 unsigned int ltq_get_cpu_hz(void)
201 {
202 	switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) {
203 	case 0:
204 		return CLOCK_333M;
205 	case 4:
206 		return DDR_HZ;
207 	case 8:
208 		return DDR_HZ << 1;
209 	default:
210 		return DDR_HZ >> 1;
211 	}
212 }
213 EXPORT_SYMBOL(ltq_get_cpu_hz);
214 
ltq_get_fpi_hz(void)215 unsigned int ltq_get_fpi_hz(void)
216 {
217 	unsigned int ddr_clock = DDR_HZ;
218 
219 	if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40)
220 		return ddr_clock >> 1;
221 	return ddr_clock;
222 }
223 EXPORT_SYMBOL(ltq_get_fpi_hz);
224