Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCH 0/6] staging: BCM2835 MMAL V4L2 camera driver

415 views
Skip to first unread message

Eric Anholt

unread,
Jan 27, 2017, 5:00:07 PM1/27/17
to
Here's my first pass at importing the camera driver. There's a bunch
of TODO left to it, most of which is documented, and the rest being
standard checkpatch fare.

Unfortunately, when I try modprobing it on my pi3, the USB network
device dies, consistently. I'm not sure what's going on here yet, but
I'm going to keep working on some debug of it. I've unfortunately
changed a lot of variables (pi3 vs pi2, upstream vs downstream, vchi's
updates while in staging, 4.9 vs 4.4), so I probably won't figure it
out today.

Note that the "Update the driver to the current VCHI API" patch will
conflict with the outstanding "Add vchi_queue_kernel_message and
vchi_queue_user_message" series, but the fix should be pretty obvious
when that lands.

I built this against 4.10-rc1, but a merge with staging-next was clean
and still built fine.

Eric Anholt (6):
staging: Import the BCM2835 MMAL-based V4L2 camera driver.
staging: bcm2835-v4l2: Update the driver to the current VCHI API.
staging: bcm2835-v4l2: Add a build system for the module.
staging: bcm2835-v4l2: Add a TODO file for improvements we need.
staging: bcm2835-v4l2: Apply many whitespace fixes from checkpatch.
staging: bcm2835-v4l2: Apply spelling fixes from checkpatch.

drivers/staging/media/Kconfig | 2 +
drivers/staging/media/Makefile | 1 +
drivers/staging/media/platform/bcm2835/Kconfig | 10 +
drivers/staging/media/platform/bcm2835/Makefile | 11 +
drivers/staging/media/platform/bcm2835/TODO | 39 +
.../media/platform/bcm2835/bcm2835-camera.c | 2024 ++++++++++++++++++++
.../media/platform/bcm2835/bcm2835-camera.h | 145 ++
drivers/staging/media/platform/bcm2835/controls.c | 1335 +++++++++++++
.../staging/media/platform/bcm2835/mmal-common.h | 53 +
.../media/platform/bcm2835/mmal-encodings.h | 127 ++
.../media/platform/bcm2835/mmal-msg-common.h | 50 +
.../media/platform/bcm2835/mmal-msg-format.h | 81 +
.../staging/media/platform/bcm2835/mmal-msg-port.h | 107 ++
drivers/staging/media/platform/bcm2835/mmal-msg.h | 404 ++++
.../media/platform/bcm2835/mmal-parameters.h | 689 +++++++
.../staging/media/platform/bcm2835/mmal-vchiq.c | 1920 +++++++++++++++++++
.../staging/media/platform/bcm2835/mmal-vchiq.h | 178 ++
17 files changed, 7176 insertions(+)
create mode 100644 drivers/staging/media/platform/bcm2835/Kconfig
create mode 100644 drivers/staging/media/platform/bcm2835/Makefile
create mode 100644 drivers/staging/media/platform/bcm2835/TODO
create mode 100644 drivers/staging/media/platform/bcm2835/bcm2835-camera.c
create mode 100644 drivers/staging/media/platform/bcm2835/bcm2835-camera.h
create mode 100644 drivers/staging/media/platform/bcm2835/controls.c
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-common.h
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-encodings.h
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-common.h
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-format.h
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-port.h
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg.h
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-parameters.h
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-vchiq.c
create mode 100644 drivers/staging/media/platform/bcm2835/mmal-vchiq.h

--
2.11.0

Eric Anholt

unread,
Jan 27, 2017, 5:00:09 PM1/27/17
to
49bec49fd7f2 ("staging: vc04_services: remove vchiq_copy_from_user")
removed the flags/msg_handle arguments, which were unused, and pushed
the implementation of copying using memcpy vs copy_from_user to the
caller.

Signed-off-by: Eric Anholt <er...@anholt.net>
---
drivers/staging/media/platform/bcm2835/mmal-vchiq.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/media/platform/bcm2835/mmal-vchiq.c b/drivers/staging/media/platform/bcm2835/mmal-vchiq.c
index 781322542d5a..24bd2948136c 100644
--- a/drivers/staging/media/platform/bcm2835/mmal-vchiq.c
+++ b/drivers/staging/media/platform/bcm2835/mmal-vchiq.c
@@ -378,6 +378,14 @@ static int inline_receive(struct vchiq_mmal_instance *instance,
return 0;
}

+static ssize_t mmal_memcpy_wrapper(void *src, void *dst,
+ size_t offset, size_t size)
+{
+ memcpy(dst + offset, src + offset, size);
+
+ return size;
+}
+
/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
static int
buffer_from_host(struct vchiq_mmal_instance *instance,
@@ -442,10 +450,9 @@ buffer_from_host(struct vchiq_mmal_instance *instance,

vchi_service_use(instance->handle);

- ret = vchi_msg_queue(instance->handle, &m,
+ ret = vchi_msg_queue(instance->handle, mmal_memcpy_wrapper, &m,
sizeof(struct mmal_msg_header) +
- sizeof(m.u.buffer_from_host),
- VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
+ sizeof(m.u.buffer_from_host));

if (ret != 0) {
release_msg_context(msg_context);
@@ -731,9 +738,9 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
vchi_service_use(instance->handle);

ret = vchi_msg_queue(instance->handle,
+ mmal_memcpy_wrapper,
msg,
- sizeof(struct mmal_msg_header) + payload_len,
- VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
+ sizeof(struct mmal_msg_header) + payload_len);

vchi_service_release(instance->handle);

--
2.11.0

Eric Anholt

unread,
Jan 27, 2017, 5:10:08 PM1/27/17
to
Generated with checkpatch.pl --fix-inplace, some manual fixes for
cases where checkpatch fixed one out of multiple lines of mis-indented
function parameters, and then git add -p out of the results.

I skipped some fixes that should probably instead be replaced with the
BIT() macro.

Signed-off-by: Eric Anholt <er...@anholt.net>
---
.../media/platform/bcm2835/bcm2835-camera.c | 90 ++++----
drivers/staging/media/platform/bcm2835/controls.c | 236 ++++++++++-----------
.../staging/media/platform/bcm2835/mmal-vchiq.c | 13 +-
3 files changed, 167 insertions(+), 172 deletions(-)

diff --git a/drivers/staging/media/platform/bcm2835/bcm2835-camera.c b/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
index 4f03949aecf3..4541a363905c 100644
--- a/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
+++ b/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
@@ -38,7 +38,7 @@
#define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2"
#define MIN_WIDTH 32
#define MIN_HEIGHT 32
-#define MIN_BUFFER_SIZE (80*1024)
+#define MIN_BUFFER_SIZE (80 * 1024)

#define MAX_VIDEO_MODE_WIDTH 1280
#define MAX_VIDEO_MODE_HEIGHT 720
@@ -420,6 +420,7 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
static int enable_camera(struct bm2835_mmal_dev *dev)
{
int ret;
+
if (!dev->camera_use_count) {
ret = vchiq_mmal_port_parameter_set(
dev->instance,
@@ -451,6 +452,7 @@ static int enable_camera(struct bm2835_mmal_dev *dev)
static int disable_camera(struct bm2835_mmal_dev *dev)
{
int ret;
+
if (!dev->camera_use_count) {
v4l2_err(&dev->v4l2_dev,
"Disabled the camera when already disabled\n");
@@ -459,6 +461,7 @@ static int disable_camera(struct bm2835_mmal_dev *dev)
dev->camera_use_count--;
if (!dev->camera_use_count) {
unsigned int i = 0xFFFFFFFF;
+
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
"Disabling camera\n");
ret =
@@ -643,12 +646,14 @@ static void stop_streaming(struct vb2_queue *vq)
static void bm2835_mmal_lock(struct vb2_queue *vq)
{
struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+
mutex_lock(&dev->mutex);
}

static void bm2835_mmal_unlock(struct vb2_queue *vq)
{
struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+
mutex_unlock(&dev->mutex);
}

@@ -737,7 +742,7 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
1, 0);

v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Overlay: Now w/h %dx%d l/t %dx%d\n",
+ "Overlay: Now w/h %dx%d l/t %dx%d\n",
f->fmt.win.w.width, f->fmt.win.w.height,
f->fmt.win.w.left, f->fmt.win.w.top);

@@ -759,7 +764,7 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
dev->overlay = f->fmt.win;
if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) {
set_overlay_params(dev,
- &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+ &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
}

return 0;
@@ -771,6 +776,7 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on)
struct bm2835_mmal_dev *dev = video_drvdata(file);
struct vchiq_mmal_port *src;
struct vchiq_mmal_port *dst;
+
if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
(!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
return 0; /* already in requested state */
@@ -842,7 +848,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
a->fmt.pixelformat = V4L2_PIX_FMT_YUV420;
a->fmt.bytesperline = preview_port->es.video.width;
a->fmt.sizeimage = (preview_port->es.video.width *
- preview_port->es.video.height * 3)>>1;
+ preview_port->es.video.height * 3) >> 1;
a->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;

return 0;
@@ -958,8 +964,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.field = V4L2_FIELD_NONE;

v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Clipping/aligning %dx%d format %08X\n",
- f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
+ "Clipping/aligning %dx%d format %08X\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);

v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, dev->max_width, 1,
&f->fmt.pix.height, MIN_HEIGHT, dev->max_height,
@@ -969,8 +975,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
/* Image buffer has to be padded to allow for alignment, even though
* we then remove that padding before delivering the buffer.
*/
- f->fmt.pix.sizeimage = ((f->fmt.pix.height+15)&~15) *
- (((f->fmt.pix.width+31)&~31) * mfmt->depth) >> 3;
+ f->fmt.pix.sizeimage = ((f->fmt.pix.height + 15) & ~15) *
+ (((f->fmt.pix.width + 31) & ~31) * mfmt->depth) >> 3;

if ((mfmt->flags & V4L2_FMT_FLAG_COMPRESSED) &&
f->fmt.pix.sizeimage < MIN_BUFFER_SIZE)
@@ -985,7 +991,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.priv = 0;

v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Now %dx%d format %08X\n",
+ "Now %dx%d format %08X\n",
f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);

v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
@@ -1203,9 +1209,9 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
encode_component);
if (ret) {
v4l2_dbg(1, bcm2835_v4l2_debug,
- &dev->v4l2_dev,
- "%s Failed to enable encode components\n",
- __func__);
+ &dev->v4l2_dev,
+ "%s Failed to enable encode components\n",
+ __func__);
}
}
if (!ret) {
@@ -1216,10 +1222,10 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev,
if (port->format.encoding ==
MMAL_ENCODING_JPEG) {
v4l2_dbg(1, bcm2835_v4l2_debug,
- &dev->v4l2_dev,
- "JPG - buf size now %d was %d\n",
- f->fmt.pix.sizeimage,
- port->current_buffer.size);
+ &dev->v4l2_dev,
+ "JPG - buf size now %d was %d\n",
+ f->fmt.pix.sizeimage,
+ port->current_buffer.size);
port->current_buffer.size =
(f->fmt.pix.sizeimage <
(100 << 10))
@@ -1332,7 +1338,7 @@ int vidioc_enum_framesizes(struct file *file, void *fh,

/* timeperframe is arbitrary and continous */
static int vidioc_enum_frameintervals(struct file *file, void *priv,
- struct v4l2_frmivalenum *fival)
+ struct v4l2_frmivalenum *fival)
{
struct bm2835_mmal_dev *dev = video_drvdata(file);
int i;
@@ -1362,7 +1368,7 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
}

static int vidioc_g_parm(struct file *file, void *priv,
- struct v4l2_streamparm *parm)
+ struct v4l2_streamparm *parm)
{
struct bm2835_mmal_dev *dev = video_drvdata(file);

@@ -1380,7 +1386,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
(u64)(b).numerator * (a).denominator)

static int vidioc_s_parm(struct file *file, void *priv,
- struct v4l2_streamparm *parm)
+ struct v4l2_streamparm *parm)
{
struct bm2835_mmal_dev *dev = video_drvdata(file);
struct v4l2_fract tpf;
@@ -1516,7 +1522,7 @@ static struct video_device vdev_template = {
* by those cameras.
*/
static int get_num_cameras(struct vchiq_mmal_instance *instance,
- unsigned int resolutions[][2], int num_resolutions)
+ unsigned int resolutions[][2], int num_resolutions)
{
int ret;
struct vchiq_mmal_component *cam_info_component;
@@ -1621,14 +1627,14 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev)
dev->rgb_bgr_swapped = true;
param_size = sizeof(supported_encodings);
ret = vchiq_mmal_port_parameter_get(dev->instance,
- &camera->output[MMAL_CAMERA_PORT_CAPTURE],
- MMAL_PARAMETER_SUPPORTED_ENCODINGS,
- &supported_encodings,
- &param_size);
+ &camera->output[MMAL_CAMERA_PORT_CAPTURE],
+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+ &supported_encodings,
+ &param_size);
if (ret == 0) {
int i;

- for (i = 0; i < param_size/sizeof(u32); i++) {
+ for (i = 0; i < param_size / sizeof(u32); i++) {
if (supported_encodings[i] == MMAL_ENCODING_BGR24) {
/* Found BGR24 first - old firmware. */
break;
@@ -1671,9 +1677,9 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev)
format->es->video.frame_rate.den = 1;

vchiq_mmal_port_parameter_set(dev->instance,
- &camera->output[MMAL_CAMERA_PORT_VIDEO],
- MMAL_PARAMETER_NO_IMAGE_PADDING,
- &bool_true, sizeof(bool_true));
+ &camera->output[MMAL_CAMERA_PORT_VIDEO],
+ MMAL_PARAMETER_NO_IMAGE_PADDING,
+ &bool_true, sizeof(bool_true));

format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;

@@ -1697,9 +1703,9 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev)
dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;

vchiq_mmal_port_parameter_set(dev->instance,
- &camera->output[MMAL_CAMERA_PORT_CAPTURE],
- MMAL_PARAMETER_NO_IMAGE_PADDING,
- &bool_true, sizeof(bool_true));
+ &camera->output[MMAL_CAMERA_PORT_CAPTURE],
+ MMAL_PARAMETER_NO_IMAGE_PADDING,
+ &bool_true, sizeof(bool_true));

/* get the preview component ready */
ret = vchiq_mmal_component_init(
@@ -1750,11 +1756,12 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev)
&dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
encoder_port->format.encoding = MMAL_ENCODING_H264;
ret = vchiq_mmal_port_set_format(dev->instance,
- encoder_port);
+ encoder_port);
}

{
unsigned int enable = 1;
+
vchiq_mmal_port_parameter_set(
dev->instance,
&dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
@@ -1762,10 +1769,10 @@ static int __init mmal_init(struct bm2835_mmal_dev *dev)
&enable, sizeof(enable));

vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
- MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
- &enable,
- sizeof(enable));
+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
+ &enable,
+ sizeof(enable));
}
ret = bm2835_mmal_set_all_camera_controls(dev);
if (ret < 0)
@@ -1808,7 +1815,7 @@ static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev,
*vfd = vdev_template;
if (gst_v4l2src_is_broken) {
v4l2_info(&dev->v4l2_dev,
- "Work-around for gstreamer issue is active.\n");
+ "Work-around for gstreamer issue is active.\n");
vfd->ioctl_ops = &camera0_ioctl_ops_gstreamer;
}

@@ -1828,8 +1835,9 @@ static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev,
return ret;

v4l2_info(vfd->v4l2_dev,
- "V4L2 device registered as %s - stills mode > %dx%d\n",
- video_device_node_name(vfd), max_video_width, max_video_height);
+ "V4L2 device registered as %s - stills mode > %dx%d\n",
+ video_device_node_name(vfd),
+ max_video_width, max_video_height);

return 0;
}
@@ -1881,7 +1889,7 @@ static struct v4l2_format default_v4l2_format = {
.fmt.pix.width = 1024,
.fmt.pix.bytesperline = 0,
.fmt.pix.height = 768,
- .fmt.pix.sizeimage = 1024*768,
+ .fmt.pix.sizeimage = 1024 * 768,
};

static int __init bm2835_mmal_init(void)
@@ -1995,7 +2003,7 @@ static int __init bm2835_mmal_init(void)
gdev[camera] = NULL;
}
pr_info("%s: error %d while loading driver\n",
- BM2835_MMAL_MODULE_NAME, ret);
+ BM2835_MMAL_MODULE_NAME, ret);

return ret;
}
diff --git a/drivers/staging/media/platform/bcm2835/controls.c b/drivers/staging/media/platform/bcm2835/controls.c
index fe61330ba2a6..a40987b2e75d 100644
--- a/drivers/staging/media/platform/bcm2835/controls.c
+++ b/drivers/staging/media/platform/bcm2835/controls.c
@@ -171,8 +171,8 @@ static const struct v4l2_mmal_scene_config scene_configs[] = {
/* control handlers*/

static int ctrl_set_rational(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
struct mmal_parameter_rational rational_value;
struct vchiq_mmal_port *control;
@@ -189,8 +189,8 @@ static int ctrl_set_rational(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_value(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
u32 u32_value;
struct vchiq_mmal_port *control;
@@ -205,8 +205,8 @@ static int ctrl_set_value(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_iso(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
u32 u32_value;
struct vchiq_mmal_port *control;
@@ -235,15 +235,15 @@ static int ctrl_set_iso(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
s32 s32_value;
struct vchiq_mmal_port *control;

control = &dev->component[MMAL_COMPONENT_CAMERA]->control;

- s32_value = (ctrl->val-12)*2; /* Convert from index to 1/6ths */
+ s32_value = (ctrl->val - 12) * 2; /* Convert from index to 1/6ths */

return vchiq_mmal_port_parameter_set(dev->instance, control,
mmal_ctrl->mmal_id,
@@ -251,8 +251,8 @@ static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_rotate(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
int ret;
u32 u32_value;
@@ -282,8 +282,8 @@ static int ctrl_set_rotate(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_flip(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
int ret;
u32 u32_value;
@@ -322,12 +322,11 @@ static int ctrl_set_flip(struct bm2835_mmal_dev *dev,
&u32_value, sizeof(u32_value));

return ret;
-
}

static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode_user;
u32 shutter_speed = 0;
@@ -362,15 +361,15 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
shutter_speed = dev->manual_shutter_speed;

ret = vchiq_mmal_port_parameter_set(dev->instance,
- control,
- MMAL_PARAMETER_SHUTTER_SPEED,
- &shutter_speed,
- sizeof(shutter_speed));
+ control,
+ MMAL_PARAMETER_SHUTTER_SPEED,
+ &shutter_speed,
+ sizeof(shutter_speed));
ret += vchiq_mmal_port_parameter_set(dev->instance,
- control,
- MMAL_PARAMETER_EXPOSURE_MODE,
- &exp_mode,
- sizeof(u32));
+ control,
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &exp_mode,
+ sizeof(u32));
dev->exposure_mode_active = exp_mode;
}
/* exposure_dynamic_framerate (V4L2_CID_EXPOSURE_AUTO_PRIORITY) should
@@ -382,8 +381,8 @@ static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
switch (ctrl->val) {
case V4L2_EXPOSURE_METERING_AVERAGE:
@@ -403,7 +402,6 @@ static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX;
break;
*/
-
}

if (dev->scene_mode == V4L2_SCENE_MODE_NONE) {
@@ -420,8 +418,8 @@ static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
u32 u32_value;
struct vchiq_mmal_port *control;
@@ -449,8 +447,8 @@ static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
u32 u32_value;
struct vchiq_mmal_port *control;
@@ -497,7 +495,6 @@ static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
case V4L2_WHITE_BALANCE_SHADE:
u32_value = MMAL_PARAM_AWBMODE_SHADE;
break;
-
}

return vchiq_mmal_port_parameter_set(dev->instance, control,
@@ -506,8 +503,8 @@ static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
struct vchiq_mmal_port *control;
struct mmal_parameter_awbgains gains;
@@ -529,8 +526,8 @@ static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
int ret = -EINVAL;
int i, j;
@@ -539,7 +536,6 @@ static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,

for (i = 0; i < ARRAY_SIZE(v4l2_to_mmal_effects_values); i++) {
if (ctrl->val == v4l2_to_mmal_effects_values[i].v4l2_effect) {
-
imagefx.effect =
v4l2_to_mmal_effects_values[i].mmal_effect;
imagefx.num_effect_params =
@@ -588,8 +584,8 @@ static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
int ret = -EINVAL;
struct vchiq_mmal_port *control;
@@ -600,8 +596,9 @@ static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
dev->colourfx.enable = ctrl->val & 0xff;

ret = vchiq_mmal_port_parameter_set(dev->instance, control,
- MMAL_PARAMETER_COLOUR_EFFECT,
- &dev->colourfx, sizeof(dev->colourfx));
+ MMAL_PARAMETER_COLOUR_EFFECT,
+ &dev->colourfx,
+ sizeof(dev->colourfx));

v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
"%s: After: mmal_ctrl:%p ctrl id:0x%x ctrl val:%d ret %d(%d)\n",
@@ -611,8 +608,8 @@ static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_bitrate(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
int ret;
struct vchiq_mmal_port *encoder_out;
@@ -629,8 +626,8 @@ static int ctrl_set_bitrate(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
u32 bitrate_mode;
struct vchiq_mmal_port *encoder_out;
@@ -649,15 +646,15 @@ static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
}

vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
- mmal_ctrl->mmal_id,
+ mmal_ctrl->mmal_id,
&bitrate_mode,
sizeof(bitrate_mode));
return 0;
}

static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
u32 u32_value;
struct vchiq_mmal_port *jpeg_out;
@@ -672,8 +669,8 @@ static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
u32 u32_value;
struct vchiq_mmal_port *vid_enc_ctl;
@@ -688,8 +685,8 @@ static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
struct mmal_parameter_video_profile param;
int ret = 0;
@@ -791,7 +788,7 @@ static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev,
}

ret = vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
mmal_ctrl->mmal_id,
&param, sizeof(param));
}
@@ -799,16 +796,16 @@ static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev,
}

static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev,
- struct v4l2_ctrl *ctrl,
- const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
{
int ret = 0;
int shutter_speed;
struct vchiq_mmal_port *control;

v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "scene mode selected %d, was %d\n", ctrl->val,
- dev->scene_mode);
+ "scene mode selected %d, was %d\n", ctrl->val,
+ dev->scene_mode);
control = &dev->component[MMAL_COMPONENT_CAMERA]->control;

if (ctrl->val == dev->scene_mode)
@@ -824,25 +821,25 @@ static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev,
shutter_speed = 0;

v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
- __func__, shutter_speed, dev->exposure_mode_user,
- dev->metering_mode);
+ "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
+ __func__, shutter_speed, dev->exposure_mode_user,
+ dev->metering_mode);
ret = vchiq_mmal_port_parameter_set(dev->instance,
- control,
- MMAL_PARAMETER_SHUTTER_SPEED,
- &shutter_speed,
- sizeof(shutter_speed));
+ control,
+ MMAL_PARAMETER_SHUTTER_SPEED,
+ &shutter_speed,
+ sizeof(shutter_speed));
ret += vchiq_mmal_port_parameter_set(dev->instance,
- control,
- MMAL_PARAMETER_EXPOSURE_MODE,
- &dev->exposure_mode_user,
- sizeof(u32));
+ control,
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &dev->exposure_mode_user,
+ sizeof(u32));
dev->exposure_mode_active = dev->exposure_mode_user;
ret += vchiq_mmal_port_parameter_set(dev->instance,
- control,
- MMAL_PARAMETER_EXP_METERING_MODE,
- &dev->metering_mode,
- sizeof(u32));
+ control,
+ MMAL_PARAMETER_EXP_METERING_MODE,
+ &dev->metering_mode,
+ sizeof(u32));
ret += set_framerate_params(dev);
} else {
/* Set up scene mode */
@@ -875,33 +872,32 @@ static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev,
metering_mode = scene->metering_mode;

v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
- __func__, shutter_speed, exposure_mode, metering_mode);
+ "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
+ __func__, shutter_speed, exposure_mode, metering_mode);

ret = vchiq_mmal_port_parameter_set(dev->instance, control,
- MMAL_PARAMETER_SHUTTER_SPEED,
- &shutter_speed,
- sizeof(shutter_speed));
- ret += vchiq_mmal_port_parameter_set(dev->instance,
- control,
- MMAL_PARAMETER_EXPOSURE_MODE,
- &exposure_mode,
- sizeof(u32));
+ MMAL_PARAMETER_SHUTTER_SPEED,
+ &shutter_speed,
+ sizeof(shutter_speed));
+ ret += vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &exposure_mode,
+ sizeof(u32));
dev->exposure_mode_active = exposure_mode;
ret += vchiq_mmal_port_parameter_set(dev->instance, control,
- MMAL_PARAMETER_EXPOSURE_MODE,
- &exposure_mode,
- sizeof(u32));
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &exposure_mode,
+ sizeof(u32));
ret += vchiq_mmal_port_parameter_set(dev->instance, control,
- MMAL_PARAMETER_EXP_METERING_MODE,
- &metering_mode,
- sizeof(u32));
+ MMAL_PARAMETER_EXP_METERING_MODE,
+ &metering_mode,
+ sizeof(u32));
ret += set_framerate_params(dev);
}
if (ret) {
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "%s: Setting scene to %d, ret=%d\n",
- __func__, ctrl->val, ret);
+ "%s: Setting scene to %d, ret=%d\n",
+ __func__, ctrl->val, ret);
ret = -EINVAL;
}
return 0;
@@ -925,7 +921,7 @@ static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl)
ret = mmal_ctrl->setter(dev, ctrl, mmal_ctrl);
if (ret)
pr_warn("ctrl id:%d/MMAL param %08X- returned ret %d\n",
- ctrl->id, mmal_ctrl->mmal_id, ret);
+ ctrl->id, mmal_ctrl->mmal_id, ret);
if (mmal_ctrl->ignore_errors)
ret = 0;
return ret;
@@ -935,8 +931,6 @@ static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = {
.s_ctrl = bm2835_mmal_s_ctrl,
};

-
-
static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
{
V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD,
@@ -1005,7 +999,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
{
V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
/* Units of 100usecs */
- 1, 1*1000*10, 100*10, 1, NULL,
+ 1, 1 * 1000 * 10, 100 * 10, 1, NULL,
MMAL_PARAMETER_SHUTTER_SPEED,
&ctrl_set_exposure,
false
@@ -1013,7 +1007,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
{
V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU,
0, ARRAY_SIZE(ev_bias_qmenu) - 1,
- (ARRAY_SIZE(ev_bias_qmenu)+1)/2 - 1, 0, ev_bias_qmenu,
+ (ARRAY_SIZE(ev_bias_qmenu) + 1) / 2 - 1, 0, ev_bias_qmenu,
MMAL_PARAMETER_EXPOSURE_COMP,
&ctrl_set_value_ev,
false
@@ -1101,7 +1095,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
},
{
V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD,
- 25*1000, 25*1000*1000, 10*1000*1000, 25*1000, NULL,
+ 25 * 1000, 25 * 1000 * 1000, 10 * 1000 * 1000, 25 * 1000, NULL,
MMAL_PARAMETER_VIDEO_BIT_RATE,
&ctrl_set_bitrate,
false
@@ -1192,8 +1186,8 @@ int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev)
&v4l2_ctrls[c]);
if (!v4l2_ctrls[c].ignore_errors && ret) {
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Failed when setting default values for ctrl %d\n",
- c);
+ "Failed when setting default values for ctrl %d\n",
+ c);
break;
}
}
@@ -1207,7 +1201,7 @@ int set_framerate_params(struct bm2835_mmal_dev *dev)
int ret;

if ((dev->exposure_mode_active != MMAL_PARAM_EXPOSUREMODE_OFF) &&
- (dev->exp_auto_priority)) {
+ (dev->exp_auto_priority)) {
/* Variable FPS. Define min FPS as 1fps.
* Max as max defined FPS.
*/
@@ -1224,35 +1218,32 @@ int set_framerate_params(struct bm2835_mmal_dev *dev)
}

v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Set fps range to %d/%d to %d/%d\n",
- fps_range.fps_low.num,
- fps_range.fps_low.den,
- fps_range.fps_high.num,
- fps_range.fps_high.den
- );
+ "Set fps range to %d/%d to %d/%d\n",
+ fps_range.fps_low.num,
+ fps_range.fps_low.den,
+ fps_range.fps_high.num,
+ fps_range.fps_high.den);

ret = vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_CAMERA]->
- output[MMAL_CAMERA_PORT_PREVIEW],
- MMAL_PARAMETER_FPS_RANGE,
- &fps_range, sizeof(fps_range));
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_PREVIEW],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
ret += vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_CAMERA]->
- output[MMAL_CAMERA_PORT_VIDEO],
- MMAL_PARAMETER_FPS_RANGE,
- &fps_range, sizeof(fps_range));
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_VIDEO],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
ret += vchiq_mmal_port_parameter_set(dev->instance,
- &dev->component[MMAL_COMPONENT_CAMERA]->
- output[MMAL_CAMERA_PORT_CAPTURE],
- MMAL_PARAMETER_FPS_RANGE,
- &fps_range, sizeof(fps_range));
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_CAPTURE],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
if (ret)
v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
- "Failed to set fps ret %d\n",
- ret);
+ "Failed to set fps ret %d\n", ret);

return ret;
-
}

int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
@@ -1318,7 +1309,7 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,

if (hdl->error) {
pr_err("error adding control %d/%d id 0x%x\n", c,
- V4L2_CTRL_COUNT, ctrl->id);
+ V4L2_CTRL_COUNT, ctrl->id);
return hdl->error;
}

@@ -1328,7 +1319,7 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
switch (ctrl->type) {
case MMAL_CONTROL_TYPE_CLUSTER:
v4l2_ctrl_auto_cluster(ctrl->min,
- &dev->ctrls[c+1],
+ &dev->ctrls[c + 1],
ctrl->max,
ctrl->def);
break;
@@ -1338,7 +1329,6 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
case MMAL_CONTROL_TYPE_INT_MENU:
break;
}
-
}

return 0;
diff --git a/drivers/staging/media/platform/bcm2835/mmal-vchiq.c b/drivers/staging/media/platform/bcm2835/mmal-vchiq.c
index 24bd2948136c..cc968442adc4 100644
--- a/drivers/staging/media/platform/bcm2835/mmal-vchiq.c
+++ b/drivers/staging/media/platform/bcm2835/mmal-vchiq.c
@@ -637,7 +637,6 @@ static void service_callback(void *param,

/* handling is different for buffer messages */
switch (msg->h.type) {
-
case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
vchi_held_msg_release(&msg_handle);
break;
@@ -722,7 +721,7 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
if (payload_len >
(MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
pr_err("payload length %d exceeds max:%d\n", payload_len,
- (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header)));
+ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header)));
return -EINVAL;
}

@@ -749,7 +748,7 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
return ret;
}

- ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, 3*HZ);
+ ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, 3 * HZ);
if (ret <= 0) {
pr_err("error %d waiting for sync completion\n", ret);
if (ret == 0)
@@ -807,7 +806,6 @@ static void dump_port_info(struct vchiq_mmal_port *port)

static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
{
-
/* todo do readonly fields need setting at all? */
p->type = port->type;
p->index = port->index;
@@ -883,7 +881,6 @@ static int port_info_set(struct vchiq_mmal_instance *instance,
vchi_held_msg_release(&rmsg_handle);

return ret;
-
}

/* use port info get message to retrive port information */
@@ -1334,7 +1331,7 @@ static int port_parameter_get(struct vchiq_mmal_instance *instance,
rmsg->u.port_parameter_get_reply.size);

pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
- ret, port->component->handle, port->handle, parameter_id);
+ ret, port->component->handle, port->handle, parameter_id);

release_msg:
vchi_held_msg_release(&rmsg_handle);
@@ -1358,12 +1355,12 @@ static int port_disable(struct vchiq_mmal_instance *instance,
ret = port_action_port(instance, port,
MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
if (ret == 0) {
-
/* drain all queued buffers on port */
spin_lock_irqsave(&port->slock, flags);

list_for_each_safe(buf_head, q, &port->buffers) {
struct mmal_buffer *mmalbuf;
+
mmalbuf = list_entry(buf_head, struct mmal_buffer,
list);
list_del(buf_head);
@@ -1415,6 +1412,7 @@ static int port_enable(struct vchiq_mmal_instance *instance,
hdr_count = 1;
list_for_each(buf_head, &port->buffers) {
struct mmal_buffer *mmalbuf;
+
mmalbuf = list_entry(buf_head, struct mmal_buffer,
list);
ret = buffer_from_host(instance, port, mmalbuf);
@@ -1456,7 +1454,6 @@ int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
mutex_unlock(&instance->vchiq_mutex);

return ret;
-
}

int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
--
2.11.0

Dave Stevenson

unread,
Feb 5, 2017, 5:40:04 PM2/5/17
to
Hi Mauro.

I'm going to stick my head above the parapet as one of the original
authors back when I worked at Broadcom.
As it happens I started working at Raspberry Pi last Monday, so that
puts me in a place where I can work on this again a bit more. (The last
two years have been just a spare time support role).
Whilst I have done kernel development work in various roles, it's all
been downstream so I've not been that active on these lists before.

All formatting/checkpatch comments noted.
Checkpatch was whinging when this was first written around December 2013
about long lines, so many got broken up to shut it up. Views on code
style and checkpatch seem to have changed a little since then.
I thought we had made checkpatch happy before the driver was pushed, but
with some of the comments still having // style I guess some slipped
through the net.
Yes chunks of this could do with refactoring to reduce the levels of
indentation - always more to do.
If I've removed any formatting/style type comments in my cuts it's not
because I'm ignoring them, just that they're not something that needs
discussion (just fixing). I've only taken out the really big lumps of
code with no comments on.

Newbie question: if this has already been merged to staging, where am I
looking for the relevant tree to add patches on top of?
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git branch
staging-next?

Responses to the rest inline.
TL;DR answer is that you are seeing the top edge of a full ISP
processing pipe and optional encoders running on the GPU, mainly as
there are blocks that can't be exposed for IP reasons (Raspberry Pi only
being the customer not silicon vendor constrains what can and can't be
made public).
That doesn't seem to fit very well into V4L2 which expects that it can
see all the detail, so there are a few nasty spots to shoe-horn it in.
If there are better ways to solve the problems, then I'm open to them.

Thanks
Dave


On 03/02/17 18:59, Mauro Carvalho Chehab wrote:
> HI Eric,
>
> Em Fri, 27 Jan 2017 13:54:58 -0800
> Eric Anholt <er...@anholt.net> escreveu:
>
>> - Supports raw YUV capture, preview, JPEG and H264.
>> - Uses videobuf2 for data transfer, using dma_buf.
>> - Uses 3.6.10 timestamping
>> - Camera power based on use
>> - Uses immutable input mode on video encoder
>>
>> This code comes from the Raspberry Pi kernel tree (rpi-4.9.y) as of
>> a15ba877dab4e61ea3fc7b006e2a73828b083c52.
>
> First of all, thanks for that! Having an upstream driver for the
> RPi camera is something that has been long waited!
>
> Greg was kick on merging it on staging ;) Anyway, the real review
> will happen when the driver becomes ready to be promoted out of
> staging. When you address the existing issues and get it ready to
> merge, please send the patch with such changes to linux-media ML.
> I'll do a full review on it by then.

Is that even likely given the dependence on VCHI? I wasn't expecting
VCHI to leave staging, which would force this to remain too.

> Still, let me do a quick review on this driver, specially at the
> non-MMAL code.
>
>>
>> Signed-off-by: Eric Anholt <er...@anholt.net>
>> ---
>> .../media/platform/bcm2835/bcm2835-camera.c | 2016 ++++++++++++++++++++
>> .../media/platform/bcm2835/bcm2835-camera.h | 145 ++
>> drivers/staging/media/platform/bcm2835/controls.c | 1345 +++++++++++++
>> .../staging/media/platform/bcm2835/mmal-common.h | 53 +
>> .../media/platform/bcm2835/mmal-encodings.h | 127 ++
>> .../media/platform/bcm2835/mmal-msg-common.h | 50 +
>> .../media/platform/bcm2835/mmal-msg-format.h | 81 +
>> .../staging/media/platform/bcm2835/mmal-msg-port.h | 107 ++
>> drivers/staging/media/platform/bcm2835/mmal-msg.h | 404 ++++
>> .../media/platform/bcm2835/mmal-parameters.h | 689 +++++++
>> .../staging/media/platform/bcm2835/mmal-vchiq.c | 1916 +++++++++++++++++++
>> .../staging/media/platform/bcm2835/mmal-vchiq.h | 178 ++
>> 12 files changed, 7111 insertions(+)
>> create mode 100644 drivers/staging/media/platform/bcm2835/bcm2835-camera.c
>> create mode 100644 drivers/staging/media/platform/bcm2835/bcm2835-camera.h
>> create mode 100644 drivers/staging/media/platform/bcm2835/controls.c
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-common.h
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-encodings.h
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-common.h
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-format.h
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-port.h
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg.h
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-parameters.h
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-vchiq.c
>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-vchiq.h
>>
>> diff --git a/drivers/staging/media/platform/bcm2835/bcm2835-camera.c b/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
>> new file mode 100644
>> index 000000000000..4f03949aecf3
>> --- /dev/null
>> +++ b/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
>> @@ -0,0 +1,2016 @@
>> +/*
>> + * Broadcom BM2835 V4L2 driver
>> + *
>> + * Copyright © 2013 Raspberry Pi (Trading) Ltd.
>> + *
>> + * This file is subject to the terms and conditions of the GNU General Public
>> + * License. See the file COPYING in the main directory of this archive
>> + * for more details.
>> + *
>> + * Authors: Vincent Sanders <vincent...@collabora.co.uk>
>> + * Dave Stevenson <dst...@broadcom.com>
>> + * Simon Mellor <sime...@broadcom.com>
>> + * Luke Diamand <lu...@broadcom.com>

All of these are now dead email addresses.
Mine could be updated to dave.st...@raspberrypi.org, but the others
should probably be deleted.

>> + */
>> +
>> +#include <linux/errno.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/slab.h>
>> +#include <media/videobuf2-vmalloc.h>
>> +#include <media/videobuf2-dma-contig.h>
>> +#include <media/v4l2-device.h>
>> +#include <media/v4l2-ioctl.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-fh.h>
>> +#include <media/v4l2-event.h>
>> +#include <media/v4l2-common.h>
>> +#include <linux/delay.h>
>> +
>> +#include "mmal-common.h"
>> +#include "mmal-encodings.h"
>> +#include "mmal-vchiq.h"
>> +#include "mmal-msg.h"
>> +#include "mmal-parameters.h"
>> +#include "bcm2835-camera.h"
>> +
>> +#define BM2835_MMAL_VERSION "0.0.2"
>> +#define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2"
>> +#define MIN_WIDTH 32
>> +#define MIN_HEIGHT 32
>> +#define MIN_BUFFER_SIZE (80*1024)
>> +
>> +#define MAX_VIDEO_MODE_WIDTH 1280
>> +#define MAX_VIDEO_MODE_HEIGHT 720
>
> Hmm... Doesn't the max resolution depend on the sensor?
>
>> +
>> +#define MAX_BCM2835_CAMERAS 2
>> +
>> +MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
>> +MODULE_AUTHOR("Vincent Sanders");
>> +MODULE_LICENSE("GPL");
>> +MODULE_VERSION(BM2835_MMAL_VERSION);
>> +
>> +int bcm2835_v4l2_debug;
>> +module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
>> +MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
>> +
>> +#define UNSET (-1)
>> +static int video_nr[] = {[0 ... (MAX_BCM2835_CAMERAS - 1)] = UNSET };
>> +module_param_array(video_nr, int, NULL, 0644);
>> +MODULE_PARM_DESC(video_nr, "videoX start numbers, -1 is autodetect");
>> +
>> +static int max_video_width = MAX_VIDEO_MODE_WIDTH;
>> +static int max_video_height = MAX_VIDEO_MODE_HEIGHT;
>> +module_param(max_video_width, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
>> +MODULE_PARM_DESC(max_video_width, "Threshold for video mode");
>> +module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
>> +MODULE_PARM_DESC(max_video_height, "Threshold for video mode");
>
> That seems a terrible hack! let the user specify the resolution via
> modprobe parameter... That should depend on the hardware capabilities
> instead.

This is sitting on top of an OpenMaxIL style camera component (though
accessed via MMAL - long story, but basically MMAL removed a bundle of
the ugly/annoying parts of IL).
It has the extension above V1.1.2 that you have a preview port, video
capture port, and stills capture port. Stills captures have additional
processing stages to improve image quality, whilst video has to maintain
framerate.

If you're asked for YUV or RGB frame, how do you choose between video or
stills? That's what is being set with these parameters, not the sensor
resolution. Having independent stills and video processing options
doesn't appear to be something that is supported in V4L2, but I'm open
to suggestions.
There were thoughts that they could be exposed as different /dev/videoN
devices, but that then poses a quandry to the client app as to which
node to open, so complicates the client significantly. On the plus side
it would then allow for things like zero shutter lag captures, and
stills during video, where you want multiple streams (apparently)
simultaneously, but is that worth the complexity? The general view was no.

>> +
>> +/* Gstreamer bug https://bugzilla.gnome.org/show_bug.cgi?id=726521
>> + * v4l2src does bad (and actually wrong) things when the vidioc_enum_framesizes
>> + * function says type V4L2_FRMSIZE_TYPE_STEPWISE, which we do by default.
>> + * It's happier if we just don't say anything at all, when it then
>> + * sets up a load of defaults that it thinks might work.
>> + * If gst_v4l2src_is_broken is non-zero, then we remove the function from
>> + * our function table list (actually switch to an alternate set, but same
>> + * result).
>> + */
>> +static int gst_v4l2src_is_broken;
>> +module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
>> +MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer");
>
> Not sure if I liked this hack here. AFAIKT, GStreamer fixed the bug with
> V4L2_FRMSIZE_TYPE_STEPWISE already.

I will double check on Monday. The main Raspberry Pi distribution is
based on Debian, so packages can be quite out of date. This bug
certainly affected Wheezy, but I don't know for certain about Jessie.
Sid still hasn't been adopted.

Also be aware that exactly the same issue of not supporting
V4L2_FRMSIZE_TYPE_STEPWISE affects Chromium for WebRTC, and they seem
not to be too bothered about fixing it -
https://bugs.chromium.org/p/chromium/issues/detail?id=249953
Now admittedly it's not the kernel's responsibility to work around
application issues, but if it hobbles a board then that is an issue.

>> +
>> +/* global device data array */
>> +static struct bm2835_mmal_dev *gdev[MAX_BCM2835_CAMERAS];
>> +
>> +#define FPS_MIN 1
>> +#define FPS_MAX 90
>> +
>> +/* timeperframe: min/max and default */
>> +static const struct v4l2_fract
>> + tpf_min = {.numerator = 1, .denominator = FPS_MAX},
>> + tpf_max = {.numerator = 1, .denominator = FPS_MIN},
>> + tpf_default = {.numerator = 1000, .denominator = 30000};
>> +
>> +/* video formats */
>> +static struct mmal_fmt formats[] = {
>> + {
>> + .name = "4:2:0, planar, YUV",
>> + .fourcc = V4L2_PIX_FMT_YUV420,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_I420,
>> + .depth = 12,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 1,
>
> Alignment here should be two tabs, instead.
>
>> + },
>> + {
>
> I prefer if you use, instead:
>
> }, {
>
>> + .name = "4:2:2, packed, YUYV",
>> + .fourcc = V4L2_PIX_FMT_YUYV,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_YUYV,
>> + .depth = 16,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 2,
>> + },
>> + {
>> + .name = "RGB24 (LE)",
>> + .fourcc = V4L2_PIX_FMT_RGB24,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_RGB24,
>> + .depth = 24,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 3,
>> + },
>> + {
>> + .name = "JPEG",
>> + .fourcc = V4L2_PIX_FMT_JPEG,
>> + .flags = V4L2_FMT_FLAG_COMPRESSED,
>> + .mmal = MMAL_ENCODING_JPEG,
>> + .depth = 8,
>> + .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
>> + .ybbp = 0,
>> + },
>> + {
>> + .name = "H264",
>> + .fourcc = V4L2_PIX_FMT_H264,
>> + .flags = V4L2_FMT_FLAG_COMPRESSED,
>> + .mmal = MMAL_ENCODING_H264,
>> + .depth = 8,
>> + .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
>> + .ybbp = 0,
>> + },
>> + {
>> + .name = "MJPEG",
>> + .fourcc = V4L2_PIX_FMT_MJPEG,
>> + .flags = V4L2_FMT_FLAG_COMPRESSED,
>> + .mmal = MMAL_ENCODING_MJPEG,
>> + .depth = 8,
>> + .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
>> + .ybbp = 0,
>> + },
>> + {
>> + .name = "4:2:2, packed, YVYU",
>> + .fourcc = V4L2_PIX_FMT_YVYU,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_YVYU,
>> + .depth = 16,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 2,
>> + },
>> + {
>> + .name = "4:2:2, packed, VYUY",
>> + .fourcc = V4L2_PIX_FMT_VYUY,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_VYUY,
>> + .depth = 16,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 2,
>> + },
>> + {
>> + .name = "4:2:2, packed, UYVY",
>> + .fourcc = V4L2_PIX_FMT_UYVY,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_UYVY,
>> + .depth = 16,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 2,
>> + },
>> + {
>> + .name = "4:2:0, planar, NV12",
>> + .fourcc = V4L2_PIX_FMT_NV12,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_NV12,
>> + .depth = 12,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 1,
>> + },
>> + {
>> + .name = "RGB24 (BE)",
>> + .fourcc = V4L2_PIX_FMT_BGR24,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_BGR24,
>> + .depth = 24,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 3,
>> + },
>> + {
>> + .name = "4:2:0, planar, YVU",
>> + .fourcc = V4L2_PIX_FMT_YVU420,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_YV12,
>> + .depth = 12,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 1,
>> + },
>> + {
>> + .name = "4:2:0, planar, NV21",
>> + .fourcc = V4L2_PIX_FMT_NV21,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_NV21,
>> + .depth = 12,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 1,
>> + },
>> + {
>> + .name = "RGB32 (BE)",
>> + .fourcc = V4L2_PIX_FMT_BGR32,
>> + .flags = 0,
>> + .mmal = MMAL_ENCODING_BGRA,
>> + .depth = 32,
>> + .mmal_component = MMAL_COMPONENT_CAMERA,
>> + .ybbp = 4,
>> + },
>> +};
>> +
>> +static struct mmal_fmt *get_format(struct v4l2_format *f)
>> +{
>> + struct mmal_fmt *fmt;
>> + unsigned int k;
>> +
>> + for (k = 0; k < ARRAY_SIZE(formats); k++) {
>> + fmt = &formats[k];
>> + if (fmt->fourcc == f->fmt.pix.pixelformat)
>> + break;
>> + }
>> +
>> + if (k == ARRAY_SIZE(formats))
>> + return NULL;
>
> Again, doesn't the formats depend on the camera sensor module?

Not in this case.
You're at the end of a full ISP processing pipe, and there is the option
for including either JPEG, MJPEG, or H264 encoding on the end. It is
supported to ask the camera component which formats it supports, but
you'll still need a conversion table from those MMAL types to V4L2
enums, and options for adding the encoded formats.

>> +
>> + return &formats[k];
>> +}
>> +
>> +/* ------------------------------------------------------------------
>> + Videobuf queue operations
>> + ------------------------------------------------------------------*/
>> +
>> +static int queue_setup(struct vb2_queue *vq,
>> + unsigned int *nbuffers, unsigned int *nplanes,
>> + unsigned int sizes[], struct device *alloc_ctxs[])
>> +{
>> + struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
>> + unsigned long size;
>> +
>> + /* refuse queue setup if port is not configured */
>> + if (dev->capture.port == NULL) {
>> + v4l2_err(&dev->v4l2_dev,
>> + "%s: capture port not configured\n", __func__);
>> + return -EINVAL;
>> + }
>> +
>> + size = dev->capture.port->current_buffer.size;
>> + if (size == 0) {
>> + v4l2_err(&dev->v4l2_dev,
>> + "%s: capture port buffer size is zero\n", __func__);
>> + return -EINVAL;
>> + }
>> +
>> + if (*nbuffers < (dev->capture.port->current_buffer.num + 2))
>> + *nbuffers = (dev->capture.port->current_buffer.num + 2);
>> +
>> + *nplanes = 1;
>> +
>> + sizes[0] = size;
>> +
>> + /*
>> + * videobuf2-vmalloc allocator is context-less so no need to set
>> + * alloc_ctxs array.
>> + */
>> +
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
>> + __func__, dev);
>> +
>> + return 0;
>> +}
>> +
>> +static int buffer_prepare(struct vb2_buffer *vb)
>> +{
>> + struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
>> + unsigned long size;
>> +
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
>> + __func__, dev);
>> +
>> + BUG_ON(dev->capture.port == NULL);
>> + BUG_ON(dev->capture.fmt == NULL);
>
> Please don't use BUG()/BUG_ON(), except if the driver would be doing
> something wrong enough to justify crashing the Kernel. That's not
> the case here. Instead, returning -ENODEV should be enough.
>
>> +
>> + size = dev->capture.stride * dev->capture.height;
>> + if (vb2_plane_size(vb, 0) < size) {
>> + v4l2_err(&dev->v4l2_dev,
>> + "%s data will not fit into plane (%lu < %lu)\n",
>> + __func__, vb2_plane_size(vb, 0), size);
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static inline bool is_capturing(struct bm2835_mmal_dev *dev)
>> +{
>> + return dev->capture.camera_port ==
>> + &dev->
>> + component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
>
> Weird indentation. Just merge everything on a single line.
>
>
>> +}
>> +
>> +static void buffer_cb(struct vchiq_mmal_instance *instance,
>> + struct vchiq_mmal_port *port,
>> + int status,
>> + struct mmal_buffer *buf,
>> + unsigned long length, u32 mmal_flags, s64 dts, s64 pts)
>> +{
>> + struct bm2835_mmal_dev *dev = port->cb_ctx;
>> +
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
>> + "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
>> + __func__, status, buf, length, mmal_flags, pts);
>> +
>> + if (status != 0) {
>> + /* error in transfer */
>> + if (buf != NULL) {
>> + /* there was a buffer with the error so return it */
>> + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
>> + }
>> + return;
>> + } else if (length == 0) {
>
> Doesn't need an else above. That would remove one indentation level,
> with is a good thing.
>
>> + /* stream ended */
>> + if (buf != NULL) {
>> + /* this should only ever happen if the port is
>> + * disabled and there are buffers still queued
>> + */
>> + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
>> + pr_debug("Empty buffer");
>> + } else if (dev->capture.frame_count) {
>> + /* grab another frame */
>> + if (is_capturing(dev)) {
>> + pr_debug("Grab another frame");
>> + vchiq_mmal_port_parameter_set(
>> + instance,
>> + dev->capture.
>> + camera_port,
>> + MMAL_PARAMETER_CAPTURE,
>> + &dev->capture.
>> + frame_count,
>> + sizeof(dev->capture.frame_count));
>> + }
>> + } else {
>> + /* signal frame completion */
>> + complete(&dev->capture.frame_cmplt);
>> + }
>
> Better to add a return here and avoid the else below. That makes it
> more readable, and avoid weird line breakages due to 80 column
> soft-limit.
>
>> + } else {
>> + if (dev->capture.frame_count) {
>> + if (dev->capture.vc_start_timestamp != -1 &&
>> + pts != 0) {
>> + struct timeval timestamp;
>> + s64 runtime_us = pts -
>> + dev->capture.vc_start_timestamp;
>
> Please either put the statement on a single line or indent the second
> like with the argument after the equal operator.
>
>> + u32 div = 0;
>> + u32 rem = 0;
>> +
>> + div =
>> + div_u64_rem(runtime_us, USEC_PER_SEC, &rem);
>> + timestamp.tv_sec =
>> + dev->capture.kernel_start_ts.tv_sec + div;
>> + timestamp.tv_usec =
>> + dev->capture.kernel_start_ts.tv_usec + rem;
>
> Please don't break the lines.
>> +
>> + if (timestamp.tv_usec >=
>> + USEC_PER_SEC) {
>
> I suspect you could put it on a single line.
>
>> + timestamp.tv_sec++;
>> + timestamp.tv_usec -=
>> + USEC_PER_SEC;
>> + }
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
>> + "Convert start time %d.%06d and %llu "
>> + "with offset %llu to %d.%06d\n",
>
> Don't break strings on multiple lines.
>
>> + (int)dev->capture.kernel_start_ts.
>> + tv_sec,
>> + (int)dev->capture.kernel_start_ts.
>> + tv_usec,
>> + dev->capture.vc_start_timestamp, pts,
>> + (int)timestamp.tv_sec,
>> + (int)timestamp.tv_usec);
>> + buf->vb.vb2_buf.timestamp = timestamp.tv_sec * 1000000000ULL +
>> + timestamp.tv_usec * 1000ULL;
>
> Not sure if I understood the above logic... Why don't you just do
> buf->vb.vb2_buf.timestamp = ktime_get_ns();

What's the processing latency through the ISP and optional
H264/MJPG/JPEG encode to get to this point? Typically you're looking at
30-80ms depending on exposure time and various other factors, which
would be enough to put A/V sync out if not compensated for.

The GPU side is timestamping all buffers with the CSI frame start
interrupt timestamp, but based on the GPU STC. There is a MMAL call to
read the GPU STC which is made at streamon (stored in
dev->capture.vc_start_timestamp), and therefore this is taking a delta
from there to get a more accurate timestamp.
(An improvement would be to reread it every N seconds to ensure there
was no drift, but the Linux kernel tick is actually off the same clock,
so it is only clock corrections that would introduce a drift).
As I understand it UVC is doing a similar thing, although it is trying
to compensate for clock drift too.

Now one could argue that ideally you want the timestamp for the start of
exposure, but there is no event outside of the sensor to trigger that.
You could compute it, but the exposure time control loop is running on
the GPU so the kernel doesn't know the exposure time. It's also a bit of
a funny thing anyway when dealing with rolling shutter sensors and
therefore considering which line you want the start of exposure for.

>
>> + } else {
>> + buf->vb.vb2_buf.timestamp = ktime_get_ns();
>> + }
>> +
>> + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
>> + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
>> +
>> + if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
>> + is_capturing(dev)) {
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
>> + "Grab another frame as buffer has EOS");
>> + vchiq_mmal_port_parameter_set(
>> + instance,
>> + dev->capture.
>> + camera_port,
>> + MMAL_PARAMETER_CAPTURE,
>> + &dev->capture.
>> + frame_count,
>> + sizeof(dev->capture.frame_count));
>> + }
>> + } else {
>> + /* signal frame completion */
>> + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
>> + complete(&dev->capture.frame_cmplt);
>
> I would move the error condition to happen before and just return,
> in order to reduce the indentation.
>
>> + }
>> + }
>> +}
>> +

<snip>

>> +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
>> + struct v4l2_fmtdesc *f)
>> +{
>> + struct mmal_fmt *fmt;
>> +
>> + if (f->index >= ARRAY_SIZE(formats))
>> + return -EINVAL;
>> +
>> + fmt = &formats[f->index];
>
> Shouldn't this be checking if the sensor is the Sony one or the Omnivision?
>
> Same applies to g_fmt and s_fmt.

Not when the ISP is in the way. This is effectively the list of output
formats from the ISP (and optional encoders), not the sensor.

>> +
>> + strlcpy(f->description, fmt->name, sizeof(f->description));
>> + f->pixelformat = fmt->fourcc;
>> + f->flags = fmt->flags;
>> +
>> + return 0;
>> +}
>> +
>> +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
>> + struct v4l2_format *f)
>> +{
>> + struct bm2835_mmal_dev *dev = video_drvdata(file);
>> +
>> + f->fmt.pix.width = dev->capture.width;
>> + f->fmt.pix.height = dev->capture.height;
>> + f->fmt.pix.field = V4L2_FIELD_NONE;
>> + f->fmt.pix.pixelformat = dev->capture.fmt->fourcc;
>> + f->fmt.pix.bytesperline = dev->capture.stride;
>> + f->fmt.pix.sizeimage = dev->capture.buffersize;
>> +
>> + if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24)
>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
>> + else if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG)
>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
>> + else
>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
>> + f->fmt.pix.priv = 0;
>> +
>> + v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
>> + __func__);
>> + return 0;
>> +}
>> +
>> +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
>> + struct v4l2_format *f)
>> +{
>> + struct bm2835_mmal_dev *dev = video_drvdata(file);
>> + struct mmal_fmt *mfmt;
>> +
>> + mfmt = get_format(f);
>> + if (!mfmt) {
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
>> + "Fourcc format (0x%08x) unknown.\n",
>> + f->fmt.pix.pixelformat);
>> + f->fmt.pix.pixelformat = formats[0].fourcc;
>> + mfmt = get_format(f);
>> + }
>> +
>> + f->fmt.pix.field = V4L2_FIELD_NONE;
>> +
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
>> + "Clipping/aligning %dx%d format %08X\n",
>> + f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
>> +
>> + v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, dev->max_width, 1,
>> + &f->fmt.pix.height, MIN_HEIGHT, dev->max_height,
>> + 1, 0);
>
> Hmm... that looks weird... For YUY formats, the step is usually 2 or 4.
> Also, as most cameras use internally a bayer sensor, they don't allow
> aligning to 1, except when then have scallers.

Correct. It should be multiples of 2 in either direction.

>> + f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
>> +
>> + /* Image buffer has to be padded to allow for alignment, even though
>> + * we then remove that padding before delivering the buffer.
>> + */
>> + f->fmt.pix.sizeimage = ((f->fmt.pix.height+15)&~15) *
>> + (((f->fmt.pix.width+31)&~31) * mfmt->depth) >> 3;
>
> It seems that you're fixing the bug at the steps used by
> v4l_bound_align_image() by rounding up the buffer size. That's wrong!
> Just ensure that the width/height will be a valid resolution and
> remove this hack.

No, this is working around the fact that very few clients respect
bytesperline (eg QV4L2 and libv4lconvert for many of the formats).

The ISP needs to be writing to buffers with the stride being a multiple
of 32, and height a multiple of 16 (and that includes between planes of
YUV420). V4L2 appears not to allow that, therefore there is then a
second operation run in-place on the buffer to remove that padding, but
the buffer needs to be sized sufficiently to handle the padded image first.
I had a conversation with Hans back in 2013 with regard this, and there
wasn't a good solution proposed. It could potentially be specified using
the cropping API, but that pushes the responsibility back onto every
client app to drive things in a very specific manner. If they don't
respect bytesperline they are even less likely to handle cropping.
You could restrict the resolution to being a multiple of 32 on the width
and 16 on the height, but in doing so you're not exposing the full
capabilities.

I'm open to suggestions as to how V4L2 can do this without just beating
up client apps who do the wrong thing.

Multiplanar formats seem not to be an option as the ISP is expecting one
contiguous buffer to be provided to take all the planes, but the
multiplanar stuff supplies multiple independent buffers. Again please
correct me if I'm wrong on that.

>> +
>> + if ((mfmt->flags & V4L2_FMT_FLAG_COMPRESSED) &&
>> + f->fmt.pix.sizeimage < MIN_BUFFER_SIZE)
>> + f->fmt.pix.sizeimage = MIN_BUFFER_SIZE;
>> +
>> + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
>> + else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
>> + else
>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
>> + f->fmt.pix.priv = 0;
>> +
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
>> + "Now %dx%d format %08X\n",
>> + f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
>> +
>> + v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
>> + __func__);
>> + return 0;
>> +}
>> +
>> +static int mmal_setup_components(struct bm2835_mmal_dev *dev,
>> + struct v4l2_format *f)
>> +{
>> + int ret;
>> + struct vchiq_mmal_port *port = NULL, *camera_port = NULL;
>> + struct vchiq_mmal_component *encode_component = NULL;
>> + struct mmal_fmt *mfmt = get_format(f);
>> +
>> + BUG_ON(!mfmt);
>> +
>> + if (dev->capture.encode_component) {
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
>> + "vid_cap - disconnect previous tunnel\n");
>> +
>> + /* Disconnect any previous connection */
>> + vchiq_mmal_port_connect_tunnel(dev->instance,
>> + dev->capture.camera_port, NULL);
>> + dev->capture.camera_port = NULL;
>> + ret = vchiq_mmal_component_disable(dev->instance,
>> + dev->capture.
>> + encode_component);
>> + if (ret)
>> + v4l2_err(&dev->v4l2_dev,
>> + "Failed to disable encode component %d\n",
>> + ret);
>> +
>> + dev->capture.encode_component = NULL;
>> + }
>> + /* format dependant port setup */
>> + switch (mfmt->mmal_component) {
>> + case MMAL_COMPONENT_CAMERA:
>> + /* Make a further decision on port based on resolution */
>> + if (f->fmt.pix.width <= max_video_width
>> + && f->fmt.pix.height <= max_video_height)
>> + camera_port = port =
>> + &dev->component[MMAL_COMPONENT_CAMERA]->
>> + output[MMAL_CAMERA_PORT_VIDEO];
>> + else
>> + camera_port = port =
>> + &dev->component[MMAL_COMPONENT_CAMERA]->
>> + output[MMAL_CAMERA_PORT_CAPTURE];
>
> Not sure if I got this... What are you intending to do here?

As noted above, what do you consider a still when dealing with raw RGB
or YUV buffers. This is switching between video and stills quality
processing based on resolution.

>> + break;
>> + case MMAL_COMPONENT_IMAGE_ENCODE:
>> + encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
>> + port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
>> + camera_port =
>> + &dev->component[MMAL_COMPONENT_CAMERA]->
>> + output[MMAL_CAMERA_PORT_CAPTURE];
>> + break;

<snip>

>> +/* timeperframe is arbitrary and continous */
>> +static int vidioc_enum_frameintervals(struct file *file, void *priv,
>> + struct v4l2_frmivalenum *fival)
>> +{
>> + struct bm2835_mmal_dev *dev = video_drvdata(file);
>> + int i;
>> +
>> + if (fival->index)
>> + return -EINVAL;
>> +
>> + for (i = 0; i < ARRAY_SIZE(formats); i++)
>> + if (formats[i].fourcc == fival->pixel_format)
>> + break;
>> + if (i == ARRAY_SIZE(formats))
>> + return -EINVAL;
>> +
>> + /* regarding width & height - we support any within range */
>> + if (fival->width < MIN_WIDTH || fival->width > dev->max_width ||
>> + fival->height < MIN_HEIGHT || fival->height > dev->max_height)
>> + return -EINVAL;
>> +
>> + fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
>
> That seems wrong! Webcam sensors usually require a multiple of at least 2
> for both horizontal and vertical resolutions, due to the way the pixels
> are packaged internally.
>
> Typically, only analog TV uses V4L2_FRMIVAL_TYPE_CONTINUOUS.
>
> Ok, if you're using expensive sensors with sophisticated scalers on
> it, you could have a continuous resolution, but I doubt this is the
> case here.

Isn't this frame interval, not resolution, although yes, it ought to
sanity check the resolution to be a multiple of 2 in each direction.

With regard frame interval, it could be specified as STEPWISE with an
increment of 32.5usecs or 18.9usecs (the default line time for ov5647
and imx219 respectively), but to most people that would count as continuous.

There is the added complication that the GPU code will select the most
appropriate sensor mode (about 7 are defined) based on the frame rate
and resolution requested, and each of the modes has different line
times. Reading it back would be possible but just seemed excessive.


I'm curious now, how does analogue TV count as CONTINUOUS when surely it
isn't something that can be set on a tuner that is only relaying the
received video signal.

>> +
>> + /* fill in stepwise (step=1.0 is requred by V4L2 spec) */
>> + fival->stepwise.min = tpf_min;
>> + fival->stepwise.max = tpf_max;
>> + fival->stepwise.step = (struct v4l2_fract) {1, 1};
>> +
>> + return 0;
>> +}
>> +

<snip>

>> +/* Returns the number of cameras, and also the max resolution supported
>> + * by those cameras.
>> + */
>> +static int get_num_cameras(struct vchiq_mmal_instance *instance,
>> + unsigned int resolutions[][2], int num_resolutions)
>> +{
>> + int ret;
>> + struct vchiq_mmal_component *cam_info_component;
>> + struct mmal_parameter_camera_info_t cam_info = {0};
>> + int param_size = sizeof(cam_info);
>> + int i;
>> +
>> + /* create a camera_info component */
>> + ret = vchiq_mmal_component_init(instance, "camera_info",
>> + &cam_info_component);
>> + if (ret < 0)
>> + /* Unusual failure - let's guess one camera. */
>> + return 1;
>
> Hmm... what happens if no cameras are plugged to RPi?

More that this query wasn't available on early GPU firmware versions -
it was added in 2016 when the IMX219 camera support was added.
If there are genuinely no cameras connected, then the camera component
create at a later stage will fail and that it also handled.

>> +
>> + if (vchiq_mmal_port_parameter_get(instance,
>> + &cam_info_component->control,
>> + MMAL_PARAMETER_CAMERA_INFO,
>> + &cam_info,
>> + &param_size)) {
>> + pr_info("Failed to get camera info\n");
>> + }
>> + for (i = 0;
>> + i < (cam_info.num_cameras > num_resolutions ?
>> + num_resolutions :
>> + cam_info.num_cameras);
>> + i++) {
>> + resolutions[i][0] = cam_info.cameras[i].max_width;
>> + resolutions[i][1] = cam_info.cameras[i].max_height;
>> + }
>> +
>> + vchiq_mmal_component_finalise(instance,
>> + cam_info_component);
>> +
>> + return cam_info.num_cameras;
>> +}
>> +
>> +static int set_camera_parameters(struct vchiq_mmal_instance *instance,
>> + struct vchiq_mmal_component *camera,
>> + struct bm2835_mmal_dev *dev)
>> +{
>> + int ret;
>> + struct mmal_parameter_camera_config cam_config = {
>> + .max_stills_w = dev->max_width,
>> + .max_stills_h = dev->max_height,
>> + .stills_yuv422 = 1,
>> + .one_shot_stills = 1,
>> + .max_preview_video_w = (max_video_width > 1920) ?
>> + max_video_width : 1920,
>> + .max_preview_video_h = (max_video_height > 1088) ?
>> + max_video_height : 1088,
>
> Hmm... why do you need to limit the max resolution to 1920x1088? Is it
> a limit of the MMAL/firmware?

Memory usage.
Video mode runs as an optimised pipeline so requires multiple frame buffers.
Stills mode typically has to stop the sensor, reprogram for full res
mode, stream for one frame, and then stops the sensor again, therefore
only one stills res buffer is required.
If you've specified video mode to run at more than 1080P, then the GPU
needs to be told up front so that it can allocate the extra memory.

>> + .num_preview_video_frames = 3,
>> + .stills_capture_circular_buffer_height = 0,
>> + .fast_preview_resume = 0,
>> + .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
>> + };
>> +
>> + ret = vchiq_mmal_port_parameter_set(instance, &camera->control,
>> + MMAL_PARAMETER_CAMERA_CONFIG,
>> + &cam_config, sizeof(cam_config));
>> + return ret;
>> +}
>> +
>> +#define MAX_SUPPORTED_ENCODINGS 20
>> +
>> +/* MMAL instance and component init */
>> +static int __init mmal_init(struct bm2835_mmal_dev *dev)
>> +{
>> + int ret;
>> + struct mmal_es_format *format;
>> + u32 bool_true = 1;
>> + u32 supported_encodings[MAX_SUPPORTED_ENCODINGS];
>> + int param_size;
>> + struct vchiq_mmal_component *camera;
>> +
>> + ret = vchiq_mmal_init(&dev->instance);
>> + if (ret < 0)
>> + return ret;
>> +
>> + /* get the camera component ready */
>> + ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
>> + &dev->component[MMAL_COMPONENT_CAMERA]);
>> + if (ret < 0)
>> + goto unreg_mmal;
>> +
>> + camera = dev->component[MMAL_COMPONENT_CAMERA];
>> + if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
>> + ret = -EINVAL;
>> + goto unreg_camera;
>> + }
>> +
>> + ret = set_camera_parameters(dev->instance,
>> + camera,
>> + dev);
>> + if (ret < 0)
>> + goto unreg_camera;
>> +
>> + /* There was an error in the firmware that meant the camera component
>> + * produced BGR instead of RGB.
>> + * This is now fixed, but in order to support the old firmwares, we
>> + * have to check.
>> + */
>> + dev->rgb_bgr_swapped = true;
>> + param_size = sizeof(supported_encodings);
>> + ret = vchiq_mmal_port_parameter_get(dev->instance,
>> + &camera->output[MMAL_CAMERA_PORT_CAPTURE],
>> + MMAL_PARAMETER_SUPPORTED_ENCODINGS,
>> + &supported_encodings,
>> + &param_size);
>> + if (ret == 0) {
>> + int i;
>> +
>> + for (i = 0; i < param_size/sizeof(u32); i++) {
>> + if (supported_encodings[i] == MMAL_ENCODING_BGR24) {
>> + /* Found BGR24 first - old firmware. */
>> + break;
>> + }
>> + if (supported_encodings[i] == MMAL_ENCODING_RGB24) {
>> + /* Found RGB24 first
>> + * new firmware, so use RGB24.
>> + */
>> + dev->rgb_bgr_swapped = false;
>> + break;
>> + }
>> + }
>> + }
>> + format = &camera->output[MMAL_CAMERA_PORT_PREVIEW].format;
>> +
>> + format->encoding = MMAL_ENCODING_OPAQUE;
>> + format->encoding_variant = MMAL_ENCODING_I420;
>> +
>> + format->es->video.width = 1024;
>> + format->es->video.height = 768;
>
> Shouldn't this be checking if the hardware supports 1024x768?
> Same note for similar parameters below.

All the supported sensors can do 1024x768 JPEG. This is just setting up
some defaults.

>> + format->es->video.crop.x = 0;
>> + format->es->video.crop.y = 0;
>> + format->es->video.crop.width = 1024;
>> + format->es->video.crop.height = 768;
>> + format->es->video.frame_rate.num = 0; /* Rely on fps_range */
>> + format->es->video.frame_rate.den = 1;
>> +
>> + format = &camera->output[MMAL_CAMERA_PORT_VIDEO].format;
>> +
>> + format->encoding = MMAL_ENCODING_OPAQUE;
>> + format->encoding_variant = MMAL_ENCODING_I420;
>> +
>> + format->es->video.width = 1024;
>> + format->es->video.height = 768;
>> + format->es->video.crop.x = 0;
>> + format->es->video.crop.y = 0;
>> + format->es->video.crop.width = 1024;
>> + format->es->video.crop.height = 768;
>> + format->es->video.frame_rate.num = 0; /* Rely on fps_range */
>> + format->es->video.frame_rate.den = 1;
>> +
>> + vchiq_mmal_port_parameter_set(dev->instance,
>> + &camera->output[MMAL_CAMERA_PORT_VIDEO],
>> + MMAL_PARAMETER_NO_IMAGE_PADDING,
>> + &bool_true, sizeof(bool_true));
>> +
>> + format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;
>> +
>> + format->encoding = MMAL_ENCODING_OPAQUE;
>> +
>> + format->es->video.width = 2592;
>> + format->es->video.height = 1944;
>
> Shouldn't this be checking if the hardware supports such resolution?
> Where this magic numbers came from? Why is it different than the previous
> resolution?

Video vs stills port.
TBH I'd actually want to double check whether this is necessary as I
thought it went through the standard s_fmt path to set up the default
mode, and that would do all this anyway.

>> + format->es->video.crop.x = 0;
>> + format->es->video.crop.y = 0;
>> + format->es->video.crop.width = 2592;
>> + format->es->video.crop.height = 1944;
>> + format->es->video.frame_rate.num = 0; /* Rely on fps_range */
>> + format->es->video.frame_rate.den = 1;
>> +
>> + dev->capture.width = format->es->video.width;
>> + dev->capture.height = format->es->video.height;
>> + dev->capture.fmt = &formats[0];
>> + dev->capture.encode_component = NULL;
>> + dev->capture.timeperframe = tpf_default;
>> + dev->capture.enc_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
>> + dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
>> +

<snip>

>> +int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev)
>> +{
>> + int c;
>> + int ret = 0;
>> +
>> + for (c = 0; c < V4L2_CTRL_COUNT; c++) {
>> + if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) {
>> + ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c],
>> + &v4l2_ctrls[c]);
>> + if (!v4l2_ctrls[c].ignore_errors && ret) {
>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
>> + "Failed when setting default values for ctrl %d\n",
>> + c);
>> + break;
>> + }
>> + }
>> + }
>
> There's something weird here... it is exposing all controls without
> checking if the hardware supports them. Does the VC4 firmware
> emulate the parameters on sensors that don't support? Otherwise,
> you'll need to query the hardware (or use DT) and only expose the controls that
> are provided by the given camera module.

You're at the end of the ISP. Everything except flips, exposure time and
analogue gain are implemented in the ISP so therefore they are supported.
All sensors are expected to support flips, exposure time and analogue
gain correctly (otherwise I complain to whoever wrote the camera driver!).

<snip>

>> +/* data in message, memcpy from packet into output buffer */
>> +static int inline_receive(struct vchiq_mmal_instance *instance,
>> + struct mmal_msg *msg,
>> + struct mmal_msg_context *msg_context)
>> +{
>> + unsigned long flags = 0;
>> +
>> + /* take buffer from queue */
>> + spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
>> + if (list_empty(&msg_context->u.bulk.port->buffers)) {
>> + spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
>> + pr_err("buffer list empty trying to receive inline\n");
>> +
>> + /* todo: this is a serious error, we should never have
>> + * commited a buffer_to_host operation to the mmal
>> + * port without the buffer to back it up (with
>> + * underflow handling) and there is no obvious way to
>> + * deal with this. Less bad than the bulk case as we
>> + * can just drop this on the floor but...unhelpful
>> + */
>
> If the bug is serious enough to corrupt memory, better to call BUG(),
> as otherwise it could do insane things, including corrupting a dirty
> disk cache - with could result on filesystem corruption.

I'd need to check exactly what the situation is here. It's been a while
since I've looked at the buffer handling code, but will review and make
it a BUG_ON if appropriate.

>> + return -EINVAL;
>> + }
>> +

<snip>

Michael Zoran

unread,
Feb 5, 2017, 6:20:05 PM2/5/17
to
Dave: I'd personally like to see the current version of vchi stabbed,
poisoned, beaten, shot, chained and thrown in a river.:)

Would it be possible to find another transport for this driver to
remove the dependency on VCHI? Given the process of improving drivers
in stagging, I don't expect VCHI to ever make it out of staging in it's
current form either. One possibility is mbox, but it has the limitation
of one one request at a time.

Also, you mention protecting IP and that V4L expects everything to be
exposed. How does V4L2 work if I have a hybrid software/hardware video
capture device?

In the case of other drivers in linux that upload a large firmware blob
into who knows where, how does the open source part of the driver hook
into the firmware blob?
> _______________________________________________
> linux-rpi-kernel mailing list
> linux-rp...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rpi-kernel

Greg Kroah-Hartman

unread,
Feb 6, 2017, 3:40:05 AM2/6/17
to
On Sun, Feb 05, 2017 at 10:15:21PM +0000, Dave Stevenson wrote:
> Newbie question: if this has already been merged to staging, where am I
> looking for the relevant tree to add patches on top of?
> git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git branch
> staging-next?

Yes, that is the correct place.

thanks,

greg k-h

Mauro Carvalho Chehab

unread,
Feb 6, 2017, 7:40:11 AM2/6/17
to
Em Sun, 5 Feb 2017 22:15:21 +0000
Dave Stevenson <linux...@destevenson.freeserve.co.uk> escreveu:

> Hi Mauro.
>
> I'm going to stick my head above the parapet as one of the original
> authors back when I worked at Broadcom.
> As it happens I started working at Raspberry Pi last Monday, so that
> puts me in a place where I can work on this again a bit more. (The last
> two years have been just a spare time support role).
> Whilst I have done kernel development work in various roles, it's all
> been downstream so I've not been that active on these lists before.
>
> All formatting/checkpatch comments noted.
> Checkpatch was whinging when this was first written around December 2013
> about long lines, so many got broken up to shut it up. Views on code
> style and checkpatch seem to have changed a little since then.
> I thought we had made checkpatch happy before the driver was pushed, but
> with some of the comments still having // style I guess some slipped
> through the net.

Checkpatch now has some checks that are only enabled with --strict.

That's because some maintainers end by accepting patches using
different criteria, because of historic reasons.

Also, please notice that checkpatch is just a tool that gives you
a hint about what's wrong, but doesn't spare manual review, as,
on some cases, we violate what's indicated there, as the real goal
of the coding style is to make the code simpler and easier to review.

> Yes chunks of this could do with refactoring to reduce the levels of
> indentation - always more to do.
> If I've removed any formatting/style type comments in my cuts it's not
> because I'm ignoring them, just that they're not something that needs
> discussion (just fixing). I've only taken out the really big lumps of
> code with no comments on.

Ok.

> Newbie question: if this has already been merged to staging, where am I
> looking for the relevant tree to add patches on top of?
> git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git branch
> staging-next?

Yes.

>
> Responses to the rest inline.
> TL;DR answer is that you are seeing the top edge of a full ISP
> processing pipe and optional encoders running on the GPU, mainly as
> there are blocks that can't be exposed for IP reasons (Raspberry Pi only
> being the customer not silicon vendor constrains what can and can't be
> made public).
> That doesn't seem to fit very well into V4L2 which expects that it can
> see all the detail, so there are a few nasty spots to shoe-horn it in.
> If there are better ways to solve the problems, then I'm open to them.

If the goal was to protect some IP related to the sensors, I guess
this is not going to protect anything, as there are recent driver
submissions on linux-media for the ov5647 driver:

https://patchwork.kernel.org/patch/9472441/

There are also open source drivers for the Sony imx219 camera
floating around for android and chromeOS:

https://chromium.googlesource.com/chromiumos/third_party/kernel/+/factory-ryu-6486.14.B-chromeos-3.14/drivers/media/i2c/soc_camera/imx219.c
https://android.googlesource.com/kernel/bcm/+/android-bcm-tetra-3.10-lollipop-wear-release/drivers/media/video/imx219.c

Plus, there's a datasheet (with another driver) available at:
https://github.com/rellimmot/Sony-IMX219-Raspberry-Pi-V2-CMOS

So, you're not really protecting IP here.

If the goal is to protect some proprietary algorithm meant to enhance
the camera captured streams, doing things like (auto-focus, auto-white
adjustments, scaling, etc), and/or implementing codec encoders, you should,
instead, restructure such codecs as mem2mem V4L2 drivers. There are a bunch
of such codecs already for other SoC where such functions are implemented
on GPU.

If you add DMABUF capabilities and media controller to the capture
driver and to the mem2mem drivers, userspace can use the V4L2 APIs
to use those modules using the arrangements they need, without
performance impacts.

So, by obfuscating the code, you're not protecting anything. Just making
harder for RPi customers to use, as you're providing a driver that is
limited.

>
> Thanks
> Dave
>
>
> On 03/02/17 18:59, Mauro Carvalho Chehab wrote:
> > HI Eric,
> >
> > Em Fri, 27 Jan 2017 13:54:58 -0800
> > Eric Anholt <er...@anholt.net> escreveu:
> >
> >> - Supports raw YUV capture, preview, JPEG and H264.
> >> - Uses videobuf2 for data transfer, using dma_buf.
> >> - Uses 3.6.10 timestamping
> >> - Camera power based on use
> >> - Uses immutable input mode on video encoder
> >>
> >> This code comes from the Raspberry Pi kernel tree (rpi-4.9.y) as of
> >> a15ba877dab4e61ea3fc7b006e2a73828b083c52.
> >
> > First of all, thanks for that! Having an upstream driver for the
> > RPi camera is something that has been long waited!
> >
> > Greg was kick on merging it on staging ;) Anyway, the real review
> > will happen when the driver becomes ready to be promoted out of
> > staging. When you address the existing issues and get it ready to
> > merge, please send the patch with such changes to linux-media ML.
> > I'll do a full review on it by then.
>
> Is that even likely given the dependence on VCHI? I wasn't expecting
> VCHI to leave staging, which would force this to remain too.

I didn't analyze the VCHI driver. As I said before, if you rewrite
the driver in a way that the Kernel can actually see the sensors
via an I2C interface, you probably can get rid of the VCHI interface
for the capture part.

You could take a look on the other mem2mem drivers and see if are
there some way to provide an interface for the GPU encoders in a
similar way to what those drivers do.
I see.

> If you're asked for YUV or RGB frame, how do you choose between video or
> stills? That's what is being set with these parameters, not the sensor
> resolution. Having independent stills and video processing options
> doesn't appear to be something that is supported in V4L2, but I'm open
> to suggestions.

At the capture stage:

Assuming that the user wants to use different resolutions for video and
stills (for example, you're seeing a real time video, then you "click"
to capture a still image), you can create two buffer groups, one for
low-res video and another one for high-res image. When the button is
clicked, it will stop the low-res stream, set the parameters for the
high-res image and capture it.

For post-processing stage:

Switch the media pipeline via the media controller adding the post
processing codecs that will enhance the image.

We're discussing for a while (and there are patches floating around)
ways to improve it via the request API (with would allow different
configs to be ready to be use allowing to switch between those
settings in an atomic way, reducing the time to switch from different
configs).

> There were thoughts that they could be exposed as different /dev/videoN
> devices, but that then poses a quandry to the client app as to which
> node to open, so complicates the client significantly. On the plus side
> it would then allow for things like zero shutter lag captures, and
> stills during video, where you want multiple streams (apparently)
> simultaneously, but is that worth the complexity? The general view was no.

IMHO, that's the best option if you want to give flexibility to
user apps. Those that don't want/need it, could just setup the
pipeline via media-ctl and use any V4L application to get images from
a single /dev/videoN devnode; those that want complex setups could use
multiple /dev/videoN nodes.

>
> >> +
> >> +/* Gstreamer bug https://bugzilla.gnome.org/show_bug.cgi?id=726521
> >> + * v4l2src does bad (and actually wrong) things when the vidioc_enum_framesizes
> >> + * function says type V4L2_FRMSIZE_TYPE_STEPWISE, which we do by default.
> >> + * It's happier if we just don't say anything at all, when it then
> >> + * sets up a load of defaults that it thinks might work.
> >> + * If gst_v4l2src_is_broken is non-zero, then we remove the function from
> >> + * our function table list (actually switch to an alternate set, but same
> >> + * result).
> >> + */
> >> +static int gst_v4l2src_is_broken;
> >> +module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
> >> +MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer");
> >
> > Not sure if I liked this hack here. AFAIKT, GStreamer fixed the bug with
> > V4L2_FRMSIZE_TYPE_STEPWISE already.
>
> I will double check on Monday. The main Raspberry Pi distribution is
> based on Debian, so packages can be quite out of date. This bug
> certainly affected Wheezy, but I don't know for certain about Jessie.
> Sid still hasn't been adopted.

Well, at the RPi distro, the best would be to backport the gst patches
that fixed the bug instead, as it would affect other V4L2 hardware
connected via USB too.

> Also be aware that exactly the same issue of not supporting
> V4L2_FRMSIZE_TYPE_STEPWISE affects Chromium for WebRTC, and they seem
> not to be too bothered about fixing it -
> https://bugs.chromium.org/p/chromium/issues/detail?id=249953
> Now admittedly it's not the kernel's responsibility to work around
> application issues, but if it hobbles a board then that is an issue.

Those lazy maintainers... :-)
The better would be to split those GPU encoders on a mem2mem driver.
This way, if all the userspace want is the raw images, they can
get it without passing though a GPU pipeline.

The big problem here is that the user doesn't really know what
formats are produced by the camera from those that are post-processed.

On applications that require low latency, that could have a big
impact. For example, if someone is using a RPi on a robot or on
a self-piloted drone, the lowest latency the better.
Ah, so this is due to the extra latency introduced by GPU.

> (An improvement would be to reread it every N seconds to ensure there
> was no drift, but the Linux kernel tick is actually off the same clock,
> so it is only clock corrections that would introduce a drift).
> As I understand it UVC is doing a similar thing, although it is trying
> to compensate for clock drift too.

What happens when daylight saving time changes is applied? Will it
indicate an one hour latency?
If you find a bug on any clients that we maintain (qv4l2, libv4l,
tvtime, xawtv), please submit us a patch. If this issue was fixed
when you noticed (in 2013, as you're saying below), then we wouldn't
need to concern about it nowadays ;)

> The ISP needs to be writing to buffers with the stride being a multiple
> of 32, and height a multiple of 16 (and that includes between planes of
> YUV420). V4L2 appears not to allow that, therefore there is then a
> second operation run in-place on the buffer to remove that padding, but
> the buffer needs to be sized sufficiently to handle the padded image first.
>
> I had a conversation with Hans back in 2013 with regard this, and there
> wasn't a good solution proposed. It could potentially be specified using
> the cropping API, but that pushes the responsibility back onto every
> client app to drive things in a very specific manner. If they don't
> respect bytesperline they are even less likely to handle cropping.
> You could restrict the resolution to being a multiple of 32 on the width
> and 16 on the height, but in doing so you're not exposing the full
> capabilities.
>
> I'm open to suggestions as to how V4L2 can do this without just beating
> up client apps who do the wrong thing.
>
> Multiplanar formats seem not to be an option as the ISP is expecting one
> contiguous buffer to be provided to take all the planes, but the
> multiplanar stuff supplies multiple independent buffers. Again please
> correct me if I'm wrong on that.

Not sure if I fully understand what happens there... Does it add
alignment pads in the middle of the image, or just at the end of
the buffer? If such pads are added in the middle of the image, it
is actually violating the fourcc formats, as they're not meant to
have PADs inside it.
That sounds an ugly hack. Unlikely to be accepted upstream.
On analog TV, the horizontal resolution configures the sampling rate.
As the image is analog, it is possible to sample it on any interval.
Typical values are from 32 to 720. Both the luminance and chroma
A/D converters can be configured the same way, on most devices.

Also, most hardware have a scaler. The scaler does scaling for
the vertical resolution and for horizontal resolution. On most
hardware, the step for both scales is one. Typically, the output
format is either RGB or BGR.
Ok.
I see. One additional reason why it would be good if the capture
driver could run independently from GPU. That way, only the
encoding codecs would have such restriction.
Ok.
I guess the OV5647 doesn't support this resolution, even for still
images, as it is a 5Mpixel sensor.
Ok.
Ok.

> >> + return -EINVAL;
> >> + }
> >> +
>
> <snip>



Thanks,
Mauro

Hans Verkuil

unread,
Feb 6, 2017, 8:00:05 AM2/6/17
to
On 02/06/2017 12:37 PM, Dave Stevenson wrote:
> Hi Hans.
>
> On 06/02/17 09:08, Hans Verkuil wrote:
>> Hi Eric,
>>
>> Great to see this driver appearing for upstream merging!
>>
>> See below for my review comments, focusing mostly on V4L2 specifics.
>>
>> On 01/27/2017 10:54 PM, Eric Anholt wrote:
>>> - Supports raw YUV capture, preview, JPEG and H264.
>>> - Uses videobuf2 for data transfer, using dma_buf.
>>> - Uses 3.6.10 timestamping
>>> - Camera power based on use
>>> - Uses immutable input mode on video encoder
>>>
>>> This code comes from the Raspberry Pi kernel tree (rpi-4.9.y) as of
>>> a15ba877dab4e61ea3fc7b006e2a73828b083c52.
>>>
>>> Signed-off-by: Eric Anholt <er...@anholt.net>
>>> ---
>>> .../media/platform/bcm2835/bcm2835-camera.c | 2016 ++++++++++++++++++++
>>> .../media/platform/bcm2835/bcm2835-camera.h | 145 ++
>>> drivers/staging/media/platform/bcm2835/controls.c | 1345 +++++++++++++
>>> .../staging/media/platform/bcm2835/mmal-common.h | 53 +
>>> .../media/platform/bcm2835/mmal-encodings.h | 127 ++
>>> .../media/platform/bcm2835/mmal-msg-common.h | 50 +
>>> .../media/platform/bcm2835/mmal-msg-format.h | 81 +
>>> .../staging/media/platform/bcm2835/mmal-msg-port.h | 107 ++
>>> drivers/staging/media/platform/bcm2835/mmal-msg.h | 404 ++++
>>> .../media/platform/bcm2835/mmal-parameters.h | 689 +++++++
>>> .../staging/media/platform/bcm2835/mmal-vchiq.c | 1916 +++++++++++++++++++
>>> .../staging/media/platform/bcm2835/mmal-vchiq.h | 178 ++
>>> 12 files changed, 7111 insertions(+)
>>> create mode 100644 drivers/staging/media/platform/bcm2835/bcm2835-camera.c
>>> create mode 100644 drivers/staging/media/platform/bcm2835/bcm2835-camera.h
>>> create mode 100644 drivers/staging/media/platform/bcm2835/controls.c
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-common.h
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-encodings.h
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-common.h
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-format.h
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-port.h
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg.h
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-parameters.h
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-vchiq.c
>>> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-vchiq.h
>>>
>>> diff --git a/drivers/staging/media/platform/bcm2835/bcm2835-camera.c b/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
>>> new file mode 100644
>>> index 000000000000..4f03949aecf3
>>> --- /dev/null
>>> +++ b/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
>>> @@ -0,0 +1,2016 @@
>>
>> <snip>
>>
>>> +static int start_streaming(struct vb2_queue *vq, unsigned int count)
>>> +{
>>> + struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
>>> + int ret;
>>> + int parameter_size;
>>> +
>>> + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
>>> + __func__, dev);
>>> +
>>> + /* ensure a format has actually been set */
>>> + if (dev->capture.port == NULL)
>>> + return -EINVAL;
>>
>> Standard mistake. If start_streaming returns an error, then it should call vb2_buffer_done
>> for all queued buffers with state VB2_BUF_STATE_QUEUED. Otherwise the buffer administration
>> gets unbalanced.
>
> OK.
> This is an error path that I'm not convinced can ever be followed, just
> defensive programming. It may be a candidate for just removing, but yes
> otherwise it needs to be fixed to do the right thing.

It's not for this specific 'if', it is for all the paths where start_streaming or
stop_streaming can return a non-0 code.

Sorry if that was clear to you already, I just mention this to be unambiguous.

<snip>

>>> + f->pixelformat = fmt->fourcc;
>>> + f->flags = fmt->flags;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
>>> + struct v4l2_format *f)
>>> +{
>>> + struct bm2835_mmal_dev *dev = video_drvdata(file);
>>> +
>>> + f->fmt.pix.width = dev->capture.width;
>>> + f->fmt.pix.height = dev->capture.height;
>>> + f->fmt.pix.field = V4L2_FIELD_NONE;
>>> + f->fmt.pix.pixelformat = dev->capture.fmt->fourcc;
>>> + f->fmt.pix.bytesperline = dev->capture.stride;
>>> + f->fmt.pix.sizeimage = dev->capture.buffersize;
>>> +
>>> + if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24)
>>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
>>> + else if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG)
>>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
>>> + else
>>> + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
>>
>> Colorspace has nothing to do with the pixel format. It should come from the
>> sensor/video receiver.
>>
>> If this information is not available, then COLORSPACE_SRGB is generally a
>> good fallback.
>
> I would if I could, but then I fail v4l2-compliance on V4L2_PIX_FMT_JPEG
> https://git.linuxtv.org/v4l-utils.git/tree/utils/v4l2-compliance/v4l2-test-formats.cpp#n329
> The special case for JPEG therefore has to remain.

Correct. Sorry, my fault, I forgot about that.

>
> It looks like I tripped over the subtlety between V4L2_COLORSPACE_,
> V4L2_XFER_FUNC_, V4L2_YCBCR_ENC_, and V4L2_QUANTIZATION_, and Y'CbCr
> encoding vs colourspace.
>
> The ISP coefficients are set up for BT601 limited range, and any
> conversion back to RGB is done based on that. That seemed to fit
> SMPTE170M rather than SRGB.

Colorspace refers to the primary colors + whitepoint that are used to
create the colors (basically this answers the question to which colors
R, G and B exactly refer to). The SMPTE170M has different primaries
compared to sRGB (and a different default transfer function as well).

RGB vs Y'CbCr is just an encoding and it doesn't change the underlying
colorspace. Unfortunately, the term 'colorspace' is often abused to just
refer to RGB vs Y'CbCr.

If the colorspace is SRGB, then when the pixelformat is a Y'CbCr encoding,
then the BT601 limited range encoding is implied, unless overridden via
the ycbcr_enc and/or quantization fields in struct v4l2_pix_format.

In other words, this does already the right thing.

The JPEG colorspace is a short-hand for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601
and V4L2_QUANTIZATION_FULL_RANGE. It's historical that this colorspace exists.

If I would redesign this this JPEG colorspace would be dropped.

For a lot more colorspace information see:

https://hverkuil.home.xs4all.nl/spec/uapi/v4l/colorspaces.html

>
> I do note that as there is now support for more RGB formats (BGR24 and
> BGR32) the first "if" needs extending to cover those. Or I don't care
> and only special case JPEG with all others just reporting SRGB.
>

Only special case JPEG.

But as I said, this information really needs to come from the sensor or
video receiver since this driver has no knowledge of this.

<snip>

>>
>> This is IMHO unnecessarily complex.
>>
>> My recommendation is that controls are added with a set of v4l2_ctrl_new_std* calls
>> or if you really want to by walking a struct v4l2_ctrl_config array and adding controls
>> via v4l2_ctrl_new_custom.
>>
>> The s_ctrl is a switch that calls the 'setter' function.
>>
>> No need for arrays, callbacks, etc. Just keep it simple.
>
> I can look into that, but I'm not sure I fully follow what you are
> suggesting.
>
> In the current implementation things like V4L2_CID_SATURATION,
> V4L2_CID_SHARPNESS, V4L2_CID_CONTRAST, and V4L2_CID_BRIGHTNESS all use
> the one common ctrl_set_rational setter function because the only thing
> different in setting is the MMAL_PARAMETER_xxx value. I guess that could
> move into the common setter based on V4L2_CID_xxx, but then the control
> configuration is split between multiple places which feels less well
> contained.

See e.g. samples/v4l/v4l2-pci-skeleton.c: in the probe function (or in a
function called from there if there are a lot of controls) you add the
controls, and in s_ctrl you handle them.

But this is just my preference.

So in s_ctrl you would see something like this:

switch (ctrl->id) {
case V4L2_CID_SATURATION:
ctrl_set_rational(ctrl->val, MMAL_PARAMETER_SAT);
break;
case V4L2_CID_BRIGHTNESS:
ctrl_set_rational(ctrl->val, MMAL_PARAMETER_BRIGHTNESS);
break;
...
}

>
>> <snip>
>>
>> Final question: did you run v4l2-compliance over this driver? Before this driver can
>> be moved out of staging it should pass the compliance tests. Note: always compile
>> this test from the main repository, don't rely on distros. That ensures you use the
>> latest code.
>>
>> The compliance test is part of the v4l-utils repo (https://git.linuxtv.org/v4l-utils.git/).
>>
>> If you have any questions about the v4l2-compliance output (it can be a bit obscure at
>> times), just mail me or ask the question on the #v4l irc channel.
>
> I haven't checked this version, but the downstream version has 43
> passes, 0 failures, 0 warnings.
>
> The full output:
> v4l2-compliance SHA : 99306f20cc7e76cf2161e3059de4da245aed2130

That's pretty recent. Good to know you've used this.

Also test with v4l2-compliance -f: this tests all available formats.

>
> Driver Info:
> Driver name : bm2835 mmal
> Card type : mmal service 16.1
> Bus info : platform:bcm2835-v4l2
> Driver version: 4.4.45
> Capabilities : 0x85200005
> Video Capture
> Video Overlay
> Read/Write
> Streaming
> Extended Pix Format
> Device Capabilities
> Device Caps : 0x05200005
> Video Capture
> Video Overlay
> Read/Write
> Streaming
> Extended Pix Format
>
> Compliance test for device /dev/video0 (not using libv4l2):
>
> Required ioctls:
> test VIDIOC_QUERYCAP: OK
>
> Allow for multiple opens:
> test second video open: OK
> test VIDIOC_QUERYCAP: OK
> test VIDIOC_G/S_PRIORITY: OK
> test for unlimited opens: OK
>
> Debug ioctls:
> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
> test VIDIOC_LOG_STATUS: OK
>
> Input ioctls:
> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
> test VIDIOC_ENUMAUDIO: OK (Not Supported)
> test VIDIOC_G/S/ENUMINPUT: OK
> test VIDIOC_G/S_AUDIO: OK (Not Supported)
> Inputs: 1 Audio Inputs: 0 Tuners: 0
>
> Output ioctls:
> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
> Outputs: 0 Audio Outputs: 0 Modulators: 0
>
> Input/Output configuration ioctls:
> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
> test VIDIOC_G/S_EDID: OK (Not Supported)
>
> Test input 0:
>
> Control ioctls:
> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
> test VIDIOC_QUERYCTRL: OK
> test VIDIOC_G/S_CTRL: OK
> test VIDIOC_G/S/TRY_EXT_CTRLS: OK
> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> Standard Controls: 33 Private Controls: 0
>
> Format ioctls:
> test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
> test VIDIOC_G/S_PARM: OK
> test VIDIOC_G_FBUF: OK
> test VIDIOC_G_FMT: OK
> test VIDIOC_TRY_FMT: OK
> test VIDIOC_S_FMT: OK
> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> test Cropping: OK (Not Supported)
> test Composing: OK (Not Supported)
> test Scaling: OK

Is scaling supported? Just checking.

>
> Codec ioctls:
> test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
> test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
>
> Buffer ioctls:
> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
> test VIDIOC_EXPBUF: OK (Not Supported)
>
> Test input 0:
>
>
> Total: 43, Succeeded: 43, Failed: 0, Warnings: 0

Note that v4l2-compliance does very limited testing of overlay handling.
You should test this manually to make sure it functions properly.

Regards,

Hans

Hans Verkuil

unread,
Feb 6, 2017, 8:00:07 AM2/6/17
to
On 01/27/2017 10:54 PM, Eric Anholt wrote:
> - Supports raw YUV capture, preview, JPEG and H264.
> - Uses videobuf2 for data transfer, using dma_buf.
> - Uses 3.6.10 timestamping
> - Camera power based on use
> - Uses immutable input mode on video encoder
>
> This code comes from the Raspberry Pi kernel tree (rpi-4.9.y) as of
> a15ba877dab4e61ea3fc7b006e2a73828b083c52.
>
> Signed-off-by: Eric Anholt <er...@anholt.net>
> ---
> .../media/platform/bcm2835/bcm2835-camera.c | 2016 ++++++++++++++++++++
> .../media/platform/bcm2835/bcm2835-camera.h | 145 ++
> drivers/staging/media/platform/bcm2835/controls.c | 1345 +++++++++++++
> .../staging/media/platform/bcm2835/mmal-common.h | 53 +
> .../media/platform/bcm2835/mmal-encodings.h | 127 ++
> .../media/platform/bcm2835/mmal-msg-common.h | 50 +
> .../media/platform/bcm2835/mmal-msg-format.h | 81 +
> .../staging/media/platform/bcm2835/mmal-msg-port.h | 107 ++
> drivers/staging/media/platform/bcm2835/mmal-msg.h | 404 ++++
> .../media/platform/bcm2835/mmal-parameters.h | 689 +++++++
> .../staging/media/platform/bcm2835/mmal-vchiq.c | 1916 +++++++++++++++++++
> .../staging/media/platform/bcm2835/mmal-vchiq.h | 178 ++
> 12 files changed, 7111 insertions(+)
> create mode 100644 drivers/staging/media/platform/bcm2835/bcm2835-camera.c
> create mode 100644 drivers/staging/media/platform/bcm2835/bcm2835-camera.h
> create mode 100644 drivers/staging/media/platform/bcm2835/controls.c
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-common.h
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-encodings.h
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-common.h
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-format.h
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg-port.h
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-msg.h
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-parameters.h
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-vchiq.c
> create mode 100644 drivers/staging/media/platform/bcm2835/mmal-vchiq.h
>
> diff --git a/drivers/staging/media/platform/bcm2835/bcm2835-camera.c b/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
> new file mode 100644
> index 000000000000..4f03949aecf3
> --- /dev/null
> +++ b/drivers/staging/media/platform/bcm2835/bcm2835-camera.c
> @@ -0,0 +1,2016 @@

<snip>

> +static int __init bm2835_mmal_init(void)
> +{
> + int ret;
> + struct bm2835_mmal_dev *dev;
> + struct vb2_queue *q;
> + int camera;
> + unsigned int num_cameras;
> + struct vchiq_mmal_instance *instance;
> + unsigned int resolutions[MAX_BCM2835_CAMERAS][2];
> +
> + ret = vchiq_mmal_init(&instance);
> + if (ret < 0)
> + return ret;
> +
> + num_cameras = get_num_cameras(instance,
> + resolutions,
> + MAX_BCM2835_CAMERAS);
> + if (num_cameras > MAX_BCM2835_CAMERAS)
> + num_cameras = MAX_BCM2835_CAMERAS;
> +
> + for (camera = 0; camera < num_cameras; camera++) {
> + dev = kzalloc(sizeof(struct bm2835_mmal_dev), GFP_KERNEL);
> + if (!dev)
> + return -ENOMEM;
> +
> + dev->camera_num = camera;
> + dev->max_width = resolutions[camera][0];
> + dev->max_height = resolutions[camera][1];
> +
> + /* setup device defaults */
> + dev->overlay.w.left = 150;
> + dev->overlay.w.top = 50;
> + dev->overlay.w.width = 1024;
> + dev->overlay.w.height = 768;
> + dev->overlay.clipcount = 0;
> + dev->overlay.field = V4L2_FIELD_NONE;
> + dev->overlay.global_alpha = 255;
> +
> + dev->capture.fmt = &formats[3]; /* JPEG */
> +
> + /* v4l device registration */
> + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
> + "%s", BM2835_MMAL_MODULE_NAME);
> + ret = v4l2_device_register(NULL, &dev->v4l2_dev);
> + if (ret)
> + goto free_dev;
> +
> + /* setup v4l controls */
> + ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
> + if (ret < 0)
> + goto unreg_dev;
> + dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
> +
> + /* mmal init */
> + dev->instance = instance;
> + ret = mmal_init(dev);
> + if (ret < 0)
> + goto unreg_dev;
> +
> + /* initialize queue */
> + q = &dev->capture.vb_vidq;
> + memset(q, 0, sizeof(*q));
> + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;

I'm missing VB2_DMABUF here!

In fact, with dmabuf support I wonder if you still need overlay support.

Using dma-buf and just pass a gpu buffer to v4l2 is preferred over overlays.

Regards,

Hans

> + q->drv_priv = dev;
> + q->buf_struct_size = sizeof(struct mmal_buffer);
> + q->ops = &bm2835_mmal_video_qops;
> + q->mem_ops = &vb2_vmalloc_memops;
> + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> + ret = vb2_queue_init(q);
> + if (ret < 0)
> + goto unreg_dev;
> +
> + /* v4l2 core mutex used to protect all fops and v4l2 ioctls. */
> + mutex_init(&dev->mutex);
> +
> + /* initialise video devices */
> + ret = bm2835_mmal_init_device(dev, &dev->vdev);
> + if (ret < 0)
> + goto unreg_dev;
> +
> + /* Really want to call vidioc_s_fmt_vid_cap with the default
> + * format, but currently the APIs don't join up.
> + */
> + ret = mmal_setup_components(dev, &default_v4l2_format);
> + if (ret < 0) {
> + v4l2_err(&dev->v4l2_dev,
> + "%s: could not setup components\n", __func__);
> + goto unreg_dev;
> + }
> +
> + v4l2_info(&dev->v4l2_dev,
> + "Broadcom 2835 MMAL video capture ver %s loaded.\n",
> + BM2835_MMAL_VERSION);
> +
> + gdev[camera] = dev;
> + }
> + return 0;
> +
> +unreg_dev:
> + v4l2_ctrl_handler_free(&dev->ctrl_handler);
> + v4l2_device_unregister(&dev->v4l2_dev);
> +
> +free_dev:
> + kfree(dev);
> +
> + for ( ; camera > 0; camera--) {
> + bcm2835_cleanup_instance(gdev[camera]);
> + gdev[camera] = NULL;
> + }
> + pr_info("%s: error %d while loading driver\n",
> + BM2835_MMAL_MODULE_NAME, ret);
> +
> + return ret;
> +}
> +
> +static void __exit bm2835_mmal_exit(void)
> +{
> + int camera;
> + struct vchiq_mmal_instance *instance = gdev[0]->instance;
> +
> + for (camera = 0; camera < MAX_BCM2835_CAMERAS; camera++) {
> + bcm2835_cleanup_instance(gdev[camera]);
> + gdev[camera] = NULL;
> + }
> + vchiq_mmal_finalise(instance);
> +}
> +
> +module_init(bm2835_mmal_init);
> +module_exit(bm2835_mmal_exit);

Dave Stevenson

unread,
Feb 6, 2017, 10:10:05 AM2/6/17
to
Hi Mauro.

Can I just say that I'm not attempting to upstream this, others are.
I've just answered questions raised.

On 06/02/17 12:37, Mauro Carvalho Chehab wrote:
> Em Sun, 5 Feb 2017 22:15:21 +0000
> Dave Stevenson <linux...@destevenson.freeserve.co.uk> escreveu:
>
>
> If the goal was to protect some IP related to the sensors, I guess
> this is not going to protect anything, as there are recent driver
> submissions on linux-media for the ov5647 driver:
>
> https://patchwork.kernel.org/patch/9472441/
>
> There are also open source drivers for the Sony imx219 camera
> floating around for android and chromeOS:
>
> https://chromium.googlesource.com/chromiumos/third_party/kernel/+/factory-ryu-6486.14.B-chromeos-3.14/drivers/media/i2c/soc_camera/imx219.c
> https://android.googlesource.com/kernel/bcm/+/android-bcm-tetra-3.10-lollipop-wear-release/drivers/media/video/imx219.c
>
> Plus, there's a datasheet (with another driver) available at:
> https://github.com/rellimmot/Sony-IMX219-Raspberry-Pi-V2-CMOS
>
> So, you're not really protecting IP here.

None of the ISP processing, control loops, or tuning are open.
Yes there are kernel drivers kicking around for OV5647 and IMX219 now,
but very little will consume raw Bayer.
That is also Omnivision or Sony IP, not Broadcom IP.

> If the goal is to protect some proprietary algorithm meant to enhance
> the camera captured streams, doing things like (auto-focus, auto-white
> adjustments, scaling, etc), and/or implementing codec encoders, you should,
> instead, restructure such codecs as mem2mem V4L2 drivers. There are a bunch
> of such codecs already for other SoC where such functions are implemented
> on GPU.
>
> If you add DMABUF capabilities and media controller to the capture
> driver and to the mem2mem drivers, userspace can use the V4L2 APIs
> to use those modules using the arrangements they need, without
> performance impacts.
>
> So, by obfuscating the code, you're not protecting anything. Just making
> harder for RPi customers to use, as you're providing a driver that is
> limited.
>
>>

<snip>

>>> Greg was kick on merging it on staging ;) Anyway, the real review
>>> will happen when the driver becomes ready to be promoted out of
>>> staging. When you address the existing issues and get it ready to
>>> merge, please send the patch with such changes to linux-media ML.
>>> I'll do a full review on it by then.
>>
>> Is that even likely given the dependence on VCHI? I wasn't expecting
>> VCHI to leave staging, which would force this to remain too.
>
> I didn't analyze the VCHI driver. As I said before, if you rewrite
> the driver in a way that the Kernel can actually see the sensors
> via an I2C interface, you probably can get rid of the VCHI interface
> for the capture part.
>
> You could take a look on the other mem2mem drivers and see if are
> there some way to provide an interface for the GPU encoders in a
> similar way to what those drivers do.

I will be looking at a sub dev driver for just the CCP2/CSI1/CSI2
receiver as Broadcom did manage to release (probably unintentionally) a
bastardised soc-camera driver for it and therefore the info is in the
public domain.

It would be possible to write a second sub dev driver that was similar
to this in using VCHI/MMAL to create another mem2mem device to wrap the
ISP, but that would just be an image processing pipe - control loops
would all be elsewhere (userspace).
I haven't seen a sensible mechanism within V4L2 for exporting image
statistics for AE, AWB, AF, or histograms to userspace so that
appropriate algorithms can be run there. Have I missed them, or do they
not exist?

<snip>
All this provides wonderful flexibility, but most apps don't care or
want to get involved in media-ctl. If opening /dev/video0 doesn't give
them images then they won't change it, and will claim that the platform
is broken.
How do you address those users?

>>
>>>> +
>>>> +/* Gstreamer bug https://bugzilla.gnome.org/show_bug.cgi?id=726521
>>>> + * v4l2src does bad (and actually wrong) things when the vidioc_enum_framesizes
>>>> + * function says type V4L2_FRMSIZE_TYPE_STEPWISE, which we do by default.
>>>> + * It's happier if we just don't say anything at all, when it then
>>>> + * sets up a load of defaults that it thinks might work.
>>>> + * If gst_v4l2src_is_broken is non-zero, then we remove the function from
>>>> + * our function table list (actually switch to an alternate set, but same
>>>> + * result).
>>>> + */
>>>> +static int gst_v4l2src_is_broken;
>>>> +module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
>>>> +MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer");
>>>
>>> Not sure if I liked this hack here. AFAIKT, GStreamer fixed the bug with
>>> V4L2_FRMSIZE_TYPE_STEPWISE already.
>>
>> I will double check on Monday. The main Raspberry Pi distribution is
>> based on Debian, so packages can be quite out of date. This bug
>> certainly affected Wheezy, but I don't know for certain about Jessie.
>> Sid still hasn't been adopted.
>
> Well, at the RPi distro, the best would be to backport the gst patches
> that fixed the bug instead, as it would affect other V4L2 hardware
> connected via USB too.

I have yet to see a USB webcam that claims to support
V4L2_FRMSIZE_TYPE_STEPWISE.
Any camera that claimed V4L2_FRMSIZE_TYPE_DISCRETE was fine.

>> Also be aware that exactly the same issue of not supporting
>> V4L2_FRMSIZE_TYPE_STEPWISE affects Chromium for WebRTC, and they seem
>> not to be too bothered about fixing it -
>> https://bugs.chromium.org/p/chromium/issues/detail?id=249953
>> Now admittedly it's not the kernel's responsibility to work around
>> application issues, but if it hobbles a board then that is an issue.
>
> Those lazy maintainers... :-)

It's the downside of it only affecting a very few cameras - it makes the
priority pretty low to fix them.

<snip>

>>>> + for (k = 0; k < ARRAY_SIZE(formats); k++) {
>>>> + fmt = &formats[k];
>>>> + if (fmt->fourcc == f->fmt.pix.pixelformat)
>>>> + break;
>>>> + }
>>>> +
>>>> + if (k == ARRAY_SIZE(formats))
>>>> + return NULL;
>>>
>>> Again, doesn't the formats depend on the camera sensor module?
>>
>> Not in this case.
>> You're at the end of a full ISP processing pipe, and there is the option
>> for including either JPEG, MJPEG, or H264 encoding on the end. It is
>> supported to ask the camera component which formats it supports, but
>> you'll still need a conversion table from those MMAL types to V4L2
>> enums, and options for adding the encoded formats.
>
> The better would be to split those GPU encoders on a mem2mem driver.
> This way, if all the userspace want is the raw images, they can
> get it without passing though a GPU pipeline.

Raw Bayer images are not available from this driver, therefore anything
has to go through some level of GPU pipe.

> The big problem here is that the user doesn't really know what
> formats are produced by the camera from those that are post-processed.
>
> On applications that require low latency, that could have a big
> impact. For example, if someone is using a RPi on a robot or on
> a self-piloted drone, the lowest latency the better.

mem2mem devices would be actually INCREASING the latency.
The GPU solution is currently starting to process the Bayer frame as it
comes in from the sensor, so the last line of the fully processed YUV
image is typically available about 4ms after the frame end.
V4L2 appears not to have a mechanism to pass stripes down the line, so
the ISP can't start on the frame until the frame end. Please correct me
if I'm wrong.


And with all due respect, how many apps actually set up a chain of V4L2
devices?
The majority of users just want to get images. The framework may offer
all the bells and whistles, but if they're too complex to use then most
clients ignore them.
The majority of users seem to just pick up off-the-shelf apps and expect
them to work off /dev/video0.

<snip>

>>>> + (int)dev->capture.kernel_start_ts.
>>>> + tv_sec,
>>>> + (int)dev->capture.kernel_start_ts.
>>>> + tv_usec,
>>>> + dev->capture.vc_start_timestamp, pts,
>>>> + (int)timestamp.tv_sec,
>>>> + (int)timestamp.tv_usec);
>>>> + buf->vb.vb2_buf.timestamp = timestamp.tv_sec * 1000000000ULL +
>>>> + timestamp.tv_usec * 1000ULL;
>>>
>>> Not sure if I understood the above logic... Why don't you just do
>>> buf->vb.vb2_buf.timestamp = ktime_get_ns();
>>
>> What's the processing latency through the ISP and optional
>> H264/MJPG/JPEG encode to get to this point? Typically you're looking at
>> 30-80ms depending on exposure time and various other factors, which
>> would be enough to put A/V sync out if not compensated for.
>>
>> The GPU side is timestamping all buffers with the CSI frame start
>> interrupt timestamp, but based on the GPU STC. There is a MMAL call to
>> read the GPU STC which is made at streamon (stored in
>> dev->capture.vc_start_timestamp), and therefore this is taking a delta
>> from there to get a more accurate timestamp.
>
> Ah, so this is due to the extra latency introduced by GPU.

To account for processing time, yes.
The spec says timestamp is meant to be
"For capture streams this is time when the first data byte was captured,
as returned by the clock_gettime()"
so that is what you're getting.

>> (An improvement would be to reread it every N seconds to ensure there
>> was no drift, but the Linux kernel tick is actually off the same clock,
>> so it is only clock corrections that would introduce a drift).
>> As I understand it UVC is doing a similar thing, although it is trying
>> to compensate for clock drift too.
>
> What happens when daylight saving time changes is applied? Will it
> indicate an one hour latency?

I was expecting nothing.
From the man page for clock_gettime()
CLOCK_MONOTONIC
Clock that cannot be set and represents monotonic time since
some unspecified starting point. This clock is not affected
by discontinuous jumps in the system time (e.g., if the system
administrator manually changes the clock), but is affected by
the incremental adjustments performed by adjtime(3) and NTP.
Isn't daylight savings time a discontinuous jump in system time, so
shouldn't affect CLOCK_MONOTONIC? Or is it going to slew the clock until
it accounts for it?
If slewed then rereading every N seconds would compensate.

>> Now one could argue that ideally you want the timestamp for the start of
>> exposure, but there is no event outside of the sensor to trigger that.
>> You could compute it, but the exposure time control loop is running on
>> the GPU so the kernel doesn't know the exposure time. It's also a bit of
>> a funny thing anyway when dealing with rolling shutter sensors and
>> therefore considering which line you want the start of exposure for.

Rereading the spec for the struct v4l2_buffer timestamp field I see that
it is specified as the first byte, so the implementation is correct.

<snip>

>>>
>>> It seems that you're fixing the bug at the steps used by
>>> v4l_bound_align_image() by rounding up the buffer size. That's wrong!
>>> Just ensure that the width/height will be a valid resolution and
>>> remove this hack.
>>
>> No, this is working around the fact that very few clients respect
>> bytesperline (eg QV4L2 and libv4lconvert for many of the formats).
>
> If you find a bug on any clients that we maintain (qv4l2, libv4l,
> tvtime, xawtv), please submit us a patch. If this issue was fixed
> when you noticed (in 2013, as you're saying below), then we wouldn't
> need to concern about it nowadays ;)

You may fix your maintained apps (or request patches to fix them), but
there are so many others that aren't supported by yourselves.
Memory says that those weren't the specific apps I was needing to get
working back in 2013, I've only observed the issues in the last week as
I was trying to remove this nastiness.

I do have patches for libv4lconvert to handle VYUY (the only one of the
YUYV family that wasn't supported) and also NV12/NV21. They should both
handle bytesperline correctly as well.
I'll double check them and submit it soon.

>> The ISP needs to be writing to buffers with the stride being a multiple
>> of 32, and height a multiple of 16 (and that includes between planes of
>> YUV420). V4L2 appears not to allow that, therefore there is then a
>> second operation run in-place on the buffer to remove that padding, but
>> the buffer needs to be sized sufficiently to handle the padded image first.
>>
>> I had a conversation with Hans back in 2013 with regard this, and there
>> wasn't a good solution proposed. It could potentially be specified using
>> the cropping API, but that pushes the responsibility back onto every
>> client app to drive things in a very specific manner. If they don't
>> respect bytesperline they are even less likely to handle cropping.
>> You could restrict the resolution to being a multiple of 32 on the width
>> and 16 on the height, but in doing so you're not exposing the full
>> capabilities.
>>
>> I'm open to suggestions as to how V4L2 can do this without just beating
>> up client apps who do the wrong thing.
>>
>> Multiplanar formats seem not to be an option as the ISP is expecting one
>> contiguous buffer to be provided to take all the planes, but the
>> multiplanar stuff supplies multiple independent buffers. Again please
>> correct me if I'm wrong on that.
>
> Not sure if I fully understand what happens there... Does it add
> alignment pads in the middle of the image, or just at the end of
> the buffer? If such pads are added in the middle of the image, it
> is actually violating the fourcc formats, as they're not meant to
> have PADs inside it.

Example of a YUV420 image with 636x478 (ie just under VGA, and not nice
multiples).
For the hardware, bytesperline needs to be a multiple of 32, so 640 (and
would be left at that if every possible client observed bytesperline).
The height has to be a multiple of 16, so 480. The buffer is then:
640x480 = 307200 bytes of Y
320x240 = 76800 bytes of U
320x240 = 76800 bytes of V.
460800 bytes total.

So yes, there are 640*2 bytes of padding between the Y&U, and 320*1
bytes between U&V. That is indeed violating the fourcc for
V4L2_PIX_FMT_YUV420, therefore the GPU is memcpying the U & V planes to
remove it. The buffer is allocated at 460800 bytes so that it is large
enough to take the padded image before being copied. bytesused in the
v4l2_buffer struct should be correctly set to 636*478*1.5 = 456012 bytes.
When the bytesperline isn't a multiple of 32 then the GPU is memcpying
line by line to remove the padding on the end of each line as clients
ignore it.
It's a painful operation, but if the framework has no mechanism to deal
with that then it is necessary.


<snip>

>>>> + /* format dependant port setup */
>>>> + switch (mfmt->mmal_component) {
>>>> + case MMAL_COMPONENT_CAMERA:
>>>> + /* Make a further decision on port based on resolution */
>>>> + if (f->fmt.pix.width <= max_video_width
>>>> + && f->fmt.pix.height <= max_video_height)
>>>> + camera_port = port =
>>>> + &dev->component[MMAL_COMPONENT_CAMERA]->
>>>> + output[MMAL_CAMERA_PORT_VIDEO];
>>>> + else
>>>> + camera_port = port =
>>>> + &dev->component[MMAL_COMPONENT_CAMERA]->
>>>> + output[MMAL_CAMERA_PORT_CAPTURE];
>>>
>>> Not sure if I got this... What are you intending to do here?
>>
>> As noted above, what do you consider a still when dealing with raw RGB
>> or YUV buffers. This is switching between video and stills quality
>> processing based on resolution.
>
> That sounds an ugly hack. Unlikely to be accepted upstream.

I'm not the one trying to upstream this ;-)

<snip>
No, the ISP would have that limitation.

Dave

Dave Stevenson

unread,
Feb 6, 2017, 10:30:06 AM2/6/17
to
Hi Hans.

On 06/02/17 12:58, Hans Verkuil wrote:
> On 02/06/2017 12:37 PM, Dave Stevenson wrote:
>> Hi Hans.
>>
>> On 06/02/17 09:08, Hans Verkuil wrote:
>>> Hi Eric,
>>>
>>> Great to see this driver appearing for upstream merging!
>>>
>>> See below for my review comments, focusing mostly on V4L2 specifics.
>>>

<snip>
https://linuxtv.org/downloads/v4l-dvb-apis-new/uapi/v4l/pixfmt-007.html#colorspace-srgb-v4l2-colorspace-srgb
"The default transfer function is V4L2_XFER_FUNC_SRGB. The default
Y’CbCr encoding is V4L2_YCBCR_ENC_601. The default Y’CbCr quantization
is full range."
So full range or limited?

> The JPEG colorspace is a short-hand for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601
> and V4L2_QUANTIZATION_FULL_RANGE. It's historical that this colorspace exists.
>
> If I would redesign this this JPEG colorspace would be dropped.
>
> For a lot more colorspace information see:
>
> https://hverkuil.home.xs4all.nl/spec/uapi/v4l/colorspaces.html
>
>>
>> I do note that as there is now support for more RGB formats (BGR24 and
>> BGR32) the first "if" needs extending to cover those. Or I don't care
>> and only special case JPEG with all others just reporting SRGB.
>>
>
> Only special case JPEG.
>
> But as I said, this information really needs to come from the sensor or
> video receiver since this driver has no knowledge of this.

OK.
OK, thanks for the clarification. That can be done.

>>
>>> <snip>
>>>
>>> Final question: did you run v4l2-compliance over this driver? Before this driver can
>>> be moved out of staging it should pass the compliance tests. Note: always compile
>>> this test from the main repository, don't rely on distros. That ensures you use the
>>> latest code.
>>>
>>> The compliance test is part of the v4l-utils repo (https://git.linuxtv.org/v4l-utils.git/).
>>>
>>> If you have any questions about the v4l2-compliance output (it can be a bit obscure at
>>> times), just mail me or ask the question on the #v4l irc channel.
>>
>> I haven't checked this version, but the downstream version has 43
>> passes, 0 failures, 0 warnings.
>>
>> The full output:
>> v4l2-compliance SHA : 99306f20cc7e76cf2161e3059de4da245aed2130
>
> That's pretty recent. Good to know you've used this.
>
> Also test with v4l2-compliance -f: this tests all available formats.

OK.
The cropping/composing/scaling API is not currently supported.
The hardware can do it, but I need to work out how it should be set up,
and what resolutions to quote via V4L2_SEL_TGT_CROP_BOUNDS and similar.
It just needs a bit of time.

>>
>> Codec ioctls:
>> test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
>> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
>> test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
>>
>> Buffer ioctls:
>> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
>> test VIDIOC_EXPBUF: OK (Not Supported)
>>
>> Test input 0:
>>
>>
>> Total: 43, Succeeded: 43, Failed: 0, Warnings: 0
>
> Note that v4l2-compliance does very limited testing of overlay handling.
> You should test this manually to make sure it functions properly.

OK, thanks for the heads up. It's not one that gets used that often in
the wild either from what I can tell.

> Regards,
>
> Hans

Thanks,
Dave

Hans Verkuil

unread,
Feb 6, 2017, 11:10:06 AM2/6/17
to
Ah, good catch. The default range for SRGB is full range, so the documentation
is correct. This is according to the sYCC standard.

This means that you need to set the quantization field to limited range in this driver.

Sorry for the confusion I caused.

Interesting, I should take a look at other drivers since I suspect that this is
signaled wrong elsewhere as well. It used to be limited range but I changed it
to full range (as per the sYCC spec). But in practice it is limited range in most
cases.

I'll take another look at this on Friday.

I recommend that you leave the code as is for now.

Regards,

Hans
OK. This needs some attention before it can be moved out of staging.

Regards,

Hans

Hans Verkuil

unread,
Feb 10, 2017, 4:50:05 AM2/10/17
to
I posted a patch to correct the default quantization range mapping for sRGB and AdobeRGB:

https://patchwork.linuxtv.org/patch/39306/

So even though the standards say full range, this would break backwards compatibility
with all current kernel drivers since they all produce limited range when converting
sRGB or AdobeRGB to a Y'CbCr format.

Thanks for bringing this to my attention!

Regards,

Hans

Mauro Carvalho Chehab

unread,
Mar 15, 2017, 10:10:07 AM3/15/17
to
Em Fri, 27 Jan 2017 13:54:57 -0800
Eric Anholt <er...@anholt.net> escreveu:

> Here's my first pass at importing the camera driver. There's a bunch
> of TODO left to it, most of which is documented, and the rest being
> standard checkpatch fare.
>
> Unfortunately, when I try modprobing it on my pi3, the USB network
> device dies, consistently. I'm not sure what's going on here yet, but
> I'm going to keep working on some debug of it. I've unfortunately
> changed a lot of variables (pi3 vs pi2, upstream vs downstream, vchi's
> updates while in staging, 4.9 vs 4.4), so I probably won't figure it
> out today.
>
> Note that the "Update the driver to the current VCHI API" patch will
> conflict with the outstanding "Add vchi_queue_kernel_message and
> vchi_queue_user_message" series, but the fix should be pretty obvious
> when that lands.
>
> I built this against 4.10-rc1, but a merge with staging-next was clean
> and still built fine.

I'm trying it, building from the linux-next branch of the staging
tree. No joy.

That's what happens when I modprobe it:

[ 991.841549] bcm2835_v4l2: module is from the staging directory, the quality is unknown, you have been warned.
[ 991.842931] vchiq_get_state: g_state.remote == NULL
[ 991.843437] vchiq_get_state: g_state.remote == NULL
[ 991.843940] vchiq_get_state: g_state.remote == NULL
[ 991.844444] vchiq_get_state: g_state.remote == NULL
[ 991.844947] vchiq_get_state: g_state.remote == NULL
[ 991.845451] vchiq_get_state: g_state.remote == NULL
[ 991.845954] vchiq_get_state: g_state.remote == NULL
[ 991.846457] vchiq_get_state: g_state.remote == NULL
[ 991.846961] vchiq_get_state: g_state.remote == NULL
[ 991.847464] vchiq_get_state: g_state.remote == NULL
[ 991.847969] vchiq: vchiq_initialise: videocore not initialized

[ 991.847973] mmal_vchiq: Failed to initialise VCHI instance (status=-1)


Thanks,
Mauro

Stefan Wahren

unread,
Mar 15, 2017, 6:00:05 PM3/15/17
to
Hi Mauro,

> Mauro Carvalho Chehab <mch...@s-opensource.com> hat am 15. März 2017 um 15:01 geschrieben:
only a guess, but did you add the vchiq node to the device tree?

vchiq: vchiq@7e00b840 {
compatible = "brcm,bcm2835-vchiq";
reg = <0x7e00b840 0xf>;
interrupts = <0 2>;
cache-line-size = <32>;
firmware = <&firmware>;
};

For a Raspberry Pi 3 you will need cache-line-size to be 64.

Regards
Stefan

>
> Thanks,
> Mauro

Eric Anholt

unread,
Mar 15, 2017, 6:10:05 PM3/15/17
to
Yeah, this failure mode sucks. I'm guessing you don't have a VCHI node
in the DT? Patch attached.

I haven't followed up on getting the DT documented so that it can be
merged, and it sounds like Michael has some plans for changing how VCHI
and VCHI's consumers get attached to each other so that it's not
DT-based anyway.

From 9488974b836b1fba7d32af34d612151872f9ce0d Mon Sep 17 00:00:00 2001
From: Eric Anholt <er...@anholt.net>
Date: Mon, 3 Oct 2016 11:23:34 -0700
Subject: [PATCH] ARM: bcm2835: Add VCHIQ to the DT.

Signed-off-by: Eric Anholt <er...@anholt.net>
---
arch/arm/boot/dts/bcm2835-rpi.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index caf2707680c1..f5fb5c5aa07a 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -26,6 +26,14 @@
firmware = <&firmware>;
#power-domain-cells = <1>;
};
+
+ vchiq {
+ compatible = "brcm,bcm2835-vchiq";
+ reg = <0x7e00b840 0xf>;
+ interrupts = <0 2>;
+ cache-line-size = <32>;
+ firmware = <&firmware>;
+ };
};
};

--
2.11.0

signature.asc

Mauro Carvalho Chehab

unread,
Mar 15, 2017, 9:20:06 PM3/15/17
to
Em Wed, 15 Mar 2017 15:01:29 -0700
Eric Anholt <er...@anholt.net> escreveu:
No, I didn't. Thanks! Applied it but, unfortunately, didn't work.
Perhaps I'm missing some other patch. I'm compiling it from
the Greg's staging tree (branch staging-next):
https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/log/?h=staging-next

Btw, as I'm running Raspbian, and didn't want to use compat32 bits,
I'm compiling the Kernel as an arm32 bits Kernel.

I did a small trick to build the DTB on arm32:

ln -sf ../../../arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts arch/arm/boot/dts/bcm2837-rpi-3-b.dts
ln -sf ../../../arm64/boot/dts/broadcom/bcm2837.dtsi arch/arm/boot/dts/bcm2837.dtsi
git checkout arch/arm/boot/dts/Makefile
sed "s,bcm2835-rpi-zero.dtb,bcm2835-rpi-zero.dtb bcm2837-rpi-3-b.dtb," a && mv a arch/arm/boot/dts/Makefile

> I haven't followed up on getting the DT documented so that it can be
> merged, and it sounds like Michael has some plans for changing how VCHI
> and VCHI's consumers get attached to each other so that it's not
> DT-based anyway.

I see.

>
> From 9488974b836b1fba7d32af34d612151872f9ce0d Mon Sep 17 00:00:00 2001
> From: Eric Anholt <er...@anholt.net>
> Date: Mon, 3 Oct 2016 11:23:34 -0700
> Subject: [PATCH] ARM: bcm2835: Add VCHIQ to the DT.
>
> Signed-off-by: Eric Anholt <er...@anholt.net>
> ---
> arch/arm/boot/dts/bcm2835-rpi.dtsi | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> index caf2707680c1..f5fb5c5aa07a 100644
> --- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
> +++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> @@ -26,6 +26,14 @@
> firmware = <&firmware>;
> #power-domain-cells = <1>;
> };
> +
> + vchiq {
> + compatible = "brcm,bcm2835-vchiq";
> + reg = <0x7e00b840 0xf>;
> + interrupts = <0 2>;
> + cache-line-size = <32>;
> + firmware = <&firmware>;
> + };
> };
> };
>



Thanks,
Mauro

Michael Zoran

unread,
Mar 15, 2017, 9:50:05 PM3/15/17
to
On Wed, 2017-03-15 at 22:08 -0300, Mauro Carvalho Chehab wrote:

> No, I didn't. Thanks! Applied it but, unfortunately, didn't work.
> Perhaps I'm missing some other patch. I'm compiling it from
> the Greg's staging tree (branch staging-next):
> https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.
> git/log/?h=staging-next
>
> Btw, as I'm running Raspbian, and didn't want to use compat32 bits, 
> I'm compiling the Kernel as an arm32 bits Kernel.
>
> I did a small trick to build the DTB on arm32:
>
> ln -sf ../../../arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts
> arch/arm/boot/dts/bcm2837-rpi-3-b.dts
> ln -sf ../../../arm64/boot/dts/broadcom/bcm2837.dtsi
> arch/arm/boot/dts/bcm2837.dtsi
> git checkout arch/arm/boot/dts/Makefile
> sed "s,bcm2835-rpi-zero.dtb,bcm2835-rpi-zero.dtb bcm2837-rpi-3-
> b.dtb," a && mv a arch/arm/boot/dts/Makefile
>

Two other hacks are currently needed to get the camera to work:

1. Add this to config.txt(This required to get the firmware to detect
the camera)

start_x=1
gpu_mem=128

2. VC4 is incompatible with the firmware at this time, so you need
to presently munge the build configuration. What you do is leave
simplefb in the build config(I'm assuming you already have that), but
you will need to remove VC4 from the config.

The firmware currently adds a node for a simplefb for debugging
purposes to show the boot log. Surprisingly, this is still good enough
for basic usage and testing.

The only remaining issue is that since simplefb is intented for
debugging, you wan't be able to use many of the RPI specific
applications.  

I've been using cheese and ffmpeg to test the camera which are not RPI
specific.

Mauro Carvalho Chehab

unread,
Mar 16, 2017, 5:40:05 AM3/16/17
to
Em Wed, 15 Mar 2017 18:46:24 -0700
Michael Zoran <mzo...@crowfest.net> escreveu:

> On Wed, 2017-03-15 at 22:08 -0300, Mauro Carvalho Chehab wrote:
>
> > No, I didn't. Thanks! Applied it but, unfortunately, didn't work.
> > Perhaps I'm missing some other patch. I'm compiling it from
> > the Greg's staging tree (branch staging-next):
> > https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.
> > git/log/?h=staging-next
> >
> > Btw, as I'm running Raspbian, and didn't want to use compat32 bits, 
> > I'm compiling the Kernel as an arm32 bits Kernel.
> >
> > I did a small trick to build the DTB on arm32:
> >
> > ln -sf ../../../arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts
> > arch/arm/boot/dts/bcm2837-rpi-3-b.dts
> > ln -sf ../../../arm64/boot/dts/broadcom/bcm2837.dtsi
> > arch/arm/boot/dts/bcm2837.dtsi
> > git checkout arch/arm/boot/dts/Makefile
> > sed "s,bcm2835-rpi-zero.dtb,bcm2835-rpi-zero.dtb bcm2837-rpi-3-
> > b.dtb," a && mv a arch/arm/boot/dts/Makefile
> >
>
> Two other hacks are currently needed to get the camera to work:
>
> 1. Add this to config.txt(This required to get the firmware to detect
> the camera)
>
> start_x=1
> gpu_mem=128

I had this already.

>
> 2. VC4 is incompatible with the firmware at this time, so you need
> to presently munge the build configuration. What you do is leave
> simplefb in the build config(I'm assuming you already have that), but
> you will need to remove VC4 from the config.
>
> The firmware currently adds a node for a simplefb for debugging
> purposes to show the boot log. Surprisingly, this is still good enough
> for basic usage and testing.

That solved the issue. Thanks! It would be good to add a notice
about that at the TODO, not let it build if DRM_VC4.

Please consider applying the enclosed path.

> The only remaining issue is that since simplefb is intented for
> debugging, you wan't be able to use many of the RPI specific
> applications.  
>
> I've been using cheese and ffmpeg to test the camera which are not RPI
> specific.

I did a quick test with camorama and qv4l2. it worked with both.

Thanks,
Mauro


[PATCH] staging: bcm2835-camera: make it dependent of !DRM_VC4

Currently, if DRM_VC4 is enabled, this driver doesn't work,
as the firmware doesn't support having both enabled at the
same time.

Document that and prevent it to be built if !DRM_VC4.

Signed-off-by: Mauro Carvalho Chehab <mch...@s-opensource.com>

diff --git a/drivers/staging/vc04_services/bcm2835-camera/Kconfig b/drivers/staging/vc04_services/bcm2835-camera/Kconfig
index b8b01aa4e426..678dc2efb91a 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/Kconfig
+++ b/drivers/staging/vc04_services/bcm2835-camera/Kconfig
@@ -2,6 +2,8 @@ config VIDEO_BCM2835
tristate "BCM2835 Camera"
depends on MEDIA_SUPPORT
depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
+ # Currently, firmware is incompatible with VC4 DRM driver
+ depends on !DRM_VC4
select BCM2835_VCHIQ
select VIDEOBUF2_VMALLOC
select BTREE
diff --git a/drivers/staging/vc04_services/bcm2835-camera/TODO b/drivers/staging/vc04_services/bcm2835-camera/TODO
index 61a509992b9a..fec70a1cc4a3 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/TODO
+++ b/drivers/staging/vc04_services/bcm2835-camera/TODO
@@ -37,3 +37,4 @@ v4l2 module after VCHI loads.
This was a temporary workaround for a bug that was fixed mid-2014, and
we should remove it before stabilizing the driver.

+6) Make firmware compatible with both DRM_VC4 and VIDEO_BCM2835.

Eric Anholt

unread,
Mar 17, 2017, 8:40:03 PM3/17/17
to
Mauro Carvalho Chehab <mch...@s-opensource.com> writes:

The VC4 incompatibility (camera firmware's AWB ends up briefly using the
GPU, without coordinating with the Linux driver) is supposed to be fixed
in current firmware
(https://github.com/raspberrypi/firmware/issues/760#issuecomment-287391025)
signature.asc

Mauro Carvalho Chehab

unread,
Mar 19, 2017, 1:00:05 PM3/19/17
to
Em Fri, 17 Mar 2017 17:34:36 -0700
Eric Anholt <er...@anholt.net> escreveu:
With the current firmware, when X starts, the screen becomes blank,
with upstream Kernel (it works with the downstream Kernel shipped with
the firmware).

Maybe something changed at DT?

Thanks,
Mauro

Michael Zoran

unread,
Mar 19, 2017, 1:10:05 PM3/19/17
to
Hi, exactly which DT are you using and which drivers are you using for
video. If this is a RPI 3, then as you know VC4 doesn't work due to the
HDMI hotplug issue. So I'm not 100% sure how you were getting video.

A working DT that I tried this morning with the current firmware is
posted here:
http://lists.infradead.org/pipermail/linux-rpi-kernel/2017-March/005924
.html

It even works with minecraft_pi!

Mauro Carvalho Chehab

unread,
Mar 19, 2017, 9:20:04 PM3/19/17
to
Em Sun, 19 Mar 2017 10:04:28 -0700
I'm using the one at Greg's staging tree.

> If this is a RPI 3, then as you know VC4 doesn't work due to the
> HDMI hotplug issue. So I'm not 100% sure how you were getting video.

>
> A working DT that I tried this morning with the current firmware is
> posted here:
> http://lists.infradead.org/pipermail/linux-rpi-kernel/2017-March/005924
> .html
>
> It even works with minecraft_pi!


Yeah, something like that solved it, thanks! With the new firmware
and the enclosed patch, compiling with VIDEO_BCM2835

I had to comment two blocks for it to work with upstream Kernel, though.

Patch enclosed.

Thanks!
Mauro

[PATCH] bcm2837-rpi-3-b.dts: fix it to work with newer firmware

Newer firmware require extra stuff to DT.

Suggested-by: Michael Zoran <mzo...@crowfest.net>
Signed-off-by: Mauro Carvalho Chehab <mch...@s-opensource.com>

diff --git a/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts b/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts
index c309633a1e87..7e8d42904022 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts
@@ -17,6 +17,45 @@
gpios = <&gpio 47 0>;
};
};
+
+
+ soc {
+
+// hvs at 7e400000 {
+// status = "disabled";
+// };
+
+// v3d: v3d at 7ec00000 {
+// status = "disabled";
+// };
+
+ vc4: gpu {
+ status = "disabled";
+ };
+
+ fb: fb {
+ status = "disabled";
+ };
+
+ vchiq: vchiq {
+ compatible = "brcm,bcm2835-vchiq";
+ reg = <0x7e00b840 0xf>;
+ interrupts = <0 2>;
+ cache-line-size = <32>;
+ firmware = <&firmware>;
+ };
+
+ audio: audio {
+ compatible = "brcm,bcm2835-audio";
+ brcm,pwm-channels = <8>;
+ };
+
+ };
+
+ __overrides__ {
+ cache_line_size = <&vchiq>, "cache-line-size:0";
+ };
+
};

&uart1 {


Thanks,
Mauro

Mauro Carvalho Chehab

unread,
Mar 20, 2017, 7:10:05 AM3/20/17
to
Em Sun, 19 Mar 2017 22:11:07 -0300
Mauro Carvalho Chehab <mch...@s-opensource.com> escreveu:

> Em Sun, 19 Mar 2017 10:04:28 -0700
> Michael Zoran <mzo...@crowfest.net> escreveu:
>

> > A working DT that I tried this morning with the current firmware is
> > posted here:
> > http://lists.infradead.org/pipermail/linux-rpi-kernel/2017-March/005924
> > .html
> >
> > It even works with minecraft_pi!

With the new firmware, sometime after booting, I'm getting an oops, caused
by bcm2835_audio/vchiq:

[ 298.788995] Unable to handle kernel NULL pointer dereference at virtual address 00000034
[ 298.821458] pgd = ed004000
[ 298.832294] [00000034] *pgd=2e5e9835, *pte=00000000, *ppte=00000000
[ 298.857450] Internal error: Oops: 17 [#1] SMP ARM
[ 298.876273] Modules linked in: cfg80211 hid_logitech_hidpp hid_logitech_dj snd_bcm2835(C) snd_pcm snd_timer snd soundcore vchiq(C) uio_pdrv_genirq uio fuse
[ 298.932064] CPU: 3 PID: 847 Comm: pulseaudio Tainted: G C 4.11.0-rc1+ #56
[ 298.963774] Hardware name: Generic DT based system
[ 298.982945] task: ef758580 task.stack: ee4c6000
[ 299.001080] PC is at mutex_lock+0x14/0x3c
[ 299.017148] LR is at vchiq_add_service_internal+0x138/0x3a0 [vchiq]
[ 299.042246] pc : [<c0c849d4>] lr : [<bf059654>] psr: 40000013
sp : ee4c7ca8 ip : 00000000 fp : ef709800
[ 299.088240] r10: 00000000 r9 : ee3bffc0 r8 : 00000034
[ 299.109153] r7 : 00000003 r6 : 00000000 r5 : ee4c7d00 r4 : ee1d8c00
[ 299.135291] r3 : ef758580 r2 : 00000000 r1 : ffffffc8 r0 : 00000034
[ 299.161431] Flags: nZcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
[ 299.190008] Control: 10c5383d Table: 2d00406a DAC: 00000051
[ 299.213011] Process pulseaudio (pid: 847, stack limit = 0xee4c6220)
[ 299.238104] Stack: (0xee4c7ca8 to 0xee4c8000)
[ 299.255539] 7ca0: c1403d54 80400040 ff7f0600 ff7f0660 bf06b578 ee3bffc0
[ 299.288301] 7cc0: 00000000 ee3afd00 00000000 ee4c7d00 00000000 bf0640b4 00000000 bf066428
[ 299.321064] 7ce0: ee3afd00 ee3afd00 ee4c7d34 ee3af444 ee3bffc0 ee3af444 ee3bffc0 bf0662ec
[ 299.353826] 7d00: 41554453 bf065db0 ee3afd00 00010002 bf0d7408 ee3af440 00000000 bf0d7408
[ 299.386587] 7d20: ee79bd80 bf0d5a04 00000000 ef709800 00000020 00000002 00000001 41554453
[ 299.419349] 7d40: 00000000 00000000 00000000 bf0d559c ee3af440 00000001 00000001 00000000
[ 299.452111] 7d60: ee24ac80 ee24ac80 ee1c4a00 00000000 ee79bd80 ee24ace8 00000001 bf0d4dfc
[ 299.484872] 7d80: 0000000b ffffffff ee4b8c3c 00000000 ee4c7dc8 ee4b8800 ee4b8c28 ee4c6000
[ 299.517635] 7da0: 00000000 ee4b8c3c ed029e40 bf0c0404 ee4b8800 ee1c4a00 ee4b8800 ed029e40
[ 299.550398] 7dc0: 00000000 bf0c0560 ee072340 00000000 ef758580 c0367b7c ee4b8c40 ee4b8c40
[ 299.583161] 7de0: 00000000 ee4b8800 ed029e40 ee318f80 ed029e40 00000006 ee318f80 bf0c0748
[ 299.615924] 7e00: bf0a3430 ee4f6180 00000000 c0428fe0 ee318f80 000021b0 00000026 ed029e40
[ 299.648697] 7e20: ee318f80 ed029e48 c0428f1c ee4c7e94 00000006 c0421cc0 ee4c7ed0 00000000
[ 299.681464] 7e40: 00000802 00000000 ee4c7e94 00000006 ee318f80 c0432c8c ee4c7f40 c0433bc0
[ 299.714225] 7e60: 00000000 ed029e40 00000000 00000041 00000000 ed004000 00000000 ee4c6000
[ 299.746987] 7e80: eec69808 00000005 00000000 00000002 ee318f80 ef0d2910 ee924908 bf0ba284
[ 299.779750] 7ea0: ee31bbc0 bebb53c4 ee4e1d00 00000011 ee4c7f74 00000001 fffff000 c0308b04
[ 299.812512] 7ec0: ee4c6000 00000000 bebb5710 c0434578 ef0d2910 ee924908 73541c18 00000008
[ 299.845274] 7ee0: ee4a7019 00000000 00000000 ee899bb0 ee318f80 00000101 00000002 00000084
[ 299.878037] 7f00: 00000000 00000000 00000000 ee4c7f10 ee318df8 ed029840 40045532 bebb53c4
[ 299.910799] 7f20: ee4c6000 ee4a7000 c1403ef8 bebb550c 00000011 ee5eca00 00000020 ee5eca18
[ 299.943562] 7f40: ee4a7000 00000000 00080802 00000002 ffffff9c fffff000 00000011 ffffff9c
[ 299.976324] 7f60: ee4a7000 c0422e70 00000002 c04359b0 ed029840 00000802 ed020000 00000006
[ 300.009086] 7f80: 00000100 00000001 00000000 ffffffff 00000004 b189d000 00000005 c0308b04
[ 300.041848] 7fa0: ee4c6000 c0308940 ffffffff 00000004 bebb550c 00080802 bebb53c4 00084b58
[ 300.074611] 7fc0: ffffffff 00000004 b189d000 00000005 00000000 bebb550c 00099448 bebb5710
[ 300.107373] 7fe0: 00000000 bebb53c8 b6c40da4 b6c24334 80000010 bebb550c 2fffd861 2fffdc61
[ 300.140190] [<c0c849d4>] (mutex_lock) from [<bf059654>] (vchiq_add_service_internal+0x138/0x3a0 [vchiq])
[ 300.178237] [<bf059654>] (vchiq_add_service_internal [vchiq]) from [<bf0640b4>] (vchiq_open_service+0x58/0xf0 [vchiq])
[ 300.221152] [<bf0640b4>] (vchiq_open_service [vchiq]) from [<bf0662ec>] (vchi_service_open+0x74/0xa8 [vchiq])
[ 300.260919] [<bf0662ec>] (vchi_service_open [vchiq]) from [<bf0d5a04>] (bcm2835_audio_open+0xe8/0x2d0 [snd_bcm2835])
[ 300.303111] [<bf0d5a04>] (bcm2835_audio_open [snd_bcm2835]) from [<bf0d4dfc>] (snd_bcm2835_playback_open_generic+0xc0/0x1c4 [snd_bcm2835])
[ 300.352975] [<bf0d4dfc>] (snd_bcm2835_playback_open_generic [snd_bcm2835]) from [<bf0c0404>] (snd_pcm_open_substream+0x60/0x110 [snd_pcm])
[ 300.402848] [<bf0c0404>] (snd_pcm_open_substream [snd_pcm]) from [<bf0c0560>] (snd_pcm_open+0xac/0x1fc [snd_pcm])
[ 300.444009] [<bf0c0560>] (snd_pcm_open [snd_pcm]) from [<bf0c0748>] (snd_pcm_playback_open+0x3c/0x5c [snd_pcm])
[ 300.484459] [<bf0c0748>] (snd_pcm_playback_open [snd_pcm]) from [<c0428fe0>] (chrdev_open+0xc4/0x180)
[ 300.521408] [<c0428fe0>] (chrdev_open) from [<c0421cc0>] (do_dentry_open.constprop.3+0x1fc/0x304)
[ 300.556964] [<c0421cc0>] (do_dentry_open.constprop.3) from [<c0432c8c>] (path_openat+0x588/0x1078)
[ 300.592866] [<c0432c8c>] (path_openat) from [<c0434578>] (do_filp_open+0x60/0xc4)
[ 300.622846] [<c0434578>] (do_filp_open) from [<c0422e70>] (do_sys_open+0x110/0x1c0)
[ 300.653524] [<c0422e70>] (do_sys_open) from [<c0308940>] (ret_fast_syscall+0x0/0x3c)


Thanks,
Mauro

Michael Zoran

unread,
Mar 20, 2017, 7:10:07 AM3/20/17
to
Hi, can you e-mail out your config.txt? Do you have audio enabled in
config.txt?

Stefan Wahren

unread,
Mar 20, 2017, 8:00:05 AM3/20/17
to
Hi Mauro,
> _______________________________________________
> linux-rpi-kernel mailing list
> linux-rp...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rpi-kernel

can you try to revert this change: 001943e8ea3c8 ("staging:
vc04_services: Refactor conditionals")?

Mauro Carvalho Chehab

unread,
Mar 20, 2017, 11:10:06 AM3/20/17
to
Em Mon, 20 Mar 2017 04:08:21 -0700
yes, I have this:

$ cat config.txt |grep -i audio
# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# Enable audio (loads snd_bcm2835)
dtparam=audio=on

Full config attached.

Thanks,
Mauro


---

# Latest RPi Kernel
#kernel=rpi-4.10.y/vmlinuz-4.11.0-rc2-v8+
#device_tree=rpi-4.10.y/bcm2837-rpi-3-b.dtb

# Upstream Kernel
kernel=upstream/vmlinuz-4.11.0-rc1+
device_tree=upstream/bcm2837-rpi-3-b.dtb

# For more options and information see
# http://rpf.io/configtxtreadme
# Some settings may impact device functionality. See link above for details

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on

# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi

# Additional overlays and parameters are documented /boot/overlays/README

# Enable audio (loads snd_bcm2835)
dtparam=audio=on

# NOOBS Auto-generated Settings:
hdmi_force_hotplug=1
start_x=1
gpu_mem=128

enable_uart=1

Michael Zoran

unread,
Mar 20, 2017, 11:20:06 AM3/20/17
to
On Mon, 2017-03-20 at 11:58 -0300, Mauro Carvalho Chehab wrote:
> Em Mon, 20 Mar 2017 04:08:21 -0700
> Michael Zoran <mzo...@crowfest.net> escreveu:
>
> > On Mon, 2017-03-20 at 07:58 -0300, Mauro Carvalho Chehab wrote:
> > > Em Sun, 19 Mar 2017 22:11:07 -0300
> > > Mauro Carvalho Chehab <mch...@s-opensource.com> escreveu:
> > >   
> > > > Em Sun, 19 Mar 2017 10:04:28 -0700
> > > > Michael Zoran <mzo...@crowfest.net> escreveu:
> > > >   
> > > > > A working DT that I tried this morning with the current
> > > > > firmware
> > > > > is
> > > > > posted here:
> > > > > http://lists.infradead.org/pipermail/linux-rpi-kernel/2017-Ma
> > > > > rch/
> > > > > 005924
> > > > > .html
> > > > >
> > > > > It even works with minecraft_pi!    
> > >
> > >   
> >
> > Hi, can you e-mail out your config.txt?  Do you have audio enabled
> > in
> > config.txt?
>
> yes, I have this:
>
> $ cat config.txt |grep -i audio
> # uncomment to force a HDMI mode rather than DVI. This can make audio
> work in
> # Enable audio (loads snd_bcm2835)
> dtparam=audio=on
>
> Full config attached.
>
> Thanks,
> Mauro
>

Are you using Eric Anholt's HDMI Audio driver that's included in VC4?
That could well be incompatible with the firmware driver. Or are you
using a half mode of VC4 for audio and VCHIQ for video?

Mauro Carvalho Chehab

unread,
Mar 20, 2017, 12:00:05 PM3/20/17
to
Em Mon, 20 Mar 2017 08:11:41 -0700
I'm using vanilla staging Kernel, from Greg's tree:
https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/commit/?h=staging-next&id=7bc49cb9b9b8bad32536c4b6d1aff1824c1adc6c

Plus the DWC2 fixup I wrote and DT changes you pointed
(see enclosed).

I can disable the audio overlay here, as I don't have anything
connected to audio inputs/outputs.

Regards,
Mauro

---


diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index 38e6050035bc..1f42190e8558 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -27,6 +27,14 @@
firmware = <&firmware>;
#power-domain-cells = <1>;
};
+
+ vchiq {
+ compatible = "brcm,bcm2835-vchiq";
+ reg = <0x7e00b840 0xf>;
+ interrupts = <0 2>;
+ cache-line-size = <32>;
+ firmware = <&firmware>;
+ };
};
};
Thanks,
Mauro

Michael Zoran

unread,
Mar 20, 2017, 12:10:06 PM3/20/17
to
Why is the vchiq node in the tree twice? For me to even respond anymore
you you going to have to include your entire dtb(whatever you are
using) run through dtc -I dtb -O dts. You are also going to have to
include your exact .config file you used for building, and exactly what
these DWC2 fixeups are.

You don't even state exactly what platform you are using, Is it even an
RPI of some kind.

Mauro Carvalho Chehab

unread,
Mar 22, 2017, 1:20:09 PM3/22/17
to
Hi Michael,

Em Mon, 20 Mar 2017 08:40:11 -0700
Michael Zoran <mzo...@crowfest.net> escreveu:

> > > Are you using Eric Anholt's HDMI Audio driver that's included in
> > > VC4? 
> > > That could well be incompatible with the firmware driver. Or are
> > > you
> > > using a half mode of VC4 for audio and VCHIQ for video?
> >
> > I'm using vanilla staging Kernel, from Greg's tree:
> > https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.
> > git/commit/?h=staging-
> > next&id=7bc49cb9b9b8bad32536c4b6d1aff1824c1adc6c
> >
> > Plus the DWC2 fixup I wrote and DT changes you pointed
> > (see enclosed).
> >
> > I can disable the audio overlay here, as I don't have anything 
> > connected to audio inputs/outputs.
> >
> > Regards,
> > Mauro
> >
>
> Why is the vchiq node in the tree twice? For me to even respond anymore
> you you going to have to include your entire dtb(whatever you are
> using) run through dtc -I dtb -O dts. You are also going to have to
> include your exact .config file you used for building, and exactly what
> these DWC2 fixeups are.
>
> You don't even state exactly what platform you are using, Is it even an
> RPI of some kind.

It is a RPi3 board. The exact procedure that I took is described here:
https://blogs.s-osg.org/use-v4l2-cameras-raspberry-pi-3-upstream-kernel/

After it, I updated the firmware to the newest one, from:
https://github.com/raspberrypi/firmware.git

commit 384559354762f36aa55584560d8749fc66a4cfd0
Author: popcornmix <popco...@gmail.com>
Date: Sat Mar 18 17:48:59 2017 +0000
kernel: Bump to 4.9.16

Then I applied two patches on the top of it:

https://patchwork.linuxtv.org/patch/40093/
https://patchwork.linuxtv.org/patch/40146/

As the second patch has entries for vchiq, I ended by having it
duplicated (although the DTB has it only once, as you can see below).

Regards,
Mauro

----

Output of:
$ dtc -I dtb -O dts /devel/arm_rootdir/install/bcm2837-rpi-3-b.dtb

/dts-v1/;

/ {
compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
model = "Raspberry Pi 3 Model B";
interrupt-parent = <0x1>;
#address-cells = <0x1>;
#size-cells = <0x1>;

chosen {
bootargs = "earlyprintk console=ttyAMA0";
};

soc {
compatible = "simple-bus";
#address-cells = <0x1>;
#size-cells = <0x1>;
ranges = <0x7e000000 0x3f000000 0x1000000 0x40000000 0x40000000 0x1000>;
dma-ranges = <0xc0000000 0x0 0x3f000000>;

timer@7e003000 {
compatible = "brcm,bcm2835-system-timer";
reg = <0x7e003000 0x1000>;
interrupts = <0x1 0x0 0x1 0x1 0x1 0x2 0x1 0x3>;
clock-frequency = <0xf4240>;
};

dma@7e007000 {
compatible = "brcm,bcm2835-dma";
reg = <0x7e007000 0xf00>;
interrupts = <0x1 0x10 0x1 0x11 0x1 0x12 0x1 0x13 0x1 0x14 0x1 0x15 0x1 0x16 0x1 0x17 0x1 0x18 0x1 0x19 0x1 0x1a 0x1 0x1b 0x1 0x1b 0x1 0x1b 0x1 0x1b 0x1 0x1c>;
interrupt-names = "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6", "dma7", "dma8", "dma9", "dma10", "dma11", "dma12", "dma13", "dma14", "dma-shared-all";
#dma-cells = <0x1>;
brcm,dma-channel-mask = <0x7f35>;
linux,phandle = <0x5>;
phandle = <0x5>;
};

interrupt-controller@7e00b200 {
compatible = "brcm,bcm2836-armctrl-ic";
reg = <0x7e00b200 0x200>;
interrupt-controller;
#interrupt-cells = <0x2>;
interrupt-parent = <0x2>;
interrupts = <0x8>;
linux,phandle = <0x1>;
phandle = <0x1>;
};

watchdog@7e100000 {
compatible = "brcm,bcm2835-pm-wdt";
reg = <0x7e100000 0x28>;
};

cprman@7e101000 {
compatible = "brcm,bcm2835-cprman";
#clock-cells = <0x1>;
reg = <0x7e101000 0x2000>;
clocks = <0x3>;
linux,phandle = <0x4>;
phandle = <0x4>;
};

rng@7e104000 {
compatible = "brcm,bcm2835-rng";
reg = <0x7e104000 0x10>;
};

mailbox@7e00b880 {
compatible = "brcm,bcm2835-mbox";
reg = <0x7e00b880 0x40>;
interrupts = <0x0 0x1>;
#mbox-cells = <0x0>;
linux,phandle = <0xf>;
phandle = <0xf>;
};

gpio@7e200000 {
compatible = "brcm,bcm2835-gpio";
reg = <0x7e200000 0xb4>;
interrupts = <0x2 0x11 0x2 0x12 0x2 0x13 0x2 0x14>;
gpio-controller;
#gpio-cells = <0x2>;
interrupt-controller;
#interrupt-cells = <0x2>;
pinctrl-names = "default";
linux,phandle = <0x11>;
phandle = <0x11>;

dpi_gpio0 {
brcm,pins = <0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b>;
brcm,function = <0x6>;
};

emmc_gpio22 {
brcm,pins = <0x16 0x17 0x18 0x19 0x1a 0x1b>;
brcm,function = <0x7>;
};

emmc_gpio34 {
brcm,pins = <0x22 0x23 0x24 0x25 0x26 0x27>;
brcm,function = <0x7>;
brcm,pull = <0x0 0x2 0x2 0x2 0x2 0x2>;
};

emmc_gpio48 {
brcm,pins = <0x30 0x31 0x32 0x33 0x34 0x35>;
brcm,function = <0x7>;
linux,phandle = <0xa>;
phandle = <0xa>;
};

gpclk0_gpio4 {
brcm,pins = <0x4>;
brcm,function = <0x4>;
};

gpclk1_gpio5 {
brcm,pins = <0x5>;
brcm,function = <0x4>;
};

gpclk1_gpio42 {
brcm,pins = <0x2a>;
brcm,function = <0x4>;
};

gpclk1_gpio44 {
brcm,pins = <0x2c>;
brcm,function = <0x4>;
};

gpclk2_gpio6 {
brcm,pins = <0x6>;
brcm,function = <0x4>;
};

gpclk2_gpio43 {
brcm,pins = <0x2b>;
brcm,function = <0x4>;
};

i2c0_gpio0 {
brcm,pins = <0x0 0x1>;
brcm,function = <0x4>;
linux,phandle = <0x6>;
phandle = <0x6>;
};

i2c0_gpio32 {
brcm,pins = <0x20 0x22>;
brcm,function = <0x4>;
};

i2c0_gpio44 {
brcm,pins = <0x2c 0x2d>;
brcm,function = <0x5>;
};

i2c1_gpio2 {
brcm,pins = <0x2 0x3>;
brcm,function = <0x4>;
linux,phandle = <0xb>;
phandle = <0xb>;
};

i2c1_gpio44 {
brcm,pins = <0x2c 0x2d>;
brcm,function = <0x6>;
};

i2c_slave_gpio18 {
brcm,pins = <0x12 0x13 0x14 0x15>;
brcm,function = <0x7>;
};

jtag_gpio4 {
brcm,pins = <0x4 0x5 0x6 0xc 0xd>;
brcm,function = <0x3>;
};

jtag_gpio22 {
brcm,pins = <0x16 0x17 0x18 0x19 0x1a 0x1b>;
brcm,function = <0x3>;
};

pcm_gpio18 {
brcm,pins = <0x12 0x13 0x14 0x15>;
brcm,function = <0x4>;
};

pcm_gpio28 {
brcm,pins = <0x1c 0x1d 0x1e 0x1f>;
brcm,function = <0x6>;
};

pwm0_gpio12 {
brcm,pins = <0xc>;
brcm,function = <0x4>;
};

pwm0_gpio18 {
brcm,pins = <0x12>;
brcm,function = <0x2>;
};

pwm0_gpio40 {
brcm,pins = <0x28>;
brcm,function = <0x4>;
linux,phandle = <0x8>;
phandle = <0x8>;
};

pwm1_gpio13 {
brcm,pins = <0xd>;
brcm,function = <0x4>;
};

pwm1_gpio19 {
brcm,pins = <0x13>;
brcm,function = <0x2>;
};

pwm1_gpio41 {
brcm,pins = <0x29>;
brcm,function = <0x4>;
};

pwm1_gpio45 {
brcm,pins = <0x2d>;
brcm,function = <0x4>;
linux,phandle = <0x9>;
phandle = <0x9>;
};

sdhost_gpio48 {
brcm,pins = <0x30 0x31 0x32 0x33 0x34 0x35>;
brcm,function = <0x4>;
};

spi0_gpio7 {
brcm,pins = <0x7 0x8 0x9 0xa 0xb>;
brcm,function = <0x4>;
};

spi0_gpio35 {
brcm,pins = <0x23 0x24 0x25 0x26 0x27>;
brcm,function = <0x4>;
};

spi1_gpio16 {
brcm,pins = <0x10 0x11 0x12 0x13 0x14 0x15>;
brcm,function = <0x3>;
};

spi2_gpio40 {
brcm,pins = <0x28 0x29 0x2a 0x2b 0x2c 0x2d>;
brcm,function = <0x3>;
};

uart0_gpio14 {
brcm,pins = <0xe 0xf>;
brcm,function = <0x4>;
};

uart0_ctsrts_gpio16 {
brcm,pins = <0x10 0x11>;
brcm,function = <0x7>;
};

uart0_gpio30 {
brcm,pins = <0x1e 0x1f>;
brcm,function = <0x7>;
};

uart0_ctsrts_gpio32 {
brcm,pins = <0x20 0x21>;
brcm,function = <0x7>;
};

uart1_gpio14 {
brcm,pins = <0xe 0xf>;
brcm,function = <0x2>;
};

uart1_ctsrts_gpio16 {
brcm,pins = <0x10 0x11>;
brcm,function = <0x2>;
};

uart1_gpio32 {
brcm,pins = <0x20 0x21>;
brcm,function = <0x2>;
};

uart1_ctsrts_gpio30 {
brcm,pins = <0x1e 0x1f>;
brcm,function = <0x2>;
};

uart1_gpio36 {
brcm,pins = <0x24 0x25 0x26 0x27>;
brcm,function = <0x6>;
};

uart1_gpio40 {
brcm,pins = <0x28 0x29>;
brcm,function = <0x2>;
};

uart1_ctsrts_gpio42 {
brcm,pins = <0x2a 0x2b>;
brcm,function = <0x2>;
};

gpioout {
brcm,pins = <0x6>;
brcm,function = <0x1>;
};

alt0 {
brcm,pins = <0x4 0x5 0x7 0x8 0x9 0xa 0xb 0xe 0xf>;
brcm,function = <0x4>;
};
};

serial@7e201000 {
compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
reg = <0x7e201000 0x1000>;
interrupts = <0x2 0x19>;
clocks = <0x4 0x13 0x4 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
};

i2s@7e203000 {
compatible = "brcm,bcm2835-i2s";
reg = <0x7e203000 0x20 0x7e101098 0x2>;
dmas = <0x5 0x2 0x5 0x3>;
dma-names = "tx", "rx";
status = "disabled";
};

spi@7e204000 {
compatible = "brcm,bcm2835-spi";
reg = <0x7e204000 0x1000>;
interrupts = <0x2 0x16>;
clocks = <0x4 0x14>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "disabled";
};

i2c@7e205000 {
compatible = "brcm,bcm2835-i2c";
reg = <0x7e205000 0x1000>;
interrupts = <0x2 0x15>;
clocks = <0x4 0x14>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <0x6>;
clock-frequency = <0x186a0>;
};

pixelvalve@7e206000 {
compatible = "brcm,bcm2835-pixelvalve0";
reg = <0x7e206000 0x100>;
interrupts = <0x2 0xd>;
};

pixelvalve@7e207000 {
compatible = "brcm,bcm2835-pixelvalve1";
reg = <0x7e207000 0x100>;
interrupts = <0x2 0xe>;
};

thermal@7e212000 {
compatible = "brcm,bcm2837-thermal";
reg = <0x7e212000 0x8>;
clocks = <0x4 0x1b>;
status = "okay";
};

aux@0x7e215000 {
compatible = "brcm,bcm2835-aux";
#clock-cells = <0x1>;
reg = <0x7e215000 0x8>;
clocks = <0x4 0x14>;
linux,phandle = <0x7>;
phandle = <0x7>;
};

serial@7e215040 {
compatible = "brcm,bcm2835-aux-uart";
reg = <0x7e215040 0x40>;
interrupts = <0x1 0x1d>;
clocks = <0x7 0x0>;
status = "okay";
};

spi@7e215080 {
compatible = "brcm,bcm2835-aux-spi";
reg = <0x7e215080 0x40>;
interrupts = <0x1 0x1d>;
clocks = <0x7 0x1>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "disabled";
};

spi@7e2150c0 {
compatible = "brcm,bcm2835-aux-spi";
reg = <0x7e2150c0 0x40>;
interrupts = <0x1 0x1d>;
clocks = <0x7 0x2>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "disabled";
};

pwm@7e20c000 {
compatible = "brcm,bcm2835-pwm";
reg = <0x7e20c000 0x28>;
clocks = <0x4 0x1e>;
assigned-clocks = <0x4 0x1e>;
assigned-clock-rates = <0x989680>;
#pwm-cells = <0x2>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <0x8 0x9>;
};

sdhci@7e300000 {
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e300000 0x100>;
interrupts = <0x2 0x1e>;
clocks = <0x4 0x1c>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <0xa>;
bus-width = <0x4>;
};

hvs@7e400000 {
compatible = "brcm,bcm2835-hvs";
reg = <0x7e400000 0x6000>;
interrupts = <0x2 0x1>;
};

i2c@7e804000 {
compatible = "brcm,bcm2835-i2c";
reg = <0x7e804000 0x1000>;
interrupts = <0x2 0x15>;
clocks = <0x4 0x14>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <0xb>;
clock-frequency = <0x186a0>;
};

i2c@7e805000 {
compatible = "brcm,bcm2835-i2c";
reg = <0x7e805000 0x1000>;
interrupts = <0x2 0x15>;
clocks = <0x4 0x14>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "okay";
linux,phandle = <0xd>;
phandle = <0xd>;
};

vec@7e806000 {
compatible = "brcm,bcm2835-vec";
reg = <0x7e806000 0x1000>;
clocks = <0x4 0x18>;
interrupts = <0x2 0x1b>;
status = "okay";
power-domains = <0xc 0x7>;
};

pixelvalve@7e807000 {
compatible = "brcm,bcm2835-pixelvalve2";
reg = <0x7e807000 0x100>;
interrupts = <0x2 0xa>;
};

hdmi@7e902000 {
compatible = "brcm,bcm2835-hdmi";
reg = <0x7e902000 0x600 0x7e808000 0x100>;
interrupts = <0x2 0x8 0x2 0x9>;
ddc = <0xd>;
clocks = <0x4 0x10 0x4 0x19>;
clock-names = "pixel", "hdmi";
status = "okay";
power-domains = <0xc 0x5>;
};

usb@7e980000 {
compatible = "brcm,bcm2835-usb";
reg = <0x7e980000 0x10000>;
interrupts = <0x1 0x9>;
#address-cells = <0x1>;
#size-cells = <0x0>;
clocks = <0xe>;
clock-names = "otg";
power-domains = <0xc 0x6>;
dr_mode = "host";

usb1@1 {
compatible = "usb424,9514";
reg = <0x1>;
#address-cells = <0x1>;
#size-cells = <0x0>;

usbether@1 {
compatible = "usb424,ec00";
reg = <0x1>;
};
};
};

v3d@7ec00000 {
compatible = "brcm,bcm2835-v3d";
reg = <0x7ec00000 0x1000>;
interrupts = <0x1 0xa>;
power-domains = <0xc 0xa>;
};

gpu {
compatible = "brcm,bcm2835-vc4";
status = "disabled";
};

local_intc {
compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>;
interrupt-controller;
#interrupt-cells = <0x1>;
interrupt-parent = <0x2>;
linux,phandle = <0x2>;
phandle = <0x2>;
};

firmware {
compatible = "raspberrypi,bcm2835-firmware";
mboxes = <0xf>;
linux,phandle = <0x10>;
phandle = <0x10>;
};

power {
compatible = "raspberrypi,bcm2835-power";
firmware = <0x10>;
#power-domain-cells = <0x1>;
linux,phandle = <0xc>;
phandle = <0xc>;
};

vchiq {
compatible = "brcm,bcm2835-vchiq";
reg = <0x7e00b840 0xf>;
interrupts = <0x0 0x2>;
cache-line-size = <0x20>;
firmware = <0x10>;
linux,phandle = <0x12>;
phandle = <0x12>;
};

fb {
status = "disabled";
};

audio {
compatible = "brcm,bcm2835-audio";
brcm,pwm-channels = <0x8>;
};
};

clocks {
compatible = "simple-bus";
#address-cells = <0x1>;
#size-cells = <0x0>;

clock@3 {
compatible = "fixed-clock";
reg = <0x3>;
#clock-cells = <0x0>;
clock-output-names = "osc";
clock-frequency = <0x124f800>;
linux,phandle = <0x3>;
phandle = <0x3>;
};

clock@4 {
compatible = "fixed-clock";
reg = <0x4>;
#clock-cells = <0x0>;
clock-output-names = "otg";
clock-frequency = <0x1c9c3800>;
linux,phandle = <0xe>;
phandle = <0xe>;
};
};

timer {
compatible = "arm,armv7-timer";
interrupt-parent = <0x2>;
interrupts = <0x0 0x1 0x3 0x2>;
always-on;
};

cpus {
#address-cells = <0x1>;
#size-cells = <0x0>;

cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x0>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0xd8>;
};

cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x1>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0xe0>;
};

cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x2>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0xe8>;
};

cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x3>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0xf0>;
};
};

memory {
device_type = "memory";
reg = <0x0 0x40000000>;
};

leds {
compatible = "gpio-leds";

act {
label = "ACT";
default-state = "keep";
linux,default-trigger = "heartbeat";
gpios = <0x11 0x2f 0x0>;
};
};

aliases {
ethernet = "/soc/usb@7e980000/usb1@1/usbether@1";
};

__overrides__ {
cache_line_size = [00 00 00 12 63 61 63 68 65 2d 6c 69 6e 65 2d 73 69 7a 65 3a 30 00];
};
};
0 new messages