diff options
| author | Ujwal Patel <ujwalp@codeaurora.org> | 2012-08-22 05:12:03 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:12:11 -0700 |
| commit | c058172604e924fd71d414c9f7745e649e16e720 (patch) | |
| tree | 4f7226c2f33425300bddef79d6053d07cffe4444 /drivers/video/fbdev | |
| parent | 296c8620bde5ea927a1ba18eef9d24b02931ba56 (diff) | |
msm: mdss: Add support for HDMI Tx driver
This patch adds the HDMI Tx driver in mdss domain. It uses
device tree framework to get the platform data and then registers
this device as dtv panel to mdss frame buffer domain.
Change-Id: I55534919bacea5b044c1da5d44dda8db496e1528
Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
[cip@codeaurora.org: Moved new file locations,
replace regulator_set_optimum_mode with regulator_set_load,
add linux/regulator/consumer.h include]
Signed-off-by: Clarence Ip <cip@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/Makefile | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 1105 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.h | 93 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_util.c | 485 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_util.h | 400 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_io_util.c | 153 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_io_util.h | 50 |
8 files changed, 2297 insertions, 0 deletions
diff --git a/drivers/video/fbdev/msm/Kconfig b/drivers/video/fbdev/msm/Kconfig index 3b8fa3df1f98..09792bebaa66 100644 --- a/drivers/video/fbdev/msm/Kconfig +++ b/drivers/video/fbdev/msm/Kconfig @@ -939,4 +939,12 @@ config FB_MSM_MDSS_WRITEBACK The MDSS Writeback Panel provides support for routing the output of MDSS frame buffer driver and MDP processing to memory. +config FB_MSM_MDSS_HDMI_PANEL + depends on FB_MSM_MDSS + bool "MDSS HDMI Tx Panel" + default n + ---help--- + The MDSS HDMI Panel provides support for transmitting TMDS signals of + MDSS frame buffer data to connected hdmi compliant TVs, monitors etc. + endif diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile index b6294f41ec5d..6bc21bc13d69 100644 --- a/drivers/video/fbdev/msm/Makefile +++ b/drivers/video/fbdev/msm/Makefile @@ -7,10 +7,13 @@ mdss-mdp-objs += mdss_mdp_overlay.o mdss-mdp-objs += mdss_mdp_wb.o obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss_io_util.o mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss-dsi-objs += mdss_dsi_panel.o mdss-dsi-objs += msm_mdss_io_8974.o obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_util.o obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c new file mode 100644 index 000000000000..68fefed1193b --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -0,0 +1,1105 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_address.h> +#include <linux/of_gpio.h> +#include <linux/types.h> + +/* #define DEBUG */ + +#include "mdss_fb.h" +#include "mdss_hdmi_tx.h" +#include "mdss.h" +#include "mdss_panel.h" + +#define DRV_NAME "hdmi-tx" +#define COMPATIBLE_NAME "qcom,hdmi-tx" + +static irqreturn_t hdmi_tx_isr(int irq, void *data); + +struct mdss_hw hdmi_tx_hw = { + .hw_ndx = MDSS_HW_HDMI, + .ptr = NULL, + .irq_handler = hdmi_tx_isr, +}; + +const char *hdmi_pm_name(enum hdmi_tx_power_module_type module) +{ + switch (module) { + case HDMI_TX_HPD_PM: return "HDMI_TX_HPD_PM"; + case HDMI_TX_CORE_PM: return "HDMI_TX_CORE_PM"; + case HDMI_TX_CEC_PM: return "HDMI_TX_CEC_PM"; + default: return "???"; + } +} /* hdmi_pm_name */ + +static const char *hdmi_tx_clk_name(u32 clk) +{ + switch (clk) { + case HDMI_TX_AHB_CLK: return "hdmi_ahb_clk"; + case HDMI_TX_APP_CLK: return "hdmi_app_clk"; + case HDMI_TX_EXTP_CLK: return "hdmi_extp_clk"; + default: return "???"; + } +} /* hdmi_tx_clk_name */ + +static const char *hdmi_tx_io_name(u32 io) +{ + switch (io) { + case HDMI_TX_CORE_IO: return "core_physical"; + case HDMI_TX_PHY_IO: return "phy_physical"; + case HDMI_TX_QFPROM_IO: return "qfprom_physical"; + default: return NULL; + } +} /* hdmi_tx_io_name */ + +static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + return HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base, + HDMI_CTRL) & BIT(0); +} /* hdmi_tx_is_controller_on */ + +static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + return !(HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base, + HDMI_CTRL) & BIT(1)); +} /* hdmi_tx_is_dvi_mode */ + +static int hdmi_tx_init_panel_info(uint32_t resolution, + struct mdss_panel_info *pinfo) +{ + const struct hdmi_disp_mode_timing_type *timing = + hdmi_get_supported_mode(resolution); + + if (!timing || !pinfo) { + DEV_ERR("%s: invalid input.\n", __func__); + return -EINVAL; + } + + pinfo->xres = timing->active_h; + pinfo->yres = timing->active_v; + pinfo->clk_rate = timing->pixel_freq*1000; + + pinfo->lcdc.h_back_porch = timing->back_porch_h; + pinfo->lcdc.h_front_porch = timing->front_porch_h; + pinfo->lcdc.h_pulse_width = timing->pulse_width_h; + pinfo->lcdc.v_back_porch = timing->back_porch_v; + pinfo->lcdc.v_front_porch = timing->front_porch_v; + pinfo->lcdc.v_pulse_width = timing->pulse_width_v; + + pinfo->type = DTV_PANEL; + pinfo->pdest = DISPLAY_2; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + pinfo->fb_num = 1; + + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + + return 0; +} /* hdmi_tx_init_panel_info */ + +/* Table indicating the video format supported by the HDMI TX Core */ +/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */ +static void hdmi_tx_setup_video_mode_lut(void) +{ + hdmi_set_supported_mode(HDMI_VFRMT_640x480p60_4_3); + hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_4_3); + hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_720x576p50_4_3); + hdmi_set_supported_mode(HDMI_VFRMT_720x576p50_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1440x480i60_4_3); + hdmi_set_supported_mode(HDMI_VFRMT_1440x480i60_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1440x576i50_4_3); + hdmi_set_supported_mode(HDMI_VFRMT_1440x576i50_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1280x720p50_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1280x720p60_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p24_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p25_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p30_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p50_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1920x1080i60_16_9); + hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9); +} /* hdmi_tx_setup_video_mode_lut */ + +static void hdmi_tx_hpd_state_work(struct work_struct *work) +{ + u32 hpd_state = false; + struct hdmi_tx_ctrl *hdmi_ctrl = NULL; + struct hdmi_tx_io_data *io = NULL; + + hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_state_work); + if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) { + DEV_DBG("%s: invalid input\n", __func__); + return; + } + + io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; + DEV_DBG("%s: Got HPD interrupt\n", __func__); + + hpd_state = (HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1; + mutex_lock(&hdmi_ctrl->mutex); + if ((hdmi_ctrl->hpd_prev_state != hdmi_ctrl->hpd_state) || + (hdmi_ctrl->hpd_state != hpd_state)) { + + hdmi_ctrl->hpd_state = hpd_state; + hdmi_ctrl->hpd_prev_state = hdmi_ctrl->hpd_state; + hdmi_ctrl->hpd_stable = 0; + + DEV_DBG("%s: state not stable yet, wait again (%d|%d|%d)\n", + __func__, hdmi_ctrl->hpd_prev_state, + hdmi_ctrl->hpd_state, hpd_state); + + mutex_unlock(&hdmi_ctrl->mutex); + + mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2); + + return; + } + + if (hdmi_ctrl->hpd_stable) { + mutex_unlock(&hdmi_ctrl->mutex); + DEV_DBG("%s: no more timer, depending on IRQ now\n", + __func__); + return; + } + + hdmi_ctrl->hpd_stable = 1; + DEV_INFO("HDMI HPD: event detected\n"); + + /* + *todo: Revisit cable chg detected condition when HPD support is ready + */ + hdmi_ctrl->hpd_cable_chg_detected = false; + mutex_unlock(&hdmi_ctrl->mutex); + + if (hpd_state) { + DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n"); + kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE); + switch_set_state(&hdmi_ctrl->sdev, 1); + DEV_INFO("%s: Hdmi state switch to %d\n", __func__, + hdmi_ctrl->sdev.state); + } else { + DEV_INFO("HDMI HPD: sense DISCONNECTED: send OFFLINE\n"); + kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE); + switch_set_state(&hdmi_ctrl->sdev, 0); + DEV_INFO("%s: Hdmi state switch to %d\n", __func__, + hdmi_ctrl->sdev.state); + } + + /* Set IRQ for HPD */ + HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2)); +} /* hdmi_tx_hpd_state_work */ + +static int hdmi_tx_check_capability(void __iomem *base) +{ + u32 hdmi_disabled, hdcp_disabled; + + if (!base) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + /* QFPROM_RAW_FEAT_CONFIG_ROW0_LSB */ + hdcp_disabled = HDMI_REG_R_ND(base, 0x000000F8) & BIT(31); + /* QFPROM_RAW_FEAT_CONFIG_ROW0_MSB */ + hdmi_disabled = HDMI_REG_R_ND(base, 0x000000FC) & BIT(0); + + DEV_DBG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__, + hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON"); + + if (hdmi_disabled) { + DEV_ERR("%s: HDMI disabled\n", __func__); + return -ENODEV; + } + + if (hdcp_disabled) + DEV_WARN("%s: HDCP disabled\n", __func__); + + return 0; +} /* hdmi_tx_check_capability */ + +/* todo: revisit when new HPD debouncing logic is available */ +static void hdmi_tx_hpd_state_timer(unsigned long data) +{ + struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data; + + if (hdmi_ctrl) + queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_state_work); + else + DEV_ERR("%s: invalid input\n", __func__); +} /* hdmi_tx_hpd_state_timer */ + +static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata, + u32 clk_idx) +{ + if (!pdata || clk_idx > HDMI_TX_MAX_CLK) { + DEV_ERR("%s: invalid input\n", __func__); + return NULL; + } + + return pdata->clk[clk_idx]; +} /* hdmi_tx_get_clk */ + +static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata, + u32 clk_idx, unsigned long clk_rate) +{ + int rc = 0; + struct clk *clk = NULL; + + if (!pdata) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + clk = hdmi_tx_get_clk(pdata, clk_idx); + if (clk) { + rc = clk_set_rate(clk, clk_rate); + if (IS_ERR_VALUE(rc)) + DEV_ERR("%s: failed rc=%d\n", __func__, rc); + else + DEV_DBG("%s: clk=%d rate=%lu\n", __func__, + clk_idx, clk_rate); + } else { + DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx); + rc = -EINVAL; + } + + return rc; +} /* hdmi_tx_clk_set_rate */ + +static int hdmi_tx_power_on(struct mdss_panel_data *panel_data) +{ + return 0; +} /* hdmi_tx_power_on */ + +static int hdmi_tx_power_off(struct mdss_panel_data *panel_data) +{ + return 0; +} /* hdmi_tx_power_off */ + +static irqreturn_t hdmi_tx_isr(int irq, void *data) +{ + u32 hpd_int_status; + u32 hpd_int_ctrl; + struct hdmi_tx_io_data *io = NULL; + struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data; + + if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) { + DEV_WARN("%s: invalid input data, ISR ignored\n", __func__); + return IRQ_HANDLED; + } + + io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; + if (!io->base) { + DEV_WARN("%s: io not initialized, ISR ignored\n", __func__); + return IRQ_HANDLED; + } + + /* Process HPD Interrupt */ + hpd_int_status = HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS); + hpd_int_ctrl = HDMI_REG_R(io->base, HDMI_HPD_INT_CTRL); + if ((hpd_int_ctrl & BIT(2)) && (hpd_int_status & BIT(0))) { + u32 cable_detected = hpd_int_status & BIT(1); + + /* + * Clear all interrupts, timer will turn IRQ back on + * Leaving the bit[2] on, else core goes off + * on getting HPD during power off. + */ + HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, BIT(2) | BIT(0)); + + DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__, + hpd_int_ctrl, hpd_int_status); + + mutex_lock(&hdmi_ctrl->mutex); + hdmi_ctrl->hpd_cable_chg_detected = true; + hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1; + hdmi_ctrl->hpd_stable = 0; + mutex_unlock(&hdmi_ctrl->mutex); + + mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2); + + return IRQ_HANDLED; + } + + DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl, + hpd_int_status); + + return IRQ_HANDLED; +} /* hdmi_tx_isr */ + +static void hdmi_tx_clk_deinit(struct hdmi_tx_platform_data *pdata) +{ + int i; + if (!pdata) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + for (i = HDMI_TX_MAX_CLK - 1; i >= 0; i--) { + if (pdata->clk[i]) + clk_put(pdata->clk[i]); + pdata->clk[i] = NULL; + } +} /* hdmi_tx_clk_deinit */ + +static int hdmi_tx_clk_init(struct platform_device *pdev, + struct hdmi_tx_platform_data *pdata) +{ + int rc = 0; + struct device *dev = NULL; + struct clk *clk = NULL; + + if (!pdev || !pdata) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + dev = &pdev->dev; + + clk = clk_get(dev, "iface_clk"); + rc = IS_ERR(clk); + if (rc) { + DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__, + hdmi_tx_clk_name(HDMI_TX_AHB_CLK)); + goto error; + } + pdata->clk[HDMI_TX_AHB_CLK] = clk; + + clk = clk_get(dev, "core_clk"); + rc = IS_ERR(clk); + if (rc) { + DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__, + hdmi_tx_clk_name(HDMI_TX_APP_CLK)); + goto error; + } + pdata->clk[HDMI_TX_APP_CLK] = clk; + + clk = clk_get(dev, "extp_clk"); + rc = IS_ERR(clk); + if (rc) { + DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__, + hdmi_tx_clk_name(HDMI_TX_EXTP_CLK)); + goto error; + } + pdata->clk[HDMI_TX_EXTP_CLK] = clk; + + /* + * extpclk src is hdmi phy pll. This phy pll programming requires + * hdmi_ahb_clk. So enable it and then disable. + */ + rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]); + if (rc) { + DEV_ERR("%s: failed to enable '%s' clk\n", __func__, + hdmi_tx_clk_name(HDMI_TX_AHB_CLK)); + goto error; + } + rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK, + HDMI_TX_EXTP_CLK_DEFAULT); + if (rc) { + DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__, + hdmi_tx_clk_name(HDMI_TX_EXTP_CLK)); + clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]); + goto error; + } + clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]); + + return rc; + +error: + hdmi_tx_clk_deinit(pdata); + return rc; +} /* hdmi_tx_clk_init */ + +static void hdmi_tx_dev_deinit(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + switch_dev_unregister(&hdmi_ctrl->sdev); + del_timer(&hdmi_ctrl->hpd_state_timer); + if (hdmi_ctrl->workq) + destroy_workqueue(hdmi_ctrl->workq); + mutex_destroy(&hdmi_ctrl->mutex); + + hdmi_tx_hw.ptr = NULL; +} /* hdmi_tx_dev_deinit */ + +static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int rc = 0; + struct hdmi_tx_platform_data *pdata = NULL; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + pdata = &hdmi_ctrl->pdata; + + rc = hdmi_tx_check_capability(pdata->io[HDMI_TX_QFPROM_IO].base); + if (rc) { + DEV_ERR("%s: no HDMI device\n", __func__); + goto fail_no_hdmi; + } + + /* irq enable/disable will be handled in hpd on/off */ + hdmi_tx_hw.ptr = (void *)hdmi_ctrl; + + hdmi_tx_setup_video_mode_lut(); + mutex_init(&hdmi_ctrl->mutex); + hdmi_ctrl->workq = create_workqueue("hdmi_tx_workq"); + if (!hdmi_ctrl->workq) { + DEV_ERR("%s: hdmi_tx_workq creation failed.\n", __func__); + goto fail_create_workq; + } + + INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work); + init_timer(&hdmi_ctrl->hpd_state_timer); + hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer; + hdmi_ctrl->hpd_state_timer.data = (u32)hdmi_ctrl; + hdmi_ctrl->hpd_state_timer.expires = 0xffffffffL; + + hdmi_ctrl->sdev.name = "hdmi"; + if (switch_dev_register(&hdmi_ctrl->sdev) < 0) { + DEV_ERR("%s: Hdmi switch registration failed\n", __func__); + goto fail_switch_dev; + } + + return 0; + +fail_switch_dev: + del_timer(&hdmi_ctrl->hpd_state_timer); +fail_create_workq: + if (hdmi_ctrl->workq) + destroy_workqueue(hdmi_ctrl->workq); + mutex_destroy(&hdmi_ctrl->mutex); +fail_no_hdmi: + return rc; +} /* hdmi_tx_dev_init */ + +static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int rc = 0; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + hdmi_ctrl->panel_data.on = hdmi_tx_power_on; + hdmi_ctrl->panel_data.off = hdmi_tx_power_off; + + hdmi_ctrl->video_resolution = HDMI_VFRMT_1920x1080p60_16_9; + rc = hdmi_tx_init_panel_info(hdmi_ctrl->video_resolution, + &hdmi_ctrl->panel_data.panel_info); + if (rc) { + DEV_ERR("%s: hdmi_init_panel_info failed\n", __func__); + return rc; + } + + rc = mdss_register_panel(&hdmi_ctrl->panel_data); + if (rc) { + DEV_ERR("%s: FAILED: to register HDMI panel\n", __func__); + return rc; + } + + return rc; +} /* hdmi_tx_register_panel */ + +static void hdmi_tx_put_dt_vreg_data(struct device *dev, + struct dss_module_power *module_power) +{ + if (!module_power) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + if (module_power->vreg_config) { + devm_kfree(dev, module_power->vreg_config); + module_power->vreg_config = NULL; + } + module_power->num_vreg = 0; +} /* hdmi_tx_put_dt_vreg_data */ + +static int hdmi_tx_get_dt_vreg_data(struct device *dev, + struct dss_module_power *mp, u32 module_type) +{ + int i, j, rc = 0; + int dt_vreg_total = 0, mod_vreg_total = 0; + u32 ndx_mask = 0; + u32 *val_array = NULL; + const char *mod_name = NULL; + struct device_node *of_node = NULL; + char prop_name[32]; + + if (!dev || !mp) { + DEV_ERR("%s: invalid input\n", __func__); + rc = -EINVAL; + goto error; + } + + switch (module_type) { + case HDMI_TX_HPD_PM: + mod_name = "hpd"; + break; + case HDMI_TX_CORE_PM: + mod_name = "core"; + break; + case HDMI_TX_CEC_PM: + mod_name = "cec"; + break; + default: + DEV_ERR("%s: invalid module type=%d\n", __func__, + module_type); + return -EINVAL; + } + + DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type)); + + of_node = dev->of_node; + + memset(prop_name, 0, sizeof(prop_name)); + snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, "supply-names"); + dt_vreg_total = of_property_count_strings(of_node, prop_name); + if (dt_vreg_total < 0) { + DEV_ERR("%s: vreg not found. rc=%d\n", __func__, + dt_vreg_total); + rc = dt_vreg_total; + goto error; + } + + /* count how many vreg for particular hdmi module */ + for (i = 0; i < dt_vreg_total; i++) { + const char *st = NULL; + memset(prop_name, 0, sizeof(prop_name)); + snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, + "supply-names"); + rc = of_property_read_string_index(of_node, + prop_name, i, &st); + if (rc) { + DEV_ERR("%s: error reading name. i=%d, rc=%d\n", + __func__, i, rc); + goto error; + } + + if (strnstr(st, mod_name, strlen(st))) { + ndx_mask |= BIT(i); + mod_vreg_total++; + } + } + + if (mod_vreg_total > 0) { + mp->num_vreg = mod_vreg_total; + mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) * + mod_vreg_total, GFP_KERNEL); + if (!mp->vreg_config) { + DEV_ERR("%s: can't alloc '%s' vreg mem\n", __func__, + hdmi_pm_name(module_type)); + goto error; + } + } else { + DEV_DBG("%s: no vreg\n", __func__); + return 0; + } + + val_array = devm_kzalloc(dev, sizeof(u32) * dt_vreg_total, GFP_KERNEL); + if (!val_array) { + DEV_ERR("%s: can't allocate vreg scratch mem\n", __func__); + rc = -ENOMEM; + goto error; + } + + for (i = 0, j = 0; (i < dt_vreg_total) && (j < mod_vreg_total); i++) { + const char *st = NULL; + + if (!(ndx_mask & BIT(0))) { + ndx_mask >>= 1; + continue; + } + + /* vreg-name */ + memset(prop_name, 0, sizeof(prop_name)); + snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, + "supply-names"); + rc = of_property_read_string_index(of_node, + prop_name, i, &st); + if (rc) { + DEV_ERR("%s: error reading name. i=%d, rc=%d\n", + __func__, i, rc); + goto error; + } + snprintf(mp->vreg_config[j].vreg_name, 32, "%s", st); + + /* vreg-type */ + memset(prop_name, 0, sizeof(prop_name)); + snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, + "supply-type"); + memset(val_array, 0, sizeof(u32) * dt_vreg_total); + rc = of_property_read_u32_array(of_node, + prop_name, val_array, dt_vreg_total); + if (rc) { + DEV_ERR("%s: error read '%s' vreg type. rc=%d\n", + __func__, hdmi_pm_name(module_type), rc); + goto error; + } + mp->vreg_config[j].type = val_array[i]; + + /* vreg-min-voltage */ + memset(prop_name, 0, sizeof(prop_name)); + snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, + "min-voltage-level"); + memset(val_array, 0, sizeof(u32) * dt_vreg_total); + rc = of_property_read_u32_array(of_node, + prop_name, val_array, + dt_vreg_total); + if (rc) { + DEV_ERR("%s: error read '%s' min volt. rc=%d\n", + __func__, hdmi_pm_name(module_type), rc); + goto error; + } + mp->vreg_config[j].min_voltage = val_array[i]; + + /* vreg-max-voltage */ + memset(prop_name, 0, sizeof(prop_name)); + snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, + "max-voltage-level"); + memset(val_array, 0, sizeof(u32) * dt_vreg_total); + rc = of_property_read_u32_array(of_node, + prop_name, val_array, + dt_vreg_total); + if (rc) { + DEV_ERR("%s: error read '%s' max volt. rc=%d\n", + __func__, hdmi_pm_name(module_type), rc); + goto error; + } + mp->vreg_config[j].max_voltage = val_array[i]; + + /* vreg-op-mode */ + memset(prop_name, 0, sizeof(prop_name)); + snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, + "op-mode"); + memset(val_array, 0, sizeof(u32) * dt_vreg_total); + rc = of_property_read_u32_array(of_node, + prop_name, val_array, + dt_vreg_total); + if (rc) { + DEV_ERR("%s: error read '%s' min volt. rc=%d\n", + __func__, hdmi_pm_name(module_type), rc); + goto error; + } + mp->vreg_config[j].optimum_voltage = val_array[i]; + + DEV_DBG("%s: %s type=%d, min=%d, max=%d, op=%d\n", + __func__, mp->vreg_config[j].vreg_name, + mp->vreg_config[j].type, + mp->vreg_config[j].min_voltage, + mp->vreg_config[j].max_voltage, + mp->vreg_config[j].optimum_voltage); + + ndx_mask >>= 1; + j++; + } + + devm_kfree(dev, val_array); + + return rc; + +error: + for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--) + hdmi_tx_put_dt_vreg_data(dev, mp); + if (val_array) + devm_kfree(dev, val_array); + return rc; +} /* hdmi_tx_get_dt_vreg_data */ + +static void hdmi_tx_put_dt_gpio_data(struct device *dev, + struct dss_module_power *module_power) +{ + if (!module_power) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + if (module_power->gpio_config) { + devm_kfree(dev, module_power->gpio_config); + module_power->gpio_config = NULL; + } + module_power->num_gpio = 0; +} /* hdmi_tx_put_dt_gpio_data */ + +static int hdmi_tx_get_dt_gpio_data(struct device *dev, + struct dss_module_power *mp, u32 module_type) +{ + int i, j, rc = 0; + int dt_gpio_total = 0, mod_gpio_total = 0; + u32 ndx_mask = 0; + const char *mod_name = NULL; + struct device_node *of_node = NULL; + char prop_name[32]; + snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, "gpio-names"); + + if (!dev || !mp) { + DEV_ERR("%s: invalid input\n", __func__); + rc = -EINVAL; + goto error; + } + + switch (module_type) { + case HDMI_TX_HPD_PM: + mod_name = "hpd"; + break; + case HDMI_TX_CORE_PM: + mod_name = "core"; + break; + case HDMI_TX_CEC_PM: + mod_name = "cec"; + break; + default: + DEV_ERR("%s: invalid module type=%d\n", __func__, + module_type); + return -EINVAL; + } + + DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type)); + + of_node = dev->of_node; + + dt_gpio_total = of_gpio_count(of_node); + if (dt_gpio_total < 0) { + DEV_ERR("%s: gpio not found. rc=%d\n", __func__, + dt_gpio_total); + rc = dt_gpio_total; + goto error; + } + + /* count how many gpio for particular hdmi module */ + for (i = 0; i < dt_gpio_total; i++) { + const char *st = NULL; + + rc = of_property_read_string_index(of_node, + prop_name, i, &st); + if (rc) { + DEV_ERR("%s: error reading name. i=%d, rc=%d\n", + __func__, i, rc); + goto error; + } + + if (strnstr(st, mod_name, strlen(st))) { + ndx_mask |= BIT(i); + mod_gpio_total++; + continue; + } + } + + if (mod_gpio_total > 0) { + mp->num_gpio = mod_gpio_total; + mp->gpio_config = devm_kzalloc(dev, sizeof(struct dss_gpio) * + mod_gpio_total, GFP_KERNEL); + if (!mp->gpio_config) { + DEV_ERR("%s: can't alloc '%s' gpio mem\n", __func__, + hdmi_pm_name(module_type)); + goto error; + } + } else { + DEV_DBG("%s: no gpio\n", __func__); + return 0; + } + + + for (i = 0, j = 0; (i < dt_gpio_total) && (j < mod_gpio_total); i++) { + const char *st = NULL; + + if (!(ndx_mask & BIT(0))) { + ndx_mask >>= 1; + continue; + } + + /* gpio-name */ + rc = of_property_read_string_index(of_node, + prop_name, i, &st); + if (rc) { + DEV_ERR("%s: error reading name. i=%d, rc=%d\n", + __func__, i, rc); + goto error; + } + snprintf(mp->gpio_config[j].gpio_name, 32, "%s", st); + + /* gpio-number */ + mp->gpio_config[j].gpio = of_get_gpio(of_node, i); + + DEV_DBG("%s: gpio num=%d, name=%s\n", __func__, + mp->gpio_config[j].gpio, + mp->gpio_config[j].gpio_name); + + ndx_mask >>= 1; + j++; + } + + return rc; + +error: + for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--) + hdmi_tx_put_dt_gpio_data(dev, mp); + + return rc; +} /* hdmi_tx_get_dt_gpio_data */ + +static struct resource *hdmi_tx_get_res_byname(struct platform_device *pdev, + unsigned int type, const char *name) +{ + struct resource *res = NULL; + + res = platform_get_resource_byname(pdev, type, name); + if (!res) + DEV_ERR("%s: '%s' resource not found\n", __func__, name); + + return res; +} /* hdmi_tx_get_res_byname */ + +static int hdmi_tx_ioremap_byname(struct platform_device *pdev, + struct hdmi_tx_io_data *io_data, u32 io_type) +{ + struct resource *res = NULL; + + if (!pdev) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + res = hdmi_tx_get_res_byname(pdev, IORESOURCE_MEM, + hdmi_tx_io_name(io_type)); + if (!res) { + DEV_ERR("%s: '%s' hdmi_tx_get_res_byname failed\n", __func__, + hdmi_tx_io_name(io_type)); + return -ENODEV; + } + + io_data->len = resource_size(res); + io_data->base = ioremap(res->start, io_data->len); + if (!io_data->base) { + DEV_ERR("%s: '%s' ioremap failed\n", __func__, + hdmi_tx_io_name(io_type)); + return -EIO; + } + + return 0; +} /* hdmi_tx_ioremap_byname */ + +static void hdmi_tx_put_dt_data(struct device *dev, + struct hdmi_tx_platform_data *pdata) +{ + int i; + if (!dev || !pdata) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + hdmi_tx_clk_deinit(pdata); + + for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--) + hdmi_tx_put_dt_vreg_data(dev, &pdata->power_data[i]); + + for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--) + hdmi_tx_put_dt_gpio_data(dev, &pdata->power_data[i]); + + for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--) { + if (pdata->io[i].base) + iounmap(pdata->io[i].base); + pdata->io[i].base = NULL; + pdata->io[i].len = 0; + } +} /* hdmi_tx_put_dt_data */ + +static int hdmi_tx_get_dt_data(struct platform_device *pdev, + struct hdmi_tx_platform_data *pdata) +{ + int i, rc = 0; + struct device_node *of_node = NULL; + + if (!pdev || !pdata) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + of_node = pdev->dev.of_node; + + rc = of_property_read_u32(of_node, "cell-index", &pdev->id); + if (rc) { + DEV_ERR("%s: dev id from dt not found.rc=%d\n", + __func__, rc); + goto error; + } + DEV_DBG("%s: id=%d\n", __func__, pdev->id); + + /* IO */ + for (i = 0; i < HDMI_TX_MAX_IO; i++) { + rc = hdmi_tx_ioremap_byname(pdev, &pdata->io[i], i); + if (rc) { + DEV_ERR("%s: '%s' remap failed\n", __func__, + hdmi_tx_io_name(i)); + goto error; + } + DEV_INFO("%s: '%s': start = 0x%x, len=0x%x\n", __func__, + hdmi_tx_io_name(i), (u32)pdata->io[i].base, + pdata->io[i].len); + } + + /* GPIO */ + for (i = 0; i < HDMI_TX_MAX_PM; i++) { + rc = hdmi_tx_get_dt_gpio_data(&pdev->dev, + &pdata->power_data[i], i); + if (rc) { + DEV_ERR("%s: '%s' get_dt_gpio_data failed.rc=%d\n", + __func__, hdmi_pm_name(i), rc); + goto error; + } + } + + /* VREG */ + for (i = 0; i < HDMI_TX_MAX_PM; i++) { + rc = hdmi_tx_get_dt_vreg_data(&pdev->dev, + &pdata->power_data[i], i); + if (rc) { + DEV_ERR("%s: '%s' get_dt_vreg_data failed.rc=%d\n", + __func__, hdmi_pm_name(i), rc); + goto error; + } + } + + /* CLK */ + rc = hdmi_tx_clk_init(pdev, pdata); + if (rc) { + DEV_ERR("%s: FAILED: clk init. rc=%d\n", __func__, rc); + goto error; + } + + return rc; + +error: + hdmi_tx_put_dt_data(&pdev->dev, pdata); + return rc; +} /* hdmi_tx_get_dt_data */ + +static int hdmi_tx_probe(struct platform_device *pdev) +{ + int rc = 0; + struct device_node *of_node = pdev->dev.of_node; + struct hdmi_tx_ctrl *hdmi_ctrl = NULL; + + if (!of_node) { + DEV_ERR("%s: FAILED: of_node not found\n", __func__); + rc = -ENODEV; + return rc; + } + + hdmi_ctrl = devm_kzalloc(&pdev->dev, sizeof(*hdmi_ctrl), GFP_KERNEL); + if (!hdmi_ctrl) { + DEV_ERR("%s: FAILED: cannot alloc hdmi tx ctrl\n", __func__); + rc = -ENOMEM; + goto failed_no_mem; + } + + platform_set_drvdata(pdev, hdmi_ctrl); + hdmi_ctrl->pdev = pdev; + + rc = hdmi_tx_get_dt_data(pdev, &hdmi_ctrl->pdata); + if (rc) { + DEV_ERR("%s: FAILED: parsing device tree data. rc=%d\n", + __func__, rc); + goto failed_dt_data; + } + + rc = hdmi_tx_dev_init(hdmi_ctrl); + if (rc) { + DEV_ERR("%s: FAILED: hdmi_tx_dev_init. rc=%d\n", __func__, rc); + goto failed_dev_init; + } + + rc = hdmi_tx_register_panel(hdmi_ctrl); + if (rc) { + DEV_ERR("%s: FAILED: register_panel. rc=%d\n", __func__, rc); + goto failed_reg_panel; + } + + return rc; + +failed_reg_panel: + hdmi_tx_dev_deinit(hdmi_ctrl); +failed_dev_init: + hdmi_tx_put_dt_data(&pdev->dev, &hdmi_ctrl->pdata); +failed_dt_data: + devm_kfree(&pdev->dev, hdmi_ctrl); +failed_no_mem: + return rc; +} /* hdmi_tx_probe */ + +static int hdmi_tx_remove(struct platform_device *pdev) +{ + struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev); + if (!hdmi_ctrl) { + DEV_ERR("%s: no driver data\n", __func__); + return -ENODEV; + } + + hdmi_tx_dev_deinit(hdmi_ctrl); + hdmi_tx_put_dt_data(&pdev->dev, &hdmi_ctrl->pdata); + devm_kfree(&hdmi_ctrl->pdev->dev, hdmi_ctrl); + + return 0; +} /* hdmi_tx_remove */ + +static const struct of_device_id hdmi_tx_dt_match[] = { + {.compatible = COMPATIBLE_NAME,}, +}; +MODULE_DEVICE_TABLE(of, hdmi_tx_dt_match); + +static struct platform_driver this_driver = { + .probe = hdmi_tx_probe, + .remove = hdmi_tx_remove, + .driver = { + .name = DRV_NAME, + .of_match_table = hdmi_tx_dt_match, + }, +}; + +static int __init hdmi_tx_drv_init(void) +{ + int rc; + + rc = platform_driver_register(&this_driver); + if (rc) + DEV_ERR("%s: FAILED: rc=%d\n", __func__, rc); + + return rc; +} /* hdmi_tx_drv_init */ + +static void __exit hdmi_tx_drv_exit(void) +{ + platform_driver_unregister(&this_driver); +} /* hdmi_tx_drv_exit */ + +module_init(hdmi_tx_drv_init); +module_exit(hdmi_tx_drv_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.3"); +MODULE_DESCRIPTION("HDMI MSM TX driver"); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h new file mode 100644 index 000000000000..4a0685700c03 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __MDSS_HDMI_TX_H__ +#define __MDSS_HDMI_TX_H__ + +#include <linux/switch.h> +#include "mdss_hdmi_util.h" +#include "mdss_io_util.h" + +#define HDMI_TX_EXTP_CLK_DEFAULT 148500000 +#define HDMI_TX_EXTP_CLK_LOW 148500000 +#define HDMI_TX_EXTP_CLK_NOMINAL 297000000 +#define HDMI_TX_EXTP_CLK_TURBO 297000000 /* ToDo: Find correct value */ + +enum hdmi_tx_clk_type { + HDMI_TX_AHB_CLK, + HDMI_TX_APP_CLK, + HDMI_TX_EXTP_CLK, + HDMI_TX_MAX_CLK +}; + +enum hdmi_tx_io_type { + HDMI_TX_CORE_IO, + HDMI_TX_PHY_IO, + HDMI_TX_QFPROM_IO, + HDMI_TX_MAX_IO +}; + +enum hdmi_tx_power_module_type { + HDMI_TX_HPD_PM, + HDMI_TX_CORE_PM, + HDMI_TX_CEC_PM, + HDMI_TX_MAX_PM +}; + +struct hdmi_tx_io_data { + u32 len; + void __iomem *base; +}; + +struct hdmi_tx_platform_data { + /* Data filled from device tree nodes */ + struct hdmi_tx_io_data io[HDMI_TX_MAX_IO]; + struct dss_module_power power_data[HDMI_TX_MAX_PM]; + + /* clk and regulator handles */ + struct clk *clk[HDMI_TX_MAX_CLK]; +}; + +struct hdmi_tx_ctrl { + struct platform_device *pdev; + struct hdmi_tx_platform_data pdata; + struct mdss_panel_data panel_data; + + struct mutex mutex; + struct kobject *kobj; + struct switch_dev sdev; + struct workqueue_struct *workq; + + uint32_t video_resolution; + u32 panel_power_on; + + u32 hpd_initialized; + int hpd_stable; + u32 hpd_prev_state; + u32 hpd_cable_chg_detected; + u32 hpd_state; + u32 hpd_feature_on; + struct work_struct hpd_state_work; + struct timer_list hpd_state_timer; + + unsigned long pixel_clk; + u32 xres; + u32 yres; + u32 frame_rate; + + u32 present_hdcp; + + u8 spd_vendor_name[8]; + u8 spd_product_description[16]; +}; + +#endif /* __MDSS_HDMI_TX_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c new file mode 100644 index 000000000000..c7f899814d82 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -0,0 +1,485 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/io.h> +#include <mach/board.h> +#include "mdss_hdmi_util.h" + +const char *hdmi_reg_name(u32 offset) +{ + switch (offset) { + case 0x00000000: return "HDMI_CTRL"; + case 0x00000010: return "HDMI_TEST_PATTERN"; + case 0x00000014: return "HDMI_RANDOM_PATTERN"; + case 0x00000018: return "HDMI_PKT_BLK_CTRL"; + case 0x0000001C: return "HDMI_STATUS"; + case 0x00000020: return "HDMI_AUDIO_PKT_CTRL"; + case 0x00000024: return "HDMI_ACR_PKT_CTRL"; + case 0x00000028: return "HDMI_VBI_PKT_CTRL"; + case 0x0000002C: return "HDMI_INFOFRAME_CTRL0"; + case 0x00000030: return "HDMI_INFOFRAME_CTRL1"; + case 0x00000034: return "HDMI_GEN_PKT_CTRL"; + case 0x0000003C: return "HDMI_ACP"; + case 0x00000040: return "HDMI_GC"; + case 0x00000044: return "HDMI_AUDIO_PKT_CTRL2"; + case 0x00000048: return "HDMI_ISRC1_0"; + case 0x0000004C: return "HDMI_ISRC1_1"; + case 0x00000050: return "HDMI_ISRC1_2"; + case 0x00000054: return "HDMI_ISRC1_3"; + case 0x00000058: return "HDMI_ISRC1_4"; + case 0x0000005C: return "HDMI_ISRC2_0"; + case 0x00000060: return "HDMI_ISRC2_1"; + case 0x00000064: return "HDMI_ISRC2_2"; + case 0x00000068: return "HDMI_ISRC2_3"; + case 0x0000006C: return "HDMI_AVI_INFO0"; + case 0x00000070: return "HDMI_AVI_INFO1"; + case 0x00000074: return "HDMI_AVI_INFO2"; + case 0x00000078: return "HDMI_AVI_INFO3"; + case 0x0000007C: return "HDMI_MPEG_INFO0"; + case 0x00000080: return "HDMI_MPEG_INFO1"; + case 0x00000084: return "HDMI_GENERIC0_HDR"; + case 0x00000088: return "HDMI_GENERIC0_0"; + case 0x0000008C: return "HDMI_GENERIC0_1"; + case 0x00000090: return "HDMI_GENERIC0_2"; + case 0x00000094: return "HDMI_GENERIC0_3"; + case 0x00000098: return "HDMI_GENERIC0_4"; + case 0x0000009C: return "HDMI_GENERIC0_5"; + case 0x000000A0: return "HDMI_GENERIC0_6"; + case 0x000000A4: return "HDMI_GENERIC1_HDR"; + case 0x000000A8: return "HDMI_GENERIC1_0"; + case 0x000000AC: return "HDMI_GENERIC1_1"; + case 0x000000B0: return "HDMI_GENERIC1_2"; + case 0x000000B4: return "HDMI_GENERIC1_3"; + case 0x000000B8: return "HDMI_GENERIC1_4"; + case 0x000000BC: return "HDMI_GENERIC1_5"; + case 0x000000C0: return "HDMI_GENERIC1_6"; + case 0x000000C4: return "HDMI_ACR_32_0"; + case 0x000000C8: return "HDMI_ACR_32_1"; + case 0x000000CC: return "HDMI_ACR_44_0"; + case 0x000000D0: return "HDMI_ACR_44_1"; + case 0x000000D4: return "HDMI_ACR_48_0"; + case 0x000000D8: return "HDMI_ACR_48_1"; + case 0x000000DC: return "HDMI_ACR_STATUS_0"; + case 0x000000E0: return "HDMI_ACR_STATUS_1"; + case 0x000000E4: return "HDMI_AUDIO_INFO0"; + case 0x000000E8: return "HDMI_AUDIO_INFO1"; + case 0x000000EC: return "HDMI_CS_60958_0"; + case 0x000000F0: return "HDMI_CS_60958_1"; + case 0x000000F8: return "HDMI_RAMP_CTRL0"; + case 0x000000FC: return "HDMI_RAMP_CTRL1"; + case 0x00000100: return "HDMI_RAMP_CTRL2"; + case 0x00000104: return "HDMI_RAMP_CTRL3"; + case 0x00000108: return "HDMI_CS_60958_2"; + case 0x00000110: return "HDMI_HDCP_CTRL"; + case 0x00000114: return "HDMI_HDCP_DEBUG_CTRL"; + case 0x00000118: return "HDMI_HDCP_INT_CTRL"; + case 0x0000011C: return "HDMI_HDCP_LINK0_STATUS"; + case 0x00000120: return "HDMI_HDCP_DDC_CTRL_0"; + case 0x00000124: return "HDMI_HDCP_DDC_CTRL_1"; + case 0x00000128: return "HDMI_HDCP_DDC_STATUS"; + case 0x0000012C: return "HDMI_HDCP_ENTROPY_CTRL0"; + case 0x00000130: return "HDMI_HDCP_RESET"; + case 0x00000134: return "HDMI_HDCP_RCVPORT_DATA0"; + case 0x00000138: return "HDMI_HDCP_RCVPORT_DATA1"; + case 0x0000013C: return "HDMI_HDCP_RCVPORT_DATA2_0"; + case 0x00000140: return "HDMI_HDCP_RCVPORT_DATA2_1"; + case 0x00000144: return "HDMI_HDCP_RCVPORT_DATA3"; + case 0x00000148: return "HDMI_HDCP_RCVPORT_DATA4"; + case 0x0000014C: return "HDMI_HDCP_RCVPORT_DATA5"; + case 0x00000150: return "HDMI_HDCP_RCVPORT_DATA6"; + case 0x00000154: return "HDMI_HDCP_RCVPORT_DATA7"; + case 0x00000158: return "HDMI_HDCP_RCVPORT_DATA8"; + case 0x0000015C: return "HDMI_HDCP_RCVPORT_DATA9"; + case 0x00000160: return "HDMI_HDCP_RCVPORT_DATA10"; + case 0x00000164: return "HDMI_HDCP_RCVPORT_DATA11"; + case 0x00000168: return "HDMI_HDCP_RCVPORT_DATA12"; + case 0x0000016C: return "HDMI_VENSPEC_INFO0"; + case 0x00000170: return "HDMI_VENSPEC_INFO1"; + case 0x00000174: return "HDMI_VENSPEC_INFO2"; + case 0x00000178: return "HDMI_VENSPEC_INFO3"; + case 0x0000017C: return "HDMI_VENSPEC_INFO4"; + case 0x00000180: return "HDMI_VENSPEC_INFO5"; + case 0x00000184: return "HDMI_VENSPEC_INFO6"; + case 0x00000194: return "HDMI_HDCP_DEBUG"; + case 0x0000019C: return "HDMI_TMDS_CTRL_CHAR"; + case 0x000001A4: return "HDMI_TMDS_CTRL_SEL"; + case 0x000001A8: return "HDMI_TMDS_SYNCCHAR01"; + case 0x000001AC: return "HDMI_TMDS_SYNCCHAR23"; + case 0x000001B4: return "HDMI_TMDS_DEBUG"; + case 0x000001B8: return "HDMI_TMDS_CTL_BITS"; + case 0x000001BC: return "HDMI_TMDS_DCBAL_CTRL"; + case 0x000001C0: return "HDMI_TMDS_DCBAL_CHAR"; + case 0x000001C8: return "HDMI_TMDS_CTL01_GEN"; + case 0x000001CC: return "HDMI_TMDS_CTL23_GEN"; + case 0x000001D0: return "HDMI_AUDIO_CFG"; + case 0x00000204: return "HDMI_DEBUG"; + case 0x00000208: return "HDMI_USEC_REFTIMER"; + case 0x0000020C: return "HDMI_DDC_CTRL"; + case 0x00000210: return "HDMI_DDC_ARBITRATION"; + case 0x00000214: return "HDMI_DDC_INT_CTRL"; + case 0x00000218: return "HDMI_DDC_SW_STATUS"; + case 0x0000021C: return "HDMI_DDC_HW_STATUS"; + case 0x00000220: return "HDMI_DDC_SPEED"; + case 0x00000224: return "HDMI_DDC_SETUP"; + case 0x00000228: return "HDMI_DDC_TRANS0"; + case 0x0000022C: return "HDMI_DDC_TRANS1"; + case 0x00000230: return "HDMI_DDC_TRANS2"; + case 0x00000234: return "HDMI_DDC_TRANS3"; + case 0x00000238: return "HDMI_DDC_DATA"; + case 0x0000023C: return "HDMI_HDCP_SHA_CTRL"; + case 0x00000240: return "HDMI_HDCP_SHA_STATUS"; + case 0x00000244: return "HDMI_HDCP_SHA_DATA"; + case 0x00000248: return "HDMI_HDCP_SHA_DBG_M0_0"; + case 0x0000024C: return "HDMI_HDCP_SHA_DBG_M0_1"; + case 0x00000250: return "HDMI_HPD_INT_STATUS"; + case 0x00000254: return "HDMI_HPD_INT_CTRL"; + case 0x00000258: return "HDMI_HPD_CTRL"; + case 0x0000025C: return "HDMI_HDCP_ENTROPY_CTRL1"; + case 0x00000260: return "HDMI_HDCP_SW_UPPER_AN"; + case 0x00000264: return "HDMI_HDCP_SW_LOWER_AN"; + case 0x00000268: return "HDMI_CRC_CTRL"; + case 0x0000026C: return "HDMI_VID_CRC"; + case 0x00000270: return "HDMI_AUD_CRC"; + case 0x00000274: return "HDMI_VBI_CRC"; + case 0x0000027C: return "HDMI_DDC_REF"; + case 0x00000284: return "HDMI_HDCP_SW_UPPER_AKSV"; + case 0x00000288: return "HDMI_HDCP_SW_LOWER_AKSV"; + case 0x0000028C: return "HDMI_CEC_CTRL"; + case 0x00000290: return "HDMI_CEC_WR_DATA"; + case 0x00000294: return "HDMI_CEC_RETRANSMIT"; + case 0x00000298: return "HDMI_CEC_STATUS"; + case 0x0000029C: return "HDMI_CEC_INT"; + case 0x000002A0: return "HDMI_CEC_ADDR"; + case 0x000002A4: return "HDMI_CEC_TIME"; + case 0x000002A8: return "HDMI_CEC_REFTIMER"; + case 0x000002AC: return "HDMI_CEC_RD_DATA"; + case 0x000002B0: return "HDMI_CEC_RD_FILTER"; + case 0x000002B4: return "HDMI_ACTIVE_H"; + case 0x000002B8: return "HDMI_ACTIVE_V"; + case 0x000002BC: return "HDMI_ACTIVE_V_F2"; + case 0x000002C0: return "HDMI_TOTAL"; + case 0x000002C4: return "HDMI_V_TOTAL_F2"; + case 0x000002C8: return "HDMI_FRAME_CTRL"; + case 0x000002CC: return "HDMI_AUD_INT"; + case 0x000002D0: return "HDMI_DEBUG_BUS_CTRL"; + case 0x000002D4: return "HDMI_PHY_CTRL"; + case 0x000002DC: return "HDMI_CEC_WR_RANGE"; + case 0x000002E0: return "HDMI_CEC_RD_RANGE"; + case 0x000002E4: return "HDMI_VERSION"; + case 0x000002F4: return "HDMI_BIST_ENABLE"; + case 0x000002F8: return "HDMI_TIMING_ENGINE_EN"; + case 0x000002FC: return "HDMI_INTF_CONFIG"; + case 0x00000300: return "HDMI_HSYNC_CTL"; + case 0x00000304: return "HDMI_VSYNC_PERIOD_F0"; + case 0x00000308: return "HDMI_VSYNC_PERIOD_F1"; + case 0x0000030C: return "HDMI_VSYNC_PULSE_WIDTH_F0"; + case 0x00000310: return "HDMI_VSYNC_PULSE_WIDTH_F1"; + case 0x00000314: return "HDMI_DISPLAY_V_START_F0"; + case 0x00000318: return "HDMI_DISPLAY_V_START_F1"; + case 0x0000031C: return "HDMI_DISPLAY_V_END_F0"; + case 0x00000320: return "HDMI_DISPLAY_V_END_F1"; + case 0x00000324: return "HDMI_ACTIVE_V_START_F0"; + case 0x00000328: return "HDMI_ACTIVE_V_START_F1"; + case 0x0000032C: return "HDMI_ACTIVE_V_END_F0"; + case 0x00000330: return "HDMI_ACTIVE_V_END_F1"; + case 0x00000334: return "HDMI_DISPLAY_HCTL"; + case 0x00000338: return "HDMI_ACTIVE_HCTL"; + case 0x0000033C: return "HDMI_HSYNC_SKEW"; + case 0x00000340: return "HDMI_POLARITY_CTL"; + case 0x00000344: return "HDMI_TPG_MAIN_CONTROL"; + case 0x00000348: return "HDMI_TPG_VIDEO_CONFIG"; + case 0x0000034C: return "HDMI_TPG_COMPONENT_LIMITS"; + case 0x00000350: return "HDMI_TPG_RECTANGLE"; + case 0x00000354: return "HDMI_TPG_INITIAL_VALUE"; + case 0x00000358: return "HDMI_TPG_BLK_WHT_PATTERN_FRAMES"; + case 0x0000035C: return "HDMI_TPG_RGB_MAPPING"; + default: return "???"; + } +} /* hdmi_reg_name */ + +void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug) +{ + u32 in_val; + + writel_relaxed(value, addr+offset); + if (debug && PORT_DEBUG) { + in_val = readl_relaxed(addr+offset); + DEV_DBG("HDMI[%04x] => %08x [%08x] %s\n", offset, value, + in_val, hdmi_reg_name(offset)); + } +} /* hdmi_reg_w */ + +u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug) +{ + u32 value = readl_relaxed(addr+offset); + if (debug && PORT_DEBUG) + DEV_DBG("HDMI[%04x] <= %08x %s\n", offset, value, + hdmi_reg_name(offset)); + return value; +} /* hdmi_reg_r */ + +void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix) +{ + if (REG_DUMP) + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4, + (void *)base, length, false); +} /* hdmi_reg_dump */ + +static struct hdmi_disp_mode_timing_type + hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX] = { + HDMI_SETTINGS_640x480p60_4_3, + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p24_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p25_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p30_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9), +}; /* hdmi_supported_video_mode_lut */ + +#define HDMI_SETUP_LUT(MODE) do { \ + struct hdmi_disp_mode_timing_type mode = HDMI_SETTINGS_##MODE; \ + hdmi_supported_video_mode_lut[mode.video_format] = mode; \ + } while (0) + +const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode) +{ + const struct hdmi_disp_mode_timing_type *ret = NULL; + + if (mode >= HDMI_VFRMT_MAX) + return NULL; + + ret = &hdmi_supported_video_mode_lut[mode]; + + if (ret == NULL || !ret->supported) + return NULL; + + return ret; +} /* hdmi_get_supported_mode */ + +void hdmi_set_supported_mode(u32 mode) +{ + switch (mode) { + case HDMI_VFRMT_640x480p60_4_3: + HDMI_SETUP_LUT(640x480p60_4_3); + break; + case HDMI_VFRMT_720x480p60_4_3: + HDMI_SETUP_LUT(720x480p60_4_3); + break; + case HDMI_VFRMT_720x480p60_16_9: + HDMI_SETUP_LUT(720x480p60_16_9); + break; + case HDMI_VFRMT_720x576p50_4_3: + HDMI_SETUP_LUT(720x576p50_4_3); + break; + case HDMI_VFRMT_720x576p50_16_9: + HDMI_SETUP_LUT(720x576p50_16_9); + break; + case HDMI_VFRMT_1440x480i60_4_3: + HDMI_SETUP_LUT(1440x480i60_4_3); + break; + case HDMI_VFRMT_1440x480i60_16_9: + HDMI_SETUP_LUT(1440x480i60_16_9); + break; + case HDMI_VFRMT_1440x576i50_4_3: + HDMI_SETUP_LUT(1440x576i50_4_3); + break; + case HDMI_VFRMT_1440x576i50_16_9: + HDMI_SETUP_LUT(1440x576i50_16_9); + break; + case HDMI_VFRMT_1280x720p50_16_9: + HDMI_SETUP_LUT(1280x720p50_16_9); + break; + case HDMI_VFRMT_1280x720p60_16_9: + HDMI_SETUP_LUT(1280x720p60_16_9); + break; + case HDMI_VFRMT_1920x1080p24_16_9: + HDMI_SETUP_LUT(1920x1080p24_16_9); + break; + case HDMI_VFRMT_1920x1080p25_16_9: + HDMI_SETUP_LUT(1920x1080p25_16_9); + break; + case HDMI_VFRMT_1920x1080p30_16_9: + HDMI_SETUP_LUT(1920x1080p30_16_9); + break; + case HDMI_VFRMT_1920x1080p50_16_9: + HDMI_SETUP_LUT(1920x1080p50_16_9); + break; + case HDMI_VFRMT_1920x1080i60_16_9: + HDMI_SETUP_LUT(1920x1080i60_16_9); + break; + case HDMI_VFRMT_1920x1080p60_16_9: + HDMI_SETUP_LUT(1920x1080p60_16_9); + break; + default: + DEV_ERR("%s: unsupported mode=%d\n", __func__, mode); + } +} /* hdmi_set_supported_mode */ + +const char *hdmi_get_video_fmt_2string(u32 format) +{ + switch (format) { + case HDMI_VFRMT_640x480p60_4_3: return " 640x 480 p60 4/3"; + case HDMI_VFRMT_720x480p60_4_3: return " 720x 480 p60 4/3"; + case HDMI_VFRMT_720x480p60_16_9: return " 720x 480 p60 16/9"; + case HDMI_VFRMT_1280x720p60_16_9: return "1280x 720 p60 16/9"; + case HDMI_VFRMT_1920x1080i60_16_9: return "1920x1080 i60 16/9"; + case HDMI_VFRMT_1440x480i60_4_3: return "1440x 480 i60 4/3"; + case HDMI_VFRMT_1440x480i60_16_9: return "1440x 480 i60 16/9"; + case HDMI_VFRMT_1440x240p60_4_3: return "1440x 240 p60 4/3"; + case HDMI_VFRMT_1440x240p60_16_9: return "1440x 240 p60 16/9"; + case HDMI_VFRMT_2880x480i60_4_3: return "2880x 480 i60 4/3"; + case HDMI_VFRMT_2880x480i60_16_9: return "2880x 480 i60 16/9"; + case HDMI_VFRMT_2880x240p60_4_3: return "2880x 240 p60 4/3"; + case HDMI_VFRMT_2880x240p60_16_9: return "2880x 240 p60 16/9"; + case HDMI_VFRMT_1440x480p60_4_3: return "1440x 480 p60 4/3"; + case HDMI_VFRMT_1440x480p60_16_9: return "1440x 480 p60 16/9"; + case HDMI_VFRMT_1920x1080p60_16_9: return "1920x1080 p60 16/9"; + case HDMI_VFRMT_720x576p50_4_3: return " 720x 576 p50 4/3"; + case HDMI_VFRMT_720x576p50_16_9: return " 720x 576 p50 16/9"; + case HDMI_VFRMT_1280x720p50_16_9: return "1280x 720 p50 16/9"; + case HDMI_VFRMT_1920x1080i50_16_9: return "1920x1080 i50 16/9"; + case HDMI_VFRMT_1440x576i50_4_3: return "1440x 576 i50 4/3"; + case HDMI_VFRMT_1440x576i50_16_9: return "1440x 576 i50 16/9"; + case HDMI_VFRMT_1440x288p50_4_3: return "1440x 288 p50 4/3"; + case HDMI_VFRMT_1440x288p50_16_9: return "1440x 288 p50 16/9"; + case HDMI_VFRMT_2880x576i50_4_3: return "2880x 576 i50 4/3"; + case HDMI_VFRMT_2880x576i50_16_9: return "2880x 576 i50 16/9"; + case HDMI_VFRMT_2880x288p50_4_3: return "2880x 288 p50 4/3"; + case HDMI_VFRMT_2880x288p50_16_9: return "2880x 288 p50 16/9"; + case HDMI_VFRMT_1440x576p50_4_3: return "1440x 576 p50 4/3"; + case HDMI_VFRMT_1440x576p50_16_9: return "1440x 576 p50 16/9"; + case HDMI_VFRMT_1920x1080p50_16_9: return "1920x1080 p50 16/9"; + case HDMI_VFRMT_1920x1080p24_16_9: return "1920x1080 p24 16/9"; + case HDMI_VFRMT_1920x1080p25_16_9: return "1920x1080 p25 16/9"; + case HDMI_VFRMT_1920x1080p30_16_9: return "1920x1080 p30 16/9"; + case HDMI_VFRMT_2880x480p60_4_3: return "2880x 480 p60 4/3"; + case HDMI_VFRMT_2880x480p60_16_9: return "2880x 480 p60 16/9"; + case HDMI_VFRMT_2880x576p50_4_3: return "2880x 576 p50 4/3"; + case HDMI_VFRMT_2880x576p50_16_9: return "2880x 576 p50 16/9"; + case HDMI_VFRMT_1920x1250i50_16_9: return "1920x1250 i50 16/9"; + case HDMI_VFRMT_1920x1080i100_16_9:return "1920x1080 i100 16/9"; + case HDMI_VFRMT_1280x720p100_16_9: return "1280x 720 p100 16/9"; + case HDMI_VFRMT_720x576p100_4_3: return " 720x 576 p100 4/3"; + case HDMI_VFRMT_720x576p100_16_9: return " 720x 576 p100 16/9"; + case HDMI_VFRMT_1440x576i100_4_3: return "1440x 576 i100 4/3"; + case HDMI_VFRMT_1440x576i100_16_9: return "1440x 576 i100 16/9"; + case HDMI_VFRMT_1920x1080i120_16_9:return "1920x1080 i120 16/9"; + case HDMI_VFRMT_1280x720p120_16_9: return "1280x 720 p120 16/9"; + case HDMI_VFRMT_720x480p120_4_3: return " 720x 480 p120 4/3"; + case HDMI_VFRMT_720x480p120_16_9: return " 720x 480 p120 16/9"; + case HDMI_VFRMT_1440x480i120_4_3: return "1440x 480 i120 4/3"; + case HDMI_VFRMT_1440x480i120_16_9: return "1440x 480 i120 16/9"; + case HDMI_VFRMT_720x576p200_4_3: return " 720x 576 p200 4/3"; + case HDMI_VFRMT_720x576p200_16_9: return " 720x 576 p200 16/9"; + case HDMI_VFRMT_1440x576i200_4_3: return "1440x 576 i200 4/3"; + case HDMI_VFRMT_1440x576i200_16_9: return "1440x 576 i200 16/9"; + case HDMI_VFRMT_720x480p240_4_3: return " 720x 480 p240 4/3"; + case HDMI_VFRMT_720x480p240_16_9: return " 720x 480 p240 16/9"; + case HDMI_VFRMT_1440x480i240_4_3: return "1440x 480 i240 4/3"; + case HDMI_VFRMT_1440x480i240_16_9: return "1440x 480 i240 16/9"; + default: return "???"; + } +} /* hdmi_get_video_fmt_2string */ + +const char *hdmi_get_single_video_3d_fmt_2string(u32 format) +{ + switch (format) { + case TOP_AND_BOTTOM: return "TAB"; + case FRAME_PACKING: return "FP"; + case SIDE_BY_SIDE_HALF: return "SSH"; + } + return ""; +} /* hdmi_get_single_video_3d_fmt_2string */ + +ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf) +{ + ssize_t ret, len = 0; + ret = snprintf(buf, PAGE_SIZE, "%s", + hdmi_get_single_video_3d_fmt_2string( + format & FRAME_PACKING)); + len += ret; + + if (len && (format & TOP_AND_BOTTOM)) + ret = snprintf(buf + len, PAGE_SIZE, ":%s", + hdmi_get_single_video_3d_fmt_2string( + format & TOP_AND_BOTTOM)); + else + ret = snprintf(buf + len, PAGE_SIZE, "%s", + hdmi_get_single_video_3d_fmt_2string( + format & TOP_AND_BOTTOM)); + len += ret; + + if (len && (format & SIDE_BY_SIDE_HALF)) + ret = snprintf(buf + len, PAGE_SIZE, ":%s", + hdmi_get_single_video_3d_fmt_2string( + format & SIDE_BY_SIDE_HALF)); + else + ret = snprintf(buf + len, PAGE_SIZE, "%s", + hdmi_get_single_video_3d_fmt_2string( + format & SIDE_BY_SIDE_HALF)); + len += ret; + + return len; +} /* hdmi_get_video_3d_fmt_2string */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h new file mode 100644 index 000000000000..db76bfd3cffa --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -0,0 +1,400 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __HDMI_UTIL_H__ +#define __HDMI_UTIL_H__ + +#define DEV_INFO(fmt, args...) pr_info(fmt, ##args) +#define DEV_WARN(fmt, args...) pr_warn(fmt, ##args) +#define DEV_ERR(fmt, args...) pr_err(fmt, ##args) + +#ifdef DEBUG +#define DEV_DBG(fmt, args...) pr_err(fmt, ##args) +#else +#define DEV_DBG(args...) (void)0 +#endif + +#define PORT_DEBUG 0 +#define REG_DUMP 0 +void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug); +u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug); + +#define HDMI_REG_W_ND(addr, offset, val) hdmi_reg_w(addr, offset, val, false) +#define HDMI_REG_W(addr, offset, val) hdmi_reg_w(addr, offset, val, true) +#define HDMI_REG_R_ND(addr, offset) hdmi_reg_r(addr, offset, false) +#define HDMI_REG_R(addr, offset) hdmi_reg_r(addr, offset, true) + +/* HDMI_TX Registers */ +#define HDMI_CTRL (0x00000000) +#define HDMI_TEST_PATTERN (0x00000010) +#define HDMI_RANDOM_PATTERN (0x00000014) +#define HDMI_PKT_BLK_CTRL (0x00000018) +#define HDMI_STATUS (0x0000001C) +#define HDMI_AUDIO_PKT_CTRL (0x00000020) +#define HDMI_ACR_PKT_CTRL (0x00000024) +#define HDMI_VBI_PKT_CTRL (0x00000028) +#define HDMI_INFOFRAME_CTRL0 (0x0000002C) +#define HDMI_INFOFRAME_CTRL1 (0x00000030) +#define HDMI_GEN_PKT_CTRL (0x00000034) +#define HDMI_ACP (0x0000003C) +#define HDMI_GC (0x00000040) +#define HDMI_AUDIO_PKT_CTRL2 (0x00000044) +#define HDMI_ISRC1_0 (0x00000048) +#define HDMI_ISRC1_1 (0x0000004C) +#define HDMI_ISRC1_2 (0x00000050) +#define HDMI_ISRC1_3 (0x00000054) +#define HDMI_ISRC1_4 (0x00000058) +#define HDMI_ISRC2_0 (0x0000005C) +#define HDMI_ISRC2_1 (0x00000060) +#define HDMI_ISRC2_2 (0x00000064) +#define HDMI_ISRC2_3 (0x00000068) +#define HDMI_AVI_INFO0 (0x0000006C) +#define HDMI_AVI_INFO1 (0x00000070) +#define HDMI_AVI_INFO2 (0x00000074) +#define HDMI_AVI_INFO3 (0x00000078) +#define HDMI_MPEG_INFO0 (0x0000007C) +#define HDMI_MPEG_INFO1 (0x00000080) +#define HDMI_GENERIC0_HDR (0x00000084) +#define HDMI_GENERIC0_0 (0x00000088) +#define HDMI_GENERIC0_1 (0x0000008C) +#define HDMI_GENERIC0_2 (0x00000090) +#define HDMI_GENERIC0_3 (0x00000094) +#define HDMI_GENERIC0_4 (0x00000098) +#define HDMI_GENERIC0_5 (0x0000009C) +#define HDMI_GENERIC0_6 (0x000000A0) +#define HDMI_GENERIC1_HDR (0x000000A4) +#define HDMI_GENERIC1_0 (0x000000A8) +#define HDMI_GENERIC1_1 (0x000000AC) +#define HDMI_GENERIC1_2 (0x000000B0) +#define HDMI_GENERIC1_3 (0x000000B4) +#define HDMI_GENERIC1_4 (0x000000B8) +#define HDMI_GENERIC1_5 (0x000000BC) +#define HDMI_GENERIC1_6 (0x000000C0) +#define HDMI_ACR_32_0 (0x000000C4) +#define HDMI_ACR_32_1 (0x000000C8) +#define HDMI_ACR_44_0 (0x000000CC) +#define HDMI_ACR_44_1 (0x000000D0) +#define HDMI_ACR_48_0 (0x000000D4) +#define HDMI_ACR_48_1 (0x000000D8) +#define HDMI_ACR_STATUS_0 (0x000000DC) +#define HDMI_ACR_STATUS_1 (0x000000E0) +#define HDMI_AUDIO_INFO0 (0x000000E4) +#define HDMI_AUDIO_INFO1 (0x000000E8) +#define HDMI_CS_60958_0 (0x000000EC) +#define HDMI_CS_60958_1 (0x000000F0) +#define HDMI_RAMP_CTRL0 (0x000000F8) +#define HDMI_RAMP_CTRL1 (0x000000FC) +#define HDMI_RAMP_CTRL2 (0x00000100) +#define HDMI_RAMP_CTRL3 (0x00000104) +#define HDMI_CS_60958_2 (0x00000108) +#define HDMI_HDCP_CTRL (0x00000110) +#define HDMI_HDCP_DEBUG_CTRL (0x00000114) +#define HDMI_HDCP_INT_CTRL (0x00000118) +#define HDMI_HDCP_LINK0_STATUS (0x0000011C) +#define HDMI_HDCP_DDC_CTRL_0 (0x00000120) +#define HDMI_HDCP_DDC_CTRL_1 (0x00000124) +#define HDMI_HDCP_DDC_STATUS (0x00000128) +#define HDMI_HDCP_ENTROPY_CTRL0 (0x0000012C) +#define HDMI_HDCP_RESET (0x00000130) +#define HDMI_HDCP_RCVPORT_DATA0 (0x00000134) +#define HDMI_HDCP_RCVPORT_DATA1 (0x00000138) +#define HDMI_HDCP_RCVPORT_DATA2_0 (0x0000013C) +#define HDMI_HDCP_RCVPORT_DATA2_1 (0x00000140) +#define HDMI_HDCP_RCVPORT_DATA3 (0x00000144) +#define HDMI_HDCP_RCVPORT_DATA4 (0x00000148) +#define HDMI_HDCP_RCVPORT_DATA5 (0x0000014C) +#define HDMI_HDCP_RCVPORT_DATA6 (0x00000150) +#define HDMI_HDCP_RCVPORT_DATA7 (0x00000154) +#define HDMI_HDCP_RCVPORT_DATA8 (0x00000158) +#define HDMI_HDCP_RCVPORT_DATA9 (0x0000015C) +#define HDMI_HDCP_RCVPORT_DATA10 (0x00000160) +#define HDMI_HDCP_RCVPORT_DATA11 (0x00000164) +#define HDMI_HDCP_RCVPORT_DATA12 (0x00000168) +#define HDMI_VENSPEC_INFO0 (0x0000016C) +#define HDMI_VENSPEC_INFO1 (0x00000170) +#define HDMI_VENSPEC_INFO2 (0x00000174) +#define HDMI_VENSPEC_INFO3 (0x00000178) +#define HDMI_VENSPEC_INFO4 (0x0000017C) +#define HDMI_VENSPEC_INFO5 (0x00000180) +#define HDMI_VENSPEC_INFO6 (0x00000184) +#define HDMI_HDCP_DEBUG (0x00000194) +#define HDMI_TMDS_CTRL_CHAR (0x0000019C) +#define HDMI_TMDS_CTRL_SEL (0x000001A4) +#define HDMI_TMDS_SYNCCHAR01 (0x000001A8) +#define HDMI_TMDS_SYNCCHAR23 (0x000001AC) +#define HDMI_TMDS_DEBUG (0x000001B4) +#define HDMI_TMDS_CTL_BITS (0x000001B8) +#define HDMI_TMDS_DCBAL_CTRL (0x000001BC) +#define HDMI_TMDS_DCBAL_CHAR (0x000001C0) +#define HDMI_TMDS_CTL01_GEN (0x000001C8) +#define HDMI_TMDS_CTL23_GEN (0x000001CC) +#define HDMI_AUDIO_CFG (0x000001D0) +#define HDMI_DEBUG (0x00000204) +#define HDMI_USEC_REFTIMER (0x00000208) +#define HDMI_DDC_CTRL (0x0000020C) +#define HDMI_DDC_ARBITRATION (0x00000210) +#define HDMI_DDC_INT_CTRL (0x00000214) +#define HDMI_DDC_SW_STATUS (0x00000218) +#define HDMI_DDC_HW_STATUS (0x0000021C) +#define HDMI_DDC_SPEED (0x00000220) +#define HDMI_DDC_SETUP (0x00000224) +#define HDMI_DDC_TRANS0 (0x00000228) +#define HDMI_DDC_TRANS1 (0x0000022C) +#define HDMI_DDC_TRANS2 (0x00000230) +#define HDMI_DDC_TRANS3 (0x00000234) +#define HDMI_DDC_DATA (0x00000238) +#define HDMI_HDCP_SHA_CTRL (0x0000023C) +#define HDMI_HDCP_SHA_STATUS (0x00000240) +#define HDMI_HDCP_SHA_DATA (0x00000244) +#define HDMI_HDCP_SHA_DBG_M0_0 (0x00000248) +#define HDMI_HDCP_SHA_DBG_M0_1 (0x0000024C) +#define HDMI_HPD_INT_STATUS (0x00000250) +#define HDMI_HPD_INT_CTRL (0x00000254) +#define HDMI_HPD_CTRL (0x00000258) +#define HDMI_HDCP_ENTROPY_CTRL1 (0x0000025C) +#define HDMI_HDCP_SW_UPPER_AN (0x00000260) +#define HDMI_HDCP_SW_LOWER_AN (0x00000264) +#define HDMI_CRC_CTRL (0x00000268) +#define HDMI_VID_CRC (0x0000026C) +#define HDMI_AUD_CRC (0x00000270) +#define HDMI_VBI_CRC (0x00000274) +#define HDMI_DDC_REF (0x0000027C) +#define HDMI_HDCP_SW_UPPER_AKSV (0x00000284) +#define HDMI_HDCP_SW_LOWER_AKSV (0x00000288) +#define HDMI_CEC_CTRL (0x0000028C) +#define HDMI_CEC_WR_DATA (0x00000290) +#define HDMI_CEC_RETRANSMIT (0x00000294) +#define HDMI_CEC_STATUS (0x00000298) +#define HDMI_CEC_INT (0x0000029C) +#define HDMI_CEC_ADDR (0x000002A0) +#define HDMI_CEC_TIME (0x000002A4) +#define HDMI_CEC_REFTIMER (0x000002A8) +#define HDMI_CEC_RD_DATA (0x000002AC) +#define HDMI_CEC_RD_FILTER (0x000002B0) +#define HDMI_ACTIVE_H (0x000002B4) +#define HDMI_ACTIVE_V (0x000002B8) +#define HDMI_ACTIVE_V_F2 (0x000002BC) +#define HDMI_TOTAL (0x000002C0) +#define HDMI_V_TOTAL_F2 (0x000002C4) +#define HDMI_FRAME_CTRL (0x000002C8) +#define HDMI_AUD_INT (0x000002CC) +#define HDMI_DEBUG_BUS_CTRL (0x000002D0) +#define HDMI_PHY_CTRL (0x000002D4) +#define HDMI_CEC_WR_RANGE (0x000002DC) +#define HDMI_CEC_RD_RANGE (0x000002E0) +#define HDMI_VERSION (0x000002E4) +#define HDMI_BIST_ENABLE (0x000002F4) +#define HDMI_TIMING_ENGINE_EN (0x000002F8) +#define HDMI_INTF_CONFIG (0x000002FC) +#define HDMI_HSYNC_CTL (0x00000300) +#define HDMI_VSYNC_PERIOD_F0 (0x00000304) +#define HDMI_VSYNC_PERIOD_F1 (0x00000308) +#define HDMI_VSYNC_PULSE_WIDTH_F0 (0x0000030C) +#define HDMI_VSYNC_PULSE_WIDTH_F1 (0x00000310) +#define HDMI_DISPLAY_V_START_F0 (0x00000314) +#define HDMI_DISPLAY_V_START_F1 (0x00000318) +#define HDMI_DISPLAY_V_END_F0 (0x0000031C) +#define HDMI_DISPLAY_V_END_F1 (0x00000320) +#define HDMI_ACTIVE_V_START_F0 (0x00000324) +#define HDMI_ACTIVE_V_START_F1 (0x00000328) +#define HDMI_ACTIVE_V_END_F0 (0x0000032C) +#define HDMI_ACTIVE_V_END_F1 (0x00000330) +#define HDMI_DISPLAY_HCTL (0x00000334) +#define HDMI_ACTIVE_HCTL (0x00000338) +#define HDMI_HSYNC_SKEW (0x0000033C) +#define HDMI_POLARITY_CTL (0x00000340) +#define HDMI_TPG_MAIN_CONTROL (0x00000344) +#define HDMI_TPG_VIDEO_CONFIG (0x00000348) +#define HDMI_TPG_COMPONENT_LIMITS (0x0000034C) +#define HDMI_TPG_RECTANGLE (0x00000350) +#define HDMI_TPG_INITIAL_VALUE (0x00000354) +#define HDMI_TPG_BLK_WHT_PATTERN_FRAMES (0x00000358) +#define HDMI_TPG_RGB_MAPPING (0x0000035C) + +/* HDMI PHY Registers, use them with PHY base and _ND macro */ +#define HDMI_PHY_ANA_CFG0 (0x00000000) +#define HDMI_PHY_ANA_CFG1 (0x00000004) +#define HDMI_PHY_PD_CTRL0 (0x00000010) +#define HDMI_PHY_PD_CTRL1 (0x00000014) +#define HDMI_PHY_BIST_CFG0 (0x00000034) +#define HDMI_PHY_BIST_PATN0 (0x0000003C) +#define HDMI_PHY_BIST_PATN1 (0x00000040) +#define HDMI_PHY_BIST_PATN2 (0x00000044) +#define HDMI_PHY_BIST_PATN3 (0x00000048) + +/* all video formats defined by EIA CEA 861D */ +#define HDMI_VFRMT_640x480p60_4_3 0 +#define HDMI_VFRMT_720x480p60_4_3 1 +#define HDMI_VFRMT_720x480p60_16_9 2 +#define HDMI_VFRMT_1280x720p60_16_9 3 +#define HDMI_VFRMT_1920x1080i60_16_9 4 +#define HDMI_VFRMT_720x480i60_4_3 5 +#define HDMI_VFRMT_1440x480i60_4_3 HDMI_VFRMT_720x480i60_4_3 +#define HDMI_VFRMT_720x480i60_16_9 6 +#define HDMI_VFRMT_1440x480i60_16_9 HDMI_VFRMT_720x480i60_16_9 +#define HDMI_VFRMT_720x240p60_4_3 7 +#define HDMI_VFRMT_1440x240p60_4_3 HDMI_VFRMT_720x240p60_4_3 +#define HDMI_VFRMT_720x240p60_16_9 8 +#define HDMI_VFRMT_1440x240p60_16_9 HDMI_VFRMT_720x240p60_16_9 +#define HDMI_VFRMT_2880x480i60_4_3 9 +#define HDMI_VFRMT_2880x480i60_16_9 10 +#define HDMI_VFRMT_2880x240p60_4_3 11 +#define HDMI_VFRMT_2880x240p60_16_9 12 +#define HDMI_VFRMT_1440x480p60_4_3 13 +#define HDMI_VFRMT_1440x480p60_16_9 14 +#define HDMI_VFRMT_1920x1080p60_16_9 15 +#define HDMI_VFRMT_720x576p50_4_3 16 +#define HDMI_VFRMT_720x576p50_16_9 17 +#define HDMI_VFRMT_1280x720p50_16_9 18 +#define HDMI_VFRMT_1920x1080i50_16_9 19 +#define HDMI_VFRMT_720x576i50_4_3 20 +#define HDMI_VFRMT_1440x576i50_4_3 HDMI_VFRMT_720x576i50_4_3 +#define HDMI_VFRMT_720x576i50_16_9 21 +#define HDMI_VFRMT_1440x576i50_16_9 HDMI_VFRMT_720x576i50_16_9 +#define HDMI_VFRMT_720x288p50_4_3 22 +#define HDMI_VFRMT_1440x288p50_4_3 HDMI_VFRMT_720x288p50_4_3 +#define HDMI_VFRMT_720x288p50_16_9 23 +#define HDMI_VFRMT_1440x288p50_16_9 HDMI_VFRMT_720x288p50_16_9 +#define HDMI_VFRMT_2880x576i50_4_3 24 +#define HDMI_VFRMT_2880x576i50_16_9 25 +#define HDMI_VFRMT_2880x288p50_4_3 26 +#define HDMI_VFRMT_2880x288p50_16_9 27 +#define HDMI_VFRMT_1440x576p50_4_3 28 +#define HDMI_VFRMT_1440x576p50_16_9 29 +#define HDMI_VFRMT_1920x1080p50_16_9 30 +#define HDMI_VFRMT_1920x1080p24_16_9 31 +#define HDMI_VFRMT_1920x1080p25_16_9 32 +#define HDMI_VFRMT_1920x1080p30_16_9 33 +#define HDMI_VFRMT_2880x480p60_4_3 34 +#define HDMI_VFRMT_2880x480p60_16_9 35 +#define HDMI_VFRMT_2880x576p50_4_3 36 +#define HDMI_VFRMT_2880x576p50_16_9 37 +#define HDMI_VFRMT_1920x1250i50_16_9 38 +#define HDMI_VFRMT_1920x1080i100_16_9 39 +#define HDMI_VFRMT_1280x720p100_16_9 40 +#define HDMI_VFRMT_720x576p100_4_3 41 +#define HDMI_VFRMT_720x576p100_16_9 42 +#define HDMI_VFRMT_720x576i100_4_3 43 +#define HDMI_VFRMT_1440x576i100_4_3 HDMI_VFRMT_720x576i100_4_3 +#define HDMI_VFRMT_720x576i100_16_9 44 +#define HDMI_VFRMT_1440x576i100_16_9 HDMI_VFRMT_720x576i100_16_9 +#define HDMI_VFRMT_1920x1080i120_16_9 45 +#define HDMI_VFRMT_1280x720p120_16_9 46 +#define HDMI_VFRMT_720x480p120_4_3 47 +#define HDMI_VFRMT_720x480p120_16_9 48 +#define HDMI_VFRMT_720x480i120_4_3 49 +#define HDMI_VFRMT_1440x480i120_4_3 HDMI_VFRMT_720x480i120_4_3 +#define HDMI_VFRMT_720x480i120_16_9 50 +#define HDMI_VFRMT_1440x480i120_16_9 HDMI_VFRMT_720x480i120_16_9 +#define HDMI_VFRMT_720x576p200_4_3 51 +#define HDMI_VFRMT_720x576p200_16_9 52 +#define HDMI_VFRMT_720x576i200_4_3 53 +#define HDMI_VFRMT_1440x576i200_4_3 HDMI_VFRMT_720x576i200_4_3 +#define HDMI_VFRMT_720x576i200_16_9 54 +#define HDMI_VFRMT_1440x576i200_16_9 HDMI_VFRMT_720x576i200_16_9 +#define HDMI_VFRMT_720x480p240_4_3 55 +#define HDMI_VFRMT_720x480p240_16_9 56 +#define HDMI_VFRMT_720x480i240_4_3 57 +#define HDMI_VFRMT_1440x480i240_4_3 HDMI_VFRMT_720x480i240_4_3 +#define HDMI_VFRMT_720x480i240_16_9 58 +#define HDMI_VFRMT_1440x480i240_16_9 HDMI_VFRMT_720x480i240_16_9 +#define HDMI_VFRMT_MAX 59 +#define HDMI_VFRMT_FORCE_32BIT 0x7FFFFFFF + +#define VFRMT_NOT_SUPPORTED(VFRMT) \ + {VFRMT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false} + +#define HDMI_SETTINGS_640x480p60_4_3 \ + {HDMI_VFRMT_640x480p60_4_3, 640, 16, 96, 48, true, \ + 480, 10, 2, 33, true, 25200, 60000, false, true} +#define HDMI_SETTINGS_720x480p60_4_3 \ + {HDMI_VFRMT_720x480p60_4_3, 720, 16, 62, 60, true, \ + 480, 9, 6, 30, true, 27030, 60000, false, true} +#define HDMI_SETTINGS_720x480p60_16_9 \ + {HDMI_VFRMT_720x480p60_16_9, 720, 16, 62, 60, true, \ + 480, 9, 6, 30, true, 27030, 60000, false, true} +#define HDMI_SETTINGS_1280x720p60_16_9 \ + {HDMI_VFRMT_1280x720p60_16_9, 1280, 110, 40, 220, false, \ + 720, 5, 5, 20, false, 74250, 60000, false, true} +#define HDMI_SETTINGS_1920x1080i60_16_9 \ + {HDMI_VFRMT_1920x1080i60_16_9, 1920, 88, 44, 148, false, \ + 540, 2, 5, 5, false, 74250, 60000, false, true} +#define HDMI_SETTINGS_1440x480i60_4_3 \ + {HDMI_VFRMT_1440x480i60_4_3, 1440, 38, 124, 114, true, \ + 240, 4, 3, 15, true, 27000, 60000, true, true} +#define HDMI_SETTINGS_1440x480i60_16_9 \ + {HDMI_VFRMT_1440x480i60_16_9, 1440, 38, 124, 114, true, \ + 240, 4, 3, 15, true, 27000, 60000, true, true} +#define HDMI_SETTINGS_1920x1080p60_16_9 \ + {HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, false, \ + 1080, 4, 5, 36, false, 148500, 60000, false, true} +#define HDMI_SETTINGS_720x576p50_4_3 \ + {HDMI_VFRMT_720x576p50_4_3, 720, 12, 64, 68, true, \ + 576, 5, 5, 39, true, 27000, 50000, false, true} +#define HDMI_SETTINGS_720x576p50_16_9 \ + {HDMI_VFRMT_720x576p50_16_9, 720, 12, 64, 68, true, \ + 576, 5, 5, 39, true, 27000, 50000, false, true} +#define HDMI_SETTINGS_1280x720p50_16_9 \ + {HDMI_VFRMT_1280x720p50_16_9, 1280, 440, 40, 220, false, \ + 720, 5, 5, 20, false, 74250, 50000, false, true} +#define HDMI_SETTINGS_1440x576i50_4_3 \ + {HDMI_VFRMT_1440x576i50_4_3, 1440, 24, 126, 138, true, \ + 288, 2, 3, 19, true, 27000, 50000, true, true} +#define HDMI_SETTINGS_1440x576i50_16_9 \ + {HDMI_VFRMT_1440x576i50_16_9, 1440, 24, 126, 138, true, \ + 288, 2, 3, 19, true, 27000, 50000, true, true} +#define HDMI_SETTINGS_1920x1080p50_16_9 \ + {HDMI_VFRMT_1920x1080p50_16_9, 1920, 528, 44, 148, false, \ + 1080, 4, 5, 36, false, 148500, 50000, false, true} +#define HDMI_SETTINGS_1920x1080p24_16_9 \ + {HDMI_VFRMT_1920x1080p24_16_9, 1920, 638, 44, 148, false, \ + 1080, 4, 5, 36, false, 74250, 24000, false, true} +#define HDMI_SETTINGS_1920x1080p25_16_9 \ + {HDMI_VFRMT_1920x1080p25_16_9, 1920, 528, 44, 148, false, \ + 1080, 4, 5, 36, false, 74250, 25000, false, true} +#define HDMI_SETTINGS_1920x1080p30_16_9 \ + {HDMI_VFRMT_1920x1080p30_16_9, 1920, 88, 44, 148, false, \ + 1080, 4, 5, 36, false, 74250, 30000, false, true} + +#define TOP_AND_BOTTOM 0x10 +#define FRAME_PACKING 0x20 +#define SIDE_BY_SIDE_HALF 0x40 + +struct hdmi_disp_mode_timing_type { + u32 video_format; + u32 active_h; + u32 front_porch_h; + u32 pulse_width_h; + u32 back_porch_h; + u32 active_low_h; + u32 active_v; + u32 front_porch_v; + u32 pulse_width_v; + u32 back_porch_v; + u32 active_low_v; + /* Must divide by 1000 to get the actual frequency in MHZ */ + u32 pixel_freq; + /* Must divide by 1000 to get the actual frequency in HZ */ + u32 refresh_rate; + u32 interlaced; + u32 supported; +}; + +void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix); +const char *hdmi_reg_name(u32 offset); + +const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode); +void hdmi_set_supported_mode(u32 mode); +const char *hdmi_get_video_fmt_2string(u32 format); +ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf); + +#endif /* __HDMI_UTIL_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_io_util.c b/drivers/video/fbdev/msm/mdss_io_util.c new file mode 100644 index 000000000000..c4680c144a8a --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_io_util.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/regulator/consumer.h> +#include "mdss_io_util.h" + +int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg, + int num_vreg, int config) +{ + int i = 0, rc = 0; + struct dss_vreg *curr_vreg; + + if (config) { + for (i = 0; i < num_vreg; i++) { + curr_vreg = &in_vreg[i]; + curr_vreg->vreg = regulator_get(dev, + curr_vreg->vreg_name); + if (IS_ERR(curr_vreg->vreg)) { + pr_err("%s: %s get failed\n", + __func__, + curr_vreg->vreg_name); + curr_vreg->vreg = NULL; + goto vreg_get_fail; + } + if (curr_vreg->type == DSS_REG_LDO) { + rc = regulator_set_voltage( + curr_vreg->vreg, + curr_vreg->min_voltage, + curr_vreg->max_voltage); + if (rc < 0) { + pr_err("%s: %s set voltage failed\n", + __func__, + curr_vreg->vreg_name); + goto vreg_set_voltage_fail; + } + if (curr_vreg->optimum_voltage >= 0) { + rc = regulator_set_load( + curr_vreg->vreg, + curr_vreg->optimum_voltage); + if (rc < 0) { + pr_err( + "%s: %s set opt mode failed\n", + __func__, + curr_vreg->vreg_name); + goto vreg_set_opt_mode_fail; + } + } + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + if (curr_vreg->vreg && + regulator_is_enabled(curr_vreg->vreg)) { + if (curr_vreg->type == DSS_REG_LDO) { + if (curr_vreg->optimum_voltage >= 0) { + regulator_set_load( + curr_vreg->vreg, 0); + } + regulator_set_voltage(curr_vreg->vreg, + 0, curr_vreg->max_voltage); + } + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + } + } + } + return 0; + +vreg_unconfig: +if (curr_vreg->type == DSS_REG_LDO) + regulator_set_load(curr_vreg->vreg, 0); + +vreg_set_opt_mode_fail: +if (curr_vreg->type == DSS_REG_LDO) + regulator_set_voltage(curr_vreg->vreg, 0, curr_vreg->max_voltage); + +vreg_set_voltage_fail: + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + +vreg_get_fail: + for (i--; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + goto vreg_unconfig; + } + return -EPERM; +} /* msm_dss_config_vreg */ + +int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) +{ + int i = 0, rc = 0; + if (enable) { + for (i = 0; i < num_vreg; i++) { + if (IS_ERR(in_vreg[i].vreg)) { + pr_err("%s: %s null regulator\n", + __func__, in_vreg[i].vreg_name); + goto disable_vreg; + } + rc = regulator_enable(in_vreg[i].vreg); + if (rc < 0) { + pr_err("%s: %s enable failed\n", + __func__, in_vreg[i].vreg_name); + goto disable_vreg; + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) + regulator_disable(in_vreg[i].vreg); + } + return rc; + +disable_vreg: + for (i--; i >= 0; i--) + regulator_disable(in_vreg[i].vreg); + return rc; +} /* msm_dss_enable_vreg */ + +int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable) +{ + int i = 0, rc = 0; + if (enable) { + for (i = 0; i < num_gpio; i++) { + rc = gpio_request(in_gpio[i].gpio, + in_gpio[i].gpio_name); + if (rc < 0) { + pr_err("%s: %s enable failed\n", + __func__, in_gpio[i].gpio_name); + goto disable_gpio; + } + } + } else { + for (i = num_gpio-1; i >= 0; i--) + gpio_free(in_gpio[i].gpio); + } + return rc; + +disable_gpio: + for (i--; i >= 0; i--) + gpio_free(in_gpio[i].gpio); + return rc; +} /* msm_dss_enable_gpio */ diff --git a/drivers/video/fbdev/msm/mdss_io_util.h b/drivers/video/fbdev/msm/mdss_io_util.h new file mode 100644 index 000000000000..f8d3b90f47b4 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_io_util.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __MDSS_IO_UTIL_H__ +#define __MDSS_IO_UTIL_H__ + +#include <linux/gpio.h> +#include <linux/regulator/consumer.h> + +enum dss_vreg_type { + DSS_REG_LDO, + DSS_REG_VS, +}; + +struct dss_vreg { + struct regulator *vreg; /* vreg handle */ + char vreg_name[32]; + enum dss_vreg_type type; + int min_voltage; + int max_voltage; + int optimum_voltage; +}; + +struct dss_gpio { + unsigned gpio; + char gpio_name[32]; +}; + +struct dss_module_power { + unsigned num_vreg; + struct dss_vreg *vreg_config; + unsigned num_gpio; + struct dss_gpio *gpio_config; +}; + +int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable); +int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg, + int num_vreg, int config); +int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable); + +#endif /* __MDSS_IO_UTIL_H__ */ |
