summaryrefslogtreecommitdiff
path: root/drivers/media/platform/renesas
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/renesas')
-rw-r--r--drivers/media/platform/renesas/Kconfig16
-rw-r--r--drivers/media/platform/renesas/Makefile1
-rw-r--r--drivers/media/platform/renesas/rcar-csi2.c (renamed from drivers/media/platform/renesas/rcar-vin/rcar-csi2.c)754
-rw-r--r--drivers/media/platform/renesas/rcar-fcp.c2
-rw-r--r--drivers/media/platform/renesas/rcar-isp.c7
-rw-r--r--drivers/media/platform/renesas/rcar-vin/Kconfig16
-rw-r--r--drivers/media/platform/renesas/rcar-vin/Makefile1
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-core.c24
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-dma.c48
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c52
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-vin.h6
-rw-r--r--drivers/media/platform/renesas/rcar_drif.c6
-rw-r--r--drivers/media/platform/renesas/rcar_fdp1.c4
-rw-r--r--drivers/media/platform/renesas/rcar_jpu.c6
-rw-r--r--drivers/media/platform/renesas/renesas-ceu.c4
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c18
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h80
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h37
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c79
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c103
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c384
-rw-r--r--drivers/media/platform/renesas/sh_vou.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_brx.c31
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_clu.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drm.c27
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drm.h2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drv.c2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.c66
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.h48
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hgo.c28
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hgt.c20
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_histo.c78
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hsit.c6
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_lif.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_lut.c1
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_pipe.c103
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_pipe.h48
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rpf.c56
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rwpf.c26
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rwpf.h3
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_sru.c37
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_uds.c51
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_uif.c15
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_video.c224
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_wpf.c43
45 files changed, 1553 insertions, 1022 deletions
diff --git a/drivers/media/platform/renesas/Kconfig b/drivers/media/platform/renesas/Kconfig
index ed788e991f74..c7fc718a30a5 100644
--- a/drivers/media/platform/renesas/Kconfig
+++ b/drivers/media/platform/renesas/Kconfig
@@ -14,6 +14,22 @@ config VIDEO_RENESAS_CEU
help
This is a v4l2 driver for the Renesas CEU Interface
+config VIDEO_RCAR_CSI2
+ tristate "R-Car MIPI CSI-2 Receiver"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && OF
+ depends on ARCH_RENESAS || COMPILE_TEST
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select RESET_CONTROLLER
+ select V4L2_FWNODE
+ help
+ Support for Renesas R-Car MIPI CSI-2 receiver.
+ Supports R-Car Gen3 and RZ/G2 SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rcar-csi2.
+
config VIDEO_RCAR_ISP
tristate "R-Car Image Signal Processor (ISP)"
depends on V4L_PLATFORM_DRIVERS
diff --git a/drivers/media/platform/renesas/Makefile b/drivers/media/platform/renesas/Makefile
index 55854e868887..50774a20330c 100644
--- a/drivers/media/platform/renesas/Makefile
+++ b/drivers/media/platform/renesas/Makefile
@@ -7,6 +7,7 @@ obj-y += rcar-vin/
obj-y += rzg2l-cru/
obj-y += vsp1/
+obj-$(CONFIG_VIDEO_RCAR_CSI2) += rcar-csi2.o
obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o
obj-$(CONFIG_VIDEO_RCAR_ISP) += rcar-isp.o
obj-$(CONFIG_VIDEO_RENESAS_CEU) += renesas-ceu.o
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-csi2.c
index 582d5e35db0e..0a53dd47d7bf 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-csi2.c
@@ -135,13 +135,23 @@ struct rcar_csi2;
/* V4H BASE registers */
#define V4H_N_LANES_REG 0x0004
#define V4H_CSI2_RESETN_REG 0x0008
+
#define V4H_PHY_MODE_REG 0x001c
+#define V4H_PHY_MODE_DPHY 0
+#define V4H_PHY_MODE_CPHY 1
+
#define V4H_PHY_SHUTDOWNZ_REG 0x0040
#define V4H_DPHY_RSTZ_REG 0x0044
#define V4H_FLDC_REG 0x0804
#define V4H_FLDD_REG 0x0808
#define V4H_IDIC_REG 0x0810
+
#define V4H_PHY_EN_REG 0x2000
+#define V4H_PHY_EN_ENABLE_3 BIT(7)
+#define V4H_PHY_EN_ENABLE_2 BIT(6)
+#define V4H_PHY_EN_ENABLE_1 BIT(5)
+#define V4H_PHY_EN_ENABLE_0 BIT(4)
+#define V4H_PHY_EN_ENABLE_CLK BIT(0)
#define V4H_ST_PHYST_REG 0x2814
#define V4H_ST_PHYST_ST_PHY_READY BIT(31)
@@ -173,17 +183,19 @@ struct rcar_csi2;
#define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n) (0x23840 + ((n) * 2)) /* n = 0 - 11 */
#define V4H_CORE_DIG_RW_COMMON_REG(n) (0x23880 + ((n) * 2)) /* n = 0 - 15 */
#define V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(n) (0x239e0 + ((n) * 2)) /* n = 0 - 3 */
-#define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG 0x2a400
#define V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG 0x2a60c
/* V4H C-PHY */
#define V4H_CORE_DIG_RW_TRIO0_REG(n) (0x22100 + ((n) * 2)) /* n = 0 - 3 */
#define V4H_CORE_DIG_RW_TRIO1_REG(n) (0x22500 + ((n) * 2)) /* n = 0 - 3 */
#define V4H_CORE_DIG_RW_TRIO2_REG(n) (0x22900 + ((n) * 2)) /* n = 0 - 3 */
+#define V4H_CORE_DIG_CLANE_0_RW_CFG_0_REG 0x2a000
#define V4H_CORE_DIG_CLANE_0_RW_LP_0_REG 0x2a080
#define V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(n) (0x2a100 + ((n) * 2)) /* n = 0 - 6 */
+#define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG 0x2a400
#define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG 0x2a480
#define V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(n) (0x2a500 + ((n) * 2)) /* n = 0 - 6 */
+#define V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG 0x2a800
#define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG 0x2a880
#define V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(n) (0x2a900 + ((n) * 2)) /* n = 0 - 6 */
@@ -237,17 +249,37 @@ static const struct rcsi2_cphy_setting cphy_setting_table_r8a779g0[] = {
{ /* sentinel */ },
};
+/* V4M registers */
+#define V4M_OVR1_REG 0x0848
+#define V4M_OVR1_FORCERXMODE_3 BIT(12)
+#define V4M_OVR1_FORCERXMODE_2 BIT(11)
+#define V4M_OVR1_FORCERXMODE_1 BIT(10)
+#define V4M_OVR1_FORCERXMODE_0 BIT(9)
+
+#define V4M_FRXM_REG 0x2004
+#define V4M_FRXM_FORCERXMODE_3 BIT(3)
+#define V4M_FRXM_FORCERXMODE_2 BIT(2)
+#define V4M_FRXM_FORCERXMODE_1 BIT(1)
+#define V4M_FRXM_FORCERXMODE_0 BIT(0)
+
+#define V4M_PHYPLL_REG 0x02050
+#define V4M_CSI0CLKFCPR_REG 0x02054
+#define V4M_PHTW_REG 0x02060
+#define V4M_PHTR_REG 0x02064
+#define V4M_PHTC_REG 0x02068
+
struct phtw_value {
- u16 data;
- u16 code;
+ u8 data;
+ u8 code;
};
-struct rcsi2_mbps_reg {
+struct rcsi2_mbps_info {
u16 mbps;
- u16 reg;
+ u8 reg;
+ u16 osc_freq; /* V4M */
};
-static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = {
+static const struct rcsi2_mbps_info phtw_mbps_v3u[] = {
{ .mbps = 1500, .reg = 0xcc },
{ .mbps = 1550, .reg = 0x1d },
{ .mbps = 1600, .reg = 0x27 },
@@ -272,7 +304,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
+static const struct rcsi2_mbps_info phtw_mbps_h3_v3h_m3n[] = {
{ .mbps = 80, .reg = 0x86 },
{ .mbps = 90, .reg = 0x86 },
{ .mbps = 100, .reg = 0x87 },
@@ -292,7 +324,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
+static const struct rcsi2_mbps_info phtw_mbps_v3m_e3[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x20 },
{ .mbps = 100, .reg = 0x40 },
@@ -336,7 +368,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
#define PHYPLL_REG 0x68
#define PHYPLL_HSFREQRANGE(n) ((n) << 16)
-static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = {
+static const struct rcsi2_mbps_info hsfreqrange_v3u[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x10 },
{ .mbps = 100, .reg = 0x20 },
@@ -402,7 +434,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = {
+static const struct rcsi2_mbps_info hsfreqrange_h3_v3h_m3n[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x10 },
{ .mbps = 100, .reg = 0x20 },
@@ -449,7 +481,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = {
+static const struct rcsi2_mbps_info hsfreqrange_m3w[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x10 },
{ .mbps = 100, .reg = 0x20 },
@@ -496,6 +528,73 @@ static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = {
{ /* sentinel */ },
};
+static const struct rcsi2_mbps_info hsfreqrange_v4m[] = {
+ { .mbps = 80, .reg = 0x00, .osc_freq = 0x01a9 },
+ { .mbps = 90, .reg = 0x10, .osc_freq = 0x01a9 },
+ { .mbps = 100, .reg = 0x20, .osc_freq = 0x01a9 },
+ { .mbps = 110, .reg = 0x30, .osc_freq = 0x01a9 },
+ { .mbps = 120, .reg = 0x01, .osc_freq = 0x01a9 },
+ { .mbps = 130, .reg = 0x11, .osc_freq = 0x01a9 },
+ { .mbps = 140, .reg = 0x21, .osc_freq = 0x01a9 },
+ { .mbps = 150, .reg = 0x31, .osc_freq = 0x01a9 },
+ { .mbps = 160, .reg = 0x02, .osc_freq = 0x01a9 },
+ { .mbps = 170, .reg = 0x12, .osc_freq = 0x01a9 },
+ { .mbps = 180, .reg = 0x22, .osc_freq = 0x01a9 },
+ { .mbps = 190, .reg = 0x32, .osc_freq = 0x01a9 },
+ { .mbps = 205, .reg = 0x03, .osc_freq = 0x01a9 },
+ { .mbps = 220, .reg = 0x13, .osc_freq = 0x01a9 },
+ { .mbps = 235, .reg = 0x23, .osc_freq = 0x01a9 },
+ { .mbps = 250, .reg = 0x33, .osc_freq = 0x01a9 },
+ { .mbps = 275, .reg = 0x04, .osc_freq = 0x01a9 },
+ { .mbps = 300, .reg = 0x14, .osc_freq = 0x01a9 },
+ { .mbps = 325, .reg = 0x25, .osc_freq = 0x01a9 },
+ { .mbps = 350, .reg = 0x35, .osc_freq = 0x01a9 },
+ { .mbps = 400, .reg = 0x05, .osc_freq = 0x01a9 },
+ { .mbps = 450, .reg = 0x16, .osc_freq = 0x01a9 },
+ { .mbps = 500, .reg = 0x26, .osc_freq = 0x01a9 },
+ { .mbps = 550, .reg = 0x37, .osc_freq = 0x01a9 },
+ { .mbps = 600, .reg = 0x07, .osc_freq = 0x01a9 },
+ { .mbps = 650, .reg = 0x18, .osc_freq = 0x01a9 },
+ { .mbps = 700, .reg = 0x28, .osc_freq = 0x01a9 },
+ { .mbps = 750, .reg = 0x39, .osc_freq = 0x01a9 },
+ { .mbps = 800, .reg = 0x09, .osc_freq = 0x01a9 },
+ { .mbps = 850, .reg = 0x19, .osc_freq = 0x01a9 },
+ { .mbps = 900, .reg = 0x29, .osc_freq = 0x01a9 },
+ { .mbps = 950, .reg = 0x3a, .osc_freq = 0x01a9 },
+ { .mbps = 1000, .reg = 0x0a, .osc_freq = 0x01a9 },
+ { .mbps = 1050, .reg = 0x1a, .osc_freq = 0x01a9 },
+ { .mbps = 1100, .reg = 0x2a, .osc_freq = 0x01a9 },
+ { .mbps = 1150, .reg = 0x3b, .osc_freq = 0x01a9 },
+ { .mbps = 1200, .reg = 0x0b, .osc_freq = 0x01a9 },
+ { .mbps = 1250, .reg = 0x1b, .osc_freq = 0x01a9 },
+ { .mbps = 1300, .reg = 0x2b, .osc_freq = 0x01a9 },
+ { .mbps = 1350, .reg = 0x3c, .osc_freq = 0x01a9 },
+ { .mbps = 1400, .reg = 0x0c, .osc_freq = 0x01a9 },
+ { .mbps = 1450, .reg = 0x1c, .osc_freq = 0x01a9 },
+ { .mbps = 1500, .reg = 0x2c, .osc_freq = 0x01a9 },
+ { .mbps = 1550, .reg = 0x3d, .osc_freq = 0x0108 },
+ { .mbps = 1600, .reg = 0x0d, .osc_freq = 0x0110 },
+ { .mbps = 1650, .reg = 0x1d, .osc_freq = 0x0119 },
+ { .mbps = 1700, .reg = 0x2e, .osc_freq = 0x0121 },
+ { .mbps = 1750, .reg = 0x3e, .osc_freq = 0x012a },
+ { .mbps = 1800, .reg = 0x0e, .osc_freq = 0x0132 },
+ { .mbps = 1850, .reg = 0x1e, .osc_freq = 0x013b },
+ { .mbps = 1900, .reg = 0x2f, .osc_freq = 0x0143 },
+ { .mbps = 1950, .reg = 0x3f, .osc_freq = 0x014c },
+ { .mbps = 2000, .reg = 0x0f, .osc_freq = 0x0154 },
+ { .mbps = 2050, .reg = 0x40, .osc_freq = 0x015d },
+ { .mbps = 2100, .reg = 0x41, .osc_freq = 0x0165 },
+ { .mbps = 2150, .reg = 0x42, .osc_freq = 0x016e },
+ { .mbps = 2200, .reg = 0x43, .osc_freq = 0x0176 },
+ { .mbps = 2250, .reg = 0x44, .osc_freq = 0x017f },
+ { .mbps = 2300, .reg = 0x45, .osc_freq = 0x0187 },
+ { .mbps = 2350, .reg = 0x46, .osc_freq = 0x0190 },
+ { .mbps = 2400, .reg = 0x47, .osc_freq = 0x0198 },
+ { .mbps = 2450, .reg = 0x48, .osc_freq = 0x01a1 },
+ { .mbps = 2500, .reg = 0x49, .osc_freq = 0x01a9 },
+ { /* sentinel */ },
+};
+
/* PHY ESC Error Monitor */
#define PHEERM_REG 0x74
@@ -575,6 +674,21 @@ static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code)
return NULL;
}
+struct rcsi2_cphy_line_order {
+ enum v4l2_mbus_csi2_cphy_line_orders_type order;
+ u16 cfg;
+ u16 ctrl29;
+};
+
+static const struct rcsi2_cphy_line_order rcsi2_cphy_line_orders[] = {
+ { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_ABC, .cfg = 0x0, .ctrl29 = 0x0 },
+ { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_ACB, .cfg = 0xa, .ctrl29 = 0x1 },
+ { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_BAC, .cfg = 0xc, .ctrl29 = 0x1 },
+ { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_BCA, .cfg = 0x5, .ctrl29 = 0x0 },
+ { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_CAB, .cfg = 0x3, .ctrl29 = 0x0 },
+ { .order = V4L2_MBUS_CSI2_CPHY_LINE_ORDER_CBA, .cfg = 0x9, .ctrl29 = 0x1 }
+};
+
enum rcar_csi2_pads {
RCAR_CSI2_SINK,
RCAR_CSI2_SOURCE_VC0,
@@ -584,12 +698,19 @@ enum rcar_csi2_pads {
NR_OF_RCAR_CSI2_PAD,
};
+struct rcsi2_register_layout {
+ unsigned int phtw;
+ unsigned int phypll;
+};
+
struct rcar_csi2_info {
+ const struct rcsi2_register_layout *regs;
int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps);
int (*phy_post_init)(struct rcar_csi2 *priv);
- int (*start_receiver)(struct rcar_csi2 *priv);
+ int (*start_receiver)(struct rcar_csi2 *priv,
+ struct v4l2_subdev_state *state);
void (*enter_standby)(struct rcar_csi2 *priv);
- const struct rcsi2_mbps_reg *hsfreqrange;
+ const struct rcsi2_mbps_info *hsfreqrange;
unsigned int csi0clkfreqrange;
unsigned int num_channels;
bool clear_ulps;
@@ -613,13 +734,12 @@ struct rcar_csi2 {
int channel_vc[4];
- struct mutex lock; /* Protects mf and stream_count. */
- struct v4l2_mbus_framefmt mf;
int stream_count;
bool cphy;
unsigned short lanes;
unsigned char lane_swap[4];
+ enum v4l2_mbus_csi2_cphy_line_orders_type line_orders[3];
};
static inline struct rcar_csi2 *sd_to_csi2(struct v4l2_subdev *sd)
@@ -632,6 +752,16 @@ static inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n)
return container_of(n, struct rcar_csi2, notifier);
}
+static unsigned int rcsi2_num_pads(const struct rcar_csi2 *priv)
+{
+ /* Used together with R-Car ISP: one sink and one source pad. */
+ if (priv->info->use_isp)
+ return 2;
+
+ /* Used together with R-Car VIN: one sink and four source pads. */
+ return 5;
+}
+
static u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg)
{
return ioread32(priv->base + reg);
@@ -642,11 +772,88 @@ static void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data)
iowrite32(data, priv->base + reg);
}
+static u16 rcsi2_read16(struct rcar_csi2 *priv, unsigned int reg)
+{
+ return ioread16(priv->base + reg);
+}
+
static void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data)
{
iowrite16(data, priv->base + reg);
}
+static void rcsi2_modify16(struct rcar_csi2 *priv, unsigned int reg, u16 data, u16 mask)
+{
+ u16 val;
+
+ val = rcsi2_read16(priv, reg) & ~mask;
+ rcsi2_write16(priv, reg, val | data);
+}
+
+static int rcsi2_phtw_write(struct rcar_csi2 *priv, u8 data, u8 code)
+{
+ unsigned int timeout;
+
+ rcsi2_write(priv, priv->info->regs->phtw,
+ PHTW_DWEN | PHTW_TESTDIN_DATA(data) |
+ PHTW_CWEN | PHTW_TESTDIN_CODE(code));
+
+ /* Wait for DWEN and CWEN to be cleared by hardware. */
+ for (timeout = 0; timeout <= 20; timeout++) {
+ if (!(rcsi2_read(priv, priv->info->regs->phtw) & (PHTW_DWEN | PHTW_CWEN)))
+ return 0;
+
+ usleep_range(1000, 2000);
+ }
+
+ dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n");
+
+ return -ETIMEDOUT;
+}
+
+static int rcsi2_phtw_write_array(struct rcar_csi2 *priv,
+ const struct phtw_value *values,
+ unsigned int size)
+{
+ int ret;
+
+ for (unsigned int i = 0; i < size; i++) {
+ ret = rcsi2_phtw_write(priv, values[i].data, values[i].code);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct rcsi2_mbps_info *
+rcsi2_mbps_to_info(struct rcar_csi2 *priv,
+ const struct rcsi2_mbps_info *infotable, unsigned int mbps)
+{
+ const struct rcsi2_mbps_info *info;
+ const struct rcsi2_mbps_info *prev = NULL;
+
+ if (mbps < infotable->mbps)
+ dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps",
+ mbps, infotable->mbps);
+
+ for (info = infotable; info->mbps != 0; info++) {
+ if (info->mbps >= mbps)
+ break;
+ prev = info;
+ }
+
+ if (!info->mbps) {
+ dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
+ return NULL;
+ }
+
+ if (prev && ((mbps - prev->mbps) <= (info->mbps - mbps)))
+ info = prev;
+
+ return info;
+}
+
static void rcsi2_enter_standby_gen3(struct rcar_csi2 *priv)
{
rcsi2_write(priv, PHYCNT_REG, 0);
@@ -699,29 +906,13 @@ static int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps)
{
- const struct rcsi2_mbps_reg *hsfreq;
- const struct rcsi2_mbps_reg *hsfreq_prev = NULL;
-
- if (mbps < priv->info->hsfreqrange->mbps)
- dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps",
- mbps, priv->info->hsfreqrange->mbps);
+ const struct rcsi2_mbps_info *info;
- for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) {
- if (hsfreq->mbps >= mbps)
- break;
- hsfreq_prev = hsfreq;
- }
-
- if (!hsfreq->mbps) {
- dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
+ info = rcsi2_mbps_to_info(priv, priv->info->hsfreqrange, mbps);
+ if (!info)
return -ERANGE;
- }
- if (hsfreq_prev &&
- ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps)))
- hsfreq = hsfreq_prev;
-
- rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg));
+ rcsi2_write(priv, priv->info->regs->phypll, PHYPLL_HSFREQRANGE(info->reg));
return 0;
}
@@ -808,20 +999,25 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
return 0;
}
-static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv)
+static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv,
+ struct v4l2_subdev_state *state)
{
const struct rcar_csi2_format *format;
u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
+ const struct v4l2_mbus_framefmt *fmt;
unsigned int lanes;
unsigned int i;
int mbps, ret;
+ /* Use the format on the sink pad to compute the receiver config. */
+ fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK);
+
dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
- priv->mf.width, priv->mf.height,
- priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i');
+ fmt->width, fmt->height,
+ fmt->field == V4L2_FIELD_NONE ? 'p' : 'i');
/* Code is validated in set_fmt. */
- format = rcsi2_code_to_fmt(priv->mf.code);
+ format = rcsi2_code_to_fmt(fmt->code);
if (!format)
return -EINVAL;
@@ -849,11 +1045,11 @@ static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv)
vcdt2 |= vcdt_part << ((i % 2) * 16);
}
- if (priv->mf.field == V4L2_FIELD_ALTERNATE) {
+ if (fmt->field == V4L2_FIELD_ALTERNATE) {
fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2
| FLD_FLD_EN;
- if (priv->mf.height == 240)
+ if (fmt->height == 240)
fld |= FLD_FLD_NUM(0);
else
fld |= FLD_FLD_NUM(1);
@@ -947,6 +1143,26 @@ static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv)
return 0;
}
+static void rsci2_set_line_order(struct rcar_csi2 *priv,
+ enum v4l2_mbus_csi2_cphy_line_orders_type order,
+ unsigned int cfgreg, unsigned int ctrlreg)
+{
+ const struct rcsi2_cphy_line_order *info = NULL;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(rcsi2_cphy_line_orders); i++) {
+ if (rcsi2_cphy_line_orders[i].order == order) {
+ info = &rcsi2_cphy_line_orders[i];
+ break;
+ }
+ }
+
+ if (!info)
+ return;
+
+ rcsi2_modify16(priv, cfgreg, info->cfg, 0x000f);
+ rcsi2_modify16(priv, ctrlreg, info->ctrl29, 0x0100);
+}
+
static int rcsi2_wait_phy_start_v4h(struct rcar_csi2 *priv, u32 match)
{
unsigned int timeout;
@@ -1024,12 +1240,18 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps)
rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(1), conf->trio1);
rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(1), conf->trio1);
- /*
- * Configure pin-swap.
- * TODO: This registers is not documented yet, the values should depend
- * on the 'clock-lanes' and 'data-lanes' devicetree properties.
- */
- rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, 0xf5);
+ /* Configure data line order. */
+ rsci2_set_line_order(priv, priv->line_orders[0],
+ V4H_CORE_DIG_CLANE_0_RW_CFG_0_REG,
+ V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9));
+ rsci2_set_line_order(priv, priv->line_orders[1],
+ V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG,
+ V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(9));
+ rsci2_set_line_order(priv, priv->line_orders[2],
+ V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG,
+ V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(9));
+
+ /* TODO: This registers is not documented. */
rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000);
/* Leave Shutdown mode */
@@ -1049,15 +1271,18 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps)
return 0;
}
-static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv)
+static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv,
+ struct v4l2_subdev_state *state)
{
const struct rcar_csi2_format *format;
+ const struct v4l2_mbus_framefmt *fmt;
unsigned int lanes;
int msps;
int ret;
- /* Calculate parameters */
- format = rcsi2_code_to_fmt(priv->mf.code);
+ /* Use the format on the sink pad to compute the receiver config. */
+ fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK);
+ format = rcsi2_code_to_fmt(fmt->code);
if (!format)
return -EINVAL;
@@ -1075,11 +1300,11 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv)
rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0);
/* PHY static setting */
- rcsi2_write(priv, V4H_PHY_EN_REG, BIT(0));
+ rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK);
rcsi2_write(priv, V4H_FLDC_REG, 0);
rcsi2_write(priv, V4H_FLDD_REG, 0);
rcsi2_write(priv, V4H_IDIC_REG, 0);
- rcsi2_write(priv, V4H_PHY_MODE_REG, BIT(0));
+ rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_CPHY);
rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1);
/* Reset CSI2 */
@@ -1114,7 +1339,201 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv)
return 0;
}
-static int rcsi2_start(struct rcar_csi2 *priv)
+static int rcsi2_d_phy_setting_v4m(struct rcar_csi2 *priv, int data_rate)
+{
+ unsigned int timeout;
+ int ret;
+
+ static const struct phtw_value step1[] = {
+ { .data = 0x00, .code = 0x00 },
+ { .data = 0x00, .code = 0x1e },
+ };
+
+ /* Shutdown and reset PHY. */
+ rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0));
+ rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0));
+
+ /* Start internal calibration (POR). */
+ ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
+ if (ret)
+ return ret;
+
+ /* Wait for POR to complete. */
+ for (timeout = 10; timeout > 0; timeout--) {
+ if ((rcsi2_read(priv, V4M_PHTR_REG) & 0xf0000) == 0x70000)
+ break;
+ usleep_range(1000, 2000);
+ }
+
+ if (!timeout) {
+ dev_err(priv->dev, "D-PHY calibration failed\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int rcsi2_set_osc_freq(struct rcar_csi2 *priv, unsigned int mbps)
+{
+ const struct rcsi2_mbps_info *info;
+ struct phtw_value steps[] = {
+ { .data = 0x00, .code = 0x00 },
+ { .code = 0xe2 }, /* Data filled in below. */
+ { .code = 0xe3 }, /* Data filled in below. */
+ { .data = 0x01, .code = 0xe4 },
+ };
+
+ info = rcsi2_mbps_to_info(priv, priv->info->hsfreqrange, mbps);
+ if (!info)
+ return -ERANGE;
+
+ /* Fill in data for command. */
+ steps[1].data = (info->osc_freq & 0x00ff) >> 0;
+ steps[2].data = (info->osc_freq & 0x0f00) >> 8;
+
+ return rcsi2_phtw_write_array(priv, steps, ARRAY_SIZE(steps));
+}
+
+static int rcsi2_init_common_v4m(struct rcar_csi2 *priv, unsigned int mbps)
+{
+ int ret;
+
+ static const struct phtw_value step1[] = {
+ { .data = 0x00, .code = 0x00 },
+ { .data = 0x3c, .code = 0x08 },
+ };
+
+ static const struct phtw_value step2[] = {
+ { .data = 0x00, .code = 0x00 },
+ { .data = 0x80, .code = 0xe0 },
+ { .data = 0x31, .code = 0xe1 },
+ { .data = 0x06, .code = 0x00 },
+ { .data = 0x11, .code = 0x11 },
+ { .data = 0x08, .code = 0x00 },
+ { .data = 0x11, .code = 0x11 },
+ { .data = 0x0a, .code = 0x00 },
+ { .data = 0x11, .code = 0x11 },
+ { .data = 0x0c, .code = 0x00 },
+ { .data = 0x11, .code = 0x11 },
+ { .data = 0x01, .code = 0x00 },
+ { .data = 0x31, .code = 0xaa },
+ { .data = 0x05, .code = 0x00 },
+ { .data = 0x05, .code = 0x09 },
+ { .data = 0x07, .code = 0x00 },
+ { .data = 0x05, .code = 0x09 },
+ { .data = 0x09, .code = 0x00 },
+ { .data = 0x05, .code = 0x09 },
+ { .data = 0x0b, .code = 0x00 },
+ { .data = 0x05, .code = 0x09 },
+ };
+
+ static const struct phtw_value step3[] = {
+ { .data = 0x01, .code = 0x00 },
+ { .data = 0x06, .code = 0xab },
+ };
+
+ if (priv->info->hsfreqrange) {
+ ret = rcsi2_set_phypll(priv, mbps);
+ if (ret)
+ return ret;
+
+ ret = rcsi2_set_osc_freq(priv, mbps);
+ if (ret)
+ return ret;
+ }
+
+ if (mbps <= 1500) {
+ ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
+ if (ret)
+ return ret;
+ }
+
+ if (priv->info->csi0clkfreqrange)
+ rcsi2_write(priv, V4M_CSI0CLKFCPR_REG,
+ CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange));
+
+ rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK |
+ V4H_PHY_EN_ENABLE_0 | V4H_PHY_EN_ENABLE_1 |
+ V4H_PHY_EN_ENABLE_2 | V4H_PHY_EN_ENABLE_3);
+
+ if (mbps > 1500) {
+ ret = rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2));
+ if (ret)
+ return ret;
+ }
+
+ return rcsi2_phtw_write_array(priv, step3, ARRAY_SIZE(step3));
+}
+
+static int rcsi2_start_receiver_v4m(struct rcar_csi2 *priv,
+ struct v4l2_subdev_state *state)
+{
+ const struct rcar_csi2_format *format;
+ const struct v4l2_mbus_framefmt *fmt;
+ unsigned int lanes;
+ int mbps;
+ int ret;
+
+ /* Calculate parameters */
+ fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK);
+ format = rcsi2_code_to_fmt(fmt->code);
+ if (!format)
+ return -EINVAL;
+
+ ret = rcsi2_get_active_lanes(priv, &lanes);
+ if (ret)
+ return ret;
+
+ mbps = rcsi2_calc_mbps(priv, format->bpp, lanes);
+ if (mbps < 0)
+ return mbps;
+
+ /* Reset LINK and PHY */
+ rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0);
+ rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0);
+ rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0);
+ rcsi2_write(priv, V4M_PHTC_REG, PHTC_TESTCLR);
+
+ /* PHY static setting */
+ rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK);
+ rcsi2_write(priv, V4H_FLDC_REG, 0);
+ rcsi2_write(priv, V4H_FLDD_REG, 0);
+ rcsi2_write(priv, V4H_IDIC_REG, 0);
+ rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_DPHY);
+ rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1);
+
+ rcsi2_write(priv, V4M_FRXM_REG,
+ V4M_FRXM_FORCERXMODE_0 | V4M_FRXM_FORCERXMODE_1 |
+ V4M_FRXM_FORCERXMODE_2 | V4M_FRXM_FORCERXMODE_3);
+ rcsi2_write(priv, V4M_OVR1_REG,
+ V4M_OVR1_FORCERXMODE_0 | V4M_OVR1_FORCERXMODE_1 |
+ V4M_OVR1_FORCERXMODE_2 | V4M_OVR1_FORCERXMODE_3);
+
+ /* Reset CSI2 */
+ rcsi2_write(priv, V4M_PHTC_REG, 0);
+ rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0));
+
+ /* Common settings */
+ ret = rcsi2_init_common_v4m(priv, mbps);
+ if (ret)
+ return ret;
+
+ /* D-PHY settings */
+ ret = rcsi2_d_phy_setting_v4m(priv, mbps);
+ if (ret)
+ return ret;
+
+ rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 |
+ V4H_ST_PHYST_ST_STOPSTATE_1 |
+ V4H_ST_PHYST_ST_STOPSTATE_2 |
+ V4H_ST_PHYST_ST_STOPSTATE_3);
+
+ rcsi2_write(priv, V4M_FRXM_REG, 0);
+
+ return 0;
+}
+
+static int rcsi2_start(struct rcar_csi2 *priv, struct v4l2_subdev_state *state)
{
int ret;
@@ -1122,7 +1541,7 @@ static int rcsi2_start(struct rcar_csi2 *priv)
if (ret < 0)
return ret;
- ret = priv->info->start_receiver(priv);
+ ret = priv->info->start_receiver(priv, state);
if (ret) {
rcsi2_enter_standby(priv);
return ret;
@@ -1146,17 +1565,16 @@ static void rcsi2_stop(struct rcar_csi2 *priv)
static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
+ struct v4l2_subdev_state *state;
int ret = 0;
- mutex_lock(&priv->lock);
+ if (!priv->remote)
+ return -ENODEV;
- if (!priv->remote) {
- ret = -ENODEV;
- goto out;
- }
+ state = v4l2_subdev_lock_and_get_active_state(&priv->subdev);
if (enable && priv->stream_count == 0) {
- ret = rcsi2_start(priv);
+ ret = rcsi2_start(priv, state);
if (ret)
goto out;
} else if (!enable && priv->stream_count == 1) {
@@ -1165,49 +1583,29 @@ static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
priv->stream_count += enable ? 1 : -1;
out:
- mutex_unlock(&priv->lock);
+ v4l2_subdev_unlock_state(state);
return ret;
}
static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
- struct v4l2_mbus_framefmt *framefmt;
+ unsigned int num_pads = rcsi2_num_pads(priv);
- mutex_lock(&priv->lock);
+ if (format->pad > RCAR_CSI2_SINK)
+ return v4l2_subdev_get_fmt(sd, state, format);
if (!rcsi2_code_to_fmt(format->format.code))
format->format.code = rcar_csi2_formats[0].code;
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- priv->mf = format->format;
- } else {
- framefmt = v4l2_subdev_state_get_format(sd_state, 0);
- *framefmt = format->format;
- }
+ *v4l2_subdev_state_get_format(state, format->pad) = format->format;
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct rcar_csi2 *priv = sd_to_csi2(sd);
-
- mutex_lock(&priv->lock);
-
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- format->format = priv->mf;
- else
- format->format = *v4l2_subdev_state_get_format(sd_state, 0);
-
- mutex_unlock(&priv->lock);
+ /* Propagate the format to the source pads. */
+ for (unsigned int i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
+ *v4l2_subdev_state_get_format(state, i) = format->format;
return 0;
}
@@ -1218,7 +1616,7 @@ static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = {
static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = {
.set_fmt = rcsi2_set_pad_format,
- .get_fmt = rcsi2_get_pad_format,
+ .get_fmt = v4l2_subdev_get_fmt,
};
static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
@@ -1226,6 +1624,33 @@ static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
.pad = &rcar_csi2_pad_ops,
};
+static int rcsi2_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct rcar_csi2 *priv = sd_to_csi2(sd);
+ unsigned int num_pads = rcsi2_num_pads(priv);
+
+ static const struct v4l2_mbus_framefmt rcar_csi2_default_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = MEDIA_BUS_FMT_RGB888_1X24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .field = V4L2_FIELD_NONE,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_DEFAULT,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+ };
+
+ for (unsigned int i = RCAR_CSI2_SINK; i < num_pads; i++)
+ *v4l2_subdev_state_get_format(state, i) = rcar_csi2_default_fmt;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops rcar_csi2_internal_ops = {
+ .init_state = rcsi2_init_state,
+};
+
static irqreturn_t rcsi2_irq(int irq, void *data)
{
struct rcar_csi2 *priv = data;
@@ -1251,14 +1676,17 @@ static irqreturn_t rcsi2_irq(int irq, void *data)
static irqreturn_t rcsi2_irq_thread(int irq, void *data)
{
+ struct v4l2_subdev_state *state;
struct rcar_csi2 *priv = data;
- mutex_lock(&priv->lock);
+ state = v4l2_subdev_lock_and_get_active_state(&priv->subdev);
+
rcsi2_stop(priv);
usleep_range(1000, 2000);
- if (rcsi2_start(priv))
+ if (rcsi2_start(priv, state))
dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n");
- mutex_unlock(&priv->lock);
+
+ v4l2_subdev_unlock_state(state);
return IRQ_HANDLED;
}
@@ -1366,6 +1794,9 @@ static int rcsi2_parse_v4l2(struct rcar_csi2 *priv,
}
}
+ for (i = 0; i < ARRAY_SIZE(priv->line_orders); i++)
+ priv->line_orders[i] = vep->bus.mipi_csi2.line_orders[i];
+
return 0;
}
@@ -1425,64 +1856,16 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv)
* NOTE: Magic values are from the datasheet and lack documentation.
*/
-static int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code)
-{
- unsigned int timeout;
-
- rcsi2_write(priv, PHTW_REG,
- PHTW_DWEN | PHTW_TESTDIN_DATA(data) |
- PHTW_CWEN | PHTW_TESTDIN_CODE(code));
-
- /* Wait for DWEN and CWEN to be cleared by hardware. */
- for (timeout = 0; timeout <= 20; timeout++) {
- if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN)))
- return 0;
-
- usleep_range(1000, 2000);
- }
-
- dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n");
-
- return -ETIMEDOUT;
-}
-
-static int rcsi2_phtw_write_array(struct rcar_csi2 *priv,
- const struct phtw_value *values)
-{
- const struct phtw_value *value;
- int ret;
-
- for (value = values; value->data || value->code; value++) {
- ret = rcsi2_phtw_write(priv, value->data, value->code);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps,
- const struct rcsi2_mbps_reg *values, u16 code)
+ const struct rcsi2_mbps_info *values, u8 code)
{
- const struct rcsi2_mbps_reg *value;
- const struct rcsi2_mbps_reg *prev_value = NULL;
+ const struct rcsi2_mbps_info *info;
- for (value = values; value->mbps; value++) {
- if (value->mbps >= mbps)
- break;
- prev_value = value;
- }
-
- if (prev_value &&
- ((mbps - prev_value->mbps) <= (value->mbps - mbps)))
- value = prev_value;
-
- if (!value->mbps) {
- dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
+ info = rcsi2_mbps_to_info(priv, values, mbps);
+ if (!info)
return -ERANGE;
- }
- return rcsi2_phtw_write(priv, value->reg, code);
+ return rcsi2_phtw_write(priv, info->reg, code);
}
static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
@@ -1494,7 +1877,6 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
{ .data = 0x11, .code = 0xe4 },
{ .data = 0x01, .code = 0xe5 },
{ .data = 0x10, .code = 0x04 },
- { /* sentinel */ },
};
static const struct phtw_value step2[] = {
@@ -1503,12 +1885,11 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
{ .data = 0x4b, .code = 0xac },
{ .data = 0x03, .code = 0x00 },
{ .data = 0x80, .code = 0x07 },
- { /* sentinel */ },
};
int ret;
- ret = rcsi2_phtw_write_array(priv, step1);
+ ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
if (ret)
return ret;
@@ -1523,7 +1904,7 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
return ret;
}
- return rcsi2_phtw_write_array(priv, step2);
+ return rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2));
}
static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps)
@@ -1549,10 +1930,9 @@ static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv)
{ .data = 0xee, .code = 0x54 },
{ .data = 0xee, .code = 0x84 },
{ .data = 0xee, .code = 0x94 },
- { /* sentinel */ },
};
- return rcsi2_phtw_write_array(priv, step1);
+ return rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
}
static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
@@ -1561,20 +1941,17 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
/* In case of 1500Mbps or less */
static const struct phtw_value step1[] = {
{ .data = 0xcc, .code = 0xe2 },
- { /* sentinel */ },
};
static const struct phtw_value step2[] = {
{ .data = 0x01, .code = 0xe3 },
{ .data = 0x11, .code = 0xe4 },
{ .data = 0x01, .code = 0xe5 },
- { /* sentinel */ },
};
/* In case of 1500Mbps or less */
static const struct phtw_value step3[] = {
{ .data = 0x38, .code = 0x08 },
- { /* sentinel */ },
};
static const struct phtw_value step4[] = {
@@ -1582,29 +1959,28 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
{ .data = 0x4b, .code = 0xac },
{ .data = 0x03, .code = 0x00 },
{ .data = 0x80, .code = 0x07 },
- { /* sentinel */ },
};
int ret;
if (mbps != 0 && mbps <= 1500)
- ret = rcsi2_phtw_write_array(priv, step1);
+ ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
else
ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2);
if (ret)
return ret;
- ret = rcsi2_phtw_write_array(priv, step2);
+ ret = rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2));
if (ret)
return ret;
if (mbps != 0 && mbps <= 1500) {
- ret = rcsi2_phtw_write_array(priv, step3);
+ ret = rcsi2_phtw_write_array(priv, step3, ARRAY_SIZE(step3));
if (ret)
return ret;
}
- ret = rcsi2_phtw_write_array(priv, step4);
+ ret = rcsi2_phtw_write_array(priv, step4, ARRAY_SIZE(step4));
if (ret)
return ret;
@@ -1688,7 +2064,13 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv,
return PTR_ERR_OR_ZERO(priv->rstc);
}
+static const struct rcsi2_register_layout rcsi2_registers_gen3 = {
+ .phtw = PHTW_REG,
+ .phypll = PHYPLL_REG,
+};
+
static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1700,6 +2082,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_h3es2,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1711,6 +2094,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
+ .regs = &rcsi2_registers_gen3,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
.hsfreqrange = hsfreqrange_m3w,
@@ -1719,6 +2103,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = {
+ .regs = &rcsi2_registers_gen3,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
.hsfreqrange = hsfreqrange_m3w,
@@ -1727,6 +2112,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1738,6 +2124,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_v3m_e3,
.phy_post_init = rcsi2_phy_post_init_v3m_e3,
.start_receiver = rcsi2_start_receiver_gen3,
@@ -1747,6 +2134,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1757,6 +2145,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_v3m_e3,
.phy_post_init = rcsi2_phy_post_init_v3m_e3,
.start_receiver = rcsi2_start_receiver_gen3,
@@ -1766,6 +2155,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_v3u,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1777,11 +2167,26 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = {
+ .regs = &rcsi2_registers_gen3,
.start_receiver = rcsi2_start_receiver_v4h,
.use_isp = true,
.support_cphy = true,
};
+static const struct rcsi2_register_layout rcsi2_registers_v4m = {
+ .phtw = V4M_PHTW_REG,
+ .phypll = V4M_PHYPLL_REG,
+};
+
+static const struct rcar_csi2_info rcar_csi2_info_r8a779h0 = {
+ .regs = &rcsi2_registers_v4m,
+ .start_receiver = rcsi2_start_receiver_v4m,
+ .hsfreqrange = hsfreqrange_v4m,
+ .csi0clkfreqrange = 0x0c,
+ .use_isp = true,
+ .support_dphy = true,
+};
+
static const struct of_device_id rcar_csi2_of_table[] = {
{
.compatible = "renesas,r8a774a1-csi2",
@@ -1835,6 +2240,10 @@ static const struct of_device_id rcar_csi2_of_table[] = {
.compatible = "renesas,r8a779g0-csi2",
.data = &rcar_csi2_info_r8a779g0,
},
+ {
+ .compatible = "renesas,r8a779h0-csi2",
+ .data = &rcar_csi2_info_r8a779h0,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
@@ -1870,23 +2279,23 @@ static int rcsi2_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
- mutex_init(&priv->lock);
priv->stream_count = 0;
ret = rcsi2_probe_resources(priv, pdev);
if (ret) {
dev_err(priv->dev, "Failed to get resources\n");
- goto error_mutex;
+ return ret;
}
platform_set_drvdata(pdev, priv);
ret = rcsi2_parse_dt(priv);
if (ret)
- goto error_mutex;
+ return ret;
priv->subdev.owner = THIS_MODULE;
priv->subdev.dev = &pdev->dev;
+ priv->subdev.internal_ops = &rcar_csi2_internal_ops;
v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops);
v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s",
@@ -1896,7 +2305,7 @@ static int rcsi2_probe(struct platform_device *pdev)
priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
priv->subdev.entity.ops = &rcar_csi2_entity_ops;
- num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD;
+ num_pads = rcsi2_num_pads(priv);
priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
@@ -1912,19 +2321,25 @@ static int rcsi2_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
+ ret = v4l2_subdev_init_finalize(&priv->subdev);
+ if (ret)
+ goto error_pm_runtime;
+
ret = v4l2_async_register_subdev(&priv->subdev);
if (ret < 0)
- goto error_async;
+ goto error_subdev;
dev_info(priv->dev, "%d lanes found\n", priv->lanes);
return 0;
+error_subdev:
+ v4l2_subdev_cleanup(&priv->subdev);
+error_pm_runtime:
+ pm_runtime_disable(&pdev->dev);
error_async:
v4l2_async_nf_unregister(&priv->notifier);
v4l2_async_nf_cleanup(&priv->notifier);
-error_mutex:
- mutex_destroy(&priv->lock);
return ret;
}
@@ -1936,14 +2351,13 @@ static void rcsi2_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&priv->notifier);
v4l2_async_nf_cleanup(&priv->notifier);
v4l2_async_unregister_subdev(&priv->subdev);
+ v4l2_subdev_cleanup(&priv->subdev);
pm_runtime_disable(&pdev->dev);
-
- mutex_destroy(&priv->lock);
}
static struct platform_driver rcar_csi2_pdrv = {
- .remove_new = rcsi2_remove,
+ .remove = rcsi2_remove,
.probe = rcsi2_probe,
.driver = {
.name = "rcar-csi2",
diff --git a/drivers/media/platform/renesas/rcar-fcp.c b/drivers/media/platform/renesas/rcar-fcp.c
index bcef7b87da7c..cee9bbce4e3a 100644
--- a/drivers/media/platform/renesas/rcar-fcp.c
+++ b/drivers/media/platform/renesas/rcar-fcp.c
@@ -164,7 +164,7 @@ MODULE_DEVICE_TABLE(of, rcar_fcp_of_match);
static struct platform_driver rcar_fcp_platform_driver = {
.probe = rcar_fcp_probe,
- .remove_new = rcar_fcp_remove,
+ .remove = rcar_fcp_remove,
.driver = {
.name = "rcar-fcp",
.of_match_table = rcar_fcp_of_match,
diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c
index 530d65fc546b..c515278e3be5 100644
--- a/drivers/media/platform/renesas/rcar-isp.c
+++ b/drivers/media/platform/renesas/rcar-isp.c
@@ -431,7 +431,9 @@ static int risp_probe_resources(struct rcar_isp *isp,
static const struct of_device_id risp_of_id_table[] = {
{ .compatible = "renesas,r8a779a0-isp" },
{ .compatible = "renesas,r8a779g0-isp" },
- { /* sentinel */ },
+ /* Keep above for compatibility with old DTB files. */
+ { .compatible = "renesas,rcar-gen4-isp" },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, risp_of_id_table);
@@ -518,10 +520,11 @@ static void risp_remove(struct platform_device *pdev)
static struct platform_driver rcar_isp_driver = {
.driver = {
.name = "rcar-isp",
+ .suppress_bind_attrs = true,
.of_match_table = risp_of_id_table,
},
.probe = risp_probe,
- .remove_new = risp_remove,
+ .remove = risp_remove,
};
module_platform_driver(rcar_isp_driver);
diff --git a/drivers/media/platform/renesas/rcar-vin/Kconfig b/drivers/media/platform/renesas/rcar-vin/Kconfig
index de55fe63d84c..2ec857ab83cb 100644
--- a/drivers/media/platform/renesas/rcar-vin/Kconfig
+++ b/drivers/media/platform/renesas/rcar-vin/Kconfig
@@ -1,20 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-config VIDEO_RCAR_CSI2
- tristate "R-Car MIPI CSI-2 Receiver"
- depends on V4L_PLATFORM_DRIVERS
- depends on VIDEO_DEV && OF
- depends on ARCH_RENESAS || COMPILE_TEST
- select MEDIA_CONTROLLER
- select VIDEO_V4L2_SUBDEV_API
- select RESET_CONTROLLER
- select V4L2_FWNODE
- help
- Support for Renesas R-Car MIPI CSI-2 receiver.
- Supports R-Car Gen3 and RZ/G2 SoCs.
-
- To compile this driver as a module, choose M here: the
- module will be called rcar-csi2.
-
config VIDEO_RCAR_VIN
tristate "R-Car Video Input (VIN) Driver"
depends on V4L_PLATFORM_DRIVERS
diff --git a/drivers/media/platform/renesas/rcar-vin/Makefile b/drivers/media/platform/renesas/rcar-vin/Makefile
index 00d809f5d2c1..5938ad6290c8 100644
--- a/drivers/media/platform/renesas/rcar-vin/Makefile
+++ b/drivers/media/platform/renesas/rcar-vin/Makefile
@@ -1,5 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
rcar-vin-objs = rcar-core.o rcar-dma.o rcar-v4l2.o
-obj-$(CONFIG_VIDEO_RCAR_CSI2) += rcar-csi2.o
obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin.o
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
index 809c3a38cc4a..ddfb18e6e7a4 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
@@ -1274,20 +1274,12 @@ static const struct rvin_info rcar_info_r8a77995 = {
.scaler = rvin_scaler_gen3,
};
-static const struct rvin_info rcar_info_r8a779a0 = {
- .model = RCAR_GEN3,
- .use_mc = true,
- .use_isp = true,
- .nv12 = true,
- .max_width = 4096,
- .max_height = 4096,
-};
-
-static const struct rvin_info rcar_info_r8a779g0 = {
+static const struct rvin_info rcar_info_gen4 = {
.model = RCAR_GEN3,
.use_mc = true,
.use_isp = true,
.nv12 = true,
+ .raw10 = true,
.max_width = 4096,
.max_height = 4096,
};
@@ -1354,12 +1346,18 @@ static const struct of_device_id rvin_of_id_table[] = {
.data = &rcar_info_r8a77995,
},
{
+ /* Keep to be compatible with old DTS files. */
.compatible = "renesas,vin-r8a779a0",
- .data = &rcar_info_r8a779a0,
+ .data = &rcar_info_gen4,
},
{
+ /* Keep to be compatible with old DTS files. */
.compatible = "renesas,vin-r8a779g0",
- .data = &rcar_info_r8a779g0,
+ .data = &rcar_info_gen4,
+ },
+ {
+ .compatible = "renesas,rcar-gen4-vin",
+ .data = &rcar_info_gen4,
},
{ /* Sentinel */ },
};
@@ -1446,7 +1444,7 @@ static struct platform_driver rcar_vin_driver = {
.of_match_table = rvin_of_id_table,
},
.probe = rcar_vin_probe,
- .remove_new = rcar_vin_remove,
+ .remove = rcar_vin_remove,
};
module_platform_driver(rcar_vin_driver);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
index e2c40abc6d3d..8773998101ff 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
@@ -123,7 +123,9 @@
/* Video n Data Mode Register bits */
#define VNDMR_A8BIT(n) (((n) & 0xff) << 24)
#define VNDMR_A8BIT_MASK (0xff << 24)
+#define VNDMR_RMODE_RAW10 (2 << 19)
#define VNDMR_YMODE_Y8 (1 << 12)
+#define VNDMR_YC_THR (1 << 11)
#define VNDMR_EXRGB (1 << 8)
#define VNDMR_BPSM (1 << 4)
#define VNDMR_ABIT (1 << 2)
@@ -742,12 +744,22 @@ static int rvin_setup(struct rvin_dev *vin)
*/
switch (vin->mbus_code) {
case MEDIA_BUS_FMT_YUYV8_1X16:
- /* BT.601/BT.1358 16bit YCbCr422 */
- vnmc |= VNMC_INF_YUV16;
+ if (vin->is_csi)
+ /* YCbCr422 8-bit */
+ vnmc |= VNMC_INF_YUV8_BT601;
+ else
+ /* BT.601/BT.1358 16bit YCbCr422 */
+ vnmc |= VNMC_INF_YUV16;
input_is_yuv = true;
break;
case MEDIA_BUS_FMT_UYVY8_1X16:
- vnmc |= VNMC_INF_YUV16 | VNMC_YCAL;
+ if (vin->is_csi)
+ /* YCbCr422 8-bit */
+ vnmc |= VNMC_INF_YUV8_BT601;
+ else
+ /* BT.601/BT.1358 16bit YCbCr422 */
+ vnmc |= VNMC_INF_YUV16;
+ vnmc |= VNMC_YCAL;
input_is_yuv = true;
break;
case MEDIA_BUS_FMT_UYVY8_2X8:
@@ -780,6 +792,12 @@ static int rvin_setup(struct rvin_dev *vin)
case MEDIA_BUS_FMT_Y8_1X8:
vnmc |= VNMC_INF_RAW8;
break;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ vnmc |= VNMC_INF_RGB666;
+ break;
default:
break;
}
@@ -888,6 +906,12 @@ static int rvin_setup(struct rvin_dev *vin)
dmr = 0;
}
break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ dmr = VNDMR_RMODE_RAW10 | VNDMR_YC_THR;
+ break;
default:
vin_err(vin, "Invalid pixelformat (0x%x)\n",
vin->format.pixelformat);
@@ -1270,6 +1294,22 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
if (vin->format.pixelformat != V4L2_PIX_FMT_GREY)
return -EPIPE;
break;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR10)
+ return -EPIPE;
+ break;
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG10)
+ return -EPIPE;
+ break;
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG10)
+ return -EPIPE;
+ break;
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB10)
+ return -EPIPE;
+ break;
default:
return -EPIPE;
}
@@ -1519,8 +1559,6 @@ static const struct vb2_ops rvin_qops = {
.buf_queue = rvin_buffer_queue,
.start_streaming = rvin_start_streaming_vq,
.stop_streaming = rvin_stop_streaming_vq,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
void rvin_dma_unregister(struct rvin_dev *vin)
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
index 073f70c6ac68..756fdfdbce61 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
@@ -86,6 +86,22 @@ static const struct rvin_video_format rvin_formats[] = {
.fourcc = V4L2_PIX_FMT_GREY,
.bpp = 1,
},
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .bpp = 4,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .bpp = 4,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .bpp = 4,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .bpp = 4,
+ },
};
const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
@@ -106,6 +122,13 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333))
return NULL;
break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ if (!vin->info->raw10)
+ return NULL;
+ break;
default:
break;
}
@@ -407,6 +430,26 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
f->pixelformat = V4L2_PIX_FMT_SRGGB8;
return 0;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SBGGR10;
+ return 0;
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SGBRG10;
+ return 0;
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SGRBG10;
+ return 0;
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SRGGB10;
+ return 0;
default:
return -EINVAL;
}
@@ -730,7 +773,8 @@ static int rvin_s_dv_timings(struct file *file, void *priv_fh,
struct v4l2_subdev *sd = vin_to_source(vin);
int ret;
- ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
+ ret = v4l2_subdev_call(sd, pad, s_dv_timings,
+ vin->parallel.sink_pad, timings);
if (ret)
return ret;
@@ -744,7 +788,8 @@ static int rvin_g_dv_timings(struct file *file, void *priv_fh,
struct rvin_dev *vin = video_drvdata(file);
struct v4l2_subdev *sd = vin_to_source(vin);
- return v4l2_subdev_call(sd, video, g_dv_timings, timings);
+ return v4l2_subdev_call(sd, pad, g_dv_timings,
+ vin->parallel.sink_pad, timings);
}
static int rvin_query_dv_timings(struct file *file, void *priv_fh,
@@ -753,7 +798,8 @@ static int rvin_query_dv_timings(struct file *file, void *priv_fh,
struct rvin_dev *vin = video_drvdata(file);
struct v4l2_subdev *sd = vin_to_source(vin);
- return v4l2_subdev_call(sd, video, query_dv_timings, timings);
+ return v4l2_subdev_call(sd, pad, query_dv_timings,
+ vin->parallel.sink_pad, timings);
}
static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
index 792336dada44..f87d4bc9e53e 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
@@ -59,7 +59,7 @@ enum rvin_isp_id {
#define RVIN_REMOTES_MAX \
(((unsigned int)RVIN_CSI_MAX) > ((unsigned int)RVIN_ISP_MAX) ? \
- RVIN_CSI_MAX : RVIN_ISP_MAX)
+ (unsigned int)RVIN_CSI_MAX : (unsigned int)RVIN_ISP_MAX)
/**
* enum rvin_dma_state - DMA states
@@ -151,7 +151,8 @@ struct rvin_group_route {
* @model: VIN model
* @use_mc: use media controller instead of controlling subdevice
* @use_isp: the VIN is connected to the ISP and not to the CSI-2
- * @nv12: support outputing NV12 pixel format
+ * @nv12: support outputting NV12 pixel format
+ * @raw10: support outputting RAW10 pixel format
* @max_width: max input width the VIN supports
* @max_height: max input height the VIN supports
* @routes: list of possible routes from the CSI-2 recivers to
@@ -163,6 +164,7 @@ struct rvin_info {
bool use_mc;
bool use_isp;
bool nv12;
+ bool raw10;
unsigned int max_width;
unsigned int max_height;
diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c
index f21d05054341..fc8b6bbef793 100644
--- a/drivers/media/platform/renesas/rcar_drif.c
+++ b/drivers/media/platform/renesas/rcar_drif.c
@@ -861,8 +861,6 @@ static const struct vb2_ops rcar_drif_vb2_ops = {
.buf_queue = rcar_drif_buf_queue,
.start_streaming = rcar_drif_start_streaming,
.stop_streaming = rcar_drif_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int rcar_drif_querycap(struct file *file, void *fh,
@@ -1071,7 +1069,6 @@ static int rcar_drif_sdr_register(struct rcar_drif_sdr *sdr)
sdr->vdev->release = video_device_release;
sdr->vdev->lock = &sdr->v4l2_mutex;
sdr->vdev->queue = &sdr->vb_queue;
- sdr->vdev->queue->lock = &sdr->vb_queue_mutex;
sdr->vdev->ctrl_handler = &sdr->ctrl_hdl;
sdr->vdev->v4l2_dev = &sdr->v4l2_dev;
sdr->vdev->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER |
@@ -1316,6 +1313,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)
sdr->vb_queue.ops = &rcar_drif_vb2_ops;
sdr->vb_queue.mem_ops = &vb2_vmalloc_memops;
sdr->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ sdr->vb_queue.lock = &sdr->vb_queue_mutex;
/* Init videobuf2 queue */
ret = vb2_queue_init(&sdr->vb_queue);
@@ -1475,7 +1473,7 @@ static struct platform_driver rcar_drif_driver = {
.pm = &rcar_drif_pm_ops,
},
.probe = rcar_drif_probe,
- .remove_new = rcar_drif_remove,
+ .remove = rcar_drif_remove,
};
module_platform_driver(rcar_drif_driver);
diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c
index a2565b269f3b..5d453a7a8988 100644
--- a/drivers/media/platform/renesas/rcar_fdp1.c
+++ b/drivers/media/platform/renesas/rcar_fdp1.c
@@ -2032,8 +2032,6 @@ static const struct vb2_ops fdp1_qops = {
.buf_queue = fdp1_buf_queue,
.start_streaming = fdp1_start_streaming,
.stop_streaming = fdp1_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -2444,7 +2442,7 @@ MODULE_DEVICE_TABLE(of, fdp1_dt_ids);
static struct platform_driver fdp1_pdrv = {
.probe = fdp1_probe,
- .remove_new = fdp1_remove,
+ .remove = fdp1_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = fdp1_dt_ids,
diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c
index fff349e45067..81038df71bb5 100644
--- a/drivers/media/platform/renesas/rcar_jpu.c
+++ b/drivers/media/platform/renesas/rcar_jpu.c
@@ -14,7 +14,7 @@
* 3) V4L2_CID_JPEG_ACTIVE_MARKER
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/interrupt.h>
@@ -1171,8 +1171,6 @@ static const struct vb2_ops jpu_qops = {
.buf_finish = jpu_buf_finish,
.start_streaming = jpu_start_streaming,
.stop_streaming = jpu_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int jpu_queue_init(void *priv, struct vb2_queue *src_vq,
@@ -1736,7 +1734,7 @@ static const struct dev_pm_ops jpu_pm_ops = {
static struct platform_driver jpu_driver = {
.probe = jpu_probe,
- .remove_new = jpu_remove,
+ .remove = jpu_remove,
.driver = {
.of_match_table = jpu_dt_ids,
.name = DRV_NAME,
diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c
index 167760276796..8cceafe491b1 100644
--- a/drivers/media/platform/renesas/renesas-ceu.c
+++ b/drivers/media/platform/renesas/renesas-ceu.c
@@ -761,8 +761,6 @@ static const struct vb2_ops ceu_vb2_ops = {
.queue_setup = ceu_vb2_setup,
.buf_queue = ceu_vb2_queue,
.buf_prepare = ceu_vb2_prepare,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = ceu_start_streaming,
.stop_streaming = ceu_stop_streaming,
};
@@ -1723,7 +1721,7 @@ static struct platform_driver ceu_driver = {
.of_match_table = of_match_ptr(ceu_of_match),
},
.probe = ceu_probe,
- .remove_new = ceu_remove,
+ .remove = ceu_remove,
};
module_platform_driver(ceu_driver);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 280efd2a8185..89be584a4988 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -72,7 +72,6 @@ static int rzg2l_cru_group_notify_complete(struct v4l2_async_notifier *notifier)
source->name, sink->name);
return ret;
}
- cru->csi.channel = 0;
cru->ip.remote = cru->csi.subdev;
/* Create media device link between CRU IP <-> CRU OUTPUT */
@@ -209,7 +208,7 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru)
const struct of_device_id *match;
int ret;
- cru->pad.flags = MEDIA_PAD_FL_SINK;
+ cru->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
ret = media_entity_pads_init(&cru->vdev.entity, 1, &cru->pad);
if (ret)
return ret;
@@ -242,7 +241,7 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru)
static int rzg2l_cru_probe(struct platform_device *pdev)
{
struct rzg2l_cru_dev *cru;
- int ret;
+ int irq, ret;
cru = devm_kzalloc(&pdev->dev, sizeof(*cru), GFP_KERNEL);
if (!cru)
@@ -270,9 +269,14 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
cru->dev = &pdev->dev;
cru->info = of_device_get_match_data(&pdev->dev);
- cru->image_conv_irq = platform_get_irq(pdev, 0);
- if (cru->image_conv_irq < 0)
- return cru->image_conv_irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, rzg2l_cru_irq, 0,
+ KBUILD_MODNAME, cru);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to request irq\n");
platform_set_drvdata(pdev, cru);
@@ -325,7 +329,7 @@ static struct platform_driver rzg2l_cru_driver = {
.of_match_table = rzg2l_cru_of_id_table,
},
.probe = rzg2l_cru_probe,
- .remove_new = rzg2l_cru_remove,
+ .remove = rzg2l_cru_remove,
};
module_platform_driver(rzg2l_cru_driver);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
new file mode 100644
index 000000000000..1c9f22118a5d
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * rzg2l-cru-regs.h--RZ/G2L (and alike SoCs) CRU Registers Definitions
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#ifndef __RZG2L_CRU_REGS_H__
+#define __RZG2L_CRU_REGS_H__
+
+/* HW CRU Registers Definition */
+
+/* CRU Control Register */
+#define CRUnCTRL 0x0
+#define CRUnCTRL_VINSEL(x) ((x) << 0)
+
+/* CRU Interrupt Enable Register */
+#define CRUnIE 0x4
+#define CRUnIE_EFE BIT(17)
+
+/* CRU Interrupt Status Register */
+#define CRUnINTS 0x8
+#define CRUnINTS_SFS BIT(16)
+
+/* CRU Reset Register */
+#define CRUnRST 0xc
+#define CRUnRST_VRESETN BIT(0)
+
+/* Memory Bank Base Address (Lower) Register for CRU Image Data */
+#define AMnMBxADDRL(x) (0x100 + ((x) * 8))
+
+/* Memory Bank Base Address (Higher) Register for CRU Image Data */
+#define AMnMBxADDRH(x) (0x104 + ((x) * 8))
+
+/* Memory Bank Enable Register for CRU Image Data */
+#define AMnMBVALID 0x148
+#define AMnMBVALID_MBVALID(x) GENMASK(x, 0)
+
+/* Memory Bank Status Register for CRU Image Data */
+#define AMnMBS 0x14c
+#define AMnMBS_MBSTS 0x7
+
+/* AXI Master Transfer Setting Register for CRU Image Data */
+#define AMnAXIATTR 0x158
+#define AMnAXIATTR_AXILEN_MASK GENMASK(3, 0)
+#define AMnAXIATTR_AXILEN (0xf)
+
+/* AXI Master FIFO Pointer Register for CRU Image Data */
+#define AMnFIFOPNTR 0x168
+#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0)
+#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16)
+
+/* AXI Master Transfer Stop Register for CRU Image Data */
+#define AMnAXISTP 0x174
+#define AMnAXISTP_AXI_STOP BIT(0)
+
+/* AXI Master Transfer Stop Status Register for CRU Image Data */
+#define AMnAXISTPACK 0x178
+#define AMnAXISTPACK_AXI_STOP_ACK BIT(0)
+
+/* CRU Image Processing Enable Register */
+#define ICnEN 0x200
+#define ICnEN_ICEN BIT(0)
+
+/* CRU Image Processing Main Control Register */
+#define ICnMC 0x208
+#define ICnMC_CSCTHR BIT(5)
+#define ICnMC_INF(x) ((x) << 16)
+#define ICnMC_VCSEL(x) ((x) << 22)
+#define ICnMC_INF_MASK GENMASK(21, 16)
+
+/* CRU Module Status Register */
+#define ICnMS 0x254
+#define ICnMS_IA BIT(2)
+
+/* CRU Data Output Mode Register */
+#define ICnDMR 0x26c
+#define ICnDMR_YCMODE_UYVY (1 << 4)
+
+#endif /* __RZG2L_CRU_REGS_H__ */
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 811603f18af0..8b898ce05b84 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -8,6 +8,7 @@
#ifndef __RZG2L_CRU__
#define __RZG2L_CRU__
+#include <linux/irqreturn.h>
#include <linux/reset.h>
#include <media/v4l2-async.h>
@@ -30,6 +31,11 @@
#define RZG2L_CRU_MIN_INPUT_HEIGHT 240
#define RZG2L_CRU_MAX_INPUT_HEIGHT 4095
+enum rzg2l_csi2_pads {
+ RZG2L_CRU_IP_SINK = 0,
+ RZG2L_CRU_IP_SOURCE,
+};
+
/**
* enum rzg2l_cru_dma_state - DMA states
* @RZG2L_CRU_DMA_STOPPED: No operation in progress
@@ -47,7 +53,6 @@ enum rzg2l_cru_dma_state {
struct rzg2l_cru_csi {
struct v4l2_async_connection *asd;
struct v4l2_subdev *subdev;
- u32 channel;
};
struct rzg2l_cru_ip {
@@ -58,6 +63,24 @@ struct rzg2l_cru_ip {
};
/**
+ * struct rzg2l_cru_ip_format - CRU IP format
+ * @code: Media bus code
+ * @datatype: MIPI CSI2 data type
+ * @format: 4CC format identifier (V4L2_PIX_FMT_*)
+ * @icndmr: ICnDMR register value
+ * @bpp: bytes per pixel
+ * @yuv: Flag to indicate whether the format is YUV-based.
+ */
+struct rzg2l_cru_ip_format {
+ u32 code;
+ u32 datatype;
+ u32 format;
+ u32 icndmr;
+ u8 bpp;
+ bool yuv;
+};
+
+/**
* struct rzg2l_cru_dev - Renesas CRU device structure
* @dev: (OF) device
* @base: device I/O register space remapped to virtual memory
@@ -68,8 +91,6 @@ struct rzg2l_cru_ip {
*
* @vclk: CRU Main clock
*
- * @image_conv_irq: Holds image conversion interrupt number
- *
* @vdev: V4L2 video device associated with CRU
* @v4l2_dev: V4L2 device
* @num_buf: Holds the current number of buffers enabled
@@ -105,8 +126,6 @@ struct rzg2l_cru_dev {
struct clk *vclk;
- int image_conv_irq;
-
struct video_device vdev;
struct v4l2_device v4l2_dev;
u8 num_buf;
@@ -133,9 +152,6 @@ struct rzg2l_cru_dev {
struct v4l2_pix_format format;
};
-void rzg2l_cru_vclk_unprepare(struct rzg2l_cru_dev *cru);
-int rzg2l_cru_vclk_prepare(struct rzg2l_cru_dev *cru);
-
int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru);
void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru);
@@ -144,6 +160,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
+irqreturn_t rzg2l_cru_irq(int irq, void *data);
const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
@@ -151,4 +168,8 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru);
void rzg2l_cru_ip_subdev_unregister(struct rzg2l_cru_dev *cru);
struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru);
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code);
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format);
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
+
#endif
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index d20f4eff93a4..881e910dce02 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -108,6 +108,7 @@ struct rzg2l_csi2 {
struct reset_control *presetn;
struct reset_control *cmn_rstb;
struct clk *sysclk;
+ struct clk *vclk;
unsigned long vclk_rate;
struct v4l2_subdev subdev;
@@ -182,12 +183,15 @@ static const struct rzg2l_csi2_timings rzg2l_csi2_global_timings[] = {
struct rzg2l_csi2_format {
u32 code;
- unsigned int datatype;
unsigned int bpp;
};
static const struct rzg2l_csi2_format rzg2l_csi2_formats[] = {
- { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 },
+ { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16 },
+ { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, },
+ { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, },
+ { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, },
+ { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, },
};
static inline struct rzg2l_csi2 *sd_to_csi2(struct v4l2_subdev *sd)
@@ -361,7 +365,7 @@ static int rzg2l_csi2_dphy_setting(struct v4l2_subdev *sd, bool on)
return rzg2l_csi2_dphy_disable(csi2);
}
-static void rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2)
+static int rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2)
{
unsigned long vclk_rate = csi2->vclk_rate / HZ_PER_MHZ;
u32 frrskw, frrclk, frrskw_coeff, frrclk_coeff;
@@ -386,11 +390,15 @@ static void rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2)
rzg2l_csi2_write(csi2, CSI2nDTEL, 0xf778ff0f);
rzg2l_csi2_write(csi2, CSI2nDTEH, 0x00ffff1f);
+ clk_disable_unprepare(csi2->vclk);
+
/* Enable LINK reception */
rzg2l_csi2_write(csi2, CSI2nMCT3, CSI2nMCT3_RXEN);
+
+ return clk_prepare_enable(csi2->vclk);
}
-static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2)
+static int rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2)
{
unsigned int timeout = VSRSTS_RETRIES;
@@ -409,18 +417,21 @@ static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2)
if (!timeout)
dev_err(csi2->dev, "Clearing CSI2nRTST.VSRSTS timed out\n");
+
+ return 0;
}
static int rzg2l_csi2_mipi_link_setting(struct v4l2_subdev *sd, bool on)
{
struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
+ int ret;
if (on)
- rzg2l_csi2_mipi_link_enable(csi2);
+ ret = rzg2l_csi2_mipi_link_enable(csi2);
else
- rzg2l_csi2_mipi_link_disable(csi2);
+ ret = rzg2l_csi2_mipi_link_disable(csi2);
- return 0;
+ return ret;
}
static int rzg2l_csi2_s_stream(struct v4l2_subdev *sd, int enable)
@@ -566,6 +577,9 @@ static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index != 0)
return -EINVAL;
+ if (!rzg2l_csi2_code_to_fmt(fse->code))
+ return -EINVAL;
+
fse->min_width = RZG2L_CSI2_MIN_WIDTH;
fse->min_height = RZG2L_CSI2_MIN_HEIGHT;
fse->max_width = RZG2L_CSI2_MAX_WIDTH;
@@ -574,6 +588,25 @@ static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
+static int rzg2l_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
+ struct media_pad *remote_pad;
+
+ if (!csi2->remote_source)
+ return -ENODEV;
+
+ remote_pad = media_pad_remote_pad_unique(&csi2->pads[RZG2L_CSI2_SINK]);
+ if (IS_ERR(remote_pad)) {
+ dev_err(csi2->dev, "can't get source pad of %s (%ld)\n",
+ csi2->remote_source->name, PTR_ERR(remote_pad));
+ return PTR_ERR(remote_pad);
+ }
+ return v4l2_subdev_call(csi2->remote_source, pad, get_frame_desc,
+ remote_pad->index, fd);
+}
+
static const struct v4l2_subdev_video_ops rzg2l_csi2_video_ops = {
.s_stream = rzg2l_csi2_s_stream,
.pre_streamon = rzg2l_csi2_pre_streamon,
@@ -585,6 +618,7 @@ static const struct v4l2_subdev_pad_ops rzg2l_csi2_pad_ops = {
.enum_frame_size = rzg2l_csi2_enum_frame_size,
.set_fmt = rzg2l_csi2_set_format,
.get_fmt = v4l2_subdev_get_fmt,
+ .get_frame_desc = rzg2l_csi2_get_frame_desc,
};
static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = {
@@ -731,7 +765,6 @@ static const struct media_entity_operations rzg2l_csi2_entity_ops = {
static int rzg2l_csi2_probe(struct platform_device *pdev)
{
struct rzg2l_csi2 *csi2;
- struct clk *vclk;
int ret;
csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
@@ -757,12 +790,11 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(csi2->sysclk),
"Failed to get system clk\n");
- vclk = clk_get(&pdev->dev, "video");
- if (IS_ERR(vclk))
- return dev_err_probe(&pdev->dev, PTR_ERR(vclk),
+ csi2->vclk = devm_clk_get(&pdev->dev, "video");
+ if (IS_ERR(csi2->vclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(csi2->vclk),
"Failed to get video clock\n");
- csi2->vclk_rate = clk_get_rate(vclk);
- clk_put(vclk);
+ csi2->vclk_rate = clk_get_rate(csi2->vclk);
csi2->dev = &pdev->dev;
@@ -789,14 +821,17 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
csi2->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
csi2->subdev.entity.ops = &rzg2l_csi2_entity_ops;
- csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
+ csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
/*
* TODO: RZ/G2L CSI2 supports 4 virtual channels, as virtual
* channels should be implemented by streams API which is under
* development lets hardcode to VC0 for now.
*/
- csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&csi2->subdev.entity, 2, csi2->pads);
+ csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ ret = media_entity_pads_init(&csi2->subdev.entity, ARRAY_SIZE(csi2->pads),
+ csi2->pads);
if (ret)
goto error_pm;
@@ -834,7 +869,7 @@ static void rzg2l_csi2_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused rzg2l_csi2_pm_runtime_suspend(struct device *dev)
+static int rzg2l_csi2_pm_runtime_suspend(struct device *dev)
{
struct rzg2l_csi2 *csi2 = dev_get_drvdata(dev);
@@ -843,7 +878,7 @@ static int __maybe_unused rzg2l_csi2_pm_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rzg2l_csi2_pm_runtime_resume(struct device *dev)
+static int rzg2l_csi2_pm_runtime_resume(struct device *dev)
{
struct rzg2l_csi2 *csi2 = dev_get_drvdata(dev);
@@ -851,21 +886,23 @@ static int __maybe_unused rzg2l_csi2_pm_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops rzg2l_csi2_pm_ops = {
- SET_RUNTIME_PM_OPS(rzg2l_csi2_pm_runtime_suspend, rzg2l_csi2_pm_runtime_resume, NULL)
+ RUNTIME_PM_OPS(rzg2l_csi2_pm_runtime_suspend,
+ rzg2l_csi2_pm_runtime_resume, NULL)
};
static const struct of_device_id rzg2l_csi2_of_table[] = {
{ .compatible = "renesas,rzg2l-csi2", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, rzg2l_csi2_of_table);
static struct platform_driver rzg2l_csi2_pdrv = {
- .remove_new = rzg2l_csi2_remove,
+ .remove = rzg2l_csi2_remove,
.probe = rzg2l_csi2_probe,
.driver = {
.name = "rzg2l-csi2",
.of_match_table = rzg2l_csi2_of_table,
- .pm = &rzg2l_csi2_pm_ops,
+ .pm = pm_ptr(&rzg2l_csi2_pm_ops),
},
};
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
index 9f351a05893e..76a2b451f1da 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
@@ -5,24 +5,56 @@
* Copyright (C) 2022 Renesas Electronics Corp.
*/
-#include "rzg2l-cru.h"
+#include <linux/delay.h>
+#include <media/mipi-csi2.h>
-struct rzg2l_cru_ip_format {
- u32 code;
- unsigned int datatype;
- unsigned int bpp;
-};
+#include "rzg2l-cru.h"
+#include "rzg2l-cru-regs.h"
static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = {
- { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 },
+ {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .datatype = MIPI_CSI2_DT_YUV422_8B,
+ .format = V4L2_PIX_FMT_UYVY,
+ .bpp = 2,
+ .icndmr = ICnDMR_YCMODE_UYVY,
+ .yuv = true,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .format = V4L2_PIX_FMT_SBGGR8,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .bpp = 1,
+ .icndmr = 0,
+ .yuv = false,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .format = V4L2_PIX_FMT_SGBRG8,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .bpp = 1,
+ .icndmr = 0,
+ .yuv = false,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .format = V4L2_PIX_FMT_SGRBG8,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .bpp = 1,
+ .icndmr = 0,
+ .yuv = false,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .format = V4L2_PIX_FMT_SRGGB8,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .bpp = 1,
+ .icndmr = 0,
+ .yuv = false,
+ },
};
-enum rzg2l_csi2_pads {
- RZG2L_CRU_IP_SINK = 0,
- RZG2L_CRU_IP_SOURCE,
-};
-
-static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code)
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code)
{
unsigned int i;
@@ -33,6 +65,26 @@ static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int c
return NULL;
}
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) {
+ if (rzg2l_cru_ip_formats[i].format == format)
+ return &rzg2l_cru_ip_formats[i];
+ }
+
+ return NULL;
+}
+
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index)
+{
+ if (index >= ARRAY_SIZE(rzg2l_cru_ip_formats))
+ return NULL;
+
+ return &rzg2l_cru_ip_formats[index];
+}
+
struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru)
{
struct v4l2_subdev_state *state;
@@ -71,26 +123,17 @@ static int rzg2l_cru_ip_s_stream(struct v4l2_subdev *sd, int enable)
if (ret)
return ret;
+ fsleep(1000);
+
ret = rzg2l_cru_start_image_processing(cru);
if (ret) {
v4l2_subdev_call(cru->ip.remote, video, post_streamoff);
return ret;
}
- rzg2l_cru_vclk_unprepare(cru);
-
ret = v4l2_subdev_call(cru->ip.remote, video, s_stream, enable);
- if (ret == -ENOIOCTLCMD)
- ret = 0;
- if (!ret) {
- ret = rzg2l_cru_vclk_prepare(cru);
- if (!ret)
- return 0;
- } else {
- /* enable back vclk so that s_stream in error path disables it */
- if (rzg2l_cru_vclk_prepare(cru))
- dev_err(cru->dev, "Failed to enable vclk\n");
- }
+ if (!ret || ret == -ENOIOCTLCMD)
+ return 0;
s_stream_ret = ret;
@@ -157,7 +200,7 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index != 0)
return -EINVAL;
- if (fse->code != MEDIA_BUS_FMT_UYVY8_1X16)
+ if (!rzg2l_cru_ip_code_to_fmt(fse->code))
return -EINVAL;
fse->min_width = RZG2L_CRU_MIN_INPUT_WIDTH;
@@ -225,8 +268,10 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru)
ip->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
ip->subdev.entity.ops = &rzg2l_cru_ip_entity_ops;
- ip->pads[0].flags = MEDIA_PAD_FL_SINK;
- ip->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ ip->pads[RZG2L_CRU_IP_SINK].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ ip->pads[RZG2L_CRU_IP_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
+ MEDIA_PAD_FL_MUST_CONNECT;
ret = media_entity_pads_init(&ip->subdev.entity, 2, ip->pads);
if (ret)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index d0ffa90bc656..cd69c8a686d3 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -15,75 +15,12 @@
#include <linux/delay.h>
#include <linux/pm_runtime.h>
+#include <media/mipi-csi2.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-dma-contig.h>
#include "rzg2l-cru.h"
-
-/* HW CRU Registers Definition */
-
-/* CRU Control Register */
-#define CRUnCTRL 0x0
-#define CRUnCTRL_VINSEL(x) ((x) << 0)
-
-/* CRU Interrupt Enable Register */
-#define CRUnIE 0x4
-#define CRUnIE_EFE BIT(17)
-
-/* CRU Interrupt Status Register */
-#define CRUnINTS 0x8
-#define CRUnINTS_SFS BIT(16)
-
-/* CRU Reset Register */
-#define CRUnRST 0xc
-#define CRUnRST_VRESETN BIT(0)
-
-/* Memory Bank Base Address (Lower) Register for CRU Image Data */
-#define AMnMBxADDRL(x) (0x100 + ((x) * 8))
-
-/* Memory Bank Base Address (Higher) Register for CRU Image Data */
-#define AMnMBxADDRH(x) (0x104 + ((x) * 8))
-
-/* Memory Bank Enable Register for CRU Image Data */
-#define AMnMBVALID 0x148
-#define AMnMBVALID_MBVALID(x) GENMASK(x, 0)
-
-/* Memory Bank Status Register for CRU Image Data */
-#define AMnMBS 0x14c
-#define AMnMBS_MBSTS 0x7
-
-/* AXI Master FIFO Pointer Register for CRU Image Data */
-#define AMnFIFOPNTR 0x168
-#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0)
-#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16)
-
-/* AXI Master Transfer Stop Register for CRU Image Data */
-#define AMnAXISTP 0x174
-#define AMnAXISTP_AXI_STOP BIT(0)
-
-/* AXI Master Transfer Stop Status Register for CRU Image Data */
-#define AMnAXISTPACK 0x178
-#define AMnAXISTPACK_AXI_STOP_ACK BIT(0)
-
-/* CRU Image Processing Enable Register */
-#define ICnEN 0x200
-#define ICnEN_ICEN BIT(0)
-
-/* CRU Image Processing Main Control Register */
-#define ICnMC 0x208
-#define ICnMC_CSCTHR BIT(5)
-#define ICnMC_INF_YUV8_422 (0x1e << 16)
-#define ICnMC_INF_USER (0x30 << 16)
-#define ICnMC_VCSEL(x) ((x) << 22)
-#define ICnMC_INF_MASK GENMASK(21, 16)
-
-/* CRU Module Status Register */
-#define ICnMS 0x254
-#define ICnMS_IA BIT(2)
-
-/* CRU Data Output Mode Register */
-#define ICnDMR 0x26c
-#define ICnDMR_YCMODE_UYVY (1 << 4)
+#include "rzg2l-cru-regs.h"
#define RZG2L_TIMEOUT_MS 100
#define RZG2L_RETRIES 10
@@ -184,46 +121,6 @@ static void rzg2l_cru_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&cru->qlock, flags);
}
-static int rzg2l_cru_mc_validate_format(struct rzg2l_cru_dev *cru,
- struct v4l2_subdev *sd,
- struct media_pad *pad)
-{
- struct v4l2_subdev_format fmt = {
- .which = V4L2_SUBDEV_FORMAT_ACTIVE,
- };
-
- fmt.pad = pad->index;
- if (v4l2_subdev_call_state_active(sd, pad, get_fmt, &fmt))
- return -EPIPE;
-
- switch (fmt.format.code) {
- case MEDIA_BUS_FMT_UYVY8_1X16:
- break;
- default:
- return -EPIPE;
- }
-
- switch (fmt.format.field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- case V4L2_FIELD_NONE:
- case V4L2_FIELD_INTERLACED_TB:
- case V4L2_FIELD_INTERLACED_BT:
- case V4L2_FIELD_INTERLACED:
- case V4L2_FIELD_SEQ_TB:
- case V4L2_FIELD_SEQ_BT:
- break;
- default:
- return -EPIPE;
- }
-
- if (fmt.format.width != cru->format.width ||
- fmt.format.height != cru->format.height)
- return -EPIPE;
-
- return 0;
-}
-
static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
int slot, dma_addr_t addr)
{
@@ -278,6 +175,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
{
unsigned int slot;
+ u32 amnaxiattr;
/*
* Set image data memory banks.
@@ -287,55 +185,47 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
for (slot = 0; slot < cru->num_buf; slot++)
rzg2l_cru_fill_hw_slot(cru, slot);
+
+ /* Set AXI burst max length to recommended setting */
+ amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
+ amnaxiattr |= AMnAXIATTR_AXILEN;
+ rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
}
-static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, bool *input_is_yuv,
- struct v4l2_mbus_framefmt *ip_sd_fmt)
+static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
+ const struct rzg2l_cru_ip_format *ip_fmt,
+ u8 csi_vc)
{
- u32 icnmc;
-
- switch (ip_sd_fmt->code) {
- case MEDIA_BUS_FMT_UYVY8_1X16:
- icnmc = ICnMC_INF_YUV8_422;
- *input_is_yuv = true;
- break;
- default:
- *input_is_yuv = false;
- icnmc = ICnMC_INF_USER;
- break;
- }
+ u32 icnmc = ICnMC_INF(ip_fmt->datatype);
icnmc |= (rzg2l_cru_read(cru, ICnMC) & ~ICnMC_INF_MASK);
/* Set virtual channel CSI2 */
- icnmc |= ICnMC_VCSEL(cru->csi.channel);
+ icnmc |= ICnMC_VCSEL(csi_vc);
rzg2l_cru_write(cru, ICnMC, icnmc);
}
static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
- struct v4l2_mbus_framefmt *ip_sd_fmt)
+ struct v4l2_mbus_framefmt *ip_sd_fmt,
+ u8 csi_vc)
{
- bool output_is_yuv = false;
- bool input_is_yuv = false;
- u32 icndmr;
+ const struct rzg2l_cru_ip_format *cru_video_fmt;
+ const struct rzg2l_cru_ip_format *cru_ip_fmt;
- rzg2l_cru_csi2_setup(cru, &input_is_yuv, ip_sd_fmt);
+ cru_ip_fmt = rzg2l_cru_ip_code_to_fmt(ip_sd_fmt->code);
+ rzg2l_cru_csi2_setup(cru, cru_ip_fmt, csi_vc);
/* Output format */
- switch (cru->format.pixelformat) {
- case V4L2_PIX_FMT_UYVY:
- icndmr = ICnDMR_YCMODE_UYVY;
- output_is_yuv = true;
- break;
- default:
+ cru_video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat);
+ if (!cru_video_fmt) {
dev_err(cru->dev, "Invalid pixelformat (0x%x)\n",
cru->format.pixelformat);
return -EINVAL;
}
/* If input and output use same colorspace, do bypass mode */
- if (output_is_yuv == input_is_yuv)
+ if (cru_ip_fmt->yuv == cru_video_fmt->yuv)
rzg2l_cru_write(cru, ICnMC,
rzg2l_cru_read(cru, ICnMC) | ICnMC_CSCTHR);
else
@@ -343,7 +233,7 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
rzg2l_cru_read(cru, ICnMC) & (~ICnMC_CSCTHR));
/* Set output data format */
- rzg2l_cru_write(cru, ICnDMR, icndmr);
+ rzg2l_cru_write(cru, ICnDMR, cru_video_fmt->icndmr);
return 0;
}
@@ -422,20 +312,48 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
spin_unlock_irqrestore(&cru->qlock, flags);
}
+static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
+{
+ struct v4l2_mbus_frame_desc fd = { };
+ struct media_pad *remote_pad;
+ int ret;
+
+ remote_pad = media_pad_remote_pad_unique(&cru->ip.pads[RZG2L_CRU_IP_SINK]);
+ ret = v4l2_subdev_call(cru->ip.remote, pad, get_frame_desc, remote_pad->index, &fd);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(cru->dev, "get_frame_desc failed on IP remote subdev\n");
+ return ret;
+ }
+ /* If remote subdev does not implement .get_frame_desc default to VC0. */
+ if (ret == -ENOIOCTLCMD)
+ return 0;
+
+ if (fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+ dev_err(cru->dev, "get_frame_desc returned invalid bus type %d\n", fd.type);
+ return -EINVAL;
+ }
+
+ if (!fd.num_entries) {
+ dev_err(cru->dev, "get_frame_desc returned zero entries\n");
+ return -EINVAL;
+ }
+
+ return fd.entry[0].bus.csi2.vc;
+}
+
int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
{
struct v4l2_mbus_framefmt *fmt = rzg2l_cru_ip_get_src_fmt(cru);
unsigned long flags;
+ u8 csi_vc;
int ret;
- spin_lock_irqsave(&cru->qlock, flags);
-
- /* Initialize image convert */
- ret = rzg2l_cru_initialize_image_conv(cru, fmt);
- if (ret) {
- spin_unlock_irqrestore(&cru->qlock, flags);
+ ret = rzg2l_cru_get_virtual_channel(cru);
+ if (ret < 0)
return ret;
- }
+ csi_vc = ret;
+
+ spin_lock_irqsave(&cru->qlock, flags);
/* Select a video input */
rzg2l_cru_write(cru, CRUnCTRL, CRUnCTRL_VINSEL(0));
@@ -450,6 +368,13 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
/* Initialize the AXI master */
rzg2l_cru_initialize_axi(cru);
+ /* Initialize image convert */
+ ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
+ if (ret) {
+ spin_unlock_irqrestore(&cru->qlock, flags);
+ return ret;
+ }
+
/* Enable interrupt */
rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE);
@@ -461,16 +386,6 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
return 0;
}
-void rzg2l_cru_vclk_unprepare(struct rzg2l_cru_dev *cru)
-{
- clk_disable_unprepare(cru->vclk);
-}
-
-int rzg2l_cru_vclk_prepare(struct rzg2l_cru_dev *cru)
-{
- return clk_prepare_enable(cru->vclk);
-}
-
static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
{
struct media_pipeline *pipe;
@@ -499,39 +414,20 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
video_device_pipeline_stop(&cru->vdev);
- pm_runtime_put_sync(cru->dev);
- clk_disable_unprepare(cru->vclk);
-
return stream_off_ret;
}
- ret = pm_runtime_resume_and_get(cru->dev);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(cru->vclk);
- if (ret)
- goto err_pm_put;
-
- ret = rzg2l_cru_mc_validate_format(cru, sd, pad);
- if (ret)
- goto err_vclk_disable;
-
pipe = media_entity_pipeline(&sd->entity) ? : &cru->vdev.pipe;
ret = video_device_pipeline_start(&cru->vdev, pipe);
if (ret)
- goto err_vclk_disable;
+ return ret;
ret = v4l2_subdev_call(sd, video, pre_streamon, 0);
- if (ret == -ENOIOCTLCMD)
- ret = 0;
- if (ret)
+ if (ret && ret != -ENOIOCTLCMD)
goto pipe_line_stop;
ret = v4l2_subdev_call(sd, video, s_stream, 1);
- if (ret == -ENOIOCTLCMD)
- ret = 0;
- if (ret)
+ if (ret && ret != -ENOIOCTLCMD)
goto err_s_stream;
return 0;
@@ -542,12 +438,6 @@ err_s_stream:
pipe_line_stop:
video_device_pipeline_stop(&cru->vdev);
-err_vclk_disable:
- clk_disable_unprepare(cru->vclk);
-
-err_pm_put:
- pm_runtime_put_sync(cru->dev);
-
return ret;
}
@@ -558,7 +448,7 @@ static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru)
rzg2l_cru_set_stream(cru, 0);
}
-static irqreturn_t rzg2l_cru_irq(int irq, void *data)
+irqreturn_t rzg2l_cru_irq(int irq, void *data)
{
struct rzg2l_cru_dev *cru = data;
unsigned int handled = 0;
@@ -646,35 +536,36 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
int ret;
+ ret = pm_runtime_resume_and_get(cru->dev);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(cru->vclk);
+ if (ret)
+ goto err_pm_put;
+
/* Release reset state */
ret = reset_control_deassert(cru->aresetn);
if (ret) {
dev_err(cru->dev, "failed to deassert aresetn\n");
- return ret;
+ goto err_vclk_disable;
}
ret = reset_control_deassert(cru->presetn);
if (ret) {
reset_control_assert(cru->aresetn);
dev_err(cru->dev, "failed to deassert presetn\n");
- return ret;
+ goto assert_aresetn;
}
- ret = request_irq(cru->image_conv_irq, rzg2l_cru_irq,
- IRQF_SHARED, KBUILD_MODNAME, cru);
- if (ret) {
- dev_err(cru->dev, "failed to request irq\n");
- goto assert_resets;
- }
-
- /* Allocate scratch buffer. */
+ /* Allocate scratch buffer */
cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage,
&cru->scratch_phys, GFP_KERNEL);
if (!cru->scratch) {
return_unused_buffers(cru, VB2_BUF_STATE_QUEUED);
dev_err(cru->dev, "Failed to allocate scratch buffer\n");
ret = -ENOMEM;
- goto free_image_conv_irq;
+ goto assert_presetn;
}
cru->sequence = 0;
@@ -693,13 +584,18 @@ out:
if (ret)
dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch,
cru->scratch_phys);
-free_image_conv_irq:
- free_irq(cru->image_conv_irq, cru);
-
-assert_resets:
+assert_presetn:
reset_control_assert(cru->presetn);
+
+assert_aresetn:
reset_control_assert(cru->aresetn);
+err_vclk_disable:
+ clk_disable_unprepare(cru->vclk);
+
+err_pm_put:
+ pm_runtime_put_sync(cru->dev);
+
return ret;
}
@@ -713,10 +609,11 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq)
dma_free_coherent(cru->dev, cru->format.sizeimage,
cru->scratch, cru->scratch_phys);
- free_irq(cru->image_conv_irq, cru);
- reset_control_assert(cru->presetn);
-
return_unused_buffers(cru, VB2_BUF_STATE_ERROR);
+
+ reset_control_assert(cru->presetn);
+ clk_disable_unprepare(cru->vclk);
+ pm_runtime_put_sync(cru->dev);
}
static const struct vb2_ops rzg2l_cru_qops = {
@@ -725,8 +622,6 @@ static const struct vb2_ops rzg2l_cru_qops = {
.buf_queue = rzg2l_cru_buffer_queue,
.start_streaming = rzg2l_cru_start_streaming_vq,
.stop_streaming = rzg2l_cru_stop_streaming_vq,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru)
@@ -788,46 +683,16 @@ error:
* V4L2 stuff
*/
-static const struct v4l2_format_info rzg2l_cru_formats[] = {
- {
- .format = V4L2_PIX_FMT_UYVY,
- .bpp[0] = 2,
- },
-};
-
-const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(rzg2l_cru_formats); i++)
- if (rzg2l_cru_formats[i].format == format)
- return rzg2l_cru_formats + i;
-
- return NULL;
-}
-
-static u32 rzg2l_cru_format_bytesperline(struct v4l2_pix_format *pix)
-{
- const struct v4l2_format_info *fmt;
-
- fmt = rzg2l_cru_format_from_pixel(pix->pixelformat);
-
- if (WARN_ON(!fmt))
- return -EINVAL;
-
- return pix->width * fmt->bpp[0];
-}
-
-static u32 rzg2l_cru_format_sizeimage(struct v4l2_pix_format *pix)
-{
- return pix->bytesperline * pix->height;
-}
-
static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
struct v4l2_pix_format *pix)
{
- if (!rzg2l_cru_format_from_pixel(pix->pixelformat))
+ const struct rzg2l_cru_ip_format *fmt;
+
+ fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat);
+ if (!fmt) {
pix->pixelformat = RZG2L_CRU_DEFAULT_FORMAT;
+ fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat);
+ }
switch (pix->field) {
case V4L2_FIELD_TOP:
@@ -846,8 +711,8 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
v4l_bound_align_image(&pix->width, 320, RZG2L_CRU_MAX_INPUT_WIDTH, 1,
&pix->height, 240, RZG2L_CRU_MAX_INPUT_HEIGHT, 2, 0);
- pix->bytesperline = rzg2l_cru_format_bytesperline(pix);
- pix->sizeimage = rzg2l_cru_format_sizeimage(pix);
+ pix->bytesperline = pix->width * fmt->bpp;
+ pix->sizeimage = pix->bytesperline * pix->height;
dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n",
pix->width, pix->height, pix->bytesperline, pix->sizeimage);
@@ -918,10 +783,13 @@ static int rzg2l_cru_g_fmt_vid_cap(struct file *file, void *priv,
static int rzg2l_cru_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- if (f->index >= ARRAY_SIZE(rzg2l_cru_formats))
+ const struct rzg2l_cru_ip_format *fmt;
+
+ fmt = rzg2l_cru_ip_index_to_fmt(f->index);
+ if (!fmt)
return -EINVAL;
- f->pixelformat = rzg2l_cru_formats[f->index].format;
+ f->pixelformat = fmt->format;
return 0;
}
@@ -997,6 +865,43 @@ static const struct v4l2_file_operations rzg2l_cru_fops = {
.read = vb2_fop_read,
};
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static int rzg2l_cru_video_link_validate(struct media_link *link)
+{
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ const struct rzg2l_cru_ip_format *video_fmt;
+ struct v4l2_subdev *subdev;
+ struct rzg2l_cru_dev *cru;
+ int ret;
+
+ subdev = media_entity_to_v4l2_subdev(link->source->entity);
+ fmt.pad = link->source->index;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret < 0)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ cru = container_of(media_entity_to_video_device(link->sink->entity),
+ struct rzg2l_cru_dev, vdev);
+ video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat);
+
+ if (fmt.format.width != cru->format.width ||
+ fmt.format.height != cru->format.height ||
+ fmt.format.field != cru->format.field ||
+ video_fmt->code != fmt.format.code)
+ return -EPIPE;
+
+ return 0;
+}
+
+static const struct media_entity_operations rzg2l_cru_video_media_ops = {
+ .link_validate = rzg2l_cru_video_link_validate,
+};
+
static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru)
{
struct video_device *vdev = &cru->vdev;
@@ -1008,6 +913,7 @@ static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru)
vdev->lock = &cru->lock;
vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
vdev->device_caps |= V4L2_CAP_IO_MC;
+ vdev->entity.ops = &rzg2l_cru_video_media_ops;
vdev->fops = &rzg2l_cru_fops;
vdev->ioctl_ops = &rzg2l_cru_ioctl_ops;
diff --git a/drivers/media/platform/renesas/sh_vou.c b/drivers/media/platform/renesas/sh_vou.c
index 1e74dd601c2b..4ad7ae188d5b 100644
--- a/drivers/media/platform/renesas/sh_vou.c
+++ b/drivers/media/platform/renesas/sh_vou.c
@@ -360,8 +360,6 @@ static const struct vb2_ops sh_vou_qops = {
.buf_queue = sh_vou_buf_queue,
.start_streaming = sh_vou_start_streaming,
.stop_streaming = sh_vou_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* Video IOCTLs */
@@ -1359,7 +1357,7 @@ static void sh_vou_remove(struct platform_device *pdev)
}
static struct platform_driver sh_vou = {
- .remove_new = sh_vou_remove,
+ .remove = sh_vou_remove,
.driver = {
.name = "sh-vou",
},
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_brx.c b/drivers/media/platform/renesas/vsp1/vsp1_brx.c
index a8535c6e2c46..5dee0490c593 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_brx.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_brx.c
@@ -96,13 +96,6 @@ static int brx_enum_frame_size(struct v4l2_subdev *subdev,
return 0;
}
-static struct v4l2_rect *brx_get_compose(struct vsp1_brx *brx,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad)
-{
- return v4l2_subdev_state_get_compose(sd_state, pad);
-}
-
static void brx_try_format(struct vsp1_brx *brx,
struct v4l2_subdev_state *sd_state,
unsigned int pad, struct v4l2_mbus_framefmt *fmt)
@@ -119,8 +112,8 @@ static void brx_try_format(struct vsp1_brx *brx,
default:
/* The BRx can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&brx->entity, sd_state,
- BRX_PAD_SINK(0));
+ format = v4l2_subdev_state_get_format(sd_state,
+ BRX_PAD_SINK(0));
fmt->code = format->code;
break;
}
@@ -150,14 +143,14 @@ static int brx_set_format(struct v4l2_subdev *subdev,
brx_try_format(brx, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&brx->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format;
/* Reset the compose rectangle. */
if (fmt->pad != brx->entity.source_pad) {
struct v4l2_rect *compose;
- compose = brx_get_compose(brx, state, fmt->pad);
+ compose = v4l2_subdev_state_get_compose(state, fmt->pad);
compose->left = 0;
compose->top = 0;
compose->width = format->width;
@@ -169,8 +162,7 @@ static int brx_set_format(struct v4l2_subdev *subdev,
unsigned int i;
for (i = 0; i <= brx->entity.source_pad; ++i) {
- format = vsp1_entity_get_pad_format(&brx->entity,
- state, i);
+ format = v4l2_subdev_state_get_format(state, i);
format->code = fmt->format.code;
}
}
@@ -205,7 +197,7 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&brx->entity.lock);
- sel->r = *brx_get_compose(brx, state, sel->pad);
+ sel->r = *v4l2_subdev_state_get_compose(state, sel->pad);
mutex_unlock(&brx->entity.lock);
return 0;
@@ -242,8 +234,7 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
* The compose rectangle top left corner must be inside the output
* frame.
*/
- format = vsp1_entity_get_pad_format(&brx->entity, state,
- brx->entity.source_pad);
+ format = v4l2_subdev_state_get_format(state, brx->entity.source_pad);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -251,11 +242,11 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
* Scaling isn't supported, the compose rectangle size must be identical
* to the sink format size.
*/
- format = vsp1_entity_get_pad_format(&brx->entity, state, sel->pad);
+ format = v4l2_subdev_state_get_format(state, sel->pad);
sel->r.width = format->width;
sel->r.height = format->height;
- compose = brx_get_compose(brx, state, sel->pad);
+ compose = v4l2_subdev_state_get_compose(state, sel->pad);
*compose = sel->r;
done:
@@ -281,6 +272,7 @@ static const struct v4l2_subdev_ops brx_ops = {
*/
static void brx_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -290,8 +282,7 @@ static void brx_configure_stream(struct vsp1_entity *entity,
unsigned int flags;
unsigned int i;
- format = vsp1_entity_get_pad_format(&brx->entity, brx->entity.state,
- brx->entity.source_pad);
+ format = v4l2_subdev_state_get_format(state, brx->entity.source_pad);
/*
* The hardware is extremely flexible but we have no userspace API to
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_clu.c b/drivers/media/platform/renesas/vsp1/vsp1_clu.c
index 625776a9bda4..98645bd2a983 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_clu.c
@@ -170,6 +170,7 @@ static const struct v4l2_subdev_ops clu_ops = {
*/
static void clu_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -181,8 +182,7 @@ static void clu_configure_stream(struct vsp1_entity *entity,
* The yuv_mode can't be changed during streaming. Cache it internally
* for future runtime configuration calls.
*/
- format = vsp1_entity_get_pad_format(&clu->entity, clu->entity.state,
- CLU_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, CLU_PAD_SINK);
clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32;
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.c b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
index 9b087bd8df7d..b5d1f238f7be 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
@@ -317,7 +317,10 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1,
list_add_tail(&released_brx->list_pipe,
&pipe->entities);
- /* Add the BRx to the pipeline. */
+ /*
+ * Add the BRx to the pipeline, inserting it just before the
+ * WPF.
+ */
dev_dbg(vsp1->dev, "%s: pipe %u: acquired %s\n",
__func__, pipe->lif->index, BRX_NAME(brx));
@@ -326,7 +329,8 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1,
pipe->brx->sink = &pipe->output->entity;
pipe->brx->sink_pad = 0;
- list_add_tail(&pipe->brx->list_pipe, &pipe->entities);
+ list_add_tail(&pipe->brx->list_pipe,
+ &pipe->output->entity.list_pipe);
}
/*
@@ -420,7 +424,7 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1,
if (!rpf->entity.pipe) {
rpf->entity.pipe = pipe;
- list_add_tail(&rpf->entity.list_pipe, &pipe->entities);
+ list_add(&rpf->entity.list_pipe, &pipe->entities);
}
brx->inputs[i].rpf = rpf;
@@ -546,6 +550,9 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
struct vsp1_dl_body *dlb;
unsigned int dl_flags = 0;
+ vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[0],
+ drm_pipe->width, 0);
+
if (drm_pipe->force_brx_release)
dl_flags |= VSP1_DL_FRAME_END_INTERNAL;
if (pipe->output->writeback)
@@ -567,9 +574,11 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
}
vsp1_entity_route_setup(entity, pipe, dlb);
- vsp1_entity_configure_stream(entity, pipe, dl, dlb);
+ vsp1_entity_configure_stream(entity, entity->state, pipe,
+ dl, dlb);
vsp1_entity_configure_frame(entity, pipe, dl, dlb);
- vsp1_entity_configure_partition(entity, pipe, dl, dlb);
+ vsp1_entity_configure_partition(entity, pipe,
+ &pipe->part_table[0], dl, dlb);
}
vsp1_dl_list_commit(dl, dl_flags);
@@ -733,6 +742,8 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
if (ret < 0)
goto unlock;
+ vsp1_pipeline_dump(pipe, "LIF setup");
+
/* Enable the VSP1. */
ret = vsp1_device_get(vsp1);
if (ret < 0)
@@ -906,6 +917,9 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index,
}
vsp1_du_pipeline_setup_inputs(vsp1, pipe);
+
+ vsp1_pipeline_dump(pipe, "atomic update");
+
vsp1_du_pipeline_configure(pipe);
done:
@@ -959,6 +973,9 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
vsp1_pipeline_init(pipe);
+ pipe->partitions = 1;
+ pipe->part_table = &drm_pipe->partition;
+
pipe->frame_end = vsp1_du_pipeline_frame_end;
/*
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.h b/drivers/media/platform/renesas/vsp1/vsp1_drm.h
index ab8b7e3161a2..3fd95b53f27e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.h
@@ -20,6 +20,7 @@
/**
* struct vsp1_drm_pipeline - State for the API exposed to the DRM driver
* @pipe: the VSP1 pipeline used for display
+ * @partition: the pre-calculated partition used by the pipeline
* @width: output display width
* @height: output display height
* @force_brx_release: when set, release the BRx during the next reconfiguration
@@ -31,6 +32,7 @@
*/
struct vsp1_drm_pipeline {
struct vsp1_pipeline pipe;
+ struct vsp1_partition partition;
unsigned int width;
unsigned int height;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c
index 1aac44d68731..9fc6bf624a52 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c
@@ -1005,7 +1005,7 @@ MODULE_DEVICE_TABLE(of, vsp1_of_match);
static struct platform_driver vsp1_platform_driver = {
.probe = vsp1_probe,
- .remove_new = vsp1_remove,
+ .remove = vsp1_remove,
.driver = {
.name = "vsp1",
.pm = &vsp1_pm_ops,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
index 0a5a7f9cc870..8b8945bd8f10 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
@@ -70,12 +70,13 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity,
}
void vsp1_entity_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
if (entity->ops->configure_stream)
- entity->ops->configure_stream(entity, pipe, dl, dlb);
+ entity->ops->configure_stream(entity, state, pipe, dl, dlb);
}
void vsp1_entity_configure_frame(struct vsp1_entity *entity,
@@ -89,11 +90,13 @@ void vsp1_entity_configure_frame(struct vsp1_entity *entity,
void vsp1_entity_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
if (entity->ops->configure_partition)
- entity->ops->configure_partition(entity, pipe, dl, dlb);
+ entity->ops->configure_partition(entity, pipe, partition,
+ dl, dlb);
}
/* -----------------------------------------------------------------------------
@@ -127,49 +130,6 @@ vsp1_entity_get_state(struct vsp1_entity *entity,
}
}
-/**
- * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
- * @entity: the entity
- * @sd_state: the state storage
- * @pad: the pad number
- *
- * Return the format stored in the given configuration for an entity's pad. The
- * configuration can be an ACTIVE or TRY configuration.
- */
-struct v4l2_mbus_framefmt *
-vsp1_entity_get_pad_format(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad)
-{
- return v4l2_subdev_state_get_format(sd_state, pad);
-}
-
-/**
- * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
- * @entity: the entity
- * @sd_state: the state storage
- * @pad: the pad number
- * @target: the selection target
- *
- * Return the selection rectangle stored in the given configuration for an
- * entity's pad. The configuration can be an ACTIVE or TRY configuration. The
- * selection target can be COMPOSE or CROP.
- */
-struct v4l2_rect *
-vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, unsigned int target)
-{
- switch (target) {
- case V4L2_SEL_TGT_COMPOSE:
- return v4l2_subdev_state_get_compose(sd_state, pad);
- case V4L2_SEL_TGT_CROP:
- return v4l2_subdev_state_get_crop(sd_state, pad);
- default:
- return NULL;
- }
-}
-
/*
* vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
* @subdev: V4L2 subdevice
@@ -191,7 +151,7 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&entity->lock);
- fmt->format = *vsp1_entity_get_pad_format(entity, state, fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(state, fmt->pad);
mutex_unlock(&entity->lock);
return 0;
@@ -238,7 +198,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&entity->lock);
- format = vsp1_entity_get_pad_format(entity, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
code->code = format->code;
mutex_unlock(&entity->lock);
}
@@ -276,7 +236,7 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(entity, state, fse->pad);
+ format = v4l2_subdev_state_get_format(state, fse->pad);
mutex_lock(&entity->lock);
@@ -346,7 +306,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
goto done;
}
- format = vsp1_entity_get_pad_format(entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == entity->source_pad) {
/* The output format can't be modified. */
@@ -374,19 +334,17 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(entity, state, entity->source_pad);
+ format = v4l2_subdev_state_get_format(state, entity->source_pad);
*format = fmt->format;
/* Reset the crop and compose rectangles. */
- selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad,
- V4L2_SEL_TGT_CROP);
+ selection = v4l2_subdev_state_get_crop(state, fmt->pad);
selection->left = 0;
selection->top = 0;
selection->width = format->width;
selection->height = format->height;
- selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad,
- V4L2_SEL_TGT_COMPOSE);
+ selection = v4l2_subdev_state_get_compose(state, fmt->pad);
selection->left = 0;
selection->top = 0;
selection->width = format->width;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.h b/drivers/media/platform/renesas/vsp1/vsp1_entity.h
index 735f32dde4b5..1bcc9e27dfdc 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.h
@@ -19,7 +19,6 @@ struct vsp1_dl_body;
struct vsp1_dl_list;
struct vsp1_pipeline;
struct vsp1_partition;
-struct vsp1_partition_window;
enum vsp1_entity_type {
VSP1_ENTITY_BRS,
@@ -78,19 +77,30 @@ struct vsp1_route {
* configuration.
*/
struct vsp1_entity_operations {
- void (*destroy)(struct vsp1_entity *);
- void (*configure_stream)(struct vsp1_entity *, struct vsp1_pipeline *,
- struct vsp1_dl_list *, struct vsp1_dl_body *);
- void (*configure_frame)(struct vsp1_entity *, struct vsp1_pipeline *,
- struct vsp1_dl_list *, struct vsp1_dl_body *);
- void (*configure_partition)(struct vsp1_entity *,
- struct vsp1_pipeline *,
- struct vsp1_dl_list *,
- struct vsp1_dl_body *);
- unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *);
- void (*partition)(struct vsp1_entity *, struct vsp1_pipeline *,
- struct vsp1_partition *, unsigned int,
- struct vsp1_partition_window *);
+ void (*destroy)(struct vsp1_entity *entity);
+ void (*configure_stream)(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
+ struct vsp1_dl_body *dlb);
+ void (*configure_frame)(struct vsp1_entity *entity,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
+ struct vsp1_dl_body *dlb);
+ void (*configure_partition)(struct vsp1_entity *entity,
+ struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
+ struct vsp1_dl_list *dl,
+ struct vsp1_dl_body *dlb);
+ unsigned int (*max_width)(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
+ struct vsp1_pipeline *pipe);
+ void (*partition)(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int index,
+ struct v4l2_rect *window);
};
struct vsp1_entity {
@@ -138,20 +148,13 @@ struct v4l2_subdev_state *
vsp1_entity_get_state(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which);
-struct v4l2_mbus_framefmt *
-vsp1_entity_get_pad_format(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad);
-struct v4l2_rect *
-vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, unsigned int target);
void vsp1_entity_route_setup(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
struct vsp1_dl_body *dlb);
void vsp1_entity_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb);
@@ -163,6 +166,7 @@ void vsp1_entity_configure_frame(struct vsp1_entity *entity,
void vsp1_entity_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
index 40c571a987ef..2c8ce7175a4e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
@@ -130,6 +130,7 @@ static const struct v4l2_ctrl_config hgo_num_bins_control = {
*/
static void hgo_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -140,11 +141,8 @@ static void hgo_configure_stream(struct vsp1_entity *entity,
unsigned int hratio;
unsigned int vratio;
- crop = vsp1_entity_get_pad_selection(entity, entity->state,
- HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
- compose = vsp1_entity_get_pad_selection(entity, entity->state,
- HISTO_PAD_SINK,
- V4L2_SEL_TGT_COMPOSE);
+ crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
+ compose = v4l2_subdev_state_get_compose(state, HISTO_PAD_SINK);
vsp1_hgo_write(hgo, dlb, VI6_HGO_REGRST, VI6_HGO_REGRST_RCLEA);
@@ -194,6 +192,16 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
if (hgo == NULL)
return ERR_PTR(-ENOMEM);
+ /* Initialize the video device and queue for statistics data. */
+ ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
+ &hgo_entity_ops, hgo_mbus_formats,
+ ARRAY_SIZE(hgo_mbus_formats),
+ HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
+ if (ret < 0) {
+ vsp1_entity_destroy(&hgo->histo.entity);
+ return ERR_PTR(ret);
+ }
+
/* Initialize the control handler. */
v4l2_ctrl_handler_init(&hgo->ctrls.handler,
vsp1->info->gen >= 3 ? 2 : 1);
@@ -209,15 +217,5 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
hgo->histo.entity.subdev.ctrl_handler = &hgo->ctrls.handler;
- /* Initialize the video device and queue for statistics data. */
- ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
- &hgo_entity_ops, hgo_mbus_formats,
- ARRAY_SIZE(hgo_mbus_formats),
- HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
- if (ret < 0) {
- vsp1_entity_destroy(&hgo->histo.entity);
- return ERR_PTR(ret);
- }
-
return hgo;
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
index 8281b86874ab..858f330d44fa 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
@@ -126,6 +126,7 @@ static const struct v4l2_ctrl_config hgt_hue_areas = {
*/
static void hgt_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -139,11 +140,8 @@ static void hgt_configure_stream(struct vsp1_entity *entity,
u8 upper;
unsigned int i;
- crop = vsp1_entity_get_pad_selection(entity, entity->state,
- HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
- compose = vsp1_entity_get_pad_selection(entity, entity->state,
- HISTO_PAD_SINK,
- V4L2_SEL_TGT_COMPOSE);
+ crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
+ compose = v4l2_subdev_state_get_compose(state, HISTO_PAD_SINK);
vsp1_hgt_write(hgt, dlb, VI6_HGT_REGRST, VI6_HGT_REGRST_RCLEA);
@@ -193,12 +191,6 @@ struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1)
if (hgt == NULL)
return ERR_PTR(-ENOMEM);
- /* Initialize the control handler. */
- v4l2_ctrl_handler_init(&hgt->ctrls, 1);
- v4l2_ctrl_new_custom(&hgt->ctrls, &hgt_hue_areas, NULL);
-
- hgt->histo.entity.subdev.ctrl_handler = &hgt->ctrls;
-
/* Initialize the video device and queue for statistics data. */
ret = vsp1_histogram_init(vsp1, &hgt->histo, VSP1_ENTITY_HGT, "hgt",
&hgt_entity_ops, hgt_mbus_formats,
@@ -209,6 +201,12 @@ struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1)
return ERR_PTR(ret);
}
+ /* Initialize the control handler. */
+ v4l2_ctrl_handler_init(&hgt->ctrls, 1);
+ v4l2_ctrl_new_custom(&hgt->ctrls, &hgt_hue_areas, NULL);
+
+ hgt->histo.entity.subdev.ctrl_handler = &hgt->ctrls;
+
v4l2_ctrl_handler_setup(&hgt->ctrls);
return hgt;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c
index 71155282ca11..c762202877ba 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c
@@ -36,9 +36,8 @@ struct vsp1_histogram_buffer *
vsp1_histogram_buffer_get(struct vsp1_histogram *histo)
{
struct vsp1_histogram_buffer *buf = NULL;
- unsigned long flags;
- spin_lock_irqsave(&histo->irqlock, flags);
+ spin_lock(&histo->irqlock);
if (list_empty(&histo->irqqueue))
goto done;
@@ -49,7 +48,7 @@ vsp1_histogram_buffer_get(struct vsp1_histogram *histo)
histo->readout = true;
done:
- spin_unlock_irqrestore(&histo->irqlock, flags);
+ spin_unlock(&histo->irqlock);
return buf;
}
@@ -58,7 +57,6 @@ void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo,
size_t size)
{
struct vsp1_pipeline *pipe = histo->entity.pipe;
- unsigned long flags;
/*
* The pipeline pointer is guaranteed to be valid as this function is
@@ -70,10 +68,10 @@ void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo,
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, size);
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
- spin_lock_irqsave(&histo->irqlock, flags);
+ spin_lock(&histo->irqlock);
histo->readout = false;
wake_up(&histo->wait_queue);
- spin_unlock_irqrestore(&histo->irqlock, flags);
+ spin_unlock(&histo->irqlock);
}
/* -----------------------------------------------------------------------------
@@ -124,11 +122,10 @@ static void histo_buffer_queue(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vsp1_histogram *histo = vb2_get_drv_priv(vb->vb2_queue);
struct vsp1_histogram_buffer *buf = to_vsp1_histogram_buffer(vbuf);
- unsigned long flags;
- spin_lock_irqsave(&histo->irqlock, flags);
+ spin_lock_irq(&histo->irqlock);
list_add_tail(&buf->queue, &histo->irqqueue);
- spin_unlock_irqrestore(&histo->irqlock, flags);
+ spin_unlock_irq(&histo->irqlock);
}
static int histo_start_streaming(struct vb2_queue *vq, unsigned int count)
@@ -140,9 +137,8 @@ static void histo_stop_streaming(struct vb2_queue *vq)
{
struct vsp1_histogram *histo = vb2_get_drv_priv(vq);
struct vsp1_histogram_buffer *buffer;
- unsigned long flags;
- spin_lock_irqsave(&histo->irqlock, flags);
+ spin_lock_irq(&histo->irqlock);
/* Remove all buffers from the IRQ queue. */
list_for_each_entry(buffer, &histo->irqqueue, queue)
@@ -152,15 +148,13 @@ static void histo_stop_streaming(struct vb2_queue *vq)
/* Wait for the buffer being read out (if any) to complete. */
wait_event_lock_irq(histo->wait_queue, !histo->readout, histo->irqlock);
- spin_unlock_irqrestore(&histo->irqlock, flags);
+ spin_unlock_irq(&histo->irqlock);
}
static const struct vb2_ops histo_video_queue_qops = {
.queue_setup = histo_queue_setup,
.buf_prepare = histo_buffer_prepare,
.buf_queue = histo_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = histo_start_streaming,
.stop_streaming = histo_stop_streaming,
};
@@ -222,9 +216,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- crop = vsp1_entity_get_pad_selection(&histo->entity, state,
- HISTO_PAD_SINK,
- V4L2_SEL_TGT_CROP);
+ crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = crop->width;
@@ -233,8 +225,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
- format = vsp1_entity_get_pad_format(&histo->entity, state,
- HISTO_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, HISTO_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = format->width;
@@ -242,9 +233,11 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
break;
case V4L2_SEL_TGT_COMPOSE:
+ sel->r = *v4l2_subdev_state_get_compose(state, sel->pad);
+ break;
+
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_entity_get_pad_selection(&histo->entity, state,
- sel->pad, sel->target);
+ sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
break;
default:
@@ -261,13 +254,10 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct vsp1_histogram *histo = subdev_to_histo(subdev);
struct v4l2_mbus_framefmt *format;
- struct v4l2_rect *selection;
/* The crop rectangle must be inside the input frame. */
- format = vsp1_entity_get_pad_format(&histo->entity, sd_state,
- HISTO_PAD_SINK);
+ format = v4l2_subdev_state_get_format(sd_state, HISTO_PAD_SINK);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
sel->r.width = clamp_t(unsigned int, sel->r.width, HISTO_MIN_SIZE,
@@ -276,14 +266,8 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
format->height - sel->r.top);
/* Set the crop rectangle and reset the compose rectangle. */
- selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
- sel->pad, V4L2_SEL_TGT_CROP);
- *selection = sel->r;
-
- selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
- sel->pad,
- V4L2_SEL_TGT_COMPOSE);
- *selection = sel->r;
+ *v4l2_subdev_state_get_crop(sd_state, sel->pad) = sel->r;
+ *v4l2_subdev_state_get_compose(sd_state, sel->pad) = sel->r;
return 0;
}
@@ -292,7 +276,6 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct vsp1_histogram *histo = subdev_to_histo(subdev);
struct v4l2_rect *compose;
struct v4l2_rect *crop;
unsigned int ratio;
@@ -305,9 +288,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
sel->r.left = 0;
sel->r.top = 0;
- crop = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
- sel->pad,
- V4L2_SEL_TGT_CROP);
+ crop = v4l2_subdev_state_get_crop(sd_state, sel->pad);
/*
* Clamp the width and height to acceptable values first and then
@@ -332,9 +313,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
ratio = 1 << (crop->height * 2 / sel->r.height / 3);
sel->r.height = crop->height / ratio;
- compose = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
- sel->pad,
- V4L2_SEL_TGT_COMPOSE);
+ compose = v4l2_subdev_state_get_compose(sd_state, sel->pad);
*compose = sel->r;
return 0;
@@ -371,31 +350,22 @@ done:
return ret;
}
-static int histo_get_format(struct v4l2_subdev *subdev,
+static int histo_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
+ struct vsp1_histogram *histo = subdev_to_histo(subdev);
+
if (fmt->pad == HISTO_PAD_SOURCE) {
fmt->format.code = MEDIA_BUS_FMT_FIXED;
fmt->format.width = 0;
fmt->format.height = 0;
fmt->format.field = V4L2_FIELD_NONE;
fmt->format.colorspace = V4L2_COLORSPACE_RAW;
+
return 0;
}
- return vsp1_subdev_get_pad_format(subdev, sd_state, fmt);
-}
-
-static int histo_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct vsp1_histogram *histo = subdev_to_histo(subdev);
-
- if (fmt->pad != HISTO_PAD_SINK)
- return histo_get_format(subdev, sd_state, fmt);
-
return vsp1_subdev_set_pad_format(subdev, sd_state, fmt,
histo->formats, histo->num_formats,
HISTO_MIN_SIZE, HISTO_MIN_SIZE,
@@ -405,7 +375,7 @@ static int histo_set_format(struct v4l2_subdev *subdev,
static const struct v4l2_subdev_pad_ops histo_pad_ops = {
.enum_mbus_code = histo_enum_mbus_code,
.enum_frame_size = histo_enum_frame_size,
- .get_fmt = histo_get_format,
+ .get_fmt = vsp1_subdev_get_pad_format,
.set_fmt = histo_set_format,
.get_selection = histo_get_selection,
.set_selection = histo_set_selection,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
index bc1299c29ac9..8ba2a7c7305c 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
@@ -78,7 +78,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
goto done;
}
- format = vsp1_entity_get_pad_format(&hsit->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == HSIT_PAD_SOURCE) {
/*
@@ -101,8 +101,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&hsit->entity, state,
- HSIT_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, HSIT_PAD_SOURCE);
*format = fmt->format;
format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
: MEDIA_BUS_FMT_AHSV8888_1X32;
@@ -128,6 +127,7 @@ static const struct v4l2_subdev_ops hsit_ops = {
*/
static void hsit_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lif.c b/drivers/media/platform/renesas/vsp1/vsp1_lif.c
index b1d21a54837b..b3d83d1c5306 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_lif.c
@@ -83,6 +83,7 @@ static const struct v4l2_subdev_ops lif_ops = {
*/
static void lif_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -93,8 +94,7 @@ static void lif_configure_stream(struct vsp1_entity *entity,
unsigned int obth;
unsigned int lbth;
- format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.state,
- LIF_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, LIF_PAD_SOURCE);
switch (entity->vsp1->version & VI6_IP_VERSION_MODEL_MASK) {
case VI6_IP_VERSION_MODEL_VSPD_GEN2:
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lut.c b/drivers/media/platform/renesas/vsp1/vsp1_lut.c
index 451d24ab0b56..dd264e6532e0 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_lut.c
@@ -146,6 +146,7 @@ static const struct v4l2_subdev_ops lut_ops = {
*/
static void lut_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
index 68d05243c3ee..bb0739f684f3 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
@@ -301,6 +301,28 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
pipe->state = VSP1_PIPELINE_STOPPED;
}
+void __vsp1_pipeline_dump(struct _ddebug *dbg, struct vsp1_pipeline *pipe,
+ const char *msg)
+{
+ struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+ struct vsp1_entity *entity;
+ bool first = true;
+
+ printk(KERN_DEBUG "%s: %s: pipe: ", dev_name(vsp1->dev), msg);
+
+ list_for_each_entry(entity, &pipe->entities, list_pipe) {
+ const char *name;
+
+ name = strchrnul(entity->subdev.name, ' ');
+ name = name ? name + 1 : entity->subdev.name;
+
+ pr_cont("%s%s", first ? "" : ", ", name);
+ first = false;
+ }
+
+ pr_cont("\n");
+}
+
/* Must be called with the pipe irqlock held. */
void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
{
@@ -444,6 +466,10 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
vsp1_uds_set_alpha(pipe->uds, dlb, alpha);
}
+/* -----------------------------------------------------------------------------
+ * VSP1 Partition Algorithm support
+ */
+
/*
* Propagate the partition calculations through the pipeline
*
@@ -452,17 +478,82 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
* source. Each entity must produce the partition required for the previous
* entity in the pipeline.
*/
-void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
- struct vsp1_partition *partition,
- unsigned int index,
- struct vsp1_partition_window *window)
+static void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int index,
+ struct v4l2_rect *window)
{
struct vsp1_entity *entity;
list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) {
if (entity->ops->partition)
- entity->ops->partition(entity, pipe, partition, index,
- window);
+ entity->ops->partition(entity, entity->state, pipe,
+ partition, index, window);
}
}
+/*
+ * vsp1_pipeline_calculate_partition - Calculate pipeline configuration for a
+ * partition
+ *
+ * @pipe: the pipeline
+ * @partition: partition that will hold the calculated values
+ * @div_size: pre-determined maximum partition division size
+ * @index: partition index
+ */
+void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int div_size,
+ unsigned int index)
+{
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect window;
+ unsigned int modulus;
+
+ /*
+ * Partitions are computed on the size before rotation, use the format
+ * at the WPF sink.
+ */
+ format = v4l2_subdev_state_get_format(pipe->output->entity.state,
+ RWPF_PAD_SINK);
+
+ /* Initialise the partition with sane starting conditions. */
+ window.left = index * div_size;
+ window.width = div_size;
+ window.top = 0;
+ window.height = format->height;
+
+ modulus = format->width % div_size;
+
+ /*
+ * We need to prevent the last partition from being smaller than the
+ * *minimum* width of the hardware capabilities.
+ *
+ * If the modulus is less than half of the partition size,
+ * the penultimate partition is reduced to half, which is added
+ * to the final partition: |1234|1234|1234|12|341|
+ * to prevent this: |1234|1234|1234|1234|1|.
+ */
+ if (modulus) {
+ /*
+ * pipe->partitions is 1 based, whilst index is a 0 based index.
+ * Normalise this locally.
+ */
+ unsigned int partitions = pipe->partitions - 1;
+
+ if (modulus < div_size / 2) {
+ if (index == partitions - 1) {
+ /* Halve the penultimate partition. */
+ window.width = div_size / 2;
+ } else if (index == partitions) {
+ /* Increase the final partition. */
+ window.width = (div_size / 2) + modulus;
+ window.left -= div_size / 2;
+ }
+ } else if (index == partitions) {
+ window.width = modulus;
+ }
+ }
+
+ vsp1_pipeline_propagate_partition(pipe, partition, index, &window);
+}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
index 674b5748d929..1ba7bdbad5a8 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
@@ -9,6 +9,7 @@
#ifndef __VSP1_PIPE_H__
#define __VSP1_PIPE_H__
+#include <linux/dynamic_debug.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -54,17 +55,6 @@ enum vsp1_pipeline_state {
};
/*
- * struct vsp1_partition_window - Partition window coordinates
- * @left: horizontal coordinate of the partition start in pixels relative to the
- * left edge of the image
- * @width: partition width in pixels
- */
-struct vsp1_partition_window {
- unsigned int left;
- unsigned int width;
-};
-
-/*
* struct vsp1_partition - A description of a slice for the partition algorithm
* @rpf: The RPF partition window configuration
* @uds_sink: The UDS input partition window configuration
@@ -73,11 +63,11 @@ struct vsp1_partition_window {
* @wpf: The WPF partition window configuration
*/
struct vsp1_partition {
- struct vsp1_partition_window rpf;
- struct vsp1_partition_window uds_sink;
- struct vsp1_partition_window uds_source;
- struct vsp1_partition_window sru;
- struct vsp1_partition_window wpf;
+ struct v4l2_rect rpf[VSP1_MAX_RPF];
+ struct v4l2_rect uds_sink;
+ struct v4l2_rect uds_source;
+ struct v4l2_rect sru;
+ struct v4l2_rect wpf;
};
/*
@@ -106,7 +96,6 @@ struct vsp1_partition {
* @configured: when false the @stream_config shall be written to the hardware
* @interlaced: True when the pipeline is configured in interlaced mode
* @partitions: The number of partitions used to process one frame
- * @partition: The current partition for configuration to process
* @part_table: The pre-calculated partitions used by the pipeline
*/
struct vsp1_pipeline {
@@ -146,7 +135,6 @@ struct vsp1_pipeline {
bool interlaced;
unsigned int partitions;
- struct vsp1_partition *partition;
struct vsp1_partition *part_table;
u32 underrun_count;
@@ -155,6 +143,24 @@ struct vsp1_pipeline {
void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
void vsp1_pipeline_init(struct vsp1_pipeline *pipe);
+void __vsp1_pipeline_dump(struct _ddebug *, struct vsp1_pipeline *pipe,
+ const char *msg);
+
+#if defined(CONFIG_DYNAMIC_DEBUG) || \
+ (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
+#define vsp1_pipeline_dump(pipe, msg) \
+ _dynamic_func_call("vsp1_pipeline_dump()", __vsp1_pipeline_dump, pipe, msg)
+#elif defined(DEBUG)
+#define vsp1_pipeline_dump(pipe, msg) \
+ __vsp1_pipeline_dump(NULL, pipe, msg)
+#else
+#define vsp1_pipeline_dump(pipe, msg) \
+({ \
+ if (0) \
+ __vsp1_pipeline_dump(NULL, pipe, msg); \
+})
+#endif
+
void vsp1_pipeline_run(struct vsp1_pipeline *pipe);
bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
@@ -166,10 +172,10 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
struct vsp1_dl_body *dlb,
unsigned int alpha);
-void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
+void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
- unsigned int index,
- struct vsp1_partition_window *window);
+ unsigned int div_size,
+ unsigned int index);
const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1,
u32 fourcc);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
index c47579efc65f..5c8b3ba1bd3c 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
@@ -48,6 +48,7 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
*/
static void rpf_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -80,12 +81,8 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride);
/* Format */
- sink_format = vsp1_entity_get_pad_format(&rpf->entity,
- rpf->entity.state,
- RWPF_PAD_SINK);
- source_format = vsp1_entity_get_pad_format(&rpf->entity,
- rpf->entity.state,
- RWPF_PAD_SOURCE);
+ sink_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
+ source_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
infmt = VI6_RPF_INFMT_CIPM
| (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
@@ -157,10 +154,8 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
if (pipe->brx) {
const struct v4l2_rect *compose;
- compose = vsp1_entity_get_pad_selection(pipe->brx,
- pipe->brx->state,
- rpf->brx_input,
- V4L2_SEL_TGT_COMPOSE);
+ compose = v4l2_subdev_state_get_compose(pipe->brx->state,
+ rpf->brx_input);
left = compose->left;
top = compose->top;
}
@@ -284,6 +279,7 @@ static void rpf_configure_frame(struct vsp1_entity *entity,
static void rpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
@@ -292,7 +288,7 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_device *vsp1 = rpf->entity.vsp1;
const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
const struct v4l2_pix_format_mplane *format = &rpf->format;
- struct v4l2_rect crop;
+ struct v4l2_rect crop = partition->rpf[rpf->entity.index];
/*
* Source size and crop offsets.
@@ -302,22 +298,6 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
* offsets are needed, as planes 2 and 3 always have identical
* strides.
*/
- crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.state);
-
- /*
- * Partition Algorithm Control
- *
- * The partition algorithm can split this frame into multiple
- * slices. We must scale our partition window based on the pipe
- * configuration to match the destination partition window.
- * To achieve this, we adjust our crop to provide a 'sub-crop'
- * matching the expected partition window. Only 'left' and
- * 'width' need to be adjusted.
- */
- if (pipe->partitions > 1) {
- crop.width = pipe->partition->rpf.width;
- crop.left += pipe->partition->rpf.left;
- }
if (pipe->interlaced) {
crop.height = round_down(crop.height / 2, fmtinfo->vsub);
@@ -366,12 +346,30 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
}
static void rpf_partition(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int partition_idx,
- struct vsp1_partition_window *window)
+ struct v4l2_rect *window)
{
- partition->rpf = *window;
+ struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
+ struct v4l2_rect *rpf_rect = &partition->rpf[rpf->entity.index];
+
+ /*
+ * Partition Algorithm Control
+ *
+ * The partition algorithm can split this frame into multiple slices. We
+ * must adjust our partition window based on the pipe configuration to
+ * match the destination partition window. To achieve this, we adjust
+ * our crop to provide a 'sub-crop' matching the expected partition
+ * window.
+ */
+ *rpf_rect = *v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
+
+ if (pipe->partitions > 1) {
+ rpf_rect->width = window->width;
+ rpf_rect->left += window->left;
+ }
}
static const struct vsp1_entity_operations rpf_entity_ops = {
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
index 09fb6ffa14e2..9d38203e73d0 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
@@ -16,12 +16,6 @@
#define RWPF_MIN_WIDTH 1
#define RWPF_MIN_HEIGHT 1
-struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
- struct v4l2_subdev_state *sd_state)
-{
- return v4l2_subdev_state_get_crop(sd_state, RWPF_PAD_SINK);
-}
-
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
*/
@@ -79,7 +73,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
- format = vsp1_entity_get_pad_format(&rwpf->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == RWPF_PAD_SOURCE) {
/*
@@ -105,7 +99,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
struct v4l2_rect *crop;
/* Update the sink crop rectangle. */
- crop = vsp1_rwpf_get_crop(rwpf, state);
+ crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
@@ -113,8 +107,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
}
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, state,
- RWPF_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
*format = fmt->format;
if (rwpf->flip.rotate) {
@@ -153,12 +146,11 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_rwpf_get_crop(rwpf, state);
+ sel->r = *v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
break;
case V4L2_SEL_TGT_CROP_BOUNDS:
- format = vsp1_entity_get_pad_format(&rwpf->entity, state,
- RWPF_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = format->width;
@@ -204,8 +196,7 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
}
/* Make sure the crop rectangle is entirely contained in the image. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, state,
- RWPF_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
/*
* Restrict the crop rectangle coordinates to multiples of 2 to avoid
@@ -225,12 +216,11 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
sel->r.height = min_t(unsigned int, sel->r.height,
format->height - sel->r.top);
- crop = vsp1_rwpf_get_crop(rwpf, state);
+ crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
*crop = sel->r;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, state,
- RWPF_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
format->width = crop->width;
format->height = crop->height;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h
index e0d212c70b2f..5ac9f0a6fafc 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h
@@ -85,7 +85,4 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols);
extern const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops;
-struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
- struct v4l2_subdev_state *sd_state);
-
#endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_sru.c b/drivers/media/platform/renesas/vsp1/vsp1_sru.c
index 11e008aa9f20..1759ce642e6e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_sru.c
@@ -131,7 +131,7 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(&sru->entity, state, SRU_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
mutex_lock(&sru->entity.lock);
@@ -184,8 +184,7 @@ static void sru_try_format(struct vsp1_sru *sru,
case SRU_PAD_SOURCE:
/* The SRU can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&sru->entity, sd_state,
- SRU_PAD_SINK);
+ format = v4l2_subdev_state_get_format(sd_state, SRU_PAD_SINK);
fmt->code = format->code;
/*
@@ -234,13 +233,12 @@ static int sru_set_format(struct v4l2_subdev *subdev,
sru_try_format(sru, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&sru->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format;
if (fmt->pad == SRU_PAD_SINK) {
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&sru->entity, state,
- SRU_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
*format = fmt->format;
sru_try_format(sru, state, SRU_PAD_SOURCE, format);
@@ -267,6 +265,7 @@ static const struct v4l2_subdev_ops sru_ops = {
*/
static void sru_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -277,10 +276,8 @@ static void sru_configure_stream(struct vsp1_entity *entity,
struct v4l2_mbus_framefmt *output;
u32 ctrl0;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
@@ -301,16 +298,14 @@ static void sru_configure_stream(struct vsp1_entity *entity,
}
static unsigned int sru_max_width(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe)
{
- struct vsp1_sru *sru = to_sru(&entity->subdev);
struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
/*
* The maximum input width of the SRU is 288 input pixels, but 32
@@ -324,24 +319,24 @@ static unsigned int sru_max_width(struct vsp1_entity *entity,
}
static void sru_partition(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int partition_idx,
- struct vsp1_partition_window *window)
+ struct v4l2_rect *window)
{
- struct vsp1_sru *sru = to_sru(&entity->subdev);
struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
/* Adapt if SRUx2 is enabled. */
if (input->width != output->width) {
window->width /= 2;
window->left /= 2;
+ window->height /= 2;
+ window->top /= 2;
}
partition->sru = *window;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uds.c b/drivers/media/platform/renesas/vsp1/vsp1_uds.c
index d89f1197b86c..c5a38478cf8c 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_uds.c
@@ -136,7 +136,7 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(&uds->entity, state, UDS_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
mutex_lock(&uds->entity.lock);
@@ -183,8 +183,7 @@ static void uds_try_format(struct vsp1_uds *uds,
case UDS_PAD_SOURCE:
/* The UDS scales but can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&uds->entity, sd_state,
- UDS_PAD_SINK);
+ format = v4l2_subdev_state_get_format(sd_state, UDS_PAD_SINK);
fmt->code = format->code;
uds_output_limits(format->width, &minimum, &maximum);
@@ -217,13 +216,12 @@ static int uds_set_format(struct v4l2_subdev *subdev,
uds_try_format(uds, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&uds->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format;
if (fmt->pad == UDS_PAD_SINK) {
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&uds->entity, state,
- UDS_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
*format = fmt->format;
uds_try_format(uds, state, UDS_PAD_SOURCE, format);
@@ -254,6 +252,7 @@ static const struct v4l2_subdev_ops uds_ops = {
*/
static void uds_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -265,10 +264,8 @@ static void uds_configure_stream(struct vsp1_entity *entity,
unsigned int vscale;
bool multitap;
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
hscale = uds_compute_ratio(input->width, output->width);
vscale = uds_compute_ratio(input->height, output->height);
@@ -303,15 +300,11 @@ static void uds_configure_stream(struct vsp1_entity *entity,
static void uds_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_uds *uds = to_uds(&entity->subdev);
- struct vsp1_partition *partition = pipe->partition;
- const struct v4l2_mbus_framefmt *output;
-
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SOURCE);
/* Input size clipping. */
vsp1_uds_write(uds, dlb, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN |
@@ -323,22 +316,20 @@ static void uds_configure_partition(struct vsp1_entity *entity,
vsp1_uds_write(uds, dlb, VI6_UDS_CLIP_SIZE,
(partition->uds_source.width
<< VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
- (output->height
+ (partition->uds_source.height
<< VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
}
static unsigned int uds_max_width(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe)
{
- struct vsp1_uds *uds = to_uds(&entity->subdev);
const struct v4l2_mbus_framefmt *output;
const struct v4l2_mbus_framefmt *input;
unsigned int hscale;
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
hscale = output->width / input->width;
/*
@@ -364,28 +355,26 @@ static unsigned int uds_max_width(struct vsp1_entity *entity,
*/
static void uds_partition(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int partition_idx,
- struct vsp1_partition_window *window)
+ struct v4l2_rect *window)
{
- struct vsp1_uds *uds = to_uds(&entity->subdev);
const struct v4l2_mbus_framefmt *output;
const struct v4l2_mbus_framefmt *input;
- /* Initialise the partition state. */
- partition->uds_sink = *window;
- partition->uds_source = *window;
-
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
partition->uds_sink.width = window->width * input->width
/ output->width;
partition->uds_sink.left = window->left * input->width
/ output->width;
+ partition->uds_sink.height = input->height;
+ partition->uds_sink.top = 0;
+
+ partition->uds_source = *window;
*window = partition->uds_sink;
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uif.c b/drivers/media/platform/renesas/vsp1/vsp1_uif.c
index f66936a28a2a..edaf28b544d2 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_uif.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_uif.c
@@ -104,8 +104,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
- format = vsp1_entity_get_pad_format(&uif->entity, state,
- UIF_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, UIF_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = format->width;
@@ -113,8 +112,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_entity_get_pad_selection(&uif->entity, state,
- sel->pad, sel->target);
+ sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
break;
default:
@@ -150,7 +148,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
}
/* The crop rectangle must be inside the input frame. */
- format = vsp1_entity_get_pad_format(&uif->entity, state, UIF_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, UIF_PAD_SINK);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -160,8 +158,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
format->height - sel->r.top);
/* Store the crop rectangle. */
- selection = vsp1_entity_get_pad_selection(&uif->entity, state,
- sel->pad, V4L2_SEL_TGT_CROP);
+ selection = v4l2_subdev_state_get_crop(state, sel->pad);
*selection = sel->r;
done:
@@ -191,6 +188,7 @@ static const struct v4l2_subdev_ops uif_ops = {
*/
static void uif_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -203,8 +201,7 @@ static void uif_configure_stream(struct vsp1_entity *entity,
vsp1_uif_write(uif, dlb, VI6_UIF_DISCOM_DOCMPMR,
VI6_UIF_DISCOM_DOCMPMR_SEL(9));
- crop = vsp1_entity_get_pad_selection(entity, entity->state,
- UIF_PAD_SINK, V4L2_SEL_TGT_CROP);
+ crop = v4l2_subdev_state_get_crop(state, UIF_PAD_SINK);
left = crop->left;
width = crop->width;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c
index 5a9cb0e5640e..03f4efd6b82b 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_video.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c
@@ -78,8 +78,14 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
if (video->rwpf->fmtinfo->mbus != fmt.format.code ||
video->rwpf->format.height != fmt.format.height ||
- video->rwpf->format.width != fmt.format.width)
- return -EINVAL;
+ video->rwpf->format.width != fmt.format.width) {
+ dev_dbg(video->vsp1->dev,
+ "Format mismatch: 0x%04x/%ux%u != 0x%04x/%ux%u\n",
+ video->rwpf->fmtinfo->mbus, video->rwpf->format.width,
+ video->rwpf->format.height, fmt.format.code,
+ fmt.format.width, fmt.format.height);
+ return -EPIPE;
+ }
return 0;
}
@@ -173,131 +179,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
}
/* -----------------------------------------------------------------------------
- * VSP1 Partition Algorithm support
- */
-
-/**
- * vsp1_video_calculate_partition - Calculate the active partition output window
- *
- * @pipe: the pipeline
- * @partition: partition that will hold the calculated values
- * @div_size: pre-determined maximum partition division size
- * @index: partition index
- */
-static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe,
- struct vsp1_partition *partition,
- unsigned int div_size,
- unsigned int index)
-{
- const struct v4l2_mbus_framefmt *format;
- struct vsp1_partition_window window;
- unsigned int modulus;
-
- /*
- * Partitions are computed on the size before rotation, use the format
- * at the WPF sink.
- */
- format = vsp1_entity_get_pad_format(&pipe->output->entity,
- pipe->output->entity.state,
- RWPF_PAD_SINK);
-
- /* A single partition simply processes the output size in full. */
- if (pipe->partitions <= 1) {
- window.left = 0;
- window.width = format->width;
-
- vsp1_pipeline_propagate_partition(pipe, partition, index,
- &window);
- return;
- }
-
- /* Initialise the partition with sane starting conditions. */
- window.left = index * div_size;
- window.width = div_size;
-
- modulus = format->width % div_size;
-
- /*
- * We need to prevent the last partition from being smaller than the
- * *minimum* width of the hardware capabilities.
- *
- * If the modulus is less than half of the partition size,
- * the penultimate partition is reduced to half, which is added
- * to the final partition: |1234|1234|1234|12|341|
- * to prevent this: |1234|1234|1234|1234|1|.
- */
- if (modulus) {
- /*
- * pipe->partitions is 1 based, whilst index is a 0 based index.
- * Normalise this locally.
- */
- unsigned int partitions = pipe->partitions - 1;
-
- if (modulus < div_size / 2) {
- if (index == partitions - 1) {
- /* Halve the penultimate partition. */
- window.width = div_size / 2;
- } else if (index == partitions) {
- /* Increase the final partition. */
- window.width = (div_size / 2) + modulus;
- window.left -= div_size / 2;
- }
- } else if (index == partitions) {
- window.width = modulus;
- }
- }
-
- vsp1_pipeline_propagate_partition(pipe, partition, index, &window);
-}
-
-static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
-{
- struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
- const struct v4l2_mbus_framefmt *format;
- struct vsp1_entity *entity;
- unsigned int div_size;
- unsigned int i;
-
- /*
- * Partitions are computed on the size before rotation, use the format
- * at the WPF sink.
- */
- format = vsp1_entity_get_pad_format(&pipe->output->entity,
- pipe->output->entity.state,
- RWPF_PAD_SINK);
- div_size = format->width;
-
- /*
- * Only Gen3+ hardware requires image partitioning, Gen2 will operate
- * with a single partition that covers the whole output.
- */
- if (vsp1->info->gen >= 3) {
- list_for_each_entry(entity, &pipe->entities, list_pipe) {
- unsigned int entity_max;
-
- if (!entity->ops->max_width)
- continue;
-
- entity_max = entity->ops->max_width(entity, pipe);
- if (entity_max)
- div_size = min(div_size, entity_max);
- }
- }
-
- pipe->partitions = DIV_ROUND_UP(format->width, div_size);
- pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table),
- GFP_KERNEL);
- if (!pipe->part_table)
- return -ENOMEM;
-
- for (i = 0; i < pipe->partitions; ++i)
- vsp1_video_calculate_partition(pipe, &pipe->part_table[i],
- div_size, i);
-
- return 0;
-}
-
-/* -----------------------------------------------------------------------------
* Pipeline Management
*/
@@ -365,13 +246,12 @@ static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
unsigned int partition)
{
+ struct vsp1_partition *part = &pipe->part_table[partition];
struct vsp1_dl_body *dlb = vsp1_dl_list_get_body0(dl);
struct vsp1_entity *entity;
- pipe->partition = &pipe->part_table[partition];
-
list_for_each_entry(entity, &pipe->entities, list_pipe)
- vsp1_entity_configure_partition(entity, pipe, dl, dlb);
+ vsp1_entity_configure_partition(entity, pipe, part, dl, dlb);
}
static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
@@ -646,11 +526,19 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe,
struct vsp1_video *video)
{
+ int ret;
+
vsp1_pipeline_init(pipe);
pipe->frame_end = vsp1_video_pipeline_frame_end;
- return vsp1_video_pipeline_build(pipe, video);
+ ret = vsp1_video_pipeline_build(pipe, video);
+ if (ret)
+ return ret;
+
+ vsp1_pipeline_dump(pipe, "video");
+
+ return 0;
}
static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video)
@@ -784,6 +672,54 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&pipe->irqlock, flags);
}
+static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
+{
+ struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+ const struct v4l2_mbus_framefmt *format;
+ struct vsp1_entity *entity;
+ unsigned int div_size;
+ unsigned int i;
+
+ /*
+ * Partitions are computed on the size before rotation, use the format
+ * at the WPF sink.
+ */
+ format = v4l2_subdev_state_get_format(pipe->output->entity.state,
+ RWPF_PAD_SINK);
+ div_size = format->width;
+
+ /*
+ * Only Gen3+ hardware requires image partitioning, Gen2 will operate
+ * with a single partition that covers the whole output.
+ */
+ if (vsp1->info->gen >= 3) {
+ list_for_each_entry(entity, &pipe->entities, list_pipe) {
+ unsigned int entity_max;
+
+ if (!entity->ops->max_width)
+ continue;
+
+ entity_max = entity->ops->max_width(entity,
+ entity->state,
+ pipe);
+ if (entity_max)
+ div_size = min(div_size, entity_max);
+ }
+ }
+
+ pipe->partitions = DIV_ROUND_UP(format->width, div_size);
+ pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table),
+ GFP_KERNEL);
+ if (!pipe->part_table)
+ return -ENOMEM;
+
+ for (i = 0; i < pipe->partitions; ++i)
+ vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[i],
+ div_size, i);
+
+ return 0;
+}
+
static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
{
struct vsp1_entity *entity;
@@ -826,7 +762,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
list_for_each_entry(entity, &pipe->entities, list_pipe) {
vsp1_entity_route_setup(entity, pipe, pipe->stream_config);
- vsp1_entity_configure_stream(entity, pipe, NULL,
+ vsp1_entity_configure_stream(entity, entity->state, pipe, NULL,
pipe->stream_config);
}
@@ -937,8 +873,6 @@ static const struct vb2_ops vsp1_video_queue_qops = {
.queue_setup = vsp1_video_queue_setup,
.buf_prepare = vsp1_video_buffer_prepare,
.buf_queue = vsp1_video_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = vsp1_video_start_streaming,
.stop_streaming = vsp1_video_stop_streaming,
};
@@ -1146,6 +1080,27 @@ static const struct v4l2_file_operations vsp1_video_fops = {
};
/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static int vsp1_video_link_validate(struct media_link *link)
+{
+ /*
+ * Ideally, link validation should be implemented here instead of
+ * calling vsp1_video_verify_format() in vsp1_video_streamon()
+ * manually. That would however break userspace that start one video
+ * device before configures formats on other video devices in the
+ * pipeline. This operation is just a no-op to silence the warnings
+ * from v4l2_subdev_link_validate().
+ */
+ return 0;
+}
+
+static const struct media_entity_operations vsp1_video_media_ops = {
+ .link_validate = vsp1_video_link_validate,
+};
+
+/* -----------------------------------------------------------------------------
* Suspend and Resume
*/
@@ -1279,6 +1234,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
/* ... and the video node... */
video->video.v4l2_dev = &video->vsp1->v4l2_dev;
+ video->video.entity.ops = &vsp1_video_media_ops;
video->video.fops = &vsp1_video_fops;
snprintf(video->video.name, sizeof(video->video.name), "%s %s",
rwpf->entity.subdev.name, direction);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
index 9693aeab1cac..f176750ccd98 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
@@ -65,12 +65,10 @@ static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation)
goto done;
}
- sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SINK);
- source_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SOURCE);
+ sink_format = v4l2_subdev_state_get_format(wpf->entity.state,
+ RWPF_PAD_SINK);
+ source_format = v4l2_subdev_state_get_format(wpf->entity.state,
+ RWPF_PAD_SOURCE);
mutex_lock(&wpf->entity.lock);
@@ -231,6 +229,7 @@ static int wpf_configure_writeback_chain(struct vsp1_rwpf *wpf,
}
static void wpf_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -245,12 +244,8 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
u32 srcrpf = 0;
int ret;
- sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SINK);
- source_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SOURCE);
+ sink_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
+ source_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
/* Format */
if (!pipe->lif || wpf->writeback) {
@@ -367,13 +362,13 @@ static void wpf_configure_frame(struct vsp1_entity *entity,
static void wpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
struct vsp1_device *vsp1 = wpf->entity.vsp1;
struct vsp1_rwpf_memory mem = wpf->mem;
- const struct v4l2_mbus_framefmt *sink_format;
const struct v4l2_pix_format_mplane *format = &wpf->format;
const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
unsigned int width;
@@ -383,21 +378,13 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
unsigned int flip;
unsigned int i;
- sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SINK);
- width = sink_format->width;
- height = sink_format->height;
- left = 0;
-
/*
- * Cropping. The partition algorithm can split the image into
- * multiple slices.
+ * Cropping. The partition algorithm can split the image into multiple
+ * slices.
*/
- if (pipe->partitions > 1) {
- width = pipe->partition->wpf.width;
- left = pipe->partition->wpf.left;
- }
+ width = partition->wpf.width;
+ left = partition->wpf.left;
+ height = partition->wpf.height;
vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
(0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
@@ -508,6 +495,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
}
static unsigned int wpf_max_width(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe)
{
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
@@ -516,10 +504,11 @@ static unsigned int wpf_max_width(struct vsp1_entity *entity,
}
static void wpf_partition(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int partition_idx,
- struct vsp1_partition_window *window)
+ struct v4l2_rect *window)
{
partition->wpf = *window;
}