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(&regs[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(&regs[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(&regs[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(&regs[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(&regs[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(&regs[c]->div[r], o * CLK_DIV_BITS, CLK_DIV_BITS * span, --div);
215    /* Wait for changes to take affect */
216    while (clkbf_get(&regs[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(&regs[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(&regs[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