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
6 Add HDMI and DP core driver.
8 Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
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
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
25 Support Cadence MHDP API library.
28 + tristate "Cadence HDMI DRM driver"
31 + tristate "Cadence DP DRM driver"
32 --- a/drivers/gpu/drm/bridge/cadence/Makefile
33 +++ b/drivers/gpu/drm/bridge/cadence/Makefile
35 #ccflags-y := -Iinclude/drm
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
41 +++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
44 + * Cadence Display Port Interface (DP) driver
46 + * Copyright (C) 2019 NXP Semiconductor, Inc.
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.
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>
70 +#define aux_to_hdp(x) container_of(x, struct imx_mhdp_device, aux)
73 + * This function only implements native DPDC reads and writes
75 +static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
76 + struct drm_dp_aux_msg *msg)
78 + struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
79 + bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
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;
90 + dev_err(mhdp->dev, "%s: only native messages supported\n", __func__);
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);
101 + if (msg->request == DP_AUX_NATIVE_WRITE) {
102 + const u8 *buf = msg->buffer;
104 + for (i = 0; i < msg->size; ++i) {
105 + ret = cdns_mhdp_dpcd_write(mhdp,
106 + msg->address + i, buf[i]);
110 + DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n");
116 + if (msg->request == DP_AUX_NATIVE_READ) {
117 + ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size);
120 + msg->reply = DP_AUX_NATIVE_REPLY_ACK;
126 +static int dp_aux_init(struct cdns_mhdp_device *mhdp,
127 + struct device *dev)
131 + mhdp->dp.aux.name = "imx_dp_aux";
132 + mhdp->dp.aux.dev = dev;
133 + mhdp->dp.aux.transfer = dp_aux_transfer;
135 + ret = drm_dp_aux_register(&mhdp->dp.aux);
140 +static int dp_aux_destroy(struct cdns_mhdp_device *mhdp)
142 + drm_dp_aux_unregister(&mhdp->dp.aux);
146 +static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp)
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);
156 +static void cdns_dp_mode_set(struct imx_mhdp_device *dp,
157 + const struct drm_display_mode *mode)
159 + struct drm_dp_link link;
160 + struct cdns_mhdp_device *mhdp = &dp->mhdp;
161 + u32 lane_mapping = mhdp->dp.lane_mapping;
165 + memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
167 + dp->dual_mode = video_is_dual_mode(mode);
169 + dp_pixel_clk_reset(mhdp);
171 + hdp_plat_call(dp, pclock_change);
173 + hdp_plat_call(dp, phy_init);
175 + ret = drm_dp_downstream_id(&mhdp->dp.aux, linkid);
177 + DRM_INFO("Failed to Get DP link ID: %d\n", ret);
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],
184 + /* Check dp link */
185 + ret = drm_dp_link_probe(&mhdp->dp.aux, &link);
187 + DRM_INFO("Failed to probe DP link: %d\n", ret);
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);
195 + drm_dp_link_power_up(&mhdp->dp.aux, &mhdp->dp.link);
197 + DRM_INFO("Failed to power DP link: %d\n", ret);
201 + /* always use the number of lanes from the display*/
202 + mhdp->dp.link.num_lanes = link.num_lanes;
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);
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);
216 + ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
218 + DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
223 + cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping);
225 + /* Set DP host capability */
226 + ret = cdns_mhdp_set_host_cap(mhdp, mhdp->dp.link.num_lanes, false);
228 + DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
232 + ret = cdns_mhdp_config_video(mhdp);
234 + DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret);
238 + /* Link trainning */
239 + ret = cdns_mhdp_train_link(mhdp);
241 + DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
245 + ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
247 + DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
254 +/* -----------------------------------------------------------------------------
257 +static enum drm_connector_status
258 +cdns_dp_connector_detect(struct drm_connector *connector, bool force)
260 + struct imx_mhdp_device *dp = container_of(connector,
261 + struct imx_mhdp_device, mhdp.connector.base);
264 + hpd = cdns_mhdp_read_hpd(&dp->mhdp);
266 + /* Cable Connected */
267 + return connector_status_connected;
269 + /* Cable Disconnedted */
270 + return connector_status_disconnected;
272 + /* Cable status unknown */
273 + DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
274 + return connector_status_unknown;
278 +static int cdns_dp_connector_get_modes(struct drm_connector *connector)
280 + struct imx_mhdp_device *dp = container_of(connector,
281 + struct imx_mhdp_device, mhdp.connector.base);
285 + edid = drm_do_get_edid(&dp->mhdp.connector.base,
286 + cdns_mhdp_get_edid_block, &dp->mhdp);
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);
298 + if (num_modes == 0)
299 + DRM_ERROR("Invalid edid\n");
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,
312 +static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = {
313 + .get_modes = cdns_dp_connector_get_modes,
316 +static int cdns_dp_bridge_attach(struct drm_bridge *bridge)
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;
322 + connector->interlace_allowed = 1;
323 + connector->polled = DRM_CONNECTOR_POLL_HPD;
325 + drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
327 + drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs,
328 + DRM_MODE_CONNECTOR_DisplayPort);
330 + drm_connector_attach_encoder(connector, encoder);
335 +static enum drm_mode_status
336 +cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
337 + const struct drm_display_mode *mode)
339 + enum drm_mode_status mode_status = MODE_OK;
341 + /* We don't support double-clocked modes */
342 + if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
343 + mode->flags & DRM_MODE_FLAG_INTERLACE)
346 + /* MAX support pixel clock rate 594MHz */
347 + if (mode->clock > 594000)
348 + return MODE_CLOCK_HIGH;
350 + /* 4096x2160 is not supported now */
351 + if (mode->hdisplay > 3840)
352 + return MODE_BAD_HVALUE;
354 + if (mode->vdisplay > 2160)
355 + return MODE_BAD_VVALUE;
357 + return mode_status;
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)
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;
368 + switch (display_info->bpc) {
370 + video->color_depth = 10;
373 + video->color_depth = 6;
376 + video->color_depth = 8;
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);
384 + DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock);
386 + mutex_lock(&dp->lock);
388 + cdns_dp_mode_set(dp, mode);
390 + mutex_unlock(&dp->lock);
393 +static void cdn_hdp_bridge_enable(struct drm_bridge *bridge)
397 +static void cdn_hdp_bridge_disable(struct drm_bridge *bridge)
399 + struct imx_mhdp_device *dp = bridge->driver_private;
400 + struct cdns_mhdp_device *mhdp = &dp->mhdp;
402 + cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
403 + drm_dp_link_power_down(&mhdp->dp.aux, &mhdp->dp.link);
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,
414 +static void hotplug_work_func(struct work_struct *work)
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;
420 + drm_helper_hpd_irq_event(connector->dev);
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]);
432 +static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
434 + struct imx_mhdp_device *dp = data;
436 + disable_irq_nosync(irq);
438 + mod_delayed_work(system_wq, &dp->hotplug_work,
439 + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
441 + return IRQ_HANDLED;
444 +static void cdns_dp_parse_dt(struct cdns_mhdp_device *mhdp)
446 + struct device_node *of_node = mhdp->dev->of_node;
449 + ret = of_property_read_u32(of_node, "lane-mapping",
450 + &mhdp->dp.lane_mapping);
452 + mhdp->dp.lane_mapping = 0xc6;
453 + dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
455 + dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->dp.lane_mapping);
457 + ret = of_property_read_u32(of_node, "link-rate", &mhdp->dp.link_rate);
459 + mhdp->dp.link_rate = 162000 ;
460 + dev_warn(mhdp->dev, "Failed to get link-rate, use default 1620MHz\n");
462 + dev_info(mhdp->dev, "link-rate %d\n", mhdp->dp.link_rate);
464 + ret = of_property_read_u32(of_node, "num-lanes", &mhdp->dp.num_lanes);
466 + mhdp->dp.num_lanes = 4;
467 + dev_warn(mhdp->dev, "Failed to get num_lanes - using default\n");
469 + dev_info(mhdp->dev, "dp_num_lanes 0x%02x\n", mhdp->dp.num_lanes);
471 + mhdp->dp.link.num_lanes = mhdp->dp.num_lanes;
472 + mhdp->dp.link.rate= mhdp->dp.link_rate;
475 +static struct imx_mhdp_device *
476 +__cdns_dp_probe(struct platform_device *pdev,
477 + const struct cdn_plat_data *plat_data)
479 + struct device *dev = &pdev->dev;
480 + struct imx_mhdp_device *dp;
481 + struct resource *iores = NULL;
484 + dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
486 + return ERR_PTR(-ENOMEM);
488 + dp->plat_data = plat_data;
489 + dp->mhdp.dev = dev;
491 + mutex_init(&dp->lock);
492 + mutex_init(&dp->audio_mutex);
493 + spin_lock_init(&dp->audio_lock);
495 + INIT_DELAYED_WORK(&dp->hotplug_work, hotplug_work_func);
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);
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);
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");
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");
521 + cdns_dp_parse_dt(&dp->mhdp);
523 + dp->dual_mode = false;
524 + hdp_plat_call(dp, fw_init);
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);
533 + /* DP PHY init before AUX init */
534 + hdp_plat_call(dp, phy_init);
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),
543 + dev_err(&pdev->dev, "can't claim irq %d\n",
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),
554 + dev_err(&pdev->dev, "can't claim irq %d\n",
558 + if (cdns_mhdp_read_hpd(&dp->mhdp))
559 + enable_irq(dp->irq[IRQ_OUT]);
561 + enable_irq(dp->irq[IRQ_IN]);
563 + dp->mhdp.bridge.base.driver_private = dp;
564 + dp->mhdp.bridge.base.funcs = &cdns_dp_bridge_funcs;
566 + dp->mhdp.bridge.base.of_node = pdev->dev.of_node;
569 + platform_set_drvdata(pdev, dp);
571 + dp_aux_init(&dp->mhdp, dev);
576 + return ERR_PTR(ret);
579 +static void __cdns_dp_remove(struct imx_mhdp_device *dp)
581 + dp_aux_destroy(&dp->mhdp);
584 +/* -----------------------------------------------------------------------------
585 + * Probe/remove API, used from platforms based on the DRM bridge API.
587 +int cdns_dp_probe(struct platform_device *pdev,
588 + const struct cdn_plat_data *plat_data)
590 + struct imx_mhdp_device *dp;
592 + dp = __cdns_dp_probe(pdev, plat_data);
594 + return PTR_ERR(dp);
596 + drm_bridge_add(&dp->mhdp.bridge.base);
600 +EXPORT_SYMBOL_GPL(cdns_dp_probe);
602 +void cdns_dp_remove(struct platform_device *pdev)
604 + struct imx_mhdp_device *dp = platform_get_drvdata(pdev);
606 + drm_bridge_remove(&dp->mhdp.bridge.base);
608 + __cdns_dp_remove(dp);
610 +EXPORT_SYMBOL_GPL(cdns_dp_remove);
612 +/* -----------------------------------------------------------------------------
613 + * Bind/unbind API, used from platforms based on the component framework.
615 +int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
616 + const struct cdn_plat_data *plat_data)
618 + struct imx_mhdp_device *dp;
621 + dp = __cdns_dp_probe(pdev, plat_data);
623 + return PTR_ERR(dp);
625 + ret = drm_bridge_attach(encoder, &dp->mhdp.bridge.base, NULL);
627 + cdns_dp_remove(pdev);
628 + DRM_ERROR("Failed to initialize bridge with drm\n");
634 +EXPORT_SYMBOL_GPL(cdns_dp_bind);
636 +void cdns_dp_unbind(struct device *dev)
638 + struct imx_mhdp_device *dp = dev_get_drvdata(dev);
640 + __cdns_dp_remove(dp);
642 +EXPORT_SYMBOL_GPL(cdns_dp_unbind);
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");
649 +++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
652 + * Cadence High-Definition Multimedia Interface (HDMI) driver
654 + * Copyright (C) 2019 NXP Semiconductor, Inc.
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.
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>
681 +static void hdmi_writel(struct cdns_mhdp_device *mhdp, u32 val, u32 offset)
683 + struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
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);
694 + writel(val, mhdp->regs + offset);
697 +static int hdmi_sink_config(struct cdns_mhdp_device *mhdp)
699 + struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
703 + if (mhdp->hdmi.char_rate > 340000) {
705 + * TMDS Character Rate above 340MHz should working in HDMI2.0
706 + * Enable scrambling and TMDS_Bit_Clock_Ratio
709 + mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
710 + } else if (scdc->scrambling.low_rates) {
712 + * Enable scrambling and HDMI2.0 when scrambling capability of sink
713 + * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
716 + mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
718 + /* Default work in HDMI1.4 */
720 + mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
724 + ret = cdns_hdmi_scdc_write(mhdp, 0x20, buff);
728 +static int hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
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));
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));
755 +static void hdmi_info_frame_set(struct cdns_mhdp_device *mhdp,
756 + u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type)
758 + u32 *packet32, len32;
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);
767 + hdmi_writel(mhdp, F_FIFO1_FLUSH(1), SOURCE_PIF_FIFO1_FLUSH);
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);
775 + /* write entry id */
776 + hdmi_writel(mhdp, F_WR_ADDR(entry_id), SOURCE_PIF_WR_ADDR);
778 + /* write request */
779 + hdmi_writel(mhdp, F_HOST_WR(1), SOURCE_PIF_WR_REQ);
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);
786 + hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
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)
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;
808 + /* Initialise info frame from DRM mode */
809 + drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
811 +#if 0 //TODO to DCSS
812 + /* Set up colorimetry */
813 + allowed_col = format == PXL_RGB ? RGB_ALLOWED_COLORIMETRY :
814 + YCC_ALLOWED_COLORIMETRY;
816 + sink_col = di->hdmi.colorimetry & allowed_col;
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;
835 + frame.colorimetry = sink_col ? HDMI_COLORIMETRY_EXTENDED :
836 + HDMI_COLORIMETRY_NONE;
837 + frame.extended_colorimetry = ext_col;
842 + frame.colorspace = HDMI_COLORSPACE_YUV444;
845 + frame.colorspace = HDMI_COLORSPACE_YUV422;
848 + frame.colorspace = HDMI_COLORSPACE_YUV420;
851 + frame.colorspace = HDMI_COLORSPACE_RGB;
855 + ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
857 + DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
862 + hdmi_info_frame_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI);
866 +static int hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
867 + struct drm_display_mode *mode)
869 + struct hdmi_vendor_infoframe frame;
873 + /* Initialise vendor frame from DRM mode */
874 + ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
876 + DRM_WARN("Unable to init vendor infoframe: %d\n", ret);
880 + ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
882 + DRM_WARN("Unable to pack vendor infoframe: %d\n", ret);
887 + hdmi_info_frame_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
891 +void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp)
893 + struct drm_display_mode *mode = &mhdp->mode;
896 + ret = hdmi_sink_config(mhdp);
898 + DRM_ERROR("%s failed\n", __func__);
902 + ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate);
904 + DRM_ERROR("%s, ret = %d\n", __func__, ret);
909 + if (mhdp->video_info.color_depth == 8)
910 + cdns_hdmi_disable_gcp(mhdp);
912 + cdns_hdmi_enable_gcp(mhdp);
914 + ret = hdmi_avi_info_set(mhdp, mode);
916 + DRM_ERROR("%s ret = %d\n", __func__, ret);
920 + /* vendor info frame is enable only when HDMI1.4 4K mode */
921 + ret = hdmi_vendor_info_set(mhdp, mode);
923 + DRM_WARN("Unable to configure Vendor infoframe\n");
925 + ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
927 + DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
931 + /* wait HDMI PHY pixel clock stable */
935 +static enum drm_connector_status
936 +cdns_hdmi_connector_detect(struct drm_connector *connector, bool force)
938 + struct imx_mhdp_device *hdmi =
939 + container_of(connector, struct imx_mhdp_device, mhdp.connector.base);
943 + hpd = cdns_mhdp_read_hpd(&hdmi->mhdp);
946 + /* Cable Connected */
947 + return connector_status_connected;
949 + /* Cable Disconnedted */
950 + return connector_status_disconnected;
952 + /* Cable status unknown */
953 + DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
954 + return connector_status_unknown;
958 +static int cdns_hdmi_connector_get_modes(struct drm_connector *connector)
960 + struct imx_mhdp_device *hdmi = container_of(connector, struct imx_mhdp_device,
961 + mhdp.connector.base);
965 + edid = drm_do_get_edid(&hdmi->mhdp.connector.base,
966 + cdns_hdmi_get_edid_block, &hdmi->mhdp);
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);
978 + if (num_modes == 0)
979 + DRM_ERROR("Invalid edid\n");
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,
992 +static const struct drm_connector_helper_funcs cdns_hdmi_connector_helper_funcs = {
993 + .get_modes = cdns_hdmi_connector_get_modes,
996 +static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge)
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;
1002 + connector->interlace_allowed = 1;
1003 + connector->polled = DRM_CONNECTOR_POLL_HPD;
1005 + drm_connector_helper_add(connector, &cdns_hdmi_connector_helper_funcs);
1007 + drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs,
1008 + DRM_MODE_CONNECTOR_HDMIA);
1010 + drm_connector_attach_encoder(connector, encoder);
1015 +static enum drm_mode_status
1016 +cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
1017 + const struct drm_display_mode *mode)
1019 + enum drm_mode_status mode_status = MODE_OK;
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)
1026 + /* MAX support pixel clock rate 148.5MHz */
1027 + if (mode->clock > 148500)
1028 + return MODE_CLOCK_HIGH;
1030 + /* 4096x2160 is not supported */
1031 + if (mode->hdisplay > 3840 || mode->vdisplay > 2160)
1032 + return MODE_BAD_HVALUE;
1034 + return mode_status;
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)
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;
1045 + switch (display_info->bpc) {
1047 + video->color_depth = 10;
1050 + video->color_depth = 6;
1053 + video->color_depth = 8;
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);
1061 + mutex_lock(&hdmi->lock);
1063 + DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock);
1065 + memcpy(&hdmi->mhdp.mode, mode, sizeof(struct drm_display_mode));
1067 + hdmi->dual_mode = video_is_dual_mode(mode);
1069 + hdmi_lanes_config(&hdmi->mhdp);
1071 + hdp_plat_call(hdmi, pclock_change);
1073 + hdp_plat_call(hdmi, phy_init);
1075 + cdns_hdmi_mode_set(&hdmi->mhdp);
1077 + mutex_unlock(&hdmi->lock);
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,
1086 +static void hotplug_work_func(struct work_struct *work)
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;
1092 + drm_helper_hpd_irq_event(connector->dev);
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]);
1105 +static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data)
1107 + struct imx_mhdp_device *hdmi = data;
1109 + disable_irq_nosync(irq);
1111 + mod_delayed_work(system_wq, &hdmi->hotplug_work,
1112 + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
1114 + return IRQ_HANDLED;
1117 +static struct imx_mhdp_device *
1118 +__cdns_hdmi_probe(struct platform_device *pdev,
1119 + const struct cdn_plat_data *plat_data)
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;
1128 + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
1130 + return ERR_PTR(-ENOMEM);
1132 + hdmi->plat_data = plat_data;
1133 + hdmi->mhdp.dev = dev;
1135 + mutex_init(&hdmi->lock);
1136 + mutex_init(&hdmi->audio_mutex);
1137 + spin_lock_init(&hdmi->audio_lock);
1139 + INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_work_func);
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);
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");
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);
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);
1166 + /* Initialize dual_mode to false */
1167 + hdmi->dual_mode = false;
1169 + /* Initialize FW */
1170 + hdp_plat_call(hdmi, fw_init);
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);
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),
1186 + dev_err(&pdev->dev, "can't claim irq %d\n",
1187 + hdmi->irq[IRQ_IN]);
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),
1197 + dev_err(&pdev->dev, "can't claim irq %d\n",
1198 + hdmi->irq[IRQ_OUT]);
1202 + if (cdns_mhdp_read_hpd(&hdmi->mhdp))
1203 + enable_irq(hdmi->irq[IRQ_OUT]);
1205 + enable_irq(hdmi->irq[IRQ_IN]);
1207 + hdmi->mhdp.bridge.base.driver_private = hdmi;
1208 + hdmi->mhdp.bridge.base.funcs = &cdns_hdmi_bridge_funcs;
1210 + hdmi->mhdp.bridge.base.of_node = pdev->dev.of_node;
1213 + memset(&pdevinfo, 0, sizeof(pdevinfo));
1214 + pdevinfo.parent = dev;
1215 + pdevinfo.id = PLATFORM_DEVID_AUTO;
1217 + platform_set_drvdata(pdev, hdmi);
1223 + return ERR_PTR(ret);
1226 +static void __cdns_hdmi_remove(struct imx_mhdp_device *hdmi)
1230 +/* -----------------------------------------------------------------------------
1231 + * Probe/remove API, used from platforms based on the DRM bridge API.
1233 +int cdns_hdmi_probe(struct platform_device *pdev,
1234 + const struct cdn_plat_data *plat_data)
1236 + struct imx_mhdp_device *hdmi;
1238 + hdmi = __cdns_hdmi_probe(pdev, plat_data);
1240 + return PTR_ERR(hdmi);
1242 + drm_bridge_add(&hdmi->mhdp.bridge.base);
1246 +EXPORT_SYMBOL_GPL(cdns_hdmi_probe);
1248 +void cdns_hdmi_remove(struct platform_device *pdev)
1250 + struct imx_mhdp_device *hdmi = platform_get_drvdata(pdev);
1252 + drm_bridge_remove(&hdmi->mhdp.bridge.base);
1254 + __cdns_hdmi_remove(hdmi);
1256 +EXPORT_SYMBOL_GPL(cdns_hdmi_remove);
1258 +/* -----------------------------------------------------------------------------
1259 + * Bind/unbind API, used from platforms based on the component framework.
1261 +int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
1262 + const struct cdn_plat_data *plat_data)
1264 + struct imx_mhdp_device *hdmi;
1267 + hdmi = __cdns_hdmi_probe(pdev, plat_data);
1269 + return PTR_ERR(hdmi);
1271 + ret = drm_bridge_attach(encoder, &hdmi->mhdp.bridge.base, NULL);
1273 + cdns_hdmi_remove(pdev);
1274 + DRM_ERROR("Failed to initialize bridge with drm\n");
1280 +EXPORT_SYMBOL_GPL(cdns_hdmi_bind);
1282 +void cdns_hdmi_unbind(struct device *dev)
1284 + struct imx_mhdp_device *hdmi = dev_get_drvdata(dev);
1286 + __cdns_hdmi_remove(hdmi);
1288 +EXPORT_SYMBOL_GPL(cdns_hdmi_unbind);
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");
1295 +++ b/include/drm/bridge/cdns-mhdp-imx.h
1298 + * Cadence High-Definition Multimedia Interface (HDMI) driver
1300 + * Copyright (C) 2019 NXP Semiconductor, Inc.
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.
1308 +#ifndef CDNS_MHDP_IMX_H_
1309 +#define CDNS_MHDP_IMX_H_
1311 +#include <drm/bridge/cdns-mhdp-common.h>
1317 +#define hdp_plat_call(hdp, operation) \
1318 + (!(hdp) ? -ENODEV : (((hdp)->plat_data && (hdp)->plat_data->operation) ? \
1319 + (hdp)->plat_data->operation(hdp) : ENOIOCTLCMD))
1321 +#define HDP_DUAL_MODE_MIN_PCLK_RATE 300000 /* KHz */
1322 +#define HDP_SINGLE_MODE_MAX_WIDTH 1920
1324 +static inline bool video_is_dual_mode(const struct drm_display_mode *mode)
1326 + return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
1327 + mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
1330 +struct imx_mhdp_device;
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;
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;
1350 + struct clk *lpcg_i2s;
1351 + struct clk *clk_i2s_bypass;
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);
1366 +struct imx_mhdp_device {
1367 + struct cdns_mhdp_device mhdp;
1369 + struct mutex lock;
1370 + struct mutex audio_mutex;
1371 + spinlock_t audio_lock;
1375 + struct imx_hdp_clks clks;
1377 + const struct cdn_plat_data *plat_data;
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;
1387 + struct audio_info audio_info;
1388 + bool sink_has_audio;
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;
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);
1417 +#endif /* CDNS_MHDP_IMX_H_ */