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
ipu6_isys_mcd_phy_powerup_ack(struct ipu6_isys * isys,u8 id)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
ipu6_isys_mcd_phy_powerdown_ack(struct ipu6_isys * isys,u8 id)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
ipu6_isys_mcd_phy_reset(struct ipu6_isys * isys,u8 id,bool assert)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
ipu6_isys_mcd_phy_ready(struct ipu6_isys * isys,u8 id)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
ipu6_isys_mcd_phy_common_init(struct ipu6_isys * isys)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
ipu6_isys_driver_port_to_phy_port(struct ipu6_isys_csi2_config * cfg)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
ipu6_isys_mcd_phy_config(struct ipu6_isys * isys)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
ipu6_isys_mcd_phy_set_power(struct ipu6_isys * isys,struct ipu6_isys_csi2_config * cfg,const struct ipu6_isys_csi2_timing * timing,bool on)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