/*++
* 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