MLK-21886-2: media: imx: Add imx815 platform support
authorGuoniu.Zhou <guoniu.zhou@nxp.com>
Wed, 29 May 2019 09:56:01 +0000 (17:56 +0800)
committerGuoniu.Zhou <guoniu.zhou@nxp.com>
Wed, 7 Aug 2019 06:29:03 +0000 (14:29 +0800)
Add imx815 platform support in camera media device framework
of imx8qxp/qm.

Signed-off-by: Guoniu.Zhou <guoniu.zhou@nxp.com>
drivers/media/platform/imx8/mxc-isi-cap.c
drivers/media/platform/imx8/mxc-isi-core.c
drivers/media/platform/imx8/mxc-isi-core.h
drivers/media/platform/imx8/mxc-isi-hw.c
drivers/media/platform/imx8/mxc-isi-hw.h
drivers/media/platform/imx8/mxc-media-dev.c
drivers/media/platform/imx8/mxc-media-dev.h

index 16d43b6..7935e49 100644 (file)
@@ -165,7 +165,8 @@ struct mxc_isi_fmt *mxc_isi_get_src_fmt(struct v4l2_subdev_format *sd_fmt)
        if (sd_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16 ||
                sd_fmt->format.code == MEDIA_BUS_FMT_YVYU8_2X8 ||
                sd_fmt->format.code == MEDIA_BUS_FMT_AYUV8_1X32 ||
-               sd_fmt->format.code == MEDIA_BUS_FMT_UYVY8_2X8)
+               sd_fmt->format.code == MEDIA_BUS_FMT_UYVY8_2X8 ||
+               sd_fmt->format.code == MEDIA_BUS_FMT_YUYV8_2X8)
                index = 1;
        else
                index = 0;
index cdb7ce8..e71f7e2 100644 (file)
@@ -11,6 +11,8 @@
  */
 #include "mxc-media-dev.h"
 
+static const struct of_device_id mxc_isi_of_match[];
+
 static irqreturn_t mxc_isi_irq_handler(int irq, void *priv)
 {
        struct mxc_isi_dev *mxc_isi = priv;
@@ -50,6 +52,44 @@ static irqreturn_t mxc_isi_irq_handler(int irq, void *priv)
        return IRQ_HANDLED;
 }
 
+static void disp_mix_sft_rstn(struct regmap *gpr, bool enable)
+{
+       if (!gpr)
+               return;
+
+       if (!enable)
+               /* release isi soft reset */
+               regmap_update_bits(gpr,
+                               DISP_MIX_SFT_RSTN_CSR,
+                               EN_BUS_BLK_CLK_RSTN | EN_ISI_APB_CLK_RSTN | EN_ISI_PROC_CLK_RSTN,
+                               EN_BUS_BLK_CLK_RSTN | EN_ISI_APB_CLK_RSTN | EN_ISI_PROC_CLK_RSTN);
+       else
+               regmap_update_bits(gpr,
+                               DISP_MIX_SFT_RSTN_CSR,
+                               EN_BUS_BLK_CLK_RSTN | EN_ISI_APB_CLK_RSTN | EN_ISI_APB_CLK_RSTN,
+                               0x0);
+
+}
+
+static void disp_mix_clks_enable(struct regmap *gpr, bool enable)
+{
+       if (!gpr)
+               return;
+
+       if (enable)
+               /* enable isi clks */
+               regmap_update_bits(gpr,
+                               DISP_MIX_CLK_EN_CSR,
+                               EN_BUS_BLK_CLK | EN_ISI_APB_CLK | EN_ISI_PROC_CLK,
+                               EN_BUS_BLK_CLK | EN_ISI_APB_CLK | EN_ISI_PROC_CLK);
+       else
+               /* disable isi clks */
+               regmap_update_bits(gpr,
+                               DISP_MIX_CLK_EN_CSR,
+                               EN_BUS_BLK_CLK | EN_ISI_APB_CLK | EN_ISI_PROC_CLK,
+                               0x0);
+}
+
 /**
  * mxc_isi_adjust_mplane_format - adjust bytesperline or sizeimage
  */
@@ -110,12 +150,158 @@ static int mxc_isi_parse_dt(struct mxc_isi_dev *mxc_isi)
        return 0;
 }
 
+static int mxc_imx8_clk_get(struct mxc_isi_dev *mxc_isi)
+{
+       struct device *dev = &mxc_isi->pdev->dev;
+
+       mxc_isi->clk = devm_clk_get(dev, NULL);
+
+       if (IS_ERR(mxc_isi->clk)) {
+               dev_err(dev, "failed to get isi clk\n");
+               return PTR_ERR(mxc_isi->clk);
+       }
+
+       return 0;
+}
+
+static int mxc_imx8_clk_enable(struct mxc_isi_dev *mxc_isi)
+{
+       struct device *dev = &mxc_isi->pdev->dev;
+       int ret;
+
+       ret = clk_prepare_enable(mxc_isi->clk);
+       if (ret < 0) {
+               dev_err(dev, "%s, enable clk error\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mxc_imx8_clk_disable(struct mxc_isi_dev *mxc_isi)
+{
+       clk_disable_unprepare(mxc_isi->clk);
+}
+
+static struct mxc_isi_dev_ops mxc_imx8_data = {
+       .clk_get     = mxc_imx8_clk_get,
+       .clk_enable  = mxc_imx8_clk_enable,
+       .clk_disable = mxc_imx8_clk_disable,
+};
+
+static int mxc_imx8mn_clk_get(struct mxc_isi_dev *mxc_isi)
+{
+       struct device *dev = &mxc_isi->pdev->dev;
+
+       mxc_isi->clk_disp_axi = devm_clk_get(dev, "disp_axi");
+       if (IS_ERR(mxc_isi->clk_disp_axi)) {
+               dev_err(dev, "failed to get disp_axi clk\n");
+               return PTR_ERR(mxc_isi->clk_disp_axi);
+       }
+
+       mxc_isi->clk_disp_apb = devm_clk_get(dev, "disp_apb");
+       if (IS_ERR(mxc_isi->clk_disp_apb)) {
+               dev_err(dev, "failed to get disp_apb clk\n");
+               return PTR_ERR(mxc_isi->clk_disp_apb);
+       }
+
+       mxc_isi->clk_root_disp_axi = devm_clk_get(dev, "disp_axi_root");
+       if (IS_ERR(mxc_isi->clk_root_disp_axi)) {
+               dev_err(dev, "failed to get disp axi root clk\n");
+               return PTR_ERR(mxc_isi->clk_root_disp_axi);
+       }
+
+       mxc_isi->clk_root_disp_apb = devm_clk_get(dev, "disp_apb_root");
+       if (IS_ERR(mxc_isi->clk_root_disp_apb)) {
+               dev_err(dev, "failed to get disp apb root clk\n");
+               return PTR_ERR(mxc_isi->clk_root_disp_apb);
+       }
+
+       return 0;
+}
+
+static int mxc_imx8mn_clk_enable(struct mxc_isi_dev *mxc_isi)
+{
+       struct device *dev = &mxc_isi->pdev->dev;
+       int ret;
+
+       ret = clk_prepare_enable(mxc_isi->clk_disp_axi);
+       if (ret < 0) {
+               dev_err(dev, "prepare and enable axi clk error\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(mxc_isi->clk_disp_apb);
+       if (ret < 0) {
+               dev_err(dev, "prepare and enable abp clk error\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(mxc_isi->clk_root_disp_axi);
+       if (ret < 0) {
+               dev_err(dev, "prepare and enable axi root clk error\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(mxc_isi->clk_root_disp_apb);
+       if (ret < 0) {
+               dev_err(dev, "prepare and enable apb root clk error\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mxc_imx8mn_clk_disable(struct mxc_isi_dev *mxc_isi)
+{
+       clk_disable_unprepare(mxc_isi->clk_root_disp_axi);
+       clk_disable_unprepare(mxc_isi->clk_root_disp_apb);
+       clk_disable_unprepare(mxc_isi->clk_disp_axi);
+       clk_disable_unprepare(mxc_isi->clk_disp_apb);
+}
+
+static struct mxc_isi_dev_ops mxc_imx8mn_data = {
+       .clk_get     = mxc_imx8mn_clk_get,
+       .clk_enable  = mxc_imx8mn_clk_enable,
+       .clk_disable = mxc_imx8mn_clk_disable,
+};
+
+static int mxc_isi_clk_get(struct mxc_isi_dev *mxc_isi)
+{
+       const struct mxc_isi_dev_ops *ops = mxc_isi->ops;
+
+       if (!ops && !ops->clk_get)
+               return -EINVAL;
+
+       return ops->clk_get(mxc_isi);
+}
+
+static int mxc_isi_clk_enable(struct mxc_isi_dev *mxc_isi)
+{
+       const struct mxc_isi_dev_ops *ops = mxc_isi->ops;
+
+       if (!ops && !ops->clk_enable)
+               return -EINVAL;
+
+       return ops->clk_enable(mxc_isi);
+}
+
+static void mxc_isi_clk_disable(struct mxc_isi_dev *mxc_isi)
+{
+       const struct mxc_isi_dev_ops *ops = mxc_isi->ops;
+
+       if (!ops && !ops->clk_disable)
+               return;
+
+       ops->clk_disable(mxc_isi);
+}
 
 static int mxc_isi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct mxc_isi_dev *mxc_isi;
        struct resource *res;
+       const struct of_device_id *of_id;
        int ret = 0;
 
        mxc_isi = devm_kzalloc(dev, sizeof(*mxc_isi), GFP_KERNEL);
@@ -123,6 +309,15 @@ static int mxc_isi_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        mxc_isi->pdev = pdev;
+       of_id = of_match_node(mxc_isi_of_match, dev->of_node);
+       if (!of_id)
+               return -EINVAL;
+
+       mxc_isi->ops = of_id->data;
+       if (!mxc_isi->ops) {
+               dev_err(dev, "Can't get platform device data\n");
+               return -EINVAL;
+       }
 
        ret = mxc_isi_parse_dt(mxc_isi);
        if (ret < 0)
@@ -140,15 +335,16 @@ static int mxc_isi_probe(struct platform_device *pdev)
        mutex_init(&mxc_isi->m2m_lock);
        atomic_set(&mxc_isi->open_count, 0);
 
-       mxc_isi->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(mxc_isi->clk)) {
-               dev_err(dev, "failed to get isi clk\n");
-               return PTR_ERR(mxc_isi->clk);
+       mxc_isi->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "isi-gpr");
+       if (IS_ERR(mxc_isi->gpr)) {
+               mxc_isi->gpr = NULL;
+               dev_warn(dev, "can't find isi-gpr property\n");
        }
-       ret = clk_prepare(mxc_isi->clk);
+
+       ret = mxc_isi_clk_get(mxc_isi);
        if (ret < 0) {
-               dev_err(dev, "%s, prepare clk error\n", __func__);
-               return -EINVAL;
+               dev_err(dev, "ISI_%d get clocks fail\n", mxc_isi->id);
+               return ret;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -164,30 +360,33 @@ static int mxc_isi_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
+       ret = mxc_isi_clk_enable(mxc_isi);
+       if (ret < 0) {
+               dev_err(dev, "ISI_%d enable clocks fail\n", mxc_isi->id);
+               return ret;
+       }
+       disp_mix_sft_rstn(mxc_isi->gpr, false);
+       disp_mix_clks_enable(mxc_isi->gpr, true);
+
        mxc_isi_clean_registers(mxc_isi);
 
        ret = devm_request_irq(dev, res->start, mxc_isi_irq_handler,
                               0, dev_name(dev), mxc_isi);
        if (ret < 0) {
                dev_err(dev, "failed to install irq (%d)\n", ret);
-               return -EINVAL;
+               goto err_clk;
        }
 
        ret = mxc_isi_initialize_capture_subdev(mxc_isi);
        if (ret < 0) {
                dev_err(dev, "failed to init cap subdev (%d)\n", ret);
-               return -EINVAL;
+               goto err_clk;
        }
 
        platform_set_drvdata(pdev, mxc_isi);
 
-       ret = clk_enable(mxc_isi->clk);
-       if (ret < 0) {
-               dev_err(dev, "%s, enable clk error\n", __func__);
-               goto err_sclk;
-       }
-
-       clk_disable_unprepare(mxc_isi->clk);
+       mxc_isi_channel_set_chain_buf(mxc_isi);
+       mxc_isi_clk_disable(mxc_isi);
 
        pm_runtime_enable(dev);
 
@@ -195,7 +394,8 @@ static int mxc_isi_probe(struct platform_device *pdev)
 
        return 0;
 
-err_sclk:
+err_clk:
+       mxc_isi_clk_disable(mxc_isi);
        mxc_isi_unregister_capture_subdev(mxc_isi);
        return ret;
 }
@@ -226,7 +426,17 @@ static int mxc_isi_pm_suspend(struct device *dev)
 
 static int mxc_isi_pm_resume(struct device *dev)
 {
-       return pm_runtime_force_resume(dev);
+       struct mxc_isi_dev *mxc_isi = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pm_runtime_force_resume(dev);
+       if (ret < 0)
+               return ret;
+
+       disp_mix_sft_rstn(mxc_isi->gpr, false);
+       disp_mix_clks_enable(mxc_isi->gpr, true);
+
+       return 0;
 }
 #endif
 
@@ -234,7 +444,8 @@ static int mxc_isi_runtime_suspend(struct device *dev)
 {
        struct mxc_isi_dev *mxc_isi = dev_get_drvdata(dev);
 
-       clk_disable_unprepare(mxc_isi->clk);
+       mxc_isi_clk_disable(mxc_isi);
+
        return 0;
 }
 
@@ -243,11 +454,13 @@ static int mxc_isi_runtime_resume(struct device *dev)
        struct mxc_isi_dev *mxc_isi = dev_get_drvdata(dev);
        int ret;
 
-       ret = clk_prepare_enable(mxc_isi->clk);
-       if (ret)
+       ret = mxc_isi_clk_enable(mxc_isi);
+       if (ret) {
                dev_err(dev, "%s clk enable fail\n", __func__);
+               return ret;
+       }
 
-       return (ret) ? ret : 0;
+       return 0;
 }
 
 static const struct dev_pm_ops mxc_isi_pm_ops = {
@@ -256,7 +469,8 @@ static const struct dev_pm_ops mxc_isi_pm_ops = {
 };
 
 static const struct of_device_id mxc_isi_of_match[] = {
-       {.compatible = "fsl,imx8-isi",},
+       {.compatible = "fsl,imx8-isi", .data = &mxc_imx8_data },
+       {.compatible = "fsl,imx8mn-isi", .data = &mxc_imx8mn_data },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, mxc_isi_of_match);
index 7eb127f..de4c253 100644 (file)
 
 #define ISI_OF_NODE_NAME       "isi"
 
+/* display_mix_sft_rstn_csr */
+#define EN_BUS_BLK_CLK_RSTN    BIT(8)
+#define EN_ISI_APB_CLK_RSTN    BIT(7)
+#define EN_ISI_PROC_CLK_RSTN   BIT(6)
+
+/* display_mix_clk_en_csr */
+#define EN_BUS_BLK_CLK         BIT(8)
+#define EN_ISI_APB_CLK         BIT(7)
+#define EN_ISI_PROC_CLK                BIT(6)
+
 #define MXC_ISI_SD_PAD_SINK_MIPI0_VC0          0
 #define MXC_ISI_SD_PAD_SINK_MIPI0_VC1          1
 #define MXC_ISI_SD_PAD_SINK_MIPI0_VC2          2
@@ -268,26 +278,40 @@ struct mxc_isi_cap_dev {
 
        struct mxc_isi_frame    src_f;
        struct mxc_isi_frame    dst_f;
-       u32                             frame_count;
+       u32                     frame_count;
 
        u32 buf_index;
 };
 
+struct mxc_isi_dev_ops {
+       int (*clk_get)(struct mxc_isi_dev *mxc_isi);
+       int (*clk_enable)(struct mxc_isi_dev *mxc_isi);
+       void (*clk_disable)(struct mxc_isi_dev *mxc_isi);
+};
+
 struct mxc_isi_dev {
        spinlock_t                      slock;
        struct mutex                    lock;
        struct mutex                    m2m_lock;
        wait_queue_head_t               irq_queue;
 
-       int                                             id;
+       int                             id;
        void __iomem                    *regs;
        unsigned long                   state;
 
        struct platform_device          *pdev;
-       struct v4l2_device                      *v4l2_dev;
+       struct v4l2_device              *v4l2_dev;
        struct mxc_isi_m2m_dev          m2m;
        struct mxc_isi_cap_dev          isi_cap;
-       struct clk              *clk;
+
+       struct clk      *clk;
+       struct clk      *clk_disp_axi;
+       struct clk      *clk_disp_apb;
+       struct clk      *clk_root_disp_axi;
+       struct clk      *clk_root_disp_apb;
+
+       struct regmap *gpr;
+       const struct mxc_isi_dev_ops *ops;
 
        u32 interface[MAX_PORTS];
        u32 flags;
index 3b3f9ea..1bf2463 100644 (file)
@@ -59,6 +59,8 @@ void dump_isi_regs(struct mxc_isi_dev *mxc_isi)
        dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_Y   0x8Ch = 0x%8x\n", readl(mxc_isi->regs + 0x8C));
        dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_U   0x90h = 0x%8x\n", readl(mxc_isi->regs + 0x90));
        dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_V   0x94h = 0x%8x\n", readl(mxc_isi->regs + 0x94));
+       dev_dbg(dev, "CHNL_SCL_IMG_CFG       0x98h = 0x%8x\n", readl(mxc_isi->regs + 0x98));
+       dev_dbg(dev, "CHNL_FLOW_CTRL         0x9Ch = 0x%8x\n", readl(mxc_isi->regs + 0x9C));
 }
 #else
 void dump_isi_regs(struct mxc_isi_dev *mxc_isi)
index 30010cb..b734c65 100644 (file)
 #define  CHNL_OUT_BUF2_ADDR_V          0x94
 
 /* Channel scale image config */
-#define  CHNL_SCL_IMG_CFG                                      0x98
+#define  CHNL_SCL_IMG_CFG                      0x98
 #define  CHNL_SCL_IMG_CFG_HEIGHT_OFFSET                16
 #define  CHNL_SCL_IMG_CFG_HEIGHT_MASK          0x1FFF0000
 #define  CHNL_SCL_IMG_CFG_WIDTH_OFFSET         0
 #define  CHNL_SCL_IMG_CFG_WIDTH_MASK           0x1FFF
 
+/* Channel Flow Control Register */
+#define  CHNL_FLOW_CTRL                                0x9C
+#define  CHNL_FLOW_CTRL_FC_DENOM_MASK          0xFF
+#define  CHNL_FLOW_CTRL_FC_DENOM_OFFSET                0
+#define  CHNL_FLOW_CTRL_FC_NUMER_MASK          0xFF0000
+#define  CHNL_FLOW_CTRL_FC_NUMER_OFFSET                0
+
 enum isi_csi_coeff {
        YUV2RGB = 0,
        RGB2YUV,
index 5c7ee3b..0d9a3a6 100644 (file)
 #include "mxc-isi-core.h"
 #include "mxc-mipi-csi2.h"
 #include "mxc-parallel-csi.h"
+#include "mxc-mipi-csi2-sam.h"
+
+static void set_soc_version(struct mxc_md *mxc_md)
+{
+       if (of_machine_is_compatible("fsl,imx8mn"))
+               mxc_md->plat = MXC_IMX8MN;
+       else if (of_machine_is_compatible("fsl,imx8qxp"))
+               mxc_md->plat = MXC_IMX8QXP;
+       else if (of_machine_is_compatible("fsl,imx8qm"))
+               mxc_md->plat = MXC_IMX8QM;
+       else
+               mxc_md->plat = INVALID_SOC;
+}
+
+static enum platform get_soc_version(struct mxc_md *mxc_md)
+{
+       return mxc_md->plat;
+}
 
 /*create default links between registered entities  */
 static int mxc_md_create_links(struct mxc_md *mxc_md)
@@ -45,6 +63,7 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
        struct mxc_sensor_info *sensor;
        struct mxc_mipi_csi2_dev *mipi_csi2;
        struct mxc_parallel_csi_dev *pcsidev;
+       struct csi_state *state;
        int num_sensors = mxc_md->subdev_notifier.num_subdevs;
        int i, j, ret = 0;
        u16  source_pad, sink_pad;
@@ -105,9 +124,15 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
                switch (mxc_isi->interface[IN_PORT]) {
 
                case ISI_INPUT_INTERFACE_MIPI0_CSI2:
-                       if (mxc_md->mipi_csi2[0] == NULL)
-                               continue;
-                       source = &mxc_md->mipi_csi2[0]->sd.entity;
+                       if (get_soc_version(mxc_md) == MXC_IMX8MN) {
+                               if (mxc_md->state[0] == NULL)
+                                       continue;
+                               source = &mxc_md->state[0]->sd.entity;
+                       } else {
+                               if (mxc_md->mipi_csi2[0] == NULL)
+                                       continue;
+                               source = &mxc_md->mipi_csi2[0]->sd.entity;
+                       }
 
                        switch (mxc_isi->interface[SUB_IN_PORT]) {
                        case ISI_INPUT_SUB_INTERFACE_VC1:
@@ -130,9 +155,15 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
                        break;
 
                case ISI_INPUT_INTERFACE_MIPI1_CSI2:
-                       if (mxc_md->mipi_csi2[1] == NULL)
-                               continue;
-                       source = &mxc_md->mipi_csi2[1]->sd.entity;
+                       if (get_soc_version(mxc_md) == MXC_IMX8MN) {
+                               if (mxc_md->state[1] == NULL)
+                                       continue;
+                               source = &mxc_md->state[1]->sd.entity;
+                       } else {
+                               if (mxc_md->mipi_csi2[1] == NULL)
+                                       continue;
+                               source = &mxc_md->mipi_csi2[1]->sd.entity;
+                       }
 
                        switch (mxc_isi->interface[SUB_IN_PORT]) {
                        case ISI_INPUT_SUB_INTERFACE_VC1:
@@ -235,21 +266,27 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
                                return ret;
                        v4l2_info(&mxc_md->v4l2_dev, "created link [%s] => [%s]\n",
                                                sensor->sd->entity.name, pcsidev->sd.entity.name);
-               } else if (mxc_md->mipi_csi2) {
-                       mipi_csi2 = mxc_md->mipi_csi2[sensor->id];
-                       if (mipi_csi2 ==  NULL)
-                               continue;
+               } else if (mxc_md->mipi_csi2 || mxc_md->state) {
+                       if (get_soc_version(mxc_md) == MXC_IMX8MN) {
+                               state = mxc_md->state[sensor->id];
+                               if (state == NULL)
+                                       continue;
+
+                               sink = &state->sd.entity;
+                               mipi_vc = (state->vchannel == true) ? 4 : 1;
+                       } else {
+                               mipi_csi2 = mxc_md->mipi_csi2[sensor->id];
+                               if (mipi_csi2 ==  NULL)
+                                       continue;
+
+                               sink = &mipi_csi2->sd.entity;
+                               mipi_vc = (mipi_csi2->vchannel == true) ? 4 : 1;
+                       }
                        source = &sensor->sd->entity;
-                       sink = &mipi_csi2->sd.entity;
 
                        source_pad = 0;  /* sensor source pad: MIPI_CSI2_SENS_VC0_PAD_SOURCE */
                        sink_pad = source_pad;  /* mipi sink pad: MXC_MIPI_CSI2_VC0_PAD_SINK; */
 
-                       if (mipi_csi2->vchannel == true)
-                               mipi_vc = 4;
-                       else
-                               mipi_vc = 1;
-
                        for (j = 0; j < mipi_vc; j++) {
                                ret = media_create_pad_link(source, source_pad + j, sink, sink_pad + j,
                                                  MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
@@ -269,7 +306,7 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
                                        return ret;
                        }
                        v4l2_info(&mxc_md->v4l2_dev, "created link [%s] => [%s]\n",
-                                 sensor->sd->entity.name, mipi_csi2->sd.entity.name);
+                                       source->name, sink->name);
                }
        }
        dev_info(&mxc_md->pdev->dev, "%s\n", __func__);
@@ -439,22 +476,36 @@ static int register_isi_entity(struct mxc_md *mxc_md, struct mxc_isi_dev *mxc_is
        return ret;
 }
 
-static int register_mipi_csi2_entity(struct mxc_md *mxc_md,
-                               struct mxc_mipi_csi2_dev *mipi_csi2)
+static int register_mipi_csi2_entity(struct mxc_md *mxc_md, void *data)
 {
-       struct v4l2_subdev *sd = &mipi_csi2->sd;
-       int ret;
+       struct mxc_mipi_csi2_dev *mipi_csi2 = NULL;
+       struct csi_state *state = NULL;
+       struct v4l2_subdev *sd;
+       int ret, id;
+
+       if (get_soc_version(mxc_md) == MXC_IMX8MN) {
+               state = (struct csi_state *)data;
+               sd = &state->sd;
+               id = state->id;
+       } else {
+               mipi_csi2 = (struct mxc_mipi_csi2_dev *)data;
+               sd = &mipi_csi2->sd;
+               id = mipi_csi2->id;
+       }
 
-       if (WARN_ON(mipi_csi2->id >= MXC_MIPI_CSI2_MAX_DEVS))
+       if (WARN_ON(id >= MXC_MIPI_CSI2_MAX_DEVS || id < 0))
                return -ENOENT;
 
        sd->grp_id = GRP_ID_MXC_MIPI_CSI2;
        ret = v4l2_device_register_subdev(&mxc_md->v4l2_dev, sd);
-       if (!ret)
-               mxc_md->mipi_csi2[mipi_csi2->id] = mipi_csi2;
-       else
+       if (!ret) {
+               if (get_soc_version(mxc_md) == MXC_IMX8MN)
+                       mxc_md->state[id] = state;
+               else
+                       mxc_md->mipi_csi2[id] = mipi_csi2;
+       } else
                v4l2_err(&mxc_md->v4l2_dev,
-                        "Failed to register MIPI-CSIS.%d (%d)\n", mipi_csi2->id, ret);
+                        "Failed to register MIPI-CSIS.%d (%d)\n", id, ret);
        return ret;
 }
 
@@ -774,6 +825,12 @@ static int mxc_md_probe(struct platform_device *pdev)
        mxc_md->pdev = pdev;
        platform_set_drvdata(pdev, mxc_md);
 
+       set_soc_version(mxc_md);
+       if (get_soc_version(mxc_md) == INVALID_SOC) {
+               dev_err(dev, "Not support soc\n");
+               return -ENODEV;
+       }
+
        mxc_md->parallel_csi = of_property_read_bool(dev->of_node, "parallel_csi");
 
        /* register media device  */
@@ -864,7 +921,7 @@ static int mxc_md_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id mxc_md_of_match[] = {
-       {       .compatible = "fsl,mxc-md",},
+       { .compatible = "fsl,mxc-md",},
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, mxc_md_of_match);
index d5ee923..05503fc 100644 (file)
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-core.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #include "mxc-mipi-csi2.h"
+#include "mxc-mipi-csi2-sam.h"
 #include "mxc-isi-core.h"
 #include "mxc-isi-hw.h"
 #include "hdmi/mxc-hdmi-rx.h"
@@ -69,6 +72,13 @@ enum mxc_subdev_index {
        IDX_MAX,
 };
 
+enum platform {
+       MXC_IMX8QM = 0,
+       MXC_IMX8QXP,
+       MXC_IMX8MN,
+       INVALID_SOC,
+};
+
 struct mxc_sensor_info {
        int                             id;
        struct v4l2_subdev              *sd;
@@ -88,25 +98,28 @@ struct mxc_mjpeg_enc{
 };
 
 struct mxc_md {
-       struct mxc_isi_dev *mxc_isi[MXC_ISI_MAX_DEVS];
-       struct mxc_hdmi_rx_dev *hdmi_rx;
-       struct mxc_parallel_csi_dev *pcsidev;
-       struct mxc_mipi_csi2_dev *mipi_csi2[MXC_MIPI_CSI2_MAX_DEVS];
-       struct mxc_sensor_info sensor[MXC_MAX_SENSORS];
-       struct mxc_mjpeg_dec  *mjpeg_dec;
-       struct mxc_mjpeg_enc  *mjpeg_enc;
-
-       int link_status;
-       int num_sensors;
-       unsigned int nr_isi;
+       struct mxc_isi_dev              *mxc_isi[MXC_ISI_MAX_DEVS];
+       struct mxc_hdmi_rx_dev          *hdmi_rx;
+       struct mxc_parallel_csi_dev     *pcsidev;
+       struct mxc_mipi_csi2_dev        *mipi_csi2[MXC_MIPI_CSI2_MAX_DEVS];
+       struct csi_state                *state[MXC_MIPI_CSI2_MAX_DEVS];
+       struct mxc_sensor_info          sensor[MXC_MAX_SENSORS];
+       struct mxc_mjpeg_dec            *mjpeg_dec;
+       struct mxc_mjpeg_enc            *mjpeg_enc;
+
+       int  link_status;
+       int  num_sensors;
+       u32  nr_isi;
        bool parallel_csi;
 
-       struct media_device media_dev;
-       struct v4l2_device v4l2_dev;
-       struct platform_device *pdev;
+       struct media_device     media_dev;
+       struct v4l2_device      v4l2_dev;
+       struct platform_device  *pdev;
+
+       struct v4l2_async_notifier      subdev_notifier;
+       struct v4l2_async_subdev        *async_subdevs[MXC_MAX_SENSORS];
 
-       struct v4l2_async_notifier subdev_notifier;
-       struct v4l2_async_subdev *async_subdevs[MXC_MAX_SENSORS];
+       enum platform plat;
 };
 
 static inline struct mxc_md *notifier_to_mxc_md(struct v4l2_async_notifier *n)