Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-omap2/clkt2xxx_dpllcore.c
10817 views
1
/*
2
* DPLL + CORE_CLK composite clock functions
3
*
4
* Copyright (C) 2005-2008 Texas Instruments, Inc.
5
* Copyright (C) 2004-2010 Nokia Corporation
6
*
7
* Contacts:
8
* Richard Woodruff <[email protected]>
9
* Paul Walmsley
10
*
11
* Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
12
* Gordon McNutt and RidgeRun, Inc.
13
*
14
* This program is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License version 2 as
16
* published by the Free Software Foundation.
17
*
18
* XXX The DPLL and CORE clocks should be split into two separate clock
19
* types.
20
*/
21
#undef DEBUG
22
23
#include <linux/kernel.h>
24
#include <linux/errno.h>
25
#include <linux/clk.h>
26
#include <linux/io.h>
27
28
#include <plat/clock.h>
29
#include <plat/sram.h>
30
#include <plat/sdrc.h>
31
32
#include "clock.h"
33
#include "clock2xxx.h"
34
#include "opp2xxx.h"
35
#include "cm2xxx_3xxx.h"
36
#include "cm-regbits-24xx.h"
37
38
/* #define DOWN_VARIABLE_DPLL 1 */ /* Experimental */
39
40
/**
41
* omap2xxx_clk_get_core_rate - return the CORE_CLK rate
42
* @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck")
43
*
44
* Returns the CORE_CLK rate. CORE_CLK can have one of three rate
45
* sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
46
* (the latter is unusual). This currently should be called with
47
* struct clk *dpll_ck, which is a composite clock of dpll_ck and
48
* core_ck.
49
*/
50
unsigned long omap2xxx_clk_get_core_rate(struct clk *clk)
51
{
52
long long core_clk;
53
u32 v;
54
55
core_clk = omap2_get_dpll_rate(clk);
56
57
v = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
58
v &= OMAP24XX_CORE_CLK_SRC_MASK;
59
60
if (v == CORE_CLK_SRC_32K)
61
core_clk = 32768;
62
else
63
core_clk *= v;
64
65
return core_clk;
66
}
67
68
/*
69
* Uses the current prcm set to tell if a rate is valid.
70
* You can go slower, but not faster within a given rate set.
71
*/
72
static long omap2_dpllcore_round_rate(unsigned long target_rate)
73
{
74
u32 high, low, core_clk_src;
75
76
core_clk_src = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
77
core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK;
78
79
if (core_clk_src == CORE_CLK_SRC_DPLL) { /* DPLL clockout */
80
high = curr_prcm_set->dpll_speed * 2;
81
low = curr_prcm_set->dpll_speed;
82
} else { /* DPLL clockout x 2 */
83
high = curr_prcm_set->dpll_speed;
84
low = curr_prcm_set->dpll_speed / 2;
85
}
86
87
#ifdef DOWN_VARIABLE_DPLL
88
if (target_rate > high)
89
return high;
90
else
91
return target_rate;
92
#else
93
if (target_rate > low)
94
return high;
95
else
96
return low;
97
#endif
98
99
}
100
101
unsigned long omap2_dpllcore_recalc(struct clk *clk)
102
{
103
return omap2xxx_clk_get_core_rate(clk);
104
}
105
106
int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
107
{
108
u32 cur_rate, low, mult, div, valid_rate, done_rate;
109
u32 bypass = 0;
110
struct prcm_config tmpset;
111
const struct dpll_data *dd;
112
113
cur_rate = omap2xxx_clk_get_core_rate(dclk);
114
mult = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
115
mult &= OMAP24XX_CORE_CLK_SRC_MASK;
116
117
if ((rate == (cur_rate / 2)) && (mult == 2)) {
118
omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
119
} else if ((rate == (cur_rate * 2)) && (mult == 1)) {
120
omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
121
} else if (rate != cur_rate) {
122
valid_rate = omap2_dpllcore_round_rate(rate);
123
if (valid_rate != rate)
124
return -EINVAL;
125
126
if (mult == 1)
127
low = curr_prcm_set->dpll_speed;
128
else
129
low = curr_prcm_set->dpll_speed / 2;
130
131
dd = clk->dpll_data;
132
if (!dd)
133
return -EINVAL;
134
135
tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg);
136
tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
137
dd->div1_mask);
138
div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
139
tmpset.cm_clksel2_pll = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
140
tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK;
141
if (rate > low) {
142
tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2;
143
mult = ((rate / 2) / 1000000);
144
done_rate = CORE_CLK_SRC_DPLL_X2;
145
} else {
146
tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL;
147
mult = (rate / 1000000);
148
done_rate = CORE_CLK_SRC_DPLL;
149
}
150
tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask));
151
tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask));
152
153
/* Worst case */
154
tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS;
155
156
if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */
157
bypass = 1;
158
159
/* For omap2xxx_sdrc_init_params() */
160
omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
161
162
/* Force dll lock mode */
163
omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
164
bypass);
165
166
/* Errata: ret dll entry state */
167
omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
168
omap2xxx_sdrc_reprogram(done_rate, 0);
169
}
170
171
return 0;
172
}
173
174
175