mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 01:51:53 +00:00
[media] s5p-fimc: Add support for Exynos4x12 FIMC-LITE
This patch adds driver for FIMC-LITE camera host interface. This new IP differs from the regular FIMC IP in that it doesn't have input DMA, scaler and color space conversion support. So it just plain camera host interface for MIPI-CSI2 and ITU-R interfaces. For the serial bus support it interworks with MIPI-CSIS and the exisiting s5p-csis driver. The FIMC-LITE and MIPI-CSIS drivers can also be reused in the Exynos5 SoC series. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
5af86c2691
commit
4af813108b
@ -1130,19 +1130,6 @@ config VIDEO_MX2
|
||||
This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
|
||||
Interface
|
||||
|
||||
config VIDEO_SAMSUNG_S5P_FIMC
|
||||
tristate "Samsung S5P and EXYNOS4 camera interface driver (EXPERIMENTAL)"
|
||||
depends on VIDEO_V4L2 && I2C && PLAT_S5P && PM_RUNTIME && \
|
||||
VIDEO_V4L2_SUBDEV_API && EXPERIMENTAL
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select V4L2_MEM2MEM_DEV
|
||||
---help---
|
||||
This is a v4l2 driver for Samsung S5P and EXYNOS4 camera
|
||||
host interface and video postprocessor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called s5p-fimc.
|
||||
|
||||
config VIDEO_ATMEL_ISI
|
||||
tristate "ATMEL Image Sensor Interface (ISI) support"
|
||||
depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
|
||||
@ -1151,16 +1138,7 @@ config VIDEO_ATMEL_ISI
|
||||
This module makes the ATMEL Image Sensor Interface available
|
||||
as a v4l2 device.
|
||||
|
||||
config VIDEO_S5P_MIPI_CSIS
|
||||
tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
|
||||
depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P
|
||||
depends on VIDEO_V4L2_SUBDEV_API && REGULATOR
|
||||
---help---
|
||||
This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called s5p-csis.
|
||||
|
||||
source "drivers/media/video/s5p-fimc/Kconfig"
|
||||
source "drivers/media/video/s5p-tv/Kconfig"
|
||||
|
||||
endif # V4L_PLATFORM_DRIVERS
|
||||
|
48
drivers/media/video/s5p-fimc/Kconfig
Normal file
48
drivers/media/video/s5p-fimc/Kconfig
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
config VIDEO_SAMSUNG_S5P_FIMC
|
||||
bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)"
|
||||
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
Say Y here to enable camera host interface devices for
|
||||
Samsung S5P and EXYNOS SoC series.
|
||||
|
||||
if VIDEO_SAMSUNG_S5P_FIMC
|
||||
|
||||
config VIDEO_S5P_FIMC
|
||||
tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
|
||||
depends on I2C
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select V4L2_MEM2MEM_DEV
|
||||
help
|
||||
This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host
|
||||
interface and video postprocessor (FIMC and FIMC-LITE) devices.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called s5p-fimc.
|
||||
|
||||
config VIDEO_S5P_MIPI_CSIS
|
||||
tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver"
|
||||
depends on REGULATOR
|
||||
help
|
||||
This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2
|
||||
receiver (MIPI-CSIS) devices.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called s5p-csis.
|
||||
|
||||
if ARCH_EXYNOS
|
||||
|
||||
config VIDEO_EXYNOS_FIMC_LITE
|
||||
tristate "EXYNOS FIMC-LITE camera interface driver"
|
||||
depends on I2C
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
help
|
||||
This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera
|
||||
host interface.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called exynos-fimc-lite.
|
||||
endif
|
||||
|
||||
endif # VIDEO_SAMSUNG_S5P_FIMC
|
@ -1,5 +1,7 @@
|
||||
s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o fimc-mdevice.o
|
||||
exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
|
||||
s5p-csis-objs := mipi-csis.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o
|
||||
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc.o
|
||||
obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o
|
||||
obj-$(CONFIG_VIDEO_S5P_FIMC) += s5p-fimc.o
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/sizes.h>
|
||||
|
||||
#include <media/media-entity.h>
|
||||
#include <media/videobuf2-core.h>
|
||||
|
1576
drivers/media/video/s5p-fimc/fimc-lite.c
Normal file
1576
drivers/media/video/s5p-fimc/fimc-lite.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -66,6 +66,9 @@ void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me)
|
||||
case CSIS_GROUP_ID:
|
||||
p->subdevs[IDX_CSIS] = sd;
|
||||
break;
|
||||
case FLITE_GROUP_ID:
|
||||
p->subdevs[IDX_FLITE] = sd;
|
||||
break;
|
||||
case FIMC_GROUP_ID:
|
||||
/* No need to control FIMC subdev through subdev ops */
|
||||
break;
|
||||
@ -336,6 +339,7 @@ static int fimc_register_callback(struct device *dev, void *p)
|
||||
|
||||
if (!fimc || !fimc->pdev)
|
||||
return 0;
|
||||
|
||||
if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS)
|
||||
return 0;
|
||||
|
||||
@ -351,6 +355,31 @@ static int fimc_register_callback(struct device *dev, void *p)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fimc_lite_register_callback(struct device *dev, void *p)
|
||||
{
|
||||
struct fimc_lite *fimc = dev_get_drvdata(dev);
|
||||
struct v4l2_subdev *sd = &fimc->subdev;
|
||||
struct fimc_md *fmd = p;
|
||||
int ret;
|
||||
|
||||
if (fimc == NULL)
|
||||
return 0;
|
||||
|
||||
if (fimc->index >= FIMC_LITE_MAX_DEVS)
|
||||
return 0;
|
||||
|
||||
fmd->fimc_lite[fimc->index] = fimc;
|
||||
sd->grp_id = FLITE_GROUP_ID;
|
||||
|
||||
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
|
||||
if (ret) {
|
||||
v4l2_err(&fmd->v4l2_dev,
|
||||
"Failed to register FIMC-LITE.%d (%d)\n",
|
||||
fimc->index, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int csis_register_callback(struct device *dev, void *p)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
@ -396,6 +425,15 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd)
|
||||
fimc_register_callback);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
driver = driver_find(FIMC_LITE_DRV_NAME, &platform_bus_type);
|
||||
if (driver && try_module_get(driver->owner)) {
|
||||
ret = driver_for_each_device(driver, NULL, fmd,
|
||||
fimc_lite_register_callback);
|
||||
if (ret)
|
||||
return ret;
|
||||
module_put(driver->owner);
|
||||
}
|
||||
/*
|
||||
* Check if there is any sensor on the MIPI-CSI2 bus and
|
||||
* if not skip the s5p-csis module loading.
|
||||
@ -433,6 +471,12 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
|
||||
v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev);
|
||||
fmd->fimc[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
|
||||
if (fmd->fimc_lite[i] == NULL)
|
||||
continue;
|
||||
v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev);
|
||||
fmd->fimc_lite[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
|
||||
if (fmd->csis[i].sd == NULL)
|
||||
continue;
|
||||
@ -456,28 +500,28 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
|
||||
* @pad: the source entity pad index
|
||||
* @fimc_id: index of the fimc device for which link should be enabled
|
||||
*/
|
||||
static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
|
||||
struct media_entity *source,
|
||||
struct v4l2_subdev *sensor,
|
||||
int pad, int fimc_id)
|
||||
static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
|
||||
struct media_entity *source,
|
||||
struct v4l2_subdev *sensor,
|
||||
int pad, int fimc_id)
|
||||
{
|
||||
struct fimc_sensor_info *s_info;
|
||||
struct media_entity *sink;
|
||||
unsigned int flags;
|
||||
unsigned int flags = 0;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < FIMC_MAX_DEVS; i++) {
|
||||
if (!fmd->fimc[i])
|
||||
break;
|
||||
continue;
|
||||
/*
|
||||
* Some FIMC variants are not fitted with camera capture
|
||||
* interface. Skip creating a link from sensor for those.
|
||||
*/
|
||||
if (sensor->grp_id == SENSOR_GROUP_ID &&
|
||||
!fmd->fimc[i]->variant->has_cam_if)
|
||||
if (!fmd->fimc[i]->variant->has_cam_if)
|
||||
continue;
|
||||
|
||||
flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
|
||||
|
||||
sink = &fmd->fimc[i]->vid_cap.subdev.entity;
|
||||
ret = media_entity_create_link(source, pad, sink,
|
||||
FIMC_SD_PAD_SINK, flags);
|
||||
@ -493,7 +537,7 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
|
||||
v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
|
||||
source->name, flags ? '=' : '-', sink->name);
|
||||
|
||||
if (flags == 0)
|
||||
if (flags == 0 || sensor == NULL)
|
||||
continue;
|
||||
s_info = v4l2_get_subdev_hostdata(sensor);
|
||||
if (!WARN_ON(s_info == NULL)) {
|
||||
@ -503,9 +547,55 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
|
||||
spin_unlock_irqrestore(&fmd->slock, irq_flags);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
|
||||
if (!fmd->fimc_lite[i])
|
||||
continue;
|
||||
|
||||
flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
|
||||
|
||||
sink = &fmd->fimc_lite[i]->subdev.entity;
|
||||
ret = media_entity_create_link(source, pad, sink,
|
||||
FLITE_SD_PAD_SINK, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Notify FIMC-LITE subdev entity */
|
||||
ret = media_entity_call(sink, link_setup, &sink->pads[0],
|
||||
&source->pads[pad], flags);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
|
||||
source->name, flags ? '=' : '-', sink->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create links from FIMC-LITE source pads to other entities */
|
||||
static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
|
||||
{
|
||||
struct media_entity *source, *sink;
|
||||
unsigned int flags = MEDIA_LNK_FL_ENABLED;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
|
||||
struct fimc_lite *fimc = fmd->fimc_lite[i];
|
||||
if (fimc == NULL)
|
||||
continue;
|
||||
source = &fimc->subdev.entity;
|
||||
sink = &fimc->vfd->entity;
|
||||
/* FIMC-LITE's subdev and video node */
|
||||
ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
|
||||
sink, 0, flags);
|
||||
if (ret)
|
||||
break;
|
||||
/* TODO: create links to other entities */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* fimc_md_create_links - create default links between registered entities
|
||||
*
|
||||
@ -562,8 +652,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
|
||||
v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
|
||||
sensor->entity.name, csis->entity.name);
|
||||
|
||||
source = &csis->entity;
|
||||
pad = CSIS_PAD_SOURCE;
|
||||
source = NULL;
|
||||
break;
|
||||
|
||||
case FIMC_ITU_601...FIMC_ITU_656:
|
||||
@ -579,9 +668,21 @@ static int fimc_md_create_links(struct fimc_md *fmd)
|
||||
if (source == NULL)
|
||||
continue;
|
||||
|
||||
ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad,
|
||||
fimc_id++);
|
||||
ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
|
||||
pad, fimc_id++);
|
||||
}
|
||||
|
||||
fimc_id = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) {
|
||||
if (fmd->csis[i].sd == NULL)
|
||||
continue;
|
||||
source = &fmd->csis[i].sd->entity;
|
||||
pad = CSIS_PAD_SOURCE;
|
||||
|
||||
ret = __fimc_md_create_fimc_sink_links(fmd, source, NULL,
|
||||
pad, fimc_id++);
|
||||
}
|
||||
|
||||
/* Create immutable links between each FIMC's subdev and video node */
|
||||
flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
|
||||
for (i = 0; i < FIMC_MAX_DEVS; i++) {
|
||||
@ -595,7 +696,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return __fimc_md_create_flite_source_links(fmd);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -703,9 +804,10 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
|
||||
static int fimc_md_link_notify(struct media_pad *source,
|
||||
struct media_pad *sink, u32 flags)
|
||||
{
|
||||
struct fimc_lite *fimc_lite = NULL;
|
||||
struct fimc_dev *fimc = NULL;
|
||||
struct fimc_pipeline *pipeline;
|
||||
struct v4l2_subdev *sd;
|
||||
struct fimc_dev *fimc;
|
||||
int ret = 0;
|
||||
|
||||
if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
|
||||
@ -714,6 +816,10 @@ static int fimc_md_link_notify(struct media_pad *source,
|
||||
sd = media_entity_to_v4l2_subdev(sink->entity);
|
||||
|
||||
switch (sd->grp_id) {
|
||||
case FLITE_GROUP_ID:
|
||||
fimc_lite = v4l2_get_subdevdata(sd);
|
||||
pipeline = &fimc_lite->pipeline;
|
||||
break;
|
||||
case FIMC_GROUP_ID:
|
||||
fimc = v4l2_get_subdevdata(sd);
|
||||
pipeline = &fimc->pipeline;
|
||||
@ -739,15 +845,23 @@ static int fimc_md_link_notify(struct media_pad *source,
|
||||
* pipeline is already in use, i.e. its video node is opened.
|
||||
* Recreate the controls destroyed during the link deactivation.
|
||||
*/
|
||||
mutex_lock(&fimc->lock);
|
||||
if (fimc->vid_cap.refcnt > 0) {
|
||||
if (fimc) {
|
||||
mutex_lock(&fimc->lock);
|
||||
if (fimc->vid_cap.refcnt > 0) {
|
||||
ret = __fimc_pipeline_initialize(pipeline,
|
||||
source->entity, true);
|
||||
if (!ret)
|
||||
ret = fimc_capture_ctrls_create(fimc);
|
||||
}
|
||||
mutex_unlock(&fimc->lock);
|
||||
} else {
|
||||
mutex_lock(&fimc_lite->lock);
|
||||
if (fimc_lite->ref_count > 0) {
|
||||
ret = __fimc_pipeline_initialize(pipeline,
|
||||
source->entity, true);
|
||||
}
|
||||
mutex_unlock(&fimc_lite->lock);
|
||||
}
|
||||
mutex_unlock(&fimc->lock);
|
||||
|
||||
return ret ? -EPIPE : ret;
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,15 @@
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "fimc-core.h"
|
||||
#include "fimc-lite.h"
|
||||
#include "mipi-csis.h"
|
||||
|
||||
/* Group IDs of sensor, MIPI CSIS and the writeback subdevs. */
|
||||
/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */
|
||||
#define SENSOR_GROUP_ID (1 << 8)
|
||||
#define CSIS_GROUP_ID (1 << 9)
|
||||
#define WRITEBACK_GROUP_ID (1 << 10)
|
||||
#define FIMC_GROUP_ID (1 << 11)
|
||||
#define FLITE_GROUP_ID (1 << 12)
|
||||
|
||||
#define FIMC_MAX_SENSORS 8
|
||||
#define FIMC_MAX_CAMCLKS 2
|
||||
@ -74,6 +76,7 @@ struct fimc_md {
|
||||
struct fimc_sensor_info sensor[FIMC_MAX_SENSORS];
|
||||
int num_sensors;
|
||||
struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS];
|
||||
struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS];
|
||||
struct fimc_dev *fimc[FIMC_MAX_DEVS];
|
||||
struct media_device media_dev;
|
||||
struct v4l2_device v4l2_dev;
|
||||
|
Loading…
Reference in New Issue
Block a user