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