Skip to content

Commit

Permalink
media: vimc: Collapse component structure into a single monolithic dr…
Browse files Browse the repository at this point in the history
…iver

vimc uses Component API to split the driver into functional components.
The real hardware resembles a monolith structure than component and
component structure added a level of complexity making it hard to
maintain without adding any real benefit.

The sensor is one vimc component that would makes sense to be a separate
module to closely align with the real hardware. It would be easier to
collapse vimc into single monolithic driver first and then split the
sensor off as a separate module.

Collapse it into a single monolithic driver removing the Component API.
This patch removes the component API and makes minimal changes to the
code base preserving the functional division of the code structure.
Preserving the functional structure allows us to split the sensor off
as a separate module in the future.

Major design elements in this change are:
- Use existing struct vimc_ent_config and struct vimc_pipeline_config
  to drive the initialization of the functional components.
- Make vimc_device and vimc_ent_config global by moving them to
  vimc-common.h
- Add two new hooks add and rm to initialize and register, unregister
  and free subdevs.
- All component API is now gone and bind and unbind hooks are modified
  to do "add" and "rm" with minimal changes to just add and rm subdevs.
- vimc-core's bind and unbind are now register and unregister.
- Add a new field to vimc_device structure for saving the pointers to
  struct vimc_ent_device(s) subdevs create in their "add" hooks. These
  get used to create links and removing the subdevs. vimc-core allocates
  this array which sized to number of entries in the topology defined in
  the vimc_pipeline_config structure.
- vimc-core invokes "add" hooks from its vimc_register_devices().
  The "add" hooks remain the same and register subdevs. They don't
  create platform devices of their own and use vimc's pdev.dev as
  their reference device. Each "add" hook returns pointer to its struct
  vimc_ent_device. This is saved in the vimc_device ent_devs array.
- vimc-core invokes "rm" hooks from its unregister to unregister subdevs
  and cleanup.
- vimc-core invokes "add" and "rm" hooks with pointer to struct vimc_device
  and the corresponding vimc_ent_device saved in the ent_devs.

The following configure and stream test works on all devices.

media-ctl -d platform:vimc -V '"Sensor A":0[fmt:SBGGR8_1X8/640x480]'
media-ctl -d platform:vimc -V '"Debayer A":0[fmt:SBGGR8_1X8/640x480]'
media-ctl -d platform:vimc -V '"Sensor B":0[fmt:SBGGR8_1X8/640x480]'
media-ctl -d platform:vimc -V '"Debayer B":0[fmt:SBGGR8_1X8/640x480]'

v4l2-ctl -z platform:vimc -d "RGB/YUV Capture" -v width=1920,height=1440
v4l2-ctl -z platform:vimc -d "Raw Capture 0" -v pixelformat=BA81
v4l2-ctl -z platform:vimc -d "Raw Capture 1" -v pixelformat=BA81

v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video1
v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video2
v4l2-ctl --stream-mmap --stream-count=100 -d /dev/video3

Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Acked-by: Helen Koike <helen.koike@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
  • Loading branch information
shuahkh authored and mchehab committed Oct 1, 2019
1 parent 713f871 commit f13d5f3
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 385 deletions.
7 changes: 4 additions & 3 deletions drivers/media/platform/vimc/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
vimc-y := vimc-core.o vimc-common.o vimc-streamer.o
vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \
vimc-debayer.o vimc-scaler.o vimc-sensor.o

obj-$(CONFIG_VIDEO_VIMC) += vimc.o

obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc-capture.o vimc-debayer.o \
vimc-scaler.o vimc-sensor.o
81 changes: 15 additions & 66 deletions drivers/media/platform/vimc/vimc-capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,13 @@
* Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
*/

#include <linux/component.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-vmalloc.h>

#include "vimc-common.h"
#include "vimc-streamer.h"

#define VIMC_CAP_DRV_NAME "vimc-capture"

struct vimc_cap_device {
struct vimc_ent_device ved;
struct video_device vdev;
Expand Down Expand Up @@ -340,13 +334,11 @@ static void vimc_cap_release(struct video_device *vdev)
kfree(vcap);
}

static void vimc_cap_comp_unbind(struct device *comp, struct device *master,
void *master_data)
void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
{
struct vimc_ent_device *ved = dev_get_drvdata(comp);
struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device,
ved);
struct vimc_cap_device *vcap;

vcap = container_of(ved, struct vimc_cap_device, ved);
vb2_queue_release(&vcap->queue);
media_entity_cleanup(ved->ent);
video_unregister_device(&vcap->vdev);
Expand Down Expand Up @@ -391,11 +383,10 @@ static void *vimc_cap_process_frame(struct vimc_ent_device *ved,
return NULL;
}

static int vimc_cap_comp_bind(struct device *comp, struct device *master,
void *master_data)
struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
const char *vcfg_name)
{
struct v4l2_device *v4l2_dev = master_data;
struct vimc_platform_data *pdata = comp->platform_data;
struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
const struct vimc_pix_map *vpix;
struct vimc_cap_device *vcap;
struct video_device *vdev;
Expand All @@ -405,7 +396,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
/* Allocate the vimc_cap_device struct */
vcap = kzalloc(sizeof(*vcap), GFP_KERNEL);
if (!vcap)
return -ENOMEM;
return NULL;

/* Allocate the pads */
vcap->ved.pads =
Expand All @@ -416,7 +407,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
}

/* Initialize the media entity */
vcap->vdev.entity.name = pdata->entity_name;
vcap->vdev.entity.name = vcfg_name;
vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L;
ret = media_entity_pads_init(&vcap->vdev.entity,
1, vcap->ved.pads);
Expand All @@ -440,8 +431,8 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,

ret = vb2_queue_init(q);
if (ret) {
dev_err(comp, "%s: vb2 queue init failed (err=%d)\n",
pdata->entity_name, ret);
dev_err(&vimc->pdev.dev, "%s: vb2 queue init failed (err=%d)\n",
vcfg_name, ret);
goto err_clean_m_ent;
}

Expand All @@ -460,8 +451,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
vcap->ved.ent = &vcap->vdev.entity;
vcap->ved.process_frame = vimc_cap_process_frame;
vcap->ved.vdev_get_format = vimc_cap_get_format;
dev_set_drvdata(comp, &vcap->ved);
vcap->dev = comp;
vcap->dev = &vimc->pdev.dev;

/* Initialize the video_device struct */
vdev = &vcap->vdev;
Expand All @@ -474,18 +464,18 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
vdev->queue = q;
vdev->v4l2_dev = v4l2_dev;
vdev->vfl_dir = VFL_DIR_RX;
strscpy(vdev->name, pdata->entity_name, sizeof(vdev->name));
strscpy(vdev->name, vcfg_name, sizeof(vdev->name));
video_set_drvdata(vdev, &vcap->ved);

/* Register the video_device with the v4l2 and the media framework */
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
if (ret) {
dev_err(comp, "%s: video register failed (err=%d)\n",
dev_err(&vimc->pdev.dev, "%s: video register failed (err=%d)\n",
vcap->vdev.name, ret);
goto err_release_queue;
}

return 0;
return &vcap->ved;

err_release_queue:
vb2_queue_release(q);
Expand All @@ -496,46 +486,5 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
err_free_vcap:
kfree(vcap);

return ret;
}

static const struct component_ops vimc_cap_comp_ops = {
.bind = vimc_cap_comp_bind,
.unbind = vimc_cap_comp_unbind,
};

static int vimc_cap_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &vimc_cap_comp_ops);
}

static int vimc_cap_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &vimc_cap_comp_ops);

return 0;
return NULL;
}

static const struct platform_device_id vimc_cap_driver_ids[] = {
{
.name = VIMC_CAP_DRV_NAME,
},
{ }
};

static struct platform_driver vimc_cap_pdrv = {
.probe = vimc_cap_probe,
.remove = vimc_cap_remove,
.id_table = vimc_cap_driver_ids,
.driver = {
.name = VIMC_CAP_DRV_NAME,
},
};

module_platform_driver(vimc_cap_pdrv);

MODULE_DEVICE_TABLE(platform, vimc_cap_driver_ids);

MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Capture");
MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>");
MODULE_LICENSE("GPL");
54 changes: 54 additions & 0 deletions drivers/media/platform/vimc/vimc-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#ifndef _VIMC_COMMON_H_
#define _VIMC_COMMON_H_

#include <linux/platform_device.h>
#include <linux/slab.h>
#include <media/media-device.h>
#include <media/v4l2-device.h>
Expand Down Expand Up @@ -111,6 +112,59 @@ struct vimc_ent_device {
struct v4l2_pix_format *fmt);
};

/**
* struct vimc_device - main device for vimc driver
*
* @pdev pointer to the platform device
* @pipe_cfg pointer to the vimc pipeline configuration structure
* @ent_devs array of vimc_ent_device pointers
* @mdev the associated media_device parent
* @v4l2_dev Internal v4l2 parent device
*/
struct vimc_device {
struct platform_device pdev;
const struct vimc_pipeline_config *pipe_cfg;
struct vimc_ent_device **ent_devs;
struct media_device mdev;
struct v4l2_device v4l2_dev;
};

/**
* struct vimc_ent_config Structure which describes individual
* configuration for each entity
*
* @name entity name
* @ved pointer to vimc_ent_device (a node in the
* topology)
* @add subdev add hook - initializes and registers
* subdev called from vimc-core
* @rm subdev rm hook - unregisters and frees
* subdev called from vimc-core
*/
struct vimc_ent_config {
const char *name;
struct vimc_ent_device *(*add)(struct vimc_device *vimc,
const char *vcfg_name);
void (*rm)(struct vimc_device *vimc, struct vimc_ent_device *ved);
};

/* prototypes for vimc_ent_config add and rm hooks */
struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
const char *vcfg_name);
void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);

struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc,
const char *vcfg_name);
void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);

struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
const char *vcfg_name);
void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);

struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc,
const char *vcfg_name);
void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);

/**
* vimc_pads_init - initialize pads
*
Expand Down
Loading

0 comments on commit f13d5f3

Please sign in to comment.