msm_shared: hdmi: Add support for generic HDMI functionality
This change generalizes the HDMI implementation for different
targets. The non target specific changes are implemented in
this change.
CRs-Fixed: 432579
Change-Id: I90f6c6752ca91e390db8659b1cb834ac5a25820e
diff --git a/platform/msm_shared/hdmi.c b/platform/msm_shared/hdmi.c
index f26d36d..422a506 100644
--- a/platform/msm_shared/hdmi.c
+++ b/platform/msm_shared/hdmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -27,27 +27,59 @@
*
*/
#include <hdmi.h>
+#include <msm_panel.h>
#include <platform/timer.h>
#include <platform/clock.h>
#include <platform/iomap.h>
-#include <platform/scm-io.h>
#define MDP4_OVERLAYPROC1_BASE 0x18000
#define MDP4_RGB_BASE 0x40000
#define MDP4_RGB_OFF 0x10000
struct hdmi_disp_mode_timing_type hdmi_timing_default = {
- .height = 1080,
+ .height = 1080,
.hsync_porch_fp = 88,
- .hsync_width = 44,
+ .hsync_width = 44,
.hsync_porch_bp = 148,
- .width = 1920,
+ .width = 1920,
.vsync_porch_fp = 4,
- .vsync_width = 5,
+ .vsync_width = 5,
.vsync_porch_bp = 36,
+ .bpp = 24,
};
-static void hdmi_msm_set_mode(int on)
+static uint8_t hdmi_msm_avi_iframe_lut[][16] = {
+/* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50
+ 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9 576p50_4_3 */
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/
+ {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18}, /*01*/
+ {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04}, /*02*/
+ {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
+ 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11}, /*03*/
+ {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/
+ {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39,
+ 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41}, /*07*/
+ {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02}, /*08*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/
+ {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1}, /*11*/
+ {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02} /*12*/
+};
+
+void hdmi_msm_set_mode(int on)
{
uint32_t val = 0;
if (on) {
@@ -64,6 +96,39 @@
return &hdmi_timing_default;
}
+void hdmi_set_fb_addr(void *addr)
+{
+ hdmi_timing_default.base = addr;
+}
+
+void hdmi_msm_panel_init(struct msm_panel_info *pinfo)
+{
+ if (!pinfo)
+ return;
+
+ pinfo->xres = hdmi_timing_default.width;
+ pinfo->yres = hdmi_timing_default.height;
+ pinfo->bpp = hdmi_timing_default.bpp;
+ pinfo->type = HDMI_PANEL;
+
+ pinfo->hdmi.h_back_porch = hdmi_timing_default.hsync_porch_bp;
+ pinfo->hdmi.h_front_porch = hdmi_timing_default.hsync_porch_fp;
+ pinfo->hdmi.h_pulse_width = hdmi_timing_default.hsync_width;
+ pinfo->hdmi.v_back_porch = hdmi_timing_default.vsync_porch_bp;
+ pinfo->hdmi.v_front_porch = hdmi_timing_default.vsync_porch_fp;
+ pinfo->hdmi.v_pulse_width = hdmi_timing_default.vsync_width;
+}
+
+void hdmi_frame_ctrl_reg()
+{
+ uint32_t hdmi_frame_ctrl;
+
+ hdmi_frame_ctrl = ((0 << 31) & 0x80000000);
+ hdmi_frame_ctrl |= ((0 << 29) & 0x20000000);
+ hdmi_frame_ctrl |= ((0 << 28) & 0x10000000);
+ writel(hdmi_frame_ctrl, HDMI_FRAME_CTRL);
+}
+
void hdmi_video_setup()
{
uint32_t hsync_total = 0;
@@ -107,96 +172,153 @@
hdmi_frame_ctrl_reg();
}
+void hdmi_msm_avi_info_frame(void)
+{
+ /* two header + length + 13 data */
+ uint8_t aviInfoFrame[16];
+ uint8_t checksum;
+ uint32_t sum;
+ uint32_t regVal;
+ uint8_t i;
+ uint8_t mode = 6; //HDMI_VFRMT_1920x1080p60_16_9
+
+ /* InfoFrame Type = 82 */
+ aviInfoFrame[0] = 0x82;
+ /* Version = 2 */
+ aviInfoFrame[1] = 2;
+ /* Length of AVI InfoFrame = 13 */
+ aviInfoFrame[2] = 13;
+
+ /* Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0 */
+ aviInfoFrame[3] = hdmi_msm_avi_iframe_lut[0][mode];
+
+ /* Setting underscan bit */
+ aviInfoFrame[3] |= 0x02;
+
+ /* Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0 */
+ aviInfoFrame[4] = hdmi_msm_avi_iframe_lut[1][mode];
+ /* Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0 */
+ aviInfoFrame[5] = hdmi_msm_avi_iframe_lut[2][mode];
+ /* Data Byte 04: 0 VIC6 VIC5 VIC4 VIC3 VIC2 VIC1 VIC0 */
+ aviInfoFrame[6] = hdmi_msm_avi_iframe_lut[3][mode];
+ /* Data Byte 05: 0 0 0 0 PR3 PR2 PR1 PR0 */
+ aviInfoFrame[7] = hdmi_msm_avi_iframe_lut[4][mode];
+ /* Data Byte 06: LSB Line No of End of Top Bar */
+ aviInfoFrame[8] = hdmi_msm_avi_iframe_lut[5][mode];
+ /* Data Byte 07: MSB Line No of End of Top Bar */
+ aviInfoFrame[9] = hdmi_msm_avi_iframe_lut[6][mode];
+ /* Data Byte 08: LSB Line No of Start of Bottom Bar */
+ aviInfoFrame[10] = hdmi_msm_avi_iframe_lut[7][mode];
+ /* Data Byte 09: MSB Line No of Start of Bottom Bar */
+ aviInfoFrame[11] = hdmi_msm_avi_iframe_lut[8][mode];
+ /* Data Byte 10: LSB Pixel Number of End of Left Bar */
+ aviInfoFrame[12] = hdmi_msm_avi_iframe_lut[9][mode];
+ /* Data Byte 11: MSB Pixel Number of End of Left Bar */
+ aviInfoFrame[13] = hdmi_msm_avi_iframe_lut[10][mode];
+ /* Data Byte 12: LSB Pixel Number of Start of Right Bar */
+ aviInfoFrame[14] = hdmi_msm_avi_iframe_lut[11][mode];
+ /* Data Byte 13: MSB Pixel Number of Start of Right Bar */
+ aviInfoFrame[15] = hdmi_msm_avi_iframe_lut[12][mode];
+
+ sum = 0;
+ for (i = 0; i < 16; i++)
+ sum += aviInfoFrame[i];
+ sum &= 0xFF;
+ sum = 256 - sum;
+ checksum = (uint8_t) sum;
+
+ regVal = aviInfoFrame[5];
+ regVal = regVal << 8 | aviInfoFrame[4];
+ regVal = regVal << 8 | aviInfoFrame[3];
+ regVal = regVal << 8 | checksum;
+ writel(regVal, MSM_HDMI_BASE + 0x006C);
+
+ regVal = aviInfoFrame[9];
+ regVal = regVal << 8 | aviInfoFrame[8];
+ regVal = regVal << 8 | aviInfoFrame[7];
+ regVal = regVal << 8 | aviInfoFrame[6];
+ writel(regVal, MSM_HDMI_BASE + 0x0070);
+
+ regVal = aviInfoFrame[13];
+ regVal = regVal << 8 | aviInfoFrame[12];
+ regVal = regVal << 8 | aviInfoFrame[11];
+ regVal = regVal << 8 | aviInfoFrame[10];
+ writel(regVal, MSM_HDMI_BASE + 0x0074);
+
+ regVal = aviInfoFrame[1];
+ regVal = regVal << 16 | aviInfoFrame[15];
+ regVal = regVal << 8 | aviInfoFrame[14];
+ writel(regVal, MSM_HDMI_BASE + 0x0078);
+
+ /* INFOFRAME_CTRL0[0x002C] */
+ /* 0x3 for AVI InfFrame enable (every frame) */
+ writel(readl(0x002C) | 0x00000003L, MSM_HDMI_BASE + 0x002C);
+}
+
void hdmi_app_clk_init(int on)
{
uint32_t val = 0;
if (on) {
- // Enable clocks
- val = secure_readl(MISC_CC2_REG);
- val |= BIT(11);
- secure_writel(val, MISC_CC2_REG);
+ /* Enable hdmi apps clock */
+ val = readl(MISC_CC2_REG);
+ val = BIT(11);
+ writel(val, MISC_CC2_REG);
udelay(10);
- val = secure_readl(MMSS_AHB_EN_REG);
+
+ /* Enable hdmi master clock */
+ val = readl(MMSS_AHB_EN_REG);
val |= BIT(14);
- secure_writel(val, MMSS_AHB_EN_REG);
+ writel(val, MMSS_AHB_EN_REG);
udelay(10);
- val = secure_readl(MMSS_AHB_EN_REG);
+
+ /* Enable hdmi slave clock */
+ val = readl(MMSS_AHB_EN_REG);
val |= BIT(4);
- secure_writel(val, MMSS_AHB_EN_REG);
+ writel(val, MMSS_AHB_EN_REG);
udelay(10);
} else {
// Disable clocks
- val = secure_readl(MISC_CC2_REG);
+ val = readl(MISC_CC2_REG);
val &= ~(BIT(11));
- secure_writel(val, MISC_CC2_REG);
+ writel(val, MISC_CC2_REG);
udelay(10);
- val = secure_readl(MMSS_AHB_EN_REG);
+ val = readl(MMSS_AHB_EN_REG);
val &= ~(BIT(14));
- secure_writel(val, MMSS_AHB_EN_REG);
+ writel(val, MMSS_AHB_EN_REG);
udelay(10);
- val = secure_readl(MMSS_AHB_EN_REG);
+ val = readl(MMSS_AHB_EN_REG);
val &= ~(BIT(4));
- secure_writel(val, MMSS_AHB_EN_REG);
+ writel(val, MMSS_AHB_EN_REG);
udelay(10);
}
}
-static void hdmi_msm_reset_core()
-{
- uint32_t reg_val = 0;
- hdmi_msm_set_mode(0);
- // Disable clocks
- hdmi_app_clk_init(0);
- udelay(5);
- // Enable clocks
- hdmi_app_clk_init(1);
-
- reg_val = secure_readl(SW_RESET_CORE_REG);
- reg_val |= BIT(11);
- secure_writel(reg_val, SW_RESET_CORE_REG);
- udelay(5);
- reg_val = secure_readl(SW_RESET_AHB_REG);
- reg_val |= BIT(9);
- secure_writel(reg_val, SW_RESET_AHB_REG);
- udelay(5);
- reg_val = secure_readl(SW_RESET_AHB_REG);
- reg_val |= BIT(9);
- secure_writel(reg_val, SW_RESET_AHB_REG);
- udelay(20);
- reg_val = secure_readl(SW_RESET_CORE_REG);
- reg_val &= ~(BIT(11));
- secure_writel(reg_val, SW_RESET_CORE_REG);
- udelay(5);
- reg_val = secure_readl(SW_RESET_AHB_REG);
- reg_val &= ~(BIT(9));
- secure_writel(reg_val, SW_RESET_AHB_REG);
- udelay(5);
- reg_val = secure_readl(SW_RESET_AHB_REG);
- reg_val &= ~(BIT(9));
- secure_writel(reg_val, SW_RESET_AHB_REG);
- udelay(5);
-}
-
-void hdmi_msm_turn_on(void)
+int hdmi_msm_turn_on(void)
{
uint32_t hotplug_control;
+
+ hdmi_msm_set_mode(0);
+
hdmi_msm_reset_core(); // Reset the core
hdmi_msm_init_phy();
+
// Enable USEC REF timer
writel(0x0001001B, HDMI_USEC_REFTIMER);
- // Video setup for HDMI
- hdmi_video_setup();
+
// Write 1 to HDMI_CTRL to enable HDMI
hdmi_msm_set_mode(1);
- dprintf(SPEW, "HDMI Core is: %s\n",
- (readl(HDMI_CTRL) & 0x00000001) ? "on" : "off");
+
+ // Video setup for HDMI
+ hdmi_video_setup();
+
+ // AVI info setup
+ hdmi_msm_avi_info_frame();
+
+ return 0;
}
-struct fbcon_config *hdmi_dtv_init(struct hdmi_disp_mode_timing_type *timing)
+int hdmi_dtv_init()
{
- uint32_t dtv_width;
- uint32_t dtv_height;
- uint32_t dtv_bpp;
uint32_t hsync_period;
uint32_t hsync_ctrl;
uint32_t hsync_start_x;
@@ -219,21 +341,13 @@
unsigned char *overlay_base;
uint32_t val;
- dprintf(SPEW, "In DTV on function\n");
-
- // Turn on all the clocks
- dtv_on();
-
- dtv_width = timing->width;
- dtv_height = timing->height;
- dtv_bpp = fb_cfg.bpp;
- fb_cfg.base = FB_ADDR;
+ struct hdmi_disp_mode_timing_type *timing =
+ hdmi_common_init_panel_info();
// MDP E config
- writel((unsigned)fb_cfg.base, MDP_BASE + 0xb0008); //FB Address
-
- writel(((fb_cfg.height << 16) | fb_cfg.width), MDP_BASE + 0xb0004);
- writel((fb_cfg.width * fb_cfg.bpp / 8), MDP_BASE + 0xb000c);
+ writel((unsigned)timing->base, MDP_BASE + 0xb0008); //FB Address
+ writel(((timing->height << 16) | timing->width), MDP_BASE + 0xb0004);
+ writel((timing->width * timing->bpp / 8), MDP_BASE + 0xb000c);
writel(0, MDP_BASE + 0xb0010);
writel(DMA_PACK_PATTERN_RGB | DMA_DSTC0G_8BITS | DMA_DSTC1B_8BITS |
@@ -247,11 +361,11 @@
rgb_base += (MDP4_RGB_OFF * 1);
writel(((timing->height << 16) | timing->width), rgb_base + 0x0000);
writel(0x0, rgb_base + 0x0004);
- writel(0x0, rgb_base + 0x0008);
+ writel(((timing->height << 16) | timing->width), rgb_base + 0x0008);
writel(0x0, rgb_base + 0x000c);
- writel(fb_cfg.base, rgb_base + 0x0010); //FB address
- writel((fb_cfg.width * fb_cfg.bpp / 8), rgb_base + 0x0040);
- writel(0x24216, rgb_base + 0x0050); //format
+ writel(timing->base, rgb_base + 0x0010); //FB address
+ writel((timing->width * timing->bpp / 8), rgb_base + 0x0040);
+ writel(0x2443F, rgb_base + 0x0050); //format
writel(0x20001, rgb_base + 0x0054); //pattern
writel(0x0, rgb_base + 0x0058);
writel(0x20000000, rgb_base + 0x005c); //phaseX
@@ -271,19 +385,20 @@
// Overlay cfg
overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;
+
writel(0x0, MDP_BASE + 0x0038); //EXternal interface select
data = ((timing->height << 16) | timing->width);
writel(data, overlay_base + 0x0008);
- writel(fb_cfg.base, overlay_base + 0x000c);
- writel((fb_cfg.width * fb_cfg.bpp / 8), overlay_base + 0x0010);
+ writel(timing->base, overlay_base + 0x000c);
+ writel((timing->width * timing->bpp / 8), overlay_base + 0x0010);
writel(0x10, overlay_base + 0x104);
writel(0x10, overlay_base + 0x124);
writel(0x10, overlay_base + 0x144);
- writel(0x1, overlay_base + 0x0004); /* directout */
+ writel(0x01, overlay_base + 0x0004); /* directout */
hsync_period =
- timing->hsync_width + timing->hsync_porch_bp + dtv_width +
+ timing->hsync_width + timing->hsync_porch_bp + timing->width +
timing->hsync_porch_fp;
hsync_ctrl = (hsync_period << 16) | timing->hsync_width;
hsync_start_x = timing->hsync_width + timing->hsync_porch_bp;
@@ -291,7 +406,7 @@
display_hctl = (hsync_end_x << 16) | hsync_start_x;
vsync_period =
- (timing->vsync_width + timing->vsync_porch_bp + dtv_height +
+ (timing->vsync_width + timing->vsync_porch_bp + timing->height +
timing->vsync_porch_fp) * hsync_period;
display_v_start =
(timing->vsync_width + timing->vsync_porch_bp) * hsync_period;
@@ -299,42 +414,36 @@
vsync_period - (timing->vsync_porch_bp * hsync_period) - 1;
dtv_underflow_clr |= 0x80000000;
- hsync_polarity = 0;
- vsync_polarity = 0;
- data_en_polarity = 0;
- ctrl_polarity =
+ hsync_polarity = 0;
+ vsync_polarity = 0;
+ data_en_polarity = 0;
+ ctrl_polarity =
(data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
- writel(hsync_ctrl, MDP_BASE + DTV_BASE + 0x4);
- writel(vsync_period, MDP_BASE + DTV_BASE + 0x8);
- writel(timing->vsync_width * hsync_period, MDP_BASE + DTV_BASE + 0xc);
- writel(display_hctl, MDP_BASE + DTV_BASE + 0x18);
+ writel(hsync_ctrl, MDP_BASE + DTV_BASE + 0x4);
+ writel(vsync_period, MDP_BASE + DTV_BASE + 0x8);
+ writel(timing->vsync_width * hsync_period,
+ MDP_BASE + DTV_BASE + 0xc);
+ writel(display_hctl, MDP_BASE + DTV_BASE + 0x18);
writel(display_v_start, MDP_BASE + DTV_BASE + 0x1c);
- writel(0x25a197, MDP_BASE + DTV_BASE + 0x20);
- writel(dtv_border_clr, MDP_BASE + DTV_BASE + 0x40);
- writel(0x8fffffff, MDP_BASE + DTV_BASE + 0x44);
- writel(dtv_hsync_skew, MDP_BASE + DTV_BASE + 0x48);
- writel(ctrl_polarity, MDP_BASE + DTV_BASE + 0x50);
- writel(0, MDP_BASE + DTV_BASE + 0x2c);
- writel(active_v_start, MDP_BASE + DTV_BASE + 0x30);
- writel(active_v_end, MDP_BASE + DTV_BASE + 0x38);
+ writel(0x25a197, MDP_BASE + DTV_BASE + 0x20);
+ writel(dtv_border_clr, MDP_BASE + DTV_BASE + 0x40);
+ writel(0x8fffffff, MDP_BASE + DTV_BASE + 0x44);
+ writel(dtv_hsync_skew, MDP_BASE + DTV_BASE + 0x48);
+ writel(ctrl_polarity, MDP_BASE + DTV_BASE + 0x50);
+ writel(0x0, MDP_BASE + DTV_BASE + 0x2c);
+ writel(active_v_start, MDP_BASE + DTV_BASE + 0x30);
+ writel(active_v_end, MDP_BASE + DTV_BASE + 0x38);
- /*
- * Keep Display solid color, for future debugging
- */
-# if 0
- writel(0xffffffff, 0x05151008);
- val = readl(MDP_BASE + 0x50050);
- val |= BIT(22);
- writel(val, MDP_BASE + 0x50050);
- writel(BIT(5), MDP_BASE + 0x18000);
-#endif
/* Enable DTV block */
- writel(0x1, MDP_BASE + DTV_BASE);
+ writel(0x01, MDP_BASE + DTV_BASE);
+
+ /* Flush mixer/pipes configurations */
val = BIT(1);
val |= BIT(5);
writel(val, MDP_BASE + 0x18000);
- return &fb_cfg;
+
+ return 0;
}
void hdmi_display_shutdown()