| /* |
| * drivers/display/lcd/aml_lcd.c |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the named License, |
| * or any later version. |
| * |
| * 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 <common.h> |
| #include <malloc.h> |
| #include <asm/cpu_id.h> |
| #include <asm/arch/gpio.h> |
| #ifdef CONFIG_OF_LIBFDT |
| #include <libfdt.h> |
| #endif |
| #include <amlogic/keyunify.h> |
| #include <amlogic/aml_lcd.h> |
| #ifdef CONFIG_AML_LCD_EXTERN |
| #include <amlogic/aml_lcd_extern.h> |
| #endif |
| #include "aml_lcd_reg.h" |
| #include "aml_lcd_common.h" |
| #ifdef CONFIG_AML_LCD_TABLET |
| #include "lcd_tablet/mipi_dsi_util.h" |
| #endif |
| |
| #define PANEL_NAME "panel" |
| |
| unsigned int lcd_debug_print_flag; |
| unsigned int lcd_debug_test; |
| static struct aml_lcd_drv_s aml_lcd_driver; |
| static void lcd_mute_setting(unsigned char flag); |
| |
| static void lcd_chip_detect(void) |
| { |
| #if 1 |
| unsigned int cpu_type; |
| |
| cpu_type = get_cpu_id().family_id; |
| switch (cpu_type) { |
| case MESON_CPU_MAJOR_ID_GXTVBB: |
| aml_lcd_driver.chip_type = LCD_CHIP_GXTVBB; |
| break; |
| case MESON_CPU_MAJOR_ID_GXL: |
| aml_lcd_driver.chip_type = LCD_CHIP_GXL; |
| break; |
| case MESON_CPU_MAJOR_ID_GXM: |
| aml_lcd_driver.chip_type = LCD_CHIP_GXM; |
| break; |
| case MESON_CPU_MAJOR_ID_TXL: |
| aml_lcd_driver.chip_type = LCD_CHIP_TXL; |
| break; |
| case MESON_CPU_MAJOR_ID_TXLX: |
| aml_lcd_driver.chip_type = LCD_CHIP_TXLX; |
| break; |
| case MESON_CPU_MAJOR_ID_AXG: |
| aml_lcd_driver.chip_type = LCD_CHIP_AXG; |
| break; |
| case MESON_CPU_MAJOR_ID_TXHD: |
| aml_lcd_driver.chip_type = LCD_CHIP_TXHD; |
| break; |
| case MESON_CPU_MAJOR_ID_G12A: |
| aml_lcd_driver.chip_type = LCD_CHIP_G12A; |
| break; |
| default: |
| aml_lcd_driver.chip_type = LCD_CHIP_MAX; |
| } |
| #else |
| aml_lcd_driver.chip_type = LCD_CHIP_G12A; |
| #endif |
| if (lcd_debug_print_flag) |
| LCDPR("check chip: %d\n", aml_lcd_driver.chip_type); |
| } |
| |
| static int lcd_check_valid(void) |
| { |
| if (aml_lcd_driver.config_check == NULL) { |
| LCDERR("invalid lcd config\n"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| static void lcd_power_ctrl(int status) |
| { |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| struct lcd_power_ctrl_s *lcd_power; |
| struct lcd_power_step_s *power_step; |
| #ifdef CONFIG_AML_LCD_EXTERN |
| struct aml_lcd_extern_driver_s *ext_drv; |
| #endif |
| char *str; |
| int i, gpio; |
| |
| i = 0; |
| lcd_power = lcd_drv->lcd_config->lcd_power; |
| while (i < LCD_PWR_STEP_MAX) { |
| if (status) |
| power_step = &lcd_power->power_on_step[i]; |
| else |
| power_step = &lcd_power->power_off_step[i]; |
| |
| if (power_step->type >= LCD_POWER_TYPE_MAX) |
| break; |
| if (lcd_debug_print_flag) { |
| LCDPR("power_ctrl: %d, step %d: type=%d, index=%d, value=%d, delay=%d\n", |
| status, i, power_step->type, power_step->index, |
| power_step->value, power_step->delay); |
| } |
| switch (power_step->type) { |
| case LCD_POWER_TYPE_CPU: |
| if (power_step->index < LCD_CPU_GPIO_NUM_MAX) { |
| str = lcd_power->cpu_gpio[power_step->index]; |
| gpio = aml_lcd_gpio_name_map_num(str); |
| aml_lcd_gpio_set(gpio, power_step->value); |
| } else { |
| LCDERR("cpu_gpio index: %d\n", power_step->index); |
| } |
| break; |
| case LCD_POWER_TYPE_PMU: |
| if (power_step->index < LCD_PMU_GPIO_NUM_MAX) |
| LCDPR("to do\n"); |
| else |
| LCDERR("pmu_gpio index: %d\n", power_step->index); |
| break; |
| case LCD_POWER_TYPE_SIGNAL: |
| if (status) |
| lcd_drv->driver_init(); |
| else |
| lcd_drv->driver_disable(); |
| break; |
| #ifdef CONFIG_AML_LCD_EXTERN |
| case LCD_POWER_TYPE_EXTERN: |
| ext_drv = aml_lcd_extern_get_driver(); |
| if (ext_drv) { |
| if (status) { |
| if (ext_drv->power_on) |
| ext_drv->power_on(); |
| else |
| LCDERR("no ext power on\n"); |
| } else { |
| if (ext_drv->power_off) |
| ext_drv->power_off(); |
| else |
| LCDERR("no ext power off\n"); |
| } |
| } |
| break; |
| #endif |
| default: |
| break; |
| } |
| if (power_step->delay) |
| mdelay(power_step->delay); |
| i++; |
| } |
| |
| if (lcd_debug_print_flag) |
| LCDPR("%s: %d\n", __func__, status); |
| } |
| |
| static void lcd_module_enable(char *mode) |
| { |
| unsigned int sync_duration; |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| struct lcd_config_s *pconf = lcd_drv->lcd_config; |
| int ret; |
| |
| ret = lcd_drv->config_check(mode); |
| if (ret) { |
| LCDERR("init exit\n"); |
| return; |
| } |
| |
| sync_duration = pconf->lcd_timing.sync_duration_num; |
| sync_duration = (sync_duration * 10 / pconf->lcd_timing.sync_duration_den); |
| LCDPR("enable: %s, %s, %ux%u@%u.%uHz\n", pconf->lcd_basic.model_name, |
| lcd_type_type_to_str(pconf->lcd_basic.lcd_type), |
| pconf->lcd_basic.h_active, pconf->lcd_basic.v_active, |
| (sync_duration / 10), (sync_duration % 10)); |
| |
| lcd_drv->driver_init_pre(); |
| lcd_power_ctrl(1); |
| lcd_vcbus_write(VPP_POSTBLEND_H_SIZE, pconf->lcd_basic.h_active); |
| lcd_vcbus_write(VENC_INTCTRL, 0x200); |
| |
| aml_bl_pwm_config_update(lcd_drv->bl_config); |
| aml_bl_set_level(lcd_drv->bl_config->level_default); |
| aml_bl_power_ctrl(1, 1); |
| lcd_mute_setting(0); |
| |
| lcd_drv->lcd_status = 1; |
| } |
| |
| static void lcd_module_disable(void) |
| { |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| |
| LCDPR("disable: %s\n", lcd_drv->lcd_config->lcd_basic.model_name); |
| |
| lcd_mute_setting(1); |
| aml_bl_power_ctrl(0, 1); |
| |
| lcd_power_ctrl(0); |
| |
| lcd_drv->lcd_status = 0; |
| } |
| |
| static void lcd_timing_info_print(struct lcd_config_s * pconf) |
| { |
| unsigned int hs_width, hs_bp, hs_pol, h_period; |
| unsigned int vs_width, vs_bp, vs_pol, v_period; |
| unsigned int video_on_pixel, video_on_line; |
| |
| video_on_pixel = pconf->lcd_timing.video_on_pixel; |
| video_on_line = pconf->lcd_timing.video_on_line; |
| h_period = pconf->lcd_basic.h_period; |
| v_period = pconf->lcd_basic.v_period; |
| |
| hs_width = pconf->lcd_timing.hsync_width; |
| hs_bp = pconf->lcd_timing.hsync_bp; |
| hs_pol = pconf->lcd_timing.hsync_pol; |
| vs_width = pconf->lcd_timing.vsync_width; |
| vs_bp = pconf->lcd_timing.vsync_bp; |
| vs_pol = pconf->lcd_timing.vsync_pol; |
| |
| printf("h_period %d\n" |
| "v_period %d\n" |
| "hs_width %d\n" |
| "hs_backporch %d\n" |
| "hs_pol %d\n" |
| "vs_width %d\n" |
| "vs_backporch %d\n" |
| "vs_pol %d\n" |
| "video_on_pixel %d\n" |
| "video_on_line %d\n\n", |
| h_period, v_period, hs_width, hs_bp, hs_pol, |
| vs_width, vs_bp, vs_pol, video_on_pixel, video_on_line); |
| |
| printf("h_period_min %d\n" |
| "h_period_max %d\n" |
| "v_period_min %d\n" |
| "v_period_max %d\n" |
| "pclk_min %d\n" |
| "pclk_max %d\n\n", |
| pconf->lcd_basic.h_period_min, pconf->lcd_basic.h_period_max, |
| pconf->lcd_basic.v_period_min, pconf->lcd_basic.v_period_max, |
| pconf->lcd_basic.lcd_clk_min, pconf->lcd_basic.lcd_clk_max); |
| } |
| |
| static void lcd_power_info_print(struct lcd_config_s *pconf, int status) |
| { |
| int i; |
| struct lcd_power_step_s *power_step; |
| |
| if (status) |
| printf("power on step:\n"); |
| else |
| printf("power off step:\n"); |
| |
| i = 0; |
| while (i < LCD_PWR_STEP_MAX) { |
| if (status) |
| power_step = &pconf->lcd_power->power_on_step[i]; |
| else |
| power_step = &pconf->lcd_power->power_off_step[i]; |
| |
| if (power_step->type >= LCD_POWER_TYPE_MAX) |
| break; |
| switch (power_step->type) { |
| case LCD_POWER_TYPE_CPU: |
| case LCD_POWER_TYPE_PMU: |
| printf("%d: type=%d, index=%d, value=%d, delay=%d\n", |
| i, power_step->type, power_step->index, |
| power_step->value, power_step->delay); |
| break; |
| case LCD_POWER_TYPE_EXTERN: |
| printf("%d: type=%d, index=%d, delay=%d\n", |
| i, power_step->type, power_step->index, |
| power_step->delay); |
| break; |
| case LCD_POWER_TYPE_SIGNAL: |
| printf("%d: type=%d, delay=%d\n", |
| i, power_step->type, power_step->delay); |
| break; |
| default: |
| break; |
| } |
| i++; |
| } |
| } |
| |
| static void lcd_pinmux_info_print(struct lcd_config_s *pconf) |
| { |
| int i; |
| |
| printf("pinmux:\n"); |
| |
| i = 0; |
| while (i < LCD_PINMUX_NUM) { |
| if (pconf->pinmux_set[i][0] == LCD_PINMUX_END) |
| break; |
| printf("pinmux_set: %d, 0x%08x\n", |
| pconf->pinmux_set[i][0], pconf->pinmux_set[i][1]); |
| i++; |
| } |
| i = 0; |
| while (i < LCD_PINMUX_NUM) { |
| if (pconf->pinmux_clr[i][0] == LCD_PINMUX_END) |
| break; |
| printf("pinmux_clr: %d, 0x%08x\n", |
| pconf->pinmux_clr[i][0], pconf->pinmux_clr[i][1]); |
| i++; |
| } |
| |
| printf("\n"); |
| } |
| |
| static void lcd_info_print(void) |
| { |
| unsigned int lcd_clk; |
| unsigned int sync_duration; |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| struct lcd_config_s *pconf = lcd_drv->lcd_config; |
| |
| LCDPR("driver version: %s\n", lcd_drv->version); |
| LCDPR("key_valid: %d\n", aml_lcd_driver.lcd_config->lcd_key_valid); |
| LCDPR("mode: %s, status: %d\n", |
| lcd_mode_mode_to_str(aml_lcd_driver.lcd_config->lcd_mode), lcd_drv->lcd_status); |
| |
| lcd_clk = (pconf->lcd_timing.lcd_clk / 1000); |
| sync_duration = pconf->lcd_timing.sync_duration_num; |
| sync_duration = (sync_duration * 10 / pconf->lcd_timing.sync_duration_den); |
| LCDPR("%s, %s %ubit, %ux%u@%u.%uHz\n" |
| "fr_adj_type %d\n" |
| "lcd_clk %u.%03uMHz\n" |
| "ss_level %u\n\n", |
| pconf->lcd_basic.model_name, |
| lcd_type_type_to_str(pconf->lcd_basic.lcd_type), |
| pconf->lcd_basic.lcd_bits, |
| pconf->lcd_basic.h_active, pconf->lcd_basic.v_active, |
| (sync_duration / 10), (sync_duration % 10), |
| pconf->lcd_timing.fr_adjust_type, |
| (lcd_clk / 1000), (lcd_clk % 1000), |
| pconf->lcd_timing.ss_level); |
| |
| lcd_timing_info_print(pconf); |
| |
| switch (pconf->lcd_basic.lcd_type) { |
| case LCD_LVDS: |
| printf("lvds_repack %u\n" |
| "dual_port %u\n" |
| "pn_swap %u\n" |
| "port_swap %u\n" |
| "lane_reverse %u\n" |
| "phy_vswing 0x%x\n" |
| "phy_preem 0x%x\n" |
| "phy_clk_vswing 0x%x\n" |
| "phy_clk_preem 0x%x\n\n", |
| pconf->lcd_control.lvds_config->lvds_repack, |
| pconf->lcd_control.lvds_config->dual_port, |
| pconf->lcd_control.lvds_config->pn_swap, |
| pconf->lcd_control.lvds_config->port_swap, |
| pconf->lcd_control.lvds_config->lane_reverse, |
| pconf->lcd_control.lvds_config->phy_vswing, |
| pconf->lcd_control.lvds_config->phy_preem, |
| pconf->lcd_control.lvds_config->phy_clk_vswing, |
| pconf->lcd_control.lvds_config->phy_clk_preem); |
| break; |
| case LCD_MLVDS: |
| printf("channel_num %d\n" |
| "channel_sel1 0x%08x\n" |
| "channel_sel1 0x%08x\n" |
| "clk_phase 0x%04x\n" |
| "pn_swap %u\n" |
| "bit_swap %u\n" |
| "phy_vswing 0x%x\n" |
| "phy_preem 0x%x\n" |
| "bit_rate %dHz\n" |
| "pi_clk_sel 0x%03x\n" |
| "tcon_fb_addr 0x%08x\n\n", |
| pconf->lcd_control.mlvds_config->channel_num, |
| pconf->lcd_control.mlvds_config->channel_sel0, |
| pconf->lcd_control.mlvds_config->channel_sel1, |
| pconf->lcd_control.mlvds_config->clk_phase, |
| pconf->lcd_control.mlvds_config->pn_swap, |
| pconf->lcd_control.mlvds_config->bit_swap, |
| pconf->lcd_control.mlvds_config->phy_vswing, |
| pconf->lcd_control.mlvds_config->phy_preem, |
| pconf->lcd_control.mlvds_config->bit_rate, |
| pconf->lcd_control.mlvds_config->pi_clk_sel, |
| pconf->lcd_control.mlvds_config->fb_addr); |
| lcd_pinmux_info_print(pconf); |
| break; |
| case LCD_VBYONE: |
| printf("lane_count %u\n" |
| "region_num %u\n" |
| "byte_mode %u\n" |
| "phy_vswing 0x%x\n" |
| "phy_preemphasis 0x%x\n" |
| "ctrl_flag 0x%x\n\n", |
| pconf->lcd_control.vbyone_config->lane_count, |
| pconf->lcd_control.vbyone_config->region_num, |
| pconf->lcd_control.vbyone_config->byte_mode, |
| pconf->lcd_control.vbyone_config->phy_vswing, |
| pconf->lcd_control.vbyone_config->phy_preem, |
| pconf->lcd_control.vbyone_config->ctrl_flag); |
| if (pconf->lcd_control.vbyone_config->ctrl_flag & 0x1) { |
| printf("power_on_reset_en %u\n" |
| "power_on_reset_delay %ums\n\n", |
| (pconf->lcd_control.vbyone_config->ctrl_flag & 0x1), |
| pconf->lcd_control.vbyone_config->power_on_reset_delay); |
| } |
| if (pconf->lcd_control.vbyone_config->ctrl_flag & 0x2) { |
| printf("hpd_data_delay_en %u\n" |
| "hpd_data_delay %ums\n\n", |
| ((pconf->lcd_control.vbyone_config->ctrl_flag >> 1) & 0x1), |
| pconf->lcd_control.vbyone_config->hpd_data_delay); |
| } |
| if (pconf->lcd_control.vbyone_config->ctrl_flag & 0x4) { |
| printf("cdr_training_hold_en %u\n" |
| "cdr_training_hold %ums\n\n", |
| ((pconf->lcd_control.vbyone_config->ctrl_flag >> 2) & 0x1), |
| pconf->lcd_control.vbyone_config->cdr_training_hold); |
| } |
| if (pconf->lcd_control.vbyone_config->vx1_sw_filter_en) { |
| printf("vx1_sw_filter_en %u\n" |
| "vx1_sw_filter_time %u\n" |
| "vx1_sw_filter_cnt %u\n" |
| "vx1_sw_filter_retry_cnt %u\n" |
| "vx1_sw_filter_retry_delay %u\n" |
| "vx1_sw_cdr_detect_time %u\n" |
| "vx1_sw_cdr_detect_cnt %u\n" |
| "vx1_sw_cdr_timeout_cnt %u\n\n", |
| pconf->lcd_control.vbyone_config->vx1_sw_filter_en, |
| pconf->lcd_control.vbyone_config->vx1_sw_filter_time, |
| pconf->lcd_control.vbyone_config->vx1_sw_filter_cnt, |
| pconf->lcd_control.vbyone_config->vx1_sw_filter_retry_cnt, |
| pconf->lcd_control.vbyone_config->vx1_sw_filter_retry_delay, |
| pconf->lcd_control.vbyone_config->vx1_sw_cdr_detect_time, |
| pconf->lcd_control.vbyone_config->vx1_sw_cdr_detect_cnt, |
| pconf->lcd_control.vbyone_config->vx1_sw_cdr_timeout_cnt); |
| } |
| lcd_pinmux_info_print(pconf); |
| break; |
| case LCD_TTL: |
| printf("clk_pol %u\n" |
| "hvsync_valid %u\n" |
| "DE_valid %u\n" |
| "bit_swap %u\n" |
| "rb_swap %u\n\n", |
| pconf->lcd_control.ttl_config->clk_pol, |
| (pconf->lcd_control.ttl_config->sync_valid >> 0) & 1, |
| (pconf->lcd_control.ttl_config->sync_valid >> 1) & 1, |
| (pconf->lcd_control.ttl_config->swap_ctrl >> 0) & 1, |
| (pconf->lcd_control.ttl_config->swap_ctrl >> 1) & 1); |
| lcd_pinmux_info_print(pconf); |
| break; |
| case LCD_MIPI: |
| #ifdef CONFIG_AML_LCD_TABLET |
| mipi_dsi_print_info(pconf); |
| #endif |
| break; |
| default: |
| break; |
| } |
| |
| lcd_power_info_print(pconf, 1); |
| lcd_power_info_print(pconf, 0); |
| } |
| |
| static unsigned int lcd_reg_dump_clk[] = { |
| HHI_HPLL_CNTL, |
| HHI_HPLL_CNTL2, |
| HHI_HPLL_CNTL3, |
| HHI_HPLL_CNTL4, |
| HHI_HPLL_CNTL5, |
| HHI_HPLL_CNTL6, |
| HHI_VID_PLL_CLK_DIV, |
| HHI_VIID_CLK_DIV, |
| HHI_VIID_CLK_CNTL, |
| HHI_VID_CLK_CNTL2, |
| }; |
| |
| static unsigned int lcd_reg_dump_clk_axg[] = { |
| HHI_GP0_PLL_CNTL, |
| HHI_GP0_PLL_CNTL1, |
| HHI_GP0_PLL_CNTL2, |
| HHI_GP0_PLL_CNTL3, |
| HHI_GP0_PLL_CNTL4, |
| HHI_GP0_PLL_CNTL5, |
| HHI_VIID_CLK_DIV, |
| HHI_VIID_CLK_CNTL, |
| HHI_VID_CLK_CNTL2, |
| }; |
| |
| static unsigned int lcd_reg_dump_clk_gp0_g12a[] = { |
| HHI_GP0_PLL_CNTL0, |
| HHI_GP0_PLL_CNTL1, |
| HHI_GP0_PLL_CNTL2, |
| HHI_GP0_PLL_CNTL3, |
| HHI_GP0_PLL_CNTL4, |
| HHI_GP0_PLL_CNTL5, |
| HHI_GP0_PLL_CNTL6, |
| HHI_VIID_CLK_DIV, |
| HHI_VIID_CLK_CNTL, |
| HHI_VID_CLK_CNTL2, |
| HHI_MIPIDSI_PHY_CLK_CNTL, |
| }; |
| |
| static unsigned int lcd_reg_dump_clk_hpll_g12a[] = { |
| HHI_HDMI_PLL_CNTL0, |
| HHI_HDMI_PLL_CNTL1, |
| HHI_HDMI_PLL_CNTL2, |
| HHI_HDMI_PLL_CNTL3, |
| HHI_HDMI_PLL_CNTL4, |
| HHI_HDMI_PLL_CNTL5, |
| HHI_HDMI_PLL_CNTL6, |
| HHI_VID_PLL_CLK_DIV, |
| HHI_VIID_CLK_DIV, |
| HHI_VIID_CLK_CNTL, |
| HHI_VID_CLK_CNTL2, |
| HHI_MIPIDSI_PHY_CLK_CNTL, |
| }; |
| |
| static unsigned int lcd_reg_dump_encl[] = { |
| VPU_VIU_VENC_MUX_CTRL, |
| ENCL_VIDEO_EN, |
| ENCL_VIDEO_MODE, |
| ENCL_VIDEO_MODE_ADV, |
| ENCL_VIDEO_MAX_PXCNT, |
| ENCL_VIDEO_MAX_LNCNT, |
| ENCL_VIDEO_HAVON_BEGIN, |
| ENCL_VIDEO_HAVON_END, |
| ENCL_VIDEO_VAVON_BLINE, |
| ENCL_VIDEO_VAVON_ELINE, |
| ENCL_VIDEO_HSO_BEGIN, |
| ENCL_VIDEO_HSO_END, |
| ENCL_VIDEO_VSO_BEGIN, |
| ENCL_VIDEO_VSO_END, |
| ENCL_VIDEO_VSO_BLINE, |
| ENCL_VIDEO_VSO_ELINE, |
| ENCL_VIDEO_RGBIN_CTRL, |
| L_GAMMA_CNTL_PORT, |
| L_RGB_BASE_ADDR, |
| L_RGB_COEFF_ADDR, |
| L_POL_CNTL_ADDR, |
| L_DITH_CNTL_ADDR, |
| }; |
| |
| static void lcd_ttl_reg_print(void) |
| { |
| unsigned int reg; |
| |
| printf("\nttl registers:\n"); |
| reg = L_DUAL_PORT_CNTL_ADDR; |
| printf("PORT_CNTL [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_STH1_HS_ADDR; |
| printf("STH1_HS_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_STH1_HE_ADDR; |
| printf("STH1_HE_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_STH1_VS_ADDR; |
| printf("STH1_VS_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_STH1_VE_ADDR; |
| printf("STH1_VE_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_STV1_HS_ADDR; |
| printf("STV1_HS_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_STV1_HE_ADDR; |
| printf("STV1_HE_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_STV1_VS_ADDR; |
| printf("STV1_VS_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_STV1_VE_ADDR; |
| printf("STV1_VE_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_OEH_HS_ADDR; |
| printf("OEH_HS_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_OEH_HE_ADDR; |
| printf("OEH_HE_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_OEH_VS_ADDR; |
| printf("OEH_VS_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = L_OEH_VE_ADDR; |
| printf("OEH_VE_ADDR [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| } |
| |
| static void lcd_lvds_reg_print(void) |
| { |
| unsigned int reg; |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| |
| printf("\nlvds registers:\n"); |
| reg = LVDS_PACK_CNTL_ADDR; |
| printf("LVDS_PACK_CNTL [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = LVDS_GEN_CNTL; |
| printf("LVDS_GEN_CNTL [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = LCD_PORT_SWAP; |
| printf("LCD_PORT_SWAP [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = HHI_LVDS_TX_PHY_CNTL0; |
| printf("LVDS_PHY_CNTL0 [0x%04x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_LVDS_TX_PHY_CNTL1; |
| printf("LVDS_PHY_CNTL1 [0x%04x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| |
| switch (lcd_drv->chip_type) { |
| case LCD_CHIP_TXHD: |
| reg = LVDS_CH_SWAP0; |
| printf("LVDS_CH_SWAP0 [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = LVDS_CH_SWAP1; |
| printf("LVDS_CH_SWAP1 [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = LVDS_CH_SWAP2; |
| printf("LVDS_CH_SWAP2 [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void lcd_mlvds_reg_print(void) |
| { |
| unsigned int reg; |
| |
| reg = PERIPHS_PIN_MUX_4; |
| printf("\nPERIPHS_PIN_MUX_4 [0x%08x] = 0x%08x\n", |
| reg, lcd_periphs_read(reg)); |
| reg = PERIPHS_PIN_MUX_5; |
| printf("PERIPHS_PIN_MUX_5 [0x%08x] = 0x%08x\n", |
| reg, lcd_periphs_read(reg)); |
| |
| lcd_lvds_reg_print(); |
| |
| printf("\ntcon clk registers:\n"); |
| reg = HHI_TCON_CLK_CNTL; |
| printf("HHI_TCON_CLK_CNTL [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_HPLL_CNTL6; |
| printf("HHI_HPLL_CNTL6 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_DIF_TCON_CNTL0; |
| printf("HHI_DIF_TCON_CNTL0 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_DIF_TCON_CNTL1; |
| printf("HHI_DIF_TCON_CNTL1 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_DIF_TCON_CNTL2; |
| printf("HHI_DIF_TCON_CNTL2 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| |
| printf("\ntcon top registers:\n"); |
| reg = TCON_TOP_CTRL; |
| printf("TCON_TOP_CTRL [0x%04x] = 0x%08x\n", |
| reg, lcd_tcon_read(reg)); |
| reg = TCON_OUT_CH_SEL0; |
| printf("TCON_OUT_CH_SEL0 [0x%04x] = 0x%08x\n", |
| reg, lcd_tcon_read(reg)); |
| reg = TCON_OUT_CH_SEL1; |
| printf("TCON_OUT_CH_SEL1 [0x%04x] = 0x%08x\n", |
| reg, lcd_tcon_read(reg)); |
| reg = TCON_STATUS0; |
| printf("TCON_STATUS0 [0x%04x] = 0x%08x\n", |
| reg, lcd_tcon_read(reg)); |
| reg = TCON_PLLLOCK_CNTL; |
| printf("TCON_PLLLOCK_CNTL [0x%04x] = 0x%08x\n", |
| reg, lcd_tcon_read(reg)); |
| reg = TCON_RST_CTRL; |
| printf("TCON_RST_CTRL [0x%04x] = 0x%08x\n", |
| reg, lcd_tcon_read(reg)); |
| reg = TCON_CLK_CTRL; |
| printf("TCON_CLK_CTRL [0x%04x] = 0x%08x\n", |
| reg, lcd_tcon_read(reg)); |
| reg = TCON_STATUS1; |
| printf("TCON_STATUS1 [0x%04x] = 0x%08x\n", |
| reg, lcd_tcon_read(reg)); |
| } |
| |
| static void lcd_vbyone_reg_print(void) |
| { |
| unsigned int reg; |
| |
| printf("\nvbyone registers:\n"); |
| switch (aml_lcd_driver.chip_type) { |
| case LCD_CHIP_GXTVBB: |
| reg = PERIPHS_PIN_MUX_7; |
| break; |
| case LCD_CHIP_TXL: |
| case LCD_CHIP_TXLX: |
| reg = PERIPHS_PIN_MUX_0; |
| break; |
| default: |
| reg = PERIPHS_PIN_MUX_0; |
| break; |
| } |
| printf("VX1_PINMUX [0x%08x] = 0x%08x\n", |
| reg, lcd_periphs_read(reg)); |
| reg = VBO_STATUS_L; |
| printf("VX1_STATUS [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = VBO_FSM_HOLDER_L; |
| printf("VX1_FSM_HOLDER_L [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = VBO_FSM_HOLDER_H; |
| printf("VX1_FSM_HOLDER_H [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = VBO_INTR_STATE_CTRL; |
| printf("VX1_INTR_STATE_CTRL [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = VBO_INTR_UNMASK; |
| printf("VX1_INTR_UNMASK [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| reg = VBO_INTR_STATE; |
| printf("VX1_INTR_STATE [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| switch (aml_lcd_driver.chip_type) { |
| case LCD_CHIP_TXL: |
| case LCD_CHIP_TXLX: |
| reg = VBO_INSGN_CTRL; |
| printf("VBO_INSGN_CTRL [0x%04x] = 0x%08x\n", |
| reg, lcd_vcbus_read(reg)); |
| break; |
| default: |
| break; |
| } |
| reg = HHI_LVDS_TX_PHY_CNTL0; |
| printf("VX1_PHY_CNTL0 [0x%04x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| } |
| |
| static void lcd_mipi_reg_print(void) |
| { |
| unsigned int reg; |
| |
| printf("\nmipi_dsi registers:\n"); |
| reg = MIPI_DSI_TOP_CNTL; |
| printf("MIPI_DSI_TOP_CNTL [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_TOP_CLK_CNTL; |
| printf("MIPI_DSI_TOP_CLK_CNTL [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_PWR_UP_OS; |
| printf("MIPI_DSI_DWC_PWR_UP_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_PCKHDL_CFG_OS; |
| printf("MIPI_DSI_DWC_PCKHDL_CFG_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_LPCLK_CTRL_OS; |
| printf("MIPI_DSI_DWC_LPCLK_CTRL_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_CMD_MODE_CFG_OS; |
| printf("MIPI_DSI_DWC_CMD_MODE_CFG_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_VID_MODE_CFG_OS; |
| printf("MIPI_DSI_DWC_VID_MODE_CFG_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_MODE_CFG_OS; |
| printf("MIPI_DSI_DWC_MODE_CFG_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_PHY_STATUS_OS; |
| printf("MIPI_DSI_DWC_PHY_STATUS_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_INT_ST0_OS; |
| printf("MIPI_DSI_DWC_INT_ST0_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_DWC_INT_ST1_OS; |
| printf("MIPI_DSI_DWC_INT_ST1_OS [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_TOP_STAT; |
| printf("MIPI_DSI_TOP_STAT [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_TOP_INTR_CNTL_STAT; |
| printf("MIPI_DSI_TOP_INTR_CNTL_STAT [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| reg = MIPI_DSI_TOP_MEM_PD; |
| printf("MIPI_DSI_TOP_MEM_PD [0x%04x] = 0x%08x\n", |
| reg, dsi_host_read(reg)); |
| } |
| |
| static void lcd_phy_analog_reg_print(void) |
| { |
| unsigned int reg; |
| |
| printf("\nphy analog registers:\n"); |
| reg = HHI_DIF_CSI_PHY_CNTL1; |
| printf("PHY_CNTL1 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_DIF_CSI_PHY_CNTL2; |
| printf("PHY_CNTL2 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_DIF_CSI_PHY_CNTL3; |
| printf("PHY_CNTL3 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| } |
| |
| static void lcd_mipi_phy_analog_reg_print(void) |
| { |
| unsigned int reg; |
| |
| printf("\nphy analog registers:\n"); |
| reg = HHI_MIPI_CNTL0; |
| printf("PHY_CNTL1 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_MIPI_CNTL1; |
| printf("PHY_CNTL2 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| reg = HHI_MIPI_CNTL2; |
| printf("PHY_CNTL3 [0x%08x] = 0x%08x\n", |
| reg, lcd_hiu_read(reg)); |
| } |
| |
| static void lcd_reg_print(void) |
| { |
| int i; |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| struct lcd_config_s *pconf; |
| |
| pconf = lcd_drv->lcd_config; |
| printf("clk registers:\n"); |
| switch (aml_lcd_driver.chip_type) { |
| case LCD_CHIP_G12A: |
| if (lcd_drv->lcd_config->lcd_clk_path) { |
| for (i = 0; i < ARRAY_SIZE(lcd_reg_dump_clk_gp0_g12a); i++) { |
| printf("hiu [0x%08x] = 0x%08x\n", |
| lcd_reg_dump_clk_gp0_g12a[i], |
| lcd_hiu_read(lcd_reg_dump_clk_gp0_g12a[i])); |
| } |
| } else { |
| for (i = 0; i < ARRAY_SIZE(lcd_reg_dump_clk_hpll_g12a); i++) { |
| printf("hiu [0x%08x] = 0x%08x\n", |
| lcd_reg_dump_clk_hpll_g12a[i], |
| lcd_hiu_read(lcd_reg_dump_clk_hpll_g12a[i])); |
| } |
| } |
| break; |
| case LCD_CHIP_AXG: |
| for (i = 0; i < ARRAY_SIZE(lcd_reg_dump_clk_axg); i++) { |
| printf("hiu [0x%08x] = 0x%08x\n", |
| lcd_reg_dump_clk_axg[i], |
| lcd_hiu_read(lcd_reg_dump_clk_axg[i])); |
| } |
| break; |
| default: |
| for (i = 0; i < ARRAY_SIZE(lcd_reg_dump_clk); i++) { |
| printf("hiu [0x%08x] = 0x%08x\n", |
| lcd_reg_dump_clk[i], |
| lcd_hiu_read(lcd_reg_dump_clk[i])); |
| } |
| break; |
| } |
| |
| printf("\nencl registers:\n"); |
| for (i = 0; i < ARRAY_SIZE(lcd_reg_dump_encl); i++) { |
| printf("vcbus [0x%04x] = 0x%08x\n", |
| lcd_reg_dump_encl[i], |
| lcd_vcbus_read(lcd_reg_dump_encl[i])); |
| } |
| |
| switch (pconf->lcd_basic.lcd_type) { |
| case LCD_TTL: |
| lcd_ttl_reg_print(); |
| break; |
| case LCD_LVDS: |
| lcd_lvds_reg_print(); |
| lcd_phy_analog_reg_print(); |
| break; |
| case LCD_VBYONE: |
| lcd_vbyone_reg_print(); |
| lcd_phy_analog_reg_print(); |
| break; |
| case LCD_MLVDS: |
| lcd_mlvds_reg_print(); |
| lcd_phy_analog_reg_print(); |
| break; |
| case LCD_MIPI: |
| lcd_mipi_reg_print(); |
| lcd_mipi_phy_analog_reg_print(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void lcd_vbyone_filter_flag_print(struct lcd_config_s *pconf) |
| { |
| struct vbyone_config_s *vx1_conf = pconf->lcd_control.vbyone_config; |
| |
| switch (aml_lcd_driver.chip_type) { |
| case LCD_CHIP_TXL: |
| case LCD_CHIP_TXLX: |
| LCDPR("vx1_sw_filter_en: %d\n", vx1_conf->vx1_sw_filter_en); |
| LCDPR("vx1_sw_filter_time: %d\n", vx1_conf->vx1_sw_filter_time); |
| LCDPR("vx1_sw_filter_cnt: %d\n", vx1_conf->vx1_sw_filter_cnt); |
| LCDPR("vx1_sw_filter_retry_cnt: %d\n", vx1_conf->vx1_sw_filter_retry_cnt); |
| LCDPR("vx1_sw_filter_retry_delay: %d\n", vx1_conf->vx1_sw_filter_retry_delay); |
| LCDPR("vx1_sw_cdr_detect_time: %d\n", vx1_conf->vx1_sw_cdr_detect_time); |
| LCDPR("vx1_sw_cdr_detect_cnt: %d\n", vx1_conf->vx1_sw_cdr_detect_cnt); |
| LCDPR("vx1_sw_cdr_timeout_cnt: %d\n", vx1_conf->vx1_sw_cdr_timeout_cnt); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void lcd_vbyone_filter_env_init(struct lcd_config_s *pconf) |
| { |
| struct vbyone_config_s *vx1_conf = pconf->lcd_control.vbyone_config; |
| char *str; |
| unsigned int temp = 0; |
| |
| str = getenv("lcd_debug_vx1_sw_filter"); |
| if (str) |
| temp = simple_strtoul(str, NULL, 10); |
| if (temp == 0) |
| return; |
| |
| LCDPR("%s\n", __func__); |
| str = getenv("vx1_sw_filter_en"); |
| if (str) { |
| vx1_conf->vx1_sw_filter_en = simple_strtoul(str, NULL, 10); |
| LCDPR("vx1_sw_filter_en: %d\n", vx1_conf->vx1_sw_filter_en); |
| } |
| |
| str = getenv("vx1_sw_filter_time"); /* 100us */ |
| if (str) { |
| vx1_conf->vx1_sw_filter_time = simple_strtoul(str, NULL, 10); |
| LCDPR("vx1_sw_filter_time: %d\n", vx1_conf->vx1_sw_filter_time); |
| } |
| |
| str = getenv("vx1_sw_filter_cnt"); |
| if (str) { |
| vx1_conf->vx1_sw_filter_cnt = simple_strtoul(str, NULL, 10); |
| LCDPR("vx1_sw_filter_cnt: %d\n", vx1_conf->vx1_sw_filter_cnt); |
| } |
| |
| str = getenv("vx1_sw_filter_retry_cnt"); |
| if (str) { |
| vx1_conf->vx1_sw_filter_retry_cnt = simple_strtoul(str, NULL, 10); |
| LCDPR("vx1_sw_filter_retry_cnt: %d\n", vx1_conf->vx1_sw_filter_retry_cnt); |
| } |
| |
| str = getenv("vx1_sw_filter_retry_delay"); /* ms */ |
| if (str) { |
| vx1_conf->vx1_sw_filter_retry_delay = simple_strtoul(str, NULL, 10); |
| LCDPR("vx1_sw_filter_retry_delay: %d\n", vx1_conf->vx1_sw_filter_retry_delay); |
| } |
| |
| str = getenv("vx1_sw_cdr_detect_time"); /* us * 100 */ |
| if (str) { |
| vx1_conf->vx1_sw_cdr_detect_time = simple_strtoul(str, NULL, 10); |
| LCDPR("vx1_sw_cdr_detect_time: %d\n", vx1_conf->vx1_sw_cdr_detect_time); |
| } |
| |
| str = getenv("vx1_sw_cdr_detect_cnt"); |
| if (str) { |
| vx1_conf->vx1_sw_cdr_detect_cnt = simple_strtoul(str, NULL, 10); |
| LCDPR("vx1_sw_cdr_detect_cnt: %d\n", vx1_conf->vx1_sw_cdr_detect_cnt); |
| } |
| |
| str = getenv("vx1_sw_cdr_timeout_cnt"); |
| if (str) { |
| vx1_conf->vx1_sw_cdr_timeout_cnt = simple_strtoul(str, NULL, 10); |
| LCDPR("vx1_sw_cdr_timeout_cnt: %d\n", vx1_conf->vx1_sw_cdr_timeout_cnt); |
| } |
| } |
| |
| #ifdef CONFIG_AML_LCD_EXTERN |
| static int lcd_extern_load_config(char *dt_addr, struct lcd_config_s *pconf) |
| { |
| struct lcd_power_step_s *power_step; |
| int index, i; |
| |
| /* mipi extern_init is special */ |
| if (pconf->lcd_basic.lcd_type == LCD_MIPI) { |
| index = pconf->lcd_control.mipi_config->extern_init; |
| if (index < LCD_EXTERN_INDEX_INVALID) |
| aml_lcd_extern_probe(dt_addr, index); |
| } |
| |
| i = 0; |
| while (i < LCD_PWR_STEP_MAX) { |
| power_step = &pconf->lcd_power->power_on_step[i]; |
| if (power_step->type >= LCD_POWER_TYPE_MAX) |
| break; |
| if (power_step->type == LCD_POWER_TYPE_EXTERN) { |
| if (lcd_debug_print_flag) { |
| LCDPR("power_on: step %d: type=%d, index=%d\n", |
| i, power_step->type, power_step->index); |
| } |
| index = power_step->index; |
| if (index < LCD_EXTERN_INDEX_INVALID) |
| aml_lcd_extern_probe(dt_addr, index); |
| } |
| i++; |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| #ifdef CONFIG_OF_LIBFDT |
| static int lcd_init_load_from_dts(char *dt_addr) |
| { |
| struct lcd_config_s *pconf = aml_lcd_driver.lcd_config; |
| int parent_offset; |
| char *propdata, *p; |
| const char *str; |
| int i, j, temp; |
| |
| /* check bl_key_valid */ |
| parent_offset = fdt_path_offset(dt_addr, "/backlight"); |
| if (parent_offset < 0) { |
| LCDERR("not find /backlight node: %s\n", fdt_strerror(parent_offset)); |
| aml_lcd_driver.bl_config->bl_key_valid = 0; |
| } |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "key_valid", NULL); |
| if (propdata == NULL) { |
| LCDERR("failed to get key_valid\n"); |
| aml_lcd_driver.bl_config->bl_key_valid = 0; |
| } else { |
| aml_lcd_driver.bl_config->bl_key_valid = (unsigned char)(be32_to_cpup((u32*)propdata)); |
| } |
| |
| parent_offset = fdt_path_offset(dt_addr, "/lcd"); |
| if (parent_offset < 0) { |
| LCDERR("not find /lcd node: %s\n", fdt_strerror(parent_offset)); |
| return -1; |
| } |
| |
| /* check lcd_mode & lcd_key_valid */ |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "mode", NULL); |
| if (propdata == NULL) { |
| LCDERR("failed to get mode\n"); |
| return -1; |
| } else { |
| pconf->lcd_mode = lcd_mode_str_to_mode(propdata); |
| } |
| str = propdata; |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "key_valid", NULL); |
| if (propdata == NULL) { |
| LCDERR("failed to get key_valid\n"); |
| pconf->lcd_key_valid = 0; |
| } else { |
| pconf->lcd_key_valid = (unsigned char)(be32_to_cpup((u32*)propdata)); |
| } |
| LCDPR("detect mode: %s, key_valid: %d\n", str, pconf->lcd_key_valid); |
| |
| /* check lcd_clk_path */ |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "clk_path", NULL); |
| if (propdata == NULL) { |
| if (lcd_debug_print_flag) |
| LCDPR("failed to get clk_path\n"); |
| pconf->lcd_clk_path = 0; |
| } else { |
| pconf->lcd_clk_path = (unsigned char)(be32_to_cpup((u32*)propdata)); |
| LCDPR("detect lcd_clk_path: %d\n", pconf->lcd_clk_path); |
| } |
| str = getenv("lcd_clk_path"); |
| if (str) { |
| temp = simple_strtoul(str, NULL, 10); |
| if (temp) |
| pconf->lcd_clk_path = 1; |
| else |
| pconf->lcd_clk_path = 0; |
| LCDPR("lcd_clk_path flag set clk_path: %d\n", pconf->lcd_clk_path); |
| } |
| |
| i = 0; |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "lcd_cpu_gpio_names", NULL); |
| if (propdata == NULL) { |
| LCDPR("failed to get lcd_cpu_gpio_names\n"); |
| } else { |
| p = propdata; |
| while (i < LCD_CPU_GPIO_NUM_MAX) { |
| str = p; |
| if (strlen(str) == 0) |
| break; |
| strcpy(pconf->lcd_power->cpu_gpio[i], str); |
| if (lcd_debug_print_flag) { |
| LCDPR("i=%d, gpio=%s\n", |
| i, pconf->lcd_power->cpu_gpio[i]); |
| } |
| p += strlen(p) + 1; |
| i++; |
| } |
| } |
| for (j = i; j < LCD_CPU_GPIO_NUM_MAX; j++) |
| strcpy(pconf->lcd_power->cpu_gpio[j], "invalid"); |
| |
| return 0; |
| } |
| #endif |
| |
| static int lcd_init_load_from_bsp(void) |
| { |
| struct lcd_config_s *pconf = aml_lcd_driver.lcd_config; |
| int i, j, temp; |
| char *str; |
| |
| /*pconf->lcd_key_valid = 0; |
| aml_lcd_driver.bl_config->bl_key_valid = 0;*/ |
| LCDPR("detect mode: %s, key_valid: %d\n", |
| lcd_mode_mode_to_str(pconf->lcd_mode), pconf->lcd_key_valid); |
| |
| i = 0; |
| while (i < LCD_CPU_GPIO_NUM_MAX) { |
| if (strcmp(pconf->lcd_power->cpu_gpio[i], "invalid") == 0) |
| break; |
| i++; |
| } |
| for (j = i; j < LCD_CPU_GPIO_NUM_MAX; j++) { |
| strcpy(pconf->lcd_power->cpu_gpio[j], "invalid"); |
| } |
| |
| str = getenv("lcd_clk_path"); |
| if (str) { |
| temp = simple_strtoul(str, NULL, 10); |
| if (temp) |
| pconf->lcd_clk_path = 1; |
| else |
| pconf->lcd_clk_path = 0; |
| LCDPR("lcd_clk_path flag set clk_path: %d\n", pconf->lcd_clk_path); |
| } |
| |
| return 0; |
| } |
| |
| static int lcd_config_probe(void) |
| { |
| int load_id = 0; |
| char *dt_addr, *str; |
| #ifdef CONFIG_OF_LIBFDT |
| int parent_offset; |
| #endif |
| int ret; |
| |
| dt_addr = NULL; |
| #ifdef CONFIG_OF_LIBFDT |
| #ifdef CONFIG_DTB_MEM_ADDR |
| dt_addr = (char *)CONFIG_DTB_MEM_ADDR; |
| #else |
| dt_addr = (char *)0x01000000; |
| #endif |
| if (fdt_check_header(dt_addr) < 0) { |
| LCDERR("check dts: %s, load default lcd parameters\n", |
| fdt_strerror(fdt_check_header(dt_addr))); |
| } else { |
| parent_offset = fdt_path_offset(dt_addr, "/lcd"); |
| if (parent_offset < 0) { |
| LCDERR("not find /lcd node: %s\n", fdt_strerror(parent_offset)); |
| load_id = 0x0; |
| } else { |
| load_id = 0x1; |
| } |
| } |
| #endif |
| |
| lcd_debug_test = 0; |
| str = getenv("lcd_debug_test"); |
| if (str == NULL) |
| lcd_debug_test = 0; |
| else |
| lcd_debug_test = simple_strtoul(str, NULL, 10); |
| if (lcd_debug_test) { |
| load_id = 0x0; |
| LCDPR("lcd_debug_test flag: %d\n", lcd_debug_test); |
| } |
| |
| if (load_id & 0x1 ) { |
| #ifdef CONFIG_OF_LIBFDT |
| ret = lcd_init_load_from_dts(dt_addr); |
| if (ret) |
| return -1; |
| if (aml_lcd_driver.unifykey_test_flag) { |
| aml_lcd_driver.bl_config->bl_key_valid = 1; |
| aml_lcd_driver.lcd_config->lcd_key_valid = 1; |
| LCDPR("force bl_key_valid & lcd_key_valid to 1\n"); |
| } |
| if (aml_lcd_driver.lcd_config->lcd_key_valid) { |
| ret = aml_lcd_unifykey_check("lcd"); |
| if (ret == 0) { |
| LCDPR("load config from unifykey\n"); |
| load_id |= 0x10; |
| } else { |
| LCDPR("load config from dts\n"); |
| } |
| } else { |
| LCDPR("load config from dts\n"); |
| } |
| #endif |
| } else { |
| ret = lcd_init_load_from_bsp(); |
| if (ret) |
| return -1; |
| if (aml_lcd_driver.unifykey_test_flag) { |
| aml_lcd_driver.bl_config->bl_key_valid = 1; |
| aml_lcd_driver.lcd_config->lcd_key_valid = 1; |
| LCDPR("force bl_key_valid & lcd_key_valid to 1\n"); |
| } |
| if (aml_lcd_driver.lcd_config->lcd_key_valid) { |
| ret = aml_lcd_unifykey_check("lcd"); |
| if (ret == 0) { |
| LCDPR("load lcd_config from unifykey\n"); |
| load_id |= 0x10; |
| } else { |
| LCDPR("load lcd_config from bsp\n"); |
| } |
| } else { |
| LCDPR("load config from bsp\n"); |
| } |
| } |
| |
| lcd_clk_config_probe(); |
| |
| /* load lcd config */ |
| switch (aml_lcd_driver.lcd_config->lcd_mode) { |
| #ifdef CONFIG_AML_LCD_TV |
| case LCD_MODE_TV: |
| ret = get_lcd_tv_config(dt_addr, load_id); |
| break; |
| #endif |
| #ifdef CONFIG_AML_LCD_TABLET |
| case LCD_MODE_TABLET: |
| ret = get_lcd_tablet_config(dt_addr, load_id); |
| break; |
| #endif |
| default: |
| LCDERR("invalid lcd mode: %d\n", aml_lcd_driver.lcd_config->lcd_mode); |
| break; |
| } |
| if (ret) { |
| aml_lcd_driver.config_check = NULL; |
| LCDERR("invalid lcd config\n"); |
| return -1; |
| } |
| if (aml_lcd_driver.lcd_config->lcd_basic.lcd_type == LCD_VBYONE) |
| lcd_vbyone_filter_env_init(aml_lcd_driver.lcd_config); |
| if (aml_lcd_driver.chip_type == LCD_CHIP_TXHD) |
| lcd_tcon_probe(dt_addr, aml_lcd_driver.lcd_config, load_id); |
| |
| #ifdef CONFIG_AML_LCD_EXTERN |
| lcd_extern_load_config(dt_addr, aml_lcd_driver.lcd_config); |
| #endif |
| |
| /* load bl config */ |
| if (aml_lcd_driver.bl_config->bl_key_valid) { |
| ret = aml_lcd_unifykey_check("backlight"); |
| if (ret == 0) { |
| LCDPR("load backlight_config from unifykey\n"); |
| load_id |= 0x10; |
| } else { |
| load_id &= ~(0x10); |
| } |
| } else { |
| load_id &= ~(0x10); |
| } |
| aml_bl_config_load(dt_addr, load_id); |
| |
| if (lcd_debug_print_flag) { |
| if (aml_lcd_driver.lcd_config->lcd_basic.lcd_type == LCD_VBYONE) |
| lcd_vbyone_filter_flag_print(aml_lcd_driver.lcd_config); |
| } |
| |
| return 0; |
| } |
| |
| int lcd_probe(void) |
| { |
| #ifdef LCD_DEBUG_INFO |
| lcd_debug_print_flag = 1; |
| #else |
| char *str; |
| int ret = 0; |
| |
| str = getenv("lcd_debug_print"); |
| if (str == NULL) { |
| lcd_debug_print_flag = 0; |
| } else { |
| lcd_debug_print_flag = simple_strtoul(str, NULL, 10); |
| LCDPR("lcd_debug_print flag: %d\n", lcd_debug_print_flag); |
| } |
| #endif |
| |
| lcd_chip_detect(); |
| lcd_config_bsp_init(); |
| ret = lcd_config_probe(); |
| if (ret) |
| return 0; |
| |
| aml_bl_power_ctrl(0, 0); /* init backlight ctrl port */ |
| mdelay(10); |
| |
| return 0; |
| } |
| |
| int lcd_remove(void) |
| { |
| #ifdef CONFIG_AML_LCD_EXTERN |
| aml_lcd_extern_remove(); |
| #endif |
| |
| return 0; |
| } |
| |
| /* ********************************************** * |
| lcd driver API |
| * ********************************************** */ |
| static void lcd_enable(char *mode) |
| { |
| if (lcd_check_valid()) |
| return; |
| if (aml_lcd_driver.lcd_status) |
| LCDPR("already enabled\n"); |
| else |
| lcd_module_enable(mode); |
| } |
| |
| static void lcd_disable(void) |
| { |
| if (lcd_check_valid()) |
| return; |
| if (aml_lcd_driver.lcd_status) |
| lcd_module_disable(); |
| else |
| LCDPR("already disabled\n"); |
| } |
| |
| static void aml_lcd_set_ss(int level) |
| { |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| |
| if (lcd_check_valid()) |
| return; |
| if (aml_lcd_driver.lcd_status) { |
| lcd_drv->lcd_config->lcd_timing.ss_level = level; |
| lcd_set_spread_spectrum(); |
| } else { |
| LCDPR("already disabled\n"); |
| } |
| } |
| |
| static char *aml_lcd_get_ss(void) |
| { |
| char *str = "invalid"; |
| |
| if (lcd_check_valid()) |
| return str; |
| if (aml_lcd_driver.lcd_status) |
| str = lcd_get_spread_spectrum(); |
| else |
| LCDPR("already disabled\n"); |
| |
| return str; |
| } |
| |
| #define LCD_WAIT_VSYNC_TIMEOUT 50000 |
| void lcd_wait_vsync(void) |
| { |
| int line_cnt, line_cnt_previous; |
| int i = 0; |
| |
| line_cnt = 0x1fff; |
| line_cnt_previous = lcd_vcbus_getb(ENCL_INFO_READ, 16, 13); |
| while (i++ < LCD_WAIT_VSYNC_TIMEOUT) { |
| line_cnt = lcd_vcbus_getb(ENCL_INFO_READ, 16, 13); |
| if (line_cnt < line_cnt_previous) |
| break; |
| line_cnt_previous = line_cnt; |
| udelay(2); |
| } |
| /*LCDPR("line_cnt=%d, line_cnt_previous=%d, i=%d\n", |
| * line_cnt, line_cnt_previous, i); |
| */ |
| } |
| |
| #define TV_LCD_ENC_TST_NUM_MAX 9 |
| static char *lcd_enc_tst_str[] = { |
| "0-None", /* 0 */ |
| "1-Color Bar", /* 1 */ |
| "2-Thin Line", /* 2 */ |
| "3-Dot Grid", /* 3 */ |
| "4-Gray", /* 4 */ |
| "5-Red", /* 5 */ |
| "6-Green", /* 6 */ |
| "7-Blue", /* 7 */ |
| "8-Black", /* 8 */ |
| }; |
| |
| static unsigned int lcd_enc_tst[][7] = { |
| /*tst_mode, Y, Cb, Cr, tst_en, vfifo_en rgbin*/ |
| {0, 0x200, 0x200, 0x200, 0, 1, 3}, /* 0 */ |
| {1, 0x200, 0x200, 0x200, 1, 0, 1}, /* 1 */ |
| {2, 0x200, 0x200, 0x200, 1, 0, 1}, /* 2 */ |
| {3, 0x200, 0x200, 0x200, 1, 0, 1}, /* 3 */ |
| {0, 0x1ff, 0x1ff, 0x1ff, 1, 0, 3}, /* 4 */ |
| {0, 0x3ff, 0x0, 0x0, 1, 0, 3}, /* 5 */ |
| {0, 0x0, 0x3ff, 0x0, 1, 0, 3}, /* 6 */ |
| {0, 0x0, 0x0, 0x3ff, 1, 0, 3}, /* 7 */ |
| {0, 0x0, 0x0, 0x0, 1, 0, 3}, /* 8 */ |
| }; |
| |
| static void lcd_test(unsigned int num) |
| { |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| unsigned int start, width; |
| |
| start = lcd_drv->lcd_config->lcd_timing.video_on_pixel; |
| width = lcd_drv->lcd_config->lcd_basic.h_active / 9; |
| num = (num >= TV_LCD_ENC_TST_NUM_MAX) ? 0 : num; |
| |
| lcd_wait_vsync(); |
| lcd_vcbus_write(ENCL_VIDEO_RGBIN_CTRL, lcd_enc_tst[num][6]); |
| lcd_vcbus_write(ENCL_TST_MDSEL, lcd_enc_tst[num][0]); |
| lcd_vcbus_write(ENCL_TST_Y, lcd_enc_tst[num][1]); |
| lcd_vcbus_write(ENCL_TST_CB, lcd_enc_tst[num][2]); |
| lcd_vcbus_write(ENCL_TST_CR, lcd_enc_tst[num][3]); |
| lcd_vcbus_write(ENCL_TST_CLRBAR_STRT, start); |
| lcd_vcbus_write(ENCL_TST_CLRBAR_WIDTH, width); |
| lcd_vcbus_write(ENCL_TST_EN, lcd_enc_tst[num][4]); |
| lcd_vcbus_setb(ENCL_VIDEO_MODE_ADV, lcd_enc_tst[num][5], 3, 1); |
| if (num > 0) { |
| LCDPR("show test pattern: %s\n", lcd_enc_tst_str[num]); |
| } else { |
| LCDPR("disable test pattern\n"); |
| } |
| } |
| |
| static void lcd_mute_setting(unsigned char flag) |
| { |
| lcd_wait_vsync(); |
| if (flag) { |
| lcd_vcbus_write(ENCL_VIDEO_RGBIN_CTRL, 3); |
| lcd_vcbus_write(ENCL_TST_MDSEL, 0); |
| lcd_vcbus_write(ENCL_TST_Y, 0); |
| lcd_vcbus_write(ENCL_TST_CB, 0); |
| lcd_vcbus_write(ENCL_TST_CR, 0); |
| lcd_vcbus_write(ENCL_TST_EN, 1); |
| lcd_vcbus_setb(ENCL_VIDEO_MODE_ADV, 0, 3, 1); |
| LCDPR("set mute\n"); |
| } else { |
| lcd_vcbus_setb(ENCL_VIDEO_MODE_ADV, 1, 3, 1); |
| lcd_vcbus_write(ENCL_TST_EN, 0); |
| LCDPR("clear mute\n"); |
| } |
| } |
| |
| static void aml_lcd_test(int num) |
| { |
| if (lcd_check_valid()) |
| return; |
| if (aml_lcd_driver.lcd_status) |
| lcd_test(num); |
| else |
| LCDPR("already disabled\n"); |
| } |
| |
| static void aml_lcd_clk(void) |
| { |
| if (lcd_check_valid()) |
| return; |
| lcd_clk_config_print(); |
| } |
| |
| static void aml_lcd_info(void) |
| { |
| if (lcd_check_valid()) |
| return; |
| lcd_info_print(); |
| } |
| |
| static void aml_lcd_reg(void) |
| { |
| if (lcd_check_valid()) |
| return; |
| lcd_reg_print(); |
| } |
| |
| static void aml_lcd_tcon_reg(void) |
| { |
| if (lcd_check_valid()) |
| return; |
| lcd_tcon_regs_readback_print(aml_lcd_driver.lcd_config->lcd_control.mlvds_config); |
| } |
| |
| static void aml_lcd_tcon_table(void) |
| { |
| if (lcd_check_valid()) |
| return; |
| lcd_tcon_regs_table_print(aml_lcd_driver.lcd_config->lcd_control.mlvds_config); |
| } |
| |
| static void aml_set_backlight_level(int level) |
| { |
| aml_bl_set_level(level); |
| } |
| |
| static int aml_get_backlight_level(void) |
| { |
| return aml_bl_get_level(); |
| } |
| |
| static void aml_backlight_power_on(void) |
| { |
| aml_bl_power_ctrl(1, 1); |
| } |
| |
| static void aml_backlight_power_off(void) |
| { |
| aml_bl_power_ctrl(0, 1); |
| } |
| |
| static void aml_lcd_key_test(void) |
| { |
| if (aml_lcd_driver.unifykey_test_flag) { |
| aml_lcd_unifykey_test(); |
| lcd_config_probe(); |
| } else { |
| printf("lcd unifykey test disabled\n"); |
| } |
| } |
| |
| static void aml_lcd_key_tcon_test(void) |
| { |
| if (aml_lcd_driver.unifykey_test_flag) { |
| aml_lcd_unifykey_tcon_test(1080); |
| lcd_config_probe(); |
| } else { |
| printf("lcd unifykey test disabled\n"); |
| } |
| } |
| |
| static void aml_lcd_key_dump(void) |
| { |
| int flag = LCD_UKEY_DEBUG_NORMAL; |
| |
| switch (aml_lcd_driver.chip_type) { |
| case LCD_CHIP_TXHD: |
| flag |= LCD_UKEY_DEBUG_TCON; |
| break; |
| default: |
| break; |
| } |
| aml_lcd_unifykey_dump(flag); |
| } |
| |
| static void aml_lcd_extern_info(void) |
| { |
| #ifdef CONFIG_AML_LCD_EXTERN |
| struct aml_lcd_extern_driver_s *ext_drv; |
| |
| ext_drv = aml_lcd_extern_get_driver(); |
| if (ext_drv) |
| ext_drv->info_print(); |
| #else |
| printf("lcd_extern is not support\n"); |
| #endif |
| } |
| |
| static struct aml_lcd_drv_s aml_lcd_driver = { |
| .lcd_status = 0, |
| .lcd_config = &lcd_config_dft, |
| .bl_config = &bl_config_dft, |
| .config_check = NULL, |
| .lcd_probe = lcd_probe, |
| .lcd_enable = lcd_enable, |
| .lcd_disable = lcd_disable, |
| .lcd_set_ss = aml_lcd_set_ss, |
| .lcd_get_ss = aml_lcd_get_ss, |
| .lcd_test = aml_lcd_test, |
| .lcd_clk = aml_lcd_clk, |
| .lcd_info = aml_lcd_info, |
| .lcd_reg = aml_lcd_reg, |
| .lcd_tcon_reg = aml_lcd_tcon_reg, |
| .lcd_tcon_table = aml_lcd_tcon_table, |
| .bl_on = aml_backlight_power_on, |
| .bl_off = aml_backlight_power_off, |
| .set_bl_level = aml_set_backlight_level, |
| .get_bl_level = aml_get_backlight_level, |
| .bl_config_print = aml_bl_config_print, |
| .unifykey_test_flag = 0, /* default disable unifykey test */ |
| .unifykey_test = aml_lcd_key_test, |
| .unifykey_tcon_test = aml_lcd_key_tcon_test, |
| .unifykey_dump = aml_lcd_key_dump, |
| .lcd_extern_info = aml_lcd_extern_info, |
| }; |
| |
| struct aml_lcd_drv_s *aml_lcd_get_driver(void) |
| { |
| return &aml_lcd_driver; |
| } |