ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch
1 From 9d6e1670f14a77c092ce32b559de52d7ddea3748 Mon Sep 17 00:00:00 2001
2 From: Sandor Yu <Sandor.yu@nxp.com>
3 Date: Fri, 23 Aug 2019 13:57:49 +0800
4 Subject: [PATCH] drm: bridge: Add Cadence DP/HDMI core driver
5
6 Add HDMI and DP core driver.
7
8 Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
9 ---
10  drivers/gpu/drm/bridge/cadence/Kconfig          |   6 +
11  drivers/gpu/drm/bridge/cadence/Makefile         |   2 +
12  drivers/gpu/drm/bridge/cadence/cdns-dp-core.c   | 605 ++++++++++++++++++++++
13  drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 643 ++++++++++++++++++++++++
14  include/drm/bridge/cdns-mhdp-imx.h              | 121 +++++
15  5 files changed, 1377 insertions(+)
16  create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
17  create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
18  create mode 100644 include/drm/bridge/cdns-mhdp-imx.h
19
20 --- a/drivers/gpu/drm/bridge/cadence/Kconfig
21 +++ b/drivers/gpu/drm/bridge/cadence/Kconfig
22 @@ -5,3 +5,9 @@ config DRM_CDNS_MHDP
23         depends on OF
24         help
25           Support Cadence MHDP API library.
26 +
27 +config DRM_CDNS_HDMI
28 +       tristate "Cadence HDMI DRM driver"
29 +
30 +config DRM_CDNS_DP
31 +       tristate "Cadence DP DRM driver"
32 --- a/drivers/gpu/drm/bridge/cadence/Makefile
33 +++ b/drivers/gpu/drm/bridge/cadence/Makefile
34 @@ -1,3 +1,5 @@
35  #ccflags-y := -Iinclude/drm
36  
37  obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp-common.o cdns-mhdp-hdmi.o
38 +obj-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
39 +obj-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
40 --- /dev/null
41 +++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
42 @@ -0,0 +1,605 @@
43 +/*
44 + * Cadence Display Port Interface (DP) driver
45 + *
46 + * Copyright (C) 2019 NXP Semiconductor, Inc.
47 + *
48 + * This program is free software; you can redistribute it and/or modify
49 + * it under the terms of the GNU General Public License as published by
50 + * the Free Software Foundation; either version 2 of the License, or
51 + * (at your option) any later version.
52 + *
53 + */
54 +
55 +#include <drm/bridge/cdns-mhdp-imx.h>
56 +#include <drm/drm_atomic_helper.h>
57 +#include <drm/drm_crtc_helper.h>
58 +#include <drm/drm_edid.h>
59 +#include <drm/drm_encoder_slave.h>
60 +#include <drm/drm_of.h>
61 +#include <drm/drm_probe_helper.h>
62 +#include <drm/drmP.h>
63 +#include <linux/delay.h>
64 +#include <linux/err.h>
65 +#include <linux/irq.h>
66 +#include <linux/module.h>
67 +#include <linux/mutex.h>
68 +#include <linux/of_device.h>
69 +
70 +#define aux_to_hdp(x) container_of(x, struct imx_mhdp_device, aux)
71 +
72 +/*
73 + * This function only implements native DPDC reads and writes
74 + */
75 +static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
76 +               struct drm_dp_aux_msg *msg)
77 +{
78 +       struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
79 +       bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
80 +       int ret;
81 +
82 +       /* Ignore address only message */
83 +       if ((msg->size == 0) || (msg->buffer == NULL)) {
84 +               msg->reply = native ?
85 +                       DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
86 +               return msg->size;
87 +       }
88 +
89 +       if (!native) {
90 +               dev_err(mhdp->dev, "%s: only native messages supported\n", __func__);
91 +               return -EINVAL;
92 +       }
93 +
94 +       /* msg sanity check */
95 +       if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
96 +               dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n",
97 +                                               __func__, msg->size, (unsigned int)msg->request);
98 +               return -EINVAL;
99 +       }
100 +
101 +       if (msg->request == DP_AUX_NATIVE_WRITE) {
102 +               const u8 *buf = msg->buffer;
103 +               int i;
104 +               for (i = 0; i < msg->size; ++i) {
105 +                       ret = cdns_mhdp_dpcd_write(mhdp,
106 +                                                  msg->address + i, buf[i]);
107 +                       if (!ret)
108 +                               continue;
109 +
110 +                       DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n");
111 +
112 +                       return ret;
113 +               }
114 +       }
115 +
116 +       if (msg->request == DP_AUX_NATIVE_READ) {
117 +               ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size);
118 +               if (ret < 0)
119 +                       return -EIO;
120 +               msg->reply = DP_AUX_NATIVE_REPLY_ACK;
121 +               return msg->size;
122 +       }
123 +       return 0;
124 +}
125 +
126 +static int dp_aux_init(struct cdns_mhdp_device *mhdp,
127 +                 struct device *dev)
128 +{
129 +       int ret;
130 +
131 +       mhdp->dp.aux.name = "imx_dp_aux";
132 +       mhdp->dp.aux.dev = dev;
133 +       mhdp->dp.aux.transfer = dp_aux_transfer;
134 +
135 +       ret = drm_dp_aux_register(&mhdp->dp.aux);
136 +
137 +       return ret;
138 +}
139 +
140 +static int dp_aux_destroy(struct cdns_mhdp_device *mhdp)
141 +{
142 +       drm_dp_aux_unregister(&mhdp->dp.aux);
143 +       return 0;
144 +}
145 +
146 +static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp)
147 +{
148 +       u32 val;
149 +
150 +       /* reset pixel clk */
151 +       val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
152 +       cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
153 +       cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
154 +}
155 +
156 +static void cdns_dp_mode_set(struct imx_mhdp_device *dp,
157 +                       const struct drm_display_mode *mode)
158 +{
159 +       struct drm_dp_link link;
160 +       struct cdns_mhdp_device *mhdp = &dp->mhdp;
161 +       u32 lane_mapping = mhdp->dp.lane_mapping;
162 +       int ret;
163 +       char linkid[6];
164 +
165 +       memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
166 +
167 +       dp->dual_mode = video_is_dual_mode(mode);
168 +
169 +       dp_pixel_clk_reset(mhdp);
170 +
171 +       hdp_plat_call(dp, pclock_change);
172 +
173 +       hdp_plat_call(dp, phy_init);
174 +
175 +       ret = drm_dp_downstream_id(&mhdp->dp.aux, linkid);
176 +       if (ret < 0) {
177 +               DRM_INFO("Failed to Get DP link ID: %d\n", ret);
178 +               return;
179 +       }
180 +       DRM_INFO("DP link id: %s, 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
181 +                linkid, linkid[0], linkid[1], linkid[2], linkid[3], linkid[4],
182 +                linkid[5]);
183 +
184 +       /* Check dp link */
185 +       ret = drm_dp_link_probe(&mhdp->dp.aux, &link);
186 +       if (ret < 0) {
187 +               DRM_INFO("Failed to probe DP link: %d\n", ret);
188 +               return;
189 +       }
190 +       DRM_INFO("DP revision: 0x%x\n", link.revision);
191 +       DRM_INFO("DP rate: %d Mbps\n", link.rate);
192 +       DRM_INFO("DP number of lanes: %d\n", link.num_lanes);
193 +       DRM_INFO("DP capabilities: 0x%lx\n", link.capabilities);
194 +
195 +       drm_dp_link_power_up(&mhdp->dp.aux, &mhdp->dp.link);
196 +       if (ret < 0) {
197 +               DRM_INFO("Failed to power DP link: %d\n", ret);
198 +               return;
199 +       }
200 +
201 +       /* always use the number of lanes from the display*/
202 +       mhdp->dp.link.num_lanes = link.num_lanes;
203 +
204 +       /* Use the lower link rate */
205 +       if (mhdp->dp.link_rate != 0) {
206 +               mhdp->dp.link.rate = min(mhdp->dp.link_rate, (u32)link.rate);
207 +               DRM_DEBUG("DP actual link rate:  0x%x\n", link.rate);
208 +       }
209 +
210 +       /* initialize phy if lanes or link rate differnt */
211 +       if (mhdp->dp.link.num_lanes != mhdp->dp.num_lanes ||
212 +                       mhdp->dp.link.rate != mhdp->dp.link_rate)
213 +               hdp_plat_call(dp, phy_init);
214 +
215 +       /* Video off */
216 +       ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
217 +       if (ret) {
218 +               DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
219 +               return;
220 +       }
221 +
222 +       /* Line swaping */
223 +       cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping);
224 +
225 +       /* Set DP host capability */
226 +       ret = cdns_mhdp_set_host_cap(mhdp, mhdp->dp.link.num_lanes, false);
227 +       if (ret) {
228 +               DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
229 +               return;
230 +       }
231 +
232 +       ret = cdns_mhdp_config_video(mhdp);
233 +       if (ret) {
234 +               DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret);
235 +               return;
236 +       }
237 +
238 +       /* Link trainning */
239 +       ret = cdns_mhdp_train_link(mhdp);
240 +       if (ret) {
241 +               DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
242 +               return;
243 +       }
244 +
245 +       ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
246 +       if (ret) {
247 +               DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
248 +               return;
249 +       }
250 +
251 +       return;
252 +}
253 +
254 +/* -----------------------------------------------------------------------------
255 + * dp TX Setup
256 + */
257 +static enum drm_connector_status
258 +cdns_dp_connector_detect(struct drm_connector *connector, bool force)
259 +{
260 +       struct imx_mhdp_device *dp = container_of(connector,
261 +                                       struct imx_mhdp_device, mhdp.connector.base);
262 +       u8 hpd = 0xf;
263 +
264 +       hpd = cdns_mhdp_read_hpd(&dp->mhdp);
265 +       if (hpd == 1)
266 +               /* Cable Connected */
267 +               return connector_status_connected;
268 +       else if (hpd == 0)
269 +               /* Cable Disconnedted */
270 +               return connector_status_disconnected;
271 +       else {
272 +               /* Cable status unknown */
273 +               DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
274 +               return connector_status_unknown;
275 +       }
276 +}
277 +
278 +static int cdns_dp_connector_get_modes(struct drm_connector *connector)
279 +{
280 +       struct imx_mhdp_device *dp = container_of(connector,
281 +                                               struct imx_mhdp_device, mhdp.connector.base);
282 +       int num_modes = 0;
283 +       struct edid *edid;
284 +
285 +       edid = drm_do_get_edid(&dp->mhdp.connector.base,
286 +                                  cdns_mhdp_get_edid_block, &dp->mhdp);
287 +       if (edid) {
288 +               dev_info(dp->mhdp.dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
289 +                        edid->header[0], edid->header[1],
290 +                        edid->header[2], edid->header[3],
291 +                        edid->header[4], edid->header[5],
292 +                        edid->header[6], edid->header[7]);
293 +               drm_connector_update_edid_property(connector, edid);
294 +               num_modes = drm_add_edid_modes(connector, edid);
295 +               kfree(edid);
296 +       }
297 +
298 +       if (num_modes == 0)
299 +               DRM_ERROR("Invalid edid\n");
300 +       return num_modes;
301 +}
302 +
303 +static const struct drm_connector_funcs cdns_dp_connector_funcs = {
304 +       .fill_modes = drm_helper_probe_single_connector_modes,
305 +       .detect = cdns_dp_connector_detect,
306 +       .destroy = drm_connector_cleanup,
307 +       .reset = drm_atomic_helper_connector_reset,
308 +       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
309 +       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
310 +};
311 +
312 +static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = {
313 +       .get_modes = cdns_dp_connector_get_modes,
314 +};
315 +
316 +static int cdns_dp_bridge_attach(struct drm_bridge *bridge)
317 +{
318 +       struct imx_mhdp_device *dp = bridge->driver_private;
319 +       struct drm_encoder *encoder = bridge->encoder;
320 +       struct drm_connector *connector = &dp->mhdp.connector.base;
321 +
322 +       connector->interlace_allowed = 1;
323 +       connector->polled = DRM_CONNECTOR_POLL_HPD;
324 +
325 +       drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
326 +
327 +       drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs,
328 +                          DRM_MODE_CONNECTOR_DisplayPort);
329 +
330 +       drm_connector_attach_encoder(connector, encoder);
331 +
332 +       return 0;
333 +}
334 +
335 +static enum drm_mode_status
336 +cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
337 +                         const struct drm_display_mode *mode)
338 +{
339 +       enum drm_mode_status mode_status = MODE_OK;
340 +
341 +       /* We don't support double-clocked modes */
342 +       if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
343 +                       mode->flags & DRM_MODE_FLAG_INTERLACE)
344 +               return MODE_BAD;
345 +
346 +       /* MAX support pixel clock rate 594MHz */
347 +       if (mode->clock > 594000)
348 +               return MODE_CLOCK_HIGH;
349 +
350 +       /* 4096x2160 is not supported now */
351 +       if (mode->hdisplay > 3840)
352 +               return MODE_BAD_HVALUE;
353 +
354 +       if (mode->vdisplay > 2160)
355 +               return MODE_BAD_VVALUE;
356 +
357 +       return mode_status;
358 +}
359 +
360 +static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
361 +                                   const struct drm_display_mode *orig_mode,
362 +                                   const struct drm_display_mode *mode)
363 +{
364 +       struct imx_mhdp_device *dp = bridge->driver_private;
365 +       struct drm_display_info *display_info = &dp->mhdp.connector.base.display_info;
366 +       struct video_info *video = &dp->mhdp.video_info;
367 +
368 +       switch (display_info->bpc) {
369 +       case 10:
370 +               video->color_depth = 10;
371 +               break;
372 +       case 6:
373 +               video->color_depth = 6;
374 +               break;
375 +       default:
376 +               video->color_depth = 8;
377 +               break;
378 +       }
379 +
380 +       video->color_fmt = PXL_RGB;
381 +       video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
382 +       video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
383 +
384 +       DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
385 +
386 +       mutex_lock(&dp->lock);
387 +
388 +       cdns_dp_mode_set(dp, mode);
389 +
390 +       mutex_unlock(&dp->lock);
391 +}
392 +
393 +static void cdn_hdp_bridge_enable(struct drm_bridge *bridge)
394 +{
395 +}
396 +
397 +static void cdn_hdp_bridge_disable(struct drm_bridge *bridge)
398 +{      
399 +       struct imx_mhdp_device *dp = bridge->driver_private;
400 +       struct cdns_mhdp_device *mhdp = &dp->mhdp;
401 +
402 +       cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
403 +       drm_dp_link_power_down(&mhdp->dp.aux, &mhdp->dp.link);
404 +}
405 +
406 +static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
407 +       .attach = cdns_dp_bridge_attach,
408 +       .enable = cdn_hdp_bridge_enable,
409 +       .disable = cdn_hdp_bridge_disable,
410 +       .mode_set = cdns_dp_bridge_mode_set,
411 +       .mode_valid = cdns_dp_bridge_mode_valid,
412 +};
413 +
414 +static void hotplug_work_func(struct work_struct *work)
415 +{
416 +       struct imx_mhdp_device *dp = container_of(work,
417 +                                          struct imx_mhdp_device, hotplug_work.work);
418 +       struct drm_connector *connector = &dp->mhdp.connector.base;
419 +
420 +       drm_helper_hpd_irq_event(connector->dev);
421 +
422 +       if (connector->status == connector_status_connected) {
423 +               DRM_INFO("HDMI/DP Cable Plug In\n");
424 +               enable_irq(dp->irq[IRQ_OUT]);
425 +       } else if (connector->status == connector_status_disconnected) {
426 +               /* Cable Disconnedted  */
427 +               DRM_INFO("HDMI/DP Cable Plug Out\n");
428 +               enable_irq(dp->irq[IRQ_IN]);
429 +       }
430 +}
431 +
432 +static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
433 +{
434 +       struct imx_mhdp_device *dp = data;
435 +
436 +       disable_irq_nosync(irq);
437 +
438 +       mod_delayed_work(system_wq, &dp->hotplug_work,
439 +                       msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
440 +
441 +       return IRQ_HANDLED;
442 +}
443 +
444 +static void cdns_dp_parse_dt(struct cdns_mhdp_device *mhdp)
445 +{
446 +       struct device_node *of_node = mhdp->dev->of_node;
447 +       int ret;
448 +
449 +       ret = of_property_read_u32(of_node, "lane-mapping",
450 +                                               &mhdp->dp.lane_mapping);
451 +       if (ret) {
452 +               mhdp->dp.lane_mapping = 0xc6;
453 +               dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
454 +       }
455 +       dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->dp.lane_mapping);
456 +
457 +       ret = of_property_read_u32(of_node, "link-rate", &mhdp->dp.link_rate);
458 +       if (ret) {
459 +               mhdp->dp.link_rate = 162000 ;
460 +               dev_warn(mhdp->dev, "Failed to get link-rate, use default 1620MHz\n");
461 +       }
462 +       dev_info(mhdp->dev, "link-rate %d\n", mhdp->dp.link_rate);
463 +       
464 +       ret = of_property_read_u32(of_node, "num-lanes", &mhdp->dp.num_lanes);
465 +       if (ret) {
466 +               mhdp->dp.num_lanes = 4;
467 +               dev_warn(mhdp->dev, "Failed to get num_lanes - using default\n");
468 +       }
469 +       dev_info(mhdp->dev, "dp_num_lanes 0x%02x\n", mhdp->dp.num_lanes);
470 +
471 +       mhdp->dp.link.num_lanes = mhdp->dp.num_lanes;
472 +       mhdp->dp.link.rate= mhdp->dp.link_rate;
473 +}
474 +
475 +static struct imx_mhdp_device *
476 +__cdns_dp_probe(struct platform_device *pdev,
477 +               const struct cdn_plat_data *plat_data)
478 +{
479 +       struct device *dev = &pdev->dev;
480 +       struct imx_mhdp_device *dp;
481 +       struct resource *iores = NULL;
482 +       int ret;
483 +
484 +       dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
485 +       if (!dp)
486 +               return ERR_PTR(-ENOMEM);
487 +
488 +       dp->plat_data = plat_data;
489 +       dp->mhdp.dev = dev;
490 +
491 +       mutex_init(&dp->lock);
492 +       mutex_init(&dp->audio_mutex);
493 +       spin_lock_init(&dp->audio_lock);
494 +
495 +       INIT_DELAYED_WORK(&dp->hotplug_work, hotplug_work_func);
496 +
497 +       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
498 +       dp->mhdp.regs = devm_ioremap(dev, iores->start, resource_size(iores));
499 +       if (IS_ERR(dp->mhdp.regs)) {
500 +               ret = PTR_ERR(dp->mhdp.regs);
501 +               goto err_out;
502 +       }
503 +
504 +#if 0
505 +       iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
506 +       dp->regs_ss = devm_ioremap(dev, iores->start, resource_size(iores));
507 +       if (IS_ERR(dp->regs_ss)) {
508 +               ret = PTR_ERR(dp->regs_ss);
509 +               goto err_out;
510 +       }
511 +#endif
512 +
513 +       dp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
514 +       if (dp->irq[IRQ_IN] < 0)
515 +               dev_info(&pdev->dev, "No plug_in irq number\n");
516 +
517 +       dp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
518 +       if (dp->irq[IRQ_OUT] < 0)
519 +               dev_info(&pdev->dev, "No plug_out irq number\n");
520 +
521 +       cdns_dp_parse_dt(&dp->mhdp);
522 +
523 +       dp->dual_mode = false;
524 +       hdp_plat_call(dp, fw_init);
525 +
526 +       /* DP FW alive check */
527 +       ret = cdns_mhdp_check_alive(&dp->mhdp);
528 +       if (ret == false) {
529 +               DRM_ERROR("NO dp FW running\n");
530 +               return ERR_PTR(-ENXIO);
531 +       }
532 +
533 +       /* DP PHY init before AUX init */
534 +       hdp_plat_call(dp, phy_init);
535 +
536 +       /* Enable Hotplug Detect IRQ thread */
537 +       irq_set_status_flags(dp->irq[IRQ_IN], IRQ_NOAUTOEN);
538 +       ret = devm_request_threaded_irq(dev, dp->irq[IRQ_IN],
539 +                                       NULL, cdns_dp_irq_thread,
540 +                                       IRQF_ONESHOT, dev_name(dev),
541 +                                       dp);
542 +       if (ret) {
543 +               dev_err(&pdev->dev, "can't claim irq %d\n",
544 +                                               dp->irq[IRQ_IN]);
545 +               goto err_out;
546 +       }
547 +       
548 +       irq_set_status_flags(dp->irq[IRQ_OUT], IRQ_NOAUTOEN);
549 +       ret = devm_request_threaded_irq(dev, dp->irq[IRQ_OUT],
550 +                                       NULL, cdns_dp_irq_thread,
551 +                                       IRQF_ONESHOT, dev_name(dev),
552 +                                       dp);
553 +       if (ret) {
554 +               dev_err(&pdev->dev, "can't claim irq %d\n",
555 +                                               dp->irq[IRQ_OUT]);
556 +               goto err_out;
557 +       }
558 +       if (cdns_mhdp_read_hpd(&dp->mhdp))
559 +               enable_irq(dp->irq[IRQ_OUT]);
560 +       else
561 +               enable_irq(dp->irq[IRQ_IN]);
562 +
563 +       dp->mhdp.bridge.base.driver_private = dp;
564 +       dp->mhdp.bridge.base.funcs = &cdns_dp_bridge_funcs;
565 +#ifdef CONFIG_OF
566 +       dp->mhdp.bridge.base.of_node = pdev->dev.of_node;
567 +#endif
568 +
569 +       platform_set_drvdata(pdev, dp);
570 +       
571 +       dp_aux_init(&dp->mhdp, dev);
572 +
573 +       return dp;
574 +
575 +err_out:
576 +       return ERR_PTR(ret);
577 +}
578 +
579 +static void __cdns_dp_remove(struct imx_mhdp_device *dp)
580 +{
581 +       dp_aux_destroy(&dp->mhdp);
582 +}
583 +
584 +/* -----------------------------------------------------------------------------
585 + * Probe/remove API, used from platforms based on the DRM bridge API.
586 + */
587 +int cdns_dp_probe(struct platform_device *pdev,
588 +                 const struct cdn_plat_data *plat_data)
589 +{
590 +       struct imx_mhdp_device *dp;
591 +
592 +       dp = __cdns_dp_probe(pdev, plat_data);
593 +       if (IS_ERR(dp))
594 +               return PTR_ERR(dp);
595 +
596 +       drm_bridge_add(&dp->mhdp.bridge.base);
597 +
598 +       return 0;
599 +}
600 +EXPORT_SYMBOL_GPL(cdns_dp_probe);
601 +
602 +void cdns_dp_remove(struct platform_device *pdev)
603 +{
604 +       struct imx_mhdp_device *dp = platform_get_drvdata(pdev);
605 +
606 +       drm_bridge_remove(&dp->mhdp.bridge.base);
607 +
608 +       __cdns_dp_remove(dp);
609 +}
610 +EXPORT_SYMBOL_GPL(cdns_dp_remove);
611 +
612 +/* -----------------------------------------------------------------------------
613 + * Bind/unbind API, used from platforms based on the component framework.
614 + */
615 +int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
616 +                const struct cdn_plat_data *plat_data)
617 +{
618 +       struct imx_mhdp_device *dp;
619 +       int ret;
620 +
621 +       dp = __cdns_dp_probe(pdev, plat_data);
622 +       if (IS_ERR(dp))
623 +               return PTR_ERR(dp);
624 +
625 +       ret = drm_bridge_attach(encoder, &dp->mhdp.bridge.base, NULL);
626 +       if (ret) {
627 +               cdns_dp_remove(pdev);
628 +               DRM_ERROR("Failed to initialize bridge with drm\n");
629 +               return ret;
630 +       }
631 +
632 +       return 0;
633 +}
634 +EXPORT_SYMBOL_GPL(cdns_dp_bind);
635 +
636 +void cdns_dp_unbind(struct device *dev)
637 +{
638 +       struct imx_mhdp_device *dp = dev_get_drvdata(dev);
639 +
640 +       __cdns_dp_remove(dp);
641 +}
642 +EXPORT_SYMBOL_GPL(cdns_dp_unbind);
643 +
644 +MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
645 +MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
646 +MODULE_LICENSE("GPL");
647 +MODULE_ALIAS("platform:cdn-dp");
648 --- /dev/null
649 +++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
650 @@ -0,0 +1,643 @@
651 +/*
652 + * Cadence High-Definition Multimedia Interface (HDMI) driver
653 + *
654 + * Copyright (C) 2019 NXP Semiconductor, Inc.
655 + *
656 + * This program is free software; you can redistribute it and/or modify
657 + * it under the terms of the GNU General Public License as published by
658 + * the Free Software Foundation; either version 2 of the License, or
659 + * (at your option) any later version.
660 + *
661 + */
662 +
663 +#include <drm/bridge/cdns-mhdp-imx.h>
664 +#include <drm/drm_atomic_helper.h>
665 +#include <drm/drm_crtc_helper.h>
666 +#include <drm/drm_edid.h>
667 +#include <drm/drm_encoder_slave.h>
668 +#include <drm/drm_of.h>
669 +#include <drm/drm_probe_helper.h>
670 +#include <drm/drmP.h>
671 +#include <linux/delay.h>
672 +#include <linux/err.h>
673 +#include <linux/hdmi.h>
674 +#include <linux/irq.h>
675 +#include <linux/module.h>
676 +#include <linux/mfd/syscon.h>
677 +#include <linux/mutex.h>
678 +#include <linux/regmap.h>
679 +#include <linux/of_device.h>
680 +
681 +static void hdmi_writel(struct cdns_mhdp_device *mhdp, u32 val, u32 offset)
682 +{
683 +       struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
684 +
685 +       /* TODO */
686 +       if (offset >= 0x1000 && hdmi->regmap_csr) {
687 +               /* Remap address to low 4K memory */
688 +               regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, offset >> 12);
689 +               writel(val, (offset & 0xfff) + mhdp->regs);
690 +               /* Restore address mapping */
691 +               regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, 0);
692 +
693 +       } else
694 +               writel(val, mhdp->regs + offset);
695 +}
696 +
697 +static int hdmi_sink_config(struct cdns_mhdp_device *mhdp)
698 +{
699 +       struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
700 +       u8 buff;
701 +       int ret;
702 +
703 +       if (mhdp->hdmi.char_rate > 340000) {
704 +               /*
705 +                * TMDS Character Rate above 340MHz should working in HDMI2.0
706 +                * Enable scrambling and TMDS_Bit_Clock_Ratio
707 +                */
708 +               buff = 3;
709 +               mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
710 +       } else  if (scdc->scrambling.low_rates) {
711 +               /*
712 +                * Enable scrambling and HDMI2.0 when scrambling capability of sink
713 +                * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
714 +                */
715 +               buff = 1;
716 +               mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
717 +       } else {
718 +               /* Default work in HDMI1.4 */
719 +               buff = 0;
720 +               mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
721 +        }
722 +
723 +       /* TMDS config */
724 +       ret = cdns_hdmi_scdc_write(mhdp, 0x20, buff);
725 +       return ret;
726 +}
727 +
728 +static int hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
729 +{
730 +       int ret;
731 +
732 +       /* TODO */
733 +       /* Set the lane swapping */
734 +//     if (cpu_is_imx8qm())
735 +               ret = cdns_mhdp_reg_write(mhdp, LANES_CONFIG,
736 +                                                   F_SOURCE_PHY_LANE0_SWAP(3) |
737 +                                                   F_SOURCE_PHY_LANE1_SWAP(0) |
738 +                                                   F_SOURCE_PHY_LANE2_SWAP(1) |
739 +                                                   F_SOURCE_PHY_LANE3_SWAP(2) |
740 +                                                   F_SOURCE_PHY_COMB_BYPASS(0) |
741 +                                                       F_SOURCE_PHY_20_10(1));
742 +#if 0
743 +       else
744 +               ret = cdns_mhdp_reg_write(mhdp, LANES_CONFIG,
745 +                                                   F_SOURCE_PHY_LANE0_SWAP(0) |
746 +                                                   F_SOURCE_PHY_LANE1_SWAP(1) |
747 +                                                   F_SOURCE_PHY_LANE2_SWAP(2) |
748 +                                                   F_SOURCE_PHY_LANE3_SWAP(3) |
749 +                                                   F_SOURCE_PHY_COMB_BYPASS(0) |
750 +                                                       F_SOURCE_PHY_20_10(1));
751 +#endif
752 +       return ret;
753 +}
754 +
755 +static void hdmi_info_frame_set(struct cdns_mhdp_device *mhdp,
756 +                                       u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type)
757 +{
758 +       u32 *packet32, len32;
759 +       u32 val, i;
760 +
761 +       /* invalidate entry */
762 +       val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id);
763 +       hdmi_writel(mhdp, val, SOURCE_PIF_PKT_ALLOC_REG);
764 +       hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
765 +
766 +       /* flush fifo 1 */
767 +       hdmi_writel(mhdp, F_FIFO1_FLUSH(1), SOURCE_PIF_FIFO1_FLUSH);
768 +
769 +       /* write packet into memory */
770 +       packet32 = (u32 *)packet;
771 +       len32 = packet_len / 4;
772 +       for (i = 0; i < len32; i++)
773 +               hdmi_writel(mhdp, F_DATA_WR(packet32[i]), SOURCE_PIF_DATA_WR);
774 +
775 +       /* write entry id */
776 +       hdmi_writel(mhdp, F_WR_ADDR(entry_id), SOURCE_PIF_WR_ADDR);
777 +
778 +       /* write request */
779 +       hdmi_writel(mhdp, F_HOST_WR(1), SOURCE_PIF_WR_REQ);
780 +
781 +       /* update entry */
782 +       val =  F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) |
783 +                       F_PACKET_TYPE(packet_type) | F_PKT_ALLOC_ADDRESS(entry_id);
784 +       hdmi_writel(mhdp, val, SOURCE_PIF_PKT_ALLOC_REG);
785 +
786 +       hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
787 +}
788 +
789 +#define RGB_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
790 +                                BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
791 +#define YCC_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
792 +                                BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM) |\
793 +                                BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601) |\
794 +                                BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601) |\
795 +                                BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709) |\
796 +                                BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
797 +static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp,
798 +                               struct drm_display_mode *mode)
799 +{
800 +       struct hdmi_avi_infoframe frame;
801 +//     struct drm_display_info *di = &mhdp->connector.base.display_info;
802 +//     enum hdmi_extended_colorimetry ext_col;
803 +//     u32 sink_col, allowed_col;
804 +       int format = mhdp->video_info.color_fmt;
805 +       u8 buf[32];
806 +       int ret;
807 +
808 +       /* Initialise info frame from DRM mode */
809 +       drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
810 +
811 +#if 0 //TODO to DCSS
812 +       /* Set up colorimetry */
813 +       allowed_col = format == PXL_RGB ? RGB_ALLOWED_COLORIMETRY :
814 +                                                 YCC_ALLOWED_COLORIMETRY;
815 +
816 +       sink_col = di->hdmi.colorimetry & allowed_col;
817 +
818 +       if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020))
819 +               ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020;
820 +       else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM))
821 +               ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM;
822 +       else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
823 +               ext_col = HDMI_EXTENDED_COLORIMETRY_OPRGB;
824 +       else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709))
825 +               ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
826 +       else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601))
827 +               ext_col = HDMI_EXTENDED_COLORIMETRY_OPYCC_601;
828 +       else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601))
829 +               ext_col = HDMI_EXTENDED_COLORIMETRY_S_YCC_601;
830 +       else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
831 +               ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
832 +       else
833 +               ext_col = 0;
834 +
835 +       frame.colorimetry = sink_col ? HDMI_COLORIMETRY_EXTENDED :
836 +                                         HDMI_COLORIMETRY_NONE;
837 +       frame.extended_colorimetry = ext_col;
838 +#endif
839 +
840 +       switch (format) {
841 +       case YCBCR_4_4_4:
842 +               frame.colorspace = HDMI_COLORSPACE_YUV444;
843 +               break;
844 +       case YCBCR_4_2_2:
845 +               frame.colorspace = HDMI_COLORSPACE_YUV422;
846 +               break;
847 +       case YCBCR_4_2_0:
848 +               frame.colorspace = HDMI_COLORSPACE_YUV420;
849 +               break;
850 +       default:
851 +               frame.colorspace = HDMI_COLORSPACE_RGB;
852 +               break;
853 +       }
854 +
855 +       ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
856 +       if (ret < 0) {
857 +               DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
858 +               return -1;
859 +       }
860 +
861 +       buf[0] = 0;
862 +       hdmi_info_frame_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI);
863 +       return 0;
864 +}
865 +
866 +static int hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
867 +                               struct drm_display_mode *mode)
868 +{
869 +       struct hdmi_vendor_infoframe frame;
870 +       u8 buf[32];
871 +       int ret;
872 +
873 +       /* Initialise vendor frame from DRM mode */
874 +       ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
875 +       if (ret < 0) {
876 +               DRM_WARN("Unable to init vendor infoframe: %d\n", ret);
877 +               return -1;
878 +       }
879 +
880 +       ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
881 +       if (ret < 0) {
882 +               DRM_WARN("Unable to pack vendor infoframe: %d\n", ret);
883 +               return -1;
884 +       }
885 +
886 +       buf[0] = 0;
887 +       hdmi_info_frame_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
888 +       return 0;
889 +}
890 +
891 +void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp)
892 +{
893 +       struct drm_display_mode *mode = &mhdp->mode;
894 +       int ret;
895 +
896 +       ret = hdmi_sink_config(mhdp);
897 +       if (ret < 0) {
898 +               DRM_ERROR("%s failed\n", __func__);
899 +               return;
900 +       }
901 +
902 +       ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate);
903 +       if (ret < 0) {
904 +               DRM_ERROR("%s, ret = %d\n", __func__, ret);
905 +               return;
906 +       }
907 +
908 +       /* Config GCP */
909 +       if (mhdp->video_info.color_depth == 8)
910 +               cdns_hdmi_disable_gcp(mhdp);
911 +       else
912 +               cdns_hdmi_enable_gcp(mhdp);
913 +
914 +       ret = hdmi_avi_info_set(mhdp, mode);
915 +       if (ret < 0) {
916 +               DRM_ERROR("%s ret = %d\n", __func__, ret);
917 +               return;
918 +       }
919 +
920 +       /* vendor info frame is enable only  when HDMI1.4 4K mode */
921 +       ret = hdmi_vendor_info_set(mhdp, mode);
922 +       if (ret < 0)
923 +               DRM_WARN("Unable to configure Vendor infoframe\n");
924 +
925 +       ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
926 +       if (ret < 0) {
927 +               DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
928 +               return;
929 +       }
930 +
931 +       /* wait HDMI PHY pixel clock stable */
932 +       msleep(50);
933 +}
934 +
935 +static enum drm_connector_status
936 +cdns_hdmi_connector_detect(struct drm_connector *connector, bool force)
937 +{
938 +       struct imx_mhdp_device *hdmi =
939 +                               container_of(connector, struct imx_mhdp_device, mhdp.connector.base);
940 +
941 +       u8 hpd = 0xf;
942 +
943 +       hpd = cdns_mhdp_read_hpd(&hdmi->mhdp);
944 +
945 +       if (hpd == 1)
946 +               /* Cable Connected */
947 +               return connector_status_connected;
948 +       else if (hpd == 0)
949 +               /* Cable Disconnedted */
950 +               return connector_status_disconnected;
951 +       else {
952 +               /* Cable status unknown */
953 +               DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
954 +               return connector_status_unknown;
955 +       }
956 +}
957 +
958 +static int cdns_hdmi_connector_get_modes(struct drm_connector *connector)
959 +{
960 +       struct imx_mhdp_device *hdmi = container_of(connector, struct imx_mhdp_device,
961 +                                            mhdp.connector.base);
962 +       int num_modes = 0;
963 +       struct edid *edid;
964 +
965 +       edid = drm_do_get_edid(&hdmi->mhdp.connector.base,
966 +                                  cdns_hdmi_get_edid_block, &hdmi->mhdp);
967 +       if (edid) {
968 +               dev_info(hdmi->mhdp.dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
969 +                        edid->header[0], edid->header[1],
970 +                        edid->header[2], edid->header[3],
971 +                        edid->header[4], edid->header[5],
972 +                        edid->header[6], edid->header[7]);
973 +               drm_connector_update_edid_property(connector, edid);
974 +               num_modes = drm_add_edid_modes(connector, edid);
975 +               kfree(edid);
976 +       }
977 +
978 +       if (num_modes == 0)
979 +               DRM_ERROR("Invalid edid\n");
980 +       return num_modes;
981 +}
982 +
983 +static const struct drm_connector_funcs cdns_hdmi_connector_funcs = {
984 +       .fill_modes = drm_helper_probe_single_connector_modes,
985 +       .detect = cdns_hdmi_connector_detect,
986 +       .destroy = drm_connector_cleanup,
987 +       .reset = drm_atomic_helper_connector_reset,
988 +       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
989 +       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
990 +};
991 +
992 +static const struct drm_connector_helper_funcs cdns_hdmi_connector_helper_funcs = {
993 +       .get_modes = cdns_hdmi_connector_get_modes,
994 +};
995 +
996 +static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge)
997 +{
998 +       struct imx_mhdp_device *hdmi = bridge->driver_private;
999 +       struct drm_encoder *encoder = bridge->encoder;
1000 +       struct drm_connector *connector = &hdmi->mhdp.connector.base;
1001 +
1002 +       connector->interlace_allowed = 1;
1003 +       connector->polled = DRM_CONNECTOR_POLL_HPD;
1004 +
1005 +       drm_connector_helper_add(connector, &cdns_hdmi_connector_helper_funcs);
1006 +
1007 +       drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs,
1008 +                          DRM_MODE_CONNECTOR_HDMIA);
1009 +
1010 +       drm_connector_attach_encoder(connector, encoder);
1011 +
1012 +       return 0;
1013 +}
1014 +
1015 +static enum drm_mode_status
1016 +cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
1017 +                         const struct drm_display_mode *mode)
1018 +{
1019 +       enum drm_mode_status mode_status = MODE_OK;
1020 +
1021 +       /* We don't support double-clocked and Interlaced modes */
1022 +       if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
1023 +                       mode->flags & DRM_MODE_FLAG_INTERLACE)
1024 +               return MODE_BAD;
1025 +
1026 +       /* MAX support pixel clock rate 148.5MHz */
1027 +       if (mode->clock > 148500)
1028 +               return MODE_CLOCK_HIGH;
1029 +
1030 +       /* 4096x2160 is not supported */
1031 +       if (mode->hdisplay > 3840 || mode->vdisplay > 2160)
1032 +               return MODE_BAD_HVALUE;
1033 +
1034 +       return mode_status;
1035 +}
1036 +
1037 +static void cdns_hdmi_bridge_mode_set(struct drm_bridge *bridge,
1038 +                                   const struct drm_display_mode *orig_mode,
1039 +                                   const struct drm_display_mode *mode)
1040 +{
1041 +       struct imx_mhdp_device *hdmi = bridge->driver_private;
1042 +       struct drm_display_info *display_info = &hdmi->mhdp.connector.base.display_info;
1043 +       struct video_info *video = &hdmi->mhdp.video_info;
1044 +
1045 +       switch (display_info->bpc) {
1046 +       case 10:
1047 +               video->color_depth = 10;
1048 +               break;
1049 +       case 6:
1050 +               video->color_depth = 6;
1051 +               break;
1052 +       default:
1053 +               video->color_depth = 8;
1054 +               break;
1055 +       }
1056 +
1057 +       video->color_fmt = PXL_RGB;
1058 +       video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
1059 +       video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
1060 +
1061 +       mutex_lock(&hdmi->lock);
1062 +
1063 +       DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); 
1064 +
1065 +       memcpy(&hdmi->mhdp.mode, mode, sizeof(struct drm_display_mode));
1066 +
1067 +       hdmi->dual_mode = video_is_dual_mode(mode);
1068 +
1069 +       hdmi_lanes_config(&hdmi->mhdp);
1070 +
1071 +       hdp_plat_call(hdmi, pclock_change);
1072 +
1073 +       hdp_plat_call(hdmi, phy_init);
1074 +
1075 +       cdns_hdmi_mode_set(&hdmi->mhdp);
1076 +
1077 +       mutex_unlock(&hdmi->lock);
1078 +}
1079 +
1080 +static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = {
1081 +       .attach = cdns_hdmi_bridge_attach,
1082 +       .mode_set = cdns_hdmi_bridge_mode_set,
1083 +       .mode_valid = cdns_hdmi_bridge_mode_valid,
1084 +};
1085 +
1086 +static void hotplug_work_func(struct work_struct *work)
1087 +{
1088 +       struct imx_mhdp_device *hdmi = container_of(work,
1089 +                                          struct imx_mhdp_device, hotplug_work.work);
1090 +       struct drm_connector *connector = &hdmi->mhdp.connector.base;
1091 +
1092 +       drm_helper_hpd_irq_event(connector->dev);
1093 +
1094 +       if (connector->status == connector_status_connected) {
1095 +               /* Cable Connected */
1096 +               DRM_INFO("HDMI Cable Plug In\n");
1097 +               enable_irq(hdmi->irq[IRQ_OUT]);
1098 +       } else if (connector->status == connector_status_disconnected) {
1099 +               /* Cable Disconnedted  */
1100 +               DRM_INFO("HDMI Cable Plug Out\n");
1101 +               enable_irq(hdmi->irq[IRQ_IN]);
1102 +       }
1103 +}
1104 +
1105 +static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data)
1106 +{
1107 +       struct imx_mhdp_device *hdmi = data;
1108 +
1109 +       disable_irq_nosync(irq);
1110 +
1111 +       mod_delayed_work(system_wq, &hdmi->hotplug_work,
1112 +                       msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
1113 +
1114 +       return IRQ_HANDLED;
1115 +}
1116 +
1117 +static struct imx_mhdp_device *
1118 +__cdns_hdmi_probe(struct platform_device *pdev,
1119 +                       const struct cdn_plat_data *plat_data)
1120 +{
1121 +       struct device *dev = &pdev->dev;
1122 +       struct device_node *np = dev->of_node;
1123 +       struct platform_device_info pdevinfo;
1124 +       struct imx_mhdp_device *hdmi;
1125 +       struct resource *iores = NULL;
1126 +       int ret;
1127 +
1128 +       hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
1129 +       if (!hdmi)
1130 +               return ERR_PTR(-ENOMEM);
1131 +
1132 +       hdmi->plat_data = plat_data;
1133 +       hdmi->mhdp.dev = dev;
1134 +
1135 +       mutex_init(&hdmi->lock);
1136 +       mutex_init(&hdmi->audio_mutex);
1137 +       spin_lock_init(&hdmi->audio_lock);
1138 +
1139 +       INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_work_func);
1140 +
1141 +       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1142 +       hdmi->mhdp.regs = devm_ioremap(dev, iores->start, resource_size(iores));
1143 +       if (IS_ERR(hdmi->mhdp.regs)) {
1144 +               ret = PTR_ERR(hdmi->mhdp.regs);
1145 +               goto err_out;
1146 +       }
1147 +
1148 +       /* csr register base */
1149 +       hdmi->regmap_csr = syscon_regmap_lookup_by_phandle(np, "csr");
1150 +       if (IS_ERR(hdmi->regmap_csr)) {
1151 +               dev_info(dev, "No csr regmap\n");
1152 +       }
1153 +
1154 +       hdmi->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
1155 +       if (hdmi->irq[IRQ_IN] < 0) {
1156 +               dev_info(&pdev->dev, "No plug_in irq number\n");
1157 +               return ERR_PTR(-EPROBE_DEFER);
1158 +       }
1159 +
1160 +       hdmi->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
1161 +       if (hdmi->irq[IRQ_OUT] < 0) {
1162 +               dev_info(&pdev->dev, "No plug_out irq number\n");
1163 +               return ERR_PTR(-EPROBE_DEFER);
1164 +       }
1165 +
1166 +       /* Initialize dual_mode to false */
1167 +       hdmi->dual_mode = false;
1168 +
1169 +       /* Initialize FW */
1170 +       hdp_plat_call(hdmi, fw_init);
1171 +
1172 +       /* HDMI FW alive check */
1173 +       ret = cdns_mhdp_check_alive(&hdmi->mhdp);
1174 +       if (ret == false) {
1175 +               DRM_ERROR("NO HDMI FW running\n");
1176 +               return ERR_PTR(-ENXIO);
1177 +       }
1178 +
1179 +       /* Enable Hotplug Detect thread */
1180 +       irq_set_status_flags(hdmi->irq[IRQ_IN], IRQ_NOAUTOEN);
1181 +       ret = devm_request_threaded_irq(dev, hdmi->irq[IRQ_IN],
1182 +                                       NULL, cdns_hdmi_irq_thread,
1183 +                                       IRQF_ONESHOT, dev_name(dev),
1184 +                                       hdmi);
1185 +       if (ret) {
1186 +               dev_err(&pdev->dev, "can't claim irq %d\n",
1187 +                                               hdmi->irq[IRQ_IN]);
1188 +               goto err_out;
1189 +       }
1190 +       
1191 +       irq_set_status_flags(hdmi->irq[IRQ_OUT], IRQ_NOAUTOEN);
1192 +       ret = devm_request_threaded_irq(dev, hdmi->irq[IRQ_OUT],
1193 +                                       NULL, cdns_hdmi_irq_thread,
1194 +                                       IRQF_ONESHOT, dev_name(dev),
1195 +                                       hdmi);
1196 +       if (ret) {
1197 +               dev_err(&pdev->dev, "can't claim irq %d\n",
1198 +                                               hdmi->irq[IRQ_OUT]);
1199 +               goto err_out;
1200 +       }
1201 +
1202 +       if (cdns_mhdp_read_hpd(&hdmi->mhdp))
1203 +               enable_irq(hdmi->irq[IRQ_OUT]);
1204 +       else
1205 +               enable_irq(hdmi->irq[IRQ_IN]);
1206 +
1207 +       hdmi->mhdp.bridge.base.driver_private = hdmi;
1208 +       hdmi->mhdp.bridge.base.funcs = &cdns_hdmi_bridge_funcs;
1209 +#ifdef CONFIG_OF
1210 +       hdmi->mhdp.bridge.base.of_node = pdev->dev.of_node;
1211 +#endif
1212 +
1213 +       memset(&pdevinfo, 0, sizeof(pdevinfo));
1214 +       pdevinfo.parent = dev;
1215 +       pdevinfo.id = PLATFORM_DEVID_AUTO;
1216 +
1217 +       platform_set_drvdata(pdev, hdmi);
1218 +
1219 +       return hdmi;
1220 +
1221 +err_out:
1222 +
1223 +       return ERR_PTR(ret);
1224 +}
1225 +
1226 +static void __cdns_hdmi_remove(struct imx_mhdp_device *hdmi)
1227 +{
1228 +}
1229 +
1230 +/* -----------------------------------------------------------------------------
1231 + * Probe/remove API, used from platforms based on the DRM bridge API.
1232 + */
1233 +int cdns_hdmi_probe(struct platform_device *pdev,
1234 +                 const struct cdn_plat_data *plat_data)
1235 +{
1236 +       struct imx_mhdp_device *hdmi;
1237 +
1238 +       hdmi = __cdns_hdmi_probe(pdev, plat_data);
1239 +       if (IS_ERR(hdmi))
1240 +               return PTR_ERR(hdmi);
1241 +
1242 +       drm_bridge_add(&hdmi->mhdp.bridge.base);
1243 +
1244 +       return 0;
1245 +}
1246 +EXPORT_SYMBOL_GPL(cdns_hdmi_probe);
1247 +
1248 +void cdns_hdmi_remove(struct platform_device *pdev)
1249 +{
1250 +       struct imx_mhdp_device *hdmi = platform_get_drvdata(pdev);
1251 +
1252 +       drm_bridge_remove(&hdmi->mhdp.bridge.base);
1253 +
1254 +       __cdns_hdmi_remove(hdmi);
1255 +}
1256 +EXPORT_SYMBOL_GPL(cdns_hdmi_remove);
1257 +
1258 +/* -----------------------------------------------------------------------------
1259 + * Bind/unbind API, used from platforms based on the component framework.
1260 + */
1261 +int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
1262 +                const struct cdn_plat_data *plat_data)
1263 +{
1264 +       struct imx_mhdp_device *hdmi;
1265 +       int ret;
1266 +
1267 +       hdmi = __cdns_hdmi_probe(pdev, plat_data);
1268 +       if (IS_ERR(hdmi))
1269 +               return PTR_ERR(hdmi);
1270 +
1271 +       ret = drm_bridge_attach(encoder, &hdmi->mhdp.bridge.base, NULL);
1272 +       if (ret) {
1273 +               cdns_hdmi_remove(pdev);
1274 +               DRM_ERROR("Failed to initialize bridge with drm\n");
1275 +               return ret;
1276 +       }
1277 +
1278 +       return 0;
1279 +}
1280 +EXPORT_SYMBOL_GPL(cdns_hdmi_bind);
1281 +
1282 +void cdns_hdmi_unbind(struct device *dev)
1283 +{
1284 +       struct imx_mhdp_device *hdmi = dev_get_drvdata(dev);
1285 +
1286 +       __cdns_hdmi_remove(hdmi);
1287 +}
1288 +EXPORT_SYMBOL_GPL(cdns_hdmi_unbind);
1289 +
1290 +MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
1291 +MODULE_DESCRIPTION("Cadence HDMI transmitter driver");
1292 +MODULE_LICENSE("GPL");
1293 +MODULE_ALIAS("platform:cdn-hdmi");
1294 --- /dev/null
1295 +++ b/include/drm/bridge/cdns-mhdp-imx.h
1296 @@ -0,0 +1,121 @@
1297 +/*
1298 + * Cadence High-Definition Multimedia Interface (HDMI) driver
1299 + *
1300 + * Copyright (C) 2019 NXP Semiconductor, Inc.
1301 + *
1302 + * This program is free software; you can redistribute it and/or modify
1303 + * it under the terms of the GNU General Public License as published by
1304 + * the Free Software Foundation; either version 2 of the License, or
1305 + * (at your option) any later version.
1306 + *
1307 + */
1308 +#ifndef CDNS_MHDP_IMX_H_
1309 +#define CDNS_MHDP_IMX_H_
1310 +
1311 +#include <drm/bridge/cdns-mhdp-common.h>
1312 +
1313 +#define IRQ_IN    0
1314 +#define IRQ_OUT   1
1315 +#define IRQ_NUM   2
1316 +
1317 +#define hdp_plat_call(hdp, operation)                  \
1318 +       (!(hdp) ? -ENODEV : (((hdp)->plat_data && (hdp)->plat_data->operation) ?        \
1319 +        (hdp)->plat_data->operation(hdp) : ENOIOCTLCMD))
1320 +
1321 +#define HDP_DUAL_MODE_MIN_PCLK_RATE    300000  /* KHz */
1322 +#define HDP_SINGLE_MODE_MAX_WIDTH      1920
1323 +
1324 +static inline bool video_is_dual_mode(const struct drm_display_mode *mode)
1325 +{
1326 +       return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
1327 +               mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
1328 +}
1329 +
1330 +struct imx_mhdp_device;
1331 +
1332 +struct imx_hdp_clks {
1333 +       struct clk *av_pll;
1334 +       struct clk *dig_pll;
1335 +       struct clk *clk_ipg;
1336 +       struct clk *clk_core;
1337 +       struct clk *clk_pxl;
1338 +       struct clk *clk_pxl_mux;
1339 +       struct clk *clk_pxl_link;
1340 +
1341 +       struct clk *lpcg_hdp;
1342 +       struct clk *lpcg_msi;
1343 +       struct clk *lpcg_pxl;
1344 +       struct clk *lpcg_vif;
1345 +       struct clk *lpcg_lis;
1346 +       struct clk *lpcg_apb;
1347 +       struct clk *lpcg_apb_csr;
1348 +       struct clk *lpcg_apb_ctrl;
1349 +
1350 +       struct clk *lpcg_i2s;
1351 +       struct clk *clk_i2s_bypass;
1352 +};
1353 +
1354 +struct cdn_plat_data {
1355 +       /* Vendor PHY support */
1356 +       int (*phy_init)(struct imx_mhdp_device *hdmi);
1357 +       int (*bind)(struct platform_device *pdev,
1358 +                       struct drm_encoder *encoder,
1359 +                       const struct cdn_plat_data *plat_data);
1360 +       void (*unbind)(struct device *dev);
1361 +       int (*fw_init)(struct imx_mhdp_device *hdp);
1362 +       void (*pclock_change)(struct imx_mhdp_device *hdp);
1363 +       char is_dp;
1364 +};
1365 +
1366 +struct imx_mhdp_device {
1367 +       struct cdns_mhdp_device mhdp;
1368 +
1369 +       struct mutex lock;
1370 +       struct mutex audio_mutex;
1371 +       spinlock_t audio_lock;
1372 +       bool connected;
1373 +       bool active;
1374 +       bool suspended;
1375 +       struct imx_hdp_clks clks;
1376 +
1377 +       const struct cdn_plat_data *plat_data;
1378 +
1379 +       int irq[IRQ_NUM];
1380 +       struct delayed_work hotplug_work;
1381 +       //void __iomem *regmap_csr;
1382 +       struct regmap *regmap_csr;
1383 +       u32 csr_pxl_mux_reg;
1384 +       u32 csr_ctrl0_reg;
1385 +       u32 csr_ctrl0_sec;
1386 +
1387 +       struct audio_info audio_info;
1388 +       bool sink_has_audio;
1389 +       u32 dual_mode;
1390 +
1391 +       struct device           *pd_mhdp_dev;
1392 +       struct device           *pd_pll0_dev;
1393 +       struct device           *pd_pll1_dev;
1394 +       struct device_link      *pd_mhdp_link;
1395 +       struct device_link      *pd_pll0_link;
1396 +       struct device_link      *pd_pll1_link;
1397 +
1398 +       u32 phy_init;
1399 +};
1400 +
1401 +int cdns_hdmi_probe(struct platform_device *pdev,
1402 +                 const struct cdn_plat_data *plat_data);
1403 +void cdns_hdmi_remove(struct platform_device *pdev);
1404 +void cdns_hdmi_unbind(struct device *dev);
1405 +int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
1406 +                const struct cdn_plat_data *plat_data);
1407 +void cdns_hdmi_set_sample_rate(struct imx_mhdp_device *hdmi, unsigned int rate);
1408 +void cdns_hdmi_audio_enable(struct imx_mhdp_device *hdmi);
1409 +void cdns_hdmi_audio_disable(struct imx_mhdp_device *hdmi);
1410 +int cdns_dp_probe(struct platform_device *pdev,
1411 +                 const struct cdn_plat_data *plat_data);
1412 +void cdns_dp_remove(struct platform_device *pdev);
1413 +void cdns_dp_unbind(struct device *dev);
1414 +int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
1415 +                const struct cdn_plat_data *plat_data);
1416 +
1417 +#endif /* CDNS_MHDP_IMX_H_ */