1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright(c) 2020 Intel Corporation. 4 * Zhu YiXin <yixin.zhu@intel.com> 5 * Rahul Tanwar <rahul.tanwar@intel.com> 6 */ 7 8 #ifndef __CLK_CGU_H 9 #define __CLK_CGU_H 10 11 #include <linux/io.h> 12 13 struct lgm_clk_mux { 14 struct clk_hw hw; 15 void __iomem *membase; 16 unsigned int reg; 17 u8 shift; 18 u8 width; 19 unsigned long flags; 20 spinlock_t lock; 21 }; 22 23 struct lgm_clk_divider { 24 struct clk_hw hw; 25 void __iomem *membase; 26 unsigned int reg; 27 u8 shift; 28 u8 width; 29 u8 shift_gate; 30 u8 width_gate; 31 unsigned long flags; 32 const struct clk_div_table *table; 33 spinlock_t lock; 34 }; 35 36 struct lgm_clk_ddiv { 37 struct clk_hw hw; 38 void __iomem *membase; 39 unsigned int reg; 40 u8 shift0; 41 u8 width0; 42 u8 shift1; 43 u8 width1; 44 u8 shift2; 45 u8 width2; 46 u8 shift_gate; 47 u8 width_gate; 48 unsigned int mult; 49 unsigned int div; 50 unsigned long flags; 51 spinlock_t lock; 52 }; 53 54 struct lgm_clk_gate { 55 struct clk_hw hw; 56 void __iomem *membase; 57 unsigned int reg; 58 u8 shift; 59 unsigned long flags; 60 spinlock_t lock; 61 }; 62 63 enum lgm_clk_type { 64 CLK_TYPE_FIXED, 65 CLK_TYPE_MUX, 66 CLK_TYPE_DIVIDER, 67 CLK_TYPE_FIXED_FACTOR, 68 CLK_TYPE_GATE, 69 CLK_TYPE_NONE, 70 }; 71 72 /** 73 * struct lgm_clk_provider 74 * @membase: IO mem base address for CGU. 75 * @np: device node 76 * @dev: device 77 * @clk_data: array of hw clocks and clk number. 78 */ 79 struct lgm_clk_provider { 80 void __iomem *membase; 81 struct device_node *np; 82 struct device *dev; 83 struct clk_hw_onecell_data clk_data; 84 spinlock_t lock; 85 }; 86 87 enum pll_type { 88 TYPE_ROPLL, 89 TYPE_LJPLL, 90 TYPE_NONE, 91 }; 92 93 struct lgm_clk_pll { 94 struct clk_hw hw; 95 void __iomem *membase; 96 unsigned int reg; 97 unsigned long flags; 98 enum pll_type type; 99 spinlock_t lock; 100 }; 101 102 /** 103 * struct lgm_pll_clk_data 104 * @id: platform specific id of the clock. 105 * @name: name of this pll clock. 106 * @parent_data: parent clock data. 107 * @num_parents: number of parents. 108 * @flags: optional flags for basic clock. 109 * @type: platform type of pll. 110 * @reg: offset of the register. 111 */ 112 struct lgm_pll_clk_data { 113 unsigned int id; 114 const char *name; 115 const struct clk_parent_data *parent_data; 116 u8 num_parents; 117 unsigned long flags; 118 enum pll_type type; 119 int reg; 120 }; 121 122 #define LGM_PLL(_id, _name, _pdata, _flags, \ 123 _reg, _type) \ 124 { \ 125 .id = _id, \ 126 .name = _name, \ 127 .parent_data = _pdata, \ 128 .num_parents = ARRAY_SIZE(_pdata), \ 129 .flags = _flags, \ 130 .reg = _reg, \ 131 .type = _type, \ 132 } 133 134 struct lgm_clk_ddiv_data { 135 unsigned int id; 136 const char *name; 137 const struct clk_parent_data *parent_data; 138 u8 flags; 139 unsigned long div_flags; 140 unsigned int reg; 141 u8 shift0; 142 u8 width0; 143 u8 shift1; 144 u8 width1; 145 u8 shift_gate; 146 u8 width_gate; 147 u8 ex_shift; 148 u8 ex_width; 149 }; 150 151 #define LGM_DDIV(_id, _name, _pname, _flags, _reg, \ 152 _shft0, _wdth0, _shft1, _wdth1, \ 153 _shft_gate, _wdth_gate, _xshft, _df) \ 154 { \ 155 .id = _id, \ 156 .name = _name, \ 157 .parent_data = &(const struct clk_parent_data){ \ 158 .fw_name = _pname, \ 159 .name = _pname, \ 160 }, \ 161 .flags = _flags, \ 162 .reg = _reg, \ 163 .shift0 = _shft0, \ 164 .width0 = _wdth0, \ 165 .shift1 = _shft1, \ 166 .width1 = _wdth1, \ 167 .shift_gate = _shft_gate, \ 168 .width_gate = _wdth_gate, \ 169 .ex_shift = _xshft, \ 170 .ex_width = 1, \ 171 .div_flags = _df, \ 172 } 173 174 struct lgm_clk_branch { 175 unsigned int id; 176 enum lgm_clk_type type; 177 const char *name; 178 const struct clk_parent_data *parent_data; 179 u8 num_parents; 180 unsigned long flags; 181 unsigned int mux_off; 182 u8 mux_shift; 183 u8 mux_width; 184 unsigned long mux_flags; 185 unsigned int mux_val; 186 unsigned int div_off; 187 u8 div_shift; 188 u8 div_width; 189 u8 div_shift_gate; 190 u8 div_width_gate; 191 unsigned long div_flags; 192 unsigned int div_val; 193 const struct clk_div_table *div_table; 194 unsigned int gate_off; 195 u8 gate_shift; 196 unsigned long gate_flags; 197 unsigned int gate_val; 198 unsigned int mult; 199 unsigned int div; 200 }; 201 202 /* clock flags definition */ 203 #define CLOCK_FLAG_VAL_INIT BIT(16) 204 #define MUX_CLK_SW BIT(17) 205 206 #define LGM_MUX(_id, _name, _pdata, _f, _reg, \ 207 _shift, _width, _cf, _v) \ 208 { \ 209 .id = _id, \ 210 .type = CLK_TYPE_MUX, \ 211 .name = _name, \ 212 .parent_data = _pdata, \ 213 .num_parents = ARRAY_SIZE(_pdata), \ 214 .flags = _f, \ 215 .mux_off = _reg, \ 216 .mux_shift = _shift, \ 217 .mux_width = _width, \ 218 .mux_flags = _cf, \ 219 .mux_val = _v, \ 220 } 221 222 #define LGM_DIV(_id, _name, _pname, _f, _reg, _shift, _width, \ 223 _shift_gate, _width_gate, _cf, _v, _dtable) \ 224 { \ 225 .id = _id, \ 226 .type = CLK_TYPE_DIVIDER, \ 227 .name = _name, \ 228 .parent_data = &(const struct clk_parent_data){ \ 229 .fw_name = _pname, \ 230 .name = _pname, \ 231 }, \ 232 .num_parents = 1, \ 233 .flags = _f, \ 234 .div_off = _reg, \ 235 .div_shift = _shift, \ 236 .div_width = _width, \ 237 .div_shift_gate = _shift_gate, \ 238 .div_width_gate = _width_gate, \ 239 .div_flags = _cf, \ 240 .div_val = _v, \ 241 .div_table = _dtable, \ 242 } 243 244 #define LGM_GATE(_id, _name, _pname, _f, _reg, \ 245 _shift, _cf, _v) \ 246 { \ 247 .id = _id, \ 248 .type = CLK_TYPE_GATE, \ 249 .name = _name, \ 250 .parent_data = &(const struct clk_parent_data){ \ 251 .fw_name = _pname, \ 252 .name = _pname, \ 253 }, \ 254 .num_parents = !_pname ? 0 : 1, \ 255 .flags = _f, \ 256 .gate_off = _reg, \ 257 .gate_shift = _shift, \ 258 .gate_flags = _cf, \ 259 .gate_val = _v, \ 260 } 261 262 #define LGM_FIXED(_id, _name, _pname, _f, _reg, \ 263 _shift, _width, _cf, _freq, _v) \ 264 { \ 265 .id = _id, \ 266 .type = CLK_TYPE_FIXED, \ 267 .name = _name, \ 268 .parent_data = &(const struct clk_parent_data){ \ 269 .fw_name = _pname, \ 270 .name = _pname, \ 271 }, \ 272 .num_parents = !_pname ? 0 : 1, \ 273 .flags = _f, \ 274 .div_off = _reg, \ 275 .div_shift = _shift, \ 276 .div_width = _width, \ 277 .div_flags = _cf, \ 278 .div_val = _v, \ 279 .mux_flags = _freq, \ 280 } 281 282 #define LGM_FIXED_FACTOR(_id, _name, _pname, _f, _reg, \ 283 _shift, _width, _cf, _v, _m, _d) \ 284 { \ 285 .id = _id, \ 286 .type = CLK_TYPE_FIXED_FACTOR, \ 287 .name = _name, \ 288 .parent_data = &(const struct clk_parent_data){ \ 289 .fw_name = _pname, \ 290 .name = _pname, \ 291 }, \ 292 .num_parents = 1, \ 293 .flags = _f, \ 294 .div_off = _reg, \ 295 .div_shift = _shift, \ 296 .div_width = _width, \ 297 .div_flags = _cf, \ 298 .div_val = _v, \ 299 .mult = _m, \ 300 .div = _d, \ 301 } 302 303 static inline void lgm_set_clk_val(void __iomem *membase, u32 reg, 304 u8 shift, u8 width, u32 set_val) 305 { 306 u32 mask = (GENMASK(width - 1, 0) << shift); 307 u32 regval; 308 309 regval = readl(membase + reg); 310 regval = (regval & ~mask) | ((set_val << shift) & mask); 311 writel(regval, membase + reg); 312 } 313 314 static inline u32 lgm_get_clk_val(void __iomem *membase, u32 reg, 315 u8 shift, u8 width) 316 { 317 u32 mask = (GENMASK(width - 1, 0) << shift); 318 u32 val; 319 320 val = readl(membase + reg); 321 val = (val & mask) >> shift; 322 323 return val; 324 } 325 326 int lgm_clk_register_branches(struct lgm_clk_provider *ctx, 327 const struct lgm_clk_branch *list, 328 unsigned int nr_clk); 329 int lgm_clk_register_plls(struct lgm_clk_provider *ctx, 330 const struct lgm_pll_clk_data *list, 331 unsigned int nr_clk); 332 int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx, 333 const struct lgm_clk_ddiv_data *list, 334 unsigned int nr_clk); 335 #endif /* __CLK_CGU_H */ 336