aboutsummaryrefslogtreecommitdiff
path: root/target/linux/bcm27xx/patches-6.1/950-1206-media-rp1-csi2-Use-get_frame_desc-to-get-CSI-2-VC-an.patch
blob: bd5789a1b33b680039a78fe6380de9714fe34a77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
From 425a6b752c38b50c97220db37a67b18b281f56e5 Mon Sep 17 00:00:00 2001
From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Date: Thu, 21 Sep 2023 15:28:20 +0300
Subject: [PATCH] media: rp1: csi2: Use get_frame_desc to get CSI-2 VC and DT

Use get_frame_desc pad op for asking the CSI-2 VC and DT from the source
device driver, instead of hardcoding to VC 0, and getting the DT from a
formats table. To keep backward compatibility with sources that do not
implement get_frame_desc, implement a fallback mechanism that always
uses VC 0, and gets the DT from the formats table, based on the CSI2's
sink pad's format.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
 .../media/platform/raspberrypi/rp1_cfe/cfe.c  |  4 +-
 .../media/platform/raspberrypi/rp1_cfe/csi2.c | 75 ++++++++++++++++++-
 .../media/platform/raspberrypi/rp1_cfe/csi2.h |  2 +-
 3 files changed, 77 insertions(+), 4 deletions(-)

--- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c
+++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c
@@ -838,7 +838,7 @@ static void cfe_start_channel(struct cfe
 		 * this is handled by the CSI2 AUTO_ARM mode.
 		 */
 		csi2_start_channel(&cfe->csi2, cfe->fe_csi2_channel,
-				   fmt->csi_dt, CSI2_MODE_FE_STREAMING,
+				   CSI2_MODE_FE_STREAMING,
 				   true, false, width, height);
 		csi2_set_buffer(&cfe->csi2, cfe->fe_csi2_channel, 0, 0, -1);
 		pisp_fe_start(&cfe->fe);
@@ -872,7 +872,7 @@ static void cfe_start_channel(struct cfe
 			}
 		}
 		/* Unconditionally start this CSI2 channel. */
-		csi2_start_channel(&cfe->csi2, node->id, fmt->csi_dt,
+		csi2_start_channel(&cfe->csi2, node->id,
 				   mode,
 				   /* Auto arm */
 				   false,
--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c
+++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.c
@@ -324,12 +324,84 @@ void csi2_set_compression(struct csi2_de
 	csi2_reg_write(csi2, CSI2_CH_COMP_CTRL(channel), compression);
 }
 
+static int csi2_get_vc_dt_fallback(struct csi2_device *csi2,
+				   unsigned int channel, u8 *vc, u8 *dt)
+{
+	struct v4l2_subdev *sd = &csi2->sd;
+	struct v4l2_subdev_state *state;
+	struct v4l2_mbus_framefmt *fmt;
+	const struct cfe_fmt *cfe_fmt;
+
+	state = v4l2_subdev_get_locked_active_state(sd);
+
+	/* Without Streams API, the channel number matches the sink pad */
+	fmt = v4l2_subdev_get_pad_format(sd, state, channel);
+	if (!fmt)
+		return -EINVAL;
+
+	cfe_fmt = find_format_by_code(fmt->code);
+	if (!cfe_fmt)
+		return -EINVAL;
+
+	*vc = 0;
+	*dt = cfe_fmt->csi_dt;
+
+	return 0;
+}
+
+static int csi2_get_vc_dt(struct csi2_device *csi2, unsigned int channel,
+			  u8 *vc, u8 *dt)
+{
+	struct v4l2_mbus_frame_desc remote_desc;
+	const struct media_pad *remote_pad;
+	struct v4l2_subdev *source_sd;
+	int ret;
+
+	/* Without Streams API, the channel number matches the sink pad */
+	remote_pad = media_pad_remote_pad_first(&csi2->pad[channel]);
+	if (!remote_pad)
+		return -EPIPE;
+
+	source_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+	ret = v4l2_subdev_call(source_sd, pad, get_frame_desc,
+			       remote_pad->index, &remote_desc);
+	if (ret == -ENOIOCTLCMD) {
+		csi2_dbg("source does not support get_frame_desc, use fallback\n");
+		return csi2_get_vc_dt_fallback(csi2, channel, vc, dt);
+	} else if (ret) {
+		csi2_err("Failed to get frame descriptor\n");
+		return ret;
+	}
+
+	if (remote_desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+		csi2_err("Frame descriptor does not describe CSI-2 link");
+		return -EINVAL;
+	}
+
+	if (remote_desc.num_entries != 1) {
+		csi2_err("Frame descriptor does not have a single entry");
+		return -EINVAL;
+	}
+
+	*vc = remote_desc.entry[0].bus.csi2.vc;
+	*dt = remote_desc.entry[0].bus.csi2.dt;
+
+	return 0;
+}
+
 void csi2_start_channel(struct csi2_device *csi2, unsigned int channel,
-			u16 dt, enum csi2_mode mode, bool auto_arm,
+			enum csi2_mode mode, bool auto_arm,
 			bool pack_bytes, unsigned int width,
 			unsigned int height)
 {
 	u32 ctrl;
+	int ret;
+	u8 vc, dt;
+
+	ret = csi2_get_vc_dt(csi2, channel, &vc, &dt);
+	if (ret)
+		return;
 
 	csi2_dbg("%s [%u]\n", __func__, channel);
 
@@ -369,6 +441,7 @@ void csi2_start_channel(struct csi2_devi
 		csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), 0);
 	}
 
+	set_field(&ctrl, vc, VC_MASK);
 	set_field(&ctrl, dt, DT_MASK);
 	csi2_reg_write(csi2, CSI2_CH_CTRL(channel), ctrl);
 	csi2->num_lines[channel] = height;
--- a/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h
+++ b/drivers/media/platform/raspberrypi/rp1_cfe/csi2.h
@@ -79,7 +79,7 @@ void csi2_set_compression(struct csi2_de
 			  enum csi2_compression_mode mode, unsigned int shift,
 			  unsigned int offset);
 void csi2_start_channel(struct csi2_device *csi2, unsigned int channel,
-			u16 dt, enum csi2_mode mode, bool auto_arm,
+			enum csi2_mode mode, bool auto_arm,
 			bool pack_bytes, unsigned int width,
 			unsigned int height);
 void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel);