Skip to content

Commit e66f81b

Browse files
committed
clk: sunxi-ng: Implement factors offsets
The factors we've seen so far all had an offset of one. However, on the earlier Allwinner SoCs, some factors could have no offset at all, meaning that the value computed to reach the rate we want to use was the one we had to program in the registers. Implement an additional field for the factors that can have such an offset (linears, not based on a power of two) to specify that offset. This offset is not linked to the extremums that can be specified in those structures too. The minimum and maximum are representing the range of values we can use to try to compute the best rate. The offset comes later on when we want to set the best value in the registers. Acked-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
1 parent d77e813 commit e66f81b

File tree

8 files changed

+79
-29
lines changed

8 files changed

+79
-29
lines changed

drivers/clk/sunxi-ng/ccu_div.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct ccu_div_internal {
4141
u8 width;
4242

4343
u32 max;
44+
u32 offset;
4445

4546
u32 flags;
4647

@@ -58,20 +59,27 @@ struct ccu_div_internal {
5859
#define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table) \
5960
_SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0)
6061

61-
#define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \
62+
#define _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _off, _max, _flags) \
6263
{ \
6364
.shift = _shift, \
6465
.width = _width, \
6566
.flags = _flags, \
6667
.max = _max, \
68+
.offset = _off, \
6769
}
6870

71+
#define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \
72+
_SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, 1, _max, _flags)
73+
6974
#define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \
7075
_SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, 0, _flags)
7176

7277
#define _SUNXI_CCU_DIV_MAX(_shift, _width, _max) \
7378
_SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, 0)
7479

80+
#define _SUNXI_CCU_DIV_OFFSET(_shift, _width, _offset) \
81+
_SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _offset, 0, 0)
82+
7583
#define _SUNXI_CCU_DIV(_shift, _width) \
7684
_SUNXI_CCU_DIV_FLAGS(_shift, _width, 0)
7785

drivers/clk/sunxi-ng/ccu_mp.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,14 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
8989

9090
m = reg >> cmp->m.shift;
9191
m &= (1 << cmp->m.width) - 1;
92+
m += cmp->m.offset;
93+
if (!m)
94+
m++;
9295

9396
p = reg >> cmp->p.shift;
9497
p &= (1 << cmp->p.width) - 1;
9598

96-
return (parent_rate >> p) / (m + 1);
99+
return (parent_rate >> p) / m;
97100
}
98101

99102
static int ccu_mp_determine_rate(struct clk_hw *hw,
@@ -124,9 +127,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
124127
reg = readl(cmp->common.base + cmp->common.reg);
125128
reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
126129
reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift);
130+
reg |= (m - cmp->m.offset) << cmp->m.shift;
131+
reg |= ilog2(p) << cmp->p.shift;
127132

128-
writel(reg | (ilog2(p) << cmp->p.shift) | ((m - 1) << cmp->m.shift),
129-
cmp->common.base + cmp->common.reg);
133+
writel(reg, cmp->common.base + cmp->common.reg);
130134

131135
spin_unlock_irqrestore(cmp->common.lock, flags);
132136

drivers/clk/sunxi-ng/ccu_mult.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ static unsigned long ccu_mult_recalc_rate(struct clk_hw *hw,
8585
ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1,
8686
&parent_rate);
8787

88-
return parent_rate * (val + 1);
88+
return parent_rate * (val + cm->mult.offset);
8989
}
9090

9191
static int ccu_mult_determine_rate(struct clk_hw *hw,
@@ -121,9 +121,9 @@ static int ccu_mult_set_rate(struct clk_hw *hw, unsigned long rate,
121121

122122
reg = readl(cm->common.base + cm->common.reg);
123123
reg &= ~GENMASK(cm->mult.width + cm->mult.shift - 1, cm->mult.shift);
124+
reg |= ((_cm.mult - cm->mult.offset) << cm->mult.shift);
124125

125-
writel(reg | ((_cm.mult - 1) << cm->mult.shift),
126-
cm->common.base + cm->common.reg);
126+
writel(reg, cm->common.base + cm->common.reg);
127127

128128
spin_unlock_irqrestore(cm->common.lock, flags);
129129

drivers/clk/sunxi-ng/ccu_mult.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,28 @@
66
#include "ccu_mux.h"
77

88
struct ccu_mult_internal {
9+
u8 offset;
910
u8 shift;
1011
u8 width;
1112
u8 min;
1213
};
1314

14-
#define _SUNXI_CCU_MULT_MIN(_shift, _width, _min) \
15-
{ \
16-
.shift = _shift, \
17-
.width = _width, \
18-
.min = _min, \
15+
#define _SUNXI_CCU_MULT_OFFSET_MIN(_shift, _width, _offset, _min) \
16+
{ \
17+
.min = _min, \
18+
.offset = _offset, \
19+
.shift = _shift, \
20+
.width = _width, \
1921
}
2022

23+
#define _SUNXI_CCU_MULT_MIN(_shift, _width, _min) \
24+
_SUNXI_CCU_MULT_OFFSET_MIN(_shift, _width, 1, _min)
25+
26+
#define _SUNXI_CCU_MULT_OFFSET(_shift, _width, _offset) \
27+
_SUNXI_CCU_MULT_OFFSET_MIN(_shift, _width, _offset, 1)
28+
2129
#define _SUNXI_CCU_MULT(_shift, _width) \
22-
_SUNXI_CCU_MULT_MIN(_shift, _width, 1)
30+
_SUNXI_CCU_MULT_OFFSET_MIN(_shift, _width, 1, 1)
2331

2432
struct ccu_mult {
2533
u32 enable;

drivers/clk/sunxi-ng/ccu_nk.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,17 @@ static unsigned long ccu_nk_recalc_rate(struct clk_hw *hw,
7676

7777
n = reg >> nk->n.shift;
7878
n &= (1 << nk->n.width) - 1;
79+
n += nk->n.offset;
80+
if (!n)
81+
n++;
7982

8083
k = reg >> nk->k.shift;
8184
k &= (1 << nk->k.width) - 1;
85+
k += nk->k.offset;
86+
if (!k)
87+
k++;
8288

83-
rate = parent_rate * (n + 1) * (k + 1);
84-
89+
rate = parent_rate * n * k;
8590
if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
8691
rate /= nk->fixed_post_div;
8792

@@ -135,8 +140,9 @@ static int ccu_nk_set_rate(struct clk_hw *hw, unsigned long rate,
135140
reg &= ~GENMASK(nk->n.width + nk->n.shift - 1, nk->n.shift);
136141
reg &= ~GENMASK(nk->k.width + nk->k.shift - 1, nk->k.shift);
137142

138-
writel(reg | ((_nk.k - 1) << nk->k.shift) | ((_nk.n - 1) << nk->n.shift),
139-
nk->common.base + nk->common.reg);
143+
reg |= (_nk.k - nk->k.offset) << nk->k.shift;
144+
reg |= (_nk.n - nk->n.offset) << nk->n.shift;
145+
writel(reg, nk->common.base + nk->common.reg);
140146

141147
spin_unlock_irqrestore(nk->common.lock, flags);
142148

drivers/clk/sunxi-ng/ccu_nkm.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,23 @@ static unsigned long ccu_nkm_recalc_rate(struct clk_hw *hw,
8282

8383
n = reg >> nkm->n.shift;
8484
n &= (1 << nkm->n.width) - 1;
85+
n += nkm->n.offset;
86+
if (!n)
87+
n++;
8588

8689
k = reg >> nkm->k.shift;
8790
k &= (1 << nkm->k.width) - 1;
91+
k += nkm->k.offset;
92+
if (!k)
93+
k++;
8894

8995
m = reg >> nkm->m.shift;
9096
m &= (1 << nkm->m.width) - 1;
97+
m += nkm->m.offset;
98+
if (!m)
99+
m++;
91100

92-
return parent_rate * (n + 1) * (k + 1) / (m + 1);
101+
return parent_rate * n * k / m;
93102
}
94103

95104
static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
@@ -145,10 +154,9 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate,
145154
reg &= ~GENMASK(nkm->k.width + nkm->k.shift - 1, nkm->k.shift);
146155
reg &= ~GENMASK(nkm->m.width + nkm->m.shift - 1, nkm->m.shift);
147156

148-
reg |= (_nkm.n - 1) << nkm->n.shift;
149-
reg |= (_nkm.k - 1) << nkm->k.shift;
150-
reg |= (_nkm.m - 1) << nkm->m.shift;
151-
157+
reg |= (_nkm.n - nkm->n.offset) << nkm->n.shift;
158+
reg |= (_nkm.k - nkm->k.offset) << nkm->k.shift;
159+
reg |= (_nkm.m - nkm->m.offset) << nkm->m.shift;
152160
writel(reg, nkm->common.base + nkm->common.reg);
153161

154162
spin_unlock_irqrestore(nkm->common.lock, flags);

drivers/clk/sunxi-ng/ccu_nkmp.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,17 +88,26 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw,
8888

8989
n = reg >> nkmp->n.shift;
9090
n &= (1 << nkmp->n.width) - 1;
91+
n += nkmp->n.offset;
92+
if (!n)
93+
n++;
9194

9295
k = reg >> nkmp->k.shift;
9396
k &= (1 << nkmp->k.width) - 1;
97+
k += nkmp->k.offset;
98+
if (!k)
99+
k++;
94100

95101
m = reg >> nkmp->m.shift;
96102
m &= (1 << nkmp->m.width) - 1;
103+
m += nkmp->m.offset;
104+
if (!m)
105+
m++;
97106

98107
p = reg >> nkmp->p.shift;
99108
p &= (1 << nkmp->p.width) - 1;
100109

101-
return (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
110+
return parent_rate * n * k >> p / m;
102111
}
103112

104113
static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -148,9 +157,9 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
148157
reg &= ~GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift);
149158
reg &= ~GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift);
150159

151-
reg |= (_nkmp.n - 1) << nkmp->n.shift;
152-
reg |= (_nkmp.k - 1) << nkmp->k.shift;
153-
reg |= (_nkmp.m - 1) << nkmp->m.shift;
160+
reg |= (_nkmp.n - nkmp->n.offset) << nkmp->n.shift;
161+
reg |= (_nkmp.k - nkmp->k.offset) << nkmp->k.shift;
162+
reg |= (_nkmp.m - nkmp->m.offset) << nkmp->m.shift;
154163
reg |= ilog2(_nkmp.p) << nkmp->p.shift;
155164

156165
writel(reg, nkmp->common.base + nkmp->common.reg);

drivers/clk/sunxi-ng/ccu_nm.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,17 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
8080

8181
n = reg >> nm->n.shift;
8282
n &= (1 << nm->n.width) - 1;
83+
n += nm->n.offset;
84+
if (!n)
85+
n++;
8386

8487
m = reg >> nm->m.shift;
8588
m &= (1 << nm->m.width) - 1;
89+
m += nm->m.offset;
90+
if (!m)
91+
m++;
8692

87-
return parent_rate * (n + 1) / (m + 1);
93+
return parent_rate * n / m;
8894
}
8995

9096
static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -129,8 +135,9 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
129135
reg &= ~GENMASK(nm->n.width + nm->n.shift - 1, nm->n.shift);
130136
reg &= ~GENMASK(nm->m.width + nm->m.shift - 1, nm->m.shift);
131137

132-
writel(reg | ((_nm.m - 1) << nm->m.shift) | ((_nm.n - 1) << nm->n.shift),
133-
nm->common.base + nm->common.reg);
138+
reg |= (_nm.n - nm->n.offset) << nm->n.shift;
139+
reg |= (_nm.m - nm->m.offset) << nm->m.shift;
140+
writel(reg, nm->common.base + nm->common.reg);
134141

135142
spin_unlock_irqrestore(nm->common.lock, flags);
136143

0 commit comments

Comments
 (0)