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 13#include "clock.h" 14 15/*********** 16 *** DIV *** 17 ***********/ 18 19freq_t 20_div_get_freq(clk_t* clk) 21{ 22 clk_regs_io_t** clk_regs; 23 uint32_t div; 24 uint32_t fin; 25 int clkid; 26 clkid = exynos_clk_get_priv_id(clk); 27 clk_regs = clk_get_clk_regs(clk); 28 fin = clk_get_freq(clk->parent); 29 div = exynos_cmu_get_div(clk_regs, clkid, 1); 30 return fin / (div + 1); 31} 32 33freq_t 34_div_set_freq(clk_t* clk, freq_t hz) 35{ 36 clk_regs_io_t** clk_regs; 37 uint32_t div; 38 uint32_t fin; 39 int clkid; 40 clkid = exynos_clk_get_priv_id(clk); 41 clk_regs = clk_get_clk_regs(clk); 42 fin = clk_get_freq(clk->parent); 43 if (fin / 1 < hz) { 44 /* Parent frequency too low */ 45 fin = clk_set_freq(clk->parent, hz * (MASK(DIV_VAL_BITS) / 2 + 1)); 46 } 47 if (fin / (MASK(DIV_VAL_BITS) + 1) > hz) { 48 /* Parent frequency too high */ 49 fin = clk_set_freq(clk->parent, hz * (MASK(DIV_VAL_BITS) / 2 + 1)); 50 } 51 div = fin / hz; 52 if (div > MASK(DIV_VAL_BITS)) { 53 /* This should have been caught by now, but best to protect against overflow */ 54 div = MASK(CLK_DIV_BITS); 55 } 56 57 exynos_cmu_set_div(clk_regs, clkid, 1, div); 58 return clk_get_freq(clk); 59} 60 61void 62_div_recal(clk_t* clk) 63{ 64 assert(0); 65} 66 67/*********** 68 *** PLL *** 69 ***********/ 70 71freq_t 72_pll_get_freq(clk_t* clk) 73{ 74 const struct pll_priv* pll_priv; 75 int clkid, pll_idx; 76 77 pll_priv = exynos_clk_get_priv_pll(clk); 78 clkid = pll_priv->clkid; 79 pll_idx = pll_priv->pll_offset; 80 81 return exynos_pll_get_freq(clk, clkid, pll_idx); 82} 83 84freq_t 85_pll_set_freq(clk_t* clk, freq_t hz) 86{ 87 volatile struct pll_regs* pll_regs; 88 const struct pll_priv* pll_priv; 89 clk_regs_io_t** clk_regs; 90 struct mpsk_tbl *tbl; 91 int tbl_size; 92 int mhz = hz / (1 * MHZ); 93 uint32_t mps, k; 94 uint32_t con0, con1; 95 int i; 96 int clkid, c, r, o, pll_idx; 97 98 /* get clk regs address and clkid */ 99 clk_regs = clk_get_clk_regs(clk); 100 pll_priv = exynos_clk_get_priv_pll(clk); 101 clkid = pll_priv->clkid; 102 pll_idx = pll_priv->pll_offset; 103 clkid_decode(clkid, &c, &r, &o); 104 /* prepare searching the correct frequency parameter */ 105 tbl = pll_priv->tbl; 106 tbl_size = pll_priv->pll_tbl_size; 107 pll_regs = (volatile struct pll_regs*)&clk_regs[c]->pll_lock[pll_idx]; 108 /* Search the table for an appropriate frequency value and get parameters */ 109 mps = tbl[tbl_size - 1].mps; 110 k = tbl[tbl_size - 1].k; 111 for (i = 0; i < tbl_size; i++) { 112 if (tbl[i].mhz >= mhz) { 113 mps = tbl[i].mps; 114 k = tbl[i].k; 115 break; 116 } 117 } 118 /* set PLL_FOUT to XXTI and bypass PLL */ 119 exynos_cmu_set_src(clk_regs, clkid, 0x0); 120 /* updating involved bits in con0 and con1 regs */ 121 con0 = pll_regs->con0 & ~PLL_MPS_MASK; 122 con1 = pll_regs->con1 & ~PLL_K_MASK; 123 if (pll_priv->type == PLLTYPE_MPSK) { 124 pll_regs->con1 = (con1 | k); 125 } 126 pll_regs->con0 = (con0 | mps | PLL_ENABLE); 127 while (!(pll_regs->con0 & PLL_LOCKED)); 128 /* PLL is configured, set PLL_FOUT to PLL */ 129 exynos_cmu_set_src(clk_regs, clkid, 0x1); 130 131 return clk_get_freq(clk); 132} 133 134void 135_pll_recal(clk_t* clk) 136{ 137 assert(0); 138} 139 140clk_t* 141_pll_init(clk_t* clk) 142{ 143 clk_t* parent = clk_get_clock(clk_get_clock_sys(clk), CLK_MASTER); 144 clk_init(parent); 145 clk_register_child(parent, clk); 146 return clk; 147} 148