diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch | 474 |
1 files changed, 0 insertions, 474 deletions
diff --git a/target/linux/layerscape/patches-5.4/805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch b/target/linux/layerscape/patches-5.4/805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch deleted file mode 100644 index 742928e71a..0000000000 --- a/target/linux/layerscape/patches-5.4/805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch +++ /dev/null @@ -1,474 +0,0 @@ -From ed9e7a6b3346b186a7bd22d9b62072e55ff7b9c5 Mon Sep 17 00:00:00 2001 -From: Sandor Yu <Sandor.yu@nxp.com> -Date: Mon, 2 Sep 2019 14:57:05 +0800 -Subject: [PATCH] drm: bridge: cadence: Add CEC driver for cdns mhdp hdmi - -Add cec driver for cdns mhdp hdmi. - -Signed-off-by: Sandor Yu <Sandor.yu@nxp.com> ---- - drivers/gpu/drm/bridge/cadence/Kconfig | 3 + - drivers/gpu/drm/bridge/cadence/Makefile | 1 + - drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 0 - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 9 + - drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c | 347 ++++++++++++++++++++++ - drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 0 - drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c | 0 - include/drm/bridge/cdns-mhdp-common.h | 24 +- - 8 files changed, 382 insertions(+), 2 deletions(-) - mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c - mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c - mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c - mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c - ---- a/drivers/gpu/drm/bridge/cadence/Kconfig -+++ b/drivers/gpu/drm/bridge/cadence/Kconfig -@@ -14,3 +14,6 @@ config DRM_CDNS_DP - - config DRM_CDNS_AUDIO - tristate "Cadence MHDP Audio driver" -+ -+config DRM_CDNS_HDMI_CEC -+ tristate "Cadence MHDP HDMI CEC driver" ---- a/drivers/gpu/drm/bridge/cadence/Makefile -+++ b/drivers/gpu/drm/bridge/cadence/Makefile -@@ -2,3 +2,4 @@ obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp - obj-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o - obj-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o - obj-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o -+obj-$(CONFIG_DRM_CDNS_HDMI_CEC) += cdns-mhdp-cec.o ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -515,6 +515,11 @@ __cdns_hdmi_probe(struct platform_device - /* register audio driver */ - cdns_mhdp_register_audio_driver(dev); - -+ /* register cec driver */ -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+ cdns_mhdp_register_cec_driver(dev); -+#endif -+ - return hdmi; - - err_out: -@@ -524,6 +529,10 @@ err_out: - - static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp) - { -+ /* unregister cec driver */ -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+ cdns_mhdp_unregister_cec_driver(mhdp->dev); -+#endif - cdns_mhdp_unregister_audio_driver(mhdp->dev); - } - ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -@@ -0,0 +1,347 @@ -+/* -+ * Copyright 2019 NXP -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+#include <linux/module.h> -+#include <linux/workqueue.h> -+#include <linux/kthread.h> -+#include <linux/freezer.h> -+#include <drm/bridge/cdns-mhdp-common.h> -+ -+#define CEC_NAME "cdns-mhdp-cec" -+ -+#define REG_ADDR_OFF 4 -+#define MAX_LA_IDX 4 -+#define MAX_LA_VAL 15 -+ -+/* regsiter define */ -+#define TX_MSG_HEADER 0x33800 -+#define TX_MSG_LENGTH 0x33840 -+#define TX_MSG_CMD 0x33844 -+#define RX_MSG_CMD 0x33850 -+#define RX_CLEAR_BUF 0x33854 -+#define LOGICAL_ADDRESS_LA0 0x33858 -+ -+#define CLK_DIV_MSB 0x3386c -+#define CLK_DIV_LSB 0x33870 -+#define RX_MSG_DATA1 0x33900 -+#define RX_MSG_LENGTH 0x33940 -+#define RX_MSG_STATUS 0x33944 -+#define NUM_OF_MSG_RX_BUF 0x33948 -+#define TX_MSG_STATUS 0x3394c -+#define DB_L_TIMER 0x33980 -+ -+/** -+ * CEC Transceiver operation. -+ */ -+enum { -+ CEC_TX_STOP, -+ CEC_TX_TRANSMIT, -+ CEC_TX_ABORT, -+ CEC_TX_ABORT_AND_TRANSMIT -+}; -+ -+/** -+ * CEC Transceiver status. -+ */ -+enum { -+ CEC_STS_IDLE, -+ CEC_STS_BUSY, -+ CEC_STS_SUCCESS, -+ CEC_STS_ERROR -+}; -+ -+/** -+ * CEC Receiver operation. -+ */ -+enum { -+ CEC_RX_STOP, -+ CEC_RX_READ, -+ CEC_RX_DISABLE, -+ CEC_RX_ABORT_AND_CLR_FIFO -+}; -+/** -+ * Maximum number of Messages in the RX Buffers. -+ */ -+#define CEC_MAX_RX_MSGS 2 -+ -+static u32 mhdp_cec_read(struct cdns_mhdp_cec *cec, u32 offset) -+{ -+ struct cdns_mhdp_device *mhdp = -+ container_of(cec, struct cdns_mhdp_device, hdmi.cec); -+ return cdns_mhdp_bus_read(mhdp, offset); -+} -+ -+static void mhdp_cec_write(struct cdns_mhdp_cec *cec, u32 offset, u32 val) -+{ -+ struct cdns_mhdp_device *mhdp = -+ container_of(cec, struct cdns_mhdp_device, hdmi.cec); -+ cdns_mhdp_bus_write(val, mhdp, offset); -+} -+ -+static void mhdp_cec_clear_rx_buffer(struct cdns_mhdp_cec *cec) -+{ -+ mhdp_cec_write(cec, RX_CLEAR_BUF, 1); -+ mhdp_cec_write(cec, RX_CLEAR_BUF, 0); -+} -+ -+static void mhdp_cec_set_divider(struct cdns_mhdp_cec *cec) -+{ -+ struct cdns_mhdp_device *mhdp = -+ container_of(cec, struct cdns_mhdp_device, hdmi.cec); -+ u32 clk_div; -+ -+ /* Set clock divider */ -+ clk_div = cdns_mhdp_get_fw_clk(mhdp) * 10; -+ -+ mhdp_cec_write(cec, CLK_DIV_MSB, -+ (clk_div >> 8) & 0xFF); -+ mhdp_cec_write(cec, CLK_DIV_LSB, clk_div & 0xFF); -+} -+ -+static u32 mhdp_cec_read_message(struct cdns_mhdp_cec *cec) -+{ -+ struct cec_msg *msg = &cec->msg; -+ int len; -+ int i; -+ -+ mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_READ); -+ -+ len = mhdp_cec_read(cec, RX_MSG_LENGTH); -+ msg->len = len + 1; -+ dev_dbg(cec->dev, "RX MSG len =%d\n", len); -+ -+ /* Read RX MSG bytes */ -+ for (i = 0; i < msg->len; ++i) { -+ msg->msg[i] = (u8) mhdp_cec_read(cec, RX_MSG_DATA1 + (i * REG_ADDR_OFF)); -+ dev_dbg(cec->dev, "RX MSG[%d]=0x%x\n", i, msg->msg[i]); -+ } -+ -+ mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_STOP); -+ -+ return true; -+} -+ -+static u32 mhdp_cec_write_message(struct cdns_mhdp_cec *cec, struct cec_msg *msg) -+{ -+ u8 i; -+ -+ mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP); -+ -+ if (msg->len > CEC_MAX_MSG_SIZE) { -+ dev_err(cec->dev, "Invalid MSG size!\n"); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < msg->len; ++i) -+ printk("msg[%d]=0x%x\n",i, msg->msg[i]); -+ -+ /* Write Message to register */ -+ for (i = 0; i < msg->len; ++i) { -+ mhdp_cec_write(cec, TX_MSG_HEADER + (i * REG_ADDR_OFF), -+ msg->msg[i]); -+ } -+ /* Write Message Length (payload + opcode) */ -+ mhdp_cec_write(cec, TX_MSG_LENGTH, msg->len - 1); -+ -+ mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_TRANSMIT); -+ -+ return true; -+} -+ -+//static void cec_abort_tx_transfer(struct cdns_mhdp_cec *cec) -+//{ -+// cec_write(cec, TX_MSG_CMD, CEC_TX_ABORT); -+// cec_write(cec, TX_MSG_CMD, CEC_TX_STOP); -+//} -+ -+static int mhdp_cec_set_logical_addr(struct cdns_mhdp_cec *cec, u32 la) -+{ -+ u8 i; -+ u8 la_reg; -+ -+ if (la >= MAX_LA_VAL) { -+ dev_err(cec->dev, "Error logical Addr\n"); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < MAX_LA_IDX; ++i) { -+ la_reg = -+ mhdp_cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF)); -+ -+ if (la_reg & 0x10) -+ continue; -+ -+ if ((la_reg & 0xF) == la) { -+ dev_warn(cec->dev, "Warning. LA already in use.\n"); -+ return true; -+ } -+ -+ la = (la & 0xF) | (1 << 4); -+ -+ mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la); -+ return true; -+ } -+ -+ dev_warn(cec->dev, "All LA in use\n"); -+ -+ return false; -+} -+ -+static int mhdp_cec_poll_worker(void *_cec) -+{ -+ struct cdns_mhdp_cec *cec = (struct cdns_mhdp_cec *)_cec; -+ int num_rx_msgs, i; -+ int sts; -+ -+ set_freezable(); -+ -+ for (;;) { -+ if (kthread_freezable_should_stop(NULL)) -+ break; -+ -+ /* Check TX State */ -+ sts = mhdp_cec_read(cec, TX_MSG_STATUS); -+ switch (sts) { -+ case CEC_STS_SUCCESS: -+ cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, -+ 0); -+ mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP); -+ break; -+ case CEC_STS_ERROR: -+ mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP); -+ cec_transmit_done(cec->adap, -+ CEC_TX_STATUS_MAX_RETRIES | -+ CEC_TX_STATUS_NACK, 0, 1, 0, 0); -+ break; -+ case CEC_STS_BUSY: -+ default: -+ break; -+ } -+ -+ /* Check RX State */ -+ sts = mhdp_cec_read(cec, RX_MSG_STATUS); -+ num_rx_msgs = mhdp_cec_read(cec, NUM_OF_MSG_RX_BUF); -+ switch (sts) { -+ case CEC_STS_SUCCESS: -+ if (num_rx_msgs == 0xf) -+ num_rx_msgs = CEC_MAX_RX_MSGS; -+ -+ if (num_rx_msgs > CEC_MAX_RX_MSGS) { -+ dev_err(cec->dev, "Error rx msg num %d\n", -+ num_rx_msgs); -+ mhdp_cec_clear_rx_buffer(cec); -+ break; -+ } -+ -+ /* Rx FIFO Depth 2 RX MSG */ -+ for (i = 0; i < num_rx_msgs; i++) { -+ mhdp_cec_read_message(cec); -+ cec->msg.rx_status = CEC_RX_STATUS_OK; -+ cec_received_msg(cec->adap, &cec->msg); -+ } -+ break; -+ default: -+ break; -+ } -+ -+ if (!kthread_should_stop()) -+ schedule_timeout_idle(20); -+ } -+ -+ return 0; -+} -+ -+static int mhdp_cec_adap_enable(struct cec_adapter *adap, bool enable) -+{ -+ struct cdns_mhdp_cec *cec = adap->priv; -+ -+ if (enable) { -+ mhdp_cec_write(cec, DB_L_TIMER, 0x10); -+ mhdp_cec_set_divider(cec); -+ } else -+ mhdp_cec_set_divider(cec); -+ -+ return 0; -+} -+ -+static int mhdp_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) -+{ -+ struct cdns_mhdp_cec *cec = adap->priv; -+ -+ return mhdp_cec_set_logical_addr(cec, addr); -+} -+ -+static int mhdp_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, -+ u32 signal_free_time, struct cec_msg *msg) -+{ -+ struct cdns_mhdp_cec *cec = adap->priv; -+ -+ mhdp_cec_write_message(cec, msg); -+ -+ return 0; -+} -+ -+static const struct cec_adap_ops cdns_mhdp_cec_adap_ops = { -+ .adap_enable = mhdp_cec_adap_enable, -+ .adap_log_addr = mhdp_cec_adap_log_addr, -+ .adap_transmit = mhdp_cec_adap_transmit, -+}; -+ -+int cdns_mhdp_register_cec_driver(struct device *dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec; -+ int ret; -+ -+ cec->adap = cec_allocate_adapter(&cdns_mhdp_cec_adap_ops, cec, -+ CEC_NAME, -+ CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS | -+ CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH -+ | CEC_CAP_RC, 1); -+ ret = PTR_ERR_OR_ZERO(cec->adap); -+ if (ret) -+ return ret; -+ ret = cec_register_adapter(cec->adap, dev); -+ if (ret) { -+ cec_delete_adapter(cec->adap); -+ return ret; -+ } -+ -+ cec->dev = dev; -+ -+ cec->cec_worker = kthread_create(mhdp_cec_poll_worker, cec, "cdns-mhdp-cec"); -+ if (IS_ERR(cec->cec_worker)) -+ dev_err(cec->dev, "failed create hdp cec thread\n"); -+ -+ wake_up_process(cec->cec_worker); -+ -+ dev_dbg(dev, "CEC successfuly probed\n"); -+ return 0; -+} -+ -+int cdns_mhdp_unregister_cec_driver(struct device *dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec; -+ -+ if (cec->cec_worker) { -+ kthread_stop(cec->cec_worker); -+ cec->cec_worker = NULL; -+ } -+ cec_unregister_adapter(cec->adap); -+ return 0; -+} -+ -+MODULE_AUTHOR("Sandor.Yu@NXP.com"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("NXP CDNS MHDP CEC driver"); ---- a/include/drm/bridge/cdns-mhdp-common.h -+++ b/include/drm/bridge/cdns-mhdp-common.h -@@ -21,7 +21,7 @@ - #include <drm/drm_connector.h> - #include <drm/drm_dp_helper.h> - #include <drm/drm_dp_mst_helper.h> -- -+#include <media/cec.h> - #include <linux/bitops.h> - - #define ADDR_IMEM 0x10000 -@@ -605,6 +605,17 @@ struct cdns_mhdp_connector { - struct cdns_mhdp_bridge *bridge; - }; - -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+struct cdns_mhdp_cec { -+ struct cec_adapter *adap; -+ struct device *dev; -+ struct mutex lock; -+ -+ struct cec_msg msg; -+ struct task_struct *cec_worker; -+}; -+#endif -+ - struct cdns_mhdp_device { - void __iomem *regs; - -@@ -633,7 +644,7 @@ struct cdns_mhdp_device { - bool plugged; - - union { -- struct cdn_dp_data { -+ struct _dp_data { - struct drm_dp_link link; - struct drm_dp_aux aux; - struct cdns_mhdp_host host; -@@ -645,6 +656,9 @@ struct cdns_mhdp_device { - u32 num_lanes; - } dp; - struct _hdmi_data { -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+ struct cdns_mhdp_cec cec; -+#endif - u32 char_rate; - u32 hdmi_type; - } hdmi; -@@ -713,4 +727,10 @@ int cdns_hdmi_disable_gcp(struct cdns_mh - int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp); - - bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp); -+/* CEC */ -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+int cdns_mhdp_register_cec_driver(struct device *dev); -+int cdns_mhdp_unregister_cec_driver(struct device *dev); -+#endif -+ - #endif /* CDNS_MHDP_COMMON_H_ */ |