From 198a1a08968395be2f651869ded65f2e7a0631a1 Mon Sep 17 00:00:00 2001 From: "Guoniu.Zhou" Date: Wed, 29 May 2019 17:56:01 +0800 Subject: [PATCH] MLK-21886-2: media: imx: Add imx815 platform support Add imx815 platform support in camera media device framework of imx8qxp/qm. Signed-off-by: Guoniu.Zhou --- drivers/media/platform/imx8/mxc-isi-cap.c | 3 +- drivers/media/platform/imx8/mxc-isi-core.c | 260 ++++++++++++++++++-- drivers/media/platform/imx8/mxc-isi-core.h | 32 ++- drivers/media/platform/imx8/mxc-isi-hw.c | 2 + drivers/media/platform/imx8/mxc-isi-hw.h | 9 +- drivers/media/platform/imx8/mxc-media-dev.c | 111 +++++++-- drivers/media/platform/imx8/mxc-media-dev.h | 45 ++-- 7 files changed, 390 insertions(+), 72 deletions(-) diff --git a/drivers/media/platform/imx8/mxc-isi-cap.c b/drivers/media/platform/imx8/mxc-isi-cap.c index 16d43b6a786f..7935e4989d85 100644 --- a/drivers/media/platform/imx8/mxc-isi-cap.c +++ b/drivers/media/platform/imx8/mxc-isi-cap.c @@ -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; diff --git a/drivers/media/platform/imx8/mxc-isi-core.c b/drivers/media/platform/imx8/mxc-isi-core.c index cdb7ce8f4e01..e71f7e2ebeed 100644 --- a/drivers/media/platform/imx8/mxc-isi-core.c +++ b/drivers/media/platform/imx8/mxc-isi-core.c @@ -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); diff --git a/drivers/media/platform/imx8/mxc-isi-core.h b/drivers/media/platform/imx8/mxc-isi-core.h index 7eb127f3b470..de4c25326229 100644 --- a/drivers/media/platform/imx8/mxc-isi-core.h +++ b/drivers/media/platform/imx8/mxc-isi-core.h @@ -24,6 +24,16 @@ #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; diff --git a/drivers/media/platform/imx8/mxc-isi-hw.c b/drivers/media/platform/imx8/mxc-isi-hw.c index 3b3f9ea9e7ec..1bf24638580a 100644 --- a/drivers/media/platform/imx8/mxc-isi-hw.c +++ b/drivers/media/platform/imx8/mxc-isi-hw.c @@ -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) diff --git a/drivers/media/platform/imx8/mxc-isi-hw.h b/drivers/media/platform/imx8/mxc-isi-hw.h index 30010cbc5345..b734c651b8bc 100644 --- a/drivers/media/platform/imx8/mxc-isi-hw.h +++ b/drivers/media/platform/imx8/mxc-isi-hw.h @@ -448,12 +448,19 @@ #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, diff --git a/drivers/media/platform/imx8/mxc-media-dev.c b/drivers/media/platform/imx8/mxc-media-dev.c index 5c7ee3b3b31b..0d9a3a68266c 100644 --- a/drivers/media/platform/imx8/mxc-media-dev.c +++ b/drivers/media/platform/imx8/mxc-media-dev.c @@ -36,6 +36,24 @@ #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); diff --git a/drivers/media/platform/imx8/mxc-media-dev.h b/drivers/media/platform/imx8/mxc-media-dev.h index d5ee92317519..05503fc9aedc 100644 --- a/drivers/media/platform/imx8/mxc-media-dev.h +++ b/drivers/media/platform/imx8/mxc-media-dev.h @@ -35,8 +35,11 @@ #include #include #include +#include +#include #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) -- 2.17.1