Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Marvell Kirkwood SoC clocks |
| 3 | * |
| 4 | * Copyright (C) 2012 Marvell |
| 5 | * |
| 6 | * Gregory CLEMENT <gregory.clement@free-electrons.com> |
| 7 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> |
| 8 | * Andrew Lunn <andrew@lunn.ch> |
| 9 | * |
| 10 | * This file is licensed under the terms of the GNU General Public |
| 11 | * License version 2. This program is licensed "as is" without any |
| 12 | * warranty of any kind, whether express or implied. |
| 13 | */ |
| 14 | |
| 15 | #include <linux/kernel.h> |
| 16 | #include <linux/clk-provider.h> |
| 17 | #include <linux/io.h> |
| 18 | #include <linux/of.h> |
| 19 | #include "common.h" |
| 20 | |
| 21 | /* |
| 22 | * Core Clocks |
| 23 | * |
| 24 | * Kirkwood PLL sample-at-reset configuration |
| 25 | * (6180 has different SAR layout than other Kirkwood SoCs) |
| 26 | * |
| 27 | * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282) |
| 28 | * 4 = 600 MHz |
| 29 | * 6 = 800 MHz |
| 30 | * 7 = 1000 MHz |
| 31 | * 9 = 1200 MHz |
| 32 | * 12 = 1500 MHz |
| 33 | * 13 = 1600 MHz |
| 34 | * 14 = 1800 MHz |
| 35 | * 15 = 2000 MHz |
| 36 | * others reserved. |
| 37 | * |
| 38 | * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282) |
| 39 | * 1 = (1/2) * CPU |
| 40 | * 3 = (1/3) * CPU |
| 41 | * 5 = (1/4) * CPU |
| 42 | * others reserved. |
| 43 | * |
| 44 | * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282) |
| 45 | * 2 = (1/2) * CPU |
| 46 | * 4 = (1/3) * CPU |
| 47 | * 6 = (1/4) * CPU |
| 48 | * 7 = (2/9) * CPU |
| 49 | * 8 = (1/5) * CPU |
| 50 | * 9 = (1/6) * CPU |
| 51 | * others reserved. |
| 52 | * |
| 53 | * SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only) |
| 54 | * 5 = [CPU = 600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU] |
| 55 | * 6 = [CPU = 800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU] |
| 56 | * 7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU] |
| 57 | * others reserved. |
| 58 | * |
| 59 | * SAR0[21] : TCLK frequency |
| 60 | * 0 = 200 MHz |
| 61 | * 1 = 166 MHz |
| 62 | * others reserved. |
| 63 | */ |
| 64 | |
| 65 | #define SAR_KIRKWOOD_CPU_FREQ(x) \ |
| 66 | (((x & (1 << 1)) >> 1) | \ |
| 67 | ((x & (1 << 22)) >> 21) | \ |
| 68 | ((x & (3 << 3)) >> 1)) |
| 69 | #define SAR_KIRKWOOD_L2_RATIO(x) \ |
| 70 | (((x & (3 << 9)) >> 9) | \ |
| 71 | (((x & (1 << 19)) >> 17))) |
| 72 | #define SAR_KIRKWOOD_DDR_RATIO 5 |
| 73 | #define SAR_KIRKWOOD_DDR_RATIO_MASK 0xf |
| 74 | #define SAR_MV88F6180_CLK 2 |
| 75 | #define SAR_MV88F6180_CLK_MASK 0x7 |
| 76 | #define SAR_KIRKWOOD_TCLK_FREQ 21 |
| 77 | #define SAR_KIRKWOOD_TCLK_FREQ_MASK 0x1 |
| 78 | |
| 79 | enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR }; |
| 80 | |
Sachin Kamat | 847b1c0 | 2013-08-12 14:44:05 +0530 | [diff] [blame] | 81 | static const struct coreclk_ratio kirkwood_coreclk_ratios[] __initconst = { |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 82 | { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", }, |
| 83 | { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", } |
| 84 | }; |
| 85 | |
| 86 | static u32 __init kirkwood_get_tclk_freq(void __iomem *sar) |
| 87 | { |
| 88 | u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) & |
| 89 | SAR_KIRKWOOD_TCLK_FREQ_MASK; |
| 90 | return (opt) ? 166666667 : 200000000; |
| 91 | } |
| 92 | |
Sachin Kamat | 847b1c0 | 2013-08-12 14:44:05 +0530 | [diff] [blame] | 93 | static const u32 kirkwood_cpu_freqs[] __initconst = { |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 94 | 0, 0, 0, 0, |
| 95 | 600000000, |
| 96 | 0, |
| 97 | 800000000, |
| 98 | 1000000000, |
| 99 | 0, |
| 100 | 1200000000, |
| 101 | 0, 0, |
| 102 | 1500000000, |
| 103 | 1600000000, |
| 104 | 1800000000, |
| 105 | 2000000000 |
| 106 | }; |
| 107 | |
| 108 | static u32 __init kirkwood_get_cpu_freq(void __iomem *sar) |
| 109 | { |
| 110 | u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar)); |
| 111 | return kirkwood_cpu_freqs[opt]; |
| 112 | } |
| 113 | |
Sachin Kamat | 847b1c0 | 2013-08-12 14:44:05 +0530 | [diff] [blame] | 114 | static const int kirkwood_cpu_l2_ratios[8][2] __initconst = { |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 115 | { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 }, |
| 116 | { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 } |
| 117 | }; |
| 118 | |
Sachin Kamat | 847b1c0 | 2013-08-12 14:44:05 +0530 | [diff] [blame] | 119 | static const int kirkwood_cpu_ddr_ratios[16][2] __initconst = { |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 120 | { 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 }, |
| 121 | { 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 }, |
| 122 | { 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 }, |
| 123 | { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 } |
| 124 | }; |
| 125 | |
| 126 | static void __init kirkwood_get_clk_ratio( |
| 127 | void __iomem *sar, int id, int *mult, int *div) |
| 128 | { |
| 129 | switch (id) { |
| 130 | case KIRKWOOD_CPU_TO_L2: |
| 131 | { |
| 132 | u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar)); |
| 133 | *mult = kirkwood_cpu_l2_ratios[opt][0]; |
| 134 | *div = kirkwood_cpu_l2_ratios[opt][1]; |
| 135 | break; |
| 136 | } |
| 137 | case KIRKWOOD_CPU_TO_DDR: |
| 138 | { |
| 139 | u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) & |
| 140 | SAR_KIRKWOOD_DDR_RATIO_MASK; |
| 141 | *mult = kirkwood_cpu_ddr_ratios[opt][0]; |
| 142 | *div = kirkwood_cpu_ddr_ratios[opt][1]; |
| 143 | break; |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | |
Sachin Kamat | 847b1c0 | 2013-08-12 14:44:05 +0530 | [diff] [blame] | 148 | static const u32 mv88f6180_cpu_freqs[] __initconst = { |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 149 | 0, 0, 0, 0, 0, |
| 150 | 600000000, |
| 151 | 800000000, |
| 152 | 1000000000 |
| 153 | }; |
| 154 | |
| 155 | static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar) |
| 156 | { |
| 157 | u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK; |
| 158 | return mv88f6180_cpu_freqs[opt]; |
| 159 | } |
| 160 | |
Sachin Kamat | 847b1c0 | 2013-08-12 14:44:05 +0530 | [diff] [blame] | 161 | static const int mv88f6180_cpu_ddr_ratios[8][2] __initconst = { |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 162 | { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, |
| 163 | { 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 } |
| 164 | }; |
| 165 | |
| 166 | static void __init mv88f6180_get_clk_ratio( |
| 167 | void __iomem *sar, int id, int *mult, int *div) |
| 168 | { |
| 169 | switch (id) { |
| 170 | case KIRKWOOD_CPU_TO_L2: |
| 171 | { |
| 172 | /* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */ |
| 173 | *mult = 1; |
| 174 | *div = 2; |
| 175 | break; |
| 176 | } |
| 177 | case KIRKWOOD_CPU_TO_DDR: |
| 178 | { |
| 179 | u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & |
| 180 | SAR_MV88F6180_CLK_MASK; |
| 181 | *mult = mv88f6180_cpu_ddr_ratios[opt][0]; |
| 182 | *div = mv88f6180_cpu_ddr_ratios[opt][1]; |
| 183 | break; |
| 184 | } |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | static const struct coreclk_soc_desc kirkwood_coreclks = { |
| 189 | .get_tclk_freq = kirkwood_get_tclk_freq, |
| 190 | .get_cpu_freq = kirkwood_get_cpu_freq, |
| 191 | .get_clk_ratio = kirkwood_get_clk_ratio, |
| 192 | .ratios = kirkwood_coreclk_ratios, |
| 193 | .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios), |
| 194 | }; |
| 195 | |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 196 | static const struct coreclk_soc_desc mv88f6180_coreclks = { |
| 197 | .get_tclk_freq = kirkwood_get_tclk_freq, |
| 198 | .get_cpu_freq = mv88f6180_get_cpu_freq, |
| 199 | .get_clk_ratio = mv88f6180_get_clk_ratio, |
| 200 | .ratios = kirkwood_coreclk_ratios, |
| 201 | .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios), |
| 202 | }; |
| 203 | |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 204 | /* |
| 205 | * Clock Gating Control |
| 206 | */ |
| 207 | |
Sachin Kamat | 847b1c0 | 2013-08-12 14:44:05 +0530 | [diff] [blame] | 208 | static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 209 | { "ge0", NULL, 0, 0 }, |
| 210 | { "pex0", NULL, 2, 0 }, |
| 211 | { "usb0", NULL, 3, 0 }, |
| 212 | { "sdio", NULL, 4, 0 }, |
| 213 | { "tsu", NULL, 5, 0 }, |
| 214 | { "runit", NULL, 7, 0 }, |
| 215 | { "xor0", NULL, 8, 0 }, |
| 216 | { "audio", NULL, 9, 0 }, |
| 217 | { "powersave", "cpuclk", 11, 0 }, |
| 218 | { "sata0", NULL, 14, 0 }, |
| 219 | { "sata1", NULL, 15, 0 }, |
| 220 | { "xor1", NULL, 16, 0 }, |
| 221 | { "crypto", NULL, 17, 0 }, |
| 222 | { "pex1", NULL, 18, 0 }, |
| 223 | { "ge1", NULL, 19, 0 }, |
| 224 | { "tdm", NULL, 20, 0 }, |
| 225 | { } |
| 226 | }; |
| 227 | |
Sebastian Hesselbarth | 58d516a | 2014-01-25 19:19:10 +0100 | [diff] [blame] | 228 | static void __init kirkwood_clk_init(struct device_node *np) |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 229 | { |
Sebastian Hesselbarth | 58d516a | 2014-01-25 19:19:10 +0100 | [diff] [blame] | 230 | struct device_node *cgnp = |
| 231 | of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock"); |
| 232 | |
| 233 | |
| 234 | if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock")) |
| 235 | mvebu_coreclk_setup(np, &mv88f6180_coreclks); |
| 236 | else |
| 237 | mvebu_coreclk_setup(np, &kirkwood_coreclks); |
| 238 | |
| 239 | if (cgnp) |
| 240 | mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); |
Sebastian Hesselbarth | e89406c | 2013-05-11 03:08:04 +0200 | [diff] [blame] | 241 | } |
Sebastian Hesselbarth | 58d516a | 2014-01-25 19:19:10 +0100 | [diff] [blame] | 242 | CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", |
| 243 | kirkwood_clk_init); |
| 244 | CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock", |
| 245 | kirkwood_clk_init); |