Commit 88fa8311 authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab

[media] s5p-fimc: Add support for ISP Writeback data input bus type

A second sink pad is added to each FIMC.N subdev that will be used
to link it to the FIMC-IS-ISP subdev. Only V4L2_MBUS_FMT_YUV10_1X30
format is supported at this pad (FIMC_SD_PAD_SINK_FIFO).
The routine checking for mismatch in the image formats at sides of
the links is updated to account for the fact FIMC.X subdevs now have
sink pads at the pad indexes 0, 1 and source pad at pad index 2.
If link to FIMC.X pad 1 is activated we switch FIMC input data bus
type to the ISP Writeback. Only a single active link to FIMC.X pad 0
or 1 will be allowed at any time.
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 056f4f30
......@@ -2,6 +2,7 @@
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 MFD_SYSCON
help
Say Y here to enable camera host interface devices for
Samsung S5P and EXYNOS SoC series.
......
......@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/list.h>
#include <linux/mfd/syscon.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
......@@ -78,6 +79,10 @@ static struct fimc_fmt fimc_formats[] = {
.memplanes = 1,
.colplanes = 1,
.flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
}, {
.name = "YUV 4:4:4",
.mbus_code = V4L2_MBUS_FMT_YUV10_1X30,
.flags = FMT_FLAGS_WRITEBACK,
}, {
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
......@@ -959,6 +964,11 @@ static int fimc_probe(struct platform_device *pdev)
spin_lock_init(&fimc->slock);
mutex_init(&fimc->lock);
fimc->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,sysreg");
if (IS_ERR(fimc->sysreg))
return PTR_ERR(fimc->sysreg);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
fimc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(fimc->regs))
......
......@@ -12,6 +12,7 @@
/*#define DEBUG*/
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/types.h>
......@@ -163,6 +164,7 @@ struct fimc_fmt {
#define FMT_FLAGS_M2M (1 << 1 | 1 << 2)
#define FMT_HAS_ALPHA (1 << 3)
#define FMT_FLAGS_COMPRESSED (1 << 4)
#define FMT_FLAGS_WRITEBACK (1 << 5)
};
/**
......@@ -303,9 +305,10 @@ struct fimc_m2m_device {
int refcnt;
};
#define FIMC_SD_PAD_SINK 0
#define FIMC_SD_PAD_SOURCE 1
#define FIMC_SD_PADS_NUM 2
#define FIMC_SD_PAD_SINK_CAM 0
#define FIMC_SD_PAD_SINK_FIFO 1
#define FIMC_SD_PAD_SOURCE 2
#define FIMC_SD_PADS_NUM 3
/**
* struct fimc_vid_cap - camera capture device information
......@@ -314,7 +317,9 @@ struct fimc_m2m_device {
* @subdev: subdev exposing the FIMC processing block
* @vd_pad: fimc video capture node pad
* @sd_pads: fimc video processing block pads
* @mf: media bus format at the FIMC camera input (and the scaler output) pad
* @ci_fmt: image format at the FIMC camera input (and the scaler output)
* @wb_fmt: image format at the FIMC ISP Writeback input
* @source_config: external image source related configuration structure
* @pending_buf_q: the pending buffer queue head
* @active_buf_q: the queue head of buffers scheduled in hardware
* @vbq: the capture am video buffer queue
......@@ -333,8 +338,10 @@ struct fimc_vid_cap {
struct video_device vfd;
struct v4l2_subdev subdev;
struct media_pad vd_pad;
struct v4l2_mbus_framefmt mf;
struct media_pad sd_pads[FIMC_SD_PADS_NUM];
struct v4l2_mbus_framefmt ci_fmt;
struct v4l2_mbus_framefmt wb_fmt;
struct fimc_source_info source_config;
struct list_head pending_buf_q;
struct list_head active_buf_q;
struct vb2_queue vbq;
......@@ -426,6 +433,7 @@ struct fimc_ctx;
* @lock: the mutex protecting this data structure
* @pdev: pointer to the FIMC platform device
* @pdata: pointer to the device platform data
* @sysreg: pointer to the SYSREG regmap
* @variant: the IP variant information
* @id: FIMC device index (0..FIMC_MAX_DEVS)
* @clock: clocks required for FIMC operation
......@@ -443,6 +451,7 @@ struct fimc_dev {
struct mutex lock;
struct platform_device *pdev;
struct s5p_platform_fimc *pdata;
struct regmap *sysreg;
const struct fimc_variant *variant;
const struct fimc_drvdata *drv_data;
u16 id;
......
......@@ -267,6 +267,11 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd,
if (!s_info || !fmd)
return NULL;
/*
* If FIMC bus type is not Writeback FIFO assume it is same
* as sensor_bus_type.
*/
s_info->pdata.fimc_bus_type = s_info->pdata.sensor_bus_type;
adapter = i2c_get_adapter(s_info->pdata.i2c_bus_num);
if (!adapter) {
......@@ -807,7 +812,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
sink = &fmd->fimc[i]->vid_cap.subdev.entity;
ret = media_entity_create_link(source, pad, sink,
FIMC_SD_PAD_SINK, flags);
FIMC_SD_PAD_SINK_CAM, flags);
if (ret)
return ret;
......
/*
* Register interface file for Samsung Camera Interface (FIMC) driver
*
* Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki, <s.nawrocki@samsung.com>
* Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/regmap.h>
#include <media/s5p_fimc.h>
#include "fimc-mdevice.h"
#include "fimc-reg.h"
#include "fimc-core.h"
void fimc_hw_reset(struct fimc_dev *dev)
{
u32 cfg;
......@@ -598,7 +600,8 @@ static const struct mbus_pixfmt_desc pix_desc[] = {
int fimc_hw_set_camera_source(struct fimc_dev *fimc,
struct fimc_source_info *source)
{
struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
struct fimc_vid_cap *vc = &fimc->vid_cap;
struct fimc_frame *f = &vc->ctx->s_frame;
u32 bus_width, cfg = 0;
int i;
......@@ -606,7 +609,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
case FIMC_BUS_TYPE_ITU_601:
case FIMC_BUS_TYPE_ITU_656:
for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
if (vc->ci_fmt.code == pix_desc[i].pixelcode) {
cfg = pix_desc[i].cisrcfmt;
bus_width = pix_desc[i].bus_width;
break;
......@@ -614,9 +617,9 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
}
if (i == ARRAY_SIZE(pix_desc)) {
v4l2_err(&fimc->vid_cap.vfd,
v4l2_err(&vc->vfd,
"Camera color format not supported: %d\n",
fimc->vid_cap.mf.code);
vc->ci_fmt.code);
return -EINVAL;
}
......@@ -631,6 +634,10 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
if (fimc_fmt_is_user_defined(f->fmt->color))
cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
break;
default:
case FIMC_BUS_TYPE_ISP_WRITEBACK:
/* Anything to do here ? */
break;
}
cfg |= (f->o_width << 16) | f->o_height;
......@@ -660,16 +667,17 @@ void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
int fimc_hw_set_camera_type(struct fimc_dev *fimc,
struct fimc_source_info *source)
{
u32 cfg, tmp;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
u32 csis_data_alignment = 32;
u32 cfg, tmp;
cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
/* Select ITU B interface, disable Writeback path and test pattern. */
cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A |
FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB |
FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG);
FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG |
FIMC_REG_CIGCTRL_SELWB_A);
switch (source->fimc_bus_type) {
case FIMC_BUS_TYPE_MIPI_CSI2:
......@@ -679,7 +687,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A;
/* TODO: add remaining supported formats. */
switch (vid_cap->mf.code) {
switch (vid_cap->ci_fmt.code) {
case V4L2_MBUS_FMT_VYUY8_2X8:
tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT;
break;
......@@ -691,7 +699,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
default:
v4l2_err(&vid_cap->vfd,
"Not supported camera pixel format: %#x\n",
vid_cap->mf.code);
vid_cap->ci_fmt.code);
return -EINVAL;
}
tmp |= (csis_data_alignment == 32) << 8;
......@@ -704,6 +712,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
break;
case FIMC_BUS_TYPE_LCD_WRITEBACK_A:
cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
/* fall through */
case FIMC_BUS_TYPE_ISP_WRITEBACK:
if (fimc->variant->has_isp_wb)
cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
else
WARN_ONCE(1, "ISP Writeback input is not supported\n");
break;
default:
v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n",
......@@ -784,3 +798,40 @@ void fimc_deactivate_capture(struct fimc_dev *fimc)
fimc_hw_enable_scaler(fimc, false);
fimc_hw_en_lastirq(fimc, false);
}
int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc)
{
struct regmap *map = fimc->sysreg;
unsigned int mask, val, camblk_cfg;
int ret;
ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg);
if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3))
return ret;
if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id))
val = 0x1 << (fimc->id + 20);
else
val = 0;
mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN;
ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val);
if (ret < 0)
return ret;
usleep_range(1000, 2000);
val |= SYSREG_CAMBLK_FIFORST_ISP;
ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val);
if (ret < 0)
return ret;
mask = SYSREG_ISPBLK_FIFORST_CAM_BLK;
ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask);
if (ret < 0)
return ret;
usleep_range(1000, 2000);
return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask);
}
......@@ -52,6 +52,8 @@
#define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19)
#define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16)
#define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12)
/* 0 - selects Writeback A (LCD), 1 - selects Writeback B (LCD/ISP) */
#define FIMC_REG_CIGCTRL_SELWB_A (1 << 10)
#define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8)
#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7)
#define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6)
......@@ -276,6 +278,14 @@
/* Output frame buffer sequence mask */
#define FIMC_REG_CIFCNTSEQ 0x1fc
/* SYSREG ISP Writeback register address offsets */
#define SYSREG_ISPBLK 0x020c
#define SYSREG_ISPBLK_FIFORST_CAM_BLK (1 << 7)
#define SYSREG_CAMBLK 0x0218
#define SYSREG_CAMBLK_FIFORST_ISP (1 << 15)
#define SYSREG_CAMBLK_ISPWB_FULL_EN (7 << 20)
/*
* Function declarations
*/
......@@ -309,6 +319,7 @@ void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on);
void fimc_hw_disable_capture(struct fimc_dev *dev);
s32 fimc_hw_get_frame_index(struct fimc_dev *dev);
s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev);
int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc);
void fimc_activate_capture(struct fimc_ctx *ctx);
void fimc_deactivate_capture(struct fimc_dev *fimc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment