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