diff options
Diffstat (limited to 'drivers/autotst/dispc.c')
| -rw-r--r-- | drivers/autotst/dispc.c | 1221 |
1 files changed, 1221 insertions, 0 deletions
diff --git a/drivers/autotst/dispc.c b/drivers/autotst/dispc.c new file mode 100644 index 00000000..763be07e --- /dev/null +++ b/drivers/autotst/dispc.c @@ -0,0 +1,1221 @@ +/* + * 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/clk.h> +#include <linux/io.h> +#include <linux/fb.h> +#include <linux/delay.h> + +#include <soc/sprd/hardware.h> +#include <soc/sprd/globalregs.h> +#include <soc/sprd/irqs.h> +#include <soc/sprd/sci.h> +//#include <soc/sprd/sci_glb_regs.h> + +//#include <mach/pinmap.h> + +#include "dispc_reg.h" +#include "lcd_dummy.h" +#include "dispc.h" +#include "pinmap_gpio.h" + +#define pr_debug printk + +#ifdef CONFIG_FB_SCX15 +#define DISPC_CLOCK_PARENT ("clk_192m") +#define DISPC_CLOCK (192*1000000) +#define DISPC_DBI_CLOCK_PARENT ("clk_256m") +#define DISPC_DBI_CLOCK (256*1000000) +#define DISPC_DPI_CLOCK_PARENT ("clk_192m") +#define SPRDFB_DPI_CLOCK_SRC (192000000) +#define DISPC_DPI_CLOCK (192*1000000/18) +#else +#define DISPC_CLOCK_PARENT ("clk_256m") +#define DISPC_CLOCK (256*1000000) +#define DISPC_DBI_CLOCK_PARENT ("clk_256m") +#define DISPC_DBI_CLOCK (256*1000000) +#define DISPC_DPI_CLOCK_PARENT ("clk_384m") +#define SPRDFB_DPI_CLOCK_SRC (384000000) +#define DISPC_DPI_CLOCK (384*1000000/36) +#endif + +#define DISPC_EMC_EN_PARENT ("clk_aon_apb") + +#if ((defined CONFIG_FB_SCX30G)||(defined CONFIG_FB_SCX35L)) +#define DISPC_PLL_CLK ("clk_dispc0") +#define DISPC_DBI_CLK ("clk_dispc0_dbi") +#define DISPC_DPI_CLK ("clk_dispc0_dpi") +#else +#define DISPC_PLL_CLK ("clk_disc0") +#define DISPC_DBI_CLK ("clk_disc0_dbi") +#define DISPC_DPI_CLK ("clk_disc0_dpi") +#endif +#define DISPC_EMC_CLK ("clk_disp_emc") + +#define PATTEN_GRID_WIDTH (40) +#define PATTEN_GRID_HEIGHT (40) +#define PATTEN_COLOR_COUNT (7) + +extern struct panel_spec lcd_dummy_mipi_spec; +extern struct panel_spec lcd_dummy_rgb_spec; +extern struct panel_spec lcd_dummy_mcu_spec; + +extern void autotst_dsi_dump(void); +extern void autotst_dsi_dump1(void); +extern int32_t autotst_dsi_init(struct panel_spec *panel); +extern int32_t autotst_dsi_uninit(void); + +struct autotst_dispc_context { + struct clk *clk_dispc; + struct clk *clk_dispc_dpi; + struct clk *clk_dispc_dbi; + struct clk *clk_dispc_emc; + uint32_t fb_addr_v; + uint32_t fb_addr_p; + uint32_t fb_size; + uint32_t dispc_if; + bool is_inited; +}; + +static struct autotst_dispc_context autotst_dispc_ctx = {0}; +static struct panel_spec *autotst_panel = NULL; + +static uint32_t g_patten_table[PATTEN_COLOR_COUNT] = + {0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00, 0xff00ffff, 0xffff00ff, 0xffffffff}; + +unsigned long sprd_adi_base; + +#if 0 /*designed for RGB, not used for SHARKL*/ +int autotst_dispc_pin_ctrl(int type) +{ + static int pin_table[29]; + static int is_first_time = true; + int i; + u32 regs = REG_PIN_LCD_CSN1; + u32 func; + + if (is_first_time) { + for (i = 0; i < 29; ++i) { + pin_table[i] = pinmap_get(regs); + regs += 4; + } + is_first_time = false; + } + + if (type == DISPC_PIN_FUNC3) + func = BITS_PIN_DS(1) | BITS_PIN_AF(DISPC_PIN_FUNC3) | BIT_PIN_SLP_AP; + else { + pr_err("The function hasn't been implemented yet\n"); + return 0; + } + + regs = REG_PIN_LCD_CSN1; + for (i = 0; i < 29; ++i) { + if (type == DISPC_PIN_FUNC0) + pinmap_set(regs, pin_table[i]); + else + pinmap_set(regs, func); + regs += 4; + } + + return 0; +} +#endif + +int autotst_pin_ctrl(int type, int gpio_num, int gpio_pull) +{ + static int pin_table; + int i; + u32 regs = REG_PIN_U0TXD; + u32 func; + u32 mask; +#ifdef CONFIG_REGULATOR_SC2713S + mask = BIT_LDO_SD_PD | BIT_LDO_SIM0_PD | BIT_LDO_SIM1_PD | BIT_LDO_SIM2_PD | BIT_LDO_CAMA_PD |\ + BIT_LDO_CAMD_PD | BIT_LDO_CAMIO_PD | BIT_LDO_CAMMOT_PD; + + ANA_REG_BIC(ANA_REG_GLB_LDO_PD_CTRL, mask); + + for (i = 0; i < ARRAY_SIZE(pinmap_gpio); ++i) { + if( gpio_num == pinmap_gpio[i].num){ + regs = pinmap_gpio[i].reg; + pin_table = pinmap_get(regs); + break; + } + } + + if (type == DISPC_PIN_FUNC3){ + func = BITS_PIN_DS(1) | BITS_PIN_AF(DISPC_PIN_FUNC3) | BIT_PIN_SLP_AP | gpio_pull; + }else { + pr_err("The function hasn't been implemented yet\n"); + } + + if (type == DISPC_PIN_FUNC0){ + pinmap_set(regs, pin_table); + }else{ + pinmap_set(regs, func); + } +#endif + return 0; +} + +/**********************************************/ +/* MCU PANEL CONFIG */ +/**********************************************/ +static uint32_t mcu_calc_timing(struct timing_mcu *timing) +{ + uint32_t clk_rate; + uint32_t rcss, rlpw, rhpw, wcss, wlpw, whpw; + struct clk * clk = NULL; + + if(NULL == timing){ + printk(KERN_ERR "autotst_dispc: [%s]: Invalid Param\n", __FUNCTION__); + return 0; + } + + clk = clk_get(NULL,"clk_dispc_dbi"); + if (IS_ERR(clk)) { + printk(KERN_WARNING "autotst_dispc: get clk_dispc_dbi fail!\n"); + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_dispc_dbi ok!\n"); + } +// clk_rate = clk_get_rate(clk) / 1000000; + clk_rate = 250; // dummy 250M Hz + + pr_debug(KERN_INFO "autotst_dispc: [%s] clk_rate: 0x%x\n", __FUNCTION__, clk_rate); + + /******************************************************** + * we assume : t = ? ns, dispc_dbi = ? MHz so + * 1ns need cycle : dispc_dbi /1000 + * tns need cycles : t * dispc_dbi / 1000 + * + ********************************************************/ +#define MAX_DBI_RWCSS_TIMING_VALUE 15 +#define MAX_DBI_RWLPW_TIMING_VALUE 63 +#define MAX_DBI_RWHPW_TIMING_VALUE 63 +#define DBI_CYCLES(ns) (( (ns) * clk_rate + 1000 - 1)/ 1000) + + /* ceiling*/ + rcss = DBI_CYCLES(timing->rcss); + if (rcss > MAX_DBI_RWCSS_TIMING_VALUE) { + rcss = MAX_DBI_RWCSS_TIMING_VALUE ; + } + + rlpw = DBI_CYCLES(timing->rlpw); + if (rlpw > MAX_DBI_RWLPW_TIMING_VALUE) { + rlpw = MAX_DBI_RWLPW_TIMING_VALUE ; + } + + rhpw = DBI_CYCLES (timing->rhpw); + if (rhpw > MAX_DBI_RWHPW_TIMING_VALUE) { + rhpw = MAX_DBI_RWHPW_TIMING_VALUE ; + } + + wcss = DBI_CYCLES(timing->wcss); + if (wcss > MAX_DBI_RWCSS_TIMING_VALUE) { + wcss = MAX_DBI_RWCSS_TIMING_VALUE ; + } + + wlpw = DBI_CYCLES(timing->wlpw); + if (wlpw > MAX_DBI_RWLPW_TIMING_VALUE) { + wlpw = MAX_DBI_RWLPW_TIMING_VALUE ; + } + +#ifndef CONFIG_LCD_CS_ALWAYS_LOW + /* dispc/lcdc will waste one cycle because CS pulse will use one cycle*/ + whpw = DBI_CYCLES (timing->whpw) - 1; +#else + whpw = DBI_CYCLES (timing->whpw) ; +#endif + if (whpw > MAX_DBI_RWHPW_TIMING_VALUE) { + whpw = MAX_DBI_RWHPW_TIMING_VALUE ; + } + + return (whpw | (wlpw << 6) | (wcss << 12) + | (rhpw << 16) |(rlpw << 22) | (rcss << 28)); +} + +#ifdef CONFIG_FB_LCD_CS1 +/*cs1*/ +static void mcu_dispc_init_config(struct panel_spec *panel) +{ + uint32_t reg_val = 0; + + pr_debug("autotst_dispc: [%s] for cs1\n", __FUNCTION__); + + if(NULL == panel){ + printk(KERN_ERR "autotst_dispc: [%s] fail.(Invalid Param)\n", __FUNCTION__); + return; + } + + if(SPRDFB_PANEL_TYPE_MCU != panel->type){ + printk(KERN_ERR "autotst_dispc: [%s] fail.(not mcu panel)\n", __FUNCTION__); + return; + } + + /*use dbi as interface*/ + dispc_set_bits((2<<1), DISPC_CTRL); + autotst_dispc_ctx.dispc_if = DISPC_IF_DBI; + + /* CS1 bus mode [BIT8]: 8080/6800 */ + switch (panel->info.mcu->bus_mode) { + case LCD_BUS_8080: + break; + case LCD_BUS_6800: + reg_val |= (1<<8); + break; + default: + break; + } + /* CS1 bus width [BIT11:9] */ + switch (panel->info.mcu->bus_width) { + case 8: + break; + case 9: + reg_val |= (1 << 9); + break; + case 16: + reg_val |= (2 << 9); + break; + case 18: + reg_val |= (3 << 9) ; + break; + case 24: + reg_val |= (4 << 9); + break; + default: + break; + } + + /*CS1 pixel bits [BIT13:12]*/ + switch (panel->info.mcu->bpp) { + case 16: + break; + case 18: + reg_val |= (1 << 12) ; + break; + case 24: + reg_val |= (2 << 12); + break; + default: + break; + } + +#ifndef CONFIG_FB_NO_FMARK + /*TE enable*/ + reg_val |= (1 << 16); + if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){ + reg_val |= (1<< 17); + } + dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY); +#endif + +#ifdef CONFIG_LCD_CS_ALWAYS_LOW + /*CS alway low mode*/ + reg_val |= (1<<21); +#else + /*CS not alway low mode*/ +#endif + + /*CS1 selected*/ + reg_val |= (1 << 20); + + dispc_write(reg_val, DISPC_DBI_CTRL); + + pr_debug("autotst_dispc: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL)); +} + +static void mcu_dispc_set_timing(struct panel_spec *panel) +{ + uint32_t timing = 0; + + pr_debug("autotst_dispc: [%s] for cs1\n", __FUNCTION__); + + timing = mcu_calc_timing(panel->info.mcu->timing); + dispc_write(timing,DISPC_DBI_TIMING1); +} + +#else +/*cs0*/ +static void mcu_dispc_init_config(struct panel_spec *panel) +{ + uint32_t reg_val = 0; + + pr_debug("autotst_dispc: [%s] for cs0\n", __FUNCTION__); + + if(NULL == panel){ + printk(KERN_ERR "autotst_dispc: [%s] fail.(Invalid Param)\n", __FUNCTION__); + return; + } + + if(SPRDFB_PANEL_TYPE_MCU != panel->type){ + printk(KERN_ERR "autotst_dispc: [%s] fail.(not mcu panel)\n", __FUNCTION__); + return; + } + + /*use dbi as interface*/ + dispc_set_bits((2<<1), DISPC_CTRL); + autotst_dispc_ctx.dispc_if = DISPC_IF_DBI; + + /* CS0 bus mode [BIT0]: 8080/6800 */ + switch (panel->info.mcu->bus_mode) { + case LCD_BUS_8080: + break; + case LCD_BUS_6800: + reg_val |= 1; + break; + default: + break; + } + /* CS0 bus width [BIT3:1] */ + switch (panel->info.mcu->bus_width) { + case 8: + break; + case 9: + reg_val |= (1 << 1); + break; + case 16: + reg_val |= (2 << 1); + break; + case 18: + reg_val |= (3 << 1) ; + break; + case 24: + reg_val |= (4 << 1); + break; + default: + break; + } + + /*CS0 pixel bits [BIT5:4]*/ + switch (panel->info.mcu->bpp) { + case 16: + break; + case 18: + reg_val |= (1 << 4) ; + break; + case 24: + reg_val |= (2 << 4); + break; + default: + break; + } + +#ifndef CONFIG_FB_NO_FMARK + /*TE enable*/ + reg_val |= (1 << 16); + if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){ + reg_val |= (1<< 17); + } + dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY); +#endif + +#ifdef CONFIG_LCD_CS_ALWAYS_LOW + /*CS alway low mode*/ + reg_val |= (1<<21); +#else + /*CS not alway low mode*/ +#endif + + /*CS0 selected*/ + + dispc_write(reg_val, DISPC_DBI_CTRL); + + pr_debug("autotst_dispc: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL)); +} + +static void mcu_dispc_set_timing(struct panel_spec *panel) +{ + uint32_t timing = 0; + + pr_debug("autotst_dispc: [%s] for cs0\n", __FUNCTION__); + + timing = mcu_calc_timing(panel->info.mcu->timing); + dispc_write(timing,DISPC_DBI_TIMING0); +} +#endif + + +/**********************************************/ +/* RGB PANEL CONFIG */ +/**********************************************/ +static uint32_t rgb_calc_h_timing(struct timing_rgb *timing) +{ + return (timing->hsync | (timing->hbp << 8) | (timing->hfp << 20)); +} + + +static uint32_t rgb_calc_v_timing(struct timing_rgb *timing) +{ + return (timing->vsync| (timing->vbp << 8) | (timing->vfp << 20)); +} + +static void rgb_dispc_init_config(struct panel_spec *panel) +{ + uint32_t reg_val = dispc_read(DISPC_DPI_CTRL); + + pr_debug("autotst_dispc: [%s]\n", __FUNCTION__); + + if(NULL == panel){ + printk(KERN_ERR "autotst_dispc: [%s] fail.(Invalid Param)\n", __FUNCTION__); + return; + } + + if(SPRDFB_PANEL_TYPE_RGB != panel->type){ + printk(KERN_ERR "autotst_dispc: [%s] fail.(not mcu panel)\n", __FUNCTION__); + return; + } + + /*use dpi as interface*/ + dispc_clear_bits((3<<1), DISPC_CTRL); + autotst_dispc_ctx.dispc_if = DISPC_IF_DPI; + + /*h sync pol*/ + if(SPRDFB_POLARITY_NEG == panel->info.rgb->h_sync_pol){ + reg_val |= (1<<0); + } + + /*v sync pol*/ + if(SPRDFB_POLARITY_NEG == panel->info.rgb->v_sync_pol){ + reg_val |= (1<<1); + } + + /*de sync pol*/ + if(SPRDFB_POLARITY_NEG == panel->info.rgb->de_pol){ + reg_val |= (1<<2); + } + +#ifdef CONFIG_DPI_SINGLE_RUN + /*single run mode*/ + reg_val |= (1<<3); +#endif + + /*dpi bits*/ + switch(panel->info.rgb->video_bus_width){ + case 16: + break; + case 18: + reg_val |= (1 << 6); + break; + case 24: + reg_val |= (2 << 6); + break; + default: + break; + } + + dispc_write(reg_val, DISPC_DPI_CTRL); + + pr_debug("autotst_dispc: [%s] DISPC_DPI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DPI_CTRL)); +} + +static void rgb_dispc_set_timing(struct panel_spec *panel) +{ + uint32_t timing_h = 0; + uint32_t timing_v = 0; + + pr_debug("autotst_dispc: [%s]\n", __FUNCTION__); + + timing_h = rgb_calc_h_timing(panel->info.rgb->timing); + timing_v = rgb_calc_v_timing(panel->info.rgb->timing); + + dispc_write(timing_h, DISPC_DPI_H_TIMING); + dispc_write(timing_v, DISPC_DPI_V_TIMING); +} + + +/**********************************************/ +/* MIPI PANEL CONFIG */ +/**********************************************/ +static void mipi_dispc_init_config(struct panel_spec *panel) +{ + uint32_t reg_val = dispc_read(DISPC_DPI_CTRL); + + pr_debug("autotst_dispc: [%s]\n", __FUNCTION__); + + if(NULL == panel){ + printk(KERN_ERR "autotst_dispc: [%s] fail.(Invalid Param)\n", __FUNCTION__); + return; + } + + if(SPRDFB_PANEL_TYPE_MIPI != panel->type){ + printk(KERN_ERR "autotst_dispc: [%s] fail.(not mcu panel)\n", __FUNCTION__); + return; + } + + if(SPRDFB_MIPI_MODE_CMD == panel->info.mipi->work_mode){ + /*use edpi as interface*/ + dispc_set_bits((1<<1), DISPC_CTRL); + autotst_dispc_ctx.dispc_if = DISPC_IF_EDPI; + }else{ + /*use dpi as interface*/ + dispc_clear_bits((3<<1), DISPC_CTRL); + autotst_dispc_ctx.dispc_if = DISPC_IF_DPI; + } + + /*h sync pol*/ + if(SPRDFB_POLARITY_NEG == panel->info.mipi->h_sync_pol){ + reg_val |= (1<<0); + } + + /*v sync pol*/ + if(SPRDFB_POLARITY_NEG == panel->info.mipi->v_sync_pol){ + reg_val |= (1<<1); + } + + /*de sync pol*/ + if(SPRDFB_POLARITY_NEG == panel->info.mipi->de_pol){ + reg_val |= (1<<2); + } + + if(SPRDFB_MIPI_MODE_VIDEO == panel->info.mipi->work_mode){ +#ifdef CONFIG_DPI_SINGLE_RUN + /*single run mode*/ + reg_val |= (1<<3); +#endif + }else{ + if(!(panel->cap & PANEL_CAP_NOT_TEAR_SYNC)){ + printk("autotst_dispc: mipi_dispc_init_config not support TE\n"); + /*enable te*/ + reg_val |= (1<<8); + } + /*te pol*/ + if(SPRDFB_POLARITY_NEG == panel->info.mipi->te_pol){ + reg_val |= (1<<9); + } + /*use external te*/ + reg_val |= (1<<10); + } + + /*dpi bits*/ + switch(panel->info.rgb->video_bus_width){ + case 16: + break; + case 18: + reg_val |= (1 << 6); + break; + case 24: + reg_val |= (2 << 6); + break; + default: + break; + } + + dispc_write(reg_val, DISPC_DPI_CTRL); + + pr_debug("autotst_dispc: [%s] DISPC_DPI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DPI_CTRL)); +} + +static void mipi_dispc_set_timing(struct panel_spec *panel) +{ + uint32_t timing_h = 0; + uint32_t timing_v = 0; + + pr_debug("autotst_dispc: [%s]\n", __FUNCTION__); + + timing_h = rgb_calc_h_timing(panel->info.mipi->timing); + timing_v = rgb_calc_v_timing(panel->info.mipi->timing); + + dispc_write(timing_h, DISPC_DPI_H_TIMING); + dispc_write(timing_v, DISPC_DPI_V_TIMING); +} + +/**********************************************/ +/* COMMON CONFIG */ +/**********************************************/ +static void dispc_print_clk(void) +{ + uint32_t reg_val0,reg_val1,reg_val2; + reg_val0 = sci_glb_read(SPRD_AONAPB_BASE+0x4, 0xffffffff); + reg_val1 = sci_glb_read(SPRD_AHB_BASE, 0xffffffff); + reg_val2 = sci_glb_read(SPRD_APBREG_BASE, 0xffffffff); + printk("autotst_dispc:0x402e0004 = 0x%x 0x20d00000 = 0x%x 0x71300000 = 0x%x \n",reg_val0, reg_val1, reg_val2); + reg_val0 = sci_glb_read(SPRD_APBCKG_BASE+0x34, 0xffffffff); + reg_val1 = sci_glb_read(SPRD_APBCKG_BASE+0x30, 0xffffffff); + reg_val2 = sci_glb_read(SPRD_APBCKG_BASE+0x2c, 0xffffffff); + printk("autotst_dispc:0x71200034 = 0x%x 0x71200030 = 0x%x 0x7120002c = 0x%x \n",reg_val0, reg_val1, reg_val2); +} + +static void dispc_reset(void) +{ + sci_glb_set(REG_AHB_SOFT_RST, (BIT_DISPC0_SOFT_RST) ); + udelay(10); + sci_glb_clr(REG_AHB_SOFT_RST, (BIT_DISPC0_SOFT_RST) ); +} + +static inline void dispc_set_bg_color(uint32_t bg_color) +{ + dispc_write(bg_color, DISPC_BG_COLOR); +} + +static inline void dispc_set_osd_ck(uint32_t ck_color) +{ + dispc_write(ck_color, DISPC_OSD_CK); +} + +static inline void dispc_osd_enable(bool is_enable) +{ + uint32_t reg_val; + + reg_val = dispc_read(DISPC_OSD_CTRL); + if(is_enable){ + reg_val = reg_val | (BIT(0)); + } + else{ + reg_val = reg_val & (~(BIT(0))); + } + dispc_write(reg_val, DISPC_OSD_CTRL); +} + + +static void dispc_dithering_enable(bool enable) +{ + if(enable){ + dispc_set_bits(BIT(6), DISPC_CTRL); + }else{ + dispc_clear_bits(BIT(6), DISPC_CTRL); + } +} + +static void dispc_pwr_enable(bool enable) +{ + if(enable){ + dispc_set_bits(BIT(7), DISPC_CTRL); + }else{ + dispc_clear_bits(BIT(7), DISPC_CTRL); + } +} + +static void dispc_set_exp_mode(uint16_t exp_mode) +{ + uint32_t reg_val = dispc_read(DISPC_CTRL); + + reg_val &= ~(0x3 << 16); + reg_val |= (exp_mode << 16); + dispc_write(reg_val, DISPC_CTRL); +} + +static void dispc_module_enable(void) +{ + /*dispc module enable */ + dispc_write((1<<0), DISPC_CTRL); + + /*disable dispc INT*/ + dispc_write(0x0, DISPC_INT_EN); + + /* clear dispc INT */ + dispc_write(0x1F, DISPC_INT_CLR); +} + +static void dispc_layer_init(struct panel_spec *panel) +{ + uint32_t reg_val = 0; + +// dispc_clear_bits((1<<0),DISPC_IMG_CTRL); + dispc_write(0x0, DISPC_IMG_CTRL); + dispc_clear_bits((1<<0),DISPC_OSD_CTRL); + + /******************* OSD layer setting **********************/ + + /*enable OSD layer*/ + reg_val |= (1 << 0); + + /*disable color key */ + + /* alpha mode select - block alpha*/ + reg_val |= (1 << 2); + + /* data format */ + //if (var->bits_per_pixel == 32) { + if(1){ + /* ABGR */ + reg_val |= (3 << 4); + /* rb switch */ + reg_val |= (1 << 15); + } else { + /* RGB565 */ + reg_val |= (5 << 4); + /* B2B3B0B1 */ + reg_val |= (2 << 8); + } + + dispc_write(reg_val, DISPC_OSD_CTRL); + + /* OSD layer alpha value */ + dispc_write(0xff, DISPC_OSD_ALPHA); + + /* OSD layer size */ + reg_val = ( panel->width & 0xfff) | (( panel->height & 0xfff ) << 16); + dispc_write(reg_val, DISPC_OSD_SIZE_XY); + + /* OSD layer start position */ + dispc_write(0, DISPC_OSD_DISP_XY); + + /* OSD layer pitch */ + reg_val = ( panel->width & 0xfff) ; + dispc_write(reg_val, DISPC_OSD_PITCH); + + /* OSD color_key value */ + dispc_set_osd_ck(0x0); + + /* DISPC workplane size */ + reg_val = ( panel->width & 0xfff) | ((panel->height & 0xfff ) << 16); + dispc_write(reg_val, DISPC_SIZE_XY); +} + +static void dispc_run(void) +{ + if(DISPC_IF_DPI == autotst_dispc_ctx.dispc_if){ + /*dpi register update*/ + dispc_set_bits(BIT(5), DISPC_DPI_CTRL); + udelay(30); + + /*dpi register update with SW and VSync*/ + dispc_clear_bits(BIT(4), DISPC_DPI_CTRL); + + /* start refresh */ + dispc_set_bits((1 << 4), DISPC_CTRL); + + }else{ + /* start refresh */ + dispc_set_bits((1 << 4), DISPC_CTRL); + } +} + +static void dispc_stop(void) +{ + if(DISPC_IF_DPI == autotst_dispc_ctx.dispc_if){ + /*dpi register update with SW only*/ + dispc_set_bits(BIT(4), DISPC_DPI_CTRL); + + /* stop refresh */ + dispc_clear_bits((1 << 4), DISPC_CTRL); + } +} + +static int dispc_clk_enable(struct autotst_dispc_context *dispc_ctx_ptr) +{ + int ret = 0; + bool is_dispc_enable=false; + bool is_dispc_dpi_enable=false; + + pr_debug(KERN_INFO "autotst_dispc:[%s]\n",__FUNCTION__); + if(!dispc_ctx_ptr){ + return -1; + } + + ret = clk_enable(dispc_ctx_ptr->clk_dispc); + if(ret){ + printk("autotst_dispc:enable clk_dispc error!!!\n"); + ret=-1; + goto ERROR_CLK_ENABLE; + } + is_dispc_enable=true; + ret = clk_enable(dispc_ctx_ptr->clk_dispc_dpi); + if(ret){ + printk("autotst_dispc:enable clk_dispc_dpi error!!!\n"); + ret=-1; + goto ERROR_CLK_ENABLE; + } + is_dispc_dpi_enable=true; + ret = clk_enable(dispc_ctx_ptr->clk_dispc_dbi); + if(ret){ + printk("autotst_dispc:enable clk_dispc_dbi error!!!\n"); + ret=-1; + goto ERROR_CLK_ENABLE; + } + + return ret; + +ERROR_CLK_ENABLE: + if(is_dispc_enable){ + clk_disable(dispc_ctx_ptr->clk_dispc); + } + if(is_dispc_dpi_enable){ + clk_disable(dispc_ctx_ptr->clk_dispc_dpi); + } + + printk("autotst_dispc:sprdfb_dispc_clk_enable error!!!!!!\n"); + return ret; +} + +static int32_t dispc_clk_init(void) +{ + int ret = 0; + struct clk *clk_parent1, *clk_parent2, *clk_parent3, *clk_parent4; + + pr_debug(KERN_INFO "autotst_dispc:[%s]\n", __FUNCTION__); + + sci_glb_set(DISPC_CORE_EN, BIT_DISPC_CORE_EN); + + clk_parent1 = clk_get(NULL, DISPC_CLOCK_PARENT); + if (IS_ERR(clk_parent1)) { + printk(KERN_WARNING "autotst_dispc: get clk_parent1 fail!\n"); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_parent1 ok!\n"); + } + + clk_parent2 = clk_get(NULL, DISPC_DBI_CLOCK_PARENT); + if (IS_ERR(clk_parent2)) { + printk(KERN_WARNING "autotst_dispc: get clk_parent2 fail!\n"); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_parent2 ok!\n"); + } + + clk_parent3 = clk_get(NULL, DISPC_DPI_CLOCK_PARENT); + if (IS_ERR(clk_parent3)) { + printk(KERN_WARNING "autotst_dispc: get clk_parent3 fail!\n"); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_parent3 ok!\n"); + } + + clk_parent4 = clk_get(NULL, DISPC_EMC_EN_PARENT); + if (IS_ERR(clk_parent3)) { + printk(KERN_WARNING "autotst_dispc: get clk_parent4 fail!\n"); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_parent4 ok!\n"); + } + + autotst_dispc_ctx.clk_dispc = clk_get(NULL, DISPC_PLL_CLK); + if (IS_ERR(autotst_dispc_ctx.clk_dispc)) { + printk(KERN_WARNING "autotst_dispc: get clk_dispc fail!\n"); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_dispc ok!\n"); + } + + autotst_dispc_ctx.clk_dispc_dbi = clk_get(NULL, DISPC_DBI_CLK); + if (IS_ERR(autotst_dispc_ctx.clk_dispc_dbi)) { + printk(KERN_WARNING "autotst_dispc: get clk_dispc_dbi fail!\n"); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_dispc_dbi ok!\n"); + } + + autotst_dispc_ctx.clk_dispc_dpi = clk_get(NULL, DISPC_DPI_CLK); + if (IS_ERR(autotst_dispc_ctx.clk_dispc_dpi)) { + printk(KERN_WARNING "autotst_dispc: get clk_dispc_dpi fail!\n"); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_dispc_dpi ok!\n"); + } + + autotst_dispc_ctx.clk_dispc_emc = clk_get(NULL, DISPC_EMC_CLK); + if (IS_ERR(autotst_dispc_ctx.clk_dispc_emc)) { + printk(KERN_WARNING "autotst_dispc: get clk_dispc_dpi fail!\n"); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc: get clk_dispc_emc ok!\n"); + } + + ret = clk_set_parent(autotst_dispc_ctx.clk_dispc, clk_parent1); + if(ret){ + printk(KERN_ERR "autotst_dispc: dispc set clk parent fail\n"); + } + ret = clk_set_rate(autotst_dispc_ctx.clk_dispc, DISPC_CLOCK); + if(ret){ + printk(KERN_ERR "autotst_dispc: dispc set clk parent fail\n"); + } + + ret = clk_set_parent(autotst_dispc_ctx.clk_dispc_dbi, clk_parent2); + if(ret){ + printk(KERN_ERR "autotst_dispc: dispc set dbi clk parent fail\n"); + } + ret = clk_set_rate(autotst_dispc_ctx.clk_dispc_dbi, DISPC_DBI_CLOCK); + if(ret){ + printk(KERN_ERR "autotst_dispc: dispc set dbi clk parent fail\n"); + } + + ret = clk_set_parent(autotst_dispc_ctx.clk_dispc_dpi, clk_parent3); + if(ret){ + printk(KERN_ERR "autotst_dispc: dispc set dpi clk parent fail\n"); + } + ret = clk_set_rate(autotst_dispc_ctx.clk_dispc_dpi, DISPC_DPI_CLOCK); + if(ret){ + printk(KERN_ERR "autotst_dispc: dispc set dpi clk parent fail\n"); + } + + ret = clk_set_parent(autotst_dispc_ctx.clk_dispc_emc, clk_parent4); + if(ret){ + printk(KERN_ERR "autotst_dispc: dispc set emc clk parent fail\n"); + } + + ret = clk_enable(autotst_dispc_ctx.clk_dispc_emc); + if(ret){ + printk("autotst_dispc:enable clk_dispc_emc error!!!\n"); + return -1; + } + + ret = dispc_clk_enable(&autotst_dispc_ctx); + if (ret) { + printk(KERN_WARNING "autotst_dispc:[%s] enable dispc_clk fail!\n",__FUNCTION__); + return -1; + } else { + pr_debug(KERN_INFO "autotst_dispc:[%s] enable dispc_clk ok!\n",__FUNCTION__); + } + + dispc_print_clk(); + + return 0; +} + +static int dispc_clk_disable(struct autotst_dispc_context *dispc_ctx_ptr) +{ + pr_debug(KERN_INFO "autotst_dispc:[%s]\n",__FUNCTION__); + if(!dispc_ctx_ptr){ + return 0; + } + + pr_debug(KERN_INFO "autotst_dispc:sprdfb_dispc_clk_disable real\n"); + clk_disable(dispc_ctx_ptr->clk_dispc); + clk_disable(dispc_ctx_ptr->clk_dispc_dpi); + clk_disable(dispc_ctx_ptr->clk_dispc_dbi); + + return 0; +} + +static void draw_patten(uint32_t* buffer, int buffer_w, int buffer_h, int grid_w, int grid_h) +{ + int h = 0; + int v = 0; + int i,j; + int grid_in_width = buffer_h / grid_w; + unsigned int c = 0; + + for (j = 0; j < buffer_h; j++) { + for (i = 0; i < buffer_w; i++) { + h = i / grid_w; + v = j / grid_h; + c = g_patten_table[(v*grid_in_width+h) % PATTEN_COLOR_COUNT]; + buffer[j*buffer_w+i] = c; + } + } +} + +static int dispc_fb_prepare(struct panel_spec *panel) +{ + uint32_t fb_size = 0;// should be ABGR888 + uint32_t *p_pixel = NULL; + + fb_size = panel->width * panel->height * 4;// should be ABGR888 + + autotst_dispc_ctx.fb_addr_v = __get_free_pages(GFP_ATOMIC | __GFP_ZERO , get_order(fb_size)); + if (!autotst_dispc_ctx.fb_addr_v) { + printk(KERN_ERR "sprdfb: %s Failed to allocate frame buffer\n", __FUNCTION__); + return -1; + } + printk(KERN_INFO "sprdfb: got %d bytes frame buffer at 0x%x\n", fb_size, + autotst_dispc_ctx.fb_addr_v); + + autotst_dispc_ctx.fb_addr_p = __pa(autotst_dispc_ctx.fb_addr_v); + autotst_dispc_ctx.fb_size = fb_size; + + p_pixel = autotst_dispc_ctx.fb_addr_v; + draw_patten(p_pixel, panel->width, panel->height, PATTEN_GRID_WIDTH, PATTEN_GRID_HEIGHT); + + return 0; +} + +void dispc_dump(void) +{ + int i = 0; + for(i=0;i<256;i+=16){ + printk("autotst_dispc: %x: 0x%x, 0x%x, 0x%x, 0x%x\n", i, dispc_read(i), + dispc_read(i+4), + dispc_read(i+8), + dispc_read(i+12)); + } + printk("**************************\n"); +} + +int32_t autotst_dispc_uninit(int display_type) +{ + printk(KERN_INFO "autotst_dispc:[%s]\n",__FUNCTION__); + + dispc_stop(); + dispc_clk_disable(&autotst_dispc_ctx); + if(DISPLAY_TYPE_MIPI == display_type){ + autotst_dsi_uninit(); + } + if(0 != autotst_dispc_ctx.fb_addr_v){ + free_pages(autotst_dispc_ctx.fb_addr_v, get_order(autotst_dispc_ctx.fb_size)); + } + autotst_dispc_ctx.fb_addr_v = 0; + autotst_dispc_ctx.fb_addr_p = 0; + autotst_dispc_ctx.fb_size = 0; + return 0; +} + +int32_t autotst_dispc_init(int display_type) +{ + int ret = 0; + + printk(KERN_INFO "autotst_dispc:[%s]\n",__FUNCTION__); + + //autotst_dsi_dump(); + + autotst_dispc_uninit(DISPLAY_TYPE_MIPI); + + ret = dispc_clk_init(); + if(ret){ + printk(KERN_WARNING "autotst_dispc: dispc_clk_init fail!\n"); + return -1; + } + + dispc_reset(); + dispc_module_enable(); + + /*set bg color*/ + dispc_set_bg_color(0xFFFFFFFF); + /*enable dithering*/ + dispc_dithering_enable(true); + /*use MSBs as img exp mode*/ + dispc_set_exp_mode(0x0); + //enable DISPC Power Control + dispc_pwr_enable(true); + + switch(display_type){ + case DISPLAY_TYPE_MCU: + autotst_panel = &lcd_dummy_mcu_spec; + mcu_dispc_init_config(autotst_panel); + mcu_dispc_set_timing(autotst_panel); + break; + case DISPLAY_TYPE_RGB: + autotst_panel = &lcd_dummy_rgb_spec; + rgb_dispc_init_config(autotst_panel); + rgb_dispc_set_timing(autotst_panel); + autotst_dispc_ctx.dispc_if = DISPC_IF_DPI; + break; + case DISPLAY_TYPE_MIPI: + autotst_panel = &lcd_dummy_mipi_spec; + mipi_dispc_init_config(autotst_panel); + mipi_dispc_set_timing(autotst_panel); + autotst_dsi_init(autotst_panel); + break; + default: + printk("autotst_dispc:[%s] error display type (%d)\n", __FUNCTION__, display_type); + } + + dispc_layer_init(autotst_panel); + + if(DISPC_IF_DPI == autotst_dispc_ctx.dispc_if){ + if(1){ + /*set dpi register update only with SW*/ + dispc_set_bits(BIT(4), DISPC_DPI_CTRL); + }else{ + /*set dpi register update with SW & VSYNC*/ + dispc_clear_bits(BIT(4), DISPC_DPI_CTRL); + } + /*enable dispc update done INT*/ + //dispc_write((1<<4), DISPC_INT_EN); + }else{ + /* enable dispc DONE INT*/ + //dispc_write((1<<0), DISPC_INT_EN); + } + //dispc_set_bits(BIT(2), DISPC_INT_EN); + return 0; +} + +int32_t autotst_dispc_refresh (void) +{ + int ret = 0; + uint32_t size = (autotst_panel->width& 0xffff) | ((autotst_panel->height) << 16); + printk(KERN_INFO "autotst_dispc:[%s]\n",__FUNCTION__); + + //autotst_dsi_dump(); + + ret = dispc_fb_prepare(autotst_panel); + if(0 != ret){ + printk("autotst_dispc: refresh fail!(can't prepare frame buffer)!]n"); + return -1; + } + + dispc_write(autotst_dispc_ctx.fb_addr_p, DISPC_OSD_BASE_ADDR); + dispc_write(0, DISPC_OSD_DISP_XY); + dispc_write(size, DISPC_OSD_SIZE_XY); + dispc_write(autotst_panel->width, DISPC_OSD_PITCH); + dispc_write(size, DISPC_SIZE_XY); + + dispc_run(); + +#if 1 + pr_debug("DISPC_CTRL: 0x%x\n", dispc_read(DISPC_CTRL)); + pr_debug("DISPC_SIZE_XY: 0x%x\n", dispc_read(DISPC_SIZE_XY)); + pr_debug("DISPC_BG_COLOR: 0x%x\n", dispc_read(DISPC_BG_COLOR)); + pr_debug("DISPC_INT_EN: 0x%x\n", dispc_read(DISPC_INT_EN)); + pr_debug("DISPC_OSD_CTRL: 0x%x\n", dispc_read(DISPC_OSD_CTRL)); + pr_debug("DISPC_OSD_BASE_ADDR: 0x%x\n", dispc_read(DISPC_OSD_BASE_ADDR)); + pr_debug("DISPC_OSD_SIZE_XY: 0x%x\n", dispc_read(DISPC_OSD_SIZE_XY)); + pr_debug("DISPC_OSD_PITCH: 0x%x\n", dispc_read(DISPC_OSD_PITCH)); + pr_debug("DISPC_OSD_DISP_XY: 0x%x\n", dispc_read(DISPC_OSD_DISP_XY)); + pr_debug("DISPC_OSD_ALPHA : 0x%x\n", dispc_read(DISPC_OSD_ALPHA)); +#else + mdelay(20); + dispc_dump(); + autotst_dsi_dump(); + autotst_dsi_dump1(); +#endif + return 0; +} + +/**********************************************/ +/* MCU OPERATION */ +/**********************************************/ +int32_t autotst_dispc_mcu_send_cmd(uint32_t cmd) +{ + /* busy wait for ahb fifo full sign's disappearance */ + while(dispc_read(DISPC_DBI_QUEUE) & BIT(5)); + + dispc_write(cmd, DISPC_DBI_CMD); + + return 0; +} + +int32_t autotst_dispc_mcu_send_cmd_data(uint32_t cmd, uint32_t data) +{ + /* busy wait for ahb fifo full sign's disappearance */ + while(dispc_read(DISPC_DBI_QUEUE) & BIT(5)); + + dispc_write(cmd, DISPC_DBI_CMD); + + /* busy wait for ahb fifo full sign's disappearance */ + while(dispc_read(DISPC_DBI_QUEUE) & BIT(5)); + + dispc_write(data, DISPC_DBI_DATA); + + return 0; +} + +int32_t autotst_dispc_mcu_send_data(uint32_t data) +{ + /* busy wait for ahb fifo full sign's disappearance */ + while(dispc_read(DISPC_DBI_QUEUE) & BIT(5)); + + dispc_write(data, DISPC_DBI_DATA); + + return 0; +} + +uint32_t autotst_dispc_mcu_read_data(void) +{ + /* busy wait for ahb fifo full sign's disappearance */ + while(dispc_read(DISPC_DBI_QUEUE) & BIT(5)); + dispc_write(1 << 24, DISPC_DBI_DATA); + udelay(50); + return dispc_read(DISPC_DBI_RDATA); +} + + |
