1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Lontium LT9211 bridge driver |
4 | * |
5 | * LT9211 is capable of converting: |
6 | * 2xDSI/2xLVDS/1xDPI -> 2xDSI/2xLVDS/1xDPI |
7 | * Currently supported is: |
8 | * 1xDSI -> 1xLVDS |
9 | * |
10 | * Copyright (C) 2022 Marek Vasut <marex@denx.de> |
11 | */ |
12 | |
13 | #include <linux/bits.h> |
14 | #include <linux/clk.h> |
15 | #include <linux/gpio/consumer.h> |
16 | #include <linux/i2c.h> |
17 | #include <linux/media-bus-format.h> |
18 | #include <linux/module.h> |
19 | #include <linux/of_graph.h> |
20 | #include <linux/regmap.h> |
21 | #include <linux/regulator/consumer.h> |
22 | |
23 | #include <drm/drm_atomic_helper.h> |
24 | #include <drm/drm_bridge.h> |
25 | #include <drm/drm_mipi_dsi.h> |
26 | #include <drm/drm_of.h> |
27 | #include <drm/drm_panel.h> |
28 | #include <drm/drm_print.h> |
29 | #include <drm/drm_probe_helper.h> |
30 | |
31 | #define REG_PAGE_CONTROL 0xff |
32 | #define REG_CHIPID0 0x8100 |
33 | #define REG_CHIPID0_VALUE 0x18 |
34 | #define REG_CHIPID1 0x8101 |
35 | #define REG_CHIPID1_VALUE 0x01 |
36 | #define REG_CHIPID2 0x8102 |
37 | #define REG_CHIPID2_VALUE 0xe3 |
38 | |
39 | #define REG_DSI_LANE 0xd000 |
40 | /* DSI lane count - 0 means 4 lanes ; 1, 2, 3 means 1, 2, 3 lanes. */ |
41 | #define REG_DSI_LANE_COUNT(n) ((n) & 3) |
42 | |
43 | struct lt9211 { |
44 | struct drm_bridge bridge; |
45 | struct device *dev; |
46 | struct regmap *regmap; |
47 | struct mipi_dsi_device *dsi; |
48 | struct drm_bridge *panel_bridge; |
49 | struct gpio_desc *reset_gpio; |
50 | struct regulator *vccio; |
51 | bool lvds_dual_link; |
52 | bool lvds_dual_link_even_odd_swap; |
53 | }; |
54 | |
55 | static const struct regmap_range lt9211_rw_ranges[] = { |
56 | regmap_reg_range(0xff, 0xff), |
57 | regmap_reg_range(0x8100, 0x816b), |
58 | regmap_reg_range(0x8200, 0x82aa), |
59 | regmap_reg_range(0x8500, 0x85ff), |
60 | regmap_reg_range(0x8600, 0x86a0), |
61 | regmap_reg_range(0x8700, 0x8746), |
62 | regmap_reg_range(0xd000, 0xd0a7), |
63 | regmap_reg_range(0xd400, 0xd42c), |
64 | regmap_reg_range(0xd800, 0xd838), |
65 | regmap_reg_range(0xd9c0, 0xd9d5), |
66 | }; |
67 | |
68 | static const struct regmap_access_table lt9211_rw_table = { |
69 | .yes_ranges = lt9211_rw_ranges, |
70 | .n_yes_ranges = ARRAY_SIZE(lt9211_rw_ranges), |
71 | }; |
72 | |
73 | static const struct regmap_range_cfg lt9211_range = { |
74 | .name = "lt9211" , |
75 | .range_min = 0x0000, |
76 | .range_max = 0xda00, |
77 | .selector_reg = REG_PAGE_CONTROL, |
78 | .selector_mask = 0xff, |
79 | .selector_shift = 0, |
80 | .window_start = 0, |
81 | .window_len = 0x100, |
82 | }; |
83 | |
84 | static const struct regmap_config lt9211_regmap_config = { |
85 | .reg_bits = 8, |
86 | .val_bits = 8, |
87 | .rd_table = <9211_rw_table, |
88 | .wr_table = <9211_rw_table, |
89 | .volatile_table = <9211_rw_table, |
90 | .ranges = <9211_range, |
91 | .num_ranges = 1, |
92 | .cache_type = REGCACHE_MAPLE, |
93 | .max_register = 0xda00, |
94 | }; |
95 | |
96 | static struct lt9211 *bridge_to_lt9211(struct drm_bridge *bridge) |
97 | { |
98 | return container_of(bridge, struct lt9211, bridge); |
99 | } |
100 | |
101 | static int lt9211_attach(struct drm_bridge *bridge, |
102 | enum drm_bridge_attach_flags flags) |
103 | { |
104 | struct lt9211 *ctx = bridge_to_lt9211(bridge); |
105 | |
106 | return drm_bridge_attach(encoder: bridge->encoder, bridge: ctx->panel_bridge, |
107 | previous: &ctx->bridge, flags); |
108 | } |
109 | |
110 | static int lt9211_read_chipid(struct lt9211 *ctx) |
111 | { |
112 | u8 chipid[3]; |
113 | int ret; |
114 | |
115 | /* Read Chip ID registers and verify the chip can communicate. */ |
116 | ret = regmap_bulk_read(map: ctx->regmap, REG_CHIPID0, val: chipid, val_count: 3); |
117 | if (ret < 0) { |
118 | dev_err(ctx->dev, "Failed to read Chip ID: %d\n" , ret); |
119 | return ret; |
120 | } |
121 | |
122 | /* Test for known Chip ID. */ |
123 | if (chipid[0] != REG_CHIPID0_VALUE || chipid[1] != REG_CHIPID1_VALUE || |
124 | chipid[2] != REG_CHIPID2_VALUE) { |
125 | dev_err(ctx->dev, "Unknown Chip ID: 0x%02x 0x%02x 0x%02x\n" , |
126 | chipid[0], chipid[1], chipid[2]); |
127 | return -EINVAL; |
128 | } |
129 | |
130 | return 0; |
131 | } |
132 | |
133 | static int lt9211_system_init(struct lt9211 *ctx) |
134 | { |
135 | const struct reg_sequence lt9211_system_init_seq[] = { |
136 | { 0x8201, 0x18 }, |
137 | { 0x8606, 0x61 }, |
138 | { 0x8607, 0xa8 }, |
139 | { 0x8714, 0x08 }, |
140 | { 0x8715, 0x00 }, |
141 | { 0x8718, 0x0f }, |
142 | { 0x8722, 0x08 }, |
143 | { 0x8723, 0x00 }, |
144 | { 0x8726, 0x0f }, |
145 | { 0x810b, 0xfe }, |
146 | }; |
147 | |
148 | return regmap_multi_reg_write(map: ctx->regmap, regs: lt9211_system_init_seq, |
149 | ARRAY_SIZE(lt9211_system_init_seq)); |
150 | } |
151 | |
152 | static int lt9211_configure_rx(struct lt9211 *ctx) |
153 | { |
154 | const struct reg_sequence lt9211_rx_phy_seq[] = { |
155 | { 0x8202, 0x44 }, |
156 | { 0x8204, 0xa0 }, |
157 | { 0x8205, 0x22 }, |
158 | { 0x8207, 0x9f }, |
159 | { 0x8208, 0xfc }, |
160 | /* ORR with 0xf8 here to enable DSI DN/DP swap. */ |
161 | { 0x8209, 0x01 }, |
162 | { 0x8217, 0x0c }, |
163 | { 0x8633, 0x1b }, |
164 | }; |
165 | |
166 | const struct reg_sequence lt9211_rx_cal_reset_seq[] = { |
167 | { 0x8120, 0x7f }, |
168 | { 0x8120, 0xff }, |
169 | }; |
170 | |
171 | const struct reg_sequence lt9211_rx_dig_seq[] = { |
172 | { 0x8630, 0x85 }, |
173 | /* 0x8588: BIT 6 set = MIPI-RX, BIT 4 unset = LVDS-TX */ |
174 | { 0x8588, 0x40 }, |
175 | { 0x85ff, 0xd0 }, |
176 | { REG_DSI_LANE, REG_DSI_LANE_COUNT(ctx->dsi->lanes) }, |
177 | { 0xd002, 0x05 }, |
178 | }; |
179 | |
180 | const struct reg_sequence lt9211_rx_div_reset_seq[] = { |
181 | { 0x810a, 0xc0 }, |
182 | { 0x8120, 0xbf }, |
183 | }; |
184 | |
185 | const struct reg_sequence lt9211_rx_div_clear_seq[] = { |
186 | { 0x810a, 0xc1 }, |
187 | { 0x8120, 0xff }, |
188 | }; |
189 | |
190 | int ret; |
191 | |
192 | ret = regmap_multi_reg_write(map: ctx->regmap, regs: lt9211_rx_phy_seq, |
193 | ARRAY_SIZE(lt9211_rx_phy_seq)); |
194 | if (ret) |
195 | return ret; |
196 | |
197 | ret = regmap_multi_reg_write(map: ctx->regmap, regs: lt9211_rx_cal_reset_seq, |
198 | ARRAY_SIZE(lt9211_rx_cal_reset_seq)); |
199 | if (ret) |
200 | return ret; |
201 | |
202 | ret = regmap_multi_reg_write(map: ctx->regmap, regs: lt9211_rx_dig_seq, |
203 | ARRAY_SIZE(lt9211_rx_dig_seq)); |
204 | if (ret) |
205 | return ret; |
206 | |
207 | ret = regmap_multi_reg_write(map: ctx->regmap, regs: lt9211_rx_div_reset_seq, |
208 | ARRAY_SIZE(lt9211_rx_div_reset_seq)); |
209 | if (ret) |
210 | return ret; |
211 | |
212 | usleep_range(min: 10000, max: 15000); |
213 | |
214 | return regmap_multi_reg_write(map: ctx->regmap, regs: lt9211_rx_div_clear_seq, |
215 | ARRAY_SIZE(lt9211_rx_div_clear_seq)); |
216 | } |
217 | |
218 | static int lt9211_autodetect_rx(struct lt9211 *ctx, |
219 | const struct drm_display_mode *mode) |
220 | { |
221 | u16 width, height; |
222 | u32 byteclk; |
223 | u8 buf[5]; |
224 | u8 format; |
225 | u8 bc[3]; |
226 | int ret; |
227 | |
228 | /* Measure ByteClock frequency. */ |
229 | ret = regmap_write(map: ctx->regmap, reg: 0x8600, val: 0x01); |
230 | if (ret) |
231 | return ret; |
232 | |
233 | /* Give the chip time to lock onto RX stream. */ |
234 | msleep(msecs: 100); |
235 | |
236 | /* Read the ByteClock frequency from the chip. */ |
237 | ret = regmap_bulk_read(map: ctx->regmap, reg: 0x8608, val: bc, val_count: sizeof(bc)); |
238 | if (ret) |
239 | return ret; |
240 | |
241 | /* RX ByteClock in kHz */ |
242 | byteclk = ((bc[0] & 0xf) << 16) | (bc[1] << 8) | bc[2]; |
243 | |
244 | /* Width/Height/Format Auto-detection */ |
245 | ret = regmap_bulk_read(map: ctx->regmap, reg: 0xd082, val: buf, val_count: sizeof(buf)); |
246 | if (ret) |
247 | return ret; |
248 | |
249 | width = (buf[0] << 8) | buf[1]; |
250 | height = (buf[3] << 8) | buf[4]; |
251 | format = buf[2] & 0xf; |
252 | |
253 | if (format == 0x3) { /* YUV422 16bit */ |
254 | width /= 2; |
255 | } else if (format == 0xa) { /* RGB888 24bit */ |
256 | width /= 3; |
257 | } else { |
258 | dev_err(ctx->dev, "Unsupported DSI pixel format 0x%01x\n" , |
259 | format); |
260 | return -EINVAL; |
261 | } |
262 | |
263 | if (width != mode->hdisplay) { |
264 | dev_err(ctx->dev, |
265 | "RX: Detected DSI width (%d) does not match mode hdisplay (%d)\n" , |
266 | width, mode->hdisplay); |
267 | return -EINVAL; |
268 | } |
269 | |
270 | if (height != mode->vdisplay) { |
271 | dev_err(ctx->dev, |
272 | "RX: Detected DSI height (%d) does not match mode vdisplay (%d)\n" , |
273 | height, mode->vdisplay); |
274 | return -EINVAL; |
275 | } |
276 | |
277 | dev_dbg(ctx->dev, "RX: %dx%d format=0x%01x byteclock=%d kHz\n" , |
278 | width, height, format, byteclk); |
279 | |
280 | return 0; |
281 | } |
282 | |
283 | static int lt9211_configure_timing(struct lt9211 *ctx, |
284 | const struct drm_display_mode *mode) |
285 | { |
286 | const struct reg_sequence lt9211_timing[] = { |
287 | { 0xd00d, (mode->vtotal >> 8) & 0xff }, |
288 | { 0xd00e, mode->vtotal & 0xff }, |
289 | { 0xd00f, (mode->vdisplay >> 8) & 0xff }, |
290 | { 0xd010, mode->vdisplay & 0xff }, |
291 | { 0xd011, (mode->htotal >> 8) & 0xff }, |
292 | { 0xd012, mode->htotal & 0xff }, |
293 | { 0xd013, (mode->hdisplay >> 8) & 0xff }, |
294 | { 0xd014, mode->hdisplay & 0xff }, |
295 | { 0xd015, (mode->vsync_end - mode->vsync_start) & 0xff }, |
296 | { 0xd016, (mode->hsync_end - mode->hsync_start) & 0xff }, |
297 | { 0xd017, ((mode->vsync_start - mode->vdisplay) >> 8) & 0xff }, |
298 | { 0xd018, (mode->vsync_start - mode->vdisplay) & 0xff }, |
299 | { 0xd019, ((mode->hsync_start - mode->hdisplay) >> 8) & 0xff }, |
300 | { 0xd01a, (mode->hsync_start - mode->hdisplay) & 0xff }, |
301 | }; |
302 | |
303 | return regmap_multi_reg_write(map: ctx->regmap, regs: lt9211_timing, |
304 | ARRAY_SIZE(lt9211_timing)); |
305 | } |
306 | |
307 | static int lt9211_configure_plls(struct lt9211 *ctx, |
308 | const struct drm_display_mode *mode) |
309 | { |
310 | const struct reg_sequence lt9211_pcr_seq[] = { |
311 | { 0xd026, 0x17 }, |
312 | { 0xd027, 0xc3 }, |
313 | { 0xd02d, 0x30 }, |
314 | { 0xd031, 0x10 }, |
315 | { 0xd023, 0x20 }, |
316 | { 0xd038, 0x02 }, |
317 | { 0xd039, 0x10 }, |
318 | { 0xd03a, 0x20 }, |
319 | { 0xd03b, 0x60 }, |
320 | { 0xd03f, 0x04 }, |
321 | { 0xd040, 0x08 }, |
322 | { 0xd041, 0x10 }, |
323 | { 0x810b, 0xee }, |
324 | { 0x810b, 0xfe }, |
325 | }; |
326 | |
327 | unsigned int pval; |
328 | int ret; |
329 | |
330 | /* DeSSC PLL reference clock is 25 MHz XTal. */ |
331 | ret = regmap_write(map: ctx->regmap, reg: 0x822d, val: 0x48); |
332 | if (ret) |
333 | return ret; |
334 | |
335 | if (mode->clock < 44000) { |
336 | ret = regmap_write(map: ctx->regmap, reg: 0x8235, val: 0x83); |
337 | } else if (mode->clock < 88000) { |
338 | ret = regmap_write(map: ctx->regmap, reg: 0x8235, val: 0x82); |
339 | } else if (mode->clock < 176000) { |
340 | ret = regmap_write(map: ctx->regmap, reg: 0x8235, val: 0x81); |
341 | } else { |
342 | dev_err(ctx->dev, |
343 | "Unsupported mode clock (%d kHz) above 176 MHz.\n" , |
344 | mode->clock); |
345 | return -EINVAL; |
346 | } |
347 | |
348 | if (ret) |
349 | return ret; |
350 | |
351 | /* Wait for the DeSSC PLL to stabilize. */ |
352 | msleep(msecs: 100); |
353 | |
354 | ret = regmap_multi_reg_write(map: ctx->regmap, regs: lt9211_pcr_seq, |
355 | ARRAY_SIZE(lt9211_pcr_seq)); |
356 | if (ret) |
357 | return ret; |
358 | |
359 | /* PCR stability test takes seconds. */ |
360 | ret = regmap_read_poll_timeout(ctx->regmap, 0xd087, pval, pval & 0x8, |
361 | 20000, 10000000); |
362 | if (ret) |
363 | dev_err(ctx->dev, "PCR unstable, ret=%i\n" , ret); |
364 | |
365 | return ret; |
366 | } |
367 | |
368 | static int lt9211_configure_tx(struct lt9211 *ctx, bool jeida, |
369 | bool bpp24, bool de) |
370 | { |
371 | const struct reg_sequence system_lt9211_tx_phy_seq[] = { |
372 | /* DPI output disable */ |
373 | { 0x8262, 0x00 }, |
374 | /* BIT(7) is LVDS dual-port */ |
375 | { 0x823b, 0x38 | (ctx->lvds_dual_link ? BIT(7) : 0) }, |
376 | { 0x823e, 0x92 }, |
377 | { 0x823f, 0x48 }, |
378 | { 0x8240, 0x31 }, |
379 | { 0x8243, 0x80 }, |
380 | { 0x8244, 0x00 }, |
381 | { 0x8245, 0x00 }, |
382 | { 0x8249, 0x00 }, |
383 | { 0x824a, 0x01 }, |
384 | { 0x824e, 0x00 }, |
385 | { 0x824f, 0x00 }, |
386 | { 0x8250, 0x00 }, |
387 | { 0x8253, 0x00 }, |
388 | { 0x8254, 0x01 }, |
389 | /* LVDS channel order, Odd:Even 0x10..A:B, 0x40..B:A */ |
390 | { 0x8646, ctx->lvds_dual_link_even_odd_swap ? 0x40 : 0x10 }, |
391 | { 0x8120, 0x7b }, |
392 | { 0x816b, 0xff }, |
393 | }; |
394 | |
395 | const struct reg_sequence system_lt9211_tx_dig_seq[] = { |
396 | { 0x8559, 0x40 | (jeida ? BIT(7) : 0) | |
397 | (de ? BIT(5) : 0) | (bpp24 ? BIT(4) : 0) }, |
398 | { 0x855a, 0xaa }, |
399 | { 0x855b, 0xaa }, |
400 | { 0x855c, ctx->lvds_dual_link ? BIT(0) : 0 }, |
401 | { 0x85a1, 0x77 }, |
402 | { 0x8640, 0x40 }, |
403 | { 0x8641, 0x34 }, |
404 | { 0x8642, 0x10 }, |
405 | { 0x8643, 0x23 }, |
406 | { 0x8644, 0x41 }, |
407 | { 0x8645, 0x02 }, |
408 | }; |
409 | |
410 | const struct reg_sequence system_lt9211_tx_pll_seq[] = { |
411 | /* TX PLL power down */ |
412 | { 0x8236, 0x01 }, |
413 | { 0x8237, ctx->lvds_dual_link ? 0x2a : 0x29 }, |
414 | { 0x8238, 0x06 }, |
415 | { 0x8239, 0x30 }, |
416 | { 0x823a, 0x8e }, |
417 | { 0x8737, 0x14 }, |
418 | { 0x8713, 0x00 }, |
419 | { 0x8713, 0x80 }, |
420 | }; |
421 | |
422 | unsigned int pval; |
423 | int ret; |
424 | |
425 | ret = regmap_multi_reg_write(map: ctx->regmap, regs: system_lt9211_tx_phy_seq, |
426 | ARRAY_SIZE(system_lt9211_tx_phy_seq)); |
427 | if (ret) |
428 | return ret; |
429 | |
430 | ret = regmap_multi_reg_write(map: ctx->regmap, regs: system_lt9211_tx_dig_seq, |
431 | ARRAY_SIZE(system_lt9211_tx_dig_seq)); |
432 | if (ret) |
433 | return ret; |
434 | |
435 | ret = regmap_multi_reg_write(map: ctx->regmap, regs: system_lt9211_tx_pll_seq, |
436 | ARRAY_SIZE(system_lt9211_tx_pll_seq)); |
437 | if (ret) |
438 | return ret; |
439 | |
440 | ret = regmap_read_poll_timeout(ctx->regmap, 0x871f, pval, pval & 0x80, |
441 | 10000, 1000000); |
442 | if (ret) { |
443 | dev_err(ctx->dev, "TX PLL unstable, ret=%i\n" , ret); |
444 | return ret; |
445 | } |
446 | |
447 | ret = regmap_read_poll_timeout(ctx->regmap, 0x8720, pval, pval & 0x80, |
448 | 10000, 1000000); |
449 | if (ret) { |
450 | dev_err(ctx->dev, "TX PLL unstable, ret=%i\n" , ret); |
451 | return ret; |
452 | } |
453 | |
454 | return 0; |
455 | } |
456 | |
457 | static void lt9211_atomic_enable(struct drm_bridge *bridge, |
458 | struct drm_bridge_state *old_bridge_state) |
459 | { |
460 | struct lt9211 *ctx = bridge_to_lt9211(bridge); |
461 | struct drm_atomic_state *state = old_bridge_state->base.state; |
462 | const struct drm_bridge_state *bridge_state; |
463 | const struct drm_crtc_state *crtc_state; |
464 | const struct drm_display_mode *mode; |
465 | struct drm_connector *connector; |
466 | struct drm_crtc *crtc; |
467 | bool lvds_format_24bpp; |
468 | bool lvds_format_jeida; |
469 | u32 bus_flags; |
470 | int ret; |
471 | |
472 | ret = regulator_enable(regulator: ctx->vccio); |
473 | if (ret) { |
474 | dev_err(ctx->dev, "Failed to enable vccio: %d\n" , ret); |
475 | return; |
476 | } |
477 | |
478 | /* Deassert reset */ |
479 | gpiod_set_value(desc: ctx->reset_gpio, value: 1); |
480 | usleep_range(min: 20000, max: 21000); /* Very long post-reset delay. */ |
481 | |
482 | /* Get the LVDS format from the bridge state. */ |
483 | bridge_state = drm_atomic_get_new_bridge_state(state, bridge); |
484 | bus_flags = bridge_state->output_bus_cfg.flags; |
485 | |
486 | switch (bridge_state->output_bus_cfg.format) { |
487 | case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: |
488 | lvds_format_24bpp = false; |
489 | lvds_format_jeida = true; |
490 | break; |
491 | case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: |
492 | lvds_format_24bpp = true; |
493 | lvds_format_jeida = true; |
494 | break; |
495 | case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: |
496 | lvds_format_24bpp = true; |
497 | lvds_format_jeida = false; |
498 | break; |
499 | default: |
500 | /* |
501 | * Some bridges still don't set the correct |
502 | * LVDS bus pixel format, use SPWG24 default |
503 | * format until those are fixed. |
504 | */ |
505 | lvds_format_24bpp = true; |
506 | lvds_format_jeida = false; |
507 | dev_warn(ctx->dev, |
508 | "Unsupported LVDS bus format 0x%04x, please check output bridge driver. Falling back to SPWG24.\n" , |
509 | bridge_state->output_bus_cfg.format); |
510 | break; |
511 | } |
512 | |
513 | /* |
514 | * Retrieve the CRTC adjusted mode. This requires a little dance to go |
515 | * from the bridge to the encoder, to the connector and to the CRTC. |
516 | */ |
517 | connector = drm_atomic_get_new_connector_for_encoder(state, |
518 | encoder: bridge->encoder); |
519 | crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; |
520 | crtc_state = drm_atomic_get_new_crtc_state(state, crtc); |
521 | mode = &crtc_state->adjusted_mode; |
522 | |
523 | ret = lt9211_read_chipid(ctx); |
524 | if (ret) |
525 | return; |
526 | |
527 | ret = lt9211_system_init(ctx); |
528 | if (ret) |
529 | return; |
530 | |
531 | ret = lt9211_configure_rx(ctx); |
532 | if (ret) |
533 | return; |
534 | |
535 | ret = lt9211_autodetect_rx(ctx, mode); |
536 | if (ret) |
537 | return; |
538 | |
539 | ret = lt9211_configure_timing(ctx, mode); |
540 | if (ret) |
541 | return; |
542 | |
543 | ret = lt9211_configure_plls(ctx, mode); |
544 | if (ret) |
545 | return; |
546 | |
547 | ret = lt9211_configure_tx(ctx, jeida: lvds_format_jeida, bpp24: lvds_format_24bpp, |
548 | de: bus_flags & DRM_BUS_FLAG_DE_HIGH); |
549 | if (ret) |
550 | return; |
551 | |
552 | dev_dbg(ctx->dev, "LT9211 enabled.\n" ); |
553 | } |
554 | |
555 | static void lt9211_atomic_disable(struct drm_bridge *bridge, |
556 | struct drm_bridge_state *old_bridge_state) |
557 | { |
558 | struct lt9211 *ctx = bridge_to_lt9211(bridge); |
559 | int ret; |
560 | |
561 | /* |
562 | * Put the chip in reset, pull nRST line low, |
563 | * and assure lengthy 10ms reset low timing. |
564 | */ |
565 | gpiod_set_value(desc: ctx->reset_gpio, value: 0); |
566 | usleep_range(min: 10000, max: 11000); /* Very long reset duration. */ |
567 | |
568 | ret = regulator_disable(regulator: ctx->vccio); |
569 | if (ret) |
570 | dev_err(ctx->dev, "Failed to disable vccio: %d\n" , ret); |
571 | |
572 | regcache_mark_dirty(map: ctx->regmap); |
573 | } |
574 | |
575 | static enum drm_mode_status |
576 | lt9211_mode_valid(struct drm_bridge *bridge, |
577 | const struct drm_display_info *info, |
578 | const struct drm_display_mode *mode) |
579 | { |
580 | /* LVDS output clock range 25..176 MHz */ |
581 | if (mode->clock < 25000) |
582 | return MODE_CLOCK_LOW; |
583 | if (mode->clock > 176000) |
584 | return MODE_CLOCK_HIGH; |
585 | |
586 | return MODE_OK; |
587 | } |
588 | |
589 | #define MAX_INPUT_SEL_FORMATS 1 |
590 | |
591 | static u32 * |
592 | lt9211_atomic_get_input_bus_fmts(struct drm_bridge *bridge, |
593 | struct drm_bridge_state *bridge_state, |
594 | struct drm_crtc_state *crtc_state, |
595 | struct drm_connector_state *conn_state, |
596 | u32 output_fmt, |
597 | unsigned int *num_input_fmts) |
598 | { |
599 | u32 *input_fmts; |
600 | |
601 | *num_input_fmts = 0; |
602 | |
603 | input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, size: sizeof(*input_fmts), |
604 | GFP_KERNEL); |
605 | if (!input_fmts) |
606 | return NULL; |
607 | |
608 | /* This is the DSI-end bus format */ |
609 | input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; |
610 | *num_input_fmts = 1; |
611 | |
612 | return input_fmts; |
613 | } |
614 | |
615 | static const struct drm_bridge_funcs lt9211_funcs = { |
616 | .attach = lt9211_attach, |
617 | .mode_valid = lt9211_mode_valid, |
618 | .atomic_enable = lt9211_atomic_enable, |
619 | .atomic_disable = lt9211_atomic_disable, |
620 | .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, |
621 | .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, |
622 | .atomic_get_input_bus_fmts = lt9211_atomic_get_input_bus_fmts, |
623 | .atomic_reset = drm_atomic_helper_bridge_reset, |
624 | }; |
625 | |
626 | static int lt9211_parse_dt(struct lt9211 *ctx) |
627 | { |
628 | struct device_node *port2, *port3; |
629 | struct drm_bridge *panel_bridge; |
630 | struct device *dev = ctx->dev; |
631 | struct drm_panel *panel; |
632 | int dual_link; |
633 | int ret; |
634 | |
635 | ctx->vccio = devm_regulator_get(dev, id: "vccio" ); |
636 | if (IS_ERR(ptr: ctx->vccio)) |
637 | return dev_err_probe(dev, err: PTR_ERR(ptr: ctx->vccio), |
638 | fmt: "Failed to get supply 'vccio'\n" ); |
639 | |
640 | ctx->lvds_dual_link = false; |
641 | ctx->lvds_dual_link_even_odd_swap = false; |
642 | |
643 | port2 = of_graph_get_port_by_id(node: dev->of_node, id: 2); |
644 | port3 = of_graph_get_port_by_id(node: dev->of_node, id: 3); |
645 | dual_link = drm_of_lvds_get_dual_link_pixel_order(port1: port2, port2: port3); |
646 | of_node_put(node: port2); |
647 | of_node_put(node: port3); |
648 | |
649 | if (dual_link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS) { |
650 | ctx->lvds_dual_link = true; |
651 | /* Odd pixels to LVDS Channel A, even pixels to B */ |
652 | ctx->lvds_dual_link_even_odd_swap = false; |
653 | } else if (dual_link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS) { |
654 | ctx->lvds_dual_link = true; |
655 | /* Even pixels to LVDS Channel A, odd pixels to B */ |
656 | ctx->lvds_dual_link_even_odd_swap = true; |
657 | } |
658 | |
659 | ret = drm_of_find_panel_or_bridge(np: dev->of_node, port: 2, endpoint: 0, panel: &panel, bridge: &panel_bridge); |
660 | if (ret < 0) |
661 | return ret; |
662 | if (panel) { |
663 | panel_bridge = devm_drm_panel_bridge_add(dev, panel); |
664 | if (IS_ERR(ptr: panel_bridge)) |
665 | return PTR_ERR(ptr: panel_bridge); |
666 | } |
667 | |
668 | ctx->panel_bridge = panel_bridge; |
669 | |
670 | return 0; |
671 | } |
672 | |
673 | static int lt9211_host_attach(struct lt9211 *ctx) |
674 | { |
675 | const struct mipi_dsi_device_info info = { |
676 | .type = "lt9211" , |
677 | .channel = 0, |
678 | .node = NULL, |
679 | }; |
680 | struct device *dev = ctx->dev; |
681 | struct device_node *host_node; |
682 | struct device_node *endpoint; |
683 | struct mipi_dsi_device *dsi; |
684 | struct mipi_dsi_host *host; |
685 | int dsi_lanes; |
686 | int ret; |
687 | |
688 | endpoint = of_graph_get_endpoint_by_regs(parent: dev->of_node, port_reg: 0, reg: -1); |
689 | dsi_lanes = drm_of_get_data_lanes_count(endpoint, min: 1, max: 4); |
690 | host_node = of_graph_get_remote_port_parent(node: endpoint); |
691 | host = of_find_mipi_dsi_host_by_node(node: host_node); |
692 | of_node_put(node: host_node); |
693 | of_node_put(node: endpoint); |
694 | |
695 | if (!host) |
696 | return -EPROBE_DEFER; |
697 | |
698 | if (dsi_lanes < 0) |
699 | return dsi_lanes; |
700 | |
701 | dsi = devm_mipi_dsi_device_register_full(dev, host, info: &info); |
702 | if (IS_ERR(ptr: dsi)) |
703 | return dev_err_probe(dev, err: PTR_ERR(ptr: dsi), |
704 | fmt: "failed to create dsi device\n" ); |
705 | |
706 | ctx->dsi = dsi; |
707 | |
708 | dsi->lanes = dsi_lanes; |
709 | dsi->format = MIPI_DSI_FMT_RGB888; |
710 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | |
711 | MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_NO_HSA | |
712 | MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP | |
713 | MIPI_DSI_MODE_NO_EOT_PACKET; |
714 | |
715 | ret = devm_mipi_dsi_attach(dev, dsi); |
716 | if (ret < 0) { |
717 | dev_err(dev, "failed to attach dsi to host: %d\n" , ret); |
718 | return ret; |
719 | } |
720 | |
721 | return 0; |
722 | } |
723 | |
724 | static int lt9211_probe(struct i2c_client *client) |
725 | { |
726 | struct device *dev = &client->dev; |
727 | struct lt9211 *ctx; |
728 | int ret; |
729 | |
730 | ctx = devm_kzalloc(dev, size: sizeof(*ctx), GFP_KERNEL); |
731 | if (!ctx) |
732 | return -ENOMEM; |
733 | |
734 | ctx->dev = dev; |
735 | |
736 | /* |
737 | * Put the chip in reset, pull nRST line low, |
738 | * and assure lengthy 10ms reset low timing. |
739 | */ |
740 | ctx->reset_gpio = devm_gpiod_get_optional(dev: ctx->dev, con_id: "reset" , |
741 | flags: GPIOD_OUT_LOW); |
742 | if (IS_ERR(ptr: ctx->reset_gpio)) |
743 | return PTR_ERR(ptr: ctx->reset_gpio); |
744 | |
745 | usleep_range(min: 10000, max: 11000); /* Very long reset duration. */ |
746 | |
747 | ret = lt9211_parse_dt(ctx); |
748 | if (ret) |
749 | return ret; |
750 | |
751 | ctx->regmap = devm_regmap_init_i2c(client, <9211_regmap_config); |
752 | if (IS_ERR(ptr: ctx->regmap)) |
753 | return PTR_ERR(ptr: ctx->regmap); |
754 | |
755 | dev_set_drvdata(dev, data: ctx); |
756 | i2c_set_clientdata(client, data: ctx); |
757 | |
758 | ctx->bridge.funcs = <9211_funcs; |
759 | ctx->bridge.of_node = dev->of_node; |
760 | drm_bridge_add(bridge: &ctx->bridge); |
761 | |
762 | ret = lt9211_host_attach(ctx); |
763 | if (ret) |
764 | drm_bridge_remove(bridge: &ctx->bridge); |
765 | |
766 | return ret; |
767 | } |
768 | |
769 | static void lt9211_remove(struct i2c_client *client) |
770 | { |
771 | struct lt9211 *ctx = i2c_get_clientdata(client); |
772 | |
773 | drm_bridge_remove(bridge: &ctx->bridge); |
774 | } |
775 | |
776 | static struct i2c_device_id lt9211_id[] = { |
777 | { "lontium,lt9211" }, |
778 | {}, |
779 | }; |
780 | MODULE_DEVICE_TABLE(i2c, lt9211_id); |
781 | |
782 | static const struct of_device_id lt9211_match_table[] = { |
783 | { .compatible = "lontium,lt9211" }, |
784 | {}, |
785 | }; |
786 | MODULE_DEVICE_TABLE(of, lt9211_match_table); |
787 | |
788 | static struct i2c_driver lt9211_driver = { |
789 | .probe = lt9211_probe, |
790 | .remove = lt9211_remove, |
791 | .id_table = lt9211_id, |
792 | .driver = { |
793 | .name = "lt9211" , |
794 | .of_match_table = lt9211_match_table, |
795 | }, |
796 | }; |
797 | module_i2c_driver(lt9211_driver); |
798 | |
799 | MODULE_AUTHOR("Marek Vasut <marex@denx.de>" ); |
800 | MODULE_DESCRIPTION("Lontium LT9211 DSI/LVDS/DPI bridge driver" ); |
801 | MODULE_LICENSE("GPL" ); |
802 | |