0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/kernel.h>
0014 #include <linux/slab.h>
0015 #include <linux/clk-provider.h>
0016 #include <linux/io.h>
0017 #include <linux/of.h>
0018 #include <linux/of_address.h>
0019 #include "common.h"
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 #define SAR_KIRKWOOD_CPU_FREQ(x) \
0066 (((x & (1 << 1)) >> 1) | \
0067 ((x & (1 << 22)) >> 21) | \
0068 ((x & (3 << 3)) >> 1))
0069 #define SAR_KIRKWOOD_L2_RATIO(x) \
0070 (((x & (3 << 9)) >> 9) | \
0071 (((x & (1 << 19)) >> 17)))
0072 #define SAR_KIRKWOOD_DDR_RATIO 5
0073 #define SAR_KIRKWOOD_DDR_RATIO_MASK 0xf
0074 #define SAR_MV88F6180_CLK 2
0075 #define SAR_MV88F6180_CLK_MASK 0x7
0076 #define SAR_KIRKWOOD_TCLK_FREQ 21
0077 #define SAR_KIRKWOOD_TCLK_FREQ_MASK 0x1
0078
0079 enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
0080
0081 static const struct coreclk_ratio kirkwood_coreclk_ratios[] __initconst = {
0082 { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
0083 { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
0084 };
0085
0086 static u32 __init kirkwood_get_tclk_freq(void __iomem *sar)
0087 {
0088 u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) &
0089 SAR_KIRKWOOD_TCLK_FREQ_MASK;
0090 return (opt) ? 166666667 : 200000000;
0091 }
0092
0093 static const u32 kirkwood_cpu_freqs[] __initconst = {
0094 0, 0, 0, 0,
0095 600000000,
0096 0,
0097 800000000,
0098 1000000000,
0099 0,
0100 1200000000,
0101 0, 0,
0102 1500000000,
0103 1600000000,
0104 1800000000,
0105 2000000000
0106 };
0107
0108 static u32 __init kirkwood_get_cpu_freq(void __iomem *sar)
0109 {
0110 u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar));
0111 return kirkwood_cpu_freqs[opt];
0112 }
0113
0114 static const int kirkwood_cpu_l2_ratios[8][2] __initconst = {
0115 { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
0116 { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
0117 };
0118
0119 static const int kirkwood_cpu_ddr_ratios[16][2] __initconst = {
0120 { 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
0121 { 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 },
0122 { 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 },
0123 { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }
0124 };
0125
0126 static void __init kirkwood_get_clk_ratio(
0127 void __iomem *sar, int id, int *mult, int *div)
0128 {
0129 switch (id) {
0130 case KIRKWOOD_CPU_TO_L2:
0131 {
0132 u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar));
0133 *mult = kirkwood_cpu_l2_ratios[opt][0];
0134 *div = kirkwood_cpu_l2_ratios[opt][1];
0135 break;
0136 }
0137 case KIRKWOOD_CPU_TO_DDR:
0138 {
0139 u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) &
0140 SAR_KIRKWOOD_DDR_RATIO_MASK;
0141 *mult = kirkwood_cpu_ddr_ratios[opt][0];
0142 *div = kirkwood_cpu_ddr_ratios[opt][1];
0143 break;
0144 }
0145 }
0146 }
0147
0148 static const u32 mv88f6180_cpu_freqs[] __initconst = {
0149 0, 0, 0, 0, 0,
0150 600000000,
0151 800000000,
0152 1000000000
0153 };
0154
0155 static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar)
0156 {
0157 u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK;
0158 return mv88f6180_cpu_freqs[opt];
0159 }
0160
0161 static const int mv88f6180_cpu_ddr_ratios[8][2] __initconst = {
0162 { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
0163 { 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 }
0164 };
0165
0166 static void __init mv88f6180_get_clk_ratio(
0167 void __iomem *sar, int id, int *mult, int *div)
0168 {
0169 switch (id) {
0170 case KIRKWOOD_CPU_TO_L2:
0171 {
0172
0173 *mult = 1;
0174 *div = 2;
0175 break;
0176 }
0177 case KIRKWOOD_CPU_TO_DDR:
0178 {
0179 u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) &
0180 SAR_MV88F6180_CLK_MASK;
0181 *mult = mv88f6180_cpu_ddr_ratios[opt][0];
0182 *div = mv88f6180_cpu_ddr_ratios[opt][1];
0183 break;
0184 }
0185 }
0186 }
0187
0188 static u32 __init mv98dx1135_get_tclk_freq(void __iomem *sar)
0189 {
0190 return 166666667;
0191 }
0192
0193 static const struct coreclk_soc_desc kirkwood_coreclks = {
0194 .get_tclk_freq = kirkwood_get_tclk_freq,
0195 .get_cpu_freq = kirkwood_get_cpu_freq,
0196 .get_clk_ratio = kirkwood_get_clk_ratio,
0197 .ratios = kirkwood_coreclk_ratios,
0198 .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
0199 };
0200
0201 static const struct coreclk_soc_desc mv88f6180_coreclks = {
0202 .get_tclk_freq = kirkwood_get_tclk_freq,
0203 .get_cpu_freq = mv88f6180_get_cpu_freq,
0204 .get_clk_ratio = mv88f6180_get_clk_ratio,
0205 .ratios = kirkwood_coreclk_ratios,
0206 .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
0207 };
0208
0209 static const struct coreclk_soc_desc mv98dx1135_coreclks = {
0210 .get_tclk_freq = mv98dx1135_get_tclk_freq,
0211 .get_cpu_freq = kirkwood_get_cpu_freq,
0212 .get_clk_ratio = kirkwood_get_clk_ratio,
0213 .ratios = kirkwood_coreclk_ratios,
0214 .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
0215 };
0216
0217
0218
0219
0220
0221 static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
0222 { "ge0", NULL, 0, 0 },
0223 { "pex0", NULL, 2, 0 },
0224 { "usb0", NULL, 3, 0 },
0225 { "sdio", NULL, 4, 0 },
0226 { "tsu", NULL, 5, 0 },
0227 { "runit", NULL, 7, 0 },
0228 { "xor0", NULL, 8, 0 },
0229 { "audio", NULL, 9, 0 },
0230 { "sata0", NULL, 14, 0 },
0231 { "sata1", NULL, 15, 0 },
0232 { "xor1", NULL, 16, 0 },
0233 { "crypto", NULL, 17, 0 },
0234 { "pex1", NULL, 18, 0 },
0235 { "ge1", NULL, 19, 0 },
0236 { "tdm", NULL, 20, 0 },
0237 { }
0238 };
0239
0240
0241
0242
0243
0244
0245 struct clk_muxing_soc_desc {
0246 const char *name;
0247 const char **parents;
0248 int num_parents;
0249 int shift;
0250 int width;
0251 unsigned long flags;
0252 };
0253
0254 struct clk_muxing_ctrl {
0255 spinlock_t *lock;
0256 struct clk **muxes;
0257 int num_muxes;
0258 };
0259
0260 static const char *powersave_parents[] = {
0261 "cpuclk",
0262 "ddrclk",
0263 };
0264
0265 static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = {
0266 { "powersave", powersave_parents, ARRAY_SIZE(powersave_parents),
0267 11, 1, 0 },
0268 { }
0269 };
0270
0271 static struct clk *clk_muxing_get_src(
0272 struct of_phandle_args *clkspec, void *data)
0273 {
0274 struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data;
0275 int n;
0276
0277 if (clkspec->args_count < 1)
0278 return ERR_PTR(-EINVAL);
0279
0280 for (n = 0; n < ctrl->num_muxes; n++) {
0281 struct clk_mux *mux =
0282 to_clk_mux(__clk_get_hw(ctrl->muxes[n]));
0283 if (clkspec->args[0] == mux->shift)
0284 return ctrl->muxes[n];
0285 }
0286 return ERR_PTR(-ENODEV);
0287 }
0288
0289 static void __init kirkwood_clk_muxing_setup(struct device_node *np,
0290 const struct clk_muxing_soc_desc *desc)
0291 {
0292 struct clk_muxing_ctrl *ctrl;
0293 void __iomem *base;
0294 int n;
0295
0296 base = of_iomap(np, 0);
0297 if (WARN_ON(!base))
0298 return;
0299
0300 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
0301 if (WARN_ON(!ctrl))
0302 goto ctrl_out;
0303
0304
0305 ctrl->lock = &ctrl_gating_lock;
0306
0307
0308 for (n = 0; desc[n].name;)
0309 n++;
0310
0311 ctrl->num_muxes = n;
0312 ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *),
0313 GFP_KERNEL);
0314 if (WARN_ON(!ctrl->muxes))
0315 goto muxes_out;
0316
0317 for (n = 0; n < ctrl->num_muxes; n++) {
0318 ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name,
0319 desc[n].parents, desc[n].num_parents,
0320 desc[n].flags, base, desc[n].shift,
0321 desc[n].width, desc[n].flags, ctrl->lock);
0322 WARN_ON(IS_ERR(ctrl->muxes[n]));
0323 }
0324
0325 of_clk_add_provider(np, clk_muxing_get_src, ctrl);
0326
0327 return;
0328 muxes_out:
0329 kfree(ctrl);
0330 ctrl_out:
0331 iounmap(base);
0332 }
0333
0334 static void __init kirkwood_clk_init(struct device_node *np)
0335 {
0336 struct device_node *cgnp =
0337 of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
0338
0339
0340 if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
0341 mvebu_coreclk_setup(np, &mv88f6180_coreclks);
0342 else if (of_device_is_compatible(np, "marvell,mv98dx1135-core-clock"))
0343 mvebu_coreclk_setup(np, &mv98dx1135_coreclks);
0344 else
0345 mvebu_coreclk_setup(np, &kirkwood_coreclks);
0346
0347 if (cgnp) {
0348 mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
0349 kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc);
0350
0351 of_node_put(cgnp);
0352 }
0353 }
0354 CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
0355 kirkwood_clk_init);
0356 CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
0357 kirkwood_clk_init);
0358 CLK_OF_DECLARE(98dx1135_clk, "marvell,mv98dx1135-core-clock",
0359 kirkwood_clk_init);