Files
test/drivers/source/camera/csi-rtos/csi_drv/csi_hw.c
2025-11-07 20:19:23 +08:00

1928 lines
67 KiB
C

/*
* csi_hw.c
*
* Semidrive platform csi controller driver core file (system independent)
*
* Copyright (C) 2022, Semidrive Communications Inc.
*
* This file is licensed under a dual GPLv2 or X11 license.
*/
#include "camera/sdrv-cam-os-def.h"
#include "csi_reg.h"
#include "csi_hw.h"
#define REMAPPING_WORDS ((64 * 6 + 31) / 32)
#define DEFAULT_SKIP_FRAMES 1
#define IMG_MAX_WIDTH ((1 << 16) - 1)
#define IMG_MAX_HEIGHT ((1 << 16) - 1)
#define FIELD_HAS_BOTH(field) (field == CSI_FIELD_INTERLACED)
#define CSI_IMG_ERR_RETURN(csi_dev, img_id, param) \
do { \
if ((csi_dev == NULL) || (img_id >= CSI_IMG_NUM) || (param == NULL)) { \
csi_err("%s: failed to get csi_dev %p, img_id %d, param %p\n", \
__func__, csi_dev, img_id, param); \
return -1; \
} \
} while (0);
enum csi_ip_version {
CSI_V1 = 0,
CSI_V2,
};
enum frame_buffer_mode {
FB_MODE_NORMAL = 0,
FB_MODE_ROUND,
};
/* Please define CSI_V1 for Kunlun, CSI_V2 for Taishan(E3) */
#ifndef CONFIG_CSI_VERSION
#define CONFIG_CSI_VERSION CSI_V1
#endif
#define IMG_STREAM_NUM_V1 2
#define IMG_STREAM_NUM 3
static int s_test_cnt;
int is_addr_64bit = (sizeof(dma_addr_t) / 8);
enum image_status {
IMG_STATUS_IDLE = 0,
IMG_STATUS_STREAM_ON,
IMG_STATUS_MAX,
};
int csi_cfg_img_buf(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct csi_img_buf *buf);
struct csi_core_internal;
struct csi_format_pack {
uint32_t output_fmt;
uint32_t bus_fmt;
uint8_t is_parallel;
uint8_t bpp[3];
uint8_t planes;
uint8_t fc_dualline;
uint8_t valid_pix_odd; /* valid pixel count in one pack(48 bits) for odd
line */
uint8_t valid_pix_even; /* valid pixel count in one pack(48 bits) for even
line */
uint8_t pack_cycle_odd; /* parallel: package how many bytes(one byte per
cycle) in one pack(48 bits) for odd line */
uint8_t pack_cycle_even; /* parallel: package how many bytes(one byte per
cycle) in one pack(48 bits) for even line */
uint8_t pack_cycle_uv_odd; /* parallel: U/V exists in pack for odd line */
uint8_t pack_cycle_uv_even; /* parallel: U/V exists in pack for even line */
uint32_t split[3]; /* data_sel, [0] for stream0(plane1), [1] for
stream1(plane2) */
uint32_t pack[3]; /* color_depth, [0] for stream0(plane1), [1] for
stream1(plane2) */
/* parallel: remapping pack(48bits) to 64bits( 4-ch x 16bits) */
const uint32_t *bitmap;
};
struct csi_img_err_cnt {
uint32_t bt_err;
uint32_t bt_fatal;
uint32_t crop_err;
uint32_t pix_err;
uint32_t overflow;
uint32_t stream0_err;
uint32_t stream1_err;
uint32_t stream2_err;
};
struct csi_img_internal {
uint32_t id;
uint32_t frm_cnt;
uint32_t bus_type; /* should be enum csi_bus_type */
uint32_t bus_fmt; /* should be enum csi_mbus_fmt */
uint32_t bus_flag;
uint32_t output_fmt; /* should be enum csi_out_fmt */
uint32_t field;
uint32_t second_field;
uint32_t skip_frame;
uint32_t shadow_cnt;
uint32_t status;
spinlock_t status_lock;
struct csi_img_err_cnt err_cnt;
const struct csi_format_pack *pfmt;
struct csi_img_buf next_buf;
/* [0] for frame and odd field, [1] for even field */
struct csi_img_size size[2];
struct csi_img_crop crop[2];
uint32_t crop_update;
spinlock_t crop_lock;
uint32_t fb_mode;
struct mem_range round_mem[3];
struct csi_core_internal *core;
struct csi_callback_t irq_cb;
};
struct csi_core_internal {
uint32_t host_id;
uint32_t inited;
uint32_t sync;
uint32_t sync_irq;
uint32_t ip_version;
reg_addr_t base;
spinlock_t glb_reg_lock;
struct csi_hw_dev ex_dev;
struct csi_img_internal images[CSI_IMG_NUM];
};
struct wdma_fifo_t {
uint32_t dfifo;
uint32_t cfifo;
};
static struct csi_core_internal csi_cores[CSI_HOST_NUM] = {
{
.host_id = CSI_HOST_0,
.ip_version = CONFIG_CSI_VERSION,
.ex_dev =
{
.host_id = CSI_HOST_0,
},
},
{
.host_id = CSI_HOST_1,
.ip_version = CONFIG_CSI_VERSION,
.ex_dev =
{
.host_id = CSI_HOST_1,
},
},
{
.host_id = CSI_HOST_2,
.ip_version = CONFIG_CSI_VERSION,
.ex_dev =
{
.host_id = CSI_HOST_2,
},
},
};
/*
* formats pack for mipi-csi input
*/
const struct csi_format_pack csi_mipi_fmts[] = {
/* idx = 0 */
{
.output_fmt = CSI_FMT_UYVY,
.bus_fmt = CSI_MBUS_UYVY8_2X8,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1, /* 1: 2 pixels one pack, 0: 1 pixels one pack */
.valid_pix_even = 1,
.split = {0x1A}, /* 3bits-per-sec: 0 | 0 | 3 | 2, */
.pack = {0x108}, /* 5bits-per-sec: 0 | 0 | 8 | 8, */
},
/* idx = 1 */
{
.output_fmt = CSI_FMT_YUYV,
.bus_fmt = CSI_MBUS_UYVY8_2X8,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.split = {0x13}, /* 3bits-per-sec: 0 | 0 | 2 | 3, */
.pack = {0x108}, /* 5bits-per-sec: 0 | 0 | 8 | 8, */
},
/* idx = 2 */
{
.output_fmt = CSI_FMT_UYVY,
.bus_fmt = CSI_MBUS_UYVY10_2X10,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.split = {0x1A}, /* 3bits-per-sec: 0 | 0 | 3 | 2, */
.pack = {0x108}, /* 5bits-per-sec: 0 | 0 | 8 | 8, */
},
/* idx = 3 */
{
.output_fmt = CSI_FMT_YUYV,
.bus_fmt = CSI_MBUS_UYVY10_2X10,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.split = {0x13}, /* 3bits-per-sec: 0 | 0 | 2 | 3, */
.pack = {0x108}, /* 5bits-per-sec: 0 | 0 | 8 | 8, */
},
/* idx = 4 */
{
.output_fmt = CSI_FMT_RGB24,
.bus_fmt = CSI_MBUS_RGB888_1X24,
.bpp = {24},
.planes = 1,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.split = {0xE53}, /* 3bits-per-sec: x | 1 | 2 | 3, x=16bit(0) */
.pack = {0x2108}, /* 5bits-per-sec: 0 | 8 | 8 | 8, */
},
/* idx = 5 */
{
.output_fmt = CSI_FMT_BGR24,
.bus_fmt = CSI_MBUS_RGB888_1X24,
.bpp = {24},
.planes = 1,
.valid_pix_odd = 0, /* 0: 1 pixels one pack */
.valid_pix_even = 0,
.split = {0xED1}, /* 3bits-per-sec: x | 3 | 2 | 1, x=16bit(0) */
.pack = {0x2108}, /* 5bits-per-sec: 0 | 8 | 8 | 8, */
},
};
/*
* bit 00-15: 4 5 6 7 8 9 0 1, 2 3 4 5 6 7 8 9
* bit 16-31: 14 15 16 17 18 19 10 11, 12 13 14 15 16 17 18 19
* bit 32-47: 24 25 26 27 28 29 20 21, 22 23 24 25 26 27 28 29
* bit 48-63: 34 35 36 37 38 39 30 31, 32 33 34 35 36 37 38 39
*/
const uint32_t mapping_default[][REMAPPING_WORDS] = {
[CSI_V1] = {/* for Kunlun */
0x481c6144, 0x40c20402, 0x2481c614, 0xd24503ce, 0xe34c2ca4, 0x4d24503c,
0x5c6da658, 0x85d65547, 0x75c6da65, 0xe69648e2, 0x28607de9, 0x9e69648e
},
[CSI_V2] = {/* for Taishan 8bits */
0x00000000, 0x20400000, 0x1C61440C, 0x00000000, 0xC2CA0000, 0x4503CE34,
0x00000000, 0x65540000, 0x6DA6585D, 0x00000000, 0x07DE0000, 0x9648E286
},
};
const uint32_t mapping_e3_24bit[REMAPPING_WORDS] = {
/* for Taishan 24 bits */
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20400000, 0x1c61440c,
0x00000000, 0xa2480000, 0x3ce34c2c, 0x00000000, 0x24500000, 0x5d65544d,
};
const uint32_t mapping_e3_24bit_dc[REMAPPING_WORDS] = {
/* for Taishan 24 bits input from dmux */
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40c20400, 0x2481c614,
0x00000000, 0xe34c2ca0, 0x4d24503c, 0x00000000, 0x85d65540, 0x75c6da65,
};
/*
* bit 00-15: 0 0 0 0 0 0 0 0, 2 3 4 5 6 7 8 9
* bit 16-31: 0 0 0 0 0 0 0 0, 12 13 14 15 16 17 18 19
* bit 32-47: 0 0 0 0 0 0 0 0, 0 0 0 0 0 0 0 0
* bit 48-63: 0 0 0 0 0 0 0 0, 0 0 0 0 0 0 0 0
*/
const uint32_t mapping_e3_bt1120[REMAPPING_WORDS] = {
/* for Taishan bt1120 16 bits */
0x00000000, 0x40c20000, 0x2481c614, 0x00000000, 0xe34c0000, 0x4d24503c,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
const uint32_t mapping_e3_16bit[REMAPPING_WORDS] = {
/* for Taishan YUYV/UYVY 16 bits */
0x00000000, 0x20400000, 0x1c61440c, 0x00000000, 0xa2480000, 0x3ce34c2c,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
/*
* formats pack for parallel input
*/
const struct csi_format_pack csi_parallel_fmts[] = {
/* idx = 0 */
{
.output_fmt = CSI_FMT_UYVY,
.bus_fmt = CSI_MBUS_UYVY8_2X8,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.pack_cycle_uv_odd = 3,
.pack_cycle_uv_even = 3,
.split = {0x53}, /* 3bits-per-sec: 0 | 1 | 2 | 3, */
.pack = {0x42108, 0x3F}, /* 5bits-per-sec: 8 | 8 | 8 | 8, */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 1 */
{
.output_fmt = CSI_FMT_YUYV,
.bus_fmt = CSI_MBUS_UYVY8_2X8,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.pack_cycle_uv_odd = 3,
.pack_cycle_uv_even = 3,
.split = {0x21A}, /* 3bits-per-sec: 1 | 0 | 3 | 2, */
.pack = {0x42108, 0x3F}, /* 5bits-per-sec: 8 | 8 | 8 | 8, */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 2 */
{
.output_fmt = CSI_FMT_UYVY,
.bus_fmt = CSI_MBUS_YUYV8_2X8,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.pack_cycle_uv_odd = 3,
.pack_cycle_uv_even = 3,
.split = {0x21A}, /* 3bits-per-sec: 1 | 0 | 3 | 2, */
.pack = {0x42108}, /* 5bits-per-sec: 8 | 8 | 8 | 8, */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 3 */
{
.output_fmt = CSI_FMT_YUYV,
.bus_fmt = CSI_MBUS_YUYV8_2X8,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.pack_cycle_uv_odd = 3,
.pack_cycle_uv_even = 3,
.split = {0x53}, /* 3bits-per-sec: 0 | 1 | 2 | 3, */
.pack = {0x42108}, /* 5bits-per-sec: 8 | 8 | 8 | 8, */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 4 */
{
.output_fmt = CSI_FMT_RGB24,
.bus_fmt = CSI_MBUS_RGB888_1X24,
.bpp = {24},
.planes = 1,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.pack_cycle_odd = 2, /* 2: pack 3bytes in 48bits pack for odd line */
.pack_cycle_even = 2, /* 2: pack 3bytes in 48bits pack for even line */
.split = {0xE53}, /* 3bits-per-sec: x | 1 | 2 | 3, x=16bit(0) */
.pack = {0x2108}, /* 5bits-per-sec: 0 | 8 | 8 | 8, */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 5 */
{
.output_fmt = CSI_FMT_BGR24,
.bus_fmt = CSI_MBUS_RGB888_1X24,
.bpp = {24},
.planes = 1,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.pack_cycle_odd = 2, /* 2: pack 3bytes in 48bits pack for odd line */
.pack_cycle_even = 2, /* 2: pack 3bytes in 48bits pack for even line */
.split = {0xED1}, /* 3bits-per-sec: x | 3 | 2 | 1, x=16bit(0) */
.pack = {0x2108}, /* 5bits-per-sec: 0 | 8 | 8 | 8, */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 6 */
{
.output_fmt = CSI_FMT_NV16, /* Y-Y-Y-Y, U-V-U-V, two planes*/
.bus_fmt = CSI_MBUS_UYVY8_2X8,
.bpp = {8, 8},
.planes = 2,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.pack_cycle_uv_odd = 3,
.pack_cycle_uv_even = 3,
.split = {0x02, 0x0B}, /* 3bits-per-sec: 0|0|0|2, 0|0|1|3 */
.pack = {0x108, 0x108}, /* 5bits-per-sec: 0|0|8|8, 0|0|8|8 */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 7 */
{
.output_fmt = CSI_FMT_NV61, /* Y-Y-Y-Y, V-U-V-U, two planes*/
.bus_fmt = CSI_MBUS_UYVY8_2X8,
.bpp = {8, 8},
.planes = 2,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.pack_cycle_uv_odd = 3,
.pack_cycle_uv_even = 3,
.split = {0x02, 0x19}, /* 3bits-per-sec: 0|0|0|2, 0|0|3|1 */
.pack = {0x108, 0x108}, /* 5bits-per-sec: 0|0|8|8, 0|0|8|8 */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 8 */
{
.output_fmt = CSI_FMT_YUV422P, /* Y, U, V, three planes*/
.bus_fmt = CSI_MBUS_UYVY8_2X8,
.bpp = {8, 4, 4},
.planes = 3,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.pack_cycle_uv_odd = 3,
.pack_cycle_uv_even = 3,
.split = {0x02, 0x03, 0x01}, /* 0|0|0|2, 0|0|0|3, 0|0|0|1 */
.pack = {0x108, 0x08, 0x08}, /* 0|0|8|8, 0|0|0|8, 0|0|0|8 */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 9 */
{
.output_fmt = CSI_FMT_RGB16,
.bus_fmt = CSI_MBUS_RGB565_1X16,
.bpp = {16},
.planes = 1,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.split = {0xE53}, /* 3bits-per-sec: x | 1 | 2 | 3, x=16bit(0) */
.pack = {0x42108}, /* 5bits-per-sec: 8 | 8 | 8 | 8, */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 10 */
{
.output_fmt = CSI_FMT_RGB24,
.bus_fmt = CSI_MBUS_RGB24_1X24,
.bpp = {24},
.planes = 1,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.pack_cycle_odd = 0, /* 0: pack 1cycle in 48bits pack for odd line */
.pack_cycle_even = 0, /* 0: pack 1cycle in 48bits pack for even line */
.split = {0xE53}, /* 3bits-per-sec: x | 1 | 2 | 3, x=16bit(0) */
.pack = {0x2108}, /* 5bits-per-sec: 0 | 8 | 8 | 8, */
.bitmap = mapping_e3_24bit,
},
/* idx = 11 */
{
.output_fmt = CSI_FMT_RGB24,
.bus_fmt = CSI_MBUS_BGR24_1X24,
.bpp = {24},
.planes = 1,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.pack_cycle_odd = 0, /* 0: pack 1cycle in 48bits pack for odd line */
.pack_cycle_even = 0, /* 0: pack 1cycle in 48bits pack for even line */
.split = {0xED1}, /* 3bits-per-sec: x | 3 | 2 | 1, x=16bit(0) */
.pack = {0x2108}, /* 5bits-per-sec: 0 | 8 | 8 | 8, */
.bitmap = mapping_e3_24bit,
},
/* idx = 12 */
{
.output_fmt = CSI_FMT_NV16, /* Y-Y-Y-Y, U-V-U-V, two planes*/
.bus_fmt = CSI_MBUS_YUYV8_2X8,
.bpp = {8, 8},
.planes = 2,
.valid_pix_odd = 1,
.valid_pix_even = 1,
.pack_cycle_odd = 3, /* 3: pack 4bytes in 48bits pack for odd line */
.pack_cycle_even = 3, /* 3: pack 4bytes in 48bits pack for even line */
.pack_cycle_uv_odd = 3,
.pack_cycle_uv_even = 3,
.split = {0x0B, 0x02}, /* 3bits-per-sec: 0|0|0|2, 0|0|1|3 */
.pack = {0x108, 0x108}, /* 5bits-per-sec: 0|0|8|8, 0|0|8|8 */
.bitmap = mapping_default[CONFIG_CSI_VERSION],
},
/* idx = 13 */
{
.output_fmt = CSI_FMT_YUYV,
.bus_fmt = CSI_MBUS_YUYV8_1X16, // YUYV8_1X16
.bpp = {16},
.planes = 1,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.pack_cycle_odd = 0, /* 0: pack 1cycle in 48bits pack for odd line */
.pack_cycle_even = 0, /* 0: pack 1cycle in 48bits pack for even line */
.split = {0x008}, /* 3bits-per-sec: 0 | 0 | 1 | 0, x=16bit(0) */
.pack = {0x108}, /* 5bits-per-sec: 0 | 0 | 8 | 8, */
.bitmap = mapping_e3_bt1120,
},
/* idx = 14 */
{
.output_fmt = CSI_FMT_NV16,
.bus_fmt = CSI_MBUS_YUYV8_1X16, // YUYV8_1X16
.bpp = {8, 8},
.planes = 2,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.pack_cycle_odd = 0, /* 0: pack 1cycle in 48bits pack for odd line */
.pack_cycle_even = 0, /* 0: pack 1cycle in 48bits pack for even line */
.split = {0x01, 0x00},/* 3bits-per-sec: 0|0|0|1, 0|0|0|0 */
.pack = {0x08, 0x08}, /* 5bits-per-sec: 0|0|0|8, 0|0|0|8 */
.bitmap = mapping_e3_bt1120,
},
/* idx = 15 */
{
.output_fmt = CSI_FMT_YUYV,
.bus_fmt = CSI_MBUS_UYVY8_1X16, // UYVY8_1X16
.bpp = {16},
.planes = 1,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.pack_cycle_odd = 0, /* 0: pack 1cycle in 48bits pack for odd line */
.pack_cycle_even = 0, /* 0: pack 1cycle in 48bits pack for even line */
.split = {0x001}, /* 3bits-per-sec: 0 | 0 | 0 | 1, x=16bit(0) */
.pack = {0x108}, /* 5bits-per-sec: 0 | 0 | 8 | 8, */
.bitmap = mapping_e3_bt1120,
},
/* idx = 16 */
{
.output_fmt = CSI_FMT_NV16,
.bus_fmt = CSI_MBUS_UYVY8_1X16, // UYVY8_1X16
.bpp = {8, 8},
.planes = 2,
.valid_pix_odd = 0,
.valid_pix_even = 0,
.pack_cycle_odd = 0, /* 0: pack 1cycle in 48bits pack for odd line */
.pack_cycle_even = 0, /* 0: pack 1cycle in 48bits pack for even line */
.split = {0x00, 0x01},/* 3bits-per-sec: 0|0|0|0, 0|0|0|1 */
.pack = {0x08, 0x08}, /* 5bits-per-sec: 0|0|0|8, 0|0|0|8 */
.bitmap = mapping_e3_bt1120,
},
};
static inline void csi_set(struct csi_core_internal *csi_core, uint32_t addr,
uint32_t mask, uint32_t set_val)
{
unsigned long flags;
spin_lock_irqsave(&csi_core->glb_reg_lock, flags);
reg_write(csi_core->base, addr,
(reg_read(csi_core->base, addr) & ~mask) | set_val);
spin_unlock_irqrestore(&csi_core->glb_reg_lock, flags);
}
/* set reg to default value */
static void csi_img_set_default(struct csi_img_internal *img)
{
struct csi_core_internal *csi_core = img->core;
int i, n = img->id;
reg_write(csi_core->base, CSI_REG_IMG_RGBY_BADDR_H(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_RGBY_BADDR_L(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_U_BADDR_H(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_U_BADDR_L(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_V_BADDR_H(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_V_BADDR_L(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_RGBY_STRIDE(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_U_STRIDE(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_V_STRIDE(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_SIZE(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_IPI_CTRL(n), 0x4000);
reg_write(csi_core->base, CSI_REG_IMG_IF_PIXEL_MASK0(n), 0xFFFFFFFF);
reg_write(csi_core->base, CSI_REG_IMG_IF_PIXEL_MASK1(n), 0xFFFFFFFF);
reg_write(csi_core->base, CSI_REG_IMG_CHN_CTRL(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_CHN_SPLIT0(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_CHN_SPLIT1(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_CHN_CROP0(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_CHN_CROP1(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_CHN_PACK0(n), 0x00);
reg_write(csi_core->base, CSI_REG_IMG_CHN_PACK1(n), 0x00);
i = n * 2;
reg_write(csi_core->base, CSI_REG_WDMA_CHN_DFIFO(i), 0x00400008);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_CFIFO(i), 0x04);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL0(i), 0x3C8);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL1(i), 0x00);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL2(i), 0x0B);
i++;
reg_write(csi_core->base, CSI_REG_WDMA_CHN_DFIFO(i), 0x00400008);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_CFIFO(i), 0x04);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL0(i), 0x3C8);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL1(i), 0x00);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL2(i), 0x0B);
reg_write(csi_core->base, CSI_REG_PARA_BT_CTRL0(n), 0x00);
reg_write(csi_core->base, CSI_REG_PARA_BT_CTRL1(n), 0x00);
reg_write(csi_core->base, CSI_REG_PARA_BT_CTRL2(n), 0x00);
if (csi_core->ip_version < CSI_V2)
return;
i = 0;
reg_write(csi_core->base, CSI_REG_WDMA_CHN_DFIFO(i), 0x00400008);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_CFIFO(i), 0x04);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL0(i), 0x3C8);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL1(i), 0x00);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL2(i), 0x0B);
i = 1;
reg_write(csi_core->base, CSI_REG_WDMA_CHN_DFIFO(i), 0x00200004);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_CFIFO(i), 0x04);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL0(i), 0x3C8);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL1(i), 0x00);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL2(i), 0x0B);
i = 2;
reg_write(csi_core->base, CSI_REG_WDMA_CHN_DFIFO(i), 0x00200004);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_CFIFO(i), 0x04);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL0(i), 0x3C8);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL1(i), 0x00);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL2(i), 0x0B);
i = 3;
reg_write(csi_core->base, CSI_REG_WDMA_CHN_DFIFO(i), 0x00400008);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_CFIFO(i), 0x04);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL0(i), 0x3C8);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL1(i), 0x00);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL2(i), 0x0B);
reg_write(csi_core->base, CSI_REG_IMG_FB_CTRL(n), 0x00);
csi_set(csi_core, CSI_REG_ENABLE, (3 << 16), 0);
}
/* set ipi ctrl, channel ctrl */
static int csi_img_set_channel(struct csi_img_internal *img)
{
struct csi_core_internal *csi_core = img->core;
const struct csi_format_pack *fmt = img->pfmt;
int i, n, stream_num;
uint32_t chn_ctrl, ipi_ctrl;
n = img->id;
stream_num = (fmt->planes > IMG_STREAM_NUM) ? IMG_STREAM_NUM : fmt->planes;
ipi_ctrl = reg_read(csi_core->base, CSI_REG_IMG_IPI_CTRL(n));
ipi_ctrl &= ~(0x7);
ipi_ctrl |= (img->bus_type & 7);
if (img->bus_type == CSI_BUS_MIPICSI2) {
switch (fmt->bus_fmt) {
case CSI_MBUS_UYVY8_2X8:
case CSI_MBUS_YUYV8_2X8:
case CSI_MBUS_UYVY10_2X10:
ipi_ctrl |= (1 << 6);
break;
case CSI_MBUS_UYVY8_1_5X8:
ipi_ctrl |= (1 << 4);
break;
case CSI_MBUS_VYUY8_1_5X8:
ipi_ctrl |= (1 << 3);
break;
default:
break;
}
} else {
ipi_ctrl &= ~(0x1F << 9);
ipi_ctrl |= ((fmt->fc_dualline & 1) << 13);
ipi_ctrl |=
((fmt->valid_pix_even & 3) << 11) | ((fmt->valid_pix_odd & 3) << 9);
}
s_test_cnt++;
// img->skip_frame = (s_test_cnt>>3)&3;
csi_err("s_test_cnt %d, skip_frame: %d\n", s_test_cnt, img->skip_frame);
/* vsync_mask_count */
ipi_ctrl &= ~(3 << 7);
ipi_ctrl |= ((img->skip_frame & 3) << 7);
reg_write(csi_core->base, CSI_REG_IMG_IPI_CTRL(n), ipi_ctrl);
/* set channel ctrl: stream enable */
chn_ctrl = reg_read(csi_core->base, CSI_REG_IMG_CHN_CTRL(n));
chn_ctrl &= ~(0x7);
chn_ctrl |= ((1 << stream_num) - 1);
reg_write(csi_core->base, CSI_REG_IMG_CHN_CTRL(n), chn_ctrl);
for (i = 0; i < stream_num; i++) {
int split[4], color_depth[4];
split[0] = (fmt->split[i] & 0x7);
split[1] = ((fmt->split[i] >> 3) & 0x7);
split[2] = ((fmt->split[i] >> 6) & 0x7);
split[3] = ((fmt->split[i] >> 9) & 0x7);
color_depth[0] = (fmt->pack[i] & 0x1F);
color_depth[1] = ((fmt->pack[i] >> 5) & 0x1F);
color_depth[2] = ((fmt->pack[i] >> 10) & 0x1F);
color_depth[3] = ((fmt->pack[i] >> 15) & 0x1F);
csi_info("%s: pix_fmt: 0x%08x, bus_type 0x%x\n", __func__,
fmt->output_fmt, fmt->bus_fmt);
csi_info("plane.%d, split= [%d, %d, %d, %d], color_depth = [%d, %d, "
"%d, %d]\n",
i, split[3], split[2], split[1], split[0], color_depth[3],
color_depth[2], color_depth[1], color_depth[0]);
reg_write(csi_core->base, CSI_REG_IMG_CHN_SPLIT0(n) + i * 4,
fmt->split[i]);
reg_write(csi_core->base, CSI_REG_IMG_CHN_PACK0(n) + i * 4,
fmt->pack[i]);
}
return 0;
}
/* set crop */
static int csi_img_set_crop(struct csi_img_internal *img)
{
struct csi_core_internal *csi_core = img->core;
const struct csi_format_pack *fmt = img->pfmt;
int i, n, stream_num;
uint32_t crop_en, start, length, val;
uint32_t chn_ctrl;
n = img->id;
stream_num = (fmt->planes > IMG_STREAM_NUM) ? IMG_STREAM_NUM : fmt->planes;
/* set hcrop: width crop */
crop_en = (img->crop[0].w == img->size[0].w) ? 0 : 1;
if (!crop_en) {
csi_set(csi_core, CSI_REG_IMG_CHN_CTRL(n), 0x38, 0);
goto set_vcrop;
}
csi_info("%s: csi%d img%d width crop enable\n", __func__, csi_core->host_id,
img->id);
chn_ctrl = reg_read(csi_core->base, CSI_REG_IMG_CHN_CTRL(n));
chn_ctrl &= ~(0x38); /* bit[5:3] */
crop_en = (1 << stream_num) - 1;
chn_ctrl |= (crop_en << 3);
reg_write(csi_core->base, CSI_REG_IMG_CHN_CTRL(n), chn_ctrl);
for (i = 0; i < stream_num; i++) {
start = img->crop[0].x / (fmt->valid_pix_odd + 1);
length = img->crop[0].w / (fmt->valid_pix_odd + 1);
val = (((length - 1) & 0xFFFF) << 16) | (start & 0xFFFF);
reg_write(csi_core->base, CSI_REG_IMG_CHN_CROP0(n) + i * 4, val);
}
set_vcrop:
/* height crop is not supported by Kunlun */
if (csi_core->ip_version < CSI_V2)
return 0;
/* set vcrop: height crop, height crop is supported by Taishan(E3) */
crop_en = (img->crop[0].h == img->size[0].h) ? 0 : 1;
if (!crop_en) {
csi_set(csi_core, CSI_REG_IMG_CHN_CTRL(n), 0x1C00, 0);
return 0;
}
csi_info("%s: csi%d img%d height crop enable\n", __func__,
csi_core->host_id, img->id);
chn_ctrl = reg_read(csi_core->base, CSI_REG_IMG_CHN_CTRL(n));
chn_ctrl &= ~(0x1C00); /* bit[12:10] */
crop_en = (1 << stream_num) - 1;
chn_ctrl |= (crop_en << 10);
reg_write(csi_core->base, CSI_REG_IMG_CHN_CTRL(n), chn_ctrl);
for (i = 0; i < stream_num; i++) {
start = img->crop[0].y;
length = img->crop[0].h;
val = (((length - 1) & 0xFFFF) << 16) | (start & 0xFFFF);
reg_write(csi_core->base, CSI_REG_IMG_CHN_VCROP0(n) + i * 4, val);
}
return 0;
}
/* set size, stride */
static int csi_img_set_size(struct csi_img_internal *img)
{
struct csi_core_internal *csi_core = img->core;
const struct csi_format_pack *fmt = img->pfmt;
int i, n = img->id;
uint32_t width, height, out_width, stride;
/* set size */
if (img->bus_type == CSI_BUS_MIPICSI2)
width = img->size[0].w - 1;
else
width = img->size[0].w - (1 + fmt->valid_pix_odd);
height = img->size[0].h - 1;
reg_write(csi_core->base, CSI_REG_IMG_SIZE(n),
((width & 0xFFFF) << 16) | (height & 0xFFFF));
/* set stride */
out_width = img->crop[0].w;
for (i = 0; i < fmt->planes; i++) {
if (FIELD_HAS_BOTH(img->field))
stride = 2 * out_width * fmt->bpp[i] / 8;
else
stride = out_width * fmt->bpp[i] / 8;
reg_write(csi_core->base, CSI_REG_IMG_RGBY_STRIDE(n) + i * 4, stride);
}
csi_img_set_crop(img);
return 0;
}
static int csi_img_set_wdma(struct csi_img_internal *img)
{
struct csi_core_internal *csi_core = img->core;
int i, k, n;
uint32_t axi0 = 0x3C8;
uint32_t axi1 = 0x00;
uint32_t axi2 = 0x0B;
struct wdma_fifo_t wfifo[2][2] = {
{
/* for one plane output, assign all fifo to stream0 */
{0x00400010, 0x08},
{0x00400000, 0x00},
},
{
/* for two planes output */
{0x00400008, 0x04},
{0x00400008, 0x04},
},
};
k = (img->pfmt->planes == 1) ? 0 : 1;
n = img->id * 2;
for (i = 0; i < IMG_STREAM_NUM_V1; i++, n++) {
reg_write(csi_core->base, CSI_REG_WDMA_CHN_DFIFO(n), wfifo[k][i].dfifo);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_CFIFO(n), wfifo[k][i].cfifo);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL0(n), axi0);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL1(n), axi1);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL2(n), axi2);
}
return 0;
}
/*
* for CSI V2 (taishan)
* ch0: thread streams max, ch1: only one stream
*/
static int csi_img_set_wdma_v2(struct csi_img_internal *img)
{
struct csi_core_internal *csi_core = img->core;
int i, k, n, stream_num;
uint32_t axi0 = 0x3C8;
uint32_t axi1 = 0x00;
uint32_t axi2 = 0x0B;
struct wdma_fifo_t wfifo[4][3] = {
{
/* for one plane output, assign all fifo to stream0 */
{0x00400010, 0x08},
{0x00200000, 0x00},
{0x00200000, 0x00},
},
{
/* for two planes output */
{0x00400008, 0x04},
{0x00400008, 0x04},
{0x00200000, 0x00},
},
{
/* for three planes output */
{0x00400008, 0x04},
{0x00200004, 0x02},
{0x00200004, 0x02},
},
{
/* for channel[1] one plane output, assign all fifo to stream0 */
{0x00400008, 0x04},
{0x00400000, 0x00},
{0x00400000, 0x00},
},
};
k = (img->id == 1) ? 3 : (img->pfmt->planes - 1);
stream_num = (img->id == 1) ? 1 : IMG_STREAM_NUM;
n = (img->id == 1) ? 3 : 0;
for (i = 0; i < stream_num; i++, n++) {
csi_info("ch%d, n=%d, i=%d, k=%d, difo 0x%08x cfifo 0x%08x\n", img->id,
n, i, k, wfifo[k][i].dfifo, wfifo[k][i].cfifo);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_DFIFO(n), wfifo[k][i].dfifo);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_CFIFO(n), wfifo[k][i].cfifo);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL0(n), axi0);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL1(n), axi1);
reg_write(csi_core->base, CSI_REG_WDMA_CHN_AXI_CTRL2(n), axi2);
}
return 0;
}
static int csi_img_set_para_bt(struct csi_img_internal *img)
{
struct csi_core_internal *csi_core = img->core;
int i;
uint32_t value0 = 0, value1 = 0, value2 = 0, height;
const struct csi_format_pack *fmt = img->pfmt;
const uint32_t *map = fmt->bitmap;
if (img->bus_type == CSI_BUS_MIPICSI2) {
reg_write(csi_core->base, CSI_REG_PARA_BT_CTRL0(img->id), value0);
return 0;
}
if ((img->id == 1) &&
(fmt->bus_fmt == CSI_MBUS_RGB24_1X24 ||
fmt->bus_fmt == CSI_MBUS_BGR24_1X24)) {
map = mapping_e3_24bit_dc;
}
if ((img->bus_type != CSI_BUS_BT1120_SDR) &&
(fmt->bus_fmt == CSI_MBUS_UYVY8_1X16 ||
fmt->bus_fmt == CSI_MBUS_YUYV8_1X16)) {
map = mapping_e3_16bit;
}
value0 |= (1 << 0) | ((fmt->pack_cycle_odd & 3) << 1) |
((fmt->pack_cycle_even & 3) << 3) |
((fmt->pack_cycle_uv_odd & 3) << 6) |
((fmt->pack_cycle_uv_even & 3) << 8);
/* data enable pol */
if (img->bus_flag & MBUS_DE_ACTIVE_LOW)
value0 |= (1 << 10);
/* vsync pol */
if (img->bus_flag & MBUS_VSYNC_ACTIVE_LOW)
value0 |= (1 << 11);
/* hsync pol */
if (img->bus_flag & MBUS_HSYNC_ACTIVE_HIGH)
value0 |= (1 << 12);
/* pclk pol */
if (img->bus_flag & MBUS_PCLK_SAMPLE_RISING)
value0 |= (1 << 13);
if (img->bus_type == CSI_BUS_BT656 || img->bus_type == CSI_BUS_BT1120_SDR) {
if (FIELD_HAS_BOTH(img->field)) {
height = img->size[1].h - 1;
value0 |= (1 << 14) | (height << 15);
value1 = (1 << 2);
} else {
value1 = (1 << 0) | (1 << 2) | (img->size[0].w << 16);
}
} else if (img->bus_type == CSI_BUS_PARALLEL4) {
value1 = (1 << 0) | (1 << 2) | (img->size[0].w << 16);
}
if (FIELD_HAS_BOTH(img->field))
value2 = 0;
else
value2 = (1 << 17);
reg_write(csi_core->base, CSI_REG_PARA_BT_CTRL0(img->id), value0);
reg_write(csi_core->base, CSI_REG_PARA_BT_CTRL1(img->id), value1);
reg_write(csi_core->base, CSI_REG_PARA_BT_CTRL2(img->id), value2);
for (i = 0; i < REMAPPING_WORDS; i++)
reg_write(csi_core->base, CSI_REG_PIXEL_MAP(img->id) + i * 4, map[i]);
/* for Mapping debug
if (1) {
uint32_t imap[3], bit_map[16];
int j;
for (j = 0; j < 4; j++) {
imap[0] = map[j * 3 + 0];
imap[1] = map[j * 3 + 1];
imap[2] = map[j * 3 + 2];
bit_map[0] = ((imap[0] >> 0) & 0x3F);
bit_map[1] = ((imap[0] >> 6) & 0x3F);
bit_map[2] = ((imap[0] >> 12) & 0x3F);
bit_map[3] = ((imap[0] >> 18) & 0x3F);
bit_map[4] = ((imap[0] >> 24) & 0x3F);
bit_map[5] = ((imap[0] >> 30) & 0x3);
bit_map[5] |= ((imap[1] << 2) & 0x3C);
bit_map[6] = ((imap[1] >> 4) & 0x3F);
bit_map[7] = ((imap[1] >> 10) & 0x3F);
bit_map[8] = ((imap[1] >> 16) & 0x3F);
bit_map[9] = ((imap[1] >> 22) & 0x3F);
bit_map[10] = ((imap[1] >> 28) & 0xF);
bit_map[10] |= ((imap[2] << 4) & 0x30);
bit_map[11] = ((imap[2] >> 2) & 0x3F);
bit_map[12] = ((imap[2] >> 8) & 0x3F);
bit_map[13] = ((imap[2] >> 14) & 0x3F);
bit_map[14] = ((imap[2] >> 20) & 0x3F);
bit_map[15] = ((imap[2] >> 26) & 0x3F);
csi_info("map idx %d, data %d %d %d %d %d %d %d %d,
%d %d %d %d %d %d %d %d\n", j * 16, bit_map[0], bit_map[1], bit_map[2],
bit_map[3], bit_map[4], bit_map[5], bit_map[6], bit_map[7], bit_map[8],
bit_map[9], bit_map[10], bit_map[11], bit_map[12], bit_map[13],
bit_map[14], bit_map[15]);
}
}
*/
return 0;
}
static int csi_img_set_memrange(struct csi_img_internal *img)
{
struct csi_core_internal *csi_core = img->core;
int n = img->id;
uint32_t mask = (1 << 28) - 1;
// asw/dc singnal enable
csi_info("%s: asw/dc irq enable\n", __func__);
csi_set(csi_core, CSI_REG_ENABLE, (3 << 16), (3 << 16));
reg_write(csi_core->base, CSI_REG_IMG_FB_CTRL(n), (img->fb_mode & 1));
if (img->fb_mode == FB_MODE_NORMAL)
return 0;
csi_set(csi_core, CSI_REG_ENABLE, (3 << 16), (3 << 16));
reg_write(csi_core->base, CSI_REG_IMG_UP_RGBY_ADDR(n),
((img->round_mem[0].up >> 12) & mask));
reg_write(csi_core->base, CSI_REG_IMG_LOW_RGBY_ADDR(n),
((img->round_mem[0].low >> 12) & mask));
reg_write(csi_core->base, CSI_REG_IMG_UP_U_ADDR(n),
((img->round_mem[1].up >> 12) & mask));
reg_write(csi_core->base, CSI_REG_IMG_LOW_U_ADDR(n),
((img->round_mem[1].low >> 12) & mask));
reg_write(csi_core->base, CSI_REG_IMG_UP_V_ADDR(n),
((img->round_mem[2].up >> 12) & mask));
reg_write(csi_core->base, CSI_REG_IMG_LOW_V_ADDR(n),
((img->round_mem[2].low >> 12) & mask));
/* TODO - temp set circle buffer range and stride */
csi_set(csi_core, CSI_REG_IMG_FB_CTRL(n), (7 << 1), (img->round_mem[2].low << 1));
reg_write(csi_core->base, CSI_REG_IMG_RGBY_STRIDE(n) + 0, img->round_mem[2].up);
return 0;
}
/* set img 1~3 buffer address base on buffer of img0 for sync mode */
static void csi_img_set_sync_buf(struct csi_img_internal *img,
struct csi_img_buf *buf)
{
int i, n = img->id;
struct csi_core_internal *csi_core = img->core;
const struct csi_format_pack *fmt = img->pfmt;
dma_addr_t paddr[3];
uint32_t *ptr_u32;
uint32_t addr_l[3], addr_h[3], stride[3], height[3], offset[3];
for (i = 0; i < (int)fmt->planes; i++) {
stride[i] =
reg_read(csi_core->base, CSI_REG_IMG_RGBY_STRIDE(n) + i * 4);
height[i] =
img->size[0].h; /* todo: U/V height may be 1/2, such as YUV420 */
offset[i] = n * stride[i] * height[i];
paddr[i] = buf->paddr[i] + offset[i];
ptr_u32 = (uint32_t *)&paddr[i];
addr_l[i] = ptr_u32[0];
addr_h[i] = (is_addr_64bit ? ptr_u32[1] : 0);
reg_write(csi_core->base, CSI_REG_IMG_RGBY_BADDR_H(n) + i * 8,
addr_h[i]);
reg_write(csi_core->base, CSI_REG_IMG_RGBY_BADDR_L(n) + i * 8,
addr_l[i]);
}
csi_set(csi_core, CSI_REG_REG_LOAD, (1 << n), (1 << n));
}
/* update buffer addr for second field */
static int csi_img_set_field_buf(struct csi_img_internal *img,
struct csi_img_buf *buf)
{
struct csi_core_internal *csi_core = img->core;
const struct csi_format_pack *fmt = img->pfmt;
int i, n = img->id;
dma_addr_t paddr[3];
uint32_t *ptr_u32;
uint32_t addr_l[3], addr_h[3], stride[3];
/* default set bottom field as second */
for (i = 0; i < (int)fmt->planes; i++) {
stride[i] =
reg_read(csi_core->base, CSI_REG_IMG_RGBY_STRIDE(n) + i * 4);
paddr[i] = buf->paddr[i] + (stride[i] / 2);
ptr_u32 = (uint32_t *)&paddr[i];
addr_l[i] = ptr_u32[0];
addr_h[i] = (is_addr_64bit ? ptr_u32[1] : 0);
reg_write(csi_core->base, CSI_REG_IMG_RGBY_BADDR_H(n) + i * 8,
addr_h[i]);
reg_write(csi_core->base, CSI_REG_IMG_RGBY_BADDR_L(n) + i * 8,
addr_l[i]);
}
/* shadow_set_n*/
csi_set(csi_core, CSI_REG_REG_LOAD, (1 << n), (1 << n));
return 0;
}
static int csi_img_set_regs(struct csi_img_internal *img)
{
int ret = 0, n = img->id;
uint32_t set_val;
struct csi_core_internal *csi_core = img->core;
struct csi_img_buf *base_buf = &img->next_buf;
csi_img_set_default(img);
ret |= csi_cfg_img_buf(&csi_core->ex_dev, n, &img->next_buf);
ret |= csi_img_set_channel(img);
ret |= csi_img_set_size(img);
ret |= csi_img_set_para_bt(img);
if (csi_core->ip_version < CSI_V2) {
ret |= csi_img_set_wdma(img);
} else {
ret |= csi_img_set_wdma_v2(img);
ret |= csi_img_set_memrange(img);
}
if (ret) {
csi_err("%s, csi%d, img %d, failed to set regs\n", __func__,
csi_core->host_id, img->id);
return ret;
}
if (csi_core->sync == 0) {
/* enalbe irq */
if (img->bus_type != CSI_BUS_BT656)
csi_set(csi_core, CSI_REG_INT_MASK0, INT0_MASK(n), INT0_MASK(n));
else
csi_set(csi_core, CSI_REG_INT_MASK0, INT0_BT_MASK(n),
INT0_BT_MASK(n));
csi_set(csi_core, CSI_REG_INT_MASK1, INT1_ERR_MASK(n),
INT1_ERR_MASK(n));
csi_err("irq_mask: 0x%08x 0x%08x\n",
reg_read(csi_core->base, CSI_REG_INT_MASK0),
reg_read(csi_core->base, CSI_REG_INT_MASK1));
/* [17]: WDMA_CFG_LOAD, [15:8]: update mask_n, [7:4]: shadow_update_n
* by software(force shashow) */
set_val = ((1 << 17)) | 0x5500 | (0x11 << n);
csi_set(csi_core, CSI_REG_REG_LOAD, set_val, set_val);
/* enable stream */
csi_set(csi_core, CSI_REG_ENABLE, (1 << n), (1 << n));
return 0;
}
for (n = CSI_IMG1; n <= CSI_IMG3; n++) {
img = &csi_core->images[n];
csi_img_set_default(img);
ret |= csi_img_set_channel(img);
ret |= csi_img_set_size(img);
ret |= csi_img_set_para_bt(img);
ret |= csi_img_set_wdma(img);
if (ret) {
csi_err("%s, csi%d, img %d, failed to set regs\n", __func__,
csi_core->host_id, img->id);
return ret;
}
csi_img_set_sync_buf(&csi_core->images[n], base_buf);
/* enalbe irq */
csi_set(csi_core, CSI_REG_INT_MASK0, INT0_MASK(n), INT0_MASK(n));
csi_set(csi_core, CSI_REG_INT_MASK1, INT1_ERR_MASK(n),
INT1_ERR_MASK(n));
}
set_val = ((1 << 17)) | 0xFFF0;
csi_set(csi_core, CSI_REG_REG_LOAD, set_val, set_val);
/* enable all stream */
csi_set(csi_core, CSI_REG_ENABLE, 0xF, 0xF);
return 0;
}
/* setup parameter base on input configuration */
static int csi_img_setup_param(struct csi_img_internal *img)
{
int i, total;
uint32_t n;
struct csi_core_internal *csi_core = img->core;
const struct csi_format_pack *fmt_pack;
if ((img->bus_type >= CSI_BUS_TYPE_MAX) ||
(img->bus_type == CSI_BUS_PARALLEL1) ||
(img->bus_type == CSI_BUS_BT1120_DDR)) {
csi_err("%s, csi%d, img %d, unsupported bus_type %d\n", __func__,
csi_core->host_id, img->id, img->bus_type);
return -1;
}
if (img->field != CSI_FIELD_NONE && img->field != CSI_FIELD_INTERLACED) {
csi_err("%s, csi%d, img %d, unsupported field_type %d\n", __func__,
csi_core->host_id, img->id, img->field);
return -1;
}
total = FIELD_HAS_BOTH(img->field) ? 2 : 1;
for (i = 0; i < total; i++) {
if ((img->size[i].w > IMG_MAX_WIDTH) ||
(img->size[i].h > IMG_MAX_HEIGHT)) {
csi_err("%s, csi%d, img %d, unsupported size %d %d\n", __func__,
csi_core->host_id, img->id, img->size[i].w, img->size[i].h);
return -1;
}
if (img->crop[i].x == 0 && img->crop[i].y == 0 && img->crop[i].w == 0 &&
img->crop[i].h == 0) {
img->crop[i].w = img->size[i].w;
img->crop[i].h = img->size[i].h;
}
if (((img->crop[i].x + img->crop[i].w) > img->size[i].w) ||
((img->crop[i].y + img->crop[i].h) > img->size[i].h)) {
csi_err(
"%s, csi%d, img %d, error crop (%d %d %d %d) for size %d %d\n",
__func__, csi_core->host_id, img->id, img->crop[i].x,
img->crop[i].y, img->crop[i].w, img->crop[i].h, img->size[i].w,
img->size[i].h);
return -1;
}
}
if (img->bus_type == CSI_BUS_MIPICSI2) {
fmt_pack = &csi_mipi_fmts[0];
total = sizeof(csi_mipi_fmts) / sizeof(csi_mipi_fmts[0]);
} else {
fmt_pack = &csi_parallel_fmts[0];
total = sizeof(csi_parallel_fmts) / sizeof(csi_parallel_fmts[0]);
}
for (i = 0; i < total; i++, fmt_pack++) {
if (fmt_pack->bus_fmt != img->bus_fmt ||
fmt_pack->output_fmt != img->output_fmt)
continue;
img->pfmt = fmt_pack;
csi_info("%s, csi%d, img%d, bus type %d bus_fmt %d, outfmt: 0x%08x, "
"index %d\n",
__func__, csi_core->host_id, img->id, img->bus_type,
img->bus_fmt, fmt_pack->output_fmt, i);
}
if (img->pfmt == NULL) {
csi_err(
"%s, csi%d, img%d, bus type %d bus_fmt %d, error outfmt: 0x%08x\n",
__func__, csi_core->host_id, img->id, img->bus_type, img->bus_fmt,
fmt_pack->output_fmt);
}
if (img->bus_type == CSI_BUS_MIPICSI2)
img->skip_frame = 0;
else
img->skip_frame = DEFAULT_SKIP_FRAMES;
csi_info("%s, csi%d img%d setup params done\n", __func__,
img->core->host_id, img->id);
if (csi_core->sync == 0)
return 0;
for (n = CSI_IMG1; n <= CSI_IMG3; n++) {
img = &csi_core->images[n];
memcpy(img, &csi_core->images[0], sizeof(struct csi_img_internal));
spin_lock_init(&img->status_lock);
img->id = n;
}
return 0;
}
static void csi_err_handle(struct csi_img_internal *img, uint32_t sync,
uint32_t value0, uint32_t value1)
{
int n = img->id;
if (sync) {
if (value0 & CSI_INT0_BT_ERR)
img->err_cnt.bt_err++;
if (value0 & CSI_INT0_BT_FATAL)
img->err_cnt.bt_fatal++;
if (value1 & (CSI_INT1_CROP_ERR0 | CSI_INT1_CROP_ERR1 |
CSI_INT1_CROP_ERR2 | CSI_INT1_CROP_ERR3))
img->err_cnt.crop_err++;
if (value1 & (CSI_INT1_PIXEL_ERR0 | CSI_INT1_PIXEL_ERR1 |
CSI_INT1_PIXEL_ERR2 | CSI_INT1_PIXEL_ERR3))
img->err_cnt.pix_err++;
if (value1 & (CSI_INT1_OVERFLOW0 | CSI_INT1_OVERFLOW1 |
CSI_INT1_OVERFLOW2 | CSI_INT1_OVERFLOW3))
img->err_cnt.overflow++;
if (value1 & (CSI_INT1_IMG0_BUSERR0 | CSI_INT1_IMG1_BUSERR0 |
CSI_INT1_IMG2_BUSERR0 | CSI_INT1_IMG3_BUSERR0))
img->err_cnt.stream0_err++;
if (value1 & (CSI_INT1_IMG0_BUSERR1 | CSI_INT1_IMG1_BUSERR1 |
CSI_INT1_IMG2_BUSERR1 | CSI_INT1_IMG3_BUSERR1))
img->err_cnt.stream1_err++;
if (value1 & (CSI_INT1_IMG0_BUSERR2 | CSI_INT1_IMG1_BUSERR2 |
CSI_INT1_IMG2_BUSERR2 | CSI_INT1_IMG3_BUSERR2))
img->err_cnt.stream2_err++;
} else {
if (value0 & (CSI_INT0_BT_ERR << n))
img->err_cnt.bt_err++;
if (value0 & (CSI_INT0_BT_FATAL << n))
img->err_cnt.bt_fatal++;
if (value1 & (CSI_INT1_CROP_ERR0 << n))
img->err_cnt.crop_err++;
if (value1 & (CSI_INT1_PIXEL_ERR0 << n))
img->err_cnt.pix_err++;
if (value1 & (CSI_INT1_OVERFLOW0 << n))
img->err_cnt.overflow++;
if (value1 & (CSI_INT1_IMG0_BUSERR0 << n))
img->err_cnt.stream0_err++;
if (value1 & (CSI_INT1_IMG0_BUSERR1 << n))
img->err_cnt.stream1_err++;
if (value1 & (CSI_INT1_IMG0_BUSERR2 << n))
img->err_cnt.stream2_err++;
}
csi_err("%s, csi%d img%d error. int0=0x%08x, int1=0x%08x\n", __func__,
img->core->host_id, img->id, value0, value1);
csi_err("frm_cnt %d, bt_err %d, bt_fatal %d, crop_err %d, pix_err %d, "
"overflow %d\n",
img->frm_cnt, img->err_cnt.bt_err, img->err_cnt.bt_fatal,
img->err_cnt.crop_err, img->err_cnt.pix_err, img->err_cnt.overflow);
}
/* ============================== external API below
* ===================================== */
/* ============== following interface for csi_image ================== */
int csi_reset_img(struct csi_hw_dev *csi_dev, uint32_t img_id, uint32_t cmd)
{
int n = img_id;
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
CSI_IMG_ERR_RETURN(csi_dev, img_id, &cmd);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
if (cmd | CSI_RESET_IMG_HW) {
csi_set(csi_core, CSI_REG_ENABLE, (1 << n), (1 << n));
usleep_range(2, 10);
csi_set(csi_core, CSI_REG_ENABLE, (1 << n), 0);
}
if (cmd | CSI_RESET_IMG_CTX) {
memset(img, 0, sizeof(struct csi_img_internal));
spin_lock_init(&img->status_lock);
spin_lock_init(&img->crop_lock);
img->core = csi_core;
img->id = n;
}
csi_info("%s, csi%d img%d reset cmd 0x%x done\n", __func__,
img->core->host_id, img->id, cmd);
return 0;
}
int csi_register_callback(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct csi_callback_t *cb)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
CSI_IMG_ERR_RETURN(csi_dev, img_id, cb);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
memcpy(&img->irq_cb, cb, sizeof(struct csi_callback_t));
csi_info("%s, csi%d img%d done\n", __func__, img->core->host_id, img->id);
return 0;
}
int csi_cfg_bus(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct csi_bus_info *bus)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
CSI_IMG_ERR_RETURN(csi_dev, img_id, bus);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
img->bus_type = bus->bus_type;
img->bus_fmt = bus->mbus_fmt;
img->bus_flag = bus->bus_flag;
csi_info("%s, csi%d, img%d, bus type %d bus_fmt %d, bus_flag 0x%x\n",
__func__, csi_core->host_id, img_id, img->bus_type, img->bus_fmt,
img->bus_flag);
return 0;
}
int csi_query_outfmts(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct csi_outfmt_info *fmt)
{
int i, total;
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
const struct csi_format_pack *fmt_pack;
CSI_IMG_ERR_RETURN(csi_dev, img_id, fmt);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
if (img->bus_type == CSI_BUS_MIPICSI2) {
fmt_pack = &csi_mipi_fmts[0];
total = sizeof(csi_mipi_fmts) / sizeof(csi_mipi_fmts[0]);
} else {
fmt_pack = &csi_parallel_fmts[0];
total = sizeof(csi_parallel_fmts) / sizeof(csi_parallel_fmts[0]);
}
fmt->count = 0;
for (i = 0; i < total; i++, fmt_pack++) {
if (fmt_pack->bus_fmt != img->bus_fmt)
continue;
fmt->fmts[fmt->count] = fmt_pack->output_fmt;
fmt->count++;
csi_info("%s, csi%d, img%d, bus type %d bus_fmt %d, outfmt%d: 0x%08x\n",
__func__, csi_core->host_id, img_id, img->bus_type,
img->bus_fmt, fmt->count, fmt_pack->output_fmt);
}
return 0;
}
int csi_cfg_outfmt(struct csi_hw_dev *csi_dev, uint32_t img_id, uint32_t outfmt)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
CSI_IMG_ERR_RETURN(csi_dev, img_id, &outfmt);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
img->output_fmt = outfmt;
csi_info("%s, csi%d, img%d, output fmt %d\n", __func__, csi_core->host_id,
img_id, img->output_fmt);
return 0;
}
int csi_cfg_field(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct csi_field_info *field)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
CSI_IMG_ERR_RETURN(csi_dev, img_id, field);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
img->field = field->field_type;
csi_info("%s, csi%d, img%d, field_type %d\n", __func__, csi_core->host_id,
img_id, img->field);
return 0;
}
int csi_cfg_size(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct csi_img_size *size)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
CSI_IMG_ERR_RETURN(csi_dev, img_id, size);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
img->size[0] = size[0];
img->size[1] = size[1];
csi_info("%s, csi%d, img%d, size0[ %d x %d ], size1[ %d x %d ]\n", __func__,
csi_core->host_id, img_id, size[0].w, size[0].h, size[1].w,
size[1].h);
return 0;
}
int csi_cfg_crop(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct csi_img_crop *crop)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
unsigned long flags = 0;
CSI_IMG_ERR_RETURN(csi_dev, img_id, crop);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
csi_info("%s, csi%d, img%d, crop0[%d %d %d %d], crop1[%d %d %d %d]\n",
__func__, csi_core->host_id, img_id, crop[0].x, crop[0].y,
crop[0].w, crop[0].h, crop[1].x, crop[1].y, crop[1].w, crop[1].h);
if (img->status != IMG_STATUS_STREAM_ON) {
img->crop[0] = crop[0];
img->crop[1] = crop[1];
return 0;
}
if (((crop[0].x + crop[0].w) > img->size[0].w) ||
((crop[0].y + crop[0].h) > img->size[0].h) || (crop[0].w == 0) ||
(crop[0].h == 0)) {
csi_info("%s, csi%d, img%d, error crop0[%d %d %d %d]\n", __func__,
csi_core->host_id, img_id, crop[0].x, crop[0].y, crop[0].w,
crop[0].h);
return -1;
}
spin_lock_irqsave(&img->crop_lock, flags);
if (img->crop_update == 0) {
/* make sure previous setting is update to register. */
img->crop_update = (img->crop[0].x ^ crop[0].x);
img->crop_update |= (img->crop[0].y ^ crop[0].y);
img->crop_update |= (img->crop[0].w ^ crop[0].w);
img->crop_update |= (img->crop[0].h ^ crop[0].h);
if (img->crop_update)
img->crop[0] = crop[0];
}
spin_unlock_irqrestore(&img->crop_lock, flags);
return 0;
}
int csi_cfg_img_buf(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct csi_img_buf *buf)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
int i, n = img_id;
uint32_t addr_l[3], addr_h[3];
CSI_IMG_ERR_RETURN(csi_dev, img_id, buf);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
img->next_buf = *buf;
if (csi_core->sync && img_id != CSI_IMG0) {
csi_err("%s: invalid img_id %d for sync mode\n\n", __func__, img_id);
return -1;
}
if (img->pfmt == NULL) {
csi_err("csi img%d is not stream on\n", img_id);
return 0;
}
for (i = 0; i < img->pfmt->planes; i++) {
uint32_t *ptr_u32 = (uint32_t *)&buf->paddr[i];
addr_l[i] = ptr_u32[0];
addr_h[i] = (is_addr_64bit ? ptr_u32[1] : 0);
reg_write(csi_core->base, CSI_REG_IMG_RGBY_BADDR_H(n) + i * 8,
addr_h[i]);
reg_write(csi_core->base, CSI_REG_IMG_RGBY_BADDR_L(n) + i * 8,
addr_l[i]);
}
/* shadow_set_n*/
csi_set(csi_core, CSI_REG_REG_LOAD, (1 << n), (1 << n));
if (!csi_core->sync || img->status != IMG_STATUS_STREAM_ON)
return 0;
/* if sync mode and is stream on, img1~3 buffer should be updated as well */
for (n = CSI_IMG1; n <= CSI_IMG3; n++)
csi_img_set_sync_buf(&csi_core->images[n], buf);
return 0;
}
int csi_cfg_mem_range(struct csi_hw_dev *csi_dev, uint32_t img_id,
struct mem_range *mem)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
CSI_IMG_ERR_RETURN(csi_dev, img_id, mem);
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
img->fb_mode = FB_MODE_ROUND;
memcpy(img->round_mem, mem, sizeof(img->round_mem));
csi_info("%s, csi%d, img%d, mem [0x%08x 0x%08x], [0x%08x 0x%08x], [0x%08x "
"0x%08x]\n",
__func__, csi_core->host_id, img_id, mem[0].low, mem[0].up,
mem[1].low, mem[1].up, mem[2].low, mem[2].up);
return 0;
}
void show_csi_regs(struct csi_core_internal *csi_core)
{
uint32_t i, val;
csi_info("Not show zero value register\n");
for (i = 0; i < 0x8A0; i += 4) {
val = reg_read(csi_core->base, i);
if (val)
csi_info("[0x%08x]:0x%x\n", (uint32_t)(csi_core->base + i), val);
}
}
int csi_stream_on(struct csi_hw_dev *csi_dev, uint32_t img_id)
{
int ret;
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
if ((csi_dev == NULL) || (img_id >= CSI_IMG_NUM)) {
csi_err("%s: failed to get csi_dev %p, img_id %d\n", __func__, csi_dev,
img_id);
return -1;
}
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
img = &csi_core->images[img_id];
ret = csi_img_setup_param(img);
if (ret) {
csi_err("%s: csi%d, img_id %d failed to setup param\n", __func__,
csi_core->host_id, img_id);
return -1;
}
ret = csi_img_set_regs(img);
if (ret) {
csi_err("%s: csi%d, img_id %d failed to stream on\n", __func__,
csi_core->host_id, img_id);
return -1;
}
show_csi_regs(csi_core);
memset(&img->err_cnt, 0, sizeof(struct csi_img_err_cnt));
img->frm_cnt = 0;
img->shadow_cnt = 0;
img->status = IMG_STATUS_STREAM_ON;
return 0;
}
int csi_stream_off(struct csi_hw_dev *csi_dev, uint32_t img_id)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
int n, img_s, img_e;
unsigned long flags = 0;
if ((csi_dev == NULL) || (img_id >= CSI_IMG_NUM)) {
csi_err("%s: failed to get csi_dev %p, img_id %d\n", __func__, csi_dev,
img_id);
return -1;
}
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
if (csi_core->sync == 0) {
img_s = img_id;
img_e = img_id;
} else {
img_s = CSI_IMG0;
img_e = CSI_IMG3;
}
for (n = img_s; n <= img_e; n++) {
img = &csi_core->images[n];
spin_lock_irqsave(&img->status_lock, flags);
/* disable stream */
csi_set(csi_core, CSI_REG_ENABLE, (1 << n), 0);
/* disable irq */
csi_set(csi_core, CSI_REG_INT_MASK0, INT0_MASK(n), 0);
csi_set(csi_core, CSI_REG_INT_MASK1, INT1_ERR_MASK(n), 0);
csi_set(csi_core, CSI_REG_REG_LOAD, (1 << (4 + n)), (1 << (4 + n)));
img->status = IMG_STATUS_IDLE;
spin_unlock_irqrestore(&img->status_lock, flags);
}
return 0;
}
/* ================ following interface for csi_core =============== */
int csi_cfg_sync(struct csi_hw_dev *csi_dev, uint32_t sync)
{
struct csi_core_internal *csi_core;
if (csi_dev == NULL || csi_dev->host_id >= CSI_HOST_NUM) {
csi_err("%s: fail to get input csi dev %p\n", __func__, csi_dev);
return -1;
}
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
csi_core->sync = !!sync;
csi_info("%s: csi%d sync_mode %d\n", __func__, csi_core->host_id,
csi_core->sync);
return 0;
}
int csi_irq_handle(struct csi_hw_dev *csi_dev)
{
struct csi_core_internal *csi_core;
struct csi_img_internal *img;
int i, is_err;
uint32_t value0, value1;
unsigned long flags = 0;
if (csi_dev == NULL) {
csi_err("%s: failed to get csi_dev %p\n", __func__, csi_dev);
return -1;
}
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
value0 = reg_read(csi_core->base, CSI_REG_INT_STAT0);
value1 = reg_read(csi_core->base, CSI_REG_INT_STAT1);
reg_write(csi_core->base, CSI_REG_INT_STAT0, value0);
reg_write(csi_core->base, CSI_REG_INT_STAT1, value1);
csi_debug("int: value 0x%08x 0x%08x, sync %d\n", value0, value1,
csi_core->sync);
if (csi_core->sync) {
img = &csi_core->images[0];
spin_lock_irqsave(&img->status_lock, flags);
if (img->status != IMG_STATUS_STREAM_ON) {
spin_unlock_irqrestore(&img->status_lock, flags);
return 0;
}
/* [0:3] - img store done, [4:7] - img shadow done */
csi_core->sync_irq |= (value0 & 0xff);
if ((csi_core->sync_irq & 0x0f) == 0x0f) {
if (img->irq_cb.csi_frame_done)
img->irq_cb.csi_frame_done(img->irq_cb.caller, img->id);
csi_core->sync_irq &= 0xf0;
img->frm_cnt++;
}
if ((csi_core->sync_irq & 0xf0) == 0xf0) {
if (img->irq_cb.csi_update_buf)
img->irq_cb.csi_update_buf(img->irq_cb.caller, img->id);
csi_core->sync_irq &= 0x0f;
}
if ((img->frm_cnt > 1) &&
((value0 & INT0_ERR_MASK_ALL) || (value1 & INT1_ERR_MASK_ALL))) {
if (img->irq_cb.csi_error_handle)
img->irq_cb.csi_error_handle(img->irq_cb.caller, img->id);
csi_err_handle(img, 1, value0, value1);
}
spin_unlock_irqrestore(&img->status_lock, flags);
} else {
for (i = CSI_IMG0; i <= CSI_IMG3; i++) {
img = &csi_core->images[i];
spin_lock_irqsave(&img->status_lock, flags);
if (img->status != IMG_STATUS_STREAM_ON) {
spin_unlock_irqrestore(&img->status_lock, flags);
continue;
}
csi_debug("int: img%d status %d proc \n", img->id, img->status);
is_err = value0 & INT0_ERR_MASK(i);
is_err |= (value1 & INT1_ERR_MASK(i));
if (value0 & (CSI_INT0_STORE_DONE0 << i)) {
csi_debug("int: img%d status %d csi_frame_done %p\n", img->id,
img->status, img->irq_cb.csi_frame_done);
if (img->shadow_cnt && !is_err && img->irq_cb.csi_frame_done) {
img->irq_cb.csi_frame_done(img->irq_cb.caller, img->id);
}
if (img->frm_cnt < 5)
csi_info("frame_done: %d\n", img->frm_cnt);
img->frm_cnt++;
}
if (value0 & (CSI_INT0_SHADOW_SET0 << i)) {
if (FIELD_HAS_BOTH(img->field) && img->second_field == 0) {
img->second_field = 1;
csi_img_set_field_buf(img, &img->next_buf);
} else if (!is_err && img->irq_cb.csi_update_buf) {
img->second_field = 0;
csi_debug("int: img%d updata buf caller %p\n", img->id,
img->irq_cb.caller);
img->irq_cb.csi_update_buf(img->irq_cb.caller, img->id);
}
spin_lock_irqsave(&img->crop_lock, flags);
if (img->crop_update) {
csi_img_set_crop(img);
csi_set(csi_core, CSI_REG_REG_LOAD, (1 << i), (1 << i));
img->crop_update = 0;
}
spin_unlock_irqrestore(&img->crop_lock, flags);
if (img->shadow_cnt < 5)
csi_info("shadow_done: %d\n", img->shadow_cnt);
img->shadow_cnt++;
}
if ((img->frm_cnt > 1) && is_err) {
if (img->irq_cb.csi_error_handle)
img->irq_cb.csi_error_handle(img->irq_cb.caller, img->id);
csi_err_handle(img, 0, value0, value1);
}
spin_unlock_irqrestore(&img->status_lock, flags);
}
}
return 0;
}
const struct csi_hw_operations csi_ops = {
.csi_irq_handle = csi_irq_handle,
.csi_cfg_sync = csi_cfg_sync,
.csi_reset_img = csi_reset_img,
.csi_register_callback = csi_register_callback,
.csi_cfg_bus = csi_cfg_bus,
.csi_query_outfmts = csi_query_outfmts,
.csi_cfg_outfmt = csi_cfg_outfmt,
.csi_cfg_field = csi_cfg_field,
.csi_cfg_size = csi_cfg_size,
.csi_cfg_crop = csi_cfg_crop,
.csi_cfg_img_buf = csi_cfg_img_buf,
.csi_cfg_mem_range = csi_cfg_mem_range,
.csi_stream_on = csi_stream_on,
.csi_stream_off = csi_stream_off,
};
struct csi_hw_dev *csi_hw_init(reg_addr_t base, uint32_t host_id)
{
struct csi_core_internal *csi_core;
int i;
if (host_id >= CSI_HOST_NUM) {
csi_err("%s: error input csi host id %d, should be 0~2\n", __func__,
host_id);
return NULL;
}
csi_core = &csi_cores[host_id];
if (csi_core->inited) {
csi_warn("%s: csi%d is already inited\n", __func__, host_id);
return &csi_core->ex_dev;
}
for (i = 0; i < CSI_IMG_NUM; i++) {
csi_core->images[i].id = i;
csi_core->images[i].core = csi_core;
spin_lock_init(&csi_core->images[i].status_lock);
spin_lock_init(&csi_core->images[i].crop_lock);
}
spin_lock_init(&csi_core->glb_reg_lock);
csi_core->base = base;
/* global reset */
reg_write(csi_core->base, CSI_REG_ENABLE, (1 << 8));
usleep_range(2, 10);
reg_write(csi_core->base, CSI_REG_ENABLE, 0);
csi_core->ex_dev.priv_data = (void *)csi_core;
csi_core->ex_dev.ops = csi_ops;
csi_core->inited = 1;
csi_info("%s: csi%d init done. ver %d\n", __func__,
host_id, csi_core->ip_version);
return &csi_core->ex_dev;
}
int csi_hw_deinit(struct csi_hw_dev *csi_dev)
{
struct csi_core_internal *csi_core;
if (csi_dev == NULL) {
csi_err("%s: NULL input csi dev\n", __func__);
return -1;
}
if (csi_dev->host_id >= CSI_HOST_NUM) {
csi_err("%s: error input csi dev host_id %d\n", __func__,
csi_dev->host_id);
return -1;
}
csi_core = (struct csi_core_internal *)csi_dev->priv_data;
/* global reset */
reg_write(csi_core->base, CSI_REG_ENABLE, (1 << 8));
usleep_range(2, 10);
reg_write(csi_core->base, CSI_REG_ENABLE, 0);
csi_core->inited = 0;
csi_info("%s: csi%d deinit done\n", __func__, csi_core->host_id);
return 0;
}