1 /* 2 * Copyright (c) 2014 MundoReader S.L. 3 * Author: Heiko Stuebner <heiko@sntech.de> 4 * 5 * based on 6 * 7 * samsung/clk.h 8 * Copyright (c) 2013 Samsung Electronics Co., Ltd. 9 * Copyright (c) 2013 Linaro Ltd. 10 * Author: Thomas Abraham <thomas.ab@samsung.com> 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 */ 22 23 #ifndef CLK_ROCKCHIP_CLK_H 24 #define CLK_ROCKCHIP_CLK_H 25 26 #include <linux/io.h> 27 #include <linux/clk.h> 28 #include <linux/clk-provider.h> 29 30 #define HIWORD_UPDATE(val, mask, shift) \ 31 ((val) << (shift) | (mask) << ((shift) + 16)) 32 33 /* register positions shared by RK2928, RK3066 and RK3188 */ 34 #define RK2928_PLL_CON(x) ((x) * 0x4) 35 #define RK2928_MODE_CON 0x40 36 #define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44) 37 #define RK2928_CLKGATE_CON(x) ((x) * 0x4 + 0xd0) 38 #define RK2928_GLB_SRST_FST 0x100 39 #define RK2928_GLB_SRST_SND 0x104 40 #define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110) 41 #define RK2928_MISC_CON 0x134 42 43 #define RK3288_PLL_CON(x) RK2928_PLL_CON(x) 44 #define RK3288_MODE_CON 0x50 45 #define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60) 46 #define RK3288_CLKGATE_CON(x) ((x) * 0x4 + 0x160) 47 #define RK3288_GLB_SRST_FST 0x1b0 48 #define RK3288_GLB_SRST_SND 0x1b4 49 #define RK3288_SOFTRST_CON(x) ((x) * 0x4 + 0x1b8) 50 #define RK3288_MISC_CON 0x1e8 51 #define RK3288_SDMMC_CON0 0x200 52 #define RK3288_SDMMC_CON1 0x204 53 #define RK3288_SDIO0_CON0 0x208 54 #define RK3288_SDIO0_CON1 0x20c 55 #define RK3288_SDIO1_CON0 0x210 56 #define RK3288_SDIO1_CON1 0x214 57 #define RK3288_EMMC_CON0 0x218 58 #define RK3288_EMMC_CON1 0x21c 59 60 enum rockchip_pll_type { 61 pll_rk3066, 62 }; 63 64 #define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \ 65 { \ 66 .rate = _rate##U, \ 67 .nr = _nr, \ 68 .nf = _nf, \ 69 .no = _no, \ 70 .bwadj = ((_nf) >> 1), \ 71 } 72 73 #define RK3066_PLL_RATE_BWADJ(_rate, _nr, _nf, _no, _bw) \ 74 { \ 75 .rate = _rate##U, \ 76 .nr = _nr, \ 77 .nf = _nf, \ 78 .no = _no, \ 79 .bwadj = _bw, \ 80 } 81 82 struct rockchip_pll_rate_table { 83 unsigned long rate; 84 unsigned int nr; 85 unsigned int nf; 86 unsigned int no; 87 unsigned int bwadj; 88 }; 89 90 /** 91 * struct rockchip_pll_clock: information about pll clock 92 * @id: platform specific id of the clock. 93 * @name: name of this pll clock. 94 * @parent_name: name of the parent clock. 95 * @flags: optional flags for basic clock. 96 * @con_offset: offset of the register for configuring the PLL. 97 * @mode_offset: offset of the register for configuring the PLL-mode. 98 * @mode_shift: offset inside the mode-register for the mode of this pll. 99 * @lock_shift: offset inside the lock register for the lock status. 100 * @type: Type of PLL to be registered. 101 * @pll_flags: hardware-specific flags 102 * @rate_table: Table of usable pll rates 103 * 104 * Flags: 105 * ROCKCHIP_PLL_SYNC_RATE - check rate parameters to match against the 106 * rate_table parameters and ajust them if necessary. 107 */ 108 struct rockchip_pll_clock { 109 unsigned int id; 110 const char *name; 111 const char *const *parent_names; 112 u8 num_parents; 113 unsigned long flags; 114 int con_offset; 115 int mode_offset; 116 int mode_shift; 117 int lock_shift; 118 enum rockchip_pll_type type; 119 u8 pll_flags; 120 struct rockchip_pll_rate_table *rate_table; 121 }; 122 123 #define ROCKCHIP_PLL_SYNC_RATE BIT(0) 124 125 #define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift, \ 126 _lshift, _pflags, _rtable) \ 127 { \ 128 .id = _id, \ 129 .type = _type, \ 130 .name = _name, \ 131 .parent_names = _pnames, \ 132 .num_parents = ARRAY_SIZE(_pnames), \ 133 .flags = CLK_GET_RATE_NOCACHE | _flags, \ 134 .con_offset = _con, \ 135 .mode_offset = _mode, \ 136 .mode_shift = _mshift, \ 137 .lock_shift = _lshift, \ 138 .pll_flags = _pflags, \ 139 .rate_table = _rtable, \ 140 } 141 142 struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, 143 const char *name, const char *const *parent_names, 144 u8 num_parents, void __iomem *base, int con_offset, 145 int grf_lock_offset, int lock_shift, int reg_mode, 146 int mode_shift, struct rockchip_pll_rate_table *rate_table, 147 u8 clk_pll_flags, spinlock_t *lock); 148 149 struct rockchip_cpuclk_clksel { 150 int reg; 151 u32 val; 152 }; 153 154 #define ROCKCHIP_CPUCLK_NUM_DIVIDERS 2 155 struct rockchip_cpuclk_rate_table { 156 unsigned long prate; 157 struct rockchip_cpuclk_clksel divs[ROCKCHIP_CPUCLK_NUM_DIVIDERS]; 158 }; 159 160 /** 161 * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock 162 * @core_reg: register offset of the core settings register 163 * @div_core_shift: core divider offset used to divide the pll value 164 * @div_core_mask: core divider mask 165 * @mux_core_shift: offset of the core multiplexer 166 */ 167 struct rockchip_cpuclk_reg_data { 168 int core_reg; 169 u8 div_core_shift; 170 u32 div_core_mask; 171 int mux_core_reg; 172 u8 mux_core_shift; 173 }; 174 175 struct clk *rockchip_clk_register_cpuclk(const char *name, 176 const char *const *parent_names, u8 num_parents, 177 const struct rockchip_cpuclk_reg_data *reg_data, 178 const struct rockchip_cpuclk_rate_table *rates, 179 int nrates, void __iomem *reg_base, spinlock_t *lock); 180 181 struct clk *rockchip_clk_register_mmc(const char *name, 182 const char *const *parent_names, u8 num_parents, 183 void __iomem *reg, int shift); 184 185 #define ROCKCHIP_INVERTER_HIWORD_MASK BIT(0) 186 187 struct clk *rockchip_clk_register_inverter(const char *name, 188 const char *const *parent_names, u8 num_parents, 189 void __iomem *reg, int shift, int flags, 190 spinlock_t *lock); 191 192 #define PNAME(x) static const char *const x[] __initconst 193 194 enum rockchip_clk_branch_type { 195 branch_composite, 196 branch_mux, 197 branch_divider, 198 branch_fraction_divider, 199 branch_gate, 200 branch_mmc, 201 branch_inverter, 202 }; 203 204 struct rockchip_clk_branch { 205 unsigned int id; 206 enum rockchip_clk_branch_type branch_type; 207 const char *name; 208 const char *const *parent_names; 209 u8 num_parents; 210 unsigned long flags; 211 int muxdiv_offset; 212 u8 mux_shift; 213 u8 mux_width; 214 u8 mux_flags; 215 u8 div_shift; 216 u8 div_width; 217 u8 div_flags; 218 struct clk_div_table *div_table; 219 int gate_offset; 220 u8 gate_shift; 221 u8 gate_flags; 222 }; 223 224 #define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\ 225 df, go, gs, gf) \ 226 { \ 227 .id = _id, \ 228 .branch_type = branch_composite, \ 229 .name = cname, \ 230 .parent_names = pnames, \ 231 .num_parents = ARRAY_SIZE(pnames), \ 232 .flags = f, \ 233 .muxdiv_offset = mo, \ 234 .mux_shift = ms, \ 235 .mux_width = mw, \ 236 .mux_flags = mf, \ 237 .div_shift = ds, \ 238 .div_width = dw, \ 239 .div_flags = df, \ 240 .gate_offset = go, \ 241 .gate_shift = gs, \ 242 .gate_flags = gf, \ 243 } 244 245 #define COMPOSITE_NOMUX(_id, cname, pname, f, mo, ds, dw, df, \ 246 go, gs, gf) \ 247 { \ 248 .id = _id, \ 249 .branch_type = branch_composite, \ 250 .name = cname, \ 251 .parent_names = (const char *[]){ pname }, \ 252 .num_parents = 1, \ 253 .flags = f, \ 254 .muxdiv_offset = mo, \ 255 .div_shift = ds, \ 256 .div_width = dw, \ 257 .div_flags = df, \ 258 .gate_offset = go, \ 259 .gate_shift = gs, \ 260 .gate_flags = gf, \ 261 } 262 263 #define COMPOSITE_NOMUX_DIVTBL(_id, cname, pname, f, mo, ds, dw,\ 264 df, dt, go, gs, gf) \ 265 { \ 266 .id = _id, \ 267 .branch_type = branch_composite, \ 268 .name = cname, \ 269 .parent_names = (const char *[]){ pname }, \ 270 .num_parents = 1, \ 271 .flags = f, \ 272 .muxdiv_offset = mo, \ 273 .div_shift = ds, \ 274 .div_width = dw, \ 275 .div_flags = df, \ 276 .div_table = dt, \ 277 .gate_offset = go, \ 278 .gate_shift = gs, \ 279 .gate_flags = gf, \ 280 } 281 282 #define COMPOSITE_NODIV(_id, cname, pnames, f, mo, ms, mw, mf, \ 283 go, gs, gf) \ 284 { \ 285 .id = _id, \ 286 .branch_type = branch_composite, \ 287 .name = cname, \ 288 .parent_names = pnames, \ 289 .num_parents = ARRAY_SIZE(pnames), \ 290 .flags = f, \ 291 .muxdiv_offset = mo, \ 292 .mux_shift = ms, \ 293 .mux_width = mw, \ 294 .mux_flags = mf, \ 295 .gate_offset = go, \ 296 .gate_shift = gs, \ 297 .gate_flags = gf, \ 298 } 299 300 #define COMPOSITE_NOGATE(_id, cname, pnames, f, mo, ms, mw, mf, \ 301 ds, dw, df) \ 302 { \ 303 .id = _id, \ 304 .branch_type = branch_composite, \ 305 .name = cname, \ 306 .parent_names = pnames, \ 307 .num_parents = ARRAY_SIZE(pnames), \ 308 .flags = f, \ 309 .muxdiv_offset = mo, \ 310 .mux_shift = ms, \ 311 .mux_width = mw, \ 312 .mux_flags = mf, \ 313 .div_shift = ds, \ 314 .div_width = dw, \ 315 .div_flags = df, \ 316 .gate_offset = -1, \ 317 } 318 319 #define COMPOSITE_NOGATE_DIVTBL(_id, cname, pnames, f, mo, ms, \ 320 mw, mf, ds, dw, df, dt) \ 321 { \ 322 .id = _id, \ 323 .branch_type = branch_composite, \ 324 .name = cname, \ 325 .parent_names = pnames, \ 326 .num_parents = ARRAY_SIZE(pnames), \ 327 .flags = f, \ 328 .muxdiv_offset = mo, \ 329 .mux_shift = ms, \ 330 .mux_width = mw, \ 331 .mux_flags = mf, \ 332 .div_shift = ds, \ 333 .div_width = dw, \ 334 .div_flags = df, \ 335 .div_table = dt, \ 336 .gate_offset = -1, \ 337 } 338 339 #define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\ 340 { \ 341 .id = _id, \ 342 .branch_type = branch_fraction_divider, \ 343 .name = cname, \ 344 .parent_names = (const char *[]){ pname }, \ 345 .num_parents = 1, \ 346 .flags = f, \ 347 .muxdiv_offset = mo, \ 348 .div_shift = 16, \ 349 .div_width = 16, \ 350 .div_flags = df, \ 351 .gate_offset = go, \ 352 .gate_shift = gs, \ 353 .gate_flags = gf, \ 354 } 355 356 #define MUX(_id, cname, pnames, f, o, s, w, mf) \ 357 { \ 358 .id = _id, \ 359 .branch_type = branch_mux, \ 360 .name = cname, \ 361 .parent_names = pnames, \ 362 .num_parents = ARRAY_SIZE(pnames), \ 363 .flags = f, \ 364 .muxdiv_offset = o, \ 365 .mux_shift = s, \ 366 .mux_width = w, \ 367 .mux_flags = mf, \ 368 .gate_offset = -1, \ 369 } 370 371 #define DIV(_id, cname, pname, f, o, s, w, df) \ 372 { \ 373 .id = _id, \ 374 .branch_type = branch_divider, \ 375 .name = cname, \ 376 .parent_names = (const char *[]){ pname }, \ 377 .num_parents = 1, \ 378 .flags = f, \ 379 .muxdiv_offset = o, \ 380 .div_shift = s, \ 381 .div_width = w, \ 382 .div_flags = df, \ 383 .gate_offset = -1, \ 384 } 385 386 #define DIVTBL(_id, cname, pname, f, o, s, w, df, dt) \ 387 { \ 388 .id = _id, \ 389 .branch_type = branch_divider, \ 390 .name = cname, \ 391 .parent_names = (const char *[]){ pname }, \ 392 .num_parents = 1, \ 393 .flags = f, \ 394 .muxdiv_offset = o, \ 395 .div_shift = s, \ 396 .div_width = w, \ 397 .div_flags = df, \ 398 .div_table = dt, \ 399 } 400 401 #define GATE(_id, cname, pname, f, o, b, gf) \ 402 { \ 403 .id = _id, \ 404 .branch_type = branch_gate, \ 405 .name = cname, \ 406 .parent_names = (const char *[]){ pname }, \ 407 .num_parents = 1, \ 408 .flags = f, \ 409 .gate_offset = o, \ 410 .gate_shift = b, \ 411 .gate_flags = gf, \ 412 } 413 414 #define MMC(_id, cname, pname, offset, shift) \ 415 { \ 416 .id = _id, \ 417 .branch_type = branch_mmc, \ 418 .name = cname, \ 419 .parent_names = (const char *[]){ pname }, \ 420 .num_parents = 1, \ 421 .muxdiv_offset = offset, \ 422 .div_shift = shift, \ 423 } 424 425 #define INVERTER(_id, cname, pname, io, is, if) \ 426 { \ 427 .id = _id, \ 428 .branch_type = branch_inverter, \ 429 .name = cname, \ 430 .parent_names = (const char *[]){ pname }, \ 431 .num_parents = 1, \ 432 .muxdiv_offset = io, \ 433 .div_shift = is, \ 434 .div_flags = if, \ 435 } 436 437 void rockchip_clk_init(struct device_node *np, void __iomem *base, 438 unsigned long nr_clks); 439 struct regmap *rockchip_clk_get_grf(void); 440 void rockchip_clk_add_lookup(struct clk *clk, unsigned int id); 441 void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, 442 unsigned int nr_clk); 443 void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, 444 unsigned int nr_pll, int grf_lock_offset); 445 void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name, 446 const char *const *parent_names, u8 num_parents, 447 const struct rockchip_cpuclk_reg_data *reg_data, 448 const struct rockchip_cpuclk_rate_table *rates, 449 int nrates); 450 void rockchip_clk_protect_critical(const char *const clocks[], int nclocks); 451 void rockchip_register_restart_notifier(unsigned int reg); 452 453 #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) 454 455 #ifdef CONFIG_RESET_CONTROLLER 456 void rockchip_register_softrst(struct device_node *np, 457 unsigned int num_regs, 458 void __iomem *base, u8 flags); 459 #else 460 static inline void rockchip_register_softrst(struct device_node *np, 461 unsigned int num_regs, 462 void __iomem *base, u8 flags) 463 { 464 } 465 #endif 466 467 #endif 468