summaryrefslogtreecommitdiff
path: root/drivers/media/sprd_gsp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/sprd_gsp')
-rw-r--r--drivers/media/sprd_gsp/Kconfig6
-rw-r--r--drivers/media/sprd_gsp/Makefile22
-rw-r--r--drivers/media/sprd_gsp/gsp_config_if.c293
-rw-r--r--drivers/media/sprd_gsp/gsp_config_if.h484
-rw-r--r--drivers/media/sprd_gsp/gsp_debug.h336
-rw-r--r--drivers/media/sprd_gsp/gsp_drv.c1253
-rw-r--r--drivers/media/sprd_gsp/gsp_drv_common.h103
-rw-r--r--drivers/media/sprd_gsp/scaler_coef_cal.c811
-rw-r--r--drivers/media/sprd_gsp/scaler_coef_cal.h72
-rw-r--r--drivers/media/sprd_gsp/sin_cos.c153
-rw-r--r--drivers/media/sprd_gsp/sin_cos.h24
11 files changed, 3557 insertions, 0 deletions
diff --git a/drivers/media/sprd_gsp/Kconfig b/drivers/media/sprd_gsp/Kconfig
new file mode 100644
index 00000000..47a4f909
--- /dev/null
+++ b/drivers/media/sprd_gsp/Kconfig
@@ -0,0 +1,6 @@
+config VIDEO_GSP_SPRD
+ tristate "SPRD GSP driver"
+ # depends on ARCH_SC8825
+ # default m
+ help
+ Support GSP for SPRD
diff --git a/drivers/media/sprd_gsp/Makefile b/drivers/media/sprd_gsp/Makefile
new file mode 100644
index 00000000..2360bf7d
--- /dev/null
+++ b/drivers/media/sprd_gsp/Makefile
@@ -0,0 +1,22 @@
+# SC88XX Platform Support
+
+
+ifeq ($(CONFIG_ARCH_SCX35),y)
+
+# CONFIG_VIDEO_GSP_SPRD = m
+ifeq ($(CONFIG_VIDEO_GSP_SPRD),y)
+sprd_gsp-objs := scaler_coef_cal.o gsp_config_if.o gsp_drv.o
+obj-$(CONFIG_VIDEO_GSP_SPRD) += sprd_gsp.o
+else
+sprd_gsp-objs := sin_cos.o scaler_coef_cal.o gsp_config_if.o gsp_drv.o
+obj-m += sprd_gsp.o
+endif
+
+# $(warning ytc-------------------------- : $(CONFIG_VIDEO_GSP_SPRD))
+
+
+# EXTRA_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=neon
+EXTRA_CFLAGS += $(arch_variant_cflags)
+# arch_variant_ldflags := -Wl,--fix-cortex-a8
+
+endif
diff --git a/drivers/media/sprd_gsp/gsp_config_if.c b/drivers/media/sprd_gsp/gsp_config_if.c
new file mode 100644
index 00000000..190a77ee
--- /dev/null
+++ b/drivers/media/sprd_gsp/gsp_config_if.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**---------------------------------------------------------------------------*
+** Dependencies *
+**---------------------------------------------------------------------------*/
+//#include <linux/irq.h>
+
+
+#include "gsp_config_if.h"
+
+
+
+/**---------------------------------------------------------------------------*
+ ** Dependencies *
+ **---------------------------------------------------------------------------*/
+
+/**---------------------------------------------------------------------------*
+ ** Macro Definition *
+ **---------------------------------------------------------------------------*/
+
+
+/**---------------------------------------------------------------------------*
+ ** Function Define *
+ **---------------------------------------------------------------------------*/
+
+LOCAL void GSP_SetLayer0Parameter(gsp_context_t *gspCtx)
+{
+ if(!gspCtx->gsp_cfg.layer0_info.layer_en) {
+ GSP_L0_ENABLE_SET(0);
+ return ;
+ }
+
+ GSP_L0_ADDR_SET(gspCtx->gsp_cfg.layer0_info.src_addr);
+ GSP_L0_PITCH_SET(gspCtx->gsp_cfg.layer0_info.pitch);
+ GSP_L0_CLIPRECT_SET(gspCtx->gsp_cfg.layer0_info.clip_rect);
+ GSP_L0_DESRECT_SET(gspCtx->gsp_cfg.layer0_info.des_rect);
+ GSP_L0_GREY_SET(gspCtx->gsp_cfg.layer0_info.grey);
+ GSP_L0_ENDIAN_SET(gspCtx->gsp_cfg.layer0_info.endian_mode);
+ GSP_L0_ALPHA_SET(gspCtx->gsp_cfg.layer0_info.alpha);
+ GSP_L0_COLORKEY_SET(gspCtx->gsp_cfg.layer0_info.colorkey);
+ GSP_L0_IMGFORMAT_SET(gspCtx->gsp_cfg.layer0_info.img_format);
+ GSP_L0_ROTMODE_SET(gspCtx->gsp_cfg.layer0_info.rot_angle);
+ GSP_L0_COLORKEYENABLE_SET(gspCtx->gsp_cfg.layer0_info.colorkey_en);
+ GSP_L0_PALLETENABLE_SET(gspCtx->gsp_cfg.layer0_info.pallet_en);
+ //GSP_L0_SCALETAPMODE_SET(gspCtx->gsp_cfg.layer0_info.row_tap_mode,gspCtx->gsp_cfg.layer0_info.col_tap_mode);
+
+}
+
+
+LOCAL void GSP_SetLayer1Parameter(gsp_context_t *gspCtx)
+{
+ if(!gspCtx->gsp_cfg.layer1_info.layer_en) {
+ GSP_L1_ENABLE_SET(0);
+ return ;
+ }
+
+ GSP_L1_ADDR_SET(gspCtx->gsp_cfg.layer1_info.src_addr);
+ GSP_L1_PITCH_SET(gspCtx->gsp_cfg.layer1_info.pitch);
+ GSP_L1_CLIPRECT_SET(gspCtx->gsp_cfg.layer1_info.clip_rect);
+ GSP_L1_DESPOS_SET(gspCtx->gsp_cfg.layer1_info.des_pos);
+ GSP_L1_GREY_SET(gspCtx->gsp_cfg.layer1_info.grey);
+ GSP_L1_ENDIAN_SET(gspCtx->gsp_cfg.layer1_info.endian_mode);
+ GSP_L1_ALPHA_SET(gspCtx->gsp_cfg.layer1_info.alpha);
+ GSP_L1_COLORKEY_SET(gspCtx->gsp_cfg.layer1_info.colorkey);
+ GSP_L1_IMGFORMAT_SET(gspCtx->gsp_cfg.layer1_info.img_format);
+ GSP_L1_ROTMODE_SET(gspCtx->gsp_cfg.layer1_info.rot_angle);
+ GSP_L1_COLORKEYENABLE_SET(gspCtx->gsp_cfg.layer1_info.colorkey_en);
+ GSP_L1_PALLETENABLE_SET(gspCtx->gsp_cfg.layer1_info.pallet_en);
+
+}
+
+
+LOCAL void GSP_SetLayerDesParameter(gsp_context_t *gspCtx)
+{
+ if(!gspCtx->gsp_cfg.layer0_info.layer_en && !gspCtx->gsp_cfg.layer1_info.layer_en) {
+ return ;
+ }
+
+ GSP_Ld_ADDR_SET(gspCtx->gsp_cfg.layer_des_info.src_addr);
+ GSP_Ld_PITCH_SET(gspCtx->gsp_cfg.layer_des_info.pitch);
+ GSP_Ld_ENDIAN_SET(gspCtx->gsp_cfg.layer_des_info.endian_mode);
+ GSP_Ld_IMGFORMAT_SET(gspCtx->gsp_cfg.layer_des_info.img_format);
+ GSP_Ld_COMPRESSRGB888_SET(gspCtx->gsp_cfg.layer_des_info.compress_r8_en);
+}
+
+LOCAL void GSP_SetMiscParameter(gsp_context_t *gspCtx)
+{
+ if(!gspCtx->gsp_cfg.layer0_info.layer_en && !gspCtx->gsp_cfg.layer1_info.layer_en) {
+ return ;
+ }
+
+ GSP_L0_ENABLE_SET(gspCtx->gsp_cfg.layer0_info.layer_en);
+ GSP_L1_ENABLE_SET(gspCtx->gsp_cfg.layer1_info.layer_en);
+
+ if(gspCtx->gsp_cfg.layer0_info.scaling_en == 1) {
+ GSP_SCALESTATUS_RESET();
+ }
+ GSP_SCALE_ENABLE_SET(gspCtx->gsp_cfg.layer0_info.scaling_en);
+
+
+ GSP_PMARGB_ENABLE_SET(gspCtx->gsp_cfg.layer0_info.pmargb_en||gspCtx->gsp_cfg.layer1_info.pmargb_en);
+ GSP_L0_PMARGBMODE_SET(gspCtx->gsp_cfg.layer0_info.pmargb_mod);
+ GSP_L1_PMARGBMODE_SET(gspCtx->gsp_cfg.layer1_info.pmargb_mod);
+ GSP_PAGES_BOARDER_SPLIT_SET(gspCtx->gsp_cfg.misc_info.split_pages);
+ GSP_Y2R_OPT_SET(gspCtx->gsp_cfg.misc_info.y2r_opt);
+ GSP_DITHER_ENABLE_SET(gspCtx->gsp_cfg.misc_info.dithering_en);
+ //GSP_AHB_CLOCK_SET(gspCtx->gsp_cfg.misc_info.ahb_clock);
+ GSP_CLOCK_SET(gspCtx->gsp_cfg.misc_info.gsp_clock);
+ GSP_EMC_GAP_SET(gspCtx->gsp_cfg.misc_info.gsp_gap);
+}
+
+PUBLIC void GSP_module_enable(gsp_context_t *gspCtx)
+{
+ int ret = 0;
+ //GSP_HWMODULE_ENABLE();
+ if(gspCtx->gsp_clk != NULL) {
+ ret = clk_prepare_enable(gspCtx->gsp_clk);
+ if(ret) {
+ GSP_TRACE(KERN_ERR "%s: enable clock failed!\n",__FUNCTION__);
+ return;
+ } else {
+ pr_debug(KERN_INFO "%s: enable clock ok!\n",__FUNCTION__);
+ }
+ } else {
+ GSP_TRACE(KERN_ERR "%s: gsp_clk not init yet!\n",__FUNCTION__);
+ }
+}
+PUBLIC void GSP_module_disable(gsp_context_t *gspCtx)
+{
+ if(gspCtx->gsp_clk != NULL) {
+ //GSP_HWMODULE_DISABLE();//disable may not use the enable regiter
+ clk_disable_unprepare(gspCtx->gsp_clk);
+ } else {
+ printk(KERN_ERR "%s: gsp_clk not init yet!\n",__FUNCTION__);
+ }
+}
+
+/*
+func:GSP_ClocksCheckPhase0
+desc: check all clock except iommu
+*/
+PUBLIC int GSP_ClocksCheckPhase0(void)
+{
+ int ret = 0;
+
+ //check GSP enable
+ if(0==(GSP_REG_READ(GSP_MOD_EN)&GSP_MOD_EN_BIT)) {
+ printk(KERN_ERR "%s: err: gsp enable is not set!%lx:%08x\n",__FUNCTION__,
+ (ulong)GSP_MOD_EN,GSP_REG_READ(GSP_MOD_EN));
+ ret++;
+ } else {
+ if(GSP_WORKSTATUS_GET() != 0) {
+ printk(KERN_ERR "%s: err:busy is still on!!!!\n",__FUNCTION__);
+ ret++;
+ }
+ }
+
+ //check GSP clock select
+ if(GSP_CLK_SEL_BIT_MASK!=(GSP_REG_READ(GSP_CLOCK_BASE)&GSP_CLK_SEL_BIT_MASK)) {
+ printk(KERN_INFO "%s: info: gsp clock select is not set to hightest freq!%lx:%08x\n",__FUNCTION__,
+ (ulong)GSP_CLOCK_BASE,GSP_REG_READ(GSP_CLOCK_BASE));
+ }
+
+ //check GSP AUTO_GATE clock
+ if(0==(GSP_REG_READ(GSP_AUTO_GATE_ENABLE_BASE)&GSP_AUTO_GATE_ENABLE_BIT)) {
+ printk(KERN_ERR "%s: err: gsp auto gate clock is not enable!%lx:%08x\n",__FUNCTION__,
+ (ulong)GSP_AUTO_GATE_ENABLE_BASE,GSP_REG_READ(GSP_AUTO_GATE_ENABLE_BASE));
+ ret++;
+ }
+
+ //check GSP EMC clock
+ if(0==(GSP_REG_READ(GSP_EMC_MATRIX_BASE)&GSP_EMC_MATRIX_BIT)) {
+ printk(KERN_ERR "%s: err: gsp emc clock is not enable!%lx:%08x\n",__FUNCTION__,
+ (ulong)GSP_EMC_MATRIX_BASE,GSP_REG_READ(GSP_EMC_MATRIX_BASE));
+ ret++;
+ }
+ return (ret>0)?GSP_KERNEL_CLOCK_ERR:GSP_NO_ERR;
+}
+
+/*
+func:GSP_ClocksCheckPhase1
+desc: check iommu cfg
+*/
+PUBLIC int GSP_ClocksCheckPhase1(void)
+{
+ int ret = 0;
+ uint32_t ctl_val = GSP_REG_READ(GSP_MMU_CTRL_BASE);
+ uint32_t addr_y0 = GSP_L0_ADDRY_GET();
+ uint32_t addr_uv0 = GSP_L0_ADDRUV_GET();
+ uint32_t addr_va0 = GSP_L0_ADDRVA_GET();
+ uint32_t addr_y1 = GSP_L1_ADDRY_GET();
+ uint32_t addr_uv1 = GSP_L1_ADDRUV_GET();
+ uint32_t addr_va1 = GSP_L1_ADDRVA_GET();
+ uint32_t addr_yd = GSP_Ld_ADDRY_GET();
+ uint32_t addr_uvd = GSP_Ld_ADDRUV_GET();
+ uint32_t addr_vad = GSP_Ld_ADDRVA_GET();
+
+#define IOVA_CHECK(addr) (0x10000000<= (addr) && (addr) < 0x80000000)
+
+ //check GSP IOMMU ENABLE
+ if(((ctl_val & 0x1)==0 || (ctl_val & 0xF0000000)==0)/*IOMMU be disabled*/
+ &&(((GSP_L0_ENABLE_GET() == 1) && (IOVA_CHECK(addr_y0) || IOVA_CHECK(addr_uv0) || IOVA_CHECK(addr_va0)))/*L0 is enabled and use iova*/
+ ||((GSP_L1_ENABLE_GET() == 1) && (IOVA_CHECK(addr_y1) || IOVA_CHECK(addr_uv1) || IOVA_CHECK(addr_va1)))/*L1 is enabled and use iova*/
+ ||((GSP_L0_ENABLE_GET() == 1 ||GSP_L1_ENABLE_GET() == 1 ) && (IOVA_CHECK(addr_yd) || IOVA_CHECK(addr_uvd) || IOVA_CHECK(addr_vad))))) {
+ printk(KERN_ERR "%s: err: gsp iommu is not enable or iova base is null!%lx:%08x\n",__FUNCTION__,
+ (ulong)GSP_MMU_CTRL_BASE,GSP_REG_READ(GSP_MMU_CTRL_BASE));
+ ret++;
+ }
+ return (ret>0)?GSP_KERNEL_CLOCK_ERR:GSP_NO_ERR;
+}
+
+PUBLIC int GSP_Init(gsp_context_t *gspCtx)
+{
+ int ret = 0;
+ GSP_module_enable(gspCtx);
+ ret = clk_prepare_enable(gspCtx->gsp_emc_clk);
+ //GSP_AUTO_GATE_ENABLE();//gsp driver take charge of auto_gate bit instead of pm
+ if(ret) {
+ printk(KERN_ERR "%s: enable emc clock failed!\n",__FUNCTION__);
+ return GSP_KERNEL_CLOCK_ERR;
+ } else {
+ pr_debug(KERN_INFO "%s: enable emc clock ok!\n",__FUNCTION__);
+ }
+
+ //GSP_HWMODULE_SOFTRESET();//sharkL bug 350028
+ GSP_IRQMODE_SET(GSP_IRQ_MODE_LEVEL);
+ ret = GSP_ClocksCheckPhase0();
+ return ret;
+}
+PUBLIC void GSP_Deinit(gsp_context_t *gspCtx)
+{
+ clk_disable_unprepare(gspCtx->gsp_emc_clk);
+ GSP_IRQSTATUS_CLEAR();
+ GSP_IRQENABLE_SET(GSP_IRQ_TYPE_DISABLE);
+ GSP_module_disable(gspCtx);
+}
+
+PUBLIC void GSP_ConfigLayer(GSP_MODULE_ID_E layer_id, gsp_context_t *gspCtx)
+{
+ switch(layer_id) {
+ case GSP_MODULE_LAYER0:
+ GSP_SetLayer0Parameter(gspCtx);
+ break;
+
+ case GSP_MODULE_LAYER1:
+ GSP_SetLayer1Parameter(gspCtx);
+ break;
+
+ case GSP_MODULE_DST:
+ GSP_SetLayerDesParameter(gspCtx);
+ break;
+
+ default:
+ GSP_SetMiscParameter(gspCtx);
+ break;
+ }
+}
+
+PUBLIC void GSP_Wait_Finish(void)
+{
+ if(GSP_WORKSTATUS_GET() != 0) {
+ printk(KERN_ERR "%s: err:busy is still on!!!!\n",__FUNCTION__);
+ }
+}
+
+
+PUBLIC uint32_t GSP_Trigger(void)
+{
+ int ret = GSP_ClocksCheckPhase1();
+ if(ret) {
+ return ret;
+ }
+ if(GSP_ERRFLAG_GET()) {
+ //GSP_ASSERT();
+ return GSP_ERRCODE_GET();
+ }
+
+ GSP_IRQENABLE_SET(GSP_IRQ_TYPE_ENABLE);
+ GSP_ENGINE_TRIGGER();
+ return 0;
+}
+
diff --git a/drivers/media/sprd_gsp/gsp_config_if.h b/drivers/media/sprd_gsp/gsp_config_if.h
new file mode 100644
index 00000000..48c2fe70
--- /dev/null
+++ b/drivers/media/sprd_gsp/gsp_config_if.h
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __GSP_CONFIG_IF_H_
+#define __GSP_CONFIG_IF_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /**---------------------------------------------------------------------------*
+ ** Dependencies *
+ **---------------------------------------------------------------------------*/
+
+
+#include <video/gsp_types_shark.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <soc/sprd/globalregs.h> //define IRQ_GSP_INT
+#include <soc/sprd/sci.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include "gsp_drv_common.h"
+
+//#include "shark_reg_int.h" //for INT1_IRQ_EN
+
+
+
+ /**---------------------------------------------------------------------------*
+ ** struct Definition *
+ **---------------------------------------------------------------------------*/
+
+ typedef struct _GSP_LAYER1_REG_T_TAG_
+ {
+ union _GSP_LAYER1_CFG_TAG gsp_layer1_cfg_u;
+ union _GSP_LAYER1_Y_ADDR_TAG gsp_layer1_y_addr_u;
+ union _GSP_LAYER1_UV_ADDR_TAG gsp_layer1_uv_addr_u;
+ union _GSP_LAYER1_VA_ADDR_TAG gsp_layer1_va_addr_u;
+ union _GSP_LAYER1_PITCH_TAG gsp_layer1_pitch_u;
+ union _GSP_LAYER1_CLIP_START_TAG gsp_layer1_clip_start_u;
+ union _GSP_LAYER1_CLIP_SIZE_TAG gsp_layer1_clip_size_u;
+ union _GSP_LAYER1_DES_START_TAG gsp_layer1_des_start_u;
+ union _GSP_LAYER1_GREY_RGB_TAG gsp_layer1_grey_rgb_u;
+ union _GSP_LAYER1_ENDIAN_TAG gsp_layer1_endian_u;
+ union _GSP_LAYER1_ALPHA_TAG gsp_layer1_alpha_u;
+ union _GSP_LAYER1_CK_TAG gsp_layer1_ck_u;
+ }
+ GSP_LAYER1_REG_T;
+
+ typedef struct _GSP_CMDQ_REG_T_TAG_
+ {
+ union _GSP_CMD_ADDR_TAG gsp_cmd_addr_u;
+ union _GSP_CMD_CFG_TAG gsp_cmd_cfg_u;
+ }
+ GSP_CMDQ_REG_T;
+
+#define GSP_L1_CMDQ_SET(cfg)\
+ *(GSP_CMDQ_REG_T*)(&((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cmd_addr_u) = (cfg)
+
+
+ /**---------------------------------------------------------------------------*
+ ** Macro Definition *
+ **---------------------------------------------------------------------------*/
+
+
+#ifdef CONFIG_FPGA
+//GSP job config relative
+#define GSP_MOD_EN (SPRD_AHB_BASE)
+#define GSP_SOFT_RESET (SPRD_AHB_BASE + 0x04)
+
+//GSP DDR access relative
+//#define SPRD_AONAPB_PHYS 0X402E0000
+#define GSP_EMC_MATRIX_BASE (SPRD_AONAPB_BASE + 0x04) // GSP access DDR through matrix to AXI, must enable gsp-gate on this matrix
+#define GSP_EMC_MATRIX_BIT (1<<11) // [11] gsp-gate bit on matrix , EMC is DDR controller, should always enabled
+
+//GSP inner work loggy clock ctl
+//#define SPRD_APBCKG_PHYS 0X71200000
+#define GSP_CLOCK_BASE (SPRD_APBCKG_BASE + 0x28)
+#define GSP_CLOCK_256M_BIT (3)// div form PLL clock, use[1:0] 2bit, 0:96M 1:153.6M 2:192M 3:256M
+
+//force enable GSP inner work loggy clock, used for debug
+//#define SPRD_AHB_PHYS 0X20D00000
+#define GSP_AUTO_GATE_ENABLE_BASE (SPRD_AHB_BASE + 0x40)
+#define GSP_AUTO_GATE_ENABLE_BIT (1<<8)//[8] is gate switch, 1:GSP work clk enable by busy signal, 0:force enable, control by busy will save power
+
+//GSP register set clock , through AHB bus
+//#define SPRD_APBCKG_PHYS 0X71200000
+#define GSP_AHB_CLOCK_BASE (SPRD_APBCKG_BASE + 0x20)
+#define GSP_AHB_CLOCK_26M_BIT (0)// [1:0] is used by GSP, 0:26M
+#define GSP_AHB_CLOCK_192M_BIT (3)// [1:0] is used by GSP, 0:26M 1:76M 2:128M 3:192M
+
+
+//interrupt relative
+#define TB_GSP_INT (0x33) //gsp hardware irq number
+#define GSP_IRQ_BIT (1<<19) //gsp hardware irq bit, == (TB_GSP_INT % 32)
+#define GSP_SOFT_RST_BIT (1<<3) //gsp chip module soft reset bit
+#define GSP_MOD_EN_BIT (1<<3) //gsp chip module enable bit
+
+#else
+//GSP job config relative
+#define GSP_MOD_EN (REG_AP_AHB_AHB_EB)
+#define GSP_SOFT_RESET (REG_AP_AHB_AHB_RST)
+
+//GSP DDR access relative
+//#define SPRD_AONAPB_PHYS 0X402E0000
+#define GSP_EMC_MATRIX_BASE (REG_AON_APB_APB_EB1) // GSP access DDR through matrix to AXI, must enable gsp-gate on this matrix
+#define GSP_EMC_MATRIX_BIT (BIT_GSP_EMC_EB) // [13] gsp-gate bit on matrix , EMC is DDR controller, should always enabled
+#define GSP_CLK_SEL_BIT_MASK (0x3)
+
+//GSP inner work loggy clock ctl
+//#define SPRD_APBCKG_PHYS 0X71200000
+#define GSP_CLOCK_BASE (REG_AP_CLK_GSP_CFG)
+typedef enum _GSP_core_freq_
+{
+ GSP_CLOCK_96M_BIT,
+ GSP_CLOCK_153P6M_BIT,
+ GSP_CLOCK_192M_BIT,
+ GSP_CLOCK_256M_BIT
+}
+GSP_CORE_GREQ;
+
+
+//force enable GSP inner work loggy clock, used for debug
+//#define SPRD_AHB_PHYS 0X20D00000
+#define GSP_AUTO_GATE_ENABLE_BASE (REG_AP_AHB_AP_SYS_AUTO_SLEEP_CFG)
+#define GSP_AUTO_GATE_ENABLE_BIT (BIT_GSP_AUTO_GATE_EN)//[8] is gate switch, 1:GSP work clk enable by busy signal, 0:force enable, control by busy will save power
+#define GSP_CKG_FORCE_ENABLE_BIT (BIT_GSP_CKG_FORCE_EN)
+
+//GSP register set clock , through AHB bus
+//#define SPRD_APBCKG_PHYS 0X71200000
+#define GSP_AHB_CLOCK_BASE (REG_AP_CLK_AP_AHB_CFG)
+#define GSP_AHB_CLOCK_26M_BIT (0)// [1:0] is used by GSP, 0:26M
+#define GSP_AHB_CLOCK_192M_BIT (3)// [1:0] is used by GSP, 0:26M 1:76M 2:128M 3:192M
+
+//interrupt relative
+#ifndef CONFIG_OF
+#define TB_GSP_INT (IRQ_GSP_INT) //gsp hardware irq number
+#define GSP_IRQ_BIT SCI_INTC_IRQ_BIT(TB_GSP_INT) //gsp hardware irq bit, == (TB_GSP_INT % 32)
+#endif
+#define GSP_SOFT_RST_BIT (BIT_GSP_SOFT_RST) //gsp chip module soft reset bit
+#define GSP_MOD_EN_BIT (BIT_GSP_EB) //gsp chip module enable bit
+
+#endif
+
+#ifdef CONFIG_OF
+#define GSP_REG_BASE (g_gsp_base_addr)
+#else
+#define GSP_REG_BASE (SPRD_GSP_BASE)
+#endif
+#define GSP_HOR_COEF_BASE (GSP_REG_BASE + 0x90)
+#define GSP_VER_COEF_BASE (GSP_REG_BASE + 0x110)
+#define GSP_L1_BASE (GSP_REG_BASE + 0x60)
+
+
+#ifdef CONFIG_OF
+#define GSP_CLOCK_PARENT3 ("clk_gsp_parent")
+#else
+#define GSP_CLOCK_PARENT3 ("clk_256m")
+#define GSP_CLOCK_PARENT2 ("clk_192m")
+#define GSP_CLOCK_PARENT1 ("clk_153m6")
+#define GSP_CLOCK_PARENT0 ("clk_96m")
+#endif
+#define GSP_CLOCK_NAME ("clk_gsp")
+#define GSP_EMC_CLOCK_PARENT_NAME ("clk_aon_apb")
+#define GSP_EMC_CLOCK_NAME ("clk_gsp_emc")
+
+
+#ifdef CONFIG_FPGA
+#define GSP_EMC_MATRIX_ENABLE() (*(volatile uint32_t*)(GSP_EMC_MATRIX_BASE) |= GSP_EMC_MATRIX_BIT)
+#define GSP_CLOCK_SET(sel)\
+{\
+ *(volatile uint32_t*)(GSP_CLOCK_BASE) &= ~3;\
+ *(volatile uint32_t*)(GSP_CLOCK_BASE) |= (sel);\
+}
+#define GSP_AUTO_GATE_ENABLE() (*(volatile uint32_t*)(GSP_AUTO_GATE_ENABLE_BASE) |= GSP_AUTO_GATE_ENABLE_BIT)
+#define GSP_AHB_CLOCK_SET(sel)\
+{\
+ *(volatile uint32_t*)(GSP_AHB_CLOCK_BASE) &= ~3;\
+ *(volatile uint32_t*)(GSP_AHB_CLOCK_BASE) |= (sel);\
+}
+#define GSP_AHB_CLOCK_GET(sel) (*(volatile uint32_t*)(GSP_AHB_CLOCK_BASE)&0x3)
+
+
+//0x402B001C multi-media force shutdown [25]
+//0x402E0000 MM enable
+#define GSP_ENABLE_MM(addr)\
+{\
+ *(volatile unsigned long *)(SPRD_PMU_BASE+0x1c) &= ~(1<<25);\
+ *(volatile unsigned long *)(SPRD_AONAPB_BASE) |= (1<<25);\
+}
+
+#define GSP_HWMODULE_SOFTRESET()\
+ *(volatile uint32_t *)(GSP_SOFT_RESET) |= GSP_SOFT_RST_BIT;\
+ udelay(10);\
+ *(volatile uint32_t *)(GSP_SOFT_RESET) &= (~GSP_SOFT_RST_BIT)
+
+#define GSP_HWMODULE_ENABLE()\
+ *(volatile uint32_t *)(GSP_MOD_EN) |= (GSP_MOD_EN_BIT)
+
+#define GSP_HWMODULE_DISABLE(bit)\
+ *(volatile uint32_t *)(GSP_MOD_EN) &= (~(GSP_MOD_EN_BIT))
+
+#else
+
+#define GSP_REG_READ(reg) (*(volatile uint32_t*)(reg))
+#define GSP_REG_WRITE(reg,value) (*(volatile uint32_t*)reg = value)
+
+#define GSP_EMC_MATRIX_ENABLE() sci_glb_set(GSP_EMC_MATRIX_BASE, GSP_EMC_MATRIX_BIT)
+#define GSP_CLOCK_SET(sel) sci_glb_write(GSP_CLOCK_BASE, (sel), 0x3)
+#define GSP_AUTO_GATE_ENABLE() sci_glb_set(GSP_AUTO_GATE_ENABLE_BASE, GSP_AUTO_GATE_ENABLE_BIT)
+#define GSP_AUTO_GATE_DISABLE() sci_glb_clr(GSP_AUTO_GATE_ENABLE_BASE, GSP_AUTO_GATE_ENABLE_BIT)
+#define GSP_FORCE_GATE_ENABLE() sci_glb_set(GSP_AUTO_GATE_ENABLE_BASE, GSP_CKG_FORCE_ENABLE_BIT)
+#define GSP_AHB_CLOCK_SET(sel) sci_glb_write(GSP_AHB_CLOCK_BASE, (sel), 0x3)
+#define GSP_AHB_CLOCK_GET() sci_glb_read(GSP_AHB_CLOCK_BASE,0x3)
+
+//#define sci_get_chip_id() GSP_REG_READ(SPRD_AONAPB_BASE+0xFC)
+
+
+
+//0x402B001C multi-media force shutdown [25]
+//0x402E0000 MM enable
+#define GSP_ENABLE_MM(addr)\
+{\
+ sci_glb_clr((REG_PMU_APB_PD_MM_TOP_CFG),(BIT_PD_MM_TOP_FORCE_SHUTDOWN));\
+ sci_glb_set(REG_AON_APB_APB_EB0,(BIT_PD_MM_TOP_FORCE_SHUTDOWN));\
+}
+
+
+#ifdef CONFIG_OF
+#define GSP_MMU_CTRL_BASE (g_gsp_mmu_ctrl_addr)
+#else
+#define GSP_MMU_CTRL_BASE (SPRD_GSPMMU_BASE+0x8000)
+#endif
+
+#define GSP_HWMODULE_SOFTRESET()\
+{\
+ sci_glb_set(GSP_SOFT_RESET,GSP_SOFT_RST_BIT);\
+ udelay(10);\
+ sci_glb_clr(GSP_SOFT_RESET,GSP_SOFT_RST_BIT);\
+ GSP_REG_WRITE(GSP_MMU_CTRL_BASE,0x10000001);\
+}
+#define GSP_HWMODULE_ENABLE() sci_glb_set(GSP_MOD_EN,GSP_MOD_EN_BIT)
+#define GSP_HWMODULE_DISABLE() sci_glb_clr(GSP_MOD_EN,GSP_MOD_EN_BIT)
+
+#endif
+#define GSP_EMC_GAP_SET(interval)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.dist_rb = (interval)
+
+#ifndef CONFIG_64BIT // arch 32bit
+#define GSP_L0_ADDR_SET(addr)\
+ *(volatile GSP_DATA_ADDR_T*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_y_addr_u) = (addr)
+#define GSP_L1_ADDR_SET(addr)\
+ *(volatile GSP_DATA_ADDR_T*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_y_addr_u) = (addr)
+#define GSP_Ld_ADDR_SET(addr)\
+ *(volatile GSP_DATA_ADDR_T*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_des_y_addr_u) = (addr)
+
+#define GSP_L0_CLIPRECT_SET(rect)\
+ *(volatile GSP_RECT_T*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_clip_start_u) = (rect)
+#define GSP_L1_CLIPRECT_SET(rect)\
+ *(volatile GSP_RECT_T*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_clip_start_u) = (rect)
+
+#else //arch 64bit
+
+#define GSP_L0_ADDR_SET(addr)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_y_addr_u.dwValue = (uint32_t)(addr.addr_y);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_uv_addr_u.dwValue = (uint32_t)(addr.addr_uv);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_va_addr_u.dwValue = (uint32_t)(addr.addr_v)
+
+#define GSP_L1_ADDR_SET(addr)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_y_addr_u.dwValue = (uint32_t)(addr.addr_y);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_uv_addr_u.dwValue = (uint32_t)(addr.addr_uv);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_va_addr_u.dwValue = (uint32_t)(addr.addr_v)
+
+#define GSP_Ld_ADDR_SET(addr)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_des_y_addr_u.dwValue = (uint32_t)(addr.addr_y);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_des_uv_addr_u.dwValue = (uint32_t)(addr.addr_uv);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_des_v_addr_u.dwValue = (uint32_t)(addr.addr_v)
+
+#define GSP_L0_CLIPRECT_SET(rect)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_clip_start_u.mBits.clip_start_x_l0 = (rect.st_x);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_clip_start_u.mBits.clip_start_y_l0 = (rect.st_y);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_clip_size_u.mBits.clip_size_x_l0 = (rect.rect_w);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_clip_size_u.mBits.clip_size_y_l0 = (rect.rect_h)
+#define GSP_L1_CLIPRECT_SET(rect)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_clip_start_u.mBits.clip_start_x_l1 = (rect.st_x);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_clip_start_u.mBits.clip_start_y_l1 = (rect.st_y);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_clip_size_u.mBits.clip_size_x_l1 = (rect.rect_w);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_clip_size_u.mBits.clip_size_y_l1 = (rect.rect_h)
+#endif
+
+#define GSP_L0_PITCH_GET() (*(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_pitch_u))
+#define GSP_L0_PITCH_SET(pitch)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_pitch_u) = (pitch)
+#define GSP_L1_PITCH_SET(pitch)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_pitch_u) = (pitch)
+#define GSP_Ld_PITCH_SET(pitch)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_des_pitch_u) = (pitch)
+
+
+#define GSP_L0_ADDRY_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_y_addr_u.dwValue)
+#define GSP_L0_ADDRUV_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_uv_addr_u.dwValue)
+#define GSP_L0_ADDRVA_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_va_addr_u.dwValue)
+#define GSP_L1_ADDRY_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_y_addr_u.dwValue)
+#define GSP_L1_ADDRUV_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_uv_addr_u.dwValue)
+#define GSP_L1_ADDRVA_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_va_addr_u.dwValue)
+#define GSP_Ld_ADDRY_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_des_y_addr_u.dwValue)
+#define GSP_Ld_ADDRUV_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_des_uv_addr_u.dwValue)
+#define GSP_Ld_ADDRVA_GET() (((GSP_REG_T*)GSP_REG_BASE)->gsp_des_v_addr_u.dwValue)
+
+
+#define GSP_L0_DESRECT_SET(rect)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_des_start_u) = *((uint32_t*)&(rect).st_x);\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_des_size_u) = *((uint32_t*)&(rect).rect_w)
+#define GSP_L1_DESPOS_SET(pos)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_des_start_u) = *(uint32_t*)(&(pos))
+
+
+#define GSP_L0_GREY_SET(grey)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_grey_rgb_u) = *(uint32_t*)(&(grey))
+#define GSP_L1_GREY_SET(grey)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_grey_rgb_u) = *(uint32_t*)(&(grey))
+
+
+#define GSP_L0_ENDIAN_SET(endian_mode)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_endian_u) = \
+ (((endian_mode).y_word_endn & 0x03) << 0)\
+ |(((endian_mode).y_lng_wrd_endn & 0x01) << 2)\
+ |(((endian_mode).uv_word_endn & 0x03) << 3)\
+ |(((endian_mode).uv_lng_wrd_endn & 0x01) << 5)\
+ |(((endian_mode).va_word_endn & 0x03) << 6)\
+ |(((endian_mode).va_lng_wrd_endn & 0x01) << 8)\
+ |(((endian_mode).rgb_swap_mode & 0x07) << 9)\
+ |(((endian_mode).a_swap_mode & 0x01) << 12)
+#define GSP_L1_ENDIAN_SET(endian_mode)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_endian_u) = \
+ (((endian_mode).y_word_endn & 0x03) << 0)\
+ |(((endian_mode).y_lng_wrd_endn & 0x01) << 2)\
+ |(((endian_mode).uv_word_endn & 0x03) << 3)\
+ |(((endian_mode).uv_lng_wrd_endn & 0x01) << 5)\
+ |(((endian_mode).va_word_endn & 0x03) << 6)\
+ |(((endian_mode).va_lng_wrd_endn & 0x01) << 8)\
+ |(((endian_mode).rgb_swap_mode & 0x07) << 9)\
+ |(((endian_mode).a_swap_mode & 0x01) << 12)
+#define GSP_Ld_ENDIAN_SET(endian_mode)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_des_data_endian_u) = \
+ (((endian_mode).y_word_endn & 0x03) << 0)\
+ |(((endian_mode).y_lng_wrd_endn & 0x01) << 2)\
+ |(((endian_mode).uv_word_endn & 0x03) << 3)\
+ |(((endian_mode).uv_lng_wrd_endn & 0x01) << 5)\
+ |(((endian_mode).va_word_endn & 0x03) << 6)\
+ |(((endian_mode).va_lng_wrd_endn & 0x01) << 8)\
+ |(((endian_mode).rgb_swap_mode & 0x07) << 9)\
+ |(((endian_mode).a_swap_mode & 0x01) << 12)
+
+#define GSP_L0_ALPHA_SET(alpha)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_alpha_u) = (alpha)
+#define GSP_L1_ALPHA_SET(alpha)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_alpha_u) = (alpha)
+
+#define GSP_L0_COLORKEY_SET(colorkey)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_ck_u) = *(uint32_t*)(&(colorkey))
+#define GSP_L1_COLORKEY_SET(colorkey)\
+ *(volatile uint32_t*)(&((GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_ck_u) = *(uint32_t*)(&(colorkey))
+
+#define GSP_L0_IMGFORMAT_SET(format)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_cfg_u.mBits.img_format_l0 = (format)
+#define GSP_L1_IMGFORMAT_SET(format)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_cfg_u.mBits.img_format_l1 = (format)
+#define GSP_Ld_IMGFORMAT_SET(format)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_des_data_cfg_u.mBits.des_img_format = (format)
+#define GSP_Ld_COMPRESSRGB888_SET(enable)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_des_data_cfg_u.mBits.compress_r8 = (enable)
+
+#define GSP_L0_ROTMODE_SET(mode)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_cfg_u.mBits.rot_mod_l0 = (mode)
+#define GSP_L1_ROTMODE_SET(mode)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_cfg_u.mBits.rot_mod_l1 = (mode)
+
+#define GSP_L0_COLORKEYENABLE_SET(colorkey_en)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_cfg_u.mBits.ck_en_l0 = (colorkey_en)
+#define GSP_L1_COLORKEYENABLE_SET(colorkey_en)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_cfg_u.mBits.ck_en_l1 = (colorkey_en)
+
+#define GSP_L0_PALLETENABLE_SET(pallet_en)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_cfg_u.mBits.pallet_en_l0 = (pallet_en)
+#define GSP_L1_PALLETENABLE_SET(pallet_en)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer1_cfg_u.mBits.pallet_en_l1 = (pallet_en)
+
+#define GSP_L0_SCALETAPMODE_SET(row_tap,col_tap)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_cfg_u.mBits.row_tap_mod = (row_tap);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_cfg_u.mBits.col_tap_mod = (col_tap)
+
+#define GSP_IRQMODE_SET(mode)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_int_cfg_u.mBits.int_mod = (mode)
+#define GSP_IRQENABLE_SET(int_enable)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_int_cfg_u.mBits.int_en = (int_enable)
+
+ //Level-interrupt clear signal, internal GSP HW module
+
+#define GSP_IRQSTATUS_CLEAR()\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_int_cfg_u.mBits.int_clr = 1;\
+ udelay(10);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_int_cfg_u.mBits.int_clr = 0
+
+#define GSP_WORKSTATUS_GET() (((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.gsp_busy)
+#define GSP_ERRFLAG_GET() (((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.error_flag)
+#define GSP_ERRCODE_GET() (((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.error_code)
+
+#define GSP_DITHER_ENABLE_SET(dith_en)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.dither_en = (dith_en)
+#define GSP_PMARGB_ENABLE_SET(pm_en)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.pmargb_en = (pm_en)
+#define GSP_L0_PMARGBMODE_SET(mode)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.pmargb_mod0 = (mode)
+#define GSP_L1_PMARGBMODE_SET(mode)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.pmargb_mod1 = (mode)
+#define GSP_SCALE_ENABLE_SET(scal_en)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.scale_en = (scal_en)
+#define GSP_SCALE_ENABLE_GET() (((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.scale_en)
+
+//v==0:allowed a burst stride 4K boarder; v==1:split a burst into 2 request , when sride 4K boarder.
+//gsp_cfg_u.mBits.split 0:split 1:don't split
+#define GSP_PAGES_BOARDER_SPLIT_SET(v)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.no_split = (!(v))
+
+#define GSP_Y2R_OPT_SET(v)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.y2r_opt = (v)
+
+
+#define GSP_PAGES_BOARDER_SPLIT_GET()\
+ (!((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.no_split)
+
+#define GSP_SCALESTATUS_RESET()\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.scale_status_clr = 1;\
+ udelay(10);\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.scale_status_clr = 0
+
+#define GSP_L0_ENABLE_SET(enable)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.l0_en = (enable)
+#define GSP_L1_ENABLE_SET(enable)\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.l1_en = (enable)
+#define GSP_ENGINE_TRIGGER()\
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.gsp_run = 1
+
+#define GSP_L0_ENABLE_GET() (((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.l0_en)
+#define GSP_L1_ENABLE_GET() (((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.l1_en)
+
+#define GSP_CFG_L1_PARAM(param)\
+ *(volatile GSP_LAYER1_REG_T *)GSP_L1_BASE = (param)
+ /**---------------------------------------------------------------------------*
+ ** Data Definition *
+ **---------------------------------------------------------------------------*/
+
+ /**---------------------------------------------------------------------------*
+ ** Function Propertype *
+ **---------------------------------------------------------------------------*/
+
+PUBLIC int GSP_Init(gsp_context_t *gspCtx);
+PUBLIC void GSP_Deinit(gsp_context_t *gspCtx);
+PUBLIC void GSP_ConfigLayer(GSP_MODULE_ID_E layer_id, gsp_context_t *gspCtx);
+PUBLIC uint32_t GSP_Trigger(void);
+PUBLIC void GSP_Wait_Finish(void);
+PUBLIC void GSP_module_enable(gsp_context_t *gspCtx);
+PUBLIC void GSP_module_disable(gsp_context_t *gspCtx);
+PUBLIC int GSP_ClocksCheckPhase0(void);
+PUBLIC int GSP_ClocksCheckPhase1(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+//the end of Shark_gsp_drv.h
diff --git a/drivers/media/sprd_gsp/gsp_debug.h b/drivers/media/sprd_gsp/gsp_debug.h
new file mode 100644
index 00000000..7acbb41f
--- /dev/null
+++ b/drivers/media/sprd_gsp/gsp_debug.h
@@ -0,0 +1,336 @@
+
+#ifndef __GSP_DEBUG_IF_H_
+#define __GSP_DEBUG_IF_H_
+
+#include "gsp_drv_common.h"
+
+
+#define ERR_RECORD_INDEX_ADD(v) (v = ((v+1)&(GSP_ERR_RECORD_CNT-1)))
+#define ERR_RECORD_INDEX_ADD_RP() ERR_RECORD_INDEX_ADD(gspCtx->gsp_reg_err_record_rp)
+#define ERR_RECORD_INDEX_ADD_WP() ERR_RECORD_INDEX_ADD(gspCtx->gsp_reg_err_record_wp)
+#define ERR_RECORD_INDEX_GET_RP() (gspCtx->gsp_reg_err_record_rp)
+#define ERR_RECORD_INDEX_GET_WP() (gspCtx->gsp_reg_err_record_wp)
+#define ERR_RECORD_ADD(v) (gspCtx->gsp_reg_err_record[gspCtx->gsp_reg_err_record_wp] = (v))
+#define ERR_RECORD_GET(v) (&gspCtx->gsp_reg_err_record[gspCtx->gsp_reg_err_record_rp])
+#define ERR_RECORD_EMPTY() (gspCtx->gsp_reg_err_record_rp == gspCtx->gsp_reg_err_record_wp)
+#define ERR_RECORD_FULL() (((gspCtx->gsp_reg_err_record_wp+1)&(GSP_ERR_RECORD_CNT-1)) == gspCtx->gsp_reg_err_record_rp)
+
+
+#ifndef GSP_DEBUG
+#define GSP_GAP 0
+#define GSP_CLOCK 3
+#else
+static ulong gsp_gap = 0;
+module_param(gsp_gap, ulong, 0644);//S_IRUGO|S_IWUGO
+MODULE_PARM_DESC(gsp_gap, "gsp ddr gap(0~255)");
+
+static uint gsp_clock = 3;
+module_param(gsp_clock, uint, 0644);
+MODULE_PARM_DESC(gsp_clock, "gsp clock(0:96M 1:153.6M 2:192M 3:256M)");
+
+#define GSP_GAP gsp_gap
+#define GSP_CLOCK gsp_clock
+#endif
+
+#ifdef GSP_DEBUG
+#define GSP_TRACE printk
+#else
+#define GSP_TRACE pr_debug
+#endif
+
+
+static void printCfgInfo(gsp_context_t *gspCtx)// gspDrvdata
+{
+ GSP_CONFIG_INFO_T gsp_cfg;
+
+ if (NULL == gspCtx) {
+ return;
+ }
+
+ gsp_cfg = gspCtx->gsp_cfg;
+
+ printk("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \n");
+ printk( "misc: ahb_clock %d|gsp_clock %d|dithering_en %d|gsp_gap %d\n",
+ gsp_cfg.misc_info.ahb_clock,
+ gsp_cfg.misc_info.gsp_clock,
+ gsp_cfg.misc_info.dithering_en,
+ gsp_cfg.misc_info.gsp_gap);
+
+ printk( "L0: format:%d,pitch:%d,clip(x:%d,y:%d,w:%d,h:%d) =rot:%d=> des(x:%d,y:%d,w:%d,h:%d)\n",
+ gsp_cfg.layer0_info.img_format,
+ gsp_cfg.layer0_info.pitch,
+ gsp_cfg.layer0_info.clip_rect.st_x,
+ gsp_cfg.layer0_info.clip_rect.st_y,
+ gsp_cfg.layer0_info.clip_rect.rect_w,
+ gsp_cfg.layer0_info.clip_rect.rect_h,
+ gsp_cfg.layer0_info.rot_angle,
+ gsp_cfg.layer0_info.des_rect.st_x,
+ gsp_cfg.layer0_info.des_rect.st_y,
+ gsp_cfg.layer0_info.des_rect.rect_w,
+ gsp_cfg.layer0_info.des_rect.rect_h);
+ printk( "L0: alpha:%d,colorkey_en:%d,pallet_en:%d,scaling_en:%d,layer_en:%d,pmargb_en:%d,pmargb_mod:%d\n",
+ gsp_cfg.layer0_info.alpha,
+ gsp_cfg.layer0_info.colorkey_en,
+ gsp_cfg.layer0_info.pallet_en,
+ gsp_cfg.layer0_info.scaling_en,
+ gsp_cfg.layer0_info.layer_en,
+ gsp_cfg.layer0_info.pmargb_en,
+ gsp_cfg.layer0_info.pmargb_mod);
+ printk( "L0: col_tap_mode:%d,row_tap_mode:%d,a_swap_mode:%d,rgb_swap_mode:%d,va_word_endn:%d,va_lng_wrd_endn:%d,uv_word_endn:%d,uv_lng_wrd_endn:%d,y_word_endn:%d,y_lng_wrd_endn:%d\n",
+ gsp_cfg.layer0_info.col_tap_mode,
+ gsp_cfg.layer0_info.row_tap_mode,
+ gsp_cfg.layer0_info.endian_mode.a_swap_mode,
+ gsp_cfg.layer0_info.endian_mode.rgb_swap_mode,
+ gsp_cfg.layer0_info.endian_mode.va_word_endn,
+ gsp_cfg.layer0_info.endian_mode.va_lng_wrd_endn,
+ gsp_cfg.layer0_info.endian_mode.uv_word_endn,
+ gsp_cfg.layer0_info.endian_mode.uv_lng_wrd_endn,
+ gsp_cfg.layer0_info.endian_mode.y_word_endn,
+ gsp_cfg.layer0_info.endian_mode.y_lng_wrd_endn);
+ printk( "L0: addr_y:0x%08x,addr_uv:0x%08x,addr_v:0x%08x,(grey r:%d,g:%d,b:%d,a:%d),(colorkey r:%d,g:%d,b:%d,a:%d)\n",
+ gsp_cfg.layer0_info.src_addr.addr_y,
+ gsp_cfg.layer0_info.src_addr.addr_uv,
+ gsp_cfg.layer0_info.src_addr.addr_v,
+ gsp_cfg.layer0_info.grey.r_val,
+ gsp_cfg.layer0_info.grey.g_val,
+ gsp_cfg.layer0_info.grey.b_val,
+ gsp_cfg.layer0_info.grey.a_val,
+ gsp_cfg.layer0_info.colorkey.r_val,
+ gsp_cfg.layer0_info.colorkey.g_val,
+ gsp_cfg.layer0_info.colorkey.b_val,
+ gsp_cfg.layer0_info.colorkey.a_val);
+
+
+ printk( "L1: format:%d,pitch:%d,clip(x:%d,y:%d,w:%d,h:%d) =rot:%d=> des(x:%d,y:%d)\n",
+ gsp_cfg.layer1_info.img_format,
+ gsp_cfg.layer1_info.pitch,
+ gsp_cfg.layer1_info.clip_rect.st_x,
+ gsp_cfg.layer1_info.clip_rect.st_y,
+ gsp_cfg.layer1_info.clip_rect.rect_w,
+ gsp_cfg.layer1_info.clip_rect.rect_h,
+ gsp_cfg.layer1_info.rot_angle,
+ gsp_cfg.layer1_info.des_pos.pos_pt_x,
+ gsp_cfg.layer1_info.des_pos.pos_pt_y);
+ printk( "L1: alpha:%d,colorkey_en:%d,pallet_en:%d,layer_en:%d,pmargb_en:%d,pmargb_mod:%d\n",
+ gsp_cfg.layer1_info.alpha,
+ gsp_cfg.layer1_info.colorkey_en,
+ gsp_cfg.layer1_info.pallet_en,
+ gsp_cfg.layer1_info.layer_en,
+ gsp_cfg.layer1_info.pmargb_en,
+ gsp_cfg.layer1_info.pmargb_mod);
+
+ printk( "L1: col_tap_mode:%d,row_tap_mode:%d,a_swap_mode:%d,rgb_swap_mode:%d,va_word_endn:%d,va_lng_wrd_endn:%d,uv_word_endn:%d,uv_lng_wrd_endn:%d,y_word_endn:%d,y_lng_wrd_endn:%d\n",
+ gsp_cfg.layer1_info.col_tap_mode,
+ gsp_cfg.layer1_info.row_tap_mode,
+ gsp_cfg.layer1_info.endian_mode.a_swap_mode,
+ gsp_cfg.layer1_info.endian_mode.rgb_swap_mode,
+ gsp_cfg.layer1_info.endian_mode.va_word_endn,
+ gsp_cfg.layer1_info.endian_mode.va_lng_wrd_endn,
+ gsp_cfg.layer1_info.endian_mode.uv_word_endn,
+ gsp_cfg.layer1_info.endian_mode.uv_lng_wrd_endn,
+ gsp_cfg.layer1_info.endian_mode.y_word_endn,
+ gsp_cfg.layer1_info.endian_mode.y_lng_wrd_endn);
+ printk( "L1: addr_y:0x%08x,addr_uv:0x%08x,addr_v:0x%08x,(grey r:%d,g:%d,b:%d,a:%d),(colorkey r:%d,g:%d,b:%d,a:%d)\n",
+ gsp_cfg.layer1_info.src_addr.addr_y,
+ gsp_cfg.layer1_info.src_addr.addr_uv,
+ gsp_cfg.layer1_info.src_addr.addr_v,
+ gsp_cfg.layer1_info.grey.r_val,
+ gsp_cfg.layer1_info.grey.g_val,
+ gsp_cfg.layer1_info.grey.b_val,
+ gsp_cfg.layer1_info.grey.a_val,
+ gsp_cfg.layer1_info.colorkey.r_val,
+ gsp_cfg.layer1_info.colorkey.g_val,
+ gsp_cfg.layer1_info.colorkey.b_val,
+ gsp_cfg.layer1_info.colorkey.a_val);
+
+
+ printk( "Ld cfg:fmt:%d|pitch %04d|cmpr8 %d\n",
+ gsp_cfg.layer_des_info.img_format,
+ gsp_cfg.layer_des_info.pitch,
+ gsp_cfg.layer_des_info.compress_r8_en);
+ printk( "Ld Yaddr 0x%08x|Uaddr 0x%08x|Vaddr 0x%08x\n",
+ gsp_cfg.layer_des_info.src_addr.addr_y,
+ gsp_cfg.layer_des_info.src_addr.addr_uv,
+ gsp_cfg.layer_des_info.src_addr.addr_v);
+ printk( "Ld:a_swap_mode:%d,rgb_swap_mode:%d,va_word_endn:%d,va_lng_wrd_endn:%d,uv_word_endn:%d,uv_lng_wrd_endn:%d,y_word_endn:%d,y_lng_wrd_endn:%d\n",
+ gsp_cfg.layer_des_info.endian_mode.a_swap_mode,
+ gsp_cfg.layer_des_info.endian_mode.rgb_swap_mode,
+ gsp_cfg.layer_des_info.endian_mode.va_word_endn,
+ gsp_cfg.layer_des_info.endian_mode.va_lng_wrd_endn,
+ gsp_cfg.layer_des_info.endian_mode.uv_word_endn,
+ gsp_cfg.layer_des_info.endian_mode.uv_lng_wrd_endn,
+ gsp_cfg.layer_des_info.endian_mode.y_word_endn,
+ gsp_cfg.layer_des_info.endian_mode.y_lng_wrd_endn);
+ printk("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \n");
+}
+
+
+static void printGPSReg(void)
+{
+ GSP_REG_T *g_gsp_reg = (GSP_REG_T *)GSP_REG_BASE;
+ uint32_t i = 0;
+
+ printk("********************************************* \n");
+ printk("GSP_EN 0x%08x: 0x%08x; 0x%08x: 0x%08x; 0x%08x: 0x%08x;\n",
+ (0X20D00000),GSP_REG_READ(GSP_MOD_EN),
+ (0X20D01000),GSP_REG_READ(GSP_MOD_EN+0x1000),
+ (0X20D02000),GSP_REG_READ(GSP_MOD_EN+0x1000));//
+ printk("GSP_RESET 0x%08x: 0x%08x; 0x%08x: 0x%08x; 0x%08x: 0x%08x;\n",
+ (0X20D00004),GSP_REG_READ(GSP_SOFT_RESET),
+ (0X20D01004),GSP_REG_READ(GSP_SOFT_RESET+0x1000),
+ (0X20D02004),GSP_REG_READ(GSP_SOFT_RESET+0x1000));//
+ printk("AUTO_GATE 0x%08x: 0x%08x; 0x%08x: 0x%08x; 0x%08x: 0x%08x;\n",
+ (0X20D00040),GSP_REG_READ(GSP_AUTO_GATE_ENABLE_BASE),
+ (0X20D01040),GSP_REG_READ(GSP_AUTO_GATE_ENABLE_BASE+0x1000),
+ (0X20D02040),GSP_REG_READ(GSP_AUTO_GATE_ENABLE_BASE+0x1000));//
+ printk("GSP_CLOCK 0x%08x: 0x%08x \n",(0X71200028),GSP_REG_READ(GSP_CLOCK_BASE));
+ printk("AHB_CLOCK 0x%08x: 0x%08x \n",(0X71200020),GSP_REG_READ(GSP_AHB_CLOCK_BASE));
+ printk("EMC_EN 0x%08x: 0x%08x \n",(0X402E0004),GSP_REG_READ(GSP_EMC_MATRIX_BASE));
+
+ while(i < 0x198) {
+ printk("0x%08x: 0x%08x \n",(0x20a00000+i),GSP_REG_READ(GSP_REG_BASE+i));
+ i += 4;
+ }
+ printk( "misc: run %d|busy %d|errflag %d|errcode %02d|dither %d|pmmod0 %d|pmmod1 %d|pmen %d|scale %d|reserv2 %d|scl_stat_clr %d|l0en %d|l1en %d|rb %d\n",
+ g_gsp_reg->gsp_cfg_u.mBits.gsp_run,
+ g_gsp_reg->gsp_cfg_u.mBits.gsp_busy,
+ g_gsp_reg->gsp_cfg_u.mBits.error_flag,
+ g_gsp_reg->gsp_cfg_u.mBits.error_code,
+ g_gsp_reg->gsp_cfg_u.mBits.dither_en,
+ g_gsp_reg->gsp_cfg_u.mBits.pmargb_mod0,
+ g_gsp_reg->gsp_cfg_u.mBits.pmargb_mod1,
+ g_gsp_reg->gsp_cfg_u.mBits.pmargb_en,
+ g_gsp_reg->gsp_cfg_u.mBits.scale_en,
+ g_gsp_reg->gsp_cfg_u.mBits.y2r_opt,
+ g_gsp_reg->gsp_cfg_u.mBits.scale_status_clr,
+ g_gsp_reg->gsp_cfg_u.mBits.l0_en,
+ g_gsp_reg->gsp_cfg_u.mBits.l1_en,
+ g_gsp_reg->gsp_cfg_u.mBits.dist_rb);
+ printk( "misc: inten %d|intmod %d|intclr %d\n",
+ g_gsp_reg->gsp_int_cfg_u.mBits.int_en,
+ g_gsp_reg->gsp_int_cfg_u.mBits.int_mod,
+ g_gsp_reg->gsp_int_cfg_u.mBits.int_clr);
+
+
+ printk( "L0 cfg:fmt %d|rot %d|ck %d|pallet %d|rowtap %d|coltap %d\n",
+ g_gsp_reg->gsp_layer0_cfg_u.mBits.img_format_l0,
+ g_gsp_reg->gsp_layer0_cfg_u.mBits.rot_mod_l0,
+ g_gsp_reg->gsp_layer0_cfg_u.mBits.ck_en_l0,
+ g_gsp_reg->gsp_layer0_cfg_u.mBits.pallet_en_l0,
+ g_gsp_reg->gsp_layer0_cfg_u.mBits.row_tap_mod,
+ g_gsp_reg->gsp_layer0_cfg_u.mBits.col_tap_mod);
+ printk( "L0 blockalpha %03d, pitch %04d,(%04d,%04d)%04dx%04d => (%04d,%04d)%04dx%04d\n",
+ g_gsp_reg->gsp_layer0_alpha_u.mBits.alpha_l0,
+ g_gsp_reg->gsp_layer0_pitch_u.mBits.pitch0,
+ g_gsp_reg->gsp_layer0_clip_start_u.mBits.clip_start_x_l0,
+ g_gsp_reg->gsp_layer0_clip_start_u.mBits.clip_start_y_l0,
+ g_gsp_reg->gsp_layer0_clip_size_u.mBits.clip_size_x_l0,
+ g_gsp_reg->gsp_layer0_clip_size_u.mBits.clip_size_y_l0,
+ g_gsp_reg->gsp_layer0_des_start_u.mBits.des_start_x_l0,
+ g_gsp_reg->gsp_layer0_des_start_u.mBits.des_start_y_l0,
+ g_gsp_reg->gsp_layer0_des_size_u.mBits.des_size_x_l0,
+ g_gsp_reg->gsp_layer0_des_size_u.mBits.des_size_y_l0);
+ printk( "L0 Yaddr 0x%08x|Uaddr 0x%08x|Vaddr 0x%08x\n",
+ g_gsp_reg->gsp_layer0_y_addr_u.dwValue,
+ g_gsp_reg->gsp_layer0_uv_addr_u.dwValue,
+ g_gsp_reg->gsp_layer0_va_addr_u.dwValue);
+ printk( "L0 grey(%03d,%03d,%03d) colorkey(%03d,%03d,%03d)\n",
+ g_gsp_reg->gsp_layer0_grey_rgb_u.mBits.layer0_grey_r,
+ g_gsp_reg->gsp_layer0_grey_rgb_u.mBits.layer0_grey_g,
+ g_gsp_reg->gsp_layer0_grey_rgb_u.mBits.layer0_grey_b,
+ g_gsp_reg->gsp_layer0_ck_u.mBits.ck_r_l0,
+ g_gsp_reg->gsp_layer0_ck_u.mBits.ck_g_l0,
+ g_gsp_reg->gsp_layer0_ck_u.mBits.ck_b_l0);
+ printk( "L0 endian: y %d|u %d|v %d|rgb %d|alpha %d\n",
+ g_gsp_reg->gsp_layer0_endian_u.mBits.y_endian_mod_l0,
+ g_gsp_reg->gsp_layer0_endian_u.mBits.uv_endian_mod_l0,
+ g_gsp_reg->gsp_layer0_endian_u.mBits.va_endian_mod_l0,
+ g_gsp_reg->gsp_layer0_endian_u.mBits.rgb_swap_mod_l0,
+ g_gsp_reg->gsp_layer0_endian_u.mBits.a_swap_mod_l0);
+
+
+ printk( "L1 cfg:fmt %d|rot %d|ck %d|pallet %d\n",
+ g_gsp_reg->gsp_layer1_cfg_u.mBits.img_format_l1,
+ g_gsp_reg->gsp_layer1_cfg_u.mBits.rot_mod_l1,
+ g_gsp_reg->gsp_layer1_cfg_u.mBits.ck_en_l1,
+ g_gsp_reg->gsp_layer1_cfg_u.mBits.pallet_en_l1);
+ printk( "L1 blockalpha %03d, pitch %04d,(%04d,%04d)%04dx%04d => (%04d,%04d)\n",
+ g_gsp_reg->gsp_layer1_alpha_u.mBits.alpha_l1,
+ g_gsp_reg->gsp_layer1_pitch_u.mBits.pitch1,
+ g_gsp_reg->gsp_layer1_clip_start_u.mBits.clip_start_x_l1,
+ g_gsp_reg->gsp_layer1_clip_start_u.mBits.clip_start_y_l1,
+ g_gsp_reg->gsp_layer1_clip_size_u.mBits.clip_size_x_l1,
+ g_gsp_reg->gsp_layer1_clip_size_u.mBits.clip_size_y_l1,
+ g_gsp_reg->gsp_layer1_des_start_u.mBits.des_start_x_l1,
+ g_gsp_reg->gsp_layer1_des_start_u.mBits.des_start_y_l1);
+ printk( "L1 Yaddr 0x%08x|Uaddr 0x%08x|Vaddr 0x%08x\n",
+ g_gsp_reg->gsp_layer1_y_addr_u.dwValue,
+ g_gsp_reg->gsp_layer1_uv_addr_u.dwValue,
+ g_gsp_reg->gsp_layer1_va_addr_u.dwValue);
+ printk( "L1 grey(%03d,%03d,%03d) colorkey(%03d,%03d,%03d)\n",
+ g_gsp_reg->gsp_layer1_grey_rgb_u.mBits.grey_r_l1,
+ g_gsp_reg->gsp_layer1_grey_rgb_u.mBits.grey_g_l1,
+ g_gsp_reg->gsp_layer1_grey_rgb_u.mBits.grey_b_l1,
+ g_gsp_reg->gsp_layer1_ck_u.mBits.ck_r_l1,
+ g_gsp_reg->gsp_layer1_ck_u.mBits.ck_g_l1,
+ g_gsp_reg->gsp_layer1_ck_u.mBits.ck_b_l1);
+ printk( "L1 endian: y %d|u %d|v %d|rgb %d|alpha %d\n",
+ g_gsp_reg->gsp_layer1_endian_u.mBits.y_endian_mod_l1,
+ g_gsp_reg->gsp_layer1_endian_u.mBits.uv_endian_mod_l1,
+ g_gsp_reg->gsp_layer1_endian_u.mBits.va_endian_mod_l1,
+ g_gsp_reg->gsp_layer1_endian_u.mBits.rgb_swap_mod_l1,
+ g_gsp_reg->gsp_layer1_endian_u.mBits.a_swap_mod_l1);
+
+
+ printk( "Ld cfg:fmt %d|cmpr8 %d|pitch %04d\n",
+ g_gsp_reg->gsp_des_data_cfg_u.mBits.des_img_format,
+ g_gsp_reg->gsp_des_data_cfg_u.mBits.compress_r8,
+ g_gsp_reg->gsp_des_pitch_u.mBits.des_pitch);
+ printk( "Ld Yaddr 0x%08x|Uaddr 0x%08x|Vaddr 0x%08x\n",
+ g_gsp_reg->gsp_des_y_addr_u.dwValue,
+ g_gsp_reg->gsp_des_uv_addr_u.dwValue,
+ g_gsp_reg->gsp_des_v_addr_u.dwValue);
+ printk( "Ld endian: y %d|u %d|v %d|rgb %d|alpha %d\n",
+ g_gsp_reg->gsp_des_data_endian_u.mBits.y_endian_mod,
+ g_gsp_reg->gsp_des_data_endian_u.mBits.uv_endian_mod,
+ g_gsp_reg->gsp_des_data_endian_u.mBits.v_endian_mod,
+ g_gsp_reg->gsp_des_data_endian_u.mBits.rgb_swap_mod,
+ g_gsp_reg->gsp_des_data_endian_u.mBits.a_swap_mod);
+ printk( "********************************************* \n");
+}
+
+static void GPSTimeoutPrint(gsp_context_t *gspCtx)
+{
+ printk("%s%d:GSP_EN:0x%08x,EMC_MATRIX:0x%08x,IOMMU:0x%08x,GSP_GAP:0x%08x,GSP_CLOCK:0x%08x,GSP_AUTO_GATE:0x%08x\n",__func__,__LINE__,
+ (uint32_t)(GSP_REG_READ(GSP_MOD_EN)&GSP_MOD_EN_BIT),
+ (uint32_t)(GSP_REG_READ(GSP_EMC_MATRIX_BASE)&GSP_EMC_MATRIX_BIT),
+ GSP_REG_READ(GSP_MMU_CTRL_BASE),
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_cfg_u.mBits.dist_rb,
+ GSP_REG_READ(GSP_CLOCK_BASE)&0x3,
+ (uint32_t)(GSP_REG_READ(GSP_AUTO_GATE_ENABLE_BASE)&GSP_AUTO_GATE_ENABLE_BIT));
+ printCfgInfo(gspCtx);
+ printGPSReg();
+}
+
+void printCMDQ(GSP_LAYER1_REG_T *pDescriptors, uint32_t c)
+{
+ uint32_t i = 0;
+ while(i < c) {
+ printk("CMDQ[%d]cfg:%08x\n",i,pDescriptors->gsp_layer1_cfg_u.dwValue);
+ printk("CMDQ[%d]YADDR:%08x\n",i,pDescriptors->gsp_layer1_y_addr_u.dwValue);
+ printk("CMDQ[%d]UADDR:%08x\n",i,pDescriptors->gsp_layer1_uv_addr_u.dwValue);
+ printk("CMDQ[%d]VADDR:%08x\n",i,pDescriptors->gsp_layer1_va_addr_u.dwValue);
+ printk("CMDQ[%d]Pitch:%08x\n",i,pDescriptors->gsp_layer1_pitch_u.dwValue);
+ printk("CMDQ[%d]clip x:%04d y:%04d\n",i,pDescriptors->gsp_layer1_clip_start_u.mBits.clip_start_x_l1,pDescriptors->gsp_layer1_clip_start_u.mBits.clip_start_y_l1);
+ printk("CMDQ[%d]clip w:%04d h:%04d\n",i,pDescriptors->gsp_layer1_clip_size_u.mBits.clip_size_x_l1,pDescriptors->gsp_layer1_clip_size_u.mBits.clip_size_y_l1);
+ printk("CMDQ[%d]des x:%04d y:%04d\n",i,pDescriptors->gsp_layer1_des_start_u.mBits.des_start_x_l1,pDescriptors->gsp_layer1_des_start_u.mBits.des_start_y_l1);
+ printk("CMDQ[%d]GREY:%08x\n",i,pDescriptors->gsp_layer1_grey_rgb_u.dwValue);
+ printk("CMDQ[%d]Endian:%08x\n",i,pDescriptors->gsp_layer1_endian_u.dwValue);
+ printk("CMDQ[%d]Alpha:%08x\n",i,pDescriptors->gsp_layer1_alpha_u.dwValue);
+ printk("CMDQ[%d]CK:%08x\n",i,pDescriptors->gsp_layer1_ck_u.dwValue);
+ i++;
+ pDescriptors++;
+ }
+}
+
+#endif
diff --git a/drivers/media/sprd_gsp/gsp_drv.c b/drivers/media/sprd_gsp/gsp_drv.c
new file mode 100644
index 00000000..8606f668
--- /dev/null
+++ b/drivers/media/sprd_gsp/gsp_drv.c
@@ -0,0 +1,1253 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <linux/math64.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/io.h>//for ioremap
+#include <linux/pid.h>
+
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#endif
+
+#include <soc/sprd/arch_misc.h>// get chip id
+#include <video/ion_sprd.h>
+//#include "gsp_drv.h"
+#include "gsp_config_if.h"
+#include "scaler_coef_cal.h"
+
+#include "gsp_debug.h"
+
+
+
+#ifdef CONFIG_OF
+static struct device *s_gsp_of_dev = NULL;
+ulong g_gsp_base_addr = 0;
+ulong g_gsp_mmu_ctrl_addr = 0;
+#endif
+gsp_context_t *g_gspCtx = NULL;// only used to debug when kernel crash, not used to pass parameters
+
+static gsp_user* gsp_get_user(pid_t user_pid, gsp_context_t *gspCtx)
+{
+ gsp_user* ret_user = NULL;
+ int i;
+
+ for (i = 0; i < GSP_MAX_USER; i ++) {
+ if ((gspCtx->gsp_user_array + i)->pid == user_pid) {
+ ret_user = gspCtx->gsp_user_array + i;
+ break;
+ }
+ }
+
+ if (ret_user == NULL) {
+ for (i = 0; i < GSP_MAX_USER; i ++) {
+ if ((gspCtx->gsp_user_array + i)->pid == INVALID_USER_ID) {
+ ret_user = gspCtx->gsp_user_array + i;
+ ret_user->pid = user_pid;
+ break;
+ }
+ }
+ }
+
+ return ret_user;
+}
+
+
+static int32_t gsp_drv_open(struct inode *node, struct file *file)
+{
+ int32_t ret = GSP_NO_ERR;
+ gsp_user *pUserdata = NULL;
+ struct miscdevice *miscdev = NULL;
+ gsp_context_t *gspCtx = NULL;
+ GSP_TRACE("gsp_drv_open:pid:0x%08x enter.\n",current->pid);
+
+ miscdev = file->private_data;
+ if (NULL == miscdev) {
+ return -EINVAL;
+ }
+ gspCtx = container_of(miscdev, gsp_context_t , dev);
+ if (NULL == gspCtx) {
+ return -EINVAL;
+ }
+
+ pUserdata = (gsp_user *)gsp_get_user(current->pid, gspCtx);
+
+ if (NULL == pUserdata) {
+ printk("gsp_drv_open:pid:0x%08x user cnt full.\n",current->pid);
+ ret = GSP_KERNEL_FULL;
+ goto exit;
+ }
+ GSP_TRACE("gsp_drv_open:pid:0x%08x bf wait open sema.\n",current->pid);
+ ret = down_interruptible(&pUserdata->sem_open);
+ if(!ret) { //ret==0, wait success
+ GSP_TRACE("gsp_drv_open:pid:0x%08x wait open sema success.\n",current->pid);
+ pUserdata->priv = (void*)gspCtx;
+ file->private_data = pUserdata;
+ } else { //ret == -EINTR
+ ret = GSP_KERNEL_OPEN_INTR;
+ printk("gsp_drv_open:pid:0x%08x wait open sema failed.\n",current->pid);
+ }
+
+exit:
+ return ret;
+}
+
+
+static int32_t gsp_drv_release(struct inode *node, struct file *file)
+{
+ gsp_user* pUserdata = file->private_data;
+
+ GSP_TRACE("gsp_drv_release:pid:0x%08x.\n\n",current->pid);
+ if(pUserdata == NULL) {
+ printk("gsp_drv_release:error--pUserdata is null!, pid-0x%08x \n\n",current->pid);
+ return -ENODEV;
+ }
+ pUserdata->pid = INVALID_USER_ID;
+ sema_init(&pUserdata->sem_open, 1);
+ /*
+ //if caller thread hold gsp_hw_resource_sem,but was terminated,we release hw semaphore here
+ if(gsp_cur_client_pid == current->pid)
+ {
+ GSP_Wait_Finish();//wait busy-bit down
+ GSP_Deinit();
+ //pUserdata->own_gsp_flag = 0;
+ gsp_cur_client_pid = INVALID_USER_ID;
+ sema_init(&gsp_wait_interrupt_sem,0);
+ GSP_TRACE("%s:pid:0x%08x, release gsp-hw sema, L%d \n",__func__,pUserdata->pid,__LINE__);
+ up(&gsp_hw_resource_sem);
+ }
+ */
+ file->private_data = NULL;
+
+ return GSP_NO_ERR;
+}
+
+
+ssize_t gsp_drv_write(struct file *file, const char __user * u_data, size_t cnt, loff_t *cnt_ret)
+{
+ gsp_user* pUserdata = file->private_data;
+
+ if(pUserdata == NULL) {
+ printk("%s:error--pUserdata is null!, pid-0x%08x \n\n",__func__,current->pid);
+ return -ENODEV;
+ }
+
+ GSP_TRACE("gsp_drv_write:pid:0x%08x.\n",current->pid);
+
+ pUserdata->is_exit_force = 1;
+ /*
+ nomater the target thread "pUserdata->pid" wait on done-sema or hw resource sema,
+ send a signal to resume it and make it return from ioctl(),we does not up a sema to make target
+ thread can distinguish GSP done and signal interrupt.
+ */
+ //send_sig(SIGABRT, (struct task_struct *)pUserdata->pid, 0);
+
+ return 1;
+}
+
+ssize_t gsp_drv_read(struct file *file, char __user *u_data, size_t cnt, loff_t *cnt_ret)
+{
+ char rt_word[32]= {0};
+ gsp_user* pUserdata = file->private_data;
+
+ if(pUserdata == NULL) {
+ printk("%s:error--pUserdata is null!, pid-0x%08x \n\n",__func__,current->pid);
+ return -ENODEV;
+ }
+
+ *cnt_ret = 0;
+ *cnt_ret += sprintf(rt_word + *cnt_ret, "gsp read %zd\n",cnt);
+ return copy_to_user(u_data, (void*)rt_word, (ulong)*cnt_ret);
+}
+
+
+static void GSP_Coef_Tap_Convert(uint8_t h_tap,uint8_t v_tap, gsp_context_t *gspCtx)
+{
+ switch(h_tap) {
+ case 8:
+ gspCtx->gsp_cfg.layer0_info.row_tap_mode = 0;
+ break;
+
+ case 6:
+ gspCtx->gsp_cfg.layer0_info.row_tap_mode = 1;
+ break;
+
+ case 4:
+ gspCtx->gsp_cfg.layer0_info.row_tap_mode = 2;
+ break;
+
+ case 2:
+ gspCtx->gsp_cfg.layer0_info.row_tap_mode = 3;
+ break;
+
+ default:
+ gspCtx->gsp_cfg.layer0_info.row_tap_mode = 0;
+ break;
+ }
+
+ switch(v_tap) {
+ case 8:
+ gspCtx->gsp_cfg.layer0_info.col_tap_mode = 0;
+ break;
+
+ case 6:
+ gspCtx->gsp_cfg.layer0_info.col_tap_mode = 1;
+ break;
+
+ case 4:
+ gspCtx->gsp_cfg.layer0_info.col_tap_mode = 2;
+ break;
+
+ case 2:
+ gspCtx->gsp_cfg.layer0_info.col_tap_mode = 3;
+ break;
+
+ default:
+ gspCtx->gsp_cfg.layer0_info.col_tap_mode = 0;
+ break;
+ }
+ gspCtx->gsp_cfg.layer0_info.row_tap_mode &= 0x3;
+ gspCtx->gsp_cfg.layer0_info.col_tap_mode &= 0x3;
+}
+
+
+static int32_t GSP_Scaling_Coef_Gen_And_Config(ulong* force_calc, gsp_context_t *gspCtx)
+{
+ uint8_t h_tap = 8;
+ uint8_t v_tap = 8;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t coef_factor_w = 0;
+ uint32_t coef_factor_h = 0;
+ uint32_t after_rotate_w = 0;
+ uint32_t after_rotate_h = 0;
+ uint32_t coef_in_w = 0;
+ uint32_t coef_in_h = 0;
+ uint32_t coef_out_w = 0;
+ uint32_t coef_out_h = 0;
+ static volatile uint32_t coef_in_w_last = 0;//if the new in w h out w h equal last params, don't need calc again
+ static volatile uint32_t coef_in_h_last = 0;
+ static volatile uint32_t coef_out_w_last = 0;
+ static volatile uint32_t coef_out_h_last = 0;
+ static volatile uint32_t coef_h_tap_last = 0;
+ static volatile uint32_t coef_v_tap_last = 0;
+
+ if(gspCtx->gsp_cfg.layer0_info.scaling_en == 1) {
+ if(gspCtx->gsp_cfg.layer0_info.des_rect.rect_w < 4
+ ||gspCtx->gsp_cfg.layer0_info.des_rect.rect_h < 4) {
+ return GSP_KERNEL_GEN_OUT_RANG;
+ }
+
+ if(gspCtx->gsp_cfg.layer0_info.rot_angle == GSP_ROT_ANGLE_0
+ ||gspCtx->gsp_cfg.layer0_info.rot_angle == GSP_ROT_ANGLE_180
+ ||gspCtx->gsp_cfg.layer0_info.rot_angle == GSP_ROT_ANGLE_0_M
+ ||gspCtx->gsp_cfg.layer0_info.rot_angle == GSP_ROT_ANGLE_180_M) {
+ after_rotate_w = gspCtx->gsp_cfg.layer0_info.clip_rect.rect_w;
+ after_rotate_h = gspCtx->gsp_cfg.layer0_info.clip_rect.rect_h;
+ } else if(gspCtx->gsp_cfg.layer0_info.rot_angle == GSP_ROT_ANGLE_90
+ ||gspCtx->gsp_cfg.layer0_info.rot_angle == GSP_ROT_ANGLE_270
+ ||gspCtx->gsp_cfg.layer0_info.rot_angle == GSP_ROT_ANGLE_90_M
+ ||gspCtx->gsp_cfg.layer0_info.rot_angle == GSP_ROT_ANGLE_270_M) {
+ after_rotate_w = gspCtx->gsp_cfg.layer0_info.clip_rect.rect_h;
+ after_rotate_h = gspCtx->gsp_cfg.layer0_info.clip_rect.rect_w;
+ }
+
+ coef_factor_w = CEIL(after_rotate_w,gspCtx->gsp_cfg.layer0_info.des_rect.rect_w);
+ coef_factor_h = CEIL(after_rotate_h,gspCtx->gsp_cfg.layer0_info.des_rect.rect_h);
+
+ if(coef_factor_w > 16 || coef_factor_h > 16) {
+ return GSP_KERNEL_GEN_OUT_RANG;
+ }
+
+ if(coef_factor_w > 8) {
+ coef_factor_w = 4;
+ } else if(coef_factor_w > 4) {
+ coef_factor_w = 2;
+ } else {
+ coef_factor_w = 1;
+ }
+
+ if(coef_factor_h > 8) {
+ coef_factor_h = 4;
+ } else if(coef_factor_h > 4) {
+ coef_factor_h = 2;
+ } else {
+ coef_factor_h= 1;
+ }
+
+ coef_in_w = CEIL(after_rotate_w,coef_factor_w);
+ coef_in_h = CEIL(after_rotate_h,coef_factor_h);
+ coef_out_w = gspCtx->gsp_cfg.layer0_info.des_rect.rect_w;
+ coef_out_h = gspCtx->gsp_cfg.layer0_info.des_rect.rect_h;
+
+ if(GSP_SRC_FMT_RGB565 < gspCtx->gsp_cfg.layer0_info.img_format
+ && gspCtx->gsp_cfg.layer0_info.img_format < GSP_SRC_FMT_8BPP
+ && (coef_in_w>coef_out_w||coef_in_h>coef_out_h)) { //video scaling down
+ h_tap = 2;
+ v_tap = 2;
+ if(coef_in_w*3 <= coef_in_h*2) { // height is larger than 1.5*width
+ v_tap = 4;
+ }
+ if(coef_in_h*3 <= coef_in_w*2) { // width is larger than 1.5*height
+ h_tap = 4;
+ }
+ //GSP_TRACE("GSP, for video scaling down, we change tap to 2.\n");
+ }
+
+ //give hal a chance to set tap number
+ if((gspCtx->gsp_cfg.layer0_info.row_tap_mode>0) || (gspCtx->gsp_cfg.layer0_info.col_tap_mode>0)) {
+ //GSP_TRACE("GSP, hwc set tap: %dx%d-> ",h_tap,v_tap);
+ h_tap = (gspCtx->gsp_cfg.layer0_info.row_tap_mode>0)?gspCtx->gsp_cfg.layer0_info.row_tap_mode:h_tap;
+ v_tap = (gspCtx->gsp_cfg.layer0_info.col_tap_mode>0)?gspCtx->gsp_cfg.layer0_info.col_tap_mode:v_tap;
+ //GSP_TRACE("%dx%d\n",h_tap,v_tap);
+ }
+
+ if(*force_calc == 1
+ ||coef_in_w_last != coef_in_w
+ || coef_in_h_last != coef_in_h
+ || coef_out_w_last != coef_out_w
+ || coef_out_h_last != coef_out_h
+ || coef_h_tap_last != h_tap
+ || coef_v_tap_last != v_tap) {
+ tmp_buf = (uint32_t *)kmalloc(GSP_COEFF_BUF_SIZE, GFP_KERNEL);
+ if (NULL == tmp_buf) {
+ printk("SCALE DRV: No mem to alloc coeff buffer! \n");
+ return GSP_KERNEL_GEN_ALLOC_ERR;
+ }
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (GSP_COEFF_COEF_SIZE/4);
+
+ if (!(GSP_Gen_Block_Ccaler_Coef(coef_in_w,
+ coef_in_h,
+ coef_out_w,
+ coef_out_h,
+ h_tap,
+ v_tap,
+ h_coeff,
+ v_coeff,
+ tmp_buf + (GSP_COEFF_COEF_SIZE/2),
+ GSP_COEFF_POOL_SIZE, gspCtx))) {
+ kfree(tmp_buf);
+ printk("GSP DRV: GSP_Gen_Block_Ccaler_Coef error! \n");
+ return GSP_KERNEL_GEN_COMMON_ERR;
+ }
+ GSP_Scale_Coef_Tab_Config(h_coeff,v_coeff);//write coef-metrix to register
+ coef_in_w_last = coef_in_w;
+ coef_in_h_last = coef_in_h;
+ coef_out_w_last = coef_out_w;
+ coef_out_h_last = coef_out_h;
+ coef_h_tap_last = h_tap;
+ coef_v_tap_last = v_tap;
+ *force_calc = 0;
+ }
+
+ GSP_Coef_Tap_Convert(coef_h_tap_last,coef_v_tap_last, gspCtx);
+ GSP_L0_SCALETAPMODE_SET(gspCtx->gsp_cfg.layer0_info.row_tap_mode,gspCtx->gsp_cfg.layer0_info.col_tap_mode);
+ GSP_TRACE("GSP DRV: GSP_Gen_Block_Ccaler_Coef, register: r_tap%d,c_tap %d \n",
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_cfg_u.mBits.row_tap_mod,
+ ((volatile GSP_REG_T*)GSP_REG_BASE)->gsp_layer0_cfg_u.mBits.col_tap_mod);//
+ kfree(tmp_buf);
+ }
+ return GSP_NO_ERR;
+}
+
+/*
+func:GSP_Info_Config
+desc:config info to register
+*/
+static uint32_t GSP_Info_Config(gsp_context_t *gspCtx)
+{
+ GSP_ConfigLayer(GSP_MODULE_LAYER0,gspCtx);
+ GSP_ConfigLayer(GSP_MODULE_LAYER1,gspCtx);
+ GSP_ConfigLayer(GSP_MODULE_ID_MAX,gspCtx);
+ GSP_ConfigLayer(GSP_MODULE_DST,gspCtx);
+ return GSP_ERRCODE_GET();
+}
+
+/*
+func:GSP_Cache_Flush
+desc:
+*/
+static void GSP_Cache_Flush(void)
+{
+
+}
+
+/*
+func:GSP_Cache_Invalidate
+desc:
+*/
+static void GSP_Cache_Invalidate(void)
+{
+
+}
+
+/*
+func:GSP_Release_HWSema
+desc:
+*/
+static void GSP_Release_HWSema(gsp_context_t *gspCtx)
+{
+ gsp_user *pTempUserdata = NULL;
+
+ GSP_TRACE("%s:pid:0x%08x, was killed without release GSP hw semaphore, L%d \n",__func__,gspCtx->gsp_cur_client_pid,__LINE__);
+
+ pTempUserdata = (gsp_user *)gsp_get_user(gspCtx->gsp_cur_client_pid, gspCtx);
+ pTempUserdata->pid = INVALID_USER_ID;
+ sema_init(&pTempUserdata->sem_open, 1);
+
+ GSP_Wait_Finish();//wait busy-bit down
+ GSP_Deinit(gspCtx);
+ gspCtx->gsp_cur_client_pid = INVALID_USER_ID;
+ sema_init(&gspCtx->gsp_wait_interrupt_sem,0);
+ up(&gspCtx->gsp_hw_resource_sem);
+}
+
+static int GSP_Map(gsp_context_t *gspCtx)
+{
+ struct ion_addr_data data;
+
+ if(gspCtx->gsp_cfg.layer0_info.src_addr.addr_y == 0
+ &&gspCtx->gsp_cfg.layer0_info.mem_info.share_fd) {
+ data.fd_buffer = gspCtx->gsp_cfg.layer0_info.mem_info.share_fd;
+ if(sprd_ion_get_gsp_addr(&data)) {
+ printk("%s, L%d, error!\n",__func__,__LINE__);
+ return -1;
+ }
+ if(data.iova_enabled)
+ gspCtx->gsp_cfg.layer0_info.src_addr.addr_y = data.iova_addr;
+ else
+ gspCtx->gsp_cfg.layer0_info.src_addr.addr_y = data.phys_addr;
+ gspCtx->gsp_cfg.layer0_info.src_addr.addr_uv = gspCtx->gsp_cfg.layer0_info.src_addr.addr_y + gspCtx->gsp_cfg.layer0_info.mem_info.uv_offset;
+ gspCtx->gsp_cfg.layer0_info.src_addr.addr_v = gspCtx->gsp_cfg.layer0_info.src_addr.addr_y + gspCtx->gsp_cfg.layer0_info.mem_info.v_offset;
+ }
+
+ if(gspCtx->gsp_cfg.layer1_info.src_addr.addr_y == 0
+ &&gspCtx->gsp_cfg.layer1_info.mem_info.share_fd) {
+ data.fd_buffer = gspCtx->gsp_cfg.layer1_info.mem_info.share_fd;
+ if(sprd_ion_get_gsp_addr(&data)) {
+ printk("%s, L%d, error!\n",__func__,__LINE__);
+ return -1;
+ }
+ if(data.iova_enabled)
+ gspCtx->gsp_cfg.layer1_info.src_addr.addr_y = data.iova_addr;
+ else
+ gspCtx->gsp_cfg.layer1_info.src_addr.addr_y = data.phys_addr;
+ gspCtx->gsp_cfg.layer1_info.src_addr.addr_uv = gspCtx->gsp_cfg.layer1_info.src_addr.addr_y + gspCtx->gsp_cfg.layer1_info.mem_info.uv_offset;
+ gspCtx->gsp_cfg.layer1_info.src_addr.addr_v = gspCtx->gsp_cfg.layer1_info.src_addr.addr_y + gspCtx->gsp_cfg.layer1_info.mem_info.v_offset;
+
+ }
+
+ if(gspCtx->gsp_cfg.layer_des_info.src_addr.addr_y == 0
+ &&gspCtx->gsp_cfg.layer_des_info.mem_info.share_fd) {
+ data.fd_buffer = gspCtx->gsp_cfg.layer_des_info.mem_info.share_fd;
+ if(sprd_ion_get_gsp_addr(&data)) {
+ printk("%s, L%d, error!\n",__func__,__LINE__);
+ return -1;
+ }
+ if(data.iova_enabled)
+ gspCtx->gsp_cfg.layer_des_info.src_addr.addr_y = data.iova_addr;
+ else
+ gspCtx->gsp_cfg.layer_des_info.src_addr.addr_y = data.phys_addr;
+ gspCtx->gsp_cfg.layer_des_info.src_addr.addr_uv = gspCtx->gsp_cfg.layer_des_info.src_addr.addr_y + gspCtx->gsp_cfg.layer_des_info.mem_info.uv_offset;
+ gspCtx->gsp_cfg.layer_des_info.src_addr.addr_v = gspCtx->gsp_cfg.layer_des_info.src_addr.addr_y + gspCtx->gsp_cfg.layer_des_info.mem_info.v_offset;
+
+ }
+
+ return 0;
+}
+
+static int GSP_Unmap(gsp_context_t *gspCtx)
+{
+ if(gspCtx->gsp_cfg.layer0_info.mem_info.share_fd)
+ sprd_ion_free_gsp_addr(gspCtx->gsp_cfg.layer0_info.mem_info.share_fd);
+
+ if(gspCtx->gsp_cfg.layer1_info.mem_info.share_fd)
+ sprd_ion_free_gsp_addr(gspCtx->gsp_cfg.layer1_info.mem_info.share_fd);
+
+ if(gspCtx->gsp_cfg.layer_des_info.mem_info.share_fd)
+ sprd_ion_free_gsp_addr(gspCtx->gsp_cfg.layer_des_info.mem_info.share_fd);
+
+ return 0;
+}
+
+uint32_t __attribute__((weak)) sci_get_chip_id(void)
+{
+ printk("GSP local read chip id, *(%p) == %x \n",(void*)(SPRD_AONAPB_BASE+0xFC),GSP_REG_READ(SPRD_AONAPB_BASE+0xFC));
+ return GSP_REG_READ(SPRD_AONAPB_BASE+0xFC);
+}
+
+uint32_t gsp_get_chip_id(void)
+{
+ uint32_t adie_chip_id = sci_get_chip_id();
+ if((adie_chip_id & 0xffff0000) < 0x50000000) {
+ printk("%s[%d]:warning, chip id 0x%08x is invalidate, try to get it by reading reg directly!\n", __func__, __LINE__ , adie_chip_id);
+ adie_chip_id = GSP_REG_READ(SPRD_AONAPB_BASE+0xFC);
+ if((adie_chip_id & 0xffff0000) < 0x50000000) {
+ printk("%s[%d]:warning, chip id 0x%08x from reg is invalidate too!\n", __func__, __LINE__ , adie_chip_id);
+ }
+ }
+ printk("%s[%d] return chip id 0x%08x \n", __func__, __LINE__, adie_chip_id);
+ return adie_chip_id;
+}
+
+static GSP_ADDR_TYPE_E GSP_Get_Addr_Type(void)
+{
+ static volatile GSP_ADDR_TYPE_E s_gsp_addr_type = GSP_ADDR_TYPE_INVALUE;
+ static uint32_t s_iommuCtlBugChipList[]= {0x7715a000,0x7715a001,0x8815a000}; //bug chip list
+ //0x8730b000 tshark
+ //0x8300a001 shark
+
+
+#ifndef CONFIG_SPRD_IOMMU // shark or (dolphin/tshark not define IOMMU)
+ s_gsp_addr_type = GSP_ADDR_TYPE_PHYSICAL;
+#else // (dolphin/tshark defined IOMMU)
+ if(s_gsp_addr_type == GSP_ADDR_TYPE_INVALUE) {
+ uint32_t adie_chip_id = 0;
+ int i = 0;
+ /*set s_gsp_addr_type according to the chip id*/
+ //adie_chip_id = sci_get_ana_chip_id();
+ //printk("GSPa : get chip id :0x%08x \n", adie_chip_id);
+ adie_chip_id = gsp_get_chip_id();
+
+ if((adie_chip_id & 0xffff0000) > 0x50000000) {
+ printk("GSP : get chip id :%08x is validate, scan bugchip list.\n", adie_chip_id);
+ for (i=0; i<ARRAY_SIZE(s_iommuCtlBugChipList); i++) {
+ if(s_iommuCtlBugChipList[i] == adie_chip_id) {
+ printk("GSP : match bug chip id :%08x == [%d]\n", adie_chip_id,i);
+#ifdef GSP_IOMMU_WORKAROUND1
+ s_gsp_addr_type = GSP_ADDR_TYPE_IOVIRTUAL;
+#else
+ s_gsp_addr_type = GSP_ADDR_TYPE_PHYSICAL;
+#endif
+ break;
+ }
+ }
+ if(s_gsp_addr_type == GSP_ADDR_TYPE_INVALUE) {
+ printk("GSP : mismatch bug chip id.\n");
+ s_gsp_addr_type = GSP_ADDR_TYPE_IOVIRTUAL;
+ printk("dolphin tshark GSP : gsp address type :%d \n", s_gsp_addr_type);
+ }
+ } else {
+ printk("GSP : get chip id :%08x is invalidate,set address type as physical.\n", adie_chip_id);
+ s_gsp_addr_type = GSP_ADDR_TYPE_PHYSICAL;
+ }
+ }
+#endif
+ printk("GSP [%d]: gsp address type :%d ,\n", __LINE__, s_gsp_addr_type);
+ return s_gsp_addr_type;
+}
+
+
+
+
+static GSP_CAPABILITY_T* GSP_Config_Capability(void)
+{
+ uint32_t adie_chip_id = 0;
+ static GSP_CAPABILITY_T s_gsp_capability;
+
+ if(s_gsp_capability.magic != CAPABILITY_MAGIC_NUMBER) { // not initialized
+ memset((void*)&s_gsp_capability,0,sizeof(s_gsp_capability));
+ s_gsp_capability.max_layer_cnt = 1;
+ s_gsp_capability.blend_video_with_OSD=0;
+ s_gsp_capability.max_videoLayer_cnt = 1;
+ s_gsp_capability.max_layer_cnt_with_video = 1;
+ s_gsp_capability.scale_range_up=64;
+ s_gsp_capability.scale_range_down=1;
+ s_gsp_capability.scale_updown_sametime=0;
+ s_gsp_capability.OSD_scaling=0;
+
+ adie_chip_id = gsp_get_chip_id();
+ switch(adie_chip_id&0xFFFF0000) {
+ case 0x83000000:/*shark-0x8300a001 & 9620*/
+ s_gsp_capability.version = 0x00;
+ s_gsp_capability.scale_range_up=256;
+ break;
+ case 0x77150000:
+ case 0x88150000:
+ if(adie_chip_id == 0x7715a000
+ ||adie_chip_id == 0x7715a001
+ ||adie_chip_id == 0x8815a000) { /*dolphin iommu ctl reg access err*/
+ s_gsp_capability.version = 0x01;
+ s_gsp_capability.video_need_copy = 1;
+ s_gsp_capability.max_video_size = 1;
+ } else if(adie_chip_id == 0x7715a002
+ ||adie_chip_id == 0x7715a003
+ ||adie_chip_id == 0x8815a001
+ ||adie_chip_id == 0x8815a002) { /*dolphin iommu ctl reg access ok, but with black line bug*/
+ s_gsp_capability.version = 0x02;
+ s_gsp_capability.video_need_copy = 1;
+ s_gsp_capability.max_video_size = 1;
+ } else { /*adie_chip_id > 0x7715a003 || adie_chip_id > 0x8815a002, dolphin black line bug fixed*/
+ s_gsp_capability.version = 0x03;
+ s_gsp_capability.max_video_size = 1;
+ s_gsp_capability.scale_range_up=256;
+ printk("%s[%d]: info:a new chip id, treated as newest dolphin that without any bugs!\n",__func__,__LINE__);
+ }
+ break;
+ case 0x87300000:
+ if(adie_chip_id == 0x8730b000) { /*tshark, with black line bug*/
+ s_gsp_capability.version = 0x04;
+ s_gsp_capability.video_need_copy = 1;
+ } else { /*tshark-0x8730b001 & tshark2-? & pike-?, black line bug fixed*/
+ s_gsp_capability.version = 0x05;
+ s_gsp_capability.max_layer_cnt = 2;
+ s_gsp_capability.scale_range_up=256;
+ }
+ break;
+ #ifdef CONFIG_ARCH_SCX20
+ case 0x88600000:/*pike, same with tshark*/
+ s_gsp_capability.version = 0x05;
+ s_gsp_capability.max_layer_cnt = 2;
+ s_gsp_capability.scale_range_up=256;
+ break;
+ #endif
+ default:
+ if(adie_chip_id != 0x96300000/*SharkL, with YCbCr->RGB888*/
+ && adie_chip_id != 0x96310000/*SharkL64*/) {
+ /*
+ pikeL/sharkLT8 ...
+ after sharkL, gsp will not update any more,so these late-comers are same with sharkL.
+ */
+ printk("%s[%d]: info:a new chip id, be treated as sharkL!\n",__func__,__LINE__);
+ }
+ s_gsp_capability.version = 0x06;
+ s_gsp_capability.blend_video_with_OSD=1;
+ s_gsp_capability.max_layer_cnt_with_video = 3;
+ s_gsp_capability.max_layer_cnt = 2;
+ s_gsp_capability.scale_range_up=256;
+ break;
+ }
+ s_gsp_capability.buf_type_support=GSP_Get_Addr_Type();
+ s_gsp_capability.yuv_xywh_even = 1;
+ s_gsp_capability.crop_min.w=s_gsp_capability.crop_min.h=4;
+ s_gsp_capability.out_min.w=s_gsp_capability.out_min.h=4;
+ s_gsp_capability.crop_max.w=s_gsp_capability.crop_max.h=4095;
+ s_gsp_capability.out_max.w=s_gsp_capability.out_max.h=4095;
+ s_gsp_capability.magic = CAPABILITY_MAGIC_NUMBER;
+ }
+ return &s_gsp_capability;
+}
+static long gsp_drv_ioctl(struct file *file,
+ uint32_t cmd,
+ unsigned long arg)
+{
+ int32_t ret = -GSP_NO_ERR;
+ size_t param_size = _IOC_SIZE(cmd);
+ gsp_user* pUserdata = file->private_data;
+ gsp_context_t *gspCtx = NULL;
+ struct timespec start_time;
+ struct timespec end_time;
+ //long long cost=0;
+ memset(&start_time,0,sizeof(start_time));
+ memset(&end_time,0,sizeof(end_time));
+
+ GSP_TRACE("%s:pid:0x%08x,cmd:0x%08x, io number 0x%x, param_size %zu \n",
+ __func__,
+ pUserdata->pid,
+ cmd,
+ _IOC_NR(cmd),
+ param_size);
+
+ if (NULL == pUserdata || NULL == pUserdata->priv) {
+ return -EINVAL;
+ }
+ gspCtx = (gsp_context_t*)pUserdata->priv;
+ if(gspCtx->suspend_resume_flag==1) {
+ printk("%s[%d]: in suspend, ioctl just return!\n",__func__,__LINE__);
+ return ret;
+ }
+
+ switch (cmd) {
+ case GSP_IO_GET_CAPABILITY:
+ if (param_size>=sizeof(GSP_CAPABILITY_T)) {
+ GSP_CAPABILITY_T *cap=GSP_Config_Capability();
+ if(arg & MEM_OPS_ADDR_ALIGN_MASK || (ulong)cap & MEM_OPS_ADDR_ALIGN_MASK) {
+ GSP_TRACE("%s[%d] copy_to_user use none 8B alignment address!",__func__,__LINE__);
+ }
+ ret=copy_to_user((void __user *)arg,(const void*)cap,sizeof(GSP_CAPABILITY_T));
+ if(ret) {
+ printk("%s[%d] err:get gsp capability failed in copy_to_user !\n",__func__,__LINE__);
+ ret = GSP_KERNEL_COPY_ERR;
+ goto exit;
+ }
+ GSP_TRACE("%s[%d]: get gsp capability success in copy_to_user \n",__func__,__LINE__);
+ } else {
+ printk("%s[%d] err:get gsp capability, buffer is too small,come:%zu,need:%zu!",__func__, __LINE__,
+ param_size,sizeof(GSP_CAPABILITY_T));
+ ret = GSP_KERNEL_COPY_ERR;
+ goto exit;
+ }
+ break;
+
+ case GSP_IO_SET_PARAM: {
+ if (param_size) {
+ GSP_TRACE("%s:pid:0x%08x, bf wait gsp-hw sema, L%d \n",__func__,pUserdata->pid,__LINE__);
+
+ // the caller thread was killed without release GSP hw semaphore
+ if( gspCtx->gsp_cur_client_pid != INVALID_USER_ID) {
+ struct pid * __pid = NULL;
+ struct task_struct *__task = NULL;
+ pid_t temp_pid = INVALID_USER_ID;
+
+ GSP_TRACE("%sL%d current:%08x store_pid:0x%08x, \n",__func__,__LINE__,current->pid, gspCtx->gsp_cur_client_pid);
+ //barrier();
+ temp_pid = gspCtx->gsp_cur_client_pid;
+ __pid = find_get_pid(temp_pid);
+ if(__pid != NULL) {
+ __task = get_pid_task(__pid,PIDTYPE_PID);
+ //barrier();
+
+ if(__task != NULL) {
+ if(__task->pid != gspCtx->gsp_cur_client_pid) {
+ GSP_Release_HWSema(gspCtx);
+ }
+ } else {
+ GSP_Release_HWSema(gspCtx);
+ }
+ } else {
+ GSP_Release_HWSema(gspCtx);
+ }
+ //barrier();
+ }
+
+
+ ret = down_interruptible(&gspCtx->gsp_hw_resource_sem);
+ if(ret) {
+ printk("%s:pid:0x%08x, wait gsp-hw sema interrupt by signal,return, L%d \n",__func__,pUserdata->pid,__LINE__);
+ //receive a signal
+ ret = GSP_KERNEL_CFG_INTR;
+ goto exit;
+ }
+ GSP_TRACE("%s:pid:0x%08x, wait gsp-hw sema success, L%d \n",__func__,pUserdata->pid,__LINE__);
+ gspCtx->gsp_cur_client_pid = pUserdata->pid;
+ if(arg & MEM_OPS_ADDR_ALIGN_MASK || (ulong)&gspCtx->gsp_cfg & MEM_OPS_ADDR_ALIGN_MASK) {
+ GSP_TRACE("%s[%d] copy_from_user use none 8B alignment address!",__func__,__LINE__);
+ }
+ ret=copy_from_user((void*)&gspCtx->gsp_cfg, (void*)arg, param_size);
+ if(ret) {
+ printk("%s:pid:0x%08x, copy_params_from_user failed! \n",__func__,pUserdata->pid);
+ ret = GSP_KERNEL_COPY_ERR;
+ goto exit1;
+ } else {
+ GSP_TRACE("%s:pid:0x%08x, copy_params_from_user success!, L%d \n",__func__,pUserdata->pid,__LINE__);
+ ret = GSP_Init(gspCtx);
+ if(ret) {
+ goto exit1;
+ }
+ // if the y u v address is virtual, should be converted to phy address here!!!
+ if(gspCtx->gsp_cfg.layer0_info.layer_en == 1) {
+ if(gspCtx->gsp_cfg.layer0_info.rot_angle & 0x1) { //90 270
+ if((gspCtx->gsp_cfg.layer0_info.clip_rect.rect_w != gspCtx->gsp_cfg.layer0_info.des_rect.rect_h) ||
+ (gspCtx->gsp_cfg.layer0_info.clip_rect.rect_h != gspCtx->gsp_cfg.layer0_info.des_rect.rect_w)) {
+ gspCtx->gsp_cfg.layer0_info.scaling_en = 1;
+ }
+ } else { // 0
+ if((gspCtx->gsp_cfg.layer0_info.clip_rect.rect_w != gspCtx->gsp_cfg.layer0_info.des_rect.rect_w) ||
+ (gspCtx->gsp_cfg.layer0_info.clip_rect.rect_h != gspCtx->gsp_cfg.layer0_info.des_rect.rect_h)) {
+ gspCtx->gsp_cfg.layer0_info.scaling_en = 1;
+ }
+ }
+ }
+
+ if(GSP_Map(gspCtx)) {
+ ret = GSP_KERNEL_ADDR_MAP_ERR;
+ goto exit3;
+ }
+
+ gspCtx->gsp_cfg.misc_info.gsp_clock = GSP_CLOCK;
+ if(GSP_GAP & 0x100) {
+ gspCtx->gsp_cfg.misc_info.gsp_gap = (GSP_GAP & 0xff);
+ }
+ ret = GSP_Info_Config(gspCtx);
+ GSP_TRACE("%s:pid:0x%08x, config hw %s!, L%d \n",__func__,pUserdata->pid,(ret>0)?"failed":"success",__LINE__);
+ if(ret) {
+ printk("%s%d:pid:0x%08x, gsp config err:%d, release hw sema.\n",__func__,__LINE__,pUserdata->pid,ret);
+ goto exit3;
+ }
+ }
+ }
+
+ GSP_TRACE("%s:pid:0x%08x, in trigger to run , L%d \n",__func__,pUserdata->pid,__LINE__);
+ if(gspCtx->gsp_cur_client_pid == pUserdata->pid) {
+ GSP_TRACE("%s:pid:0x%08x, calc coef and trigger to run , L%d \n",__func__,pUserdata->pid,__LINE__);
+ GSP_Cache_Flush();
+ ret = GSP_Scaling_Coef_Gen_And_Config(&gspCtx->gsp_coef_force_calc, gspCtx);
+ if(ret) {
+ goto exit3;
+ }
+
+ ret = GSP_Trigger();
+ GSP_TRACE("%sL%d:pid:0x%08x, trigger %s!\n",__func__,__LINE__,pUserdata->pid,(ret)?"failed":"success");
+ if(ret) {
+ printk("%s%d:pid:0x%08x, trigger failed!! err_code:%d \n",__func__,__LINE__,pUserdata->pid,ret);
+ printCfgInfo(gspCtx);
+ printGPSReg();
+ ERR_RECORD_ADD(*(GSP_REG_T *)GSP_REG_BASE);
+ ERR_RECORD_INDEX_ADD_WP();
+ if (ERR_RECORD_FULL()) {
+ ERR_RECORD_INDEX_ADD_RP();
+ }
+ GSP_TRACE("%s:pid:0x%08x, release hw sema, L%d \n",__func__,pUserdata->pid,__LINE__);
+ goto exit3;
+ }
+ } else {
+ GSP_TRACE("%s:pid:0x%08x,exit L%d \n",__func__,pUserdata->pid,__LINE__);
+ ret = GSP_KERNEL_CALLER_NOT_OWN_HW;
+ goto exit3;
+ }
+
+ if(gspCtx->gsp_cur_client_pid == pUserdata->pid) {
+ GSP_TRACE("%s:pid:0x%08x, bf wait done sema, L%d \n",__func__,pUserdata->pid,__LINE__);
+ //ret = down_interruptible(&gsp_wait_interrupt_sem);//interrupt lose
+ ret = down_timeout(&gspCtx->gsp_wait_interrupt_sem,msecs_to_jiffies(500));//for interrupt lose, timeout return -ETIME,
+ if (ret == 0) { //gsp process over
+ GSP_TRACE("%s:pid:0x%08x, wait done sema success, L%d \n",__func__,pUserdata->pid,__LINE__);
+ } else if (ret == -ETIME) {
+ printk("%s%d:pid:0x%08x, wait done sema 500-ms-timeout,it's abnormal!!!!!!!! \n",__func__,__LINE__,pUserdata->pid);
+ GPSTimeoutPrint(gspCtx);
+ ret = GSP_KERNEL_WAITDONE_TIMEOUT;
+ } else if (ret) { // == -EINTR
+ printk("%s:pid:0x%08x, wait done sema interrupted by a signal, L%d \n",__func__,pUserdata->pid,__LINE__);
+ ret = GSP_KERNEL_WAITDONE_INTR;
+ }
+
+ if (pUserdata->is_exit_force) {
+ pUserdata->is_exit_force = 0;
+ ret = GSP_KERNEL_FORCE_EXIT;
+ }
+
+ GSP_Wait_Finish();//wait busy-bit down
+ GSP_Unmap(gspCtx);
+ GSP_Cache_Invalidate();
+ GSP_Deinit(gspCtx);
+ gspCtx->gsp_cur_client_pid = INVALID_USER_ID;
+ sema_init(&gspCtx->gsp_wait_interrupt_sem,0);
+ GSP_TRACE("%s:pid:0x%08x, release gsp-hw sema, L%d \n",__func__,pUserdata->pid,__LINE__);
+ up(&gspCtx->gsp_hw_resource_sem);
+ }
+ }
+ break;
+
+ default:
+ ret = GSP_KERNEL_CTL_CMD_ERR;
+ break;
+ }
+
+ return ret;
+
+exit3:
+ GSP_Deinit(gspCtx);
+//exit2:
+ GSP_Unmap(gspCtx);
+exit1:
+ gspCtx->gsp_cur_client_pid = INVALID_USER_ID;
+ up(&gspCtx->gsp_hw_resource_sem);
+exit:
+ if (ret) {
+ printk("%s:pid:0x%08x, error code 0x%x \n", __func__,pUserdata->pid,ret);
+ }
+ return ret;
+
+}
+
+static struct file_operations gsp_drv_fops = {
+ .owner = THIS_MODULE,
+ .open = gsp_drv_open,
+ .write = gsp_drv_write,
+ .read = gsp_drv_read,
+ .unlocked_ioctl = gsp_drv_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = gsp_drv_ioctl,
+#endif
+ .release = gsp_drv_release
+};
+
+static irqreturn_t gsp_irq_handler(int32_t irq, void *dev_id)
+{
+ gsp_context_t *gspCtx = (gsp_context_t *)dev_id;
+
+ GSP_TRACE("%s enter!\n",__func__);
+
+ if (NULL == gspCtx) {
+ return IRQ_NONE;
+ }
+ GSP_IRQSTATUS_CLEAR();
+ GSP_IRQENABLE_SET(GSP_IRQ_TYPE_DISABLE);
+ up(&gspCtx->gsp_wait_interrupt_sem);
+
+ return IRQ_HANDLED;
+}
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void gsp_early_suspend(struct early_suspend* es)
+{
+ gsp_context_t *gspCtx = NULL;
+ int32_t ret = -GSP_NO_ERR;
+
+ printk("%s%d\n",__func__,__LINE__);
+
+ gspCtx = container_of(es, gsp_context_t, earlysuspend);
+ if (NULL == gspCtx) {
+ return;
+ }
+
+ gspCtx->suspend_resume_flag = 1;
+
+ //in case of GSP is processing now, wait it finish and then disable
+ ret = down_timeout(&gspCtx->gsp_hw_resource_sem,msecs_to_jiffies(500));
+ if(ret) {
+ printk("%s[%d]: wait gsp-hw sema failed, ret: %d\n",__func__,__LINE__,ret);
+ GPSTimeoutPrint(gspCtx);
+ } else {
+ printk("%s[%d]: wait gsp-hw sema success. \n",__func__,__LINE__);
+ up(&gspCtx->gsp_hw_resource_sem);
+ //GSP_module_disable(gspCtx);
+ }
+}
+
+static void gsp_late_resume(struct early_suspend* es)
+{
+ gsp_context_t *gspCtx = NULL;
+
+ printk("%s%d\n",__func__,__LINE__);
+
+ gspCtx = container_of(es, gsp_context_t, earlysuspend);
+ if (NULL == gspCtx) {
+ return;
+ }
+
+ gspCtx->gsp_coef_force_calc = 1;
+ //GSP_module_enable(gspCtx);//
+
+ GSP_AUTO_GATE_ENABLE();//bug 198152
+ gspCtx->suspend_resume_flag = 0;
+}
+
+#else
+static int gsp_suspend(struct platform_device *pdev,pm_message_t state)
+{
+ gsp_context_t *gspCtx = NULL;
+ int32_t ret = -GSP_NO_ERR;
+ printk("%s%d\n",__func__,__LINE__);
+
+ gspCtx = platform_get_drvdata(pdev);
+ if (NULL == gspCtx) {
+ return -EINVAL;
+ }
+
+ gspCtx->suspend_resume_flag = 1;
+
+ //in case of GSP is processing now, wait it finish and then disable
+ ret = down_timeout(&gspCtx->gsp_hw_resource_sem,msecs_to_jiffies(500));
+ if(ret) {
+ printk("%s[%d]: wait gsp-hw sema failed, ret: %d\n",__func__,__LINE__,ret);
+ GPSTimeoutPrint(gspCtx);
+ return ret;
+ } else {
+ printk("%s[%d]: wait gsp-hw sema success. \n",__func__,__LINE__);
+ up(&gspCtx->gsp_hw_resource_sem);
+ //GSP_module_disable(gspCtx);
+ }
+ return 0;
+}
+
+static int gsp_resume(struct platform_device *pdev)
+{
+ gsp_context_t *gspCtx = NULL;
+
+ gspCtx = platform_get_drvdata(pdev);
+ if (NULL == gspCtx) {
+ return -EINVAL;
+ }
+
+ printk("%s%d\n",__func__,__LINE__);
+ gspCtx->gsp_coef_force_calc = 1;
+ //GSP_module_enable(gspCtx);//
+
+ GSP_AUTO_GATE_ENABLE();//bug 198152
+ gspCtx->suspend_resume_flag = 0;
+ return 0;
+}
+
+#endif
+
+
+static int32_t gsp_clock_init(gsp_context_t *gspCtx)
+{
+ struct clk *emc_clk_parent = NULL;
+ struct clk *gsp_clk_parent = NULL;
+ int ret = 0;
+
+#ifdef CONFIG_OF
+ emc_clk_parent = of_clk_get_by_name(s_gsp_of_dev->of_node, GSP_EMC_CLOCK_PARENT_NAME);
+#else
+ emc_clk_parent = clk_get(NULL, GSP_EMC_CLOCK_PARENT_NAME);
+#endif
+ if (IS_ERR(emc_clk_parent)) {
+ printk(KERN_ERR "gsp: get emc clk_parent failed!\n");
+ return -1;
+ } else {
+ printk(KERN_INFO "gsp: get emc clk_parent ok!\n");//pr_debug
+ }
+
+#ifdef CONFIG_OF
+ gspCtx->gsp_emc_clk = of_clk_get_by_name(s_gsp_of_dev->of_node, GSP_EMC_CLOCK_NAME);
+#else
+ gspCtx->gsp_emc_clk = clk_get(NULL, GSP_EMC_CLOCK_NAME);
+#endif
+ if (IS_ERR(gspCtx->gsp_emc_clk)) {
+ printk(KERN_ERR "gsp: get emc clk failed!\n");
+ return -1;
+ } else {
+ printk(KERN_INFO "gsp: get emc clk ok!\n");//pr_debug
+ }
+
+ ret = clk_set_parent(gspCtx->gsp_emc_clk, emc_clk_parent);
+ if(ret) {
+ printk(KERN_ERR "gsp: gsp set emc clk parent failed!\n");
+ return -1;
+ } else {
+ printk(KERN_INFO "gsp: gsp set emc clk parent ok!\n");//pr_debug
+ }
+
+#ifdef CONFIG_OF
+ gsp_clk_parent = of_clk_get_by_name(s_gsp_of_dev->of_node, GSP_CLOCK_PARENT3);
+#else
+ gsp_clk_parent = clk_get(NULL, GSP_CLOCK_PARENT3);
+#endif
+ if (IS_ERR(gsp_clk_parent)) {
+ printk(KERN_ERR "gsp: get clk_parent failed!\n");
+ return -1;
+ } else {
+ printk(KERN_INFO "gsp: get clk_parent ok!\n");
+ }
+
+#ifdef CONFIG_OF
+ gspCtx->gsp_clk = of_clk_get_by_name(s_gsp_of_dev->of_node, GSP_CLOCK_NAME);
+#else
+ gspCtx->gsp_clk = clk_get(NULL, GSP_CLOCK_NAME);
+#endif
+ if (IS_ERR(gspCtx->gsp_clk)) {
+ printk(KERN_ERR "gsp: get clk failed!\n");
+ return -1;
+ } else {
+ printk(KERN_INFO "gsp: get clk ok!\n");
+ }
+
+ ret = clk_set_parent(gspCtx->gsp_clk, gsp_clk_parent);
+ if(ret) {
+ printk(KERN_ERR "gsp: gsp set clk parent failed!\n");
+ return -1;
+ } else {
+ printk(KERN_INFO "gsp: gsp set clk parent ok!\n");
+ }
+ return ret;
+}
+
+
+int32_t gsp_drv_probe(struct platform_device *pdev)
+{
+ int32_t ret = 0;
+ int32_t i = 0;
+ gsp_context_t *gspCtx;
+
+#ifdef CONFIG_OF
+ struct resource r;
+#endif
+
+ gspCtx =kzalloc(sizeof(gsp_context_t), GFP_KERNEL);
+
+ if (NULL == gspCtx) {
+ dev_err(&pdev->dev, "Can't alloc memory for module data.\n");
+ ret = -ENOMEM;
+ }
+
+ GSP_TRACE("gsp_probe enter .\n");
+ printk("%s,AHB clock :%d\n", __func__,GSP_AHB_CLOCK_GET());
+
+#ifdef CONFIG_OF
+ s_gsp_of_dev = &(pdev->dev);
+
+ gspCtx->gsp_irq_num = irq_of_parse_and_map(s_gsp_of_dev->of_node, 0);
+
+ if(0 != of_address_to_resource(s_gsp_of_dev->of_node, 0, &r)) {
+ printk(KERN_ERR "gsp probe fail. (can't get register base address)\n");
+ goto exit;
+ }
+ g_gsp_base_addr = (unsigned long)ioremap_nocache(r.start, resource_size(&r));
+ if(!g_gsp_base_addr)
+ BUG();
+
+#ifndef GSP_IOMMU_WORKAROUND1
+#if defined(CONFIG_ARCH_SCX15) || defined(CONFIG_ARCH_SCX30G) || defined(CONFIG_ARCH_SCX35L)
+ ret = of_property_read_u32(s_gsp_of_dev->of_node, "gsp_mmu_ctrl_base", (u32*)&g_gsp_mmu_ctrl_addr);
+
+ if(0 != ret) {
+ printk("%s: read gsp_mmu_ctrl_addr fail (%d)\n", __func__, ret);
+ return ret;
+ }
+ g_gsp_mmu_ctrl_addr = (ulong)ioremap_nocache(g_gsp_mmu_ctrl_addr,sizeof(uint32_t));
+ if(!g_gsp_mmu_ctrl_addr)
+ BUG();
+#endif
+#endif
+
+ printk("gsp: irq = %d, g_gsp_base_addr = 0x%lx,\n", gspCtx->gsp_irq_num, g_gsp_base_addr);
+#else
+ gspCtx->gsp_irq_num = TB_GSP_INT;
+#endif
+
+ GSP_AUTO_GATE_ENABLE();
+ ret = gsp_clock_init(gspCtx);
+ if (ret) {
+ printk(KERN_ERR "gsp emc clock init failed. \n");
+ goto exit;
+ }
+ //GSP_module_enable(gspCtx);
+
+ gspCtx->dev.minor = MISC_DYNAMIC_MINOR;
+ gspCtx->dev.name = "sprd_gsp";
+ gspCtx->dev.fops = &gsp_drv_fops;
+ ret = misc_register(&gspCtx->dev);
+ if (ret) {
+ printk(KERN_ERR "gsp cannot register miscdev (%d)\n", ret);
+ goto exit;
+ }
+
+ ret = request_irq(gspCtx->gsp_irq_num,//
+ gsp_irq_handler,
+ 0,//IRQF_SHARED
+ "GSP",
+ gspCtx);
+
+ if (ret) {
+ printk("could not request irq %d\n", gspCtx->gsp_irq_num);
+ goto exit1;
+ }
+
+ gspCtx->gsp_cur_client_pid = INVALID_USER_ID;
+ for (i=0; i<GSP_MAX_USER; i++) {
+ gspCtx->gsp_user_array[i].pid = INVALID_USER_ID;
+ gspCtx->gsp_user_array[i].is_exit_force = 0;
+ sema_init(&(gspCtx->gsp_user_array[i].sem_open), 1);
+ }
+
+ /* initialize locks*/
+ memset(&gspCtx->gsp_cfg,0,sizeof(gspCtx->gsp_cfg));
+ sema_init(&gspCtx->gsp_hw_resource_sem, 1);
+ sema_init(&gspCtx->gsp_wait_interrupt_sem, 0);
+ /*initialize gsp_perf*/
+
+ gspCtx->cache_coef_init_flag = 0;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ memset(& gspCtx->earlysuspend,0,sizeof( gspCtx->earlysuspend));
+ gspCtx->earlysuspend.suspend = gsp_early_suspend;
+ gspCtx->earlysuspend.resume = gsp_late_resume;
+ gspCtx->earlysuspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING;
+ register_early_suspend(&gspCtx->earlysuspend);
+#endif
+
+ platform_set_drvdata(pdev, gspCtx);
+ g_gspCtx = gspCtx;
+ return ret;
+
+exit1:
+ misc_deregister(&gspCtx->dev);
+exit:
+ return ret;
+}
+
+static int32_t gsp_drv_remove(struct platform_device *dev)
+{
+ gsp_context_t *gspCtx;
+ GSP_TRACE( "gsp_remove called !\n");
+
+ gspCtx = platform_get_drvdata(dev);
+ if (NULL == gspCtx) {
+ return -EINVAL;
+ }
+ free_irq(gspCtx->gsp_irq_num, gsp_irq_handler);
+ misc_deregister(&gspCtx->dev);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id sprdgsp_dt_ids[] = {
+ { .compatible = "sprd,gsp", },
+ {}
+};
+#endif
+
+static struct platform_driver gsp_driver = {
+ .probe = gsp_drv_probe,
+ .remove = gsp_drv_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = gsp_suspend,
+ .resume = gsp_resume,
+#endif
+ .driver =
+ {
+ .owner = THIS_MODULE,
+ .name = "sprd_gsp",
+#ifdef CONFIG_OF
+ .of_match_table = of_match_ptr(sprdgsp_dt_ids),
+#endif
+ }
+};
+
+int32_t __init gsp_drv_init(void)
+{
+ printk("gsp_drv_init enter! \n");
+
+ if (platform_driver_register(&gsp_driver) != 0) {
+ printk("gsp platform driver register Failed! \n");
+ return -1;
+ } else {
+ GSP_TRACE("gsp platform driver registered successful! \n");
+ }
+ return 0;
+}
+
+
+void gsp_drv_exit(void)
+{
+ platform_driver_unregister(&gsp_driver);
+ GSP_TRACE("gsp platform driver unregistered! \n");
+}
+
+module_init(gsp_drv_init);
+module_exit(gsp_drv_exit);
+
+MODULE_DESCRIPTION("GSP Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/sprd_gsp/gsp_drv_common.h b/drivers/media/sprd_gsp/gsp_drv_common.h
new file mode 100644
index 00000000..10891344
--- /dev/null
+++ b/drivers/media/sprd_gsp/gsp_drv_common.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __GSP_DRV_COMMON_H__
+#define __GSP_DRV_COMMON_H__
+
+#include <linux/semaphore.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+//#include "gsp_drv.h"
+
+#define GSP_MAX_USER 8
+#define GSP_ERR_RECORD_CNT 8
+
+#define MEM_OPS_ADDR_ALIGN_MASK (0x7UL)
+
+//#define GSP_DEBUG
+#ifdef GSP_DEBUG
+#define GSP_TRACE printk
+#else
+#define GSP_TRACE pr_debug
+#endif
+
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+
+typedef struct _gsp_perf_data
+{
+ unsigned long gsp_perf_cnt ;
+ unsigned long long gsp_perf_s ;
+ unsigned long long gsp_perf_ns;
+ unsigned long gsp_perf;
+} gsp_perf_data_t;
+
+#define INVALID_USER_ID 0xFFFFFFFF
+
+typedef struct _gsp_user_data
+{
+ pid_t pid;
+ uint32_t is_exit_force;// if the client process hungup on IOCTL-wait-finish, this variable mark it should wakeup and return anyway
+ struct semaphore sem_open;// one thread can open device once per time
+ void *priv;
+} gsp_user;
+
+
+typedef struct _gsp_context
+{
+ struct miscdevice dev;
+
+ uint32_t gsp_irq_num;
+ struct clk *gsp_emc_clk;
+ struct clk *gsp_clk;
+ struct semaphore gsp_hw_resource_sem;//cnt == 1,only one thread can access critical section at the same time
+ struct semaphore gsp_wait_interrupt_sem;// init to 0, gsp done/timeout/client discard release sem
+
+ volatile uint32_t suspend_resume_flag;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend earlysuspend;
+#endif
+
+ uint32_t cache_coef_init_flag;
+ ulong gsp_coef_force_calc;
+
+ gsp_user gsp_user_array[GSP_MAX_USER];
+ volatile pid_t gsp_cur_client_pid;
+ GSP_CONFIG_INFO_T gsp_cfg;//protect by gsp_hw_resource_sem
+
+ GSP_REG_T gsp_reg_err_record[GSP_ERR_RECORD_CNT];
+ uint32_t gsp_reg_err_record_rp;
+ uint32_t gsp_reg_err_record_wp;
+
+} gsp_context_t;
+
+
+//extern gsp_context_t *gsp_ctx;
+#ifdef CONFIG_OF
+extern ulong g_gsp_base_addr ;
+extern ulong g_gsp_mmu_ctrl_addr ;
+#endif
+
+/*
+uint32_t get_gsp_base_addr(gsp_drv_data_t *gspDrvdata)
+{
+ return gspDrvdata->gsp_base_addr;
+}
+*/
+#endif
diff --git a/drivers/media/sprd_gsp/scaler_coef_cal.c b/drivers/media/sprd_gsp/scaler_coef_cal.c
new file mode 100644
index 00000000..9449a3a5
--- /dev/null
+++ b/drivers/media/sprd_gsp/scaler_coef_cal.c
@@ -0,0 +1,811 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sin_cos.h"
+#include <linux/math64.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include "scaler_coef_cal.h"
+#include "gsp_config_if.h"
+
+
+#define GSC_FIX 24
+#define GSC_COUNT 64
+#define TRUE 1
+#define FALSE 0
+
+#define GSC_ABS(_a) ((_a) < 0 ? -(_a) : (_a))
+#define GSC_SIGN2(input, p) {if (p>=0) input = 1; if (p < 0) input = -1;}
+#define COEF_ARR_ROWS 9
+#define COEF_ARR_COLUMNS 8
+#define COEF_ARR_COL_MAX 16
+#define MIN_POOL_SIZE (6 * 1024)
+
+#define SCI_MEMSET memset
+#define MAX( _x, _y ) (((_x) > (_y)) ? (_x) : (_y) )
+
+
+
+
+typedef struct {
+ ulong begin_addr;
+ ulong total_size;
+ ulong used_size;
+} GSC_MEM_POOL;
+
+
+static uint8_t _InitPool(void *buffer_ptr,
+ uint32_t buffer_size,
+ GSC_MEM_POOL * pool_ptr)
+{
+ if (NULL == buffer_ptr || 0 == buffer_size || NULL == pool_ptr) {
+ return FALSE;
+ }
+ if (buffer_size < MIN_POOL_SIZE) {
+ return FALSE;
+ }
+ pool_ptr->begin_addr = (ulong) buffer_ptr;
+ pool_ptr->total_size = buffer_size;
+ pool_ptr->used_size = 0;
+ //printk("GSP_InitPool:%d,begin_addr:0x%08x,total_size:%d,used_size:%d\n",__LINE__,pool_ptr->begin_addr,pool_ptr->total_size,pool_ptr->used_size);
+ return TRUE;
+}
+
+static void *_Allocate(uint32_t size,
+ uint32_t align_shift,
+ GSC_MEM_POOL * pool_ptr)
+{
+ ulong begin_addr = 0;
+ ulong temp_addr = 0;
+ if (NULL == pool_ptr) {
+ //printk("GSP_Allocate:%d _Allocate error! \n",__LINE__);
+ return NULL;
+ }
+ begin_addr = pool_ptr->begin_addr;
+ temp_addr = begin_addr + pool_ptr->used_size;
+ temp_addr = (((temp_addr + (1UL << align_shift)-1) >> align_shift) << align_shift);
+ if (temp_addr + size > begin_addr + pool_ptr->total_size) {
+ //printk("GSP_Allocate err:%d,temp_addr:0x%08x,size:%d,begin_addr:0x%08x,total_size:%d,used_size:%d\n",__LINE__,temp_addr,size,begin_addr,pool_ptr->total_size,pool_ptr->used_size);
+ return NULL;
+ }
+ pool_ptr->used_size = (temp_addr + size) - begin_addr;
+ SCI_MEMSET((void *)temp_addr, 0, size);
+ //printk("GSP_Allocate:%d _Allocate success!%08x \n",__LINE__,temp_addr);
+ return (void *)temp_addr;
+}
+
+static int64_t div64_s64_s64(int64_t dividend, int64_t divisor)
+{
+ int8_t sign = 1;
+ int64_t dividend_tmp = dividend;
+ int64_t divisor_tmp = divisor;
+ int64_t ret = 0;
+ if (0 == divisor) {
+ return 0;
+ }
+ if ((dividend >> 63) & 0x1) {
+ sign *= -1;
+ dividend_tmp = dividend * (-1);
+ }
+ if ((divisor >> 63) & 0x1) {
+ sign *= -1;
+ divisor_tmp = divisor * (-1);
+ }
+ ret = div64_s64(dividend_tmp, divisor_tmp);
+ ret *= sign;
+ return ret;
+}
+
+static void normalize_inter(int64_t * data, int16_t * int_data, uint8_t ilen)
+{
+ uint8_t it;
+ int64_t tmp_d = 0;
+ int64_t *tmp_data = NULL;
+ int64_t tmp_sum_val = 0;
+ tmp_data = data;
+ tmp_sum_val = 0;
+ for (it = 0; it < ilen; it++) {
+ tmp_sum_val += tmp_data[it];
+ }
+ if (0 == tmp_sum_val) {
+ uint8_t value = 256 / ilen;
+ for (it = 0; it < ilen; it++) {
+ tmp_d = value;
+ int_data[it] = (int16_t) tmp_d;
+ }
+ } else {
+ for (it = 0; it < ilen; it++) {
+ tmp_d =
+ div64_s64_s64(tmp_data[it] * (int64_t) 256,
+ tmp_sum_val);
+ int_data[it] = (uint16_t) tmp_d;
+ }
+ }
+}
+/* ------------------------------------------ */
+static int16_t sum_fun(int16_t *data, int8_t ilen)
+{
+ int8_t i ;
+ int16_t tmp_sum;
+ tmp_sum = 0;
+
+ for (i = 0; i < ilen; i++)
+ tmp_sum += *data++;
+
+ return tmp_sum;
+}
+
+
+
+static void adjust_filter_inter(int16_t *filter, uint8_t ilen)
+{
+ int32_t i, midi;
+ int32_t tmpi, tmp_S ;
+ int32_t tmp_val = 0 ;
+
+ tmpi = sum_fun(filter, ilen) - 256;
+ midi = ilen >> 1;
+ GSC_SIGN2(tmp_val, tmpi);
+
+ if ((tmpi & 1) == 1) { // tmpi is odd
+ filter[midi] = filter[midi] - tmp_val;
+ tmpi -= tmp_val;
+ }
+
+ //tmp_S = abs(tmpi>>1);
+
+ tmp_S = GSC_ABS(tmpi / 2);
+
+ if ((ilen & 1) == 1) { // ilen is odd
+ for (i = 0; i < tmp_S; i++) {
+ filter[midi - (i+1)] = filter[midi - (i+1)] - tmp_val;
+ filter[midi + (i+1)] = filter[midi + (i+1)] - tmp_val;
+ }
+ } else { // ilen is even
+ for (i = 0; i < tmp_S; i++) {
+ filter[midi - (i+1)] = filter[midi - (i+1)] - tmp_val;
+ filter[midi + i] = filter[midi + i] - tmp_val;
+ }
+ }
+
+ if(filter[midi] > 255) {
+ tmp_val = filter[midi] ;
+ filter[midi] = 255 ;
+ filter[midi - 1] = filter[midi - 1] + tmp_val - 255 ;
+ }
+}
+
+static int16_t CalYmodelCoef(int16_t coef_lenght,
+ int16_t * coef_data_ptr,
+ int16_t N,
+ int16_t M,
+ GSC_MEM_POOL * pool_ptr)
+{
+ int8_t mount;
+ int16_t i, mid_i, kk, j, sum_val;
+ int64_t *filter = _Allocate(GSC_COUNT * sizeof(int64_t), 3, pool_ptr);
+ int64_t *tmp_filter = _Allocate(GSC_COUNT * sizeof(int64_t), 3, pool_ptr);
+ int16_t *normal_filter = _Allocate(GSC_COUNT * sizeof(int16_t), 2, pool_ptr);
+
+ if (NULL == filter || NULL == tmp_filter || NULL == normal_filter) {
+ return 1;
+ }
+ mid_i = coef_lenght >> 1;
+ filter[mid_i] =
+ div64_s64_s64((int64_t) ((int64_t) N << GSC_FIX),
+ (int64_t) MAX(M, N));
+ for (i = 0; i < mid_i; i++) {
+ int64_t angle_x =
+ div64_s64_s64((int64_t) ARC_32_COEF * (int64_t) (i + 1) *
+ (int64_t) N, (int64_t) MAX(M,
+ N) * (int64_t) 8);
+ int64_t angle_y =
+ div64_s64_s64((int64_t) ARC_32_COEF * (int64_t) (i + 1) *
+ (int64_t) N, (int64_t) (M * N) * (int64_t) 8);
+ int32_t value_x = sin_32((int32_t) angle_x);
+ int32_t value_y = sin_32((int32_t) angle_y);
+ filter[mid_i + i + 1] =
+ div64_s64_s64((int64_t)
+ ((int64_t) value_x *
+ (int64_t) (1 << GSC_FIX)),
+ (int64_t) ((int64_t) M * (int64_t) value_y));
+ filter[mid_i - (i + 1)] = filter[mid_i + i + 1];
+ }
+ for (i = -1; i < mid_i; i++) {
+ int32_t angle_32 =
+ (int32_t)
+ div64_s64_s64((int64_t)
+ ((int64_t) 2 * (int64_t) (mid_i - i - 1) *
+ (int64_t) ARC_32_COEF),
+ (int64_t) coef_lenght);
+ int64_t a = (int64_t) 9059697;
+ int64_t b = (int64_t) 7717519;
+ int64_t t = a - ((b * cos_32(angle_32)) >> 30);
+ filter[mid_i + i + 1] = (t * filter[mid_i + i + 1]) >> GSC_FIX;
+ filter[mid_i - (i + 1)] = filter[mid_i + i + 1];
+ }
+ for (i = 0; i < 8; i++) {
+ mount = 0;
+ for (j = i; j < coef_lenght; j += 8) {
+ tmp_filter[mount] = filter[j];
+ mount++;
+ }
+ normalize_inter(tmp_filter, normal_filter, (int8_t) mount);
+ sum_val = sum_fun(normal_filter, mount);
+ if (256 != sum_val) {
+ adjust_filter_inter(normal_filter, mount);
+ }
+ mount = 0;
+ for (kk = i; kk < coef_lenght; kk += 8) {
+ coef_data_ptr[kk] = normal_filter[mount];
+ mount++;
+ }
+ }
+ return 0;
+}
+
+/* cal Y model */
+static int16_t CalY_ScalingCoef(int16_t tap,
+ int16_t D,
+ int16_t I,
+ int16_t * y_coef_data_ptr,
+ int16_t dir, GSC_MEM_POOL * pool_ptr)
+{
+ uint16_t coef_lenght;
+
+ coef_lenght = (uint16_t) (tap * 8);
+ SCI_MEMSET(y_coef_data_ptr, 0, coef_lenght * sizeof(int16_t));
+ CalYmodelCoef(coef_lenght, y_coef_data_ptr, I, D, pool_ptr);
+ return coef_lenght;
+}
+
+static int16_t CalUV_ScalingCoef(int16_t tap,
+ int16_t D,
+ int16_t I,
+ int16_t * uv_coef_data_ptr,
+ int16_t dir, GSC_MEM_POOL * pool_ptr)
+{
+ int16_t uv_coef_lenght;
+
+ if ((dir == 1)) {
+ uv_coef_lenght = (int16_t) (tap * 8);
+ CalYmodelCoef(uv_coef_lenght, uv_coef_data_ptr, I, D, pool_ptr);
+ } else {
+ if (D > I) {
+ uv_coef_lenght = (int16_t) (tap * 8);
+ } else {
+ uv_coef_lenght = (int16_t) (2 * 8);
+ }
+ CalYmodelCoef(uv_coef_lenght, uv_coef_data_ptr, I, D, pool_ptr);
+ }
+ return uv_coef_lenght;
+}
+
+static void GetFilter(int16_t * coef_data_ptr,
+ int16_t * out_filter,
+ int16_t iI_hor,
+ int16_t coef_len,
+ int16_t * filter_len)
+{
+ int16_t i, pos_start;
+
+ pos_start = coef_len / 2;
+ while (pos_start >= iI_hor) {
+ pos_start -= iI_hor;
+ }
+ for (i = 0; i < iI_hor; i++) {
+ int16_t len = 0;
+ int16_t j;
+ int16_t pos = pos_start + i;
+ while (pos >= iI_hor) {
+ pos -= iI_hor;
+ }
+ for (j = 0; j < coef_len; j+=iI_hor) {
+ *out_filter++ = coef_data_ptr[j + pos];
+ len ++;
+ }
+ *filter_len++ = len;
+ }
+}
+
+static void WriteScalarCoef(int16_t * dst_coef_ptr,
+ int16_t * coef_ptr,
+ int16_t dst_pitch,
+ int16_t src_pitch)
+{
+ int i, j;
+
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < src_pitch; j++) {
+ *(dst_coef_ptr + j) =
+ *(coef_ptr + i * src_pitch + src_pitch - 1 - j);
+ }
+ dst_coef_ptr += dst_pitch;
+ }
+}
+/*
+static void SetHorRegisterCoef(uint32_t * reg_coef_ptr, int16_t * y_coef_ptr,
+ int16_t * uv_coef_ptr)
+{
+ int32_t i = 0;
+ int16_t *y_coef_arr[COEF_ARR_ROWS] = { NULL };
+ int16_t *uv_coef_arr[COEF_ARR_ROWS] = { NULL };
+
+ for (i = 0; i < COEF_ARR_ROWS; i++)
+ {
+ y_coef_arr[i] = y_coef_ptr;
+ uv_coef_arr[i] = uv_coef_ptr;
+ y_coef_ptr += COEF_ARR_COLUMNS;
+ uv_coef_ptr += COEF_ARR_COLUMNS;
+ }
+
+ // horizontal Y Scaling Coef Config register
+ for (i = 0; i < 8; i++)
+ {
+ uint16_t p0, p1;
+ uint32_t reg;
+
+ p0 = (uint16_t) y_coef_arr[i][7];
+ p1 = (uint16_t) y_coef_arr[i][6];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ p0 = (uint16_t) y_coef_arr[i][5];
+ p1 = (uint16_t) y_coef_arr[i][4];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ p0 = (uint16_t) y_coef_arr[i][3];
+ p1 = (uint16_t) y_coef_arr[i][2];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ p0 = (uint16_t) y_coef_arr[i][1];
+ p1 = (uint16_t) y_coef_arr[i][0];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ }
+ // horizontal UV Scaling Coef Config register
+ for (i = 0; i < 8; i++)
+ {
+ uint16_t p0, p1;
+ uint32_t reg;
+
+ p0 = (uint16_t) uv_coef_arr[i][3];
+ p1 = (uint16_t) uv_coef_arr[i][2];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ p0 = (uint16_t) uv_coef_arr[i][1];
+ p1 = (uint16_t) uv_coef_arr[i][0];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ }
+}
+*/
+
+static void CheckCoefRange(int16_t * coef_ptr, int16_t rows, int16_t columns, int16_t pitch)
+{
+ int16_t i, j;
+ int16_t value, diff, sign;
+ int16_t *coef_arr[COEF_ARR_ROWS] = { NULL };
+
+ for (i = 0; i < COEF_ARR_ROWS; i++) {
+ coef_arr[i] = coef_ptr;
+ coef_ptr += pitch;
+ }
+ for (i = 0; i < rows; i++) {
+ for (j = 0; j < columns; j++) {
+ value = coef_arr[i][j];
+ if (value > 255) {
+ diff = value - 255;
+ coef_arr[i][j] = 255;
+ sign = GSC_ABS(diff);
+ if ((sign & 1) == 1) { // ilen is odd
+ coef_arr[i][j + 1] =
+ coef_arr[i][j + 1] + (diff + 1) / 2;
+ coef_arr[i][j - 1] =
+ coef_arr[i][j - 1] + (diff - 1) / 2;
+ } else { // ilen is even
+ coef_arr[i][j + 1] =
+ coef_arr[i][j + 1] + (diff) / 2;
+ coef_arr[i][j - 1] =
+ coef_arr[i][j - 1] + (diff) / 2;
+ }
+ }
+ }
+ }
+}
+
+
+static void GSP_Rearrang_Coeff(void* src, void*dst, int32_t tap)
+{
+ uint32_t i, j;
+ int16_t *src_ptr, *dst_ptr;
+
+ src_ptr = (int16_t*)src;
+ dst_ptr = (int16_t*)dst;
+ if (src_ptr == NULL || dst_ptr == NULL)
+ return;
+
+ if (0 != dst_ptr) {
+ memset((void*)dst_ptr, 0x00, 8 * 8 * sizeof(int16_t));
+ }
+
+ switch(tap) {
+ case 6:
+ case 2: {
+ for(i = 0; i<8; i++) {
+ for(j = 0; j< tap; j++) {
+ *(dst_ptr+i*8+1+j) = *(src_ptr+i*8+j);
+ }
+ }
+ }
+ break;
+
+ case 4:
+ case 8: {
+ for(i = 0; i<8; i++) {
+ for(j = 0; j< tap; j++) {
+ *(dst_ptr + i * 8 + j) = *(src_ptr + i * 8 + j);
+ }
+ }
+ }
+ break;
+ }
+}
+
+#define CACHE_COEF
+#ifdef CACHE_COEF
+//we use "Least Recently Used(LRU)" to implement the coef-matrix cache policy
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+
+#define COEF_MATRIX_ENTRY_SIZE (GSP_COEFF_COEF_SIZE/2)
+#define CACHED_COEF_CNT_MAX 32
+
+typedef struct _coef_entry {
+ struct _coef_entry* prev;
+ struct _coef_entry* next;
+ uint32_t coef[COEF_MATRIX_ENTRY_SIZE];
+ uint16_t in_w;
+ uint16_t in_h;
+ uint16_t out_w;
+ uint16_t out_h;
+ uint16_t hor_tap;
+ uint16_t ver_tap;
+} Coef_Entry;
+
+
+Coef_Entry *Coef_Entry_List_Head = NULL;
+#define LIST_ADD_TO_LIST_HEAD(pEntry)\
+{\
+ Coef_Entry_List_Head->prev->next = (pEntry);\
+ (pEntry)->prev = Coef_Entry_List_Head->prev;\
+ (pEntry)->next = Coef_Entry_List_Head;\
+ Coef_Entry_List_Head->prev = (pEntry);\
+ Coef_Entry_List_Head = (pEntry);\
+}
+
+#define LIST_FETCH_FROM_LIST(pEntry)\
+{\
+ pEntry->prev->next = pEntry->next;\
+ pEntry->next->prev = pEntry->prev;\
+}
+
+#define LIST_SET_ENTRY_KEY(pEntry,i_w,i_h,o_w,o_h,h_t,v_t)\
+{\
+ pEntry->in_w = i_w;\
+ pEntry->in_h = i_h;\
+ pEntry->out_w = o_w;\
+ pEntry->out_h = o_h;\
+ pEntry->hor_tap = h_t;\
+ pEntry->ver_tap = v_t;\
+}
+
+#define LIST_GET_THE_TAIL_ENTRY() (Coef_Entry_List_Head->prev)
+
+static int32_t cache_coef_init(gsp_context_t *gspCtx)
+{
+ Coef_Entry *Coef_Entry_Array = NULL;
+ uint32_t i = 0;
+ pr_debug("GSP_CACHE_COEF:init\n");
+
+ if(gspCtx->cache_coef_init_flag == 0) {
+ Coef_Entry_Array = (Coef_Entry *)vmalloc(sizeof(Coef_Entry)*CACHED_COEF_CNT_MAX);
+
+ if(Coef_Entry_Array) {
+ memset((void*)Coef_Entry_Array,0,sizeof(Coef_Entry)*CACHED_COEF_CNT_MAX);
+
+ Coef_Entry_List_Head = &Coef_Entry_Array[0];
+ Coef_Entry_Array[0].prev = &Coef_Entry_Array[0];
+ Coef_Entry_Array[0].next = &Coef_Entry_Array[0];
+ i++;
+
+ while(i < CACHED_COEF_CNT_MAX) {
+ LIST_ADD_TO_LIST_HEAD(&Coef_Entry_Array[i]);
+ i++;
+ }
+ gspCtx->cache_coef_init_flag = 1;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+func:cache_coef_hit_check
+desc:find the entry have the same in_w in_h out_w out_h
+return:if hit,return the entry pointer; else return null;
+*/
+static Coef_Entry* cache_coef_hit_check(uint16_t in_w, uint16_t in_h, uint16_t out_w,uint16_t out_h,
+ uint16_t hor_tap, uint16_t ver_tap)
+{
+ static uint32_t total_cnt = 0;
+ static uint32_t hit_cnt = 0;
+
+ Coef_Entry* walk = Coef_Entry_List_Head;
+
+ total_cnt++;
+ while(walk->in_w != 0) {
+ if(walk->in_w == in_w
+ && walk->in_h == in_h
+ && walk->out_w == out_w
+ && walk->out_h == out_h
+ && walk->hor_tap == hor_tap
+ && walk->ver_tap == ver_tap) {
+ hit_cnt++;
+ pr_debug("GSP_CACHE_COEF:hit, hit_ratio:%d percent\n",hit_cnt*100/total_cnt);
+ return walk;
+ }
+ if(walk->next == Coef_Entry_List_Head) {
+ break;
+ }
+ walk = walk->next;
+ }
+ pr_debug("GSP_CACHE_COEF:miss\n");
+ return NULL;
+}
+
+static Coef_Entry* cache_coef_move_entry_to_list_head(Coef_Entry* pEntry)
+{
+ LIST_FETCH_FROM_LIST(pEntry);
+ LIST_ADD_TO_LIST_HEAD(pEntry);
+ return Coef_Entry_List_Head;
+}
+
+#endif
+
+/**---------------------------------------------------------------------------*
+ ** Public Functions *
+ **---------------------------------------------------------------------------*/
+/****************************************************************************/
+/* Purpose: generate scale factor */
+/* Author: */
+/* Input: */
+/* i_w: source image width */
+/* i_h: source image height */
+/* o_w: target image width */
+/* o_h: target image height */
+/* Output: */
+/* coeff_h_ptr: pointer of horizontal coefficient buffer, the size of which must be at */
+/* least SCALER_COEF_TAP_NUM_HOR * 4 bytes */
+/* the output coefficient will be located in coeff_h_ptr[0], ......, */
+/* coeff_h_ptr[SCALER_COEF_TAP_NUM_HOR-1] */
+/* coeff_v_ptr: pointer of vertical coefficient buffer, the size of which must be at */
+/* least (SCALER_COEF_TAP_NUM_VER + 1) * 4 bytes */
+/* the output coefficient will be located in coeff_v_ptr[0], ......, */
+/* coeff_h_ptr[SCALER_COEF_TAP_NUM_VER-1] and the tap number */
+/* will be located in coeff_h_ptr[SCALER_COEF_TAP_NUM_VER] */
+/* temp_buf_ptr: temp buffer used while generate the coefficient */
+/* temp_buf_ptr: temp buffer size, 6k is the suggest size */
+/* Return: */
+/* Note: */
+/****************************************************************************/
+uint8_t GSP_Gen_Block_Ccaler_Coef(uint32_t i_w,
+ uint32_t i_h,
+ uint32_t o_w,
+ uint32_t o_h,
+ uint32_t hor_tap,
+ uint32_t ver_tap,
+ uint32_t *coeff_h_ptr,
+ uint32_t *coeff_v_ptr,
+ void *temp_buf_ptr,
+ uint32_t temp_buf_size,
+ gsp_context_t *gspCtx
+ )
+{
+ int16_t D_hor = i_w; //decimition at horizontal
+ //int16_t D_ver = i_h; //decimition at vertical
+ int16_t I_hor = o_w; //interpolation at horizontal
+ //int16_t I_ver = o_h; //interpolation at vertical
+ //int16_t I_ver_bak_uv = o_h;
+
+ int16_t *cong_com_hor = 0;
+ int16_t *cong_com_ver = 0;
+ int16_t *coeff_array = 0;
+
+ //uint16_t luma_ver_tap, chrome_ver_tap;
+ //uint16_t luma_ver_maxtap = 8, chrome_ver_maxtap = 8;
+
+ uint32_t coef_buf_size = 0;
+ int16_t *temp_filter_ptr = NULL;
+ int16_t *filter_ptr = NULL;
+ uint32_t filter_buf_size = GSC_COUNT * sizeof(int16_t);
+ int16_t filter_len[COEF_ARR_ROWS] = { 0 };
+ int16_t coef_len = 0;
+ //uint8_t is_scaling_up = FALSE;
+ //uint8_t hor_tap = 8;
+ //uint8_t ver_tap = 8;
+ GSC_MEM_POOL pool = { 0 };
+ uint32_t i = 0;
+
+#ifdef CACHE_COEF
+ Coef_Entry* pEntry = NULL;
+
+ if(gspCtx->cache_coef_init_flag == 0) {
+ cache_coef_init(gspCtx);
+ }
+
+ if(gspCtx->cache_coef_init_flag == 1) {
+ pEntry = cache_coef_hit_check(i_w,i_h,o_w,o_h,hor_tap,ver_tap);
+ if(pEntry) { //hit
+ if((ulong)coeff_h_ptr & MEM_OPS_ADDR_ALIGN_MASK || (ulong)pEntry->coef & MEM_OPS_ADDR_ALIGN_MASK) {
+ GSP_TRACE("%s[%d] memcpy use none 8B alignment address!",__func__,__LINE__);
+ }
+ memcpy((void*)coeff_h_ptr, (void*)pEntry->coef, COEF_MATRIX_ENTRY_SIZE*4);
+ cache_coef_move_entry_to_list_head(pEntry);
+ return TRUE;
+ }
+ }
+#endif
+
+ /* init pool and allocate static array */
+ if (!_InitPool(temp_buf_ptr, temp_buf_size, &pool)) {
+ printk("GSP_Gen_Block_Ccaler_Coef: _InitPool error! \n");
+ return FALSE;
+ }
+
+ coef_buf_size = COEF_ARR_ROWS * COEF_ARR_COL_MAX * sizeof(int16_t);
+ cong_com_hor = (int16_t*)_Allocate(coef_buf_size, 2, &pool);
+ cong_com_ver = (int16_t*)_Allocate(coef_buf_size, 2, &pool);
+ coeff_array = (int16_t*)_Allocate(8 * 8, 2, &pool);
+
+ if (NULL == cong_com_hor
+ || NULL == cong_com_ver
+ ||NULL == coeff_array) {
+ //printk("GSP_Gen_Block_Ccaler_Coef:%d _Allocate error!%08x,%08x,%08x\n",__LINE__,cong_com_hor,cong_com_ver,coeff_array);
+ return FALSE;
+ }
+
+ temp_filter_ptr = _Allocate(filter_buf_size, 2, &pool);
+ filter_ptr = _Allocate(filter_buf_size, 2, &pool);
+ if (NULL == temp_filter_ptr || NULL == filter_ptr) {
+ //printk("GSP_Gen_Block_Ccaler_Coef:%d _Allocate error! \n",__LINE__);
+ return FALSE;
+ }
+
+ /* calculate coefficients of Y component in horizontal direction */
+ coef_len = CalY_ScalingCoef(hor_tap, D_hor, I_hor, temp_filter_ptr, 1, &pool);
+ GetFilter(temp_filter_ptr, filter_ptr, 8, coef_len, filter_len);
+ WriteScalarCoef(cong_com_hor, filter_ptr, 8, hor_tap);
+ CheckCoefRange(cong_com_hor, 8, hor_tap, 8);
+ GSP_Rearrang_Coeff(cong_com_hor, coeff_array, hor_tap);
+ {
+ uint32_t cnts = 0, reg = 0;
+ uint16_t p0, p1;
+ for (i = 0; i < 8; i++) {
+ p0 = (uint16_t)(*(coeff_array + i * 8 + 0));
+ p1 = (uint16_t)(*(coeff_array + i * 8 + 1));
+ reg = (p0 & 0x1ff)|((p1 & 0x1ff)<<16);
+ coeff_h_ptr[cnts + 0] = reg;
+
+ p0 = (uint16_t)(*(coeff_array + i * 8 + 2));
+ p1 = (uint16_t)(*(coeff_array + i * 8 + 3));
+ reg = (p0 & 0x1ff)|((p1 & 0x1ff)<<16);
+ coeff_h_ptr[cnts + 1] = reg;
+
+ p0 = (uint16_t)(*(coeff_array + i * 8 + 4));
+ p1 = (uint16_t)(*(coeff_array + i * 8 + 5));
+ reg = (p0 & 0x1ff)|((p1 & 0x1ff)<<16);
+ coeff_h_ptr[cnts + 2] = reg;
+
+ p0 = (uint16_t)(*(coeff_array + i * 8 + 6));
+ p1 = (uint16_t)(*(coeff_array + i * 8 + 7));
+ reg = (p0 & 0x1ff)|((p1 & 0x1ff)<<16);
+ coeff_h_ptr[cnts + 3] = reg;
+
+ cnts += 4;
+ }
+ }
+
+ /* calculate coefficients of UV component in horizontal direction */
+ coef_len = CalUV_ScalingCoef(ver_tap, D_hor, I_hor, temp_filter_ptr, 1, &pool);
+ GetFilter(temp_filter_ptr, filter_ptr, 8, coef_len, filter_len);
+ WriteScalarCoef(cong_com_ver, filter_ptr, 8, ver_tap);
+ CheckCoefRange(cong_com_ver, 8, ver_tap, 8);
+ memset(coeff_array, 0x00, 8 * 8 * sizeof(int16_t));
+ GSP_Rearrang_Coeff(cong_com_ver, coeff_array, ver_tap);
+ {
+ uint32_t cnts = 0, reg = 0;
+ uint16_t p0, p1;
+ for (i = 0; i < 8; i++) {
+ p0 = (uint16_t)(*(coeff_array + i * 8 + 0));
+ p1 = (uint16_t)(*(coeff_array + i * 8 + 1));
+ reg = (p0 & 0x1ff)|((p1 & 0x1ff)<<16);
+ coeff_v_ptr[cnts + 0] = reg;
+
+ p0 = (uint16_t)(*(coeff_array + i * 8 + 2));
+ p1 = (uint16_t)(*(coeff_array + i * 8 + 3));
+ reg = (p0 & 0x1ff)|((p1 & 0x1ff)<<16);
+ coeff_v_ptr[cnts + 1] = reg;
+
+ p0 = (uint16_t)(*(coeff_array + i * 8 + 4));
+ p1 = (uint16_t)(*(coeff_array + i * 8 + 5));
+ reg = (p0 & 0x1ff)|((p1 & 0x1ff)<<16);
+ coeff_v_ptr[cnts + 2] = reg;
+
+ p0 = (uint16_t)(*(coeff_array + i * 8 + 6));
+ p1 = (uint16_t)(*(coeff_array + i * 8 + 7));
+ reg = (p0 & 0x1ff)|((p1 & 0x1ff)<<16);
+ coeff_v_ptr[cnts + 3] = reg;
+
+ cnts += 4;
+ }
+ }
+
+#ifdef CACHE_COEF
+ if(gspCtx->cache_coef_init_flag == 1) {
+ pEntry = LIST_GET_THE_TAIL_ENTRY();
+ if(pEntry->in_w == 0) {
+ pr_debug("GSP_CACHE_COEF:add\n");
+ } else {
+ pr_debug("GSP_CACHE_COEF:swap\n");
+ }
+ if((ulong)coeff_h_ptr & MEM_OPS_ADDR_ALIGN_MASK || (ulong)pEntry->coef & MEM_OPS_ADDR_ALIGN_MASK) {
+ GSP_TRACE("%s[%d] memcpy use none 8B alignment address!",__func__,__LINE__);
+ }
+ memcpy((void*)pEntry->coef,(void*)coeff_h_ptr,COEF_MATRIX_ENTRY_SIZE*4);
+ cache_coef_move_entry_to_list_head(pEntry);
+ LIST_SET_ENTRY_KEY(pEntry,i_w,i_h,o_w,o_h,hor_tap,ver_tap);
+ }
+#endif
+
+ return TRUE;
+}
+void GSP_Scale_Coef_Tab_Config(uint32_t *p_h_coeff,uint32_t *p_v_coeff)
+{
+ uint32_t i=0, j = 0;
+ uint32_t *s_scaling_reg_hor_ptr =0, *s_scaling_reg_ver_ptr=0;
+ ulong scale_h_coef_addr = GSP_HOR_COEF_BASE, scale_v_coef_addr = GSP_VER_COEF_BASE;
+
+
+ s_scaling_reg_hor_ptr = p_h_coeff;
+
+ for( i = 0; i < 8; i++) {
+ for(j = 0; j < 4; j++) {
+ *(volatile uint32_t*)scale_h_coef_addr = *s_scaling_reg_hor_ptr;
+ scale_h_coef_addr += 4;
+ s_scaling_reg_hor_ptr++;
+ }
+ }
+
+ s_scaling_reg_ver_ptr = p_v_coeff;
+ for( i = 0; i < 8; i++) {
+ for(j = 0; j < 4; j++) {
+ *(volatile uint32_t*)scale_v_coef_addr = *s_scaling_reg_ver_ptr;
+ scale_v_coef_addr += 4;
+ s_scaling_reg_ver_ptr++;
+ }
+ }
+}
diff --git a/drivers/media/sprd_gsp/scaler_coef_cal.h b/drivers/media/sprd_gsp/scaler_coef_cal.h
new file mode 100644
index 00000000..9eee8e70
--- /dev/null
+++ b/drivers/media/sprd_gsp/scaler_coef_cal.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SCALER_COEF_CAL_
+#define SCALER_COEF_CAL_
+//#include "sci_types.h"
+#include <linux/types.h>
+#include "gsp_config_if.h"
+
+#ifndef COUNT
+#define COUNT 256
+#endif
+
+#define GSP_COEFF_BUF_SIZE (8 << 10)
+#define GSP_COEFF_COEF_SIZE (1 << 10)
+#define GSP_COEFF_POOL_SIZE (6 << 10)
+
+
+
+/**---------------------------------------------------------------------------*
+ ** Public Functions *
+ **---------------------------------------------------------------------------*/
+/****************************************************************************/
+/* Purpose: generate scale factor */
+/* Author: */
+/* Input: */
+/* i_w: source image width */
+/* i_h: source image height */
+/* o_w: target image width */
+/* o_h: target image height */
+/* Output: */
+/* coeff_h_ptr: pointer of horizontal coefficient buffer, the size of which must be at */
+/* least SCALER_COEF_TAP_NUM_HOR * 4 bytes */
+/* the output coefficient will be located in coeff_h_ptr[0], ......, */
+/* coeff_h_ptr[SCALER_COEF_TAP_NUM_HOR-1] */
+/* coeff_v_ptr: pointer of vertical coefficient buffer, the size of which must be at */
+/* least (SCALER_COEF_TAP_NUM_VER + 1) * 4 bytes */
+/* the output coefficient will be located in coeff_v_ptr[0], ......, */
+/* coeff_h_ptr[SCALER_COEF_TAP_NUM_VER-1] and the tap number */
+/* will be located in coeff_h_ptr[SCALER_COEF_TAP_NUM_VER] */
+/* temp_buf_ptr: temp buffer used while generate the coefficient */
+/* temp_buf_ptr: temp buffer size, 6k is the suggest size */
+/* Return: */
+/* Note: */
+/****************************************************************************/
+uint8_t GSP_Gen_Block_Ccaler_Coef(uint32_t i_w,
+ uint32_t i_h,
+ uint32_t o_w,
+ uint32_t o_h,
+ uint32_t hor_tap,
+ uint32_t ver_tap,
+ uint32_t *coeff_h_ptr,
+ uint32_t *coeff_v_ptr,
+ void *temp_buf_ptr,
+ uint32_t temp_buf_size,
+ gsp_context_t *gspCtx);
+
+void GSP_Scale_Coef_Tab_Config(uint32_t *p_h_coeff,uint32_t *p_v_coeff);
+#endif
+
+
+
diff --git a/drivers/media/sprd_gsp/sin_cos.c b/drivers/media/sprd_gsp/sin_cos.c
new file mode 100644
index 00000000..ce78fbf8
--- /dev/null
+++ b/drivers/media/sprd_gsp/sin_cos.c
@@ -0,0 +1,153 @@
+/*
+* Copyright (C) 2012 Spreadtrum Communications Inc.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+
+#include "sin_cos.h"
+#define SINCOS_BIT_31 (1 << 31)
+#define SINCOS_BIT_30 (1 << 30)
+#define SMULL(x, y) ((int64_t)(x) * (int64_t)(y))
+
+static const uint32_t cossin_tbl[64] = {
+ 0x3ffec42d, 0x00c90e90, 0x3ff4e5e0, 0x025b0caf,
+ 0x3fe12acb, 0x03ecadcf, 0x3fc395f9, 0x057db403,
+ 0x3f9c2bfb, 0x070de172, 0x3f6af2e3, 0x089cf867,
+ 0x3f2ff24a, 0x0a2abb59, 0x3eeb3347, 0x0bb6ecef,
+ 0x3e9cc076, 0x0d415013, 0x3e44a5ef, 0x0ec9a7f3,
+ 0x3de2f148, 0x104fb80e, 0x3d77b192, 0x11d3443f,
+ 0x3d02f757, 0x135410c3, 0x3c84d496, 0x14d1e242,
+ 0x3bfd5cc4, 0x164c7ddd, 0x3b6ca4c4, 0x17c3a931,
+ 0x3ad2c2e8, 0x19372a64, 0x3a2fcee8, 0x1aa6c82b,
+ 0x3983e1e8, 0x1c1249d8, 0x38cf1669, 0x1d79775c,
+ 0x3811884d, 0x1edc1953, 0x374b54ce, 0x2039f90f,
+ 0x367c9a7e, 0x2192e09b, 0x35a5793c, 0x22e69ac8,
+ 0x34c61236, 0x2434f332, 0x33de87de, 0x257db64c,
+ 0x32eefdea, 0x26c0b162, 0x31f79948, 0x27fdb2a7,
+ 0x30f8801f, 0x29348937, 0x2ff1d9c7, 0x2a650525,
+ 0x2ee3cebe, 0x2b8ef77d, 0x2dce88aa, 0x2cb2324c
+};
+
+static int32_t sin_core(int32_t arc_q33, int32_t sign)
+{
+ int32_t a, b, B;
+ int32_t sin_a, cos_a;
+ int32_t S1, S2, S3, S4, T1;
+ int32_t R = 0;
+ int32_t C1 = 0x6487ed51;
+ int32_t C2 = -715827882;
+
+ a = arc_q33 >> 25;
+ cos_a = cossin_tbl[2 * a];
+ sin_a = cossin_tbl[2 * a + 1];
+ cos_a ^= (sign >> 31);
+ sin_a ^= (sign >> 31);
+ a = a << 25;
+ b = arc_q33 - a;
+ b -= (1 << 24);
+ B = SMULL((b << 3), C1) >> 32;
+ T1 = SMULL(B, B) >> 32;
+ S1 = sin_a;
+ S2 = SMULL(sin_a, T1 >> 1) >> 32;
+ S3 = SMULL(cos_a, B) >> 32;
+ S4 = SMULL(T1, C2) >> 32;
+ S4 = SMULL(S3, S4) >> 32;
+ R = S1 - S2 + S3 + S4;
+ return R;
+}
+
+static int32_t cos_core(int32_t arc_q33, int32_t sign)
+{
+ int32_t a, b, B;
+ int32_t sin_a, cos_a;
+ int32_t S1, S2, S3, S4, T1;
+ int32_t R = 0;
+ int32_t C1 = 0x6487ed51; //round(2 * PI * 2 ^ 28)
+ int32_t C2 = 0x2aaaaaab; //round(2^32/6)
+
+ a = arc_q33 >> 25;
+ cos_a = cossin_tbl[a * 2];
+ sin_a = cossin_tbl[a * 2 + 1];
+ cos_a ^= (sign >> 31);
+ sin_a ^= (sign >> 31);
+ a = a << 25;
+ b = arc_q33 - a;
+ b -= (1 << 24);
+ B = SMULL((b << 3), C1) >> 32;
+ T1 = SMULL(B, B) >> 32;
+ S1 = cos_a;
+ S2 = SMULL(cos_a, T1 >> 1) >> 32;
+ S3 = SMULL(sin_a, B) >> 32;
+ S4 = SMULL(T1, C2) >> 32;
+ S4 = SMULL(S3, S4) >> 32;
+ R = S1 - S2 - S3 + S4;
+ return R;
+}
+
+int32_t sin_32(int32_t n)
+{
+ int32_t s = n & SINCOS_BIT_31;
+ n = n << 1;
+ if (0 == n) {
+ return 0;
+ }
+ if (SINCOS_BIT_31 == (n & SINCOS_BIT_31)) {
+ n &= ~SINCOS_BIT_31;
+ if (n < SINCOS_BIT_30) {
+ return cos_core(n, s);
+ } else if (n == SINCOS_BIT_30) {
+ n -= 1;
+ } else if (n > SINCOS_BIT_30) {
+ n = SINCOS_BIT_31 - n;
+ }
+ return sin_core(n, s);
+ } else {
+ if (n < SINCOS_BIT_30) {
+ return sin_core(n, s);
+ }
+ if (n == SINCOS_BIT_30) {
+ n -= 1;
+ } else if (n > SINCOS_BIT_30) {
+ n = SINCOS_BIT_31 - n;
+ }
+ return cos_core(n, s);
+ }
+}
+
+int32_t cos_32(int32_t n)
+{
+ int32_t s = n & SINCOS_BIT_31;
+
+ n = n << 1;
+ if (n == SINCOS_BIT_31) {
+ return 0;
+ }
+ if (SINCOS_BIT_31 == (n & SINCOS_BIT_31)) {
+ n &= ~SINCOS_BIT_31;
+ if (n < SINCOS_BIT_30) {
+ return -sin_core(n, s);
+ } else if (n == SINCOS_BIT_30) {
+ n -= 1;
+ } else if (n > SINCOS_BIT_30) {
+ n = SINCOS_BIT_31 - n;
+ }
+ return -cos_core(n, s);
+ } else {
+ if (n < SINCOS_BIT_30) {
+ return cos_core(n, s);
+ }
+ if (n == SINCOS_BIT_30) {
+ n -= 1;
+ } else if (n > SINCOS_BIT_30) {
+ n = SINCOS_BIT_31 - n;
+ }
+ return sin_core(n, s);
+ }
+}
diff --git a/drivers/media/sprd_gsp/sin_cos.h b/drivers/media/sprd_gsp/sin_cos.h
new file mode 100644
index 00000000..ce5e0035
--- /dev/null
+++ b/drivers/media/sprd_gsp/sin_cos.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _SIN_COS_H_
+#define _SIN_COS_H_
+#include <linux/types.h>
+
+#define COSSIN_Q 30
+#define pi 3.14159265359
+#define PI_32 0x3243F6A88
+#define ARC_32_COEF 0x80000000
+#define ARC_32(arc) (int32_t)((arc) / (pi) * ARC_32_COEF);
+int32_t sin_32(int32_t n);
+int32_t cos_32(int32_t n);
+#endif