1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Driver for Renesas R-Car MIPI CSI-2 Receiver |
4 | * |
5 | * Copyright (C) 2018 Renesas Electronics Corp. |
6 | */ |
7 | |
8 | #include <linux/delay.h> |
9 | #include <linux/interrupt.h> |
10 | #include <linux/io.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of.h> |
13 | #include <linux/of_graph.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/pm_runtime.h> |
16 | #include <linux/reset.h> |
17 | #include <linux/sys_soc.h> |
18 | |
19 | #include <media/mipi-csi2.h> |
20 | #include <media/v4l2-ctrls.h> |
21 | #include <media/v4l2-device.h> |
22 | #include <media/v4l2-fwnode.h> |
23 | #include <media/v4l2-mc.h> |
24 | #include <media/v4l2-subdev.h> |
25 | |
26 | struct rcar_csi2; |
27 | |
28 | /* Register offsets and bits */ |
29 | |
30 | /* Control Timing Select */ |
31 | #define TREF_REG 0x00 |
32 | #define TREF_TREF BIT(0) |
33 | |
34 | /* Software Reset */ |
35 | #define SRST_REG 0x04 |
36 | #define SRST_SRST BIT(0) |
37 | |
38 | /* PHY Operation Control */ |
39 | #define PHYCNT_REG 0x08 |
40 | #define PHYCNT_SHUTDOWNZ BIT(17) |
41 | #define PHYCNT_RSTZ BIT(16) |
42 | #define PHYCNT_ENABLECLK BIT(4) |
43 | #define PHYCNT_ENABLE_3 BIT(3) |
44 | #define PHYCNT_ENABLE_2 BIT(2) |
45 | #define PHYCNT_ENABLE_1 BIT(1) |
46 | #define PHYCNT_ENABLE_0 BIT(0) |
47 | |
48 | /* Checksum Control */ |
49 | #define CHKSUM_REG 0x0c |
50 | #define CHKSUM_ECC_EN BIT(1) |
51 | #define CHKSUM_CRC_EN BIT(0) |
52 | |
53 | /* |
54 | * Channel Data Type Select |
55 | * VCDT[0-15]: Channel 0 VCDT[16-31]: Channel 1 |
56 | * VCDT2[0-15]: Channel 2 VCDT2[16-31]: Channel 3 |
57 | */ |
58 | #define VCDT_REG 0x10 |
59 | #define VCDT2_REG 0x14 |
60 | #define VCDT_VCDTN_EN BIT(15) |
61 | #define VCDT_SEL_VC(n) (((n) & 0x3) << 8) |
62 | #define VCDT_SEL_DTN_ON BIT(6) |
63 | #define VCDT_SEL_DT(n) (((n) & 0x3f) << 0) |
64 | |
65 | /* Frame Data Type Select */ |
66 | #define FRDT_REG 0x18 |
67 | |
68 | /* Field Detection Control */ |
69 | #define FLD_REG 0x1c |
70 | #define FLD_FLD_NUM(n) (((n) & 0xff) << 16) |
71 | #define FLD_DET_SEL(n) (((n) & 0x3) << 4) |
72 | #define FLD_FLD_EN4 BIT(3) |
73 | #define FLD_FLD_EN3 BIT(2) |
74 | #define FLD_FLD_EN2 BIT(1) |
75 | #define FLD_FLD_EN BIT(0) |
76 | |
77 | /* Automatic Standby Control */ |
78 | #define ASTBY_REG 0x20 |
79 | |
80 | /* Long Data Type Setting 0 */ |
81 | #define LNGDT0_REG 0x28 |
82 | |
83 | /* Long Data Type Setting 1 */ |
84 | #define LNGDT1_REG 0x2c |
85 | |
86 | /* Interrupt Enable */ |
87 | #define INTEN_REG 0x30 |
88 | #define INTEN_INT_AFIFO_OF BIT(27) |
89 | #define INTEN_INT_ERRSOTHS BIT(4) |
90 | #define INTEN_INT_ERRSOTSYNCHS BIT(3) |
91 | |
92 | /* Interrupt Source Mask */ |
93 | #define INTCLOSE_REG 0x34 |
94 | |
95 | /* Interrupt Status Monitor */ |
96 | #define INTSTATE_REG 0x38 |
97 | #define INTSTATE_INT_ULPS_START BIT(7) |
98 | #define INTSTATE_INT_ULPS_END BIT(6) |
99 | |
100 | /* Interrupt Error Status Monitor */ |
101 | #define INTERRSTATE_REG 0x3c |
102 | |
103 | /* Short Packet Data */ |
104 | #define SHPDAT_REG 0x40 |
105 | |
106 | /* Short Packet Count */ |
107 | #define SHPCNT_REG 0x44 |
108 | |
109 | /* LINK Operation Control */ |
110 | #define LINKCNT_REG 0x48 |
111 | #define LINKCNT_MONITOR_EN BIT(31) |
112 | #define LINKCNT_REG_MONI_PACT_EN BIT(25) |
113 | #define LINKCNT_ICLK_NONSTOP BIT(24) |
114 | |
115 | /* Lane Swap */ |
116 | #define LSWAP_REG 0x4c |
117 | #define LSWAP_L3SEL(n) (((n) & 0x3) << 6) |
118 | #define LSWAP_L2SEL(n) (((n) & 0x3) << 4) |
119 | #define LSWAP_L1SEL(n) (((n) & 0x3) << 2) |
120 | #define LSWAP_L0SEL(n) (((n) & 0x3) << 0) |
121 | |
122 | /* PHY Test Interface Write Register */ |
123 | #define PHTW_REG 0x50 |
124 | #define PHTW_DWEN BIT(24) |
125 | #define PHTW_TESTDIN_DATA(n) (((n & 0xff)) << 16) |
126 | #define PHTW_CWEN BIT(8) |
127 | #define PHTW_TESTDIN_CODE(n) ((n & 0xff)) |
128 | |
129 | #define PHYFRX_REG 0x64 |
130 | #define PHYFRX_FORCERX_MODE_3 BIT(3) |
131 | #define PHYFRX_FORCERX_MODE_2 BIT(2) |
132 | #define PHYFRX_FORCERX_MODE_1 BIT(1) |
133 | #define PHYFRX_FORCERX_MODE_0 BIT(0) |
134 | |
135 | /* V4H BASE registers */ |
136 | #define V4H_N_LANES_REG 0x0004 |
137 | #define V4H_CSI2_RESETN_REG 0x0008 |
138 | #define V4H_PHY_MODE_REG 0x001c |
139 | #define V4H_PHY_SHUTDOWNZ_REG 0x0040 |
140 | #define V4H_DPHY_RSTZ_REG 0x0044 |
141 | #define V4H_FLDC_REG 0x0804 |
142 | #define V4H_FLDD_REG 0x0808 |
143 | #define V4H_IDIC_REG 0x0810 |
144 | #define V4H_PHY_EN_REG 0x2000 |
145 | |
146 | #define V4H_ST_PHYST_REG 0x2814 |
147 | #define V4H_ST_PHYST_ST_PHY_READY BIT(31) |
148 | #define V4H_ST_PHYST_ST_STOPSTATE_3 BIT(3) |
149 | #define V4H_ST_PHYST_ST_STOPSTATE_2 BIT(2) |
150 | #define V4H_ST_PHYST_ST_STOPSTATE_1 BIT(1) |
151 | #define V4H_ST_PHYST_ST_STOPSTATE_0 BIT(0) |
152 | |
153 | /* V4H PPI registers */ |
154 | #define V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(n) (0x21800 + ((n) * 2)) /* n = 0 - 9 */ |
155 | #define V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG 0x21822 |
156 | #define V4H_PPI_CALIBCTRL_RW_COMMON_BG_0_REG 0x2184c |
157 | #define V4H_PPI_RW_LPDCOCAL_TIMEBASE_REG 0x21c02 |
158 | #define V4H_PPI_RW_LPDCOCAL_NREF_REG 0x21c04 |
159 | #define V4H_PPI_RW_LPDCOCAL_NREF_RANGE_REG 0x21c06 |
160 | #define V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG 0x21c0a |
161 | #define V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG 0x21c0c |
162 | #define V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG 0x21c10 |
163 | #define V4H_PPI_RW_COMMON_CFG_REG 0x21c6c |
164 | #define V4H_PPI_RW_TERMCAL_CFG_0_REG 0x21c80 |
165 | #define V4H_PPI_RW_OFFSETCAL_CFG_0_REG 0x21ca0 |
166 | |
167 | /* V4H CORE registers */ |
168 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(n) (0x22040 + ((n) * 2)) /* n = 0 - 15 */ |
169 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(n) (0x22440 + ((n) * 2)) /* n = 0 - 15 */ |
170 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(n) (0x22840 + ((n) * 2)) /* n = 0 - 15 */ |
171 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(n) (0x22c40 + ((n) * 2)) /* n = 0 - 15 */ |
172 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(n) (0x23040 + ((n) * 2)) /* n = 0 - 15 */ |
173 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n) (0x23840 + ((n) * 2)) /* n = 0 - 11 */ |
174 | #define V4H_CORE_DIG_RW_COMMON_REG(n) (0x23880 + ((n) * 2)) /* n = 0 - 15 */ |
175 | #define V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(n) (0x239e0 + ((n) * 2)) /* n = 0 - 3 */ |
176 | #define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG 0x2a400 |
177 | #define V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG 0x2a60c |
178 | |
179 | /* V4H C-PHY */ |
180 | #define V4H_CORE_DIG_RW_TRIO0_REG(n) (0x22100 + ((n) * 2)) /* n = 0 - 3 */ |
181 | #define V4H_CORE_DIG_RW_TRIO1_REG(n) (0x22500 + ((n) * 2)) /* n = 0 - 3 */ |
182 | #define V4H_CORE_DIG_RW_TRIO2_REG(n) (0x22900 + ((n) * 2)) /* n = 0 - 3 */ |
183 | #define V4H_CORE_DIG_CLANE_0_RW_LP_0_REG 0x2a080 |
184 | #define V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(n) (0x2a100 + ((n) * 2)) /* n = 0 - 6 */ |
185 | #define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG 0x2a480 |
186 | #define V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(n) (0x2a500 + ((n) * 2)) /* n = 0 - 6 */ |
187 | #define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG 0x2a880 |
188 | #define V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(n) (0x2a900 + ((n) * 2)) /* n = 0 - 6 */ |
189 | |
190 | struct rcsi2_cphy_setting { |
191 | u16 msps; |
192 | u16 rx2; |
193 | u16 trio0; |
194 | u16 trio1; |
195 | u16 trio2; |
196 | u16 lane27; |
197 | u16 lane29; |
198 | }; |
199 | |
200 | static const struct rcsi2_cphy_setting cphy_setting_table_r8a779g0[] = { |
201 | { .msps = 80, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0134, .trio2 = 0x6a, .lane27 = 0x0000, .lane29 = 0x0a24 }, |
202 | { .msps = 100, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x00f5, .trio2 = 0x55, .lane27 = 0x0000, .lane29 = 0x0a24 }, |
203 | { .msps = 200, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0077, .trio2 = 0x2b, .lane27 = 0x0000, .lane29 = 0x0a44 }, |
204 | { .msps = 300, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x004d, .trio2 = 0x1d, .lane27 = 0x0000, .lane29 = 0x0a44 }, |
205 | { .msps = 400, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0038, .trio2 = 0x16, .lane27 = 0x0000, .lane29 = 0x0a64 }, |
206 | { .msps = 500, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x002b, .trio2 = 0x12, .lane27 = 0x0000, .lane29 = 0x0a64 }, |
207 | { .msps = 600, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0023, .trio2 = 0x0f, .lane27 = 0x0000, .lane29 = 0x0a64 }, |
208 | { .msps = 700, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x001d, .trio2 = 0x0d, .lane27 = 0x0000, .lane29 = 0x0a84 }, |
209 | { .msps = 800, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0018, .trio2 = 0x0c, .lane27 = 0x0000, .lane29 = 0x0a84 }, |
210 | { .msps = 900, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0015, .trio2 = 0x0b, .lane27 = 0x0000, .lane29 = 0x0a84 }, |
211 | { .msps = 1000, .rx2 = 0x3e, .trio0 = 0x024a, .trio1 = 0x0012, .trio2 = 0x0a, .lane27 = 0x0400, .lane29 = 0x0a84 }, |
212 | { .msps = 1100, .rx2 = 0x44, .trio0 = 0x024a, .trio1 = 0x000f, .trio2 = 0x09, .lane27 = 0x0800, .lane29 = 0x0a84 }, |
213 | { .msps = 1200, .rx2 = 0x4a, .trio0 = 0x024a, .trio1 = 0x000e, .trio2 = 0x08, .lane27 = 0x0c00, .lane29 = 0x0a84 }, |
214 | { .msps = 1300, .rx2 = 0x51, .trio0 = 0x024a, .trio1 = 0x000c, .trio2 = 0x08, .lane27 = 0x0c00, .lane29 = 0x0aa4 }, |
215 | { .msps = 1400, .rx2 = 0x57, .trio0 = 0x024a, .trio1 = 0x000b, .trio2 = 0x07, .lane27 = 0x1000, .lane29 = 0x0aa4 }, |
216 | { .msps = 1500, .rx2 = 0x5d, .trio0 = 0x044a, .trio1 = 0x0009, .trio2 = 0x07, .lane27 = 0x1000, .lane29 = 0x0aa4 }, |
217 | { .msps = 1600, .rx2 = 0x63, .trio0 = 0x044a, .trio1 = 0x0008, .trio2 = 0x07, .lane27 = 0x1400, .lane29 = 0x0aa4 }, |
218 | { .msps = 1700, .rx2 = 0x6a, .trio0 = 0x044a, .trio1 = 0x0007, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, |
219 | { .msps = 1800, .rx2 = 0x70, .trio0 = 0x044a, .trio1 = 0x0007, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, |
220 | { .msps = 1900, .rx2 = 0x76, .trio0 = 0x044a, .trio1 = 0x0006, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, |
221 | { .msps = 2000, .rx2 = 0x7c, .trio0 = 0x044a, .trio1 = 0x0005, .trio2 = 0x06, .lane27 = 0x1800, .lane29 = 0x0aa4 }, |
222 | { .msps = 2100, .rx2 = 0x83, .trio0 = 0x044a, .trio1 = 0x0005, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, |
223 | { .msps = 2200, .rx2 = 0x89, .trio0 = 0x064a, .trio1 = 0x0004, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, |
224 | { .msps = 2300, .rx2 = 0x8f, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, |
225 | { .msps = 2400, .rx2 = 0x95, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, |
226 | { .msps = 2500, .rx2 = 0x9c, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0aa4 }, |
227 | { .msps = 2600, .rx2 = 0xa2, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
228 | { .msps = 2700, .rx2 = 0xa8, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
229 | { .msps = 2800, .rx2 = 0xae, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
230 | { .msps = 2900, .rx2 = 0xb5, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
231 | { .msps = 3000, .rx2 = 0xbb, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
232 | { .msps = 3100, .rx2 = 0xc1, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
233 | { .msps = 3200, .rx2 = 0xc7, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
234 | { .msps = 3300, .rx2 = 0xce, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
235 | { .msps = 3400, .rx2 = 0xd4, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
236 | { .msps = 3500, .rx2 = 0xda, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, |
237 | { /* sentinel */ }, |
238 | }; |
239 | |
240 | struct phtw_value { |
241 | u16 data; |
242 | u16 code; |
243 | }; |
244 | |
245 | struct rcsi2_mbps_reg { |
246 | u16 mbps; |
247 | u16 reg; |
248 | }; |
249 | |
250 | static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = { |
251 | { .mbps = 1500, .reg = 0xcc }, |
252 | { .mbps = 1550, .reg = 0x1d }, |
253 | { .mbps = 1600, .reg = 0x27 }, |
254 | { .mbps = 1650, .reg = 0x30 }, |
255 | { .mbps = 1700, .reg = 0x39 }, |
256 | { .mbps = 1750, .reg = 0x42 }, |
257 | { .mbps = 1800, .reg = 0x4b }, |
258 | { .mbps = 1850, .reg = 0x55 }, |
259 | { .mbps = 1900, .reg = 0x5e }, |
260 | { .mbps = 1950, .reg = 0x67 }, |
261 | { .mbps = 2000, .reg = 0x71 }, |
262 | { .mbps = 2050, .reg = 0x79 }, |
263 | { .mbps = 2100, .reg = 0x83 }, |
264 | { .mbps = 2150, .reg = 0x8c }, |
265 | { .mbps = 2200, .reg = 0x95 }, |
266 | { .mbps = 2250, .reg = 0x9e }, |
267 | { .mbps = 2300, .reg = 0xa7 }, |
268 | { .mbps = 2350, .reg = 0xb0 }, |
269 | { .mbps = 2400, .reg = 0xba }, |
270 | { .mbps = 2450, .reg = 0xc3 }, |
271 | { .mbps = 2500, .reg = 0xcc }, |
272 | { /* sentinel */ }, |
273 | }; |
274 | |
275 | static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { |
276 | { .mbps = 80, .reg = 0x86 }, |
277 | { .mbps = 90, .reg = 0x86 }, |
278 | { .mbps = 100, .reg = 0x87 }, |
279 | { .mbps = 110, .reg = 0x87 }, |
280 | { .mbps = 120, .reg = 0x88 }, |
281 | { .mbps = 130, .reg = 0x88 }, |
282 | { .mbps = 140, .reg = 0x89 }, |
283 | { .mbps = 150, .reg = 0x89 }, |
284 | { .mbps = 160, .reg = 0x8a }, |
285 | { .mbps = 170, .reg = 0x8a }, |
286 | { .mbps = 180, .reg = 0x8b }, |
287 | { .mbps = 190, .reg = 0x8b }, |
288 | { .mbps = 205, .reg = 0x8c }, |
289 | { .mbps = 220, .reg = 0x8d }, |
290 | { .mbps = 235, .reg = 0x8e }, |
291 | { .mbps = 250, .reg = 0x8e }, |
292 | { /* sentinel */ }, |
293 | }; |
294 | |
295 | static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { |
296 | { .mbps = 80, .reg = 0x00 }, |
297 | { .mbps = 90, .reg = 0x20 }, |
298 | { .mbps = 100, .reg = 0x40 }, |
299 | { .mbps = 110, .reg = 0x02 }, |
300 | { .mbps = 130, .reg = 0x22 }, |
301 | { .mbps = 140, .reg = 0x42 }, |
302 | { .mbps = 150, .reg = 0x04 }, |
303 | { .mbps = 170, .reg = 0x24 }, |
304 | { .mbps = 180, .reg = 0x44 }, |
305 | { .mbps = 200, .reg = 0x06 }, |
306 | { .mbps = 220, .reg = 0x26 }, |
307 | { .mbps = 240, .reg = 0x46 }, |
308 | { .mbps = 250, .reg = 0x08 }, |
309 | { .mbps = 270, .reg = 0x28 }, |
310 | { .mbps = 300, .reg = 0x0a }, |
311 | { .mbps = 330, .reg = 0x2a }, |
312 | { .mbps = 360, .reg = 0x4a }, |
313 | { .mbps = 400, .reg = 0x0c }, |
314 | { .mbps = 450, .reg = 0x2c }, |
315 | { .mbps = 500, .reg = 0x0e }, |
316 | { .mbps = 550, .reg = 0x2e }, |
317 | { .mbps = 600, .reg = 0x10 }, |
318 | { .mbps = 650, .reg = 0x30 }, |
319 | { .mbps = 700, .reg = 0x12 }, |
320 | { .mbps = 750, .reg = 0x32 }, |
321 | { .mbps = 800, .reg = 0x52 }, |
322 | { .mbps = 850, .reg = 0x72 }, |
323 | { .mbps = 900, .reg = 0x14 }, |
324 | { .mbps = 950, .reg = 0x34 }, |
325 | { .mbps = 1000, .reg = 0x54 }, |
326 | { .mbps = 1050, .reg = 0x74 }, |
327 | { .mbps = 1125, .reg = 0x16 }, |
328 | { /* sentinel */ }, |
329 | }; |
330 | |
331 | /* PHY Test Interface Clear */ |
332 | #define PHTC_REG 0x58 |
333 | #define PHTC_TESTCLR BIT(0) |
334 | |
335 | /* PHY Frequency Control */ |
336 | #define PHYPLL_REG 0x68 |
337 | #define PHYPLL_HSFREQRANGE(n) ((n) << 16) |
338 | |
339 | static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = { |
340 | { .mbps = 80, .reg = 0x00 }, |
341 | { .mbps = 90, .reg = 0x10 }, |
342 | { .mbps = 100, .reg = 0x20 }, |
343 | { .mbps = 110, .reg = 0x30 }, |
344 | { .mbps = 120, .reg = 0x01 }, |
345 | { .mbps = 130, .reg = 0x11 }, |
346 | { .mbps = 140, .reg = 0x21 }, |
347 | { .mbps = 150, .reg = 0x31 }, |
348 | { .mbps = 160, .reg = 0x02 }, |
349 | { .mbps = 170, .reg = 0x12 }, |
350 | { .mbps = 180, .reg = 0x22 }, |
351 | { .mbps = 190, .reg = 0x32 }, |
352 | { .mbps = 205, .reg = 0x03 }, |
353 | { .mbps = 220, .reg = 0x13 }, |
354 | { .mbps = 235, .reg = 0x23 }, |
355 | { .mbps = 250, .reg = 0x33 }, |
356 | { .mbps = 275, .reg = 0x04 }, |
357 | { .mbps = 300, .reg = 0x14 }, |
358 | { .mbps = 325, .reg = 0x25 }, |
359 | { .mbps = 350, .reg = 0x35 }, |
360 | { .mbps = 400, .reg = 0x05 }, |
361 | { .mbps = 450, .reg = 0x16 }, |
362 | { .mbps = 500, .reg = 0x26 }, |
363 | { .mbps = 550, .reg = 0x37 }, |
364 | { .mbps = 600, .reg = 0x07 }, |
365 | { .mbps = 650, .reg = 0x18 }, |
366 | { .mbps = 700, .reg = 0x28 }, |
367 | { .mbps = 750, .reg = 0x39 }, |
368 | { .mbps = 800, .reg = 0x09 }, |
369 | { .mbps = 850, .reg = 0x19 }, |
370 | { .mbps = 900, .reg = 0x29 }, |
371 | { .mbps = 950, .reg = 0x3a }, |
372 | { .mbps = 1000, .reg = 0x0a }, |
373 | { .mbps = 1050, .reg = 0x1a }, |
374 | { .mbps = 1100, .reg = 0x2a }, |
375 | { .mbps = 1150, .reg = 0x3b }, |
376 | { .mbps = 1200, .reg = 0x0b }, |
377 | { .mbps = 1250, .reg = 0x1b }, |
378 | { .mbps = 1300, .reg = 0x2b }, |
379 | { .mbps = 1350, .reg = 0x3c }, |
380 | { .mbps = 1400, .reg = 0x0c }, |
381 | { .mbps = 1450, .reg = 0x1c }, |
382 | { .mbps = 1500, .reg = 0x2c }, |
383 | { .mbps = 1550, .reg = 0x3d }, |
384 | { .mbps = 1600, .reg = 0x0d }, |
385 | { .mbps = 1650, .reg = 0x1d }, |
386 | { .mbps = 1700, .reg = 0x2e }, |
387 | { .mbps = 1750, .reg = 0x3e }, |
388 | { .mbps = 1800, .reg = 0x0e }, |
389 | { .mbps = 1850, .reg = 0x1e }, |
390 | { .mbps = 1900, .reg = 0x2f }, |
391 | { .mbps = 1950, .reg = 0x3f }, |
392 | { .mbps = 2000, .reg = 0x0f }, |
393 | { .mbps = 2050, .reg = 0x40 }, |
394 | { .mbps = 2100, .reg = 0x41 }, |
395 | { .mbps = 2150, .reg = 0x42 }, |
396 | { .mbps = 2200, .reg = 0x43 }, |
397 | { .mbps = 2300, .reg = 0x45 }, |
398 | { .mbps = 2350, .reg = 0x46 }, |
399 | { .mbps = 2400, .reg = 0x47 }, |
400 | { .mbps = 2450, .reg = 0x48 }, |
401 | { .mbps = 2500, .reg = 0x49 }, |
402 | { /* sentinel */ }, |
403 | }; |
404 | |
405 | static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { |
406 | { .mbps = 80, .reg = 0x00 }, |
407 | { .mbps = 90, .reg = 0x10 }, |
408 | { .mbps = 100, .reg = 0x20 }, |
409 | { .mbps = 110, .reg = 0x30 }, |
410 | { .mbps = 120, .reg = 0x01 }, |
411 | { .mbps = 130, .reg = 0x11 }, |
412 | { .mbps = 140, .reg = 0x21 }, |
413 | { .mbps = 150, .reg = 0x31 }, |
414 | { .mbps = 160, .reg = 0x02 }, |
415 | { .mbps = 170, .reg = 0x12 }, |
416 | { .mbps = 180, .reg = 0x22 }, |
417 | { .mbps = 190, .reg = 0x32 }, |
418 | { .mbps = 205, .reg = 0x03 }, |
419 | { .mbps = 220, .reg = 0x13 }, |
420 | { .mbps = 235, .reg = 0x23 }, |
421 | { .mbps = 250, .reg = 0x33 }, |
422 | { .mbps = 275, .reg = 0x04 }, |
423 | { .mbps = 300, .reg = 0x14 }, |
424 | { .mbps = 325, .reg = 0x25 }, |
425 | { .mbps = 350, .reg = 0x35 }, |
426 | { .mbps = 400, .reg = 0x05 }, |
427 | { .mbps = 450, .reg = 0x16 }, |
428 | { .mbps = 500, .reg = 0x26 }, |
429 | { .mbps = 550, .reg = 0x37 }, |
430 | { .mbps = 600, .reg = 0x07 }, |
431 | { .mbps = 650, .reg = 0x18 }, |
432 | { .mbps = 700, .reg = 0x28 }, |
433 | { .mbps = 750, .reg = 0x39 }, |
434 | { .mbps = 800, .reg = 0x09 }, |
435 | { .mbps = 850, .reg = 0x19 }, |
436 | { .mbps = 900, .reg = 0x29 }, |
437 | { .mbps = 950, .reg = 0x3a }, |
438 | { .mbps = 1000, .reg = 0x0a }, |
439 | { .mbps = 1050, .reg = 0x1a }, |
440 | { .mbps = 1100, .reg = 0x2a }, |
441 | { .mbps = 1150, .reg = 0x3b }, |
442 | { .mbps = 1200, .reg = 0x0b }, |
443 | { .mbps = 1250, .reg = 0x1b }, |
444 | { .mbps = 1300, .reg = 0x2b }, |
445 | { .mbps = 1350, .reg = 0x3c }, |
446 | { .mbps = 1400, .reg = 0x0c }, |
447 | { .mbps = 1450, .reg = 0x1c }, |
448 | { .mbps = 1500, .reg = 0x2c }, |
449 | { /* sentinel */ }, |
450 | }; |
451 | |
452 | static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = { |
453 | { .mbps = 80, .reg = 0x00 }, |
454 | { .mbps = 90, .reg = 0x10 }, |
455 | { .mbps = 100, .reg = 0x20 }, |
456 | { .mbps = 110, .reg = 0x30 }, |
457 | { .mbps = 120, .reg = 0x01 }, |
458 | { .mbps = 130, .reg = 0x11 }, |
459 | { .mbps = 140, .reg = 0x21 }, |
460 | { .mbps = 150, .reg = 0x31 }, |
461 | { .mbps = 160, .reg = 0x02 }, |
462 | { .mbps = 170, .reg = 0x12 }, |
463 | { .mbps = 180, .reg = 0x22 }, |
464 | { .mbps = 190, .reg = 0x32 }, |
465 | { .mbps = 205, .reg = 0x03 }, |
466 | { .mbps = 220, .reg = 0x13 }, |
467 | { .mbps = 235, .reg = 0x23 }, |
468 | { .mbps = 250, .reg = 0x33 }, |
469 | { .mbps = 275, .reg = 0x04 }, |
470 | { .mbps = 300, .reg = 0x14 }, |
471 | { .mbps = 325, .reg = 0x05 }, |
472 | { .mbps = 350, .reg = 0x15 }, |
473 | { .mbps = 400, .reg = 0x25 }, |
474 | { .mbps = 450, .reg = 0x06 }, |
475 | { .mbps = 500, .reg = 0x16 }, |
476 | { .mbps = 550, .reg = 0x07 }, |
477 | { .mbps = 600, .reg = 0x17 }, |
478 | { .mbps = 650, .reg = 0x08 }, |
479 | { .mbps = 700, .reg = 0x18 }, |
480 | { .mbps = 750, .reg = 0x09 }, |
481 | { .mbps = 800, .reg = 0x19 }, |
482 | { .mbps = 850, .reg = 0x29 }, |
483 | { .mbps = 900, .reg = 0x39 }, |
484 | { .mbps = 950, .reg = 0x0a }, |
485 | { .mbps = 1000, .reg = 0x1a }, |
486 | { .mbps = 1050, .reg = 0x2a }, |
487 | { .mbps = 1100, .reg = 0x3a }, |
488 | { .mbps = 1150, .reg = 0x0b }, |
489 | { .mbps = 1200, .reg = 0x1b }, |
490 | { .mbps = 1250, .reg = 0x2b }, |
491 | { .mbps = 1300, .reg = 0x3b }, |
492 | { .mbps = 1350, .reg = 0x0c }, |
493 | { .mbps = 1400, .reg = 0x1c }, |
494 | { .mbps = 1450, .reg = 0x2c }, |
495 | { .mbps = 1500, .reg = 0x3c }, |
496 | { /* sentinel */ }, |
497 | }; |
498 | |
499 | /* PHY ESC Error Monitor */ |
500 | #define PHEERM_REG 0x74 |
501 | |
502 | /* PHY Clock Lane Monitor */ |
503 | #define PHCLM_REG 0x78 |
504 | #define PHCLM_STOPSTATECKL BIT(0) |
505 | |
506 | /* PHY Data Lane Monitor */ |
507 | #define PHDLM_REG 0x7c |
508 | |
509 | /* CSI0CLK Frequency Configuration Preset Register */ |
510 | #define CSI0CLKFCPR_REG 0x260 |
511 | #define CSI0CLKFREQRANGE(n) ((n & 0x3f) << 16) |
512 | |
513 | struct rcar_csi2_format { |
514 | u32 code; |
515 | unsigned int datatype; |
516 | unsigned int bpp; |
517 | }; |
518 | |
519 | static const struct rcar_csi2_format rcar_csi2_formats[] = { |
520 | { |
521 | .code = MEDIA_BUS_FMT_RGB888_1X24, |
522 | .datatype = MIPI_CSI2_DT_RGB888, |
523 | .bpp = 24, |
524 | }, { |
525 | .code = MEDIA_BUS_FMT_UYVY8_1X16, |
526 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
527 | .bpp = 16, |
528 | }, { |
529 | .code = MEDIA_BUS_FMT_YUYV8_1X16, |
530 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
531 | .bpp = 16, |
532 | }, { |
533 | .code = MEDIA_BUS_FMT_UYVY8_2X8, |
534 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
535 | .bpp = 16, |
536 | }, { |
537 | .code = MEDIA_BUS_FMT_YUYV10_2X10, |
538 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
539 | .bpp = 20, |
540 | }, { |
541 | .code = MEDIA_BUS_FMT_Y10_1X10, |
542 | .datatype = MIPI_CSI2_DT_RAW10, |
543 | .bpp = 10, |
544 | }, { |
545 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, |
546 | .datatype = MIPI_CSI2_DT_RAW8, |
547 | .bpp = 8, |
548 | }, { |
549 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, |
550 | .datatype = MIPI_CSI2_DT_RAW8, |
551 | .bpp = 8, |
552 | }, { |
553 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, |
554 | .datatype = MIPI_CSI2_DT_RAW8, |
555 | .bpp = 8, |
556 | }, { |
557 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, |
558 | .datatype = MIPI_CSI2_DT_RAW8, |
559 | .bpp = 8, |
560 | }, { |
561 | .code = MEDIA_BUS_FMT_Y8_1X8, |
562 | .datatype = MIPI_CSI2_DT_RAW8, |
563 | .bpp = 8, |
564 | }, |
565 | }; |
566 | |
567 | static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code) |
568 | { |
569 | unsigned int i; |
570 | |
571 | for (i = 0; i < ARRAY_SIZE(rcar_csi2_formats); i++) |
572 | if (rcar_csi2_formats[i].code == code) |
573 | return &rcar_csi2_formats[i]; |
574 | |
575 | return NULL; |
576 | } |
577 | |
578 | enum rcar_csi2_pads { |
579 | RCAR_CSI2_SINK, |
580 | RCAR_CSI2_SOURCE_VC0, |
581 | RCAR_CSI2_SOURCE_VC1, |
582 | RCAR_CSI2_SOURCE_VC2, |
583 | RCAR_CSI2_SOURCE_VC3, |
584 | NR_OF_RCAR_CSI2_PAD, |
585 | }; |
586 | |
587 | struct rcar_csi2_info { |
588 | int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); |
589 | int (*phy_post_init)(struct rcar_csi2 *priv); |
590 | int (*start_receiver)(struct rcar_csi2 *priv); |
591 | void (*enter_standby)(struct rcar_csi2 *priv); |
592 | const struct rcsi2_mbps_reg *hsfreqrange; |
593 | unsigned int csi0clkfreqrange; |
594 | unsigned int num_channels; |
595 | bool clear_ulps; |
596 | bool use_isp; |
597 | bool support_dphy; |
598 | bool support_cphy; |
599 | }; |
600 | |
601 | struct rcar_csi2 { |
602 | struct device *dev; |
603 | void __iomem *base; |
604 | const struct rcar_csi2_info *info; |
605 | struct reset_control *rstc; |
606 | |
607 | struct v4l2_subdev subdev; |
608 | struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; |
609 | |
610 | struct v4l2_async_notifier notifier; |
611 | struct v4l2_subdev *remote; |
612 | unsigned int remote_pad; |
613 | |
614 | int channel_vc[4]; |
615 | |
616 | struct mutex lock; /* Protects mf and stream_count. */ |
617 | struct v4l2_mbus_framefmt mf; |
618 | int stream_count; |
619 | |
620 | bool cphy; |
621 | unsigned short lanes; |
622 | unsigned char lane_swap[4]; |
623 | }; |
624 | |
625 | static inline struct rcar_csi2 *sd_to_csi2(struct v4l2_subdev *sd) |
626 | { |
627 | return container_of(sd, struct rcar_csi2, subdev); |
628 | } |
629 | |
630 | static inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n) |
631 | { |
632 | return container_of(n, struct rcar_csi2, notifier); |
633 | } |
634 | |
635 | static u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg) |
636 | { |
637 | return ioread32(priv->base + reg); |
638 | } |
639 | |
640 | static void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data) |
641 | { |
642 | iowrite32(data, priv->base + reg); |
643 | } |
644 | |
645 | static void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data) |
646 | { |
647 | iowrite16(data, priv->base + reg); |
648 | } |
649 | |
650 | static void rcsi2_enter_standby_gen3(struct rcar_csi2 *priv) |
651 | { |
652 | rcsi2_write(priv, PHYCNT_REG, data: 0); |
653 | rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); |
654 | } |
655 | |
656 | static void rcsi2_enter_standby(struct rcar_csi2 *priv) |
657 | { |
658 | if (priv->info->enter_standby) |
659 | priv->info->enter_standby(priv); |
660 | |
661 | reset_control_assert(rstc: priv->rstc); |
662 | usleep_range(min: 100, max: 150); |
663 | pm_runtime_put(dev: priv->dev); |
664 | } |
665 | |
666 | static int rcsi2_exit_standby(struct rcar_csi2 *priv) |
667 | { |
668 | int ret; |
669 | |
670 | ret = pm_runtime_resume_and_get(dev: priv->dev); |
671 | if (ret < 0) |
672 | return ret; |
673 | |
674 | reset_control_deassert(rstc: priv->rstc); |
675 | |
676 | return 0; |
677 | } |
678 | |
679 | static int rcsi2_wait_phy_start(struct rcar_csi2 *priv, |
680 | unsigned int lanes) |
681 | { |
682 | unsigned int timeout; |
683 | |
684 | /* Wait for the clock and data lanes to enter LP-11 state. */ |
685 | for (timeout = 0; timeout <= 20; timeout++) { |
686 | const u32 lane_mask = (1 << lanes) - 1; |
687 | |
688 | if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && |
689 | (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) |
690 | return 0; |
691 | |
692 | usleep_range(min: 1000, max: 2000); |
693 | } |
694 | |
695 | dev_err(priv->dev, "Timeout waiting for LP-11 state\n" ); |
696 | |
697 | return -ETIMEDOUT; |
698 | } |
699 | |
700 | static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) |
701 | { |
702 | const struct rcsi2_mbps_reg *hsfreq; |
703 | const struct rcsi2_mbps_reg *hsfreq_prev = NULL; |
704 | |
705 | if (mbps < priv->info->hsfreqrange->mbps) |
706 | dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps" , |
707 | mbps, priv->info->hsfreqrange->mbps); |
708 | |
709 | for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) { |
710 | if (hsfreq->mbps >= mbps) |
711 | break; |
712 | hsfreq_prev = hsfreq; |
713 | } |
714 | |
715 | if (!hsfreq->mbps) { |
716 | dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)" , mbps); |
717 | return -ERANGE; |
718 | } |
719 | |
720 | if (hsfreq_prev && |
721 | ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps))) |
722 | hsfreq = hsfreq_prev; |
723 | |
724 | rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg)); |
725 | |
726 | return 0; |
727 | } |
728 | |
729 | static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, |
730 | unsigned int lanes) |
731 | { |
732 | struct v4l2_subdev *source; |
733 | struct v4l2_ctrl *ctrl; |
734 | u64 mbps; |
735 | |
736 | if (!priv->remote) |
737 | return -ENODEV; |
738 | |
739 | source = priv->remote; |
740 | |
741 | /* Read the pixel rate control from remote. */ |
742 | ctrl = v4l2_ctrl_find(hdl: source->ctrl_handler, V4L2_CID_PIXEL_RATE); |
743 | if (!ctrl) { |
744 | dev_err(priv->dev, "no pixel rate control in subdev %s\n" , |
745 | source->name); |
746 | return -EINVAL; |
747 | } |
748 | |
749 | /* |
750 | * Calculate the phypll in mbps. |
751 | * link_freq = (pixel_rate * bits_per_sample) / (2 * nr_of_lanes) |
752 | * bps = link_freq * 2 |
753 | */ |
754 | mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; |
755 | do_div(mbps, lanes * 1000000); |
756 | |
757 | /* Adjust for C-PHY, divide by 2.8. */ |
758 | if (priv->cphy) |
759 | mbps = div_u64(dividend: mbps * 5, divisor: 14); |
760 | |
761 | return mbps; |
762 | } |
763 | |
764 | static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, |
765 | unsigned int *lanes) |
766 | { |
767 | struct v4l2_mbus_config mbus_config = { 0 }; |
768 | int ret; |
769 | |
770 | *lanes = priv->lanes; |
771 | |
772 | ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config, |
773 | priv->remote_pad, &mbus_config); |
774 | if (ret == -ENOIOCTLCMD) { |
775 | dev_dbg(priv->dev, "No remote mbus configuration available\n" ); |
776 | return 0; |
777 | } |
778 | |
779 | if (ret) { |
780 | dev_err(priv->dev, "Failed to get remote mbus configuration\n" ); |
781 | return ret; |
782 | } |
783 | |
784 | switch (mbus_config.type) { |
785 | case V4L2_MBUS_CSI2_CPHY: |
786 | if (!priv->cphy) |
787 | return -EINVAL; |
788 | break; |
789 | case V4L2_MBUS_CSI2_DPHY: |
790 | if (priv->cphy) |
791 | return -EINVAL; |
792 | break; |
793 | default: |
794 | dev_err(priv->dev, "Unsupported media bus type %u\n" , |
795 | mbus_config.type); |
796 | return -EINVAL; |
797 | } |
798 | |
799 | if (mbus_config.bus.mipi_csi2.num_data_lanes > priv->lanes) { |
800 | dev_err(priv->dev, |
801 | "Unsupported mbus config: too many data lanes %u\n" , |
802 | mbus_config.bus.mipi_csi2.num_data_lanes); |
803 | return -EINVAL; |
804 | } |
805 | |
806 | *lanes = mbus_config.bus.mipi_csi2.num_data_lanes; |
807 | |
808 | return 0; |
809 | } |
810 | |
811 | static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv) |
812 | { |
813 | const struct rcar_csi2_format *format; |
814 | u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0; |
815 | unsigned int lanes; |
816 | unsigned int i; |
817 | int mbps, ret; |
818 | |
819 | dev_dbg(priv->dev, "Input size (%ux%u%c)\n" , |
820 | priv->mf.width, priv->mf.height, |
821 | priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i'); |
822 | |
823 | /* Code is validated in set_fmt. */ |
824 | format = rcsi2_code_to_fmt(code: priv->mf.code); |
825 | if (!format) |
826 | return -EINVAL; |
827 | |
828 | /* |
829 | * Enable all supported CSI-2 channels with virtual channel and |
830 | * data type matching. |
831 | * |
832 | * NOTE: It's not possible to get individual datatype for each |
833 | * source virtual channel. Once this is possible in V4L2 |
834 | * it should be used here. |
835 | */ |
836 | for (i = 0; i < priv->info->num_channels; i++) { |
837 | u32 vcdt_part; |
838 | |
839 | if (priv->channel_vc[i] < 0) |
840 | continue; |
841 | |
842 | vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) | VCDT_VCDTN_EN | |
843 | VCDT_SEL_DTN_ON | VCDT_SEL_DT(format->datatype); |
844 | |
845 | /* Store in correct reg and offset. */ |
846 | if (i < 2) |
847 | vcdt |= vcdt_part << ((i % 2) * 16); |
848 | else |
849 | vcdt2 |= vcdt_part << ((i % 2) * 16); |
850 | } |
851 | |
852 | if (priv->mf.field == V4L2_FIELD_ALTERNATE) { |
853 | fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2 |
854 | | FLD_FLD_EN; |
855 | |
856 | if (priv->mf.height == 240) |
857 | fld |= FLD_FLD_NUM(0); |
858 | else |
859 | fld |= FLD_FLD_NUM(1); |
860 | } |
861 | |
862 | /* |
863 | * Get the number of active data lanes inspecting the remote mbus |
864 | * configuration. |
865 | */ |
866 | ret = rcsi2_get_active_lanes(priv, lanes: &lanes); |
867 | if (ret) |
868 | return ret; |
869 | |
870 | phycnt = PHYCNT_ENABLECLK; |
871 | phycnt |= (1 << lanes) - 1; |
872 | |
873 | mbps = rcsi2_calc_mbps(priv, bpp: format->bpp, lanes); |
874 | if (mbps < 0) |
875 | return mbps; |
876 | |
877 | /* Enable interrupts. */ |
878 | rcsi2_write(priv, INTEN_REG, INTEN_INT_AFIFO_OF | INTEN_INT_ERRSOTHS |
879 | | INTEN_INT_ERRSOTSYNCHS); |
880 | |
881 | /* Init */ |
882 | rcsi2_write(priv, TREF_REG, TREF_TREF); |
883 | rcsi2_write(priv, PHTC_REG, data: 0); |
884 | |
885 | /* Configure */ |
886 | if (!priv->info->use_isp) { |
887 | rcsi2_write(priv, VCDT_REG, data: vcdt); |
888 | if (vcdt2) |
889 | rcsi2_write(priv, VCDT2_REG, data: vcdt2); |
890 | } |
891 | |
892 | /* Lanes are zero indexed. */ |
893 | rcsi2_write(priv, LSWAP_REG, |
894 | LSWAP_L0SEL(priv->lane_swap[0] - 1) | |
895 | LSWAP_L1SEL(priv->lane_swap[1] - 1) | |
896 | LSWAP_L2SEL(priv->lane_swap[2] - 1) | |
897 | LSWAP_L3SEL(priv->lane_swap[3] - 1)); |
898 | |
899 | /* Start */ |
900 | if (priv->info->init_phtw) { |
901 | ret = priv->info->init_phtw(priv, mbps); |
902 | if (ret) |
903 | return ret; |
904 | } |
905 | |
906 | if (priv->info->hsfreqrange) { |
907 | ret = rcsi2_set_phypll(priv, mbps); |
908 | if (ret) |
909 | return ret; |
910 | } |
911 | |
912 | if (priv->info->csi0clkfreqrange) |
913 | rcsi2_write(priv, CSI0CLKFCPR_REG, |
914 | CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange)); |
915 | |
916 | if (priv->info->use_isp) |
917 | rcsi2_write(priv, PHYFRX_REG, |
918 | PHYFRX_FORCERX_MODE_3 | PHYFRX_FORCERX_MODE_2 | |
919 | PHYFRX_FORCERX_MODE_1 | PHYFRX_FORCERX_MODE_0); |
920 | |
921 | rcsi2_write(priv, PHYCNT_REG, data: phycnt); |
922 | rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | |
923 | LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); |
924 | rcsi2_write(priv, FLD_REG, data: fld); |
925 | rcsi2_write(priv, PHYCNT_REG, data: phycnt | PHYCNT_SHUTDOWNZ); |
926 | rcsi2_write(priv, PHYCNT_REG, data: phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); |
927 | |
928 | ret = rcsi2_wait_phy_start(priv, lanes); |
929 | if (ret) |
930 | return ret; |
931 | |
932 | if (priv->info->use_isp) |
933 | rcsi2_write(priv, PHYFRX_REG, data: 0); |
934 | |
935 | /* Run post PHY start initialization, if needed. */ |
936 | if (priv->info->phy_post_init) { |
937 | ret = priv->info->phy_post_init(priv); |
938 | if (ret) |
939 | return ret; |
940 | } |
941 | |
942 | /* Clear Ultra Low Power interrupt. */ |
943 | if (priv->info->clear_ulps) |
944 | rcsi2_write(priv, INTSTATE_REG, |
945 | INTSTATE_INT_ULPS_START | |
946 | INTSTATE_INT_ULPS_END); |
947 | return 0; |
948 | } |
949 | |
950 | static int rcsi2_wait_phy_start_v4h(struct rcar_csi2 *priv, u32 match) |
951 | { |
952 | unsigned int timeout; |
953 | u32 status; |
954 | |
955 | for (timeout = 0; timeout <= 10; timeout++) { |
956 | status = rcsi2_read(priv, V4H_ST_PHYST_REG); |
957 | if ((status & match) == match) |
958 | return 0; |
959 | |
960 | usleep_range(min: 1000, max: 2000); |
961 | } |
962 | |
963 | return -ETIMEDOUT; |
964 | } |
965 | |
966 | static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) |
967 | { |
968 | const struct rcsi2_cphy_setting *conf; |
969 | |
970 | for (conf = cphy_setting_table_r8a779g0; conf->msps != 0; conf++) { |
971 | if (conf->msps > msps) |
972 | break; |
973 | } |
974 | |
975 | if (!conf->msps) { |
976 | dev_err(priv->dev, "Unsupported PHY speed for msps setting (%u Msps)" , msps); |
977 | return -ERANGE; |
978 | } |
979 | |
980 | /* C-PHY specific */ |
981 | rcsi2_write16(priv, V4H_CORE_DIG_RW_COMMON_REG(7), data: 0x0155); |
982 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(7), data: 0x0068); |
983 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(8), data: 0x0010); |
984 | |
985 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_LP_0_REG, data: 0x463c); |
986 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_LP_0_REG, data: 0x463c); |
987 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_LP_0_REG, data: 0x463c); |
988 | |
989 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(0), data: 0x00d5); |
990 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(0), data: 0x00d5); |
991 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(0), data: 0x00d5); |
992 | |
993 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(1), data: 0x0013); |
994 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(1), data: 0x0013); |
995 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(1), data: 0x0013); |
996 | |
997 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(5), data: 0x0013); |
998 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(5), data: 0x0013); |
999 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(5), data: 0x0013); |
1000 | |
1001 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(6), data: 0x000a); |
1002 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(6), data: 0x000a); |
1003 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(6), data: 0x000a); |
1004 | |
1005 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(2), data: conf->rx2); |
1006 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(2), data: conf->rx2); |
1007 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(2), data: conf->rx2); |
1008 | |
1009 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(2), data: 0x0001); |
1010 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(2), data: 0); |
1011 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(2), data: 0x0001); |
1012 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(2), data: 0x0001); |
1013 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(2), data: 0); |
1014 | |
1015 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(0), data: conf->trio0); |
1016 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(0), data: conf->trio0); |
1017 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(0), data: conf->trio0); |
1018 | |
1019 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(2), data: conf->trio2); |
1020 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(2), data: conf->trio2); |
1021 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(2), data: conf->trio2); |
1022 | |
1023 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(1), data: conf->trio1); |
1024 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(1), data: conf->trio1); |
1025 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(1), data: conf->trio1); |
1026 | |
1027 | /* |
1028 | * Configure pin-swap. |
1029 | * TODO: This registers is not documented yet, the values should depend |
1030 | * on the 'clock-lanes' and 'data-lanes' devicetree properties. |
1031 | */ |
1032 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, data: 0xf5); |
1033 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, data: 0x5000); |
1034 | |
1035 | /* Leave Shutdown mode */ |
1036 | rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); |
1037 | rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); |
1038 | |
1039 | /* Wait for calibration */ |
1040 | if (rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_PHY_READY)) { |
1041 | dev_err(priv->dev, "PHY calibration failed\n" ); |
1042 | return -ETIMEDOUT; |
1043 | } |
1044 | |
1045 | /* C-PHY setting - analog programing*/ |
1046 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9), data: conf->lane29); |
1047 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(7), data: conf->lane27); |
1048 | |
1049 | return 0; |
1050 | } |
1051 | |
1052 | static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv) |
1053 | { |
1054 | const struct rcar_csi2_format *format; |
1055 | unsigned int lanes; |
1056 | int msps; |
1057 | int ret; |
1058 | |
1059 | /* Calculate parameters */ |
1060 | format = rcsi2_code_to_fmt(code: priv->mf.code); |
1061 | if (!format) |
1062 | return -EINVAL; |
1063 | |
1064 | ret = rcsi2_get_active_lanes(priv, lanes: &lanes); |
1065 | if (ret) |
1066 | return ret; |
1067 | |
1068 | msps = rcsi2_calc_mbps(priv, bpp: format->bpp, lanes); |
1069 | if (msps < 0) |
1070 | return msps; |
1071 | |
1072 | /* Reset LINK and PHY*/ |
1073 | rcsi2_write(priv, V4H_CSI2_RESETN_REG, data: 0); |
1074 | rcsi2_write(priv, V4H_DPHY_RSTZ_REG, data: 0); |
1075 | rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, data: 0); |
1076 | |
1077 | /* PHY static setting */ |
1078 | rcsi2_write(priv, V4H_PHY_EN_REG, BIT(0)); |
1079 | rcsi2_write(priv, V4H_FLDC_REG, data: 0); |
1080 | rcsi2_write(priv, V4H_FLDD_REG, data: 0); |
1081 | rcsi2_write(priv, V4H_IDIC_REG, data: 0); |
1082 | rcsi2_write(priv, V4H_PHY_MODE_REG, BIT(0)); |
1083 | rcsi2_write(priv, V4H_N_LANES_REG, data: lanes - 1); |
1084 | |
1085 | /* Reset CSI2 */ |
1086 | rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0)); |
1087 | |
1088 | /* Registers static setting through APB */ |
1089 | /* Common setting */ |
1090 | rcsi2_write16(priv, V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(0), data: 0x1bfd); |
1091 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG, data: 0x0233); |
1092 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(6), data: 0x0027); |
1093 | rcsi2_write16(priv, V4H_PPI_CALIBCTRL_RW_COMMON_BG_0_REG, data: 0x01f4); |
1094 | rcsi2_write16(priv, V4H_PPI_RW_TERMCAL_CFG_0_REG, data: 0x0013); |
1095 | rcsi2_write16(priv, V4H_PPI_RW_OFFSETCAL_CFG_0_REG, data: 0x0003); |
1096 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_TIMEBASE_REG, data: 0x004f); |
1097 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_NREF_REG, data: 0x0320); |
1098 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_NREF_RANGE_REG, data: 0x000f); |
1099 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG, data: 0xfe18); |
1100 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG, data: 0x0c3c); |
1101 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG, data: 0x0105); |
1102 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), data: 0x1000); |
1103 | rcsi2_write16(priv, V4H_PPI_RW_COMMON_CFG_REG, data: 0x0003); |
1104 | |
1105 | /* C-PHY settings */ |
1106 | ret = rcsi2_c_phy_setting_v4h(priv, msps); |
1107 | if (ret) |
1108 | return ret; |
1109 | |
1110 | rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 | |
1111 | V4H_ST_PHYST_ST_STOPSTATE_1 | |
1112 | V4H_ST_PHYST_ST_STOPSTATE_2); |
1113 | |
1114 | return 0; |
1115 | } |
1116 | |
1117 | static int rcsi2_start(struct rcar_csi2 *priv) |
1118 | { |
1119 | int ret; |
1120 | |
1121 | ret = rcsi2_exit_standby(priv); |
1122 | if (ret < 0) |
1123 | return ret; |
1124 | |
1125 | ret = priv->info->start_receiver(priv); |
1126 | if (ret) { |
1127 | rcsi2_enter_standby(priv); |
1128 | return ret; |
1129 | } |
1130 | |
1131 | ret = v4l2_subdev_call(priv->remote, video, s_stream, 1); |
1132 | if (ret) { |
1133 | rcsi2_enter_standby(priv); |
1134 | return ret; |
1135 | } |
1136 | |
1137 | return 0; |
1138 | } |
1139 | |
1140 | static void rcsi2_stop(struct rcar_csi2 *priv) |
1141 | { |
1142 | rcsi2_enter_standby(priv); |
1143 | v4l2_subdev_call(priv->remote, video, s_stream, 0); |
1144 | } |
1145 | |
1146 | static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) |
1147 | { |
1148 | struct rcar_csi2 *priv = sd_to_csi2(sd); |
1149 | int ret = 0; |
1150 | |
1151 | mutex_lock(&priv->lock); |
1152 | |
1153 | if (!priv->remote) { |
1154 | ret = -ENODEV; |
1155 | goto out; |
1156 | } |
1157 | |
1158 | if (enable && priv->stream_count == 0) { |
1159 | ret = rcsi2_start(priv); |
1160 | if (ret) |
1161 | goto out; |
1162 | } else if (!enable && priv->stream_count == 1) { |
1163 | rcsi2_stop(priv); |
1164 | } |
1165 | |
1166 | priv->stream_count += enable ? 1 : -1; |
1167 | out: |
1168 | mutex_unlock(lock: &priv->lock); |
1169 | |
1170 | return ret; |
1171 | } |
1172 | |
1173 | static int rcsi2_set_pad_format(struct v4l2_subdev *sd, |
1174 | struct v4l2_subdev_state *sd_state, |
1175 | struct v4l2_subdev_format *format) |
1176 | { |
1177 | struct rcar_csi2 *priv = sd_to_csi2(sd); |
1178 | struct v4l2_mbus_framefmt *framefmt; |
1179 | |
1180 | mutex_lock(&priv->lock); |
1181 | |
1182 | if (!rcsi2_code_to_fmt(code: format->format.code)) |
1183 | format->format.code = rcar_csi2_formats[0].code; |
1184 | |
1185 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
1186 | priv->mf = format->format; |
1187 | } else { |
1188 | framefmt = v4l2_subdev_state_get_format(sd_state, 0); |
1189 | *framefmt = format->format; |
1190 | } |
1191 | |
1192 | mutex_unlock(lock: &priv->lock); |
1193 | |
1194 | return 0; |
1195 | } |
1196 | |
1197 | static int rcsi2_get_pad_format(struct v4l2_subdev *sd, |
1198 | struct v4l2_subdev_state *sd_state, |
1199 | struct v4l2_subdev_format *format) |
1200 | { |
1201 | struct rcar_csi2 *priv = sd_to_csi2(sd); |
1202 | |
1203 | mutex_lock(&priv->lock); |
1204 | |
1205 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
1206 | format->format = priv->mf; |
1207 | else |
1208 | format->format = *v4l2_subdev_state_get_format(sd_state, 0); |
1209 | |
1210 | mutex_unlock(lock: &priv->lock); |
1211 | |
1212 | return 0; |
1213 | } |
1214 | |
1215 | static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = { |
1216 | .s_stream = rcsi2_s_stream, |
1217 | }; |
1218 | |
1219 | static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = { |
1220 | .set_fmt = rcsi2_set_pad_format, |
1221 | .get_fmt = rcsi2_get_pad_format, |
1222 | }; |
1223 | |
1224 | static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = { |
1225 | .video = &rcar_csi2_video_ops, |
1226 | .pad = &rcar_csi2_pad_ops, |
1227 | }; |
1228 | |
1229 | static irqreturn_t rcsi2_irq(int irq, void *data) |
1230 | { |
1231 | struct rcar_csi2 *priv = data; |
1232 | u32 status, err_status; |
1233 | |
1234 | status = rcsi2_read(priv, INTSTATE_REG); |
1235 | err_status = rcsi2_read(priv, INTERRSTATE_REG); |
1236 | |
1237 | if (!status) |
1238 | return IRQ_HANDLED; |
1239 | |
1240 | rcsi2_write(priv, INTSTATE_REG, data: status); |
1241 | |
1242 | if (!err_status) |
1243 | return IRQ_HANDLED; |
1244 | |
1245 | rcsi2_write(priv, INTERRSTATE_REG, data: err_status); |
1246 | |
1247 | dev_info(priv->dev, "Transfer error, restarting CSI-2 receiver\n" ); |
1248 | |
1249 | return IRQ_WAKE_THREAD; |
1250 | } |
1251 | |
1252 | static irqreturn_t rcsi2_irq_thread(int irq, void *data) |
1253 | { |
1254 | struct rcar_csi2 *priv = data; |
1255 | |
1256 | mutex_lock(&priv->lock); |
1257 | rcsi2_stop(priv); |
1258 | usleep_range(min: 1000, max: 2000); |
1259 | if (rcsi2_start(priv)) |
1260 | dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n" ); |
1261 | mutex_unlock(lock: &priv->lock); |
1262 | |
1263 | return IRQ_HANDLED; |
1264 | } |
1265 | |
1266 | /* ----------------------------------------------------------------------------- |
1267 | * Async handling and registration of subdevices and links. |
1268 | */ |
1269 | |
1270 | static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier, |
1271 | struct v4l2_subdev *subdev, |
1272 | struct v4l2_async_connection *asc) |
1273 | { |
1274 | struct rcar_csi2 *priv = notifier_to_csi2(n: notifier); |
1275 | int pad; |
1276 | |
1277 | pad = media_entity_get_fwnode_pad(entity: &subdev->entity, fwnode: asc->match.fwnode, |
1278 | MEDIA_PAD_FL_SOURCE); |
1279 | if (pad < 0) { |
1280 | dev_err(priv->dev, "Failed to find pad for %s\n" , subdev->name); |
1281 | return pad; |
1282 | } |
1283 | |
1284 | priv->remote = subdev; |
1285 | priv->remote_pad = pad; |
1286 | |
1287 | dev_dbg(priv->dev, "Bound %s pad: %d\n" , subdev->name, pad); |
1288 | |
1289 | return media_create_pad_link(source: &subdev->entity, source_pad: pad, |
1290 | sink: &priv->subdev.entity, sink_pad: 0, |
1291 | MEDIA_LNK_FL_ENABLED | |
1292 | MEDIA_LNK_FL_IMMUTABLE); |
1293 | } |
1294 | |
1295 | static void rcsi2_notify_unbind(struct v4l2_async_notifier *notifier, |
1296 | struct v4l2_subdev *subdev, |
1297 | struct v4l2_async_connection *asc) |
1298 | { |
1299 | struct rcar_csi2 *priv = notifier_to_csi2(n: notifier); |
1300 | |
1301 | priv->remote = NULL; |
1302 | |
1303 | dev_dbg(priv->dev, "Unbind %s\n" , subdev->name); |
1304 | } |
1305 | |
1306 | static const struct v4l2_async_notifier_operations rcar_csi2_notify_ops = { |
1307 | .bound = rcsi2_notify_bound, |
1308 | .unbind = rcsi2_notify_unbind, |
1309 | }; |
1310 | |
1311 | static int rcsi2_parse_v4l2(struct rcar_csi2 *priv, |
1312 | struct v4l2_fwnode_endpoint *vep) |
1313 | { |
1314 | unsigned int i; |
1315 | |
1316 | /* Only port 0 endpoint 0 is valid. */ |
1317 | if (vep->base.port || vep->base.id) |
1318 | return -ENOTCONN; |
1319 | |
1320 | priv->lanes = vep->bus.mipi_csi2.num_data_lanes; |
1321 | |
1322 | switch (vep->bus_type) { |
1323 | case V4L2_MBUS_CSI2_DPHY: |
1324 | if (!priv->info->support_dphy) { |
1325 | dev_err(priv->dev, "D-PHY not supported\n" ); |
1326 | return -EINVAL; |
1327 | } |
1328 | |
1329 | if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) { |
1330 | dev_err(priv->dev, |
1331 | "Unsupported number of data-lanes for D-PHY: %u\n" , |
1332 | priv->lanes); |
1333 | return -EINVAL; |
1334 | } |
1335 | |
1336 | priv->cphy = false; |
1337 | break; |
1338 | case V4L2_MBUS_CSI2_CPHY: |
1339 | if (!priv->info->support_cphy) { |
1340 | dev_err(priv->dev, "C-PHY not supported\n" ); |
1341 | return -EINVAL; |
1342 | } |
1343 | |
1344 | if (priv->lanes != 3) { |
1345 | dev_err(priv->dev, |
1346 | "Unsupported number of data-lanes for C-PHY: %u\n" , |
1347 | priv->lanes); |
1348 | return -EINVAL; |
1349 | } |
1350 | |
1351 | priv->cphy = true; |
1352 | break; |
1353 | default: |
1354 | dev_err(priv->dev, "Unsupported bus: %u\n" , vep->bus_type); |
1355 | return -EINVAL; |
1356 | } |
1357 | |
1358 | for (i = 0; i < ARRAY_SIZE(priv->lane_swap); i++) { |
1359 | priv->lane_swap[i] = i < priv->lanes ? |
1360 | vep->bus.mipi_csi2.data_lanes[i] : i; |
1361 | |
1362 | /* Check for valid lane number. */ |
1363 | if (priv->lane_swap[i] < 1 || priv->lane_swap[i] > 4) { |
1364 | dev_err(priv->dev, "data-lanes must be in 1-4 range\n" ); |
1365 | return -EINVAL; |
1366 | } |
1367 | } |
1368 | |
1369 | return 0; |
1370 | } |
1371 | |
1372 | static int rcsi2_parse_dt(struct rcar_csi2 *priv) |
1373 | { |
1374 | struct v4l2_async_connection *asc; |
1375 | struct fwnode_handle *fwnode; |
1376 | struct fwnode_handle *ep; |
1377 | struct v4l2_fwnode_endpoint v4l2_ep = { |
1378 | .bus_type = V4L2_MBUS_UNKNOWN, |
1379 | }; |
1380 | int ret; |
1381 | |
1382 | ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), port: 0, endpoint: 0, flags: 0); |
1383 | if (!ep) { |
1384 | dev_err(priv->dev, "Not connected to subdevice\n" ); |
1385 | return -EINVAL; |
1386 | } |
1387 | |
1388 | ret = v4l2_fwnode_endpoint_parse(fwnode: ep, vep: &v4l2_ep); |
1389 | if (ret) { |
1390 | dev_err(priv->dev, "Could not parse v4l2 endpoint\n" ); |
1391 | fwnode_handle_put(fwnode: ep); |
1392 | return -EINVAL; |
1393 | } |
1394 | |
1395 | ret = rcsi2_parse_v4l2(priv, vep: &v4l2_ep); |
1396 | if (ret) { |
1397 | fwnode_handle_put(fwnode: ep); |
1398 | return ret; |
1399 | } |
1400 | |
1401 | fwnode = fwnode_graph_get_remote_endpoint(fwnode: ep); |
1402 | fwnode_handle_put(fwnode: ep); |
1403 | |
1404 | dev_dbg(priv->dev, "Found '%pOF'\n" , to_of_node(fwnode)); |
1405 | |
1406 | v4l2_async_subdev_nf_init(notifier: &priv->notifier, sd: &priv->subdev); |
1407 | priv->notifier.ops = &rcar_csi2_notify_ops; |
1408 | |
1409 | asc = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode, |
1410 | struct v4l2_async_connection); |
1411 | fwnode_handle_put(fwnode); |
1412 | if (IS_ERR(ptr: asc)) |
1413 | return PTR_ERR(ptr: asc); |
1414 | |
1415 | ret = v4l2_async_nf_register(notifier: &priv->notifier); |
1416 | if (ret) |
1417 | v4l2_async_nf_cleanup(notifier: &priv->notifier); |
1418 | |
1419 | return ret; |
1420 | } |
1421 | |
1422 | /* ----------------------------------------------------------------------------- |
1423 | * PHTW initialization sequences. |
1424 | * |
1425 | * NOTE: Magic values are from the datasheet and lack documentation. |
1426 | */ |
1427 | |
1428 | static int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code) |
1429 | { |
1430 | unsigned int timeout; |
1431 | |
1432 | rcsi2_write(priv, PHTW_REG, |
1433 | PHTW_DWEN | PHTW_TESTDIN_DATA(data) | |
1434 | PHTW_CWEN | PHTW_TESTDIN_CODE(code)); |
1435 | |
1436 | /* Wait for DWEN and CWEN to be cleared by hardware. */ |
1437 | for (timeout = 0; timeout <= 20; timeout++) { |
1438 | if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN))) |
1439 | return 0; |
1440 | |
1441 | usleep_range(min: 1000, max: 2000); |
1442 | } |
1443 | |
1444 | dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n" ); |
1445 | |
1446 | return -ETIMEDOUT; |
1447 | } |
1448 | |
1449 | static int rcsi2_phtw_write_array(struct rcar_csi2 *priv, |
1450 | const struct phtw_value *values) |
1451 | { |
1452 | const struct phtw_value *value; |
1453 | int ret; |
1454 | |
1455 | for (value = values; value->data || value->code; value++) { |
1456 | ret = rcsi2_phtw_write(priv, data: value->data, code: value->code); |
1457 | if (ret) |
1458 | return ret; |
1459 | } |
1460 | |
1461 | return 0; |
1462 | } |
1463 | |
1464 | static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, |
1465 | const struct rcsi2_mbps_reg *values, u16 code) |
1466 | { |
1467 | const struct rcsi2_mbps_reg *value; |
1468 | const struct rcsi2_mbps_reg *prev_value = NULL; |
1469 | |
1470 | for (value = values; value->mbps; value++) { |
1471 | if (value->mbps >= mbps) |
1472 | break; |
1473 | prev_value = value; |
1474 | } |
1475 | |
1476 | if (prev_value && |
1477 | ((mbps - prev_value->mbps) <= (value->mbps - mbps))) |
1478 | value = prev_value; |
1479 | |
1480 | if (!value->mbps) { |
1481 | dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)" , mbps); |
1482 | return -ERANGE; |
1483 | } |
1484 | |
1485 | return rcsi2_phtw_write(priv, data: value->reg, code); |
1486 | } |
1487 | |
1488 | static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, |
1489 | unsigned int mbps) |
1490 | { |
1491 | static const struct phtw_value step1[] = { |
1492 | { .data = 0xcc, .code = 0xe2 }, |
1493 | { .data = 0x01, .code = 0xe3 }, |
1494 | { .data = 0x11, .code = 0xe4 }, |
1495 | { .data = 0x01, .code = 0xe5 }, |
1496 | { .data = 0x10, .code = 0x04 }, |
1497 | { /* sentinel */ }, |
1498 | }; |
1499 | |
1500 | static const struct phtw_value step2[] = { |
1501 | { .data = 0x38, .code = 0x08 }, |
1502 | { .data = 0x01, .code = 0x00 }, |
1503 | { .data = 0x4b, .code = 0xac }, |
1504 | { .data = 0x03, .code = 0x00 }, |
1505 | { .data = 0x80, .code = 0x07 }, |
1506 | { /* sentinel */ }, |
1507 | }; |
1508 | |
1509 | int ret; |
1510 | |
1511 | ret = rcsi2_phtw_write_array(priv, values: step1); |
1512 | if (ret) |
1513 | return ret; |
1514 | |
1515 | if (mbps != 0 && mbps <= 250) { |
1516 | ret = rcsi2_phtw_write(priv, data: 0x39, code: 0x05); |
1517 | if (ret) |
1518 | return ret; |
1519 | |
1520 | ret = rcsi2_phtw_write_mbps(priv, mbps, values: phtw_mbps_h3_v3h_m3n, |
1521 | code: 0xf1); |
1522 | if (ret) |
1523 | return ret; |
1524 | } |
1525 | |
1526 | return rcsi2_phtw_write_array(priv, values: step2); |
1527 | } |
1528 | |
1529 | static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) |
1530 | { |
1531 | return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps); |
1532 | } |
1533 | |
1534 | static int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps) |
1535 | { |
1536 | return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps: 0); |
1537 | } |
1538 | |
1539 | static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) |
1540 | { |
1541 | return rcsi2_phtw_write_mbps(priv, mbps, values: phtw_mbps_v3m_e3, code: 0x44); |
1542 | } |
1543 | |
1544 | static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) |
1545 | { |
1546 | static const struct phtw_value step1[] = { |
1547 | { .data = 0xee, .code = 0x34 }, |
1548 | { .data = 0xee, .code = 0x44 }, |
1549 | { .data = 0xee, .code = 0x54 }, |
1550 | { .data = 0xee, .code = 0x84 }, |
1551 | { .data = 0xee, .code = 0x94 }, |
1552 | { /* sentinel */ }, |
1553 | }; |
1554 | |
1555 | return rcsi2_phtw_write_array(priv, values: step1); |
1556 | } |
1557 | |
1558 | static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, |
1559 | unsigned int mbps) |
1560 | { |
1561 | /* In case of 1500Mbps or less */ |
1562 | static const struct phtw_value step1[] = { |
1563 | { .data = 0xcc, .code = 0xe2 }, |
1564 | { /* sentinel */ }, |
1565 | }; |
1566 | |
1567 | static const struct phtw_value step2[] = { |
1568 | { .data = 0x01, .code = 0xe3 }, |
1569 | { .data = 0x11, .code = 0xe4 }, |
1570 | { .data = 0x01, .code = 0xe5 }, |
1571 | { /* sentinel */ }, |
1572 | }; |
1573 | |
1574 | /* In case of 1500Mbps or less */ |
1575 | static const struct phtw_value step3[] = { |
1576 | { .data = 0x38, .code = 0x08 }, |
1577 | { /* sentinel */ }, |
1578 | }; |
1579 | |
1580 | static const struct phtw_value step4[] = { |
1581 | { .data = 0x01, .code = 0x00 }, |
1582 | { .data = 0x4b, .code = 0xac }, |
1583 | { .data = 0x03, .code = 0x00 }, |
1584 | { .data = 0x80, .code = 0x07 }, |
1585 | { /* sentinel */ }, |
1586 | }; |
1587 | |
1588 | int ret; |
1589 | |
1590 | if (mbps != 0 && mbps <= 1500) |
1591 | ret = rcsi2_phtw_write_array(priv, values: step1); |
1592 | else |
1593 | ret = rcsi2_phtw_write_mbps(priv, mbps, values: phtw_mbps_v3u, code: 0xe2); |
1594 | if (ret) |
1595 | return ret; |
1596 | |
1597 | ret = rcsi2_phtw_write_array(priv, values: step2); |
1598 | if (ret) |
1599 | return ret; |
1600 | |
1601 | if (mbps != 0 && mbps <= 1500) { |
1602 | ret = rcsi2_phtw_write_array(priv, values: step3); |
1603 | if (ret) |
1604 | return ret; |
1605 | } |
1606 | |
1607 | ret = rcsi2_phtw_write_array(priv, values: step4); |
1608 | if (ret) |
1609 | return ret; |
1610 | |
1611 | return ret; |
1612 | } |
1613 | |
1614 | /* ----------------------------------------------------------------------------- |
1615 | * Platform Device Driver. |
1616 | */ |
1617 | |
1618 | static int rcsi2_link_setup(struct media_entity *entity, |
1619 | const struct media_pad *local, |
1620 | const struct media_pad *remote, u32 flags) |
1621 | { |
1622 | struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); |
1623 | struct rcar_csi2 *priv = sd_to_csi2(sd); |
1624 | struct video_device *vdev; |
1625 | int channel, vc; |
1626 | u32 id; |
1627 | |
1628 | if (!is_media_entity_v4l2_video_device(entity: remote->entity)) { |
1629 | dev_err(priv->dev, "Remote is not a video device\n" ); |
1630 | return -EINVAL; |
1631 | } |
1632 | |
1633 | vdev = media_entity_to_video_device(remote->entity); |
1634 | |
1635 | if (of_property_read_u32(np: vdev->dev_parent->of_node, propname: "renesas,id" , out_value: &id)) { |
1636 | dev_err(priv->dev, "No renesas,id, can't configure routing\n" ); |
1637 | return -EINVAL; |
1638 | } |
1639 | |
1640 | channel = id % 4; |
1641 | |
1642 | if (flags & MEDIA_LNK_FL_ENABLED) { |
1643 | if (media_pad_remote_pad_first(pad: local)) { |
1644 | dev_dbg(priv->dev, |
1645 | "Each VC can only be routed to one output channel\n" ); |
1646 | return -EINVAL; |
1647 | } |
1648 | |
1649 | vc = local->index - 1; |
1650 | |
1651 | dev_dbg(priv->dev, "Route VC%d to VIN%u on output channel %d\n" , |
1652 | vc, id, channel); |
1653 | } else { |
1654 | vc = -1; |
1655 | } |
1656 | |
1657 | priv->channel_vc[channel] = vc; |
1658 | |
1659 | return 0; |
1660 | } |
1661 | |
1662 | static const struct media_entity_operations rcar_csi2_entity_ops = { |
1663 | .link_setup = rcsi2_link_setup, |
1664 | .link_validate = v4l2_subdev_link_validate, |
1665 | }; |
1666 | |
1667 | static int rcsi2_probe_resources(struct rcar_csi2 *priv, |
1668 | struct platform_device *pdev) |
1669 | { |
1670 | int irq, ret; |
1671 | |
1672 | priv->base = devm_platform_ioremap_resource(pdev, index: 0); |
1673 | if (IS_ERR(ptr: priv->base)) |
1674 | return PTR_ERR(ptr: priv->base); |
1675 | |
1676 | irq = platform_get_irq(pdev, 0); |
1677 | if (irq < 0) |
1678 | return irq; |
1679 | |
1680 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq, handler: rcsi2_irq, |
1681 | thread_fn: rcsi2_irq_thread, IRQF_SHARED, |
1682 | KBUILD_MODNAME, dev_id: priv); |
1683 | if (ret) |
1684 | return ret; |
1685 | |
1686 | priv->rstc = devm_reset_control_get(dev: &pdev->dev, NULL); |
1687 | |
1688 | return PTR_ERR_OR_ZERO(ptr: priv->rstc); |
1689 | } |
1690 | |
1691 | static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { |
1692 | .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, |
1693 | .start_receiver = rcsi2_start_receiver_gen3, |
1694 | .enter_standby = rcsi2_enter_standby_gen3, |
1695 | .hsfreqrange = hsfreqrange_h3_v3h_m3n, |
1696 | .csi0clkfreqrange = 0x20, |
1697 | .num_channels = 4, |
1698 | .clear_ulps = true, |
1699 | .support_dphy = true, |
1700 | }; |
1701 | |
1702 | static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { |
1703 | .init_phtw = rcsi2_init_phtw_h3es2, |
1704 | .start_receiver = rcsi2_start_receiver_gen3, |
1705 | .enter_standby = rcsi2_enter_standby_gen3, |
1706 | .hsfreqrange = hsfreqrange_h3_v3h_m3n, |
1707 | .csi0clkfreqrange = 0x20, |
1708 | .num_channels = 4, |
1709 | .clear_ulps = true, |
1710 | .support_dphy = true, |
1711 | }; |
1712 | |
1713 | static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { |
1714 | .start_receiver = rcsi2_start_receiver_gen3, |
1715 | .enter_standby = rcsi2_enter_standby_gen3, |
1716 | .hsfreqrange = hsfreqrange_m3w, |
1717 | .num_channels = 4, |
1718 | .support_dphy = true, |
1719 | }; |
1720 | |
1721 | static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = { |
1722 | .start_receiver = rcsi2_start_receiver_gen3, |
1723 | .enter_standby = rcsi2_enter_standby_gen3, |
1724 | .hsfreqrange = hsfreqrange_m3w, |
1725 | .num_channels = 4, |
1726 | .support_dphy = true, |
1727 | }; |
1728 | |
1729 | static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { |
1730 | .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, |
1731 | .start_receiver = rcsi2_start_receiver_gen3, |
1732 | .enter_standby = rcsi2_enter_standby_gen3, |
1733 | .hsfreqrange = hsfreqrange_h3_v3h_m3n, |
1734 | .csi0clkfreqrange = 0x20, |
1735 | .num_channels = 4, |
1736 | .clear_ulps = true, |
1737 | .support_dphy = true, |
1738 | }; |
1739 | |
1740 | static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { |
1741 | .init_phtw = rcsi2_init_phtw_v3m_e3, |
1742 | .phy_post_init = rcsi2_phy_post_init_v3m_e3, |
1743 | .start_receiver = rcsi2_start_receiver_gen3, |
1744 | .enter_standby = rcsi2_enter_standby_gen3, |
1745 | .num_channels = 4, |
1746 | .support_dphy = true, |
1747 | }; |
1748 | |
1749 | static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { |
1750 | .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, |
1751 | .start_receiver = rcsi2_start_receiver_gen3, |
1752 | .enter_standby = rcsi2_enter_standby_gen3, |
1753 | .hsfreqrange = hsfreqrange_h3_v3h_m3n, |
1754 | .csi0clkfreqrange = 0x20, |
1755 | .clear_ulps = true, |
1756 | .support_dphy = true, |
1757 | }; |
1758 | |
1759 | static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { |
1760 | .init_phtw = rcsi2_init_phtw_v3m_e3, |
1761 | .phy_post_init = rcsi2_phy_post_init_v3m_e3, |
1762 | .start_receiver = rcsi2_start_receiver_gen3, |
1763 | .enter_standby = rcsi2_enter_standby_gen3, |
1764 | .num_channels = 2, |
1765 | .support_dphy = true, |
1766 | }; |
1767 | |
1768 | static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = { |
1769 | .init_phtw = rcsi2_init_phtw_v3u, |
1770 | .start_receiver = rcsi2_start_receiver_gen3, |
1771 | .enter_standby = rcsi2_enter_standby_gen3, |
1772 | .hsfreqrange = hsfreqrange_v3u, |
1773 | .csi0clkfreqrange = 0x20, |
1774 | .clear_ulps = true, |
1775 | .use_isp = true, |
1776 | .support_dphy = true, |
1777 | }; |
1778 | |
1779 | static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = { |
1780 | .start_receiver = rcsi2_start_receiver_v4h, |
1781 | .use_isp = true, |
1782 | .support_cphy = true, |
1783 | }; |
1784 | |
1785 | static const struct of_device_id rcar_csi2_of_table[] = { |
1786 | { |
1787 | .compatible = "renesas,r8a774a1-csi2" , |
1788 | .data = &rcar_csi2_info_r8a7796, |
1789 | }, |
1790 | { |
1791 | .compatible = "renesas,r8a774b1-csi2" , |
1792 | .data = &rcar_csi2_info_r8a77965, |
1793 | }, |
1794 | { |
1795 | .compatible = "renesas,r8a774c0-csi2" , |
1796 | .data = &rcar_csi2_info_r8a77990, |
1797 | }, |
1798 | { |
1799 | .compatible = "renesas,r8a774e1-csi2" , |
1800 | .data = &rcar_csi2_info_r8a7795, |
1801 | }, |
1802 | { |
1803 | .compatible = "renesas,r8a7795-csi2" , |
1804 | .data = &rcar_csi2_info_r8a7795, |
1805 | }, |
1806 | { |
1807 | .compatible = "renesas,r8a7796-csi2" , |
1808 | .data = &rcar_csi2_info_r8a7796, |
1809 | }, |
1810 | { |
1811 | .compatible = "renesas,r8a77961-csi2" , |
1812 | .data = &rcar_csi2_info_r8a77961, |
1813 | }, |
1814 | { |
1815 | .compatible = "renesas,r8a77965-csi2" , |
1816 | .data = &rcar_csi2_info_r8a77965, |
1817 | }, |
1818 | { |
1819 | .compatible = "renesas,r8a77970-csi2" , |
1820 | .data = &rcar_csi2_info_r8a77970, |
1821 | }, |
1822 | { |
1823 | .compatible = "renesas,r8a77980-csi2" , |
1824 | .data = &rcar_csi2_info_r8a77980, |
1825 | }, |
1826 | { |
1827 | .compatible = "renesas,r8a77990-csi2" , |
1828 | .data = &rcar_csi2_info_r8a77990, |
1829 | }, |
1830 | { |
1831 | .compatible = "renesas,r8a779a0-csi2" , |
1832 | .data = &rcar_csi2_info_r8a779a0, |
1833 | }, |
1834 | { |
1835 | .compatible = "renesas,r8a779g0-csi2" , |
1836 | .data = &rcar_csi2_info_r8a779g0, |
1837 | }, |
1838 | { /* sentinel */ }, |
1839 | }; |
1840 | MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); |
1841 | |
1842 | static const struct soc_device_attribute r8a7795[] = { |
1843 | { |
1844 | .soc_id = "r8a7795" , .revision = "ES2.*" , |
1845 | .data = &rcar_csi2_info_r8a7795es2, |
1846 | }, |
1847 | { /* sentinel */ } |
1848 | }; |
1849 | |
1850 | static int rcsi2_probe(struct platform_device *pdev) |
1851 | { |
1852 | const struct soc_device_attribute *attr; |
1853 | struct rcar_csi2 *priv; |
1854 | unsigned int i, num_pads; |
1855 | int ret; |
1856 | |
1857 | priv = devm_kzalloc(dev: &pdev->dev, size: sizeof(*priv), GFP_KERNEL); |
1858 | if (!priv) |
1859 | return -ENOMEM; |
1860 | |
1861 | priv->info = of_device_get_match_data(dev: &pdev->dev); |
1862 | |
1863 | /* |
1864 | * The different ES versions of r8a7795 (H3) behave differently but |
1865 | * share the same compatible string. |
1866 | */ |
1867 | attr = soc_device_match(matches: r8a7795); |
1868 | if (attr) |
1869 | priv->info = attr->data; |
1870 | |
1871 | priv->dev = &pdev->dev; |
1872 | |
1873 | mutex_init(&priv->lock); |
1874 | priv->stream_count = 0; |
1875 | |
1876 | ret = rcsi2_probe_resources(priv, pdev); |
1877 | if (ret) { |
1878 | dev_err(priv->dev, "Failed to get resources\n" ); |
1879 | goto error_mutex; |
1880 | } |
1881 | |
1882 | platform_set_drvdata(pdev, data: priv); |
1883 | |
1884 | ret = rcsi2_parse_dt(priv); |
1885 | if (ret) |
1886 | goto error_mutex; |
1887 | |
1888 | priv->subdev.owner = THIS_MODULE; |
1889 | priv->subdev.dev = &pdev->dev; |
1890 | v4l2_subdev_init(sd: &priv->subdev, ops: &rcar_csi2_subdev_ops); |
1891 | v4l2_set_subdevdata(sd: &priv->subdev, p: &pdev->dev); |
1892 | snprintf(buf: priv->subdev.name, size: sizeof(priv->subdev.name), fmt: "%s %s" , |
1893 | KBUILD_MODNAME, dev_name(dev: &pdev->dev)); |
1894 | priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; |
1895 | |
1896 | priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; |
1897 | priv->subdev.entity.ops = &rcar_csi2_entity_ops; |
1898 | |
1899 | num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD; |
1900 | |
1901 | priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; |
1902 | for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++) |
1903 | priv->pads[i].flags = MEDIA_PAD_FL_SOURCE; |
1904 | |
1905 | ret = media_entity_pads_init(entity: &priv->subdev.entity, num_pads, |
1906 | pads: priv->pads); |
1907 | if (ret) |
1908 | goto error_async; |
1909 | |
1910 | for (i = 0; i < ARRAY_SIZE(priv->channel_vc); i++) |
1911 | priv->channel_vc[i] = -1; |
1912 | |
1913 | pm_runtime_enable(dev: &pdev->dev); |
1914 | |
1915 | ret = v4l2_async_register_subdev(sd: &priv->subdev); |
1916 | if (ret < 0) |
1917 | goto error_async; |
1918 | |
1919 | dev_info(priv->dev, "%d lanes found\n" , priv->lanes); |
1920 | |
1921 | return 0; |
1922 | |
1923 | error_async: |
1924 | v4l2_async_nf_unregister(notifier: &priv->notifier); |
1925 | v4l2_async_nf_cleanup(notifier: &priv->notifier); |
1926 | error_mutex: |
1927 | mutex_destroy(lock: &priv->lock); |
1928 | |
1929 | return ret; |
1930 | } |
1931 | |
1932 | static void rcsi2_remove(struct platform_device *pdev) |
1933 | { |
1934 | struct rcar_csi2 *priv = platform_get_drvdata(pdev); |
1935 | |
1936 | v4l2_async_nf_unregister(notifier: &priv->notifier); |
1937 | v4l2_async_nf_cleanup(notifier: &priv->notifier); |
1938 | v4l2_async_unregister_subdev(sd: &priv->subdev); |
1939 | |
1940 | pm_runtime_disable(dev: &pdev->dev); |
1941 | |
1942 | mutex_destroy(lock: &priv->lock); |
1943 | } |
1944 | |
1945 | static struct platform_driver rcar_csi2_pdrv = { |
1946 | .remove_new = rcsi2_remove, |
1947 | .probe = rcsi2_probe, |
1948 | .driver = { |
1949 | .name = "rcar-csi2" , |
1950 | .suppress_bind_attrs = true, |
1951 | .of_match_table = rcar_csi2_of_table, |
1952 | }, |
1953 | }; |
1954 | |
1955 | module_platform_driver(rcar_csi2_pdrv); |
1956 | |
1957 | MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>" ); |
1958 | MODULE_DESCRIPTION("Renesas R-Car MIPI CSI-2 receiver driver" ); |
1959 | MODULE_LICENSE("GPL" ); |
1960 | |