Commit a11a5570 authored by Bingbu Cao's avatar Bingbu Cao Committed by Hans Verkuil

media: intel/ipu6: add IPU6 CSI2 receiver v4l2 sub-device

Input system CSI2 receiver is exposed as a v4l2 sub-device. Each CSI2
sub-device represent one single CSI2 hardware port which be linked with
external sub-device such camera sensor by linked with ISYS CSI2's sink
pad. The CSI2 source pad is linked to the sink pad of video capture device.
Signed-off-by: default avatarBingbu Cao <bingbu.cao@intel.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent f625e8d7
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2013--2024 Intel Corporation */
#ifndef IPU6_ISYS_CSI2_H
#define IPU6_ISYS_CSI2_H
#include <linux/container_of.h>
#include "ipu6-isys-subdev.h"
#include "ipu6-isys-video.h"
struct media_entity;
struct v4l2_mbus_frame_desc_entry;
struct ipu6_isys_video;
struct ipu6_isys;
struct ipu6_isys_csi2_pdata;
struct ipu6_isys_stream;
#define NR_OF_CSI2_VC 16
#define INVALID_VC_ID -1
#define NR_OF_CSI2_SINK_PADS 1
#define CSI2_PAD_SINK 0
#define NR_OF_CSI2_SRC_PADS 8
#define CSI2_PAD_SRC 1
#define NR_OF_CSI2_PADS (NR_OF_CSI2_SINK_PADS + NR_OF_CSI2_SRC_PADS)
#define CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_A 0
#define CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_B 0
#define CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_A 95
#define CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_B -8
#define CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_A 0
#define CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_B 0
#define CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_A 85
#define CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_B -2
struct ipu6_isys_csi2 {
struct ipu6_isys_subdev asd;
struct ipu6_isys_csi2_pdata *pdata;
struct ipu6_isys *isys;
struct ipu6_isys_video av[NR_OF_CSI2_SRC_PADS];
void __iomem *base;
u32 receiver_errors;
unsigned int nlanes;
unsigned int port;
unsigned int stream_count;
};
struct ipu6_isys_csi2_timing {
u32 ctermen;
u32 csettle;
u32 dtermen;
u32 dsettle;
};
struct ipu6_csi2_error {
const char *error_string;
bool is_info_only;
};
#define ipu6_isys_subdev_to_csi2(__sd) \
container_of(__sd, struct ipu6_isys_csi2, asd)
#define to_ipu6_isys_csi2(__asd) container_of(__asd, struct ipu6_isys_csi2, asd)
s64 ipu6_isys_csi2_get_link_freq(struct ipu6_isys_csi2 *csi2);
int ipu6_isys_csi2_init(struct ipu6_isys_csi2 *csi2, struct ipu6_isys *isys,
void __iomem *base, unsigned int index);
void ipu6_isys_csi2_cleanup(struct ipu6_isys_csi2 *csi2);
void ipu6_isys_csi2_sof_event_by_stream(struct ipu6_isys_stream *stream);
void ipu6_isys_csi2_eof_event_by_stream(struct ipu6_isys_stream *stream);
void ipu6_isys_register_errors(struct ipu6_isys_csi2 *csi2);
void ipu6_isys_csi2_error(struct ipu6_isys_csi2 *csi2);
int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
struct ipu6_isys_csi2 *csi2,
struct media_entity *source_entity,
struct v4l2_mbus_frame_desc_entry *entry);
void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status);
#endif /* IPU6_ISYS_CSI2_H */
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013--2024 Intel Corporation
*/
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/minmax.h>
#include <media/media-entity.h>
#include <media/mipi-csi2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include "ipu6-bus.h"
#include "ipu6-isys.h"
#include "ipu6-isys-subdev.h"
unsigned int ipu6_isys_mbus_code_to_bpp(u32 code)
{
switch (code) {
case MEDIA_BUS_FMT_RGB888_1X24:
return 24;
case MEDIA_BUS_FMT_RGB565_1X16:
case MEDIA_BUS_FMT_UYVY8_1X16:
case MEDIA_BUS_FMT_YUYV8_1X16:
return 16;
case MEDIA_BUS_FMT_SBGGR12_1X12:
case MEDIA_BUS_FMT_SGBRG12_1X12:
case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12:
return 12;
case MEDIA_BUS_FMT_SBGGR10_1X10:
case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SRGGB10_1X10:
return 10;
case MEDIA_BUS_FMT_SBGGR8_1X8:
case MEDIA_BUS_FMT_SGBRG8_1X8:
case MEDIA_BUS_FMT_SGRBG8_1X8:
case MEDIA_BUS_FMT_SRGGB8_1X8:
return 8;
default:
WARN_ON(1);
return 8;
}
}
unsigned int ipu6_isys_mbus_code_to_mipi(u32 code)
{
switch (code) {
case MEDIA_BUS_FMT_RGB565_1X16:
return MIPI_CSI2_DT_RGB565;
case MEDIA_BUS_FMT_RGB888_1X24:
return MIPI_CSI2_DT_RGB888;
case MEDIA_BUS_FMT_UYVY8_1X16:
case MEDIA_BUS_FMT_YUYV8_1X16:
return MIPI_CSI2_DT_YUV422_8B;
case MEDIA_BUS_FMT_SBGGR16_1X16:
case MEDIA_BUS_FMT_SGBRG16_1X16:
case MEDIA_BUS_FMT_SGRBG16_1X16:
case MEDIA_BUS_FMT_SRGGB16_1X16:
return MIPI_CSI2_DT_RAW16;
case MEDIA_BUS_FMT_SBGGR12_1X12:
case MEDIA_BUS_FMT_SGBRG12_1X12:
case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12:
return MIPI_CSI2_DT_RAW12;
case MEDIA_BUS_FMT_SBGGR10_1X10:
case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SRGGB10_1X10:
return MIPI_CSI2_DT_RAW10;
case MEDIA_BUS_FMT_SBGGR8_1X8:
case MEDIA_BUS_FMT_SGBRG8_1X8:
case MEDIA_BUS_FMT_SGRBG8_1X8:
case MEDIA_BUS_FMT_SRGGB8_1X8:
return MIPI_CSI2_DT_RAW8;
default:
/* return unavailable MIPI data type - 0x3f */
WARN_ON(1);
return 0x3f;
}
}
bool ipu6_isys_is_bayer_format(u32 code)
{
switch (ipu6_isys_mbus_code_to_mipi(code)) {
case MIPI_CSI2_DT_RAW8:
case MIPI_CSI2_DT_RAW10:
case MIPI_CSI2_DT_RAW12:
case MIPI_CSI2_DT_RAW14:
case MIPI_CSI2_DT_RAW16:
case MIPI_CSI2_DT_RAW20:
case MIPI_CSI2_DT_RAW24:
case MIPI_CSI2_DT_RAW28:
return true;
default:
return false;
}
}
u32 ipu6_isys_convert_bayer_order(u32 code, int x, int y)
{
static const u32 code_map[] = {
MEDIA_BUS_FMT_SRGGB8_1X8,
MEDIA_BUS_FMT_SGRBG8_1X8,
MEDIA_BUS_FMT_SGBRG8_1X8,
MEDIA_BUS_FMT_SBGGR8_1X8,
MEDIA_BUS_FMT_SRGGB10_1X10,
MEDIA_BUS_FMT_SGRBG10_1X10,
MEDIA_BUS_FMT_SGBRG10_1X10,
MEDIA_BUS_FMT_SBGGR10_1X10,
MEDIA_BUS_FMT_SRGGB12_1X12,
MEDIA_BUS_FMT_SGRBG12_1X12,
MEDIA_BUS_FMT_SGBRG12_1X12,
MEDIA_BUS_FMT_SBGGR12_1X12,
MEDIA_BUS_FMT_SRGGB16_1X16,
MEDIA_BUS_FMT_SGRBG16_1X16,
MEDIA_BUS_FMT_SGBRG16_1X16,
MEDIA_BUS_FMT_SBGGR16_1X16,
};
u32 i;
for (i = 0; i < ARRAY_SIZE(code_map); i++)
if (code_map[i] == code)
break;
if (WARN_ON(i == ARRAY_SIZE(code_map)))
return code;
return code_map[i ^ (((y & 1) << 1) | (x & 1))];
}
int ipu6_isys_subdev_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
struct v4l2_mbus_framefmt *fmt;
struct v4l2_rect *crop;
u32 code = asd->supported_codes[0];
u32 other_pad, other_stream;
unsigned int i;
int ret;
/* No transcoding, source and sink formats must match. */
if ((sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SOURCE) &&
sd->entity.num_pads > 1)
return v4l2_subdev_get_fmt(sd, state, format);
format->format.width = clamp(format->format.width, IPU6_ISYS_MIN_WIDTH,
IPU6_ISYS_MAX_WIDTH);
format->format.height = clamp(format->format.height,
IPU6_ISYS_MIN_HEIGHT,
IPU6_ISYS_MAX_HEIGHT);
for (i = 0; asd->supported_codes[i]; i++) {
if (asd->supported_codes[i] == format->format.code) {
code = asd->supported_codes[i];
break;
}
}
format->format.code = code;
format->format.field = V4L2_FIELD_NONE;
/* Store the format and propagate it to the source pad. */
fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
if (!fmt)
return -EINVAL;
*fmt = format->format;
if (!(sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SINK))
return 0;
/* propagate format to following source pad */
fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
format->stream);
if (!fmt)
return -EINVAL;
*fmt = format->format;
ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
format->pad,
format->stream,
&other_pad,
&other_stream);
if (ret)
return -EINVAL;
crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream);
/* reset crop */
crop->left = 0;
crop->top = 0;
crop->width = fmt->width;
crop->height = fmt->height;
return 0;
}
int ipu6_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
const u32 *supported_codes = asd->supported_codes;
u32 index;
for (index = 0; supported_codes[index]; index++) {
if (index == code->index) {
code->code = supported_codes[index];
return 0;
}
}
return -EINVAL;
}
static int subdev_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_krouting *routing)
{
static const struct v4l2_mbus_framefmt format = {
.width = 4096,
.height = 3072,
.code = MEDIA_BUS_FMT_SGRBG10_1X10,
.field = V4L2_FIELD_NONE,
};
int ret;
ret = v4l2_subdev_routing_validate(sd, routing,
V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
if (ret)
return ret;
return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
}
int ipu6_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
struct v4l2_mbus_framefmt *format)
{
struct v4l2_mbus_framefmt *fmt;
struct v4l2_subdev_state *state;
if (!sd || !format)
return -EINVAL;
state = v4l2_subdev_lock_and_get_active_state(sd);
fmt = v4l2_subdev_state_get_format(state, pad, stream);
if (fmt)
*format = *fmt;
v4l2_subdev_unlock_state(state);
return fmt ? 0 : -EINVAL;
}
int ipu6_isys_get_stream_pad_crop(struct v4l2_subdev *sd, u32 pad, u32 stream,
struct v4l2_rect *crop)
{
struct v4l2_subdev_state *state;
struct v4l2_rect *rect;
if (!sd || !crop)
return -EINVAL;
state = v4l2_subdev_lock_and_get_active_state(sd);
rect = v4l2_subdev_state_get_crop(state, pad, stream);
if (rect)
*crop = *rect;
v4l2_subdev_unlock_state(state);
return rect ? 0 : -EINVAL;
}
u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
{
struct v4l2_subdev_state *state;
struct v4l2_subdev_route *routes;
unsigned int i;
u32 source_stream = 0;
state = v4l2_subdev_lock_and_get_active_state(sd);
if (!state)
return 0;
routes = state->routing.routes;
for (i = 0; i < state->routing.num_routes; i++) {
if (routes[i].source_pad == pad) {
source_stream = routes[i].source_stream;
break;
}
}
v4l2_subdev_unlock_state(state);
return source_stream;
}
static int ipu6_isys_subdev_init_state(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
struct v4l2_subdev_route route = {
.sink_pad = 0,
.sink_stream = 0,
.source_pad = 1,
.source_stream = 0,
.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
};
struct v4l2_subdev_krouting routing = {
.num_routes = 1,
.routes = &route,
};
return subdev_set_routing(sd, state, &routing);
}
int ipu6_isys_subdev_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
enum v4l2_subdev_format_whence which,
struct v4l2_subdev_krouting *routing)
{
return subdev_set_routing(sd, state, routing);
}
static const struct v4l2_subdev_internal_ops ipu6_isys_subdev_internal_ops = {
.init_state = ipu6_isys_subdev_init_state,
};
int ipu6_isys_subdev_init(struct ipu6_isys_subdev *asd,
const struct v4l2_subdev_ops *ops,
unsigned int nr_ctrls,
unsigned int num_sink_pads,
unsigned int num_source_pads)
{
unsigned int num_pads = num_sink_pads + num_source_pads;
unsigned int i;
int ret;
v4l2_subdev_init(&asd->sd, ops);
asd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS |
V4L2_SUBDEV_FL_STREAMS;
asd->sd.owner = THIS_MODULE;
asd->sd.dev = &asd->isys->adev->auxdev.dev;
asd->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
asd->sd.internal_ops = &ipu6_isys_subdev_internal_ops;
asd->pad = devm_kcalloc(&asd->isys->adev->auxdev.dev, num_pads,
sizeof(*asd->pad), GFP_KERNEL);
if (!asd->pad)
return -ENOMEM;
for (i = 0; i < num_sink_pads; i++)
asd->pad[i].flags = MEDIA_PAD_FL_SINK |
MEDIA_PAD_FL_MUST_CONNECT;
for (i = num_sink_pads; i < num_pads; i++)
asd->pad[i].flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&asd->sd.entity, num_pads, asd->pad);
if (ret)
return ret;
if (asd->ctrl_init) {
ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, nr_ctrls);
if (ret)
goto out_media_entity_cleanup;
asd->ctrl_init(&asd->sd);
if (asd->ctrl_handler.error) {
ret = asd->ctrl_handler.error;
goto out_v4l2_ctrl_handler_free;
}
asd->sd.ctrl_handler = &asd->ctrl_handler;
}
asd->source = -1;
return 0;
out_v4l2_ctrl_handler_free:
v4l2_ctrl_handler_free(&asd->ctrl_handler);
out_media_entity_cleanup:
media_entity_cleanup(&asd->sd.entity);
return ret;
}
void ipu6_isys_subdev_cleanup(struct ipu6_isys_subdev *asd)
{
media_entity_cleanup(&asd->sd.entity);
v4l2_ctrl_handler_free(&asd->ctrl_handler);
}
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2013--2024 Intel Corporation */
#ifndef IPU6_ISYS_SUBDEV_H
#define IPU6_ISYS_SUBDEV_H
#include <linux/container_of.h>
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
struct ipu6_isys;
struct ipu6_isys_subdev {
struct v4l2_subdev sd;
struct ipu6_isys *isys;
u32 const *supported_codes;
struct media_pad *pad;
struct v4l2_ctrl_handler ctrl_handler;
void (*ctrl_init)(struct v4l2_subdev *sd);
int source; /* SSI stream source; -1 if unset */
};
#define to_ipu6_isys_subdev(__sd) \
container_of(__sd, struct ipu6_isys_subdev, sd)
unsigned int ipu6_isys_mbus_code_to_bpp(u32 code);
unsigned int ipu6_isys_mbus_code_to_mipi(u32 code);
bool ipu6_isys_is_bayer_format(u32 code);
u32 ipu6_isys_convert_bayer_order(u32 code, int x, int y);
int ipu6_isys_subdev_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *fmt);
int ipu6_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum
*code);
int ipu6_isys_subdev_link_validate(struct v4l2_subdev *sd,
struct media_link *link,
struct v4l2_subdev_format *source_fmt,
struct v4l2_subdev_format *sink_fmt);
u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad);
int ipu6_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
struct v4l2_mbus_framefmt *format);
int ipu6_isys_get_stream_pad_crop(struct v4l2_subdev *sd, u32 pad, u32 stream,
struct v4l2_rect *crop);
int ipu6_isys_subdev_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
enum v4l2_subdev_format_whence which,
struct v4l2_subdev_krouting *routing);
int ipu6_isys_subdev_init(struct ipu6_isys_subdev *asd,
const struct v4l2_subdev_ops *ops,
unsigned int nr_ctrls,
unsigned int num_sink_pads,
unsigned int num_source_pads);
void ipu6_isys_subdev_cleanup(struct ipu6_isys_subdev *asd);
#endif /* IPU6_ISYS_SUBDEV_H */
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2023--2024 Intel Corporation */
#ifndef IPU6_PLATFORM_ISYS_CSI2_REG_H
#define IPU6_PLATFORM_ISYS_CSI2_REG_H
#include <linux/bits.h>
#define CSI_REG_BASE 0x220000
#define CSI_REG_PORT_BASE(id) (CSI_REG_BASE + (id) * 0x1000)
/* CSI Port Genral Purpose Registers */
#define CSI_REG_PORT_GPREG_SRST 0x0
#define CSI_REG_PORT_GPREG_CSI2_SLV_REG_SRST 0x4
#define CSI_REG_PORT_GPREG_CSI2_PORT_CONTROL 0x8
/*
* Port IRQs mapping events:
* IRQ0 - CSI_FE event
* IRQ1 - CSI_SYNC
* IRQ2 - S2M_SIDS0TO7
* IRQ3 - S2M_SIDS8TO15
*/
#define CSI_PORT_REG_BASE_IRQ_CSI 0x80
#define CSI_PORT_REG_BASE_IRQ_CSI_SYNC 0xA0
#define CSI_PORT_REG_BASE_IRQ_S2M_SIDS0TOS7 0xC0
#define CSI_PORT_REG_BASE_IRQ_S2M_SIDS8TOS15 0xE0
#define CSI_PORT_REG_BASE_IRQ_EDGE_OFFSET 0x0
#define CSI_PORT_REG_BASE_IRQ_MASK_OFFSET 0x4
#define CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET 0x8
#define CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET 0xc
#define CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET 0x10
#define CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET 0x14
#define IPU6SE_CSI_RX_ERROR_IRQ_MASK GENMASK(18, 0)
#define IPU6_CSI_RX_ERROR_IRQ_MASK GENMASK(19, 0)
#define CSI_RX_NUM_ERRORS_IN_IRQ 20
#define CSI_RX_NUM_IRQ 32
#define IPU_CSI_RX_IRQ_FS_VC(chn) (1 << ((chn) * 2))
#define IPU_CSI_RX_IRQ_FE_VC(chn) (2 << ((chn) * 2))
/* PPI2CSI */
#define CSI_REG_PPI2CSI_ENABLE 0x200
#define CSI_REG_PPI2CSI_CONFIG_PPI_INTF 0x204
#define PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK GENMASK(4, 3)
#define CSI_REG_PPI2CSI_CONFIG_CSI_FEATURE 0x208
enum CSI_PPI2CSI_CTRL {
CSI_PPI2CSI_DISABLE = 0,
CSI_PPI2CSI_ENABLE = 1,
};
/* CSI_FE */
#define CSI_REG_CSI_FE_ENABLE 0x280
#define CSI_REG_CSI_FE_MODE 0x284
#define CSI_REG_CSI_FE_MUX_CTRL 0x288
#define CSI_REG_CSI_FE_SYNC_CNTR_SEL 0x290
enum CSI_FE_ENABLE_TYPE {
CSI_FE_DISABLE = 0,
CSI_FE_ENABLE = 1,
};
enum CSI_FE_MODE_TYPE {
CSI_FE_DPHY_MODE = 0,
CSI_FE_CPHY_MODE = 1,
};
enum CSI_FE_INPUT_SELECTOR {
CSI_SENSOR_INPUT = 0,
CSI_MIPIGEN_INPUT = 1,
};
enum CSI_FE_SYNC_CNTR_SEL_TYPE {
CSI_CNTR_SENSOR_LINE_ID = BIT(0),
CSI_CNTR_INT_LINE_PKT_ID = ~CSI_CNTR_SENSOR_LINE_ID,
CSI_CNTR_SENSOR_FRAME_ID = BIT(1),
CSI_CNTR_INT_FRAME_PKT_ID = ~CSI_CNTR_SENSOR_FRAME_ID,
};
/* CSI HUB General Purpose Registers */
#define CSI_REG_HUB_GPREG_SRST (CSI_REG_BASE + 0x18000)
#define CSI_REG_HUB_GPREG_SLV_REG_SRST (CSI_REG_BASE + 0x18004)
#define CSI_REG_HUB_DRV_ACCESS_PORT(id) (CSI_REG_BASE + 0x18018 + (id) * 4)
#define CSI_REG_HUB_FW_ACCESS_PORT_OFS 0x17000
#define CSI_REG_HUB_FW_ACCESS_PORT_V6OFS 0x16000
#define CSI_REG_HUB_FW_ACCESS_PORT(ofs, id) \
(CSI_REG_BASE + (ofs) + (id) * 4)
enum CSI_PORT_CLK_GATING_SWITCH {
CSI_PORT_CLK_GATING_OFF = 0,
CSI_PORT_CLK_GATING_ON = 1,
};
#define CSI_REG_BASE_HUB_IRQ 0x18200
#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE 0x238200
#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK 0x238204
#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS 0x238208
#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR 0x23820c
#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE 0x238210
#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE 0x238214
#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_EDGE 0x238220
#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_MASK 0x238224
#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_STATUS 0x238228
#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_CLEAR 0x23822c
#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_ENABLE 0x238230
#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_LEVEL_NOT_PULSE 0x238234
/* MTL IPU6V6 irq ctrl0 & ctrl1 */
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE 0x238700
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK 0x238704
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS 0x238708
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR 0x23870c
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE 0x238710
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE 0x238714
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_EDGE 0x238720
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_MASK 0x238724
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_STATUS 0x238728
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_CLEAR 0x23872c
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_ENABLE 0x238730
#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_LEVEL_NOT_PULSE 0x238734
/*
* 3:0 CSI_PORT.irq_out[3:0] CSI_PORT_CTRL0 IRQ outputs (4bits)
* [0] CSI_PORT.IRQ_CTRL0_csi
* [1] CSI_PORT.IRQ_CTRL1_csi_sync
* [2] CSI_PORT.IRQ_CTRL2_s2m_sids0to7
* [3] CSI_PORT.IRQ_CTRL3_s2m_sids8to15
*/
#define IPU6_ISYS_UNISPART_IRQ_CSI2(port) \
(0x3 << ((port) * IPU6_CSI_IRQ_NUM_PER_PIPE))
/*
* ipu6se support 2 front ends, 2 port per front end, 4 ports 0..3
* sip0 - 0, 1
* sip1 - 2, 3
* 0 and 2 support 4 data lanes, 1 and 3 support 2 data lanes
* all offset are base from isys base address
*/
#define CSI2_HUB_GPREG_SIP_SRST(sip) (0x238038 + (sip) * 4)
#define CSI2_HUB_GPREG_SIP_FB_PORT_CFG(sip) (0x238050 + (sip) * 4)
#define CSI2_HUB_GPREG_DPHY_TIMER_INCR 0x238040
#define CSI2_HUB_GPREG_HPLL_FREQ 0x238044
#define CSI2_HUB_GPREG_IS_CLK_RATIO 0x238048
#define CSI2_HUB_GPREG_HPLL_FREQ_ISCLK_RATE_OVERRIDE 0x23804c
#define CSI2_HUB_GPREG_PORT_CLKGATING_DISABLE 0x238058
#define CSI2_HUB_GPREG_SIP0_CSI_RX_A_CONTROL 0x23805c
#define CSI2_HUB_GPREG_SIP0_CSI_RX_B_CONTROL 0x238088
#define CSI2_HUB_GPREG_SIP1_CSI_RX_A_CONTROL 0x2380a4
#define CSI2_HUB_GPREG_SIP1_CSI_RX_B_CONTROL 0x2380d0
#define CSI2_SIP_TOP_CSI_RX_BASE(sip) (0x23805c + (sip) * 0x48)
#define CSI2_SIP_TOP_CSI_RX_PORT_BASE_0(port) (0x23805c + ((port) / 2) * 0x48)
#define CSI2_SIP_TOP_CSI_RX_PORT_BASE_1(port) (0x238088 + ((port) / 2) * 0x48)
/* offset from port base */
#define CSI2_SIP_TOP_CSI_RX_PORT_CONTROL 0x0
#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_TERMEN_CLANE 0x4
#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_SETTLE_CLANE 0x8
#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_TERMEN_DLANE(lane) (0xc + (lane) * 8)
#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_SETTLE_DLANE(lane) (0x10 + (lane) * 8)
#endif /* IPU6_ISYS_CSI2_REG_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