c22770da48648fd7144537ffd6c9a9ba62203a01
[openwrt/staging/blogic.git] /
1 From ffbb09db69889cb09a1d7d647364211605247158 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Wed, 16 Jun 2021 16:27:06 +0100
4 Subject: [PATCH] media: i2c: imx258: Add support for running on 2 CSI
5 data lanes
6
7 Extends the driver to also support 2 data lanes.
8 Frame rates are obviously more restricted on 2 lanes, but some
9 hardware simply hasn't wired more up.
10
11 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
12 ---
13 drivers/media/i2c/imx258.c | 212 ++++++++++++++++++++++++++++++++-----
14 1 file changed, 186 insertions(+), 26 deletions(-)
15
16 --- a/drivers/media/i2c/imx258.c
17 +++ b/drivers/media/i2c/imx258.c
18 @@ -87,13 +87,17 @@ struct imx258_reg_list {
19 const struct imx258_reg *regs;
20 };
21
22 +#define IMX258_LANE_CONFIGS 2
23 +#define IMX258_2_LANE_MODE 0
24 +#define IMX258_4_LANE_MODE 1
25 +
26 /* Link frequency config */
27 struct imx258_link_freq_config {
28 u64 link_frequency;
29 u32 pixels_per_line;
30
31 /* PLL registers for this link frequency */
32 - struct imx258_reg_list reg_list;
33 + struct imx258_reg_list reg_list[IMX258_LANE_CONFIGS];
34 };
35
36 /* Mode : resolution and related config&values */
37 @@ -113,8 +117,30 @@ struct imx258_mode {
38 struct imx258_reg_list reg_list;
39 };
40
41 -/* 4208x3120 needs 1267Mbps/lane, 4 lanes */
42 -static const struct imx258_reg mipi_1267mbps_19_2mhz[] = {
43 +/* 4208x3120 needs 1267Mbps/lane, 4 lanes. Use that rate on 2 lanes as well */
44 +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = {
45 + { 0x0136, 0x13 },
46 + { 0x0137, 0x33 },
47 + { 0x0301, 0x0A },
48 + { 0x0303, 0x02 },
49 + { 0x0305, 0x03 },
50 + { 0x0306, 0x00 },
51 + { 0x0307, 0xC6 },
52 + { 0x0309, 0x0A },
53 + { 0x030B, 0x01 },
54 + { 0x030D, 0x02 },
55 + { 0x030E, 0x00 },
56 + { 0x030F, 0xD8 },
57 + { 0x0310, 0x00 },
58 +
59 + { 0x0114, 0x01 },
60 + { 0x0820, 0x09 },
61 + { 0x0821, 0xa6 },
62 + { 0x0822, 0x66 },
63 + { 0x0823, 0x66 },
64 +};
65 +
66 +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = {
67 { 0x0136, 0x13 },
68 { 0x0137, 0x33 },
69 { 0x0301, 0x05 },
70 @@ -128,16 +154,18 @@ static const struct imx258_reg mipi_1267
71 { 0x030E, 0x00 },
72 { 0x030F, 0xD8 },
73 { 0x0310, 0x00 },
74 +
75 + { 0x0114, 0x03 },
76 { 0x0820, 0x13 },
77 { 0x0821, 0x4C },
78 { 0x0822, 0xCC },
79 { 0x0823, 0xCC },
80 };
81
82 -static const struct imx258_reg mipi_1272mbps_24mhz[] = {
83 +static const struct imx258_reg mipi_1272mbps_24mhz_2l[] = {
84 { 0x0136, 0x18 },
85 { 0x0137, 0x00 },
86 - { 0x0301, 0x05 },
87 + { 0x0301, 0x0a },
88 { 0x0303, 0x02 },
89 { 0x0305, 0x04 },
90 { 0x0306, 0x00 },
91 @@ -148,13 +176,59 @@ static const struct imx258_reg mipi_1272
92 { 0x030E, 0x00 },
93 { 0x030F, 0xD8 },
94 { 0x0310, 0x00 },
95 +
96 + { 0x0114, 0x01 },
97 { 0x0820, 0x13 },
98 { 0x0821, 0x4C },
99 { 0x0822, 0xCC },
100 { 0x0823, 0xCC },
101 };
102
103 -static const struct imx258_reg mipi_640mbps_19_2mhz[] = {
104 +static const struct imx258_reg mipi_1272mbps_24mhz_4l[] = {
105 + { 0x0136, 0x18 },
106 + { 0x0137, 0x00 },
107 + { 0x0301, 0x05 },
108 + { 0x0303, 0x02 },
109 + { 0x0305, 0x04 },
110 + { 0x0306, 0x00 },
111 + { 0x0307, 0xD4 },
112 + { 0x0309, 0x0A },
113 + { 0x030B, 0x01 },
114 + { 0x030D, 0x02 },
115 + { 0x030E, 0x00 },
116 + { 0x030F, 0xD8 },
117 + { 0x0310, 0x00 },
118 +
119 + { 0x0114, 0x03 },
120 + { 0x0820, 0x13 },
121 + { 0x0821, 0xE0 },
122 + { 0x0822, 0x00 },
123 + { 0x0823, 0x00 },
124 +};
125 +
126 +static const struct imx258_reg mipi_640mbps_19_2mhz_2l[] = {
127 + { 0x0136, 0x13 },
128 + { 0x0137, 0x33 },
129 + { 0x0301, 0x05 },
130 + { 0x0303, 0x02 },
131 + { 0x0305, 0x03 },
132 + { 0x0306, 0x00 },
133 + { 0x0307, 0x64 },
134 + { 0x0309, 0x0A },
135 + { 0x030B, 0x01 },
136 + { 0x030D, 0x02 },
137 + { 0x030E, 0x00 },
138 + { 0x030F, 0xD8 },
139 + { 0x0310, 0x00 },
140 +
141 + { 0x0114, 0x01 },
142 + { 0x0820, 0x05 },
143 + { 0x0821, 0x00 },
144 + { 0x0822, 0x00 },
145 + { 0x0823, 0x00 },
146 +};
147 +
148 +static const struct imx258_reg mipi_640mbps_19_2mhz_4l[] = {
149 { 0x0136, 0x13 },
150 { 0x0137, 0x33 },
151 { 0x0301, 0x05 },
152 @@ -168,13 +242,37 @@ static const struct imx258_reg mipi_640m
153 { 0x030E, 0x00 },
154 { 0x030F, 0xD8 },
155 { 0x0310, 0x00 },
156 +
157 + { 0x0114, 0x03 },
158 + { 0x0820, 0x0A },
159 + { 0x0821, 0x00 },
160 + { 0x0822, 0x00 },
161 + { 0x0823, 0x00 },
162 +};
163 +
164 +static const struct imx258_reg mipi_642mbps_24mhz_2l[] = {
165 + { 0x0136, 0x18 },
166 + { 0x0137, 0x00 },
167 + { 0x0301, 0x0A },
168 + { 0x0303, 0x02 },
169 + { 0x0305, 0x04 },
170 + { 0x0306, 0x00 },
171 + { 0x0307, 0x6B },
172 + { 0x0309, 0x0A },
173 + { 0x030B, 0x01 },
174 + { 0x030D, 0x02 },
175 + { 0x030E, 0x00 },
176 + { 0x030F, 0xD8 },
177 + { 0x0310, 0x00 },
178 +
179 + { 0x0114, 0x01 },
180 { 0x0820, 0x0A },
181 { 0x0821, 0x00 },
182 { 0x0822, 0x00 },
183 { 0x0823, 0x00 },
184 };
185
186 -static const struct imx258_reg mipi_642mbps_24mhz[] = {
187 +static const struct imx258_reg mipi_642mbps_24mhz_4l[] = {
188 { 0x0136, 0x18 },
189 { 0x0137, 0x00 },
190 { 0x0301, 0x05 },
191 @@ -188,6 +286,8 @@ static const struct imx258_reg mipi_642m
192 { 0x030E, 0x00 },
193 { 0x030F, 0xD8 },
194 { 0x0310, 0x00 },
195 +
196 + { 0x0114, 0x03 },
197 { 0x0820, 0x0A },
198 { 0x0821, 0x00 },
199 { 0x0822, 0x00 },
200 @@ -242,7 +342,6 @@ static const struct imx258_reg mode_4208
201 { 0x5F05, 0xED },
202 { 0x0112, 0x0A },
203 { 0x0113, 0x0A },
204 - { 0x0114, 0x03 },
205 { 0x0342, 0x14 },
206 { 0x0343, 0xE8 },
207 { 0x0344, 0x00 },
208 @@ -355,7 +454,6 @@ static const struct imx258_reg mode_2104
209 { 0x5F05, 0xED },
210 { 0x0112, 0x0A },
211 { 0x0113, 0x0A },
212 - { 0x0114, 0x03 },
213 { 0x0342, 0x14 },
214 { 0x0343, 0xE8 },
215 { 0x0344, 0x00 },
216 @@ -468,7 +566,6 @@ static const struct imx258_reg mode_1048
217 { 0x5F05, 0xED },
218 { 0x0112, 0x0A },
219 { 0x0113, 0x0A },
220 - { 0x0114, 0x03 },
221 { 0x0342, 0x14 },
222 { 0x0343, 0xE8 },
223 { 0x0344, 0x00 },
224 @@ -574,11 +671,13 @@ enum {
225
226 /*
227 * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
228 - * data rate => double data rate; number of lanes => 4; bits per pixel => 10
229 + * data rate => double data rate;
230 + * number of lanes => (configurable 2 or 4);
231 + * bits per pixel => 10
232 */
233 -static u64 link_freq_to_pixel_rate(u64 f)
234 +static u64 link_freq_to_pixel_rate(u64 f, unsigned int nlanes)
235 {
236 - f *= 2 * 4;
237 + f *= 2 * nlanes;
238 do_div(f, 10);
239
240 return f;
241 @@ -608,15 +707,27 @@ static const struct imx258_link_freq_con
242 [IMX258_LINK_FREQ_1267MBPS] = {
243 .pixels_per_line = IMX258_PPL_DEFAULT,
244 .reg_list = {
245 - .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz),
246 - .regs = mipi_1267mbps_19_2mhz,
247 + [IMX258_2_LANE_MODE] = {
248 + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_2l),
249 + .regs = mipi_1267mbps_19_2mhz_2l,
250 + },
251 + [IMX258_4_LANE_MODE] = {
252 + .num_of_regs = ARRAY_SIZE(mipi_1267mbps_19_2mhz_4l),
253 + .regs = mipi_1267mbps_19_2mhz_4l,
254 + },
255 }
256 },
257 [IMX258_LINK_FREQ_640MBPS] = {
258 .pixels_per_line = IMX258_PPL_DEFAULT,
259 .reg_list = {
260 - .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz),
261 - .regs = mipi_640mbps_19_2mhz,
262 + [IMX258_2_LANE_MODE] = {
263 + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_2l),
264 + .regs = mipi_640mbps_19_2mhz_2l,
265 + },
266 + [IMX258_4_LANE_MODE] = {
267 + .num_of_regs = ARRAY_SIZE(mipi_640mbps_19_2mhz_4l),
268 + .regs = mipi_640mbps_19_2mhz_4l,
269 + },
270 }
271 },
272 };
273 @@ -625,15 +736,27 @@ static const struct imx258_link_freq_con
274 [IMX258_LINK_FREQ_1267MBPS] = {
275 .pixels_per_line = IMX258_PPL_DEFAULT,
276 .reg_list = {
277 - .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz),
278 - .regs = mipi_1272mbps_24mhz,
279 + [IMX258_2_LANE_MODE] = {
280 + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_2l),
281 + .regs = mipi_1272mbps_24mhz_2l,
282 + },
283 + [IMX258_4_LANE_MODE] = {
284 + .num_of_regs = ARRAY_SIZE(mipi_1272mbps_24mhz_4l),
285 + .regs = mipi_1272mbps_24mhz_4l,
286 + },
287 }
288 },
289 [IMX258_LINK_FREQ_640MBPS] = {
290 .pixels_per_line = IMX258_PPL_DEFAULT,
291 .reg_list = {
292 - .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz),
293 - .regs = mipi_642mbps_24mhz,
294 + [IMX258_2_LANE_MODE] = {
295 + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_2l),
296 + .regs = mipi_642mbps_24mhz_2l,
297 + },
298 + [IMX258_4_LANE_MODE] = {
299 + .num_of_regs = ARRAY_SIZE(mipi_642mbps_24mhz_4l),
300 + .regs = mipi_642mbps_24mhz_4l,
301 + },
302 }
303 },
304 };
305 @@ -694,6 +817,7 @@ struct imx258 {
306
307 const struct imx258_link_freq_config *link_freq_configs;
308 const s64 *link_freq_menu_items;
309 + unsigned int nlanes;
310
311 /*
312 * Mutex for serialized access:
313 @@ -1024,7 +1148,7 @@ static int imx258_set_pad_format(struct
314 __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
315
316 link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
317 - pixel_rate = link_freq_to_pixel_rate(link_freq);
318 + pixel_rate = link_freq_to_pixel_rate(link_freq, imx258->nlanes);
319 __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
320 /* Update limits and set FPS to default */
321 vblank_def = imx258->cur_mode->vts_def -
322 @@ -1053,11 +1177,13 @@ static int imx258_start_streaming(struct
323 {
324 struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
325 const struct imx258_reg_list *reg_list;
326 + const struct imx258_link_freq_config *link_freq_cfg;
327 int ret, link_freq_index;
328
329 /* Setup PLL */
330 link_freq_index = imx258->cur_mode->link_freq_index;
331 - reg_list = &imx258->link_freq_configs[link_freq_index].reg_list;
332 + link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
333 + reg_list = &link_freq_cfg->reg_list[imx258->nlanes == 2 ? 0 : 1];
334 ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
335 if (ret) {
336 dev_err(&client->dev, "%s failed to set plls\n", __func__);
337 @@ -1283,9 +1409,11 @@ static int imx258_init_controls(struct i
338 imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
339
340 pixel_rate_max =
341 - link_freq_to_pixel_rate(imx258->link_freq_menu_items[0]);
342 + link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
343 + imx258->nlanes);
344 pixel_rate_min =
345 - link_freq_to_pixel_rate(imx258->link_freq_menu_items[1]);
346 + link_freq_to_pixel_rate(imx258->link_freq_menu_items[1],
347 + imx258->nlanes);
348 /* By default, PIXEL_RATE is read only */
349 imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
350 V4L2_CID_PIXEL_RATE,
351 @@ -1393,6 +1521,10 @@ static int imx258_get_regulators(struct
352 static int imx258_probe(struct i2c_client *client)
353 {
354 struct imx258 *imx258;
355 + struct fwnode_handle *endpoint;
356 + struct v4l2_fwnode_endpoint ep = {
357 + .bus_type = V4L2_MBUS_CSI2_DPHY
358 + };
359 int ret;
360 u32 val = 0;
361
362 @@ -1435,13 +1567,38 @@ static int imx258_probe(struct i2c_clien
363 return -EINVAL;
364 }
365
366 + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
367 + if (!endpoint) {
368 + dev_err(&client->dev, "Endpoint node not found\n");
369 + return -EINVAL;
370 + }
371 +
372 + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
373 + fwnode_handle_put(endpoint);
374 + if (ret == -ENXIO) {
375 + dev_err(&client->dev, "Unsupported bus type, should be CSI2\n");
376 + goto error_endpoint_poweron;
377 + } else if (ret) {
378 + dev_err(&client->dev, "Parsing endpoint node failed\n");
379 + goto error_endpoint_poweron;
380 + }
381 +
382 + /* Get number of data lanes */
383 + imx258->nlanes = ep.bus.mipi_csi2.num_data_lanes;
384 + if (imx258->nlanes != 2 && imx258->nlanes != 4) {
385 + dev_err(&client->dev, "Invalid data lanes: %u\n",
386 + imx258->nlanes);
387 + ret = -EINVAL;
388 + goto error_endpoint_poweron;
389 + }
390 +
391 /* Initialize subdev */
392 v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
393
394 /* Will be powered off via pm_runtime_idle */
395 ret = imx258_power_on(&client->dev);
396 if (ret)
397 - return ret;
398 + goto error_endpoint_poweron;
399
400 /* Check module identity */
401 ret = imx258_identify_module(imx258);
402 @@ -1486,6 +1643,9 @@ error_handler_free:
403 error_identify:
404 imx258_power_off(&client->dev);
405
406 +error_endpoint_poweron:
407 + v4l2_fwnode_endpoint_free(&ep);
408 +
409 return ret;
410 }
411