1 /* 2 * Marvell Armada 370 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 25 #define SARL 0 /* Low part [0:31] */ 26 #define SARL_A370_PCLK_FREQ_OPT 11 27 #define SARL_A370_PCLK_FREQ_OPT_MASK 0xF 28 #define SARL_A370_FAB_FREQ_OPT 15 29 #define SARL_A370_FAB_FREQ_OPT_MASK 0x1F 30 #define SARL_A370_TCLK_FREQ_OPT 20 31 #define SARL_A370_TCLK_FREQ_OPT_MASK 0x1 32 33 enum { A370_CPU_TO_NBCLK, A370_CPU_TO_HCLK, A370_CPU_TO_DRAMCLK }; 34 35 static const struct coreclk_ratio a370_coreclk_ratios[] __initconst = { 36 { .id = A370_CPU_TO_NBCLK, .name = "nbclk" }, 37 { .id = A370_CPU_TO_HCLK, .name = "hclk" }, 38 { .id = A370_CPU_TO_DRAMCLK, .name = "dramclk" }, 39 }; 40 41 static const u32 a370_tclk_freqs[] __initconst = { 42 166000000, 43 200000000, 44 }; 45 46 static u32 __init a370_get_tclk_freq(void __iomem *sar) 47 { 48 u8 tclk_freq_select = 0; 49 50 tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) & 51 SARL_A370_TCLK_FREQ_OPT_MASK); 52 return a370_tclk_freqs[tclk_freq_select]; 53 } 54 55 static const u32 a370_cpu_freqs[] __initconst = { 56 400000000, 57 533000000, 58 667000000, 59 800000000, 60 1000000000, 61 1067000000, 62 1200000000, 63 }; 64 65 static u32 __init a370_get_cpu_freq(void __iomem *sar) 66 { 67 u32 cpu_freq; 68 u8 cpu_freq_select = 0; 69 70 cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) & 71 SARL_A370_PCLK_FREQ_OPT_MASK); 72 if (cpu_freq_select >= ARRAY_SIZE(a370_cpu_freqs)) { 73 pr_err("CPU freq select unsupported %d\n", cpu_freq_select); 74 cpu_freq = 0; 75 } else 76 cpu_freq = a370_cpu_freqs[cpu_freq_select]; 77 78 return cpu_freq; 79 } 80 81 static const int a370_nbclk_ratios[32][2] __initconst = { 82 {0, 1}, {1, 2}, {2, 2}, {2, 2}, 83 {1, 2}, {1, 2}, {1, 1}, {2, 3}, 84 {0, 1}, {1, 2}, {2, 4}, {0, 1}, 85 {1, 2}, {0, 1}, {0, 1}, {2, 2}, 86 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 87 {2, 3}, {0, 1}, {0, 1}, {0, 1}, 88 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 89 {0, 1}, {0, 1}, {0, 1}, {0, 1}, 90 }; 91 92 static const int a370_hclk_ratios[32][2] __initconst = { 93 {0, 1}, {1, 2}, {2, 6}, {2, 3}, 94 {1, 3}, {1, 4}, {1, 2}, {2, 6}, 95 {0, 1}, {1, 6}, {2, 10}, {0, 1}, 96 {1, 4}, {0, 1}, {0, 1}, {2, 5}, 97 {0, 1}, {0, 1}, {0, 1}, {1, 2}, 98 {2, 6}, {0, 1}, {0, 1}, {0, 1}, 99 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 100 {0, 1}, {0, 1}, {0, 1}, {0, 1}, 101 }; 102 103 static const int a370_dramclk_ratios[32][2] __initconst = { 104 {0, 1}, {1, 2}, {2, 3}, {2, 3}, 105 {1, 3}, {1, 2}, {1, 2}, {2, 6}, 106 {0, 1}, {1, 3}, {2, 5}, {0, 1}, 107 {1, 4}, {0, 1}, {0, 1}, {2, 5}, 108 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 109 {2, 3}, {0, 1}, {0, 1}, {0, 1}, 110 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 111 {0, 1}, {0, 1}, {0, 1}, {0, 1}, 112 }; 113 114 static void __init a370_get_clk_ratio( 115 void __iomem *sar, int id, int *mult, int *div) 116 { 117 u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) & 118 SARL_A370_FAB_FREQ_OPT_MASK); 119 120 switch (id) { 121 case A370_CPU_TO_NBCLK: 122 *mult = a370_nbclk_ratios[opt][0]; 123 *div = a370_nbclk_ratios[opt][1]; 124 break; 125 case A370_CPU_TO_HCLK: 126 *mult = a370_hclk_ratios[opt][0]; 127 *div = a370_hclk_ratios[opt][1]; 128 break; 129 case A370_CPU_TO_DRAMCLK: 130 *mult = a370_dramclk_ratios[opt][0]; 131 *div = a370_dramclk_ratios[opt][1]; 132 break; 133 } 134 } 135 136 static const struct coreclk_soc_desc a370_coreclks = { 137 .get_tclk_freq = a370_get_tclk_freq, 138 .get_cpu_freq = a370_get_cpu_freq, 139 .get_clk_ratio = a370_get_clk_ratio, 140 .ratios = a370_coreclk_ratios, 141 .num_ratios = ARRAY_SIZE(a370_coreclk_ratios), 142 }; 143 144 static void __init a370_coreclk_init(struct device_node *np) 145 { 146 mvebu_coreclk_setup(np, &a370_coreclks); 147 } 148 CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock", 149 a370_coreclk_init); 150 151 /* 152 * Clock Gating Control 153 */ 154 155 static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = { 156 { "audio", NULL, 0, 0 }, 157 { "pex0_en", NULL, 1, 0 }, 158 { "pex1_en", NULL, 2, 0 }, 159 { "ge1", NULL, 3, 0 }, 160 { "ge0", NULL, 4, 0 }, 161 { "pex0", "pex0_en", 5, 0 }, 162 { "pex1", "pex1_en", 9, 0 }, 163 { "sata0", NULL, 15, 0 }, 164 { "sdio", NULL, 17, 0 }, 165 { "tdm", NULL, 25, 0 }, 166 { "ddr", NULL, 28, CLK_IGNORE_UNUSED }, 167 { "sata1", NULL, 30, 0 }, 168 { } 169 }; 170 171 static void __init a370_clk_gating_init(struct device_node *np) 172 { 173 mvebu_clk_gating_setup(np, a370_gating_desc); 174 } 175 CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock", 176 a370_clk_gating_init); 177