Merge "msm_fb: display: Add LVDS display & LVDS/DSI panel auto detect support" into msm-3.0

This commit is contained in:
Linux Build Service Account
2012-02-13 01:39:50 -08:00
committed by QuIC Gerrit Code Review
6 changed files with 210 additions and 98 deletions

View File

@@ -495,6 +495,14 @@ config FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT
---help---
Support for LCDC + MIPI panel auto detect
config FB_MSM_LVDS_MIPI_PANEL_DETECT
bool "LVDS + MIPI Panel Auto Detect"
select FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT
select FB_MSM_LVDS_CHIMEI_WXGA
select FB_MSM_MIPI_CHIMEI_WXGA
---help---
Support for LVDS + MIPI panel auto detect
config FB_MSM_MDDI_PRISM_WVGA
bool "MDDI Prism WVGA Panel"
select FB_MSM_MDDI

View File

@@ -19,9 +19,10 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/msm_iomap.h>
#include <mach/clk.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
@@ -29,10 +30,9 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <mach/clk.h>
#include "msm_fb.h"
#include "mdp4.h"
static int lvds_probe(struct platform_device *pdev);
static int lvds_remove(struct platform_device *pdev);
@@ -57,6 +57,126 @@ static struct platform_driver lvds_driver = {
static struct lcdc_platform_data *lvds_pdata;
static void lvds_init(struct msm_fb_data_type *mfd)
{
unsigned int lvds_intf, lvds_phy_cfg0;
MDP_OUTP(MDP_BASE + 0xc2034, 0x33);
usleep(1000);
/* LVDS PHY PLL configuration */
MDP_OUTP(MDP_BASE + 0xc3000, 0x08);
MDP_OUTP(MDP_BASE + 0xc3004, 0x87);
MDP_OUTP(MDP_BASE + 0xc3008, 0x30);
MDP_OUTP(MDP_BASE + 0xc300c, 0x06);
MDP_OUTP(MDP_BASE + 0xc3014, 0x20);
MDP_OUTP(MDP_BASE + 0xc3018, 0x0F);
MDP_OUTP(MDP_BASE + 0xc301c, 0x01);
MDP_OUTP(MDP_BASE + 0xc3020, 0x41);
MDP_OUTP(MDP_BASE + 0xc3024, 0x0d);
MDP_OUTP(MDP_BASE + 0xc3028, 0x07);
MDP_OUTP(MDP_BASE + 0xc302c, 0x00);
MDP_OUTP(MDP_BASE + 0xc3030, 0x1c);
MDP_OUTP(MDP_BASE + 0xc3034, 0x01);
MDP_OUTP(MDP_BASE + 0xc3038, 0x00);
MDP_OUTP(MDP_BASE + 0xc3040, 0xC0);
MDP_OUTP(MDP_BASE + 0xc3044, 0x00);
MDP_OUTP(MDP_BASE + 0xc3048, 0x30);
MDP_OUTP(MDP_BASE + 0xc304c, 0x00);
MDP_OUTP(MDP_BASE + 0xc3000, 0x11);
MDP_OUTP(MDP_BASE + 0xc3064, 0x05);
MDP_OUTP(MDP_BASE + 0xc3050, 0x20);
MDP_OUTP(MDP_BASE + 0xc3000, 0x01);
/* Wait until LVDS PLL is locked and ready */
while (!readl_relaxed(MDP_BASE + 0xc3080))
cpu_relax();
writel_relaxed(0x00, mmss_cc_base + 0x0264);
writel_relaxed(0x00, mmss_cc_base + 0x0094);
writel_relaxed(0x02, mmss_cc_base + 0x00E4);
writel_relaxed((0x80 | readl_relaxed(mmss_cc_base + 0x00E4)),
mmss_cc_base + 0x00E4);
usleep(1000);
writel_relaxed((~0x80 & readl_relaxed(mmss_cc_base + 0x00E4)),
mmss_cc_base + 0x00E4);
writel_relaxed(0x05, mmss_cc_base + 0x0094);
writel_relaxed(0x02, mmss_cc_base + 0x0264);
/* Wait until LVDS pixel clock output is enabled */
mb();
if (mfd->panel_info.bpp == 24) {
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2024, 0x151a191a);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc202c, 0x1706071b);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2030, 0x000e0f16);
if (mfd->panel_info.lvds.channel_mode ==
LVDS_DUAL_CHANNEL_MODE) {
lvds_intf = 0x0001ff80;
lvds_phy_cfg0 = BIT(6) | BIT(7);
if (mfd->panel_info.lvds.channel_swap)
lvds_intf |= BIT(4);
} else {
lvds_intf = 0x00010f84;
lvds_phy_cfg0 = BIT(6);
}
} else if (mfd->panel_info.bpp == 18) {
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
if (mfd->panel_info.lvds.channel_mode ==
LVDS_DUAL_CHANNEL_MODE) {
lvds_intf = 0x00017788;
lvds_phy_cfg0 = BIT(6) | BIT(7);
if (mfd->panel_info.lvds.channel_swap)
lvds_intf |= BIT(4);
} else {
lvds_intf = 0x0001078c;
lvds_phy_cfg0 = BIT(6);
}
}
/* MDP_LVDSPHY_CFG0 */
MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0);
/* MDP_LCDC_LVDS_INTF_CTL */
MDP_OUTP(MDP_BASE + 0xc2000, lvds_intf);
MDP_OUTP(MDP_BASE + 0xc3108, 0x30);
lvds_phy_cfg0 |= BIT(4);
/* Wait until LVDS PHY registers are configured */
mb();
usleep(1);
/* MDP_LVDSPHY_CFG0, enable serialization */
MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0);
}
static int lvds_off(struct platform_device *pdev)
{
int ret = 0;
@@ -65,7 +185,8 @@ static int lvds_off(struct platform_device *pdev)
mfd = platform_get_drvdata(pdev);
ret = panel_next_off(pdev);
clk_disable(lvds_clk);
if (lvds_clk)
clk_disable(lvds_clk);
if (lvds_pdata && lvds_pdata->lcdc_power_save)
lvds_pdata->lcdc_power_save(0);
@@ -97,22 +218,24 @@ static int lvds_on(struct platform_device *pdev)
#endif
mfd = platform_get_drvdata(pdev);
mfd->fbi->var.pixclock = clk_round_rate(lvds_clk,
mfd->fbi->var.pixclock);
ret = clk_set_rate(lvds_clk, mfd->fbi->var.pixclock);
if (ret) {
pr_err("%s: Can't set lvds clock to rate %u\n",
__func__, mfd->fbi->var.pixclock);
goto out;
if (lvds_clk) {
mfd->fbi->var.pixclock = clk_round_rate(lvds_clk,
mfd->fbi->var.pixclock);
ret = clk_set_rate(lvds_clk, mfd->fbi->var.pixclock);
if (ret) {
pr_err("%s: Can't set lvds clock to rate %u\n",
__func__, mfd->fbi->var.pixclock);
goto out;
}
clk_enable(lvds_clk);
}
clk_enable(lvds_clk);
if (lvds_pdata && lvds_pdata->lcdc_power_save)
lvds_pdata->lcdc_power_save(1);
if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
ret = lvds_pdata->lcdc_gpio_config(1);
lvds_init(mfd);
ret = panel_next_on(pdev);
out:
@@ -182,8 +305,11 @@ static int lvds_probe(struct platform_device *pdev)
mfd->fb_imgType = MDP_RGB_565;
fbi = mfd->fbi;
fbi->var.pixclock = clk_round_rate(lvds_clk,
mfd->panel_info.clk_rate);
if (lvds_clk) {
fbi->var.pixclock = clk_round_rate(lvds_clk,
mfd->panel_info.clk_rate);
}
fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
@@ -224,9 +350,9 @@ static int lvds_register_driver(void)
static int __init lvds_driver_init(void)
{
lvds_clk = clk_get(NULL, "lvds_clk");
if (IS_ERR(lvds_clk)) {
if (IS_ERR_OR_NULL(lvds_clk)) {
pr_err("Couldnt find lvds_clk\n");
return -EINVAL;
lvds_clk = NULL;
}
return lvds_register_driver();

View File

@@ -11,9 +11,19 @@
*/
#include "msm_fb.h"
#include <linux/pwm.h>
#include <linux/mfd/pm8xxx/pm8921.h>
static struct msm_panel_common_pdata *cm_pdata;
#define LVDS_CHIMEI_PWM_FREQ_HZ 300
#define LVDS_CHIMEI_PWM_PERIOD_USEC (USEC_PER_SEC / LVDS_CHIMEI_PWM_FREQ_HZ)
#define LVDS_CHIMEI_PWM_LEVEL 255
#define LVDS_CHIMEI_PWM_DUTY_LEVEL \
(LVDS_CHIMEI_PWM_PERIOD_USEC / LVDS_CHIMEI_PWM_LEVEL)
static struct lvds_panel_platform_data *cm_pdata;
static struct platform_device *cm_fbpdev;
static struct pwm_device *bl_lpm;
static int lvds_chimei_panel_on(struct platform_device *pdev)
{
@@ -27,6 +37,26 @@ static int lvds_chimei_panel_off(struct platform_device *pdev)
static void lvds_chimei_set_backlight(struct msm_fb_data_type *mfd)
{
int ret;
pr_debug("%s: back light level %d\n", __func__, mfd->bl_level);
if (bl_lpm) {
ret = pwm_config(bl_lpm, LVDS_CHIMEI_PWM_DUTY_LEVEL *
mfd->bl_level, LVDS_CHIMEI_PWM_PERIOD_USEC);
if (ret) {
pr_err("pwm_config on lpm failed %d\n", ret);
return;
}
if (mfd->bl_level) {
ret = pwm_enable(bl_lpm);
if (ret)
pr_err("pwm enable/disable on lpm failed"
"for bl %d\n", mfd->bl_level);
} else {
pwm_disable(bl_lpm);
}
}
}
static int __devinit lvds_chimei_probe(struct platform_device *pdev)
@@ -40,6 +70,17 @@ static int __devinit lvds_chimei_probe(struct platform_device *pdev)
return 0;
}
if (cm_pdata != NULL)
bl_lpm = pwm_request(cm_pdata->gpio[0],
"backlight");
if (bl_lpm == NULL || IS_ERR(bl_lpm)) {
pr_err("%s pwm_request() failed\n", __func__);
bl_lpm = NULL;
}
pr_debug("bl_lpm = %p lpm = %d\n", bl_lpm,
cm_pdata->gpio[0]);
cm_fbpdev = msm_fb_add_device(pdev);
if (!cm_fbpdev) {
dev_err(&pdev->dev, "failed to add msm_fb device\n");
@@ -85,8 +126,8 @@ static int __init lvds_chimei_wxga_init(void)
return ret;
pinfo = &lvds_chimei_panel_data.panel_info;
pinfo->xres = 320;
pinfo->yres = 240;
pinfo->xres = 1366;
pinfo->yres = 768;
MSM_FB_SINGLE_MODE_PANEL(pinfo);
pinfo->type = LVDS_PANEL;
pinfo->pdest = DISPLAY_1;
@@ -94,7 +135,7 @@ static int __init lvds_chimei_wxga_init(void)
pinfo->bpp = 24;
pinfo->fb_num = 2;
pinfo->clk_rate = 75000000;
pinfo->bl_max = 15;
pinfo->bl_max = 255;
pinfo->bl_min = 1;
/*
@@ -107,12 +148,14 @@ static int __init lvds_chimei_wxga_init(void)
pinfo->lcdc.v_back_porch = 0;
pinfo->lcdc.v_front_porch = 38;
pinfo->lcdc.v_pulse_width = 20;
pinfo->lcdc.border_clr = 0xffff00;
pinfo->lcdc.underflow_clr = 0xff;
pinfo->lcdc.hsync_skew = 0;
pinfo->lvds.channel_mode = LVDS_SINGLE_CHANNEL_MODE;
pinfo->lcdc.xres_pad = 1046;
pinfo->lcdc.yres_pad = 528;
/* Set border color, padding only for reducing active display region */
pinfo->lcdc.border_clr = 0x0;
pinfo->lcdc.xres_pad = 0;
pinfo->lcdc.yres_pad = 0;
ret = platform_device_register(&this_device);
if (ret)

View File

@@ -1221,7 +1221,7 @@ int mdp_bus_scale_update_request(uint32_t index)
return -EINVAL;
}
if (mdp_bus_scale_handle < 1) {
printk(KERN_ERR "%s invalid bus handle\n", __func__);
pr_debug("%s invalid bus handle\n", __func__);
return -EINVAL;
}
return msm_bus_scale_client_update_request(mdp_bus_scale_handle,
@@ -1318,7 +1318,7 @@ static int mdp_irq_clk_setup(void)
if (IS_ERR(mdp_pclk))
mdp_pclk = NULL;
if (mdp_rev == MDP_REV_42) {
if (mdp_rev >= MDP_REV_42) {
mdp_lut_clk = clk_get(NULL, "lut_mdp");
if (IS_ERR(mdp_lut_clk)) {
ret = PTR_ERR(mdp_lut_clk);

View File

@@ -26,6 +26,7 @@ extern uint32 mdp_intr_mask;
extern spinlock_t mdp_spin_lock;
extern struct mdp4_statistic mdp4_stat;
extern uint32 mdp4_extn_disp;
extern char *mmss_cc_base; /* mutimedia sub system clock control */
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
@@ -417,6 +418,7 @@ int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
void mdp4_dma_e_done_dtv(void);
#else
static inline void mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
@@ -438,6 +440,10 @@ static inline int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
{
return 0;
}
static inline void mdp4_dma_e_done_dtv(void)
{
return;
}
#endif
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -691,7 +697,6 @@ void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd);
void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma);
void mdp4_dma_e_done_dtv(void);
int mdp4_writeback_start(struct fb_info *info);
int mdp4_writeback_stop(struct fb_info *info);

View File

@@ -45,73 +45,6 @@ int first_pixel_start_y;
static struct mdp4_overlay_pipe *lcdc_pipe;
static struct completion lcdc_comp;
static void lvds_init(struct msm_fb_data_type *mfd)
{
unsigned int lvds_intf, lvds_phy_cfg0;
if (mfd->panel_info.bpp == 24) {
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc202c, 0x0f16171b);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2030, 0x0006070e);
if (mfd->panel_info.lvds.channel_mode ==
LVDS_DUAL_CHANNEL_MODE) {
lvds_intf = 0x0001ff80;
lvds_phy_cfg0 = BIT(6) | BIT(7);
if (mfd->panel_info.lvds.channel_swap)
lvds_intf |= BIT(4);
} else {
lvds_intf = 0x00010f84;
lvds_phy_cfg0 = BIT(6);
}
} else if (mfd->panel_info.bpp == 18) {
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
if (mfd->panel_info.lvds.channel_mode ==
LVDS_DUAL_CHANNEL_MODE) {
lvds_intf = 0x00017788;
lvds_phy_cfg0 = BIT(6) | BIT(7);
if (mfd->panel_info.lvds.channel_swap)
lvds_intf |= BIT(4);
} else {
lvds_intf = 0x0001078c;
lvds_phy_cfg0 = BIT(6);
}
}
/* MDP_LVDSPHY_CFG0 */
MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0);
/* MDP_LCDC_LVDS_INTF_CTL */
MDP_OUTP(MDP_BASE + 0xc2000, lvds_intf);
lvds_phy_cfg0 |= BIT(4);
/* MDP_LVDSPHY_CFG0, enable serialization */
MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0);
}
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
@@ -305,9 +238,6 @@ int mdp_lcdc_on(struct platform_device *pdev)
#endif
mdp_histogram_ctrl(TRUE);
if (mfd->panel.type == LVDS_PANEL)
lvds_init(mfd);
ret = panel_next_on(pdev);
if (ret == 0) {
/* enable LCDC block */