summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuoniu.zhou <guoniu.zhou@nxp.com>2019-10-25 10:00:38 +0800
committerGuoniu.zhou <guoniu.zhou@nxp.com>2019-12-02 15:37:03 +0800
commitf093fe32626a9a4486d0849c85723c8bd2db8cd8 (patch)
tree1789e7da5ab7eb9fbe9a0a9d991496b5471dc734
parentd8977ba09f7e4827cc4d68bc670b72da3fa3d06b (diff)
staging: media: imx: enable ISI for imx8mn platform
ISI is image sensor interface of imx8 family. It's reused in imx8mn platform. But they use different clock tree, so driver need to select the related clock operation for different platform. In order to solve the problem, driver define mxc_isi_dev_ops which used to control clock operation. Dispmix subsystem of imx8mn is consist of ISI, CSI, DSI and LCDIF modules. It use GPR to manage the reset and clock signal for all modules. We add a reset driver for dispmix reset function, so add related consumer of reset in ISI core driver. Signed-off-by: Guoniu.zhou <guoniu.zhou@nxp.com>
-rw-r--r--drivers/staging/media/imx/imx8-isi-cap.c21
-rw-r--r--drivers/staging/media/imx/imx8-isi-core.c287
-rw-r--r--drivers/staging/media/imx/imx8-isi-core.h26
-rw-r--r--drivers/staging/media/imx/imx8-isi-hw.c21
-rw-r--r--drivers/staging/media/imx/imx8-isi-hw.h7
5 files changed, 336 insertions, 26 deletions
diff --git a/drivers/staging/media/imx/imx8-isi-cap.c b/drivers/staging/media/imx/imx8-isi-cap.c
index cbf82bae0eaf..662780bfbb76 100644
--- a/drivers/staging/media/imx/imx8-isi-cap.c
+++ b/drivers/staging/media/imx/imx8-isi-cap.c
@@ -166,7 +166,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;
@@ -1134,6 +1135,7 @@ static int mxc_isi_cap_enum_framesizes(struct file *file, void *priv,
struct v4l2_frmsizeenum *fsize)
{
struct mxc_isi_cap_dev *isi_cap = video_drvdata(file);
+ struct device_node *parent;
struct v4l2_subdev *sd;
struct mxc_isi_fmt *fmt;
struct v4l2_subdev_frame_size_enum fse = {
@@ -1157,6 +1159,11 @@ static int mxc_isi_cap_enum_framesizes(struct file *file, void *priv,
if (ret)
return ret;
+ parent = of_get_parent(isi_cap->pdev->dev.of_node);
+ if ((of_device_is_compatible(parent, "fsl,imx8mn-isi")) &&
+ (fse.max_width > ISI_2K || fse.min_width > ISI_2K))
+ return -EINVAL;
+
if (fse.min_width == fse.max_width &&
fse.min_height == fse.max_height) {
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
@@ -1180,6 +1187,7 @@ static int mxc_isi_cap_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *interval)
{
struct mxc_isi_cap_dev *isi_cap = video_drvdata(file);
+ struct device_node *parent;
struct v4l2_subdev *sd;
struct mxc_isi_fmt *fmt;
struct v4l2_subdev_frame_interval_enum fie = {
@@ -1203,6 +1211,11 @@ static int mxc_isi_cap_enum_frameintervals(struct file *file, void *fh,
if (ret)
return ret;
+ parent = of_get_parent(isi_cap->pdev->dev.of_node);
+ if (of_device_is_compatible(parent, "fsl,imx8mn-isi") &&
+ fie.width > ISI_2K)
+ return -EINVAL;
+
interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
interval->discrete = fie.interval;
@@ -1353,6 +1366,7 @@ static int mxc_isi_subdev_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *fmt)
{
struct mxc_isi_cap_dev *isi_cap = v4l2_get_subdevdata(sd);
+ struct device_node *parent;
struct v4l2_mbus_framefmt *mf = &fmt->format;
struct mxc_isi_frame *dst_f = &isi_cap->dst_f;
struct mxc_isi_fmt *out_fmt;
@@ -1373,6 +1387,11 @@ static int mxc_isi_subdev_set_fmt(struct v4l2_subdev *sd,
return -EINVAL;
}
+ parent = of_get_parent(isi_cap->pdev->dev.of_node);
+ if (of_device_is_compatible(parent, "fsl,imx8mn-isi") &&
+ mf->width > ISI_2K)
+ return -EINVAL;
+
mutex_lock(&isi_cap->lock);
/* update out put frame size and formate */
dst_f->fmt = &mxc_isi_out_formats[i];
diff --git a/drivers/staging/media/imx/imx8-isi-core.c b/drivers/staging/media/imx/imx8-isi-core.c
index 28ce6155ad9a..8127722c5796 100644
--- a/drivers/staging/media/imx/imx8-isi-core.c
+++ b/drivers/staging/media/imx/imx8-isi-core.c
@@ -6,6 +6,8 @@
#include "imx8-isi-hw.h"
+static const struct of_device_id mxc_isi_of_match[];
+
struct mxc_isi_dev *mxc_isi_get_hostdata(struct platform_device *pdev)
{
struct mxc_isi_dev *mxc_isi;
@@ -55,6 +57,7 @@ static irqreturn_t mxc_isi_irq_handler(int irq, void *priv)
spin_lock(&mxc_isi->slock);
status = mxc_isi_get_irq_status(mxc_isi);
+ mxc_isi->status = status;
mxc_isi_clean_irq_status(mxc_isi, status);
if (status & CHNL_STS_FRM_STRD_MASK) {
@@ -88,6 +91,146 @@ static irqreturn_t mxc_isi_irq_handler(int irq, void *priv)
return IRQ_HANDLED;
}
+static int disp_mix_sft_rstn(struct reset_control *reset, bool enable)
+{
+ int ret;
+
+ if (!reset)
+ return 0;
+
+ ret = enable ? reset_control_assert(reset) :
+ reset_control_deassert(reset);
+ return ret;
+}
+
+static int disp_mix_clks_enable(struct reset_control *reset, bool enable)
+{
+ int ret;
+
+ if (!reset)
+ return 0;
+
+ ret = enable ? reset_control_assert(reset) :
+ reset_control_deassert(reset);
+ return ret;
+}
+
+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_parse_dt(struct mxc_isi_dev *mxc_isi)
{
struct device *dev = &mxc_isi->pdev->dev;
@@ -109,25 +252,114 @@ static int mxc_isi_parse_dt(struct mxc_isi_dev *mxc_isi)
return 0;
}
+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_of_parse_resets(struct mxc_isi_dev *mxc_isi)
+{
+ int ret;
+ struct device *dev = &mxc_isi->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *parent, *child;
+ struct of_phandle_args args;
+ struct reset_control *rstc;
+ const char *compat;
+ uint32_t len, rstc_num = 0;
+
+ ret = of_parse_phandle_with_args(np, "resets", "#reset-cells",
+ 0, &args);
+ if (ret)
+ return ret;
+
+ parent = args.np;
+ for_each_child_of_node(parent, child) {
+ compat = of_get_property(child, "compatible", NULL);
+ if (!compat)
+ continue;
+
+ rstc = of_reset_control_array_get(child, false, false, true);
+ if (IS_ERR(rstc))
+ continue;
+
+ len = strlen(compat);
+ if (!of_compat_cmp("isi,soft-resetn", compat, len)) {
+ mxc_isi->soft_resetn = rstc;
+ rstc_num++;
+ } else if (!of_compat_cmp("isi,clk-enable", compat, len)) {
+ mxc_isi->clk_enable = rstc;
+ rstc_num++;
+ } else {
+ dev_warn(dev, "invalid isi reset node: %s\n", compat);
+ }
+ }
+
+ if (!rstc_num) {
+ dev_err(dev, "no invalid reset control exists\n");
+ return -EINVAL;
+ }
+
+ of_node_put(parent);
+ return 0;
+}
+
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);
if (!mxc_isi)
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)
return ret;
if (mxc_isi->id >= MXC_ISI_MAX_DEVS || mxc_isi->id < 0) {
- dev_err(dev, "Invalid driver data or device id (%d)\n", mxc_isi->id);
+ dev_err(dev, "Invalid driver data or device id (%d)\n",
+ mxc_isi->id);
return -EINVAL;
}
@@ -135,16 +367,18 @@ static int mxc_isi_probe(struct platform_device *pdev)
mutex_init(&mxc_isi->lock);
atomic_set(&mxc_isi->usage_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);
+ if (of_device_is_compatible(dev->of_node, "fsl,imx8mn-isi")) {
+ ret = mxc_isi_of_parse_resets(mxc_isi);
+ if (ret) {
+ dev_warn(dev, "Can not parse reset control\n");
+ return ret;
+ }
}
- ret = clk_prepare_enable(mxc_isi->clk);
+ ret = mxc_isi_clk_get(mxc_isi);
if (ret < 0) {
- dev_err(dev, "Prepare and enable isi clk error (%d)\n", ret);
- return -EINVAL;
+ dev_err(dev, "ISI_%d get clocks fail\n", mxc_isi->id);
+ return ret;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -154,18 +388,26 @@ static int mxc_isi_probe(struct platform_device *pdev)
return PTR_ERR(mxc_isi->regs);
}
+ 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->soft_resetn, false);
+ disp_mix_clks_enable(mxc_isi->clk_enable, true);
+
mxc_isi_clean_registers(mxc_isi);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "Failed to get IRQ resource\n");
- return -ENXIO;
+ goto err;
}
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;
}
mxc_isi_channel_set_chain_buf(mxc_isi);
@@ -174,13 +416,19 @@ static int mxc_isi_probe(struct platform_device *pdev)
if (ret < 0)
dev_warn(dev, "Populate child platform device fail\n");
- clk_disable_unprepare(mxc_isi->clk);
+ mxc_isi_clk_disable(mxc_isi);
platform_set_drvdata(pdev, mxc_isi);
pm_runtime_enable(dev);
dev_info(dev, "mxc_isi.%d registered successfully\n", mxc_isi->id);
return 0;
+
+err:
+ disp_mix_clks_enable(mxc_isi->clk_enable, false);
+ disp_mix_sft_rstn(mxc_isi->soft_resetn, true);
+ mxc_isi_clk_disable(mxc_isi);
+ return -ENXIO;
}
static int mxc_isi_remove(struct platform_device *pdev)
@@ -213,7 +461,9 @@ 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);
+ disp_mix_clks_enable(mxc_isi->clk_enable, false);
+ mxc_isi_clk_disable(mxc_isi);
+
return 0;
}
@@ -222,11 +472,15 @@ 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;
+ }
+ disp_mix_sft_rstn(mxc_isi->soft_resetn, false);
+ disp_mix_clks_enable(mxc_isi->clk_enable, true);
- return (ret) ? ret : 0;
+ return 0;
}
static const struct dev_pm_ops mxc_isi_pm_ops = {
@@ -235,7 +489,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/staging/media/imx/imx8-isi-core.h b/drivers/staging/media/imx/imx8-isi-core.h
index 24fbfbd9c3b9..44f2a25271ee 100644
--- a/drivers/staging/media/imx/imx8-isi-core.h
+++ b/drivers/staging/media/imx/imx8-isi-core.h
@@ -33,6 +33,8 @@
#include <media/v4l2-ctrls.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
#include "imx8-common.h"
@@ -41,6 +43,8 @@
#define MXC_ISI_M2M "mxc-isi-m2m"
#define MXC_MAX_PLANES 3
+struct mxc_isi_dev;
+
enum mxc_isi_out_fmt {
MXC_ISI_OUT_FMT_RGBA32 = 0x0,
MXC_ISI_OUT_FMT_ABGR32,
@@ -188,6 +192,7 @@ struct mxc_isi_buffer {
struct vb2_v4l2_buffer v4l2_buf;
struct list_head list;
struct frame_addr paddr;
+ enum mxc_isi_buf_id id;
bool discard;
};
@@ -223,6 +228,12 @@ struct mxc_isi_ctx {
struct v4l2_fh fh;
};
+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_cap_dev {
struct v4l2_subdev sd;
struct video_device vdev;
@@ -265,8 +276,21 @@ struct mxc_isi_dev {
struct mxc_isi_m2m_dev *isi_m2m;
struct platform_device *pdev;
+
+ /* clk for imx8qxp/qm platform */
struct clk *clk;
+ /* clks for imx8mn platform */
+ struct clk *clk_disp_axi;
+ struct clk *clk_disp_apb;
+ struct clk *clk_root_disp_axi;
+ struct clk *clk_root_disp_apb;
+
+ const struct mxc_isi_dev_ops *ops;
+
+ struct reset_control *soft_resetn;
+ struct reset_control *clk_enable;
+
struct mutex lock;
spinlock_t slock;
@@ -285,6 +309,8 @@ struct mxc_isi_dev {
u32 pre_dec_x;
u32 pre_dec_y;
+ u32 status;
+
u32 interface[MAX_PORTS];
int id;
diff --git a/drivers/staging/media/imx/imx8-isi-hw.c b/drivers/staging/media/imx/imx8-isi-hw.c
index e39cb47ed81c..6605341e0b57 100644
--- a/drivers/staging/media/imx/imx8-isi-hw.c
+++ b/drivers/staging/media/imx/imx8-isi-hw.c
@@ -101,12 +101,13 @@ static void printk_pixelformat(char *prefix, int val)
static bool is_rgb(u32 pix_fmt)
{
if ((pix_fmt == V4L2_PIX_FMT_RGB565) ||
- (pix_fmt == V4L2_PIX_FMT_RGB24) ||
- (pix_fmt == V4L2_PIX_FMT_RGB32) ||
- (pix_fmt == V4L2_PIX_FMT_BGR32) ||
+ (pix_fmt == V4L2_PIX_FMT_RGB24) ||
+ (pix_fmt == V4L2_PIX_FMT_RGB32) ||
+ (pix_fmt == V4L2_PIX_FMT_BGR32) ||
(pix_fmt == V4L2_PIX_FMT_XRGB32) ||
(pix_fmt == V4L2_PIX_FMT_XBGR32) ||
- (pix_fmt == V4L2_PIX_FMT_BGR24) ||
+ (pix_fmt == V4L2_PIX_FMT_BGR24) ||
+ (pix_fmt == V4L2_PIX_FMT_RGBA) ||
(pix_fmt == V4L2_PIX_FMT_ABGR32) ||
(pix_fmt == V4L2_PIX_FMT_ARGB32))
return true;
@@ -116,9 +117,10 @@ static bool is_rgb(u32 pix_fmt)
static bool is_yuv(u32 pix_fmt)
{
- if ((pix_fmt == V4L2_PIX_FMT_YUYV) ||
+ if ((pix_fmt == V4L2_PIX_FMT_YUYV) ||
(pix_fmt == V4L2_PIX_FMT_YUV32) ||
(pix_fmt == V4L2_PIX_FMT_YUV444M) ||
+ (pix_fmt == V4L2_PIX_FMT_YUV24) ||
(pix_fmt == V4L2_PIX_FMT_NV12))
return true;
else
@@ -129,7 +131,7 @@ static void chain_buf(struct mxc_isi_dev *mxc_isi, struct mxc_isi_frame *frm)
{
u32 val;
- if (frm->o_width > 2048) {
+ if (frm->o_width > ISI_2K) {
val = readl(mxc_isi->regs + CHNL_CTRL);
val &= ~CHNL_CTRL_CHAIN_BUF_MASK;
val |= (CHNL_CTRL_CHAIN_BUF_2_CHAIN << CHNL_CTRL_CHAIN_BUF_OFFSET);
@@ -174,16 +176,18 @@ void mxc_isi_channel_set_outbuf(struct mxc_isi_dev *mxc_isi,
val = readl(mxc_isi->regs + CHNL_OUT_BUF_CTRL);
- if (framecount % 2 == 0) {
+ if (framecount == 0 || ((mxc_isi->status & 0x100) && (framecount != 1))) {
writel(paddr->y, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_Y);
writel(paddr->cb, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_U);
writel(paddr->cr, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_V);
val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF1_ADDR_MASK;
- } else if (framecount % 2 == 1) {
+ buf->id = MXC_ISI_BUF1;
+ } else if (framecount == 1 || mxc_isi->status & 0x200) {
writel(paddr->y, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_Y);
writel(paddr->cb, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_U);
writel(paddr->cr, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_V);
val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF2_ADDR_MASK;
+ buf->id = MXC_ISI_BUF2;
}
writel(val, mxc_isi->regs + CHNL_OUT_BUF_CTRL);
}
@@ -701,7 +705,6 @@ void mxc_isi_m2m_config_src(struct mxc_isi_dev *mxc_isi,
void mxc_isi_m2m_config_dst(struct mxc_isi_dev *mxc_isi,
struct mxc_isi_frame *dst_f)
{
- /*struct mxc_isi_frame *dst_f = &mxc_isi->isi_m2m->dst_f;*/
u32 val;
/* out format */
diff --git a/drivers/staging/media/imx/imx8-isi-hw.h b/drivers/staging/media/imx/imx8-isi-hw.h
index eefb18d81cea..268be48d1f7f 100644
--- a/drivers/staging/media/imx/imx8-isi-hw.h
+++ b/drivers/staging/media/imx/imx8-isi-hw.h
@@ -447,6 +447,13 @@
#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,