1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12#pragma once 13 14#include "../../arch/arm/clock.h" 15#if defined(CONFIG_PLAT_EXYNOS5422) 16#include "clock/exynos_5422_clock.h" 17#else 18#include "clock/exynos_common_clock.h" 19#endif 20 21#define DIV_SEP_BITS 4 22#define DIV_VAL_BITS 4 23 24/* CON 0 */ 25#define PLL_MPS_MASK PLL_MPS(0x1ff, 0x3f, 0x7) 26#define PLL_ENABLE BIT(31) 27#define PLL_LOCKED BIT(29) 28/* CON 1*/ 29#define PLL_K_MASK MASK(16) 30 31/* CLKID is used to decode the register bank and offset of a particular generic clock */ 32#define CLKID(cmu, reg, offset) ((CLKREGS_##cmu) << 10 | (reg) << 3 | (offset) << 0) 33#define CLKID_GET_OFFSET(x) ((x) & 0x7) 34#define CLKID_GET_IDX(x) (((x) >> 3) & 0x3f) 35#define CLKID_GET_CMU(x) (((x) >> 10) & 0xf) 36 37#define PLL_PRIV(pll, _type, _tbl) { \ 38 .tbl = &_tbl[0], \ 39 .type = PLLTYPE_##_type, \ 40 .pll_tbl_size = ARRAY_SIZE(_tbl), \ 41 .pll_offset = OFFSET_##pll, \ 42 .clkid = CLKID_##pll \ 43 } 44 45#define CLK_SRC_BITS 4 46#define CLK_SRCSTAT_BITS 4 47#define CLK_SRCMASK_BIT 1 48#define CLK_SRCMASK_BITS 4 49#define CLK_SRCMASK_ENABLE 1 50#define CLK_SRCMASK_DISABLE 0 51#define CLK_DIV_BITS 4 52#define CLK_DIVSTAT_BIT 1 53#define CLK_DIVSTAT_BITS 4 54#define CLK_GATE_BITS 4 55 56#define CLK_DIVSTAT_STABLE 0x0 57#define CLK_DIVSTAT_UNSTABLE 0x1 58 59#define CLK_GATE_SKIP 0x0 60#define CLK_GATE_PASS 0x1 61 62#define PLL_MPS(m,p,s) (((m) << 16) | ((p) << 8) | ((s) << 0)) 63 64struct pll_regs { 65 uint32_t lock; 66 uint32_t res[63]; 67 uint32_t con0; 68 uint32_t con1; 69 uint32_t con2; 70}; 71 72typedef volatile struct clk_regs clk_regs_io_t; 73 74struct mpsk_tbl { 75 uint32_t mhz; 76 uint32_t mps; 77 uint32_t k; 78}; 79 80enum pll_tbl_type { 81 PLLTYPE_MPS, 82 PLLTYPE_MPSK 83}; 84 85struct pll_priv { 86 struct mpsk_tbl* tbl; 87 enum pll_tbl_type type; 88 int pll_tbl_size; 89 int pll_offset; 90 int clkid; 91}; 92 93static inline clk_regs_io_t** 94clk_sys_get_clk_regs(clock_sys_t* clock_sys) 95{ 96 clk_regs_io_t** clk_regs_ptr = (clk_regs_io_t**)clock_sys->priv; 97 return clk_regs_ptr; 98}; 99 100static inline clk_regs_io_t** 101clk_get_clk_regs(clk_t* clk) 102{ 103 return clk_sys_get_clk_regs(clk->clk_sys); 104}; 105 106static inline const struct pll_priv* 107exynos_clk_get_priv_pll(clk_t* clk) { 108 return (const struct pll_priv*)clk->priv; 109} 110 111static inline int 112exynos_clk_get_priv_id(clk_t* clk) 113{ 114 return (int)clk->priv; 115} 116 117/* Generic exynos devider */ 118freq_t _div_get_freq(clk_t* clk); 119freq_t _div_set_freq(clk_t* clk, freq_t hz); 120void _div_recal(clk_t* clk); 121/* Generic exynos PLL */ 122freq_t _pll_get_freq(clk_t* clk); 123freq_t _pll_set_freq(clk_t* clk, freq_t hz); 124void _pll_recal(clk_t* clk); 125clk_t* _pll_init(clk_t* clk); 126/* PLL get_freq */ 127uint32_t exynos_pll_get_freq(clk_t* clk, int clkid, uint32_t pll_idx); 128 129/**** helpers ****/ 130static inline void 131clkid_decode(int clkid, int* cmu, int* reg, int* off) 132{ 133 *cmu = CLKID_GET_CMU(clkid); 134 *reg = CLKID_GET_IDX(clkid); 135 *off = CLKID_GET_OFFSET(clkid); 136} 137 138static inline int 139clkid_change_reg(int clkid, int change) 140{ 141 int r; 142 /* extract reg value and apply change */ 143 r = CLKID_GET_IDX(clkid) + (change); 144 /* erase old reg value out of clkid */ 145 clkid &= ~(0x3f << 3); 146 /* return clkid with new reg offset value */ 147 return clkid | ((r & 0x3f) << 3); 148} 149 150static inline int 151clkbf_get(volatile uint32_t* reg, int start_bit, int nbits) 152{ 153 uint32_t v; 154 v = *reg; 155 return (v >> start_bit) & MASK(nbits); 156} 157 158static inline void 159clkbf_set(volatile uint32_t* reg, int start_bit, int nbits, int v) 160{ 161 uint32_t o; 162 v <<= start_bit; 163 o = *reg & ~(MASK(nbits) << start_bit); 164 *reg = o | v; 165} 166 167static inline int 168exynos_cmu_get_src(clk_regs_io_t** regs, int clkid) 169{ 170 int c, r, o; 171 clkid_decode(clkid, &c, &r, &o); 172 return clkbf_get(®s[c]->src[r], o * CLK_SRC_BITS, CLK_SRC_BITS); 173} 174 175static inline int 176exynos_cmu_get_srcstat(clk_regs_io_t** regs, int clkid) 177{ 178 int c, r, o; 179 clkid_decode(clkid, &c, &r, &o); 180 return clkbf_get(®s[c]->srcstat[r], o * CLK_SRC_BITS, CLK_SRC_BITS); 181} 182 183static inline void 184exynos_cmu_set_src(clk_regs_io_t** regs, int clkid, int src) 185{ 186 int c, r, o; 187 clkid_decode(clkid, &c, &r, &o); 188 /* Configure source */ 189 clkbf_set(®s[c]->src[r], o * CLK_SRC_BITS, CLK_SRC_BITS, src); 190} 191 192static inline void 193exynos_cmu_set_src_mask(clk_regs_io_t** regs, int clkid, int val) 194{ 195 int c, r, o; 196 clkid_decode(clkid, &c, &r, &o); 197 /* Mask / unmask the clock source */ 198 clkbf_set(®s[c]->srcmask[r], o * CLK_SRCMASK_BITS, CLK_SRCMASK_BIT, val); 199} 200 201static inline int 202exynos_cmu_get_div(clk_regs_io_t** regs, int clkid, int span) 203{ 204 int c, r, o; 205 clkid_decode(clkid, &c, &r, &o); 206 return clkbf_get(®s[c]->div[r], o * CLK_DIV_BITS, CLK_DIV_BITS * span); 207} 208 209static inline void 210exynos_cmu_set_div(clk_regs_io_t** regs, int clkid, int span, int div) 211{ 212 int c, r, o; 213 clkid_decode(clkid, &c, &r, &o); 214 clkbf_set(®s[c]->div[r], o * CLK_DIV_BITS, CLK_DIV_BITS * span, --div); 215 /* Wait for changes to take affect */ 216 while (clkbf_get(®s[c]->divstat[r], o * CLK_DIVSTAT_BITS, CLK_DIVSTAT_BIT)); 217} 218 219static inline int 220exynos_cmu_get_gate(clk_regs_io_t** regs, int clkid) 221{ 222 int c, r, o; 223 clkid_decode(clkid, &c, &r, &o); 224 return clkbf_get(®s[c]->gate[r], o * CLK_GATE_BITS, CLK_GATE_BITS); 225} 226 227static inline void 228exynos_cmu_set_gate(clk_regs_io_t** regs, int clkid, int v) 229{ 230 int c, r, o; 231 clkid_decode(clkid, &c, &r, &o); 232 clkbf_set(®s[c]->gate[r], o * CLK_GATE_BITS, CLK_GATE_BITS, v); 233} 234 235static inline void 236exynos_mpll_get_pms(int v, uint32_t* p, uint32_t* m, uint32_t* s) 237{ 238 *m = (v >> 16) & 0x1ff; 239 *p = (v >> 8) & 0x3f; 240 *s = (v >> 0) & 0x7; 241} 242 243static inline uint32_t 244exynos_pll_calc_freq(uint64_t fin, uint32_t p, uint32_t m, uint32_t s) { 245 return (fin * m / p) >> s; 246} 247