summaryrefslogtreecommitdiff
path: root/drivers/video/wmt/vout-wmt.c
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-13 15:08:24 +0530
committerSrikant Patnaik2015-01-13 15:08:24 +0530
commit97327692361306d1e6259021bc425e32832fdb50 (patch)
treefe9088f3248ec61e24f404f21b9793cb644b7f01 /drivers/video/wmt/vout-wmt.c
parent2d05a8f663478a44e088d122e0d62109bbc801d0 (diff)
parenta3a8b90b61e21be3dde9101c4e86c881e0f06210 (diff)
downloadFOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.tar.gz
FOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.tar.bz2
FOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.zip
dirty fix to merging
Diffstat (limited to 'drivers/video/wmt/vout-wmt.c')
-rw-r--r--drivers/video/wmt/vout-wmt.c1523
1 files changed, 1523 insertions, 0 deletions
diff --git a/drivers/video/wmt/vout-wmt.c b/drivers/video/wmt/vout-wmt.c
new file mode 100644
index 00000000..323f9278
--- /dev/null
+++ b/drivers/video/wmt/vout-wmt.c
@@ -0,0 +1,1523 @@
+/*++
+ * linux/drivers/video/wmt/vout-wmt.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 <http://www.gnu.org/licenses/>.
+ *
+ * WonderMedia Technologies, Inc.
+ * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C
+--*/
+#undef DEBUG
+/* #define DEBUG */
+/* #define DEBUG_DETAIL */
+
+#include "vpp.h"
+
+#ifndef CFG_LOADER
+static int vo_plug_flag;
+#endif
+int vo_plug_vout;
+int (*vo_plug_func)(int hotplug);
+vout_mode_t dvo_vout_mode;
+vout_mode_t int_vout_mode;
+struct fb_videomode vo_oem_vmode;
+int hdmi_cur_plugin;
+vout_t *vo_poll_vout;
+
+/* GPIO 10 & 11 */
+swi2c_reg_t vo_gpio_scl = {
+ .bit_mask = BIT10,
+ .gpio_en = (__GPIO_BASE + 0x40),
+ .out_en = (__GPIO_BASE + 0x80),
+ .data_in = (__GPIO_BASE + 0x00),
+ .data_out = (__GPIO_BASE + 0xC0),
+ .pull_en = (__GPIO_BASE + 0x480),
+ .pull_en_bit_mask = BIT10,
+};
+
+swi2c_reg_t vo_gpio_sda = {
+ .bit_mask = BIT11,
+ .gpio_en = (__GPIO_BASE + 0x40),
+ .out_en = (__GPIO_BASE + 0x80),
+ .data_in = (__GPIO_BASE + 0x00),
+ .data_out = (__GPIO_BASE + 0xC0),
+ .pull_en = (__GPIO_BASE + 0x480),
+ .pull_en_bit_mask = BIT11,
+};
+
+swi2c_handle_t vo_swi2c_dvi = {
+ .scl_reg = &vo_gpio_scl,
+ .sda_reg = &vo_gpio_sda,
+};
+
+struct vout_init_parm_t {
+ unsigned int virtual_display;
+ unsigned int def_resx;
+ unsigned int def_resy;
+ unsigned int def_fps;
+ unsigned int ub_resx;
+ unsigned int ub_resy;
+};
+
+#define DVI_POLL_TIME_MS 100
+
+extern void hdmi_config_audio(vout_audio_t *info);
+extern vout_dev_t *lcd_get_dev(void);
+
+/*---------------------------------- API ------------------------------------*/
+int vo_i2c_proc(int id, unsigned int addr, unsigned int index,
+ char *pdata, int len)
+{
+ swi2c_handle_t *handle = 0;
+ int ret = 0;
+
+ switch (id) {
+ case 1: /* dvi */
+ if (lcd_get_type()) /* share pin with LVDS */
+ return -1;
+ handle = &vo_swi2c_dvi;
+ break;
+ default:
+ break;
+ }
+
+ if (handle) {
+ if (wmt_swi2c_check(handle))
+ return -1;
+ if (addr & 0x1) { /* read */
+ *pdata = 0xff;
+#ifdef CONFIG_WMT_EDID
+ ret = wmt_swi2c_read(handle, addr & ~0x1,
+ index, pdata, len);
+#else
+ ret = -1;
+#endif
+ } else { /* write */
+ DBG_ERR("not support sw i2c write\n");
+ }
+ }
+ return ret;
+}
+
+#ifndef CONFIG_UBOOT
+static void vo_do_plug(struct work_struct *ptr)
+{
+ vout_t *vo;
+ int plugin;
+
+ if (vo_plug_func == 0)
+ return;
+
+ vo = vout_get_entry(vo_plug_vout);
+ govrh_set_dvo_enable(vo->govr, 1);
+ plugin = vo_plug_func(1);
+ govrh_set_dvo_enable(vo->govr, plugin);
+ vout_change_status(vo, VPP_VOUT_STS_PLUGIN, plugin);
+ vo_plug_flag = 0;
+ DBG_DETAIL("vo_do_plug %d\n", plugin);
+ /* GPIO irq enable */
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x300 + VPP_VOINT_NO, 0x80, 7, 1);
+ /* GPIO input mode */
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x80, 0x1 << VPP_VOINT_NO,
+ VPP_VOINT_NO, 0x0);
+#ifdef __KERNEL__
+ vpp_netlink_notify_plug(VPP_VOUT_NUM_DVI, plugin);
+#endif
+ return;
+}
+
+DECLARE_DELAYED_WORK(vo_plug_work, vo_do_plug);
+
+static irqreturn_t vo_plug_interrupt_routine
+(
+ int irq, /*!<; // irq id */
+ void *dev_id /*!<; // device id */
+)
+{
+ DBG_DETAIL("Enter\n");
+ if ((vppif_reg8_in(GPIO_BASE_ADDR + 0x360) &
+ (0x1 << VPP_VOINT_NO)) == 0)
+ return IRQ_NONE;
+
+ /* clear int status */
+ vppif_reg8_out(GPIO_BASE_ADDR + 0x360, 0x1 << VPP_VOINT_NO);
+#ifdef __KERNEL__
+ /* if (vo_plug_flag == 0) { */
+ /* GPIO irq disable */
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x300 + VPP_VOINT_NO, 0x80, 7, 0);
+ schedule_delayed_work(&vo_plug_work, HZ/5);
+ vo_plug_flag = 1;
+ /* } */
+#else
+ if (vo_plug_func)
+ vo_do_plug(0);
+#endif
+ return IRQ_HANDLED;
+}
+
+#define CONFIG_VO_POLL_WORKQUEUE
+struct timer_list vo_poll_timer;
+#ifdef CONFIG_VO_POLL_WORKQUEUE
+static void vo_do_poll(struct work_struct *ptr)
+{
+ vout_t *vo;
+
+ vo = vo_poll_vout;
+ if (vo) {
+ if (vo->dev)
+ vo->dev->poll();
+ mod_timer(&vo_poll_timer,
+ jiffies + msecs_to_jiffies(vo_poll_timer.data));
+ }
+ return;
+}
+
+DECLARE_DELAYED_WORK(vo_poll_work, vo_do_poll);
+#else
+struct tasklet_struct vo_poll_tasklet;
+static void vo_do_poll_tasklet
+(
+ unsigned long data /*!<; // tasklet input data */
+)
+{
+ vout_t *vo;
+
+ vpp_lock();
+ vo = vo_poll_vout;
+ if (vo) {
+ if (vo->dev)
+ vo->dev->poll();
+ mod_timer(&vo_poll_timer,
+ jiffies + msecs_to_jiffies(vo_poll_timer.data));
+ }
+ vpp_unlock();
+}
+#endif
+
+void vo_do_poll_tmr(int ms)
+{
+#ifdef CONFIG_VO_POLL_WORKQUEUE
+ schedule_delayed_work(&vo_poll_work, msecs_to_jiffies(ms));
+#else
+ tasklet_schedule(&vo_poll_tasklet);
+#endif
+}
+
+static void vo_set_poll(vout_t *vo, int on, int ms)
+{
+ if (on) {
+ vo_poll_vout = vo;
+ if (vo_poll_timer.function) {
+ vo_poll_timer.data = ms / 2;
+ mod_timer(&vo_poll_timer,
+ jiffies + msecs_to_jiffies(vo_poll_timer.data));
+ } else {
+ init_timer(&vo_poll_timer);
+ vo_poll_timer.data = ms / 2;
+ vo_poll_timer.function = (void *) vo_do_poll_tmr;
+ vo_poll_timer.expires = jiffies +
+ msecs_to_jiffies(vo_poll_timer.data);
+ add_timer(&vo_poll_timer);
+ }
+#ifndef CONFIG_VO_POLL_WORKQUEUE
+ tasklet_init(&vo_poll_tasklet, vo_do_poll_tasklet, 0);
+#endif
+ } else {
+ del_timer(&vo_poll_timer);
+#ifndef CONFIG_VO_POLL_WORKQUEUE
+ tasklet_kill(&vo_poll_tasklet);
+#endif
+ vo_poll_vout = 0;
+ }
+}
+#endif
+
+void vout_set_int_type(int type)
+{
+ unsigned char reg;
+
+ reg = vppif_reg8_in(GPIO_BASE_ADDR+0x300 + VPP_VOINT_NO);
+ reg &= ~0x7;
+ switch (type) {
+ case 0: /* low level */
+ case 1: /* high level */
+ case 2: /* falling edge */
+ case 3: /* rising edge */
+ case 4: /* rising edge or falling */
+ reg |= type;
+ break;
+ default:
+ break;
+ }
+ vppif_reg8_out(GPIO_BASE_ADDR + 0x300 + VPP_VOINT_NO, reg);
+}
+EXPORT_SYMBOL(vout_set_int_type);
+
+void vout_set_int_enable(int enable)
+{
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x300 +
+ VPP_VOINT_NO, 0x80, 7, enable); /* GPIO irq enable/disable */
+}
+EXPORT_SYMBOL(vout_set_int_enable);
+
+int vout_get_clr_int(void)
+{
+ if ((vppif_reg8_in(GPIO_BASE_ADDR + 0x360) &
+ (0x1 << VPP_VOINT_NO)) == 0)
+ return 1;
+ /* clear int status */
+ vppif_reg8_out(GPIO_BASE_ADDR + 0x360, 0x1 << VPP_VOINT_NO);
+ return 0;
+}
+EXPORT_SYMBOL(vout_get_clr_int);
+
+static void vo_plug_enable(int enable, void *func, int no)
+{
+ vout_t *vo;
+
+ DBG_DETAIL("%d\n", enable);
+ vo_plug_vout = no;
+ vo = vout_get_entry(no);
+#ifdef CONFIG_WMT_EXT_DEV_PLUG_DISABLE
+ vo_plug_func = 0;
+ govrh_set_dvo_enable(vo->govr, enable);
+#else
+ vo_plug_func = func;
+ if (vo_plug_func == 0)
+ return;
+
+ if (enable) {
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x40, 0x1 << VPP_VOINT_NO,
+ VPP_VOINT_NO, 0x0); /* GPIO disable */
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x80, 0x1 << VPP_VOINT_NO,
+ VPP_VOINT_NO, 0x0); /* GPIO input mode */
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x480, 0x1 << VPP_VOINT_NO,
+ VPP_VOINT_NO, 0x1); /* GPIO pull enable */
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x4c0, 0x1 << VPP_VOINT_NO,
+ VPP_VOINT_NO, 0x1); /* GPIO pull-up */
+#ifndef CONFIG_UBOOT
+ vo_do_plug(0);
+ if (vpp_request_irq(IRQ_GPIO, vo_plug_interrupt_routine,
+ IRQF_SHARED, "vo plug", (void *) &vo_plug_vout))
+ DBG_ERR("request GPIO ISR fail\n");
+
+ vppif_reg32_write(GPIO_BASE_ADDR + 0x300 + VPP_VOINT_NO,
+ 0x80, 7, 1); /* GPIO irq enable */
+ } else {
+ vpp_free_irq(IRQ_GPIO, (void *) &vo_plug_vout);
+#endif
+ }
+#endif
+}
+
+/*--------------------------------- DVI ------------------------------------*/
+#ifdef WMT_FTBLK_VOUT_DVI
+static int vo_dvi_blank(vout_t *vo, vout_blank_t arg)
+{
+ DBG_DETAIL("(%d)\n", arg);
+ if (vo->pre_blank == VOUT_BLANK_POWERDOWN) {
+ if (vo->dev) {
+ vo->dev->init(vo);
+#ifdef __KERNEL__
+ if (vo->dev->poll)
+ vo_set_poll(vo, (vo->dev->poll) ? 1 : 0,
+ DVI_POLL_TIME_MS);
+#endif
+ }
+ }
+#ifdef __KERNEL__
+ if (arg == VOUT_BLANK_POWERDOWN)
+ vo_set_poll(vo, 0, 0);
+
+ /* patch for virtual fb,if HDMI plugin then DVI blank */
+ if (g_vpp.virtual_display || (g_vpp.dual_display == 0)) {
+ if (vout_chkplug(VPP_VOUT_NUM_HDMI)) {
+ arg = VOUT_BLANK_NORMAL;
+ vout_change_status(vo, VPP_VOUT_STS_BLANK, arg);
+ }
+ }
+#endif
+ if (!lcd_get_dev()) /* enable DVO not contain LCD */
+ govrh_set_dvo_enable(vo->govr,
+ (arg == VOUT_BLANK_UNBLANK) ? 1 : 0);
+ vo->pre_blank = arg;
+ return 0;
+}
+
+static int vo_dvi_config(vout_t *vo, int arg)
+{
+ vout_info_t *vo_info;
+
+ DBG_DETAIL("Enter\n");
+
+ vo_info = (vout_info_t *) arg;
+ govrh_set_dvo_sync_polar(vo->govr,
+ (vo_info->option & VPP_DVO_SYNC_POLAR_HI) ? 0 : 1,
+ (vo_info->option & VPP_DVO_VSYNC_POLAR_HI) ? 0 : 1);
+ return 0;
+}
+
+static int vo_dvi_init(vout_t *vo, int arg)
+{
+ unsigned int clk_delay;
+
+ DBG_DETAIL("(%d)\n", arg);
+
+ lvds_set_enable(0);
+ govrh_set_dvo_color_format(vo->govr, vo->option[0]);
+ /* bit0:0-12 bit,1-24bit */
+ govrh_set_dvo_outdatw(vo->govr, vo->option[1] & BIT0);
+ govrh_IGS_set_mode(vo->govr, 0, (vo->option[1] & 0x600) >> 9,
+ (vo->option[1] & 0x800) >> 11);
+ govrh_IGS_set_RGB_swap(vo->govr, (vo->option[1] & 0x3000) >> 12);
+ clk_delay = (vo->option[1] & BIT0) ?
+ VPP_GOVR_DVO_DELAY_24 : VPP_GOVR_DVO_DELAY_12;
+ govrh_set_dvo_clock_delay(vo->govr, ((clk_delay & BIT14) != 0x0),
+ clk_delay & 0x3FFF);
+ if (vo->dev) {
+ vo->dev->set_mode(&vo->option[0]);
+ vo->dev->set_power_down(VPP_FLAG_DISABLE);
+ if (vo->dev->interrupt)
+ vo_plug_enable(VPP_FLAG_ENABLE,
+ vo->dev->interrupt, vo->num);
+#ifdef __KERNEL__
+ if (vo->dev->poll)
+ vo_set_poll(vo, (vo->dev->poll) ? 1 : 0,
+ DVI_POLL_TIME_MS);
+#endif
+ vout_change_status(vo, VPP_VOUT_STS_PLUGIN,
+ vo->dev->check_plugin(0));
+ }
+ vo->govr->fb_p->set_csc(vo->govr->fb_p->csc_mode);
+ if (!lcd_get_dev()) {
+ govrh_set_dvo_enable(vo->govr,
+ (vo->status & VPP_VOUT_STS_BLANK) ? 0 : 1);
+ }
+ return 0;
+}
+
+static int vo_dvi_uninit(vout_t *vo, int arg)
+{
+ DBG_DETAIL("(%d)\n", arg);
+
+ vo_plug_enable(VPP_FLAG_DISABLE, 0, VPP_VOUT_NUM);
+ govrh_set_dvo_enable(vo->govr, VPP_FLAG_DISABLE);
+#ifdef __KERNEL__
+ vo_set_poll(vo, 0, DVI_POLL_TIME_MS);
+#endif
+ return 0;
+}
+
+static int vo_dvi_chkplug(vout_t *vo, int arg)
+{
+ int plugin = 1;
+
+ DBG_MSG("plugin %d\n", plugin);
+ return plugin;
+}
+
+static int vo_dvi_get_edid(vout_t *vo, int arg)
+{
+ char *buf;
+ int i, cnt;
+
+ DBG_DETAIL("Enter\n");
+
+ buf = (char *) arg;
+ memset(&buf[0], 0x0, 128 * EDID_BLOCK_MAX);
+ if (vpp_i2c_read(VPP_DVI_EDID_ID, 0xA0, 0, &buf[0], 128)) {
+ DBG_ERR("read edid\n");
+ return 1;
+ }
+
+ if (edid_checksum(buf, 128)) {
+ DBG_ERR("checksum\n");
+ return 1;
+ }
+
+ cnt = buf[0x7E];
+ if (cnt >= 3)
+ cnt = 3;
+ for (i = 1; i <= cnt; i++) {
+ vpp_i2c_read(VPP_DVI_EDID_ID, 0xA0, 0x80 * i,
+ &buf[128 * i], 128);
+ }
+ return 0;
+}
+
+vout_inf_t vo_dvi_inf = {
+ .mode = VOUT_INF_DVI,
+ .init = vo_dvi_init,
+ .uninit = vo_dvi_uninit,
+ .blank = vo_dvi_blank,
+ .config = vo_dvi_config,
+ .chkplug = vo_dvi_chkplug,
+ .get_edid = vo_dvi_get_edid,
+};
+
+int vo_dvi_initial(void)
+{
+ vout_inf_register(VOUT_INF_DVI, &vo_dvi_inf);
+ return 0;
+}
+module_init(vo_dvi_initial);
+
+#endif /* WMT_FTBLK_VOUT_DVI */
+
+/*---------------------------------- HDMI -----------------------------------*/
+void vo_hdmi_set_clock(int enable)
+{
+ DBG_DETAIL("(%d)\n", enable);
+
+ enable = (enable) ? CLK_ENABLE : CLK_DISABLE;
+ vpp_set_clock_enable(DEV_HDMII2C, enable, 0);
+ vpp_set_clock_enable(DEV_HDMI, enable, 0);
+ vpp_set_clock_enable(DEV_HDCE, enable, 0);
+}
+
+#ifdef WMT_FTBLK_VOUT_HDMI
+#ifdef __KERNEL__
+struct timer_list hdmi_cp_timer;
+static struct timer_list hdmi_plug_timer;
+#endif
+
+void vo_hdmi_cp_set_enable_tmr(int sec)
+{
+ int ms = sec * 1000;
+
+ DBG_MSG("[HDMI] set enable tmr %d sec\n", sec);
+
+ if (sec == 0) {
+ hdmi_set_cp_enable(VPP_FLAG_ENABLE);
+ return ;
+ }
+#ifdef __KERNEL__
+ if (hdmi_cp_timer.function)
+ del_timer(&hdmi_cp_timer);
+ init_timer(&hdmi_cp_timer);
+ hdmi_cp_timer.data = VPP_FLAG_ENABLE;
+ hdmi_cp_timer.function = (void *) hdmi_set_cp_enable;
+ hdmi_cp_timer.expires = jiffies + msecs_to_jiffies(ms);
+ add_timer(&hdmi_cp_timer);
+#else
+ hdmi_set_cp_enable(VPP_FLAG_ENABLE);
+#endif
+}
+
+static int vo_hdmi_blank(vout_t *vo, vout_blank_t arg)
+{
+ int enable;
+
+ DBG_DETAIL("(%d)\n", arg);
+
+ enable = (arg == VOUT_BLANK_UNBLANK) ? 1 : 0;
+ if (g_vpp.hdmi_cp_enable && enable)
+ vo_hdmi_cp_set_enable_tmr(2);
+ else
+ hdmi_set_cp_enable(VPP_FLAG_DISABLE);
+ hdmi_set_enable(enable);
+ hdmi_set_power_down((enable) ? 0 : 1);
+ return 0;
+}
+
+#ifndef CFG_LOADER
+static irqreturn_t vo_hdmi_cp_interrupt
+(
+ int irq, /*!<; // irq id */
+ void *dev_id /*!<; // device id */
+)
+{
+ vout_t *vo;
+
+ DBG_DETAIL("%d\n", irq);
+ vo = vout_get_entry(VPP_VOUT_NUM_HDMI);
+ switch (hdmi_check_cp_int()) {
+ case 1:
+ if (hdmi_cp)
+ hdmi_cp->enable(VPP_FLAG_DISABLE);
+ vo_hdmi_cp_set_enable_tmr(HDMI_CP_TIME);
+ vout_change_status(vo, VPP_VOUT_STS_CONTENT_PROTECT, 0);
+ vpp_netlink_notify_cp(0);
+ break;
+ case 0:
+ vout_change_status(vo, VPP_VOUT_STS_CONTENT_PROTECT, 1);
+ vpp_netlink_notify_cp(1);
+ break;
+ case 2:
+ hdmi_ri_tm_cnt = 3 * 30;
+ break;
+ default:
+ break;
+ }
+ return IRQ_HANDLED;
+}
+
+#ifdef __KERNEL__
+static void vo_hdmi_do_plug(struct work_struct *ptr)
+#else
+static void vo_hdmi_do_plug(void)
+#endif
+{
+ vout_t *vo;
+ int plugin;
+ int option = 0;
+
+ plugin = hdmi_check_plugin(1);
+ vo = vout_get_entry(VPP_VOUT_NUM_HDMI);
+ vout_change_status(vo, VPP_VOUT_STS_PLUGIN, plugin);
+ if (plugin) {
+ option = vout_get_edid_option(VPP_VOUT_NUM_HDMI);
+#ifdef CONFIG_VPP_DEMO
+ option |= (EDID_OPT_HDMI + EDID_OPT_AUDIO);
+#endif
+ hdmi_set_option(option);
+ } else {
+ g_vpp.hdmi_bksv[0] = g_vpp.hdmi_bksv[1] = 0;
+ }
+ vo_hdmi_blank(vo, (vo->status & VPP_VOUT_STS_BLANK) ? 1 : !(plugin));
+ if (!g_vpp.hdmi_certify_flag)
+ hdmi_hotplug_notify(plugin);
+ DBG_MSG("%d\n", plugin);
+ return;
+}
+DECLARE_WORK(vo_hdmi_plug_work, vo_hdmi_do_plug);
+
+static void hdmi_handle_plug(vpp_flag_t enable)
+{
+ schedule_work(&vo_hdmi_plug_work);
+}
+
+static void vo_hdmi_handle_plug_tmr(int ms)
+{
+ static int timer_init;
+
+ if(timer_init == 0) {
+ init_timer(&hdmi_plug_timer);
+ hdmi_plug_timer.data = VPP_FLAG_ENABLE;
+ hdmi_plug_timer.function = (void *) hdmi_handle_plug;
+ timer_init = 1;
+ }
+ hdmi_plug_timer.expires = jiffies + msecs_to_jiffies(ms);
+ mod_timer(&hdmi_plug_timer, hdmi_plug_timer.expires);
+}
+
+static irqreturn_t vo_hdmi_plug_interrupt
+(
+ int irq, /*!<; // irq id */
+ void *dev_id /*!<; // device id */
+)
+{
+ DBG_MSG("vo_hdmi_plug_interrupt %d\n", irq);
+ hdmi_clear_plug_status();
+ if (g_vpp.hdmi_certify_flag)
+ vo_hdmi_do_plug(0);
+ else
+ vo_hdmi_handle_plug_tmr(HDMI_PLUG_DELAY);
+ return IRQ_HANDLED;
+}
+#endif
+
+static int vo_hdmi_init(vout_t *vo, int arg)
+{
+ DBG_DETAIL("(%d)\n", arg);
+
+ vo_hdmi_set_clock(1);
+ vout_change_status(vout_get_entry(VPP_VOUT_NUM_HDMI),
+ VPP_VOUT_STS_PLUGIN, hdmi_check_plugin(0));
+ hdmi_enable_plugin(1);
+
+ if (g_vpp.hdmi_disable)
+ return 0;
+#ifndef CONFIG_UBOOT
+ if (vpp_request_irq(VPP_IRQ_HDMI_CP, vo_hdmi_cp_interrupt,
+ SA_INTERRUPT, "hdmi cp", (void *) 0)) {
+ DBG_ERR("*E* request HDMI ISR fail\n");
+ }
+ if (vpp_request_irq(VPP_IRQ_HDMI_HPDH, vo_hdmi_plug_interrupt,
+ SA_INTERRUPT, "hdmi plug", (void *) 0)) {
+ DBG_ERR("*E* request HDMI ISR fail\n");
+ }
+ if (vpp_request_irq(VPP_IRQ_HDMI_HPDL, vo_hdmi_plug_interrupt,
+ SA_INTERRUPT, "hdmi plug", (void *) 0)) {
+ DBG_ERR("*E* request HDMI ISR fail\n");
+ }
+#endif
+ hdmi_set_enable((vo->status & VPP_VOUT_STS_BLANK) ?
+ VPP_FLAG_DISABLE : VPP_FLAG_ENABLE);
+ return 0;
+}
+
+static int vo_hdmi_uninit(vout_t *vo, int arg)
+{
+ DBG_DETAIL("(%d)\n", arg);
+ hdmi_enable_plugin(0);
+ hdmi_set_cp_enable(VPP_FLAG_DISABLE);
+ hdmi_set_enable(VPP_FLAG_DISABLE);
+#ifndef CONFIG_UBOOT
+ vpp_free_irq(VPP_IRQ_HDMI_CP, (void *) 0);
+ vpp_free_irq(VPP_IRQ_HDMI_HPDH, (void *) 0);
+ vpp_free_irq(VPP_IRQ_HDMI_HPDL, (void *) 0);
+#endif
+ vo_hdmi_set_clock(0);
+ return 0;
+}
+
+static int vo_hdmi_config(vout_t *vo, int arg)
+{
+ vout_info_t *vo_info;
+ vdo_color_fmt colfmt;
+
+ hdmi_set_enable(0);
+ vo_info = (vout_info_t *) arg;
+
+ DBG_DETAIL("(%dx%d@%d)\n", vo_info->resx, vo_info->resy, vo_info->fps);
+ DPRINT("hdmi config (%dx%d@%d)\n", vo_info->resx, vo_info->resy, vo_info->fps);
+
+ /* 1280x720@60, HDMI pixel clock 74250060 not 74500000 */
+ if ((vo_info->resx == 1280)
+ && (vo_info->resy == 720) && (vo_info->pixclk == 74500000))
+ vo_info->pixclk = 74250060;
+ colfmt = (vo->option[0] == VDO_COL_FMT_YUV422V) ?
+ VDO_COL_FMT_YUV422H : vo->option[0];
+ hdmi_cur_plugin = hdmi_check_plugin(0);
+ hdmi_info.option = (hdmi_cur_plugin) ?
+ vout_get_edid_option(VPP_VOUT_NUM_HDMI) : 0;
+ hdmi_info.outfmt = colfmt;
+ hdmi_info.vic = hdmi_get_vic(vo_info->resx, vo_info->resy,
+ vo_info->fps, (vo_info->option & VPP_OPT_INTERLACE) ? 1 : 0);
+
+ govrh_set_csc_mode(vo->govr, vo->govr->fb_p->csc_mode);
+ hdmi_set_sync_low_active((vo_info->option & VPP_DVO_SYNC_POLAR_HI) ?
+ 0 : 1, (vo_info->option & VPP_DVO_VSYNC_POLAR_HI) ? 0 : 1);
+ hdmi_config(&hdmi_info);
+#ifdef __KERNEL__
+ mdelay(200); /* patch for VIZIO change resolution issue */
+#endif
+ hdmi_cur_plugin = hdmi_check_plugin(0);
+ vo_hdmi_blank(vo, (vo->status & VPP_VOUT_STS_BLANK) ?
+ 1 : !(hdmi_cur_plugin));
+ return 0;
+}
+
+static int vo_hdmi_chkplug(vout_t *vo, int arg)
+{
+ int plugin;
+
+ if (g_vpp.hdmi_disable)
+ return 0;
+ plugin = hdmi_get_plugin();
+ DBG_DETAIL("%d\n", plugin);
+ return plugin;
+}
+
+static int vo_hdmi_get_edid(vout_t *vo, int arg)
+{
+ char *buf;
+#ifdef CONFIG_WMT_EDID
+ int i, cnt;
+#endif
+ DBG_DETAIL("Enter\n");
+ buf = (char *) arg;
+#ifdef CONFIG_WMT_EDID
+ memset(&buf[0], 0x0, 128*EDID_BLOCK_MAX);
+ if (!hdmi_get_plugin())
+ return 1;
+
+ if (hdmi_DDC_read(0xA0, 0x0, &buf[0], 128)) {
+ DBG_ERR("read edid\n");
+ return 1;
+ }
+
+ if (edid_checksum(buf, 128)) {
+ DBG_ERR("hdmi checksum\n");
+/* g_vpp.dbg_hdmi_ddc_crc_err++; */
+ return 1;
+ }
+
+ cnt = buf[0x7E];
+ if (cnt >= 3)
+ cnt = 3;
+ for (i = 1; i <= cnt; i++)
+ hdmi_DDC_read(0xA0, 0x80 * i, &buf[128 * i], 128);
+#endif
+ return 0;
+}
+
+vout_inf_t vo_hdmi_inf = {
+ .mode = VOUT_INF_HDMI,
+ .init = vo_hdmi_init,
+ .uninit = vo_hdmi_uninit,
+ .blank = vo_hdmi_blank,
+ .config = vo_hdmi_config,
+ .chkplug = vo_hdmi_chkplug,
+ .get_edid = vo_hdmi_get_edid,
+};
+
+int vo_hdmi_initial(void)
+{
+ vout_inf_register(VOUT_INF_HDMI, &vo_hdmi_inf);
+ return 0;
+}
+module_init(vo_hdmi_initial);
+
+#endif /* WMT_FTBLK_VOUT_HDMI */
+
+/*--------------------------------- LVDS ------------------------------------*/
+#ifdef WMT_FTBLK_VOUT_LVDS
+int vo_lvds_init_flag;
+static int vo_lvds_blank(vout_t *vo, vout_blank_t arg)
+{
+ DBG_DETAIL("(%d)\n", arg);
+ if (arg == VOUT_BLANK_POWERDOWN) {
+ vppif_reg32_write(LVDS_TRE_EN, 0);
+ } else { /* avoid suspend signal not clear */
+ lvds_set_enable((arg == VOUT_BLANK_UNBLANK) ? 1 : 0);
+ }
+
+ if (vo_lvds_init_flag)
+ lvds_set_power_down(arg);
+ return 0;
+}
+
+static int vo_lvds_config(vout_t *vo, int arg)
+{
+ DBG_DETAIL("(%d)\n", arg);
+ lvds_set_power_down(VPP_FLAG_DISABLE);
+ vo_lvds_init_flag = 1;
+ return 0;
+}
+
+static int vo_lvds_init(vout_t *vo, int arg)
+{
+ DBG_DETAIL("(%d)\n", arg);
+
+ vpp_set_clock_enable(DEV_LVDS, 1, 0);
+ if (vo->dev)
+ vo->dev->set_mode(&vo->option[0]);
+ govrh_set_dvo_enable(p_govrh2, 0);
+ govrh_set_csc_mode(vo->govr, vo->govr->fb_p->csc_mode);
+ lvds_set_enable((vo->status & VPP_VOUT_STS_BLANK) ?
+ VPP_FLAG_DISABLE : VPP_FLAG_ENABLE);
+ return 0;
+}
+
+static int vo_lvds_uninit(vout_t *vo, int arg)
+{
+ DBG_DETAIL("(%d)\n", arg);
+ lvds_set_enable(VPP_FLAG_DISABLE);
+ if (vo->dev)
+ vo->dev->set_mode(0);
+ lvds_set_power_down(VPP_FLAG_ENABLE);
+ vpp_set_clock_enable(DEV_LVDS, 0, 0);
+ vo_lvds_init_flag = 0;
+ return 0;
+}
+
+static int vo_lvds_chkplug(vout_t *vo, int arg)
+{
+ DBG_DETAIL("\n");
+#if 0
+ vo = vout_get_info(VOUT_LVDS);
+ if (vo->dev)
+ return vo->dev->check_plugin(0);
+#endif
+ return 1;
+}
+
+vout_inf_t vo_lvds_inf = {
+ .mode = VOUT_INF_LVDS,
+ .capability = VOUT_INF_CAP_FIX_PLUG,
+ .init = vo_lvds_init,
+ .uninit = vo_lvds_uninit,
+ .blank = vo_lvds_blank,
+ .config = vo_lvds_config,
+ .chkplug = vo_lvds_chkplug,
+#ifdef WMT_FTBLK_VOUT_HDMI
+ .get_edid = vo_hdmi_get_edid,
+#endif
+};
+
+int vo_lvds_initial(void)
+{
+ vout_inf_register(VOUT_INF_LVDS, &vo_lvds_inf);
+ return 0;
+}
+module_init(vo_lvds_initial);
+
+#endif /* WMT_FTBLK_VOUT_LVDS */
+/*---------------------------------- API ------------------------------------*/
+#ifndef CFG_LOADER
+int vout_set_audio(vout_audio_t *arg)
+{
+ vout_t *vout;
+ int ret = 0;
+
+#if 0
+ vout = vout_get_info(VPP_VOUT_DVO2HDMI);
+ if (vout && (vout->status & VPP_VOUT_STS_PLUGIN)) {
+ if (vout->dev->set_audio)
+ vout->dev->set_audio(arg);
+ }
+#endif
+
+#ifdef WMT_FTBLK_VOUT_HDMI
+ vout = vout_get_entry(VPP_VOUT_NUM_HDMI);
+ if (vout) {
+ hdmi_config_audio(arg);
+ ret = 1;
+ }
+#endif
+ return ret;
+}
+#endif
+
+/* 3445 port1 : DVI/SDD, port2 : VGA/SDA, port3 : HDMI/LVDS */
+/* 3481 port1 : HDMI/LVDS, port2 : DVI */
+/* 3498 port1 : HDMI, port2 : DVI/LVDS */
+vout_t vout_entry_0 = {
+ .fix_cap = BIT(VOUT_INF_HDMI),
+ .option[0] = VDO_COL_FMT_ARGB,
+ .option[1] = VPP_DATAWIDHT_24,
+ .option[2] = 0,
+};
+
+vout_t vout_entry_1 = {
+ .fix_cap = BIT(VOUT_INF_DVI) + BIT(VOUT_INF_LVDS) +
+ VOUT_CAP_EXT_DEV + 0x100, /* i2c bus 1,ext dev */
+ .option[0] = VDO_COL_FMT_ARGB,
+ .option[1] = VPP_DATAWIDHT_24,
+ .option[2] = 0,
+};
+
+void vout_init_param(struct vout_init_parm_t *init_parm)
+{
+ char buf[100];
+ int varlen = 100;
+ unsigned int parm[10];
+
+ memset(init_parm, 0, sizeof(struct vout_init_parm_t));
+
+ /* register vout & set default */
+ vout_register(0, &vout_entry_0);
+ vout_entry_0.inf = vout_inf_get_entry(VOUT_INF_HDMI);
+ vout_register(1, &vout_entry_1);
+ vout_entry_1.inf = vout_inf_get_entry(VOUT_INF_DVI);
+
+ /* [uboot parameter] up bound : resx:resy */
+ if (wmt_getsyspara("wmt.display.upbound", buf, &varlen) == 0) {
+ vpp_parse_param(buf, parm, 2, 0);
+ init_parm->ub_resx = parm[0];
+ init_parm->ub_resy = parm[1];
+ MSG("up bound(%d,%d)\n", init_parm->ub_resx,
+ init_parm->ub_resy);
+ }
+
+ /* [uboot parameter] default resolution : resx:resy:fps */
+ init_parm->def_resx = VOUT_INFO_DEFAULT_RESX;
+ init_parm->def_resy = VOUT_INFO_DEFAULT_RESY;
+ init_parm->def_fps = VOUT_INFO_DEFAULT_FPS;
+ if (wmt_getsyspara("wmt.display.default.res", buf, &varlen) == 0) {
+ vpp_parse_param(buf, parm, 3, 0);
+ init_parm->def_resx = parm[0];
+ init_parm->def_resy = parm[1];
+ init_parm->def_fps = parm[2];
+ MSG("default res(%d,%d,%d)\n", init_parm->def_resx,
+ init_parm->def_resy, init_parm->def_fps);
+ } else if (wmt_getsyspara("wmt.display.param", buf, &varlen) == 0) {
+ vpp_parse_param(buf, parm, 6, 0);
+ init_parm->def_resx = parm[3];
+ init_parm->def_resy = parm[4];
+ init_parm->def_fps = parm[5];
+ MSG("param2 res(%d,%d,%d)\n", init_parm->def_resx,
+ init_parm->def_resy, init_parm->def_fps);
+ }
+}
+
+const char *vout_sys_parm_str[] = {"wmt.display.param", "wmt.display.param2"};
+int vout_check_display_info(struct vout_init_parm_t *init_parm)
+{
+ char buf[100];
+ const char *display_param[] = { "2:0:24:1024:600:60", "4:0:24:1024:600:60" };
+ int varlen = 100;
+ unsigned int parm[10];
+ vout_t *vo = 0;
+ int ret = 1;
+ int i;
+ int info_no;
+
+ DBG_DETAIL("Enter\n");
+
+ /* [uboot parameter] display param : type:op1:op2:resx:resy:fps */
+ for (i = 0; i < 2; i++) {
+ strncpy(buf, display_param[i], 19);
+ DBG_MSG("display param %d : %s\n", i, buf);
+ vpp_parse_param(buf, (unsigned int *)parm, 6, 0);
+ MSG("boot parm vo %d opt %d,%d, %dx%d@%d\n", parm[0],
+ parm[1], parm[2], parm[3], parm[4], parm[5]);
+ vo = vout_get_entry_adapter(parm[0]);
+ if (vo == 0) {
+ vout_t *vo_boot;
+
+ if (parm[0] != VOUT_BOOT) {
+ ret = 1;
+ DBG_ERR("uboot param invalid\n");
+ break;
+ }
+
+ g_vpp.virtual_display_mode = parm[1];
+ if (parm[1] == 1) {
+ init_parm->def_resx = parm[3];
+ init_parm->def_resy = parm[4];
+ init_parm->def_fps = parm[5];
+ parm[3] = 1920;
+ parm[4] = 1080;
+ parm[5] = 60;
+ } else if (parm[1] == 2) {
+ init_parm->def_resx = parm[3];
+ init_parm->def_resy = parm[4];
+ init_parm->def_fps = parm[5];
+ g_vpp.dual_display = 0;
+ break;
+ }
+
+ MSG("[VOUT] virtual display\n");
+ init_parm->virtual_display = 1;
+ g_vpp.virtual_display = 1;
+ g_vpp.fb0_bitblit = 1;
+ vo_boot = kmalloc(sizeof(vout_t), GFP_KERNEL);
+ if (vo_boot == 0) {
+ ret = 1;
+ break;
+ }
+ vo_boot->resx = parm[3];
+ vo_boot->resy = parm[4];
+ vo_boot->pixclk = parm[5];
+ vo_boot->inf = 0;
+ vo_boot->num = VPP_VOUT_INFO_NUM;
+ vo_boot->govr = 0;
+ info_no = vout_info_add_entry(vo_boot);
+ kfree(vo_boot);
+ } else {
+ vo->inf = vout_get_inf_entry_adapter(parm[0]);
+ vo->option[0] = parm[1];
+ vo->option[1] = parm[2];
+ vo->resx = parm[3];
+ vo->resy = parm[4];
+ vo->pixclk = parm[5];
+ vout_change_status(vo, VPP_VOUT_STS_BLANK,
+ (parm[2] & VOUT_OPT_BLANK) ?
+ VOUT_BLANK_NORMAL : VOUT_BLANK_UNBLANK);
+ info_no = vout_info_add_entry(vo);
+ }
+
+ switch (parm[0]) {
+ case VOUT_LVDS:
+ {
+ struct fb_videomode *vmode;
+ vout_info_t *info;
+
+ info = vout_info_get_entry(info_no);
+ vmode = 0;
+ if ((parm[1] == 0) && (parm[3] == 0) &&
+ (parm[4] == 0)) { /* auto detect */
+ if (vout_get_edid_option(vo->num)) {
+ vmode = &vo->edid_info.detail_timing[0];
+ if (vmode->pixclock == 0) {
+ vmode = 0;
+ DBG_ERR("LVDS timing\n");
+ }
+ }
+
+ if (vo->inf->get_edid(vo,
+ (int)vo->edid) == 0) {
+ if (edid_parse(vo->edid,
+ &vo->edid_info) == 0)
+ DBG_ERR("LVDS edid parse\n");
+ } else {
+ DBG_ERR("LVDS edid read\n");
+ }
+ }
+
+ if (vmode == 0) { /* use internal timing */
+ lcd_parm_t *p = 0;
+
+ if (parm[1]) {
+ p = lcd_get_parm(parm[1], parm[2]);
+ if (p)
+ lcd_set_lvds_id(parm[1]);
+ }
+
+ if (p == 0)
+ p = lcd_get_oem_parm(parm[3], parm[4]);
+ vmode = &p->vmode;
+ }
+ memcpy(&vo_oem_vmode, vmode,
+ sizeof(struct fb_videomode));
+ vo->option[2] = vmode->vmode;
+ info->resx = vmode->xres;
+ info->resy = vmode->yres;
+ info->fps = vmode->refresh;
+ vout_info_set_fixed_timing(info_no, &vo_oem_vmode);
+ lcd_set_type(1);
+ }
+ case VOUT_LCD:
+ {
+ vout_dev_t *dev;
+
+ lcd_set_parm(parm[1], parm[2] & 0xFF);
+ dev = lcd_get_dev();
+ vo->ext_dev = dev;
+ vo->dev = dev;
+ dev->vout = vo;
+ vo->option[0] = VDO_COL_FMT_ARGB;
+ vo->option[1] &= ~0xFF;
+ vo->option[1] |= VPP_DATAWIDHT_24;
+ }
+ break;
+ case VOUT_DVI:
+ case VOUT_HDMI:
+ vout_info[info_no].option = (parm[2] & 0x2) ?
+ VPP_OPT_INTERLACE : 0;
+ break;
+ default:
+ break;
+ }
+ ret = 0;
+ }
+
+ if (g_vpp.virtual_display)
+ ret = 1;
+
+ /* add vout entry to info */
+ for (i = 0; i < VPP_VOUT_NUM; i++) {
+ vo = vout_get_entry(i);
+ if (vo) {
+ if (vo->resx == 0) {
+ vo->resx = init_parm->def_resx;
+ vo->resy = init_parm->def_resy;
+ vo->pixclk = init_parm->def_fps;
+ }
+ vout_info_add_entry(vo);
+ }
+ }
+ DBG_DETAIL("Leave\n");
+ return ret;
+}
+
+void vout_check_ext_device(void)
+{
+ char buf[100];
+ int varlen = 100;
+ vout_t *vo = 0;
+ vout_dev_t *dev = 0;
+ int i;
+ vout_info_t *info;
+
+ DBG_DETAIL("Enter\n");
+ vpp_i2c_init(1, 0xA0);
+
+ /* [uboot parameter] reg operation : addr op val */
+ if (wmt_getsyspara("wmt.display.regop", buf, &varlen) == 0) {
+ unsigned int addr;
+ unsigned int val;
+ char op;
+ char *p, *endp;
+
+ p = buf;
+ while (1) {
+ addr = simple_strtoul(p, &endp, 16);
+ if (*endp == '\0')
+ break;
+
+ op = *endp;
+ if (endp[1] == '~') {
+ val = simple_strtoul(endp + 2, &endp, 16);
+ val = ~val;
+ } else {
+ val = simple_strtoul(endp + 1, &endp, 16);
+ }
+
+ DBG_DETAIL(" reg op: 0x%X %c 0x%X\n", addr, op, val);
+ switch (op) {
+ case '|':
+ REG32_VAL(addr) |= val;
+ break;
+ case '=':
+ REG32_VAL(addr) = val;
+ break;
+ case '&':
+ REG32_VAL(addr) &= val;
+ break;
+ default:
+ DBG_ERR("Error, Unknown operator %c\n", op);
+ }
+
+ if (*endp == '\0')
+ break;
+ p = endp + 1;
+ }
+ }
+
+ /* [uboot parameter] dvi device : name:i2c id */
+ vo = vout_get_entry(VPP_VOUT_NUM_DVI);
+ info = vout_get_info_entry(VPP_VOUT_NUM_DVI);
+ if (lcd_get_dev()) {
+ vo->dev->init(vo);
+ vout_info_set_fixed_timing(info->num, &p_lcd->vmode);
+ } else if (vo->ext_dev == 0) {
+ if (wmt_getsyspara("wmt.display.dvi.dev", buf, &varlen) == 0) {
+ unsigned int param[1];
+ char *p;
+
+ p = strchr(buf, ':');
+ *p = 0;
+ vpp_parse_param(p + 1, param, 1, 0x1);
+ vpp_i2c_release();
+ vpp_i2c_init(param[0], 0xA0);
+ MSG("dvi dev %s : %x\n", buf, param[0]);
+ do {
+ dev = vout_get_device(dev);
+ if (dev == 0)
+ break;
+ if (strcmp(buf, dev->name) == 0) {
+ vo->ext_dev = dev;
+ vo->dev = dev;
+ dev->vout = vo;
+
+ /* probe & init external device */
+ if (dev->init(vo)) {
+ DBG_ERR("%s not exist\n",
+ dev->name);
+ vo->dev = vo->ext_dev = 0;
+ break;
+ } else {
+ MSG("[VOUT] dvi dev %s\n", buf);
+ }
+
+ /* if LCD then set fixed timing */
+ if (vo->dev == lcd_get_dev())
+ vout_info_set_fixed_timing(
+ info->num, &p_lcd->vmode);
+ }
+ } while (1);
+ }
+ }
+
+ for (i = 0; i < VPP_VOUT_NUM; i++) {
+ vo = vout_get_entry(i);
+ if (vo == 0)
+ continue;
+
+ if ((vo->fix_cap & VOUT_CAP_EXT_DEV) && !(vo->ext_dev)) {
+ dev = 0;
+ do {
+ dev = vout_get_device(dev);
+ if (dev == 0)
+ break;
+ if (vo->fix_cap & BIT(dev->mode)) {
+ vo->inf = vout_inf_get_entry(dev->mode);
+ if (dev->init(vo) == 0) {
+ vo->ext_dev = dev;
+ vo->dev = dev;
+ dev->vout = vo;
+ break;
+ }
+ }
+ } while (1);
+ }
+ DBG_MSG("vout %d ext dev : %s\n", i,
+ (vo->dev) ? vo->dev->name : "NO");
+ }
+
+ /* [uboot parameter] oem timing :
+ pixclk:option:hsync:hbp:hpixel:hfp:vsync:vbp:vpixel:vfp */
+ if (wmt_getsyspara("wmt.display.tmr", buf, &varlen) == 0) {
+ unsigned int param[10];
+ struct fb_videomode *p;
+ int xres, yres;
+
+ p = &vo_oem_vmode;
+ DBG_MSG("tmr %s\n", buf);
+ vpp_parse_param(buf, param, 10, 0);
+ p->pixclock = param[0];
+ p->vmode = param[1];
+ p->hsync_len = param[2];
+ p->left_margin = param[3];
+ p->xres = param[4];
+ p->right_margin = param[5];
+ p->vsync_len = param[6];
+ p->upper_margin = param[7];
+ p->yres = param[8];
+ p->lower_margin = param[9];
+ p->pixclock *= 1000;
+ xres = p->hsync_len + p->left_margin + p->xres +
+ p->right_margin;
+ yres = p->vsync_len + p->upper_margin + p->yres +
+ p->lower_margin;
+ p->refresh = vpp_calc_refresh(p->pixclock, xres, yres);
+ if (p->refresh == 59)
+ p->refresh = 60;
+ DBG_MSG("tmr pixclk %d,option 0x%x\n",
+ p->pixclock, p->vmode);
+ DBG_MSG("H sync %d,bp %d,pixel %d,fp %d\n", p->hsync_len,
+ p->left_margin, p->xres, p->right_margin);
+ DBG_MSG("V sync %d,bp %d,pixel %d,fp %d\n", p->vsync_len,
+ p->upper_margin, p->yres, p->lower_margin);
+ p->pixclock = KHZ2PICOS(p->pixclock / 1000);
+ vout_info_set_fixed_timing(0, &vo_oem_vmode);
+ vout_info[0].resx = p->xres;
+ vout_info[0].resy = p->yres;
+ vout_info[0].fps = p->refresh;
+ }
+ DBG_DETAIL("Leave\n");
+}
+
+void vout_check_monitor_resolution(struct vout_init_parm_t *init_parm)
+{
+ vout_info_t *p;
+ vout_t *vo;
+ int i;
+
+ DBG_DETAIL("Check monitor support\n");
+
+ if (g_vpp.virtual_display) {
+ p = &vout_info[0];
+ if ((p->resx == 0) || (p->resy == 0)) {
+ struct fb_videomode vmode;
+ int edid_option;
+
+ for (i = 0; i < VPP_VOUT_NUM; i++) {
+ if (vout_chkplug(i) == 0) {
+ DBG_MSG("no plugin %d\n", i);
+ continue;
+ }
+
+ edid_option = vout_get_edid_option(i);
+ if ((edid_option & EDID_OPT_VALID) == 0) {
+ DBG_MSG("no EDID %d\n", i);
+ continue;
+ }
+ break;
+ }
+ vmode.xres = (i == VPP_VOUT_NUM) ? 1280 : 1920;
+ vmode.yres = (i == VPP_VOUT_NUM) ? 720 : 1080;
+ vmode.refresh = 60;
+ vmode.vmode = 0;
+ vout_find_match_mode(1, &vmode, 1);
+ init_parm->def_resx = vmode.xres;
+ init_parm->def_resy = vmode.yres;
+ init_parm->def_fps = vmode.refresh;
+
+ for (i = 0; i < VPP_VOUT_INFO_NUM; i++) {
+ p = &vout_info[i];
+ p->resx = init_parm->def_resx;
+ p->resy = init_parm->def_resy;
+ p->fps = init_parm->def_fps;
+ }
+ DBG_MSG("virtual display %dx%d@%d\n",
+ vmode.xres, vmode.yres, vmode.refresh);
+ }
+ }
+
+ for (i = 0; i < VPP_VOUT_INFO_NUM; i++) {
+ int support;
+ int vo_num;
+
+ p = &vout_info[i];
+
+ DBG_MSG("info %d (%d,%d,%d)\n", i, p->resx, p->resy, p->fps);
+
+ if (p->vo_mask == 0)
+ break;
+ if (p->govr == 0)
+ continue;
+ if (p->fixed_vmode)
+ continue;
+ if (init_parm->ub_resx)
+ p->resx = init_parm->ub_resx;
+ if (init_parm->ub_resy)
+ p->resy = init_parm->ub_resy;
+ if (!p->resx)
+ p->resx = init_parm->def_resx;
+ if (!p->resy)
+ p->resy = init_parm->def_resy;
+ if (!p->fps)
+ p->fps = init_parm->def_fps;
+
+ DBG_DETAIL("info %d (%d,%d,%d)\n", i, p->resx, p->resy, p->fps);
+
+ support = 0;
+ for (vo_num = 0; vo_num < VPP_VOUT_NUM; vo_num++) {
+ int edid_option;
+
+ if ((p->vo_mask & (0x1 << vo_num)) == 0)
+ continue;
+ vo = vout_get_entry(vo_num);
+ if (vo == 0)
+ continue;
+#ifdef CONFIG_WMT_EDID
+ if (vout_chkplug(vo_num) == 0) {
+ DBG_MSG("no plugin %d\n", vo_num);
+ continue;
+ }
+
+ vout_change_status(vo, VPP_VOUT_STS_BLANK, 0);
+ edid_option = vout_get_edid_option(vo_num);
+ if (edid_option & EDID_OPT_VALID) {
+ struct fb_videomode *vmode;
+
+ if (edid_find_support(&vo->edid_info, p->resx,
+ p->resy, p->fps, &vmode)) {
+ support = 1;
+ break;
+ } else {
+ if (vout_find_edid_support_mode(
+ &vo->edid_info,
+ (unsigned int *)&p->resx,
+ (unsigned int *)&p->resy,
+ (unsigned int *)&p->fps,
+ (edid_option & EDID_OPT_16_9) ?
+ 1 : 0)) {
+ support = 1;
+ break;
+ }
+ }
+ }
+#else
+ break;
+#endif
+ }
+
+ if (support == 0) {
+ if (vout_chkplug(VPP_VOUT_NUM_HDMI)) {
+ init_parm->def_resx = 1280;
+ init_parm->def_resy = 720;
+ init_parm->def_fps = 60;
+ } else {
+ char buf[40];
+ int varlen = 40;
+
+ if (wmt_getsyspara("wmt.display.tvformat",
+ buf, &varlen) == 0) {
+ if (strnicmp(buf, "PAL", 3) == 0) {
+ init_parm->def_resx = 720;
+ init_parm->def_resy = 576;
+ init_parm->def_fps = 50;
+ } else if (strnicmp(buf,"NTSC",4) == 0) {
+ init_parm->def_resx = 720;
+ init_parm->def_resy = 480;
+ init_parm->def_fps = 60;
+ }
+ } else {
+ init_parm->def_resx = 1024;
+ init_parm->def_resy = 768;
+ init_parm->def_fps = 60;
+ }
+ }
+ p->resx = init_parm->def_resx;
+ p->resy = init_parm->def_resy;
+ p->fps = init_parm->def_fps;
+ DBG_MSG("use default(%dx%d@%d)\n", p->resx,
+ p->resy, p->fps);
+ }
+ DBG_MSG("fb%d(%dx%d@%d)\n", i, p->resx, p->resy, p->fps);
+ }
+ DBG_DETAIL("Leave\n");
+}
+
+int vout_init(void)
+{
+ vout_t *vo;
+ int flag;
+ int i;
+ struct vout_init_parm_t init_parm;
+
+ DBG_DETAIL("Enter\n");
+
+ vout_init_param(&init_parm);
+
+ /* check vout info */
+ memset(vout_info, 0, sizeof(vout_info_t) * VPP_VOUT_INFO_NUM);
+ flag = vout_check_display_info(&init_parm);
+
+ /* probe external device */
+ vout_check_ext_device();
+
+ /* check plug & EDID for resolution */
+ if (flag)
+ vout_check_monitor_resolution(&init_parm);
+
+ if ((init_parm.virtual_display) || (g_vpp.dual_display == 0)) {
+ int plugin;
+
+ plugin = vout_chkplug(VPP_VOUT_NUM_HDMI);
+ vout_change_status(vout_get_entry(VPP_VOUT_NUM_HDMI),
+ VPP_VOUT_STS_BLANK, (plugin) ? 0 : 1);
+ vout_change_status(vout_get_entry(VPP_VOUT_NUM_DVI),
+ VPP_VOUT_STS_BLANK, (plugin) ? 1 : 0);
+ }
+
+ DBG_DETAIL("Set mode\n");
+ for (i = 0; i < VPP_VOUT_NUM; i++) {
+ vo = vout_get_entry(i);
+ if (vo && (vo->inf)) {
+ vout_inf_mode_t mode;
+
+ mode = vo->inf->mode;
+ vo->inf = 0; /* force interface init */
+ vout_set_mode(i, mode);
+ DBG_DETAIL("vout %d : inf %s, ext dev %s,status 0x%x\n",
+ i,
+ (vo->inf) ? vout_inf_str[vo->inf->mode] : "No",
+ (vo->dev) ? vo->dev->name : "No", vo->status);
+ }
+ }
+
+#ifndef CONFIG_UBOOT
+ for (i = 0; i < VPP_VOUT_NUM; i++) {
+ vo = vout_get_entry(i);
+ if (vo)
+ vout_set_blank((0x1 << i),
+ (vo->status & VPP_VOUT_STS_BLANK) ? 1 : 0);
+ }
+#endif
+
+ /* show vout info */
+ for (i = 0; i < VPP_VOUT_INFO_NUM; i++) {
+ vout_info_t *info;
+
+ info = &vout_info[i];
+ if (info->vo_mask == 0)
+ break;
+ if (i == 0) {
+ if (info->govr) {
+#ifdef WMT_FTBLK_GOVRH_CURSOR
+ p_cursor->mmio = info->govr->mmio;
+#endif
+ }
+ }
+ MSG("[VOUT] info %d,mask 0x%x,%s,%dx%d@%d\n", i, info->vo_mask,
+ (info->govr) ? vpp_mod_str[info->govr_mod] : "VIR",
+ info->resx, info->resy, info->fps);
+ }
+ DBG_DETAIL("Leave\n");
+ return 0;
+}
+
+int vout_exit(void)
+{
+ return 0;
+}