summaryrefslogtreecommitdiff
path: root/drivers/media/platform/nxp/imx8-isi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/nxp/imx8-isi')
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c135
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h6
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c18
3 files changed, 77 insertions, 82 deletions
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
index 1e79b1211b60..981648a03113 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
@@ -3,6 +3,7 @@
* Copyright 2019-2020 NXP
*/
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/errno.h>
@@ -245,26 +246,41 @@ static void mxc_isi_v4l2_cleanup(struct mxc_isi_dev *isi)
/* Panic will assert when the buffers are 50% full */
-/* For i.MX8QXP C0 and i.MX8MN ISI IER version */
+/* For i.MX8MN ISI IER version */
static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v1 = {
- .oflw_y_buf_en = { .offset = 19, .mask = 0x80000 },
- .oflw_u_buf_en = { .offset = 21, .mask = 0x200000 },
- .oflw_v_buf_en = { .offset = 23, .mask = 0x800000 },
+ .oflw_y_buf_en = { .mask = BIT(19) },
+ .oflw_u_buf_en = { .mask = BIT(21) },
+ .oflw_v_buf_en = { .mask = BIT(23) },
- .panic_y_buf_en = {.offset = 20, .mask = 0x100000 },
- .panic_u_buf_en = {.offset = 22, .mask = 0x400000 },
- .panic_v_buf_en = {.offset = 24, .mask = 0x1000000 },
+ .panic_y_buf_en = { .mask = BIT(20) },
+ .panic_u_buf_en = { .mask = BIT(22) },
+ .panic_v_buf_en = { .mask = BIT(24) },
};
-/* For i.MX8MP ISI IER version */
+/* For i.MX8QXP C0 and i.MX8MP ISI IER version */
static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v2 = {
- .oflw_y_buf_en = { .offset = 18, .mask = 0x40000 },
- .oflw_u_buf_en = { .offset = 20, .mask = 0x100000 },
- .oflw_v_buf_en = { .offset = 22, .mask = 0x400000 },
+ .oflw_y_buf_en = { .mask = BIT(18) },
+ .oflw_u_buf_en = { .mask = BIT(20) },
+ .oflw_v_buf_en = { .mask = BIT(22) },
- .panic_y_buf_en = {.offset = 19, .mask = 0x80000 },
- .panic_u_buf_en = {.offset = 21, .mask = 0x200000 },
- .panic_v_buf_en = {.offset = 23, .mask = 0x800000 },
+ .panic_y_buf_en = { .mask = BIT(19) },
+ .panic_u_buf_en = { .mask = BIT(21) },
+ .panic_v_buf_en = { .mask = BIT(23) },
+};
+
+/* For i.MX8QM ISI IER version */
+static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_qm = {
+ .oflw_y_buf_en = { .mask = BIT(16) },
+ .oflw_u_buf_en = { .mask = BIT(19) },
+ .oflw_v_buf_en = { .mask = BIT(22) },
+
+ .excs_oflw_y_buf_en = { .mask = BIT(17) },
+ .excs_oflw_u_buf_en = { .mask = BIT(20) },
+ .excs_oflw_v_buf_en = { .mask = BIT(23) },
+
+ .panic_y_buf_en = { .mask = BIT(18) },
+ .panic_u_buf_en = { .mask = BIT(21) },
+ .panic_v_buf_en = { .mask = BIT(24) },
};
/* Panic will assert when the buffers are 50% full */
@@ -274,11 +290,6 @@ static const struct mxc_isi_set_thd mxc_imx8_isi_thd_v1 = {
.panic_set_thd_v = { .mask = 0xf0000, .offset = 16, .threshold = 0x7 },
};
-static const struct clk_bulk_data mxc_imx8mn_clks[] = {
- { .id = "axi" },
- { .id = "apb" },
-};
-
static const struct mxc_isi_plat_data mxc_imx8mn_data = {
.model = MXC_ISI_IMX8MN,
.num_ports = 1,
@@ -286,8 +297,6 @@ static const struct mxc_isi_plat_data mxc_imx8mn_data = {
.reg_offset = 0,
.ier_reg = &mxc_imx8_isi_ier_v1,
.set_thd = &mxc_imx8_isi_thd_v1,
- .clks = mxc_imx8mn_clks,
- .num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
.buf_active_reverse = false,
.gasket_ops = &mxc_imx8_gasket_ops,
.has_36bit_dma = false,
@@ -300,8 +309,6 @@ static const struct mxc_isi_plat_data mxc_imx8mp_data = {
.reg_offset = 0x2000,
.ier_reg = &mxc_imx8_isi_ier_v2,
.set_thd = &mxc_imx8_isi_thd_v1,
- .clks = mxc_imx8mn_clks,
- .num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
.buf_active_reverse = true,
.gasket_ops = &mxc_imx8_gasket_ops,
.has_36bit_dma = true,
@@ -314,8 +321,6 @@ static const struct mxc_isi_plat_data mxc_imx8ulp_data = {
.reg_offset = 0x0,
.ier_reg = &mxc_imx8_isi_ier_v2,
.set_thd = &mxc_imx8_isi_thd_v1,
- .clks = mxc_imx8mn_clks,
- .num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
.buf_active_reverse = true,
.has_36bit_dma = false,
};
@@ -327,13 +332,33 @@ static const struct mxc_isi_plat_data mxc_imx93_data = {
.reg_offset = 0,
.ier_reg = &mxc_imx8_isi_ier_v2,
.set_thd = &mxc_imx8_isi_thd_v1,
- .clks = mxc_imx8mn_clks,
- .num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
.buf_active_reverse = true,
.gasket_ops = &mxc_imx93_gasket_ops,
.has_36bit_dma = false,
};
+static const struct mxc_isi_plat_data mxc_imx8qm_data = {
+ .model = MXC_ISI_IMX8QM,
+ .num_ports = 5,
+ .num_channels = 8,
+ .reg_offset = 0x10000,
+ .ier_reg = &mxc_imx8_isi_ier_qm,
+ .set_thd = &mxc_imx8_isi_thd_v1,
+ .buf_active_reverse = true,
+ .has_36bit_dma = false,
+};
+
+static const struct mxc_isi_plat_data mxc_imx8qxp_data = {
+ .model = MXC_ISI_IMX8QXP,
+ .num_ports = 5,
+ .num_channels = 6,
+ .reg_offset = 0x10000,
+ .ier_reg = &mxc_imx8_isi_ier_v2,
+ .set_thd = &mxc_imx8_isi_thd_v1,
+ .buf_active_reverse = true,
+ .has_36bit_dma = false,
+};
+
/* -----------------------------------------------------------------------------
* Power management
*/
@@ -385,7 +410,7 @@ static int mxc_isi_runtime_suspend(struct device *dev)
{
struct mxc_isi_dev *isi = dev_get_drvdata(dev);
- clk_bulk_disable_unprepare(isi->pdata->num_clks, isi->clks);
+ clk_bulk_disable_unprepare(isi->num_clks, isi->clks);
return 0;
}
@@ -395,7 +420,7 @@ static int mxc_isi_runtime_resume(struct device *dev)
struct mxc_isi_dev *isi = dev_get_drvdata(dev);
int ret;
- ret = clk_bulk_prepare_enable(isi->pdata->num_clks, isi->clks);
+ ret = clk_bulk_prepare_enable(isi->num_clks, isi->clks);
if (ret) {
dev_err(dev, "Failed to enable clocks (%d)\n", ret);
return ret;
@@ -413,27 +438,6 @@ static const struct dev_pm_ops mxc_isi_pm_ops = {
* Probe, remove & driver
*/
-static int mxc_isi_clk_get(struct mxc_isi_dev *isi)
-{
- unsigned int size = isi->pdata->num_clks
- * sizeof(*isi->clks);
- int ret;
-
- isi->clks = devm_kmemdup(isi->dev, isi->pdata->clks, size, GFP_KERNEL);
- if (!isi->clks)
- return -ENOMEM;
-
- ret = devm_clk_bulk_get(isi->dev, isi->pdata->num_clks,
- isi->clks);
- if (ret < 0) {
- dev_err(isi->dev, "Failed to acquire clocks: %d\n",
- ret);
- return ret;
- }
-
- return 0;
-}
-
static int mxc_isi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -456,34 +460,25 @@ static int mxc_isi_probe(struct platform_device *pdev)
if (!isi->pipes)
return -ENOMEM;
- ret = mxc_isi_clk_get(isi);
- if (ret < 0) {
- dev_err(dev, "Failed to get clocks\n");
- return ret;
- }
+ isi->num_clks = devm_clk_bulk_get_all(dev, &isi->clks);
+ if (isi->num_clks < 0)
+ return dev_err_probe(dev, isi->num_clks, "Failed to get clocks\n");
isi->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(isi->regs)) {
- dev_err(dev, "Failed to get ISI register map\n");
- return PTR_ERR(isi->regs);
- }
+ if (IS_ERR(isi->regs))
+ return dev_err_probe(dev, PTR_ERR(isi->regs),
+ "Failed to get ISI register map\n");
if (isi->pdata->gasket_ops) {
isi->gasket = syscon_regmap_lookup_by_phandle(dev->of_node,
"fsl,blk-ctrl");
- if (IS_ERR(isi->gasket)) {
- ret = PTR_ERR(isi->gasket);
- dev_err(dev, "failed to get gasket: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(isi->gasket))
+ return dev_err_probe(dev, PTR_ERR(isi->gasket),
+ "failed to get gasket\n");
}
dma_size = isi->pdata->has_36bit_dma ? 36 : 32;
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size));
- if (ret) {
- dev_err(dev, "failed to set DMA mask\n");
- return ret;
- }
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size));
pm_runtime_enable(dev);
@@ -541,6 +536,8 @@ static void mxc_isi_remove(struct platform_device *pdev)
static const struct of_device_id mxc_isi_of_match[] = {
{ .compatible = "fsl,imx8mn-isi", .data = &mxc_imx8mn_data },
{ .compatible = "fsl,imx8mp-isi", .data = &mxc_imx8mp_data },
+ { .compatible = "fsl,imx8qm-isi", .data = &mxc_imx8qm_data },
+ { .compatible = "fsl,imx8qxp-isi", .data = &mxc_imx8qxp_data },
{ .compatible = "fsl,imx8ulp-isi", .data = &mxc_imx8ulp_data },
{ .compatible = "fsl,imx93-isi", .data = &mxc_imx93_data },
{ /* sentinel */ },
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
index 9c7fe9e5f941..206995bedca4 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
@@ -114,7 +114,6 @@ struct mxc_isi_buffer {
};
struct mxc_isi_reg {
- u32 offset;
u32 mask;
};
@@ -158,6 +157,8 @@ struct mxc_gasket_ops {
enum model {
MXC_ISI_IMX8MN,
MXC_ISI_IMX8MP,
+ MXC_ISI_IMX8QM,
+ MXC_ISI_IMX8QXP,
MXC_ISI_IMX8ULP,
MXC_ISI_IMX93,
};
@@ -170,8 +171,6 @@ struct mxc_isi_plat_data {
const struct mxc_isi_ier_reg *ier_reg;
const struct mxc_isi_set_thd *set_thd;
const struct mxc_gasket_ops *gasket_ops;
- const struct clk_bulk_data *clks;
- unsigned int num_clks;
bool buf_active_reverse;
bool has_36bit_dma;
};
@@ -283,6 +282,7 @@ struct mxc_isi_dev {
void __iomem *regs;
struct clk_bulk_data *clks;
+ int num_clks;
struct regmap *gasket;
struct mxc_isi_crossbar crossbar;
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
index 93a55c97cd17..ede6cc74c023 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
@@ -188,11 +188,12 @@ static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd,
* Create a 1:1 mapping between pixel link inputs and outputs to
* pipelines by default.
*/
- routes = kcalloc(xbar->num_sources, sizeof(*routes), GFP_KERNEL);
+ routing.num_routes = min(xbar->num_sinks - 1, xbar->num_sources);
+ routes = kcalloc(routing.num_routes, sizeof(*routes), GFP_KERNEL);
if (!routes)
return -ENOMEM;
- for (i = 0; i < xbar->num_sources; ++i) {
+ for (i = 0; i < routing.num_routes; ++i) {
struct v4l2_subdev_route *route = &routes[i];
route->sink_pad = i;
@@ -200,7 +201,6 @@ static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd,
route->flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE;
}
- routing.num_routes = xbar->num_sources;
routing.routes = routes;
ret = __mxc_isi_crossbar_set_routing(sd, state, &routing);
@@ -352,9 +352,8 @@ static int mxc_isi_crossbar_enable_streams(struct v4l2_subdev *sd,
sink_streams);
if (ret) {
dev_err(xbar->isi->dev,
- "failed to %s streams 0x%llx on '%s':%u: %d\n",
- "enable", sink_streams, remote_sd->name,
- remote_pad, ret);
+ "failed to enable streams 0x%llx on '%s':%u: %d\n",
+ sink_streams, remote_sd->name, remote_pad, ret);
mxc_isi_crossbar_gasket_disable(xbar, sink_pad);
return ret;
}
@@ -392,9 +391,8 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd,
sink_streams);
if (ret)
dev_err(xbar->isi->dev,
- "failed to %s streams 0x%llx on '%s':%u: %d\n",
- "disable", sink_streams, remote_sd->name,
- remote_pad, ret);
+ "failed to disable streams 0x%llx on '%s':%u: %d\n",
+ sink_streams, remote_sd->name, remote_pad, ret);
mxc_isi_crossbar_gasket_disable(xbar, sink_pad);
}
@@ -453,7 +451,7 @@ int mxc_isi_crossbar_init(struct mxc_isi_dev *isi)
* the memory input.
*/
xbar->num_sinks = isi->pdata->num_ports + 1;
- xbar->num_sources = isi->pdata->num_ports;
+ xbar->num_sources = isi->pdata->num_channels;
num_pads = xbar->num_sinks + xbar->num_sources;
xbar->pads = kcalloc(num_pads, sizeof(*xbar->pads), GFP_KERNEL);