2025-12-17 15:55:25 +08:00

412 lines
13 KiB
C

/* Copyright (c) 2020 Kneron, Inc. All Rights Reserved.
*
* The information contained herein is property of Kneron, Inc.
* Terms and conditions of usage are described in detail in Kneron
* STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information.
* NO WARRANTY of ANY KIND is provided. This heading must NOT be removed
* from the file.
*/
/******************************************************************************
* Filename:
* ---------
* kdrv_dpi2ahb.c
*
* Project:
* --------
* KL520
*
* Description:
* ------------
* Configuration for KL520
*
* Author:
* -------
* Albert Chen
**
******************************************************************************/
/******************************************************************************
Head Block of The File
******************************************************************************/
// Sec 0: Comment block of the file
// Sec 1: Include File
#include "kmdw_camera.h"
#include "kdrv_dpi2ahb.h"
// Sec 2: Constant Definitions, Imported Symbols, miscellaneous
#define DPI2AHB_PAGE_NUM 2 // # of pages by one controller
#define D2A_REG_CTRL 0x00 // Control
#define D2A_REG_FNC 0x04 // Frame Number Control
#define D2A_REG_P0ADDR 0x08 // Page 0 Address
#define D2A_REG_P1ADDR 0x0C // Page 1 Address
#define D2A_REG_ICT 0x10 // Interrupt Control
#define D2A_REG_IS 0x14 // Interrupt Status
#define D2A_REG_ST 0x18 // Status
#define D2A_REG_PT 0x1C // Packet Type
#define D2A_REG_FIU0 0x20 // FI Use 0
#define D2A_REG_FIU1 0x24 // FI Use 1
#define D2A_REG_TAVR 0x28 // Tile Average Result (n)
/* D2A interrupt control & status register */
#define D2A_INT_TILE_AVG_D BIT5
#define D2A_INT_AHB_TX_ERR BIT4
#define D2A_INT_FIFO_UF BIT3
#define D2A_INT_FIFO_OF BIT2
#define D2A_INT_FN_OL BIT1
#define D2A_INT_WRD BIT0
#define D2A_INT_ALL 0x3F
#define D2A_INT_ERRORS (D2A_INT_AHB_TX_ERR | D2A_INT_FIFO_UF | D2A_INT_FIFO_OF | D2A_INT_FN_OL)
/* D2A status register */
#define D2A_ST_PG 0x3
/* D2A Packet type register */
#define D2A_PT_YUV422 0x1E
#define D2A_PT_RGB565 0x22
#define D2A_PT_RGB888 0x24
#define D2A_PT_RAW8 0x2A
#define D2A_PT_RAW10 0x2B
#define D2A_PT_RAW12 0x2C
#define D2A_PT_RAW14 0x2D
#define D2A_PT_RAW16 0x2E
#define TILE_AVG_SIZE_128 0x00000000
#define TILE_AVG_SIZE_64 BIT16
#define TILE_AVG_SIZE_32 BIT17
#define TILE_AVG_SIZE_VAL TILE_AVG_SIZE_128
#define TILE_AVG_SIZE_PIXELS 128
#if (IMGSRC_0_SENSORID == SENSOR_ID_HMX2056) || (IMGSRC_0_SENSORID == SENSOR_ID_SC132GS)
#define D2A_REG_CTRL_0 0x3000
#elif(IMGSRC_0_SENSORID == SENSOR_ID_OV9286) || (IMGSRC_0_SENSORID == SENSOR_ID_HMXRICA)
#define D2A_REG_CTRL_0 0x3008
#elif(IMGSRC_0_SENSORID == SENSOR_ID_GC2145)
#define D2A_REG_CTRL_0 0x3000
#elif(IMGSRC_0_SENSORID == SENSOR_ID_EXTERN)
#define D2A_REG_CTRL_0 0x5004
#else
#define D2A_REG_CTRL_0 0
#endif
#if (IMGSRC_1_SENSORID == SENSOR_ID_HMX2056) || (IMGSRC_1_SENSORID == SENSOR_ID_SC132GS)
#define D2A_REG_CTRL_1 0x3000
#elif(IMGSRC_1_SENSORID == SENSOR_ID_OV9286) || (IMGSRC_1_SENSORID == SENSOR_ID_HMXRICA)
#define D2A_REG_CTRL_1 0x3008
#elif(IMGSRC_1_SENSORID == SENSOR_ID_GC2145)
#define D2A_REG_CTRL_1 0x2800
#elif(IMGSRC_1_SENSORID == SENSOR_ID_EXTERN)
#define D2A_REG_CTRL_1 0x5004
#else
#define D2A_REG_CTRL_1 0
#endif
struct kdp520_dpi2ahb_context {
uint32_t irq;
uint32_t page_done_num;
uint32_t tile_avg_en;
uint32_t tile_n_w;
uint32_t tile_n_h;
};
typedef volatile union U_regDPI2AHB
{
struct
{
uint32_t D2ACtrl; //0x00 D2A Control Register
uint32_t D2AFrameNumCtrl; //0x04 D2A Frame Number Control Register
uint32_t D2APage0Addr; //0x08 Page0 Address Register
uint32_t D2APage1Addr; //0x0c Page1 Address Register
uint32_t D2AIntrCtrl; //0x10 D2A Interrupt Control Register
uint32_t D2AIntrStat; //0x14 D2A Interrupt Status Register
uint32_t D2AStatus; //0x18 D2A Status Register
uint32_t D2APacketType; //0x1c D2A Packet Type Register
uint32_t FTCInternal1; //0x20 FTC Internal Use Register 0
uint32_t FTCInternal2; //0x24 FTC Internal Use Register 1
uint32_t TAVGRn; //0x28 Tile Average Result n
}dw; //double word
struct
{
//0x00
uint32_t D2a_sr:1;
uint32_t D2a_hp:1;
uint32_t D2a_vp:1;
uint32_t D2a_da:1;
uint32_t D2a_fr_df:7;
uint32_t D2a_ft:4;
uint32_t Gamma_en:1;
uint32_t Tile_avg_size:2;
uint32_t Reserve0:14;
//0x04
uint32_t D2a_fn:1;
uint32_t Tile_avg_en:1;
uint32_t Reserve1:30;
//0x08
uint32_t D2a_pg0_addr:32;
//0x0c
uint32_t D2a_pg1_addr:32;
//0x10
uint32_t D2a_wrd_ce:1;
uint32_t D2a_fn_ol_ce:1;
uint32_t D2a_fifo_of_ce:1;
uint32_t D2a_fifo_uf_ce:1;
uint32_t Ahb_tx_err_ce:1;
uint32_t Tile_avg_d_ce:1;
uint32_t Reserve2:26;
//0x14
uint32_t D2a_wrd:1;
uint32_t D2a_fn_ol:1;
uint32_t D2a_fifo_of:1;
uint32_t D2a_fifo_uf:1;
uint32_t Ahb_tx_err:1;
uint32_t tile_avg_d:1;
uint32_t Reserve3:26;
//0x18
uint32_t D2a_pg1_b:1;
uint32_t D2a_pg0_b:1;
uint32_t Reserve4:30;
//0x1c
uint32_t D2a_pt:6;
uint32_t Reserve5:26;
//0x20
uint32_t D2a_fn_tg:1;
uint32_t Reserve6:31;
//0x24
uint32_t cs:5;
uint32_t Reserve7:27;
//0x28
uint32_t TAVGR1_0:8;
uint32_t TAVGR1_1:8;
uint32_t TAVGR1_2:8;
uint32_t TAVGR1_3:8;
}bf; //bit-field
}U_regDPI2AHB;
typedef volatile union U_regDPI2AHBCtrl
{
struct
{
//0x9c
uint32_t D2A_CtrlReg;
}dw; //double word
struct
{
//0x9c
uint32_t pwr_rst_n:1;
uint32_t sys_rst_n:1;
uint32_t ahb_rst_n:1;
uint32_t rst_n:1;
uint32_t pwr_rst_n_1:1;
uint32_t sys_rst_n_1:1;
uint32_t ahb_rst_n_1:1;
uint32_t rst_n_1:1;
uint32_t Reserve0:24;
}bf; //bit-field
}U_regDPI2AHBCtrl;
#define regdpi2ahb_0 ((union U_regDPI2AHB *) DPI2AHB_CSR_PA_BASE)
#define regdpi2ahb_1 ((union U_regDPI2AHB *) DPI2AHB_CSR_1_PA_BASE)
#define regdpi2ahb_ctrl ((union U_regDPI2AHBCtrl *) SCU_EXTREG_DPI2AHB_CTRL)
/******************************************************************************
Declaration of External Variables & Functions
******************************************************************************/
// Sec 3: declaration of external variable
// Sec 4: declaration of external function prototype
/******************************************************************************
Declaration of data structure
******************************************************************************/
// Sec 5: structure, uniou, enum, linked list
/******************************************************************************
Declaration of Global Variables & Functions
******************************************************************************/
// Sec 6: declaration of global variable
const uint32_t PixelFmtMapping[4] = {D2A_PT_RGB565, D2A_PT_RAW10, D2A_PT_RAW8, D2A_PT_YUV422};
struct kdp520_dpi2ahb_context dpi2ahb_ctx[D2A_NUM];
static kdrv_dpi2ahb_callback_t dpi2ahb_img_cb[D2A_NUM] = {NULL};
// Sec 7: declaration of global function prototype
/******************************************************************************
Declaration of static Global Variables & Functions
******************************************************************************/
// Sec 8: declaration of static global variable
// Sec 9: declaration of static function prototype
/******************************************************************************
// Sec 10: C Functions
******************************************************************************/
static int skip_next_count[2] = {0}; // >= 0
void kdrv_dpi2ahb_irqhandler(uint32_t d2a_idx)
{
uint32_t sta_is, sta_st;
//dpi2ahb_context *ctx = &dpi2ahb_ctx[d2a_idx];
struct kdp520_dpi2ahb_context *ctx = &dpi2ahb_ctx[d2a_idx];
volatile union U_regDPI2AHB *d2a_base = (d2a_idx == D2A_0) ? regdpi2ahb_0 : regdpi2ahb_1;
volatile uint32_t *D2APageAddr;
sta_is = d2a_base->dw.D2AIntrStat;
sta_st = d2a_base->dw.D2AStatus;
d2a_base->dw.D2AIntrStat = sta_is;
if (sta_is & D2A_INT_WRD)
{
sta_st = d2a_base->dw.D2AStatus;
D2APageAddr = (sta_st == BIT0) ? &d2a_base->dw.D2APage0Addr : &d2a_base->dw.D2APage1Addr;
//imgcnt++;
if (ctx->page_done_num != sta_st) // 1: page 1 done 2: page 0 done
{
D2APageAddr = (sta_st == BIT0)? &d2a_base->dw.D2APage0Addr: &d2a_base->dw.D2APage1Addr;
// hardware ping-pong buffers mechanism
if (skip_next_count[d2a_idx] <= 0)
{
uint32_t new_buf;
dpi2ahb_img_cb[d2a_idx](d2a_idx, *D2APageAddr, &new_buf);//update image buffer addr while debug
*D2APageAddr = new_buf;
}
else
{
// kmdw_printf("cam %d skip next\n", d2a_idx);
skip_next_count[d2a_idx]--;
}
}
}
if (sta_is & D2A_INT_AHB_TX_ERR)
{
// kmdw_printf("%d: cam %d error D2A_INT_AHB_TX_ERR\n", ++err_cnt, d2a_idx);
// skip what ?
}
if (sta_is & D2A_INT_FIFO_UF)
{
// kmdw_printf("%d: cam %d error D2A_INT_FIFO_UF\n", ++err_cnt, d2a_idx);
// skip what ?
}
if (sta_is & D2A_INT_FIFO_OF)
{
// kmdw_printf("%d: cam %d error D2A_INT_FIFO_OF\n", ++err_cnt, d2a_idx);
//skip_previous_count[d2a_idx] = 1; // skip previous one
skip_next_count[d2a_idx] = 1; // skip next one
}
if (sta_is & D2A_INT_FN_OL)
{
// kmdw_printf("%d: cam %d error D2A_INT_FN_OL\n", ++err_cnt, d2a_idx);
// skip what ?
}
if (ctx->tile_avg_en)
{
d2a_base->dw.D2AFrameNumCtrl = 0x2;
}
}
void kdrv_dpi2ahb_isr_0(void)
{
kdrv_dpi2ahb_irqhandler(D2A_0);
}
void kdrv_dpi2ahb_isr_1(void)
{
kdrv_dpi2ahb_irqhandler(D2A_1);
}
kdrv_status_t kdrv_dpi2ahb_enable(uint32_t cam_idx, struct cam_format* fmt)
{
uint32_t val = 0;
struct kdp520_dpi2ahb_context* d2a_ctx = &dpi2ahb_ctx[cam_idx];
union U_regDPI2AHB* d2a_base = (cam_idx == D2A_0)? regdpi2ahb_0: regdpi2ahb_1;
val = (cam_idx == D2A_0)? D2A_REG_CTRL_0: D2A_REG_CTRL_1;
if (d2a_ctx->tile_avg_en)
{
val |= TILE_AVG_SIZE_VAL;
d2a_base->dw.D2AFrameNumCtrl = 0x2;
d2a_base->dw.D2ACtrl = val;
d2a_base->dw.D2AIntrCtrl = (D2A_INT_WRD | D2A_INT_TILE_AVG_D | D2A_INT_ERRORS);
d2a_ctx->tile_n_w = (fmt->width + TILE_AVG_SIZE_PIXELS - 1) / TILE_AVG_SIZE_PIXELS;
d2a_ctx->tile_n_h = (fmt->height + TILE_AVG_SIZE_PIXELS - 1) / TILE_AVG_SIZE_PIXELS;
if (d2a_ctx->tile_n_w > TILE_BLOCK_MAX_W || d2a_ctx->tile_n_h >= TILE_BLOCK_MAX_H)
{
//kmdw_printf("[%s][%d] can't support %d x %d tiles\n", __func__, cam_idx, d2a_ctx->tile_n_w, d2a_ctx->tile_n_h);
d2a_ctx->tile_avg_en = 0;
}
}
else
{
d2a_base->dw.D2AFrameNumCtrl = 0;
d2a_base->dw.D2ACtrl = val;
d2a_base->dw.D2AIntrCtrl = (D2A_INT_WRD|D2A_INT_ERRORS);
}
d2a_base->dw.D2APacketType = PixelFmtMapping[fmt->pixelformat];
d2a_base->dw.FTCInternal1 = 0x1;
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_dpi2ahb_start(uint32_t cam_idx, kdrv_dpi2ahb_callback_t img_cb)
{
NVIC_EnableIRQ((IRQn_Type)dpi2ahb_ctx[cam_idx].irq);
dpi2ahb_img_cb[cam_idx] = img_cb;
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_dpi2ahb_stop(uint32_t cam_idx)
{
NVIC_DisableIRQ((IRQn_Type)dpi2ahb_ctx[cam_idx].irq);
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_dpi2ahb_buf_init(uint32_t cam_idx, uint32_t buf_addr_0, uint32_t buf_addr_1)
{
union U_regDPI2AHB* d2a_base = (cam_idx == D2A_0)? regdpi2ahb_0: regdpi2ahb_1;
d2a_base->dw.D2APage0Addr = buf_addr_0;
d2a_base->dw.D2APage1Addr = buf_addr_1;
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_dpi2ahb_initialize(uint32_t cam_idx)
{
if(cam_idx == D2A_0)
{
dpi2ahb_ctx[cam_idx].tile_avg_en = IMGSRC_0_TILE_AVG;
dpi2ahb_ctx[cam_idx].irq = D2A_FTDPI2AHB_IRQ;
regdpi2ahb_ctrl->dw.D2A_CtrlReg |= 0xf;
NVIC_SetVector((IRQn_Type)dpi2ahb_ctx[cam_idx].irq, (uint32_t)kdrv_dpi2ahb_isr_0);
}
else if(cam_idx == D2A_1)
{
dpi2ahb_ctx[cam_idx].tile_avg_en = IMGSRC_1_TILE_AVG;
dpi2ahb_ctx[cam_idx].irq = D2A_FTDPI2AHB_1_IRQ;
regdpi2ahb_ctrl->dw.D2A_CtrlReg |= 0xf0;
NVIC_SetVector((IRQn_Type)dpi2ahb_ctx[cam_idx].irq, (uint32_t)kdrv_dpi2ahb_isr_1);
}
return KDRV_STATUS_OK;
}