1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. |
4 | */ |
5 | |
6 | #include "dp_panel.h" |
7 | #include "dp_utils.h" |
8 | |
9 | #include <drm/drm_connector.h> |
10 | #include <drm/drm_edid.h> |
11 | #include <drm/drm_of.h> |
12 | #include <drm/drm_print.h> |
13 | |
14 | #define DP_MAX_NUM_DP_LANES 4 |
15 | #define DP_LINK_RATE_HBR2 540000 /* kbytes */ |
16 | |
17 | struct dp_panel_private { |
18 | struct device *dev; |
19 | struct drm_device *drm_dev; |
20 | struct dp_panel dp_panel; |
21 | struct drm_dp_aux *aux; |
22 | struct dp_link *link; |
23 | struct dp_catalog *catalog; |
24 | bool panel_on; |
25 | }; |
26 | |
27 | static void dp_panel_read_psr_cap(struct dp_panel_private *panel) |
28 | { |
29 | ssize_t rlen; |
30 | struct dp_panel *dp_panel; |
31 | |
32 | dp_panel = &panel->dp_panel; |
33 | |
34 | /* edp sink */ |
35 | if (dp_panel->dpcd[DP_EDP_CONFIGURATION_CAP]) { |
36 | rlen = drm_dp_dpcd_read(aux: panel->aux, DP_PSR_SUPPORT, |
37 | buffer: &dp_panel->psr_cap, size: sizeof(dp_panel->psr_cap)); |
38 | if (rlen == sizeof(dp_panel->psr_cap)) { |
39 | drm_dbg_dp(panel->drm_dev, |
40 | "psr version: 0x%x, psr_cap: 0x%x\n" , |
41 | dp_panel->psr_cap.version, |
42 | dp_panel->psr_cap.capabilities); |
43 | } else |
44 | DRM_ERROR("failed to read psr info, rlen=%zd\n" , rlen); |
45 | } |
46 | } |
47 | |
48 | static int dp_panel_read_dpcd(struct dp_panel *dp_panel) |
49 | { |
50 | int rc; |
51 | struct dp_panel_private *panel; |
52 | struct dp_link_info *link_info; |
53 | u8 *dpcd, major, minor; |
54 | |
55 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
56 | dpcd = dp_panel->dpcd; |
57 | rc = drm_dp_read_dpcd_caps(aux: panel->aux, dpcd); |
58 | if (rc) |
59 | return rc; |
60 | |
61 | dp_panel->vsc_sdp_supported = drm_dp_vsc_sdp_supported(aux: panel->aux, dpcd); |
62 | link_info = &dp_panel->link_info; |
63 | link_info->revision = dpcd[DP_DPCD_REV]; |
64 | major = (link_info->revision >> 4) & 0x0f; |
65 | minor = link_info->revision & 0x0f; |
66 | |
67 | link_info->rate = drm_dp_max_link_rate(dpcd); |
68 | link_info->num_lanes = drm_dp_max_lane_count(dpcd); |
69 | |
70 | /* Limit data lanes from data-lanes of endpoint property of dtsi */ |
71 | if (link_info->num_lanes > dp_panel->max_dp_lanes) |
72 | link_info->num_lanes = dp_panel->max_dp_lanes; |
73 | |
74 | /* Limit link rate from link-frequencies of endpoint property of dtsi */ |
75 | if (link_info->rate > dp_panel->max_dp_link_rate) |
76 | link_info->rate = dp_panel->max_dp_link_rate; |
77 | |
78 | drm_dbg_dp(panel->drm_dev, "version: %d.%d\n" , major, minor); |
79 | drm_dbg_dp(panel->drm_dev, "link_rate=%d\n" , link_info->rate); |
80 | drm_dbg_dp(panel->drm_dev, "lane_count=%d\n" , link_info->num_lanes); |
81 | |
82 | if (drm_dp_enhanced_frame_cap(dpcd)) |
83 | link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; |
84 | |
85 | dp_panel_read_psr_cap(panel); |
86 | |
87 | return rc; |
88 | } |
89 | |
90 | static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, |
91 | u32 mode_edid_bpp, u32 mode_pclk_khz) |
92 | { |
93 | struct dp_link_info *link_info; |
94 | const u32 max_supported_bpp = 30, min_supported_bpp = 18; |
95 | u32 bpp = 0, data_rate_khz = 0; |
96 | |
97 | bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); |
98 | |
99 | link_info = &dp_panel->link_info; |
100 | data_rate_khz = link_info->num_lanes * link_info->rate * 8; |
101 | |
102 | while (bpp > min_supported_bpp) { |
103 | if (mode_pclk_khz * bpp <= data_rate_khz) |
104 | break; |
105 | bpp -= 6; |
106 | } |
107 | |
108 | return bpp; |
109 | } |
110 | |
111 | static int dp_panel_update_modes(struct drm_connector *connector, |
112 | struct edid *edid) |
113 | { |
114 | int rc = 0; |
115 | |
116 | if (edid) { |
117 | rc = drm_connector_update_edid_property(connector, edid); |
118 | if (rc) { |
119 | DRM_ERROR("failed to update edid property %d\n" , rc); |
120 | return rc; |
121 | } |
122 | rc = drm_add_edid_modes(connector, edid); |
123 | return rc; |
124 | } |
125 | |
126 | rc = drm_connector_update_edid_property(connector, NULL); |
127 | if (rc) |
128 | DRM_ERROR("failed to update edid property %d\n" , rc); |
129 | |
130 | return rc; |
131 | } |
132 | |
133 | int dp_panel_read_sink_caps(struct dp_panel *dp_panel, |
134 | struct drm_connector *connector) |
135 | { |
136 | int rc, bw_code; |
137 | int count; |
138 | struct dp_panel_private *panel; |
139 | |
140 | if (!dp_panel || !connector) { |
141 | DRM_ERROR("invalid input\n" ); |
142 | return -EINVAL; |
143 | } |
144 | |
145 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
146 | |
147 | drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n" , |
148 | dp_panel->max_dp_lanes, dp_panel->max_dp_link_rate); |
149 | |
150 | rc = dp_panel_read_dpcd(dp_panel); |
151 | if (rc) { |
152 | DRM_ERROR("read dpcd failed %d\n" , rc); |
153 | return rc; |
154 | } |
155 | |
156 | bw_code = drm_dp_link_rate_to_bw_code(link_rate: dp_panel->link_info.rate); |
157 | if (!is_link_rate_valid(bw_code) || |
158 | !is_lane_count_valid(lane_count: dp_panel->link_info.num_lanes) || |
159 | (bw_code > dp_panel->max_bw_code)) { |
160 | DRM_ERROR("Illegal link rate=%d lane=%d\n" , dp_panel->link_info.rate, |
161 | dp_panel->link_info.num_lanes); |
162 | return -EINVAL; |
163 | } |
164 | |
165 | if (drm_dp_is_branch(dpcd: dp_panel->dpcd)) { |
166 | count = drm_dp_read_sink_count(aux: panel->aux); |
167 | if (!count) { |
168 | panel->link->sink_count = 0; |
169 | return -ENOTCONN; |
170 | } |
171 | } |
172 | |
173 | rc = drm_dp_read_downstream_info(aux: panel->aux, dpcd: dp_panel->dpcd, |
174 | downstream_ports: dp_panel->downstream_ports); |
175 | if (rc) |
176 | return rc; |
177 | |
178 | kfree(objp: dp_panel->edid); |
179 | dp_panel->edid = NULL; |
180 | |
181 | dp_panel->edid = drm_get_edid(connector, |
182 | adapter: &panel->aux->ddc); |
183 | if (!dp_panel->edid) { |
184 | DRM_ERROR("panel edid read failed\n" ); |
185 | /* check edid read fail is due to unplug */ |
186 | if (!dp_catalog_link_is_connected(dp_catalog: panel->catalog)) { |
187 | rc = -ETIMEDOUT; |
188 | goto end; |
189 | } |
190 | } |
191 | |
192 | end: |
193 | return rc; |
194 | } |
195 | |
196 | u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, |
197 | u32 mode_edid_bpp, u32 mode_pclk_khz) |
198 | { |
199 | struct dp_panel_private *panel; |
200 | u32 bpp; |
201 | |
202 | if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) { |
203 | DRM_ERROR("invalid input\n" ); |
204 | return 0; |
205 | } |
206 | |
207 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
208 | |
209 | if (dp_panel->video_test) |
210 | bpp = dp_link_bit_depth_to_bpp( |
211 | tbd: panel->link->test_video.test_bit_depth); |
212 | else |
213 | bpp = dp_panel_get_supported_bpp(dp_panel, mode_edid_bpp, |
214 | mode_pclk_khz); |
215 | |
216 | return bpp; |
217 | } |
218 | |
219 | int dp_panel_get_modes(struct dp_panel *dp_panel, |
220 | struct drm_connector *connector) |
221 | { |
222 | if (!dp_panel) { |
223 | DRM_ERROR("invalid input\n" ); |
224 | return -EINVAL; |
225 | } |
226 | |
227 | if (dp_panel->edid) |
228 | return dp_panel_update_modes(connector, edid: dp_panel->edid); |
229 | |
230 | return 0; |
231 | } |
232 | |
233 | static u8 dp_panel_get_edid_checksum(struct edid *edid) |
234 | { |
235 | edid += edid->extensions; |
236 | |
237 | return edid->checksum; |
238 | } |
239 | |
240 | void dp_panel_handle_sink_request(struct dp_panel *dp_panel) |
241 | { |
242 | struct dp_panel_private *panel; |
243 | |
244 | if (!dp_panel) { |
245 | DRM_ERROR("invalid input\n" ); |
246 | return; |
247 | } |
248 | |
249 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
250 | |
251 | if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { |
252 | u8 checksum; |
253 | |
254 | if (dp_panel->edid) |
255 | checksum = dp_panel_get_edid_checksum(edid: dp_panel->edid); |
256 | else |
257 | checksum = dp_panel->connector->real_edid_checksum; |
258 | |
259 | dp_link_send_edid_checksum(dp_link: panel->link, checksum); |
260 | dp_link_send_test_response(dp_link: panel->link); |
261 | } |
262 | } |
263 | |
264 | void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable) |
265 | { |
266 | struct dp_catalog *catalog; |
267 | struct dp_panel_private *panel; |
268 | |
269 | if (!dp_panel) { |
270 | DRM_ERROR("invalid input\n" ); |
271 | return; |
272 | } |
273 | |
274 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
275 | catalog = panel->catalog; |
276 | |
277 | if (!panel->panel_on) { |
278 | drm_dbg_dp(panel->drm_dev, |
279 | "DP panel not enabled, handle TPG on next on\n" ); |
280 | return; |
281 | } |
282 | |
283 | if (!enable) { |
284 | dp_catalog_panel_tpg_disable(dp_catalog: catalog); |
285 | return; |
286 | } |
287 | |
288 | drm_dbg_dp(panel->drm_dev, "calling catalog tpg_enable\n" ); |
289 | dp_catalog_panel_tpg_enable(dp_catalog: catalog, drm_mode: &panel->dp_panel.dp_mode.drm_mode); |
290 | } |
291 | |
292 | static int dp_panel_setup_vsc_sdp_yuv_420(struct dp_panel *dp_panel) |
293 | { |
294 | struct dp_catalog *catalog; |
295 | struct dp_panel_private *panel; |
296 | struct dp_display_mode *dp_mode; |
297 | struct drm_dp_vsc_sdp vsc_sdp_data; |
298 | struct dp_sdp vsc_sdp; |
299 | ssize_t len; |
300 | |
301 | if (!dp_panel) { |
302 | DRM_ERROR("invalid input\n" ); |
303 | return -EINVAL; |
304 | } |
305 | |
306 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
307 | catalog = panel->catalog; |
308 | dp_mode = &dp_panel->dp_mode; |
309 | |
310 | memset(&vsc_sdp_data, 0, sizeof(vsc_sdp_data)); |
311 | |
312 | /* VSC SDP header as per table 2-118 of DP 1.4 specification */ |
313 | vsc_sdp_data.sdp_type = DP_SDP_VSC; |
314 | vsc_sdp_data.revision = 0x05; |
315 | vsc_sdp_data.length = 0x13; |
316 | |
317 | /* VSC SDP Payload for DB16 */ |
318 | vsc_sdp_data.pixelformat = DP_PIXELFORMAT_YUV420; |
319 | vsc_sdp_data.colorimetry = DP_COLORIMETRY_DEFAULT; |
320 | |
321 | /* VSC SDP Payload for DB17 */ |
322 | vsc_sdp_data.bpc = dp_mode->bpp / 3; |
323 | vsc_sdp_data.dynamic_range = DP_DYNAMIC_RANGE_CTA; |
324 | |
325 | /* VSC SDP Payload for DB18 */ |
326 | vsc_sdp_data.content_type = DP_CONTENT_TYPE_GRAPHICS; |
327 | |
328 | len = drm_dp_vsc_sdp_pack(vsc: &vsc_sdp_data, sdp: &vsc_sdp); |
329 | if (len < 0) { |
330 | DRM_ERROR("unable to pack vsc sdp\n" ); |
331 | return len; |
332 | } |
333 | |
334 | dp_catalog_panel_enable_vsc_sdp(dp_catalog: catalog, vsc_sdp: &vsc_sdp); |
335 | |
336 | return 0; |
337 | } |
338 | |
339 | void dp_panel_dump_regs(struct dp_panel *dp_panel) |
340 | { |
341 | struct dp_catalog *catalog; |
342 | struct dp_panel_private *panel; |
343 | |
344 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
345 | catalog = panel->catalog; |
346 | |
347 | dp_catalog_dump_regs(dp_catalog: catalog); |
348 | } |
349 | |
350 | int dp_panel_timing_cfg(struct dp_panel *dp_panel) |
351 | { |
352 | u32 data, total_ver, total_hor; |
353 | struct dp_catalog *catalog; |
354 | struct dp_panel_private *panel; |
355 | struct drm_display_mode *drm_mode; |
356 | |
357 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
358 | catalog = panel->catalog; |
359 | drm_mode = &panel->dp_panel.dp_mode.drm_mode; |
360 | |
361 | drm_dbg_dp(panel->drm_dev, "width=%d hporch= %d %d %d\n" , |
362 | drm_mode->hdisplay, drm_mode->htotal - drm_mode->hsync_end, |
363 | drm_mode->hsync_start - drm_mode->hdisplay, |
364 | drm_mode->hsync_end - drm_mode->hsync_start); |
365 | |
366 | drm_dbg_dp(panel->drm_dev, "height=%d vporch= %d %d %d\n" , |
367 | drm_mode->vdisplay, drm_mode->vtotal - drm_mode->vsync_end, |
368 | drm_mode->vsync_start - drm_mode->vdisplay, |
369 | drm_mode->vsync_end - drm_mode->vsync_start); |
370 | |
371 | total_hor = drm_mode->htotal; |
372 | |
373 | total_ver = drm_mode->vtotal; |
374 | |
375 | data = total_ver; |
376 | data <<= 16; |
377 | data |= total_hor; |
378 | |
379 | catalog->total = data; |
380 | |
381 | data = (drm_mode->vtotal - drm_mode->vsync_start); |
382 | data <<= 16; |
383 | data |= (drm_mode->htotal - drm_mode->hsync_start); |
384 | |
385 | catalog->sync_start = data; |
386 | |
387 | data = drm_mode->vsync_end - drm_mode->vsync_start; |
388 | data <<= 16; |
389 | data |= (panel->dp_panel.dp_mode.v_active_low << 31); |
390 | data |= drm_mode->hsync_end - drm_mode->hsync_start; |
391 | data |= (panel->dp_panel.dp_mode.h_active_low << 15); |
392 | |
393 | catalog->width_blanking = data; |
394 | |
395 | data = drm_mode->vdisplay; |
396 | data <<= 16; |
397 | data |= drm_mode->hdisplay; |
398 | |
399 | catalog->dp_active = data; |
400 | |
401 | dp_catalog_panel_timing_cfg(dp_catalog: catalog); |
402 | |
403 | if (dp_panel->dp_mode.out_fmt_is_yuv_420) |
404 | dp_panel_setup_vsc_sdp_yuv_420(dp_panel); |
405 | |
406 | panel->panel_on = true; |
407 | |
408 | return 0; |
409 | } |
410 | |
411 | int dp_panel_init_panel_info(struct dp_panel *dp_panel) |
412 | { |
413 | struct drm_display_mode *drm_mode; |
414 | struct dp_panel_private *panel; |
415 | |
416 | drm_mode = &dp_panel->dp_mode.drm_mode; |
417 | |
418 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
419 | |
420 | /* |
421 | * print resolution info as this is a result |
422 | * of user initiated action of cable connection |
423 | */ |
424 | drm_dbg_dp(panel->drm_dev, "SET NEW RESOLUTION:\n" ); |
425 | drm_dbg_dp(panel->drm_dev, "%dx%d@%dfps\n" , |
426 | drm_mode->hdisplay, drm_mode->vdisplay, drm_mode_vrefresh(drm_mode)); |
427 | drm_dbg_dp(panel->drm_dev, |
428 | "h_porches(back|front|width) = (%d|%d|%d)\n" , |
429 | drm_mode->htotal - drm_mode->hsync_end, |
430 | drm_mode->hsync_start - drm_mode->hdisplay, |
431 | drm_mode->hsync_end - drm_mode->hsync_start); |
432 | drm_dbg_dp(panel->drm_dev, |
433 | "v_porches(back|front|width) = (%d|%d|%d)\n" , |
434 | drm_mode->vtotal - drm_mode->vsync_end, |
435 | drm_mode->vsync_start - drm_mode->vdisplay, |
436 | drm_mode->vsync_end - drm_mode->vsync_start); |
437 | drm_dbg_dp(panel->drm_dev, "pixel clock (KHz)=(%d)\n" , |
438 | drm_mode->clock); |
439 | drm_dbg_dp(panel->drm_dev, "bpp = %d\n" , dp_panel->dp_mode.bpp); |
440 | |
441 | dp_panel->dp_mode.bpp = max_t(u32, 18, |
442 | min_t(u32, dp_panel->dp_mode.bpp, 30)); |
443 | drm_dbg_dp(panel->drm_dev, "updated bpp = %d\n" , |
444 | dp_panel->dp_mode.bpp); |
445 | |
446 | return 0; |
447 | } |
448 | |
449 | static u32 dp_panel_link_frequencies(struct device_node *of_node) |
450 | { |
451 | struct device_node *endpoint; |
452 | u64 frequency = 0; |
453 | int cnt; |
454 | |
455 | endpoint = of_graph_get_endpoint_by_regs(parent: of_node, port_reg: 1, reg: 0); /* port@1 */ |
456 | if (!endpoint) |
457 | return 0; |
458 | |
459 | cnt = of_property_count_u64_elems(np: endpoint, propname: "link-frequencies" ); |
460 | |
461 | if (cnt > 0) |
462 | of_property_read_u64_index(np: endpoint, propname: "link-frequencies" , |
463 | index: cnt - 1, out_value: &frequency); |
464 | of_node_put(node: endpoint); |
465 | |
466 | do_div(frequency, |
467 | 10 * /* from symbol rate to link rate */ |
468 | 1000); /* kbytes */ |
469 | |
470 | return frequency; |
471 | } |
472 | |
473 | static int dp_panel_parse_dt(struct dp_panel *dp_panel) |
474 | { |
475 | struct dp_panel_private *panel; |
476 | struct device_node *of_node; |
477 | int cnt; |
478 | |
479 | panel = container_of(dp_panel, struct dp_panel_private, dp_panel); |
480 | of_node = panel->dev->of_node; |
481 | |
482 | /* |
483 | * data-lanes is the property of dp_out endpoint |
484 | */ |
485 | cnt = drm_of_get_data_lanes_count_ep(port: of_node, port_reg: 1, reg: 0, min: 1, DP_MAX_NUM_DP_LANES); |
486 | if (cnt < 0) { |
487 | /* legacy code, data-lanes is the property of mdss_dp node */ |
488 | cnt = drm_of_get_data_lanes_count(endpoint: of_node, min: 1, DP_MAX_NUM_DP_LANES); |
489 | } |
490 | |
491 | if (cnt > 0) |
492 | dp_panel->max_dp_lanes = cnt; |
493 | else |
494 | dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ |
495 | |
496 | dp_panel->max_dp_link_rate = dp_panel_link_frequencies(of_node); |
497 | if (!dp_panel->max_dp_link_rate) |
498 | dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2; |
499 | |
500 | return 0; |
501 | } |
502 | |
503 | struct dp_panel *dp_panel_get(struct dp_panel_in *in) |
504 | { |
505 | struct dp_panel_private *panel; |
506 | struct dp_panel *dp_panel; |
507 | int ret; |
508 | |
509 | if (!in->dev || !in->catalog || !in->aux || !in->link) { |
510 | DRM_ERROR("invalid input\n" ); |
511 | return ERR_PTR(error: -EINVAL); |
512 | } |
513 | |
514 | panel = devm_kzalloc(dev: in->dev, size: sizeof(*panel), GFP_KERNEL); |
515 | if (!panel) |
516 | return ERR_PTR(error: -ENOMEM); |
517 | |
518 | panel->dev = in->dev; |
519 | panel->aux = in->aux; |
520 | panel->catalog = in->catalog; |
521 | panel->link = in->link; |
522 | |
523 | dp_panel = &panel->dp_panel; |
524 | dp_panel->max_bw_code = DP_LINK_BW_8_1; |
525 | |
526 | ret = dp_panel_parse_dt(dp_panel); |
527 | if (ret) |
528 | return ERR_PTR(error: ret); |
529 | |
530 | return dp_panel; |
531 | } |
532 | |
533 | void dp_panel_put(struct dp_panel *dp_panel) |
534 | { |
535 | if (!dp_panel) |
536 | return; |
537 | |
538 | kfree(objp: dp_panel->edid); |
539 | } |
540 | |