1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6 #include <linux/bitfield.h>
7 #include <linux/bits.h>
8 #include <linux/delay.h>
9 #include <linux/device.h>
10 #include <linux/iopoll.h>
11 #include <linux/math64.h>
12
13 #include "ipu6-bus.h"
14 #include "ipu6-isys.h"
15 #include "ipu6-platform-isys-csi2-reg.h"
16
17 #define IPU6_DWC_DPHY_BASE(i) (0x238038 + 0x34 * (i))
18 #define IPU6_DWC_DPHY_RSTZ 0x00
19 #define IPU6_DWC_DPHY_SHUTDOWNZ 0x04
20 #define IPU6_DWC_DPHY_HSFREQRANGE 0x08
21 #define IPU6_DWC_DPHY_CFGCLKFREQRANGE 0x0c
22 #define IPU6_DWC_DPHY_TEST_IFC_ACCESS_MODE 0x10
23 #define IPU6_DWC_DPHY_TEST_IFC_REQ 0x14
24 #define IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION 0x18
25 #define IPU6_DWC_DPHY_DFT_CTRL0 0x28
26 #define IPU6_DWC_DPHY_DFT_CTRL1 0x2c
27 #define IPU6_DWC_DPHY_DFT_CTRL2 0x30
28
29 /*
30 * test IFC request definition:
31 * - req: 0 for read, 1 for write
32 * - 12 bits address
33 * - 8bits data (will ignore for read)
34 * --24----16------4-----0
35 * --|-data-|-addr-|-req-|
36 */
37 #define IFC_REQ(req, addr, data) (FIELD_PREP(GENMASK(23, 16), data) | \
38 FIELD_PREP(GENMASK(15, 4), addr) | \
39 FIELD_PREP(GENMASK(1, 0), req))
40
41 #define TEST_IFC_REQ_READ 0
42 #define TEST_IFC_REQ_WRITE 1
43 #define TEST_IFC_REQ_RESET 2
44
45 #define TEST_IFC_ACCESS_MODE_FSM 0
46 #define TEST_IFC_ACCESS_MODE_IFC_CTL 1
47
48 enum phy_fsm_state {
49 PHY_FSM_STATE_POWERON = 0,
50 PHY_FSM_STATE_BGPON = 1,
51 PHY_FSM_STATE_CAL_TYPE = 2,
52 PHY_FSM_STATE_BURNIN_CAL = 3,
53 PHY_FSM_STATE_TERMCAL = 4,
54 PHY_FSM_STATE_OFFSETCAL = 5,
55 PHY_FSM_STATE_OFFSET_LANE = 6,
56 PHY_FSM_STATE_IDLE = 7,
57 PHY_FSM_STATE_ULP = 8,
58 PHY_FSM_STATE_DDLTUNNING = 9,
59 PHY_FSM_STATE_SKEW_BACKWARD = 10,
60 PHY_FSM_STATE_INVALID,
61 };
62
dwc_dphy_write(struct ipu6_isys * isys,u32 phy_id,u32 addr,u32 data)63 static void dwc_dphy_write(struct ipu6_isys *isys, u32 phy_id, u32 addr,
64 u32 data)
65 {
66 struct device *dev = &isys->adev->auxdev.dev;
67 void __iomem *isys_base = isys->pdata->base;
68 void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
69
70 dev_dbg(dev, "write: reg 0x%lx = data 0x%x", base + addr - isys_base,
71 data);
72 writel(data, base + addr);
73 }
74
dwc_dphy_read(struct ipu6_isys * isys,u32 phy_id,u32 addr)75 static u32 dwc_dphy_read(struct ipu6_isys *isys, u32 phy_id, u32 addr)
76 {
77 struct device *dev = &isys->adev->auxdev.dev;
78 void __iomem *isys_base = isys->pdata->base;
79 void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
80 u32 data;
81
82 data = readl(base + addr);
83 dev_dbg(dev, "read: reg 0x%lx = data 0x%x", base + addr - isys_base,
84 data);
85
86 return data;
87 }
88
dwc_dphy_write_mask(struct ipu6_isys * isys,u32 phy_id,u32 addr,u32 data,u8 shift,u8 width)89 static void dwc_dphy_write_mask(struct ipu6_isys *isys, u32 phy_id, u32 addr,
90 u32 data, u8 shift, u8 width)
91 {
92 u32 temp;
93 u32 mask;
94
95 mask = (1 << width) - 1;
96 temp = dwc_dphy_read(isys, phy_id, addr);
97 temp &= ~(mask << shift);
98 temp |= (data & mask) << shift;
99 dwc_dphy_write(isys, phy_id, addr, temp);
100 }
101
dwc_dphy_read_mask(struct ipu6_isys * isys,u32 phy_id,u32 addr,u8 shift,u8 width)102 static u32 __maybe_unused dwc_dphy_read_mask(struct ipu6_isys *isys, u32 phy_id,
103 u32 addr, u8 shift, u8 width)
104 {
105 u32 val;
106
107 val = dwc_dphy_read(isys, phy_id, addr) >> shift;
108 return val & ((1 << width) - 1);
109 }
110
111 #define DWC_DPHY_TIMEOUT (5 * USEC_PER_SEC)
dwc_dphy_ifc_read(struct ipu6_isys * isys,u32 phy_id,u32 addr,u32 * val)112 static int dwc_dphy_ifc_read(struct ipu6_isys *isys, u32 phy_id, u32 addr,
113 u32 *val)
114 {
115 struct device *dev = &isys->adev->auxdev.dev;
116 void __iomem *isys_base = isys->pdata->base;
117 void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
118 void __iomem *reg;
119 u32 completion;
120 int ret;
121
122 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
123 IFC_REQ(TEST_IFC_REQ_READ, addr, 0));
124 reg = base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION;
125 ret = readl_poll_timeout(reg, completion, !(completion & BIT(0)),
126 10, DWC_DPHY_TIMEOUT);
127 if (ret) {
128 dev_err(dev, "DWC ifc request read timeout\n");
129 return ret;
130 }
131
132 *val = completion >> 8 & 0xff;
133 *val = FIELD_GET(GENMASK(15, 8), completion);
134 dev_dbg(dev, "DWC ifc read 0x%x = 0x%x", addr, *val);
135
136 return 0;
137 }
138
dwc_dphy_ifc_write(struct ipu6_isys * isys,u32 phy_id,u32 addr,u32 data)139 static int dwc_dphy_ifc_write(struct ipu6_isys *isys, u32 phy_id, u32 addr,
140 u32 data)
141 {
142 struct device *dev = &isys->adev->auxdev.dev;
143 void __iomem *isys_base = isys->pdata->base;
144 void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
145 void __iomem *reg;
146 u32 completion;
147 int ret;
148
149 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
150 IFC_REQ(TEST_IFC_REQ_WRITE, addr, data));
151 completion = readl(base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION);
152 reg = base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION;
153 ret = readl_poll_timeout(reg, completion, !(completion & BIT(0)),
154 10, DWC_DPHY_TIMEOUT);
155 if (ret)
156 dev_err(dev, "DWC ifc request write timeout\n");
157
158 return ret;
159 }
160
dwc_dphy_ifc_write_mask(struct ipu6_isys * isys,u32 phy_id,u32 addr,u32 data,u8 shift,u8 width)161 static void dwc_dphy_ifc_write_mask(struct ipu6_isys *isys, u32 phy_id,
162 u32 addr, u32 data, u8 shift, u8 width)
163 {
164 u32 temp, mask;
165 int ret;
166
167 ret = dwc_dphy_ifc_read(isys, phy_id, addr, &temp);
168 if (ret)
169 return;
170
171 mask = (1 << width) - 1;
172 temp &= ~(mask << shift);
173 temp |= (data & mask) << shift;
174 dwc_dphy_ifc_write(isys, phy_id, addr, temp);
175 }
176
dwc_dphy_ifc_read_mask(struct ipu6_isys * isys,u32 phy_id,u32 addr,u8 shift,u8 width)177 static u32 dwc_dphy_ifc_read_mask(struct ipu6_isys *isys, u32 phy_id, u32 addr,
178 u8 shift, u8 width)
179 {
180 int ret;
181 u32 val;
182
183 ret = dwc_dphy_ifc_read(isys, phy_id, addr, &val);
184 if (ret)
185 return 0;
186
187 return ((val >> shift) & ((1 << width) - 1));
188 }
189
dwc_dphy_pwr_up(struct ipu6_isys * isys,u32 phy_id)190 static int dwc_dphy_pwr_up(struct ipu6_isys *isys, u32 phy_id)
191 {
192 struct device *dev = &isys->adev->auxdev.dev;
193 u32 fsm_state;
194 int ret;
195
196 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_RSTZ, 1);
197 usleep_range(10, 20);
198 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_SHUTDOWNZ, 1);
199
200 ret = read_poll_timeout(dwc_dphy_ifc_read_mask, fsm_state,
201 (fsm_state == PHY_FSM_STATE_IDLE ||
202 fsm_state == PHY_FSM_STATE_ULP),
203 100, DWC_DPHY_TIMEOUT, false, isys,
204 phy_id, 0x1e, 0, 4);
205
206 if (ret)
207 dev_err(dev, "Dphy %d power up failed, state 0x%x", phy_id,
208 fsm_state);
209
210 return ret;
211 }
212
213 struct dwc_dphy_freq_range {
214 u8 hsfreq;
215 u16 min;
216 u16 max;
217 u16 default_mbps;
218 u16 osc_freq_target;
219 };
220
221 #define DPHY_FREQ_RANGE_NUM (63)
222 #define DPHY_FREQ_RANGE_INVALID_INDEX (0xff)
223 static const struct dwc_dphy_freq_range freqranges[DPHY_FREQ_RANGE_NUM] = {
224 {0x00, 80, 97, 80, 335},
225 {0x10, 80, 107, 90, 335},
226 {0x20, 84, 118, 100, 335},
227 {0x30, 93, 128, 110, 335},
228 {0x01, 103, 139, 120, 335},
229 {0x11, 112, 149, 130, 335},
230 {0x21, 122, 160, 140, 335},
231 {0x31, 131, 170, 150, 335},
232 {0x02, 141, 181, 160, 335},
233 {0x12, 150, 191, 170, 335},
234 {0x22, 160, 202, 180, 335},
235 {0x32, 169, 212, 190, 335},
236 {0x03, 183, 228, 205, 335},
237 {0x13, 198, 244, 220, 335},
238 {0x23, 212, 259, 235, 335},
239 {0x33, 226, 275, 250, 335},
240 {0x04, 250, 301, 275, 335},
241 {0x14, 274, 328, 300, 335},
242 {0x25, 297, 354, 325, 335},
243 {0x35, 321, 380, 350, 335},
244 {0x05, 369, 433, 400, 335},
245 {0x16, 416, 485, 450, 335},
246 {0x26, 464, 538, 500, 335},
247 {0x37, 511, 590, 550, 335},
248 {0x07, 559, 643, 600, 335},
249 {0x18, 606, 695, 650, 335},
250 {0x28, 654, 748, 700, 335},
251 {0x39, 701, 800, 750, 335},
252 {0x09, 749, 853, 800, 335},
253 {0x19, 796, 905, 850, 335},
254 {0x29, 844, 958, 900, 335},
255 {0x3a, 891, 1010, 950, 335},
256 {0x0a, 939, 1063, 1000, 335},
257 {0x1a, 986, 1115, 1050, 335},
258 {0x2a, 1034, 1168, 1100, 335},
259 {0x3b, 1081, 1220, 1150, 335},
260 {0x0b, 1129, 1273, 1200, 335},
261 {0x1b, 1176, 1325, 1250, 335},
262 {0x2b, 1224, 1378, 1300, 335},
263 {0x3c, 1271, 1430, 1350, 335},
264 {0x0c, 1319, 1483, 1400, 335},
265 {0x1c, 1366, 1535, 1450, 335},
266 {0x2c, 1414, 1588, 1500, 335},
267 {0x3d, 1461, 1640, 1550, 208},
268 {0x0d, 1509, 1693, 1600, 214},
269 {0x1d, 1556, 1745, 1650, 221},
270 {0x2e, 1604, 1798, 1700, 228},
271 {0x3e, 1651, 1850, 1750, 234},
272 {0x0e, 1699, 1903, 1800, 241},
273 {0x1e, 1746, 1955, 1850, 248},
274 {0x2f, 1794, 2008, 1900, 255},
275 {0x3f, 1841, 2060, 1950, 261},
276 {0x0f, 1889, 2113, 2000, 268},
277 {0x40, 1936, 2165, 2050, 275},
278 {0x41, 1984, 2218, 2100, 281},
279 {0x42, 2031, 2270, 2150, 288},
280 {0x43, 2079, 2323, 2200, 294},
281 {0x44, 2126, 2375, 2250, 302},
282 {0x45, 2174, 2428, 2300, 308},
283 {0x46, 2221, 2480, 2350, 315},
284 {0x47, 2269, 2500, 2400, 321},
285 {0x48, 2316, 2500, 2450, 328},
286 {0x49, 2364, 2500, 2500, 335}
287 };
288
get_hsfreq_by_mbps(u32 mbps)289 static u16 get_hsfreq_by_mbps(u32 mbps)
290 {
291 unsigned int i = DPHY_FREQ_RANGE_NUM;
292
293 while (i--) {
294 if (freqranges[i].default_mbps == mbps ||
295 (mbps >= freqranges[i].min && mbps <= freqranges[i].max))
296 return i;
297 }
298
299 return DPHY_FREQ_RANGE_INVALID_INDEX;
300 }
301
ipu6_isys_dwc_phy_config(struct ipu6_isys * isys,u32 phy_id,u32 mbps)302 static int ipu6_isys_dwc_phy_config(struct ipu6_isys *isys,
303 u32 phy_id, u32 mbps)
304 {
305 struct ipu6_bus_device *adev = isys->adev;
306 struct device *dev = &adev->auxdev.dev;
307 struct ipu6_device *isp = adev->isp;
308 u32 cfg_clk_freqrange;
309 u32 osc_freq_target;
310 u32 index;
311
312 dev_dbg(dev, "config Dphy %u with %u mbps", phy_id, mbps);
313
314 index = get_hsfreq_by_mbps(mbps);
315 if (index == DPHY_FREQ_RANGE_INVALID_INDEX) {
316 dev_err(dev, "link freq not found for mbps %u", mbps);
317 return -EINVAL;
318 }
319
320 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_HSFREQRANGE,
321 freqranges[index].hsfreq, 0, 7);
322
323 /* Force termination Calibration */
324 if (isys->phy_termcal_val) {
325 dwc_dphy_ifc_write_mask(isys, phy_id, 0x20a, 0x1, 0, 1);
326 dwc_dphy_ifc_write_mask(isys, phy_id, 0x209, 0x3, 0, 2);
327 dwc_dphy_ifc_write_mask(isys, phy_id, 0x209,
328 isys->phy_termcal_val, 4, 4);
329 }
330
331 /*
332 * Enable override to configure the DDL target oscillation
333 * frequency on bit 0 of register 0xe4
334 */
335 dwc_dphy_ifc_write_mask(isys, phy_id, 0xe4, 0x1, 0, 1);
336 /*
337 * configure registers 0xe2, 0xe3 with the
338 * appropriate DDL target oscillation frequency
339 * 0x1cc(460)
340 */
341 osc_freq_target = freqranges[index].osc_freq_target;
342 dwc_dphy_ifc_write_mask(isys, phy_id, 0xe2,
343 osc_freq_target & 0xff, 0, 8);
344 dwc_dphy_ifc_write_mask(isys, phy_id, 0xe3,
345 (osc_freq_target >> 8) & 0xf, 0, 4);
346
347 if (mbps < 1500) {
348 /* deskew_polarity_rw, for < 1.5Gbps */
349 dwc_dphy_ifc_write_mask(isys, phy_id, 0x8, 0x1, 5, 1);
350 }
351
352 /*
353 * Set cfgclkfreqrange[5:0] = round[(Fcfg_clk(MHz)-17)*4]
354 * (38.4 - 17) * 4 = ~85 (0x55)
355 */
356 cfg_clk_freqrange = (isp->buttress.ref_clk - 170) * 4 / 10;
357 dev_dbg(dev, "ref_clk = %u clk_freqrange = %u",
358 isp->buttress.ref_clk, cfg_clk_freqrange);
359 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_CFGCLKFREQRANGE,
360 cfg_clk_freqrange, 0, 8);
361
362 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0x1, 4, 1);
363 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0x1, 8, 1);
364
365 return 0;
366 }
367
ipu6_isys_dwc_phy_aggr_setup(struct ipu6_isys * isys,u32 master,u32 slave,u32 mbps)368 static void ipu6_isys_dwc_phy_aggr_setup(struct ipu6_isys *isys, u32 master,
369 u32 slave, u32 mbps)
370 {
371 /* Config mastermacro */
372 dwc_dphy_ifc_write_mask(isys, master, 0x133, 0x1, 0, 1);
373 dwc_dphy_ifc_write_mask(isys, slave, 0x133, 0x0, 0, 1);
374
375 /* Config master PHY clk lane to drive long channel clk */
376 dwc_dphy_ifc_write_mask(isys, master, 0x307, 0x1, 2, 1);
377 dwc_dphy_ifc_write_mask(isys, slave, 0x307, 0x0, 2, 1);
378
379 /* Config both PHYs data lanes to get clk from long channel */
380 dwc_dphy_ifc_write_mask(isys, master, 0x508, 0x1, 5, 1);
381 dwc_dphy_ifc_write_mask(isys, slave, 0x508, 0x1, 5, 1);
382 dwc_dphy_ifc_write_mask(isys, master, 0x708, 0x1, 5, 1);
383 dwc_dphy_ifc_write_mask(isys, slave, 0x708, 0x1, 5, 1);
384
385 /* Config slave PHY clk lane to bypass long channel clk to DDR clk */
386 dwc_dphy_ifc_write_mask(isys, master, 0x308, 0x0, 3, 1);
387 dwc_dphy_ifc_write_mask(isys, slave, 0x308, 0x1, 3, 1);
388
389 /* Override slave PHY clk lane enable (DPHYRXCLK_CLL_demux module) */
390 dwc_dphy_ifc_write_mask(isys, slave, 0xe0, 0x3, 0, 2);
391
392 /* Override slave PHY DDR clk lane enable (DPHYHSRX_div124 module) */
393 dwc_dphy_ifc_write_mask(isys, slave, 0xe1, 0x1, 1, 1);
394 dwc_dphy_ifc_write_mask(isys, slave, 0x307, 0x1, 3, 1);
395
396 /* Turn off slave PHY LP-RX clk lane */
397 dwc_dphy_ifc_write_mask(isys, slave, 0x304, 0x1, 7, 1);
398 dwc_dphy_ifc_write_mask(isys, slave, 0x305, 0xa, 0, 5);
399 }
400
401 #define PHY_E 4
ipu6_isys_dwc_phy_powerup_ack(struct ipu6_isys * isys,u32 phy_id)402 static int ipu6_isys_dwc_phy_powerup_ack(struct ipu6_isys *isys, u32 phy_id)
403 {
404 struct device *dev = &isys->adev->auxdev.dev;
405 u32 rescal_done;
406 int ret;
407
408 ret = dwc_dphy_pwr_up(isys, phy_id);
409 if (ret != 0) {
410 dev_err(dev, "Dphy %u power up failed(%d)", phy_id, ret);
411 return ret;
412 }
413
414 /* reset forcerxmode */
415 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0, 4, 1);
416 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0, 8, 1);
417
418 dev_dbg(dev, "Dphy %u is ready!", phy_id);
419
420 if (phy_id != PHY_E || isys->phy_termcal_val)
421 return 0;
422
423 usleep_range(100, 200);
424 rescal_done = dwc_dphy_ifc_read_mask(isys, phy_id, 0x221, 7, 1);
425 if (rescal_done) {
426 isys->phy_termcal_val = dwc_dphy_ifc_read_mask(isys, phy_id,
427 0x220, 2, 4);
428 dev_dbg(dev, "termcal done with value = %u",
429 isys->phy_termcal_val);
430 }
431
432 return 0;
433 }
434
ipu6_isys_dwc_phy_reset(struct ipu6_isys * isys,u32 phy_id)435 static void ipu6_isys_dwc_phy_reset(struct ipu6_isys *isys, u32 phy_id)
436 {
437 dev_dbg(&isys->adev->auxdev.dev, "Reset phy %u", phy_id);
438
439 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_SHUTDOWNZ, 0);
440 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_RSTZ, 0);
441 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_ACCESS_MODE,
442 TEST_IFC_ACCESS_MODE_FSM);
443 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
444 TEST_IFC_REQ_RESET);
445 }
446
ipu6_isys_dwc_phy_set_power(struct ipu6_isys * isys,struct ipu6_isys_csi2_config * cfg,const struct ipu6_isys_csi2_timing * timing,bool on)447 int ipu6_isys_dwc_phy_set_power(struct ipu6_isys *isys,
448 struct ipu6_isys_csi2_config *cfg,
449 const struct ipu6_isys_csi2_timing *timing,
450 bool on)
451 {
452 struct device *dev = &isys->adev->auxdev.dev;
453 void __iomem *isys_base = isys->pdata->base;
454 u32 phy_id, primary, secondary;
455 u32 nlanes, port, mbps;
456 s64 link_freq;
457 int ret;
458
459 port = cfg->port;
460
461 if (!isys_base || port >= isys->pdata->ipdata->csi2.nports) {
462 dev_warn(dev, "invalid port ID %d\n", port);
463 return -EINVAL;
464 }
465
466 nlanes = cfg->nlanes;
467 /* only port 0, 2 and 4 support 4 lanes */
468 if (nlanes == 4 && port % 2) {
469 dev_err(dev, "invalid csi-port %u with %u lanes\n", port,
470 nlanes);
471 return -EINVAL;
472 }
473
474 link_freq = ipu6_isys_csi2_get_link_freq(&isys->csi2[port]);
475 if (link_freq < 0) {
476 dev_err(dev, "get link freq failed(%lld).\n", link_freq);
477 return link_freq;
478 }
479
480 mbps = div_u64(link_freq, 500000);
481
482 phy_id = port;
483 primary = port & ~1;
484 secondary = primary + 1;
485 if (on) {
486 if (nlanes == 4) {
487 dev_dbg(dev, "config phy %u and %u in aggr mode\n",
488 primary, secondary);
489
490 ipu6_isys_dwc_phy_reset(isys, primary);
491 ipu6_isys_dwc_phy_reset(isys, secondary);
492 ipu6_isys_dwc_phy_aggr_setup(isys, primary,
493 secondary, mbps);
494
495 ret = ipu6_isys_dwc_phy_config(isys, primary, mbps);
496 if (ret)
497 return ret;
498 ret = ipu6_isys_dwc_phy_config(isys, secondary, mbps);
499 if (ret)
500 return ret;
501
502 ret = ipu6_isys_dwc_phy_powerup_ack(isys, primary);
503 if (ret)
504 return ret;
505
506 ret = ipu6_isys_dwc_phy_powerup_ack(isys, secondary);
507 return ret;
508 }
509
510 dev_dbg(dev, "config phy %u with %u lanes in non-aggr mode\n",
511 phy_id, nlanes);
512
513 ipu6_isys_dwc_phy_reset(isys, phy_id);
514 ret = ipu6_isys_dwc_phy_config(isys, phy_id, mbps);
515 if (ret)
516 return ret;
517
518 ret = ipu6_isys_dwc_phy_powerup_ack(isys, phy_id);
519 return ret;
520 }
521
522 if (nlanes == 4) {
523 dev_dbg(dev, "Power down phy %u and phy %u for port %u\n",
524 primary, secondary, port);
525 ipu6_isys_dwc_phy_reset(isys, secondary);
526 ipu6_isys_dwc_phy_reset(isys, primary);
527
528 return 0;
529 }
530
531 dev_dbg(dev, "Powerdown phy %u with %u lanes\n", phy_id, nlanes);
532
533 ipu6_isys_dwc_phy_reset(isys, phy_id);
534
535 return 0;
536 }
537