/*++ * linux/drivers/video/wmt/lcd.c * WonderMedia video post processor (VPP) driver * * Copyright c 2013 WonderMedia Technologies, Inc. * * 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 License, or * (at your option) 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * WonderMedia Technologies, Inc. * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C --*/ #define LCD_C #undef DEBUG /* #define DEBUG */ /* #define DEBUG_DETAIL */ /*----------------------- DEPENDENCE -----------------------------------------*/ #include #include "../lcd.h" #include "../vout.h" /*----------------------- PRIVATE MACRO --------------------------------------*/ /* #define LCD_XXXX xxxx *//*Example*/ /*----------------------- PRIVATE CONSTANTS ----------------------------------*/ /* #define LCD_XXXX 1 *//*Example*/ /*----------------------- PRIVATE TYPE --------------------------------------*/ /* typedef xxxx lcd_xxx_t; *//*Example*/ struct lcd_device_t { lcd_parm_t* (*get_parm)(int arg); }; /*----------EXPORTED PRIVATE VARIABLES are defined in lcd.h -------------*/ /*----------------------- INTERNAL PRIVATE VARIABLES - -----------------------*/ /* int lcd_xxx; *//*Example*/ struct lcd_device_t lcd_device_array[LCD_PANEL_MAX]; int lcd_panel_on = 1; int lcd_pwm_enable; lcd_panel_t lcd_panel_id = LCD_PANEL_MAX; int lcd_panel_bpp = 24; vout_dev_t lcd_vout_dev_ops; /*--------------------- INTERNAL PRIVATE FUNCTIONS ---------------------------*/ /* void lcd_xxx(void); *//*Example*/ lcd_panel_t lcd_lvds_id = LCD_PANEL_MAX; int lcd_type; /*----------------------- Function Body --------------------------------------*/ /*----------------------- Backlight --------------------------------------*/ void lcd_set_type(int type) { lcd_type = type; /* 0-LCD, 1-LVDS */ } int lcd_get_type(void) { return lcd_type; } static struct { int gpio; int active; } lcd_power; /*----------------------- Function Body --------------------------------------*/ static int parse_uboot_param(void) { char buf[64]; size_t l = sizeof(buf); int ret; if (wmt_getsyspara("wmt.lcd.power", buf, &l)) { pr_err("please set wmt.lcd.power\n"); return -EINVAL; } ret = sscanf(buf, "%d:%d", &lcd_power.gpio, &lcd_power.active); if (ret < 2) { pr_err("Batt: bat env param: %s\n", buf); return -EINVAL; } printk("lcd power: gpio-%d, active %d\n", lcd_power.gpio, lcd_power.active); ret = gpio_request(lcd_power.gpio, "lcd power"); if (ret) { pr_err("request gpio %d failed\n", lcd_power.gpio); return ret; } return 0; } void lcd_power_on(bool on) { if (lcd_power.gpio < 0) return; gpio_direction_output(lcd_power.gpio, on ? lcd_power.active : !lcd_power.active); } /*----------------------- Backlight --------------------------------------*/ void lcd_set_lvds_id(int id) { lcd_lvds_id = id; } int lcd_get_lvds_id(void) { return lcd_lvds_id; } void lcd_set_parm(int id, int bpp) { lcd_panel_id = id; lcd_panel_bpp = bpp; } lcd_parm_t *lcd_get_parm(lcd_panel_t id, unsigned int arg) { struct lcd_device_t *p; p = &lcd_device_array[id]; if (p && p->get_parm) return p->get_parm(arg); return 0; } vout_dev_t *lcd_get_dev(void) { if (lcd_panel_id >= LCD_PANEL_MAX) return 0; return &lcd_vout_dev_ops; } #ifdef CONFIG_KERNEL static DEFINE_SEMAPHORE(lcd_sem); #endif void lcd_set_mutex(int lock) { #ifdef CONFIG_KERNEL if (lock) down(&lcd_sem); else up(&lcd_sem); #endif } /* #define CONFIG_PANEL_SET_CLOCK */ void lcd_set_enable(int enable) { #ifdef CONFIG_PANEL_SET_CLOCK int hdmi_off; #endif DBG_MSG("%d\n", enable); if (!p_lcd) return; lcd_set_mutex(1); #ifdef CONFIG_PANEL_SET_CLOCK /* enable NA12 in Panel on */ hdmi_off = (govrh_get_MIF_enable(p_govrh)) ? 0 : 1; if (hdmi_off && enable) vpp_set_clock_enable(DEV_NA12, enable, 1); #endif if (enable) { if (p_lcd->initial) p_lcd->initial(); else { lcd_enable_signal(1); /* singal enable */ //REG32_VAL(GPIO_BASE_ADDR + 0x80) |= 0x801; //REG32_VAL(GPIO_BASE_ADDR + 0xC0) |= 0x801; } } else { if (p_lcd->uninitial) p_lcd->uninitial(); else { lcd_enable_signal(0); /* singal disable */ //REG32_VAL(GPIO_BASE_ADDR + 0xC0) &= ~0x801; } } #ifdef CONFIG_PANEL_SET_CLOCK /* disable VPP & NA12 clock in Panel off */ if (hdmi_off) { vpp_set_clock_enable(DEV_VPP, enable, 1); vpp_set_clock_enable(DEV_GOVRHD, enable, 1); vpp_set_clock_enable(DEV_HDMILVDS, enable, 1); if (enable == 0) vpp_set_clock_enable(DEV_NA12, enable, 1); } #endif lcd_set_mutex(0); } void lcd_enable_signal(int enable) { int hdmi_off; DBG_MSG("%d\n", enable); if (lcd_get_type()) { /* LVDS */ /* TODO */ } else { /* LCD */ govrh_set_dvo_enable(p_govrh2, enable); } hdmi_off = (govrh_get_MIF_enable(p_govrh)) ? 0 : 1; vpp_set_clock_enable(DEV_DVO, (hdmi_off && !enable) ? 0 : 1, 1); } #ifdef __KERNEL__ /*----------------------- LCD --------------------------------------*/ static int __init lcd_arg_panel_id ( char *str /*!<; // argument string */ ) { sscanf(str, "%d", (int *) &lcd_panel_id); if (lcd_panel_id >= LCD_PANEL_MAX) lcd_panel_id = LCD_PANEL_MAX; DBGMSG(KERN_INFO "set lcd panel id = %d\n", lcd_panel_id); return 1; } /* End of lcd_arg_panel_id */ __setup("lcdid=", lcd_arg_panel_id); #endif int lcd_panel_register(int no, void (*get_parm)(int mode)) { struct lcd_device_t *p; if (no >= LCD_PANEL_MAX) { DBGMSG(KERN_ERR "*E* lcd device no max is %d !\n", LCD_PANEL_MAX); return -1; } p = &lcd_device_array[no]; if (p->get_parm) { DBGMSG(KERN_ERR "*E* lcd device %d exist !\n", no); return -1; } p->get_parm = (void *) get_parm; return 0; } /* End of lcd_device_register */ /*----------------------- vout device plugin --------------------------------------*/ void lcd_set_power_down(int enable) { static int save_state = -1; if (save_state != enable) { /* lcd enable control by user */ lcd_power_on(enable ? false : true); lcd_set_enable(enable ? false : true); save_state = enable; } } static void wmt_config_govrh_polar(vout_t *vo) { /* wmt.display.polar [clock polar]:[hsync polart]:[vsync polar]*/ char buf[64]; size_t l = sizeof(buf); int clk_pol, hsync_pol, vsync_pol; if (wmt_getsyspara("wmt.display.polar", buf, &l)) { return; } sscanf(buf, "%d:%d:%d", &clk_pol, &hsync_pol, &vsync_pol); printk("govrh polar: clk-pol %d, hsync %d, vsync %d\n", clk_pol, hsync_pol, vsync_pol); govrh_set_dvo_clock_delay(vo->govr, clk_pol ? 0 : 1, 0); govrh_set_dvo_sync_polar(vo->govr, hsync_pol ? 0 : 1, vsync_pol ? 0 : 1); } int lcd_set_mode(unsigned int *option) { vout_t *vo; vout_inf_mode_t inf_mode; DBG_MSG("option %d,%d\n", option[0], option[1]); vo = lcd_vout_dev_ops.vout; inf_mode = vo->inf->mode; if (option) { unsigned int capability; if (lcd_panel_id == 0) p_lcd = lcd_get_oem_parm(vo->resx, vo->resy); else p_lcd = lcd_get_parm(lcd_panel_id, lcd_panel_bpp); if (!p_lcd) { DBG_ERR("lcd %d not support\n", lcd_panel_id); return -1; } DBG_MSG("[%s] %s (id %d,bpp %d)\n", vout_inf_str[inf_mode], p_lcd->vmode.name, lcd_panel_id, lcd_panel_bpp); capability = p_lcd->capability; switch (inf_mode) { case VOUT_INF_LVDS: lvds_set_sync_polar( (capability & LCD_CAP_HSYNC_HI) ? 0 : 1, (capability & LCD_CAP_VSYNC_HI) ? 0 : 1); lvds_set_rgb_type(lcd_panel_bpp); break; case VOUT_INF_DVI: govrh_set_dvo_clock_delay(vo->govr, (capability & LCD_CAP_CLK_HI) ? 0 : 1, 0); govrh_set_dvo_sync_polar(vo->govr, (capability & LCD_CAP_HSYNC_HI) ? 0 : 1, (capability & LCD_CAP_VSYNC_HI) ? 0 : 1); switch (lcd_panel_bpp) { case 15: govrh_IGS_set_mode(vo->govr, 0, 1, 1); break; case 16: govrh_IGS_set_mode(vo->govr, 0, 3, 1); break; case 18: govrh_IGS_set_mode(vo->govr, 0, 2, 1); break; case 24: govrh_IGS_set_mode(vo->govr, 0, 0, 0); break; default: break; } break; default: break; } } else p_lcd = 0; wmt_config_govrh_polar(vo); return 0; } int lcd_check_plugin(int hotplug) { return (p_lcd) ? 1 : 0; } int lcd_get_edid(char *buf) { return 1; } int lcd_config(vout_info_t *info) { info->resx = p_lcd->vmode.xres; info->resy = p_lcd->vmode.yres; info->fps = p_lcd->vmode.refresh; return 0; } int lcd_init(vout_t *vo) { DBG_MSG("%d\n", lcd_panel_id); /* vo_set_lcd_id(LCD_CHILIN_LW0700AT9003); */ if (lcd_panel_id >= LCD_PANEL_MAX) return -1; if (lcd_panel_id == 0) p_lcd = lcd_get_oem_parm(vo->resx, vo->resy); else p_lcd = lcd_get_parm(lcd_panel_id, 24); if (p_lcd == 0) return -1; /* set default parameters */ vo->resx = p_lcd->vmode.xres; vo->resy = p_lcd->vmode.yres; vo->pixclk = PICOS2KHZ(p_lcd->vmode.pixclock) * 1000; return 0; } vout_dev_t lcd_vout_dev_ops = { .name = "LCD", .mode = VOUT_INF_DVI, .capability = VOUT_DEV_CAP_FIX_RES + VOUT_DEV_CAP_FIX_PLUG, .init = lcd_init, .set_power_down = lcd_set_power_down, .set_mode = lcd_set_mode, .config = lcd_config, .check_plugin = lcd_check_plugin, .get_edid = lcd_get_edid, }; int lcd_module_init(void) { if (parse_uboot_param()) { lcd_power.gpio = -1; } vout_device_register(&lcd_vout_dev_ops); return 0; } /* End of lcd_module_init */ module_init(lcd_module_init); /*--------------------End of Function Body -----------------------------------*/ #undef LCD_C