Commit 76005817 authored by Robert Foss's avatar Robert Foss Committed by Mauro Carvalho Chehab

media: camss: Refactor CSID HW version support

In order to support Qualcomm ISP hardware architectures that diverge
from older architectures, the CSID subdevice drivers needs to be refactored
to better abstract the different ISP hardware architectures.
Signed-off-by: default avatarRobert Foss <robert.foss@linaro.org>
Reviewed-by: default avatarAndrey Konovalov <andrey.konovalov@linaro.org>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent e19b14b1
......@@ -4,6 +4,8 @@
qcom-camss-objs += \
camss.o \
camss-csid.o \
camss-csid-4-1.o \
camss-csid-4-7.o \
camss-csiphy-2ph-1-0.o \
camss-csiphy-3ph-1-0.o \
camss-csiphy.o \
......
// SPDX-License-Identifier: GPL-2.0
/*
* camss-csid-4-1.c
*
* Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
*
* Copyright (C) 2020 Linaro Ltd.
*/
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include "camss-csid.h"
#include "camss-csid-gen1.h"
#include "camss.h"
#define CAMSS_CSID_HW_VERSION 0x0
#define CAMSS_CSID_CORE_CTRL_0 0x004
#define CAMSS_CSID_CORE_CTRL_1 0x008
#define CAMSS_CSID_RST_CMD 0x00c
#define CAMSS_CSID_CID_LUT_VC_n(n) (0x010 + 0x4 * (n))
#define CAMSS_CSID_CID_n_CFG(n) (0x020 + 0x4 * (n))
#define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0)
#define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1)
#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4
#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (PLAIN_FORMAT_PLAIN8 << 8)
#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (PLAIN_FORMAT_PLAIN16 << 8)
#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9)
#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9)
#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10)
#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10)
#define CAMSS_CSID_IRQ_CLEAR_CMD 0x060
#define CAMSS_CSID_IRQ_MASK 0x064
#define CAMSS_CSID_IRQ_STATUS 0x068
#define CAMSS_CSID_TG_CTRL 0x0a0
#define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436
#define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437
#define CAMSS_CSID_TG_VC_CFG 0x0a4
#define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff
#define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f
#define CAMSS_CSID_TG_DT_n_CGG_0(n) (0x0ac + 0xc * (n))
#define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b0 + 0xc * (n))
#define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0b4 + 0xc * (n))
static const struct csid_format csid_formats[] = {
{
MEDIA_BUS_FMT_UYVY8_2X8,
DATA_TYPE_YUV422_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
2,
},
{
MEDIA_BUS_FMT_VYUY8_2X8,
DATA_TYPE_YUV422_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
2,
},
{
MEDIA_BUS_FMT_YUYV8_2X8,
DATA_TYPE_YUV422_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
2,
},
{
MEDIA_BUS_FMT_YVYU8_2X8,
DATA_TYPE_YUV422_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
2,
},
{
MEDIA_BUS_FMT_SBGGR8_1X8,
DATA_TYPE_RAW_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
1,
},
{
MEDIA_BUS_FMT_SGBRG8_1X8,
DATA_TYPE_RAW_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
1,
},
{
MEDIA_BUS_FMT_SGRBG8_1X8,
DATA_TYPE_RAW_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
1,
},
{
MEDIA_BUS_FMT_SRGGB8_1X8,
DATA_TYPE_RAW_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
1,
},
{
MEDIA_BUS_FMT_SBGGR10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
{
MEDIA_BUS_FMT_SGBRG10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
{
MEDIA_BUS_FMT_SGRBG10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
{
MEDIA_BUS_FMT_SRGGB10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
{
MEDIA_BUS_FMT_SBGGR12_1X12,
DATA_TYPE_RAW_12BIT,
DECODE_FORMAT_UNCOMPRESSED_12_BIT,
12,
1,
},
{
MEDIA_BUS_FMT_SGBRG12_1X12,
DATA_TYPE_RAW_12BIT,
DECODE_FORMAT_UNCOMPRESSED_12_BIT,
12,
1,
},
{
MEDIA_BUS_FMT_SGRBG12_1X12,
DATA_TYPE_RAW_12BIT,
DECODE_FORMAT_UNCOMPRESSED_12_BIT,
12,
1,
},
{
MEDIA_BUS_FMT_SRGGB12_1X12,
DATA_TYPE_RAW_12BIT,
DECODE_FORMAT_UNCOMPRESSED_12_BIT,
12,
1,
},
{
MEDIA_BUS_FMT_Y10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
};
static void csid_configure_stream(struct csid_device *csid, u8 enable)
{
struct csid_testgen_config *tg = &csid->testgen;
u32 val;
if (enable) {
struct v4l2_mbus_framefmt *input_format;
const struct csid_format *format;
u8 vc = 0; /* Virtual Channel 0 */
u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
u8 dt_shift;
if (tg->enabled) {
/* Config Test Generator */
u32 num_lines, num_bytes_per_line;
input_format = &csid->fmt[MSM_CSID_PAD_SRC];
format = csid_get_fmt_entry(csid->formats, csid->nformats,
input_format->code);
num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
num_lines = input_format->height;
/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
/* 1:0 VC */
val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
/* 28:16 bytes per lines, 12:0 num of lines */
val = ((num_bytes_per_line & 0x1fff) << 16) |
(num_lines & 0x1fff);
writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
/* 5:0 data type */
val = format->data_type;
writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
/* 2:0 output test pattern */
val = tg->mode - 1;
writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
} else {
struct csid_phy_config *phy = &csid->phy;
input_format = &csid->fmt[MSM_CSID_PAD_SINK];
format = csid_get_fmt_entry(csid->formats, csid->nformats,
input_format->code);
val = phy->lane_cnt - 1;
val |= phy->lane_assign << 4;
writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
val = phy->csiphy_id << 17;
val |= 0x9;
writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
}
/* Config LUT */
dt_shift = (cid % 4) * 8;
val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
val &= ~(0xff << dt_shift);
val |= format->data_type << dt_shift;
writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
if (tg->enabled) {
val = CAMSS_CSID_TG_CTRL_ENABLE;
writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
}
} else {
if (tg->enabled) {
val = CAMSS_CSID_TG_CTRL_DISABLE;
writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
}
}
}
static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
{
if (val > 0 && val <= csid->testgen.nmodes)
csid->testgen.mode = val;
return 0;
}
static u32 csid_hw_version(struct csid_device *csid)
{
u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
return hw_version;
}
static irqreturn_t csid_isr(int irq, void *dev)
{
struct csid_device *csid = dev;
u32 value;
value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
if ((value >> 11) & 0x1)
complete(&csid->reset_complete);
return IRQ_HANDLED;
}
static int csid_reset(struct csid_device *csid)
{
unsigned long time;
reinit_completion(&csid->reset_complete);
writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
time = wait_for_completion_timeout(&csid->reset_complete,
msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
if (!time) {
dev_err(csid->camss->dev, "CSID reset timeout\n");
return -EIO;
}
return 0;
}
static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
unsigned int match_format_idx, u32 match_code)
{
if (match_format_idx > 0)
return 0;
return sink_code;
}
static void csid_subdev_init(struct csid_device *csid)
{
csid->formats = csid_formats;
csid->nformats = ARRAY_SIZE(csid_formats);
csid->testgen.modes = csid_testgen_modes;
csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1;
}
const struct csid_hw_ops csid_ops_4_1 = {
.configure_stream = csid_configure_stream,
.configure_testgen_pattern = csid_configure_testgen_pattern,
.hw_version = csid_hw_version,
.isr = csid_isr,
.reset = csid_reset,
.src_pad_code = csid_src_pad_code,
.subdev_init = csid_subdev_init,
};
// SPDX-License-Identifier: GPL-2.0
/*
* camss-csid-4-7.c
*
* Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
*
* Copyright (C) 2020 Linaro Ltd.
*/
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include "camss-csid.h"
#include "camss-csid-gen1.h"
#include "camss.h"
#define CAMSS_CSID_HW_VERSION 0x0
#define CAMSS_CSID_CORE_CTRL_0 0x004
#define CAMSS_CSID_CORE_CTRL_1 0x008
#define CAMSS_CSID_RST_CMD 0x010
#define CAMSS_CSID_CID_LUT_VC_n(n) (0x014 + 0x4 * (n))
#define CAMSS_CSID_CID_n_CFG(n) (0x024 + 0x4 * (n))
#define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0)
#define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1)
#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4
#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (PLAIN_FORMAT_PLAIN8 << 8)
#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (PLAIN_FORMAT_PLAIN16 << 8)
#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9)
#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9)
#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10)
#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10)
#define CAMSS_CSID_IRQ_CLEAR_CMD 0x064
#define CAMSS_CSID_IRQ_MASK 0x068
#define CAMSS_CSID_IRQ_STATUS 0x06c
#define CAMSS_CSID_TG_CTRL 0x0a8
#define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436
#define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437
#define CAMSS_CSID_TG_VC_CFG 0x0ac
#define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff
#define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f
#define CAMSS_CSID_TG_DT_n_CGG_0(n) (0x0b4 + 0xc * (n))
#define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b8 + 0xc * (n))
#define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0bc + 0xc * (n))
static const struct csid_format csid_formats[] = {
{
MEDIA_BUS_FMT_UYVY8_2X8,
DATA_TYPE_YUV422_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
2,
},
{
MEDIA_BUS_FMT_VYUY8_2X8,
DATA_TYPE_YUV422_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
2,
},
{
MEDIA_BUS_FMT_YUYV8_2X8,
DATA_TYPE_YUV422_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
2,
},
{
MEDIA_BUS_FMT_YVYU8_2X8,
DATA_TYPE_YUV422_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
2,
},
{
MEDIA_BUS_FMT_SBGGR8_1X8,
DATA_TYPE_RAW_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
1,
},
{
MEDIA_BUS_FMT_SGBRG8_1X8,
DATA_TYPE_RAW_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
1,
},
{
MEDIA_BUS_FMT_SGRBG8_1X8,
DATA_TYPE_RAW_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
1,
},
{
MEDIA_BUS_FMT_SRGGB8_1X8,
DATA_TYPE_RAW_8BIT,
DECODE_FORMAT_UNCOMPRESSED_8_BIT,
8,
1,
},
{
MEDIA_BUS_FMT_SBGGR10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
{
MEDIA_BUS_FMT_SGBRG10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
{
MEDIA_BUS_FMT_SGRBG10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
{
MEDIA_BUS_FMT_SRGGB10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
{
MEDIA_BUS_FMT_SBGGR12_1X12,
DATA_TYPE_RAW_12BIT,
DECODE_FORMAT_UNCOMPRESSED_12_BIT,
12,
1,
},
{
MEDIA_BUS_FMT_SGBRG12_1X12,
DATA_TYPE_RAW_12BIT,
DECODE_FORMAT_UNCOMPRESSED_12_BIT,
12,
1,
},
{
MEDIA_BUS_FMT_SGRBG12_1X12,
DATA_TYPE_RAW_12BIT,
DECODE_FORMAT_UNCOMPRESSED_12_BIT,
12,
1,
},
{
MEDIA_BUS_FMT_SRGGB12_1X12,
DATA_TYPE_RAW_12BIT,
DECODE_FORMAT_UNCOMPRESSED_12_BIT,
12,
1,
},
{
MEDIA_BUS_FMT_SBGGR14_1X14,
DATA_TYPE_RAW_14BIT,
DECODE_FORMAT_UNCOMPRESSED_14_BIT,
14,
1,
},
{
MEDIA_BUS_FMT_SGBRG14_1X14,
DATA_TYPE_RAW_14BIT,
DECODE_FORMAT_UNCOMPRESSED_14_BIT,
14,
1,
},
{
MEDIA_BUS_FMT_SGRBG14_1X14,
DATA_TYPE_RAW_14BIT,
DECODE_FORMAT_UNCOMPRESSED_14_BIT,
14,
1,
},
{
MEDIA_BUS_FMT_SRGGB14_1X14,
DATA_TYPE_RAW_14BIT,
DECODE_FORMAT_UNCOMPRESSED_14_BIT,
14,
1,
},
{
MEDIA_BUS_FMT_Y10_1X10,
DATA_TYPE_RAW_10BIT,
DECODE_FORMAT_UNCOMPRESSED_10_BIT,
10,
1,
},
};
static void csid_configure_stream(struct csid_device *csid, u8 enable)
{
struct csid_testgen_config *tg = &csid->testgen;
u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
u32 val;
if (enable) {
struct v4l2_mbus_framefmt *input_format;
const struct csid_format *format;
u8 vc = 0; /* Virtual Channel 0 */
u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
u8 dt_shift;
if (tg->enabled) {
/* Config Test Generator */
u32 num_bytes_per_line, num_lines;
input_format = &csid->fmt[MSM_CSID_PAD_SRC];
format = csid_get_fmt_entry(csid->formats, csid->nformats,
input_format->code);
num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
num_lines = input_format->height;
/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
/* 1:0 VC */
val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
/* 28:16 bytes per lines, 12:0 num of lines */
val = ((num_bytes_per_line & 0x1fff) << 16) |
(num_lines & 0x1fff);
writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
/* 5:0 data type */
val = format->data_type;
writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
/* 2:0 output test pattern */
val = tg->mode - 1;
writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
} else {
struct csid_phy_config *phy = &csid->phy;
input_format = &csid->fmt[MSM_CSID_PAD_SINK];
format = csid_get_fmt_entry(csid->formats, csid->nformats,
input_format->code);
val = phy->lane_cnt - 1;
val |= phy->lane_assign << 4;
writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
val = phy->csiphy_id << 17;
val |= 0x9;
writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
}
/* Config LUT */
dt_shift = (cid % 4) * 8;
val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
val &= ~(0xff << dt_shift);
val |= format->data_type << dt_shift;
writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||
(sink_code == MEDIA_BUS_FMT_Y10_1X10 &&
src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {
val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;
val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;
val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;
}
writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
if (tg->enabled) {
val = CAMSS_CSID_TG_CTRL_ENABLE;
writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
}
} else {
if (tg->enabled) {
val = CAMSS_CSID_TG_CTRL_DISABLE;
writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
}
}
}
static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
{
if (val > 0 && val <= csid->testgen.nmodes)
csid->testgen.mode = val;
return 0;
}
static u32 csid_hw_version(struct csid_device *csid)
{
u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
return hw_version;
}
/*
* isr - CSID module interrupt service routine
* @irq: Interrupt line
* @dev: CSID device
*
* Return IRQ_HANDLED on success
*/
static irqreturn_t csid_isr(int irq, void *dev)
{
struct csid_device *csid = dev;
u32 value;
value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
if ((value >> 11) & 0x1)
complete(&csid->reset_complete);
return IRQ_HANDLED;
}
/*
* csid_reset - Trigger reset on CSID module and wait to complete
* @csid: CSID device
*
* Return 0 on success or a negative error code otherwise
*/
static int csid_reset(struct csid_device *csid)
{
unsigned long time;
reinit_completion(&csid->reset_complete);
writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
time = wait_for_completion_timeout(&csid->reset_complete,
msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
if (!time) {
dev_err(csid->camss->dev, "CSID reset timeout\n");
return -EIO;
}
return 0;
}
static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
unsigned int match_format_idx, u32 match_code)
{
switch (sink_code) {
case MEDIA_BUS_FMT_SBGGR10_1X10:
{
u32 src_code[] = {
MEDIA_BUS_FMT_SBGGR10_1X10,
MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
};
return csid_find_code(src_code, ARRAY_SIZE(src_code),
match_format_idx, match_code);
}
case MEDIA_BUS_FMT_Y10_1X10:
{
u32 src_code[] = {
MEDIA_BUS_FMT_Y10_1X10,
MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
};
return csid_find_code(src_code, ARRAY_SIZE(src_code),
match_format_idx, match_code);
}
default:
if (match_format_idx > 0)
return 0;
return sink_code;
}
}
static void csid_subdev_init(struct csid_device *csid)
{
csid->formats = csid_formats;
csid->nformats = ARRAY_SIZE(csid_formats);
csid->testgen.modes = csid_testgen_modes;
csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1;
}
const struct csid_hw_ops csid_ops_4_7 = {
.configure_stream = csid_configure_stream,
.configure_testgen_pattern = csid_configure_testgen_pattern,
.hw_version = csid_hw_version,
.isr = csid_isr,
.reset = csid_reset,
.src_pad_code = csid_src_pad_code,
.subdev_init = csid_subdev_init,
};
......@@ -11,6 +11,7 @@
#define QC_MSM_CAMSS_CSID_H
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
......@@ -44,18 +45,32 @@
#define DATA_TYPE_RAW_16BIT 0x2e
#define DATA_TYPE_RAW_20BIT 0x2f
enum csid_payload_mode {
CSID_PAYLOAD_MODE_INCREMENTING = 0,
CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,
CSID_PAYLOAD_MODE_ALL_ZEROES = 2,
CSID_PAYLOAD_MODE_ALL_ONES = 3,
CSID_PAYLOAD_MODE_RANDOM = 4,
CSID_PAYLOAD_MODE_USER_SPECIFIED = 5,
#define CSID_RESET_TIMEOUT_MS 500
enum csid_testgen_mode {
CSID_PAYLOAD_MODE_DISABLED = 0,
CSID_PAYLOAD_MODE_INCREMENTING = 1,
CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 2,
CSID_PAYLOAD_MODE_ALL_ZEROES = 3,
CSID_PAYLOAD_MODE_ALL_ONES = 4,
CSID_PAYLOAD_MODE_RANDOM = 5,
CSID_PAYLOAD_MODE_USER_SPECIFIED = 6,
CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1 = 6, /* excluding disabled */
};
struct csid_format {
u32 code;
u8 data_type;
u8 decode_format;
u8 bpp;
u8 spp; /* bus samples per pixel */
};
struct csid_testgen_config {
enum csid_testgen_mode mode;
const char * const*modes;
u8 nmodes;
u8 enabled;
enum csid_payload_mode payload_mode;
};
struct csid_phy_config {
......@@ -64,6 +79,65 @@ struct csid_phy_config {
u32 lane_assign;
};
struct csid_device;
struct csid_hw_ops {
/*
* configure_stream - Configures and starts CSID input stream
* @csid: CSID device
*/
void (*configure_stream)(struct csid_device *csid, u8 enable);
/*
* configure_testgen_pattern - Validates and configures output pattern mode
* of test pattern generator
* @csid: CSID device
*/
int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);
/*
* hw_version - Read hardware version register from hardware
* @csid: CSID device
*/
u32 (*hw_version)(struct csid_device *csid);
/*
* isr - CSID module interrupt service routine
* @irq: Interrupt line
* @dev: CSID device
*
* Return IRQ_HANDLED on success
*/
irqreturn_t (*isr)(int irq, void *dev);
/*
* reset - Trigger reset on CSID module and wait to complete
* @csid: CSID device
*
* Return 0 on success or a negative error code otherwise
*/
int (*reset)(struct csid_device *csid);
/*
* src_pad_code - Pick an output/src format based on the input/sink format
* @csid: CSID device
* @sink_code: The sink format of the input
* @match_format_idx: Request preferred index, as defined by subdevice csid_format.
* Set @match_code to 0 if used.
* @match_code: Request preferred code, set @match_format_idx to 0 if used
*
* Return 0 on failure or src format code otherwise
*/
u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,
unsigned int match_format_idx, u32 match_code);
/*
* subdev_init - Initialize CSID device according for hardware revision
* @csid: CSID device
*/
void (*subdev_init)(struct csid_device *csid);
};
struct csid_device {
struct camss *camss;
u8 id;
......@@ -83,10 +157,36 @@ struct csid_device {
struct v4l2_ctrl *testgen_mode;
const struct csid_format *formats;
unsigned int nformats;
const struct csid_hw_ops *ops;
};
struct resources;
/*
* csid_find_code - Find a format code in an array using array index or format code
* @codes: Array of format codes
* @ncodes: Length of @code array
* @req_format_idx: Request preferred index, as defined by subdevice csid_format.
* Set @match_code to 0 if used.
* @match_code: Request preferred code, set @req_format_idx to 0 if used
*
* Return 0 on failure or format code otherwise
*/
u32 csid_find_code(u32 *codes, unsigned int ncode,
unsigned int match_format_idx, u32 match_code);
/*
* csid_get_fmt_entry - Find csid_format entry with matching format code
* @formats: Array of format csid_format entries
* @nformats: Length of @nformats array
* @code: Desired format code
*
* Return formats[0] on failure to find code
*/
const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,
unsigned int nformats,
u32 code);
int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
const struct resources *res, u8 id);
......@@ -97,4 +197,9 @@ void msm_csid_unregister_entity(struct csid_device *csid);
void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);
extern const char * const csid_testgen_modes[];
extern const struct csid_hw_ops csid_ops_4_1;
extern const struct csid_hw_ops csid_ops_4_7;
#endif /* QC_MSM_CAMSS_CSID_H */
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