xref: /linux/drivers/staging/media/ipu7/ipu7-isys-csi-phy.c (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 */
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 
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
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 
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 
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 
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 
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 
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 
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