1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2013 - 2025 Intel Corporation
4 */
5
6 #include <linux/bitmap.h>
7 #include <linux/bug.h>
8 #include <linux/delay.h>
9 #include <linux/device.h>
10 #include <linux/iopoll.h>
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13
14 #include <media/mipi-csi2.h>
15 #include <media/v4l2-device.h>
16
17 #include "ipu7.h"
18 #include "ipu7-bus.h"
19 #include "ipu7-buttress.h"
20 #include "ipu7-isys.h"
21 #include "ipu7-isys-csi2.h"
22 #include "ipu7-isys-csi2-regs.h"
23 #include "ipu7-platform-regs.h"
24 #include "ipu7-isys-csi-phy.h"
25
26 #define PORT_A 0U
27 #define PORT_B 1U
28 #define PORT_C 2U
29 #define PORT_D 3U
30
31 #define N_DATA_IDS 8U
32 static DECLARE_BITMAP(data_ids, N_DATA_IDS);
33
34 struct ddlcal_counter_ref_s {
35 u16 min_mbps;
36 u16 max_mbps;
37
38 u16 ddlcal_counter_ref;
39 };
40
41 struct ddlcal_params {
42 u16 min_mbps;
43 u16 max_mbps;
44 u16 oa_lanex_hsrx_cdphy_sel_fast;
45 u16 ddlcal_max_phase;
46 u16 phase_bound;
47 u16 ddlcal_dll_fbk;
48 u16 ddlcal_ddl_coarse_bank;
49 u16 fjump_deskew;
50 u16 min_eye_opening_deskew;
51 };
52
53 struct i_thssettle_params {
54 u16 min_mbps;
55 u16 max_mbps;
56 u16 i_thssettle;
57 };
58
59 /* lane2 for 4l3t, lane1 for 2l2t */
60 struct oa_lane_clk_div_params {
61 u16 min_mbps;
62 u16 max_mbps;
63 u16 oa_lane_hsrx_hs_clk_div;
64 };
65
66 struct cdr_fbk_cap_prog_params {
67 u16 min_mbps;
68 u16 max_mbps;
69 u16 val;
70 };
71
72 static const struct ddlcal_counter_ref_s table0[] = {
73 { 1500, 1999, 118 },
74 { 2000, 2499, 157 },
75 { 2500, 3499, 196 },
76 { 3500, 4499, 274 },
77 { 4500, 4500, 352 },
78 { }
79 };
80
81 static const struct ddlcal_params table1[] = {
82 { 1500, 1587, 0, 143, 167, 17, 3, 4, 29 },
83 { 1588, 1687, 0, 135, 167, 15, 3, 4, 27 },
84 { 1688, 1799, 0, 127, 135, 15, 2, 4, 26 },
85 { 1800, 1928, 0, 119, 135, 13, 2, 3, 24 },
86 { 1929, 2076, 0, 111, 135, 13, 2, 3, 23 },
87 { 2077, 2249, 0, 103, 135, 11, 2, 3, 21 },
88 { 2250, 2454, 0, 95, 103, 11, 1, 3, 19 },
89 { 2455, 2699, 0, 87, 103, 9, 1, 3, 18 },
90 { 2700, 2999, 0, 79, 103, 9, 1, 2, 16 },
91 { 3000, 3229, 0, 71, 71, 7, 1, 2, 15 },
92 { 3230, 3599, 1, 87, 103, 9, 1, 3, 18 },
93 { 3600, 3999, 1, 79, 103, 9, 1, 2, 16 },
94 { 4000, 4499, 1, 71, 103, 7, 1, 2, 15 },
95 { 4500, 4500, 1, 63, 71, 7, 0, 2, 13 },
96 { }
97 };
98
99 static const struct i_thssettle_params table2[] = {
100 { 80, 124, 24 },
101 { 125, 249, 20 },
102 { 250, 499, 16 },
103 { 500, 749, 14 },
104 { 750, 1499, 13 },
105 { 1500, 4500, 12 },
106 { }
107 };
108
109 static const struct oa_lane_clk_div_params table6[] = {
110 { 80, 159, 0x1 },
111 { 160, 319, 0x2 },
112 { 320, 639, 0x3 },
113 { 640, 1279, 0x4 },
114 { 1280, 2560, 0x5 },
115 { 2561, 4500, 0x6 },
116 { }
117 };
118
119 static const struct cdr_fbk_cap_prog_params table7[] = {
120 { 80, 919, 0 },
121 { 920, 1029, 1 },
122 { 1030, 1169, 2 },
123 { 1170, 1349, 3 },
124 { 1350, 1589, 4 },
125 { 1590, 1949, 5 },
126 { 1950, 2499, 6 },
127 { }
128 };
129
dwc_phy_write(struct ipu7_isys * isys,u32 id,u32 addr,u16 data)130 static void dwc_phy_write(struct ipu7_isys *isys, u32 id, u32 addr, u16 data)
131 {
132 void __iomem *isys_base = isys->pdata->base;
133 void __iomem *base = isys_base + IS_IO_CDPHY_BASE(id);
134
135 dev_dbg(&isys->adev->auxdev.dev, "phy write: reg 0x%zx = data 0x%04x",
136 base + addr - isys_base, data);
137 writew(data, base + addr);
138 }
139
dwc_phy_read(struct ipu7_isys * isys,u32 id,u32 addr)140 static u16 dwc_phy_read(struct ipu7_isys *isys, u32 id, u32 addr)
141 {
142 void __iomem *isys_base = isys->pdata->base;
143 void __iomem *base = isys_base + IS_IO_CDPHY_BASE(id);
144 u16 data;
145
146 data = readw(base + addr);
147 dev_dbg(&isys->adev->auxdev.dev, "phy read: reg 0x%zx = data 0x%04x",
148 base + addr - isys_base, data);
149
150 return data;
151 }
152
dwc_csi_write(struct ipu7_isys * isys,u32 id,u32 addr,u32 data)153 static void dwc_csi_write(struct ipu7_isys *isys, u32 id, u32 addr, u32 data)
154 {
155 void __iomem *isys_base = isys->pdata->base;
156 void __iomem *base = isys_base + IS_IO_CSI2_HOST_BASE(id);
157 struct device *dev = &isys->adev->auxdev.dev;
158
159 dev_dbg(dev, "csi write: reg 0x%zx = data 0x%08x",
160 base + addr - isys_base, data);
161 writel(data, base + addr);
162 dev_dbg(dev, "csi read: reg 0x%zx = data 0x%08x",
163 base + addr - isys_base, readl(base + addr));
164 }
165
gpreg_write(struct ipu7_isys * isys,u32 id,u32 addr,u32 data)166 static void gpreg_write(struct ipu7_isys *isys, u32 id, u32 addr, u32 data)
167 {
168 void __iomem *isys_base = isys->pdata->base;
169 u32 gpreg = isys->pdata->ipdata->csi2.gpreg;
170 void __iomem *base = isys_base + gpreg + 0x1000 * id;
171 struct device *dev = &isys->adev->auxdev.dev;
172
173 dev_dbg(dev, "gpreg write: reg 0x%zx = data 0x%08x",
174 base + addr - isys_base, data);
175 writel(data, base + addr);
176 dev_dbg(dev, "gpreg read: reg 0x%zx = data 0x%08x",
177 base + addr - isys_base, readl(base + addr));
178 }
179
dwc_csi_read(struct ipu7_isys * isys,u32 id,u32 addr)180 static u32 dwc_csi_read(struct ipu7_isys *isys, u32 id, u32 addr)
181 {
182 void __iomem *isys_base = isys->pdata->base;
183 void __iomem *base = isys_base + IS_IO_CSI2_HOST_BASE(id);
184 u32 data;
185
186 data = readl(base + addr);
187 dev_dbg(&isys->adev->auxdev.dev, "csi read: reg 0x%zx = data 0x%x",
188 base + addr - isys_base, data);
189
190 return data;
191 }
192
dwc_phy_write_mask(struct ipu7_isys * isys,u32 id,u32 addr,u16 val,u8 lo,u8 hi)193 static void dwc_phy_write_mask(struct ipu7_isys *isys, u32 id, u32 addr,
194 u16 val, u8 lo, u8 hi)
195 {
196 u32 temp, mask;
197
198 WARN_ON(lo > hi);
199 WARN_ON(hi > 15);
200
201 mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi));
202 temp = dwc_phy_read(isys, id, addr);
203 temp &= ~mask;
204 temp |= (val << lo) & mask;
205 dwc_phy_write(isys, id, addr, temp);
206 }
207
dwc_csi_write_mask(struct ipu7_isys * isys,u32 id,u32 addr,u32 val,u8 hi,u8 lo)208 static void dwc_csi_write_mask(struct ipu7_isys *isys, u32 id, u32 addr,
209 u32 val, u8 hi, u8 lo)
210 {
211 u32 temp, mask;
212
213 WARN_ON(lo > hi);
214
215 mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi));
216 temp = dwc_csi_read(isys, id, addr);
217 temp &= ~mask;
218 temp |= (val << lo) & mask;
219 dwc_csi_write(isys, id, addr, temp);
220 }
221
ipu7_isys_csi_ctrl_cfg(struct ipu7_isys_csi2 * csi2)222 static void ipu7_isys_csi_ctrl_cfg(struct ipu7_isys_csi2 *csi2)
223 {
224 struct ipu7_isys *isys = csi2->isys;
225 struct device *dev = &isys->adev->auxdev.dev;
226 u32 id, lanes, phy_mode;
227 u32 val;
228
229 id = csi2->port;
230 lanes = csi2->nlanes;
231 phy_mode = csi2->phy_mode;
232 dev_dbg(dev, "csi-%d controller init with %u lanes, phy mode %u",
233 id, lanes, phy_mode);
234
235 val = dwc_csi_read(isys, id, VERSION);
236 dev_dbg(dev, "csi-%d controller version = 0x%x", id, val);
237
238 /* num of active data lanes */
239 dwc_csi_write(isys, id, N_LANES, lanes - 1);
240 dwc_csi_write(isys, id, CDPHY_MODE, phy_mode);
241 dwc_csi_write(isys, id, VC_EXTENSION, 0);
242
243 /* only mask PHY_FATAL and PKT_FATAL interrupts */
244 dwc_csi_write(isys, id, INT_MSK_PHY_FATAL, 0xff);
245 dwc_csi_write(isys, id, INT_MSK_PKT_FATAL, 0x3);
246 dwc_csi_write(isys, id, INT_MSK_PHY, 0x0);
247 dwc_csi_write(isys, id, INT_MSK_LINE, 0x0);
248 dwc_csi_write(isys, id, INT_MSK_BNDRY_FRAME_FATAL, 0x0);
249 dwc_csi_write(isys, id, INT_MSK_SEQ_FRAME_FATAL, 0x0);
250 dwc_csi_write(isys, id, INT_MSK_CRC_FRAME_FATAL, 0x0);
251 dwc_csi_write(isys, id, INT_MSK_PLD_CRC_FATAL, 0x0);
252 dwc_csi_write(isys, id, INT_MSK_DATA_ID, 0x0);
253 dwc_csi_write(isys, id, INT_MSK_ECC_CORRECTED, 0x0);
254 }
255
ipu7_isys_csi_phy_reset(struct ipu7_isys * isys,u32 id)256 static void ipu7_isys_csi_phy_reset(struct ipu7_isys *isys, u32 id)
257 {
258 dwc_csi_write(isys, id, PHY_SHUTDOWNZ, 0);
259 dwc_csi_write(isys, id, DPHY_RSTZ, 0);
260 dwc_csi_write(isys, id, CSI2_RESETN, 0);
261 gpreg_write(isys, id, PHY_RESET, 0);
262 gpreg_write(isys, id, PHY_SHUTDOWN, 0);
263 }
264
265 /* 8 Data ID monitors, each Data ID is composed by pair of VC and data type */
__dids_config(struct ipu7_isys_csi2 * csi2,u32 id,u8 vc,u8 dt)266 static int __dids_config(struct ipu7_isys_csi2 *csi2, u32 id, u8 vc, u8 dt)
267 {
268 struct ipu7_isys *isys = csi2->isys;
269 u32 reg, n;
270 u8 lo, hi;
271 int ret;
272
273 dev_dbg(&isys->adev->auxdev.dev, "config CSI-%u with vc:%u dt:0x%02x\n",
274 id, vc, dt);
275
276 dwc_csi_write(isys, id, VC_EXTENSION, 0x0);
277 n = find_first_zero_bit(data_ids, N_DATA_IDS);
278 if (n == N_DATA_IDS)
279 return -ENOSPC;
280
281 ret = test_and_set_bit(n, data_ids);
282 if (ret)
283 return -EBUSY;
284
285 reg = n < 4 ? DATA_IDS_VC_1 : DATA_IDS_VC_2;
286 lo = (n % 4) * 8;
287 hi = lo + 4;
288 dwc_csi_write_mask(isys, id, reg, vc & GENMASK(4, 0), hi, lo);
289
290 reg = n < 4 ? DATA_IDS_1 : DATA_IDS_2;
291 lo = (n % 4) * 8;
292 hi = lo + 5;
293 dwc_csi_write_mask(isys, id, reg, dt & GENMASK(5, 0), hi, lo);
294
295 return 0;
296 }
297
ipu7_isys_csi_ctrl_dids_config(struct ipu7_isys_csi2 * csi2,u32 id)298 static int ipu7_isys_csi_ctrl_dids_config(struct ipu7_isys_csi2 *csi2, u32 id)
299 {
300 struct v4l2_mbus_frame_desc_entry *desc_entry = NULL;
301 struct device *dev = &csi2->isys->adev->auxdev.dev;
302 struct v4l2_mbus_frame_desc desc;
303 struct v4l2_subdev *ext_sd;
304 struct media_pad *pad;
305 unsigned int i;
306 int ret;
307
308 pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity);
309 if (IS_ERR(pad)) {
310 dev_warn(dev, "can't get remote source pad of %s (%ld)\n",
311 csi2->asd.sd.name, PTR_ERR(pad));
312 return PTR_ERR(pad);
313 }
314
315 ext_sd = media_entity_to_v4l2_subdev(pad->entity);
316 if (WARN(!ext_sd, "Failed to get subdev for entity %s\n",
317 pad->entity->name))
318 return -ENODEV;
319
320 ret = v4l2_subdev_call(ext_sd, pad, get_frame_desc, pad->index, &desc);
321 if (ret)
322 return ret;
323
324 if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
325 dev_warn(dev, "Unsupported frame descriptor type\n");
326 return -EINVAL;
327 }
328
329 for (i = 0; i < desc.num_entries; i++) {
330 desc_entry = &desc.entry[i];
331 if (desc_entry->bus.csi2.vc < IPU7_NR_OF_CSI2_VC) {
332 ret = __dids_config(csi2, id, desc_entry->bus.csi2.vc,
333 desc_entry->bus.csi2.dt);
334 if (ret)
335 return ret;
336 }
337 }
338
339 return 0;
340 }
341
342 #define CDPHY_TIMEOUT 5000000U
ipu7_isys_phy_ready(struct ipu7_isys * isys,u32 id)343 static int ipu7_isys_phy_ready(struct ipu7_isys *isys, u32 id)
344 {
345 void __iomem *isys_base = isys->pdata->base;
346 u32 gpreg_offset = isys->pdata->ipdata->csi2.gpreg;
347 void __iomem *gpreg = isys_base + gpreg_offset + 0x1000 * id;
348 struct device *dev = &isys->adev->auxdev.dev;
349 unsigned int i;
350 u32 phy_ready;
351 u32 reg, rext;
352 int ret;
353
354 dev_dbg(dev, "waiting phy ready...\n");
355 ret = readl_poll_timeout(gpreg + PHY_READY, phy_ready,
356 phy_ready & BIT(0) && phy_ready != ~0U,
357 100, CDPHY_TIMEOUT);
358 dev_dbg(dev, "phy %u ready = 0x%08x\n", id, readl(gpreg + PHY_READY));
359 dev_dbg(dev, "csi %u PHY_RX = 0x%08x\n", id,
360 dwc_csi_read(isys, id, PHY_RX));
361 dev_dbg(dev, "csi %u PHY_STOPSTATE = 0x%08x\n", id,
362 dwc_csi_read(isys, id, PHY_STOPSTATE));
363 dev_dbg(dev, "csi %u PHY_CAL = 0x%08x\n", id,
364 dwc_csi_read(isys, id, PHY_CAL));
365 for (i = 0; i < 4U; i++) {
366 reg = CORE_DIG_DLANE_0_R_HS_RX_0 + (i * 0x400U);
367 dev_dbg(dev, "phy %u DLANE%u skewcal = 0x%04x\n",
368 id, i, dwc_phy_read(isys, id, reg));
369 }
370 dev_dbg(dev, "phy %u DDLCAL = 0x%04x\n", id,
371 dwc_phy_read(isys, id, PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5));
372 dev_dbg(dev, "phy %u TERMCAL = 0x%04x\n", id,
373 dwc_phy_read(isys, id, PPI_R_TERMCAL_DEBUG_0));
374 dev_dbg(dev, "phy %u LPDCOCAL = 0x%04x\n", id,
375 dwc_phy_read(isys, id, PPI_R_LPDCOCAL_DEBUG_RB));
376 dev_dbg(dev, "phy %u HSDCOCAL = 0x%04x\n", id,
377 dwc_phy_read(isys, id, PPI_R_HSDCOCAL_DEBUG_RB));
378 dev_dbg(dev, "phy %u LPDCOCAL_VT = 0x%04x\n", id,
379 dwc_phy_read(isys, id, PPI_R_LPDCOCAL_DEBUG_VT));
380
381 if (!ret) {
382 if (id) {
383 dev_dbg(dev, "ignore phy %u rext\n", id);
384 return 0;
385 }
386
387 rext = dwc_phy_read(isys, id,
388 CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15) & 0xfU;
389 dev_dbg(dev, "phy %u rext value = %u\n", id, rext);
390 isys->phy_rext_cal = (rext ? rext : 5);
391
392 return 0;
393 }
394
395 dev_err(dev, "wait phy ready timeout!\n");
396
397 return ret;
398 }
399
lookup_table1(u64 mbps)400 static int lookup_table1(u64 mbps)
401 {
402 unsigned int i;
403
404 for (i = 0; i < ARRAY_SIZE(table1); i++) {
405 if (mbps >= table1[i].min_mbps && mbps <= table1[i].max_mbps)
406 return i;
407 }
408
409 return -ENXIO;
410 }
411
412 static const u16 deskew_fine_mem[] = {
413 0x0404, 0x040c, 0x0414, 0x041c,
414 0x0423, 0x0429, 0x0430, 0x043a,
415 0x0445, 0x044a, 0x0450, 0x045a,
416 0x0465, 0x0469, 0x0472, 0x047a,
417 0x0485, 0x0489, 0x0490, 0x049a,
418 0x04a4, 0x04ac, 0x04b4, 0x04bc,
419 0x04c4, 0x04cc, 0x04d4, 0x04dc,
420 0x04e4, 0x04ec, 0x04f4, 0x04fc,
421 0x0504, 0x050c, 0x0514, 0x051c,
422 0x0523, 0x0529, 0x0530, 0x053a,
423 0x0545, 0x054a, 0x0550, 0x055a,
424 0x0565, 0x0569, 0x0572, 0x057a,
425 0x0585, 0x0589, 0x0590, 0x059a,
426 0x05a4, 0x05ac, 0x05b4, 0x05bc,
427 0x05c4, 0x05cc, 0x05d4, 0x05dc,
428 0x05e4, 0x05ec, 0x05f4, 0x05fc,
429 0x0604, 0x060c, 0x0614, 0x061c,
430 0x0623, 0x0629, 0x0632, 0x063a,
431 0x0645, 0x064a, 0x0650, 0x065a,
432 0x0665, 0x0669, 0x0672, 0x067a,
433 0x0685, 0x0689, 0x0690, 0x069a,
434 0x06a4, 0x06ac, 0x06b4, 0x06bc,
435 0x06c4, 0x06cc, 0x06d4, 0x06dc,
436 0x06e4, 0x06ec, 0x06f4, 0x06fc,
437 0x0704, 0x070c, 0x0714, 0x071c,
438 0x0723, 0x072a, 0x0730, 0x073a,
439 0x0745, 0x074a, 0x0750, 0x075a,
440 0x0765, 0x0769, 0x0772, 0x077a,
441 0x0785, 0x0789, 0x0790, 0x079a,
442 0x07a4, 0x07ac, 0x07b4, 0x07bc,
443 0x07c4, 0x07cc, 0x07d4, 0x07dc,
444 0x07e4, 0x07ec, 0x07f4, 0x07fc,
445 };
446
ipu7_isys_dphy_config(struct ipu7_isys * isys,u8 id,u8 lanes,bool aggregation,u64 mbps)447 static void ipu7_isys_dphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
448 bool aggregation, u64 mbps)
449 {
450 u16 hsrxval0 = 0;
451 u16 hsrxval1 = 0;
452 u16 hsrxval2 = 0;
453 int index;
454 u16 reg;
455 u16 val;
456 u32 i;
457
458 dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, 0, 0, 9);
459 if (mbps > 1500)
460 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7,
461 40, 0, 7);
462 else
463 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7,
464 104, 0, 7);
465
466 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 80, 0, 7);
467 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_0, 191, 0, 9);
468 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_7, 34, 7, 12);
469 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_1, 38, 8, 15);
470 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 4, 12, 15);
471 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 2, 10, 11);
472 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 1, 8, 8);
473 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 38, 0, 7);
474 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 1, 9, 9);
475 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_4, 10, 0, 9);
476 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_6, 20, 0, 9);
477 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_7, 19, 0, 6);
478
479 for (i = 0; i < ARRAY_SIZE(table0); i++) {
480 if (mbps >= table0[i].min_mbps && mbps <= table0[i].max_mbps) {
481 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_3,
482 table0[i].ddlcal_counter_ref,
483 0, 9);
484 break;
485 }
486 }
487
488 index = lookup_table1(mbps);
489 if (index >= 0) {
490 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_1,
491 table1[index].phase_bound, 0, 7);
492 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_5,
493 table1[index].ddlcal_dll_fbk, 4, 9);
494 dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_5,
495 table1[index].ddlcal_ddl_coarse_bank, 0, 3);
496
497 reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8;
498 val = table1[index].oa_lanex_hsrx_cdphy_sel_fast;
499 for (i = 0; i < lanes + 1; i++)
500 dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
501 12, 12);
502 }
503
504 reg = CORE_DIG_DLANE_0_RW_LP_0;
505 for (i = 0; i < lanes; i++)
506 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11);
507
508 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2,
509 0, 0, 0);
510 if (!is_ipu7(isys->adev->isp->hw_ver) ||
511 id == PORT_B || id == PORT_C) {
512 dwc_phy_write_mask(isys, id,
513 CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
514 1, 0, 0);
515 dwc_phy_write_mask(isys, id,
516 CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
517 0, 0, 0);
518 } else {
519 dwc_phy_write_mask(isys, id,
520 CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
521 0, 0, 0);
522 dwc_phy_write_mask(isys, id,
523 CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
524 1, 0, 0);
525 }
526
527 if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
528 dwc_phy_write_mask(isys, id,
529 CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
530 0, 0, 0);
531 dwc_phy_write_mask(isys, id,
532 CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
533 0, 0, 0);
534 }
535
536 dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_6, 1, 0, 2);
537 dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_6, 1, 3, 5);
538
539 reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12;
540 val = (mbps > 1500) ? 0 : 1;
541 for (i = 0; i < lanes + 1; i++) {
542 dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
543 dwc_phy_write_mask(isys, id, reg + (i * 0x400), !val, 3, 3);
544 }
545
546 reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13;
547 val = (mbps > 1500) ? 0 : 1;
548 for (i = 0; i < lanes + 1; i++) {
549 dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
550 dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 3, 3);
551 }
552
553 if (!is_ipu7(isys->adev->isp->hw_ver) || id == PORT_B || id == PORT_C)
554 reg = CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9;
555 else
556 reg = CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9;
557
558 for (i = 0; i < ARRAY_SIZE(table6); i++) {
559 if (mbps >= table6[i].min_mbps && mbps <= table6[i].max_mbps) {
560 dwc_phy_write_mask(isys, id, reg,
561 table6[i].oa_lane_hsrx_hs_clk_div,
562 5, 7);
563 break;
564 }
565 }
566
567 if (aggregation) {
568 dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_0, 1,
569 1, 1);
570
571 reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15;
572 dwc_phy_write_mask(isys, id, reg, 3, 3, 4);
573
574 val = (id == PORT_A) ? 3 : 0;
575 reg = CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15;
576 dwc_phy_write_mask(isys, id, reg, val, 3, 4);
577
578 reg = CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15;
579 dwc_phy_write_mask(isys, id, reg, 3, 3, 4);
580 }
581
582 dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_HS_RX_0, 28, 0, 7);
583 dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_HS_RX_7, 6, 0, 7);
584
585 reg = CORE_DIG_DLANE_0_RW_HS_RX_0;
586 for (i = 0; i < ARRAY_SIZE(table2); i++) {
587 if (mbps >= table2[i].min_mbps && mbps <= table2[i].max_mbps) {
588 u8 j;
589
590 for (j = 0; j < lanes; j++)
591 dwc_phy_write_mask(isys, id, reg + (j * 0x400),
592 table2[i].i_thssettle,
593 8, 15);
594 break;
595 }
596 }
597
598 /* deskew */
599 for (i = 0; i < lanes; i++) {
600 reg = CORE_DIG_DLANE_0_RW_CFG_1;
601 dwc_phy_write_mask(isys, id, reg + (i * 0x400),
602 ((mbps > 1500) ? 0x1 : 0x2), 2, 3);
603
604 reg = CORE_DIG_DLANE_0_RW_HS_RX_2;
605 dwc_phy_write_mask(isys, id, reg + (i * 0x400),
606 ((mbps > 2500) ? 0 : 1), 15, 15);
607 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 13, 13);
608 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 7, 9, 12);
609
610 reg = CORE_DIG_DLANE_0_RW_LP_0;
611 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 12, 15);
612
613 reg = CORE_DIG_DLANE_0_RW_LP_2;
614 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 0);
615
616 reg = CORE_DIG_DLANE_0_RW_HS_RX_1;
617 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 16, 0, 7);
618
619 reg = CORE_DIG_DLANE_0_RW_HS_RX_3;
620 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 2);
621 index = lookup_table1(mbps);
622 if (index >= 0) {
623 val = table1[index].fjump_deskew;
624 dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
625 3, 8);
626 }
627
628 reg = CORE_DIG_DLANE_0_RW_HS_RX_4;
629 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 150, 0, 15);
630
631 reg = CORE_DIG_DLANE_0_RW_HS_RX_5;
632 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 7);
633 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 8, 15);
634
635 reg = CORE_DIG_DLANE_0_RW_HS_RX_6;
636 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 7);
637 index = lookup_table1(mbps);
638 if (index >= 0) {
639 val = table1[index].min_eye_opening_deskew;
640 dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
641 8, 15);
642 }
643 reg = CORE_DIG_DLANE_0_RW_HS_RX_7;
644 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 13, 13);
645 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 15, 15);
646
647 reg = CORE_DIG_DLANE_0_RW_HS_RX_9;
648 index = lookup_table1(mbps);
649 if (index >= 0) {
650 val = table1[index].ddlcal_max_phase;
651 dwc_phy_write_mask(isys, id, reg + (i * 0x400),
652 val, 0, 7);
653 }
654 }
655
656 dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_LP_0, 1, 12, 15);
657 dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_LP_2, 0, 0, 0);
658
659 for (i = 0; i < ARRAY_SIZE(deskew_fine_mem); i++)
660 dwc_phy_write_mask(isys, id, CORE_DIG_COMMON_RW_DESKEW_FINE_MEM,
661 deskew_fine_mem[i], 0, 15);
662
663 if (mbps > 1500) {
664 hsrxval0 = 4;
665 hsrxval2 = 3;
666 }
667
668 if (mbps > 2500)
669 hsrxval1 = 2;
670
671 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
672 hsrxval0, 0, 2);
673 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
674 hsrxval0, 0, 2);
675 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
676 hsrxval0, 0, 2);
677 if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
678 dwc_phy_write_mask(isys, id,
679 CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
680 hsrxval0, 0, 2);
681 dwc_phy_write_mask(isys, id,
682 CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
683 hsrxval0, 0, 2);
684 }
685
686 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
687 hsrxval1, 3, 4);
688 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
689 hsrxval1, 3, 4);
690 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
691 hsrxval1, 3, 4);
692 if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
693 dwc_phy_write_mask(isys, id,
694 CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
695 hsrxval1, 3, 4);
696 dwc_phy_write_mask(isys, id,
697 CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
698 hsrxval1, 3, 4);
699 }
700
701 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15,
702 hsrxval2, 0, 2);
703 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15,
704 hsrxval2, 0, 2);
705 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15,
706 hsrxval2, 0, 2);
707 if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
708 dwc_phy_write_mask(isys, id,
709 CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15,
710 hsrxval2, 0, 2);
711 dwc_phy_write_mask(isys, id,
712 CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15,
713 hsrxval2, 0, 2);
714 }
715
716 /* force and override rext */
717 if (isys->phy_rext_cal && id) {
718 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8,
719 isys->phy_rext_cal, 0, 3);
720 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
721 1, 11, 11);
722 }
723 }
724
ipu7_isys_cphy_config(struct ipu7_isys * isys,u8 id,u8 lanes,bool aggregation,u64 mbps)725 static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
726 bool aggregation, u64 mbps)
727 {
728 u8 trios = 2;
729 u16 coarse_target;
730 u16 deass_thresh;
731 u16 delay_thresh;
732 u16 reset_thresh;
733 u16 cap_prog = 6U;
734 u16 reg;
735 u16 val;
736 u32 i;
737 u64 r64;
738 u32 r;
739
740 if (is_ipu7p5(isys->adev->isp->hw_ver))
741 val = 0x15;
742 else
743 val = 0x155;
744
745 if (is_ipu7(isys->adev->isp->hw_ver))
746 trios = 3;
747
748 dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, val, 0, 9);
749 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7, 104, 0, 7);
750 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 16, 0, 7);
751
752 reg = CORE_DIG_CLANE_0_RW_LP_0;
753 for (i = 0; i < trios; i++)
754 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11);
755
756 val = (mbps > 900U) ? 1U : 0U;
757 for (i = 0; i < trios; i++) {
758 reg = CORE_DIG_CLANE_0_RW_HS_RX_0;
759 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 0, 0);
760 dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
761
762 reg = CORE_DIG_CLANE_0_RW_HS_RX_1;
763 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
764
765 reg = CORE_DIG_CLANE_0_RW_HS_RX_5;
766 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
767
768 reg = CORE_DIG_CLANE_0_RW_HS_RX_6;
769 dwc_phy_write_mask(isys, id, reg + (i * 0x400), 10, 0, 15);
770 }
771
772 /*
773 * Below 900Msps, always use the same value.
774 * The formula is suitable for data rate 80-3500Msps.
775 * Timebase (us) = 1, DIV = 32, TDDL (UI) = 0.5
776 */
777 if (mbps >= 80U)
778 coarse_target = DIV_ROUND_UP_ULL(mbps, 16) - 1;
779 else
780 coarse_target = 56;
781
782 for (i = 0; i < trios; i++) {
783 reg = CORE_DIG_CLANE_0_RW_HS_RX_2 + i * 0x400;
784 dwc_phy_write_mask(isys, id, reg, coarse_target, 0, 15);
785 }
786
787 dwc_phy_write_mask(isys, id,
788 CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2, 1, 0, 0);
789 dwc_phy_write_mask(isys, id,
790 CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2, 0, 0, 0);
791 dwc_phy_write_mask(isys, id,
792 CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2, 1, 0, 0);
793
794 if (!is_ipu7p5(isys->adev->isp->hw_ver) && lanes == 4) {
795 dwc_phy_write_mask(isys, id,
796 CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
797 1, 0, 0);
798 dwc_phy_write_mask(isys, id,
799 CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
800 0, 0, 0);
801 }
802
803 for (i = 0; i < trios; i++) {
804 reg = CORE_DIG_RW_TRIO0_0 + i * 0x400;
805 dwc_phy_write_mask(isys, id, reg, 1, 6, 8);
806 dwc_phy_write_mask(isys, id, reg, 1, 3, 5);
807 dwc_phy_write_mask(isys, id, reg, 2, 0, 2);
808 }
809
810 deass_thresh = (u16)div64_u64_rem(7 * 1000 * 6, mbps * 5U, &r64) + 1;
811 if (r64 != 0)
812 deass_thresh++;
813
814 reg = CORE_DIG_RW_TRIO0_2;
815 for (i = 0; i < trios; i++)
816 dwc_phy_write_mask(isys, id, reg + 0x400 * i,
817 deass_thresh, 0, 7);
818
819 delay_thresh = div64_u64((224U - (9U * 7U)) * 1000U, 5U * mbps) - 7u;
820
821 if (delay_thresh < 1)
822 delay_thresh = 1;
823
824 reg = CORE_DIG_RW_TRIO0_1;
825 for (i = 0; i < trios; i++)
826 dwc_phy_write_mask(isys, id, reg + 0x400 * i,
827 delay_thresh, 0, 15);
828
829 reset_thresh = (u16)div_u64_rem(2U * 5U * mbps, 7U * 1000U, &r);
830 if (!r)
831 reset_thresh--;
832
833 if (reset_thresh < 1)
834 reset_thresh = 1;
835
836 reg = CORE_DIG_RW_TRIO0_0;
837 for (i = 0; i < trios; i++)
838 dwc_phy_write_mask(isys, id, reg + 0x400 * i,
839 reset_thresh, 9, 11);
840
841 reg = CORE_DIG_CLANE_0_RW_LP_0;
842 for (i = 0; i < trios; i++)
843 dwc_phy_write_mask(isys, id, reg + 0x400 * i, 1, 12, 15);
844
845 reg = CORE_DIG_CLANE_0_RW_LP_2;
846 for (i = 0; i < trios; i++)
847 dwc_phy_write_mask(isys, id, reg + 0x400 * i, 0, 0, 0);
848
849 reg = CORE_DIG_CLANE_0_RW_HS_RX_0;
850 for (i = 0; i < trios; i++)
851 dwc_phy_write_mask(isys, id, reg + 0x400 * i, 12, 2, 6);
852
853 for (i = 0; i < ARRAY_SIZE(table7); i++) {
854 if (mbps >= table7[i].min_mbps && mbps <= table7[i].max_mbps) {
855 cap_prog = table7[i].val;
856 break;
857 }
858 }
859
860 for (i = 0; i < (lanes + 1); i++) {
861 reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9 + 0x400 * i;
862 dwc_phy_write_mask(isys, id, reg, 4U, 0, 2);
863 dwc_phy_write_mask(isys, id, reg, 0U, 3, 4);
864
865 reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7 + 0x400 * i;
866 dwc_phy_write_mask(isys, id, reg, cap_prog, 10, 12);
867 }
868 }
869
ipu7_isys_phy_config(struct ipu7_isys * isys,u8 id,u8 lanes,bool aggregation)870 static int ipu7_isys_phy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
871 bool aggregation)
872 {
873 struct device *dev = &isys->adev->auxdev.dev;
874 u32 phy_mode;
875 s64 link_freq;
876 u64 mbps;
877
878 if (aggregation)
879 link_freq = ipu7_isys_csi2_get_link_freq(&isys->csi2[0]);
880 else
881 link_freq = ipu7_isys_csi2_get_link_freq(&isys->csi2[id]);
882
883 if (link_freq < 0) {
884 dev_err(dev, "get link freq failed (%lld)\n", link_freq);
885 return link_freq;
886 }
887
888 mbps = div_u64(link_freq, 500000);
889 dev_dbg(dev, "config phy %u with lanes %u aggregation %d mbps %lld\n",
890 id, lanes, aggregation, mbps);
891
892 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_10, 48, 0, 7);
893 dwc_phy_write_mask(isys, id, CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2,
894 1, 12, 13);
895 dwc_phy_write_mask(isys, id, CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0,
896 63, 2, 7);
897 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_STARTUP_1_1,
898 563, 0, 11);
899 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_2, 5, 0, 7);
900 /* bypass the RCAL state (bit6) */
901 if (aggregation && id != PORT_A)
902 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_2, 0x45,
903 0, 7);
904
905 dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_6, 39, 0, 7);
906 dwc_phy_write_mask(isys, id, PPI_CALIBCTRL_RW_COMMON_BG_0, 500, 0, 8);
907 dwc_phy_write_mask(isys, id, PPI_RW_TERMCAL_CFG_0, 38, 0, 6);
908 dwc_phy_write_mask(isys, id, PPI_RW_OFFSETCAL_CFG_0, 7, 0, 4);
909 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TIMEBASE, 153, 0, 9);
910 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_NREF, 800, 0, 10);
911 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_NREF_RANGE, 27, 0, 4);
912 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TWAIT_CONFIG, 47, 0, 8);
913 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TWAIT_CONFIG, 127, 9, 15);
914 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 47, 7, 15);
915 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 27, 2, 6);
916 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 3, 0, 1);
917 dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_COARSE_CFG, 1, 0, 1);
918 dwc_phy_write_mask(isys, id, PPI_RW_COMMON_CFG, 3, 0, 1);
919 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
920 0, 10, 10);
921 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
922 1, 10, 10);
923 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
924 0, 15, 15);
925 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3,
926 3, 8, 9);
927 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
928 0, 15, 15);
929 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6,
930 7, 12, 14);
931 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
932 0, 8, 10);
933 dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5,
934 0, 8, 8);
935
936 if (aggregation)
937 phy_mode = isys->csi2[0].phy_mode;
938 else
939 phy_mode = isys->csi2[id].phy_mode;
940
941 if (phy_mode == PHY_MODE_DPHY) {
942 ipu7_isys_dphy_config(isys, id, lanes, aggregation, mbps);
943 } else if (phy_mode == PHY_MODE_CPHY) {
944 ipu7_isys_cphy_config(isys, id, lanes, aggregation, mbps);
945 } else {
946 dev_err(dev, "unsupported phy mode %d!\n",
947 isys->csi2[id].phy_mode);
948 }
949
950 return 0;
951 }
952
ipu7_isys_csi_phy_powerup(struct ipu7_isys_csi2 * csi2)953 int ipu7_isys_csi_phy_powerup(struct ipu7_isys_csi2 *csi2)
954 {
955 struct ipu7_isys *isys = csi2->isys;
956 u32 lanes = csi2->nlanes;
957 bool aggregation = false;
958 u32 id = csi2->port;
959 int ret;
960
961 /* lanes remapping for aggregation (port AB) mode */
962 if (!is_ipu7(isys->adev->isp->hw_ver) && lanes > 2 && id == PORT_A) {
963 aggregation = true;
964 lanes = 2;
965 }
966
967 ipu7_isys_csi_phy_reset(isys, id);
968 gpreg_write(isys, id, PHY_CLK_LANE_CONTROL, 0x1);
969 gpreg_write(isys, id, PHY_CLK_LANE_FORCE_CONTROL, 0x2);
970 gpreg_write(isys, id, PHY_LANE_CONTROL_EN, (1U << lanes) - 1U);
971 gpreg_write(isys, id, PHY_LANE_FORCE_CONTROL, 0xf);
972 gpreg_write(isys, id, PHY_MODE, csi2->phy_mode);
973
974 /* config PORT_B if aggregation mode */
975 if (aggregation) {
976 ipu7_isys_csi_phy_reset(isys, PORT_B);
977 gpreg_write(isys, PORT_B, PHY_CLK_LANE_CONTROL, 0x0);
978 gpreg_write(isys, PORT_B, PHY_LANE_CONTROL_EN, 0x3);
979 gpreg_write(isys, PORT_B, PHY_CLK_LANE_FORCE_CONTROL, 0x2);
980 gpreg_write(isys, PORT_B, PHY_LANE_FORCE_CONTROL, 0xf);
981 gpreg_write(isys, PORT_B, PHY_MODE, csi2->phy_mode);
982 }
983
984 ipu7_isys_csi_ctrl_cfg(csi2);
985 ipu7_isys_csi_ctrl_dids_config(csi2, id);
986
987 ret = ipu7_isys_phy_config(isys, id, lanes, aggregation);
988 if (ret < 0)
989 return ret;
990
991 gpreg_write(isys, id, PHY_RESET, 1);
992 gpreg_write(isys, id, PHY_SHUTDOWN, 1);
993 dwc_csi_write(isys, id, DPHY_RSTZ, 1);
994 dwc_csi_write(isys, id, PHY_SHUTDOWNZ, 1);
995 dwc_csi_write(isys, id, CSI2_RESETN, 1);
996
997 ret = ipu7_isys_phy_ready(isys, id);
998 if (ret < 0)
999 return ret;
1000
1001 gpreg_write(isys, id, PHY_LANE_FORCE_CONTROL, 0);
1002 gpreg_write(isys, id, PHY_CLK_LANE_FORCE_CONTROL, 0);
1003
1004 /* config PORT_B if aggregation mode */
1005 if (aggregation) {
1006 ret = ipu7_isys_phy_config(isys, PORT_B, 2, aggregation);
1007 if (ret < 0)
1008 return ret;
1009
1010 gpreg_write(isys, PORT_B, PHY_RESET, 1);
1011 gpreg_write(isys, PORT_B, PHY_SHUTDOWN, 1);
1012 dwc_csi_write(isys, PORT_B, DPHY_RSTZ, 1);
1013 dwc_csi_write(isys, PORT_B, PHY_SHUTDOWNZ, 1);
1014 dwc_csi_write(isys, PORT_B, CSI2_RESETN, 1);
1015 ret = ipu7_isys_phy_ready(isys, PORT_B);
1016 if (ret < 0)
1017 return ret;
1018
1019 gpreg_write(isys, PORT_B, PHY_LANE_FORCE_CONTROL, 0);
1020 gpreg_write(isys, PORT_B, PHY_CLK_LANE_FORCE_CONTROL, 0);
1021 }
1022
1023 return 0;
1024 }
1025
ipu7_isys_csi_phy_powerdown(struct ipu7_isys_csi2 * csi2)1026 void ipu7_isys_csi_phy_powerdown(struct ipu7_isys_csi2 *csi2)
1027 {
1028 struct ipu7_isys *isys = csi2->isys;
1029
1030 ipu7_isys_csi_phy_reset(isys, csi2->port);
1031 if (!is_ipu7(isys->adev->isp->hw_ver) &&
1032 csi2->nlanes > 2U && csi2->port == PORT_A)
1033 ipu7_isys_csi_phy_reset(isys, PORT_B);
1034 }
1035