|
13 | 13 |
|
14 | 14 | #define ASPEED_NUM_CLKS 35
|
15 | 15 |
|
| 16 | +#define ASPEED_RESET_CTRL 0x04 |
| 17 | +#define ASPEED_CLK_SELECTION 0x08 |
| 18 | +#define ASPEED_CLK_STOP_CTRL 0x0c |
| 19 | +#define ASPEED_MPLL_PARAM 0x20 |
| 20 | +#define ASPEED_HPLL_PARAM 0x24 |
| 21 | +#define AST2500_HPLL_BYPASS_EN BIT(20) |
| 22 | +#define AST2400_HPLL_STRAPPED BIT(18) |
| 23 | +#define AST2400_HPLL_BYPASS_EN BIT(17) |
| 24 | +#define ASPEED_MISC_CTRL 0x2c |
| 25 | +#define UART_DIV13_EN BIT(12) |
16 | 26 | #define ASPEED_STRAP 0x70
|
| 27 | +#define CLKIN_25MHZ_EN BIT(23) |
| 28 | +#define AST2400_CLK_SOURCE_SEL BIT(18) |
| 29 | +#define ASPEED_CLK_SELECTION_2 0xd8 |
| 30 | + |
| 31 | +/* Globally visible clocks */ |
| 32 | +static DEFINE_SPINLOCK(aspeed_clk_lock); |
17 | 33 |
|
18 | 34 | /* Keeps track of all clocks */
|
19 | 35 | static struct clk_hw_onecell_data *aspeed_clk_data;
|
@@ -91,6 +107,160 @@ static const struct aspeed_gate_data aspeed_gates[] = {
|
91 | 107 | [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
|
92 | 108 | };
|
93 | 109 |
|
| 110 | +static const struct clk_div_table ast2400_div_table[] = { |
| 111 | + { 0x0, 2 }, |
| 112 | + { 0x1, 4 }, |
| 113 | + { 0x2, 6 }, |
| 114 | + { 0x3, 8 }, |
| 115 | + { 0x4, 10 }, |
| 116 | + { 0x5, 12 }, |
| 117 | + { 0x6, 14 }, |
| 118 | + { 0x7, 16 }, |
| 119 | + { 0 } |
| 120 | +}; |
| 121 | + |
| 122 | +static const struct clk_div_table ast2500_div_table[] = { |
| 123 | + { 0x0, 4 }, |
| 124 | + { 0x1, 8 }, |
| 125 | + { 0x2, 12 }, |
| 126 | + { 0x3, 16 }, |
| 127 | + { 0x4, 20 }, |
| 128 | + { 0x5, 24 }, |
| 129 | + { 0x6, 28 }, |
| 130 | + { 0x7, 32 }, |
| 131 | + { 0 } |
| 132 | +}; |
| 133 | + |
| 134 | +static struct clk_hw *aspeed_ast2400_calc_pll(const char *name, u32 val) |
| 135 | +{ |
| 136 | + unsigned int mult, div; |
| 137 | + |
| 138 | + if (val & AST2400_HPLL_BYPASS_EN) { |
| 139 | + /* Pass through mode */ |
| 140 | + mult = div = 1; |
| 141 | + } else { |
| 142 | + /* F = 24Mhz * (2-OD) * [(N + 2) / (D + 1)] */ |
| 143 | + u32 n = (val >> 5) & 0x3f; |
| 144 | + u32 od = (val >> 4) & 0x1; |
| 145 | + u32 d = val & 0xf; |
| 146 | + |
| 147 | + mult = (2 - od) * (n + 2); |
| 148 | + div = d + 1; |
| 149 | + } |
| 150 | + return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, |
| 151 | + mult, div); |
| 152 | +}; |
| 153 | + |
| 154 | +static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val) |
| 155 | +{ |
| 156 | + unsigned int mult, div; |
| 157 | + |
| 158 | + if (val & AST2500_HPLL_BYPASS_EN) { |
| 159 | + /* Pass through mode */ |
| 160 | + mult = div = 1; |
| 161 | + } else { |
| 162 | + /* F = clkin * [(M+1) / (N+1)] / (P + 1) */ |
| 163 | + u32 p = (val >> 13) & 0x3f; |
| 164 | + u32 m = (val >> 5) & 0xff; |
| 165 | + u32 n = val & 0x1f; |
| 166 | + |
| 167 | + mult = (m + 1) / (n + 1); |
| 168 | + div = p + 1; |
| 169 | + } |
| 170 | + |
| 171 | + return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, |
| 172 | + mult, div); |
| 173 | +} |
| 174 | + |
| 175 | +static void __init aspeed_ast2400_cc(struct regmap *map) |
| 176 | +{ |
| 177 | + struct clk_hw *hw; |
| 178 | + u32 val, freq, div; |
| 179 | + |
| 180 | + /* |
| 181 | + * CLKIN is the crystal oscillator, 24, 48 or 25MHz selected by |
| 182 | + * strapping |
| 183 | + */ |
| 184 | + regmap_read(map, ASPEED_STRAP, &val); |
| 185 | + if (val & CLKIN_25MHZ_EN) |
| 186 | + freq = 25000000; |
| 187 | + else if (val & AST2400_CLK_SOURCE_SEL) |
| 188 | + freq = 48000000; |
| 189 | + else |
| 190 | + freq = 24000000; |
| 191 | + hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq); |
| 192 | + pr_debug("clkin @%u MHz\n", freq / 1000000); |
| 193 | + |
| 194 | + /* |
| 195 | + * High-speed PLL clock derived from the crystal. This the CPU clock, |
| 196 | + * and we assume that it is enabled |
| 197 | + */ |
| 198 | + regmap_read(map, ASPEED_HPLL_PARAM, &val); |
| 199 | + WARN(val & AST2400_HPLL_STRAPPED, "hpll is strapped not configured"); |
| 200 | + aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2400_calc_pll("hpll", val); |
| 201 | + |
| 202 | + /* |
| 203 | + * Strap bits 11:10 define the CPU/AHB clock frequency ratio (aka HCLK) |
| 204 | + * 00: Select CPU:AHB = 1:1 |
| 205 | + * 01: Select CPU:AHB = 2:1 |
| 206 | + * 10: Select CPU:AHB = 4:1 |
| 207 | + * 11: Select CPU:AHB = 3:1 |
| 208 | + */ |
| 209 | + regmap_read(map, ASPEED_STRAP, &val); |
| 210 | + val = (val >> 10) & 0x3; |
| 211 | + div = val + 1; |
| 212 | + if (div == 3) |
| 213 | + div = 4; |
| 214 | + else if (div == 4) |
| 215 | + div = 3; |
| 216 | + hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div); |
| 217 | + aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw; |
| 218 | + |
| 219 | + /* APB clock clock selection register SCU08 (aka PCLK) */ |
| 220 | + hw = clk_hw_register_divider_table(NULL, "apb", "hpll", 0, |
| 221 | + scu_base + ASPEED_CLK_SELECTION, 23, 3, 0, |
| 222 | + ast2400_div_table, |
| 223 | + &aspeed_clk_lock); |
| 224 | + aspeed_clk_data->hws[ASPEED_CLK_APB] = hw; |
| 225 | +} |
| 226 | + |
| 227 | +static void __init aspeed_ast2500_cc(struct regmap *map) |
| 228 | +{ |
| 229 | + struct clk_hw *hw; |
| 230 | + u32 val, freq, div; |
| 231 | + |
| 232 | + /* CLKIN is the crystal oscillator, 24 or 25MHz selected by strapping */ |
| 233 | + regmap_read(map, ASPEED_STRAP, &val); |
| 234 | + if (val & CLKIN_25MHZ_EN) |
| 235 | + freq = 25000000; |
| 236 | + else |
| 237 | + freq = 24000000; |
| 238 | + hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq); |
| 239 | + pr_debug("clkin @%u MHz\n", freq / 1000000); |
| 240 | + |
| 241 | + /* |
| 242 | + * High-speed PLL clock derived from the crystal. This the CPU clock, |
| 243 | + * and we assume that it is enabled |
| 244 | + */ |
| 245 | + regmap_read(map, ASPEED_HPLL_PARAM, &val); |
| 246 | + aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2500_calc_pll("hpll", val); |
| 247 | + |
| 248 | + /* Strap bits 11:9 define the AXI/AHB clock frequency ratio (aka HCLK)*/ |
| 249 | + regmap_read(map, ASPEED_STRAP, &val); |
| 250 | + val = (val >> 9) & 0x7; |
| 251 | + WARN(val == 0, "strapping is zero: cannot determine ahb clock"); |
| 252 | + div = 2 * (val + 1); |
| 253 | + hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div); |
| 254 | + aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw; |
| 255 | + |
| 256 | + /* APB clock clock selection register SCU08 (aka PCLK) */ |
| 257 | + regmap_read(map, ASPEED_CLK_SELECTION, &val); |
| 258 | + val = (val >> 23) & 0x7; |
| 259 | + div = 4 * (val + 1); |
| 260 | + hw = clk_hw_register_fixed_factor(NULL, "apb", "hpll", 0, 1, div); |
| 261 | + aspeed_clk_data->hws[ASPEED_CLK_APB] = hw; |
| 262 | +}; |
| 263 | + |
94 | 264 | static void __init aspeed_cc_init(struct device_node *np)
|
95 | 265 | {
|
96 | 266 | struct regmap *map;
|
@@ -132,6 +302,13 @@ static void __init aspeed_cc_init(struct device_node *np)
|
132 | 302 | return;
|
133 | 303 | }
|
134 | 304 |
|
| 305 | + if (of_device_is_compatible(np, "aspeed,ast2400-scu")) |
| 306 | + aspeed_ast2400_cc(map); |
| 307 | + else if (of_device_is_compatible(np, "aspeed,ast2500-scu")) |
| 308 | + aspeed_ast2500_cc(map); |
| 309 | + else |
| 310 | + pr_err("unknown platform, failed to add clocks\n"); |
| 311 | + |
135 | 312 | aspeed_clk_data->num = ASPEED_NUM_CLKS;
|
136 | 313 | ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_clk_data);
|
137 | 314 | if (ret)
|
|
0 commit comments