| John Crispin | 8ec6d93 | 2011-03-30 09:27:48 +0200 | [diff] [blame] | 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/module.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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 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); |