aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch
diff options
context:
space:
mode:
authorDaniel Golle <daniel@makrotopia.org>2022-03-21 01:16:48 +0000
committerDaniel Golle <daniel@makrotopia.org>2022-03-21 13:11:56 +0000
commit786bf7fdaca4c75e7eba6e9aa3a8b5775fd21186 (patch)
tree926fecb2b1f6ce1e42ba7ef4c7aab8e68dfd214c /target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch
parent9470160c350d15f765c33d6c1db15d6c4709a64c (diff)
downloadupstream-786bf7fdaca4c75e7eba6e9aa3a8b5775fd21186.tar.gz
upstream-786bf7fdaca4c75e7eba6e9aa3a8b5775fd21186.tar.bz2
upstream-786bf7fdaca4c75e7eba6e9aa3a8b5775fd21186.zip
kernel: delete Linux 5.4 config and patches
As the upcoming release will be based on Linux 5.10 only, remove all kernel configuration as well as patches for Linux 5.4. There were no targets still actively using Linux 5.4. Signed-off-by: Daniel Golle <daniel@makrotopia.org> (cherry picked from commit 3a14580411adfb75f9a44eded9f41245b9e44606)
Diffstat (limited to 'target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch1417
1 files changed, 0 insertions, 1417 deletions
diff --git a/target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch b/target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch
deleted file mode 100644
index 3c0daf7daf..0000000000
--- a/target/linux/layerscape/patches-5.4/805-display-0004-drm-bridge-Add-Cadence-DP-HDMI-core-driver.patch
+++ /dev/null
@@ -1,1417 +0,0 @@
-From 9d6e1670f14a77c092ce32b559de52d7ddea3748 Mon Sep 17 00:00:00 2001
-From: Sandor Yu <Sandor.yu@nxp.com>
-Date: Fri, 23 Aug 2019 13:57:49 +0800
-Subject: [PATCH] drm: bridge: Add Cadence DP/HDMI core driver
-
-Add HDMI and DP core driver.
-
-Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
----
- drivers/gpu/drm/bridge/cadence/Kconfig | 6 +
- drivers/gpu/drm/bridge/cadence/Makefile | 2 +
- drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 605 ++++++++++++++++++++++
- drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 643 ++++++++++++++++++++++++
- include/drm/bridge/cdns-mhdp-imx.h | 121 +++++
- 5 files changed, 1377 insertions(+)
- create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
- create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
- create mode 100644 include/drm/bridge/cdns-mhdp-imx.h
-
---- a/drivers/gpu/drm/bridge/cadence/Kconfig
-+++ b/drivers/gpu/drm/bridge/cadence/Kconfig
-@@ -5,3 +5,9 @@ config DRM_CDNS_MHDP
- depends on OF
- help
- Support Cadence MHDP API library.
-+
-+config DRM_CDNS_HDMI
-+ tristate "Cadence HDMI DRM driver"
-+
-+config DRM_CDNS_DP
-+ tristate "Cadence DP DRM driver"
---- a/drivers/gpu/drm/bridge/cadence/Makefile
-+++ b/drivers/gpu/drm/bridge/cadence/Makefile
-@@ -1,3 +1,5 @@
- #ccflags-y := -Iinclude/drm
-
- obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp-common.o cdns-mhdp-hdmi.o
-+obj-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
-+obj-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
---- /dev/null
-+++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
-@@ -0,0 +1,605 @@
-+/*
-+ * Cadence Display Port Interface (DP) driver
-+ *
-+ * Copyright (C) 2019 NXP Semiconductor, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ */
-+
-+#include <drm/bridge/cdns-mhdp-imx.h>
-+#include <drm/drm_atomic_helper.h>
-+#include <drm/drm_crtc_helper.h>
-+#include <drm/drm_edid.h>
-+#include <drm/drm_encoder_slave.h>
-+#include <drm/drm_of.h>
-+#include <drm/drm_probe_helper.h>
-+#include <drm/drmP.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/irq.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+#include <linux/of_device.h>
-+
-+#define aux_to_hdp(x) container_of(x, struct imx_mhdp_device, aux)
-+
-+/*
-+ * This function only implements native DPDC reads and writes
-+ */
-+static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
-+ struct drm_dp_aux_msg *msg)
-+{
-+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
-+ bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
-+ int ret;
-+
-+ /* Ignore address only message */
-+ if ((msg->size == 0) || (msg->buffer == NULL)) {
-+ msg->reply = native ?
-+ DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
-+ return msg->size;
-+ }
-+
-+ if (!native) {
-+ dev_err(mhdp->dev, "%s: only native messages supported\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ /* msg sanity check */
-+ if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
-+ dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n",
-+ __func__, msg->size, (unsigned int)msg->request);
-+ return -EINVAL;
-+ }
-+
-+ if (msg->request == DP_AUX_NATIVE_WRITE) {
-+ const u8 *buf = msg->buffer;
-+ int i;
-+ for (i = 0; i < msg->size; ++i) {
-+ ret = cdns_mhdp_dpcd_write(mhdp,
-+ msg->address + i, buf[i]);
-+ if (!ret)
-+ continue;
-+
-+ DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n");
-+
-+ return ret;
-+ }
-+ }
-+
-+ if (msg->request == DP_AUX_NATIVE_READ) {
-+ ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size);
-+ if (ret < 0)
-+ return -EIO;
-+ msg->reply = DP_AUX_NATIVE_REPLY_ACK;
-+ return msg->size;
-+ }
-+ return 0;
-+}
-+
-+static int dp_aux_init(struct cdns_mhdp_device *mhdp,
-+ struct device *dev)
-+{
-+ int ret;
-+
-+ mhdp->dp.aux.name = "imx_dp_aux";
-+ mhdp->dp.aux.dev = dev;
-+ mhdp->dp.aux.transfer = dp_aux_transfer;
-+
-+ ret = drm_dp_aux_register(&mhdp->dp.aux);
-+
-+ return ret;
-+}
-+
-+static int dp_aux_destroy(struct cdns_mhdp_device *mhdp)
-+{
-+ drm_dp_aux_unregister(&mhdp->dp.aux);
-+ return 0;
-+}
-+
-+static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp)
-+{
-+ u32 val;
-+
-+ /* reset pixel clk */
-+ val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
-+ cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
-+ cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
-+}
-+
-+static void cdns_dp_mode_set(struct imx_mhdp_device *dp,
-+ const struct drm_display_mode *mode)
-+{
-+ struct drm_dp_link link;
-+ struct cdns_mhdp_device *mhdp = &dp->mhdp;
-+ u32 lane_mapping = mhdp->dp.lane_mapping;
-+ int ret;
-+ char linkid[6];
-+
-+ memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
-+
-+ dp->dual_mode = video_is_dual_mode(mode);
-+
-+ dp_pixel_clk_reset(mhdp);
-+
-+ hdp_plat_call(dp, pclock_change);
-+
-+ hdp_plat_call(dp, phy_init);
-+
-+ ret = drm_dp_downstream_id(&mhdp->dp.aux, linkid);
-+ if (ret < 0) {
-+ DRM_INFO("Failed to Get DP link ID: %d\n", ret);
-+ return;
-+ }
-+ DRM_INFO("DP link id: %s, 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
-+ linkid, linkid[0], linkid[1], linkid[2], linkid[3], linkid[4],
-+ linkid[5]);
-+
-+ /* Check dp link */
-+ ret = drm_dp_link_probe(&mhdp->dp.aux, &link);
-+ if (ret < 0) {
-+ DRM_INFO("Failed to probe DP link: %d\n", ret);
-+ return;
-+ }
-+ DRM_INFO("DP revision: 0x%x\n", link.revision);
-+ DRM_INFO("DP rate: %d Mbps\n", link.rate);
-+ DRM_INFO("DP number of lanes: %d\n", link.num_lanes);
-+ DRM_INFO("DP capabilities: 0x%lx\n", link.capabilities);
-+
-+ drm_dp_link_power_up(&mhdp->dp.aux, &mhdp->dp.link);
-+ if (ret < 0) {
-+ DRM_INFO("Failed to power DP link: %d\n", ret);
-+ return;
-+ }
-+
-+ /* always use the number of lanes from the display*/
-+ mhdp->dp.link.num_lanes = link.num_lanes;
-+
-+ /* Use the lower link rate */
-+ if (mhdp->dp.link_rate != 0) {
-+ mhdp->dp.link.rate = min(mhdp->dp.link_rate, (u32)link.rate);
-+ DRM_DEBUG("DP actual link rate: 0x%x\n", link.rate);
-+ }
-+
-+ /* initialize phy if lanes or link rate differnt */
-+ if (mhdp->dp.link.num_lanes != mhdp->dp.num_lanes ||
-+ mhdp->dp.link.rate != mhdp->dp.link_rate)
-+ hdp_plat_call(dp, phy_init);
-+
-+ /* Video off */
-+ ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
-+ if (ret) {
-+ DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
-+ return;
-+ }
-+
-+ /* Line swaping */
-+ cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping);
-+
-+ /* Set DP host capability */
-+ ret = cdns_mhdp_set_host_cap(mhdp, mhdp->dp.link.num_lanes, false);
-+ if (ret) {
-+ DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
-+ return;
-+ }
-+
-+ ret = cdns_mhdp_config_video(mhdp);
-+ if (ret) {
-+ DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret);
-+ return;
-+ }
-+
-+ /* Link trainning */
-+ ret = cdns_mhdp_train_link(mhdp);
-+ if (ret) {
-+ DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
-+ return;
-+ }
-+
-+ ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
-+ if (ret) {
-+ DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
-+ return;
-+ }
-+
-+ return;
-+}
-+
-+/* -----------------------------------------------------------------------------
-+ * dp TX Setup
-+ */
-+static enum drm_connector_status
-+cdns_dp_connector_detect(struct drm_connector *connector, bool force)
-+{
-+ struct imx_mhdp_device *dp = container_of(connector,
-+ struct imx_mhdp_device, mhdp.connector.base);
-+ u8 hpd = 0xf;
-+
-+ hpd = cdns_mhdp_read_hpd(&dp->mhdp);
-+ if (hpd == 1)
-+ /* Cable Connected */
-+ return connector_status_connected;
-+ else if (hpd == 0)
-+ /* Cable Disconnedted */
-+ return connector_status_disconnected;
-+ else {
-+ /* Cable status unknown */
-+ DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
-+ return connector_status_unknown;
-+ }
-+}
-+
-+static int cdns_dp_connector_get_modes(struct drm_connector *connector)
-+{
-+ struct imx_mhdp_device *dp = container_of(connector,
-+ struct imx_mhdp_device, mhdp.connector.base);
-+ int num_modes = 0;
-+ struct edid *edid;
-+
-+ edid = drm_do_get_edid(&dp->mhdp.connector.base,
-+ cdns_mhdp_get_edid_block, &dp->mhdp);
-+ if (edid) {
-+ dev_info(dp->mhdp.dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
-+ edid->header[0], edid->header[1],
-+ edid->header[2], edid->header[3],
-+ edid->header[4], edid->header[5],
-+ edid->header[6], edid->header[7]);
-+ drm_connector_update_edid_property(connector, edid);
-+ num_modes = drm_add_edid_modes(connector, edid);
-+ kfree(edid);
-+ }
-+
-+ if (num_modes == 0)
-+ DRM_ERROR("Invalid edid\n");
-+ return num_modes;
-+}
-+
-+static const struct drm_connector_funcs cdns_dp_connector_funcs = {
-+ .fill_modes = drm_helper_probe_single_connector_modes,
-+ .detect = cdns_dp_connector_detect,
-+ .destroy = drm_connector_cleanup,
-+ .reset = drm_atomic_helper_connector_reset,
-+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-+};
-+
-+static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = {
-+ .get_modes = cdns_dp_connector_get_modes,
-+};
-+
-+static int cdns_dp_bridge_attach(struct drm_bridge *bridge)
-+{
-+ struct imx_mhdp_device *dp = bridge->driver_private;
-+ struct drm_encoder *encoder = bridge->encoder;
-+ struct drm_connector *connector = &dp->mhdp.connector.base;
-+
-+ connector->interlace_allowed = 1;
-+ connector->polled = DRM_CONNECTOR_POLL_HPD;
-+
-+ drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
-+
-+ drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs,
-+ DRM_MODE_CONNECTOR_DisplayPort);
-+
-+ drm_connector_attach_encoder(connector, encoder);
-+
-+ return 0;
-+}
-+
-+static enum drm_mode_status
-+cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
-+ const struct drm_display_mode *mode)
-+{
-+ enum drm_mode_status mode_status = MODE_OK;
-+
-+ /* We don't support double-clocked modes */
-+ if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
-+ mode->flags & DRM_MODE_FLAG_INTERLACE)
-+ return MODE_BAD;
-+
-+ /* MAX support pixel clock rate 594MHz */
-+ if (mode->clock > 594000)
-+ return MODE_CLOCK_HIGH;
-+
-+ /* 4096x2160 is not supported now */
-+ if (mode->hdisplay > 3840)
-+ return MODE_BAD_HVALUE;
-+
-+ if (mode->vdisplay > 2160)
-+ return MODE_BAD_VVALUE;
-+
-+ return mode_status;
-+}
-+
-+static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
-+ const struct drm_display_mode *orig_mode,
-+ const struct drm_display_mode *mode)
-+{
-+ struct imx_mhdp_device *dp = bridge->driver_private;
-+ struct drm_display_info *display_info = &dp->mhdp.connector.base.display_info;
-+ struct video_info *video = &dp->mhdp.video_info;
-+
-+ switch (display_info->bpc) {
-+ case 10:
-+ video->color_depth = 10;
-+ break;
-+ case 6:
-+ video->color_depth = 6;
-+ break;
-+ default:
-+ video->color_depth = 8;
-+ break;
-+ }
-+
-+ video->color_fmt = PXL_RGB;
-+ video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
-+ video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
-+
-+ DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock);
-+
-+ mutex_lock(&dp->lock);
-+
-+ cdns_dp_mode_set(dp, mode);
-+
-+ mutex_unlock(&dp->lock);
-+}
-+
-+static void cdn_hdp_bridge_enable(struct drm_bridge *bridge)
-+{
-+}
-+
-+static void cdn_hdp_bridge_disable(struct drm_bridge *bridge)
-+{
-+ struct imx_mhdp_device *dp = bridge->driver_private;
-+ struct cdns_mhdp_device *mhdp = &dp->mhdp;
-+
-+ cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
-+ drm_dp_link_power_down(&mhdp->dp.aux, &mhdp->dp.link);
-+}
-+
-+static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
-+ .attach = cdns_dp_bridge_attach,
-+ .enable = cdn_hdp_bridge_enable,
-+ .disable = cdn_hdp_bridge_disable,
-+ .mode_set = cdns_dp_bridge_mode_set,
-+ .mode_valid = cdns_dp_bridge_mode_valid,
-+};
-+
-+static void hotplug_work_func(struct work_struct *work)
-+{
-+ struct imx_mhdp_device *dp = container_of(work,
-+ struct imx_mhdp_device, hotplug_work.work);
-+ struct drm_connector *connector = &dp->mhdp.connector.base;
-+
-+ drm_helper_hpd_irq_event(connector->dev);
-+
-+ if (connector->status == connector_status_connected) {
-+ DRM_INFO("HDMI/DP Cable Plug In\n");
-+ enable_irq(dp->irq[IRQ_OUT]);
-+ } else if (connector->status == connector_status_disconnected) {
-+ /* Cable Disconnedted */
-+ DRM_INFO("HDMI/DP Cable Plug Out\n");
-+ enable_irq(dp->irq[IRQ_IN]);
-+ }
-+}
-+
-+static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
-+{
-+ struct imx_mhdp_device *dp = data;
-+
-+ disable_irq_nosync(irq);
-+
-+ mod_delayed_work(system_wq, &dp->hotplug_work,
-+ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void cdns_dp_parse_dt(struct cdns_mhdp_device *mhdp)
-+{
-+ struct device_node *of_node = mhdp->dev->of_node;
-+ int ret;
-+
-+ ret = of_property_read_u32(of_node, "lane-mapping",
-+ &mhdp->dp.lane_mapping);
-+ if (ret) {
-+ mhdp->dp.lane_mapping = 0xc6;
-+ dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n");
-+ }
-+ dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->dp.lane_mapping);
-+
-+ ret = of_property_read_u32(of_node, "link-rate", &mhdp->dp.link_rate);
-+ if (ret) {
-+ mhdp->dp.link_rate = 162000 ;
-+ dev_warn(mhdp->dev, "Failed to get link-rate, use default 1620MHz\n");
-+ }
-+ dev_info(mhdp->dev, "link-rate %d\n", mhdp->dp.link_rate);
-+
-+ ret = of_property_read_u32(of_node, "num-lanes", &mhdp->dp.num_lanes);
-+ if (ret) {
-+ mhdp->dp.num_lanes = 4;
-+ dev_warn(mhdp->dev, "Failed to get num_lanes - using default\n");
-+ }
-+ dev_info(mhdp->dev, "dp_num_lanes 0x%02x\n", mhdp->dp.num_lanes);
-+
-+ mhdp->dp.link.num_lanes = mhdp->dp.num_lanes;
-+ mhdp->dp.link.rate= mhdp->dp.link_rate;
-+}
-+
-+static struct imx_mhdp_device *
-+__cdns_dp_probe(struct platform_device *pdev,
-+ const struct cdn_plat_data *plat_data)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct imx_mhdp_device *dp;
-+ struct resource *iores = NULL;
-+ int ret;
-+
-+ dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
-+ if (!dp)
-+ return ERR_PTR(-ENOMEM);
-+
-+ dp->plat_data = plat_data;
-+ dp->mhdp.dev = dev;
-+
-+ mutex_init(&dp->lock);
-+ mutex_init(&dp->audio_mutex);
-+ spin_lock_init(&dp->audio_lock);
-+
-+ INIT_DELAYED_WORK(&dp->hotplug_work, hotplug_work_func);
-+
-+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ dp->mhdp.regs = devm_ioremap(dev, iores->start, resource_size(iores));
-+ if (IS_ERR(dp->mhdp.regs)) {
-+ ret = PTR_ERR(dp->mhdp.regs);
-+ goto err_out;
-+ }
-+
-+#if 0
-+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ dp->regs_ss = devm_ioremap(dev, iores->start, resource_size(iores));
-+ if (IS_ERR(dp->regs_ss)) {
-+ ret = PTR_ERR(dp->regs_ss);
-+ goto err_out;
-+ }
-+#endif
-+
-+ dp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
-+ if (dp->irq[IRQ_IN] < 0)
-+ dev_info(&pdev->dev, "No plug_in irq number\n");
-+
-+ dp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
-+ if (dp->irq[IRQ_OUT] < 0)
-+ dev_info(&pdev->dev, "No plug_out irq number\n");
-+
-+ cdns_dp_parse_dt(&dp->mhdp);
-+
-+ dp->dual_mode = false;
-+ hdp_plat_call(dp, fw_init);
-+
-+ /* DP FW alive check */
-+ ret = cdns_mhdp_check_alive(&dp->mhdp);
-+ if (ret == false) {
-+ DRM_ERROR("NO dp FW running\n");
-+ return ERR_PTR(-ENXIO);
-+ }
-+
-+ /* DP PHY init before AUX init */
-+ hdp_plat_call(dp, phy_init);
-+
-+ /* Enable Hotplug Detect IRQ thread */
-+ irq_set_status_flags(dp->irq[IRQ_IN], IRQ_NOAUTOEN);
-+ ret = devm_request_threaded_irq(dev, dp->irq[IRQ_IN],
-+ NULL, cdns_dp_irq_thread,
-+ IRQF_ONESHOT, dev_name(dev),
-+ dp);
-+ if (ret) {
-+ dev_err(&pdev->dev, "can't claim irq %d\n",
-+ dp->irq[IRQ_IN]);
-+ goto err_out;
-+ }
-+
-+ irq_set_status_flags(dp->irq[IRQ_OUT], IRQ_NOAUTOEN);
-+ ret = devm_request_threaded_irq(dev, dp->irq[IRQ_OUT],
-+ NULL, cdns_dp_irq_thread,
-+ IRQF_ONESHOT, dev_name(dev),
-+ dp);
-+ if (ret) {
-+ dev_err(&pdev->dev, "can't claim irq %d\n",
-+ dp->irq[IRQ_OUT]);
-+ goto err_out;
-+ }
-+ if (cdns_mhdp_read_hpd(&dp->mhdp))
-+ enable_irq(dp->irq[IRQ_OUT]);
-+ else
-+ enable_irq(dp->irq[IRQ_IN]);
-+
-+ dp->mhdp.bridge.base.driver_private = dp;
-+ dp->mhdp.bridge.base.funcs = &cdns_dp_bridge_funcs;
-+#ifdef CONFIG_OF
-+ dp->mhdp.bridge.base.of_node = pdev->dev.of_node;
-+#endif
-+
-+ platform_set_drvdata(pdev, dp);
-+
-+ dp_aux_init(&dp->mhdp, dev);
-+
-+ return dp;
-+
-+err_out:
-+ return ERR_PTR(ret);
-+}
-+
-+static void __cdns_dp_remove(struct imx_mhdp_device *dp)
-+{
-+ dp_aux_destroy(&dp->mhdp);
-+}
-+
-+/* -----------------------------------------------------------------------------
-+ * Probe/remove API, used from platforms based on the DRM bridge API.
-+ */
-+int cdns_dp_probe(struct platform_device *pdev,
-+ const struct cdn_plat_data *plat_data)
-+{
-+ struct imx_mhdp_device *dp;
-+
-+ dp = __cdns_dp_probe(pdev, plat_data);
-+ if (IS_ERR(dp))
-+ return PTR_ERR(dp);
-+
-+ drm_bridge_add(&dp->mhdp.bridge.base);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(cdns_dp_probe);
-+
-+void cdns_dp_remove(struct platform_device *pdev)
-+{
-+ struct imx_mhdp_device *dp = platform_get_drvdata(pdev);
-+
-+ drm_bridge_remove(&dp->mhdp.bridge.base);
-+
-+ __cdns_dp_remove(dp);
-+}
-+EXPORT_SYMBOL_GPL(cdns_dp_remove);
-+
-+/* -----------------------------------------------------------------------------
-+ * Bind/unbind API, used from platforms based on the component framework.
-+ */
-+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-+ const struct cdn_plat_data *plat_data)
-+{
-+ struct imx_mhdp_device *dp;
-+ int ret;
-+
-+ dp = __cdns_dp_probe(pdev, plat_data);
-+ if (IS_ERR(dp))
-+ return PTR_ERR(dp);
-+
-+ ret = drm_bridge_attach(encoder, &dp->mhdp.bridge.base, NULL);
-+ if (ret) {
-+ cdns_dp_remove(pdev);
-+ DRM_ERROR("Failed to initialize bridge with drm\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(cdns_dp_bind);
-+
-+void cdns_dp_unbind(struct device *dev)
-+{
-+ struct imx_mhdp_device *dp = dev_get_drvdata(dev);
-+
-+ __cdns_dp_remove(dp);
-+}
-+EXPORT_SYMBOL_GPL(cdns_dp_unbind);
-+
-+MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
-+MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:cdn-dp");
---- /dev/null
-+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
-@@ -0,0 +1,643 @@
-+/*
-+ * Cadence High-Definition Multimedia Interface (HDMI) driver
-+ *
-+ * Copyright (C) 2019 NXP Semiconductor, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ */
-+
-+#include <drm/bridge/cdns-mhdp-imx.h>
-+#include <drm/drm_atomic_helper.h>
-+#include <drm/drm_crtc_helper.h>
-+#include <drm/drm_edid.h>
-+#include <drm/drm_encoder_slave.h>
-+#include <drm/drm_of.h>
-+#include <drm/drm_probe_helper.h>
-+#include <drm/drmP.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/hdmi.h>
-+#include <linux/irq.h>
-+#include <linux/module.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/mutex.h>
-+#include <linux/regmap.h>
-+#include <linux/of_device.h>
-+
-+static void hdmi_writel(struct cdns_mhdp_device *mhdp, u32 val, u32 offset)
-+{
-+ struct imx_mhdp_device *hdmi = container_of(mhdp, struct imx_mhdp_device, mhdp);
-+
-+ /* TODO */
-+ if (offset >= 0x1000 && hdmi->regmap_csr) {
-+ /* Remap address to low 4K memory */
-+ regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, offset >> 12);
-+ writel(val, (offset & 0xfff) + mhdp->regs);
-+ /* Restore address mapping */
-+ regmap_write(hdmi->regmap_csr, hdmi->csr_ctrl0_reg, 0);
-+
-+ } else
-+ writel(val, mhdp->regs + offset);
-+}
-+
-+static int hdmi_sink_config(struct cdns_mhdp_device *mhdp)
-+{
-+ struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
-+ u8 buff;
-+ int ret;
-+
-+ if (mhdp->hdmi.char_rate > 340000) {
-+ /*
-+ * TMDS Character Rate above 340MHz should working in HDMI2.0
-+ * Enable scrambling and TMDS_Bit_Clock_Ratio
-+ */
-+ buff = 3;
-+ mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
-+ } else if (scdc->scrambling.low_rates) {
-+ /*
-+ * Enable scrambling and HDMI2.0 when scrambling capability of sink
-+ * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
-+ */
-+ buff = 1;
-+ mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
-+ } else {
-+ /* Default work in HDMI1.4 */
-+ buff = 0;
-+ mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
-+ }
-+
-+ /* TMDS config */
-+ ret = cdns_hdmi_scdc_write(mhdp, 0x20, buff);
-+ return ret;
-+}
-+
-+static int hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
-+{
-+ int ret;
-+
-+ /* TODO */
-+ /* Set the lane swapping */
-+// if (cpu_is_imx8qm())
-+ ret = cdns_mhdp_reg_write(mhdp, LANES_CONFIG,
-+ F_SOURCE_PHY_LANE0_SWAP(3) |
-+ F_SOURCE_PHY_LANE1_SWAP(0) |
-+ F_SOURCE_PHY_LANE2_SWAP(1) |
-+ F_SOURCE_PHY_LANE3_SWAP(2) |
-+ F_SOURCE_PHY_COMB_BYPASS(0) |
-+ F_SOURCE_PHY_20_10(1));
-+#if 0
-+ else
-+ ret = cdns_mhdp_reg_write(mhdp, LANES_CONFIG,
-+ F_SOURCE_PHY_LANE0_SWAP(0) |
-+ F_SOURCE_PHY_LANE1_SWAP(1) |
-+ F_SOURCE_PHY_LANE2_SWAP(2) |
-+ F_SOURCE_PHY_LANE3_SWAP(3) |
-+ F_SOURCE_PHY_COMB_BYPASS(0) |
-+ F_SOURCE_PHY_20_10(1));
-+#endif
-+ return ret;
-+}
-+
-+static void hdmi_info_frame_set(struct cdns_mhdp_device *mhdp,
-+ u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type)
-+{
-+ u32 *packet32, len32;
-+ u32 val, i;
-+
-+ /* invalidate entry */
-+ val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id);
-+ hdmi_writel(mhdp, val, SOURCE_PIF_PKT_ALLOC_REG);
-+ hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
-+
-+ /* flush fifo 1 */
-+ hdmi_writel(mhdp, F_FIFO1_FLUSH(1), SOURCE_PIF_FIFO1_FLUSH);
-+
-+ /* write packet into memory */
-+ packet32 = (u32 *)packet;
-+ len32 = packet_len / 4;
-+ for (i = 0; i < len32; i++)
-+ hdmi_writel(mhdp, F_DATA_WR(packet32[i]), SOURCE_PIF_DATA_WR);
-+
-+ /* write entry id */
-+ hdmi_writel(mhdp, F_WR_ADDR(entry_id), SOURCE_PIF_WR_ADDR);
-+
-+ /* write request */
-+ hdmi_writel(mhdp, F_HOST_WR(1), SOURCE_PIF_WR_REQ);
-+
-+ /* update entry */
-+ val = F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) |
-+ F_PACKET_TYPE(packet_type) | F_PKT_ALLOC_ADDRESS(entry_id);
-+ hdmi_writel(mhdp, val, SOURCE_PIF_PKT_ALLOC_REG);
-+
-+ hdmi_writel(mhdp, F_PKT_ALLOC_WR_EN(1), SOURCE_PIF_PKT_ALLOC_WR_EN);
-+}
-+
-+#define RGB_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
-+ BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
-+#define YCC_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
-+ BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM) |\
-+ BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601) |\
-+ BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601) |\
-+ BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709) |\
-+ BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
-+static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp,
-+ struct drm_display_mode *mode)
-+{
-+ struct hdmi_avi_infoframe frame;
-+// struct drm_display_info *di = &mhdp->connector.base.display_info;
-+// enum hdmi_extended_colorimetry ext_col;
-+// u32 sink_col, allowed_col;
-+ int format = mhdp->video_info.color_fmt;
-+ u8 buf[32];
-+ int ret;
-+
-+ /* Initialise info frame from DRM mode */
-+ drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
-+
-+#if 0 //TODO to DCSS
-+ /* Set up colorimetry */
-+ allowed_col = format == PXL_RGB ? RGB_ALLOWED_COLORIMETRY :
-+ YCC_ALLOWED_COLORIMETRY;
-+
-+ sink_col = di->hdmi.colorimetry & allowed_col;
-+
-+ if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020))
-+ ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020;
-+ else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM))
-+ ext_col = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM;
-+ else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPRGB))
-+ ext_col = HDMI_EXTENDED_COLORIMETRY_OPRGB;
-+ else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709))
-+ ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
-+ else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_OPYCC_601))
-+ ext_col = HDMI_EXTENDED_COLORIMETRY_OPYCC_601;
-+ else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601))
-+ ext_col = HDMI_EXTENDED_COLORIMETRY_S_YCC_601;
-+ else if (sink_col & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
-+ ext_col = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
-+ else
-+ ext_col = 0;
-+
-+ frame.colorimetry = sink_col ? HDMI_COLORIMETRY_EXTENDED :
-+ HDMI_COLORIMETRY_NONE;
-+ frame.extended_colorimetry = ext_col;
-+#endif
-+
-+ switch (format) {
-+ case YCBCR_4_4_4:
-+ frame.colorspace = HDMI_COLORSPACE_YUV444;
-+ break;
-+ case YCBCR_4_2_2:
-+ frame.colorspace = HDMI_COLORSPACE_YUV422;
-+ break;
-+ case YCBCR_4_2_0:
-+ frame.colorspace = HDMI_COLORSPACE_YUV420;
-+ break;
-+ default:
-+ frame.colorspace = HDMI_COLORSPACE_RGB;
-+ break;
-+ }
-+
-+ ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
-+ if (ret < 0) {
-+ DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
-+ return -1;
-+ }
-+
-+ buf[0] = 0;
-+ hdmi_info_frame_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI);
-+ return 0;
-+}
-+
-+static int hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
-+ struct drm_display_mode *mode)
-+{
-+ struct hdmi_vendor_infoframe frame;
-+ u8 buf[32];
-+ int ret;
-+
-+ /* Initialise vendor frame from DRM mode */
-+ ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
-+ if (ret < 0) {
-+ DRM_WARN("Unable to init vendor infoframe: %d\n", ret);
-+ return -1;
-+ }
-+
-+ ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
-+ if (ret < 0) {
-+ DRM_WARN("Unable to pack vendor infoframe: %d\n", ret);
-+ return -1;
-+ }
-+
-+ buf[0] = 0;
-+ hdmi_info_frame_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
-+ return 0;
-+}
-+
-+void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp)
-+{
-+ struct drm_display_mode *mode = &mhdp->mode;
-+ int ret;
-+
-+ ret = hdmi_sink_config(mhdp);
-+ if (ret < 0) {
-+ DRM_ERROR("%s failed\n", __func__);
-+ return;
-+ }
-+
-+ ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate);
-+ if (ret < 0) {
-+ DRM_ERROR("%s, ret = %d\n", __func__, ret);
-+ return;
-+ }
-+
-+ /* Config GCP */
-+ if (mhdp->video_info.color_depth == 8)
-+ cdns_hdmi_disable_gcp(mhdp);
-+ else
-+ cdns_hdmi_enable_gcp(mhdp);
-+
-+ ret = hdmi_avi_info_set(mhdp, mode);
-+ if (ret < 0) {
-+ DRM_ERROR("%s ret = %d\n", __func__, ret);
-+ return;
-+ }
-+
-+ /* vendor info frame is enable only when HDMI1.4 4K mode */
-+ ret = hdmi_vendor_info_set(mhdp, mode);
-+ if (ret < 0)
-+ DRM_WARN("Unable to configure Vendor infoframe\n");
-+
-+ ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
-+ if (ret < 0) {
-+ DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
-+ return;
-+ }
-+
-+ /* wait HDMI PHY pixel clock stable */
-+ msleep(50);
-+}
-+
-+static enum drm_connector_status
-+cdns_hdmi_connector_detect(struct drm_connector *connector, bool force)
-+{
-+ struct imx_mhdp_device *hdmi =
-+ container_of(connector, struct imx_mhdp_device, mhdp.connector.base);
-+
-+ u8 hpd = 0xf;
-+
-+ hpd = cdns_mhdp_read_hpd(&hdmi->mhdp);
-+
-+ if (hpd == 1)
-+ /* Cable Connected */
-+ return connector_status_connected;
-+ else if (hpd == 0)
-+ /* Cable Disconnedted */
-+ return connector_status_disconnected;
-+ else {
-+ /* Cable status unknown */
-+ DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
-+ return connector_status_unknown;
-+ }
-+}
-+
-+static int cdns_hdmi_connector_get_modes(struct drm_connector *connector)
-+{
-+ struct imx_mhdp_device *hdmi = container_of(connector, struct imx_mhdp_device,
-+ mhdp.connector.base);
-+ int num_modes = 0;
-+ struct edid *edid;
-+
-+ edid = drm_do_get_edid(&hdmi->mhdp.connector.base,
-+ cdns_hdmi_get_edid_block, &hdmi->mhdp);
-+ if (edid) {
-+ dev_info(hdmi->mhdp.dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
-+ edid->header[0], edid->header[1],
-+ edid->header[2], edid->header[3],
-+ edid->header[4], edid->header[5],
-+ edid->header[6], edid->header[7]);
-+ drm_connector_update_edid_property(connector, edid);
-+ num_modes = drm_add_edid_modes(connector, edid);
-+ kfree(edid);
-+ }
-+
-+ if (num_modes == 0)
-+ DRM_ERROR("Invalid edid\n");
-+ return num_modes;
-+}
-+
-+static const struct drm_connector_funcs cdns_hdmi_connector_funcs = {
-+ .fill_modes = drm_helper_probe_single_connector_modes,
-+ .detect = cdns_hdmi_connector_detect,
-+ .destroy = drm_connector_cleanup,
-+ .reset = drm_atomic_helper_connector_reset,
-+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-+};
-+
-+static const struct drm_connector_helper_funcs cdns_hdmi_connector_helper_funcs = {
-+ .get_modes = cdns_hdmi_connector_get_modes,
-+};
-+
-+static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge)
-+{
-+ struct imx_mhdp_device *hdmi = bridge->driver_private;
-+ struct drm_encoder *encoder = bridge->encoder;
-+ struct drm_connector *connector = &hdmi->mhdp.connector.base;
-+
-+ connector->interlace_allowed = 1;
-+ connector->polled = DRM_CONNECTOR_POLL_HPD;
-+
-+ drm_connector_helper_add(connector, &cdns_hdmi_connector_helper_funcs);
-+
-+ drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs,
-+ DRM_MODE_CONNECTOR_HDMIA);
-+
-+ drm_connector_attach_encoder(connector, encoder);
-+
-+ return 0;
-+}
-+
-+static enum drm_mode_status
-+cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
-+ const struct drm_display_mode *mode)
-+{
-+ enum drm_mode_status mode_status = MODE_OK;
-+
-+ /* We don't support double-clocked and Interlaced modes */
-+ if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
-+ mode->flags & DRM_MODE_FLAG_INTERLACE)
-+ return MODE_BAD;
-+
-+ /* MAX support pixel clock rate 148.5MHz */
-+ if (mode->clock > 148500)
-+ return MODE_CLOCK_HIGH;
-+
-+ /* 4096x2160 is not supported */
-+ if (mode->hdisplay > 3840 || mode->vdisplay > 2160)
-+ return MODE_BAD_HVALUE;
-+
-+ return mode_status;
-+}
-+
-+static void cdns_hdmi_bridge_mode_set(struct drm_bridge *bridge,
-+ const struct drm_display_mode *orig_mode,
-+ const struct drm_display_mode *mode)
-+{
-+ struct imx_mhdp_device *hdmi = bridge->driver_private;
-+ struct drm_display_info *display_info = &hdmi->mhdp.connector.base.display_info;
-+ struct video_info *video = &hdmi->mhdp.video_info;
-+
-+ switch (display_info->bpc) {
-+ case 10:
-+ video->color_depth = 10;
-+ break;
-+ case 6:
-+ video->color_depth = 6;
-+ break;
-+ default:
-+ video->color_depth = 8;
-+ break;
-+ }
-+
-+ video->color_fmt = PXL_RGB;
-+ video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
-+ video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
-+
-+ mutex_lock(&hdmi->lock);
-+
-+ DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock);
-+
-+ memcpy(&hdmi->mhdp.mode, mode, sizeof(struct drm_display_mode));
-+
-+ hdmi->dual_mode = video_is_dual_mode(mode);
-+
-+ hdmi_lanes_config(&hdmi->mhdp);
-+
-+ hdp_plat_call(hdmi, pclock_change);
-+
-+ hdp_plat_call(hdmi, phy_init);
-+
-+ cdns_hdmi_mode_set(&hdmi->mhdp);
-+
-+ mutex_unlock(&hdmi->lock);
-+}
-+
-+static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = {
-+ .attach = cdns_hdmi_bridge_attach,
-+ .mode_set = cdns_hdmi_bridge_mode_set,
-+ .mode_valid = cdns_hdmi_bridge_mode_valid,
-+};
-+
-+static void hotplug_work_func(struct work_struct *work)
-+{
-+ struct imx_mhdp_device *hdmi = container_of(work,
-+ struct imx_mhdp_device, hotplug_work.work);
-+ struct drm_connector *connector = &hdmi->mhdp.connector.base;
-+
-+ drm_helper_hpd_irq_event(connector->dev);
-+
-+ if (connector->status == connector_status_connected) {
-+ /* Cable Connected */
-+ DRM_INFO("HDMI Cable Plug In\n");
-+ enable_irq(hdmi->irq[IRQ_OUT]);
-+ } else if (connector->status == connector_status_disconnected) {
-+ /* Cable Disconnedted */
-+ DRM_INFO("HDMI Cable Plug Out\n");
-+ enable_irq(hdmi->irq[IRQ_IN]);
-+ }
-+}
-+
-+static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data)
-+{
-+ struct imx_mhdp_device *hdmi = data;
-+
-+ disable_irq_nosync(irq);
-+
-+ mod_delayed_work(system_wq, &hdmi->hotplug_work,
-+ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static struct imx_mhdp_device *
-+__cdns_hdmi_probe(struct platform_device *pdev,
-+ const struct cdn_plat_data *plat_data)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct device_node *np = dev->of_node;
-+ struct platform_device_info pdevinfo;
-+ struct imx_mhdp_device *hdmi;
-+ struct resource *iores = NULL;
-+ int ret;
-+
-+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
-+ if (!hdmi)
-+ return ERR_PTR(-ENOMEM);
-+
-+ hdmi->plat_data = plat_data;
-+ hdmi->mhdp.dev = dev;
-+
-+ mutex_init(&hdmi->lock);
-+ mutex_init(&hdmi->audio_mutex);
-+ spin_lock_init(&hdmi->audio_lock);
-+
-+ INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_work_func);
-+
-+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ hdmi->mhdp.regs = devm_ioremap(dev, iores->start, resource_size(iores));
-+ if (IS_ERR(hdmi->mhdp.regs)) {
-+ ret = PTR_ERR(hdmi->mhdp.regs);
-+ goto err_out;
-+ }
-+
-+ /* csr register base */
-+ hdmi->regmap_csr = syscon_regmap_lookup_by_phandle(np, "csr");
-+ if (IS_ERR(hdmi->regmap_csr)) {
-+ dev_info(dev, "No csr regmap\n");
-+ }
-+
-+ hdmi->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
-+ if (hdmi->irq[IRQ_IN] < 0) {
-+ dev_info(&pdev->dev, "No plug_in irq number\n");
-+ return ERR_PTR(-EPROBE_DEFER);
-+ }
-+
-+ hdmi->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
-+ if (hdmi->irq[IRQ_OUT] < 0) {
-+ dev_info(&pdev->dev, "No plug_out irq number\n");
-+ return ERR_PTR(-EPROBE_DEFER);
-+ }
-+
-+ /* Initialize dual_mode to false */
-+ hdmi->dual_mode = false;
-+
-+ /* Initialize FW */
-+ hdp_plat_call(hdmi, fw_init);
-+
-+ /* HDMI FW alive check */
-+ ret = cdns_mhdp_check_alive(&hdmi->mhdp);
-+ if (ret == false) {
-+ DRM_ERROR("NO HDMI FW running\n");
-+ return ERR_PTR(-ENXIO);
-+ }
-+
-+ /* Enable Hotplug Detect thread */
-+ irq_set_status_flags(hdmi->irq[IRQ_IN], IRQ_NOAUTOEN);
-+ ret = devm_request_threaded_irq(dev, hdmi->irq[IRQ_IN],
-+ NULL, cdns_hdmi_irq_thread,
-+ IRQF_ONESHOT, dev_name(dev),
-+ hdmi);
-+ if (ret) {
-+ dev_err(&pdev->dev, "can't claim irq %d\n",
-+ hdmi->irq[IRQ_IN]);
-+ goto err_out;
-+ }
-+
-+ irq_set_status_flags(hdmi->irq[IRQ_OUT], IRQ_NOAUTOEN);
-+ ret = devm_request_threaded_irq(dev, hdmi->irq[IRQ_OUT],
-+ NULL, cdns_hdmi_irq_thread,
-+ IRQF_ONESHOT, dev_name(dev),
-+ hdmi);
-+ if (ret) {
-+ dev_err(&pdev->dev, "can't claim irq %d\n",
-+ hdmi->irq[IRQ_OUT]);
-+ goto err_out;
-+ }
-+
-+ if (cdns_mhdp_read_hpd(&hdmi->mhdp))
-+ enable_irq(hdmi->irq[IRQ_OUT]);
-+ else
-+ enable_irq(hdmi->irq[IRQ_IN]);
-+
-+ hdmi->mhdp.bridge.base.driver_private = hdmi;
-+ hdmi->mhdp.bridge.base.funcs = &cdns_hdmi_bridge_funcs;
-+#ifdef CONFIG_OF
-+ hdmi->mhdp.bridge.base.of_node = pdev->dev.of_node;
-+#endif
-+
-+ memset(&pdevinfo, 0, sizeof(pdevinfo));
-+ pdevinfo.parent = dev;
-+ pdevinfo.id = PLATFORM_DEVID_AUTO;
-+
-+ platform_set_drvdata(pdev, hdmi);
-+
-+ return hdmi;
-+
-+err_out:
-+
-+ return ERR_PTR(ret);
-+}
-+
-+static void __cdns_hdmi_remove(struct imx_mhdp_device *hdmi)
-+{
-+}
-+
-+/* -----------------------------------------------------------------------------
-+ * Probe/remove API, used from platforms based on the DRM bridge API.
-+ */
-+int cdns_hdmi_probe(struct platform_device *pdev,
-+ const struct cdn_plat_data *plat_data)
-+{
-+ struct imx_mhdp_device *hdmi;
-+
-+ hdmi = __cdns_hdmi_probe(pdev, plat_data);
-+ if (IS_ERR(hdmi))
-+ return PTR_ERR(hdmi);
-+
-+ drm_bridge_add(&hdmi->mhdp.bridge.base);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(cdns_hdmi_probe);
-+
-+void cdns_hdmi_remove(struct platform_device *pdev)
-+{
-+ struct imx_mhdp_device *hdmi = platform_get_drvdata(pdev);
-+
-+ drm_bridge_remove(&hdmi->mhdp.bridge.base);
-+
-+ __cdns_hdmi_remove(hdmi);
-+}
-+EXPORT_SYMBOL_GPL(cdns_hdmi_remove);
-+
-+/* -----------------------------------------------------------------------------
-+ * Bind/unbind API, used from platforms based on the component framework.
-+ */
-+int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-+ const struct cdn_plat_data *plat_data)
-+{
-+ struct imx_mhdp_device *hdmi;
-+ int ret;
-+
-+ hdmi = __cdns_hdmi_probe(pdev, plat_data);
-+ if (IS_ERR(hdmi))
-+ return PTR_ERR(hdmi);
-+
-+ ret = drm_bridge_attach(encoder, &hdmi->mhdp.bridge.base, NULL);
-+ if (ret) {
-+ cdns_hdmi_remove(pdev);
-+ DRM_ERROR("Failed to initialize bridge with drm\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(cdns_hdmi_bind);
-+
-+void cdns_hdmi_unbind(struct device *dev)
-+{
-+ struct imx_mhdp_device *hdmi = dev_get_drvdata(dev);
-+
-+ __cdns_hdmi_remove(hdmi);
-+}
-+EXPORT_SYMBOL_GPL(cdns_hdmi_unbind);
-+
-+MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
-+MODULE_DESCRIPTION("Cadence HDMI transmitter driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:cdn-hdmi");
---- /dev/null
-+++ b/include/drm/bridge/cdns-mhdp-imx.h
-@@ -0,0 +1,121 @@
-+/*
-+ * Cadence High-Definition Multimedia Interface (HDMI) driver
-+ *
-+ * Copyright (C) 2019 NXP Semiconductor, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ */
-+#ifndef CDNS_MHDP_IMX_H_
-+#define CDNS_MHDP_IMX_H_
-+
-+#include <drm/bridge/cdns-mhdp-common.h>
-+
-+#define IRQ_IN 0
-+#define IRQ_OUT 1
-+#define IRQ_NUM 2
-+
-+#define hdp_plat_call(hdp, operation) \
-+ (!(hdp) ? -ENODEV : (((hdp)->plat_data && (hdp)->plat_data->operation) ? \
-+ (hdp)->plat_data->operation(hdp) : ENOIOCTLCMD))
-+
-+#define HDP_DUAL_MODE_MIN_PCLK_RATE 300000 /* KHz */
-+#define HDP_SINGLE_MODE_MAX_WIDTH 1920
-+
-+static inline bool video_is_dual_mode(const struct drm_display_mode *mode)
-+{
-+ return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE ||
-+ mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false;
-+}
-+
-+struct imx_mhdp_device;
-+
-+struct imx_hdp_clks {
-+ struct clk *av_pll;
-+ struct clk *dig_pll;
-+ struct clk *clk_ipg;
-+ struct clk *clk_core;
-+ struct clk *clk_pxl;
-+ struct clk *clk_pxl_mux;
-+ struct clk *clk_pxl_link;
-+
-+ struct clk *lpcg_hdp;
-+ struct clk *lpcg_msi;
-+ struct clk *lpcg_pxl;
-+ struct clk *lpcg_vif;
-+ struct clk *lpcg_lis;
-+ struct clk *lpcg_apb;
-+ struct clk *lpcg_apb_csr;
-+ struct clk *lpcg_apb_ctrl;
-+
-+ struct clk *lpcg_i2s;
-+ struct clk *clk_i2s_bypass;
-+};
-+
-+struct cdn_plat_data {
-+ /* Vendor PHY support */
-+ int (*phy_init)(struct imx_mhdp_device *hdmi);
-+ int (*bind)(struct platform_device *pdev,
-+ struct drm_encoder *encoder,
-+ const struct cdn_plat_data *plat_data);
-+ void (*unbind)(struct device *dev);
-+ int (*fw_init)(struct imx_mhdp_device *hdp);
-+ void (*pclock_change)(struct imx_mhdp_device *hdp);
-+ char is_dp;
-+};
-+
-+struct imx_mhdp_device {
-+ struct cdns_mhdp_device mhdp;
-+
-+ struct mutex lock;
-+ struct mutex audio_mutex;
-+ spinlock_t audio_lock;
-+ bool connected;
-+ bool active;
-+ bool suspended;
-+ struct imx_hdp_clks clks;
-+
-+ const struct cdn_plat_data *plat_data;
-+
-+ int irq[IRQ_NUM];
-+ struct delayed_work hotplug_work;
-+ //void __iomem *regmap_csr;
-+ struct regmap *regmap_csr;
-+ u32 csr_pxl_mux_reg;
-+ u32 csr_ctrl0_reg;
-+ u32 csr_ctrl0_sec;
-+
-+ struct audio_info audio_info;
-+ bool sink_has_audio;
-+ u32 dual_mode;
-+
-+ struct device *pd_mhdp_dev;
-+ struct device *pd_pll0_dev;
-+ struct device *pd_pll1_dev;
-+ struct device_link *pd_mhdp_link;
-+ struct device_link *pd_pll0_link;
-+ struct device_link *pd_pll1_link;
-+
-+ u32 phy_init;
-+};
-+
-+int cdns_hdmi_probe(struct platform_device *pdev,
-+ const struct cdn_plat_data *plat_data);
-+void cdns_hdmi_remove(struct platform_device *pdev);
-+void cdns_hdmi_unbind(struct device *dev);
-+int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-+ const struct cdn_plat_data *plat_data);
-+void cdns_hdmi_set_sample_rate(struct imx_mhdp_device *hdmi, unsigned int rate);
-+void cdns_hdmi_audio_enable(struct imx_mhdp_device *hdmi);
-+void cdns_hdmi_audio_disable(struct imx_mhdp_device *hdmi);
-+int cdns_dp_probe(struct platform_device *pdev,
-+ const struct cdn_plat_data *plat_data);
-+void cdns_dp_remove(struct platform_device *pdev);
-+void cdns_dp_unbind(struct device *dev);
-+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-+ const struct cdn_plat_data *plat_data);
-+
-+#endif /* CDNS_MHDP_IMX_H_ */