1 | // SPDX-License-Identifier: GPL-2.0-or-later |
---|---|
2 | /* |
3 | * Rockchip SoC DP (Display Port) interface driver. |
4 | * |
5 | * Copyright (C) Rockchip Electronics Co., Ltd. |
6 | * Author: Andy Yan <andy.yan@rock-chips.com> |
7 | * Yakir Yang <ykk@rock-chips.com> |
8 | * Jeff Chen <jeff.chen@rock-chips.com> |
9 | */ |
10 | |
11 | #include <linux/component.h> |
12 | #include <linux/mfd/syscon.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_graph.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/pm_runtime.h> |
17 | #include <linux/regmap.h> |
18 | #include <linux/reset.h> |
19 | #include <linux/clk.h> |
20 | |
21 | #include <video/of_videomode.h> |
22 | #include <video/videomode.h> |
23 | |
24 | #include <drm/display/drm_dp_aux_bus.h> |
25 | #include <drm/display/drm_dp_helper.h> |
26 | #include <drm/drm_atomic.h> |
27 | #include <drm/drm_atomic_helper.h> |
28 | #include <drm/bridge/analogix_dp.h> |
29 | #include <drm/drm_of.h> |
30 | #include <drm/drm_panel.h> |
31 | #include <drm/drm_probe_helper.h> |
32 | #include <drm/drm_simple_kms_helper.h> |
33 | |
34 | #include "rockchip_drm_drv.h" |
35 | |
36 | #define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 |
37 | |
38 | #define GRF_REG_FIELD(_reg, _lsb, _msb) { \ |
39 | .reg = _reg, \ |
40 | .lsb = _lsb, \ |
41 | .msb = _msb, \ |
42 | .valid = true, \ |
43 | } |
44 | |
45 | struct rockchip_grf_reg_field { |
46 | u32 reg; |
47 | u32 lsb; |
48 | u32 msb; |
49 | bool valid; |
50 | }; |
51 | |
52 | /** |
53 | * struct rockchip_dp_chip_data - splite the grf setting of kind of chips |
54 | * @lcdc_sel: grf register field of lcdc_sel |
55 | * @edp_mode: grf register field of edp_mode |
56 | * @chip_type: specific chip type |
57 | * @reg: register base address |
58 | */ |
59 | struct rockchip_dp_chip_data { |
60 | const struct rockchip_grf_reg_field lcdc_sel; |
61 | const struct rockchip_grf_reg_field edp_mode; |
62 | u32 chip_type; |
63 | u32 reg; |
64 | }; |
65 | |
66 | struct rockchip_dp_device { |
67 | struct drm_device *drm_dev; |
68 | struct device *dev; |
69 | struct rockchip_encoder encoder; |
70 | struct drm_display_mode mode; |
71 | |
72 | struct clk *pclk; |
73 | struct clk *grfclk; |
74 | struct regmap *grf; |
75 | struct reset_control *rst; |
76 | struct reset_control *apbrst; |
77 | |
78 | const struct rockchip_dp_chip_data *data; |
79 | |
80 | struct analogix_dp_device *adp; |
81 | struct analogix_dp_plat_data plat_data; |
82 | }; |
83 | |
84 | static struct rockchip_dp_device *encoder_to_dp(struct drm_encoder *encoder) |
85 | { |
86 | struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); |
87 | |
88 | return container_of(rkencoder, struct rockchip_dp_device, encoder); |
89 | } |
90 | |
91 | static struct rockchip_dp_device *pdata_encoder_to_dp(struct analogix_dp_plat_data *plat_data) |
92 | { |
93 | return container_of(plat_data, struct rockchip_dp_device, plat_data); |
94 | } |
95 | |
96 | static int rockchip_grf_write(struct regmap *grf, u32 reg, u32 mask, u32 val) |
97 | { |
98 | return regmap_write(map: grf, reg, val: (mask << 16) | (val & mask)); |
99 | } |
100 | |
101 | static int rockchip_grf_field_write(struct regmap *grf, |
102 | const struct rockchip_grf_reg_field *field, |
103 | u32 val) |
104 | { |
105 | u32 mask; |
106 | |
107 | if (!field->valid) |
108 | return 0; |
109 | |
110 | mask = GENMASK(field->msb, field->lsb); |
111 | val <<= field->lsb; |
112 | |
113 | return rockchip_grf_write(grf, reg: field->reg, mask, val); |
114 | } |
115 | |
116 | static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) |
117 | { |
118 | reset_control_assert(rstc: dp->rst); |
119 | usleep_range(min: 10, max: 20); |
120 | reset_control_deassert(rstc: dp->rst); |
121 | |
122 | reset_control_assert(rstc: dp->apbrst); |
123 | usleep_range(min: 10, max: 20); |
124 | reset_control_deassert(rstc: dp->apbrst); |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) |
130 | { |
131 | struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data); |
132 | int ret; |
133 | |
134 | ret = clk_prepare_enable(clk: dp->pclk); |
135 | if (ret < 0) { |
136 | DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); |
137 | return ret; |
138 | } |
139 | |
140 | ret = rockchip_dp_pre_init(dp); |
141 | if (ret < 0) { |
142 | DRM_DEV_ERROR(dp->dev, "failed to dp pre init %d\n", ret); |
143 | clk_disable_unprepare(clk: dp->pclk); |
144 | return ret; |
145 | } |
146 | |
147 | ret = rockchip_grf_field_write(grf: dp->grf, field: &dp->data->edp_mode, val: 1); |
148 | if (ret != 0) |
149 | DRM_DEV_ERROR(dp->dev, "failed to set edp mode %d\n", ret); |
150 | |
151 | return ret; |
152 | } |
153 | |
154 | static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) |
155 | { |
156 | struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data); |
157 | int ret; |
158 | |
159 | ret = rockchip_grf_field_write(grf: dp->grf, field: &dp->data->edp_mode, val: 0); |
160 | if (ret != 0) |
161 | DRM_DEV_ERROR(dp->dev, "failed to set edp mode %d\n", ret); |
162 | |
163 | clk_disable_unprepare(clk: dp->pclk); |
164 | |
165 | return 0; |
166 | } |
167 | |
168 | static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, |
169 | struct drm_connector *connector) |
170 | { |
171 | struct drm_display_info *di = &connector->display_info; |
172 | /* VOP couldn't output YUV video format for eDP rightly */ |
173 | u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422; |
174 | |
175 | if ((di->color_formats & mask)) { |
176 | DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); |
177 | di->color_formats &= ~mask; |
178 | di->color_formats |= DRM_COLOR_FORMAT_RGB444; |
179 | di->bpc = 8; |
180 | } |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | static bool |
186 | rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder, |
187 | const struct drm_display_mode *mode, |
188 | struct drm_display_mode *adjusted_mode) |
189 | { |
190 | /* do nothing */ |
191 | return true; |
192 | } |
193 | |
194 | static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder, |
195 | struct drm_display_mode *mode, |
196 | struct drm_display_mode *adjusted) |
197 | { |
198 | /* do nothing */ |
199 | } |
200 | |
201 | static |
202 | struct drm_crtc *rockchip_dp_drm_get_new_crtc(struct drm_encoder *encoder, |
203 | struct drm_atomic_state *state) |
204 | { |
205 | struct drm_connector *connector; |
206 | struct drm_connector_state *conn_state; |
207 | |
208 | connector = drm_atomic_get_new_connector_for_encoder(state, encoder); |
209 | if (!connector) |
210 | return NULL; |
211 | |
212 | conn_state = drm_atomic_get_new_connector_state(state, connector); |
213 | if (!conn_state) |
214 | return NULL; |
215 | |
216 | return conn_state->crtc; |
217 | } |
218 | |
219 | static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder, |
220 | struct drm_atomic_state *state) |
221 | { |
222 | struct rockchip_dp_device *dp = encoder_to_dp(encoder); |
223 | struct drm_crtc *crtc; |
224 | struct drm_crtc_state *old_crtc_state; |
225 | struct of_endpoint endpoint; |
226 | struct device_node *remote_port, *remote_port_parent; |
227 | char name[32]; |
228 | u32 port_id; |
229 | int ret; |
230 | |
231 | crtc = rockchip_dp_drm_get_new_crtc(encoder, state); |
232 | if (!crtc) |
233 | return; |
234 | |
235 | old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); |
236 | /* Coming back from self refresh, nothing to do */ |
237 | if (old_crtc_state && old_crtc_state->self_refresh_active) |
238 | return; |
239 | |
240 | ret = clk_prepare_enable(clk: dp->grfclk); |
241 | if (ret < 0) { |
242 | DRM_DEV_ERROR(dp->dev, "failed to enable grfclk %d\n", ret); |
243 | return; |
244 | } |
245 | |
246 | ret = drm_of_encoder_active_endpoint(node: dp->dev->of_node, encoder, endpoint: &endpoint); |
247 | if (ret < 0) |
248 | return; |
249 | |
250 | remote_port_parent = of_graph_get_remote_port_parent(node: endpoint.local_node); |
251 | if (remote_port_parent) { |
252 | if (of_get_child_by_name(node: remote_port_parent, name: "ports")) { |
253 | remote_port = of_graph_get_remote_port(node: endpoint.local_node); |
254 | of_property_read_u32(np: remote_port, propname: "reg", out_value: &port_id); |
255 | of_node_put(node: remote_port); |
256 | sprintf(buf: name, fmt: "%s vp%d", remote_port_parent->full_name, port_id); |
257 | } else { |
258 | sprintf(buf: name, fmt: "%s %s", |
259 | remote_port_parent->full_name, endpoint.id ? "vopl": "vopb"); |
260 | } |
261 | of_node_put(node: remote_port_parent); |
262 | |
263 | DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT": "BIG"); |
264 | } |
265 | |
266 | ret = rockchip_grf_field_write(grf: dp->grf, field: &dp->data->lcdc_sel, val: endpoint.id); |
267 | if (ret != 0) |
268 | DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); |
269 | |
270 | clk_disable_unprepare(clk: dp->grfclk); |
271 | } |
272 | |
273 | static void rockchip_dp_drm_encoder_disable(struct drm_encoder *encoder, |
274 | struct drm_atomic_state *state) |
275 | { |
276 | struct rockchip_dp_device *dp = encoder_to_dp(encoder); |
277 | struct drm_crtc *crtc; |
278 | struct drm_crtc_state *new_crtc_state = NULL; |
279 | int ret; |
280 | |
281 | crtc = rockchip_dp_drm_get_new_crtc(encoder, state); |
282 | /* No crtc means we're doing a full shutdown */ |
283 | if (!crtc) |
284 | return; |
285 | |
286 | new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); |
287 | /* If we're not entering self-refresh, no need to wait for vact */ |
288 | if (!new_crtc_state || !new_crtc_state->self_refresh_active) |
289 | return; |
290 | |
291 | ret = rockchip_drm_wait_vact_end(crtc, PSR_WAIT_LINE_FLAG_TIMEOUT_MS); |
292 | if (ret) |
293 | DRM_DEV_ERROR(dp->dev, "line flag irq timed out\n"); |
294 | } |
295 | |
296 | static int |
297 | rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, |
298 | struct drm_crtc_state *crtc_state, |
299 | struct drm_connector_state *conn_state) |
300 | { |
301 | struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); |
302 | struct drm_display_info *di = &conn_state->connector->display_info; |
303 | |
304 | /* |
305 | * The hardware IC designed that VOP must output the RGB10 video |
306 | * format to eDP controller, and if eDP panel only support RGB8, |
307 | * then eDP controller should cut down the video data, not via VOP |
308 | * controller, that's why we need to hardcode the VOP output mode |
309 | * to RGA10 here. |
310 | */ |
311 | |
312 | s->output_mode = ROCKCHIP_OUT_MODE_AAAA; |
313 | s->output_type = DRM_MODE_CONNECTOR_eDP; |
314 | s->output_bpc = di->bpc; |
315 | |
316 | return 0; |
317 | } |
318 | |
319 | static const struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = { |
320 | .mode_fixup = rockchip_dp_drm_encoder_mode_fixup, |
321 | .mode_set = rockchip_dp_drm_encoder_mode_set, |
322 | .atomic_enable = rockchip_dp_drm_encoder_enable, |
323 | .atomic_disable = rockchip_dp_drm_encoder_disable, |
324 | .atomic_check = rockchip_dp_drm_encoder_atomic_check, |
325 | }; |
326 | |
327 | static int rockchip_dp_of_probe(struct rockchip_dp_device *dp) |
328 | { |
329 | struct device *dev = dp->dev; |
330 | struct device_node *np = dev->of_node; |
331 | |
332 | dp->grf = syscon_regmap_lookup_by_phandle(np, property: "rockchip,grf"); |
333 | if (IS_ERR(ptr: dp->grf)) { |
334 | DRM_DEV_ERROR(dev, "failed to get rockchip,grf property\n"); |
335 | return PTR_ERR(ptr: dp->grf); |
336 | } |
337 | |
338 | dp->grfclk = devm_clk_get(dev, id: "grf"); |
339 | if (PTR_ERR(ptr: dp->grfclk) == -ENOENT) { |
340 | dp->grfclk = NULL; |
341 | } else if (PTR_ERR(ptr: dp->grfclk) == -EPROBE_DEFER) { |
342 | return -EPROBE_DEFER; |
343 | } else if (IS_ERR(ptr: dp->grfclk)) { |
344 | DRM_DEV_ERROR(dev, "failed to get grf clock\n"); |
345 | return PTR_ERR(ptr: dp->grfclk); |
346 | } |
347 | |
348 | dp->pclk = devm_clk_get(dev, id: "pclk"); |
349 | if (IS_ERR(ptr: dp->pclk)) { |
350 | DRM_DEV_ERROR(dev, "failed to get pclk property\n"); |
351 | return PTR_ERR(ptr: dp->pclk); |
352 | } |
353 | |
354 | dp->rst = devm_reset_control_get(dev, id: "dp"); |
355 | if (IS_ERR(ptr: dp->rst)) { |
356 | DRM_DEV_ERROR(dev, "failed to get dp reset control\n"); |
357 | return PTR_ERR(ptr: dp->rst); |
358 | } |
359 | |
360 | dp->apbrst = devm_reset_control_get_optional(dev, id: "apb"); |
361 | if (IS_ERR(ptr: dp->apbrst)) { |
362 | DRM_DEV_ERROR(dev, "failed to get apb reset control\n"); |
363 | return PTR_ERR(ptr: dp->apbrst); |
364 | } |
365 | |
366 | return 0; |
367 | } |
368 | |
369 | static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp) |
370 | { |
371 | struct drm_encoder *encoder = &dp->encoder.encoder; |
372 | struct drm_device *drm_dev = dp->drm_dev; |
373 | struct device *dev = dp->dev; |
374 | int ret; |
375 | |
376 | encoder->possible_crtcs = drm_of_find_possible_crtcs(dev: drm_dev, |
377 | port: dev->of_node); |
378 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); |
379 | |
380 | ret = drm_simple_encoder_init(dev: drm_dev, encoder, |
381 | DRM_MODE_ENCODER_TMDS); |
382 | if (ret) { |
383 | DRM_ERROR("failed to initialize encoder with drm\n"); |
384 | return ret; |
385 | } |
386 | |
387 | drm_encoder_helper_add(encoder, funcs: &rockchip_dp_encoder_helper_funcs); |
388 | |
389 | return 0; |
390 | } |
391 | |
392 | static int rockchip_dp_bind(struct device *dev, struct device *master, |
393 | void *data) |
394 | { |
395 | struct rockchip_dp_device *dp = dev_get_drvdata(dev); |
396 | struct drm_device *drm_dev = data; |
397 | int ret; |
398 | |
399 | dp->drm_dev = drm_dev; |
400 | |
401 | ret = rockchip_dp_drm_create_encoder(dp); |
402 | if (ret) { |
403 | DRM_ERROR("failed to create drm encoder\n"); |
404 | return ret; |
405 | } |
406 | |
407 | rockchip_drm_encoder_set_crtc_endpoint_id(rencoder: &dp->encoder, |
408 | np: dev->of_node, port: 0, reg: 0); |
409 | |
410 | dp->plat_data.encoder = &dp->encoder.encoder; |
411 | |
412 | ret = analogix_dp_bind(dp: dp->adp, drm_dev); |
413 | if (ret) |
414 | goto err_cleanup_encoder; |
415 | |
416 | return 0; |
417 | err_cleanup_encoder: |
418 | dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder); |
419 | return ret; |
420 | } |
421 | |
422 | static void rockchip_dp_unbind(struct device *dev, struct device *master, |
423 | void *data) |
424 | { |
425 | struct rockchip_dp_device *dp = dev_get_drvdata(dev); |
426 | |
427 | analogix_dp_unbind(dp: dp->adp); |
428 | dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder); |
429 | } |
430 | |
431 | static const struct component_ops rockchip_dp_component_ops = { |
432 | .bind = rockchip_dp_bind, |
433 | .unbind = rockchip_dp_unbind, |
434 | }; |
435 | |
436 | static int rockchip_dp_link_panel(struct drm_dp_aux *aux) |
437 | { |
438 | struct analogix_dp_plat_data *plat_data = analogix_dp_aux_to_plat_data(aux); |
439 | struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data); |
440 | int ret; |
441 | |
442 | /* |
443 | * If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel |
444 | * or bridge nodes. The driver should go on for the driver-free bridge or the DP |
445 | * mode applications. |
446 | */ |
447 | ret = drm_of_find_panel_or_bridge(np: dp->dev->of_node, port: 1, endpoint: 0, panel: &plat_data->panel, NULL); |
448 | if (ret && ret != -ENODEV) |
449 | return ret; |
450 | |
451 | return component_add(dp->dev, &rockchip_dp_component_ops); |
452 | } |
453 | |
454 | static int rockchip_dp_probe(struct platform_device *pdev) |
455 | { |
456 | struct device *dev = &pdev->dev; |
457 | const struct rockchip_dp_chip_data *dp_data; |
458 | struct rockchip_dp_device *dp; |
459 | struct resource *res; |
460 | int i; |
461 | int ret; |
462 | |
463 | dp_data = of_device_get_match_data(dev); |
464 | if (!dp_data) |
465 | return -ENODEV; |
466 | |
467 | dp = devm_kzalloc(dev, size: sizeof(*dp), GFP_KERNEL); |
468 | if (!dp) |
469 | return -ENOMEM; |
470 | |
471 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
472 | |
473 | i = 0; |
474 | while (dp_data[i].reg) { |
475 | if (dp_data[i].reg == res->start) { |
476 | dp->data = &dp_data[i]; |
477 | break; |
478 | } |
479 | |
480 | i++; |
481 | } |
482 | |
483 | if (!dp->data) |
484 | return dev_err_probe(dev, err: -EINVAL, fmt: "no chip-data for %s node\n", |
485 | dev->of_node->name); |
486 | |
487 | dp->dev = dev; |
488 | dp->adp = ERR_PTR(error: -ENODEV); |
489 | dp->plat_data.dev_type = dp->data->chip_type; |
490 | dp->plat_data.power_on = rockchip_dp_poweron; |
491 | dp->plat_data.power_off = rockchip_dp_powerdown; |
492 | dp->plat_data.get_modes = rockchip_dp_get_modes; |
493 | |
494 | ret = rockchip_dp_of_probe(dp); |
495 | if (ret < 0) |
496 | return ret; |
497 | |
498 | platform_set_drvdata(pdev, data: dp); |
499 | |
500 | dp->adp = analogix_dp_probe(dev, plat_data: &dp->plat_data); |
501 | if (IS_ERR(ptr: dp->adp)) |
502 | return PTR_ERR(ptr: dp->adp); |
503 | |
504 | ret = devm_of_dp_aux_populate_bus(aux: analogix_dp_get_aux(dp: dp->adp), done_probing: rockchip_dp_link_panel); |
505 | if (ret) { |
506 | /* |
507 | * If devm_of_dp_aux_populate_bus() returns -ENODEV, the done_probing() will not |
508 | * be called because there are no EP devices. Then the rockchip_dp_link_panel() |
509 | * will be called directly in order to support the other valid DT configurations. |
510 | * |
511 | * NOTE: The devm_of_dp_aux_populate_bus() is allowed to return -EPROBE_DEFER. |
512 | */ |
513 | if (ret != -ENODEV) |
514 | return dev_err_probe(dev: dp->dev, err: ret, fmt: "failed to populate aux bus\n"); |
515 | |
516 | return rockchip_dp_link_panel(aux: analogix_dp_get_aux(dp: dp->adp)); |
517 | } |
518 | |
519 | return 0; |
520 | } |
521 | |
522 | static void rockchip_dp_remove(struct platform_device *pdev) |
523 | { |
524 | component_del(&pdev->dev, &rockchip_dp_component_ops); |
525 | } |
526 | |
527 | static int rockchip_dp_suspend(struct device *dev) |
528 | { |
529 | struct rockchip_dp_device *dp = dev_get_drvdata(dev); |
530 | |
531 | if (IS_ERR(ptr: dp->adp)) |
532 | return 0; |
533 | |
534 | return analogix_dp_suspend(dp: dp->adp); |
535 | } |
536 | |
537 | static int rockchip_dp_resume(struct device *dev) |
538 | { |
539 | struct rockchip_dp_device *dp = dev_get_drvdata(dev); |
540 | |
541 | if (IS_ERR(ptr: dp->adp)) |
542 | return 0; |
543 | |
544 | return analogix_dp_resume(dp: dp->adp); |
545 | } |
546 | |
547 | static DEFINE_RUNTIME_DEV_PM_OPS(rockchip_dp_pm_ops, rockchip_dp_suspend, |
548 | rockchip_dp_resume, NULL); |
549 | |
550 | static const struct rockchip_dp_chip_data rk3399_edp[] = { |
551 | { |
552 | .lcdc_sel = GRF_REG_FIELD(0x6250, 5, 5), |
553 | .chip_type = RK3399_EDP, |
554 | .reg = 0xff970000, |
555 | }, |
556 | { /* sentinel */ } |
557 | }; |
558 | |
559 | static const struct rockchip_dp_chip_data rk3288_dp[] = { |
560 | { |
561 | .lcdc_sel = GRF_REG_FIELD(0x025c, 5, 5), |
562 | .chip_type = RK3288_DP, |
563 | .reg = 0xff970000, |
564 | }, |
565 | { /* sentinel */ } |
566 | }; |
567 | |
568 | static const struct rockchip_dp_chip_data rk3588_edp[] = { |
569 | { |
570 | .edp_mode = GRF_REG_FIELD(0x0000, 0, 0), |
571 | .chip_type = RK3588_EDP, |
572 | .reg = 0xfdec0000, |
573 | }, |
574 | { |
575 | .edp_mode = GRF_REG_FIELD(0x0004, 0, 0), |
576 | .chip_type = RK3588_EDP, |
577 | .reg = 0xfded0000, |
578 | }, |
579 | { /* sentinel */ } |
580 | }; |
581 | |
582 | static const struct of_device_id rockchip_dp_dt_ids[] = { |
583 | {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, |
584 | {.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp }, |
585 | {.compatible = "rockchip,rk3588-edp", .data = &rk3588_edp }, |
586 | {} |
587 | }; |
588 | MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); |
589 | |
590 | struct platform_driver rockchip_dp_driver = { |
591 | .probe = rockchip_dp_probe, |
592 | .remove = rockchip_dp_remove, |
593 | .driver = { |
594 | .name = "rockchip-dp", |
595 | .pm = pm_ptr(&rockchip_dp_pm_ops), |
596 | .of_match_table = rockchip_dp_dt_ids, |
597 | }, |
598 | }; |
599 |
Definitions
- rockchip_grf_reg_field
- rockchip_dp_chip_data
- rockchip_dp_device
- encoder_to_dp
- pdata_encoder_to_dp
- rockchip_grf_write
- rockchip_grf_field_write
- rockchip_dp_pre_init
- rockchip_dp_poweron
- rockchip_dp_powerdown
- rockchip_dp_get_modes
- rockchip_dp_drm_encoder_mode_fixup
- rockchip_dp_drm_encoder_mode_set
- rockchip_dp_drm_get_new_crtc
- rockchip_dp_drm_encoder_enable
- rockchip_dp_drm_encoder_disable
- rockchip_dp_drm_encoder_atomic_check
- rockchip_dp_encoder_helper_funcs
- rockchip_dp_of_probe
- rockchip_dp_drm_create_encoder
- rockchip_dp_bind
- rockchip_dp_unbind
- rockchip_dp_component_ops
- rockchip_dp_link_panel
- rockchip_dp_probe
- rockchip_dp_remove
- rockchip_dp_suspend
- rockchip_dp_resume
- rockchip_dp_pm_ops
- rk3399_edp
- rk3288_dp
- rk3588_edp
- rockchip_dp_dt_ids
Improve your Profiling and Debugging skills
Find out more