1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Marvell Armada 370 SoC clocks 4 * 5 * Copyright (C) 2012 Marvell 6 * 7 * Gregory CLEMENT <gregory.clement@free-electrons.com> 8 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 9 * Andrew Lunn <andrew@lunn.ch> 10 * 11 */ 12 13 #include <linux/kernel.h> 14 #include <linux/clk-provider.h> 15 #include <linux/io.h> 16 #include <linux/of.h> 17 #include "common.h" 18 19 /* 20 * Core Clocks 21 */ 22 23 #define SARL 0 /* Low part [0:31] */ 24 #define SARL_A370_SSCG_ENABLE BIT(10) 25 #define SARL_A370_PCLK_FREQ_OPT 11 26 #define SARL_A370_PCLK_FREQ_OPT_MASK 0xF 27 #define SARL_A370_FAB_FREQ_OPT 15 28 #define SARL_A370_FAB_FREQ_OPT_MASK 0x1F 29 #define SARL_A370_TCLK_FREQ_OPT 20 30 #define SARL_A370_TCLK_FREQ_OPT_MASK 0x1 31 32 enum { A370_CPU_TO_NBCLK, A370_CPU_TO_HCLK, A370_CPU_TO_DRAMCLK }; 33 34 static const struct coreclk_ratio a370_coreclk_ratios[] __initconst = { 35 { .id = A370_CPU_TO_NBCLK, .name = "nbclk" }, 36 { .id = A370_CPU_TO_HCLK, .name = "hclk" }, 37 { .id = A370_CPU_TO_DRAMCLK, .name = "dramclk" }, 38 }; 39 40 static const u32 a370_tclk_freqs[] __initconst = { 41 166000000, 42 200000000, 43 }; 44 45 static u32 __init a370_get_tclk_freq(void __iomem *sar) 46 { 47 u8 tclk_freq_select = 0; 48 49 tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) & 50 SARL_A370_TCLK_FREQ_OPT_MASK); 51 return a370_tclk_freqs[tclk_freq_select]; 52 } 53 54 static const u32 a370_cpu_freqs[] __initconst = { 55 400000000, 56 533000000, 57 667000000, 58 800000000, 59 1000000000, 60 1067000000, 61 1200000000, 62 }; 63 64 static u32 __init a370_get_cpu_freq(void __iomem *sar) 65 { 66 u32 cpu_freq; 67 u8 cpu_freq_select = 0; 68 69 cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) & 70 SARL_A370_PCLK_FREQ_OPT_MASK); 71 if (cpu_freq_select >= ARRAY_SIZE(a370_cpu_freqs)) { 72 pr_err("CPU freq select unsupported %d\n", cpu_freq_select); 73 cpu_freq = 0; 74 } else 75 cpu_freq = a370_cpu_freqs[cpu_freq_select]; 76 77 return cpu_freq; 78 } 79 80 static const int a370_nbclk_ratios[32][2] __initconst = { 81 {0, 1}, {1, 2}, {2, 2}, {2, 2}, 82 {1, 2}, {1, 2}, {1, 1}, {2, 3}, 83 {0, 1}, {1, 2}, {2, 4}, {0, 1}, 84 {1, 2}, {0, 1}, {0, 1}, {2, 2}, 85 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 86 {2, 3}, {0, 1}, {0, 1}, {0, 1}, 87 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 88 {0, 1}, {0, 1}, {0, 1}, {0, 1}, 89 }; 90 91 static const int a370_hclk_ratios[32][2] __initconst = { 92 {0, 1}, {1, 2}, {2, 6}, {2, 3}, 93 {1, 3}, {1, 4}, {1, 2}, {2, 6}, 94 {0, 1}, {1, 6}, {2, 10}, {0, 1}, 95 {1, 4}, {0, 1}, {0, 1}, {2, 5}, 96 {0, 1}, {0, 1}, {0, 1}, {1, 2}, 97 {2, 6}, {0, 1}, {0, 1}, {0, 1}, 98 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 99 {0, 1}, {0, 1}, {0, 1}, {0, 1}, 100 }; 101 102 static const int a370_dramclk_ratios[32][2] __initconst = { 103 {0, 1}, {1, 2}, {2, 3}, {2, 3}, 104 {1, 3}, {1, 2}, {1, 2}, {2, 6}, 105 {0, 1}, {1, 3}, {2, 5}, {0, 1}, 106 {1, 4}, {0, 1}, {0, 1}, {2, 5}, 107 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 108 {2, 3}, {0, 1}, {0, 1}, {0, 1}, 109 {0, 1}, {0, 1}, {0, 1}, {1, 1}, 110 {0, 1}, {0, 1}, {0, 1}, {0, 1}, 111 }; 112 113 static void __init a370_get_clk_ratio( 114 void __iomem *sar, int id, int *mult, int *div) 115 { 116 u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) & 117 SARL_A370_FAB_FREQ_OPT_MASK); 118 119 switch (id) { 120 case A370_CPU_TO_NBCLK: 121 *mult = a370_nbclk_ratios[opt][0]; 122 *div = a370_nbclk_ratios[opt][1]; 123 break; 124 case A370_CPU_TO_HCLK: 125 *mult = a370_hclk_ratios[opt][0]; 126 *div = a370_hclk_ratios[opt][1]; 127 break; 128 case A370_CPU_TO_DRAMCLK: 129 *mult = a370_dramclk_ratios[opt][0]; 130 *div = a370_dramclk_ratios[opt][1]; 131 break; 132 } 133 } 134 135 static bool a370_is_sscg_enabled(void __iomem *sar) 136 { 137 return !(readl(sar) & SARL_A370_SSCG_ENABLE); 138 } 139 140 static const struct coreclk_soc_desc a370_coreclks = { 141 .get_tclk_freq = a370_get_tclk_freq, 142 .get_cpu_freq = a370_get_cpu_freq, 143 .get_clk_ratio = a370_get_clk_ratio, 144 .is_sscg_enabled = a370_is_sscg_enabled, 145 .fix_sscg_deviation = kirkwood_fix_sscg_deviation, 146 .ratios = a370_coreclk_ratios, 147 .num_ratios = ARRAY_SIZE(a370_coreclk_ratios), 148 }; 149 150 /* 151 * Clock Gating Control 152 */ 153 154 static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = { 155 { "audio", NULL, 0, 0 }, 156 { "pex0_en", NULL, 1, 0 }, 157 { "pex1_en", NULL, 2, 0 }, 158 { "ge1", NULL, 3, 0 }, 159 { "ge0", NULL, 4, 0 }, 160 { "pex0", "pex0_en", 5, 0 }, 161 { "pex1", "pex1_en", 9, 0 }, 162 { "sata0", NULL, 15, 0 }, 163 { "sdio", NULL, 17, 0 }, 164 { "crypto", NULL, 23, CLK_IGNORE_UNUSED }, 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_init(struct device_node *np) 172 { 173 struct device_node *cgnp = 174 of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock"); 175 176 mvebu_coreclk_setup(np, &a370_coreclks); 177 178 if (cgnp) 179 mvebu_clk_gating_setup(cgnp, a370_gating_desc); 180 } 181 CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init); 182 183