1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Renesas RCar Gen2 CPG MSSR driver 4 * 5 * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com> 6 * 7 * Based on the following driver from Linux kernel: 8 * r8a7796 Clock Pulse Generator / Module Standby and Software Reset 9 * 10 * Copyright (C) 2016 Glider bvba 11 */ 12 13 #include <common.h> 14 #include <clk-uclass.h> 15 #include <dm.h> 16 #include <errno.h> 17 #include <asm/io.h> 18 19 #include <dt-bindings/clock/renesas-cpg-mssr.h> 20 21 #include "renesas-cpg-mssr.h" 22 #include "rcar-gen2-cpg.h" 23 24 #define CPG_RST_MODEMR 0x0060 25 26 #define CPG_PLL0CR 0x00d8 27 #define CPG_SDCKCR 0x0074 28 29 struct clk_div_table { 30 u8 val; 31 u8 div; 32 }; 33 34 /* SDHI divisors */ 35 static const struct clk_div_table cpg_sdh_div_table[] = { 36 { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, 37 { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, 38 { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 }, 39 }; 40 41 static const struct clk_div_table cpg_sd01_div_table[] = { 42 { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, 43 { 8, 24 }, { 10, 36 }, { 11, 48 }, { 12, 10 }, 44 { 0, 0 }, 45 }; 46 47 static u8 gen2_clk_get_sdh_div(const struct clk_div_table *table, u8 val) 48 { 49 for (;;) { 50 if (!(*table).div) 51 return 0xff; 52 53 if ((*table).val == val) 54 return (*table).div; 55 56 table++; 57 } 58 } 59 60 static int gen2_clk_enable(struct clk *clk) 61 { 62 struct gen2_clk_priv *priv = dev_get_priv(clk->dev); 63 64 return renesas_clk_endisable(clk, priv->base, true); 65 } 66 67 static int gen2_clk_disable(struct clk *clk) 68 { 69 struct gen2_clk_priv *priv = dev_get_priv(clk->dev); 70 71 return renesas_clk_endisable(clk, priv->base, false); 72 } 73 74 static ulong gen2_clk_get_rate(struct clk *clk) 75 { 76 struct gen2_clk_priv *priv = dev_get_priv(clk->dev); 77 struct cpg_mssr_info *info = priv->info; 78 struct clk parent; 79 const struct cpg_core_clk *core; 80 const struct rcar_gen2_cpg_pll_config *pll_config = 81 priv->cpg_pll_config; 82 u32 value, mult, div, rate = 0; 83 int ret; 84 85 debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id); 86 87 ret = renesas_clk_get_parent(clk, info, &parent); 88 if (ret) { 89 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); 90 return ret; 91 } 92 93 if (renesas_clk_is_mod(clk)) { 94 rate = gen2_clk_get_rate(&parent); 95 debug("%s[%i] MOD clk: parent=%lu => rate=%u\n", 96 __func__, __LINE__, parent.id, rate); 97 return rate; 98 } 99 100 ret = renesas_clk_get_core(clk, info, &core); 101 if (ret) 102 return ret; 103 104 switch (core->type) { 105 case CLK_TYPE_IN: 106 if (core->id == info->clk_extal_id) { 107 rate = clk_get_rate(&priv->clk_extal); 108 debug("%s[%i] EXTAL clk: rate=%u\n", 109 __func__, __LINE__, rate); 110 return rate; 111 } 112 113 if (core->id == info->clk_extal_usb_id) { 114 rate = clk_get_rate(&priv->clk_extal_usb); 115 debug("%s[%i] EXTALR clk: rate=%u\n", 116 __func__, __LINE__, rate); 117 return rate; 118 } 119 120 return -EINVAL; 121 122 case CLK_TYPE_FF: 123 rate = (gen2_clk_get_rate(&parent) * core->mult) / core->div; 124 debug("%s[%i] FIXED clk: parent=%i mul=%i div=%i => rate=%u\n", 125 __func__, __LINE__, 126 core->parent, core->mult, core->div, rate); 127 return rate; 128 129 case CLK_TYPE_DIV6P1: /* DIV6 Clock with 1 parent clock */ 130 value = (readl(priv->base + core->offset) & 0x3f) + 1; 131 rate = gen2_clk_get_rate(&parent) / value; 132 debug("%s[%i] DIV6P1 clk: parent=%i div=%i => rate=%u\n", 133 __func__, __LINE__, 134 core->parent, value, rate); 135 return rate; 136 137 case CLK_TYPE_GEN2_MAIN: 138 rate = gen2_clk_get_rate(&parent) / pll_config->extal_div; 139 debug("%s[%i] MAIN clk: parent=%i extal_div=%i => rate=%u\n", 140 __func__, __LINE__, 141 core->parent, pll_config->extal_div, rate); 142 return rate; 143 144 case CLK_TYPE_GEN2_PLL0: 145 /* 146 * PLL0 is a configurable multiplier clock except on R-Car 147 * V2H/E2. Register the PLL0 clock as a fixed factor clock for 148 * now as there's no generic multiplier clock implementation and 149 * we currently have no need to change the multiplier value. 150 */ 151 mult = pll_config->pll0_mult; 152 if (!mult) { 153 value = readl(priv->base + CPG_PLL0CR); 154 mult = (((value >> 24) & 0x7f) + 1) * 2; 155 } 156 157 rate = (gen2_clk_get_rate(&parent) * mult) / info->pll0_div; 158 debug("%s[%i] PLL0 clk: parent=%i mult=%u => rate=%u\n", 159 __func__, __LINE__, core->parent, mult, rate); 160 return rate; 161 162 case CLK_TYPE_GEN2_PLL1: 163 rate = (gen2_clk_get_rate(&parent) * pll_config->pll1_mult) / 2; 164 debug("%s[%i] PLL1 clk: parent=%i mul=%i => rate=%u\n", 165 __func__, __LINE__, 166 core->parent, pll_config->pll1_mult, rate); 167 return rate; 168 169 case CLK_TYPE_GEN2_PLL3: 170 rate = gen2_clk_get_rate(&parent) * pll_config->pll3_mult; 171 debug("%s[%i] PLL3 clk: parent=%i mul=%i => rate=%u\n", 172 __func__, __LINE__, 173 core->parent, pll_config->pll3_mult, rate); 174 return rate; 175 176 case CLK_TYPE_GEN2_SDH: 177 value = (readl(priv->base + CPG_SDCKCR) >> 8) & 0xf; 178 div = gen2_clk_get_sdh_div(cpg_sdh_div_table, value); 179 rate = gen2_clk_get_rate(&parent) / div; 180 debug("%s[%i] SDH clk: parent=%i div=%i => rate=%u\n", 181 __func__, __LINE__, 182 core->parent, div, rate); 183 return rate; 184 185 case CLK_TYPE_GEN2_SD0: 186 value = (readl(priv->base + CPG_SDCKCR) >> 4) & 0xf; 187 div = gen2_clk_get_sdh_div(cpg_sd01_div_table, value); 188 rate = gen2_clk_get_rate(&parent) / div; 189 debug("%s[%i] SD0 clk: parent=%i div=%i => rate=%u\n", 190 __func__, __LINE__, 191 core->parent, div, rate); 192 return rate; 193 194 case CLK_TYPE_GEN2_SD1: 195 value = (readl(priv->base + CPG_SDCKCR) >> 0) & 0xf; 196 div = gen2_clk_get_sdh_div(cpg_sd01_div_table, value); 197 rate = gen2_clk_get_rate(&parent) / div; 198 debug("%s[%i] SD1 clk: parent=%i div=%i => rate=%u\n", 199 __func__, __LINE__, 200 core->parent, div, rate); 201 return rate; 202 } 203 204 printf("%s[%i] unknown fail\n", __func__, __LINE__); 205 206 return -ENOENT; 207 } 208 209 static int gen2_clk_setup_mmcif_div(struct clk *clk, ulong rate) 210 { 211 struct gen2_clk_priv *priv = dev_get_priv(clk->dev); 212 struct cpg_mssr_info *info = priv->info; 213 const struct cpg_core_clk *core; 214 struct clk parent, pparent; 215 u32 val; 216 int ret; 217 218 ret = renesas_clk_get_parent(clk, info, &parent); 219 if (ret) { 220 debug("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); 221 return ret; 222 } 223 224 if (renesas_clk_is_mod(&parent)) 225 return 0; 226 227 ret = renesas_clk_get_core(&parent, info, &core); 228 if (ret) 229 return ret; 230 231 if (strcmp(core->name, "mmc0") && strcmp(core->name, "mmc1")) 232 return 0; 233 234 ret = renesas_clk_get_parent(&parent, info, &pparent); 235 if (ret) { 236 debug("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); 237 return ret; 238 } 239 240 val = (gen2_clk_get_rate(&pparent) / rate) - 1; 241 242 debug("%s[%i] MMCIF offset=%x\n", __func__, __LINE__, core->offset); 243 244 writel(val, priv->base + core->offset); 245 246 return 0; 247 } 248 249 static ulong gen2_clk_set_rate(struct clk *clk, ulong rate) 250 { 251 /* Force correct MMC-IF divider configuration if applicable */ 252 gen2_clk_setup_mmcif_div(clk, rate); 253 return gen2_clk_get_rate(clk); 254 } 255 256 static int gen2_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) 257 { 258 if (args->args_count != 2) { 259 debug("Invaild args_count: %d\n", args->args_count); 260 return -EINVAL; 261 } 262 263 clk->id = (args->args[0] << 16) | args->args[1]; 264 265 return 0; 266 } 267 268 const struct clk_ops gen2_clk_ops = { 269 .enable = gen2_clk_enable, 270 .disable = gen2_clk_disable, 271 .get_rate = gen2_clk_get_rate, 272 .set_rate = gen2_clk_set_rate, 273 .of_xlate = gen2_clk_of_xlate, 274 }; 275 276 int gen2_clk_probe(struct udevice *dev) 277 { 278 struct gen2_clk_priv *priv = dev_get_priv(dev); 279 struct cpg_mssr_info *info = 280 (struct cpg_mssr_info *)dev_get_driver_data(dev); 281 fdt_addr_t rst_base; 282 u32 cpg_mode; 283 int ret; 284 285 priv->base = (struct gen2_base *)devfdt_get_addr(dev); 286 if (!priv->base) 287 return -EINVAL; 288 289 priv->info = info; 290 ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, info->reset_node); 291 if (ret < 0) 292 return ret; 293 294 rst_base = fdtdec_get_addr(gd->fdt_blob, ret, "reg"); 295 if (rst_base == FDT_ADDR_T_NONE) 296 return -EINVAL; 297 298 cpg_mode = readl(rst_base + CPG_RST_MODEMR); 299 300 priv->cpg_pll_config = 301 (struct rcar_gen2_cpg_pll_config *)info->get_pll_config(cpg_mode); 302 if (!priv->cpg_pll_config->extal_div) 303 return -EINVAL; 304 305 ret = clk_get_by_name(dev, "extal", &priv->clk_extal); 306 if (ret < 0) 307 return ret; 308 309 if (info->extal_usb_node) { 310 ret = clk_get_by_name(dev, info->extal_usb_node, 311 &priv->clk_extal_usb); 312 if (ret < 0) 313 return ret; 314 } 315 316 return 0; 317 } 318 319 int gen2_clk_remove(struct udevice *dev) 320 { 321 struct gen2_clk_priv *priv = dev_get_priv(dev); 322 323 return renesas_clk_remove(priv->base, priv->info); 324 } 325