/* 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; }