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
30static 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
81static 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
107int 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
127static 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
214void 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

source code of linux/drivers/gpu/drm/sprd/megacores_pll.c