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 52enum rockchip_pll_type { 53 pll_rk3066, 54}; 55 56#define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \ 57{ \ 58 .rate = _rate##U, \ 59 .nr = _nr, \ 60 .nf = _nf, \ 61 .no = _no, \ 62 .bwadj = (_nf >> 1), \ 63} 64 65struct rockchip_pll_rate_table { 66 unsigned long rate; 67 unsigned int nr; 68 unsigned int nf; 69 unsigned int no; 70 unsigned int bwadj; 71}; 72 73/** 74 * struct rockchip_pll_clock: information about pll clock 75 * @id: platform specific id of the clock. 76 * @name: name of this pll clock. 77 * @parent_name: name of the parent clock. 78 * @flags: optional flags for basic clock. 79 * @con_offset: offset of the register for configuring the PLL. 80 * @mode_offset: offset of the register for configuring the PLL-mode. 81 * @mode_shift: offset inside the mode-register for the mode of this pll. 82 * @lock_shift: offset inside the lock register for the lock status. 83 * @type: Type of PLL to be registered. 84 * @rate_table: Table of usable pll rates 85 */ 86struct rockchip_pll_clock { 87 unsigned int id; 88 const char *name; 89 const char **parent_names; 90 u8 num_parents; 91 unsigned long flags; 92 int con_offset; 93 int mode_offset; 94 int mode_shift; 95 int lock_shift; 96 enum rockchip_pll_type type; 97 struct rockchip_pll_rate_table *rate_table; 98}; 99 100#define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift, \ 101 _lshift, _rtable) \ 102 { \ 103 .id = _id, \ 104 .type = _type, \ 105 .name = _name, \ 106 .parent_names = _pnames, \ 107 .num_parents = ARRAY_SIZE(_pnames), \ 108 .flags = CLK_GET_RATE_NOCACHE | _flags, \ 109 .con_offset = _con, \ 110 .mode_offset = _mode, \ 111 .mode_shift = _mshift, \ 112 .lock_shift = _lshift, \ 113 .rate_table = _rtable, \ 114 } 115 116struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, 117 const char *name, const char **parent_names, u8 num_parents, 118 void __iomem *base, int con_offset, int grf_lock_offset, 119 int lock_shift, int reg_mode, int mode_shift, 120 struct rockchip_pll_rate_table *rate_table, 121 spinlock_t *lock); 122 123struct rockchip_cpuclk_clksel { 124 int reg; 125 u32 val; 126}; 127 128#define ROCKCHIP_CPUCLK_NUM_DIVIDERS 2 129struct rockchip_cpuclk_rate_table { 130 unsigned long prate; 131 struct rockchip_cpuclk_clksel divs[ROCKCHIP_CPUCLK_NUM_DIVIDERS]; 132}; 133 134/** 135 * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock 136 * @core_reg: register offset of the core settings register 137 * @div_core_shift: core divider offset used to divide the pll value 138 * @div_core_mask: core divider mask 139 * @mux_core_shift: offset of the core multiplexer 140 */ 141struct rockchip_cpuclk_reg_data { 142 int core_reg; 143 u8 div_core_shift; 144 u32 div_core_mask; 145 int mux_core_reg; 146 u8 mux_core_shift; 147}; 148 149struct clk *rockchip_clk_register_cpuclk(const char *name, 150 const char **parent_names, u8 num_parents, 151 const struct rockchip_cpuclk_reg_data *reg_data, 152 const struct rockchip_cpuclk_rate_table *rates, 153 int nrates, void __iomem *reg_base, spinlock_t *lock); 154 155#define PNAME(x) static const char *x[] __initconst 156 157enum rockchip_clk_branch_type { 158 branch_composite, 159 branch_mux, 160 branch_divider, 161 branch_fraction_divider, 162 branch_gate, 163}; 164 165struct rockchip_clk_branch { 166 unsigned int id; 167 enum rockchip_clk_branch_type branch_type; 168 const char *name; 169 const char **parent_names; 170 u8 num_parents; 171 unsigned long flags; 172 int muxdiv_offset; 173 u8 mux_shift; 174 u8 mux_width; 175 u8 mux_flags; 176 u8 div_shift; 177 u8 div_width; 178 u8 div_flags; 179 struct clk_div_table *div_table; 180 int gate_offset; 181 u8 gate_shift; 182 u8 gate_flags; 183}; 184 185#define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\ 186 df, go, gs, gf) \ 187 { \ 188 .id = _id, \ 189 .branch_type = branch_composite, \ 190 .name = cname, \ 191 .parent_names = pnames, \ 192 .num_parents = ARRAY_SIZE(pnames), \ 193 .flags = f, \ 194 .muxdiv_offset = mo, \ 195 .mux_shift = ms, \ 196 .mux_width = mw, \ 197 .mux_flags = mf, \ 198 .div_shift = ds, \ 199 .div_width = dw, \ 200 .div_flags = df, \ 201 .gate_offset = go, \ 202 .gate_shift = gs, \ 203 .gate_flags = gf, \ 204 } 205 206#define COMPOSITE_NOMUX(_id, cname, pname, f, mo, ds, dw, df, \ 207 go, gs, gf) \ 208 { \ 209 .id = _id, \ 210 .branch_type = branch_composite, \ 211 .name = cname, \ 212 .parent_names = (const char *[]){ pname }, \ 213 .num_parents = 1, \ 214 .flags = f, \ 215 .muxdiv_offset = mo, \ 216 .div_shift = ds, \ 217 .div_width = dw, \ 218 .div_flags = df, \ 219 .gate_offset = go, \ 220 .gate_shift = gs, \ 221 .gate_flags = gf, \ 222 } 223 224#define COMPOSITE_NOMUX_DIVTBL(_id, cname, pname, f, mo, ds, dw,\ 225 df, dt, go, gs, gf) \ 226 { \ 227 .id = _id, \ 228 .branch_type = branch_composite, \ 229 .name = cname, \ 230 .parent_names = (const char *[]){ pname }, \ 231 .num_parents = 1, \ 232 .flags = f, \ 233 .muxdiv_offset = mo, \ 234 .div_shift = ds, \ 235 .div_width = dw, \ 236 .div_flags = df, \ 237 .div_table = dt, \ 238 .gate_offset = go, \ 239 .gate_shift = gs, \ 240 .gate_flags = gf, \ 241 } 242 243#define COMPOSITE_NODIV(_id, cname, pnames, f, mo, ms, mw, mf, \ 244 go, gs, gf) \ 245 { \ 246 .id = _id, \ 247 .branch_type = branch_composite, \ 248 .name = cname, \ 249 .parent_names = pnames, \ 250 .num_parents = ARRAY_SIZE(pnames), \ 251 .flags = f, \ 252 .muxdiv_offset = mo, \ 253 .mux_shift = ms, \ 254 .mux_width = mw, \ 255 .mux_flags = mf, \ 256 .gate_offset = go, \ 257 .gate_shift = gs, \ 258 .gate_flags = gf, \ 259 } 260 261#define COMPOSITE_NOGATE(_id, cname, pnames, f, mo, ms, mw, mf, \ 262 ds, dw, df) \ 263 { \ 264 .id = _id, \ 265 .branch_type = branch_composite, \ 266 .name = cname, \ 267 .parent_names = pnames, \ 268 .num_parents = ARRAY_SIZE(pnames), \ 269 .flags = f, \ 270 .muxdiv_offset = mo, \ 271 .mux_shift = ms, \ 272 .mux_width = mw, \ 273 .mux_flags = mf, \ 274 .div_shift = ds, \ 275 .div_width = dw, \ 276 .div_flags = df, \ 277 .gate_offset = -1, \ 278 } 279 280#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\ 281 { \ 282 .id = _id, \ 283 .branch_type = branch_fraction_divider, \ 284 .name = cname, \ 285 .parent_names = (const char *[]){ pname }, \ 286 .num_parents = 1, \ 287 .flags = f, \ 288 .muxdiv_offset = mo, \ 289 .div_shift = 16, \ 290 .div_width = 16, \ 291 .div_flags = df, \ 292 .gate_offset = go, \ 293 .gate_shift = gs, \ 294 .gate_flags = gf, \ 295 } 296 297#define MUX(_id, cname, pnames, f, o, s, w, mf) \ 298 { \ 299 .id = _id, \ 300 .branch_type = branch_mux, \ 301 .name = cname, \ 302 .parent_names = pnames, \ 303 .num_parents = ARRAY_SIZE(pnames), \ 304 .flags = f, \ 305 .muxdiv_offset = o, \ 306 .mux_shift = s, \ 307 .mux_width = w, \ 308 .mux_flags = mf, \ 309 .gate_offset = -1, \ 310 } 311 312#define DIV(_id, cname, pname, f, o, s, w, df) \ 313 { \ 314 .id = _id, \ 315 .branch_type = branch_divider, \ 316 .name = cname, \ 317 .parent_names = (const char *[]){ pname }, \ 318 .num_parents = 1, \ 319 .flags = f, \ 320 .muxdiv_offset = o, \ 321 .div_shift = s, \ 322 .div_width = w, \ 323 .div_flags = df, \ 324 .gate_offset = -1, \ 325 } 326 327#define DIVTBL(_id, cname, pname, f, o, s, w, df, dt) \ 328 { \ 329 .id = _id, \ 330 .branch_type = branch_divider, \ 331 .name = cname, \ 332 .parent_names = (const char *[]){ pname }, \ 333 .num_parents = 1, \ 334 .flags = f, \ 335 .muxdiv_offset = o, \ 336 .div_shift = s, \ 337 .div_width = w, \ 338 .div_flags = df, \ 339 .div_table = dt, \ 340 } 341 342#define GATE(_id, cname, pname, f, o, b, gf) \ 343 { \ 344 .id = _id, \ 345 .branch_type = branch_gate, \ 346 .name = cname, \ 347 .parent_names = (const char *[]){ pname }, \ 348 .num_parents = 1, \ 349 .flags = f, \ 350 .gate_offset = o, \ 351 .gate_shift = b, \ 352 .gate_flags = gf, \ 353 } 354 355 356void rockchip_clk_init(struct device_node *np, void __iomem *base, 357 unsigned long nr_clks); 358struct regmap *rockchip_clk_get_grf(void); 359void rockchip_clk_add_lookup(struct clk *clk, unsigned int id); 360void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, 361 unsigned int nr_clk); 362void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, 363 unsigned int nr_pll, int grf_lock_offset); 364void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name, 365 const char **parent_names, u8 num_parents, 366 const struct rockchip_cpuclk_reg_data *reg_data, 367 const struct rockchip_cpuclk_rate_table *rates, 368 int nrates); 369void rockchip_clk_protect_critical(const char *clocks[], int nclocks); 370void rockchip_register_restart_notifier(unsigned int reg); 371 372#define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) 373 374#ifdef CONFIG_RESET_CONTROLLER 375void rockchip_register_softrst(struct device_node *np, 376 unsigned int num_regs, 377 void __iomem *base, u8 flags); 378#else 379static inline void rockchip_register_softrst(struct device_node *np, 380 unsigned int num_regs, 381 void __iomem *base, u8 flags) 382{ 383} 384#endif 385 386#endif 387