1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2020 Unisoc Inc. |
4 | */ |
5 | |
6 | #include <asm/div64.h> |
7 | #include <linux/delay.h> |
8 | #include <linux/init.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/regmap.h> |
11 | #include <linux/string.h> |
12 | |
13 | #include "sprd_dsi.h" |
14 | |
15 | #define L 0 |
16 | #define H 1 |
17 | #define CLK 0 |
18 | #define DATA 1 |
19 | #define INFINITY 0xffffffff |
20 | #define MIN_OUTPUT_FREQ (100) |
21 | |
22 | #define AVERAGE(a, b) (min(a, b) + abs((b) - (a)) / 2) |
23 | |
24 | /* sharkle */ |
25 | #define VCO_BAND_LOW 750 |
26 | #define VCO_BAND_MID 1100 |
27 | #define VCO_BAND_HIGH 1500 |
28 | #define PHY_REF_CLK 26000 |
29 | |
30 | static int dphy_calc_pll_param(struct dphy_pll *pll) |
31 | { |
32 | const u32 khz = 1000; |
33 | const u32 mhz = 1000000; |
34 | const unsigned long long factor = 100; |
35 | unsigned long long tmp; |
36 | int i; |
37 | |
38 | pll->potential_fvco = pll->freq / khz; |
39 | pll->ref_clk = PHY_REF_CLK / khz; |
40 | |
41 | for (i = 0; i < 4; ++i) { |
42 | if (pll->potential_fvco >= VCO_BAND_LOW && |
43 | pll->potential_fvco <= VCO_BAND_HIGH) { |
44 | pll->fvco = pll->potential_fvco; |
45 | pll->out_sel = BIT(i); |
46 | break; |
47 | } |
48 | pll->potential_fvco <<= 1; |
49 | } |
50 | if (pll->fvco == 0) |
51 | return -EINVAL; |
52 | |
53 | if (pll->fvco >= VCO_BAND_LOW && pll->fvco <= VCO_BAND_MID) { |
54 | /* vco band control */ |
55 | pll->vco_band = 0x0; |
56 | /* low pass filter control */ |
57 | pll->lpf_sel = 1; |
58 | } else if (pll->fvco > VCO_BAND_MID && pll->fvco <= VCO_BAND_HIGH) { |
59 | pll->vco_band = 0x1; |
60 | pll->lpf_sel = 0; |
61 | } else { |
62 | return -EINVAL; |
63 | } |
64 | |
65 | pll->nint = pll->fvco / pll->ref_clk; |
66 | tmp = pll->fvco * factor * mhz; |
67 | do_div(tmp, pll->ref_clk); |
68 | tmp = tmp - pll->nint * factor * mhz; |
69 | tmp *= BIT(20); |
70 | do_div(tmp, 100000000); |
71 | pll->kint = (u32)tmp; |
72 | pll->refin = 3; /* pre-divider bypass */ |
73 | pll->sdm_en = true; /* use fraction N PLL */ |
74 | pll->fdk_s = 0x1; /* fraction */ |
75 | pll->cp_s = 0x0; |
76 | pll->det_delay = 0x1; |
77 | |
78 | return 0; |
79 | } |
80 | |
81 | static void dphy_set_pll_reg(struct dphy_pll *pll, struct regmap *regmap) |
82 | { |
83 | u8 reg_val[9] = {0}; |
84 | int i; |
85 | |
86 | u8 reg_addr[] = { |
87 | 0x03, 0x04, 0x06, 0x08, 0x09, |
88 | 0x0a, 0x0b, 0x0e, 0x0f |
89 | }; |
90 | |
91 | reg_val[0] = 1 | (1 << 1) | (pll->lpf_sel << 2); |
92 | reg_val[1] = pll->div | (1 << 3) | (pll->cp_s << 5) | (pll->fdk_s << 7); |
93 | reg_val[2] = pll->nint; |
94 | reg_val[3] = pll->vco_band | (pll->sdm_en << 1) | (pll->refin << 2); |
95 | reg_val[4] = pll->kint >> 12; |
96 | reg_val[5] = pll->kint >> 4; |
97 | reg_val[6] = pll->out_sel | ((pll->kint << 4) & 0xf); |
98 | reg_val[7] = 1 << 4; |
99 | reg_val[8] = pll->det_delay; |
100 | |
101 | for (i = 0; i < sizeof(reg_addr); ++i) { |
102 | regmap_write(map: regmap, reg: reg_addr[i], val: reg_val[i]); |
103 | DRM_DEBUG("%02x: %02x\n" , reg_addr[i], reg_val[i]); |
104 | } |
105 | } |
106 | |
107 | int dphy_pll_config(struct dsi_context *ctx) |
108 | { |
109 | struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx); |
110 | struct regmap *regmap = ctx->regmap; |
111 | struct dphy_pll *pll = &ctx->pll; |
112 | int ret; |
113 | |
114 | pll->freq = dsi->slave->hs_rate; |
115 | |
116 | /* FREQ = 26M * (NINT + KINT / 2^20) / out_sel */ |
117 | ret = dphy_calc_pll_param(pll); |
118 | if (ret) { |
119 | drm_err(dsi->drm, "failed to calculate dphy pll parameters\n" ); |
120 | return ret; |
121 | } |
122 | dphy_set_pll_reg(pll, regmap); |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | static void dphy_set_timing_reg(struct regmap *regmap, int type, u8 val[]) |
128 | { |
129 | switch (type) { |
130 | case REQUEST_TIME: |
131 | regmap_write(map: regmap, reg: 0x31, val: val[CLK]); |
132 | regmap_write(map: regmap, reg: 0x41, val: val[DATA]); |
133 | regmap_write(map: regmap, reg: 0x51, val: val[DATA]); |
134 | regmap_write(map: regmap, reg: 0x61, val: val[DATA]); |
135 | regmap_write(map: regmap, reg: 0x71, val: val[DATA]); |
136 | |
137 | regmap_write(map: regmap, reg: 0x90, val: val[CLK]); |
138 | regmap_write(map: regmap, reg: 0xa0, val: val[DATA]); |
139 | regmap_write(map: regmap, reg: 0xb0, val: val[DATA]); |
140 | regmap_write(map: regmap, reg: 0xc0, val: val[DATA]); |
141 | regmap_write(map: regmap, reg: 0xd0, val: val[DATA]); |
142 | break; |
143 | case PREPARE_TIME: |
144 | regmap_write(map: regmap, reg: 0x32, val: val[CLK]); |
145 | regmap_write(map: regmap, reg: 0x42, val: val[DATA]); |
146 | regmap_write(map: regmap, reg: 0x52, val: val[DATA]); |
147 | regmap_write(map: regmap, reg: 0x62, val: val[DATA]); |
148 | regmap_write(map: regmap, reg: 0x72, val: val[DATA]); |
149 | |
150 | regmap_write(map: regmap, reg: 0x91, val: val[CLK]); |
151 | regmap_write(map: regmap, reg: 0xa1, val: val[DATA]); |
152 | regmap_write(map: regmap, reg: 0xb1, val: val[DATA]); |
153 | regmap_write(map: regmap, reg: 0xc1, val: val[DATA]); |
154 | regmap_write(map: regmap, reg: 0xd1, val: val[DATA]); |
155 | break; |
156 | case ZERO_TIME: |
157 | regmap_write(map: regmap, reg: 0x33, val: val[CLK]); |
158 | regmap_write(map: regmap, reg: 0x43, val: val[DATA]); |
159 | regmap_write(map: regmap, reg: 0x53, val: val[DATA]); |
160 | regmap_write(map: regmap, reg: 0x63, val: val[DATA]); |
161 | regmap_write(map: regmap, reg: 0x73, val: val[DATA]); |
162 | |
163 | regmap_write(map: regmap, reg: 0x92, val: val[CLK]); |
164 | regmap_write(map: regmap, reg: 0xa2, val: val[DATA]); |
165 | regmap_write(map: regmap, reg: 0xb2, val: val[DATA]); |
166 | regmap_write(map: regmap, reg: 0xc2, val: val[DATA]); |
167 | regmap_write(map: regmap, reg: 0xd2, val: val[DATA]); |
168 | break; |
169 | case TRAIL_TIME: |
170 | regmap_write(map: regmap, reg: 0x34, val: val[CLK]); |
171 | regmap_write(map: regmap, reg: 0x44, val: val[DATA]); |
172 | regmap_write(map: regmap, reg: 0x54, val: val[DATA]); |
173 | regmap_write(map: regmap, reg: 0x64, val: val[DATA]); |
174 | regmap_write(map: regmap, reg: 0x74, val: val[DATA]); |
175 | |
176 | regmap_write(map: regmap, reg: 0x93, val: val[CLK]); |
177 | regmap_write(map: regmap, reg: 0xa3, val: val[DATA]); |
178 | regmap_write(map: regmap, reg: 0xb3, val: val[DATA]); |
179 | regmap_write(map: regmap, reg: 0xc3, val: val[DATA]); |
180 | regmap_write(map: regmap, reg: 0xd3, val: val[DATA]); |
181 | break; |
182 | case EXIT_TIME: |
183 | regmap_write(map: regmap, reg: 0x36, val: val[CLK]); |
184 | regmap_write(map: regmap, reg: 0x46, val: val[DATA]); |
185 | regmap_write(map: regmap, reg: 0x56, val: val[DATA]); |
186 | regmap_write(map: regmap, reg: 0x66, val: val[DATA]); |
187 | regmap_write(map: regmap, reg: 0x76, val: val[DATA]); |
188 | |
189 | regmap_write(map: regmap, reg: 0x95, val: val[CLK]); |
190 | regmap_write(map: regmap, reg: 0xA5, val: val[DATA]); |
191 | regmap_write(map: regmap, reg: 0xB5, val: val[DATA]); |
192 | regmap_write(map: regmap, reg: 0xc5, val: val[DATA]); |
193 | regmap_write(map: regmap, reg: 0xd5, val: val[DATA]); |
194 | break; |
195 | case CLKPOST_TIME: |
196 | regmap_write(map: regmap, reg: 0x35, val: val[CLK]); |
197 | regmap_write(map: regmap, reg: 0x94, val: val[CLK]); |
198 | break; |
199 | |
200 | /* the following just use default value */ |
201 | case SETTLE_TIME: |
202 | fallthrough; |
203 | case TA_GET: |
204 | fallthrough; |
205 | case TA_GO: |
206 | fallthrough; |
207 | case TA_SURE: |
208 | fallthrough; |
209 | default: |
210 | break; |
211 | } |
212 | } |
213 | |
214 | void dphy_timing_config(struct dsi_context *ctx) |
215 | { |
216 | struct regmap *regmap = ctx->regmap; |
217 | struct dphy_pll *pll = &ctx->pll; |
218 | const u32 factor = 2; |
219 | const u32 scale = 100; |
220 | u32 t_ui, t_byteck, t_half_byteck; |
221 | u32 range[2], constant; |
222 | u8 val[2]; |
223 | u32 tmp = 0; |
224 | |
225 | /* t_ui: 1 ui, byteck: 8 ui, half byteck: 4 ui */ |
226 | t_ui = 1000 * scale / (pll->freq / 1000); |
227 | t_byteck = t_ui << 3; |
228 | t_half_byteck = t_ui << 2; |
229 | constant = t_ui << 1; |
230 | |
231 | /* REQUEST_TIME: HS T-LPX: LP-01 |
232 | * For T-LPX, mipi spec defined min value is 50ns, |
233 | * but maybe it shouldn't be too small, because BTA, |
234 | * LP-10, LP-00, LP-01, all of this is related to T-LPX. |
235 | */ |
236 | range[L] = 50 * scale; |
237 | range[H] = INFINITY; |
238 | val[CLK] = DIV_ROUND_UP(range[L] * (factor << 1), t_byteck) - 2; |
239 | val[DATA] = val[CLK]; |
240 | dphy_set_timing_reg(regmap, type: REQUEST_TIME, val); |
241 | |
242 | /* PREPARE_TIME: HS sequence: LP-00 */ |
243 | range[L] = 38 * scale; |
244 | range[H] = 95 * scale; |
245 | tmp = AVERAGE(range[L], range[H]); |
246 | val[CLK] = DIV_ROUND_UP(AVERAGE(range[L], range[H]), t_half_byteck) - 1; |
247 | range[L] = 40 * scale + 4 * t_ui; |
248 | range[H] = 85 * scale + 6 * t_ui; |
249 | tmp |= AVERAGE(range[L], range[H]) << 16; |
250 | val[DATA] = DIV_ROUND_UP(AVERAGE(range[L], range[H]), t_half_byteck) - 1; |
251 | dphy_set_timing_reg(regmap, type: PREPARE_TIME, val); |
252 | |
253 | /* ZERO_TIME: HS-ZERO */ |
254 | range[L] = 300 * scale; |
255 | range[H] = INFINITY; |
256 | val[CLK] = DIV_ROUND_UP(range[L] * factor + (tmp & 0xffff) |
257 | - 525 * t_byteck / 100, t_byteck) - 2; |
258 | range[L] = 145 * scale + 10 * t_ui; |
259 | val[DATA] = DIV_ROUND_UP(range[L] * factor |
260 | + ((tmp >> 16) & 0xffff) - 525 * t_byteck / 100, |
261 | t_byteck) - 2; |
262 | dphy_set_timing_reg(regmap, type: ZERO_TIME, val); |
263 | |
264 | /* TRAIL_TIME: HS-TRAIL */ |
265 | range[L] = 60 * scale; |
266 | range[H] = INFINITY; |
267 | val[CLK] = DIV_ROUND_UP(range[L] * factor - constant, t_half_byteck); |
268 | range[L] = max(8 * t_ui, 60 * scale + 4 * t_ui); |
269 | val[DATA] = DIV_ROUND_UP(range[L] * 3 / 2 - constant, t_half_byteck) - 2; |
270 | dphy_set_timing_reg(regmap, type: TRAIL_TIME, val); |
271 | |
272 | /* EXIT_TIME: */ |
273 | range[L] = 100 * scale; |
274 | range[H] = INFINITY; |
275 | val[CLK] = DIV_ROUND_UP(range[L] * factor, t_byteck) - 2; |
276 | val[DATA] = val[CLK]; |
277 | dphy_set_timing_reg(regmap, type: EXIT_TIME, val); |
278 | |
279 | /* CLKPOST_TIME: */ |
280 | range[L] = 60 * scale + 52 * t_ui; |
281 | range[H] = INFINITY; |
282 | val[CLK] = DIV_ROUND_UP(range[L] * factor, t_byteck) - 2; |
283 | val[DATA] = val[CLK]; |
284 | dphy_set_timing_reg(regmap, type: CLKPOST_TIME, val); |
285 | |
286 | /* SETTLE_TIME: |
287 | * This time is used for receiver. So for transmitter, |
288 | * it can be ignored. |
289 | */ |
290 | |
291 | /* TA_GO: |
292 | * transmitter drives bridge state(LP-00) before releasing control, |
293 | * reg 0x1f default value: 0x04, which is good. |
294 | */ |
295 | |
296 | /* TA_SURE: |
297 | * After LP-10 state and before bridge state(LP-00), |
298 | * reg 0x20 default value: 0x01, which is good. |
299 | */ |
300 | |
301 | /* TA_GET: |
302 | * receiver drives Bridge state(LP-00) before releasing control |
303 | * reg 0x21 default value: 0x03, which is good. |
304 | */ |
305 | } |
306 | |