1 /*- 2 * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 20 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #ifndef __AW_CLK_H__ 27 #define __AW_CLK_H__ 28 29 /* 30 Allwinner clocks formula : 31 32 PLLs: 33 34 (24MHz*N*K)/(M*P) 35 (24MHz*N)/(M*P) 36 (24MHz*N*2)/M 37 (24MHz*N)/M 38 (24MHz*N*K)/M 39 (24MHz*N*K/2) 40 (24MHz*N)/M 41 (24MHz*N*K/2) 42 (24MHz*N)/M 43 44 Periph clocks: 45 46 Clock Source/Divider N/Divider M 47 Clock Source/Divider N/Divider M/2 48 Clock Source*N/(Divider M+1)/(Divider P+1) 49 50 */ 51 52 struct aw_clk_init { 53 const char *name; 54 const char *parent_name; 55 uint64_t default_freq; 56 bool enable; 57 }; 58 59 #define AW_CLK_HAS_GATE 0x0001 60 #define AW_CLK_HAS_LOCK 0x0002 61 #define AW_CLK_HAS_MUX 0x0004 62 #define AW_CLK_REPARENT 0x0008 63 #define AW_CLK_SCALE_CHANGE 0x0010 64 #define AW_CLK_HAS_UPDATE 0x0040 65 #define AW_CLK_HAS_PREDIV 0x0080 66 #define AW_CLK_SET_PARENT 0x0100 67 68 #define AW_CLK_FACTOR_POWER_OF_TWO 0x0001 69 #define AW_CLK_FACTOR_ZERO_BASED 0x0002 70 #define AW_CLK_FACTOR_HAS_COND 0x0004 71 #define AW_CLK_FACTOR_FIXED 0x0008 72 #define AW_CLK_FACTOR_ZERO_IS_ONE 0x0010 73 #define AW_CLK_FACTOR_MIN_VALUE 0x0020 74 #define AW_CLK_FACTOR_MAX_VALUE 0x0040 75 76 struct aw_clk_factor { 77 uint32_t shift; /* Shift bits for the factor */ 78 uint32_t mask; /* Mask to get the factor, will be override by the clk methods */ 79 uint32_t width; /* Number of bits for the factor */ 80 uint32_t value; /* Fixed value, depends on AW_CLK_FACTOR_FIXED */ 81 82 uint32_t cond_shift; 83 uint32_t cond_mask; 84 uint32_t cond_width; 85 uint32_t cond_value; 86 87 uint32_t min_value; 88 uint32_t max_value; 89 90 uint32_t flags; /* Flags */ 91 }; 92 93 struct aw_clk_frac { 94 uint64_t freq0; 95 uint64_t freq1; 96 uint32_t mode_sel; 97 uint32_t freq_sel; 98 }; 99 100 static inline uint32_t 101 aw_clk_get_factor(uint32_t val, struct aw_clk_factor *factor) 102 { 103 uint32_t factor_val; 104 uint32_t cond; 105 106 if (factor->flags & AW_CLK_FACTOR_HAS_COND) { 107 cond = (val & factor->cond_mask) >> factor->cond_shift; 108 if (cond != factor->cond_value) 109 return (1); 110 } 111 112 if (factor->flags & AW_CLK_FACTOR_FIXED) 113 return (factor->value); 114 115 factor_val = (val & factor->mask) >> factor->shift; 116 if (factor_val == 0 && (factor->flags & AW_CLK_FACTOR_ZERO_IS_ONE)) 117 factor_val = 1; 118 119 if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) 120 factor_val = 1 << factor_val; 121 else if (!(factor->flags & AW_CLK_FACTOR_ZERO_BASED)) 122 factor_val += 1; 123 124 return (factor_val); 125 } 126 127 static inline uint32_t 128 aw_clk_factor_get_max(struct aw_clk_factor *factor) 129 { 130 uint32_t max; 131 132 if (factor->flags & AW_CLK_FACTOR_FIXED) 133 max = factor->value; 134 else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) 135 max = 1 << ((1 << factor->width) - 1); 136 else { 137 max = (1 << factor->width); 138 } 139 140 return (max); 141 } 142 143 static inline uint32_t 144 aw_clk_factor_get_min(struct aw_clk_factor *factor) 145 { 146 uint32_t min; 147 148 if (factor->flags & AW_CLK_FACTOR_FIXED) 149 min = factor->value; 150 else if (factor->flags & AW_CLK_FACTOR_ZERO_BASED) 151 min = 0; 152 else if (factor->flags & AW_CLK_FACTOR_MIN_VALUE) 153 min = factor->min_value; 154 else 155 min = 1; 156 157 return (min); 158 } 159 160 static inline uint32_t 161 aw_clk_factor_get_value(struct aw_clk_factor *factor, uint32_t raw) 162 { 163 uint32_t val; 164 165 if (factor->flags & AW_CLK_FACTOR_FIXED) 166 return (factor->value); 167 168 if (factor->flags & AW_CLK_FACTOR_ZERO_BASED) 169 val = raw; 170 else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) { 171 for (val = 0; raw != 1; val++) 172 raw >>= 1; 173 } else if (factor->flags & AW_CLK_FACTOR_MAX_VALUE) 174 val = factor->max_value; 175 else 176 val = raw - 1; 177 178 return (val); 179 } 180 181 #define CCU_RESET(idx, o, s) \ 182 [idx] = { \ 183 .offset = o, \ 184 .shift = s, \ 185 }, 186 187 #define CCU_GATE(idx, clkname, pname, o, s) \ 188 [idx] = { \ 189 .name = clkname, \ 190 .parent_name = pname, \ 191 .offset = o, \ 192 .shift = s, \ 193 }, 194 195 #define NKMP_CLK(_clkname, _id, _name, _pnames, \ 196 _offset, \ 197 _n_shift, _n_width, _n_value, _n_flags, \ 198 _k_shift, _k_width, _k_value, _k_flags, \ 199 _m_shift, _m_width, _m_value, _m_flags, \ 200 _p_shift, _p_width, _p_value, _p_flags, \ 201 _gate, \ 202 _lock, _lock_retries, \ 203 _flags) \ 204 static struct aw_clk_nkmp_def _clkname = { \ 205 .clkdef = { \ 206 .id = _id, \ 207 .name = _name, \ 208 .parent_names = _pnames, \ 209 .parent_cnt = nitems(_pnames), \ 210 }, \ 211 .offset = _offset, \ 212 .n.shift = _n_shift, \ 213 .n.width = _n_width, \ 214 .n.value = _n_value, \ 215 .n.flags = _n_flags, \ 216 .k.shift = _k_shift, \ 217 .k.width = _k_width, \ 218 .k.value = _k_value, \ 219 .k.flags = _k_flags, \ 220 .m.shift = _m_shift, \ 221 .m.width = _m_width, \ 222 .m.value = _m_value, \ 223 .m.flags = _m_flags, \ 224 .p.shift = _p_shift, \ 225 .p.width = _p_width, \ 226 .p.value = _p_value, \ 227 .p.flags = _p_flags, \ 228 .gate_shift = _gate, \ 229 .lock_shift = _lock, \ 230 .lock_retries = _lock_retries, \ 231 .flags = _flags, \ 232 } 233 234 #define NKMP_CLK_WITH_MUX(_clkname, \ 235 _id, _name, _pnames, \ 236 _offset, \ 237 _n_shift, _n_width, _n_value, _n_flags, \ 238 _k_shift, _k_width, _k_value, _k_flags, \ 239 _m_shift, _m_width, _m_value, _m_flags, \ 240 _p_shift, _p_width, _p_value, _p_flags, \ 241 _mux_shift, _mux_width, _gate, \ 242 _lock, _lock_retries, \ 243 _flags) \ 244 static struct aw_clk_nkmp_def _clkname = { \ 245 .clkdef = { \ 246 .id = _id, \ 247 .name = _name, \ 248 .parent_names = _pnames, \ 249 .parent_cnt = nitems(_pnames), \ 250 }, \ 251 .offset = _offset, \ 252 .n.shift = _n_shift, \ 253 .n.width = _n_width, \ 254 .n.value = _n_value, \ 255 .n.flags = _n_flags, \ 256 .k.shift = _k_shift, \ 257 .k.width = _k_width, \ 258 .k.value = _k_value, \ 259 .k.flags = _k_flags, \ 260 .m.shift = _m_shift, \ 261 .m.width = _m_width, \ 262 .m.value = _m_value, \ 263 .m.flags = _m_flags, \ 264 .p.shift = _p_shift, \ 265 .p.width = _p_width, \ 266 .p.value = _p_value, \ 267 .p.flags = _p_flags, \ 268 .mux_shift = _mux_shift, \ 269 .mux_width = _mux_width, \ 270 .gate_shift = _gate, \ 271 .lock_shift = _lock, \ 272 .lock_retries = _lock_retries, \ 273 .flags = _flags, \ 274 } 275 276 #define NKMP_CLK_WITH_UPDATE(_clkname, \ 277 _id, _name, _pnames, \ 278 _offset, \ 279 _n_shift, _n_width, _n_value, _n_flags, \ 280 _k_shift, _k_width, _k_value, _k_flags, \ 281 _m_shift, _m_width, _m_value, _m_flags, \ 282 _p_shift, _p_width, _p_value, _p_flags, \ 283 _gate, \ 284 _lock, _lock_retries, \ 285 _update, \ 286 _flags) \ 287 static struct aw_clk_nkmp_def _clkname = { \ 288 .clkdef = { \ 289 .id = _id, \ 290 .name = _name, \ 291 .parent_names = _pnames, \ 292 .parent_cnt = nitems(_pnames), \ 293 }, \ 294 .offset = _offset, \ 295 .n.shift = _n_shift, \ 296 .n.width = _n_width, \ 297 .n.value = _n_value, \ 298 .n.flags = _n_flags, \ 299 .k.shift = _k_shift, \ 300 .k.width = _k_width, \ 301 .k.value = _k_value, \ 302 .k.flags = _k_flags, \ 303 .m.shift = _m_shift, \ 304 .m.width = _m_width, \ 305 .m.value = _m_value, \ 306 .m.flags = _m_flags, \ 307 .p.shift = _p_shift, \ 308 .p.width = _p_width, \ 309 .p.value = _p_value, \ 310 .p.flags = _p_flags, \ 311 .gate_shift = _gate, \ 312 .lock_shift = _lock, \ 313 .lock_retries = _lock_retries, \ 314 .update_shift = _update, \ 315 .flags = _flags | AW_CLK_HAS_UPDATE, \ 316 } 317 318 #define FRAC_CLK(_clkname, _id, _name, _pnames, \ 319 _offset, \ 320 _nshift, _nwidth, _nvalue, _nflags, \ 321 _mshift, _mwidth, _mvalue, _mflags, \ 322 _gate_shift, _lock_shift,_lock_retries, \ 323 _flags, _freq0, _freq1, _mode_sel, _freq_sel, \ 324 _min_freq, _max_freq) \ 325 static struct aw_clk_frac_def _clkname = { \ 326 .clkdef = { \ 327 .id = _id, \ 328 .name = _name, \ 329 .parent_names = _pnames, \ 330 .parent_cnt = nitems(_pnames), \ 331 .flags = CLK_NODE_GLITCH_FREE, \ 332 }, \ 333 .offset = _offset, \ 334 .n.shift = _nshift, \ 335 .n.width = _nwidth, \ 336 .n.value = _nvalue, \ 337 .n.flags = _nflags, \ 338 .m.shift = _mshift, \ 339 .m.width = _mwidth, \ 340 .m.value = _mvalue, \ 341 .m.flags = _mflags, \ 342 .gate_shift = _gate_shift, \ 343 .lock_shift = _lock_shift, \ 344 .lock_retries = _lock_retries, \ 345 .flags = _flags, \ 346 .frac.freq0 = _freq0, \ 347 .frac.freq1 = _freq1, \ 348 .frac.mode_sel = _mode_sel, \ 349 .frac.freq_sel = _freq_sel, \ 350 .min_freq = _min_freq, \ 351 .max_freq = _max_freq, \ 352 } 353 354 #define M_CLK(_clkname, _id, _name, _pnames, \ 355 _offset, \ 356 _mshift, _mwidth, _mvalue, _mflags, \ 357 _mux_shift, _mux_width, \ 358 _gate_shift, \ 359 _flags) \ 360 static struct aw_clk_m_def _clkname = { \ 361 .clkdef = { \ 362 .id = _id, \ 363 .name = _name, \ 364 .parent_names = _pnames, \ 365 .parent_cnt = nitems(_pnames), \ 366 }, \ 367 .offset = _offset, \ 368 .mux_shift = _mux_shift, \ 369 .m.shift = _mshift, \ 370 .m.width = _mwidth, \ 371 .m.value = _mvalue, \ 372 .m.flags = _mflags, \ 373 .mux_width = _mux_width, \ 374 .gate_shift = _gate_shift, \ 375 .flags = _flags, \ 376 } 377 378 #define NM_CLK(_clkname, _id, _name, _pnames, \ 379 _offset, \ 380 _nshift, _nwidth, _nvalue, _nflags, \ 381 _mshift, _mwidth, _mvalue, _mflags, \ 382 _mux_shift, _mux_width, \ 383 _gate_shift, \ 384 _flags) \ 385 static struct aw_clk_nm_def _clkname = { \ 386 .clkdef = { \ 387 .id = _id, \ 388 .name = _name, \ 389 .parent_names = _pnames, \ 390 .parent_cnt = nitems(_pnames), \ 391 }, \ 392 .offset = _offset, \ 393 .n.shift = _nshift, \ 394 .n.width = _nwidth, \ 395 .n.value = _nvalue, \ 396 .n.flags = _nflags, \ 397 .mux_shift = _mux_shift, \ 398 .m.shift = _mshift, \ 399 .m.width = _mwidth, \ 400 .m.value = _mvalue, \ 401 .m.flags = _mflags, \ 402 .mux_width = _mux_width, \ 403 .gate_shift = _gate_shift, \ 404 .flags = _flags, \ 405 } 406 407 #define NMM_CLK(_clkname, _id, _name, _pnames, \ 408 _offset, \ 409 _nshift, _nwidth, _nvalue, _nflags, \ 410 _m0shift, _m0width, _m0value, _m0flags, \ 411 _m1shift, _m1width, _m1value, _m1flags, \ 412 _gate_shift, \ 413 _lock, _lock_retries, \ 414 _flags) \ 415 static struct aw_clk_nmm_def _clkname = { \ 416 .clkdef = { \ 417 .id = _id, \ 418 .name = _name, \ 419 .parent_names = _pnames, \ 420 .parent_cnt = nitems(_pnames), \ 421 }, \ 422 .offset = _offset, \ 423 .n.shift = _nshift, \ 424 .n.width = _nwidth, \ 425 .n.value = _nvalue, \ 426 .n.flags = _nflags, \ 427 .m0.shift = _m0shift, \ 428 .m0.width = _m0width, \ 429 .m0.value = _m0value, \ 430 .m0.flags = _m0flags, \ 431 .m1.shift = _m1shift, \ 432 .m1.width = _m1width, \ 433 .m1.value = _m1value, \ 434 .m1.flags = _m1flags, \ 435 .gate_shift = _gate_shift, \ 436 .lock_shift = _lock, \ 437 .lock_retries = _lock_retries, \ 438 .flags = _flags, \ 439 } 440 441 #define NP_CLK(_clkname, _id, _name, _pnames, \ 442 _offset, \ 443 _nshift, _nwidth, _nvalue, _nflags, \ 444 _pshift, _pwidth, _pvalue, _pflags, \ 445 _gate_shift, \ 446 _lock, _lock_retries, \ 447 _flags) \ 448 static struct aw_clk_np_def _clkname = { \ 449 .clkdef = { \ 450 .id = _id, \ 451 .name = _name, \ 452 .parent_names = _pnames, \ 453 .parent_cnt = nitems(_pnames), \ 454 }, \ 455 .offset = _offset, \ 456 .n.shift = _nshift, \ 457 .n.width = _nwidth, \ 458 .n.value = _nvalue, \ 459 .n.flags = _nflags, \ 460 .p.shift = _pshift, \ 461 .p.width = _pwidth, \ 462 .p.value = _pvalue, \ 463 .p.flags = _pflags, \ 464 .gate_shift = _gate_shift, \ 465 .lock_shift = _lock, \ 466 .lock_retries = _lock_retries, \ 467 .flags = _flags, \ 468 } 469 470 #define PREDIV_CLK(_clkname, _id, _name, _pnames, \ 471 _offset, \ 472 _mux_shift, _mux_width, \ 473 _div_shift, _div_width, _div_value, _div_flags, \ 474 _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \ 475 _prediv_cond_shift, _prediv_cond_width, _prediv_cond_value) \ 476 static struct aw_clk_prediv_mux_def _clkname = { \ 477 .clkdef = { \ 478 .id = _id, \ 479 .name = _name, \ 480 .parent_names = _pnames, \ 481 .parent_cnt = nitems(_pnames), \ 482 }, \ 483 .offset = _offset, \ 484 .mux_shift = _mux_shift, \ 485 .mux_width = _mux_width, \ 486 .div.shift = _div_shift, \ 487 .div.width = _div_width, \ 488 .div.value = _div_value, \ 489 .div.flags = _div_flags, \ 490 .prediv.shift = _prediv_shift, \ 491 .prediv.width = _prediv_width, \ 492 .prediv.value = _prediv_value, \ 493 .prediv.flags = _prediv_flags, \ 494 .prediv.cond_shift = _prediv_cond_shift, \ 495 .prediv.cond_width = _prediv_cond_width, \ 496 .prediv.cond_value = _prediv_cond_value, \ 497 } 498 499 #define PREDIV_CLK_WITH_MASK(_clkname, _id, _name, _pnames, \ 500 _offset, \ 501 _mux_shift, _mux_width, \ 502 _div_shift, _div_width, _div_value, _div_flags, \ 503 _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \ 504 _prediv_cond_mask, _prediv_cond_value) \ 505 static struct aw_clk_prediv_mux_def _clkname = { \ 506 .clkdef = { \ 507 .id = _id, \ 508 .name = _name, \ 509 .parent_names = _pnames, \ 510 .parent_cnt = nitems(_pnames), \ 511 }, \ 512 .offset = _offset, \ 513 .mux_shift = _mux_shift, \ 514 .mux_width = _mux_width, \ 515 .div.shift = _div_shift, \ 516 .div.width = _div_width, \ 517 .div.value = _div_value, \ 518 .div.flags = _div_flags, \ 519 .prediv.shift = _prediv_shift, \ 520 .prediv.width = _prediv_width, \ 521 .prediv.value = _prediv_value, \ 522 .prediv.flags = _prediv_flags, \ 523 .prediv.cond_shift = 0, \ 524 .prediv.cond_width = 0, \ 525 .prediv.cond_mask = _prediv_cond_mask, \ 526 .prediv.cond_value = _prediv_cond_value, \ 527 } 528 529 #define MIPI_CLK(_clkname, _id, _name, _pnames, \ 530 _offset, \ 531 _kshift, _kwidth, _kflags, _kmin, \ 532 _mshift, _mwidth, \ 533 _nshift, _nwidth, \ 534 _gate_shift, _lock_shift) \ 535 static struct aw_clk_mipi_def _clkname = { \ 536 .clkdef = { \ 537 .id = _id, \ 538 .name = _name, \ 539 .parent_names = _pnames, \ 540 .parent_cnt = nitems(_pnames) \ 541 }, \ 542 .offset = _offset, \ 543 .k.shift = _kshift, \ 544 .k.width = _kwidth, \ 545 .k.flags = _kflags, \ 546 .k.min_value = _kmin, \ 547 .m.shift = _mshift, \ 548 .m.width = _mwidth, \ 549 .n.shift = _nshift, \ 550 .n.width = _nwidth, \ 551 .gate_shift = _gate_shift, \ 552 .lock_shift = _lock_shift, \ 553 } 554 555 #define MUX_CLK(_clkname, _id, _name, _pnames, \ 556 _offset, _shift, _width) \ 557 static struct clk_mux_def _clkname = { \ 558 .clkdef = { \ 559 .id = _id, \ 560 .name = _name, \ 561 .parent_names = _pnames, \ 562 .parent_cnt = nitems(_pnames) \ 563 }, \ 564 .offset = _offset, \ 565 .shift = _shift, \ 566 .width = _width, \ 567 } 568 569 #define DIV_CLK(_clkname, _id, _name, _pnames, \ 570 _offset, \ 571 _i_shift, _i_width, \ 572 _div_flags, _div_table) \ 573 static struct clk_div_def _clkname = { \ 574 .clkdef = { \ 575 .id = _id, \ 576 .name = _name, \ 577 .parent_names = _pnames, \ 578 .parent_cnt = nitems(_pnames) \ 579 }, \ 580 .offset = _offset, \ 581 .i_shift = _i_shift, \ 582 .i_width = _i_width, \ 583 .div_flags = _div_flags, \ 584 .div_table = _div_table, \ 585 } 586 587 #define FIXED_CLK(_clkname, _id, _name, _pnames, \ 588 _freq, _mult, _div, _flags) \ 589 static struct clk_fixed_def _clkname = { \ 590 .clkdef = { \ 591 .id = _id, \ 592 .name = _name, \ 593 .parent_names = _pnames, \ 594 .parent_cnt = 1, \ 595 }, \ 596 .freq = _freq, \ 597 .mult = _mult, \ 598 .div = _div, \ 599 .fixed_flags = _flags, \ 600 } 601 602 #endif /* __AW_CLK_H__ */ 603