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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
From 5ae0488f5fc682877ae2a5d454f70884e62120ef Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Thu, 3 Oct 2019 13:35:01 +0100
Subject: [PATCH] media: bcm2835-unicam: Support unpacking CSI format
to 16bpp
The CSI packed formats are not the easiest to work with, and
the peripheral supports unpacking them to 16bpp (but NOT
shifting the data up into the MSBs).
Where V4L2 exposes a pixfmt for both packed and unpacked
formats advertise both as being supported, and unpack the
data in the peripheral.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
.../media/platform/bcm2835/bcm2835-unicam.c | 102 +++++++++---------
1 file changed, 51 insertions(+), 51 deletions(-)
--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
@@ -15,12 +15,15 @@
*
* This driver directly controls the Unicam peripheral - there is no
* involvement with the VideoCore firmware. Unicam receives CSI-2 or
- * CCP2 data and writes it into SDRAM. The only potential processing options are
- * to repack Bayer data into an alternate format, and applying windowing.
- * The repacking does not shift the data, so could repack V4L2_PIX_FMT_Sxxxx10P
+ * CCP2 data and writes it into SDRAM.
+ * The only potential processing options are to repack Bayer data into an
+ * alternate format, and applying windowing.
+ * The repacking does not shift the data, so can repack V4L2_PIX_FMT_Sxxxx10P
* to V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12,
- * but not generically up to V4L2_PIX_FMT_Sxxxx16.
- * Adding support for repacking and windowing may be added later.
+ * but not generically up to V4L2_PIX_FMT_Sxxxx16. The driver will add both
+ * formats where the relevant formats are defined, and will automatically
+ * configure the repacking as required.
+ * Support for windowing may be added later.
*
* It should be possible to connect this driver to any sensor with a
* suitable output interface and V4L2 subdevice driver.
@@ -122,13 +125,16 @@ MODULE_PARM_DESC(debug, "Debug level 0-3
/*
* struct unicam_fmt - Unicam media bus format information
- * @pixelformat: V4L2 pixel format FCC identifier.
+ * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a.
+ * @repacked_fourcc: V4L2 pixel format FCC identifier if the data is expanded
+ * out to 16bpp. 0 if n/a.
* @code: V4L2 media bus format code.
- * @depth: Bits per pixel (when stored in memory).
+ * @depth: Bits per pixel as delivered from the source.
* @csi_dt: CSI data type.
*/
struct unicam_fmt {
u32 fourcc;
+ u32 repacked_fourcc;
u32 code;
u8 depth;
u8 csi_dt;
@@ -235,41 +241,49 @@ static const struct unicam_fmt formats[]
.csi_dt = 0x2a,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10P,
+ .repacked_fourcc = V4L2_PIX_FMT_SBGGR10,
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
.depth = 10,
.csi_dt = 0x2b,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10P,
+ .repacked_fourcc = V4L2_PIX_FMT_SGBRG10,
.code = MEDIA_BUS_FMT_SGBRG10_1X10,
.depth = 10,
.csi_dt = 0x2b,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10P,
+ .repacked_fourcc = V4L2_PIX_FMT_SGRBG10,
.code = MEDIA_BUS_FMT_SGRBG10_1X10,
.depth = 10,
.csi_dt = 0x2b,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10P,
+ .repacked_fourcc = V4L2_PIX_FMT_SRGGB10,
.code = MEDIA_BUS_FMT_SRGGB10_1X10,
.depth = 10,
.csi_dt = 0x2b,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR12P,
+ .repacked_fourcc = V4L2_PIX_FMT_SBGGR12,
.code = MEDIA_BUS_FMT_SBGGR12_1X12,
.depth = 12,
.csi_dt = 0x2c,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG12P,
+ .repacked_fourcc = V4L2_PIX_FMT_SGBRG12,
.code = MEDIA_BUS_FMT_SGBRG12_1X12,
.depth = 12,
.csi_dt = 0x2c,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG12P,
+ .repacked_fourcc = V4L2_PIX_FMT_SGRBG12,
.code = MEDIA_BUS_FMT_SGRBG12_1X12,
.depth = 12,
.csi_dt = 0x2c,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB12P,
+ .repacked_fourcc = V4L2_PIX_FMT_SRGGB12,
.code = MEDIA_BUS_FMT_SRGGB12_1X12,
.depth = 12,
.csi_dt = 0x2c,
@@ -439,20 +453,6 @@ static inline void unicam_runtime_put(st
}
/* Format setup functions */
-static int find_mbus_depth_by_code(u32 code)
-{
- const struct unicam_fmt *fmt;
- unsigned int k;
-
- for (k = 0; k < ARRAY_SIZE(formats); k++) {
- fmt = &formats[k];
- if (fmt->code == code)
- return fmt->depth;
- }
-
- return 0;
-}
-
static const struct unicam_fmt *find_format_by_code(u32 code)
{
unsigned int k;
@@ -470,7 +470,8 @@ static const struct unicam_fmt *find_for
unsigned int k;
for (k = 0; k < ARRAY_SIZE(formats); k++) {
- if (formats[k].fourcc == pixelformat)
+ if (formats[k].fourcc == pixelformat ||
+ formats[k].repacked_fourcc == pixelformat)
return &formats[k];
}
@@ -478,9 +479,14 @@ static const struct unicam_fmt *find_for
}
static inline unsigned int bytes_per_line(u32 width,
- const struct unicam_fmt *fmt)
+ const struct unicam_fmt *fmt,
+ u32 v4l2_fourcc)
{
- return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
+ if (v4l2_fourcc == fmt->repacked_fourcc)
+ /* Repacking always goes to 16bpp */
+ return ALIGN(width << 1, BPL_ALIGNMENT);
+ else
+ return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
}
static int __subdev_get_format(struct unicam_device *dev,
@@ -538,7 +544,8 @@ static int unicam_calc_format_size_bpl(s
&f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0,
0);
- min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt);
+ min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt,
+ f->fmt.pix.pixelformat);
if (f->fmt.pix.bytesperline > min_bytesperline &&
f->fmt.pix.bytesperline <= MAX_BYTESPERLINE)
@@ -738,6 +745,13 @@ static int unicam_enum_fmt_vid_cap(struc
}
index++;
}
+ if (fmt->repacked_fourcc) {
+ if (index == f->index) {
+ f->pixelformat = fmt->repacked_fourcc;
+ break;
+ }
+ index++;
+ }
}
}
@@ -858,7 +872,10 @@ static int unicam_try_fmt_vid_cap(struct
}
}
- f->fmt.pix.pixelformat = fmt->fourcc;
+ if (fmt->fourcc)
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ else
+ f->fmt.pix.pixelformat = fmt->repacked_fourcc;
}
return unicam_calc_format_size_bpl(dev, fmt, f);
@@ -998,16 +1015,14 @@ static void unicam_wr_dma_config(struct
static void unicam_set_packing_config(struct unicam_device *dev)
{
- int mbus_depth = find_mbus_depth_by_code(dev->fmt->code);
- int v4l2_depth = dev->fmt->depth;
int pack, unpack;
u32 val;
- if (mbus_depth == v4l2_depth) {
+ if (dev->v_fmt.fmt.pix.pixelformat == dev->fmt->fourcc) {
unpack = UNICAM_PUM_NONE;
pack = UNICAM_PPM_NONE;
} else {
- switch (mbus_depth) {
+ switch (dev->fmt->depth) {
case 8:
unpack = UNICAM_PUM_UNPACK8;
break;
@@ -1028,26 +1043,8 @@ static void unicam_set_packing_config(st
break;
}
- switch (v4l2_depth) {
- case 8:
- pack = UNICAM_PPM_PACK8;
- break;
- case 10:
- pack = UNICAM_PPM_PACK10;
- break;
- case 12:
- pack = UNICAM_PPM_PACK12;
- break;
- case 14:
- pack = UNICAM_PPM_PACK14;
- break;
- case 16:
- pack = UNICAM_PPM_PACK16;
- break;
- default:
- pack = UNICAM_PPM_NONE;
- break;
- }
+ /* Repacking is always to 16bpp */
+ pack = UNICAM_PPM_PACK16;
}
val = 0;
@@ -1893,7 +1890,10 @@ static int unicam_probe_complete(struct
}
unicam->fmt = fmt;
- unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
+ if (fmt->fourcc)
+ unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc;
+ else
+ unicam->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc;
/* Read current subdev format */
unicam_reset_format(unicam);
|