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 div) 48 { 49 while ((*table++).val) { 50 if ((*table).div == div) 51 return div; 52 } 53 return 0xff; 54 } 55 56 static int gen2_clk_enable(struct clk *clk) 57 { 58 struct gen2_clk_priv *priv = dev_get_priv(clk->dev); 59 60 return renesas_clk_endisable(clk, priv->base, true); 61 } 62 63 static int gen2_clk_disable(struct clk *clk) 64 { 65 struct gen2_clk_priv *priv = dev_get_priv(clk->dev); 66 67 return renesas_clk_endisable(clk, priv->base, false); 68 } 69 70 static ulong gen2_clk_get_rate(struct clk *clk) 71 { 72 struct gen2_clk_priv *priv = dev_get_priv(clk->dev); 73 struct cpg_mssr_info *info = priv->info; 74 struct clk parent; 75 const struct cpg_core_clk *core; 76 const struct rcar_gen2_cpg_pll_config *pll_config = 77 priv->cpg_pll_config; 78 u32 value, mult, div, rate = 0; 79 int ret; 80 81 debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id); 82 83 ret = renesas_clk_get_parent(clk, info, &parent); 84 if (ret) { 85 printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); 86 return ret; 87 } 88 89 if (renesas_clk_is_mod(clk)) { 90 rate = gen2_clk_get_rate(&parent); 91 debug("%s[%i] MOD clk: parent=%lu => rate=%u\n", 92 __func__, __LINE__, parent.id, rate); 93 return rate; 94 } 95 96 ret = renesas_clk_get_core(clk, info, &core); 97 if (ret) 98 return ret; 99 100 switch (core->type) { 101 case CLK_TYPE_IN: 102 if (core->id == info->clk_extal_id) { 103 rate = clk_get_rate(&priv->clk_extal); 104 debug("%s[%i] EXTAL clk: rate=%u\n", 105 __func__, __LINE__, rate); 106 return rate; 107 } 108 109 if (core->id == info->clk_extal_usb_id) { 110 rate = clk_get_rate(&priv->clk_extal_usb); 111 debug("%s[%i] EXTALR clk: rate=%u\n", 112 __func__, __LINE__, rate); 113 return rate; 114 } 115 116 return -EINVAL; 117 118 case CLK_TYPE_FF: 119 rate = (gen2_clk_get_rate(&parent) * core->mult) / core->div; 120 debug("%s[%i] FIXED clk: parent=%i div=%i mul=%i => rate=%u\n", 121 __func__, __LINE__, 122 core->parent, core->mult, core->div, rate); 123 return rate; 124 125 case CLK_TYPE_DIV6P1: /* DIV6 Clock with 1 parent clock */ 126 value = (readl(priv->base + core->offset) & 0x3f) + 1; 127 rate = gen2_clk_get_rate(&parent) / value; 128 debug("%s[%i] DIV6P1 clk: parent=%i div=%i => rate=%u\n", 129 __func__, __LINE__, 130 core->parent, value, rate); 131 return rate; 132 133 case CLK_TYPE_GEN2_MAIN: 134 rate = gen2_clk_get_rate(&parent) / pll_config->extal_div; 135 debug("%s[%i] MAIN clk: parent=%i extal_div=%i => rate=%u\n", 136 __func__, __LINE__, 137 core->parent, pll_config->extal_div, rate); 138 return rate; 139 140 case CLK_TYPE_GEN2_PLL0: 141 /* 142 * PLL0 is a configurable multiplier clock except on R-Car 143 * V2H/E2. Register the PLL0 clock as a fixed factor clock for 144 * now as there's no generic multiplier clock implementation and 145 * we currently have no need to change the multiplier value. 146 */ 147 mult = pll_config->pll0_mult; 148 if (!mult) { 149 value = readl(priv->base + CPG_PLL0CR); 150 mult = (((value >> 24) & 0x7f) + 1) * 2; 151 } 152 153 rate = (gen2_clk_get_rate(&parent) * mult) / info->pll0_div; 154 debug("%s[%i] PLL0 clk: parent=%i mult=%u => rate=%u\n", 155 __func__, __LINE__, core->parent, mult, rate); 156 return rate; 157 158 case CLK_TYPE_GEN2_PLL1: 159 rate = (gen2_clk_get_rate(&parent) * pll_config->pll1_mult) / 2; 160 debug("%s[%i] PLL1 clk: parent=%i mul=%i => rate=%u\n", 161 __func__, __LINE__, 162 core->parent, pll_config->pll1_mult, rate); 163 return rate; 164 165 case CLK_TYPE_GEN2_PLL3: 166 rate = gen2_clk_get_rate(&parent) * pll_config->pll3_mult; 167 debug("%s[%i] PLL3 clk: parent=%i mul=%i => rate=%u\n", 168 __func__, __LINE__, 169 core->parent, pll_config->pll3_mult, rate); 170 return rate; 171 172 case CLK_TYPE_GEN2_SDH: 173 value = (readl(priv->base + CPG_SDCKCR) >> 8) & 0xf; 174 div = gen2_clk_get_sdh_div(cpg_sdh_div_table, value); 175 rate = gen2_clk_get_rate(&parent) / div; 176 debug("%s[%i] SDH clk: parent=%i div=%i => rate=%u\n", 177 __func__, __LINE__, 178 core->parent, div, rate); 179 return rate; 180 181 case CLK_TYPE_GEN2_SD0: 182 value = (readl(priv->base + CPG_SDCKCR) >> 4) & 0xf; 183 div = gen2_clk_get_sdh_div(cpg_sd01_div_table, value); 184 rate = gen2_clk_get_rate(&parent) / div; 185 debug("%s[%i] SD0 clk: parent=%i div=%i => rate=%u\n", 186 __func__, __LINE__, 187 core->parent, div, rate); 188 return rate; 189 190 case CLK_TYPE_GEN2_SD1: 191 value = (readl(priv->base + CPG_SDCKCR) >> 0) & 0xf; 192 div = gen2_clk_get_sdh_div(cpg_sd01_div_table, value); 193 rate = gen2_clk_get_rate(&parent) / div; 194 debug("%s[%i] SD1 clk: parent=%i div=%i => rate=%u\n", 195 __func__, __LINE__, 196 core->parent, div, rate); 197 return rate; 198 } 199 200 printf("%s[%i] unknown fail\n", __func__, __LINE__); 201 202 return -ENOENT; 203 } 204 205 static ulong gen2_clk_set_rate(struct clk *clk, ulong rate) 206 { 207 return gen2_clk_get_rate(clk); 208 } 209 210 static int gen2_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) 211 { 212 if (args->args_count != 2) { 213 debug("Invaild args_count: %d\n", args->args_count); 214 return -EINVAL; 215 } 216 217 clk->id = (args->args[0] << 16) | args->args[1]; 218 219 return 0; 220 } 221 222 const struct clk_ops gen2_clk_ops = { 223 .enable = gen2_clk_enable, 224 .disable = gen2_clk_disable, 225 .get_rate = gen2_clk_get_rate, 226 .set_rate = gen2_clk_set_rate, 227 .of_xlate = gen2_clk_of_xlate, 228 }; 229 230 int gen2_clk_probe(struct udevice *dev) 231 { 232 struct gen2_clk_priv *priv = dev_get_priv(dev); 233 struct cpg_mssr_info *info = 234 (struct cpg_mssr_info *)dev_get_driver_data(dev); 235 fdt_addr_t rst_base; 236 u32 cpg_mode; 237 int ret; 238 239 priv->base = (struct gen2_base *)devfdt_get_addr(dev); 240 if (!priv->base) 241 return -EINVAL; 242 243 priv->info = info; 244 ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, info->reset_node); 245 if (ret < 0) 246 return ret; 247 248 rst_base = fdtdec_get_addr(gd->fdt_blob, ret, "reg"); 249 if (rst_base == FDT_ADDR_T_NONE) 250 return -EINVAL; 251 252 cpg_mode = readl(rst_base + CPG_RST_MODEMR); 253 254 priv->cpg_pll_config = 255 (struct rcar_gen2_cpg_pll_config *)info->get_pll_config(cpg_mode); 256 if (!priv->cpg_pll_config->extal_div) 257 return -EINVAL; 258 259 ret = clk_get_by_name(dev, "extal", &priv->clk_extal); 260 if (ret < 0) 261 return ret; 262 263 if (info->extal_usb_node) { 264 ret = clk_get_by_name(dev, info->extal_usb_node, 265 &priv->clk_extal_usb); 266 if (ret < 0) 267 return ret; 268 } 269 270 return 0; 271 } 272 273 int gen2_clk_remove(struct udevice *dev) 274 { 275 struct gen2_clk_priv *priv = dev_get_priv(dev); 276 277 return renesas_clk_remove(priv->base, priv->info); 278 } 279