File Index
Files and directories
Sign in
FILE

ipu6-isys-mcd-phy.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/pci/intel/ipu6/ipu6-isys-mcd-phy.c C
  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
104struct phy_reg {
105	u32 reg;
106	u32 val;
107};
108
109static 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
129static 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
153static 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
177static 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
201static 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
225static 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
259static 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
293static 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
326static 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
360static 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
414static const struct phy_reg x4_port1_config_regs[] = {
415	{0x00000000, 0x00000000}
416};
417
418static 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
472static const struct phy_reg x4_port3_config_regs[] = {
473	{0x00000000, 0x00000000}
474};
475
476static 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
483static 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
490static 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
497static const struct phy_reg **config_regs[3] = {
498	x1_config_regs,
499	x2_config_regs,
500	x4_config_regs
501};
502
503static 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
523static 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
540static 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
554static 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
570static 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
592static 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
622static 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
663static refcount_t phy_power_ref_count[CSI_MCD_PHY_NUM];
664
665int 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}
~/ Read-only file preview.