Commit | Line | Data |
---|---|---|
a095f15c SP |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (c) 2018, The Linux Foundation. All rights reserved. | |
4 | */ | |
5 | ||
6 | #include <drm/drmP.h> | |
7 | #include <drm/drm_atomic.h> | |
8 | #include <drm/drm_atomic_helper.h> | |
9 | #include <drm/drm_crtc_helper.h> | |
10 | #include <drm/drm_mipi_dsi.h> | |
11 | #include <drm/drm_of.h> | |
12 | #include <drm/drm_panel.h> | |
13 | #include <linux/clk.h> | |
14 | #include <linux/gpio/consumer.h> | |
15 | #include <linux/i2c.h> | |
16 | #include <linux/of_graph.h> | |
17 | #include <linux/pm_runtime.h> | |
18 | #include <linux/regmap.h> | |
19 | #include <linux/regulator/consumer.h> | |
20 | ||
21 | /* Link Training specific registers */ | |
22 | #define SN_DEVICE_REV_REG 0x08 | |
23 | #define SN_HPD_DISABLE_REG 0x5C | |
24 | #define SN_DPPLL_SRC_REG 0x0A | |
25 | #define SN_DSI_LANES_REG 0x10 | |
26 | #define SN_DSIA_CLK_FREQ_REG 0x12 | |
27 | #define SN_ENH_FRAME_REG 0x5A | |
28 | #define SN_SSC_CONFIG_REG 0x93 | |
29 | #define SN_DATARATE_CONFIG_REG 0x94 | |
30 | #define SN_PLL_ENABLE_REG 0x0D | |
31 | #define SN_SCRAMBLE_CONFIG_REG 0x95 | |
32 | #define SN_AUX_WDATA0_REG 0x64 | |
33 | #define SN_AUX_ADDR_19_16_REG 0x74 | |
34 | #define SN_AUX_ADDR_15_8_REG 0x75 | |
35 | #define SN_AUX_ADDR_7_0_REG 0x76 | |
36 | #define SN_AUX_LENGTH_REG 0x77 | |
37 | #define SN_AUX_CMD_REG 0x78 | |
38 | #define SN_ML_TX_MODE_REG 0x96 | |
39 | /* video config specific registers */ | |
40 | #define SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG 0x20 | |
41 | #define SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG 0x24 | |
42 | #define SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG 0x2C | |
43 | #define SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG 0x2D | |
44 | #define SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG 0x30 | |
45 | #define SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG 0x31 | |
46 | #define SN_CHA_HORIZONTAL_BACK_PORCH_REG 0x34 | |
47 | #define SN_CHA_VERTICAL_BACK_PORCH_REG 0x36 | |
48 | #define SN_CHA_HORIZONTAL_FRONT_PORCH_REG 0x38 | |
49 | #define SN_CHA_VERTICAL_FRONT_PORCH_REG 0x3A | |
50 | #define SN_DATA_FORMAT_REG 0x5B | |
51 | ||
52 | #define MIN_DSI_CLK_FREQ_MHZ 40 | |
53 | ||
54 | /* fudge factor required to account for 8b/10b encoding */ | |
55 | #define DP_CLK_FUDGE_NUM 10 | |
56 | #define DP_CLK_FUDGE_DEN 8 | |
57 | ||
58 | #define DPPLL_CLK_SRC_REFCLK 0 | |
59 | #define DPPLL_CLK_SRC_DSICLK 1 | |
60 | ||
61 | #define SN_REFCLK_FREQ_OFFSET 1 | |
62 | #define SN_DSIA_LANE_OFFSET 3 | |
63 | #define SN_DP_LANE_OFFSET 4 | |
64 | #define SN_DP_DATA_RATE_OFFSET 5 | |
65 | #define SN_SYNC_POLARITY_OFFSET 7 | |
66 | ||
67 | #define SN_ENABLE_VID_STREAM_BIT BIT(3) | |
68 | #define SN_REFCLK_FREQ_BITS GENMASK(3, 1) | |
69 | #define SN_DSIA_NUM_LANES_BITS GENMASK(4, 3) | |
70 | #define SN_DP_NUM_LANES_BITS GENMASK(5, 4) | |
71 | #define SN_DP_DATA_RATE_BITS GENMASK(7, 5) | |
72 | #define SN_HPD_DISABLE_BIT BIT(0) | |
73 | ||
74 | #define SN_REGULATOR_SUPPLY_NUM 4 | |
75 | ||
76 | struct ti_sn_bridge { | |
77 | struct device *dev; | |
78 | struct regmap *regmap; | |
79 | struct drm_bridge bridge; | |
80 | struct drm_connector connector; | |
81 | struct device_node *host_node; | |
82 | struct mipi_dsi_device *dsi; | |
83 | struct clk *refclk; | |
84 | struct drm_panel *panel; | |
85 | struct gpio_desc *enable_gpio; | |
86 | struct regulator_bulk_data supplies[SN_REGULATOR_SUPPLY_NUM]; | |
87 | }; | |
88 | ||
89 | static const struct regmap_range ti_sn_bridge_volatile_ranges[] = { | |
90 | { .range_min = 0, .range_max = 0xFF }, | |
91 | }; | |
92 | ||
93 | static const struct regmap_access_table ti_sn_bridge_volatile_table = { | |
94 | .yes_ranges = ti_sn_bridge_volatile_ranges, | |
95 | .n_yes_ranges = ARRAY_SIZE(ti_sn_bridge_volatile_ranges), | |
96 | }; | |
97 | ||
98 | static const struct regmap_config ti_sn_bridge_regmap_config = { | |
99 | .reg_bits = 8, | |
100 | .val_bits = 8, | |
101 | .volatile_table = &ti_sn_bridge_volatile_table, | |
102 | .cache_type = REGCACHE_NONE, | |
103 | }; | |
104 | ||
105 | static void ti_sn_bridge_write_u16(struct ti_sn_bridge *pdata, | |
106 | unsigned int reg, u16 val) | |
107 | { | |
108 | regmap_write(pdata->regmap, reg, val & 0xFF); | |
109 | regmap_write(pdata->regmap, reg + 1, val >> 8); | |
110 | } | |
111 | ||
112 | static int __maybe_unused ti_sn_bridge_resume(struct device *dev) | |
113 | { | |
114 | struct ti_sn_bridge *pdata = dev_get_drvdata(dev); | |
115 | int ret; | |
116 | ||
117 | ret = regulator_bulk_enable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies); | |
118 | if (ret) { | |
119 | DRM_ERROR("failed to enable supplies %d\n", ret); | |
120 | return ret; | |
121 | } | |
122 | ||
123 | gpiod_set_value(pdata->enable_gpio, 1); | |
124 | ||
125 | return ret; | |
126 | } | |
127 | ||
128 | static int __maybe_unused ti_sn_bridge_suspend(struct device *dev) | |
129 | { | |
130 | struct ti_sn_bridge *pdata = dev_get_drvdata(dev); | |
131 | int ret; | |
132 | ||
133 | gpiod_set_value(pdata->enable_gpio, 0); | |
134 | ||
135 | ret = regulator_bulk_disable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies); | |
136 | if (ret) | |
137 | DRM_ERROR("failed to disable supplies %d\n", ret); | |
138 | ||
139 | return ret; | |
140 | } | |
141 | ||
142 | static const struct dev_pm_ops ti_sn_bridge_pm_ops = { | |
143 | SET_RUNTIME_PM_OPS(ti_sn_bridge_suspend, ti_sn_bridge_resume, NULL) | |
144 | }; | |
145 | ||
146 | /* Connector funcs */ | |
147 | static struct ti_sn_bridge * | |
148 | connector_to_ti_sn_bridge(struct drm_connector *connector) | |
149 | { | |
150 | return container_of(connector, struct ti_sn_bridge, connector); | |
151 | } | |
152 | ||
153 | static int ti_sn_bridge_connector_get_modes(struct drm_connector *connector) | |
154 | { | |
155 | struct ti_sn_bridge *pdata = connector_to_ti_sn_bridge(connector); | |
156 | ||
157 | return drm_panel_get_modes(pdata->panel); | |
158 | } | |
159 | ||
160 | static enum drm_mode_status | |
161 | ti_sn_bridge_connector_mode_valid(struct drm_connector *connector, | |
162 | struct drm_display_mode *mode) | |
163 | { | |
164 | /* maximum supported resolution is 4K at 60 fps */ | |
165 | if (mode->clock > 594000) | |
166 | return MODE_CLOCK_HIGH; | |
167 | ||
168 | return MODE_OK; | |
169 | } | |
170 | ||
171 | static struct drm_connector_helper_funcs ti_sn_bridge_connector_helper_funcs = { | |
172 | .get_modes = ti_sn_bridge_connector_get_modes, | |
173 | .mode_valid = ti_sn_bridge_connector_mode_valid, | |
174 | }; | |
175 | ||
176 | static enum drm_connector_status | |
177 | ti_sn_bridge_connector_detect(struct drm_connector *connector, bool force) | |
178 | { | |
179 | /** | |
180 | * TODO: Currently if drm_panel is present, then always | |
181 | * return the status as connected. Need to add support to detect | |
182 | * device state for hot pluggable scenarios. | |
183 | */ | |
184 | return connector_status_connected; | |
185 | } | |
186 | ||
187 | static const struct drm_connector_funcs ti_sn_bridge_connector_funcs = { | |
188 | .fill_modes = drm_helper_probe_single_connector_modes, | |
189 | .detect = ti_sn_bridge_connector_detect, | |
190 | .destroy = drm_connector_cleanup, | |
191 | .reset = drm_atomic_helper_connector_reset, | |
192 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | |
193 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
194 | }; | |
195 | ||
196 | static struct ti_sn_bridge *bridge_to_ti_sn_bridge(struct drm_bridge *bridge) | |
197 | { | |
198 | return container_of(bridge, struct ti_sn_bridge, bridge); | |
199 | } | |
200 | ||
201 | static int ti_sn_bridge_parse_regulators(struct ti_sn_bridge *pdata) | |
202 | { | |
203 | unsigned int i; | |
204 | const char * const ti_sn_bridge_supply_names[] = { | |
205 | "vcca", "vcc", "vccio", "vpll", | |
206 | }; | |
207 | ||
208 | for (i = 0; i < SN_REGULATOR_SUPPLY_NUM; i++) | |
209 | pdata->supplies[i].supply = ti_sn_bridge_supply_names[i]; | |
210 | ||
211 | return devm_regulator_bulk_get(pdata->dev, SN_REGULATOR_SUPPLY_NUM, | |
212 | pdata->supplies); | |
213 | } | |
214 | ||
215 | static int ti_sn_bridge_attach(struct drm_bridge *bridge) | |
216 | { | |
217 | int ret, val; | |
218 | struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); | |
219 | struct mipi_dsi_host *host; | |
220 | struct mipi_dsi_device *dsi; | |
221 | const struct mipi_dsi_device_info info = { .type = "ti_sn_bridge", | |
222 | .channel = 0, | |
223 | .node = NULL, | |
224 | }; | |
225 | ||
226 | ret = drm_connector_init(bridge->dev, &pdata->connector, | |
227 | &ti_sn_bridge_connector_funcs, | |
228 | DRM_MODE_CONNECTOR_eDP); | |
229 | if (ret) { | |
230 | DRM_ERROR("Failed to initialize connector with drm\n"); | |
231 | return ret; | |
232 | } | |
233 | ||
234 | drm_connector_helper_add(&pdata->connector, | |
235 | &ti_sn_bridge_connector_helper_funcs); | |
236 | drm_mode_connector_attach_encoder(&pdata->connector, bridge->encoder); | |
237 | ||
238 | /* | |
239 | * TODO: ideally finding host resource and dsi dev registration needs | |
240 | * to be done in bridge probe. But some existing DSI host drivers will | |
241 | * wait for any of the drm_bridge/drm_panel to get added to the global | |
242 | * bridge/panel list, before completing their probe. So if we do the | |
243 | * dsi dev registration part in bridge probe, before populating in | |
244 | * the global bridge list, then it will cause deadlock as dsi host probe | |
245 | * will never complete, neither our bridge probe. So keeping it here | |
246 | * will satisfy most of the existing host drivers. Once the host driver | |
247 | * is fixed we can move the below code to bridge probe safely. | |
248 | */ | |
249 | host = of_find_mipi_dsi_host_by_node(pdata->host_node); | |
250 | if (!host) { | |
251 | DRM_ERROR("failed to find dsi host\n"); | |
252 | ret = -ENODEV; | |
253 | goto err_dsi_host; | |
254 | } | |
255 | ||
256 | dsi = mipi_dsi_device_register_full(host, &info); | |
257 | if (IS_ERR(dsi)) { | |
258 | DRM_ERROR("failed to create dsi device\n"); | |
259 | ret = PTR_ERR(dsi); | |
260 | goto err_dsi_host; | |
261 | } | |
262 | ||
263 | /* TODO: setting to 4 lanes always for now */ | |
264 | dsi->lanes = 4; | |
265 | dsi->format = MIPI_DSI_FMT_RGB888; | |
266 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | | |
267 | MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE; | |
268 | ||
269 | /* check if continuous dsi clock is required or not */ | |
270 | pm_runtime_get_sync(pdata->dev); | |
271 | regmap_read(pdata->regmap, SN_DPPLL_SRC_REG, &val); | |
272 | pm_runtime_put(pdata->dev); | |
273 | if (!(val & DPPLL_CLK_SRC_DSICLK)) | |
274 | dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; | |
275 | ||
276 | ret = mipi_dsi_attach(dsi); | |
277 | if (ret < 0) { | |
278 | DRM_ERROR("failed to attach dsi to host\n"); | |
279 | goto err_dsi_attach; | |
280 | } | |
281 | pdata->dsi = dsi; | |
282 | ||
283 | /* attach panel to bridge */ | |
284 | drm_panel_attach(pdata->panel, &pdata->connector); | |
285 | ||
286 | return 0; | |
287 | ||
288 | err_dsi_attach: | |
289 | mipi_dsi_device_unregister(dsi); | |
290 | err_dsi_host: | |
291 | drm_connector_cleanup(&pdata->connector); | |
292 | return ret; | |
293 | } | |
294 | ||
295 | static void ti_sn_bridge_disable(struct drm_bridge *bridge) | |
296 | { | |
297 | struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); | |
298 | ||
299 | drm_panel_disable(pdata->panel); | |
300 | ||
301 | /* disable video stream */ | |
302 | regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, | |
303 | SN_ENABLE_VID_STREAM_BIT, 0); | |
304 | /* semi auto link training mode OFF */ | |
305 | regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0); | |
306 | /* disable DP PLL */ | |
307 | regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0); | |
308 | ||
309 | drm_panel_unprepare(pdata->panel); | |
310 | } | |
311 | ||
312 | static u32 ti_sn_bridge_get_dsi_freq(struct ti_sn_bridge *pdata) | |
313 | { | |
314 | u32 bit_rate_khz, clk_freq_khz; | |
315 | struct drm_display_mode *mode = | |
316 | &pdata->bridge.encoder->crtc->state->adjusted_mode; | |
317 | ||
318 | bit_rate_khz = mode->clock * | |
319 | mipi_dsi_pixel_format_to_bpp(pdata->dsi->format); | |
320 | clk_freq_khz = bit_rate_khz / (pdata->dsi->lanes * 2); | |
321 | ||
322 | return clk_freq_khz; | |
323 | } | |
324 | ||
325 | /* clk frequencies supported by bridge in Hz in case derived from REFCLK pin */ | |
326 | static const u32 ti_sn_bridge_refclk_lut[] = { | |
327 | 12000000, | |
328 | 19200000, | |
329 | 26000000, | |
330 | 27000000, | |
331 | 38400000, | |
332 | }; | |
333 | ||
334 | /* clk frequencies supported by bridge in Hz in case derived from DACP/N pin */ | |
335 | static const u32 ti_sn_bridge_dsiclk_lut[] = { | |
336 | 468000000, | |
337 | 384000000, | |
338 | 416000000, | |
339 | 486000000, | |
340 | 460800000, | |
341 | }; | |
342 | ||
343 | static void ti_sn_bridge_set_refclk_freq(struct ti_sn_bridge *pdata) | |
344 | { | |
345 | int i; | |
346 | u32 refclk_rate; | |
347 | const u32 *refclk_lut; | |
348 | size_t refclk_lut_size; | |
349 | ||
350 | if (pdata->refclk) { | |
351 | refclk_rate = clk_get_rate(pdata->refclk); | |
352 | refclk_lut = ti_sn_bridge_refclk_lut; | |
353 | refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_refclk_lut); | |
354 | clk_prepare_enable(pdata->refclk); | |
355 | } else { | |
356 | refclk_rate = ti_sn_bridge_get_dsi_freq(pdata) * 1000; | |
357 | refclk_lut = ti_sn_bridge_dsiclk_lut; | |
358 | refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_dsiclk_lut); | |
359 | } | |
360 | ||
361 | /* for i equals to refclk_lut_size means default frequency */ | |
362 | for (i = 0; i < refclk_lut_size; i++) | |
363 | if (refclk_lut[i] == refclk_rate) | |
364 | break; | |
365 | ||
366 | regmap_update_bits(pdata->regmap, SN_DPPLL_SRC_REG, | |
367 | SN_REFCLK_FREQ_BITS, i << SN_REFCLK_FREQ_OFFSET); | |
368 | } | |
369 | ||
370 | /** | |
371 | * LUT index corresponds to register value and | |
372 | * LUT values corresponds to dp data rate supported | |
373 | * by the bridge in Mbps unit. | |
374 | */ | |
375 | static const unsigned int ti_sn_bridge_dp_rate_lut[] = { | |
376 | 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400 | |
377 | }; | |
378 | ||
379 | static void ti_sn_bridge_set_dsi_dp_rate(struct ti_sn_bridge *pdata) | |
380 | { | |
381 | unsigned int bit_rate_mhz, clk_freq_mhz, dp_rate_mhz; | |
382 | unsigned int val, i; | |
383 | struct drm_display_mode *mode = | |
384 | &pdata->bridge.encoder->crtc->state->adjusted_mode; | |
385 | ||
386 | /* set DSIA clk frequency */ | |
387 | bit_rate_mhz = (mode->clock / 1000) * | |
388 | mipi_dsi_pixel_format_to_bpp(pdata->dsi->format); | |
389 | clk_freq_mhz = bit_rate_mhz / (pdata->dsi->lanes * 2); | |
390 | ||
391 | /* for each increment in val, frequency increases by 5MHz */ | |
392 | val = (MIN_DSI_CLK_FREQ_MHZ / 5) + | |
393 | (((clk_freq_mhz - MIN_DSI_CLK_FREQ_MHZ) / 5) & 0xFF); | |
394 | regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val); | |
395 | ||
396 | /* set DP data rate */ | |
397 | dp_rate_mhz = ((bit_rate_mhz / pdata->dsi->lanes) * DP_CLK_FUDGE_NUM) / | |
398 | DP_CLK_FUDGE_DEN; | |
399 | for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++) | |
400 | if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz) | |
401 | break; | |
402 | ||
403 | regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG, | |
404 | SN_DP_DATA_RATE_BITS, i << SN_DP_DATA_RATE_OFFSET); | |
405 | } | |
406 | ||
407 | static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata) | |
408 | { | |
409 | struct drm_display_mode *mode = | |
410 | &pdata->bridge.encoder->crtc->state->adjusted_mode; | |
411 | u8 hsync_polarity = 0, vsync_polarity = 0; | |
412 | ||
413 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | |
414 | hsync_polarity = BIT(SN_SYNC_POLARITY_OFFSET); | |
415 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | |
416 | vsync_polarity = BIT(SN_SYNC_POLARITY_OFFSET); | |
417 | ||
418 | ti_sn_bridge_write_u16(pdata, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG, | |
419 | mode->hdisplay); | |
420 | ti_sn_bridge_write_u16(pdata, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG, | |
421 | mode->vdisplay); | |
422 | regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG, | |
423 | (mode->hsync_end - mode->hsync_start) & 0xFF); | |
424 | regmap_write(pdata->regmap, SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG, | |
425 | (((mode->hsync_end - mode->hsync_start) >> 8) & 0x7F) | | |
426 | hsync_polarity); | |
427 | regmap_write(pdata->regmap, SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG, | |
428 | (mode->vsync_end - mode->vsync_start) & 0xFF); | |
429 | regmap_write(pdata->regmap, SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG, | |
430 | (((mode->vsync_end - mode->vsync_start) >> 8) & 0x7F) | | |
431 | vsync_polarity); | |
432 | ||
433 | regmap_write(pdata->regmap, SN_CHA_HORIZONTAL_BACK_PORCH_REG, | |
434 | (mode->htotal - mode->hsync_end) & 0xFF); | |
435 | regmap_write(pdata->regmap, SN_CHA_VERTICAL_BACK_PORCH_REG, | |
436 | (mode->vtotal - mode->vsync_end) & 0xFF); | |
437 | ||
438 | regmap_write(pdata->regmap, SN_CHA_HORIZONTAL_FRONT_PORCH_REG, | |
439 | (mode->hsync_start - mode->hdisplay) & 0xFF); | |
440 | regmap_write(pdata->regmap, SN_CHA_VERTICAL_FRONT_PORCH_REG, | |
441 | (mode->vsync_start - mode->vdisplay) & 0xFF); | |
442 | ||
443 | usleep_range(10000, 10500); /* 10ms delay recommended by spec */ | |
444 | } | |
445 | ||
446 | static void ti_sn_bridge_enable(struct drm_bridge *bridge) | |
447 | { | |
448 | struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); | |
449 | unsigned int val; | |
450 | ||
451 | drm_panel_prepare(pdata->panel); | |
452 | ||
453 | /* DSI_A lane config */ | |
454 | val = (4 - pdata->dsi->lanes) << SN_DSIA_LANE_OFFSET; | |
455 | regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG, | |
456 | SN_DSIA_NUM_LANES_BITS, val); | |
457 | ||
458 | /* DP lane config */ | |
459 | val = (pdata->dsi->lanes - 1) << SN_DP_LANE_OFFSET; | |
460 | regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, | |
461 | SN_DP_NUM_LANES_BITS, val); | |
462 | ||
463 | /* set dsi/dp clk frequency value */ | |
464 | ti_sn_bridge_set_dsi_dp_rate(pdata); | |
465 | ||
466 | /* enable DP PLL */ | |
467 | regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1); | |
468 | usleep_range(10000, 10500); /* 10ms delay recommended by spec */ | |
469 | ||
470 | /** | |
471 | * The SN65DSI86 only supports ASSR Display Authentication method and | |
472 | * this method is enabled by default. An eDP panel must support this | |
473 | * authentication method. We need to enable this method in the eDP panel | |
474 | * at DisplayPort address 0x0010A prior to link training. | |
475 | */ | |
476 | regmap_write(pdata->regmap, SN_AUX_WDATA0_REG, 0x01); | |
477 | regmap_write(pdata->regmap, SN_AUX_ADDR_19_16_REG, 0x00); | |
478 | regmap_write(pdata->regmap, SN_AUX_ADDR_15_8_REG, 0x01); | |
479 | regmap_write(pdata->regmap, SN_AUX_ADDR_7_0_REG, 0x0A); | |
480 | regmap_write(pdata->regmap, SN_AUX_LENGTH_REG, 0x01); | |
481 | regmap_write(pdata->regmap, SN_AUX_CMD_REG, 0x81); | |
482 | usleep_range(10000, 10500); /* 10ms delay recommended by spec */ | |
483 | ||
484 | /* Semi auto link training mode */ | |
485 | regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A); | |
486 | msleep(20); /* 20ms delay recommended by spec */ | |
487 | ||
488 | /* config video parameters */ | |
489 | ti_sn_bridge_set_video_timings(pdata); | |
490 | ||
491 | /* enable video stream */ | |
492 | regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, | |
493 | SN_ENABLE_VID_STREAM_BIT, SN_ENABLE_VID_STREAM_BIT); | |
494 | ||
495 | drm_panel_enable(pdata->panel); | |
496 | } | |
497 | ||
498 | static void ti_sn_bridge_pre_enable(struct drm_bridge *bridge) | |
499 | { | |
500 | struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); | |
501 | ||
502 | pm_runtime_get_sync(pdata->dev); | |
503 | ||
504 | /* configure bridge ref_clk */ | |
505 | ti_sn_bridge_set_refclk_freq(pdata); | |
506 | ||
507 | /* in case drm_panel is connected then HPD is not supported */ | |
508 | regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, | |
509 | SN_HPD_DISABLE_BIT, SN_HPD_DISABLE_BIT); | |
510 | } | |
511 | ||
512 | static void ti_sn_bridge_post_disable(struct drm_bridge *bridge) | |
513 | { | |
514 | struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge); | |
515 | ||
516 | if (pdata->refclk) | |
517 | clk_disable_unprepare(pdata->refclk); | |
518 | ||
519 | pm_runtime_put_sync(pdata->dev); | |
520 | } | |
521 | ||
522 | static const struct drm_bridge_funcs ti_sn_bridge_funcs = { | |
523 | .attach = ti_sn_bridge_attach, | |
524 | .pre_enable = ti_sn_bridge_pre_enable, | |
525 | .enable = ti_sn_bridge_enable, | |
526 | .disable = ti_sn_bridge_disable, | |
527 | .post_disable = ti_sn_bridge_post_disable, | |
528 | }; | |
529 | ||
530 | static int ti_sn_bridge_parse_dsi_host(struct ti_sn_bridge *pdata) | |
531 | { | |
532 | struct device_node *np = pdata->dev->of_node; | |
533 | ||
534 | pdata->host_node = of_graph_get_remote_node(np, 0, 0); | |
535 | ||
536 | if (!pdata->host_node) { | |
537 | DRM_ERROR("remote dsi host node not found\n"); | |
538 | return -ENODEV; | |
539 | } | |
540 | ||
541 | return 0; | |
542 | } | |
543 | ||
544 | static int ti_sn_bridge_probe(struct i2c_client *client, | |
545 | const struct i2c_device_id *id) | |
546 | { | |
547 | struct ti_sn_bridge *pdata; | |
548 | int ret; | |
549 | ||
550 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | |
551 | DRM_ERROR("device doesn't support I2C\n"); | |
552 | return -ENODEV; | |
553 | } | |
554 | ||
555 | pdata = devm_kzalloc(&client->dev, sizeof(struct ti_sn_bridge), | |
556 | GFP_KERNEL); | |
557 | if (!pdata) | |
558 | return -ENOMEM; | |
559 | ||
560 | pdata->regmap = devm_regmap_init_i2c(client, | |
561 | &ti_sn_bridge_regmap_config); | |
562 | if (IS_ERR(pdata->regmap)) { | |
563 | DRM_ERROR("regmap i2c init failed\n"); | |
564 | return PTR_ERR(pdata->regmap); | |
565 | } | |
566 | ||
567 | pdata->dev = &client->dev; | |
568 | ||
569 | ret = drm_of_find_panel_or_bridge(pdata->dev->of_node, 1, 0, | |
570 | &pdata->panel, NULL); | |
571 | if (ret) { | |
572 | DRM_ERROR("could not find any panel node\n"); | |
573 | return ret; | |
574 | } | |
575 | ||
576 | dev_set_drvdata(&client->dev, pdata); | |
577 | ||
578 | pdata->enable_gpio = devm_gpiod_get(pdata->dev, "enable", | |
579 | GPIOD_OUT_LOW); | |
580 | if (IS_ERR(pdata->enable_gpio)) { | |
581 | DRM_ERROR("failed to get enable gpio from DT\n"); | |
582 | ret = PTR_ERR(pdata->enable_gpio); | |
583 | return ret; | |
584 | } | |
585 | ||
586 | ret = ti_sn_bridge_parse_regulators(pdata); | |
587 | if (ret) { | |
588 | DRM_ERROR("failed to parse regulators\n"); | |
589 | return ret; | |
590 | } | |
591 | ||
592 | pdata->refclk = devm_clk_get(pdata->dev, "refclk"); | |
593 | if (IS_ERR(pdata->refclk)) { | |
594 | ret = PTR_ERR(pdata->refclk); | |
595 | if (ret == -EPROBE_DEFER) | |
596 | return ret; | |
597 | DRM_DEBUG_KMS("refclk not found\n"); | |
598 | pdata->refclk = NULL; | |
599 | } | |
600 | ||
601 | ret = ti_sn_bridge_parse_dsi_host(pdata); | |
602 | if (ret) | |
603 | return ret; | |
604 | ||
605 | pm_runtime_enable(pdata->dev); | |
606 | ||
607 | i2c_set_clientdata(client, pdata); | |
608 | ||
609 | pdata->bridge.funcs = &ti_sn_bridge_funcs; | |
610 | pdata->bridge.of_node = client->dev.of_node; | |
611 | ||
612 | drm_bridge_add(&pdata->bridge); | |
613 | ||
614 | return 0; | |
615 | } | |
616 | ||
617 | static int ti_sn_bridge_remove(struct i2c_client *client) | |
618 | { | |
619 | struct ti_sn_bridge *pdata = i2c_get_clientdata(client); | |
620 | ||
621 | if (!pdata) | |
622 | return -EINVAL; | |
623 | ||
624 | of_node_put(pdata->host_node); | |
625 | ||
626 | pm_runtime_disable(pdata->dev); | |
627 | ||
628 | if (pdata->dsi) { | |
629 | mipi_dsi_detach(pdata->dsi); | |
630 | mipi_dsi_device_unregister(pdata->dsi); | |
631 | } | |
632 | ||
633 | drm_bridge_remove(&pdata->bridge); | |
634 | ||
635 | return 0; | |
636 | } | |
637 | ||
638 | static struct i2c_device_id ti_sn_bridge_id[] = { | |
639 | { "ti,sn65dsi86", 0}, | |
640 | {}, | |
641 | }; | |
642 | MODULE_DEVICE_TABLE(i2c, ti_sn_bridge_id); | |
643 | ||
644 | static const struct of_device_id ti_sn_bridge_match_table[] = { | |
645 | {.compatible = "ti,sn65dsi86"}, | |
646 | {}, | |
647 | }; | |
648 | MODULE_DEVICE_TABLE(of, ti_sn_bridge_match_table); | |
649 | ||
650 | static struct i2c_driver ti_sn_bridge_driver = { | |
651 | .driver = { | |
652 | .name = "ti_sn65dsi86", | |
653 | .of_match_table = ti_sn_bridge_match_table, | |
654 | .pm = &ti_sn_bridge_pm_ops, | |
655 | }, | |
656 | .probe = ti_sn_bridge_probe, | |
657 | .remove = ti_sn_bridge_remove, | |
658 | .id_table = ti_sn_bridge_id, | |
659 | }; | |
660 | module_i2c_driver(ti_sn_bridge_driver); | |
661 | ||
662 | MODULE_AUTHOR("Sandeep Panda <spanda@codeaurora.org>"); | |
663 | MODULE_DESCRIPTION("sn65dsi86 DSI to eDP bridge driver"); | |
664 | MODULE_LICENSE("GPL v2"); |