source: src/linux/universal/linux-3.2/arch/mips/lantiq/xway/clk-xway.c @ 18171

Last change on this file since 18171 was 18171, checked in by BrainSlayer, 17 months ago

this kernel will be maintained for all targets, so target specific kernel trees will not be neccessary anymore in future

File size: 5.4 KB
Line 
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
20static 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
68static unsigned int ltq_get_pll0_fdiv(void);
69
70static 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
103static 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
112static 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
121static 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
130static 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
140static 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
151static 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
165static 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
172unsigned 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}
188EXPORT_SYMBOL(ltq_get_io_region_clock);
189
190unsigned 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}
198EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
199
200unsigned 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}
213EXPORT_SYMBOL(ltq_get_cpu_hz);
214
215unsigned 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}
223EXPORT_SYMBOL(ltq_get_fpi_hz);
Note: See TracBrowser for help on using the repository browser.