MLK-17289-5: hdmi cec: change cec driver architecture
authorSandor Yu <Sandor.yu@nxp.com>
Fri, 22 Dec 2017 10:10:31 +0000 (18:10 +0800)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
Change hdmi cec driver architecture.
Embedded cec function to hdmi driver.
Rewrite cec_read and cec_write fucntion
to support both imx8qm and imx8mq cec.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
Also include MLK-17289-6: hdp drm: Add cec register/unregister function

Add cec register/unregister function in hdp drm driver.
Add is_cec variable to check cec function setting in dtb.

Squashed MLK-17289-5 and MLK-17289-6 from imx_4.9.y because they only
build together.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
drivers/gpu/drm/imx/hdp/imx-cec.c
drivers/gpu/drm/imx/hdp/imx-cec.h
drivers/gpu/drm/imx/hdp/imx-hdp.c
drivers/gpu/drm/imx/hdp/imx-hdp.h

index 9d8c159..ef7f889 100644 (file)
 #include <media/cec.h>
 #include <soc/imx8/soc.h>
 
-#include "imx-cec.h"
+#include "imx-hdp.h"
 
 #define CEC_NAME       "hdp-cec"
 
 #define REG_ADDR_OFF 1
 
-#define B0_SILICON_ID                  0x20
-
 #define MAX_LA_IDX 4
 #define MAX_LA_VAL 15
 
 #define set_la_valid F_LOG_ADDR_VALID0
 #define get_la_valid F_LOG_ADDR_VALID0_RD
 
-u32 cec_read(void __iomem *base, u32 reg)
+u32 cec_read(struct imx_cec_dev *cec, u32 offset)
 {
-       return readl(base + (reg << 2));
+       struct imx_hdp *hdp = container_of(cec, struct imx_hdp, cec);
+       struct hdp_mem *mem = &hdp->mem;
+       u32 addr = (offset << 2) + ADDR_HDP_CEC_BASE;
+       u32 value;
+
+       hdp->rw->read_reg(mem, addr, &value);
+       return value;
 }
 
-void cec_write(void __iomem *base, u32 reg, u32 val)
+void cec_write(struct imx_cec_dev *cec, u32 offset, u32 value)
 {
-       return writel(val, base + (reg << 2));
+       struct imx_hdp *hdp = container_of(cec, struct imx_hdp, cec);
+       struct hdp_mem *mem = &hdp->mem;
+       u32 addr = (offset << 2) + ADDR_HDP_CEC_BASE;
+
+       hdp->rw->write_reg(mem, addr, value);
 }
 
 void cec_clear_rx_buffer(struct imx_cec_dev *cec)
 {
-       cec_write(cec->reg_base, RX_CLEAR_BUF, 1);
-       cec_write(cec->reg_base, RX_CLEAR_BUF, 0);
+       cec_write(cec, RX_CLEAR_BUF, 1);
+       cec_write(cec, RX_CLEAR_BUF, 0);
 }
 
 void cec_set_divider(struct imx_cec_dev *cec)
 {
        /* Set clock divider */
-
        if (cec->clk_div == 0) {
                dev_warn(cec->dev,
                         "Warning. Clock divider is 0. Changing to 1.\n");
-               cec_write(cec->reg_base, CLK_DIV_MSB, 0);
-               cec_write(cec->reg_base, CLK_DIV_LSB, 1);
+               cec_write(cec, CLK_DIV_MSB, 0);
+               cec_write(cec, CLK_DIV_LSB, 1);
        } else {
-               cec_write(cec->reg_base, CLK_DIV_MSB,
+               cec_write(cec, CLK_DIV_MSB,
                          (cec->clk_div >> 8) & 0xFF);
-               cec_write(cec->reg_base, CLK_DIV_LSB, cec->clk_div & 0xFF);
+               cec_write(cec, CLK_DIV_LSB, cec->clk_div & 0xFF);
        }
 }
 
@@ -84,29 +91,28 @@ u32 cec_read_message(struct imx_cec_dev *cec)
        int len;
        int i;
 
-       cec_write(cec->reg_base, RX_MSG_CMD, CEC_RX_READ);
+       cec_write(cec, RX_MSG_CMD, CEC_RX_READ);
 
-       len = cec_read(cec->reg_base, RX_MSG_LENGTH);
+       len = cec_read(cec, RX_MSG_LENGTH);
        msg->len = len + 1;
-       dev_dbg(cec->dev, "RX msg len =%d\n", len);
+       dev_dbg(cec->dev, "RX MSG len =%d\n", len);
 
        /* Read RX MSG bytes */
        for (i = 0; i < msg->len; ++i) {
-               msg->msg[i] = (uint8_t) cec_read(cec->reg_base,
-                                                RX_MSG_DATA1 +
-                                                (i * REG_ADDR_OFF));
+               msg->msg[i] = (u8) cec_read(cec, RX_MSG_DATA1 + (i * REG_ADDR_OFF));
+               dev_dbg(cec->dev, "RX MSG[%d]=0x%x\n", i, msg->msg[i]);
        }
 
-       cec_write(cec->reg_base, RX_MSG_CMD, CEC_RX_STOP);
+       cec_write(cec, RX_MSG_CMD, CEC_RX_STOP);
 
        return true;
 }
 
 u32 cec_write_message(struct imx_cec_dev *cec, struct cec_msg *msg)
 {
-       uint8_t i;
+       u8 i;
 
-       cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_STOP);
+       cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
 
        if (msg->len > CEC_MAX_MSG_SIZE) {
                dev_err(cec->dev, "Invalid MSG size!\n");
@@ -115,27 +121,27 @@ u32 cec_write_message(struct imx_cec_dev *cec, struct cec_msg *msg)
 
        /* Write Message to register */
        for (i = 0; i < msg->len; ++i) {
-               cec_write(cec->reg_base, TX_MSG_HEADER + (i * REG_ADDR_OFF),
+               cec_write(cec, TX_MSG_HEADER + (i * REG_ADDR_OFF),
                          msg->msg[i]);
        }
        /* Write Message Length (payload + opcode) */
-       cec_write(cec->reg_base, TX_MSG_LENGTH, msg->len - 1);
+       cec_write(cec, TX_MSG_LENGTH, msg->len - 1);
 
-       cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_TRANSMIT);
+       cec_write(cec, TX_MSG_CMD, CEC_TX_TRANSMIT);
 
        return true;
 }
 
 void cec_abort_tx_transfer(struct imx_cec_dev *cec)
 {
-       cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_ABORT);
-       cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_STOP);
+       cec_write(cec, TX_MSG_CMD, CEC_TX_ABORT);
+       cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
 }
 
 u32 imx_cec_set_logical_addr(struct imx_cec_dev *cec, u32 la)
 {
-       uint8_t i;
-       uint8_t la_reg;
+       u8 i;
+       u8 la_reg;
 
        if ((la >= MAX_LA_VAL)) {
                dev_err(cec->dev, "Error logical Addr\n");
@@ -144,8 +150,7 @@ u32 imx_cec_set_logical_addr(struct imx_cec_dev *cec, u32 la)
 
        for (i = 0; i < MAX_LA_IDX; ++i) {
                la_reg =
-                   cec_read(cec->reg_base,
-                            LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
+                   cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
 
                if (get_la_valid(la_reg))
                        continue;
@@ -157,8 +162,7 @@ u32 imx_cec_set_logical_addr(struct imx_cec_dev *cec, u32 la)
 
                la = set_la(la) | set_la_valid(1);
 
-               cec_write(cec->reg_base,
-                         LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
+               cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
                return true;
        }
 
@@ -178,15 +182,15 @@ static int cec_poll_worker(void *_cec)
                        break;
 
                /* Check TX State */
-               sts = cec_read(cec->reg_base, TX_MSG_STATUS);
+               sts = 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);
-                       cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_STOP);
+                       cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
                        break;
                case CEC_STS_ERROR:
-                       cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_STOP);
+                       cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
                        cec_transmit_done(cec->adap,
                                          CEC_TX_STATUS_MAX_RETRIES |
                                          CEC_TX_STATUS_ERROR, 0, 0, 0, 1);
@@ -197,8 +201,8 @@ static int cec_poll_worker(void *_cec)
                }
 
                /* Check RX State */
-               sts = cec_read(cec->reg_base, RX_MSG_STATUS);
-               num_rx_msgs = cec_read(cec->reg_base, NUM_OF_MSG_RX_BUF);
+               sts = cec_read(cec, RX_MSG_STATUS);
+               num_rx_msgs = cec_read(cec, NUM_OF_MSG_RX_BUF);
                switch (sts) {
                case CEC_STS_SUCCESS:
                        if (num_rx_msgs == 0xf)
@@ -234,7 +238,7 @@ static int imx_cec_adap_enable(struct cec_adapter *adap, bool enable)
        struct imx_cec_dev *cec = adap->priv;
 
        if (enable) {
-               cec_write(cec->reg_base, DB_L_TIMER, 0x10);
+               cec_write(cec, DB_L_TIMER, 0x10);
                cec_set_divider(cec);
        } else {
                cec_set_divider(cec);
@@ -267,26 +271,18 @@ static const struct cec_adap_ops imx_cec_adap_ops = {
        .adap_transmit = imx_cec_adap_transmit,
 };
 
-static int imx_cec_probe(struct platform_device *pdev)
+int imx_cec_register(struct imx_cec_dev *cec)
 {
-       struct device *dev = &pdev->dev;
-       struct resource *res;
-       struct imx_cec_dev *cec;
+       struct imx_hdp *hdp = container_of(cec, struct imx_hdp, cec);
+       struct device *dev = hdp->dev;
        int ret;
 
-       cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
-       if (!cec)
-               return -ENOMEM;
-
-       cec->dev = dev;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       cec->reg_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(cec->reg_base))
-               return PTR_ERR(cec->reg_base);
-
-       /* hdmi core clock is 133MHz */
-       cec->clk_div = 1330;
+       /* Set CEC clock divider */
+       if (hdp->clks.clk_core)
+               cec->clk_div = clk_get_rate(hdp->clks.clk_core) / 100000;
+       else
+               /* Default HDMI core clock rate 133MHz */
+               cec->clk_div = 1330;
 
        cec->adap = cec_allocate_adapter(&imx_cec_adap_ops, cec,
                                         CEC_NAME,
@@ -296,13 +292,13 @@ static int imx_cec_probe(struct platform_device *pdev)
        ret = PTR_ERR_OR_ZERO(cec->adap);
        if (ret)
                return ret;
-       ret = cec_register_adapter(cec->adap, &pdev->dev);
+       ret = cec_register_adapter(cec->adap, dev);
        if (ret) {
                cec_delete_adapter(cec->adap);
                return ret;
        }
 
-       platform_set_drvdata(pdev, cec);
+       cec->dev = dev;
 
        cec->cec_worker = kthread_create(cec_poll_worker, cec, "hdp-cec");
        if (IS_ERR(cec->cec_worker)) {
@@ -314,10 +310,8 @@ static int imx_cec_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int imx_cec_remove(struct platform_device *pdev)
+int imx_cec_unregister(struct imx_cec_dev *cec)
 {
-       struct imx_cec_dev *cec = platform_get_drvdata(pdev);
-
        if (cec->cec_worker) {
                kthread_stop(cec->cec_worker);
                cec->cec_worker = NULL;
@@ -326,24 +320,6 @@ static int imx_cec_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id imx_cec_match[] = {
-       {
-        .compatible = "fsl,imx8-hdp-cec",
-        },
-       {},
-};
-
-static struct platform_driver imx_cec_pdrv = {
-       .probe = imx_cec_probe,
-       .remove = imx_cec_remove,
-       .driver = {
-                  .name = CEC_NAME,
-                  .of_match_table = imx_cec_match,
-                  },
-};
-
-module_platform_driver(imx_cec_pdrv);
-
 MODULE_AUTHOR("Sandor.Yu@NXP.com");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("NXP IMX HDP CEC driver");
index 928fbb7..9abe387 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef _IMX_CEC_H_
 #define _IMX_CEC_H_
 
+#include <linux/cec.h>
+
 /* regsiter define */
 /* register TX_MSG_HEADER */
 #define TX_MSG_HEADER 0
@@ -333,4 +335,6 @@ struct imx_cec_dev {
        struct task_struct *cec_worker;
 };
 
+int imx_cec_register(struct imx_cec_dev *cec);
+int imx_cec_unregister(struct imx_cec_dev *cec);
 #endif
index 8ab33a8..ecb251a 100644 (file)
@@ -1067,6 +1067,7 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master,
                return -EINVAL;
        }
 
+       hdp->is_cec = of_property_read_bool(pdev->dev.of_node, "fsl,cec");
        hdp->is_edid = devtype->is_edid;
        hdp->is_4kp60 = devtype->is_4kp60;
        hdp->audio_type = devtype->audio_type;
@@ -1195,6 +1196,10 @@ static int imx_hdp_imx_bind(struct device *dev, struct device *master,
                if (hpd == 1)
                        enable_irq(hdp->irq[HPD_IRQ_OUT]);
        }
+#ifdef CONFIG_IMX_HDP_CEC
+       if (hdp->is_cec)
+               imx_cec_register(&hdp->cec);
+#endif
 
        return 0;
 err_irq:
@@ -1207,6 +1212,10 @@ static void imx_hdp_imx_unbind(struct device *dev, struct device *master,
 {
        struct imx_hdp *hdp = dev_get_drvdata(dev);
 
+#ifdef CONFIG_IMX_HDP_CEC
+       if (hdp->is_cec)
+               imx_cec_unregister(&hdp->cec);
+#endif
        imx_hdp_call(hdp, pixel_clock_disable, &hdp->clks);
        imx_hdp_call(hdp, pixel_link_deinit, &hdp->state);
 }
index 6f293cd..d656e7c 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <drm/drm_dp_helper.h>
 #include "../../../../mxc/hdp/all.h"
+#include "imx-cec.h"
 
 /* For testing hdp firmware define DEBUG_FW_LOAD */
 #undef DEBUG_FW_LOAD
@@ -195,6 +196,7 @@ struct imx_hdp {
 
        u8 is_edid;
        u8 is_4kp60;
+       u8 is_cec;
        u8 audio_type;
 
        struct mutex mutex;             /* for state below and previous_mode */
@@ -219,6 +221,8 @@ struct imx_hdp {
        int vic;
        int irq[HPD_IRQ_NUM];
        struct delayed_work hotplug_work;
+
+       struct imx_cec_dev cec;
 };
 
 u32 imx_hdp_audio(AUDIO_TYPE type, u32 sample_rate, u32 channels, u32 width);