* [PATCH 00/28] IPUv3 prep for video capture
@ 2014-06-26 1:05 Steve Longerbeam
2014-06-26 1:05 ` [PATCH 01/28] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
` (29 more replies)
0 siblings, 30 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Hi Philip, Sascha,
Here is a rebased set of IPU patches that prepares for video capture
support. Video capture is not included in this set. I've addressed
all your IPU-specific concerns from the previous patch set, the
major ones being:
- the IOMUXC control for CSI input selection has been removed. This
should be part of a future CSI media entity driver.
- the ipu-irt unit has been removed. Enabling the IRT module is
folded into ipu-ic unit. The ipu-ic unit is also cleaned up a bit.
- the ipu-csi APIs are consolidated/simplified.
- added CSI and IC base offsets for i.MX51/i.MX53.
Steve Longerbeam (28):
ARM: dts: imx6qdl: Add ipu aliases
gpu: ipu-v3: Add ipu_get_num()
gpu: ipu-v3: Add functions to set CSI/IC source muxes
gpu: ipu-v3: Rename and add IDMAC channels
gpu: ipu-v3: Add units required for video capture
gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c
gpu: ipu-v3: smfc: Convert to per-channel
gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark()
gpu: ipu-v3: Add ipu_mbus_code_to_colorspace()
gpu: ipu-v3: Add rotation mode conversion utilities
gpu: ipu-v3: Add helper function checking if pixfmt is planar
gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
gpu: ipu-v3: Add ipu_idmac_buffer_is_ready()
gpu: ipu-v3: Add ipu_idmac_clear_buffer()
gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer()
gpu: ipu-v3: Add ipu_stride_to_bytes()
gpu: ipu-v3: Add ipu_idmac_enable_watermark()
gpu: ipu-v3: Add ipu_idmac_lock_enable()
gpu: ipu-v3: Add idmac channel linking support
gpu: ipu-v3: Add ipu-cpmem unit
staging: imx-drm: Convert to new ipu_cpmem API
gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode()
gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id()
gpu: ipu-cpmem: Add ipu_cpmem_set_rotation()
gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
gpu: ipu-v3: Add more planar formats support
gpu: ipu-cpmem: Add ipu_cpmem_dump()
gpu: ipu-v3: Add ipu_dump()
arch/arm/boot/dts/imx6q.dtsi | 1 +
arch/arm/boot/dts/imx6qdl.dtsi | 1 +
drivers/gpu/ipu-v3/Makefile | 3 +-
drivers/gpu/ipu-v3/ipu-common.c | 1077 +++++++++++++++++++--------------
drivers/gpu/ipu-v3/ipu-cpmem.c | 817 +++++++++++++++++++++++++
drivers/gpu/ipu-v3/ipu-csi.c | 701 +++++++++++++++++++++
drivers/gpu/ipu-v3/ipu-ic.c | 812 +++++++++++++++++++++++++
drivers/gpu/ipu-v3/ipu-prv.h | 103 +++-
drivers/gpu/ipu-v3/ipu-smfc.c | 156 ++++-
drivers/staging/imx-drm/ipuv3-plane.c | 16 +-
include/video/imx-ipu-v3.h | 371 +++++++-----
11 files changed, 3389 insertions(+), 669 deletions(-)
create mode 100644 drivers/gpu/ipu-v3/ipu-cpmem.c
create mode 100644 drivers/gpu/ipu-v3/ipu-csi.c
create mode 100644 drivers/gpu/ipu-v3/ipu-ic.c
--
1.7.9.5
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH 01/28] ARM: dts: imx6qdl: Add ipu aliases
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-07-31 15:28 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 02/28] gpu: ipu-v3: Add ipu_get_num() Steve Longerbeam
` (28 subsequent siblings)
29 siblings, 1 reply; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Add ipu0 (and ipu1 for quad) aliases to ipu1/ipu2 nodes respectively.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
arch/arm/boot/dts/imx6q.dtsi | 1 +
arch/arm/boot/dts/imx6qdl.dtsi | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index addd3f8..fcfbac2 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -14,6 +14,7 @@
/ {
aliases {
+ ipu1 = &ipu2;
spi4 = &ecspi5;
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index ce05991..3b3d8fe 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -29,6 +29,7 @@
i2c0 = &i2c1;
i2c1 = &i2c2;
i2c2 = &i2c3;
+ ipu0 = &ipu1;
mmc0 = &usdhc1;
mmc1 = &usdhc2;
mmc2 = &usdhc3;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 02/28] gpu: ipu-v3: Add ipu_get_num()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
2014-06-26 1:05 ` [PATCH 01/28] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-07-31 15:28 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 03/28] gpu: ipu-v3: Add functions to set CSI/IC source muxes Steve Longerbeam
` (27 subsequent siblings)
29 siblings, 1 reply; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds of-alias id to ipu_soc and retrieve with ipu_get_num().
ipu_get_num() is used to select inputs to CSI units in IOMUXC.
It is also used to select an SMFC channel for video capture.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 8 ++++++++
drivers/gpu/ipu-v3/ipu-prv.h | 1 +
include/video/imx-ipu-v3.h | 5 +++++
3 files changed, 14 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 04e7b2e..a92f48b 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -55,6 +55,12 @@ static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
writel(value, ipu->idmac_reg + offset);
}
+int ipu_get_num(struct ipu_soc *ipu)
+{
+ return ipu->id;
+}
+EXPORT_SYMBOL_GPL(ipu_get_num);
+
void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
{
u32 val;
@@ -1205,6 +1211,7 @@ static int ipu_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(imx_ipu_dt_ids, &pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
struct ipu_soc *ipu;
struct resource *res;
unsigned long ipu_base;
@@ -1233,6 +1240,7 @@ static int ipu_probe(struct platform_device *pdev)
ipu->channel[i].ipu = ipu;
ipu->devtype = devtype;
ipu->ipu_type = devtype->type;
+ ipu->id = of_alias_get_id(np, "ipu");
spin_lock_init(&ipu->lock);
mutex_init(&ipu->channel_lock);
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index c93f50e..55ae20c 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -166,6 +166,7 @@ struct ipu_soc {
void __iomem *idmac_reg;
struct ipu_ch_param __iomem *cpmem_base;
+ int id;
int usecount;
struct clk *clk;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 3e43e22..739d204 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -93,6 +93,11 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
#define IPU_IRQ_VSYNC_PRE_1 (448 + 15)
/*
+ * IPU Common functions
+ */
+int ipu_get_num(struct ipu_soc *ipu);
+
+/*
* IPU Image DMA Controller (idmac) functions
*/
struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 03/28] gpu: ipu-v3: Add functions to set CSI/IC source muxes
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
2014-06-26 1:05 ` [PATCH 01/28] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
2014-06-26 1:05 ` [PATCH 02/28] gpu: ipu-v3: Add ipu_get_num() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 04/28] gpu: ipu-v3: Rename and add IDMAC channels Steve Longerbeam
` (26 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds two new functions, ipu_set_csi_src_mux() and ipu_set_ic_src_mux(),
that select the inputs to the CSI and IC respectively. Both muxes are
programmed in the IPU_CONF register.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 51 +++++++++++++++++++++++++++++++++++++++
include/video/imx-ipu-v3.h | 2 ++
2 files changed, 53 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index a92f48b..1155eb9 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -832,6 +832,57 @@ static int ipu_memory_reset(struct ipu_soc *ipu)
return 0;
}
+/*
+ * Set the source mux for the given CSI. Selects either parallel or
+ * MIPI CSI2 sources.
+ */
+void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
+{
+ unsigned long flags;
+ u32 val, mask;
+
+ mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
+ IPU_CONF_CSI0_DATA_SOURCE;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ val = ipu_cm_read(ipu, IPU_CONF);
+ if (mipi_csi2)
+ val |= mask;
+ else
+ val &= ~mask;
+ ipu_cm_write(ipu, val, IPU_CONF);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
+
+/*
+ * Set the source mux for the IC. Selects either CSI[01] or the VDI.
+ */
+void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ val = ipu_cm_read(ipu, IPU_CONF);
+ if (vdi) {
+ val |= IPU_CONF_IC_INPUT;
+ } else {
+ val &= ~IPU_CONF_IC_INPUT;
+ if (csi_id == 1)
+ val |= IPU_CONF_CSI_SEL;
+ else
+ val &= ~IPU_CONF_CSI_SEL;
+ }
+ ipu_cm_write(ipu, val, IPU_CONF);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
+
struct ipu_devtype {
const char *name;
unsigned long cm_ofs;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 739d204..52fa277 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -96,6 +96,8 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
* IPU Common functions
*/
int ipu_get_num(struct ipu_soc *ipu);
+void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
+void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
/*
* IPU Image DMA Controller (idmac) functions
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 04/28] gpu: ipu-v3: Rename and add IDMAC channels
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (2 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 03/28] gpu: ipu-v3: Add functions to set CSI/IC source muxes Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 05/28] gpu: ipu-v3: Add units required for video capture Steve Longerbeam
` (25 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Rename the ENC/VF/PP rotation channel names, to be more consistent
with the convention that *_MEM is write-to-memory channels and
MEM_* is read-from-memory channels. Also add the channels who's
source and destination is the IC.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-prv.h | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index 55ae20c..7d8d95b 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -28,17 +28,25 @@ struct ipu_soc;
#define IPUV3_CHANNEL_CSI1 1
#define IPUV3_CHANNEL_CSI2 2
#define IPUV3_CHANNEL_CSI3 3
+#define IPUV3_CHANNEL_VDI_MEM_IC_VF 5
+#define IPUV3_CHANNEL_MEM_IC_PP 11
+#define IPUV3_CHANNEL_MEM_IC_PRP_VF 12
+#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF 14
+#define IPUV3_CHANNEL_G_MEM_IC_PP 15
+#define IPUV3_CHANNEL_IC_PRP_ENC_MEM 20
+#define IPUV3_CHANNEL_IC_PRP_VF_MEM 21
+#define IPUV3_CHANNEL_IC_PP_MEM 22
#define IPUV3_CHANNEL_MEM_BG_SYNC 23
#define IPUV3_CHANNEL_MEM_FG_SYNC 27
#define IPUV3_CHANNEL_MEM_DC_SYNC 28
#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31
#define IPUV3_CHANNEL_MEM_DC_ASYNC 41
-#define IPUV3_CHANNEL_ROT_ENC_MEM 45
-#define IPUV3_CHANNEL_ROT_VF_MEM 46
-#define IPUV3_CHANNEL_ROT_PP_MEM 47
-#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT 48
-#define IPUV3_CHANNEL_ROT_VF_MEM_OUT 49
-#define IPUV3_CHANNEL_ROT_PP_MEM_OUT 50
+#define IPUV3_CHANNEL_MEM_ROT_ENC 45
+#define IPUV3_CHANNEL_MEM_ROT_VF 46
+#define IPUV3_CHANNEL_MEM_ROT_PP 47
+#define IPUV3_CHANNEL_ROT_ENC_MEM 48
+#define IPUV3_CHANNEL_ROT_VF_MEM 49
+#define IPUV3_CHANNEL_ROT_PP_MEM 50
#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51
#define IPU_MCU_T_DEFAULT 8
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 05/28] gpu: ipu-v3: Add units required for video capture
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (3 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 04/28] gpu: ipu-v3: Rename and add IDMAC channels Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-07-31 15:27 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 06/28] gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c Steve Longerbeam
` (24 subsequent siblings)
29 siblings, 1 reply; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds the following new IPU units:
- Camera Sensor Interface (csi)
- Image Converter (ic)
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/Makefile | 3 +-
drivers/gpu/ipu-v3/ipu-common.c | 63 ++-
drivers/gpu/ipu-v3/ipu-csi.c | 701 +++++++++++++++++++++++++++++++++
drivers/gpu/ipu-v3/ipu-ic.c | 812 +++++++++++++++++++++++++++++++++++++++
drivers/gpu/ipu-v3/ipu-prv.h | 12 +
include/video/imx-ipu-v3.h | 113 +++++-
6 files changed, 1688 insertions(+), 16 deletions(-)
create mode 100644 drivers/gpu/ipu-v3/ipu-csi.c
create mode 100644 drivers/gpu/ipu-v3/ipu-ic.c
diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile
index 1887972b..830804f 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/ipu-v3/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
-imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o ipu-smfc.o
+imx-ipu-v3-objs := ipu-common.o ipu-csi.o ipu-dc.o ipu-di.o ipu-dp.o \
+ ipu-dmfc.o ipu-ic.o ipu-smfc.o
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 1155eb9..0ac2103 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -667,18 +667,6 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
}
EXPORT_SYMBOL_GPL(ipu_module_disable);
-int ipu_csi_enable(struct ipu_soc *ipu, int csi)
-{
- return ipu_module_enable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN);
-}
-EXPORT_SYMBOL_GPL(ipu_csi_enable);
-
-int ipu_csi_disable(struct ipu_soc *ipu, int csi)
-{
- return ipu_module_disable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN);
-}
-EXPORT_SYMBOL_GPL(ipu_csi_disable);
-
int ipu_smfc_enable(struct ipu_soc *ipu)
{
return ipu_module_enable(ipu, IPU_CONF_SMFC_EN);
@@ -889,6 +877,9 @@ struct ipu_devtype {
unsigned long cpmem_ofs;
unsigned long srm_ofs;
unsigned long tpm_ofs;
+ unsigned long csi0_ofs;
+ unsigned long csi1_ofs;
+ unsigned long ic_ofs;
unsigned long disp0_ofs;
unsigned long disp1_ofs;
unsigned long dc_tmpl_ofs;
@@ -902,6 +893,9 @@ static struct ipu_devtype ipu_type_imx51 = {
.cpmem_ofs = 0x1f000000,
.srm_ofs = 0x1f040000,
.tpm_ofs = 0x1f060000,
+ .csi0_ofs = 0x1f030000,
+ .csi1_ofs = 0x1f038000,
+ .ic_ofs = 0x1f020000,
.disp0_ofs = 0x1e040000,
.disp1_ofs = 0x1e048000,
.dc_tmpl_ofs = 0x1f080000,
@@ -915,6 +909,9 @@ static struct ipu_devtype ipu_type_imx53 = {
.cpmem_ofs = 0x07000000,
.srm_ofs = 0x07040000,
.tpm_ofs = 0x07060000,
+ .csi0_ofs = 0x07030000,
+ .csi1_ofs = 0x07038000,
+ .ic_ofs = 0x07020000,
.disp0_ofs = 0x06040000,
.disp1_ofs = 0x06048000,
.dc_tmpl_ofs = 0x07080000,
@@ -928,6 +925,9 @@ static struct ipu_devtype ipu_type_imx6q = {
.cpmem_ofs = 0x00300000,
.srm_ofs = 0x00340000,
.tpm_ofs = 0x00360000,
+ .csi0_ofs = 0x00230000,
+ .csi1_ofs = 0x00238000,
+ .ic_ofs = 0x00220000,
.disp0_ofs = 0x00240000,
.disp1_ofs = 0x00248000,
.dc_tmpl_ofs = 0x00380000,
@@ -952,8 +952,30 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
struct device *dev = &pdev->dev;
const struct ipu_devtype *devtype = ipu->devtype;
+ ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
+ IPU_CONF_CSI0_EN, ipu_clk);
+ if (ret) {
+ unit = "csi0";
+ goto err_csi_0;
+ }
+
+ ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
+ IPU_CONF_CSI1_EN, ipu_clk);
+ if (ret) {
+ unit = "csi1";
+ goto err_csi_1;
+ }
+
+ ret = ipu_ic_init(ipu, dev,
+ ipu_base + devtype->ic_ofs,
+ ipu_base + devtype->tpm_ofs);
+ if (ret) {
+ unit = "ic";
+ goto err_ic;
+ }
+
ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
- IPU_CONF_DI0_EN, ipu_clk);
+ IPU_CONF_DI0_EN, ipu_clk);
if (ret) {
unit = "di0";
goto err_di_0;
@@ -1006,6 +1028,12 @@ err_dc:
err_di_1:
ipu_di_exit(ipu, 0);
err_di_0:
+ ipu_ic_exit(ipu);
+err_ic:
+ ipu_csi_exit(ipu, 1);
+err_csi_1:
+ ipu_csi_exit(ipu, 0);
+err_csi_0:
dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
return ret;
}
@@ -1082,6 +1110,9 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
ipu_dc_exit(ipu);
ipu_di_exit(ipu, 1);
ipu_di_exit(ipu, 0);
+ ipu_ic_exit(ipu);
+ ipu_csi_exit(ipu, 1);
+ ipu_csi_exit(ipu, 0);
}
static int platform_remove_devices_fn(struct device *dev, void *unused)
@@ -1302,6 +1333,12 @@ static int ipu_probe(struct platform_device *pdev)
ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n",
ipu_base + devtype->cpmem_ofs);
+ dev_dbg(&pdev->dev, "csi0: 0x%08lx\n",
+ ipu_base + devtype->csi0_ofs);
+ dev_dbg(&pdev->dev, "csi1: 0x%08lx\n",
+ ipu_base + devtype->csi1_ofs);
+ dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
+ ipu_base + devtype->ic_ofs);
dev_dbg(&pdev->dev, "disp0: 0x%08lx\n",
ipu_base + devtype->disp0_ofs);
dev_dbg(&pdev->dev, "disp1: 0x%08lx\n",
diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
new file mode 100644
index 0000000..3ca3e7c
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright (C) 2012-2014 Mentor Graphics Inc.
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <uapi/linux/v4l2-mediabus.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include "ipu-prv.h"
+
+struct ipu_csi {
+ void __iomem *base;
+ int id;
+ u32 module;
+ struct clk *clk_ipu; /* IPU bus clock */
+ spinlock_t lock;
+ bool inuse;
+ struct ipu_soc *ipu;
+};
+
+/* CSI Register Offsets */
+#define CSI_SENS_CONF 0x0000
+#define CSI_SENS_FRM_SIZE 0x0004
+#define CSI_ACT_FRM_SIZE 0x0008
+#define CSI_OUT_FRM_CTRL 0x000C
+#define CSI_TST_CTRL 0x0010
+#define CSI_CCIR_CODE_1 0x0014
+#define CSI_CCIR_CODE_2 0x0018
+#define CSI_CCIR_CODE_3 0x001C
+#define CSI_MIPI_DI 0x0020
+#define CSI_SKIP 0x0024
+#define CSI_CPD_CTRL 0x0028
+#define CSI_CPD_RC(n) (0x002C + ((n)*4))
+#define CSI_CPD_RS(n) (0x004C + ((n)*4))
+#define CSI_CPD_GRC(n) (0x005C + ((n)*4))
+#define CSI_CPD_GRS(n) (0x007C + ((n)*4))
+#define CSI_CPD_GBC(n) (0x008C + ((n)*4))
+#define CSI_CPD_GBS(n) (0x00AC + ((n)*4))
+#define CSI_CPD_BC(n) (0x00BC + ((n)*4))
+#define CSI_CPD_BS(n) (0x00DC + ((n)*4))
+#define CSI_CPD_OFFSET1 0x00EC
+#define CSI_CPD_OFFSET2 0x00F0
+
+/* CSI Register Fields */
+#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
+#define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700
+#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L
+#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L
+#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
+#define CSI_SENS_CONF_DATA_FMT_BAYER 3L
+#define CSI_SENS_CONF_DATA_FMT_RGB565 4L
+#define CSI_SENS_CONF_DATA_FMT_RGB555 5L
+#define CSI_SENS_CONF_DATA_FMT_RGB444 6L
+#define CSI_SENS_CONF_DATA_FMT_JPEG 7L
+
+#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
+#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
+#define CSI_SENS_CONF_DATA_POL_SHIFT 2
+#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
+#define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070L
+#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
+#define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7
+#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11
+#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
+#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
+
+#define CSI_SENS_CONF_DIVRATIO_MASK 0x00FF0000L
+#define CSI_SENS_CONF_DATA_DEST_SHIFT 24
+#define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000L
+#define CSI_SENS_CONF_JPEG8_EN_SHIFT 27
+#define CSI_SENS_CONF_JPEG_EN_SHIFT 28
+#define CSI_SENS_CONF_FORCE_EOF_SHIFT 29
+#define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31
+
+#define CSI_DATA_DEST_IC 2L
+#define CSI_DATA_DEST_IDMAC 4L
+
+#define CSI_CCIR_ERR_DET_EN 0x01000000L
+#define CSI_HORI_DOWNSIZE_EN 0x80000000L
+#define CSI_VERT_DOWNSIZE_EN 0x40000000L
+#define CSI_TEST_GEN_MODE_EN 0x01000000L
+
+#define CSI_HSC_MASK 0x1FFF0000
+#define CSI_HSC_SHIFT 16
+#define CSI_VSC_MASK 0x00000FFF
+#define CSI_VSC_SHIFT 0
+
+#define CSI_TEST_GEN_R_MASK 0x000000FFL
+#define CSI_TEST_GEN_R_SHIFT 0
+#define CSI_TEST_GEN_G_MASK 0x0000FF00L
+#define CSI_TEST_GEN_G_SHIFT 8
+#define CSI_TEST_GEN_B_MASK 0x00FF0000L
+#define CSI_TEST_GEN_B_SHIFT 16
+
+#define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007L
+#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0
+#define CSI_SKIP_SMFC_MASK 0x000000F8L
+#define CSI_SKIP_SMFC_SHIFT 3
+#define CSI_ID_2_SKIP_MASK 0x00000300L
+#define CSI_ID_2_SKIP_SHIFT 8
+
+#define CSI_COLOR_FIRST_ROW_MASK 0x00000002L
+#define CSI_COLOR_FIRST_COMP_MASK 0x00000001L
+
+/* MIPI CSI-2 data types */
+#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */
+#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */
+#define MIPI_DT_YUV422 0x1e /* UYVY... */
+#define MIPI_DT_RGB444 0x20
+#define MIPI_DT_RGB555 0x21
+#define MIPI_DT_RGB565 0x22
+#define MIPI_DT_RGB666 0x23
+#define MIPI_DT_RGB888 0x24
+#define MIPI_DT_RAW6 0x28
+#define MIPI_DT_RAW7 0x29
+#define MIPI_DT_RAW8 0x2a
+#define MIPI_DT_RAW10 0x2b
+#define MIPI_DT_RAW12 0x2c
+#define MIPI_DT_RAW14 0x2d
+
+
+static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
+{
+ return readl(csi->base + offset);
+}
+
+static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
+ unsigned offset)
+{
+ writel(value, csi->base + offset);
+}
+
+/*
+ * Enable error detection and correction for CCIR interlaced mode.
+ */
+static inline void ipu_csi_ccir_err_detection_enable(struct ipu_csi *csi)
+{
+ u32 temp;
+
+ temp = ipu_csi_read(csi, CSI_CCIR_CODE_1);
+ temp |= CSI_CCIR_ERR_DET_EN;
+ ipu_csi_write(csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+/*
+ * Disable error detection and correction for CCIR interlaced mode.
+ */
+static inline void ipu_csi_ccir_err_detection_disable(struct ipu_csi *csi)
+{
+ u32 temp;
+
+ temp = ipu_csi_read(csi, CSI_CCIR_CODE_1);
+ temp &= ~CSI_CCIR_ERR_DET_EN;
+ ipu_csi_write(csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+static inline void ipu_csi_set_horizontal_downsize(struct ipu_csi *csi,
+ bool enable)
+{
+ u32 temp;
+
+ temp = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+ if (enable)
+ temp |= CSI_HORI_DOWNSIZE_EN;
+ else
+ temp &= ~CSI_HORI_DOWNSIZE_EN;
+ ipu_csi_write(csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+static inline void ipu_csi_set_vertical_downsize(struct ipu_csi *csi,
+ bool enable)
+{
+ u32 temp;
+
+ temp = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+ if (enable)
+ temp |= CSI_VERT_DOWNSIZE_EN;
+ else
+ temp &= ~CSI_VERT_DOWNSIZE_EN;
+ ipu_csi_write(csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*
+ * Set mclk division ratio for generating test mode mclk. Only used
+ * for test generator.
+ */
+static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
+ u32 ipu_clk)
+{
+ u32 temp;
+ u32 div_ratio;
+
+ div_ratio = (ipu_clk / pixel_clk) - 1;
+
+ if (div_ratio > 0xFF || div_ratio < 0) {
+ dev_err(csi->ipu->dev,
+ "value of pixel_clk extends normal range\n");
+ return -EINVAL;
+ }
+
+ temp = ipu_csi_read(csi, CSI_SENS_CONF);
+ temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
+ ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
+ CSI_SENS_CONF);
+
+ return 0;
+}
+
+int ipu_csi_init_interface(struct ipu_csi *csi, u16 width, u16 height,
+ struct ipu_csi_signal_cfg *cfg)
+{
+ unsigned long flags;
+ u32 data = 0;
+ u32 ipu_clk;
+
+ /* Set the CSI_SENS_CONF register remaining fields */
+ data |= cfg->data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
+ cfg->data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
+ cfg->data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
+ cfg->vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
+ cfg->hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
+ cfg->pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
+ cfg->ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
+ cfg->clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
+ cfg->pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
+ cfg->force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
+ cfg->data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+
+ ipu_clk = clk_get_rate(csi->clk_ipu);
+
+ spin_lock_irqsave(&csi->lock, flags);
+
+ ipu_csi_write(csi, data, CSI_SENS_CONF);
+
+ /* Setup sensor frame size */
+ ipu_csi_write(csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);
+
+ /* Set CCIR registers */
+
+ switch (cfg->clk_mode) {
+ case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+ ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
+ ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+ break;
+ case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+ if (width == 720 && height == 625) {
+ /*
+ * PAL case
+ *
+ * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
+ * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
+ * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
+ * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
+ */
+ ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_1);
+ ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+ ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+
+ } else if (width == 720 && height == 525) {
+ /*
+ * NTSC case
+ *
+ * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
+ * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
+ * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
+ * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
+ */
+ ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_1);
+ ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+ ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+ } else {
+ dev_err(csi->ipu->dev,
+ "Unsupported CCIR656 interlaced video mode\n");
+ spin_unlock_irqrestore(&csi->lock, flags);
+ return -EINVAL;
+ }
+
+ ipu_csi_ccir_err_detection_enable(csi);
+ break;
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+ ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
+ ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+ ipu_csi_ccir_err_detection_enable(csi);
+ break;
+ case IPU_CSI_CLK_MODE_GATED_CLK:
+ case IPU_CSI_CLK_MODE_NONGATED_CLK:
+ ipu_csi_ccir_err_detection_disable(csi);
+ break;
+ }
+
+ dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
+ ipu_csi_read(csi, CSI_SENS_CONF));
+ dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
+ ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+
+ spin_unlock_irqrestore(&csi->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
+
+/*
+ * Find the CSI data format and data width codes for the given V4L2 media
+ * bus pixel format code.
+ */
+int ipu_csi_mbus_fmt_to_sig_cfg(struct ipu_csi_signal_cfg *cfg, u32 mbus_code)
+{
+ switch (mbus_code) {
+ case V4L2_MBUS_FMT_BGR565_2X8_BE:
+ case V4L2_MBUS_FMT_BGR565_2X8_LE:
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
+ cfg->mipi_dt = MIPI_DT_RGB565;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+ break;
+ case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
+ cfg->mipi_dt = MIPI_DT_RGB444;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+ break;
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
+ cfg->mipi_dt = MIPI_DT_RGB555;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+ cfg->mipi_dt = MIPI_DT_YUV422;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+ cfg->mipi_dt = MIPI_DT_YUV422;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_1X16:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+ cfg->mipi_dt = MIPI_DT_YUV422;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_16;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_1X16:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+ cfg->mipi_dt = MIPI_DT_YUV422;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_16;
+ break;
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGBRG8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case V4L2_MBUS_FMT_SRGGB8_1X8:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+ cfg->mipi_dt = MIPI_DT_RAW8;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
+ case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+ case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+ case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
+ case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+ cfg->mipi_dt = MIPI_DT_RAW10;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ case V4L2_MBUS_FMT_SGBRG10_1X10:
+ case V4L2_MBUS_FMT_SGRBG10_1X10:
+ case V4L2_MBUS_FMT_SRGGB10_1X10:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+ cfg->mipi_dt = MIPI_DT_RAW10;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_10;
+ break;
+ case V4L2_MBUS_FMT_SBGGR12_1X12:
+ case V4L2_MBUS_FMT_SGBRG12_1X12:
+ case V4L2_MBUS_FMT_SGRBG12_1X12:
+ case V4L2_MBUS_FMT_SRGGB12_1X12:
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+ cfg->mipi_dt = MIPI_DT_RAW12;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_12;
+ break;
+ case V4L2_MBUS_FMT_JPEG_1X8:
+ /* TODO */
+ cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
+ cfg->mipi_dt = MIPI_DT_RAW8;
+ cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_mbus_fmt_to_sig_cfg);
+
+bool ipu_csi_is_interlaced(struct ipu_csi *csi)
+{
+ unsigned long flags;
+ u32 sensor_protocol;
+
+ spin_lock_irqsave(&csi->lock, flags);
+ sensor_protocol =
+ (ipu_csi_read(csi, CSI_SENS_CONF) &
+ CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+ CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+ spin_unlock_irqrestore(&csi->lock, flags);
+
+ switch (sensor_protocol) {
+ case IPU_CSI_CLK_MODE_GATED_CLK:
+ case IPU_CSI_CLK_MODE_NONGATED_CLK:
+ case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+ return false;
+ break;
+ case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+ return true;
+ break;
+ default:
+ dev_err(csi->ipu->dev,
+ "CSI %d sensor protocol unsupported\n", csi->id);
+ return false;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
+
+void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
+{
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&csi->lock, flags);
+
+ reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
+ w->width = (reg & 0xFFFF) + 1;
+ w->height = (reg >> 16 & 0xFFFF) + 1;
+
+ reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+ w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
+ w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
+
+ spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_get_window);
+
+void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
+{
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&csi->lock, flags);
+
+ ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
+ CSI_ACT_FRM_SIZE);
+
+ reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+ reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
+ reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
+ ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
+
+ spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_window);
+
+void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
+ u32 r_value, u32 g_value, u32 b_value,
+ u32 pix_clk)
+{
+ unsigned long flags;
+ u32 ipu_clk = clk_get_rate(csi->clk_ipu);
+ u32 temp;
+
+ spin_lock_irqsave(&csi->lock, flags);
+
+ temp = ipu_csi_read(csi, CSI_TST_CTRL);
+
+ if (active == false) {
+ temp &= ~CSI_TEST_GEN_MODE_EN;
+ ipu_csi_write(csi, temp, CSI_TST_CTRL);
+ } else {
+ /* Set sensb_mclk div_ratio*/
+ ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
+
+ temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
+ CSI_TEST_GEN_B_MASK);
+ temp |= CSI_TEST_GEN_MODE_EN;
+ temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
+ (g_value << CSI_TEST_GEN_G_SHIFT) |
+ (b_value << CSI_TEST_GEN_B_SHIFT);
+ ipu_csi_write(csi, temp, CSI_TST_CTRL);
+ }
+
+ spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
+
+int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
+ struct ipu_csi_signal_cfg *cfg)
+{
+ unsigned long flags;
+ u32 temp;
+
+ if (vc > 3)
+ return -EINVAL;
+
+ spin_lock_irqsave(&csi->lock, flags);
+
+ temp = ipu_csi_read(csi, CSI_MIPI_DI);
+ temp &= ~(0xff << (vc * 8));
+ temp |= (cfg->mipi_dt << (vc * 8));
+ ipu_csi_write(csi, temp, CSI_MIPI_DI);
+
+ spin_unlock_irqrestore(&csi->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
+
+int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
+ u32 max_ratio, u32 id)
+{
+ unsigned long flags;
+ u32 temp;
+
+ if (max_ratio > 5 || id > 3)
+ return -EINVAL;
+
+ spin_lock_irqsave(&csi->lock, flags);
+
+ temp = ipu_csi_read(csi, CSI_SKIP);
+ temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
+ CSI_SKIP_SMFC_MASK);
+ temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
+ (id << CSI_ID_2_SKIP_SHIFT) |
+ (skip << CSI_SKIP_SMFC_SHIFT);
+ ipu_csi_write(csi, temp, CSI_SKIP);
+
+ spin_unlock_irqrestore(&csi->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
+
+int ipu_csi_set_dest(struct ipu_csi *csi, bool ic)
+{
+ unsigned long flags;
+ u32 csi_sens_conf, csi_dest;
+
+ csi_dest = ic ? CSI_DATA_DEST_IC : CSI_DATA_DEST_IDMAC;
+
+ spin_lock_irqsave(&csi->lock, flags);
+
+ csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
+ csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
+ csi_sens_conf |= (csi_dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
+ ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
+
+ spin_unlock_irqrestore(&csi->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
+
+int ipu_csi_enable(struct ipu_csi *csi)
+{
+ ipu_module_enable(csi->ipu, csi->module);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_enable);
+
+int ipu_csi_disable(struct ipu_csi *csi)
+{
+ ipu_module_disable(csi->ipu, csi->module);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_disable);
+
+struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
+{
+ unsigned long flags;
+ struct ipu_csi *csi, *ret;
+
+ if (id > 1)
+ return ERR_PTR(-EINVAL);
+
+ csi = ipu->csi_priv[id];
+ ret = csi;
+
+ spin_lock_irqsave(&csi->lock, flags);
+
+ if (csi->inuse) {
+ ret = ERR_PTR(-EBUSY);
+ goto unlock;
+ }
+
+ csi->inuse = true;
+unlock:
+ spin_unlock_irqrestore(&csi->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_get);
+
+void ipu_csi_put(struct ipu_csi *csi)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&csi->lock, flags);
+ csi->inuse = false;
+ spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_put);
+
+int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+ unsigned long base, u32 module, struct clk *clk_ipu)
+{
+ struct ipu_csi *csi;
+
+ if (id > 1)
+ return -ENODEV;
+
+ csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
+ if (!csi)
+ return -ENOMEM;
+
+ ipu->csi_priv[id] = csi;
+
+ spin_lock_init(&csi->lock);
+ csi->module = module;
+ csi->id = id;
+ csi->clk_ipu = clk_ipu;
+ csi->base = devm_ioremap(dev, base, PAGE_SIZE);
+ if (!csi->base)
+ return -ENOMEM;
+
+ dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
+ id, base, csi->base);
+ csi->ipu = ipu;
+
+ return 0;
+}
+
+void ipu_csi_exit(struct ipu_soc *ipu, int id)
+{
+}
+
+void ipu_csi_dump(struct ipu_csi *csi)
+{
+ dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n",
+ ipu_csi_read(csi, CSI_SENS_CONF));
+ dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
+ ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
+ dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n",
+ ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+ dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n",
+ ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
+ dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n",
+ ipu_csi_read(csi, CSI_TST_CTRL));
+ dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n",
+ ipu_csi_read(csi, CSI_CCIR_CODE_1));
+ dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n",
+ ipu_csi_read(csi, CSI_CCIR_CODE_2));
+ dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n",
+ ipu_csi_read(csi, CSI_CCIR_CODE_3));
+ dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n",
+ ipu_csi_read(csi, CSI_MIPI_DI));
+ dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n",
+ ipu_csi_read(csi, CSI_SKIP));
+}
+EXPORT_SYMBOL_GPL(ipu_csi_dump);
diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
new file mode 100644
index 0000000..2d305a2
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -0,0 +1,812 @@
+/*
+ * Copyright (C) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/bitrev.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include "ipu-prv.h"
+
+/* IC Register Offsets */
+#define IC_CONF 0x0000
+#define IC_PRP_ENC_RSC 0x0004
+#define IC_PRP_VF_RSC 0x0008
+#define IC_PP_RSC 0x000C
+#define IC_CMBP_1 0x0010
+#define IC_CMBP_2 0x0014
+#define IC_IDMAC_1 0x0018
+#define IC_IDMAC_2 0x001C
+#define IC_IDMAC_3 0x0020
+#define IC_IDMAC_4 0x0024
+
+/* IC Register Fields */
+#define IC_CONF_PRPENC_EN (1 << 0)
+#define IC_CONF_PRPENC_CSC1 (1 << 1)
+#define IC_CONF_PRPENC_ROT_EN (1 << 2)
+#define IC_CONF_PRPVF_EN (1 << 8)
+#define IC_CONF_PRPVF_CSC1 (1 << 9)
+#define IC_CONF_PRPVF_CSC2 (1 << 10)
+#define IC_CONF_PRPVF_CMB (1 << 11)
+#define IC_CONF_PRPVF_ROT_EN (1 << 12)
+#define IC_CONF_PP_EN (1 << 16)
+#define IC_CONF_PP_CSC1 (1 << 17)
+#define IC_CONF_PP_CSC2 (1 << 18)
+#define IC_CONF_PP_CMB (1 << 19)
+#define IC_CONF_PP_ROT_EN (1 << 20)
+#define IC_CONF_IC_GLB_LOC_A (1 << 28)
+#define IC_CONF_KEY_COLOR_EN (1 << 29)
+#define IC_CONF_RWS_EN (1 << 30)
+#define IC_CONF_CSI_MEM_WR_EN (1 << 31)
+
+#define IC_IDMAC_1_CB0_BURST_16 (1 << 0)
+#define IC_IDMAC_1_CB1_BURST_16 (1 << 1)
+#define IC_IDMAC_1_CB2_BURST_16 (1 << 2)
+#define IC_IDMAC_1_CB3_BURST_16 (1 << 3)
+#define IC_IDMAC_1_CB4_BURST_16 (1 << 4)
+#define IC_IDMAC_1_CB5_BURST_16 (1 << 5)
+#define IC_IDMAC_1_CB6_BURST_16 (1 << 6)
+#define IC_IDMAC_1_CB7_BURST_16 (1 << 7)
+#define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11)
+#define IC_IDMAC_1_PRPENC_ROT_OFFSET 11
+#define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14)
+#define IC_IDMAC_1_PRPVF_ROT_OFFSET 14
+#define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17)
+#define IC_IDMAC_1_PP_ROT_OFFSET 17
+#define IC_IDMAC_1_PP_FLIP_RS (1 << 22)
+#define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21)
+#define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20)
+
+#define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0)
+#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
+#define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10)
+#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10
+#define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20)
+#define IC_IDMAC_2_PP_HEIGHT_OFFSET 20
+
+#define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0)
+#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0
+#define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10)
+#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10
+#define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20)
+#define IC_IDMAC_3_PP_WIDTH_OFFSET 20
+
+struct ic_task_regoffs {
+ u32 rsc;
+ u32 tpmem_csc[2];
+};
+
+struct ic_task_bitfields {
+ u32 ic_conf_en;
+ u32 ic_conf_rot_en;
+ u32 ic_conf_cmb_en;
+ u32 ic_conf_csc1_en;
+ u32 ic_conf_csc2_en;
+ u32 ic_cmb_galpha_bit;
+};
+
+static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
+ [IC_TASK_ENCODER] = {
+ .rsc = IC_PRP_ENC_RSC,
+ .tpmem_csc = {0x2008, 0},
+ },
+ [IC_TASK_VIEWFINDER] = {
+ .rsc = IC_PRP_VF_RSC,
+ .tpmem_csc = {0x4028, 0x4040},
+ },
+ [IC_TASK_POST_PROCESSOR] = {
+ .rsc = IC_PP_RSC,
+ .tpmem_csc = {0x6060, 0x6078},
+ },
+};
+
+static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
+ [IC_TASK_ENCODER] = {
+ .ic_conf_en = IC_CONF_PRPENC_EN,
+ .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
+ .ic_conf_cmb_en = 0, /* NA */
+ .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
+ .ic_conf_csc2_en = 0, /* NA */
+ .ic_cmb_galpha_bit = 0, /* NA */
+ },
+ [IC_TASK_VIEWFINDER] = {
+ .ic_conf_en = IC_CONF_PRPVF_EN,
+ .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
+ .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
+ .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
+ .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
+ .ic_cmb_galpha_bit = 0,
+ },
+ [IC_TASK_POST_PROCESSOR] = {
+ .ic_conf_en = IC_CONF_PP_EN,
+ .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
+ .ic_conf_cmb_en = IC_CONF_PP_CMB,
+ .ic_conf_csc1_en = IC_CONF_PP_CSC1,
+ .ic_conf_csc2_en = IC_CONF_PP_CSC2,
+ .ic_cmb_galpha_bit = 8,
+ },
+};
+
+struct ipu_ic_priv;
+
+struct ipu_ic {
+ enum ipu_ic_task task;
+ const struct ic_task_regoffs *reg;
+ const struct ic_task_bitfields *bit;
+
+ enum ipu_color_space in_cs, g_in_cs;
+ enum ipu_color_space out_cs;
+ bool graphics;
+ bool rotation;
+ bool in_use;
+
+ struct ipu_ic_priv *priv;
+};
+
+struct ipu_ic_priv {
+ void __iomem *base;
+ void __iomem *tpmem_base;
+ spinlock_t lock;
+ struct ipu_soc *ipu;
+ int use_count;
+ struct ipu_ic task[IC_NUM_TASKS];
+};
+
+static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
+{
+ return readl(ic->priv->base + offset);
+}
+
+static inline void ipu_ic_write(struct ipu_ic *ic, u32 value,
+ unsigned offset)
+{
+ writel(value, ic->priv->base + offset);
+}
+
+static void init_csc_rgb2ycbcr(u32 __iomem *base)
+{
+ /*
+ * Y = R * .299 + G * .587 + B * .114;
+ * U = R * -.169 + G * -.332 + B * .500 + 128.;
+ * V = R * .500 + G * -.419 + B * -.0813 + 128.;
+ */
+ const u32 coeff[4][3] = {
+ {0x004D, 0x0096, 0x001D},
+ {0x01D5, 0x01AB, 0x0080},
+ {0x0080, 0x0195, 0x01EB},
+ {0x0000, 0x0200, 0x0200}, /* A0, A1, A2 */
+ };
+ u32 param;
+
+ param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
+ (coeff[1][1] << 9) | coeff[2][2];
+ writel(param, base++);
+
+ /* scale = 1, sat = 0 */
+ param = (coeff[3][0] >> 5) | (1UL << 8);
+ writel(param, base++);
+
+ param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
+ (coeff[1][0] << 9) | coeff[2][0];
+ writel(param, base++);
+
+ param = (coeff[3][1] >> 5);
+ writel(param, base++);
+
+ param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
+ (coeff[1][2] << 9) | coeff[2][1];
+ writel(param, base++);
+
+ param = (coeff[3][2] >> 5);
+ writel(param, base++);
+}
+
+static void init_csc_rgb2rgb(u32 __iomem *base)
+{
+ /* transparent RGB->RGB matrix for graphics combining */
+ const u32 coeff[4][3] = {
+ {0x0080, 0x0000, 0x0000},
+ {0x0000, 0x0080, 0x0000},
+ {0x0000, 0x0000, 0x0080},
+ {0x0000, 0x0000, 0x0000}, /* A0, A1, A2 */
+ };
+ u32 param;
+
+ param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
+ (coeff[1][1] << 9) | coeff[2][2];
+ writel(param, base++);
+
+ /* scale = 2, sat = 0 */
+ param = (coeff[3][0] >> 5) | (2UL << 8);
+ writel(param, base++);
+
+ param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
+ (coeff[1][0] << 9) | coeff[2][0];
+ writel(param, base++);
+
+ param = (coeff[3][1] >> 5);
+ writel(param, base++);
+
+ param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
+ (coeff[1][2] << 9) | coeff[2][1];
+ writel(param, base++);
+
+ param = (coeff[3][2] >> 5);
+ writel(param, base++);
+}
+
+static void init_csc_ycbcr2rgb(u32 __iomem *base)
+{
+ /*
+ * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+ * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+ * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
+ */
+ const u32 coeff[4][3] = {
+ {149, 0, 204},
+ {149, 462, 408},
+ {149, 255, 0},
+ {8192 - 446, 266, 8192 - 554}, /* A0, A1, A2 */
+ };
+ u32 param;
+
+ param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
+ (coeff[1][1] << 9) | coeff[2][2];
+ writel(param, base++);
+
+ /* scale = 2, sat = 0 */
+ param = (coeff[3][0] >> 5) | (2L << (40 - 32));
+ writel(param, base++);
+
+ param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
+ (coeff[1][0] << 9) | coeff[2][0];
+ writel(param, base++);
+
+ param = (coeff[3][1] >> 5);
+ writel(param, base++);
+
+ param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
+ (coeff[1][2] << 9) | coeff[2][1];
+ writel(param, base++);
+
+ param = (coeff[3][2] >> 5);
+ writel(param, base++);
+}
+
+static int init_csc(struct ipu_ic *ic,
+ enum ipu_color_space inf,
+ enum ipu_color_space outf,
+ int csc_index)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ u32 __iomem *base;
+
+ base = (u32 __iomem *)
+ (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
+
+ if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
+ init_csc_ycbcr2rgb(base);
+ else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
+ init_csc_rgb2ycbcr(base);
+ else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
+ init_csc_rgb2rgb(base);
+ else {
+ dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int calc_resize_coeffs(struct ipu_ic *ic,
+ u32 in_size, u32 out_size,
+ u32 *resize_coeff,
+ u32 *downsize_coeff)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ struct ipu_soc *ipu = priv->ipu;
+ u32 temp_size, temp_downsize;
+
+ /*
+ * Input size cannot be more than 4096, and output size cannot
+ * be more than 1024
+ */
+ if (in_size > 4096) {
+ dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
+ return -EINVAL;
+ }
+ if (out_size > 1024) {
+ dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
+ return -EINVAL;
+ }
+
+ /* Cannot downsize more than 8:1 */
+ if ((out_size << 3) < in_size) {
+ dev_err(ipu->dev, "Unsupported downsize\n");
+ return -EINVAL;
+ }
+
+ /* Compute downsizing coefficient */
+ temp_downsize = 0;
+ temp_size = in_size;
+ while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
+ (temp_downsize < 2)) {
+ temp_size >>= 1;
+ temp_downsize++;
+ }
+ *downsize_coeff = temp_downsize;
+
+ /*
+ * compute resizing coefficient using the following equation:
+ * resize_coeff = M * (SI - 1) / (SO - 1)
+ * where M = 2^13, SI = input size, SO = output size
+ */
+ *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
+ if (*resize_coeff >= 16384L) {
+ dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
+ *resize_coeff = 0x3FFF;
+ }
+
+ return 0;
+}
+
+void ipu_ic_task_enable(struct ipu_ic *ic)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ unsigned long flags;
+ u32 ic_conf;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ic_conf = ipu_ic_read(ic, IC_CONF);
+
+ ic_conf |= ic->bit->ic_conf_en;
+
+ if (ic->rotation)
+ ic_conf |= ic->bit->ic_conf_rot_en;
+
+ if (ic->in_cs != ic->out_cs)
+ ic_conf |= ic->bit->ic_conf_csc1_en;
+
+ if (ic->graphics) {
+ ic_conf |= ic->bit->ic_conf_cmb_en;
+ ic_conf |= ic->bit->ic_conf_csc1_en;
+
+ if (ic->g_in_cs != ic->out_cs)
+ ic_conf |= ic->bit->ic_conf_csc2_en;
+ }
+
+ ipu_ic_write(ic, ic_conf, IC_CONF);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
+
+void ipu_ic_task_disable(struct ipu_ic *ic)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ unsigned long flags;
+ u32 ic_conf;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ic_conf = ipu_ic_read(ic, IC_CONF);
+
+ ic_conf &= ~(ic->bit->ic_conf_en |
+ ic->bit->ic_conf_csc1_en |
+ ic->bit->ic_conf_rot_en);
+ if (ic->bit->ic_conf_csc2_en)
+ ic_conf &= ~ic->bit->ic_conf_csc2_en;
+ if (ic->bit->ic_conf_cmb_en)
+ ic_conf &= ~ic->bit->ic_conf_cmb_en;
+
+ ipu_ic_write(ic, ic_conf, IC_CONF);
+
+ ic->rotation = ic->graphics = false;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
+
+int ipu_ic_task_graphics_init(struct ipu_ic *ic,
+ enum ipu_color_space in_g_cs,
+ bool galpha_en, u32 galpha,
+ bool colorkey_en, u32 colorkey)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ unsigned long flags;
+ u32 reg, ic_conf;
+ int ret = 0;
+
+ if (ic->task == IC_TASK_ENCODER)
+ return -EINVAL;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ic_conf = ipu_ic_read(ic, IC_CONF);
+
+ if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
+ /* need transparent CSC1 conversion */
+ ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
+ IPUV3_COLORSPACE_RGB, 0);
+ if (ret)
+ goto unlock;
+ }
+
+ ic->g_in_cs = in_g_cs;
+
+ if (ic->g_in_cs != ic->out_cs) {
+ ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
+ if (ret)
+ goto unlock;
+ }
+
+ if (galpha_en) {
+ ic_conf |= IC_CONF_IC_GLB_LOC_A;
+ reg = ipu_ic_read(ic, IC_CMBP_1);
+ reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
+ reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
+ ipu_ic_write(ic, reg, IC_CMBP_1);
+ } else
+ ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+ if (colorkey_en) {
+ ic_conf |= IC_CONF_KEY_COLOR_EN;
+ ipu_ic_write(ic, colorkey, IC_CMBP_2);
+ } else
+ ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+
+ ipu_ic_write(ic, ic_conf, IC_CONF);
+
+ ic->graphics = true;
+unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
+
+int ipu_ic_task_init(struct ipu_ic *ic,
+ int in_width, int in_height,
+ int out_width, int out_height,
+ enum ipu_color_space in_cs,
+ enum ipu_color_space out_cs)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ u32 reg, downsize_coeff, resize_coeff;
+ unsigned long flags;
+ int ret = 0;
+
+ /* Setup vertical resizing */
+ ret = calc_resize_coeffs(ic, in_height, out_height,
+ &resize_coeff, &downsize_coeff);
+ if (ret)
+ return ret;
+
+ reg = (downsize_coeff << 30) | (resize_coeff << 16);
+
+ /* Setup horizontal resizing */
+ ret = calc_resize_coeffs(ic, in_width, out_width,
+ &resize_coeff, &downsize_coeff);
+ if (ret)
+ return ret;
+
+ reg |= (downsize_coeff << 14) | resize_coeff;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ipu_ic_write(ic, reg, ic->reg->rsc);
+
+ /* Setup color space conversion */
+ ic->in_cs = in_cs;
+ ic->out_cs = out_cs;
+
+ if (ic->in_cs != ic->out_cs) {
+ ret = init_csc(ic, ic->in_cs, ic->out_cs, 0);
+ if (ret)
+ goto unlock;
+ }
+
+unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_init);
+
+int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
+ u32 width, u32 height, int burst_size,
+ enum ipu_rotate_mode rot)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ struct ipu_soc *ipu = priv->ipu;
+ u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
+ u32 temp_rot = bitrev8(rot) >> 5;
+ bool need_hor_flip = false;
+ unsigned long flags;
+ int ret = 0;
+
+ if ((burst_size != 8) && (burst_size != 16)) {
+ dev_err(ipu->dev, "Illegal burst length for IC\n");
+ return -EINVAL;
+ }
+
+ width--;
+ height--;
+
+ if (temp_rot & 0x2) /* Need horizontal flip */
+ need_hor_flip = true;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
+ ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
+ ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
+
+ switch (channel->num) {
+ case IPUV3_CHANNEL_IC_PP_MEM:
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
+
+ if (need_hor_flip)
+ ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
+
+ ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
+ ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
+
+ ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
+ ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
+ break;
+ case IPUV3_CHANNEL_MEM_IC_PP:
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
+ break;
+ case IPUV3_CHANNEL_MEM_ROT_PP:
+ ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
+ ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
+ break;
+ case IPUV3_CHANNEL_MEM_IC_PRP_VF:
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
+ break;
+ case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
+
+ if (need_hor_flip)
+ ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
+
+ ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
+ ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
+
+ ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
+ ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
+ break;
+ case IPUV3_CHANNEL_MEM_ROT_ENC:
+ ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
+ ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
+ break;
+ case IPUV3_CHANNEL_IC_PRP_VF_MEM:
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
+
+ if (need_hor_flip)
+ ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
+
+ ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
+ ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
+
+ ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
+ ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
+ break;
+ case IPUV3_CHANNEL_MEM_ROT_VF:
+ ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
+ ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
+ break;
+ case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
+ break;
+ case IPUV3_CHANNEL_G_MEM_IC_PP:
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+ break;
+ case IPUV3_CHANNEL_VDI_MEM_IC_VF:
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
+ break;
+ default:
+ goto unlock;
+ }
+
+ ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
+ ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
+ ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
+
+ if (rot >= IPU_ROTATE_90_RIGHT)
+ ic->rotation = true;
+
+unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
+
+int ipu_ic_enable(struct ipu_ic *ic)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ unsigned long flags;
+ u32 module = IPU_CONF_IC_EN;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (ic->rotation)
+ module |= IPU_CONF_ROT_EN;
+
+ if (!priv->use_count)
+ ipu_module_enable(priv->ipu, module);
+
+ priv->use_count++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_enable);
+
+int ipu_ic_disable(struct ipu_ic *ic)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ unsigned long flags;
+ u32 module = IPU_CONF_IC_EN | IPU_CONF_ROT_EN;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->use_count--;
+
+ if (!priv->use_count)
+ ipu_module_disable(priv->ipu, module);
+
+ if (priv->use_count < 0)
+ priv->use_count = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_disable);
+
+struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
+{
+ struct ipu_ic_priv *priv = ipu->ic_priv;
+ unsigned long flags;
+ struct ipu_ic *ic, *ret;
+
+ if (task >= IC_NUM_TASKS)
+ return ERR_PTR(-EINVAL);
+
+ ic = &priv->task[task];
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (ic->in_use) {
+ ret = ERR_PTR(-EBUSY);
+ goto unlock;
+ }
+
+ ic->in_use = true;
+ ret = ic;
+
+unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_get);
+
+void ipu_ic_put(struct ipu_ic *ic)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ic->in_use = false;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_put);
+
+int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+ unsigned long base, unsigned long tpmem_base)
+{
+ struct ipu_ic_priv *priv;
+ int i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ipu->ic_priv = priv;
+
+ spin_lock_init(&priv->lock);
+ priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+ if (!priv->base)
+ return -ENOMEM;
+ priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
+ if (!priv->tpmem_base)
+ return -ENOMEM;
+
+ dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
+
+ priv->ipu = ipu;
+
+ for (i = 0; i < IC_NUM_TASKS; i++) {
+ priv->task[i].task = i;
+ priv->task[i].priv = priv;
+ priv->task[i].reg = &ic_task_reg[i];
+ priv->task[i].bit = &ic_task_bit[i];
+ }
+
+ return 0;
+}
+
+void ipu_ic_exit(struct ipu_soc *ipu)
+{
+}
+
+void ipu_ic_dump(struct ipu_ic *ic)
+{
+ struct ipu_ic_priv *priv = ic->priv;
+ struct ipu_soc *ipu = priv->ipu;
+
+ dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
+ ipu_ic_read(ic, IC_CONF));
+ dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
+ ipu_ic_read(ic, IC_PRP_ENC_RSC));
+ dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
+ ipu_ic_read(ic, IC_PRP_VF_RSC));
+ dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
+ ipu_ic_read(ic, IC_PP_RSC));
+ dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
+ ipu_ic_read(ic, IC_CMBP_1));
+ dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
+ ipu_ic_read(ic, IC_CMBP_2));
+ dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
+ ipu_ic_read(ic, IC_IDMAC_1));
+ dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
+ ipu_ic_read(ic, IC_IDMAC_2));
+ dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
+ ipu_ic_read(ic, IC_IDMAC_3));
+ dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
+ ipu_ic_read(ic, IC_IDMAC_4));
+}
+EXPORT_SYMBOL_GPL(ipu_ic_dump);
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index 7d8d95b..8e0bc1d 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -156,9 +156,11 @@ struct ipuv3_channel {
struct ipu_soc *ipu;
};
+struct ipu_csi;
struct ipu_dc_priv;
struct ipu_dmfc_priv;
struct ipu_di;
+struct ipu_ic_priv;
struct ipu_smfc_priv;
struct ipu_devtype;
@@ -189,6 +191,8 @@ struct ipu_soc {
struct ipu_dp_priv *dp_priv;
struct ipu_dmfc_priv *dmfc_priv;
struct ipu_di *di_priv[2];
+ struct ipu_csi *csi_priv[2];
+ struct ipu_ic_priv *ic_priv;
struct ipu_smfc_priv *smfc_priv;
};
@@ -200,6 +204,14 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms);
+int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+ unsigned long base, u32 module, struct clk *clk_ipu);
+void ipu_csi_exit(struct ipu_soc *ipu, int id);
+
+int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+ unsigned long base, unsigned long tpmem_base);
+void ipu_ic_exit(struct ipu_soc *ipu);
+
int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
unsigned long base, u32 module, struct clk *ipu_clk);
void ipu_di_exit(struct ipu_soc *ipu, int id);
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 52fa277..580a88c 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -61,6 +61,65 @@ struct ipu_di_signal_cfg {
u8 vsync_pin;
};
+/*
+ * Bitfield of CSI signal polarities and modes.
+ */
+struct ipu_csi_signal_cfg {
+ unsigned data_width:4;
+ unsigned clk_mode:3;
+ unsigned ext_vsync:1;
+ unsigned vsync_pol:1;
+ unsigned hsync_pol:1;
+ unsigned pixclk_pol:1;
+ unsigned data_pol:1;
+ unsigned sens_clksrc:1;
+ unsigned pack_tight:1;
+ unsigned force_eof:1;
+ unsigned data_en_pol:1;
+
+ unsigned data_fmt;
+ unsigned mipi_dt;
+};
+
+/*
+ * Enumeration of CSI data bus widths.
+ */
+enum ipu_csi_data_width {
+ IPU_CSI_DATA_WIDTH_4 = 0,
+ IPU_CSI_DATA_WIDTH_8 = 1,
+ IPU_CSI_DATA_WIDTH_10 = 3,
+ IPU_CSI_DATA_WIDTH_12 = 5,
+ IPU_CSI_DATA_WIDTH_16 = 9,
+};
+
+/*
+ * Enumeration of CSI clock modes.
+ */
+enum ipu_csi_clk_mode {
+ IPU_CSI_CLK_MODE_GATED_CLK,
+ IPU_CSI_CLK_MODE_NONGATED_CLK,
+ IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
+ IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
+ IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
+ IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
+ IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
+ IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
+};
+
+/*
+ * Enumeration of IPU rotation modes
+ */
+enum ipu_rotate_mode {
+ IPU_ROTATE_NONE = 0,
+ IPU_ROTATE_VERT_FLIP,
+ IPU_ROTATE_HORIZ_FLIP,
+ IPU_ROTATE_180,
+ IPU_ROTATE_90_RIGHT,
+ IPU_ROTATE_90_RIGHT_VFLIP,
+ IPU_ROTATE_90_RIGHT_HFLIP,
+ IPU_ROTATE_90_LEFT,
+};
+
enum ipu_color_space {
IPUV3_COLORSPACE_RGB,
IPUV3_COLORSPACE_YUV,
@@ -176,8 +235,58 @@ int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
/*
* IPU CMOS Sensor Interface (csi) functions
*/
-int ipu_csi_enable(struct ipu_soc *ipu, int csi);
-int ipu_csi_disable(struct ipu_soc *ipu, int csi);
+struct ipu_csi;
+int ipu_csi_mbus_fmt_to_sig_cfg(struct ipu_csi_signal_cfg *cfg,
+ u32 mbus_code);
+int ipu_csi_init_interface(struct ipu_csi *csi, u16 width, u16 height,
+ struct ipu_csi_signal_cfg *cfg);
+bool ipu_csi_is_interlaced(struct ipu_csi *csi);
+void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w);
+void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w);
+void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
+ u32 r_value, u32 g_value, u32 b_value,
+ u32 pix_clk);
+int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
+ struct ipu_csi_signal_cfg *cfg);
+int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
+ u32 max_ratio, u32 id);
+int ipu_csi_set_dest(struct ipu_csi *csi, bool ic);
+int ipu_csi_enable(struct ipu_csi *csi);
+int ipu_csi_disable(struct ipu_csi *csi);
+struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id);
+void ipu_csi_put(struct ipu_csi *csi);
+void ipu_csi_dump(struct ipu_csi *csi);
+
+/*
+ * IPU Image Converter (ic) functions
+ */
+enum ipu_ic_task {
+ IC_TASK_ENCODER,
+ IC_TASK_VIEWFINDER,
+ IC_TASK_POST_PROCESSOR,
+ IC_NUM_TASKS,
+};
+
+struct ipu_ic;
+int ipu_ic_task_init(struct ipu_ic *ic,
+ int in_width, int in_height,
+ int out_width, int out_height,
+ enum ipu_color_space in_cs,
+ enum ipu_color_space out_cs);
+int ipu_ic_task_graphics_init(struct ipu_ic *ic,
+ enum ipu_color_space in_g_cs,
+ bool galpha_en, u32 galpha,
+ bool colorkey_en, u32 colorkey);
+void ipu_ic_task_enable(struct ipu_ic *ic);
+void ipu_ic_task_disable(struct ipu_ic *ic);
+int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
+ u32 width, u32 height, int burst_size,
+ enum ipu_rotate_mode rot);
+int ipu_ic_enable(struct ipu_ic *ic);
+int ipu_ic_disable(struct ipu_ic *ic);
+struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task);
+void ipu_ic_put(struct ipu_ic *ic);
+void ipu_ic_dump(struct ipu_ic *ic);
/*
* IPU Sensor Multiple FIFO Controller (SMFC) functions
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 06/28] gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (4 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 05/28] gpu: ipu-v3: Add units required for video capture Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 07/28] gpu: ipu-v3: smfc: Convert to per-channel Steve Longerbeam
` (23 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 12 ------------
drivers/gpu/ipu-v3/ipu-smfc.c | 12 ++++++++++++
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 0ac2103..85220ae 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -667,18 +667,6 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
}
EXPORT_SYMBOL_GPL(ipu_module_disable);
-int ipu_smfc_enable(struct ipu_soc *ipu)
-{
- return ipu_module_enable(ipu, IPU_CONF_SMFC_EN);
-}
-EXPORT_SYMBOL_GPL(ipu_smfc_enable);
-
-int ipu_smfc_disable(struct ipu_soc *ipu)
-{
- return ipu_module_disable(ipu, IPU_CONF_SMFC_EN);
-}
-EXPORT_SYMBOL_GPL(ipu_smfc_disable);
-
int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
{
struct ipu_soc *ipu = channel->ipu;
diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c
index e4f85ad..87ac624d 100644
--- a/drivers/gpu/ipu-v3/ipu-smfc.c
+++ b/drivers/gpu/ipu-v3/ipu-smfc.c
@@ -71,6 +71,18 @@ int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_
}
EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
+int ipu_smfc_enable(struct ipu_soc *ipu)
+{
+ return ipu_module_enable(ipu, IPU_CONF_SMFC_EN);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_enable);
+
+int ipu_smfc_disable(struct ipu_soc *ipu)
+{
+ return ipu_module_disable(ipu, IPU_CONF_SMFC_EN);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_disable);
+
int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
unsigned long base)
{
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 07/28] gpu: ipu-v3: smfc: Convert to per-channel
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (5 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 06/28] gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 08/28] gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark() Steve Longerbeam
` (22 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Convert the smfc object to be specific to a single smfc channel.
Add ipu_smfc_{get|put} to retrieve and release a single smfc channel
for exclusive use, and add use counter to ipu_smfc_{enable|disable}.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-smfc.c | 132 +++++++++++++++++++++++++++++++++--------
include/video/imx-ipu-v3.h | 10 ++--
2 files changed, 112 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c
index 87ac624d..a6429ca 100644
--- a/drivers/gpu/ipu-v3/ipu-smfc.c
+++ b/drivers/gpu/ipu-v3/ipu-smfc.c
@@ -21,9 +21,18 @@
#include "ipu-prv.h"
+struct ipu_smfc {
+ struct ipu_smfc_priv *priv;
+ int chno;
+ bool inuse;
+};
+
struct ipu_smfc_priv {
void __iomem *base;
spinlock_t lock;
+ struct ipu_soc *ipu;
+ struct ipu_smfc channel[4];
+ int use_count;
};
/*SMFC Registers */
@@ -31,75 +40,146 @@ struct ipu_smfc_priv {
#define SMFC_WMC 0x0004
#define SMFC_BS 0x0008
-int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize)
+int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
{
- struct ipu_smfc_priv *smfc = ipu->smfc_priv;
+ struct ipu_smfc_priv *priv = smfc->priv;
unsigned long flags;
u32 val, shift;
- spin_lock_irqsave(&smfc->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
- shift = channel * 4;
- val = readl(smfc->base + SMFC_BS);
+ shift = smfc->chno * 4;
+ val = readl(priv->base + SMFC_BS);
val &= ~(0xf << shift);
val |= burstsize << shift;
- writel(val, smfc->base + SMFC_BS);
+ writel(val, priv->base + SMFC_BS);
- spin_unlock_irqrestore(&smfc->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
-int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id)
+int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
{
- struct ipu_smfc_priv *smfc = ipu->smfc_priv;
+ struct ipu_smfc_priv *priv = smfc->priv;
unsigned long flags;
u32 val, shift;
- spin_lock_irqsave(&smfc->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
- shift = channel * 3;
- val = readl(smfc->base + SMFC_MAP);
+ shift = smfc->chno * 3;
+ val = readl(priv->base + SMFC_MAP);
val &= ~(0x7 << shift);
val |= ((csi_id << 2) | mipi_id) << shift;
- writel(val, smfc->base + SMFC_MAP);
+ writel(val, priv->base + SMFC_MAP);
- spin_unlock_irqrestore(&smfc->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
-int ipu_smfc_enable(struct ipu_soc *ipu)
+int ipu_smfc_enable(struct ipu_smfc *smfc)
{
- return ipu_module_enable(ipu, IPU_CONF_SMFC_EN);
+ struct ipu_smfc_priv *priv = smfc->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!priv->use_count)
+ ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
+
+ priv->use_count++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(ipu_smfc_enable);
-int ipu_smfc_disable(struct ipu_soc *ipu)
+int ipu_smfc_disable(struct ipu_smfc *smfc)
{
- return ipu_module_disable(ipu, IPU_CONF_SMFC_EN);
+ struct ipu_smfc_priv *priv = smfc->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->use_count--;
+
+ if (!priv->use_count)
+ ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
+
+ if (priv->use_count < 0)
+ priv->use_count = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(ipu_smfc_disable);
+struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
+{
+ struct ipu_smfc_priv *priv = ipu->smfc_priv;
+ struct ipu_smfc *smfc, *ret;
+ unsigned long flags;
+
+ if (chno >= 4)
+ return ERR_PTR(-EINVAL);
+
+ smfc = &priv->channel[chno];
+ ret = smfc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (smfc->inuse) {
+ ret = ERR_PTR(-EBUSY);
+ goto unlock;
+ }
+
+ smfc->inuse = true;
+unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_get);
+
+void ipu_smfc_put(struct ipu_smfc *smfc)
+{
+ struct ipu_smfc_priv *priv = smfc->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ smfc->inuse = false;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_put);
+
int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
unsigned long base)
{
- struct ipu_smfc_priv *smfc;
+ struct ipu_smfc_priv *priv;
+ int i;
- smfc = devm_kzalloc(dev, sizeof(*smfc), GFP_KERNEL);
- if (!smfc)
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- ipu->smfc_priv = smfc;
- spin_lock_init(&smfc->lock);
+ ipu->smfc_priv = priv;
+ spin_lock_init(&priv->lock);
+ priv->ipu = ipu;
- smfc->base = devm_ioremap(dev, base, PAGE_SIZE);
- if (!smfc->base)
+ priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+ if (!priv->base)
return -ENOMEM;
- pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, smfc->base);
+ for (i = 0; i < 4; i++) {
+ priv->channel[i].priv = priv;
+ priv->channel[i].chno = i;
+ }
+
+ pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
return 0;
}
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 580a88c..27fb980 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -291,10 +291,12 @@ void ipu_ic_dump(struct ipu_ic *ic);
/*
* IPU Sensor Multiple FIFO Controller (SMFC) functions
*/
-int ipu_smfc_enable(struct ipu_soc *ipu);
-int ipu_smfc_disable(struct ipu_soc *ipu);
-int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id);
-int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize);
+struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno);
+void ipu_smfc_put(struct ipu_smfc *smfc);
+int ipu_smfc_enable(struct ipu_smfc *smfc);
+int ipu_smfc_disable(struct ipu_smfc *smfc);
+int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id);
+int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize);
#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 08/28] gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (6 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 07/28] gpu: ipu-v3: smfc: Convert to per-channel Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 09/28] gpu: ipu-v3: Add ipu_mbus_code_to_colorspace() Steve Longerbeam
` (21 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds ipu_smfc_set_watermark() which programs a channel's SMFC FIFO
levels at which the watermark signal is set and cleared.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-smfc.c | 20 ++++++++++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 21 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c
index a6429ca..6ca9b43 100644
--- a/drivers/gpu/ipu-v3/ipu-smfc.c
+++ b/drivers/gpu/ipu-v3/ipu-smfc.c
@@ -80,6 +80,26 @@ int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
}
EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
+int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
+{
+ struct ipu_smfc_priv *priv = smfc->priv;
+ unsigned long flags;
+ u32 val, shift;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
+ val = readl(priv->base + SMFC_WMC);
+ val &= ~(0x3f << shift);
+ val |= ((clr_level << 3) | set_level) << shift;
+ writel(val, priv->base + SMFC_WMC);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
+
int ipu_smfc_enable(struct ipu_smfc *smfc)
{
struct ipu_smfc_priv *priv = smfc->priv;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 27fb980..e69b247 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -297,6 +297,7 @@ int ipu_smfc_enable(struct ipu_smfc *smfc);
int ipu_smfc_disable(struct ipu_smfc *smfc);
int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id);
int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize);
+int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level);
#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 09/28] gpu: ipu-v3: Add ipu_mbus_code_to_colorspace()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (7 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 08/28] gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 10/28] gpu: ipu-v3: Add rotation mode conversion utilities Steve Longerbeam
` (20 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Add ipu_mbus_code_to_colorspace() to find ipu_color_space from a
media bus pixel format code.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 13 +++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 14 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 85220ae..579f03c 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -551,6 +551,19 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
}
EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
+enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
+{
+ switch (mbus_code & 0xf000) {
+ case 0x1000:
+ return IPUV3_COLORSPACE_RGB;
+ case 0x2000:
+ return IPUV3_COLORSPACE_YUV;
+ default:
+ return IPUV3_COLORSPACE_UNKNOWN;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
+
struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
{
struct ipuv3_channel *channel;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index e69b247..91aeb65 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -447,6 +447,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
+enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
int burstsize)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 10/28] gpu: ipu-v3: Add rotation mode conversion utilities
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (8 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 09/28] gpu: ipu-v3: Add ipu_mbus_code_to_colorspace() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 11/28] gpu: ipu-v3: Add helper function checking if pixfmt is planar Steve Longerbeam
` (19 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Add two functions:
- ipu_degrees_to_rot_mode(): converts a degrees, hflip, and vflip setting
to an IPU rotation mode.
- ipu_rot_mode_to_degrees(): converts an IPU rotation mode with given hflip
and vflip settings to degrees.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 64 +++++++++++++++++++++++++++++++++++++++
include/video/imx-ipu-v3.h | 4 +++
2 files changed, 68 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 579f03c..d472b27 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -564,6 +564,70 @@ enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
}
EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
+int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
+ bool hflip, bool vflip)
+{
+ u32 r90, vf, hf;
+
+ switch (degrees) {
+ case 0:
+ vf = hf = r90 = 0;
+ break;
+ case 90:
+ vf = hf = 0;
+ r90 = 1;
+ break;
+ case 180:
+ vf = hf = 1;
+ r90 = 0;
+ break;
+ case 270:
+ vf = hf = r90 = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ hf ^= (u32)hflip;
+ vf ^= (u32)vflip;
+
+ *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
+
+int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
+ bool hflip, bool vflip)
+{
+ u32 r90, vf, hf;
+
+ r90 = ((u32)mode >> 2) & 0x1;
+ hf = ((u32)mode >> 1) & 0x1;
+ vf = ((u32)mode >> 0) & 0x1;
+ hf ^= (u32)hflip;
+ vf ^= (u32)vflip;
+
+ switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
+ case IPU_ROTATE_NONE:
+ *degrees = 0;
+ break;
+ case IPU_ROTATE_90_RIGHT:
+ *degrees = 90;
+ break;
+ case IPU_ROTATE_180:
+ *degrees = 180;
+ break;
+ case IPU_ROTATE_90_LEFT:
+ *degrees = 270;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
+
struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
{
struct ipuv3_channel *channel;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 91aeb65..99cf370 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -448,6 +448,10 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
+int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
+ bool hflip, bool vflip);
+int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
+ bool hflip, bool vflip);
static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
int burstsize)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 11/28] gpu: ipu-v3: Add helper function checking if pixfmt is planar
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (9 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 10/28] gpu: ipu-v3: Add rotation mode conversion utilities Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 12/28] gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h Steve Longerbeam
` (18 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam, Dmitry Eremin-Solenikov
Add simple helper function returning true if passed pixel format is one
of supported planar ones.
Signed-off-by: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 12 ++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 13 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index d472b27..909ef71 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -551,6 +551,18 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
}
EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
+bool ipu_pixelformat_is_planar(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
+
enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
{
switch (mbus_code & 0xf000) {
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 99cf370..20776cf 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -448,6 +448,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
+bool ipu_pixelformat_is_planar(u32 pixelformat);
int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
bool hflip, bool vflip);
int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 12/28] gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (10 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 11/28] gpu: ipu-v3: Add helper function checking if pixfmt is planar Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 13/28] gpu: ipu-v3: Add ipu_idmac_buffer_is_ready() Steve Longerbeam
` (17 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Move the IDMAC channel names to imx-ipu-v3.h, to make the names
available outside IPU. Add a couple new channels in the process
(async display BG/FG, channels 24 and 29).
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-prv.h | 25 -------------------------
include/video/imx-ipu-v3.h | 30 ++++++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index 8e0bc1d..90fc02a 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -24,31 +24,6 @@ struct ipu_soc;
#include <video/imx-ipu-v3.h>
-#define IPUV3_CHANNEL_CSI0 0
-#define IPUV3_CHANNEL_CSI1 1
-#define IPUV3_CHANNEL_CSI2 2
-#define IPUV3_CHANNEL_CSI3 3
-#define IPUV3_CHANNEL_VDI_MEM_IC_VF 5
-#define IPUV3_CHANNEL_MEM_IC_PP 11
-#define IPUV3_CHANNEL_MEM_IC_PRP_VF 12
-#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF 14
-#define IPUV3_CHANNEL_G_MEM_IC_PP 15
-#define IPUV3_CHANNEL_IC_PRP_ENC_MEM 20
-#define IPUV3_CHANNEL_IC_PRP_VF_MEM 21
-#define IPUV3_CHANNEL_IC_PP_MEM 22
-#define IPUV3_CHANNEL_MEM_BG_SYNC 23
-#define IPUV3_CHANNEL_MEM_FG_SYNC 27
-#define IPUV3_CHANNEL_MEM_DC_SYNC 28
-#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31
-#define IPUV3_CHANNEL_MEM_DC_ASYNC 41
-#define IPUV3_CHANNEL_MEM_ROT_ENC 45
-#define IPUV3_CHANNEL_MEM_ROT_VF 46
-#define IPUV3_CHANNEL_MEM_ROT_PP 47
-#define IPUV3_CHANNEL_ROT_ENC_MEM 48
-#define IPUV3_CHANNEL_ROT_VF_MEM 49
-#define IPUV3_CHANNEL_ROT_PP_MEM 50
-#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51
-
#define IPU_MCU_T_DEFAULT 8
#define IPU_CM_IDMAC_REG_OFS 0x00008000
#define IPU_CM_IC_REG_OFS 0x00020000
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 20776cf..44e337b 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -135,6 +135,36 @@ enum ipu_channel_irq {
IPU_IRQ_EOS = 192,
};
+/*
+ * Enumeration of IDMAC channels
+ */
+#define IPUV3_CHANNEL_CSI0 0
+#define IPUV3_CHANNEL_CSI1 1
+#define IPUV3_CHANNEL_CSI2 2
+#define IPUV3_CHANNEL_CSI3 3
+#define IPUV3_CHANNEL_VDI_MEM_IC_VF 5
+#define IPUV3_CHANNEL_MEM_IC_PP 11
+#define IPUV3_CHANNEL_MEM_IC_PRP_VF 12
+#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF 14
+#define IPUV3_CHANNEL_G_MEM_IC_PP 15
+#define IPUV3_CHANNEL_IC_PRP_ENC_MEM 20
+#define IPUV3_CHANNEL_IC_PRP_VF_MEM 21
+#define IPUV3_CHANNEL_IC_PP_MEM 22
+#define IPUV3_CHANNEL_MEM_BG_SYNC 23
+#define IPUV3_CHANNEL_MEM_BG_ASYNC 24
+#define IPUV3_CHANNEL_MEM_FG_SYNC 27
+#define IPUV3_CHANNEL_MEM_DC_SYNC 28
+#define IPUV3_CHANNEL_MEM_FG_ASYNC 29
+#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31
+#define IPUV3_CHANNEL_MEM_DC_ASYNC 41
+#define IPUV3_CHANNEL_MEM_ROT_ENC 45
+#define IPUV3_CHANNEL_MEM_ROT_VF 46
+#define IPUV3_CHANNEL_MEM_ROT_PP 47
+#define IPUV3_CHANNEL_ROT_ENC_MEM 48
+#define IPUV3_CHANNEL_ROT_VF_MEM 49
+#define IPUV3_CHANNEL_ROT_PP_MEM 50
+#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51
+
int ipu_map_irq(struct ipu_soc *ipu, int irq);
int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
enum ipu_channel_irq irq);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 13/28] gpu: ipu-v3: Add ipu_idmac_buffer_is_ready()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (11 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 12/28] gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 14/28] gpu: ipu-v3: Add ipu_idmac_clear_buffer() Steve Longerbeam
` (16 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Add ipu_idmac_buffer_is_ready(), returns true if the given buffer in
the given channel is set ready (owned by IPU), or false if not ready
(owned by CPU core).
Support has been added for third buffer, there is no support yet for
triple-buffering in idmac channels, but this function checks
buffer-ready for third buffer in case this support is added later.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 26 +++++++++++++++++++++++++-
drivers/gpu/ipu-v3/ipu-prv.h | 1 +
include/video/imx-ipu-v3.h | 1 +
3 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 909ef71..35442f20 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -682,7 +682,7 @@ void ipu_idmac_put(struct ipuv3_channel *channel)
}
EXPORT_SYMBOL_GPL(ipu_idmac_put);
-#define idma_mask(ch) (1 << (ch & 0x1f))
+#define idma_mask(ch) (1 << ((ch) & 0x1f))
void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
bool doublebuffer)
@@ -765,6 +765,30 @@ int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
}
EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
+bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ unsigned long flags;
+ u32 reg = 0;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+ switch (buf_num) {
+ case 0:
+ reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
+ break;
+ case 1:
+ reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
+ break;
+ case 2:
+ reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
+ break;
+ }
+ spin_unlock_irqrestore(&ipu->lock, flags);
+
+ return ((reg & idma_mask(channel->num)) != 0);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
+
void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
{
struct ipu_soc *ipu = channel->ipu;
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index 90fc02a..b7b8a52 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -68,6 +68,7 @@ struct ipu_soc;
#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254)
#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF2_RDY(ch) IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 44e337b..aeb8e63 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -201,6 +201,7 @@ int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
bool doublebuffer);
int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel);
+bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
/*
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 14/28] gpu: ipu-v3: Add ipu_idmac_clear_buffer()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (12 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 13/28] gpu: ipu-v3: Add ipu_idmac_buffer_is_ready() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 15/28] gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer() Steve Longerbeam
` (15 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Add the reverse of ipu_idmac_select_buffer(), that is, clear a buffer
ready status in a channel.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 28 ++++++++++++++++++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 29 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 35442f20..63f2cf2 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -807,6 +807,34 @@ void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
}
EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
+void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ unsigned int chno = channel->num;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
+ switch (buf_num) {
+ case 0:
+ ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+ break;
+ case 1:
+ ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+ break;
+ case 2:
+ ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
+ break;
+ default:
+ break;
+ }
+ ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
+
int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
{
struct ipu_soc *ipu = channel->ipu;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index aeb8e63..9ed1c75 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -203,6 +203,7 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel);
bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
+void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
/*
* IPU Display Controller (dc) functions
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 15/28] gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (13 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 14/28] gpu: ipu-v3: Add ipu_idmac_clear_buffer() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 16/28] gpu: ipu-v3: Add ipu_stride_to_bytes() Steve Longerbeam
` (14 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds __ipu_idmac_reset_current_buffer() that resets a channel's
internal current buffer pointer so that transfers start from buffer
0 on the next channel enable.
This operation is required for channel linking to work correctly,
for instance video capture pipelines that carry out image rotations
will fail after the first streaming unless this function is called
for each channel before re-enabling the channels.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 63f2cf2..7701974 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -684,6 +684,25 @@ EXPORT_SYMBOL_GPL(ipu_idmac_put);
#define idma_mask(ch) (1 << ((ch) & 0x1f))
+/*
+ * This is an undocumented feature, a write one to a channel bit in
+ * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
+ * internal current buffer pointer so that transfers start from buffer
+ * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
+ * only says these are read-only registers). This operation is required
+ * for channel linking to work correctly, for instance video capture
+ * pipelines that carry out image rotations will fail after the first
+ * streaming unless this function is called for each channel before
+ * re-enabling the channels.
+ */
+static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ unsigned int chno = channel->num;
+
+ ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
+}
+
void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
bool doublebuffer)
{
@@ -700,6 +719,8 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
reg &= ~idma_mask(channel->num);
ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
+ __ipu_idmac_reset_current_buffer(channel);
+
spin_unlock_irqrestore(&ipu->lock, flags);
}
EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
@@ -905,6 +926,8 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
val &= ~idma_mask(channel->num);
ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+ __ipu_idmac_reset_current_buffer(channel);
+
/* Set channel buffers NOT to be ready */
ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 16/28] gpu: ipu-v3: Add ipu_stride_to_bytes()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (14 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 15/28] gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-07-31 18:02 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 17/28] gpu: ipu-v3: Add ipu_idmac_enable_watermark() Steve Longerbeam
` (13 subsequent siblings)
29 siblings, 1 reply; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds ipu_stride_to_bytes(), which converts a pixel stride to bytes,
suitable for passing to cpmem.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 30 ++++++++++++++++++++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 31 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 7701974..30afef4 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -576,6 +576,36 @@ enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
}
EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
+int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ /*
+ * for the planar YUV formats, the stride passed to
+ * cpmem must be the stride in bytes of the Y plane.
+ * And all the planar YUV formats have an 8-bit
+ * Y component.
+ */
+ return (8 * pixel_stride) >> 3;
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ return (16 * pixel_stride) >> 3;
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_RGB24:
+ return (24 * pixel_stride) >> 3;
+ case V4L2_PIX_FMT_BGR32:
+ case V4L2_PIX_FMT_RGB32:
+ return (32 * pixel_stride) >> 3;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
+
int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
bool hflip, bool vflip)
{
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 9ed1c75..17a0bb8 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -480,6 +480,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
+int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat);
bool ipu_pixelformat_is_planar(u32 pixelformat);
int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
bool hflip, bool vflip);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 17/28] gpu: ipu-v3: Add ipu_idmac_enable_watermark()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (15 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 16/28] gpu: ipu-v3: Add ipu_stride_to_bytes() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 18/28] gpu: ipu-v3: Add ipu_idmac_lock_enable() Steve Longerbeam
` (12 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds the function ipu_idmac_enable_watermark(), which enables or disables
watermarking in the IDMAC channel. Enabling watermarking can increase a
channel's AXI bus arbitration priority.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 25 +++++++++++++++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 26 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 30afef4..7be56b6 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -986,6 +986,31 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
}
EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
+/*
+ * The imx6 rev. D TRM says that enabling the WM feature will increase
+ * a channel's priority. Refer to Table 36-8 Calculated priority value.
+ * The sub-module that is the sink or source for the channel must enable
+ * watermark signal for this to take effect (SMFC_WM for instance).
+ */
+void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
+ if (enable)
+ val |= 1 << (channel->num % 32);
+ else
+ val &= ~(1 << (channel->num % 32));
+ ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
+
static int ipu_memory_reset(struct ipu_soc *ipu)
{
unsigned long timeout;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 17a0bb8..df9863a 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -196,6 +196,7 @@ void ipu_idmac_put(struct ipuv3_channel *);
int ipu_idmac_enable_channel(struct ipuv3_channel *channel);
int ipu_idmac_disable_channel(struct ipuv3_channel *channel);
+void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable);
int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 18/28] gpu: ipu-v3: Add ipu_idmac_lock_enable()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (16 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 17/28] gpu: ipu-v3: Add ipu_idmac_enable_watermark() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 19/28] gpu: ipu-v3: Add idmac channel linking support Steve Longerbeam
` (11 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds ipu_idmac_lock_enable(), which enables or disables channel
burst locking.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 69 +++++++++++++++++++++++++++++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 70 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 7be56b6..b808ee0 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -755,6 +755,75 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
}
EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
+static const struct {
+ int chnum;
+ u32 reg;
+ int shift;
+} idmac_lock_en_info[] = {
+ { .chnum = 5, .reg = IDMAC_CH_LOCK_EN_1, .shift = 0, },
+ { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift = 2, },
+ { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift = 4, },
+ { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift = 6, },
+ { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift = 8, },
+ { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
+ { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
+ { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
+ { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
+ { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
+ { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
+ { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift = 0, },
+ { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift = 2, },
+ { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift = 4, },
+ { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift = 6, },
+ { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift = 8, },
+ { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
+};
+
+int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
+{
+ struct ipu_soc *ipu = channel->ipu;
+ unsigned long flags;
+ u32 bursts, regval;
+ int i;
+
+ switch (num_bursts) {
+ case 0:
+ case 1:
+ bursts = 0x00; /* locking disabled */
+ break;
+ case 2:
+ bursts = 0x01;
+ break;
+ case 4:
+ bursts = 0x02;
+ break;
+ case 8:
+ bursts = 0x03;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
+ if (channel->num == idmac_lock_en_info[i].chnum)
+ break;
+ }
+ if (i >= ARRAY_SIZE(idmac_lock_en_info))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
+ regval &= ~(0x03 << idmac_lock_en_info[i].shift);
+ regval |= (bursts << idmac_lock_en_info[i].shift);
+ ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
+
int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
{
unsigned long lock_flags;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index df9863a..bcd5141 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -197,6 +197,7 @@ void ipu_idmac_put(struct ipuv3_channel *);
int ipu_idmac_enable_channel(struct ipuv3_channel *channel);
int ipu_idmac_disable_channel(struct ipuv3_channel *channel);
void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable);
+int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts);
int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 19/28] gpu: ipu-v3: Add idmac channel linking support
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (17 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 18/28] gpu: ipu-v3: Add ipu_idmac_lock_enable() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 20/28] gpu: ipu-v3: Add ipu-cpmem unit Steve Longerbeam
` (10 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Add idmac channel linking/unlinking functions for specific IPU
client use cases. The following linkings are currently needed:
- ipu_link_prp_enc_rot_enc():
Link IPUV3_CHANNEL_IC_PRP_ENC_MEM to IPUV3_CHANNEL_MEM_ROT_ENC.
- ipu_link_prpvf_rot_prpvf():
Links IPUV3_CHANNEL_IC_PRP_VF_MEM to IPUV3_CHANNEL_MEM_ROT_VF.
- ipu_link_pp_rot_pp():
Links IPUV3_CHANNEL_IC_PP_MEM to IPUV3_CHANNEL_MEM_ROT_PP.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 159 +++++++++++++++++++++++++++++++++++++++
drivers/gpu/ipu-v3/ipu-prv.h | 58 ++++++++++++++
include/video/imx-ipu-v3.h | 8 ++
3 files changed, 225 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index b808ee0..3f91e14 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -955,6 +955,165 @@ void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
}
EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
+/*
+ * Links IPUV3_CHANNEL_IC_PRP_ENC_MEM to IPUV3_CHANNEL_MEM_ROT_ENC
+ */
+int ipu_link_prp_enc_rot_enc(struct ipu_soc *ipu)
+{
+ unsigned long flags;
+ u32 fs_proc_flow1;
+ u32 fs_proc_flow2;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+ fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+ fs_proc_flow1 |= (0x07 << FS_PRPENC_ROT_SRC_SEL_OFFSET);
+
+ fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+ fs_proc_flow2 |= (0x01 << FS_PRPENC_DEST_SEL_OFFSET);
+
+ ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_link_prp_enc_rot_enc);
+
+/*
+ * Unlinks IPUV3_CHANNEL_IC_PRP_ENC_MEM from IPUV3_CHANNEL_MEM_ROT_ENC
+ */
+int ipu_unlink_prp_enc_rot_enc(struct ipu_soc *ipu)
+{
+ unsigned long flags;
+ u32 fs_proc_flow1;
+ u32 fs_proc_flow2;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+ fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+ fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+
+ ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_unlink_prp_enc_rot_enc);
+
+/*
+ * Links IPUV3_CHANNEL_IC_PRP_VF_MEM to IPUV3_CHANNEL_MEM_ROT_VF
+ */
+int ipu_link_prpvf_rot_prpvf(struct ipu_soc *ipu)
+{
+ unsigned long flags;
+ u32 fs_proc_flow1;
+ u32 fs_proc_flow2;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+ fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+ fs_proc_flow1 |= (0x08 << FS_PRPVF_ROT_SRC_SEL_OFFSET);
+
+ fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+ fs_proc_flow2 |= (0x01 << FS_PRPVF_DEST_SEL_OFFSET);
+
+ ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_link_prpvf_rot_prpvf);
+
+/*
+ * Unlinks IPUV3_CHANNEL_IC_PRP_VF_MEM from IPUV3_CHANNEL_MEM_ROT_VF
+ */
+int ipu_unlink_prpvf_rot_prpvf(struct ipu_soc *ipu)
+{
+ unsigned long flags;
+ u32 fs_proc_flow1;
+ u32 fs_proc_flow2;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+ fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+ fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+
+ ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_unlink_prpvf_rot_prpvf);
+
+/*
+ * Links IPUV3_CHANNEL_IC_PP_MEM to IPUV3_CHANNEL_MEM_ROT_PP
+ */
+int ipu_link_pp_rot_pp(struct ipu_soc *ipu)
+{
+ unsigned long flags;
+ u32 fs_proc_flow1;
+ u32 fs_proc_flow2;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+ fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+ fs_proc_flow1 |= (0x05 << FS_PP_ROT_SRC_SEL_OFFSET);
+
+ fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+ fs_proc_flow2 |= (0x03 << FS_PP_DEST_SEL_OFFSET);
+
+ ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_link_pp_rot_pp);
+
+/*
+ * Unlinks IPUV3_CHANNEL_IC_PP_MEM from IPUV3_CHANNEL_MEM_ROT_PP
+ */
+int ipu_unlink_pp_rot_pp(struct ipu_soc *ipu)
+{
+ unsigned long flags;
+ u32 fs_proc_flow1;
+ u32 fs_proc_flow2;
+
+ spin_lock_irqsave(&ipu->lock, flags);
+
+ fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+ fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+ fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+
+ ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+ spin_unlock_irqrestore(&ipu->lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_unlink_pp_rot_pp);
+
int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
{
struct ipu_soc *ipu = channel->ipu;
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index b7b8a52..b84ec63 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -78,6 +78,64 @@ struct ipu_soc;
#define IPU_DI0_COUNTER_RELEASE (1 << 24)
#define IPU_DI1_COUNTER_RELEASE (1 << 25)
+#define FS_PRPENC_ROT_SRC_SEL_MASK (0xf << 0)
+#define FS_PRPENC_ROT_SRC_SEL_OFFSET 0
+#define FS_PRPVF_ROT_SRC_SEL_MASK (0xf << 8)
+#define FS_PRPVF_ROT_SRC_SEL_OFFSET 8
+#define FS_PP_ROT_SRC_SEL_MASK (0xf << 16)
+#define FS_PP_ROT_SRC_SEL_OFFSET 16
+#define FS_PP_SRC_SEL_MASK (0xf << 12)
+#define FS_PP_SRC_SEL_OFFSET 12
+#define FS_PP_SRC_SEL_VDOA (1 << 15)
+#define FS_PRP_SRC_SEL_MASK (0xf << 24)
+#define FS_PRP_SRC_SEL_OFFSET 24
+#define FS_VF_IN_VALID (1 << 31)
+#define FS_ENC_IN_VALID (1 << 30)
+#define FS_VDI_SRC_SEL_MASK (0x3 << 28)
+#define FS_VDI_SRC_SEL_VDOA (0x2 << 28)
+#define FS_VDOA_DEST_SEL_MASK (0x3 << 16)
+#define FS_VDOA_DEST_SEL_VDI (0x2 << 16)
+#define FS_VDOA_DEST_SEL_IC (0x1 << 16)
+#define FS_VDI_SRC_SEL_OFFSET 28
+
+#define FS_PRPENC_DEST_SEL_MASK (0xf << 0)
+#define FS_PRPENC_DEST_SEL_OFFSET 0
+#define FS_PRPVF_DEST_SEL_MASK (0xf << 4)
+#define FS_PRPVF_DEST_SEL_OFFSET 4
+#define FS_PRPVF_ROT_DEST_SEL_MASK (0xf << 8)
+#define FS_PRPVF_ROT_DEST_SEL_OFFSET 8
+#define FS_PP_DEST_SEL_MASK (0xf << 12)
+#define FS_PP_DEST_SEL_OFFSET 12
+#define FS_PP_ROT_DEST_SEL_MASK (0xf << 16)
+#define FS_PP_ROT_DEST_SEL_OFFSET 16
+#define FS_PRPENC_ROT_DEST_SEL_MASK (0xf << 20)
+#define FS_PRPENC_ROT_DEST_SEL_OFFSET 20
+
+#define FS_SMFC0_DEST_SEL_MASK (0xf << 0)
+#define FS_SMFC0_DEST_SEL_OFFSET 0
+#define FS_SMFC1_DEST_SEL_MASK (0x7 << 4)
+#define FS_SMFC1_DEST_SEL_OFFSET 4
+#define FS_SMFC2_DEST_SEL_MASK (0xf << 7)
+#define FS_SMFC2_DEST_SEL_OFFSET 7
+#define FS_SMFC3_DEST_SEL_MASK (0x7 << 11)
+#define FS_SMFC3_DEST_SEL_OFFSET 11
+
+#define FS_DC1_SRC_SEL_MASK (0xf << 20)
+#define FS_DC1_SRC_SEL_OFFSET 20
+#define FS_DC2_SRC_SEL_MASK (0xf << 16)
+#define FS_DC2_SRC_SEL_OFFSET 16
+#define FS_DP_SYNC0_SRC_SEL_MASK (0xf << 0)
+#define FS_DP_SYNC0_SRC_SEL_OFFSET 0
+#define FS_DP_SYNC1_SRC_SEL_MASK (0xf << 4)
+#define FS_DP_SYNC1_SRC_SEL_OFFSET 4
+#define FS_DP_ASYNC0_SRC_SEL_MASK (0xf << 8)
+#define FS_DP_ASYNC0_SRC_SEL_OFFSET 8
+#define FS_DP_ASYNC1_SRC_SEL_MASK (0xf << 12)
+#define FS_DP_ASYNC1_SRC_SEL_OFFSET 12
+
+#define FS_AUTO_REF_PER_MASK 0
+#define FS_AUTO_REF_PER_OFFSET 16
+
#define IPU_IDMAC_REG(offset) (offset)
#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index bcd5141..0b0ce04 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -207,6 +207,14 @@ bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
+/* Channel linking functions */
+int ipu_link_prp_enc_rot_enc(struct ipu_soc *ipu);
+int ipu_unlink_prp_enc_rot_enc(struct ipu_soc *ipu);
+int ipu_link_prpvf_rot_prpvf(struct ipu_soc *ipu);
+int ipu_unlink_prpvf_rot_prpvf(struct ipu_soc *ipu);
+int ipu_link_pp_rot_pp(struct ipu_soc *ipu);
+int ipu_unlink_pp_rot_pp(struct ipu_soc *ipu);
+
/*
* IPU Display Controller (dc) functions
*/
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 20/28] gpu: ipu-v3: Add ipu-cpmem unit
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (18 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 19/28] gpu: ipu-v3: Add idmac channel linking support Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 21/28] staging: imx-drm: Convert to new ipu_cpmem API Steve Longerbeam
` (9 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Move channel parameter memory setup functions and macros into a new
submodule ipu-cpmem. In the process, cleanup arguments to the functions
to take a channel pointer instead of a pointer into cpmem for that
channel. That allows the structure of the parameter memory to be
private to ipu-cpmem.c.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/Makefile | 4 +-
drivers/gpu/ipu-v3/ipu-common.c | 457 +-----------------------------
drivers/gpu/ipu-v3/ipu-cpmem.c | 597 +++++++++++++++++++++++++++++++++++++++
drivers/gpu/ipu-v3/ipu-prv.h | 14 +-
include/video/imx-ipu-v3.h | 188 +++---------
5 files changed, 658 insertions(+), 602 deletions(-)
create mode 100644 drivers/gpu/ipu-v3/ipu-cpmem.c
diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile
index 830804f..107ec23 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/ipu-v3/Makefile
@@ -1,4 +1,4 @@
obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
-imx-ipu-v3-objs := ipu-common.o ipu-csi.o ipu-dc.o ipu-di.o ipu-dp.o \
- ipu-dmfc.o ipu-ic.o ipu-smfc.o
+imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
+ ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 3f91e14..81930f3 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -44,17 +44,6 @@ static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
writel(value, ipu->cm_reg + offset);
}
-static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
-{
- return readl(ipu->idmac_reg + offset);
-}
-
-static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
- unsigned offset)
-{
- writel(value, ipu->idmac_reg + offset);
-}
-
int ipu_get_num(struct ipu_soc *ipu)
{
return ipu->id;
@@ -71,379 +60,6 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
}
EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update);
-struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel)
-{
- struct ipu_soc *ipu = channel->ipu;
-
- return ipu->cpmem_base + channel->num;
-}
-EXPORT_SYMBOL_GPL(ipu_get_cpmem);
-
-void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel)
-{
- struct ipu_soc *ipu = channel->ipu;
- struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel);
- u32 val;
-
- if (ipu->ipu_type == IPUV3EX)
- ipu_ch_param_write_field(p, IPU_FIELD_ID, 1);
-
- val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num));
- val |= 1 << (channel->num % 32);
- ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num));
-};
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
-
-void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v)
-{
- u32 bit = (wbs >> 8) % 160;
- u32 size = wbs & 0xff;
- u32 word = (wbs >> 8) / 160;
- u32 i = bit / 32;
- u32 ofs = bit % 32;
- u32 mask = (1 << size) - 1;
- u32 val;
-
- pr_debug("%s %d %d %d\n", __func__, word, bit , size);
-
- val = readl(&base->word[word].data[i]);
- val &= ~(mask << ofs);
- val |= v << ofs;
- writel(val, &base->word[word].data[i]);
-
- if ((bit + size - 1) / 32 > i) {
- val = readl(&base->word[word].data[i + 1]);
- val &= ~(mask >> (ofs ? (32 - ofs) : 0));
- val |= v >> (ofs ? (32 - ofs) : 0);
- writel(val, &base->word[word].data[i + 1]);
- }
-}
-EXPORT_SYMBOL_GPL(ipu_ch_param_write_field);
-
-u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs)
-{
- u32 bit = (wbs >> 8) % 160;
- u32 size = wbs & 0xff;
- u32 word = (wbs >> 8) / 160;
- u32 i = bit / 32;
- u32 ofs = bit % 32;
- u32 mask = (1 << size) - 1;
- u32 val = 0;
-
- pr_debug("%s %d %d %d\n", __func__, word, bit , size);
-
- val = (readl(&base->word[word].data[i]) >> ofs) & mask;
-
- if ((bit + size - 1) / 32 > i) {
- u32 tmp;
- tmp = readl(&base->word[word].data[i + 1]);
- tmp &= mask >> (ofs ? (32 - ofs) : 0);
- val |= tmp << (ofs ? (32 - ofs) : 0);
- }
-
- return val;
-}
-EXPORT_SYMBOL_GPL(ipu_ch_param_read_field);
-
-int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p,
- const struct ipu_rgb *rgb)
-{
- int bpp = 0, npb = 0, ro, go, bo, to;
-
- ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
- go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
- bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
- to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
-
- ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro);
- ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go);
- ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo);
-
- if (rgb->transp.length) {
- ipu_ch_param_write_field(p, IPU_FIELD_WID3,
- rgb->transp.length - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to);
- } else {
- ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS3,
- rgb->bits_per_pixel);
- }
-
- switch (rgb->bits_per_pixel) {
- case 32:
- bpp = 0;
- npb = 15;
- break;
- case 24:
- bpp = 1;
- npb = 19;
- break;
- case 16:
- bpp = 3;
- npb = 31;
- break;
- case 8:
- bpp = 5;
- npb = 63;
- break;
- default:
- return -EINVAL;
- }
- ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
- ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
-
-int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
- int width)
-{
- int bpp = 0, npb = 0;
-
- switch (width) {
- case 32:
- bpp = 0;
- npb = 15;
- break;
- case 24:
- bpp = 1;
- npb = 19;
- break;
- case 16:
- bpp = 3;
- npb = 31;
- break;
- case 8:
- bpp = 5;
- npb = 63;
- break;
- default:
- return -EINVAL;
- }
-
- ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
- ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
-
-void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p,
- u32 pixel_format)
-{
- switch (pixel_format) {
- case V4L2_PIX_FMT_UYVY:
- ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */
- ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0xA); /* pix format */
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */
- break;
- case V4L2_PIX_FMT_YUYV:
- ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */
- ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0x8); /* pix format */
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */
- break;
- }
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
-
-void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
- u32 pixel_format, int stride, int u_offset, int v_offset)
-{
- switch (pixel_format) {
- case V4L2_PIX_FMT_YUV420:
- ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8);
- ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8);
- break;
- case V4L2_PIX_FMT_YVU420:
- ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_UBO, v_offset / 8);
- ipu_ch_param_write_field(p, IPU_FIELD_VBO, u_offset / 8);
- break;
- }
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
-
-void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
- int stride, int height)
-{
- int u_offset, v_offset;
- int uv_stride = 0;
-
- switch (pixel_format) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- uv_stride = stride / 2;
- u_offset = stride * height;
- v_offset = u_offset + (uv_stride * height / 2);
- ipu_cpmem_set_yuv_planar_full(p, pixel_format, stride,
- u_offset, v_offset);
- break;
- }
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
-
-static const struct ipu_rgb def_rgb_32 = {
- .red = { .offset = 16, .length = 8, },
- .green = { .offset = 8, .length = 8, },
- .blue = { .offset = 0, .length = 8, },
- .transp = { .offset = 24, .length = 8, },
- .bits_per_pixel = 32,
-};
-
-static const struct ipu_rgb def_bgr_32 = {
- .red = { .offset = 0, .length = 8, },
- .green = { .offset = 8, .length = 8, },
- .blue = { .offset = 16, .length = 8, },
- .transp = { .offset = 24, .length = 8, },
- .bits_per_pixel = 32,
-};
-
-static const struct ipu_rgb def_rgb_24 = {
- .red = { .offset = 16, .length = 8, },
- .green = { .offset = 8, .length = 8, },
- .blue = { .offset = 0, .length = 8, },
- .transp = { .offset = 0, .length = 0, },
- .bits_per_pixel = 24,
-};
-
-static const struct ipu_rgb def_bgr_24 = {
- .red = { .offset = 0, .length = 8, },
- .green = { .offset = 8, .length = 8, },
- .blue = { .offset = 16, .length = 8, },
- .transp = { .offset = 0, .length = 0, },
- .bits_per_pixel = 24,
-};
-
-static const struct ipu_rgb def_rgb_16 = {
- .red = { .offset = 11, .length = 5, },
- .green = { .offset = 5, .length = 6, },
- .blue = { .offset = 0, .length = 5, },
- .transp = { .offset = 0, .length = 0, },
- .bits_per_pixel = 16,
-};
-
-static const struct ipu_rgb def_bgr_16 = {
- .red = { .offset = 0, .length = 5, },
- .green = { .offset = 5, .length = 6, },
- .blue = { .offset = 11, .length = 5, },
- .transp = { .offset = 0, .length = 0, },
- .bits_per_pixel = 16,
-};
-
-#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
-#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
- (pix->width * (y) / 4) + (x) / 2)
-#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
- (pix->width * pix->height / 4) + \
- (pix->width * (y) / 4) + (x) / 2)
-
-int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc)
-{
- switch (drm_fourcc) {
- case DRM_FORMAT_YUV420:
- case DRM_FORMAT_YVU420:
- /* pix format */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2);
- /* burst size */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63);
- break;
- case DRM_FORMAT_UYVY:
- /* bits/pixel */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
- /* pix format */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA);
- /* burst size */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
- break;
- case DRM_FORMAT_YUYV:
- /* bits/pixel */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
- /* pix format */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8);
- /* burst size */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
- break;
- case DRM_FORMAT_ABGR8888:
- case DRM_FORMAT_XBGR8888:
- ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32);
- break;
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_XRGB8888:
- ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32);
- break;
- case DRM_FORMAT_BGR888:
- ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24);
- break;
- case DRM_FORMAT_RGB888:
- ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24);
- break;
- case DRM_FORMAT_RGB565:
- ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16);
- break;
- case DRM_FORMAT_BGR565:
- ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
-
-/*
- * The V4L2 spec defines packed RGB formats in memory byte order, which from
- * point of view of the IPU corresponds to little-endian words with the first
- * component in the least significant bits.
- * The DRM pixel formats and IPU internal representation are ordered the other
- * way around, with the first named component ordered at the most significant
- * bits. Further, V4L2 formats are not well defined:
- * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
- * We choose the interpretation which matches GStreamer behavior.
- */
-static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
-{
- switch (pixelformat) {
- case V4L2_PIX_FMT_RGB565:
- /*
- * Here we choose the 'corrected' interpretation of RGBP, a
- * little-endian 16-bit word with the red component at the most
- * significant bits:
- * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
- */
- return DRM_FORMAT_RGB565;
- case V4L2_PIX_FMT_BGR24:
- /* B G R <=> [24:0] R:G:B */
- return DRM_FORMAT_RGB888;
- case V4L2_PIX_FMT_RGB24:
- /* R G B <=> [24:0] B:G:R */
- return DRM_FORMAT_BGR888;
- case V4L2_PIX_FMT_BGR32:
- /* B G R A <=> [32:0] A:B:G:R */
- return DRM_FORMAT_XRGB8888;
- case V4L2_PIX_FMT_RGB32:
- /* R G B A <=> [32:0] A:B:G:R */
- return DRM_FORMAT_XBGR8888;
- case V4L2_PIX_FMT_UYVY:
- return DRM_FORMAT_UYVY;
- case V4L2_PIX_FMT_YUYV:
- return DRM_FORMAT_YUYV;
- case V4L2_PIX_FMT_YUV420:
- return DRM_FORMAT_YUV420;
- case V4L2_PIX_FMT_YVU420:
- return DRM_FORMAT_YVU420;
- }
-
- return -EINVAL;
-}
-
enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
{
switch (drm_fourcc) {
@@ -471,66 +87,6 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
}
EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
-int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
- struct ipu_image *image)
-{
- struct v4l2_pix_format *pix = &image->pix;
- int y_offset, u_offset, v_offset;
-
- pr_debug("%s: resolution: %dx%d stride: %d\n",
- __func__, pix->width, pix->height,
- pix->bytesperline);
-
- ipu_cpmem_set_resolution(cpmem, image->rect.width,
- image->rect.height);
- ipu_cpmem_set_stride(cpmem, pix->bytesperline);
-
- ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
-
- switch (pix->pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
- u_offset = U_OFFSET(pix, image->rect.left,
- image->rect.top) - y_offset;
- v_offset = V_OFFSET(pix, image->rect.left,
- image->rect.top) - y_offset;
-
- ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat,
- pix->bytesperline, u_offset, v_offset);
- ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset);
- break;
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUYV:
- ipu_cpmem_set_buffer(cpmem, 0, image->phys +
- image->rect.left * 2 +
- image->rect.top * image->pix.bytesperline);
- break;
- case V4L2_PIX_FMT_RGB32:
- case V4L2_PIX_FMT_BGR32:
- ipu_cpmem_set_buffer(cpmem, 0, image->phys +
- image->rect.left * 4 +
- image->rect.top * image->pix.bytesperline);
- break;
- case V4L2_PIX_FMT_RGB565:
- ipu_cpmem_set_buffer(cpmem, 0, image->phys +
- image->rect.left * 2 +
- image->rect.top * image->pix.bytesperline);
- break;
- case V4L2_PIX_FMT_RGB24:
- case V4L2_PIX_FMT_BGR24:
- ipu_cpmem_set_buffer(cpmem, 0, image->phys +
- image->rect.left * 3 +
- image->rect.top * image->pix.bytesperline);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
-
enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
{
switch (pixelformat) {
@@ -1387,6 +943,12 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
struct device *dev = &pdev->dev;
const struct ipu_devtype *devtype = ipu->devtype;
+ ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
+ if (ret) {
+ unit = "cpmem";
+ goto err_cpmem;
+ }
+
ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
IPU_CONF_CSI0_EN, ipu_clk);
if (ret) {
@@ -1469,6 +1031,8 @@ err_ic:
err_csi_1:
ipu_csi_exit(ipu, 0);
err_csi_0:
+ ipu_cpmem_exit(ipu);
+err_cpmem:
dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
return ret;
}
@@ -1548,6 +1112,7 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
ipu_ic_exit(ipu);
ipu_csi_exit(ipu, 1);
ipu_csi_exit(ipu, 0);
+ ipu_cpmem_exit(ipu);
}
static int platform_remove_devices_fn(struct device *dev, void *unused)
@@ -1796,10 +1361,8 @@ static int ipu_probe(struct platform_device *pdev)
ipu->idmac_reg = devm_ioremap(&pdev->dev,
ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
PAGE_SIZE);
- ipu->cpmem_base = devm_ioremap(&pdev->dev,
- ipu_base + devtype->cpmem_ofs, PAGE_SIZE);
- if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base)
+ if (!ipu->cm_reg || !ipu->idmac_reg)
return -ENOMEM;
ipu->clk = devm_clk_get(&pdev->dev, "bus");
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
new file mode 100644
index 0000000..7adfa78
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2012 Mentor Graphics Inc.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/types.h>
+#include <linux/bitrev.h>
+#include <linux/io.h>
+#include <drm/drm_fourcc.h>
+#include "ipu-prv.h"
+
+struct ipu_cpmem_word {
+ u32 data[5];
+ u32 res[3];
+};
+
+struct ipu_ch_param {
+ struct ipu_cpmem_word word[2];
+};
+
+struct ipu_cpmem {
+ struct ipu_ch_param __iomem *base;
+ u32 module;
+ spinlock_t lock;
+ int use_count;
+ struct ipu_soc *ipu;
+};
+
+#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+
+#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
+#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
+#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
+#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
+#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
+#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
+#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
+
+#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
+#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
+#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
+#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
+#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
+#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
+#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
+#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
+#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
+#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
+#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
+#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
+#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
+#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
+#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
+#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
+#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
+#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
+#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
+#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
+#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
+#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
+#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
+#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
+#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
+#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
+#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
+#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
+#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
+#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
+#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
+#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
+#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
+#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
+#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
+#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
+#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
+#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
+#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
+#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
+#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
+#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
+#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
+#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
+#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
+#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
+#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
+#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
+#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
+#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
+
+static inline struct ipu_ch_param __iomem *
+ipu_get_cpmem(struct ipuv3_channel *ch)
+{
+ struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
+
+ return cpmem->base + ch->num;
+}
+
+static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
+{
+ struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
+ u32 bit = (wbs >> 8) % 160;
+ u32 size = wbs & 0xff;
+ u32 word = (wbs >> 8) / 160;
+ u32 i = bit / 32;
+ u32 ofs = bit % 32;
+ u32 mask = (1 << size) - 1;
+ u32 val;
+
+ pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+ val = readl(&base->word[word].data[i]);
+ val &= ~(mask << ofs);
+ val |= v << ofs;
+ writel(val, &base->word[word].data[i]);
+
+ if ((bit + size - 1) / 32 > i) {
+ val = readl(&base->word[word].data[i + 1]);
+ val &= ~(mask >> (ofs ? (32 - ofs) : 0));
+ val |= v >> (ofs ? (32 - ofs) : 0);
+ writel(val, &base->word[word].data[i + 1]);
+ }
+}
+
+static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
+{
+ struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
+ u32 bit = (wbs >> 8) % 160;
+ u32 size = wbs & 0xff;
+ u32 word = (wbs >> 8) / 160;
+ u32 i = bit / 32;
+ u32 ofs = bit % 32;
+ u32 mask = (1 << size) - 1;
+ u32 val = 0;
+
+ pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+ val = (readl(&base->word[word].data[i]) >> ofs) & mask;
+
+ if ((bit + size - 1) / 32 > i) {
+ u32 tmp;
+
+ tmp = readl(&base->word[word].data[i + 1]);
+ tmp &= mask >> (ofs ? (32 - ofs) : 0);
+ val |= tmp << (ofs ? (32 - ofs) : 0);
+ }
+
+ return val;
+}
+
+/*
+ * The V4L2 spec defines packed RGB formats in memory byte order, which from
+ * point of view of the IPU corresponds to little-endian words with the first
+ * component in the least significant bits.
+ * The DRM pixel formats and IPU internal representation are ordered the other
+ * way around, with the first named component ordered at the most significant
+ * bits. Further, V4L2 formats are not well defined:
+ * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
+ * We choose the interpretation which matches GStreamer behavior.
+ */
+static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_RGB565:
+ /*
+ * Here we choose the 'corrected' interpretation of RGBP, a
+ * little-endian 16-bit word with the red component at the most
+ * significant bits:
+ * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
+ */
+ return DRM_FORMAT_RGB565;
+ case V4L2_PIX_FMT_BGR24:
+ /* B G R <=> [24:0] R:G:B */
+ return DRM_FORMAT_RGB888;
+ case V4L2_PIX_FMT_RGB24:
+ /* R G B <=> [24:0] B:G:R */
+ return DRM_FORMAT_BGR888;
+ case V4L2_PIX_FMT_BGR32:
+ /* B G R A <=> [32:0] A:B:G:R */
+ return DRM_FORMAT_XRGB8888;
+ case V4L2_PIX_FMT_RGB32:
+ /* R G B A <=> [32:0] A:B:G:R */
+ return DRM_FORMAT_XBGR8888;
+ case V4L2_PIX_FMT_UYVY:
+ return DRM_FORMAT_UYVY;
+ case V4L2_PIX_FMT_YUYV:
+ return DRM_FORMAT_YUYV;
+ case V4L2_PIX_FMT_YUV420:
+ return DRM_FORMAT_YUV420;
+ case V4L2_PIX_FMT_YVU420:
+ return DRM_FORMAT_YVU420;
+ }
+
+ return -EINVAL;
+}
+
+void ipu_cpmem_zero(struct ipuv3_channel *ch)
+{
+ struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+ void __iomem *base = p;
+ int i;
+
+ for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
+ writel(0, base + i * sizeof(u32));
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
+
+void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
+{
+ ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
+
+void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
+{
+ ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
+
+void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
+{
+ struct ipu_soc *ipu = ch->ipu;
+ u32 val;
+
+ if (ipu->ipu_type == IPUV3EX)
+ ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
+
+ val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
+ val |= 1 << (ch->num % 32);
+ ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
+};
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
+
+void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
+{
+ if (bufnum)
+ ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
+ else
+ ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
+
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+{
+ ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8);
+ ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1);
+};
+EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
+
+void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
+{
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
+};
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
+
+int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
+ const struct ipu_rgb *rgb)
+{
+ int bpp = 0, npb = 0, ro, go, bo, to;
+
+ ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
+ go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
+ bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
+ to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
+
+ ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
+ ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
+ ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
+
+ if (rgb->transp.length) {
+ ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
+ rgb->transp.length - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
+ } else {
+ ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
+ ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
+ rgb->bits_per_pixel);
+ }
+
+ switch (rgb->bits_per_pixel) {
+ case 32:
+ bpp = 0;
+ npb = 15;
+ break;
+ case 24:
+ bpp = 1;
+ npb = 19;
+ break;
+ case 16:
+ bpp = 3;
+ npb = 31;
+ break;
+ case 8:
+ bpp = 5;
+ npb = 63;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
+
+int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
+{
+ int bpp = 0, npb = 0;
+
+ switch (width) {
+ case 32:
+ bpp = 0;
+ npb = 15;
+ break;
+ case 24:
+ bpp = 1;
+ npb = 19;
+ break;
+ case 16:
+ bpp = 3;
+ npb = 31;
+ break;
+ case 8:
+ bpp = 5;
+ npb = 63;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
+
+void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
+{
+ switch (pixel_format) {
+ case V4L2_PIX_FMT_UYVY:
+ ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
+
+void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
+ u32 pixel_format, int stride,
+ int u_offset, int v_offset)
+{
+ switch (pixel_format) {
+ case V4L2_PIX_FMT_YUV420:
+ ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
+ ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
+ ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
+
+void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
+ u32 pixel_format, int stride, int height)
+{
+ int u_offset, v_offset;
+ int uv_stride = 0;
+
+ switch (pixel_format) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ uv_stride = stride / 2;
+ u_offset = stride * height;
+ v_offset = u_offset + (uv_stride * height / 2);
+ ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+ u_offset, v_offset);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
+
+static const struct ipu_rgb def_rgb_32 = {
+ .red = { .offset = 16, .length = 8, },
+ .green = { .offset = 8, .length = 8, },
+ .blue = { .offset = 0, .length = 8, },
+ .transp = { .offset = 24, .length = 8, },
+ .bits_per_pixel = 32,
+};
+
+static const struct ipu_rgb def_bgr_32 = {
+ .red = { .offset = 0, .length = 8, },
+ .green = { .offset = 8, .length = 8, },
+ .blue = { .offset = 16, .length = 8, },
+ .transp = { .offset = 24, .length = 8, },
+ .bits_per_pixel = 32,
+};
+
+static const struct ipu_rgb def_rgb_24 = {
+ .red = { .offset = 16, .length = 8, },
+ .green = { .offset = 8, .length = 8, },
+ .blue = { .offset = 0, .length = 8, },
+ .transp = { .offset = 0, .length = 0, },
+ .bits_per_pixel = 24,
+};
+
+static const struct ipu_rgb def_bgr_24 = {
+ .red = { .offset = 0, .length = 8, },
+ .green = { .offset = 8, .length = 8, },
+ .blue = { .offset = 16, .length = 8, },
+ .transp = { .offset = 0, .length = 0, },
+ .bits_per_pixel = 24,
+};
+
+static const struct ipu_rgb def_rgb_16 = {
+ .red = { .offset = 11, .length = 5, },
+ .green = { .offset = 5, .length = 6, },
+ .blue = { .offset = 0, .length = 5, },
+ .transp = { .offset = 0, .length = 0, },
+ .bits_per_pixel = 16,
+};
+
+static const struct ipu_rgb def_bgr_16 = {
+ .red = { .offset = 0, .length = 5, },
+ .green = { .offset = 5, .length = 6, },
+ .blue = { .offset = 11, .length = 5, },
+ .transp = { .offset = 0, .length = 0, },
+ .bits_per_pixel = 16,
+};
+
+#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
+#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * (y) / 4) + (x) / 2)
+#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * pix->height / 4) + \
+ (pix->width * (y) / 4) + (x) / 2)
+
+int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
+{
+ switch (drm_fourcc) {
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ /* pix format */
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
+ /* burst size */
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+ break;
+ case DRM_FORMAT_UYVY:
+ /* bits/pixel */
+ ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
+ /* pix format */
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
+ /* burst size */
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+ break;
+ case DRM_FORMAT_YUYV:
+ /* bits/pixel */
+ ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
+ /* pix format */
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
+ /* burst size */
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+ break;
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ ipu_cpmem_set_format_rgb(ch, &def_bgr_32);
+ break;
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ ipu_cpmem_set_format_rgb(ch, &def_rgb_32);
+ break;
+ case DRM_FORMAT_BGR888:
+ ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
+ break;
+ case DRM_FORMAT_RGB888:
+ ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
+ break;
+ case DRM_FORMAT_RGB565:
+ ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
+ break;
+ case DRM_FORMAT_BGR565:
+ ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
+
+int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
+{
+ struct v4l2_pix_format *pix = &image->pix;
+ int y_offset, u_offset, v_offset;
+
+ pr_debug("%s: resolution: %dx%d stride: %d\n",
+ __func__, pix->width, pix->height,
+ pix->bytesperline);
+
+ ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
+ ipu_cpmem_set_stride(ch, pix->bytesperline);
+
+ ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+ u_offset = U_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+ v_offset = V_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+
+ ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+ pix->bytesperline, u_offset, v_offset);
+ ipu_cpmem_set_buffer(ch, 0, image->phys + y_offset);
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
+ ipu_cpmem_set_buffer(ch, 0, image->phys +
+ image->rect.left * 2 +
+ image->rect.top * image->pix.bytesperline);
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_BGR32:
+ ipu_cpmem_set_buffer(ch, 0, image->phys +
+ image->rect.left * 4 +
+ image->rect.top * image->pix.bytesperline);
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ ipu_cpmem_set_buffer(ch, 0, image->phys +
+ image->rect.left * 2 +
+ image->rect.top * image->pix.bytesperline);
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ ipu_cpmem_set_buffer(ch, 0, image->phys +
+ image->rect.left * 3 +
+ image->rect.top * image->pix.bytesperline);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
+
+int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
+{
+ struct ipu_cpmem *cpmem;
+
+ cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
+ if (!cpmem)
+ return -ENOMEM;
+
+ ipu->cpmem_priv = cpmem;
+
+ spin_lock_init(&cpmem->lock);
+ cpmem->base = devm_ioremap(dev, base, SZ_128K);
+ if (!cpmem->base)
+ return -ENOMEM;
+
+ dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
+ base, cpmem->base);
+ cpmem->ipu = ipu;
+
+ return 0;
+}
+
+void ipu_cpmem_exit(struct ipu_soc *ipu)
+{
+}
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index b84ec63..5623515 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -190,6 +190,7 @@ struct ipuv3_channel {
struct ipu_soc *ipu;
};
+struct ipu_cpmem;
struct ipu_csi;
struct ipu_dc_priv;
struct ipu_dmfc_priv;
@@ -208,7 +209,6 @@ struct ipu_soc {
void __iomem *cm_reg;
void __iomem *idmac_reg;
- struct ipu_ch_param __iomem *cpmem_base;
int id;
int usecount;
@@ -221,6 +221,7 @@ struct ipu_soc {
int irq_err;
struct irq_domain *domain;
+ struct ipu_cpmem *cpmem_priv;
struct ipu_dc_priv *dc_priv;
struct ipu_dp_priv *dp_priv;
struct ipu_dmfc_priv *dmfc_priv;
@@ -230,6 +231,17 @@ struct ipu_soc {
struct ipu_smfc_priv *smfc_priv;
};
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
+ unsigned offset)
+{
+ writel(value, ipu->idmac_reg + offset);
+}
+
void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 0b0ce04..a86a98a 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -207,6 +207,42 @@ bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
+/*
+ * IPU Channel Parameter Memory (cpmem) functions
+ */
+struct ipu_rgb {
+ struct fb_bitfield red;
+ struct fb_bitfield green;
+ struct fb_bitfield blue;
+ struct fb_bitfield transp;
+ int bits_per_pixel;
+};
+
+struct ipu_image {
+ struct v4l2_pix_format pix;
+ struct v4l2_rect rect;
+ dma_addr_t phys;
+};
+
+void ipu_cpmem_zero(struct ipuv3_channel *ch);
+void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres);
+void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
+void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
+int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
+ const struct ipu_rgb *rgb);
+int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width);
+void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format);
+void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
+ u32 pixel_format, int stride,
+ int u_offset, int v_offset);
+void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
+ u32 pixel_format, int stride, int height);
+int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc);
+int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image);
+
/* Channel linking functions */
int ipu_link_prp_enc_rot_enc(struct ipu_soc *ipu);
int ipu_unlink_prp_enc_rot_enc(struct ipu_soc *ipu);
@@ -341,152 +377,6 @@ int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id);
int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize);
int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level);
-#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
-
-#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
-#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
-#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
-#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
-#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
-#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
-#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
-
-#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
-#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
-#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
-#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
-#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
-#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
-#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
-#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
-#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
-#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
-#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
-#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
-#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
-#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
-#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
-#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
-#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
-#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
-#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
-#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
-#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
-#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
-#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
-#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
-#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
-#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
-#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
-#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
-#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
-#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
-#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
-#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
-#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
-#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
-#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
-#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
-#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
-#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
-#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
-#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
-#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
-#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
-#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
-#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
-#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
-#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
-#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
-#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
-#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
-#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
-
-struct ipu_cpmem_word {
- u32 data[5];
- u32 res[3];
-};
-
-struct ipu_ch_param {
- struct ipu_cpmem_word word[2];
-};
-
-void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v);
-u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs);
-struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel);
-void ipu_ch_param_dump(struct ipu_ch_param __iomem *p);
-
-static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p)
-{
- int i;
- void __iomem *base = p;
-
- for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
- writel(0, base + i * sizeof(u32));
-}
-
-static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p,
- int bufnum, dma_addr_t buf)
-{
- if (bufnum)
- ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3);
- else
- ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3);
-}
-
-static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p,
- int xres, int yres)
-{
- ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1);
-}
-
-static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p,
- int stride)
-{
- ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1);
-}
-
-void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel);
-
-struct ipu_rgb {
- struct fb_bitfield red;
- struct fb_bitfield green;
- struct fb_bitfield blue;
- struct fb_bitfield transp;
- int bits_per_pixel;
-};
-
-struct ipu_image {
- struct v4l2_pix_format pix;
- struct v4l2_rect rect;
- dma_addr_t phys;
-};
-
-int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
- int width);
-
-int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *,
- const struct ipu_rgb *rgb);
-
-static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p,
- int stride)
-{
- ipu_ch_param_write_field(p, IPU_FIELD_SO, 1);
- ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8);
- ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1);
-};
-
-void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
- int stride, int height);
-void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p,
- u32 pixel_format);
-void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
- u32 pixel_format, int stride, int u_offset, int v_offset);
-int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat);
-int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
- struct ipu_image *image);
-
enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
@@ -497,12 +387,6 @@ int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
bool hflip, bool vflip);
-static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
- int burstsize)
-{
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1);
-};
-
struct ipu_client_platformdata {
int csi;
int di;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 21/28] staging: imx-drm: Convert to new ipu_cpmem API
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (19 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 20/28] gpu: ipu-v3: Add ipu-cpmem unit Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 22/28] gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode() Steve Longerbeam
` (8 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
The ipu_cpmem_*() calls now take a channel pointer instead of a
pointer into cpmem for that channel.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/staging/imx-drm/ipuv3-plane.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 6f393a1..6ffe1bb 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -62,7 +62,6 @@ static inline int calc_bandwidth(int width, int height, unsigned int vref)
int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
int x, int y)
{
- struct ipu_ch_param __iomem *cpmem;
struct drm_gem_cma_object *cma_obj;
unsigned long eba;
@@ -75,13 +74,12 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
&cma_obj->paddr, x, y);
- cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
- ipu_cpmem_set_stride(cpmem, fb->pitches[0]);
+ ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
eba = cma_obj->paddr + fb->offsets[0] +
fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
- ipu_cpmem_set_buffer(cpmem, 0, eba);
- ipu_cpmem_set_buffer(cpmem, 1, eba);
+ ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
+ ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
/* cache offsets for subsequent pageflips */
ipu_plane->x = x;
@@ -97,7 +95,6 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
- struct ipu_ch_param __iomem *cpmem;
struct device *dev = ipu_plane->base.dev->dev;
int ret;
@@ -175,10 +172,9 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
return ret;
}
- cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
- ipu_ch_param_zero(cpmem);
- ipu_cpmem_set_resolution(cpmem, src_w, src_h);
- ret = ipu_cpmem_set_fmt(cpmem, fb->pixel_format);
+ ipu_cpmem_zero(ipu_plane->ipu_ch);
+ ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
+ ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
if (ret < 0) {
dev_err(dev, "unsupported pixel format 0x%08x\n",
fb->pixel_format);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 22/28] gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (20 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 21/28] staging: imx-drm: Convert to new ipu_cpmem API Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 23/28] gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id() Steve Longerbeam
` (7 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds ipu_cpmem_set_block_mode().
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-cpmem.c | 6 ++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 7 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 7adfa78..28adf39 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -260,6 +260,12 @@ void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
};
EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
+void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
+{
+ ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
+
int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
const struct ipu_rgb *rgb)
{
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index a86a98a..6146bc7 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -231,6 +231,7 @@ void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
+void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
const struct ipu_rgb *rgb);
int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 23/28] gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (21 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 22/28] gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 24/28] gpu: ipu-cpmem: Add ipu_cpmem_set_rotation() Steve Longerbeam
` (6 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds ipu_cpmem_set_axi_id() to set which AXI bus master the channel
will use to transfer data onto AXI bus.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-cpmem.c | 7 +++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 8 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 28adf39..2d1b376 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -254,6 +254,13 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
};
EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
+void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
+{
+ id &= 0x3;
+ ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
+
void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
{
ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 6146bc7..066b10d 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -230,6 +230,7 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 24/28] gpu: ipu-cpmem: Add ipu_cpmem_set_rotation()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (22 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 23/28] gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 25/28] gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image() Steve Longerbeam
` (5 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds ipu_cpmem_set_rotation().
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-cpmem.c | 10 ++++++++++
include/video/imx-ipu-v3.h | 2 ++
2 files changed, 12 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 2d1b376..f52e4b4 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -64,6 +64,7 @@ struct ipu_cpmem {
#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
+#define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3)
#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
@@ -273,6 +274,15 @@ void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
+void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
+ enum ipu_rotate_mode rot)
+{
+ u32 temp_rot = bitrev8(rot) >> 5;
+
+ ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
+
int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
const struct ipu_rgb *rgb)
{
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 066b10d..3d3cea0 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -233,6 +233,8 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
+void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
+ enum ipu_rotate_mode rot);
int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
const struct ipu_rgb *rgb);
int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 25/28] gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (23 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 24/28] gpu: ipu-cpmem: Add ipu_cpmem_set_rotation() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 26/28] gpu: ipu-v3: Add more planar formats support Steve Longerbeam
` (4 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Add a second buffer physaddr to struct ipu_image, for double-buffering
support.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-cpmem.c | 32 ++++++++++++++++----------------
include/video/imx-ipu-v3.h | 3 ++-
2 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index f52e4b4..cfe2f53 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -538,7 +538,7 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
{
struct v4l2_pix_format *pix = &image->pix;
- int y_offset, u_offset, v_offset;
+ int offset, y_offset, u_offset, v_offset;
pr_debug("%s: resolution: %dx%d stride: %d\n",
__func__, pix->width, pix->height,
@@ -560,30 +560,30 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
pix->bytesperline, u_offset, v_offset);
- ipu_cpmem_set_buffer(ch, 0, image->phys + y_offset);
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
break;
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YUYV:
- ipu_cpmem_set_buffer(ch, 0, image->phys +
- image->rect.left * 2 +
- image->rect.top * image->pix.bytesperline);
+ case V4L2_PIX_FMT_RGB565:
+ offset = image->rect.left * 2 +
+ image->rect.top * pix->bytesperline;
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
break;
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:
- ipu_cpmem_set_buffer(ch, 0, image->phys +
- image->rect.left * 4 +
- image->rect.top * image->pix.bytesperline);
- break;
- case V4L2_PIX_FMT_RGB565:
- ipu_cpmem_set_buffer(ch, 0, image->phys +
- image->rect.left * 2 +
- image->rect.top * image->pix.bytesperline);
+ offset = image->rect.left * 4 +
+ image->rect.top * pix->bytesperline;
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
break;
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- ipu_cpmem_set_buffer(ch, 0, image->phys +
- image->rect.left * 3 +
- image->rect.top * image->pix.bytesperline);
+ offset = image->rect.left * 3 +
+ image->rect.top * pix->bytesperline;
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
break;
default:
return -EINVAL;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 3d3cea0..542652f 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -221,7 +221,8 @@ struct ipu_rgb {
struct ipu_image {
struct v4l2_pix_format pix;
struct v4l2_rect rect;
- dma_addr_t phys;
+ dma_addr_t phys0;
+ dma_addr_t phys1;
};
void ipu_cpmem_zero(struct ipuv3_channel *ch);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 26/28] gpu: ipu-v3: Add more planar formats support
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (24 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 25/28] gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-06-26 1:05 ` [PATCH 27/28] gpu: ipu-cpmem: Add ipu_cpmem_dump() Steve Longerbeam
` (3 subsequent siblings)
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam, Dmitry Eremin-Solenikov, Mohsin Kazmi
Adds support for the following planar and partial-planar formats:
YUV422
NV12
NV21
NV16
NV61
Signed-off-by: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
Signed-off-by: Mohsin Kazmi <mohsin_kazmi@mentor.com>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 21 ++++++
drivers/gpu/ipu-v3/ipu-cpmem.c | 146 +++++++++++++++++++++++++++++++++++++--
2 files changed, 161 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 81930f3..115572e 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -80,6 +80,12 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
case DRM_FORMAT_UYVY:
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_YUV422:
+ case DRM_FORMAT_YVU422:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
return IPUV3_COLORSPACE_YUV;
default:
return IPUV3_COLORSPACE_UNKNOWN;
@@ -92,8 +98,13 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
switch (pixelformat) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
return IPUV3_COLORSPACE_YUV;
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:
@@ -112,6 +123,11 @@ bool ipu_pixelformat_is_planar(u32 pixelformat)
switch (pixelformat) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
return true;
}
@@ -137,6 +153,11 @@ int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
switch (pixelformat) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
/*
* for the planar YUV formats, the stride passed to
* cpmem must be the stride in bytes of the Y plane.
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index cfe2f53..45a014e 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -193,8 +193,18 @@ static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
return DRM_FORMAT_YUYV;
case V4L2_PIX_FMT_YUV420:
return DRM_FORMAT_YUV420;
+ case V4L2_PIX_FMT_YUV422P:
+ return DRM_FORMAT_YUV422;
case V4L2_PIX_FMT_YVU420:
return DRM_FORMAT_YVU420;
+ case V4L2_PIX_FMT_NV12:
+ return DRM_FORMAT_NV12;
+ case V4L2_PIX_FMT_NV21:
+ return DRM_FORMAT_NV21;
+ case V4L2_PIX_FMT_NV16:
+ return DRM_FORMAT_NV16;
+ case V4L2_PIX_FMT_NV61:
+ return DRM_FORMAT_NV61;
}
return -EINVAL;
@@ -394,6 +404,7 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
{
switch (pixel_format) {
case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV422P:
ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
@@ -403,6 +414,18 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
+ ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
+ break;
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV61:
+ ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1);
+ ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
+ ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
+ break;
}
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
@@ -422,6 +445,25 @@ void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
u_offset, v_offset);
break;
+ case V4L2_PIX_FMT_YUV422P:
+ uv_stride = stride / 2;
+ u_offset = stride * height;
+ v_offset = u_offset + (uv_stride * height);
+ ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+ u_offset, v_offset);
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ u_offset = stride * height;
+ ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+ u_offset, 0);
+ break;
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV61:
+ v_offset = stride * height;
+ ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+ 0, v_offset);
+ break;
}
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
@@ -475,11 +517,20 @@ static const struct ipu_rgb def_bgr_16 = {
};
#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
-#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
- (pix->width * (y) / 4) + (x) / 2)
-#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
- (pix->width * pix->height / 4) + \
- (pix->width * (y) / 4) + (x) / 2)
+#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * (y) / 4) + (x) / 2)
+#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * pix->height / 4) + \
+ (pix->width * (y) / 4) + (x) / 2)
+#define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * (y) / 2) + (x) / 2)
+#define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * pix->height / 2) + \
+ (pix->width * (y) / 2) + (x) / 2)
+#define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * (y) / 2) + (x))
+#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
+ (pix->width * y) + (x))
int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
{
@@ -491,6 +542,27 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
/* burst size */
ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
break;
+ case DRM_FORMAT_YUV422:
+ case DRM_FORMAT_YVU422:
+ /* pix format */
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
+ /* burst size */
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+ break;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ /* pix format */
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
+ /* burst size */
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+ break;
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ /* pix format */
+ ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
+ /* burst size */
+ ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+ break;
case DRM_FORMAT_UYVY:
/* bits/pixel */
ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
@@ -559,7 +631,69 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
image->rect.top) - y_offset;
ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
- pix->bytesperline, u_offset, v_offset);
+ pix->bytesperline,
+ u_offset, v_offset);
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+ u_offset = U2_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+ v_offset = V2_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+
+ ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+ pix->bytesperline,
+ u_offset, v_offset);
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+ break;
+ case V4L2_PIX_FMT_NV12:
+ y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+ u_offset = UV_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+ v_offset = 0;
+
+ ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+ pix->bytesperline,
+ u_offset, v_offset);
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+ break;
+ case V4L2_PIX_FMT_NV21:
+ y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+ u_offset = 0;
+ v_offset = UV_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+
+ ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+ pix->bytesperline,
+ u_offset, v_offset);
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+ break;
+ case V4L2_PIX_FMT_NV16:
+ y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+ u_offset = UV2_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+ v_offset = 0;
+
+ ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+ pix->bytesperline,
+ u_offset, v_offset);
+ ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+ ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+ break;
+ case V4L2_PIX_FMT_NV61:
+ y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+ u_offset = 0;
+ v_offset = UV2_OFFSET(pix, image->rect.left,
+ image->rect.top) - y_offset;
+
+ ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+ pix->bytesperline,
+ u_offset, v_offset);
ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
break;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 27/28] gpu: ipu-cpmem: Add ipu_cpmem_dump()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (25 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 26/28] gpu: ipu-v3: Add more planar formats support Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-07-31 18:06 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 28/28] gpu: ipu-v3: Add ipu_dump() Steve Longerbeam
` (2 subsequent siblings)
29 siblings, 1 reply; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds ipu_cpmem_dump() which dumps a channel's cpmem to debug.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-cpmem.c | 63 ++++++++++++++++++++++++++++++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 64 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 45a014e..5cb36d3 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -727,6 +727,69 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
+void ipu_cpmem_dump(struct ipuv3_channel *ch)
+{
+ struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+ struct ipu_soc *ipu = ch->ipu;
+ int chno = ch->num;
+
+ dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
+ readl(&p->word[0].data[0]),
+ readl(&p->word[0].data[1]),
+ readl(&p->word[0].data[2]),
+ readl(&p->word[0].data[3]),
+ readl(&p->word[0].data[4]));
+ dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
+ readl(&p->word[1].data[0]),
+ readl(&p->word[1].data[1]),
+ readl(&p->word[1].data[2]),
+ readl(&p->word[1].data[3]),
+ readl(&p->word[1].data[4]));
+ dev_dbg(ipu->dev, "PFS 0x%x, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
+ dev_dbg(ipu->dev, "BPP 0x%x, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
+ dev_dbg(ipu->dev, "NPB 0x%x\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
+
+ dev_dbg(ipu->dev, "FW %d, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_FW));
+ dev_dbg(ipu->dev, "FH %d, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_FH));
+ dev_dbg(ipu->dev, "EBA0 0x%x\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
+ dev_dbg(ipu->dev, "EBA1 0x%x\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
+ dev_dbg(ipu->dev, "Stride %d\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_SL));
+ dev_dbg(ipu->dev, "scan_order %d\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_SO));
+ dev_dbg(ipu->dev, "uv_stride %d\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
+ dev_dbg(ipu->dev, "u_offset 0x%x\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
+ dev_dbg(ipu->dev, "v_offset 0x%x\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
+
+ dev_dbg(ipu->dev, "Width0 %d+1, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
+ dev_dbg(ipu->dev, "Width1 %d+1, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
+ dev_dbg(ipu->dev, "Width2 %d+1, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
+ dev_dbg(ipu->dev, "Width3 %d+1, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
+ dev_dbg(ipu->dev, "Offset0 %d, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
+ dev_dbg(ipu->dev, "Offset1 %d, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
+ dev_dbg(ipu->dev, "Offset2 %d, ",
+ ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
+ dev_dbg(ipu->dev, "Offset3 %d\n",
+ ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
+
int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
{
struct ipu_cpmem *cpmem;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 542652f..62f9c4b 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -247,6 +247,7 @@ void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
u32 pixel_format, int stride, int height);
int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc);
int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image);
+void ipu_cpmem_dump(struct ipuv3_channel *ch);
/* Channel linking functions */
int ipu_link_prp_enc_rot_enc(struct ipu_soc *ipu);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH 28/28] gpu: ipu-v3: Add ipu_dump()
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (26 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 27/28] gpu: ipu-cpmem: Add ipu_cpmem_dump() Steve Longerbeam
@ 2014-06-26 1:05 ` Steve Longerbeam
2014-07-17 11:10 ` [PATCH 00/28] IPUv3 prep for video capture Hans Verkuil
2014-07-31 15:28 ` Philipp Zabel
29 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-06-26 1:05 UTC (permalink / raw)
To: linux-media; +Cc: Steve Longerbeam
Adds ipu_dump() which dumps IPU register state to debug.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
drivers/gpu/ipu-v3/ipu-common.c | 38 ++++++++++++++++++++++++++++++++++++++
include/video/imx-ipu-v3.h | 1 +
2 files changed, 39 insertions(+)
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 115572e..af00e8c 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -1310,6 +1310,44 @@ static void ipu_irq_exit(struct ipu_soc *ipu)
irq_domain_remove(ipu->domain);
}
+void ipu_dump(struct ipu_soc *ipu)
+{
+ int i;
+
+ dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_CONF));
+ dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CONF));
+ dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
+ dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
+ dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
+ dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
+ dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
+ dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
+ dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
+ dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
+ dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
+ dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
+ dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
+ dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+ for (i = 0; i < 15; i++)
+ dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
+ ipu_cm_read(ipu, IPU_INT_CTRL(i)));
+}
+EXPORT_SYMBOL_GPL(ipu_dump);
+
static int ipu_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 62f9c4b..1ed1062 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -187,6 +187,7 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
int ipu_get_num(struct ipu_soc *ipu);
void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
+void ipu_dump(struct ipu_soc *ipu);
/*
* IPU Image DMA Controller (idmac) functions
--
1.7.9.5
^ permalink raw reply related [flat|nested] 42+ messages in thread
* Re: [PATCH 00/28] IPUv3 prep for video capture
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (27 preceding siblings ...)
2014-06-26 1:05 ` [PATCH 28/28] gpu: ipu-v3: Add ipu_dump() Steve Longerbeam
@ 2014-07-17 11:10 ` Hans Verkuil
2014-07-17 20:44 ` Steve Longerbeam
2014-07-31 15:28 ` Philipp Zabel
29 siblings, 1 reply; 42+ messages in thread
From: Hans Verkuil @ 2014-07-17 11:10 UTC (permalink / raw)
To: Steve Longerbeam, linux-media; +Cc: Steve Longerbeam
Hi Steve,
I don't know what your plan is, but when you want to mainline this it is
the gpu subsystem that needs to review it. I noticed it wasn't cross-posted
to the dri-devel mailinglist.
I am a bit worried about the amount of v4l2-specific stuff that is going
into drivers/gpu/ipu-v3. Do things like csc and csi really belong there
instead of under drivers/media?
Let me know if this was just preliminary code, or if this was intended to
be the final code. I suspect the former.
Regards,
Hans
On 06/26/2014 03:05 AM, Steve Longerbeam wrote:
> Hi Philip, Sascha,
>
> Here is a rebased set of IPU patches that prepares for video capture
> support. Video capture is not included in this set. I've addressed
> all your IPU-specific concerns from the previous patch set, the
> major ones being:
>
> - the IOMUXC control for CSI input selection has been removed. This
> should be part of a future CSI media entity driver.
>
> - the ipu-irt unit has been removed. Enabling the IRT module is
> folded into ipu-ic unit. The ipu-ic unit is also cleaned up a bit.
>
> - the ipu-csi APIs are consolidated/simplified.
>
> - added CSI and IC base offsets for i.MX51/i.MX53.
>
>
> Steve Longerbeam (28):
> ARM: dts: imx6qdl: Add ipu aliases
> gpu: ipu-v3: Add ipu_get_num()
> gpu: ipu-v3: Add functions to set CSI/IC source muxes
> gpu: ipu-v3: Rename and add IDMAC channels
> gpu: ipu-v3: Add units required for video capture
> gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c
> gpu: ipu-v3: smfc: Convert to per-channel
> gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark()
> gpu: ipu-v3: Add ipu_mbus_code_to_colorspace()
> gpu: ipu-v3: Add rotation mode conversion utilities
> gpu: ipu-v3: Add helper function checking if pixfmt is planar
> gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
> gpu: ipu-v3: Add ipu_idmac_buffer_is_ready()
> gpu: ipu-v3: Add ipu_idmac_clear_buffer()
> gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer()
> gpu: ipu-v3: Add ipu_stride_to_bytes()
> gpu: ipu-v3: Add ipu_idmac_enable_watermark()
> gpu: ipu-v3: Add ipu_idmac_lock_enable()
> gpu: ipu-v3: Add idmac channel linking support
> gpu: ipu-v3: Add ipu-cpmem unit
> staging: imx-drm: Convert to new ipu_cpmem API
> gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode()
> gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id()
> gpu: ipu-cpmem: Add ipu_cpmem_set_rotation()
> gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
> gpu: ipu-v3: Add more planar formats support
> gpu: ipu-cpmem: Add ipu_cpmem_dump()
> gpu: ipu-v3: Add ipu_dump()
>
> arch/arm/boot/dts/imx6q.dtsi | 1 +
> arch/arm/boot/dts/imx6qdl.dtsi | 1 +
> drivers/gpu/ipu-v3/Makefile | 3 +-
> drivers/gpu/ipu-v3/ipu-common.c | 1077 +++++++++++++++++++--------------
> drivers/gpu/ipu-v3/ipu-cpmem.c | 817 +++++++++++++++++++++++++
> drivers/gpu/ipu-v3/ipu-csi.c | 701 +++++++++++++++++++++
> drivers/gpu/ipu-v3/ipu-ic.c | 812 +++++++++++++++++++++++++
> drivers/gpu/ipu-v3/ipu-prv.h | 103 +++-
> drivers/gpu/ipu-v3/ipu-smfc.c | 156 ++++-
> drivers/staging/imx-drm/ipuv3-plane.c | 16 +-
> include/video/imx-ipu-v3.h | 371 +++++++-----
> 11 files changed, 3389 insertions(+), 669 deletions(-)
> create mode 100644 drivers/gpu/ipu-v3/ipu-cpmem.c
> create mode 100644 drivers/gpu/ipu-v3/ipu-csi.c
> create mode 100644 drivers/gpu/ipu-v3/ipu-ic.c
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 00/28] IPUv3 prep for video capture
2014-07-17 11:10 ` [PATCH 00/28] IPUv3 prep for video capture Hans Verkuil
@ 2014-07-17 20:44 ` Steve Longerbeam
2014-07-23 13:17 ` Laurent Pinchart
0 siblings, 1 reply; 42+ messages in thread
From: Steve Longerbeam @ 2014-07-17 20:44 UTC (permalink / raw)
To: Hans Verkuil, Steve Longerbeam, linux-media
On 07/17/2014 04:10 AM, Hans Verkuil wrote:
> Hi Steve,
>
> I don't know what your plan is, but when you want to mainline this it is
> the gpu subsystem that needs to review it. I noticed it wasn't cross-posted
> to the dri-devel mailinglist.
Hi Hans,
I'm reworking these patches, I've merged in some of the changes
posted by Philip Zabel ("[RFC PATCH 00/26] i.MX5/6 IPUv3 CSI/IC"),
specifically I've decided to use their version of ipu-ic.c, and
also brought in their video-mux subdev driver. So I'm fine with
cancelling this patch set.
When/if I post the reworked v4l2 drivers that implement the media
entity/device framework I will post the ipu-v3 specific changes
to dri-devel as well.
The reason I like Philip's version of ipu-ic is that it implements
tiling to allow resizing output frames larger than 1024x1024. We
(Mentor Graphics) did the same IC tiling, but it was done inside
a separate mem2mem driver. By moving the tiling into ipu-ic, it
allows >1024x1024 resizing to be part of an imx-ipuv3-ic media
entity, and this entity can be part of multiple video pipelines
(capture, video output, mem2mem).
>
> I am a bit worried about the amount of v4l2-specific stuff that is going
> into drivers/gpu/ipu-v3. Do things like csc and csi really belong there
> instead of under drivers/media?
The current philosophy of the ipu-v3 driver seems to be that it is a
library of IPU register-level primitives, so ipu-csi and ipu-ic follow
that model. There will be nothing v4l2-specific in ipu-csi and ipu-ic,
although the v4l2 subdev's will be the only clients of ipu-csi and
ipu-ic.
>
> Let me know if this was just preliminary code, or if this was intended to
> be the final code. I suspect the former.
This is all been reworked so go ahead and cancel it.
Thanks,
Steve
>
>
>
> On 06/26/2014 03:05 AM, Steve Longerbeam wrote:
>> Hi Philip, Sascha,
>>
>> Here is a rebased set of IPU patches that prepares for video capture
>> support. Video capture is not included in this set. I've addressed
>> all your IPU-specific concerns from the previous patch set, the
>> major ones being:
>>
>> - the IOMUXC control for CSI input selection has been removed. This
>> should be part of a future CSI media entity driver.
>>
>> - the ipu-irt unit has been removed. Enabling the IRT module is
>> folded into ipu-ic unit. The ipu-ic unit is also cleaned up a bit.
>>
>> - the ipu-csi APIs are consolidated/simplified.
>>
>> - added CSI and IC base offsets for i.MX51/i.MX53.
>>
>>
>> Steve Longerbeam (28):
>> ARM: dts: imx6qdl: Add ipu aliases
>> gpu: ipu-v3: Add ipu_get_num()
>> gpu: ipu-v3: Add functions to set CSI/IC source muxes
>> gpu: ipu-v3: Rename and add IDMAC channels
>> gpu: ipu-v3: Add units required for video capture
>> gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c
>> gpu: ipu-v3: smfc: Convert to per-channel
>> gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark()
>> gpu: ipu-v3: Add ipu_mbus_code_to_colorspace()
>> gpu: ipu-v3: Add rotation mode conversion utilities
>> gpu: ipu-v3: Add helper function checking if pixfmt is planar
>> gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
>> gpu: ipu-v3: Add ipu_idmac_buffer_is_ready()
>> gpu: ipu-v3: Add ipu_idmac_clear_buffer()
>> gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer()
>> gpu: ipu-v3: Add ipu_stride_to_bytes()
>> gpu: ipu-v3: Add ipu_idmac_enable_watermark()
>> gpu: ipu-v3: Add ipu_idmac_lock_enable()
>> gpu: ipu-v3: Add idmac channel linking support
>> gpu: ipu-v3: Add ipu-cpmem unit
>> staging: imx-drm: Convert to new ipu_cpmem API
>> gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode()
>> gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id()
>> gpu: ipu-cpmem: Add ipu_cpmem_set_rotation()
>> gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
>> gpu: ipu-v3: Add more planar formats support
>> gpu: ipu-cpmem: Add ipu_cpmem_dump()
>> gpu: ipu-v3: Add ipu_dump()
>>
>> arch/arm/boot/dts/imx6q.dtsi | 1 +
>> arch/arm/boot/dts/imx6qdl.dtsi | 1 +
>> drivers/gpu/ipu-v3/Makefile | 3 +-
>> drivers/gpu/ipu-v3/ipu-common.c | 1077 +++++++++++++++++++--------------
>> drivers/gpu/ipu-v3/ipu-cpmem.c | 817 +++++++++++++++++++++++++
>> drivers/gpu/ipu-v3/ipu-csi.c | 701 +++++++++++++++++++++
>> drivers/gpu/ipu-v3/ipu-ic.c | 812 +++++++++++++++++++++++++
>> drivers/gpu/ipu-v3/ipu-prv.h | 103 +++-
>> drivers/gpu/ipu-v3/ipu-smfc.c | 156 ++++-
>> drivers/staging/imx-drm/ipuv3-plane.c | 16 +-
>> include/video/imx-ipu-v3.h | 371 +++++++-----
>> 11 files changed, 3389 insertions(+), 669 deletions(-)
>> create mode 100644 drivers/gpu/ipu-v3/ipu-cpmem.c
>> create mode 100644 drivers/gpu/ipu-v3/ipu-csi.c
>> create mode 100644 drivers/gpu/ipu-v3/ipu-ic.c
>>
>
--
Steve Longerbeam | Senior Embedded Engineer, ESD Services
Mentor Embedded(tm) | 46871 Bayside Parkway, Fremont, CA 94538
P 510.354.5838 | M 408.410.2735
Nucleus(r) | Linux(r) | Android(tm) | Services | UI | Multi-OS
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 00/28] IPUv3 prep for video capture
2014-07-17 20:44 ` Steve Longerbeam
@ 2014-07-23 13:17 ` Laurent Pinchart
2014-07-25 21:21 ` Steve Longerbeam
0 siblings, 1 reply; 42+ messages in thread
From: Laurent Pinchart @ 2014-07-23 13:17 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: Hans Verkuil, Steve Longerbeam, linux-media
Hi Steve,
On Thursday 17 July 2014 13:44:12 Steve Longerbeam wrote:
> On 07/17/2014 04:10 AM, Hans Verkuil wrote:
> > Hi Steve,
> >
> > I don't know what your plan is, but when you want to mainline this it is
> > the gpu subsystem that needs to review it. I noticed it wasn't
> > cross-posted
> > to the dri-devel mailinglist.
>
> Hi Hans,
>
> I'm reworking these patches, I've merged in some of the changes
> posted by Philip Zabel ("[RFC PATCH 00/26] i.MX5/6 IPUv3 CSI/IC"),
> specifically I've decided to use their version of ipu-ic.c, and
> also brought in their video-mux subdev driver. So I'm fine with
> cancelling this patch set.
>
> When/if I post the reworked v4l2 drivers that implement the media
> entity/device framework I will post the ipu-v3 specific changes
> to dri-devel as well.
>
> The reason I like Philip's version of ipu-ic is that it implements
> tiling to allow resizing output frames larger than 1024x1024. We
> (Mentor Graphics) did the same IC tiling, but it was done inside
> a separate mem2mem driver. By moving the tiling into ipu-ic, it
> allows >1024x1024 resizing to be part of an imx-ipuv3-ic media
> entity, and this entity can be part of multiple video pipelines
> (capture, video output, mem2mem).
>
> > I am a bit worried about the amount of v4l2-specific stuff that is going
> > into drivers/gpu/ipu-v3. Do things like csc and csi really belong there
> > instead of under drivers/media?
>
> The current philosophy of the ipu-v3 driver seems to be that it is a
> library of IPU register-level primitives, so ipu-csi and ipu-ic follow
> that model. There will be nothing v4l2-specific in ipu-csi and ipu-ic,
> although the v4l2 subdev's will be the only clients of ipu-csi and
> ipu-ic.
I have a bit of trouble following up, due to my lack of knowledge of the
Freescale platforms. It would help if you could explain briefly how the
various IPU modules interact with each other at the hardware and software
level, and what the acronyms stand for (I assume IPU means Image Processing
Unit, CSI means Camera Serial Interface, but I don't know what IC is in this
context).
Are the CSI receivers linked to the graphics IP cores at the hardware level ?
> > Let me know if this was just preliminary code, or if this was intended to
> > be the final code. I suspect the former.
>
> This is all been reworked so go ahead and cancel it.
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 00/28] IPUv3 prep for video capture
2014-07-23 13:17 ` Laurent Pinchart
@ 2014-07-25 21:21 ` Steve Longerbeam
0 siblings, 0 replies; 42+ messages in thread
From: Steve Longerbeam @ 2014-07-25 21:21 UTC (permalink / raw)
To: Laurent Pinchart; +Cc: Hans Verkuil, Steve Longerbeam, linux-media
On 07/23/2014 06:17 AM, Laurent Pinchart wrote:
> Hi Steve,
>
> On Thursday 17 July 2014 13:44:12 Steve Longerbeam wrote:
>> On 07/17/2014 04:10 AM, Hans Verkuil wrote:
>>> Hi Steve,
>>>
>>> I don't know what your plan is, but when you want to mainline this it is
>>> the gpu subsystem that needs to review it. I noticed it wasn't
>>> cross-posted
>>> to the dri-devel mailinglist.
>> Hi Hans,
>>
>> I'm reworking these patches, I've merged in some of the changes
>> posted by Philip Zabel ("[RFC PATCH 00/26] i.MX5/6 IPUv3 CSI/IC"),
>> specifically I've decided to use their version of ipu-ic.c, and
>> also brought in their video-mux subdev driver. So I'm fine with
>> cancelling this patch set.
>>
>> When/if I post the reworked v4l2 drivers that implement the media
>> entity/device framework I will post the ipu-v3 specific changes
>> to dri-devel as well.
>>
>> The reason I like Philip's version of ipu-ic is that it implements
>> tiling to allow resizing output frames larger than 1024x1024. We
>> (Mentor Graphics) did the same IC tiling, but it was done inside
>> a separate mem2mem driver. By moving the tiling into ipu-ic, it
>> allows >1024x1024 resizing to be part of an imx-ipuv3-ic media
>> entity, and this entity can be part of multiple video pipelines
>> (capture, video output, mem2mem).
>>
>>> I am a bit worried about the amount of v4l2-specific stuff that is going
>>> into drivers/gpu/ipu-v3. Do things like csc and csi really belong there
>>> instead of under drivers/media?
>> The current philosophy of the ipu-v3 driver seems to be that it is a
>> library of IPU register-level primitives, so ipu-csi and ipu-ic follow
>> that model. There will be nothing v4l2-specific in ipu-csi and ipu-ic,
>> although the v4l2 subdev's will be the only clients of ipu-csi and
>> ipu-ic.
Hi Laurent,
> I have a bit of trouble following up, due to my lack of knowledge of the
> Freescale platforms. It would help if you could explain briefly how the
> various IPU modules interact with each other at the hardware and software
> level, and what the acronyms stand for (I assume IPU means Image Processing
> Unit, CSI means Camera Serial Interface, but I don't know what IC is in this
> context).
Yes, IPU and CSI are acronyms as you describe. IC stands for Image
Converter. The IC carries out scaling, color-space conversion, and
rotation. The IC has three independent task sub-blocks that can carry
out those three operations concurrently using some kind of task time-
sharing mechanism. The three IC tasks are referred to as "pre-processing
for encode" (PRP ENC), "pre-processing for viewfinder" (PRP VF) and
"post-processing" (PP). So for example, a video capture pipeline could
be actively streaming the PRP ENC task while a mem2mem pipeline
could concurrently be using the PP task.
>
> Are the CSI receivers linked to the graphics IP cores at the hardware level ?]
Yes, the raw frames from the CSI can be directed to either memory, the
IC, or to a video deinterlacing controller (VDIC).
The IPU contains a custom DMA controller (the IDMAC). There is a set
of ~64 IDMAC channels that are dedicated to specific video pipelines.
IDMAC channels can be linked together in hardware (a frame-completion
signal from a source channel can trigger start of DMA in a sink channel).
Here is one example hardware video pipeline in i.MX6 (there are many
more). This example is to send raw interlaced frames from the CSI to
the VDIC, and then the progressive frames to IC PRP VF task for additional
scaling/CSC/rotation:
CSI0 --> VDIC --> IC PRP VF --- idmac channel 21 ---> memory
If you're interested in knowing more about the i.MX6 you can pick
up Freescale's TRM at:
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=i.MX6Q&fpsp=1&tab=Documentation_Tab
The i.MX6 TRM is of poor quality, not good enough for actual register-level
programming in many areas, especially the IPU chapter. But good enough for
getting a general overview.
Steve
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 05/28] gpu: ipu-v3: Add units required for video capture
2014-06-26 1:05 ` [PATCH 05/28] gpu: ipu-v3: Add units required for video capture Steve Longerbeam
@ 2014-07-31 15:27 ` Philipp Zabel
2014-07-31 15:31 ` Philipp Zabel
2014-07-31 17:41 ` Philipp Zabel
0 siblings, 2 replies; 42+ messages in thread
From: Philipp Zabel @ 2014-07-31 15:27 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam
Am Mittwoch, den 25.06.2014, 18:05 -0700 schrieb Steve Longerbeam:
> Adds the following new IPU units:
>
> - Camera Sensor Interface (csi)
> - Image Converter (ic)
This patch should be split in two parts, IC and CSI.
[...]
> +/*
> + * Enable error detection and correction for CCIR interlaced mode.
> + */
> +static inline void ipu_csi_ccir_err_detection_enable(struct ipu_csi *csi)
> +{
> + u32 temp;
> +
> + temp = ipu_csi_read(csi, CSI_CCIR_CODE_1);
> + temp |= CSI_CCIR_ERR_DET_EN;
> + ipu_csi_write(csi, temp, CSI_CCIR_CODE_1);
> +
> +}
> +
> +/*
> + * Disable error detection and correction for CCIR interlaced mode.
> + */
> +static inline void ipu_csi_ccir_err_detection_disable(struct ipu_csi *csi)
> +{
> + u32 temp;
> +
> + temp = ipu_csi_read(csi, CSI_CCIR_CODE_1);
> + temp &= ~CSI_CCIR_ERR_DET_EN;
> + ipu_csi_write(csi, temp, CSI_CCIR_CODE_1);
> +
> +}
This is too complicated for my taste, can't we just set the flag when
CCIR_CODE_1 is written below and remove these two functions?
[...]
> +int ipu_csi_init_interface(struct ipu_csi *csi, u16 width, u16 height,
> + struct ipu_csi_signal_cfg *cfg)
> +{
> + unsigned long flags;
> + u32 data = 0;
> + u32 ipu_clk;
ipu_clk is unused.
> +
> + /* Set the CSI_SENS_CONF register remaining fields */
> + data |= cfg->data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
> + cfg->data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
Instead of having the user call ipu_csi_mbus_fmt_to_sig_cfg to fill
these fields, can't we just pass the mbus_code parameter directly and
calculate data_width and data_fmt inside ipu_csi_init_interface?
> + cfg->data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
> + cfg->vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
> + cfg->hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
> + cfg->pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
Same for those, here I'd prefer we use v4l2_mbus_config.
> + cfg->ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
> + cfg->clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
> + cfg->pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
> + cfg->force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
> + cfg->data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
> +
> + ipu_clk = clk_get_rate(csi->clk_ipu);
ipu_clk is unused.
> + spin_lock_irqsave(&csi->lock, flags);
> +
> + ipu_csi_write(csi, data, CSI_SENS_CONF);
> +
> + /* Setup sensor frame size */
> + ipu_csi_write(csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);
> +
> + /* Set CCIR registers */
> +
> + switch (cfg->clk_mode) {
> + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
> + ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
> + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
> + break;
> + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
> + if (width == 720 && height == 625) {
Shouldn't we also accept 576 lines here? I'd like to capture just the
visible frame.
> + /*
> + * PAL case
> + *
> + * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
> + * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
> + * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
> + * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
> + */
> + ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_1);
As mentioned above, you could just set CCIR_ERR_DET_EN here:
ccir1 = 0x40596 | CSI_CCIR_ERR_DET_EN;
ipu_csi_write(csi, ccir1, CSI_CCIR_CODE_1);
And using something like
#define CSI_CCIR_STRT_BLNK_1ST(x) (((x) & 0x7) << 0)
#define CSI_CCIR_END_BLNK_1ST(x) (((x) & 0x7) << 3)
#define CSI_CCIR_STRT_BLNK_2ND(x) (((x) & 0x7) << 6)
#define CSI_CCIR_END_BLNK_2ND(x) (((x) & 0x7) << 9)
#define CSI_CCIR_STRT_ACTV(x) (((x) & 0x7) << 16)
#define CSI_CCIR_END_ACTV(x) (((x) & 0x7) << 19)
instead of the hex-value + comment combination would better document
where which bit fields actually are.
> + ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
> + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
The TRM says CSI_CCIR_PRECOM is bits [29:0], and [31:30] are reserved /
read-only / always zero. Also, for BT.656 bits [29:24] are ignored. Did
you investigate whether this value is correct?
> +
> + } else if (width == 720 && height == 525) {
As above, shouldn't we also accept 480 lines here?
> + /*
> + * NTSC case
> + *
> + * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
> + * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
> + * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
> + * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
> + */
> + ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_1);
> + ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
> + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
Same as for PAL.
> + } else {
> + dev_err(csi->ipu->dev,
> + "Unsupported CCIR656 interlaced video mode\n");
> + spin_unlock_irqrestore(&csi->lock, flags);
> + return -EINVAL;
> + }
> +
> + ipu_csi_ccir_err_detection_enable(csi);
> + break;
> + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
> + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
> + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
> + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
> + ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
> + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
Same issues as above, only here bits [29:0] are used (3x10bits)
according to the TRM.
> + ipu_csi_ccir_err_detection_enable(csi);
> + break;
> + case IPU_CSI_CLK_MODE_GATED_CLK:
> + case IPU_CSI_CLK_MODE_NONGATED_CLK:
> + ipu_csi_ccir_err_detection_disable(csi);
> + break;
> + }
> +
> + dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
> + ipu_csi_read(csi, CSI_SENS_CONF));
> + dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
> + ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
> +
> + spin_unlock_irqrestore(&csi->lock, flags);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
[...]
> +bool ipu_csi_is_interlaced(struct ipu_csi *csi)
Why do we have to read back the sensor configuration? The user who
called ipu_csi_init_interface should already have this information.
[...]
> +
> +{
> + unsigned long flags;
> + u32 reg;
> +
> + spin_lock_irqsave(&csi->lock, flags);
> +
> + reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
> + w->width = (reg & 0xFFFF) + 1;
> + w->height = (reg >> 16 & 0xFFFF) + 1;
> +
> + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
> + w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
> + w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
> +
> + spin_unlock_irqrestore(&csi->lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_get_window);
> +
> +void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
> +{
> + unsigned long flags;
> + u32 reg;
> +
> + spin_lock_irqsave(&csi->lock, flags);
> +
> + ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
> + CSI_ACT_FRM_SIZE);
> +
> + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
> + reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
> + reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
> + ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
> +
> + spin_unlock_irqrestore(&csi->lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_set_window);
> +
> +void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
> + u32 r_value, u32 g_value, u32 b_value,
> + u32 pix_clk)
> +{
> + unsigned long flags;
> + u32 ipu_clk = clk_get_rate(csi->clk_ipu);
> + u32 temp;
> +
> + spin_lock_irqsave(&csi->lock, flags);
> +
> + temp = ipu_csi_read(csi, CSI_TST_CTRL);
> +
> + if (active == false) {
> + temp &= ~CSI_TEST_GEN_MODE_EN;
> + ipu_csi_write(csi, temp, CSI_TST_CTRL);
> + } else {
> + /* Set sensb_mclk div_ratio*/
> + ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
> +
> + temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
> + CSI_TEST_GEN_B_MASK);
> + temp |= CSI_TEST_GEN_MODE_EN;
> + temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
> + (g_value << CSI_TEST_GEN_G_SHIFT) |
> + (b_value << CSI_TEST_GEN_B_SHIFT);
> + ipu_csi_write(csi, temp, CSI_TST_CTRL);
> + }
> +
> + spin_unlock_irqrestore(&csi->lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
> +
> +int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
> + struct ipu_csi_signal_cfg *cfg)
> +{
> + unsigned long flags;
> + u32 temp;
> +
> + if (vc > 3)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&csi->lock, flags);
> +
> + temp = ipu_csi_read(csi, CSI_MIPI_DI);
> + temp &= ~(0xff << (vc * 8));
> + temp |= (cfg->mipi_dt << (vc * 8));
> + ipu_csi_write(csi, temp, CSI_MIPI_DI);
> +
> + spin_unlock_irqrestore(&csi->lock, flags);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
> +
> +int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
> + u32 max_ratio, u32 id)
> +{
> + unsigned long flags;
> + u32 temp;
> +
> + if (max_ratio > 5 || id > 3)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&csi->lock, flags);
> +
> + temp = ipu_csi_read(csi, CSI_SKIP);
> + temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
> + CSI_SKIP_SMFC_MASK);
> + temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
> + (id << CSI_ID_2_SKIP_SHIFT) |
> + (skip << CSI_SKIP_SMFC_SHIFT);
> + ipu_csi_write(csi, temp, CSI_SKIP);
> +
> + spin_unlock_irqrestore(&csi->lock, flags);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
> +
> +int ipu_csi_set_dest(struct ipu_csi *csi, bool ic)
> +{
> + unsigned long flags;
> + u32 csi_sens_conf, csi_dest;
> +
> + csi_dest = ic ? CSI_DATA_DEST_IC : CSI_DATA_DEST_IDMAC;
> +
> + spin_lock_irqsave(&csi->lock, flags);
> +
> + csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
> + csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
> + csi_sens_conf |= (csi_dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
> + ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
> +
> + spin_unlock_irqrestore(&csi->lock, flags);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
> +
> +int ipu_csi_enable(struct ipu_csi *csi)
> +{
> + ipu_module_enable(csi->ipu, csi->module);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_enable);
> +
> +int ipu_csi_disable(struct ipu_csi *csi)
> +{
> + ipu_module_disable(csi->ipu, csi->module);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_disable);
> +
> +struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
> +{
> + unsigned long flags;
> + struct ipu_csi *csi, *ret;
> +
> + if (id > 1)
> + return ERR_PTR(-EINVAL);
> +
> + csi = ipu->csi_priv[id];
> + ret = csi;
> +
> + spin_lock_irqsave(&csi->lock, flags);
> +
> + if (csi->inuse) {
> + ret = ERR_PTR(-EBUSY);
> + goto unlock;
> + }
> +
> + csi->inuse = true;
> +unlock:
> + spin_unlock_irqrestore(&csi->lock, flags);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_get);
> +
> +void ipu_csi_put(struct ipu_csi *csi)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&csi->lock, flags);
> + csi->inuse = false;
> + spin_unlock_irqrestore(&csi->lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_put);
> +
> +int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
> + unsigned long base, u32 module, struct clk *clk_ipu)
> +{
> + struct ipu_csi *csi;
> +
> + if (id > 1)
> + return -ENODEV;
> +
> + csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
> + if (!csi)
> + return -ENOMEM;
> +
> + ipu->csi_priv[id] = csi;
> +
> + spin_lock_init(&csi->lock);
> + csi->module = module;
> + csi->id = id;
> + csi->clk_ipu = clk_ipu;
> + csi->base = devm_ioremap(dev, base, PAGE_SIZE);
> + if (!csi->base)
> + return -ENOMEM;
> +
> + dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
> + id, base, csi->base);
> + csi->ipu = ipu;
> +
> + return 0;
> +}
> +
> +void ipu_csi_exit(struct ipu_soc *ipu, int id)
> +{
> +}
> +
> +void ipu_csi_dump(struct ipu_csi *csi)
> +{
> + dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n",
> + ipu_csi_read(csi, CSI_SENS_CONF));
> + dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
> + ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
> + dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n",
> + ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
> + dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n",
> + ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
> + dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n",
> + ipu_csi_read(csi, CSI_TST_CTRL));
> + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n",
> + ipu_csi_read(csi, CSI_CCIR_CODE_1));
> + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n",
> + ipu_csi_read(csi, CSI_CCIR_CODE_2));
> + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n",
> + ipu_csi_read(csi, CSI_CCIR_CODE_3));
> + dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n",
> + ipu_csi_read(csi, CSI_MIPI_DI));
> + dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n",
> + ipu_csi_read(csi, CSI_SKIP));
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_dump);
> diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
> new file mode 100644
> index 0000000..2d305a2
> --- /dev/null
> +++ b/drivers/gpu/ipu-v3/ipu-ic.c
> @@ -0,0 +1,812 @@
> +/*
> + * Copyright (C) 2012-2014 Mentor Graphics Inc.
> + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/types.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/spinlock.h>
> +#include <linux/bitrev.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include "ipu-prv.h"
> +
> +/* IC Register Offsets */
> +#define IC_CONF 0x0000
> +#define IC_PRP_ENC_RSC 0x0004
> +#define IC_PRP_VF_RSC 0x0008
> +#define IC_PP_RSC 0x000C
> +#define IC_CMBP_1 0x0010
> +#define IC_CMBP_2 0x0014
> +#define IC_IDMAC_1 0x0018
> +#define IC_IDMAC_2 0x001C
> +#define IC_IDMAC_3 0x0020
> +#define IC_IDMAC_4 0x0024
> +
> +/* IC Register Fields */
> +#define IC_CONF_PRPENC_EN (1 << 0)
> +#define IC_CONF_PRPENC_CSC1 (1 << 1)
> +#define IC_CONF_PRPENC_ROT_EN (1 << 2)
> +#define IC_CONF_PRPVF_EN (1 << 8)
> +#define IC_CONF_PRPVF_CSC1 (1 << 9)
> +#define IC_CONF_PRPVF_CSC2 (1 << 10)
> +#define IC_CONF_PRPVF_CMB (1 << 11)
> +#define IC_CONF_PRPVF_ROT_EN (1 << 12)
> +#define IC_CONF_PP_EN (1 << 16)
> +#define IC_CONF_PP_CSC1 (1 << 17)
> +#define IC_CONF_PP_CSC2 (1 << 18)
> +#define IC_CONF_PP_CMB (1 << 19)
> +#define IC_CONF_PP_ROT_EN (1 << 20)
> +#define IC_CONF_IC_GLB_LOC_A (1 << 28)
> +#define IC_CONF_KEY_COLOR_EN (1 << 29)
> +#define IC_CONF_RWS_EN (1 << 30)
> +#define IC_CONF_CSI_MEM_WR_EN (1 << 31)
> +
> +#define IC_IDMAC_1_CB0_BURST_16 (1 << 0)
> +#define IC_IDMAC_1_CB1_BURST_16 (1 << 1)
> +#define IC_IDMAC_1_CB2_BURST_16 (1 << 2)
> +#define IC_IDMAC_1_CB3_BURST_16 (1 << 3)
> +#define IC_IDMAC_1_CB4_BURST_16 (1 << 4)
> +#define IC_IDMAC_1_CB5_BURST_16 (1 << 5)
> +#define IC_IDMAC_1_CB6_BURST_16 (1 << 6)
> +#define IC_IDMAC_1_CB7_BURST_16 (1 << 7)
> +#define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11)
> +#define IC_IDMAC_1_PRPENC_ROT_OFFSET 11
> +#define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14)
> +#define IC_IDMAC_1_PRPVF_ROT_OFFSET 14
> +#define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17)
> +#define IC_IDMAC_1_PP_ROT_OFFSET 17
> +#define IC_IDMAC_1_PP_FLIP_RS (1 << 22)
> +#define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21)
> +#define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20)
> +
> +#define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0)
> +#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
> +#define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10)
> +#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10
> +#define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20)
> +#define IC_IDMAC_2_PP_HEIGHT_OFFSET 20
> +
> +#define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0)
> +#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0
> +#define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10)
> +#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10
> +#define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20)
> +#define IC_IDMAC_3_PP_WIDTH_OFFSET 20
> +
> +struct ic_task_regoffs {
> + u32 rsc;
> + u32 tpmem_csc[2];
> +};
> +
> +struct ic_task_bitfields {
> + u32 ic_conf_en;
> + u32 ic_conf_rot_en;
> + u32 ic_conf_cmb_en;
> + u32 ic_conf_csc1_en;
> + u32 ic_conf_csc2_en;
> + u32 ic_cmb_galpha_bit;
> +};
> +
> +static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
> + [IC_TASK_ENCODER] = {
> + .rsc = IC_PRP_ENC_RSC,
> + .tpmem_csc = {0x2008, 0},
> + },
> + [IC_TASK_VIEWFINDER] = {
> + .rsc = IC_PRP_VF_RSC,
> + .tpmem_csc = {0x4028, 0x4040},
> + },
> + [IC_TASK_POST_PROCESSOR] = {
> + .rsc = IC_PP_RSC,
> + .tpmem_csc = {0x6060, 0x6078},
> + },
> +};
> +
> +static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
> + [IC_TASK_ENCODER] = {
> + .ic_conf_en = IC_CONF_PRPENC_EN,
> + .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
> + .ic_conf_cmb_en = 0, /* NA */
> + .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
> + .ic_conf_csc2_en = 0, /* NA */
> + .ic_cmb_galpha_bit = 0, /* NA */
> + },
> + [IC_TASK_VIEWFINDER] = {
> + .ic_conf_en = IC_CONF_PRPVF_EN,
> + .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
> + .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
> + .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
> + .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
> + .ic_cmb_galpha_bit = 0,
> + },
> + [IC_TASK_POST_PROCESSOR] = {
> + .ic_conf_en = IC_CONF_PP_EN,
> + .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
> + .ic_conf_cmb_en = IC_CONF_PP_CMB,
> + .ic_conf_csc1_en = IC_CONF_PP_CSC1,
> + .ic_conf_csc2_en = IC_CONF_PP_CSC2,
> + .ic_cmb_galpha_bit = 8,
> + },
> +};
> +
> +struct ipu_ic_priv;
> +
> +struct ipu_ic {
> + enum ipu_ic_task task;
> + const struct ic_task_regoffs *reg;
> + const struct ic_task_bitfields *bit;
> +
> + enum ipu_color_space in_cs, g_in_cs;
> + enum ipu_color_space out_cs;
> + bool graphics;
> + bool rotation;
> + bool in_use;
> +
> + struct ipu_ic_priv *priv;
> +};
> +
> +struct ipu_ic_priv {
> + void __iomem *base;
> + void __iomem *tpmem_base;
> + spinlock_t lock;
> + struct ipu_soc *ipu;
> + int use_count;
> + struct ipu_ic task[IC_NUM_TASKS];
> +};
> +
> +static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
> +{
> + return readl(ic->priv->base + offset);
> +}
> +
> +static inline void ipu_ic_write(struct ipu_ic *ic, u32 value,
> + unsigned offset)
> +{
> + writel(value, ic->priv->base + offset);
> +}
> +
> +static void init_csc_rgb2ycbcr(u32 __iomem *base)
> +{
> + /*
> + * Y = R * .299 + G * .587 + B * .114;
> + * U = R * -.169 + G * -.332 + B * .500 + 128.;
> + * V = R * .500 + G * -.419 + B * -.0813 + 128.;
> + */
> + const u32 coeff[4][3] = {
> + {0x004D, 0x0096, 0x001D},
> + {0x01D5, 0x01AB, 0x0080},
> + {0x0080, 0x0195, 0x01EB},
> + {0x0000, 0x0200, 0x0200}, /* A0, A1, A2 */
> + };
> + u32 param;
> +
> + param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
> + (coeff[1][1] << 9) | coeff[2][2];
> + writel(param, base++);
> +
> + /* scale = 1, sat = 0 */
> + param = (coeff[3][0] >> 5) | (1UL << 8);
> + writel(param, base++);
> +
> + param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
> + (coeff[1][0] << 9) | coeff[2][0];
> + writel(param, base++);
> +
> + param = (coeff[3][1] >> 5);
> + writel(param, base++);
> +
> + param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
> + (coeff[1][2] << 9) | coeff[2][1];
> + writel(param, base++);
> +
> + param = (coeff[3][2] >> 5);
> + writel(param, base++);
> +}
> +
> +static void init_csc_rgb2rgb(u32 __iomem *base)
> +{
> + /* transparent RGB->RGB matrix for graphics combining */
> + const u32 coeff[4][3] = {
> + {0x0080, 0x0000, 0x0000},
> + {0x0000, 0x0080, 0x0000},
> + {0x0000, 0x0000, 0x0080},
> + {0x0000, 0x0000, 0x0000}, /* A0, A1, A2 */
> + };
> + u32 param;
> +
> + param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
> + (coeff[1][1] << 9) | coeff[2][2];
> + writel(param, base++);
> +
> + /* scale = 2, sat = 0 */
> + param = (coeff[3][0] >> 5) | (2UL << 8);
> + writel(param, base++);
> +
> + param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
> + (coeff[1][0] << 9) | coeff[2][0];
> + writel(param, base++);
> +
> + param = (coeff[3][1] >> 5);
> + writel(param, base++);
> +
> + param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
> + (coeff[1][2] << 9) | coeff[2][1];
> + writel(param, base++);
> +
> + param = (coeff[3][2] >> 5);
> + writel(param, base++);
> +}
> +
> +static void init_csc_ycbcr2rgb(u32 __iomem *base)
> +{
> + /*
> + * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
> + * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
> + * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
> + */
> + const u32 coeff[4][3] = {
> + {149, 0, 204},
> + {149, 462, 408},
> + {149, 255, 0},
> + {8192 - 446, 266, 8192 - 554}, /* A0, A1, A2 */
> + };
> + u32 param;
> +
> + param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
> + (coeff[1][1] << 9) | coeff[2][2];
> + writel(param, base++);
> +
> + /* scale = 2, sat = 0 */
> + param = (coeff[3][0] >> 5) | (2L << (40 - 32));
> + writel(param, base++);
> +
> + param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
> + (coeff[1][0] << 9) | coeff[2][0];
> + writel(param, base++);
> +
> + param = (coeff[3][1] >> 5);
> + writel(param, base++);
> +
> + param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
> + (coeff[1][2] << 9) | coeff[2][1];
> + writel(param, base++);
> +
> + param = (coeff[3][2] >> 5);
> + writel(param, base++);
> +}
> +
> +static int init_csc(struct ipu_ic *ic,
> + enum ipu_color_space inf,
> + enum ipu_color_space outf,
> + int csc_index)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + u32 __iomem *base;
> +
> + base = (u32 __iomem *)
> + (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
> +
> + if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
> + init_csc_ycbcr2rgb(base);
> + else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
> + init_csc_rgb2ycbcr(base);
> + else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
> + init_csc_rgb2rgb(base);
> + else {
> + dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int calc_resize_coeffs(struct ipu_ic *ic,
> + u32 in_size, u32 out_size,
> + u32 *resize_coeff,
> + u32 *downsize_coeff)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + struct ipu_soc *ipu = priv->ipu;
> + u32 temp_size, temp_downsize;
> +
> + /*
> + * Input size cannot be more than 4096, and output size cannot
> + * be more than 1024
> + */
> + if (in_size > 4096) {
> + dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
> + return -EINVAL;
> + }
> + if (out_size > 1024) {
> + dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
> + return -EINVAL;
> + }
> +
> + /* Cannot downsize more than 8:1 */
> + if ((out_size << 3) < in_size) {
> + dev_err(ipu->dev, "Unsupported downsize\n");
> + return -EINVAL;
> + }
> +
> + /* Compute downsizing coefficient */
> + temp_downsize = 0;
> + temp_size = in_size;
> + while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
> + (temp_downsize < 2)) {
> + temp_size >>= 1;
> + temp_downsize++;
> + }
> + *downsize_coeff = temp_downsize;
> +
> + /*
> + * compute resizing coefficient using the following equation:
> + * resize_coeff = M * (SI - 1) / (SO - 1)
> + * where M = 2^13, SI = input size, SO = output size
> + */
> + *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
> + if (*resize_coeff >= 16384L) {
> + dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
> + *resize_coeff = 0x3FFF;
> + }
> +
> + return 0;
> +}
> +
> +void ipu_ic_task_enable(struct ipu_ic *ic)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + unsigned long flags;
> + u32 ic_conf;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + ic_conf = ipu_ic_read(ic, IC_CONF);
> +
> + ic_conf |= ic->bit->ic_conf_en;
> +
> + if (ic->rotation)
> + ic_conf |= ic->bit->ic_conf_rot_en;
> +
> + if (ic->in_cs != ic->out_cs)
> + ic_conf |= ic->bit->ic_conf_csc1_en;
> +
> + if (ic->graphics) {
> + ic_conf |= ic->bit->ic_conf_cmb_en;
> + ic_conf |= ic->bit->ic_conf_csc1_en;
> +
> + if (ic->g_in_cs != ic->out_cs)
> + ic_conf |= ic->bit->ic_conf_csc2_en;
> + }
> +
> + ipu_ic_write(ic, ic_conf, IC_CONF);
> +
> + spin_unlock_irqrestore(&priv->lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
> +
> +void ipu_ic_task_disable(struct ipu_ic *ic)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + unsigned long flags;
> + u32 ic_conf;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + ic_conf = ipu_ic_read(ic, IC_CONF);
> +
> + ic_conf &= ~(ic->bit->ic_conf_en |
> + ic->bit->ic_conf_csc1_en |
> + ic->bit->ic_conf_rot_en);
> + if (ic->bit->ic_conf_csc2_en)
> + ic_conf &= ~ic->bit->ic_conf_csc2_en;
> + if (ic->bit->ic_conf_cmb_en)
> + ic_conf &= ~ic->bit->ic_conf_cmb_en;
> +
> + ipu_ic_write(ic, ic_conf, IC_CONF);
> +
> + ic->rotation = ic->graphics = false;
> +
> + spin_unlock_irqrestore(&priv->lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
> +
> +int ipu_ic_task_graphics_init(struct ipu_ic *ic,
> + enum ipu_color_space in_g_cs,
> + bool galpha_en, u32 galpha,
> + bool colorkey_en, u32 colorkey)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + unsigned long flags;
> + u32 reg, ic_conf;
> + int ret = 0;
> +
> + if (ic->task == IC_TASK_ENCODER)
> + return -EINVAL;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + ic_conf = ipu_ic_read(ic, IC_CONF);
> +
> + if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
> + /* need transparent CSC1 conversion */
> + ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
> + IPUV3_COLORSPACE_RGB, 0);
> + if (ret)
> + goto unlock;
> + }
> +
> + ic->g_in_cs = in_g_cs;
> +
> + if (ic->g_in_cs != ic->out_cs) {
> + ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
> + if (ret)
> + goto unlock;
> + }
> +
> + if (galpha_en) {
> + ic_conf |= IC_CONF_IC_GLB_LOC_A;
> + reg = ipu_ic_read(ic, IC_CMBP_1);
> + reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
> + reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
> + ipu_ic_write(ic, reg, IC_CMBP_1);
> + } else
> + ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
> +
> + if (colorkey_en) {
> + ic_conf |= IC_CONF_KEY_COLOR_EN;
> + ipu_ic_write(ic, colorkey, IC_CMBP_2);
> + } else
> + ic_conf &= ~IC_CONF_KEY_COLOR_EN;
> +
> + ipu_ic_write(ic, ic_conf, IC_CONF);
> +
> + ic->graphics = true;
> +unlock:
> + spin_unlock_irqrestore(&priv->lock, flags);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
> +
> +int ipu_ic_task_init(struct ipu_ic *ic,
> + int in_width, int in_height,
> + int out_width, int out_height,
> + enum ipu_color_space in_cs,
> + enum ipu_color_space out_cs)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + u32 reg, downsize_coeff, resize_coeff;
> + unsigned long flags;
> + int ret = 0;
> +
> + /* Setup vertical resizing */
> + ret = calc_resize_coeffs(ic, in_height, out_height,
> + &resize_coeff, &downsize_coeff);
> + if (ret)
> + return ret;
> +
> + reg = (downsize_coeff << 30) | (resize_coeff << 16);
> +
> + /* Setup horizontal resizing */
> + ret = calc_resize_coeffs(ic, in_width, out_width,
> + &resize_coeff, &downsize_coeff);
> + if (ret)
> + return ret;
> +
> + reg |= (downsize_coeff << 14) | resize_coeff;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + ipu_ic_write(ic, reg, ic->reg->rsc);
> +
> + /* Setup color space conversion */
> + ic->in_cs = in_cs;
> + ic->out_cs = out_cs;
> +
> + if (ic->in_cs != ic->out_cs) {
> + ret = init_csc(ic, ic->in_cs, ic->out_cs, 0);
> + if (ret)
> + goto unlock;
> + }
> +
> +unlock:
> + spin_unlock_irqrestore(&priv->lock, flags);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_task_init);
> +
> +int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
> + u32 width, u32 height, int burst_size,
> + enum ipu_rotate_mode rot)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + struct ipu_soc *ipu = priv->ipu;
> + u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
> + u32 temp_rot = bitrev8(rot) >> 5;
> + bool need_hor_flip = false;
> + unsigned long flags;
> + int ret = 0;
> +
> + if ((burst_size != 8) && (burst_size != 16)) {
> + dev_err(ipu->dev, "Illegal burst length for IC\n");
> + return -EINVAL;
> + }
> +
> + width--;
> + height--;
> +
> + if (temp_rot & 0x2) /* Need horizontal flip */
> + need_hor_flip = true;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
> + ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
> + ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
> +
> + switch (channel->num) {
> + case IPUV3_CHANNEL_IC_PP_MEM:
> + if (burst_size == 16)
> + ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
> +
> + if (need_hor_flip)
> + ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
> +
> + ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
> + ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
> +
> + ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
> + ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
> + break;
> + case IPUV3_CHANNEL_MEM_IC_PP:
> + if (burst_size == 16)
> + ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
> + break;
> + case IPUV3_CHANNEL_MEM_ROT_PP:
> + ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
> + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
> + break;
> + case IPUV3_CHANNEL_MEM_IC_PRP_VF:
> + if (burst_size == 16)
> + ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
> + break;
> + case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
> + if (burst_size == 16)
> + ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
> +
> + if (need_hor_flip)
> + ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
> +
> + ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
> + ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
> +
> + ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
> + ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
> + break;
> + case IPUV3_CHANNEL_MEM_ROT_ENC:
> + ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
> + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
> + break;
> + case IPUV3_CHANNEL_IC_PRP_VF_MEM:
> + if (burst_size == 16)
> + ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
> +
> + if (need_hor_flip)
> + ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
> +
> + ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
> + ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
> +
> + ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
> + ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
> + break;
> + case IPUV3_CHANNEL_MEM_ROT_VF:
> + ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
> + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
> + break;
> + case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
> + if (burst_size == 16)
> + ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
> + break;
> + case IPUV3_CHANNEL_G_MEM_IC_PP:
> + if (burst_size == 16)
> + ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
> + break;
> + case IPUV3_CHANNEL_VDI_MEM_IC_VF:
> + if (burst_size == 16)
> + ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
> + else
> + ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
> + break;
> + default:
> + goto unlock;
> + }
> +
> + ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
> + ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
> + ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
> +
> + if (rot >= IPU_ROTATE_90_RIGHT)
> + ic->rotation = true;
> +
> +unlock:
> + spin_unlock_irqrestore(&priv->lock, flags);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
> +
> +int ipu_ic_enable(struct ipu_ic *ic)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + unsigned long flags;
> + u32 module = IPU_CONF_IC_EN;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + if (ic->rotation)
> + module |= IPU_CONF_ROT_EN;
> +
> + if (!priv->use_count)
> + ipu_module_enable(priv->ipu, module);
> +
> + priv->use_count++;
> +
> + spin_unlock_irqrestore(&priv->lock, flags);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_enable);
> +
> +int ipu_ic_disable(struct ipu_ic *ic)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + unsigned long flags;
> + u32 module = IPU_CONF_IC_EN | IPU_CONF_ROT_EN;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + priv->use_count--;
> +
> + if (!priv->use_count)
> + ipu_module_disable(priv->ipu, module);
> +
> + if (priv->use_count < 0)
> + priv->use_count = 0;
> +
> + spin_unlock_irqrestore(&priv->lock, flags);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_disable);
> +
> +struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
> +{
> + struct ipu_ic_priv *priv = ipu->ic_priv;
> + unsigned long flags;
> + struct ipu_ic *ic, *ret;
> +
> + if (task >= IC_NUM_TASKS)
> + return ERR_PTR(-EINVAL);
> +
> + ic = &priv->task[task];
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + if (ic->in_use) {
> + ret = ERR_PTR(-EBUSY);
> + goto unlock;
> + }
> +
> + ic->in_use = true;
> + ret = ic;
> +
> +unlock:
> + spin_unlock_irqrestore(&priv->lock, flags);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_get);
> +
> +void ipu_ic_put(struct ipu_ic *ic)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> + ic->in_use = false;
> + spin_unlock_irqrestore(&priv->lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_put);
> +
> +int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
> + unsigned long base, unsigned long tpmem_base)
> +{
> + struct ipu_ic_priv *priv;
> + int i;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + ipu->ic_priv = priv;
> +
> + spin_lock_init(&priv->lock);
> + priv->base = devm_ioremap(dev, base, PAGE_SIZE);
> + if (!priv->base)
> + return -ENOMEM;
> + priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
> + if (!priv->tpmem_base)
> + return -ENOMEM;
> +
> + dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
> +
> + priv->ipu = ipu;
> +
> + for (i = 0; i < IC_NUM_TASKS; i++) {
> + priv->task[i].task = i;
> + priv->task[i].priv = priv;
> + priv->task[i].reg = &ic_task_reg[i];
> + priv->task[i].bit = &ic_task_bit[i];
> + }
> +
> + return 0;
> +}
> +
> +void ipu_ic_exit(struct ipu_soc *ipu)
> +{
> +}
> +
> +void ipu_ic_dump(struct ipu_ic *ic)
> +{
> + struct ipu_ic_priv *priv = ic->priv;
> + struct ipu_soc *ipu = priv->ipu;
> +
> + dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
> + ipu_ic_read(ic, IC_CONF));
> + dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
> + ipu_ic_read(ic, IC_PRP_ENC_RSC));
> + dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
> + ipu_ic_read(ic, IC_PRP_VF_RSC));
> + dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
> + ipu_ic_read(ic, IC_PP_RSC));
> + dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
> + ipu_ic_read(ic, IC_CMBP_1));
> + dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
> + ipu_ic_read(ic, IC_CMBP_2));
> + dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
> + ipu_ic_read(ic, IC_IDMAC_1));
> + dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
> + ipu_ic_read(ic, IC_IDMAC_2));
> + dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
> + ipu_ic_read(ic, IC_IDMAC_3));
> + dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
> + ipu_ic_read(ic, IC_IDMAC_4));
> +}
> +EXPORT_SYMBOL_GPL(ipu_ic_dump);
> diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
> index 7d8d95b..8e0bc1d 100644
> --- a/drivers/gpu/ipu-v3/ipu-prv.h
> +++ b/drivers/gpu/ipu-v3/ipu-prv.h
> @@ -156,9 +156,11 @@ struct ipuv3_channel {
> struct ipu_soc *ipu;
> };
>
> +struct ipu_csi;
> struct ipu_dc_priv;
> struct ipu_dmfc_priv;
> struct ipu_di;
> +struct ipu_ic_priv;
> struct ipu_smfc_priv;
>
> struct ipu_devtype;
> @@ -189,6 +191,8 @@ struct ipu_soc {
> struct ipu_dp_priv *dp_priv;
> struct ipu_dmfc_priv *dmfc_priv;
> struct ipu_di *di_priv[2];
> + struct ipu_csi *csi_priv[2];
> + struct ipu_ic_priv *ic_priv;
> struct ipu_smfc_priv *smfc_priv;
> };
>
> @@ -200,6 +204,14 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
> bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
> int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms);
>
> +int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
> + unsigned long base, u32 module, struct clk *clk_ipu);
> +void ipu_csi_exit(struct ipu_soc *ipu, int id);
> +
> +int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
> + unsigned long base, unsigned long tpmem_base);
> +void ipu_ic_exit(struct ipu_soc *ipu);
> +
> int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
> unsigned long base, u32 module, struct clk *ipu_clk);
> void ipu_di_exit(struct ipu_soc *ipu, int id);
> diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
> index 52fa277..580a88c 100644
> --- a/include/video/imx-ipu-v3.h
> +++ b/include/video/imx-ipu-v3.h
> @@ -61,6 +61,65 @@ struct ipu_di_signal_cfg {
> u8 vsync_pin;
> };
>
> +/*
> + * Bitfield of CSI signal polarities and modes.
> + */
> +struct ipu_csi_signal_cfg {
> + unsigned data_width:4;
> + unsigned clk_mode:3;
> + unsigned ext_vsync:1;
> + unsigned vsync_pol:1;
> + unsigned hsync_pol:1;
> + unsigned pixclk_pol:1;
> + unsigned data_pol:1;
> + unsigned sens_clksrc:1;
> + unsigned pack_tight:1;
> + unsigned force_eof:1;
> + unsigned data_en_pol:1;
> +
> + unsigned data_fmt;
> + unsigned mipi_dt;
> +};
> +
> +/*
> + * Enumeration of CSI data bus widths.
> + */
> +enum ipu_csi_data_width {
> + IPU_CSI_DATA_WIDTH_4 = 0,
> + IPU_CSI_DATA_WIDTH_8 = 1,
> + IPU_CSI_DATA_WIDTH_10 = 3,
> + IPU_CSI_DATA_WIDTH_12 = 5,
> + IPU_CSI_DATA_WIDTH_16 = 9,
> +};
> +
> +/*
> + * Enumeration of CSI clock modes.
> + */
> +enum ipu_csi_clk_mode {
> + IPU_CSI_CLK_MODE_GATED_CLK,
> + IPU_CSI_CLK_MODE_NONGATED_CLK,
> + IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
> + IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
> + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
> + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
> + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
> + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
> +};
> +
> +/*
> + * Enumeration of IPU rotation modes
> + */
> +enum ipu_rotate_mode {
> + IPU_ROTATE_NONE = 0,
> + IPU_ROTATE_VERT_FLIP,
> + IPU_ROTATE_HORIZ_FLIP,
> + IPU_ROTATE_180,
> + IPU_ROTATE_90_RIGHT,
> + IPU_ROTATE_90_RIGHT_VFLIP,
> + IPU_ROTATE_90_RIGHT_HFLIP,
> + IPU_ROTATE_90_LEFT,
> +};
> +
> enum ipu_color_space {
> IPUV3_COLORSPACE_RGB,
> IPUV3_COLORSPACE_YUV,
> @@ -176,8 +235,58 @@ int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
> /*
> * IPU CMOS Sensor Interface (csi) functions
> */
> -int ipu_csi_enable(struct ipu_soc *ipu, int csi);
> -int ipu_csi_disable(struct ipu_soc *ipu, int csi);
> +struct ipu_csi;
> +int ipu_csi_mbus_fmt_to_sig_cfg(struct ipu_csi_signal_cfg *cfg,
> + u32 mbus_code);
> +int ipu_csi_init_interface(struct ipu_csi *csi, u16 width, u16 height,
> + struct ipu_csi_signal_cfg *cfg);
> +bool ipu_csi_is_interlaced(struct ipu_csi *csi);
> +void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w);
> +void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w);
> +void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
> + u32 r_value, u32 g_value, u32 b_value,
> + u32 pix_clk);
> +int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
> + struct ipu_csi_signal_cfg *cfg);
> +int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
> + u32 max_ratio, u32 id);
> +int ipu_csi_set_dest(struct ipu_csi *csi, bool ic);
> +int ipu_csi_enable(struct ipu_csi *csi);
> +int ipu_csi_disable(struct ipu_csi *csi);
> +struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id);
> +void ipu_csi_put(struct ipu_csi *csi);
> +void ipu_csi_dump(struct ipu_csi *csi);
> +
> +/*
> + * IPU Image Converter (ic) functions
> + */
> +enum ipu_ic_task {
> + IC_TASK_ENCODER,
> + IC_TASK_VIEWFINDER,
> + IC_TASK_POST_PROCESSOR,
> + IC_NUM_TASKS,
> +};
> +
> +struct ipu_ic;
> +int ipu_ic_task_init(struct ipu_ic *ic,
> + int in_width, int in_height,
> + int out_width, int out_height,
> + enum ipu_color_space in_cs,
> + enum ipu_color_space out_cs);
> +int ipu_ic_task_graphics_init(struct ipu_ic *ic,
> + enum ipu_color_space in_g_cs,
> + bool galpha_en, u32 galpha,
> + bool colorkey_en, u32 colorkey);
> +void ipu_ic_task_enable(struct ipu_ic *ic);
> +void ipu_ic_task_disable(struct ipu_ic *ic);
> +int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
> + u32 width, u32 height, int burst_size,
> + enum ipu_rotate_mode rot);
> +int ipu_ic_enable(struct ipu_ic *ic);
> +int ipu_ic_disable(struct ipu_ic *ic);
> +struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task);
> +void ipu_ic_put(struct ipu_ic *ic);
> +void ipu_ic_dump(struct ipu_ic *ic);
>
> /*
> * IPU Sensor Multiple FIFO Controller (SMFC) functions
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 00/28] IPUv3 prep for video capture
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
` (28 preceding siblings ...)
2014-07-17 11:10 ` [PATCH 00/28] IPUv3 prep for video capture Hans Verkuil
@ 2014-07-31 15:28 ` Philipp Zabel
29 siblings, 0 replies; 42+ messages in thread
From: Philipp Zabel @ 2014-07-31 15:28 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam
Hi Steve,
Am Mittwoch, den 25.06.2014, 18:05 -0700 schrieb Steve Longerbeam:
> Hi Philip, Sascha,
>
> Here is a rebased set of IPU patches that prepares for video capture
> support. Video capture is not included in this set. I've addressed
> all your IPU-specific concerns from the previous patch set, the
> major ones being:
>
> - the IOMUXC control for CSI input selection has been removed. This
> should be part of a future CSI media entity driver.
>
> - the ipu-irt unit has been removed. Enabling the IRT module is
> folded into ipu-ic unit. The ipu-ic unit is also cleaned up a bit.
>
> - the ipu-csi APIs are consolidated/simplified.
>
> - added CSI and IC base offsets for i.MX51/i.MX53.
Sorry for the delay, I have only now started to look at the IPU again in
detail, and I still have a few comments. I'll reply to the individual
patches.
regards
Philipp
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 01/28] ARM: dts: imx6qdl: Add ipu aliases
2014-06-26 1:05 ` [PATCH 01/28] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
@ 2014-07-31 15:28 ` Philipp Zabel
2014-08-01 14:04 ` Shawn Guo
0 siblings, 1 reply; 42+ messages in thread
From: Philipp Zabel @ 2014-07-31 15:28 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam, Shawn Guo
Am Mittwoch, den 25.06.2014, 18:05 -0700 schrieb Steve Longerbeam:
> Add ipu0 (and ipu1 for quad) aliases to ipu1/ipu2 nodes respectively.
>
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
> arch/arm/boot/dts/imx6q.dtsi | 1 +
> arch/arm/boot/dts/imx6qdl.dtsi | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
> index addd3f8..fcfbac2 100644
> --- a/arch/arm/boot/dts/imx6q.dtsi
> +++ b/arch/arm/boot/dts/imx6q.dtsi
> @@ -14,6 +14,7 @@
>
> / {
> aliases {
> + ipu1 = &ipu2;
> spi4 = &ecspi5;
> };
>
> diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
> index ce05991..3b3d8fe 100644
> --- a/arch/arm/boot/dts/imx6qdl.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl.dtsi
> @@ -29,6 +29,7 @@
> i2c0 = &i2c1;
> i2c1 = &i2c2;
> i2c2 = &i2c3;
> + ipu0 = &ipu1;
> mmc0 = &usdhc1;
> mmc1 = &usdhc2;
> mmc2 = &usdhc3;
I think Shawn (added to Cc:) should take this patch separately, please
consider sending it to him.
regards
Philipp
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 02/28] gpu: ipu-v3: Add ipu_get_num()
2014-06-26 1:05 ` [PATCH 02/28] gpu: ipu-v3: Add ipu_get_num() Steve Longerbeam
@ 2014-07-31 15:28 ` Philipp Zabel
0 siblings, 0 replies; 42+ messages in thread
From: Philipp Zabel @ 2014-07-31 15:28 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam
Am Mittwoch, den 25.06.2014, 18:05 -0700 schrieb Steve Longerbeam:
> Adds of-alias id to ipu_soc and retrieve with ipu_get_num().
>
> ipu_get_num() is used to select inputs to CSI units in IOMUXC.
> It is also used to select an SMFC channel for video capture.
I still don't see the use of this. The IOMUXC multiplexing will be
handled outside of the IPU driver, and why would SMFC channel allocation
be different for the two IPUs? I'd say let's drop this for now.
regards
Philipp
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
> drivers/gpu/ipu-v3/ipu-common.c | 8 ++++++++
> drivers/gpu/ipu-v3/ipu-prv.h | 1 +
> include/video/imx-ipu-v3.h | 5 +++++
> 3 files changed, 14 insertions(+)
>
> diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
> index 04e7b2e..a92f48b 100644
> --- a/drivers/gpu/ipu-v3/ipu-common.c
> +++ b/drivers/gpu/ipu-v3/ipu-common.c
> @@ -55,6 +55,12 @@ static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
> writel(value, ipu->idmac_reg + offset);
> }
>
> +int ipu_get_num(struct ipu_soc *ipu)
> +{
> + return ipu->id;
> +}
> +EXPORT_SYMBOL_GPL(ipu_get_num);
> +
> void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
> {
> u32 val;
> @@ -1205,6 +1211,7 @@ static int ipu_probe(struct platform_device *pdev)
> {
> const struct of_device_id *of_id =
> of_match_device(imx_ipu_dt_ids, &pdev->dev);
> + struct device_node *np = pdev->dev.of_node;
> struct ipu_soc *ipu;
> struct resource *res;
> unsigned long ipu_base;
> @@ -1233,6 +1240,7 @@ static int ipu_probe(struct platform_device *pdev)
> ipu->channel[i].ipu = ipu;
> ipu->devtype = devtype;
> ipu->ipu_type = devtype->type;
> + ipu->id = of_alias_get_id(np, "ipu");
>
> spin_lock_init(&ipu->lock);
> mutex_init(&ipu->channel_lock);
> diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
> index c93f50e..55ae20c 100644
> --- a/drivers/gpu/ipu-v3/ipu-prv.h
> +++ b/drivers/gpu/ipu-v3/ipu-prv.h
> @@ -166,6 +166,7 @@ struct ipu_soc {
> void __iomem *idmac_reg;
> struct ipu_ch_param __iomem *cpmem_base;
>
> + int id;
> int usecount;
>
> struct clk *clk;
> diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
> index 3e43e22..739d204 100644
> --- a/include/video/imx-ipu-v3.h
> +++ b/include/video/imx-ipu-v3.h
> @@ -93,6 +93,11 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
> #define IPU_IRQ_VSYNC_PRE_1 (448 + 15)
>
> /*
> + * IPU Common functions
> + */
> +int ipu_get_num(struct ipu_soc *ipu);
> +
> +/*
> * IPU Image DMA Controller (idmac) functions
> */
> struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel);
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 05/28] gpu: ipu-v3: Add units required for video capture
2014-07-31 15:27 ` Philipp Zabel
@ 2014-07-31 15:31 ` Philipp Zabel
2014-07-31 17:41 ` Philipp Zabel
1 sibling, 0 replies; 42+ messages in thread
From: Philipp Zabel @ 2014-07-31 15:31 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam
Sorry about the near full-quote, this mail was sent prematurely as I
just learned Evolution does send mail on Ctrl+Enter. I'll continue this
later.
regards
Philipp
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 05/28] gpu: ipu-v3: Add units required for video capture
2014-07-31 15:27 ` Philipp Zabel
2014-07-31 15:31 ` Philipp Zabel
@ 2014-07-31 17:41 ` Philipp Zabel
1 sibling, 0 replies; 42+ messages in thread
From: Philipp Zabel @ 2014-07-31 17:41 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam
Am Donnerstag, den 31.07.2014, 17:27 +0200 schrieb Philipp Zabel:
> > +static void init_csc_rgb2ycbcr(u32 __iomem *base)
> > +{
> > + /*
> > + * Y = R * .299 + G * .587 + B * .114;
> > + * U = R * -.169 + G * -.332 + B * .500 + 128.;
> > + * V = R * .500 + G * -.419 + B * -.0813 + 128.;
> > + */
> > + const u32 coeff[4][3] = {
> > + {0x004D, 0x0096, 0x001D},
> > + {0x01D5, 0x01AB, 0x0080},
> > + {0x0080, 0x0195, 0x01EB},
> > + {0x0000, 0x0200, 0x0200}, /* A0, A1, A2 */
> > + };
> > + u32 param;
> > +
> > + param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
> > + (coeff[1][1] << 9) | coeff[2][2];
> > + writel(param, base++);
> > +
> > + /* scale = 1, sat = 0 */
> > + param = (coeff[3][0] >> 5) | (1UL << 8);
> > + writel(param, base++);
> > +
> > + param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
> > + (coeff[1][0] << 9) | coeff[2][0];
> > + writel(param, base++);
> > +
> > + param = (coeff[3][1] >> 5);
> > + writel(param, base++);
> > +
> > + param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
> > + (coeff[1][2] << 9) | coeff[2][1];
> > + writel(param, base++);
> > +
> > + param = (coeff[3][2] >> 5);
> > + writel(param, base++);
> > +}
> > +
> > +static void init_csc_rgb2rgb(u32 __iomem *base)
> > +{
> > + /* transparent RGB->RGB matrix for graphics combining */
> > + const u32 coeff[4][3] = {
> > + {0x0080, 0x0000, 0x0000},
> > + {0x0000, 0x0080, 0x0000},
> > + {0x0000, 0x0000, 0x0080},
> > + {0x0000, 0x0000, 0x0000}, /* A0, A1, A2 */
> > + };
> > + u32 param;
> > +
> > + param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
> > + (coeff[1][1] << 9) | coeff[2][2];
> > + writel(param, base++);
> > +
> > + /* scale = 2, sat = 0 */
> > + param = (coeff[3][0] >> 5) | (2UL << 8);
> > + writel(param, base++);
> > +
> > + param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
> > + (coeff[1][0] << 9) | coeff[2][0];
> > + writel(param, base++);
> > +
> > + param = (coeff[3][1] >> 5);
> > + writel(param, base++);
> > +
> > + param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
> > + (coeff[1][2] << 9) | coeff[2][1];
> > + writel(param, base++);
> > +
> > + param = (coeff[3][2] >> 5);
> > + writel(param, base++);
> > +}
> > +
> > +static void init_csc_ycbcr2rgb(u32 __iomem *base)
> > +{
> > + /*
> > + * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
> > + * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
> > + * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
> > + */
> > + const u32 coeff[4][3] = {
> > + {149, 0, 204},
> > + {149, 462, 408},
> > + {149, 255, 0},
> > + {8192 - 446, 266, 8192 - 554}, /* A0, A1, A2 */
> > + };
> > + u32 param;
> > +
> > + param = (coeff[3][0] << 27) | (coeff[0][0] << 18) |
> > + (coeff[1][1] << 9) | coeff[2][2];
> > + writel(param, base++);
> > +
> > + /* scale = 2, sat = 0 */
> > + param = (coeff[3][0] >> 5) | (2L << (40 - 32));
> > + writel(param, base++);
> > +
> > + param = (coeff[3][1] << 27) | (coeff[0][1] << 18) |
> > + (coeff[1][0] << 9) | coeff[2][0];
> > + writel(param, base++);
> > +
> > + param = (coeff[3][1] >> 5);
> > + writel(param, base++);
> > +
> > + param = (coeff[3][2] << 27) | (coeff[0][2] << 18) |
> > + (coeff[1][2] << 9) | coeff[2][1];
> > + writel(param, base++);
> > +
> > + param = (coeff[3][2] >> 5);
> > + writel(param, base++);
> > +}
Instead of repeating the same code three times, we could have three
global static const arrays for coefficients and scaling factors, and
only one function to apply any of them (or merge the code into
init_csc).
[...]
> > +static int calc_resize_coeffs(struct ipu_ic *ic,
> > + u32 in_size, u32 out_size,
> > + u32 *resize_coeff,
> > + u32 *downsize_coeff)
> > +{
> > + struct ipu_ic_priv *priv = ic->priv;
> > + struct ipu_soc *ipu = priv->ipu;
> > + u32 temp_size, temp_downsize;
> > +
> > + /*
> > + * Input size cannot be more than 4096, and output size cannot
> > + * be more than 1024
> > + */
> > + if (in_size > 4096) {
> > + dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
> > + return -EINVAL;
> > + }
> > + if (out_size > 1024) {
> > + dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
> > + return -EINVAL;
> > + }
> > +
> > + /* Cannot downsize more than 8:1 */
> > + if ((out_size << 3) < in_size) {
> > + dev_err(ipu->dev, "Unsupported downsize\n");
> > + return -EINVAL;
> > + }
> > +
> > + /* Compute downsizing coefficient */
> > + temp_downsize = 0;
> > + temp_size = in_size;
> > + while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
> > + (temp_downsize < 2)) {
> > + temp_size >>= 1;
> > + temp_downsize++;
> > + }
> > + *downsize_coeff = temp_downsize;
> > +
> > + /*
> > + * compute resizing coefficient using the following equation:
> > + * resize_coeff = M * (SI - 1) / (SO - 1)
> > + * where M = 2^13, SI = input size, SO = output size
> > + */
> > + *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
> > + if (*resize_coeff >= 16384L) {
> > + dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
> > + *resize_coeff = 0x3FFF;
> > + }
> > +
> > + return 0;
> > +}
This is fine for now, but to support tiled mem2mem scaling we will have
to make the scaling coefficient calculation independent from the tile
size.
[...]
regards
Philipp
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 16/28] gpu: ipu-v3: Add ipu_stride_to_bytes()
2014-06-26 1:05 ` [PATCH 16/28] gpu: ipu-v3: Add ipu_stride_to_bytes() Steve Longerbeam
@ 2014-07-31 18:02 ` Philipp Zabel
0 siblings, 0 replies; 42+ messages in thread
From: Philipp Zabel @ 2014-07-31 18:02 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam
Am Mittwoch, den 25.06.2014, 18:05 -0700 schrieb Steve Longerbeam:
> Adds ipu_stride_to_bytes(), which converts a pixel stride to bytes,
> suitable for passing to cpmem.
This is not IPU specific. You already have the bytesperline information
from the V4L2 driver or have to calculate it there, and that shouldn't
be done by calling into IPU core code.
regards
Philipp
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 27/28] gpu: ipu-cpmem: Add ipu_cpmem_dump()
2014-06-26 1:05 ` [PATCH 27/28] gpu: ipu-cpmem: Add ipu_cpmem_dump() Steve Longerbeam
@ 2014-07-31 18:06 ` Philipp Zabel
0 siblings, 0 replies; 42+ messages in thread
From: Philipp Zabel @ 2014-07-31 18:06 UTC (permalink / raw)
To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam
Am Mittwoch, den 25.06.2014, 18:05 -0700 schrieb Steve Longerbeam:
> Adds ipu_cpmem_dump() which dumps a channel's cpmem to debug.
Maybe #ifdef DEBUG this and ipu_dump?
regards
Philipp
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH 01/28] ARM: dts: imx6qdl: Add ipu aliases
2014-07-31 15:28 ` Philipp Zabel
@ 2014-08-01 14:04 ` Shawn Guo
0 siblings, 0 replies; 42+ messages in thread
From: Shawn Guo @ 2014-08-01 14:04 UTC (permalink / raw)
To: Philipp Zabel; +Cc: Steve Longerbeam, linux-media, Steve Longerbeam
On Thu, Jul 31, 2014 at 05:28:06PM +0200, Philipp Zabel wrote:
>
> Am Mittwoch, den 25.06.2014, 18:05 -0700 schrieb Steve Longerbeam:
> > Add ipu0 (and ipu1 for quad) aliases to ipu1/ipu2 nodes respectively.
> >
> > Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
>
> Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Please send the patch to LAKML and copy me if it's intended to be
applied on IMX tree.
Shawn
^ permalink raw reply [flat|nested] 42+ messages in thread
end of thread, other threads:[~2014-08-01 14:04 UTC | newest]
Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-06-26 1:05 [PATCH 00/28] IPUv3 prep for video capture Steve Longerbeam
2014-06-26 1:05 ` [PATCH 01/28] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
2014-07-31 15:28 ` Philipp Zabel
2014-08-01 14:04 ` Shawn Guo
2014-06-26 1:05 ` [PATCH 02/28] gpu: ipu-v3: Add ipu_get_num() Steve Longerbeam
2014-07-31 15:28 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 03/28] gpu: ipu-v3: Add functions to set CSI/IC source muxes Steve Longerbeam
2014-06-26 1:05 ` [PATCH 04/28] gpu: ipu-v3: Rename and add IDMAC channels Steve Longerbeam
2014-06-26 1:05 ` [PATCH 05/28] gpu: ipu-v3: Add units required for video capture Steve Longerbeam
2014-07-31 15:27 ` Philipp Zabel
2014-07-31 15:31 ` Philipp Zabel
2014-07-31 17:41 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 06/28] gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c Steve Longerbeam
2014-06-26 1:05 ` [PATCH 07/28] gpu: ipu-v3: smfc: Convert to per-channel Steve Longerbeam
2014-06-26 1:05 ` [PATCH 08/28] gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 09/28] gpu: ipu-v3: Add ipu_mbus_code_to_colorspace() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 10/28] gpu: ipu-v3: Add rotation mode conversion utilities Steve Longerbeam
2014-06-26 1:05 ` [PATCH 11/28] gpu: ipu-v3: Add helper function checking if pixfmt is planar Steve Longerbeam
2014-06-26 1:05 ` [PATCH 12/28] gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h Steve Longerbeam
2014-06-26 1:05 ` [PATCH 13/28] gpu: ipu-v3: Add ipu_idmac_buffer_is_ready() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 14/28] gpu: ipu-v3: Add ipu_idmac_clear_buffer() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 15/28] gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 16/28] gpu: ipu-v3: Add ipu_stride_to_bytes() Steve Longerbeam
2014-07-31 18:02 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 17/28] gpu: ipu-v3: Add ipu_idmac_enable_watermark() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 18/28] gpu: ipu-v3: Add ipu_idmac_lock_enable() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 19/28] gpu: ipu-v3: Add idmac channel linking support Steve Longerbeam
2014-06-26 1:05 ` [PATCH 20/28] gpu: ipu-v3: Add ipu-cpmem unit Steve Longerbeam
2014-06-26 1:05 ` [PATCH 21/28] staging: imx-drm: Convert to new ipu_cpmem API Steve Longerbeam
2014-06-26 1:05 ` [PATCH 22/28] gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 23/28] gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 24/28] gpu: ipu-cpmem: Add ipu_cpmem_set_rotation() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 25/28] gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image() Steve Longerbeam
2014-06-26 1:05 ` [PATCH 26/28] gpu: ipu-v3: Add more planar formats support Steve Longerbeam
2014-06-26 1:05 ` [PATCH 27/28] gpu: ipu-cpmem: Add ipu_cpmem_dump() Steve Longerbeam
2014-07-31 18:06 ` Philipp Zabel
2014-06-26 1:05 ` [PATCH 28/28] gpu: ipu-v3: Add ipu_dump() Steve Longerbeam
2014-07-17 11:10 ` [PATCH 00/28] IPUv3 prep for video capture Hans Verkuil
2014-07-17 20:44 ` Steve Longerbeam
2014-07-23 13:17 ` Laurent Pinchart
2014-07-25 21:21 ` Steve Longerbeam
2014-07-31 15:28 ` Philipp Zabel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).