xref: /linux/drivers/media/pci/intel/ipu6/ipu6-isys-mcd-phy.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2013--2024 Intel Corporation
4  */
5 
6 #include <linux/bits.h>
7 #include <linux/container_of.h>
8 #include <linux/device.h>
9 #include <linux/iopoll.h>
10 #include <linux/list.h>
11 #include <linux/refcount.h>
12 #include <linux/time64.h>
13 
14 #include <media/v4l2-async.h>
15 
16 #include "ipu6.h"
17 #include "ipu6-bus.h"
18 #include "ipu6-isys.h"
19 #include "ipu6-isys-csi2.h"
20 #include "ipu6-platform-isys-csi2-reg.h"
21 
22 #define CSI_REG_HUB_GPREG_PHY_CTL(id) (CSI_REG_BASE + 0x18008 + (id) * 0x8)
23 #define CSI_REG_HUB_GPREG_PHY_CTL_RESET			BIT(4)
24 #define CSI_REG_HUB_GPREG_PHY_CTL_PWR_EN		BIT(0)
25 #define CSI_REG_HUB_GPREG_PHY_STATUS(id) (CSI_REG_BASE + 0x1800c + (id) * 0x8)
26 #define CSI_REG_HUB_GPREG_PHY_POWER_ACK			BIT(0)
27 #define CSI_REG_HUB_GPREG_PHY_READY			BIT(4)
28 
29 #define MCD_PHY_POWER_STATUS_TIMEOUT			(200 * USEC_PER_MSEC)
30 
31 /*
32  * bridge to phy in buttress reg map, each phy has 16 kbytes
33  * only 2 phys for TGL U and Y
34  */
35 #define IPU6_ISYS_MCD_PHY_BASE(i)			(0x10000 + (i) * 0x4000)
36 
37 /*
38  *  There are 2 MCD DPHY instances on TGL and 1 MCD DPHY instance on ADL.
39  *  Each MCD PHY has 12-lanes which has 8 data lanes and 4 clock lanes.
40  *  CSI port 1, 3 (5, 7) can support max 2 data lanes.
41  *  CSI port 0, 2 (4, 6) can support max 4 data lanes.
42  *  PHY configurations are PPI based instead of port.
43  *  Left:
44  *  +---------+---------+---------+---------+--------+---------+----------+
45  *  |         |         |         |         |        |         |          |
46  *  | PPI     | PPI5    | PPI4    | PPI3    | PPI2   | PPI1    | PPI0     |
47  *  +---------+---------+---------+---------+--------+---------+----------+
48  *  |         |         |         |         |        |         |          |
49  *  | x4      | unused  | D3      | D2      | C0     | D0      | D1       |
50  *  |---------+---------+---------+---------+--------+---------+----------+
51  *  |         |         |         |         |        |         |          |
52  *  | x2x2    | C1      | D0      | D1      | C0     | D0      | D1       |
53  *  ----------+---------+---------+---------+--------+---------+----------+
54  *  |         |         |         |         |        |         |          |
55  *  | x2x1    | C1      | D0      | unused  | C0     | D0      | D1       |
56  *  +---------+---------+---------+---------+--------+---------+----------+
57  *  |         |         |         |         |        |         |          |
58  *  | x1x1    | C1      | D0      | unused  | C0     | D0      | unused   |
59  *  +---------+---------+---------+---------+--------+---------+----------+
60  *  |         |         |         |         |        |         |          |
61  *  | x1x2    | C1      | D0      | D1      | C0     | D0      | unused   |
62  *  +---------+---------+---------+---------+--------+---------+----------+
63  *
64  *  Right:
65  *  +---------+---------+---------+---------+--------+---------+----------+
66  *  |         |         |         |         |        |         |          |
67  *  | PPI     | PPI6    | PPI7    | PPI8    | PPI9   | PPI10   | PPI11    |
68  *  +---------+---------+---------+---------+--------+---------+----------+
69  *  |         |         |         |         |        |         |          |
70  *  | x4      | D1      | D0      | C2      | D2     | D3      | unused   |
71  *  |---------+---------+---------+---------+--------+---------+----------+
72  *  |         |         |         |         |        |         |          |
73  *  | x2x2    | D1      | D0      | C2      | D1     | D0      | C3       |
74  *  ----------+---------+---------+---------+--------+---------+----------+
75  *  |         |         |         |         |        |         |          |
76  *  | x2x1    | D1      | D0      | C2      | unused | D0      | C3       |
77  *  +---------+---------+---------+---------+--------+---------+----------+
78  *  |         |         |         |         |        |         |          |
79  *  | x1x1    | unused  | D0      | C2      | unused | D0      | C3       |
80  *  +---------+---------+---------+---------+--------+---------+----------+
81  *  |         |         |         |         |        |         |          |
82  *  | x1x2    | unused  | D0      | C2      | D1     | D0      | C3       |
83  *  +---------+---------+---------+---------+--------+---------+----------+
84  *
85  * ppi mapping per phy :
86  *
87  * x4 + x4:
88  * Left : port0 - PPI range {0, 1, 2, 3, 4}
89  * Right: port2 - PPI range {6, 7, 8, 9, 10}
90  *
91  * x4 + x2x2:
92  * Left: port0 - PPI range {0, 1, 2, 3, 4}
93  * Right: port2 - PPI range {6, 7, 8}, port3 - PPI range {9, 10, 11}
94  *
95  * x2x2 + x4:
96  * Left: port0 - PPI range {0, 1, 2}, port1 - PPI range {3, 4, 5}
97  * Right: port2 - PPI range {6, 7, 8, 9, 10}
98  *
99  * x2x2 + x2x2:
100  * Left : port0 - PPI range {0, 1, 2}, port1 - PPI range {3, 4, 5}
101  * Right: port2 - PPI range {6, 7, 8}, port3 - PPI range {9, 10, 11}
102  */
103 
104 struct phy_reg {
105 	u32 reg;
106 	u32 val;
107 };
108 
109 static const struct phy_reg common_init_regs[] = {
110 	/* for TGL-U, use 0x80000000 */
111 	{0x00000040, 0x80000000},
112 	{0x00000044, 0x00a80880},
113 	{0x00000044, 0x00b80880},
114 	{0x00000010, 0x0000078c},
115 	{0x00000344, 0x2f4401e2},
116 	{0x00000544, 0x924401e2},
117 	{0x00000744, 0x594401e2},
118 	{0x00000944, 0x624401e2},
119 	{0x00000b44, 0xfc4401e2},
120 	{0x00000d44, 0xc54401e2},
121 	{0x00000f44, 0x034401e2},
122 	{0x00001144, 0x8f4401e2},
123 	{0x00001344, 0x754401e2},
124 	{0x00001544, 0xe94401e2},
125 	{0x00001744, 0xcb4401e2},
126 	{0x00001944, 0xfa4401e2}
127 };
128 
129 static const struct phy_reg x1_port0_config_regs[] = {
130 	{0x00000694, 0xc80060fa},
131 	{0x00000680, 0x3d4f78ea},
132 	{0x00000690, 0x10a0140b},
133 	{0x000006a8, 0xdf04010a},
134 	{0x00000700, 0x57050060},
135 	{0x00000710, 0x0030001c},
136 	{0x00000738, 0x5f004444},
137 	{0x0000073c, 0x78464204},
138 	{0x00000748, 0x7821f940},
139 	{0x0000074c, 0xb2000433},
140 	{0x00000494, 0xfe6030fa},
141 	{0x00000480, 0x29ef5ed0},
142 	{0x00000490, 0x10a0540b},
143 	{0x000004a8, 0x7a01010a},
144 	{0x00000500, 0xef053460},
145 	{0x00000510, 0xe030101c},
146 	{0x00000538, 0xdf808444},
147 	{0x0000053c, 0xc8422204},
148 	{0x00000540, 0x0180088c},
149 	{0x00000574, 0x00000000},
150 	{0x00000000, 0x00000000}
151 };
152 
153 static const struct phy_reg x1_port1_config_regs[] = {
154 	{0x00000c94, 0xc80060fa},
155 	{0x00000c80, 0xcf47abea},
156 	{0x00000c90, 0x10a0840b},
157 	{0x00000ca8, 0xdf04010a},
158 	{0x00000d00, 0x57050060},
159 	{0x00000d10, 0x0030001c},
160 	{0x00000d38, 0x5f004444},
161 	{0x00000d3c, 0x78464204},
162 	{0x00000d48, 0x7821f940},
163 	{0x00000d4c, 0xb2000433},
164 	{0x00000a94, 0xc91030fa},
165 	{0x00000a80, 0x5a166ed0},
166 	{0x00000a90, 0x10a0540b},
167 	{0x00000aa8, 0x5d060100},
168 	{0x00000b00, 0xef053460},
169 	{0x00000b10, 0xa030101c},
170 	{0x00000b38, 0xdf808444},
171 	{0x00000b3c, 0xc8422204},
172 	{0x00000b40, 0x0180088c},
173 	{0x00000b74, 0x00000000},
174 	{0x00000000, 0x00000000}
175 };
176 
177 static const struct phy_reg x1_port2_config_regs[] = {
178 	{0x00001294, 0x28f000fa},
179 	{0x00001280, 0x08130cea},
180 	{0x00001290, 0x10a0140b},
181 	{0x000012a8, 0xd704010a},
182 	{0x00001300, 0x8d050060},
183 	{0x00001310, 0x0030001c},
184 	{0x00001338, 0xdf008444},
185 	{0x0000133c, 0x78422204},
186 	{0x00001348, 0x7821f940},
187 	{0x0000134c, 0x5a000433},
188 	{0x00001094, 0x2d20b0fa},
189 	{0x00001080, 0xade75dd0},
190 	{0x00001090, 0x10a0540b},
191 	{0x000010a8, 0xb101010a},
192 	{0x00001100, 0x33053460},
193 	{0x00001110, 0x0030101c},
194 	{0x00001138, 0xdf808444},
195 	{0x0000113c, 0xc8422204},
196 	{0x00001140, 0x8180088c},
197 	{0x00001174, 0x00000000},
198 	{0x00000000, 0x00000000}
199 };
200 
201 static const struct phy_reg x1_port3_config_regs[] = {
202 	{0x00001894, 0xc80060fa},
203 	{0x00001880, 0x0f90fd6a},
204 	{0x00001890, 0x10a0840b},
205 	{0x000018a8, 0xdf04010a},
206 	{0x00001900, 0x57050060},
207 	{0x00001910, 0x0030001c},
208 	{0x00001938, 0x5f004444},
209 	{0x0000193c, 0x78464204},
210 	{0x00001948, 0x7821f940},
211 	{0x0000194c, 0xb2000433},
212 	{0x00001694, 0x3050d0fa},
213 	{0x00001680, 0x0ef6d050},
214 	{0x00001690, 0x10a0540b},
215 	{0x000016a8, 0xe301010a},
216 	{0x00001700, 0x69053460},
217 	{0x00001710, 0xa030101c},
218 	{0x00001738, 0xdf808444},
219 	{0x0000173c, 0xc8422204},
220 	{0x00001740, 0x0180088c},
221 	{0x00001774, 0x00000000},
222 	{0x00000000, 0x00000000}
223 };
224 
225 static const struct phy_reg x2_port0_config_regs[] = {
226 	{0x00000694, 0xc80060fa},
227 	{0x00000680, 0x3d4f78ea},
228 	{0x00000690, 0x10a0140b},
229 	{0x000006a8, 0xdf04010a},
230 	{0x00000700, 0x57050060},
231 	{0x00000710, 0x0030001c},
232 	{0x00000738, 0x5f004444},
233 	{0x0000073c, 0x78464204},
234 	{0x00000748, 0x7821f940},
235 	{0x0000074c, 0xb2000433},
236 	{0x00000494, 0xc80060fa},
237 	{0x00000480, 0x29ef5ed8},
238 	{0x00000490, 0x10a0540b},
239 	{0x000004a8, 0x7a01010a},
240 	{0x00000500, 0xef053460},
241 	{0x00000510, 0xe030101c},
242 	{0x00000538, 0xdf808444},
243 	{0x0000053c, 0xc8422204},
244 	{0x00000540, 0x0180088c},
245 	{0x00000574, 0x00000000},
246 	{0x00000294, 0xc80060fa},
247 	{0x00000280, 0xcb45b950},
248 	{0x00000290, 0x10a0540b},
249 	{0x000002a8, 0x8c01010a},
250 	{0x00000300, 0xef053460},
251 	{0x00000310, 0x8030101c},
252 	{0x00000338, 0x41808444},
253 	{0x0000033c, 0x32422204},
254 	{0x00000340, 0x0180088c},
255 	{0x00000374, 0x00000000},
256 	{0x00000000, 0x00000000}
257 };
258 
259 static const struct phy_reg x2_port1_config_regs[] = {
260 	{0x00000c94, 0xc80060fa},
261 	{0x00000c80, 0xcf47abea},
262 	{0x00000c90, 0x10a0840b},
263 	{0x00000ca8, 0xdf04010a},
264 	{0x00000d00, 0x57050060},
265 	{0x00000d10, 0x0030001c},
266 	{0x00000d38, 0x5f004444},
267 	{0x00000d3c, 0x78464204},
268 	{0x00000d48, 0x7821f940},
269 	{0x00000d4c, 0xb2000433},
270 	{0x00000a94, 0xc80060fa},
271 	{0x00000a80, 0x5a166ed8},
272 	{0x00000a90, 0x10a0540b},
273 	{0x00000aa8, 0x7a01010a},
274 	{0x00000b00, 0xef053460},
275 	{0x00000b10, 0xa030101c},
276 	{0x00000b38, 0xdf808444},
277 	{0x00000b3c, 0xc8422204},
278 	{0x00000b40, 0x0180088c},
279 	{0x00000b74, 0x00000000},
280 	{0x00000894, 0xc80060fa},
281 	{0x00000880, 0x4d4f21d0},
282 	{0x00000890, 0x10a0540b},
283 	{0x000008a8, 0x5601010a},
284 	{0x00000900, 0xef053460},
285 	{0x00000910, 0x8030101c},
286 	{0x00000938, 0xdf808444},
287 	{0x0000093c, 0xc8422204},
288 	{0x00000940, 0x0180088c},
289 	{0x00000974, 0x00000000},
290 	{0x00000000, 0x00000000}
291 };
292 
293 static const struct phy_reg x2_port2_config_regs[] = {
294 	{0x00001294, 0xc80060fa},
295 	{0x00001280, 0x08130cea},
296 	{0x00001290, 0x10a0140b},
297 	{0x000012a8, 0xd704010a},
298 	{0x00001300, 0x8d050060},
299 	{0x00001310, 0x0030001c},
300 	{0x00001338, 0xdf008444},
301 	{0x0000133c, 0x78422204},
302 	{0x00001348, 0x7821f940},
303 	{0x0000134c, 0x5a000433},
304 	{0x00001094, 0xc80060fa},
305 	{0x00001080, 0xade75dd8},
306 	{0x00001090, 0x10a0540b},
307 	{0x000010a8, 0xb101010a},
308 	{0x00001100, 0x33053460},
309 	{0x00001110, 0x0030101c},
310 	{0x00001138, 0xdf808444},
311 	{0x0000113c, 0xc8422204},
312 	{0x00001140, 0x8180088c},
313 	{0x00001174, 0x00000000},
314 	{0x00000e94, 0xc80060fa},
315 	{0x00000e80, 0x0fbf16d0},
316 	{0x00000e90, 0x10a0540b},
317 	{0x00000ea8, 0x7a01010a},
318 	{0x00000f00, 0xf5053460},
319 	{0x00000f10, 0xc030101c},
320 	{0x00000f38, 0xdf808444},
321 	{0x00000f3c, 0xc8422204},
322 	{0x00000f40, 0x8180088c},
323 	{0x00000000, 0x00000000}
324 };
325 
326 static const struct phy_reg x2_port3_config_regs[] = {
327 	{0x00001894, 0xc80060fa},
328 	{0x00001880, 0x0f90fd6a},
329 	{0x00001890, 0x10a0840b},
330 	{0x000018a8, 0xdf04010a},
331 	{0x00001900, 0x57050060},
332 	{0x00001910, 0x0030001c},
333 	{0x00001938, 0x5f004444},
334 	{0x0000193c, 0x78464204},
335 	{0x00001948, 0x7821f940},
336 	{0x0000194c, 0xb2000433},
337 	{0x00001694, 0xc80060fa},
338 	{0x00001680, 0x0ef6d058},
339 	{0x00001690, 0x10a0540b},
340 	{0x000016a8, 0x7a01010a},
341 	{0x00001700, 0x69053460},
342 	{0x00001710, 0xa030101c},
343 	{0x00001738, 0xdf808444},
344 	{0x0000173c, 0xc8422204},
345 	{0x00001740, 0x0180088c},
346 	{0x00001774, 0x00000000},
347 	{0x00001494, 0xc80060fa},
348 	{0x00001480, 0xf9d34bd0},
349 	{0x00001490, 0x10a0540b},
350 	{0x000014a8, 0x7a01010a},
351 	{0x00001500, 0x1b053460},
352 	{0x00001510, 0x0030101c},
353 	{0x00001538, 0xdf808444},
354 	{0x0000153c, 0xc8422204},
355 	{0x00001540, 0x8180088c},
356 	{0x00001574, 0x00000000},
357 	{0x00000000, 0x00000000}
358 };
359 
360 static const struct phy_reg x4_port0_config_regs[] = {
361 	{0x00000694, 0xc80060fa},
362 	{0x00000680, 0x3d4f78fa},
363 	{0x00000690, 0x10a0140b},
364 	{0x000006a8, 0xdf04010a},
365 	{0x00000700, 0x57050060},
366 	{0x00000710, 0x0030001c},
367 	{0x00000738, 0x5f004444},
368 	{0x0000073c, 0x78464204},
369 	{0x00000748, 0x7821f940},
370 	{0x0000074c, 0xb2000433},
371 	{0x00000494, 0xfe6030fa},
372 	{0x00000480, 0x29ef5ed8},
373 	{0x00000490, 0x10a0540b},
374 	{0x000004a8, 0x7a01010a},
375 	{0x00000500, 0xef053460},
376 	{0x00000510, 0xe030101c},
377 	{0x00000538, 0xdf808444},
378 	{0x0000053c, 0xc8422204},
379 	{0x00000540, 0x0180088c},
380 	{0x00000574, 0x00000004},
381 	{0x00000294, 0x23e030fa},
382 	{0x00000280, 0xcb45b950},
383 	{0x00000290, 0x10a0540b},
384 	{0x000002a8, 0x8c01010a},
385 	{0x00000300, 0xef053460},
386 	{0x00000310, 0x8030101c},
387 	{0x00000338, 0x41808444},
388 	{0x0000033c, 0x32422204},
389 	{0x00000340, 0x0180088c},
390 	{0x00000374, 0x00000004},
391 	{0x00000894, 0x5620b0fa},
392 	{0x00000880, 0x4d4f21dc},
393 	{0x00000890, 0x10a0540b},
394 	{0x000008a8, 0x5601010a},
395 	{0x00000900, 0xef053460},
396 	{0x00000910, 0x8030101c},
397 	{0x00000938, 0xdf808444},
398 	{0x0000093c, 0xc8422204},
399 	{0x00000940, 0x0180088c},
400 	{0x00000974, 0x00000004},
401 	{0x00000a94, 0xc91030fa},
402 	{0x00000a80, 0x5a166ecc},
403 	{0x00000a90, 0x10a0540b},
404 	{0x00000aa8, 0x5d01010a},
405 	{0x00000b00, 0xef053460},
406 	{0x00000b10, 0xa030101c},
407 	{0x00000b38, 0xdf808444},
408 	{0x00000b3c, 0xc8422204},
409 	{0x00000b40, 0x0180088c},
410 	{0x00000b74, 0x00000004},
411 	{0x00000000, 0x00000000}
412 };
413 
414 static const struct phy_reg x4_port1_config_regs[] = {
415 	{0x00000000, 0x00000000}
416 };
417 
418 static const struct phy_reg x4_port2_config_regs[] = {
419 	{0x00001294, 0x28f000fa},
420 	{0x00001280, 0x08130cfa},
421 	{0x00001290, 0x10c0140b},
422 	{0x000012a8, 0xd704010a},
423 	{0x00001300, 0x8d050060},
424 	{0x00001310, 0x0030001c},
425 	{0x00001338, 0xdf008444},
426 	{0x0000133c, 0x78422204},
427 	{0x00001348, 0x7821f940},
428 	{0x0000134c, 0x5a000433},
429 	{0x00001094, 0x2d20b0fa},
430 	{0x00001080, 0xade75dd8},
431 	{0x00001090, 0x10a0540b},
432 	{0x000010a8, 0xb101010a},
433 	{0x00001100, 0x33053460},
434 	{0x00001110, 0x0030101c},
435 	{0x00001138, 0xdf808444},
436 	{0x0000113c, 0xc8422204},
437 	{0x00001140, 0x8180088c},
438 	{0x00001174, 0x00000004},
439 	{0x00000e94, 0xd308d0fa},
440 	{0x00000e80, 0x0fbf16d0},
441 	{0x00000e90, 0x10a0540b},
442 	{0x00000ea8, 0x2c01010a},
443 	{0x00000f00, 0xf5053460},
444 	{0x00000f10, 0xc030101c},
445 	{0x00000f38, 0xdf808444},
446 	{0x00000f3c, 0xc8422204},
447 	{0x00000f40, 0x8180088c},
448 	{0x00000f74, 0x00000004},
449 	{0x00001494, 0x136850fa},
450 	{0x00001480, 0xf9d34bdc},
451 	{0x00001490, 0x10a0540b},
452 	{0x000014a8, 0x5a01010a},
453 	{0x00001500, 0x1b053460},
454 	{0x00001510, 0x0030101c},
455 	{0x00001538, 0xdf808444},
456 	{0x0000153c, 0xc8422204},
457 	{0x00001540, 0x8180088c},
458 	{0x00001574, 0x00000004},
459 	{0x00001694, 0x3050d0fa},
460 	{0x00001680, 0x0ef6d04c},
461 	{0x00001690, 0x10a0540b},
462 	{0x000016a8, 0xe301010a},
463 	{0x00001700, 0x69053460},
464 	{0x00001710, 0xa030101c},
465 	{0x00001738, 0xdf808444},
466 	{0x0000173c, 0xc8422204},
467 	{0x00001740, 0x0180088c},
468 	{0x00001774, 0x00000004},
469 	{0x00000000, 0x00000000}
470 };
471 
472 static const struct phy_reg x4_port3_config_regs[] = {
473 	{0x00000000, 0x00000000}
474 };
475 
476 static const struct phy_reg *x1_config_regs[4] = {
477 	x1_port0_config_regs,
478 	x1_port1_config_regs,
479 	x1_port2_config_regs,
480 	x1_port3_config_regs
481 };
482 
483 static const struct phy_reg *x2_config_regs[4] = {
484 	x2_port0_config_regs,
485 	x2_port1_config_regs,
486 	x2_port2_config_regs,
487 	x2_port3_config_regs
488 };
489 
490 static const struct phy_reg *x4_config_regs[4] = {
491 	x4_port0_config_regs,
492 	x4_port1_config_regs,
493 	x4_port2_config_regs,
494 	x4_port3_config_regs
495 };
496 
497 static const struct phy_reg **config_regs[3] = {
498 	x1_config_regs,
499 	x2_config_regs,
500 	x4_config_regs
501 };
502 
503 static int ipu6_isys_mcd_phy_powerup_ack(struct ipu6_isys *isys, u8 id)
504 {
505 	struct device *dev = &isys->adev->auxdev.dev;
506 	void __iomem *isys_base = isys->pdata->base;
507 	u32 val;
508 	int ret;
509 
510 	val = readl(isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
511 	val |= CSI_REG_HUB_GPREG_PHY_CTL_PWR_EN;
512 	writel(val, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
513 
514 	ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id),
515 				 val, val & CSI_REG_HUB_GPREG_PHY_POWER_ACK,
516 				 200, MCD_PHY_POWER_STATUS_TIMEOUT);
517 	if (ret)
518 		dev_err(dev, "PHY%d powerup ack timeout", id);
519 
520 	return ret;
521 }
522 
523 static int ipu6_isys_mcd_phy_powerdown_ack(struct ipu6_isys *isys, u8 id)
524 {
525 	struct device *dev = &isys->adev->auxdev.dev;
526 	void __iomem *isys_base = isys->pdata->base;
527 	u32 val;
528 	int ret;
529 
530 	writel(0, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
531 	ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id),
532 				 val, !(val & CSI_REG_HUB_GPREG_PHY_POWER_ACK),
533 				 200, MCD_PHY_POWER_STATUS_TIMEOUT);
534 	if (ret)
535 		dev_err(dev, "PHY%d powerdown ack timeout", id);
536 
537 	return ret;
538 }
539 
540 static void ipu6_isys_mcd_phy_reset(struct ipu6_isys *isys, u8 id, bool assert)
541 {
542 	void __iomem *isys_base = isys->pdata->base;
543 	u32 val;
544 
545 	val = readl(isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
546 	if (assert)
547 		val |= CSI_REG_HUB_GPREG_PHY_CTL_RESET;
548 	else
549 		val &= ~(CSI_REG_HUB_GPREG_PHY_CTL_RESET);
550 
551 	writel(val, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
552 }
553 
554 static int ipu6_isys_mcd_phy_ready(struct ipu6_isys *isys, u8 id)
555 {
556 	struct device *dev = &isys->adev->auxdev.dev;
557 	void __iomem *isys_base = isys->pdata->base;
558 	u32 val;
559 	int ret;
560 
561 	ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id),
562 				 val, val & CSI_REG_HUB_GPREG_PHY_READY,
563 				 200, MCD_PHY_POWER_STATUS_TIMEOUT);
564 	if (ret)
565 		dev_err(dev, "PHY%d ready ack timeout", id);
566 
567 	return ret;
568 }
569 
570 static void ipu6_isys_mcd_phy_common_init(struct ipu6_isys *isys)
571 {
572 	struct ipu6_bus_device *adev = isys->adev;
573 	struct ipu6_device *isp = adev->isp;
574 	void __iomem *isp_base = isp->base;
575 	struct sensor_async_sd *s_asd;
576 	struct v4l2_async_connection *asc;
577 	void __iomem *phy_base;
578 	unsigned int i;
579 	u8 phy_id;
580 
581 	list_for_each_entry(asc, &isys->notifier.done_list, asc_entry) {
582 		s_asd = container_of(asc, struct sensor_async_sd, asc);
583 		phy_id = s_asd->csi2.port / 4;
584 		phy_base = isp_base + IPU6_ISYS_MCD_PHY_BASE(phy_id);
585 
586 		for (i = 0; i < ARRAY_SIZE(common_init_regs); i++)
587 			writel(common_init_regs[i].val,
588 			       phy_base + common_init_regs[i].reg);
589 	}
590 }
591 
592 static int ipu6_isys_driver_port_to_phy_port(struct ipu6_isys_csi2_config *cfg)
593 {
594 	int phy_port;
595 	int ret;
596 
597 	if (!(cfg->nlanes == 4 || cfg->nlanes == 2 || cfg->nlanes == 1))
598 		return -EINVAL;
599 
600 	/* B,F -> C0 A,E -> C1 C,G -> C2 D,H -> C4 */
601 	/* normalize driver port number */
602 	phy_port = cfg->port % 4;
603 
604 	/* swap port number only for A and B */
605 	if (phy_port == 0)
606 		phy_port = 1;
607 	else if (phy_port == 1)
608 		phy_port = 0;
609 
610 	ret = phy_port;
611 
612 	/* check validity per lane configuration */
613 	if (cfg->nlanes == 4 && !(phy_port == 0 || phy_port == 2))
614 		ret = -EINVAL;
615 	else if ((cfg->nlanes == 2 || cfg->nlanes == 1) &&
616 		 !(phy_port >= 0 && phy_port <= 3))
617 		ret = -EINVAL;
618 
619 	return ret;
620 }
621 
622 static int ipu6_isys_mcd_phy_config(struct ipu6_isys *isys)
623 {
624 	struct device *dev = &isys->adev->auxdev.dev;
625 	struct ipu6_bus_device *adev = isys->adev;
626 	const struct phy_reg **phy_config_regs;
627 	struct ipu6_device *isp = adev->isp;
628 	void __iomem *isp_base = isp->base;
629 	struct sensor_async_sd *s_asd;
630 	struct ipu6_isys_csi2_config cfg;
631 	struct v4l2_async_connection *asc;
632 	int phy_port, phy_id;
633 	unsigned int i;
634 	void __iomem *phy_base;
635 
636 	list_for_each_entry(asc, &isys->notifier.done_list, asc_entry) {
637 		s_asd = container_of(asc, struct sensor_async_sd, asc);
638 		cfg.port = s_asd->csi2.port;
639 		cfg.nlanes = s_asd->csi2.nlanes;
640 		phy_port = ipu6_isys_driver_port_to_phy_port(&cfg);
641 		if (phy_port < 0) {
642 			dev_err(dev, "invalid port %d for lane %d", cfg.port,
643 				cfg.nlanes);
644 			return -ENXIO;
645 		}
646 
647 		phy_id = cfg.port / 4;
648 		phy_base = isp_base + IPU6_ISYS_MCD_PHY_BASE(phy_id);
649 		dev_dbg(dev, "port%d PHY%u lanes %u\n", cfg.port, phy_id,
650 			cfg.nlanes);
651 
652 		phy_config_regs = config_regs[cfg.nlanes / 2];
653 		cfg.port = phy_port;
654 		for (i = 0; phy_config_regs[cfg.port][i].reg; i++)
655 			writel(phy_config_regs[cfg.port][i].val,
656 			       phy_base + phy_config_regs[cfg.port][i].reg);
657 	}
658 
659 	return 0;
660 }
661 
662 #define CSI_MCD_PHY_NUM		2
663 static refcount_t phy_power_ref_count[CSI_MCD_PHY_NUM];
664 
665 int ipu6_isys_mcd_phy_set_power(struct ipu6_isys *isys,
666 				struct ipu6_isys_csi2_config *cfg,
667 				const struct ipu6_isys_csi2_timing *timing,
668 				bool on)
669 {
670 	struct device *dev = &isys->adev->auxdev.dev;
671 	void __iomem *isys_base = isys->pdata->base;
672 	u8 port, phy_id;
673 	refcount_t *ref;
674 	int ret;
675 
676 	port = cfg->port;
677 	phy_id = port / 4;
678 
679 	ref = &phy_power_ref_count[phy_id];
680 
681 	dev_dbg(dev, "for phy %d port %d, lanes: %d\n", phy_id, port,
682 		cfg->nlanes);
683 
684 	if (!isys_base || port >= isys->pdata->ipdata->csi2.nports) {
685 		dev_warn(dev, "invalid port ID %d\n", port);
686 		return -EINVAL;
687 	}
688 
689 	if (on) {
690 		if (refcount_read(ref)) {
691 			dev_dbg(dev, "for phy %d is already UP", phy_id);
692 			refcount_inc(ref);
693 			return 0;
694 		}
695 
696 		ret = ipu6_isys_mcd_phy_powerup_ack(isys, phy_id);
697 		if (ret)
698 			return ret;
699 
700 		ipu6_isys_mcd_phy_reset(isys, phy_id, 0);
701 		ipu6_isys_mcd_phy_common_init(isys);
702 
703 		ret = ipu6_isys_mcd_phy_config(isys);
704 		if (ret)
705 			return ret;
706 
707 		ipu6_isys_mcd_phy_reset(isys, phy_id, 1);
708 		ret = ipu6_isys_mcd_phy_ready(isys, phy_id);
709 		if (ret)
710 			return ret;
711 
712 		refcount_set(ref, 1);
713 		return 0;
714 	}
715 
716 	if (!refcount_dec_and_test(ref))
717 		return 0;
718 
719 	return ipu6_isys_mcd_phy_powerdown_ack(isys, phy_id);
720 }
721