增加所有文件
This commit is contained in:
889
drivers/source/camera/csi-baremetal/csi_drv/csi_drv.c
Normal file
889
drivers/source/camera/csi-baremetal/csi_drv/csi_drv.c
Normal file
@@ -0,0 +1,889 @@
|
||||
/*
|
||||
* csi_drv.c
|
||||
*
|
||||
* Copyright (c) 2021 Semidrive Semiconductor.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Description: csi controller driver (system adaptive)
|
||||
*
|
||||
* Revision History:
|
||||
* -----------------
|
||||
*/
|
||||
#include "camera/sdrv-cam-baremetal-def.h"
|
||||
#include "camera/vdev_defs.h"
|
||||
#include "csi_drv.h"
|
||||
#include "csi_hw.h"
|
||||
|
||||
#define MAX_CSI_INST CONFIG_CSI_NUM
|
||||
#define MAX_CSI_CHANNEL CONFIG_CSI_CH_NUM
|
||||
#define MAX_BUF_CNT 16
|
||||
#define MAX_QLEN 1
|
||||
#define SKIP_FRAME_NUM (1 << 0)
|
||||
|
||||
enum channel_status {
|
||||
STOPPED,
|
||||
RUNNING,
|
||||
IDLE,
|
||||
};
|
||||
|
||||
#define CHECK_CSI_ID_CH(id, ch) \
|
||||
do { \
|
||||
if ((id >= MAX_CSI_INST) || (ch >= MAX_CSI_CHANNEL)) { \
|
||||
cam_err("%s: error id %d\n", __func__, id); \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct camera_device;
|
||||
|
||||
struct camera_buffer {
|
||||
struct list_node list;
|
||||
uint32_t buffer_idx;
|
||||
uint32_t frm_cnt;
|
||||
uint32_t timestamp;
|
||||
dma_addr_t paddr[3];
|
||||
};
|
||||
|
||||
struct cam_queue {
|
||||
int qlen;
|
||||
struct list_node qhead;
|
||||
};
|
||||
static struct camera_buffer s_buffers[MAX_CSI_INST][MAX_CSI_CHANNEL]
|
||||
[MAX_BUF_CNT];
|
||||
|
||||
struct camera_channel {
|
||||
struct camera_device *host;
|
||||
uint32_t ch_id;
|
||||
uint32_t enable;
|
||||
uint32_t status;
|
||||
uint32_t frm_cnt;
|
||||
uint32_t update_cnt;
|
||||
|
||||
struct camera_buffer *bufs;
|
||||
struct list_node empty;
|
||||
|
||||
struct list_node in_bufq;
|
||||
struct list_node out_bufq;
|
||||
struct cam_queue active_q;
|
||||
struct camera_buffer *next_buf;
|
||||
completion_t completion;
|
||||
spinlock_t bufq_lock;
|
||||
|
||||
struct mem_range cam_mem[3];
|
||||
|
||||
struct csi_ch_params cfg;
|
||||
};
|
||||
|
||||
struct camera_device {
|
||||
uint32_t host_id; /* host ip id */
|
||||
struct csi_device ex_dev;
|
||||
|
||||
struct csi_hw_dev *csi_hw;
|
||||
uint32_t csi_irq;
|
||||
reg_addr_t csi_base;
|
||||
uint32_t bt; /* bus type */
|
||||
uint32_t sync;
|
||||
struct camera_channel cam_ch[MAX_CSI_CHANNEL];
|
||||
};
|
||||
|
||||
struct csi_channel_ops ch_ops;
|
||||
static struct camera_device s_cam_devices[MAX_CSI_INST];
|
||||
|
||||
#ifdef _CONFIG_OS_SAFETY_
|
||||
static enum handler_return camera_int_handler(void *data)
|
||||
{
|
||||
enum handler_return ret = INT_NO_RESCHEDULE;
|
||||
struct camera_device *cam_dev = (struct camera_device *)data;
|
||||
|
||||
cam_dev->csi_hw->ops.csi_irq_handle(cam_dev->csi_hw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t get_irq(uint32_t id)
|
||||
{
|
||||
if (id == CSI_HOST_0)
|
||||
return CSI1_INTERRUPT_NUM;
|
||||
else if (id == CSI_HOST_1)
|
||||
return CSI2_INTERRUPT_NUM;
|
||||
else
|
||||
return CSI3_INTERRUPT_NUM;
|
||||
}
|
||||
|
||||
static reg_addr_t get_reg_base(uint32_t id)
|
||||
{
|
||||
uint32_t res;
|
||||
int32_t ret, res_index = 0;
|
||||
addr_t phy_addr = 0;
|
||||
|
||||
if (id == CSI_HOST_0)
|
||||
res = RES_CSI_CSI1;
|
||||
else if (id == CSI_HOST_1)
|
||||
res = RES_CSI_CSI2;
|
||||
else
|
||||
res = RES_CSI_CSI3;
|
||||
|
||||
ret = res_get_info_by_id(res, &phy_addr, &res_index);
|
||||
if (ret < 0) {
|
||||
cam_err("%s: get resource 0x%x fail, csi_id=%d, ret=%d\n", __func__,
|
||||
res, id, ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cam_info("%s: csi%d, base 0x%lx\n", __func__, id, (unsigned long)phy_addr);
|
||||
return (reg_addr_t)phy_addr;
|
||||
}
|
||||
|
||||
#else /* _CONFIG_OS_SSDK_ */
|
||||
|
||||
#define get_irq(id) CSI_INTR_NUM
|
||||
#define get_reg_base(id) APB_CSI_BASE
|
||||
|
||||
static int camera_int_handler(uint32_t irq, void *data)
|
||||
{
|
||||
struct camera_device *cam_dev = (struct camera_device *)data;
|
||||
cam_debug("camera_int_handler: enter irq: %d\n", irq);
|
||||
cam_dev->csi_hw->ops.csi_irq_handle(cam_dev->csi_hw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_int_handler(uint32_t irq, irq_handler handler, void *data)
|
||||
{
|
||||
irq_attach(irq, handler, data);
|
||||
irq_enable(irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t to_vdev_pixfmt(uint32_t csi_pix_fmt)
|
||||
{
|
||||
switch (csi_pix_fmt) {
|
||||
case CSI_FMT_YUYV:
|
||||
return VDEV_PIX_FMT_YUYV;
|
||||
|
||||
case CSI_FMT_UYVY:
|
||||
return VDEV_PIX_FMT_UYVY;
|
||||
|
||||
case CSI_FMT_NV16:
|
||||
return VDEV_PIX_FMT_NV16;
|
||||
|
||||
case CSI_FMT_NV61:
|
||||
return VDEV_PIX_FMT_NV61;
|
||||
|
||||
case CSI_FMT_YUV422P:
|
||||
return VDEV_PIX_FMT_YUV422P;
|
||||
|
||||
case CSI_FMT_RGB24:
|
||||
return VDEV_PIX_FMT_RGB24;
|
||||
|
||||
case CSI_FMT_BGR24:
|
||||
return VDEV_PIX_FMT_BGR24;
|
||||
|
||||
case CSI_FMT_RGB16:
|
||||
return VDEV_PIX_FMT_RGB16;
|
||||
|
||||
default:
|
||||
; // return VDEV_PIX_FMT_UYVY;
|
||||
}
|
||||
|
||||
return VDEV_PIX_FMT_UYVY;
|
||||
}
|
||||
|
||||
static uint32_t to_csi_pixfmt(uint32_t vdev_pix_fmt)
|
||||
{
|
||||
switch (vdev_pix_fmt) {
|
||||
case VDEV_PIX_FMT_YUYV:
|
||||
return CSI_FMT_YUYV;
|
||||
|
||||
case VDEV_PIX_FMT_UYVY:
|
||||
return CSI_FMT_UYVY;
|
||||
|
||||
case VDEV_PIX_FMT_NV16:
|
||||
return CSI_FMT_NV16;
|
||||
|
||||
case VDEV_PIX_FMT_NV61:
|
||||
return CSI_FMT_NV61;
|
||||
|
||||
case VDEV_PIX_FMT_YUV422P:
|
||||
return CSI_FMT_YUV422P;
|
||||
|
||||
case VDEV_PIX_FMT_RGB24:
|
||||
return CSI_FMT_RGB24;
|
||||
|
||||
case VDEV_PIX_FMT_BGR24:
|
||||
return CSI_FMT_BGR24;
|
||||
|
||||
case VDEV_PIX_FMT_RGB16:
|
||||
return CSI_FMT_RGB16;
|
||||
|
||||
default:
|
||||
; // return CSI_FMT_UYVY;
|
||||
}
|
||||
|
||||
return CSI_FMT_UYVY;
|
||||
}
|
||||
|
||||
static int camera_frame_done(void *caller, uint32_t ch)
|
||||
{
|
||||
struct camera_channel *pch = (struct camera_channel *)caller;
|
||||
struct camera_device *cam_dev = pch->host;
|
||||
struct list_node *node;
|
||||
struct camera_buffer *pbuf;
|
||||
unsigned long flags = 0;
|
||||
|
||||
#ifdef TEST_CAM_FPS
|
||||
static uint64_t time_last, time_cur;
|
||||
time_cur = current_time_hires();
|
||||
if (pch->frm_cnt == 0)
|
||||
time_last = time_cur;
|
||||
if ((pch->frm_cnt & 0x1f) == 0x1f) {
|
||||
uint64_t fps_1_us = 32000000000000ul / (time_cur - time_last);
|
||||
cam_info("frm_cnt %d, cam_fps: %llu.%06llu\n", pch->frm_cnt,
|
||||
fps_1_us / 1000000, fps_1_us % 1000000);
|
||||
time_last = time_cur;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pch->status == STOPPED) {
|
||||
pch->frm_cnt++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pch->active_q.qlen == 0) {
|
||||
if (pch->status == RUNNING)
|
||||
cam_err("csi%d img%d, active_q empty\n", cam_dev->host_id, ch);
|
||||
pch->frm_cnt++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pch->active_q.qlen > MAX_QLEN)
|
||||
cam_err("csi%d img%d, active_q full\n", cam_dev->host_id, ch);
|
||||
|
||||
spin_lock_irqsave(&pch->bufq_lock, flags);
|
||||
|
||||
node = list_peek_head(&pch->active_q.qhead);
|
||||
list_delete(node);
|
||||
pch->active_q.qlen--;
|
||||
|
||||
if (pch->frm_cnt < SKIP_FRAME_NUM) {
|
||||
list_add_tail(&pch->in_bufq, node);
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
pch->frm_cnt++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pbuf = containerof(node, struct camera_buffer, list);
|
||||
pbuf->timestamp = pch->frm_cnt * 10; /* TODO: get_systime(); */
|
||||
pbuf->frm_cnt = pch->frm_cnt;
|
||||
list_add_tail(&pch->out_bufq, &pbuf->list);
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
|
||||
completion_done(&pch->completion);
|
||||
|
||||
cam_debug("%s, csi%d img%d, frm_cnt %d, buf_idx %d\n", __func__,
|
||||
cam_dev->host_id, ch, pch->frm_cnt, pbuf->buffer_idx);
|
||||
|
||||
pch->frm_cnt++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int camera_update_buf(void *caller, uint32_t ch)
|
||||
{
|
||||
struct camera_channel *pch = (struct camera_channel *)caller;
|
||||
struct camera_device *cam_dev = pch->host;
|
||||
struct list_node *node;
|
||||
struct camera_buffer *pbuf;
|
||||
struct csi_img_buf buf;
|
||||
unsigned long flags = 0;
|
||||
|
||||
pch->update_cnt++;
|
||||
if (pch->status == STOPPED)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&pch->bufq_lock, flags);
|
||||
node = list_peek_head(&pch->in_bufq);
|
||||
if (node == NULL) {
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
if (pch->status == RUNNING) {
|
||||
pch->status = IDLE;
|
||||
cam_debug("ch %d vbuf_list is empty\n", ch);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
pch->status = RUNNING;
|
||||
|
||||
if (pch->active_q.qlen >= MAX_QLEN) {
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
cam_err("csi%d img%d, active_q overflow\n", cam_dev->host_id, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pch->next_buf) {
|
||||
pbuf = pch->next_buf;
|
||||
list_add_tail(&pch->active_q.qhead, &pbuf->list);
|
||||
pch->active_q.qlen++;
|
||||
pch->next_buf = NULL;
|
||||
}
|
||||
|
||||
list_delete(node);
|
||||
pbuf = containerof(node, struct camera_buffer, list);
|
||||
pch->next_buf = pbuf;
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
|
||||
buf.paddr[0] = pbuf->paddr[0];
|
||||
buf.paddr[1] = pbuf->paddr[1];
|
||||
buf.paddr[2] = pbuf->paddr[2];
|
||||
cam_dev->csi_hw->ops.csi_cfg_img_buf(cam_dev->csi_hw, ch, &buf);
|
||||
|
||||
cam_debug("%s, csi%d img%d, done\n", __func__, cam_dev->host_id, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int camera_error_handle(void *caller, uint32_t ch)
|
||||
{
|
||||
struct camera_channel *pch = (struct camera_channel *)caller;
|
||||
struct camera_device *cam_dev = pch->host;
|
||||
|
||||
cam_err("%s, csi%d img%d, error\n", __func__, cam_dev->host_id, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct csi_device *camera_dev_init(uint32_t id)
|
||||
{
|
||||
int i;
|
||||
struct camera_device *cam_dev;
|
||||
|
||||
if (id >= MAX_CSI_INST) {
|
||||
cam_err("%s: error id %d\n", __func__, id);
|
||||
return NULL;
|
||||
}
|
||||
cam_dev = &s_cam_devices[id];
|
||||
cam_dev->host_id = id;
|
||||
cam_dev->csi_irq = get_irq(id);
|
||||
cam_dev->csi_base = (reg_addr_t)get_reg_base(id);
|
||||
cam_dev->bt = 1;
|
||||
cam_dev->sync = 0;
|
||||
cam_err("csi%d init: irq %d, reg_base 0x%08x\n", id, cam_dev->csi_irq,
|
||||
(uint32_t)cam_dev->csi_base);
|
||||
|
||||
cam_dev->csi_hw = (void *)csi_hw_init(cam_dev->csi_base, id);
|
||||
if (cam_dev->csi_hw == NULL) {
|
||||
cam_err("%s: faile to init csi_hw\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cam_dev->csi_hw->ops.csi_cfg_sync(cam_dev->csi_hw, cam_dev->sync);
|
||||
|
||||
cam_info("enalbe irq: %d\n", cam_dev->csi_irq);
|
||||
register_int_handler(cam_dev->csi_irq, camera_int_handler, cam_dev);
|
||||
|
||||
for (i = 0; i < MAX_CSI_CHANNEL; i++) {
|
||||
cam_dev->cam_ch[i].ch_id = i;
|
||||
cam_dev->cam_ch[i].host = cam_dev;
|
||||
spin_lock_init(&cam_dev->cam_ch[i].bufq_lock);
|
||||
}
|
||||
|
||||
cam_dev->ex_dev.ops = ch_ops;
|
||||
|
||||
cam_info("%s: done\n", __func__);
|
||||
return &cam_dev->ex_dev;
|
||||
}
|
||||
|
||||
static int channel_open(uint32_t id, uint32_t ch)
|
||||
{
|
||||
int i;
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
struct camera_buffer *pbuf;
|
||||
struct csi_callback_t cb;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
cam_dev->csi_hw->ops.csi_reset_img(cam_dev->csi_hw, ch,
|
||||
CSI_RESET_IMG_CTX | CSI_RESET_IMG_HW);
|
||||
|
||||
list_initialize(&pch->empty);
|
||||
pch->bufs = &s_buffers[id][ch][0];
|
||||
memset(pch->bufs, 0, sizeof(struct camera_buffer) * MAX_BUF_CNT);
|
||||
for (i = 0, pbuf = pch->bufs; i < MAX_BUF_CNT; i++, pbuf++) {
|
||||
list_add_tail(&pch->empty, &pbuf->list);
|
||||
}
|
||||
|
||||
list_initialize(&pch->out_bufq);
|
||||
list_initialize(&pch->in_bufq);
|
||||
list_initialize(&pch->active_q.qhead);
|
||||
pch->active_q.qlen = 0;
|
||||
pch->next_buf = NULL;
|
||||
completion_init(&pch->completion);
|
||||
|
||||
pch->cfg.bus_type = CSI_BUS_PARALLEL2;
|
||||
pch->cfg.bus_fmt = CSI_MBUS_UYVY8_2X8;
|
||||
pch->cfg.width = 1920;
|
||||
pch->cfg.height = 1080;
|
||||
pch->cfg.crop_en = 0;
|
||||
pch->cfg.set_pix_fmt = CSI_FMT_UYVY;
|
||||
pch->cfg.pix_fmt_num = 1;
|
||||
pch->cfg.pix_fmt[0] = CSI_FMT_UYVY;
|
||||
|
||||
memset(&cb, 0, sizeof(struct csi_callback_t));
|
||||
cb.caller = (void *)pch;
|
||||
cb.csi_frame_done = camera_frame_done;
|
||||
cb.csi_update_buf = camera_update_buf;
|
||||
cb.csi_error_handle = camera_error_handle;
|
||||
cam_info("csi_register_callback: caller %p, done %p\n", cb.caller,
|
||||
cb.csi_frame_done);
|
||||
|
||||
cam_dev->csi_hw->ops.csi_register_callback(cam_dev->csi_hw, ch, &cb);
|
||||
|
||||
pch->enable = 1;
|
||||
pch->status = STOPPED;
|
||||
cam_info("%s: ch %d done\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_close(uint32_t id, uint32_t ch)
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
pch->enable = 0;
|
||||
pch->status = STOPPED;
|
||||
completion_destroy(&pch->completion);
|
||||
|
||||
cam_info("%s: ch %d done\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_cfg_bus_type(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param)
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
switch (param->bus_type) {
|
||||
case VDEV_MBUS_PARALLEL:
|
||||
case VDEV_MBUS_CSI1:
|
||||
pch->cfg.bus_type = CSI_BUS_PARALLEL4;
|
||||
break;
|
||||
case VDEV_MBUS_PARALLEL2:
|
||||
pch->cfg.bus_type = CSI_BUS_PARALLEL2;
|
||||
break;
|
||||
case VDEV_MBUS_BT656:
|
||||
pch->cfg.bus_type = CSI_BUS_BT656;
|
||||
break;
|
||||
case VDEV_MBUS_BT1120SDR:
|
||||
pch->cfg.bus_type = CSI_BUS_BT1120_SDR;
|
||||
break;
|
||||
default:
|
||||
cam_err("%s: error vdev bus type %d\n", __func__, param->bus_type);
|
||||
break;
|
||||
}
|
||||
|
||||
cam_info("%s: ch %d ,bus %d ,done\n", __func__, ch, pch->cfg.bus_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_cfg_bus_fmt(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param)
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
switch (param->bus_fmt) {
|
||||
case VDEV_MBUS_FMT_UYVY:
|
||||
pch->cfg.bus_fmt = CSI_MBUS_UYVY8_2X8;
|
||||
break;
|
||||
|
||||
case VDEV_MBUS_FMT_YUYV:
|
||||
pch->cfg.bus_fmt = CSI_MBUS_YUYV8_2X8;
|
||||
break;
|
||||
|
||||
case VDEV_MBUS_FMT_UYVY16:
|
||||
pch->cfg.bus_fmt = CSI_MBUS_UYVY8_1X16;
|
||||
break;
|
||||
|
||||
case VDEV_MBUS_FMT_YUYV16:
|
||||
pch->cfg.bus_fmt = CSI_MBUS_YUYV8_1X16;
|
||||
break;
|
||||
|
||||
case VDEV_MBUS_FMT_RGB888:
|
||||
pch->cfg.bus_fmt = CSI_MBUS_RGB888_1X24;
|
||||
break;
|
||||
|
||||
case VDEV_MBUS_FMT_RGB24:
|
||||
pch->cfg.bus_fmt = CSI_MBUS_RGB24_1X24;
|
||||
break;
|
||||
|
||||
case VDEV_MBUS_FMT_BGR24:
|
||||
pch->cfg.bus_fmt = CSI_MBUS_BGR24_1X24;
|
||||
break;
|
||||
|
||||
case VDEV_MBUS_FMT_RGB565:
|
||||
pch->cfg.bus_fmt = CSI_MBUS_RGB565_1X16;
|
||||
break;
|
||||
|
||||
default:
|
||||
cam_err("%s: error vdev bus fmt %d\n", __func__, param->bus_fmt);
|
||||
break;
|
||||
}
|
||||
|
||||
cam_info("%s: ch %d %d done\n", __func__, ch, pch->cfg.bus_fmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_enum_pixfmt(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param)
|
||||
{
|
||||
int ret;
|
||||
uint32_t i;
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
struct csi_bus_info bus_info;
|
||||
struct csi_outfmt_info res;
|
||||
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
bus_info.bus_type = pch->cfg.bus_type;
|
||||
bus_info.mbus_fmt = pch->cfg.bus_fmt;
|
||||
bus_info.bus_flag = 0;
|
||||
|
||||
ret = cam_dev->csi_hw->ops.csi_cfg_bus(cam_dev->csi_hw, ch, &bus_info);
|
||||
ret |= cam_dev->csi_hw->ops.csi_query_outfmts(cam_dev->csi_hw, ch, &res);
|
||||
|
||||
if (ret == 0 && res.count > 0) {
|
||||
param->pix_fmt_num = res.count;
|
||||
for (i = 0; i < res.count; i++) {
|
||||
param->pix_fmt[i] = to_vdev_pixfmt(res.fmts[i]);
|
||||
if (i == 0)
|
||||
pch->cfg.set_pix_fmt = res.fmts[i];
|
||||
}
|
||||
} else {
|
||||
param->pix_fmt_num = 1;
|
||||
param->pix_fmt[0] = VDEV_PIX_FMT_UYVY;
|
||||
}
|
||||
|
||||
cam_info("%s: ch %d done\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_cfg_pixfmt(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param)
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
pch->cfg.set_pix_fmt = to_csi_pixfmt(param->set_pix_fmt);
|
||||
|
||||
cam_info("%s: ch %d done,\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_cfg_size(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param)
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
if (param->field_type == VDEV_FIELD_INTERLACED) {
|
||||
pch->cfg.field_type = CSI_FIELD_INTERLACED;
|
||||
pch->cfg.width_even = param->width_even;
|
||||
pch->cfg.height_even = param->height_even;
|
||||
} else {
|
||||
pch->cfg.field_type = CSI_FIELD_NONE;
|
||||
}
|
||||
pch->cfg.width = param->width;
|
||||
pch->cfg.height = param->height;
|
||||
|
||||
cam_info("%s: ch %d done\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_cfg_crop(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param)
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
struct csi_img_crop crop[2];
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
pch->cfg.crop_en = 1;
|
||||
pch->cfg.crop_x = param->crop_x;
|
||||
pch->cfg.crop_y = param->crop_y;
|
||||
pch->cfg.crop_w = param->crop_w;
|
||||
pch->cfg.crop_h = param->crop_h;
|
||||
|
||||
if (pch->status != STOPPED) {
|
||||
memset(&crop[0], 0, sizeof(crop));
|
||||
crop[0].x = pch->cfg.crop_x;
|
||||
crop[0].y = pch->cfg.crop_y;
|
||||
crop[0].w = pch->cfg.crop_w;
|
||||
crop[0].h = pch->cfg.crop_h;
|
||||
cam_dev->csi_hw->ops.csi_cfg_crop(cam_dev->csi_hw, ch, &crop[0]);
|
||||
}
|
||||
cam_info("%s: ch %d done\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_stream(uint32_t id, uint32_t ch, int on)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t outfmt = CSI_FMT_YUYV;
|
||||
struct csi_bus_info bus_info;
|
||||
struct csi_field_info field;
|
||||
struct csi_img_size size[2];
|
||||
struct csi_img_crop crop[2];
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
struct list_node *node;
|
||||
unsigned long flags = 0;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
if ((on && (pch->status != STOPPED)) || (!on && (pch->status == STOPPED))) {
|
||||
cam_err("%s: csi %d img %d already stream %s\n", __func__, id, ch,
|
||||
(on ? "on" : "off"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (on == 0) {
|
||||
goto stream_off;
|
||||
}
|
||||
|
||||
pch->status = IDLE;
|
||||
|
||||
bus_info.bus_type = pch->cfg.bus_type;
|
||||
bus_info.mbus_fmt = pch->cfg.bus_fmt;
|
||||
bus_info.bus_flag = 0;
|
||||
ret = cam_dev->csi_hw->ops.csi_cfg_bus(cam_dev->csi_hw, ch, &bus_info);
|
||||
|
||||
outfmt = pch->cfg.set_pix_fmt;
|
||||
ret |= cam_dev->csi_hw->ops.csi_cfg_outfmt(cam_dev->csi_hw, ch, outfmt);
|
||||
|
||||
field.field_type = pch->cfg.field_type;
|
||||
ret |= cam_dev->csi_hw->ops.csi_cfg_field(cam_dev->csi_hw, ch, &field);
|
||||
|
||||
memset(&size[0], 0, sizeof(size));
|
||||
size[0].w = pch->cfg.width;
|
||||
size[0].h = pch->cfg.height;
|
||||
size[1].w = pch->cfg.width_even;
|
||||
size[1].h = pch->cfg.height_even;
|
||||
ret |= cam_dev->csi_hw->ops.csi_cfg_size(cam_dev->csi_hw, ch, &size[0]);
|
||||
|
||||
if (pch->cfg.crop_en == 1) {
|
||||
memset(&crop[0], 0, sizeof(crop));
|
||||
crop[0].x = pch->cfg.crop_x;
|
||||
crop[0].y = pch->cfg.crop_y;
|
||||
crop[0].w = pch->cfg.crop_w;
|
||||
crop[0].h = pch->cfg.crop_h;
|
||||
ret |= cam_dev->csi_hw->ops.csi_cfg_crop(cam_dev->csi_hw, ch, &crop[0]);
|
||||
}
|
||||
|
||||
ret |= camera_update_buf(pch, ch);
|
||||
|
||||
ret |= cam_dev->csi_hw->ops.csi_stream_on(cam_dev->csi_hw, ch);
|
||||
if (ret) {
|
||||
cam_info("%s: ch %d error\n", __func__, ch);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pch->frm_cnt = 0;
|
||||
pch->update_cnt = 0;
|
||||
pch->status = RUNNING;
|
||||
|
||||
cam_info("%s: ch %d stream on done\n", __func__, ch);
|
||||
return 0;
|
||||
|
||||
stream_off:
|
||||
pch->status = STOPPED;
|
||||
|
||||
cam_dev->csi_hw->ops.csi_stream_off(cam_dev->csi_hw, ch);
|
||||
|
||||
/* clear all buffer queue here */
|
||||
spin_lock_irqsave(&pch->bufq_lock, flags);
|
||||
do {
|
||||
node = list_peek_head(&pch->out_bufq);
|
||||
if (node == NULL)
|
||||
break;
|
||||
list_delete(node);
|
||||
list_add_tail(&pch->empty, node);
|
||||
} while (1);
|
||||
|
||||
do {
|
||||
node = list_peek_head(&pch->in_bufq);
|
||||
if (node == NULL)
|
||||
break;
|
||||
list_delete(node);
|
||||
list_add_tail(&pch->empty, node);
|
||||
} while (1);
|
||||
|
||||
do {
|
||||
node = list_peek_head(&pch->active_q.qhead);
|
||||
if (node == NULL)
|
||||
break;
|
||||
list_delete(node);
|
||||
list_add_tail(&pch->empty, node);
|
||||
} while (1);
|
||||
|
||||
if (pch->next_buf) {
|
||||
list_add_tail(&pch->empty, &pch->next_buf->list);
|
||||
pch->next_buf = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
|
||||
cam_info("%s: ch %d stream off done\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_cfg_memrange(uint32_t id, uint32_t ch, uint32_t low[3],
|
||||
uint32_t up[3])
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
pch->cam_mem[0].low = low[0];
|
||||
pch->cam_mem[0].up = up[0];
|
||||
pch->cam_mem[1].low = low[1];
|
||||
pch->cam_mem[1].up = up[1];
|
||||
pch->cam_mem[2].low = low[2];
|
||||
pch->cam_mem[2].up = up[2];
|
||||
cam_dev->csi_hw->ops.csi_cfg_mem_range(cam_dev->csi_hw, ch,
|
||||
&pch->cam_mem[0]);
|
||||
|
||||
cam_info("%s: ch %d done\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_qbuf(uint32_t id, uint32_t ch, void *buf)
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
struct camera_buffer *pbuf;
|
||||
struct list_node *node;
|
||||
struct vdev_buffer *in_buf = (struct vdev_buffer *)buf;
|
||||
unsigned long flags = 0;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
spin_lock_irqsave(&pch->bufq_lock, flags);
|
||||
node = list_peek_head(&pch->empty);
|
||||
if (node == NULL) {
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
cam_err("%s: ch %d failed\n", __func__, ch);
|
||||
return -1;
|
||||
}
|
||||
list_delete(node);
|
||||
pbuf = containerof(node, struct camera_buffer, list);
|
||||
pbuf->buffer_idx = in_buf->buffer_idx;
|
||||
pbuf->paddr[0] = (dma_addr_t)in_buf->paddr[0];
|
||||
pbuf->paddr[1] = (dma_addr_t)in_buf->paddr[1];
|
||||
pbuf->paddr[2] = (dma_addr_t)in_buf->paddr[2];
|
||||
list_add_tail(&pch->in_bufq, &pbuf->list);
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
|
||||
// cam_info("%s: ch %d done, buf idx %d\n", __func__, ch,
|
||||
// in_buf->buffer_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channel_dqbuf(uint32_t id, uint32_t ch, void *buf)
|
||||
{
|
||||
struct camera_device *cam_dev;
|
||||
struct camera_channel *pch;
|
||||
struct camera_buffer *pbuf;
|
||||
struct list_node *node;
|
||||
struct vdev_buffer *out_buf = (struct vdev_buffer *)buf;
|
||||
uint32_t timeout_ms;
|
||||
unsigned long flags = 0;
|
||||
CHECK_CSI_ID_CH(id, ch);
|
||||
|
||||
cam_dev = &s_cam_devices[id];
|
||||
pch = &cam_dev->cam_ch[ch];
|
||||
|
||||
spin_lock_irqsave(&pch->bufq_lock, flags);
|
||||
node = list_peek_head(&pch->out_bufq);
|
||||
if (node != NULL) {
|
||||
cam_debug("%s: ch %d get node\n", __func__, ch);
|
||||
goto get_node;
|
||||
}
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
|
||||
timeout_ms = (out_buf->timeout_ms > 0) ? out_buf->timeout_ms : (10 * 1000);
|
||||
cam_debug("%s: ch %d wait timeout %d ms\n", __func__, ch, timeout_ms);
|
||||
if (wait_completion_timeout(&pch->completion, timeout_ms) < 0) {
|
||||
cam_err("%s: ch %d failed for timeout %d ms\n", __func__, ch,
|
||||
timeout_ms);
|
||||
return -1;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pch->bufq_lock, flags);
|
||||
node = list_peek_head(&pch->out_bufq);
|
||||
if (node == NULL) {
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
cam_debug("%s: ch %d node null\n", __func__, ch);
|
||||
return -1;
|
||||
}
|
||||
|
||||
get_node:
|
||||
list_delete(node);
|
||||
pbuf = containerof(node, struct camera_buffer, list);
|
||||
out_buf->buffer_idx = pbuf->buffer_idx;
|
||||
out_buf->frm_cnt = pbuf->frm_cnt;
|
||||
out_buf->timestamp = pbuf->timestamp;
|
||||
out_buf->paddr[0] = (void *)pbuf->paddr[0];
|
||||
out_buf->paddr[1] = (void *)pbuf->paddr[1];
|
||||
out_buf->paddr[2] = (void *)pbuf->paddr[2];
|
||||
|
||||
memset(pbuf, 0, sizeof(struct camera_buffer));
|
||||
list_add_tail(&pch->empty, &pbuf->list);
|
||||
spin_unlock_irqrestore(&pch->bufq_lock, flags);
|
||||
|
||||
cam_debug("%s: ch %d done\n", __func__, ch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct csi_channel_ops ch_ops = {
|
||||
.channel_open = channel_open,
|
||||
.channel_close = channel_close,
|
||||
.channel_stream = channel_stream,
|
||||
.channel_cfg_bus_type = channel_cfg_bus_type,
|
||||
.channel_cfg_bus_fmt = channel_cfg_bus_fmt,
|
||||
.channel_cfg_size = channel_cfg_size,
|
||||
.channel_cfg_crop = channel_cfg_crop,
|
||||
.channel_enum_pixfmt = channel_enum_pixfmt,
|
||||
.channel_cfg_pixfmt = channel_cfg_pixfmt,
|
||||
|
||||
.channel_cfg_memrange = channel_cfg_memrange,
|
||||
.channel_qbuf = channel_qbuf,
|
||||
.channel_dqbuf = channel_dqbuf,
|
||||
};
|
||||
61
drivers/source/camera/csi-baremetal/csi_drv/csi_drv.h
Normal file
61
drivers/source/camera/csi-baremetal/csi_drv/csi_drv.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file csi_drv.h
|
||||
*
|
||||
* Copyright (c) 2021 Semidrive Semiconductor.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Description: csi driver interface
|
||||
*
|
||||
* Revision History:
|
||||
* -----------------
|
||||
*/
|
||||
#ifndef __CSI_DRV_H__
|
||||
#define __CSI_DRV_H__
|
||||
|
||||
struct csi_ch_params {
|
||||
uint32_t bus_type;
|
||||
uint32_t bus_fmt;
|
||||
uint32_t field_type;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t width_even;
|
||||
uint32_t height_even;
|
||||
uint32_t crop_en;
|
||||
uint32_t crop_x;
|
||||
uint32_t crop_y;
|
||||
uint32_t crop_w;
|
||||
uint32_t crop_h;
|
||||
uint32_t set_pix_fmt;
|
||||
uint32_t pix_fmt_num;
|
||||
uint32_t pix_fmt[8];
|
||||
};
|
||||
|
||||
struct csi_channel_ops {
|
||||
int (*channel_open)(uint32_t id, uint32_t ch);
|
||||
int (*channel_close)(uint32_t id, uint32_t ch);
|
||||
int (*channel_stream)(uint32_t id, uint32_t ch, int enable);
|
||||
int (*channel_qbuf)(uint32_t id, uint32_t ch, void *buf);
|
||||
int (*channel_dqbuf)(uint32_t id, uint32_t ch, void *buf);
|
||||
int (*channel_cfg_bus_type)(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param);
|
||||
int (*channel_cfg_bus_fmt)(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param);
|
||||
int (*channel_cfg_size)(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param);
|
||||
int (*channel_cfg_crop)(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param);
|
||||
int (*channel_enum_pixfmt)(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param);
|
||||
int (*channel_cfg_pixfmt)(uint32_t id, uint32_t ch,
|
||||
struct csi_ch_params *param);
|
||||
int (*channel_cfg_memrange)(uint32_t id, uint32_t ch, uint32_t low[3],
|
||||
uint32_t up[3]);
|
||||
};
|
||||
|
||||
struct csi_device {
|
||||
struct csi_channel_ops ops;
|
||||
};
|
||||
|
||||
struct csi_device *camera_dev_init(uint32_t id);
|
||||
|
||||
#endif /* __CSI_DRV_H__ */
|
||||
1928
drivers/source/camera/csi-baremetal/csi_drv/csi_hw.c
Normal file
1928
drivers/source/camera/csi-baremetal/csi_drv/csi_hw.c
Normal file
File diff suppressed because it is too large
Load Diff
195
drivers/source/camera/csi-baremetal/csi_drv/csi_hw.h
Normal file
195
drivers/source/camera/csi-baremetal/csi_drv/csi_hw.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* csi_hw.h
|
||||
*
|
||||
* Semidrive platform csi controller ip core header file
|
||||
*
|
||||
* Copyright (C) 2022, Semidrive Communications Inc.
|
||||
*
|
||||
* This file is licensed under a dual GPLv2 or X11 license.
|
||||
*/
|
||||
|
||||
#ifndef __CSI_HW_H__
|
||||
#define __CSI_HW_H__
|
||||
#include <stdint.h>
|
||||
|
||||
/* max output format for one specified input bus fmt */
|
||||
#define CSI_OUTFMT_MAX 8
|
||||
|
||||
/* csi hardware id */
|
||||
enum csi_host_id {
|
||||
CSI_HOST_0 = 0,
|
||||
CSI_HOST_1,
|
||||
CSI_HOST_2,
|
||||
CSI_HOST_NUM,
|
||||
};
|
||||
|
||||
/* image channel id in one csi hardware device */
|
||||
enum csi_img_id { CSI_IMG0 = 0, CSI_IMG1, CSI_IMG2, CSI_IMG3, CSI_IMG_NUM };
|
||||
|
||||
/*
|
||||
* for cmd of: int csi_reset_img(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
* uint32_t cmd); CSI_RESET_IMG_HW: reset hardware (csi virtual channel)
|
||||
* CSI_RESET_IMG_CTX: reset image software context.
|
||||
* (CSI_RESET_IMG_HW | CSI_RESET_IMG_CTX) should be applied every time video
|
||||
* open ”CSI_RESET_IMG_HW only“ can be applied for error recovering
|
||||
*/
|
||||
enum csi_img_reset_type {
|
||||
CSI_RESET_IMG_HW = (1 << 0),
|
||||
CSI_RESET_IMG_CTX = (1 << 1),
|
||||
};
|
||||
|
||||
/* input camera signal interface type */
|
||||
enum csi_bus_type {
|
||||
CSI_BUS_MIPICSI2 = 0, /* mipi-csi2 */
|
||||
CSI_BUS_PARALLEL1, /* continuous clk, VSYNC & HSYNC, gate mode1 -- NOT
|
||||
SUPPORTED */
|
||||
CSI_BUS_PARALLEL2, /* continuous clk, VSYNC * HSYNC, gate mode2 */
|
||||
CSI_BUS_PARALLEL3, /* non-continuous clk, VSYNC */
|
||||
CSI_BUS_PARALLEL4, /* continuous clk, VSYNC & HSYNC, DE(data-enable), same
|
||||
as MIPICSI2 */
|
||||
CSI_BUS_BT656, /* clk, data */
|
||||
CSI_BUS_BT1120_SDR, /* clk, single data one cycle */
|
||||
CSI_BUS_BT1120_DDR, /* clk, double data one cycle -- NOT SUPPORTED */
|
||||
CSI_BUS_TYPE_MAX
|
||||
};
|
||||
|
||||
/* input media format */
|
||||
enum csi_mbus_fmt {
|
||||
CSI_MBUS_UYVY8_2X8 =
|
||||
1, /* for mipi-csi YUV422-8bit, for parallel UYVY-8bit */
|
||||
CSI_MBUS_YUYV8_2X8, /* for parallel YUYV-8bit*/
|
||||
CSI_MBUS_YUYV8_1X16, /* for parallel YUYV-16bit*/
|
||||
CSI_MBUS_UYVY8_1X16, /* for parallel UYVY-16bit*/
|
||||
CSI_MBUS_UYVY10_2X10, /* for mipi-csi YUV422-10bit */
|
||||
CSI_MBUS_UYVY8_1_5X8, /* for mipi-csi YUV420-legacy, for parallel
|
||||
UYY-VYY-8bit */
|
||||
CSI_MBUS_VYUY8_1_5X8, /* for mipi-csi YUV420, for parallel VYY-UYY-8bit
|
||||
*/
|
||||
CSI_MBUS_RGB888_1X24, /* for mipi-csi RGB-8bit, for parallel RGB-8bit */
|
||||
CSI_MBUS_RGB565_1X16, /* for mipi-csi RGB-6bit, for parallel RGB-6bit */
|
||||
CSI_MBUS_RGB24_1X24, /* for parallel RGB-24bit*/
|
||||
CSI_MBUS_BGR24_1X24, /* for parallel RGB-24bit*/
|
||||
/* More types to be added ....*/
|
||||
CSI_MBUS_FMT_MAX
|
||||
};
|
||||
|
||||
enum csi_bus_flag {
|
||||
MBUS_DE_ACTIVE_LOW = (1 << 0),
|
||||
MBUS_VSYNC_ACTIVE_LOW = (1 << 1),
|
||||
MBUS_HSYNC_ACTIVE_HIGH = (1 << 2),
|
||||
MBUS_PCLK_SAMPLE_RISING = (1 << 3),
|
||||
};
|
||||
|
||||
/* csi output format (stored in memory) */
|
||||
enum csi_out_fmt {
|
||||
CSI_FMT_YUYV = 1, /* Y-U-Y-V, 8-8-8-8 */
|
||||
CSI_FMT_UYVY, /* U-Y-V-Y, 8-8-8-8 */
|
||||
CSI_FMT_NV16, /* Y-Y-Y-Y, U-V-U-V, two planes*/
|
||||
CSI_FMT_NV61, /* Y-Y-Y-Y, V-U-V-U, two planes*/
|
||||
CSI_FMT_YUV422P, /* Y, U, V, three planes*/
|
||||
CSI_FMT_RGB24, /* R-G-B, 8-8-8*/
|
||||
CSI_FMT_BGR24, /* B-G-R, 8-8-8*/
|
||||
CSI_FMT_RGB16, /* R-G-B, 5-6-5*/
|
||||
/* More types to be added ....*/
|
||||
CSI_FMT_MAX,
|
||||
};
|
||||
|
||||
/* input image type. For BT656, interlaced field is supportted. Other cases
|
||||
* should be CSI_FIELD_NONE */
|
||||
enum csi_field_type {
|
||||
CSI_FIELD_NONE, /* no field, progressive */
|
||||
CSI_FIELD_TOP,
|
||||
CSI_FIELD_BOTTOM,
|
||||
CSI_FIELD_INTERLACED, /* both top and bottom field and interlaced into one
|
||||
frame */
|
||||
CSI_FIELD_MAX,
|
||||
};
|
||||
|
||||
struct csi_img_crop {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t w;
|
||||
uint32_t h;
|
||||
};
|
||||
|
||||
struct csi_img_size {
|
||||
uint32_t w;
|
||||
uint32_t h;
|
||||
};
|
||||
|
||||
struct csi_img_buf {
|
||||
dma_addr_t paddr[3];
|
||||
};
|
||||
|
||||
struct mem_range {
|
||||
uint32_t up;
|
||||
uint32_t low;
|
||||
};
|
||||
|
||||
struct csi_bus_info {
|
||||
uint32_t bus_type; /* should be enum csi_bus_type */
|
||||
uint32_t mbus_fmt; /* should be enum csi_mbus_fmt */
|
||||
uint32_t bus_flag;
|
||||
};
|
||||
|
||||
/* supported output formats for one specified bus_types and mbus_fmt */
|
||||
struct csi_outfmt_info {
|
||||
uint32_t count;
|
||||
uint32_t fmts[CSI_OUTFMT_MAX];
|
||||
};
|
||||
|
||||
struct csi_field_info {
|
||||
uint32_t field_type; /* should be enum csi_field_type */
|
||||
};
|
||||
|
||||
struct csi_callback_t {
|
||||
void *caller;
|
||||
int (*csi_frame_done)(void *caller, uint32_t img_id);
|
||||
int (*csi_update_buf)(void *caller, uint32_t img_id);
|
||||
int (*csi_error_handle)(void *caller, uint32_t img_id);
|
||||
};
|
||||
|
||||
struct csi_hw_dev;
|
||||
|
||||
struct csi_hw_operations {
|
||||
/* ==== following interface for csi_core ==== */
|
||||
int (*csi_irq_handle)(struct csi_hw_dev *csi_dev);
|
||||
int (*csi_cfg_sync)(struct csi_hw_dev *csi_dev, uint32_t sync);
|
||||
|
||||
/* ==== following interface for csi_image (one of virtual channel) ==== */
|
||||
int (*csi_reset_img)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
uint32_t cmd);
|
||||
int (*csi_register_callback)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
struct csi_callback_t *cb);
|
||||
int (*csi_cfg_bus)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
struct csi_bus_info *bus);
|
||||
int (*csi_query_outfmts)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
struct csi_outfmt_info *fmt);
|
||||
int (*csi_cfg_outfmt)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
uint32_t outfmt);
|
||||
int (*csi_cfg_field)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
struct csi_field_info *field);
|
||||
int (*csi_cfg_size)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
struct csi_img_size *size);
|
||||
int (*csi_cfg_crop)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
struct csi_img_crop *crop);
|
||||
int (*csi_cfg_img_buf)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
struct csi_img_buf *buf);
|
||||
int (*csi_cfg_mem_range)(struct csi_hw_dev *csi_dev, uint32_t img_id,
|
||||
struct mem_range *mem);
|
||||
|
||||
int (*csi_stream_on)(struct csi_hw_dev *csi_dev, uint32_t img_id);
|
||||
int (*csi_stream_off)(struct csi_hw_dev *csi_dev, uint32_t img_id);
|
||||
};
|
||||
|
||||
struct csi_hw_dev {
|
||||
void *priv_data;
|
||||
uint32_t host_id;
|
||||
struct csi_hw_operations ops;
|
||||
};
|
||||
|
||||
/* ==== following interface for csi_core ==== */
|
||||
struct csi_hw_dev *csi_hw_init(reg_addr_t base, uint32_t host_id);
|
||||
int csi_hw_deinit(struct csi_hw_dev *csi_dev);
|
||||
|
||||
#endif
|
||||
131
drivers/source/camera/csi-baremetal/csi_drv/csi_reg.h
Normal file
131
drivers/source/camera/csi-baremetal/csi_drv/csi_reg.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* csi_reg.h
|
||||
*
|
||||
* Semidrive platform mipi csi2 header file
|
||||
*
|
||||
* Copyright (C) 2021, Semidrive Communications Inc.
|
||||
*
|
||||
* This file is licensed under a dual GPLv2 or X11 license.
|
||||
*/
|
||||
|
||||
#ifndef __CSI_REG_H__
|
||||
#define __CSI_REG_H__
|
||||
|
||||
/* all registers in csi ip */
|
||||
|
||||
#define CSI_REG_ENABLE 0x00
|
||||
#define CSI_REG_INT_STAT0 0x04
|
||||
#define CSI_REG_INT_STAT1 0x08
|
||||
#define CSI_REG_INT_MASK0 0x0c
|
||||
#define CSI_REG_INT_MASK1 0x10
|
||||
#define CSI_REG_REG_LOAD 0x14
|
||||
|
||||
/* n: 0 ~ 3, indicates image channel. */
|
||||
#define CSI_REG_IMG_RGBY_BADDR_H(n) (0x100 + n * 0x80)
|
||||
#define CSI_REG_IMG_RGBY_BADDR_L(n) (0x104 + n * 0x80)
|
||||
#define CSI_REG_IMG_U_BADDR_H(n) (0x108 + n * 0x80)
|
||||
#define CSI_REG_IMG_U_BADDR_L(n) (0x10c + n * 0x80)
|
||||
#define CSI_REG_IMG_V_BADDR_H(n) (0x110 + n * 0x80)
|
||||
#define CSI_REG_IMG_V_BADDR_L(n) (0x114 + n * 0x80)
|
||||
#define CSI_REG_IMG_RGBY_STRIDE(n) (0x118 + n * 0x80)
|
||||
#define CSI_REG_IMG_U_STRIDE(n) (0x11c + n * 0x80)
|
||||
#define CSI_REG_IMG_V_STRIDE(n) (0x120 + n * 0x80)
|
||||
#define CSI_REG_IMG_SIZE(n) (0x124 + n * 0x80)
|
||||
#define CSI_REG_IMG_IPI_CTRL(n) (0x128 + n * 0x80)
|
||||
#define CSI_REG_IMG_IF_PIXEL_MASK0(n) (0x12c + n * 0x80)
|
||||
#define CSI_REG_IMG_IF_PIXEL_MASK1(n) (0x130 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_CTRL(n) (0x134 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_SPLIT0(n) (0x138 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_SPLIT1(n) (0x13c + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_SPLIT2(n) (0x140 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_CROP0(n) (0x144 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_CROP1(n) (0x148 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_CROP2(n) (0x14c + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_PACK0(n) (0x150 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_PACK1(n) (0x154 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_PACK2(n) (0x158 + n * 0x80)
|
||||
#define CSI_REG_IMG_CHN_VCROP0(n) (0x15c + n * 0x80)
|
||||
|
||||
/* n: 0 ~ 7, indicates wdma output channel, max 2 channels for each image */
|
||||
#define CSI_REG_WDMA_CHN_DFIFO(n) (0x300 + n * 0x20)
|
||||
#define CSI_REG_WDMA_CHN_CFIFO(n) (0x304 + n * 0x20)
|
||||
#define CSI_REG_WDMA_CHN_AXI_CTRL0(n) (0x308 + n * 0x20)
|
||||
#define CSI_REG_WDMA_CHN_AXI_CTRL1(n) (0x30c + n * 0x20)
|
||||
#define CSI_REG_WDMA_CHN_AXI_CTRL2(n) (0x310 + n * 0x20)
|
||||
#define CSI_REG_WDMA_CHN_STATE(n) (0x314 + n * 0x20)
|
||||
|
||||
/* n: 0 ~ 3, indicates image channel.
|
||||
* Actually 1~3 will never be used because only image0 can get input from
|
||||
* outside of SOC
|
||||
*/
|
||||
#define CSI_REG_PARA_BT_CTRL0(n) (0x500 + n * 0x40)
|
||||
#define CSI_REG_PARA_BT_CTRL1(n) (0x504 + n * 0x40)
|
||||
#define CSI_REG_PARA_BT_CTRL2(n) (0x508 + n * 0x40)
|
||||
#define CSI_REG_PIXEL_MAP(n) (0x50C + n * 0x40)
|
||||
|
||||
/* n: 0 ~ 1, indicates image channel. */
|
||||
#define CSI_REG_IMG_FB_CTRL(n) (0x800 + n * 0x80)
|
||||
#define CSI_REG_IMG_UP_RGBY_ADDR(n) (0x804 + n * 0x80)
|
||||
#define CSI_REG_IMG_LOW_RGBY_ADDR(n) (0x808 + n * 0x80)
|
||||
#define CSI_REG_IMG_UP_U_ADDR(n) (0x810 + n * 0x80)
|
||||
#define CSI_REG_IMG_LOW_U_ADDR(n) (0x814 + n * 0x80)
|
||||
#define CSI_REG_IMG_UP_V_ADDR(n) (0x818 + n * 0x80)
|
||||
#define CSI_REG_IMG_LOW_V_ADDR(n) (0x81c + n * 0x80)
|
||||
|
||||
enum csi_int0_status {
|
||||
CSI_INT0_STORE_DONE0 = (1 << 0),
|
||||
CSI_INT0_STORE_DONE1 = (1 << 1),
|
||||
CSI_INT0_STORE_DONE2 = (1 << 2),
|
||||
CSI_INT0_STORE_DONE3 = (1 << 3),
|
||||
CSI_INT0_SHADOW_SET0 = (1 << 4),
|
||||
CSI_INT0_SHADOW_SET1 = (1 << 5),
|
||||
CSI_INT0_SHADOW_SET2 = (1 << 6),
|
||||
CSI_INT0_SHADOW_SET3 = (1 << 7),
|
||||
CSI_INT0_BT_ERR = (1 << 8),
|
||||
CSI_INT0_BT_FATAL = (1 << 9),
|
||||
CSI_INT0_BT_FIELD_CHANGE = (1 << 10),
|
||||
};
|
||||
|
||||
enum csi_int1_status {
|
||||
CSI_INT1_CROP_ERR0 = (1 << 0),
|
||||
CSI_INT1_CROP_ERR1 = (1 << 1),
|
||||
CSI_INT1_CROP_ERR2 = (1 << 2),
|
||||
CSI_INT1_CROP_ERR3 = (1 << 3),
|
||||
CSI_INT1_PIXEL_ERR0 = (1 << 4),
|
||||
CSI_INT1_PIXEL_ERR1 = (1 << 5),
|
||||
CSI_INT1_PIXEL_ERR2 = (1 << 6),
|
||||
CSI_INT1_PIXEL_ERR3 = (1 << 7),
|
||||
CSI_INT1_OVERFLOW0 = (1 << 8),
|
||||
CSI_INT1_OVERFLOW1 = (1 << 9),
|
||||
CSI_INT1_OVERFLOW2 = (1 << 10),
|
||||
CSI_INT1_OVERFLOW3 = (1 << 11),
|
||||
CSI_INT1_IMG0_BUSERR0 = (1 << 12),
|
||||
CSI_INT1_IMG0_BUSERR1 = (1 << 13),
|
||||
CSI_INT1_IMG0_BUSERR2 = (1 << 14),
|
||||
CSI_INT1_IMG1_BUSERR0 = (1 << 15),
|
||||
CSI_INT1_IMG1_BUSERR1 = (1 << 16),
|
||||
CSI_INT1_IMG1_BUSERR2 = (1 << 17),
|
||||
CSI_INT1_IMG2_BUSERR0 = (1 << 18),
|
||||
CSI_INT1_IMG2_BUSERR1 = (1 << 19),
|
||||
CSI_INT1_IMG2_BUSERR2 = (1 << 20),
|
||||
CSI_INT1_IMG3_BUSERR0 = (1 << 21),
|
||||
CSI_INT1_IMG3_BUSERR1 = (1 << 22),
|
||||
CSI_INT1_IMG3_BUSERR2 = (1 << 23),
|
||||
};
|
||||
|
||||
#define INT0_ERR_MASK(n) ((CSI_INT0_BT_ERR << n) | (CSI_INT0_BT_FATAL << 0))
|
||||
|
||||
#define INT0_MASK(n) (CSI_INT0_SHADOW_SET0 << n)
|
||||
#define INT0_BT_MASK(n) (INT0_ERR_MASK(n) | (CSI_INT0_SHADOW_SET0 << n))
|
||||
|
||||
#define INT0_ERR_MASK_ALL \
|
||||
(INT0_ERR_MASK(0) | INT0_ERR_MASK(1) | INT0_ERR_MASK(2) | INT0_ERR_MASK(3))
|
||||
|
||||
#define INT1_ERR_MASK(n) \
|
||||
(((CSI_INT1_CROP_ERR0 | CSI_INT1_PIXEL_ERR0 | CSI_INT1_OVERFLOW0) << n) | \
|
||||
(CSI_INT1_IMG0_BUSERR0 << (n * 3)))
|
||||
|
||||
#define INT1_ERR_MASK_ALL \
|
||||
(INT1_ERR_MASK(0) | INT1_ERR_MASK(1) | INT1_ERR_MASK(2) | INT1_ERR_MASK(3))
|
||||
|
||||
#endif /* __CSI_REG_H__ */
|
||||
Reference in New Issue
Block a user