Merge "platform: msm_shared: Flush the cache only for size of data"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 322a5eb..5451150 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -2336,6 +2336,30 @@
return;
}
+void cmd_updatevol(const char *vol_name, void *data, unsigned sz)
+{
+ struct ptentry *sys_ptn;
+ struct ptable *ptable;
+
+ ptable = flash_get_ptable();
+ if (ptable == NULL) {
+ fastboot_fail("partition table doesn't exist");
+ return;
+ }
+
+ sys_ptn = ptable_find(ptable, "system");
+ if (sys_ptn == NULL) {
+ fastboot_fail("system partition not found");
+ return;
+ }
+
+ sz = ROUND_TO_PAGE(sz, page_mask);
+ if (update_ubi_vol(sys_ptn, vol_name, data, sz))
+ fastboot_fail("update_ubi_vol failed");
+ else
+ fastboot_okay("");
+}
+
void cmd_flash_nand(const char *arg, void *data, unsigned sz)
{
struct ptentry *ptn;
@@ -2350,7 +2374,9 @@
ptn = ptable_find(ptable, arg);
if (ptn == NULL) {
- fastboot_fail("unknown partition name");
+ dprintf(INFO, "unknown partition name (%s). Trying updatevol\n",
+ arg);
+ cmd_updatevol(arg, data, sz);
return;
}
diff --git a/dev/gcdb/display/gcdb_display.c b/dev/gcdb/display/gcdb_display.c
index 4a49b1b..c2433a1 100755
--- a/dev/gcdb/display/gcdb_display.c
+++ b/dev/gcdb/display/gcdb_display.c
@@ -197,9 +197,9 @@
struct dfps_info *dfps;
index = partition_get_index("splash");
- if (index == 0) {
- dprintf(CRITICAL, "ERROR: splash Partition table not found\n");
- ret = ERROR;
+ if (index == INVALID_PTN) {
+ dprintf(INFO, "%s: splash partition table not found\n", __func__);
+ ret = NO_ERROR;
goto splash_err;
}
@@ -258,9 +258,9 @@
unsigned long long ptn;
index = partition_get_index("splash");
- if (index == 0) {
- dprintf(CRITICAL, "ERROR: splash Partition table not found\n");
- ret = ERROR;
+ if (index == INVALID_PTN) {
+ dprintf(INFO, "%s: splash partition table not found\n", __func__);
+ ret = NO_ERROR;
goto store_err;
}
diff --git a/include/dev/flash-ubi.h b/include/dev/flash-ubi.h
index 50577cc..a8bf819 100644
--- a/include/dev/flash-ubi.h
+++ b/include/dev/flash-ubi.h
@@ -77,6 +77,8 @@
/* Erase counter header magic number (ASCII "UBI#") */
#define UBI_EC_HDR_MAGIC 0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
#define UBI_MAGIC "UBI#"
#define UBI_MAGIC_SIZE 0x04
@@ -129,30 +131,85 @@
#define UBI_MAX_VOLUMES 128
#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
+#define UBI_VID_DYNAMIC 1
+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
#define UBI_FM_SB_VOLUME_ID (UBI_INTERNAL_VOL_START + 1)
+/* A record in the UBI volume table. */
+struct __attribute__ ((packed)) ubi_vtbl_record {
+ uint32_t reserved_pebs;
+ uint32_t alignment;
+ uint32_t data_pad;
+ uint8_t vol_type;
+ uint8_t upd_marker;
+ uint16_t name_len;
+#define UBI_VOL_NAME_MAX 127
+ uint8_t name[UBI_VOL_NAME_MAX+1];
+ uint8_t flags;
+ uint8_t padding[23];
+ uint32_t crc;
+};
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(uint32_t))
+
+/* PEB status */
+enum {
+ UBI_UNKNOWN = 0,
+ UBI_BAD_PEB,
+ UBI_FREE_PEB,
+ UBI_USED_PEB,
+ UBI_EMPTY_PEB
+};
+
+/**
+ * struct peb_info - In RAM info on a PEB
+ * @ec: erase counter
+ * @status: status of this PEB: UBI_BAD_PEB/USED/FREE/EMPTY
+ * @volume: if status = UBI_USED_PEB this is the volume
+ * ID this PEB belongs to -1 for any other status
+ */
+struct peb_info {
+ uint64_t ec;
+ int status;
+ int volume;
+};
+
/**
* struct ubi_scan_info - UBI scanning information.
- * @ec: erase counters or eraseblock status for all eraseblocks
+ * @pebs_data: info on all of partition PEBs
* @mean_ec: mean erase counter
+ * @vtbl_peb1: number of the first PEB holding the volume table
+ * (relative to the beginning of the partition)
+ * @vtbl_peb1: number of the second PEB holding the volume table
+ * (relative to the beginning of the partition)
* @bad_cnt: count of bad eraseblocks
- * @good_cnt: count of non-bad eraseblocks
* @empty_cnt: count of empty eraseblocks
+ * @free_cnt: count of free eraseblocks
+ * @used_cnt: count of used eraseblocks
+ * @fastmap_sb: PEB number holding FM superblock. If FM is not present: -1
* @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means
* undefined)
* @data_offs: data offset from the found EC headers (%-1 means undefined)
* @image_seq: image sequence
+ * @read_image_seq: image sequence read from NAND while scanning
*/
struct ubi_scan_info {
- uint64_t *ec;
+ struct peb_info *pebs_data;
uint64_t mean_ec;
+ int vtbl_peb1;
+ int vtbl_peb2;
int bad_cnt;
- int good_cnt;
int empty_cnt;
+ int free_cnt;
+ int used_cnt;
+ int fastmap_sb;
unsigned vid_hdr_offs;
unsigned data_offs;
uint32_t image_seq;
+ uint32_t read_image_seq;
};
int flash_ubi_img(struct ptentry *ptn, void *data, unsigned size);
+int update_ubi_vol(struct ptentry *ptn, const char* vol_name,
+ void *data, unsigned size);
#endif
diff --git a/include/dev/udc.h b/include/dev/udc.h
index 42ced0e..31d9755 100644
--- a/include/dev/udc.h
+++ b/include/dev/udc.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2009, Google Inc.
* All rights reserved.
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, 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
@@ -50,6 +50,8 @@
#define UDC_TYPE_BULK_IN 1
#define UDC_TYPE_BULK_OUT 2
+#define UDC_TYPE_INTR_IN 3
+#define UDC_TYPE_INTR_OUT 4
struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt);
void udc_endpoint_free(struct udc_endpoint *ept);
diff --git a/platform/msm8994/acpuclock.c b/platform/msm8994/acpuclock.c
index c59e61a..0b64ce0 100644
--- a/platform/msm8994/acpuclock.c
+++ b/platform/msm8994/acpuclock.c
@@ -519,3 +519,45 @@
writel(0x0, DSI_PIXEL1_CBCR);
}
}
+
+void hdmi_core_ahb_clk_enable(void)
+{
+ int ret;
+
+ /* Configure hdmi ahb clock */
+ ret = clk_get_set_enable("hdmi_ahb_clk", 0, 1);
+ if(ret) {
+ dprintf(CRITICAL, "failed to set hdmi_ahb_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
+
+ /* Configure hdmi core clock */
+ ret = clk_get_set_enable("hdmi_core_clk", 19200000, 1);
+ if(ret) {
+ dprintf(CRITICAL, "failed to set hdmi_core_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
+}
+
+void hdmi_pixel_clk_enable(uint32_t rate)
+{
+ int ret;
+
+ /* Configure hdmi pixel clock */
+ ret = clk_get_set_enable("hdmi_extp_clk", rate, 1);
+ if(ret) {
+ dprintf(CRITICAL, "failed to set hdmi_extp_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
+}
+
+void hdmi_pixel_clk_disable(void)
+{
+ clk_disable(clk_get("hdmi_extp_clk"));
+}
+
+void hdmi_core_ahb_clk_disable(void)
+{
+ clk_disable(clk_get("hdmi_core_clk"));
+ clk_disable(clk_get("hdmi_ahb_clk"));
+}
diff --git a/platform/msm8994/include/platform/clock.h b/platform/msm8994/include/platform/clock.h
index c4efe85..72d9787 100644
--- a/platform/msm8994/include/platform/clock.h
+++ b/platform/msm8994/include/platform/clock.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 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
@@ -50,6 +50,13 @@
#define MDP_CBCR REG_MM(0x231C)
#define MDP_LUT_CBCR REG_MM(0x2320)
#define MDP_AHB_CBCR REG_MM(0x2308)
+#define MDSS_HDMI_AHB_CBCR REG_MM(0x230C)
+#define MDSS_HDMI_CBCR REG_MM(0x2338)
+#define MDSS_EXTPCLK_CBCR REG_MM(0x2324)
+#define EXTPCLK_CMD_RCGR REG_MM(0x2060)
+#define EXTPCLK_CFG_RCGR REG_MM(0x2064)
+#define HDMI_CMD_RCGR REG_MM(0x2100)
+#define HDMI_CFG_RCGR REG_MM(0x2104)
#define MDP_AXI_CMD_RCGR REG_MM(0x5040)
#define MDP_AXI_CFG_RCGR REG_MM(0x5044)
@@ -122,5 +129,9 @@
void mmss_bus_clock_disable(void);
void mdp_clock_enable(void);
void mdp_clock_disable(void);
+void hdmi_core_ahb_clk_enable(void);
+void hdmi_pixel_clk_enable(uint32_t rate);
+void hdmi_pixel_clk_disable(void);
+void hdmi_core_ahb_clk_disable(void);
#endif
diff --git a/platform/msm8994/include/platform/iomap.h b/platform/msm8994/include/platform/iomap.h
index bb9709f..ce823de 100644
--- a/platform/msm8994/include/platform/iomap.h
+++ b/platform/msm8994/include/platform/iomap.h
@@ -316,6 +316,11 @@
#endif
#define MDP_INTF_2_TIMING_ENGINE_EN REG_MDP(0x6C000)
+#ifdef MDP_INTF_3_TIMING_ENGINE_EN
+#undef MDP_INTF_3_TIMING_ENGINE_EN
+#endif
+#define MDP_INTF_3_TIMING_ENGINE_EN REG_MDP(0x6C800)
+
#ifdef MDP_CTL_0_BASE
#undef MDP_CTL_0_BASE
#endif
@@ -356,6 +361,11 @@
#endif
#define MDP_INTF_2_BASE REG_MDP(0x6c000)
+#ifdef MDP_INTF_3_BASE
+#undef MDP_INTF_3_BASE
+#endif
+#define MDP_INTF_3_BASE REG_MDP(0x6c800)
+
#ifdef MDP_CLK_CTRL0
#undef MDP_CLK_CTRL0
#endif
@@ -561,4 +571,60 @@
#define QPNP_GREEN_LPG_CTRL_BASE 0xB200
#define QPNP_RED_LPG_CTRL_BASE 0xB300
+/* HDMI reg addresses */
+#define HDMI_BASE 0xFD9A8000
+#define REG_HDMI(off) (HDMI_BASE + (off))
+
+#define HDMI_ACR_32_0 REG_HDMI(0xC4)
+#define HDMI_ACR_32_1 REG_HDMI(0xC8)
+#define HDMI_ACR_44_0 REG_HDMI(0xCC)
+#define HDMI_ACR_44_1 REG_HDMI(0xD0)
+#define HDMI_ACR_48_0 REG_HDMI(0xD4)
+#define HDMI_ACR_48_1 REG_HDMI(0xD8)
+#define HDMI_AUDIO_PKT_CTRL2 REG_HDMI(0x44)
+#define HDMI_ACR_PKT_CTRL REG_HDMI(0x24)
+#define HDMI_INFOFRAME_CTRL0 REG_HDMI(0x2C)
+#define HDMI_AUDIO_INFO0 REG_HDMI(0xE4)
+#define HDMI_AUDIO_INFO1 REG_HDMI(0xE8)
+#define HDMI_AUDIO_PKT_CTRL REG_HDMI(0x20)
+#define HDMI_VBI_PKT_CTRL REG_HDMI(0x28)
+#define HDMI_GEN_PKT_CTRL REG_HDMI(0x34)
+#define HDMI_GC REG_HDMI(0x40)
+#define HDMI_AUDIO_CFG REG_HDMI(0x1D0)
+
+#define HDMI_DDC_SPEED REG_HDMI(0x220)
+#define HDMI_DDC_SETUP REG_HDMI(0x224)
+#define HDMI_DDC_REF REG_HDMI(0x27C)
+#define HDMI_DDC_DATA REG_HDMI(0x238)
+#define HDMI_DDC_TRANS0 REG_HDMI(0x228)
+#define HDMI_DDC_TRANS1 REG_HDMI(0x22C)
+#define HDMI_DDC_CTRL REG_HDMI(0x20C)
+#define HDMI_DDC_INT_CTRL REG_HDMI(0x214)
+#define HDMI_DDC_SW_STATUS REG_HDMI(0x218)
+#define HDMI_DDC_ARBITRATION REG_HDMI(0x210)
+
+#define HDMI_USEC_REFTIMER REG_HDMI(0x208)
+#define HDMI_CTRL REG_HDMI(0x000)
+#define HDMI_HPD_INT_STATUS REG_HDMI(0x250)
+#define HDMI_HPD_INT_CTRL REG_HDMI(0x254)
+#define HDMI_HPD_CTRL REG_HDMI(0x258)
+#define HDMI_PHY_CTRL REG_HDMI(0x2D4)
+#define HDMI_TOTAL REG_HDMI(0x2C0)
+#define HDMI_ACTIVE_H REG_HDMI(0x2B4)
+#define HDMI_ACTIVE_V REG_HDMI(0x2B8)
+#define HDMI_V_TOTAL_F2 REG_HDMI(0x2C4)
+#define HDMI_ACTIVE_V_F2 REG_HDMI(0x2BC)
+#define HDMI_FRAME_CTRL REG_HDMI(0x2C8)
+
+#define HDMI_AVI_INFO0 REG_HDMI(0x06C)
+#define HDMI_AVI_INFO1 REG_HDMI(0x070)
+#define HDMI_AVI_INFO2 REG_HDMI(0x074)
+#define HDMI_AVI_INFO3 REG_HDMI(0x078)
+
+#define LPASS_LPAIF_RDDMA_CTL0 0xFE0D2000
+#define LPASS_LPAIF_RDDMA_BASE0 0xFE0D2004
+#define LPASS_LPAIF_RDDMA_BUFF_LEN0 0xFE0D2008
+#define LPASS_LPAIF_RDDMA_PER_LEN0 0xFE0D2010
+#define LPASS_LPAIF_DEBUG_CTL 0xFE0DE004
+
#endif
diff --git a/platform/msm8994/msm8994-clock.c b/platform/msm8994/msm8994-clock.c
index 8653f8d..41efbe3 100644
--- a/platform/msm8994/msm8994-clock.c
+++ b/platform/msm8994/msm8994-clock.c
@@ -48,6 +48,7 @@
#define gpll0_mm_source_val 5
#define edppll_270_mm_source_val 4
#define edppll_350_mm_source_val 4
+#define hdmipll_mm_source_val 3
struct clk_freq_tbl rcg_dummy_freq = F_END;
@@ -794,6 +795,78 @@
},
};
+static struct branch_clk mdss_hdmi_ahb_clk = {
+ .cbcr_reg = (uint32_t *) MDSS_HDMI_AHB_CBCR,
+ .has_sibling = 1,
+ .c = {
+ .dbg_name = "mdss_hdmi_ahb_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
+static struct clk_freq_tbl ftbl_mdss_hdmi_clk[] = {
+ F_MM( 19200000, cxo, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk hdmi_clk_src = {
+ .cmd_reg = (uint32_t *) HDMI_CMD_RCGR,
+ .cfg_reg = (uint32_t *) HDMI_CFG_RCGR,
+ .set_rate = clock_lib2_rcg_set_rate_hid,
+ .freq_tbl = ftbl_mdss_hdmi_clk,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "hdmi_clk_src",
+ .ops = &clk_ops_rcg,
+ },
+};
+
+static struct branch_clk mdss_hdmi_clk = {
+ .cbcr_reg = (uint32_t *) MDSS_HDMI_CBCR,
+ .has_sibling = 0,
+ .parent = &hdmi_clk_src.c,
+ .c = {
+ .dbg_name = "mdss_hdmi_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
+static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
+ F_MDSS( 74250000, hdmipll, 1, 0, 0),
+ F_MDSS( 25200000, hdmipll, 1, 0, 0),
+ F_MDSS( 27000000, hdmipll, 1, 0, 0),
+ F_MDSS( 27030000, hdmipll, 1, 0, 0),
+ F_MDSS( 27070000, hdmipll, 1, 0, 0),
+ F_MDSS( 65000000, hdmipll, 1, 0, 0),
+ F_MDSS(108000000, hdmipll, 1, 0, 0),
+ F_MDSS(148500000, hdmipll, 1, 0, 0),
+ F_MDSS(268500000, hdmipll, 1, 0, 0),
+ F_MDSS(297000000, hdmipll, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk extpclk_clk_src = {
+ .cmd_reg = (uint32_t *) EXTPCLK_CMD_RCGR,
+ .cfg_reg = (uint32_t *) EXTPCLK_CFG_RCGR,
+ .set_rate = clock_lib2_rcg_set_rate_hid,
+ .freq_tbl = ftbl_mdss_extpclk_clk,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "extpclk_clk_src",
+ .ops = &clk_ops_rcg,
+ },
+};
+
+static struct branch_clk mdss_extpclk_clk = {
+ .cbcr_reg = (uint32_t *) MDSS_EXTPCLK_CBCR,
+ .has_sibling = 0,
+ .parent = &extpclk_clk_src.c,
+ .c = {
+ .dbg_name = "mdss_extpclk_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
/* Clock lookup table */
static struct clk_lookup msm_8994_clocks[] =
{
@@ -837,6 +910,10 @@
CLK_LOOKUP("edp_pixel_clk", mdss_edppixel_clk.c),
CLK_LOOKUP("edp_link_clk", mdss_edplink_clk.c),
CLK_LOOKUP("edp_aux_clk", mdss_edpaux_clk.c),
+
+ CLK_LOOKUP("hdmi_ahb_clk", mdss_hdmi_ahb_clk.c),
+ CLK_LOOKUP("hdmi_core_clk", mdss_hdmi_clk.c),
+ CLK_LOOKUP("hdmi_extp_clk", mdss_extpclk_clk.c),
};
void msm8992_sdc1_clock_override()
diff --git a/platform/msm_shared/display.c b/platform/msm_shared/display.c
index ecffcc4..0897b58 100644
--- a/platform/msm_shared/display.c
+++ b/platform/msm_shared/display.c
@@ -290,7 +290,22 @@
if (pdata->clk_func)
ret = pdata->clk_func(1, &(panel->panel_info));
- /* Only enabled for auto PLL calculation */
+ if (ret)
+ goto msm_display_init_out;
+
+ /* Read specifications from panel if available.
+ * If further clocks should be enabled, they can be enabled
+ * using pll_clk_func
+ */
+ if (pdata->update_panel_info)
+ ret = pdata->update_panel_info();
+
+ if (ret)
+ goto msm_display_init_out;
+
+ /* Enabled for auto PLL calculation or to enable
+ * additional clocks
+ */
if (pdata->pll_clk_func)
ret = pdata->pll_clk_func(1, &(panel->panel_info));
diff --git a/platform/msm_shared/flash-ubi.c b/platform/msm_shared/flash-ubi.c
index 0051a3a..9b9dd51 100644
--- a/platform/msm_shared/flash-ubi.c
+++ b/platform/msm_shared/flash-ubi.c
@@ -118,6 +118,30 @@
}
/**
+ * calc_data_len - calculate how much real data is stored in the buffer
+ * @page_size: min I/O of the device
+ * @buf: a buffer with the contents of the physical eraseblock
+ * @len: the buffer length
+ *
+ * This function calculates how much "real data" is stored in @buf and
+ * returns the length (in number of pages). Continuous 0xFF bytes at the end
+ * of the buffer are not considered as "real data".
+ */
+static int calc_data_len(int page_size, const void *buf, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; i--)
+ if (((const uint8_t *)buf)[i] != 0xFF)
+ break;
+
+ /* The resulting length must be aligned to the minimum flash I/O size */
+ len = i + 1;
+ len = (len + page_size - 1) / page_size;
+ return len;
+}
+
+/**
* read_ec_hdr - read and check an erase counter header.
* @peb: number of the physical erase block to read the header for
* @ec_hdr: a &struct ubi_ec_hdr object where to store the read erase counter
@@ -209,6 +233,141 @@
}
/**
+ * read_vid_hdr - read and check an Volume identifier header.
+ * @peb: number of the physical erase block to read the header for
+ * @vid_hdr: a &struct ubi_vid_hdr object where to store the read header
+ * @vid_hdr_offset: offset of the VID header from the beginning of the PEB
+ * (in bytes)
+ *
+ * This function reads the volume identifier header from physical
+ * eraseblock @peb and stores it in @vid_hdr. This function also checks the
+ * validity of the read header.
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ * 1 - if the PEB is free (no VID hdr)
+ */
+static int read_vid_hdr(uint32_t peb, struct ubi_vid_hdr *vid_hdr,
+ int vid_hdr_offset)
+{
+ unsigned char *spare, *tmp_buf;
+ int ret = -1;
+ uint32_t crc, magic;
+ int page_size = flash_page_size();
+ int num_pages_per_blk = flash_block_size()/page_size;
+
+ spare = (unsigned char *)malloc(flash_spare_size());
+ if (!spare)
+ {
+ dprintf(CRITICAL, "read_vid_hdr: Mem allocation failed\n");
+ return ret;
+ }
+
+ tmp_buf = (unsigned char *)malloc(page_size);
+ if (!tmp_buf)
+ {
+ dprintf(CRITICAL, "read_vid_hdr: Mem allocation failed\n");
+ goto out_tmp_buf;
+ }
+
+ if (qpic_nand_block_isbad(peb * num_pages_per_blk)) {
+ dprintf(CRITICAL, "read_vid_hdr: Bad block @ %d\n", peb);
+ goto out;
+ }
+
+ if (qpic_nand_read(peb * num_pages_per_blk + vid_hdr_offset/page_size,
+ 1, tmp_buf, spare)) {
+ dprintf(CRITICAL, "read_vid_hdr: Read %d failed \n", peb);
+ goto out;
+ }
+ memcpy(vid_hdr, tmp_buf, UBI_VID_HDR_SIZE);
+
+ if (check_pattern((void *)vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+ ret = 1;
+ goto out;
+ }
+
+ magic = BE32(vid_hdr->magic);
+ if (magic != UBI_VID_HDR_MAGIC) {
+ dprintf(CRITICAL,
+ "read_vid_hdr: Wrong magic at peb-%d Expected: %d, received %d\n",
+ peb, UBI_VID_HDR_MAGIC, BE32(vid_hdr->magic));
+ goto out;
+ }
+
+ crc = mtd_crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+ if (BE32(vid_hdr->hdr_crc) != crc) {
+ dprintf(CRITICAL,
+ "read_vid_hdr: Wrong crc at peb-%d: calculated %d, received %d\n",
+ peb,crc, BE32(vid_hdr->hdr_crc));
+ goto out;
+ }
+
+ ret = 0;
+out:
+ free(tmp_buf);
+out_tmp_buf:
+ free(spare);
+ return ret;
+}
+
+/**
+ * read_leb_data - read data section of the PEB (LEB).
+ * @peb: number of the physical erase block to read the data for
+ * @leb_data: a buffer where to store the read data at
+ * @leb_size: LEB size
+ * @data_offset: offset of the data from the beginning of the PEB
+ * (in bytes)
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+static int read_leb_data(uint32_t peb, void *leb_data,
+ int leb_size, int data_offset)
+{
+ unsigned char *spare, *tmp_buf;
+ int ret = -1;
+ int page_size = flash_page_size();
+ int block_size = flash_block_size();
+ int num_pages_per_blk = block_size/page_size;
+
+ spare = (unsigned char *)malloc(flash_spare_size());
+ if (!spare)
+ {
+ dprintf(CRITICAL, "read_leb_data: Mem allocation failed\n");
+ return ret;
+ }
+
+ tmp_buf = (unsigned char *)malloc(leb_size);
+ if (!tmp_buf)
+ {
+ dprintf(CRITICAL, "read_leb_data: Mem allocation failed\n");
+ goto out_tmp_buf;
+ }
+
+ if (qpic_nand_block_isbad(peb * num_pages_per_blk)) {
+ dprintf(CRITICAL, "read_leb_data: Bad block @ %d\n", peb);
+ goto out;
+ }
+
+ if (qpic_nand_read(peb * num_pages_per_blk + data_offset/page_size,
+ leb_size/page_size, tmp_buf, spare)) {
+ dprintf(CRITICAL, "read_leb_data: Read %d failed \n", peb);
+ goto out;
+ }
+ memcpy(leb_data, tmp_buf, leb_size);
+
+ ret = 0;
+out:
+ free(tmp_buf);
+out_tmp_buf:
+ free(spare);
+ return ret;
+}
+
+/**
* write_ec_header() - Write provided ec_header for given PEB
* @peb: number of the physical erase block to write the header to
* @new_ech: the ec_header to write
@@ -247,6 +406,97 @@
}
/**
+ * write_vid_header() - Write provided vid_header for given PEB
+ * @peb: number of the physical erase block to write the header to
+ * @new_vidh: the vid_header to write
+ * @offset: vid_hdr offset in bytes from the beginning of the PEB
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+static int write_vid_header(uint32_t peb,
+ struct ubi_vid_hdr *new_vidh, int offset)
+{
+ unsigned page_size = flash_page_size();
+ int num_pages_per_blk = flash_block_size()/page_size;
+ unsigned char *buf;
+ int ret = 0;
+
+ buf = malloc(sizeof(uint8_t) * page_size);
+ if (!buf) {
+ dprintf(CRITICAL, "write_vid_header: Mem allocation failed\n");
+ return -1;
+ }
+
+ memset(buf, 0, page_size);
+ ASSERT(page_size > sizeof(*new_vidh));
+ memcpy(buf, new_vidh, UBI_VID_HDR_SIZE);
+ ret = qpic_nand_write(peb * num_pages_per_blk + offset/page_size,
+ 1, buf, 0);
+ if (ret) {
+ dprintf(CRITICAL,
+ "write_vid_header: qpic_nand_write failed with %d\n", ret);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ free(buf);
+ return ret;
+}
+
+/**
+ * write_leb_data - write data section of the PEB (LEB).
+ * @peb: number of the physical erase block to write the data for
+ * @leb_data: a data buffer to write
+ * @size: data size
+ * @data_offset: offset of the data from the beginning of the PEB
+ * (in bytes)
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+static int write_leb_data(uint32_t peb, void *data,
+ int size, int data_offset)
+{
+ unsigned char *tmp_buf;
+ int ret = -1;
+ int num_pages;
+ int page_size = flash_page_size();
+ int block_size = flash_block_size();
+ int num_pages_per_blk = block_size/page_size;
+
+ tmp_buf = (unsigned char *)malloc(block_size - data_offset);
+ if (!tmp_buf)
+ {
+ dprintf(CRITICAL, "write_leb_data: Mem allocation failed\n");
+ return -1;
+ }
+
+ if (size < block_size - data_offset)
+ num_pages = size / page_size;
+ else
+ num_pages = calc_data_len(page_size, data,
+ block_size - data_offset);
+ memcpy(tmp_buf, data, num_pages * page_size);
+ ret = qpic_nand_write(peb * num_pages_per_blk + data_offset/page_size,
+ num_pages, tmp_buf, 0);
+ if (ret) {
+ dprintf(CRITICAL,
+ "write_vid_header: qpic_nand_write failed with %d\n", ret);
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ free(tmp_buf);
+ return ret;
+}
+
+/**
* scan_partition() - Collect the ec_headers info of a given partition
* @ptn: partition to read the headers of
*
@@ -257,7 +507,8 @@
{
struct ubi_scan_info *si;
struct ubi_ec_hdr *ec_hdr;
- unsigned i, curr_peb;
+ struct ubi_vid_hdr vid_hdr;
+ unsigned i;
unsigned long long sum = 0;
int page_size = flash_page_size();
int ret;
@@ -270,13 +521,13 @@
}
memset((void *)si, 0, sizeof(*si));
- si->ec = malloc(ptn->length * sizeof(uint64_t));
- if (!si->ec) {
+ si->pebs_data = malloc(ptn->length * sizeof(struct peb_info));
+ if (!si->pebs_data) {
dprintf(CRITICAL,"scan_partition: (%s) Memory allocation failed\n",
ptn->name);
- goto out_failed_ec;
+ goto out_failed_pebs;
}
- memset((void *)si->ec, 0, ptn->length * sizeof(uint64_t));
+ memset((void *)si->pebs_data, 0, ptn->length * sizeof(struct peb_info));
ec_hdr = malloc(UBI_EC_HDR_SIZE);
if (!ec_hdr) {
@@ -285,16 +536,18 @@
goto out_failed;
}
- curr_peb = ptn->start;
si->vid_hdr_offs = 0;
si->image_seq = rand() & UBI_IMAGE_SEQ_BASE;
-
+ si->vtbl_peb1 = -1;
+ si->vtbl_peb2 = -1;
+ si->fastmap_sb = -1;
for (i = 0; i < ptn->length; i++){
- ret = read_ec_hdr(curr_peb + i, ec_hdr);
+ ret = read_ec_hdr(ptn->start + i, ec_hdr);
switch (ret) {
case 1:
si->empty_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].status = UBI_EMPTY_PEB;
break;
case 0:
if (!si->vid_hdr_offs) {
@@ -304,44 +557,83 @@
si->vid_hdr_offs % page_size ||
si->data_offs % page_size) {
si->bad_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
si->vid_hdr_offs = 0;
continue;
}
if (BE32(ec_hdr->vid_hdr_offset) != si->vid_hdr_offs) {
si->bad_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
continue;
}
if (BE32(ec_hdr->data_offset) != si->data_offs) {
si->bad_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
continue;
}
}
- si->good_cnt++;
- si->ec[i] = BE64(ec_hdr->ec);
+ si->read_image_seq = BE32(ec_hdr->image_seq);
+ si->pebs_data[i].ec = BE64(ec_hdr->ec);
+ /* Now read the VID header to find if the peb is free */
+ ret = read_vid_hdr(ptn->start + i, &vid_hdr,
+ BE32(ec_hdr->vid_hdr_offset));
+ switch (ret) {
+ case 1:
+ si->pebs_data[i].status = UBI_FREE_PEB;
+ si->free_cnt++;
+ break;
+ case 0:
+ si->pebs_data[i].status = UBI_USED_PEB;
+ si->pebs_data[i].volume = BE32(vid_hdr.vol_id);
+ if (BE32(vid_hdr.vol_id) == UBI_LAYOUT_VOLUME_ID) {
+ if (si->vtbl_peb1 == -1)
+ si->vtbl_peb1 = i;
+ else if (si->vtbl_peb2 == -1)
+ si->vtbl_peb2 = i;
+ else
+ dprintf(CRITICAL,
+ "scan_partition: Found > 2 copies of vtbl");
+ }
+ if (BE32(vid_hdr.vol_id) == UBI_FM_SB_VOLUME_ID)
+ si->fastmap_sb = i;
+ si->used_cnt++;
+ break;
+ case -1:
+ default:
+ si->bad_cnt++;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].status = UBI_BAD_PEB;
+ break;
+ }
break;
case -1:
default:
si->bad_cnt++;
- si->ec[i] = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+ si->pebs_data[i].status = UBI_BAD_PEB;
break;
}
}
+ /* Sanity check */
+ if (si->bad_cnt + si->empty_cnt + si->free_cnt + si->used_cnt != (int)ptn->length) {
+ dprintf(CRITICAL,"scan_partition: peb count doesn't sum up \n");
+ goto out_failed;
+ }
+
/*
* If less then 95% of the PEBs were "bad" (didn't have valid
* ec header), then set mean_ec = UBI_DEF_ERACE_COUNTER.
*/
sum = 0;
- if (si->good_cnt && (double)(si->good_cnt / ptn->length) * 100 > 95) {
+ if ((si->free_cnt + si->used_cnt) &&
+ (double)((si->free_cnt + si->used_cnt) / ptn->length) * 100 > 95) {
for (i = 0; i < ptn->length; i++) {
- if (si->ec[i] == UBI_MAX_ERASECOUNTER)
+ if (si->pebs_data[i].ec == UBI_MAX_ERASECOUNTER)
continue;
- sum += si->ec[i];
+ sum += si->pebs_data[i].ec;
}
- si->mean_ec = sum / si->good_cnt;
+ si->mean_ec = sum / (si->free_cnt + si->used_cnt);
} else {
si->mean_ec = UBI_DEF_ERACE_COUNTER;
}
@@ -349,8 +641,8 @@
return si;
out_failed:
- free(si->ec);
-out_failed_ec:
+ free(si->pebs_data);
+out_failed_pebs:
free(si);
return NULL;
}
@@ -369,8 +661,8 @@
{
uint32_t crc;
- if (si->ec[index] < UBI_MAX_ERASECOUNTER)
- old_ech->ec = BE64(si->ec[index] + 1);
+ if (si->pebs_data[index].ec < UBI_MAX_ERASECOUNTER)
+ old_ech->ec = BE64(si->pebs_data[index].ec + 1);
else
old_ech->ec = BE64(si->mean_ec);
@@ -386,28 +678,25 @@
old_ech->hdr_crc = BE32(crc);
}
-/**
- * calc_data_len - calculate how much real data is stored in the buffer
- * @page_size: min I/O of the device
- * @buf: a buffer with the contents of the physical eraseblock
- * @len: the buffer length
- *
- * This function calculates how much "real data" is stored in @buf and
- * returns the length (in number of pages). Continuous 0xFF bytes at the end
- * of the buffer are not considered as "real data".
- */
-static int calc_data_len(int page_size, const void *buf, int len)
+
+static void update_vid_header(struct ubi_vid_hdr *vid_hdr,
+ const struct ubi_scan_info *si, uint32_t vol_id,
+ uint32_t lnum, uint32_t data_pad)
{
- int i;
+ uint32_t crc;
- for (i = len - 1; i >= 0; i--)
- if (((const uint8_t *)buf)[i] != 0xFF)
- break;
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->sqnum = BE64(si->image_seq);
+ vid_hdr->vol_id = BE32(vol_id);
+ vid_hdr->lnum = BE32(lnum);
+ vid_hdr->compat = 0;
+ vid_hdr->data_pad = BE32(data_pad);
- /* The resulting length must be aligned to the minimum flash I/O size */
- len = i + 1;
- len = (len + page_size - 1) / page_size;
- return len;
+ vid_hdr->magic = BE32(UBI_VID_HDR_MAGIC);
+ vid_hdr->version = UBI_VERSION;
+ crc = mtd_crc32(UBI_CRC32_INIT,
+ (const void *)vid_hdr, UBI_VID_HDR_SIZE_CRC);
+ vid_hdr->hdr_crc = BE32(crc);
}
/**
@@ -450,7 +739,7 @@
int ret;
if (need_erase && qpic_nand_blk_erase(peb_num * num_pages_per_blk)) {
- dprintf(INFO, "flash_ubi_img: erase of %d failed\n", peb_num);
+ dprintf(INFO, "ubi_erase_peb: erase of %d failed\n", peb_num);
return -1;
}
memset(&new_ech, 0xff, sizeof(new_ech));
@@ -459,10 +748,11 @@
/* Write new ec_header */
ret = write_ec_header(peb_num, &new_ech);
if (ret) {
- dprintf(CRITICAL, "flash_ubi_img: write ec_header to %d failed\n",
+ dprintf(CRITICAL, "ubi_erase_peb: write ec_header to %d failed\n",
peb_num);
return -1;
}
+ si->pebs_data[peb_num - ptn_start].status = UBI_FREE_PEB;
return 0;
}
@@ -609,7 +899,224 @@
}
out:
- free(si->ec);
+ free(si->pebs_data);
free(si);
return ret;
}
+
+/**
+ * find_volume() - Find given volume in a partition by it's name
+ * @si: pointer to struct ubi_scan_info
+ * @ptn_start: PEB number the partition begins at
+ * @vol_name: name of the volume to search for
+ * @vol_info: info obout the found volume
+ *
+ * This functions reads the volume table, then iterates over all its records
+ * and searches for a volume with a given name. If found, the volume table
+ * record describing this volume is returned at @vol_info. The volume
+ * id returned as a return code of the function.
+ *
+ * Returns:
+ * -1 - if the volume was not found
+ * volume in dex when found
+ */
+static int find_volume(struct ubi_scan_info *si, int ptn_start,
+ const char *vol_name, struct ubi_vtbl_record *vol_info)
+{
+ int i, vtbl_records, vtbl_peb, ret = -1;
+ int block_size = flash_block_size();
+ void *leb_data;
+ struct ubi_vtbl_record *curr_vol;
+
+ if (si->vtbl_peb1 < 0) {
+ dprintf(CRITICAL,"find_volume: vtbl not found \n");
+ return -1;
+ }
+ vtbl_peb = si->vtbl_peb1;
+
+ vtbl_records = (block_size - si->data_offs) / UBI_VTBL_RECORD_SIZE;
+ if (vtbl_records > UBI_MAX_VOLUMES)
+ vtbl_records = UBI_MAX_VOLUMES;
+
+ leb_data = malloc(block_size - si->data_offs);
+ if (!leb_data) {
+ dprintf(CRITICAL,"find_volume: Memory allocation failed\n");
+ goto out_free_leb;
+ }
+retry:
+ /* First read the volume table */
+ if (read_leb_data(vtbl_peb + ptn_start, leb_data,
+ block_size - si->data_offs, si->data_offs)) {
+ dprintf(CRITICAL,"find_volume: read_leb_data failed\n");
+ if (vtbl_peb == si->vtbl_peb1 && si->vtbl_peb2 != -1) {
+ vtbl_peb = si->vtbl_peb2;
+ goto retry;
+ }
+ goto out_free_leb;
+ }
+
+ /* Now search for the required volume ID */
+ for (i = 0; i < vtbl_records; i++) {
+ curr_vol = (struct ubi_vtbl_record *)
+ (leb_data + UBI_VTBL_RECORD_SIZE*i);
+ if (!curr_vol->vol_type)
+ break;
+ if (!strcmp((char *)curr_vol->name, vol_name)) {
+ ret = i;
+ memcpy((void*)vol_info, curr_vol, sizeof(struct ubi_vtbl_record));
+ break;
+ }
+ }
+
+out_free_leb:
+ free(leb_data);
+ return ret;
+}
+
+/**
+ * write_one_peb() - writes data to a PEB, including VID header
+ * @curr_peb - PEB to write to
+ * @ptn_start: number of first PEB of the partition
+ * @si: pointer to struct ubi_scan_info
+ * @idx: index of required PEB in si->pebs_data array
+ * @lnum: lun number this LEB belongs to
+ * @vol_id: volume ID this PEB belongs to
+ * @data: data to write
+ * @size: size of the data
+ *
+ * Assumption: EC header correctly written and PEB erased
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+static int write_one_peb(int curr_peb, int ptn_start,
+ struct ubi_scan_info *si,
+ int lnum, int vol_id, void* data, int size)
+{
+ int ret;
+ struct ubi_vid_hdr vidh;
+
+ memset((void *)&vidh, 0, UBI_VID_HDR_SIZE);
+ update_vid_header(&vidh, si, vol_id, lnum, 0);
+ if (write_vid_header(curr_peb + ptn_start, &vidh, si->vid_hdr_offs)) {
+ dprintf(CRITICAL,
+ "update_ubi_vol: write_vid_header for peb %d failed \n",
+ curr_peb);
+ ret = -1;
+ goto out;
+ }
+
+ /* now write the data */
+ ret = write_leb_data(curr_peb + ptn_start, data, size, si->data_offs);
+ if (ret)
+ dprintf(CRITICAL, "update_ubi_vol: writing data to peb-%d failed\n",
+ curr_peb);
+ else
+ si->pebs_data[curr_peb].status = UBI_USED_PEB;
+out:
+ return ret;
+}
+
+/**
+ * update_ubi_vol() - Write the provided (UBI) image to given volume
+ * @ptn: partition holding the required volume
+ * @data: the image to write
+ * @size: size of the image to write
+ *
+ * Return codes:
+ * -1 - in case of error
+ * 0 - on success
+ */
+int update_ubi_vol(struct ptentry *ptn, const char* vol_name,
+ void *data, unsigned size)
+{
+ struct ubi_scan_info *si;
+ int vol_id, vol_pebs, curr_peb = 0, ret = -1;
+ unsigned block_size = flash_block_size();
+ void *img_peb;
+ struct ubi_vtbl_record curr_vol;
+ int img_pebs, lnum = 0;
+
+ si = scan_partition(ptn);
+ if (!si) {
+ dprintf(CRITICAL, "update_ubi_vol: scan_partition failed\n");
+ return -1;
+ }
+ if (si->read_image_seq)
+ si->image_seq = si->read_image_seq;
+
+ vol_id = find_volume(si, ptn->start, vol_name, &curr_vol);
+ if (vol_id == -1) {
+ dprintf(CRITICAL, "update_ubi_vol: dint find volume\n");
+ goto out;
+ }
+ if (si->fastmap_sb > -1 &&
+ ubi_erase_peb(ptn->start + si->fastmap_sb, 1, si, ptn->start)) {
+ dprintf(CRITICAL, "update_ubi_vol: fastmap invalidation failed\n");
+ goto out;
+ }
+
+ img_pebs = size / (block_size - si->data_offs);
+ if (size % (block_size - si->data_offs))
+ img_pebs++;
+
+ vol_pebs = BE32(curr_vol.reserved_pebs);
+ if (img_pebs > vol_pebs) {
+ dprintf(CRITICAL,
+ "update_ubi_vol: Provided image is too big. Requires %d PEBs, avail. only %d\n",
+ img_pebs, vol_pebs);
+ goto out;
+ }
+
+ /* First erase all volume used PEBs */
+ curr_peb = 0;
+ while (curr_peb < (int)ptn->length) {
+ if (si->pebs_data[curr_peb].status != UBI_USED_PEB ||
+ si->pebs_data[curr_peb].volume != vol_id) {
+ curr_peb++;
+ continue;
+ }
+ if (ubi_erase_peb(ptn->start + curr_peb, 1, si, ptn->start))
+ goto out;
+ curr_peb++;
+ }
+
+ /* Flash the image */
+ img_peb = data;
+ lnum = 0;
+ for (curr_peb = 0;
+ curr_peb < (int)ptn->length && size && vol_pebs;
+ curr_peb++) {
+ if (si->pebs_data[curr_peb].status != UBI_FREE_PEB &&
+ si->pebs_data[curr_peb].status != UBI_EMPTY_PEB)
+ continue;
+
+ if (write_one_peb(curr_peb, ptn->start, si,
+ lnum++, vol_id, img_peb,
+ (size < block_size - si->data_offs ? size :
+ block_size - si->data_offs))) {
+ dprintf(CRITICAL, "update_ubi_vol: write_one_peb failed\n");
+ goto out;
+ }
+ if (size < block_size - si->data_offs)
+ size = 0;
+ else
+ size -= (block_size - si->data_offs);
+ vol_pebs--;
+ img_peb += block_size - si->data_offs;
+ }
+
+ if (size) {
+ dprintf(CRITICAL,
+ "update_ubi_vol: Not enough available PEBs for writing the volume\n");
+ goto out;
+ }
+ ret = 0;
+out:
+ free(si->pebs_data);
+ free(si);
+ return ret;
+}
+
+
diff --git a/platform/msm_shared/hdmi_pll_20nm.c b/platform/msm_shared/hdmi_pll_20nm.c
new file mode 100644
index 0000000..6c2aeeb
--- /dev/null
+++ b/platform/msm_shared/hdmi_pll_20nm.c
@@ -0,0 +1,1059 @@
+/* Copyright (c) 2015, 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 met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <err.h>
+#include <reg.h>
+#include <smem.h>
+#include <bits.h>
+#include <msm_panel.h>
+#include <platform/timer.h>
+#include <platform/iomap.h>
+
+
+#define HDMI_PHY_CMD_SIZE 68
+#define HDMI_PHY_CLK_SIZE 97
+
+#define HDMI_PHY_BASE 0xFD9A9200
+#define HDMI_PLL_BASE 0xFD9A8600
+
+/* hdmi phy registers */
+enum {
+ CALC_QSERDES_COM_SYSCLK_EN_SEL_TXBAND = 0,
+ CALC_QSERDES_COM_DIV_REF1,
+ CALC_QSERDES_COM_DIV_REF2,
+ CALC_QSERDES_COM_KVCO_COUNT1,
+ CALC_QSERDES_COM_KVCO_COUNT2,
+ CALC_QSERDES_COM_KVCO_CAL_CNTRL,
+ CALC_QSERDES_COM_KVCO_CODE,
+ CALC_QSERDES_COM_VREF_CFG3,
+ CALC_QSERDES_COM_VREF_CFG4,
+ CALC_QSERDES_COM_VREF_CFG5,
+ CALC_QSERDES_COM_PLL_IP_SETI,
+ CALC_QSERDES_COM_PLL_CP_SETI,
+ CALC_QSERDES_COM_PLL_IP_SETP,
+ CALC_QSERDES_COM_PLL_CP_SETP,
+ CALC_QSERDES_COM_PLL_CRCTRL,
+ CALC_QSERDES_COM_DIV_FRAC_START1,
+ CALC_QSERDES_COM_DIV_FRAC_START2,
+ CALC_QSERDES_COM_DIV_FRAC_START3,
+ CALC_QSERDES_COM_DEC_START1,
+ CALC_QSERDES_COM_DEC_START2,
+ CALC_QSERDES_COM_PLLLOCK_CMP1,
+ CALC_QSERDES_COM_PLLLOCK_CMP2,
+ CALC_QSERDES_COM_PLLLOCK_CMP3,
+ CALC_QSERDES_COM_PLLLOCK_CMP_EN,
+ CALC_QSERDES_COM_RESETSM_CNTRL,
+ CALC_HDMI_PHY_MODE,
+ CALC_MAX
+};
+
+/* Set to 1 for auto KVCO cal; set to 0 for fixed value */
+#define HDMI_PHY_AUTO_KVCO_CAL 1
+
+/* PLL REGISTERS */
+#define QSERDES_COM_SYS_CLK_CTRL (0x000)
+#define QSERDES_COM_PLL_VCOTAIL_EN (0x004)
+#define QSERDES_COM_CMN_MODE (0x008)
+#define QSERDES_COM_IE_TRIM (0x00C)
+#define QSERDES_COM_IP_TRIM (0x010)
+#define QSERDES_COM_PLL_CNTRL (0x014)
+#define QSERDES_COM_PLL_PHSEL_CONTROL (0x018)
+#define QSERDES_COM_IPTAT_TRIM_VCCA_TX_SEL (0x01C)
+#define QSERDES_COM_PLL_PHSEL_DC (0x020)
+#define QSERDES_COM_PLL_IP_SETI (0x024)
+#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL (0x028)
+#define QSERDES_COM_PLL_BKG_KVCO_CAL_EN (0x02C)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x030)
+#define QSERDES_COM_PLL_CP_SETI (0x034)
+#define QSERDES_COM_PLL_IP_SETP (0x038)
+#define QSERDES_COM_PLL_CP_SETP (0x03C)
+#define QSERDES_COM_ATB_SEL1 (0x040)
+#define QSERDES_COM_ATB_SEL2 (0x044)
+#define QSERDES_COM_SYSCLK_EN_SEL_TXBAND (0x048)
+#define QSERDES_COM_RESETSM_CNTRL (0x04C)
+#define QSERDES_COM_RESETSM_CNTRL2 (0x050)
+#define QSERDES_COM_RESETSM_CNTRL3 (0x054)
+#define QSERDES_COM_RESETSM_PLL_CAL_COUNT1 (0x058)
+#define QSERDES_COM_RESETSM_PLL_CAL_COUNT2 (0x05C)
+#define QSERDES_COM_DIV_REF1 (0x060)
+#define QSERDES_COM_DIV_REF2 (0x064)
+#define QSERDES_COM_KVCO_COUNT1 (0x068)
+#define QSERDES_COM_KVCO_COUNT2 (0x06C)
+#define QSERDES_COM_KVCO_CAL_CNTRL (0x070)
+#define QSERDES_COM_KVCO_CODE (0x074)
+#define QSERDES_COM_VREF_CFG1 (0x078)
+#define QSERDES_COM_VREF_CFG2 (0x07C)
+#define QSERDES_COM_VREF_CFG3 (0x080)
+#define QSERDES_COM_VREF_CFG4 (0x084)
+#define QSERDES_COM_VREF_CFG5 (0x088)
+#define QSERDES_COM_VREF_CFG6 (0x08C)
+#define QSERDES_COM_PLLLOCK_CMP1 (0x090)
+#define QSERDES_COM_PLLLOCK_CMP2 (0x094)
+#define QSERDES_COM_PLLLOCK_CMP3 (0x098)
+#define QSERDES_COM_PLLLOCK_CMP_EN (0x09C)
+#define QSERDES_COM_BGTC (0x0A0)
+#define QSERDES_COM_PLL_TEST_UPDN (0x0A4)
+#define QSERDES_COM_PLL_VCO_TUNE (0x0A8)
+#define QSERDES_COM_DEC_START1 (0x0AC)
+#define QSERDES_COM_PLL_AMP_OS (0x0B0)
+#define QSERDES_COM_SSC_EN_CENTER (0x0B4)
+#define QSERDES_COM_SSC_ADJ_PER1 (0x0B8)
+#define QSERDES_COM_SSC_ADJ_PER2 (0x0BC)
+#define QSERDES_COM_SSC_PER1 (0x0C0)
+#define QSERDES_COM_SSC_PER2 (0x0C4)
+#define QSERDES_COM_SSC_STEP_SIZE1 (0x0C8)
+#define QSERDES_COM_SSC_STEP_SIZE2 (0x0CC)
+#define QSERDES_COM_RES_CODE_UP (0x0D0)
+#define QSERDES_COM_RES_CODE_DN (0x0D4)
+#define QSERDES_COM_RES_CODE_UP_OFFSET (0x0D8)
+#define QSERDES_COM_RES_CODE_DN_OFFSET (0x0DC)
+#define QSERDES_COM_RES_CODE_START_SEG1 (0x0E0)
+#define QSERDES_COM_RES_CODE_START_SEG2 (0x0E4)
+#define QSERDES_COM_RES_CODE_CAL_CSR (0x0E8)
+#define QSERDES_COM_RES_CODE (0x0EC)
+#define QSERDES_COM_RES_TRIM_CONTROL (0x0F0)
+#define QSERDES_COM_RES_TRIM_CONTROL2 (0x0F4)
+#define QSERDES_COM_RES_TRIM_EN_VCOCALDONE (0x0F8)
+#define QSERDES_COM_FAUX_EN (0x0FC)
+#define QSERDES_COM_DIV_FRAC_START1 (0x100)
+#define QSERDES_COM_DIV_FRAC_START2 (0x104)
+#define QSERDES_COM_DIV_FRAC_START3 (0x108)
+#define QSERDES_COM_DEC_START2 (0x10C)
+#define QSERDES_COM_PLL_RXTXEPCLK_EN (0x110)
+#define QSERDES_COM_PLL_CRCTRL (0x114)
+#define QSERDES_COM_PLL_CLKEPDIV (0x118)
+#define QSERDES_COM_PLL_FREQUPDATE (0x11C)
+#define QSERDES_COM_PLL_BKGCAL_TRIM_UP (0x120)
+#define QSERDES_COM_PLL_BKGCAL_TRIM_DN (0x124)
+#define QSERDES_COM_PLL_BKGCAL_TRIM_MUX (0x128)
+#define QSERDES_COM_PLL_BKGCAL_VREF_CFG (0x12C)
+#define QSERDES_COM_PLL_BKGCAL_DIV_REF1 (0x130)
+#define QSERDES_COM_PLL_BKGCAL_DIV_REF2 (0x134)
+#define QSERDES_COM_MUXADDR (0x138)
+#define QSERDES_COM_LOW_POWER_RO_CONTROL (0x13C)
+#define QSERDES_COM_POST_DIVIDER_CONTROL (0x140)
+#define QSERDES_COM_HR_OCLK2_DIVIDER (0x144)
+#define QSERDES_COM_HR_OCLK3_DIVIDER (0x148)
+#define QSERDES_COM_PLL_VCO_HIGH (0x14C)
+#define QSERDES_COM_RESET_SM (0x150)
+#define QSERDES_COM_MUXVAL (0x154)
+#define QSERDES_COM_CORE_RES_CODE_DN (0x158)
+#define QSERDES_COM_CORE_RES_CODE_UP (0x15C)
+#define QSERDES_COM_CORE_VCO_TUNE (0x160)
+#define QSERDES_COM_CORE_VCO_TAIL (0x164)
+#define QSERDES_COM_CORE_KVCO_CODE (0x168)
+
+/* Tx Channel 0 REGISTERS */
+#define QSERDES_TX_L0_BIST_MODE_LANENO (0x00)
+#define QSERDES_TX_L0_CLKBUF_ENABLE (0x04)
+#define QSERDES_TX_L0_TX_EMP_POST1_LVL (0x08)
+#define QSERDES_TX_L0_TX_DRV_LVL (0x0C)
+#define QSERDES_TX_L0_RESET_TSYNC_EN (0x10)
+#define QSERDES_TX_L0_LPB_EN (0x14)
+#define QSERDES_TX_L0_RES_CODE_UP (0x18)
+#define QSERDES_TX_L0_RES_CODE_DN (0x1C)
+#define QSERDES_TX_L0_PERL_LENGTH1 (0x20)
+#define QSERDES_TX_L0_PERL_LENGTH2 (0x24)
+#define QSERDES_TX_L0_SERDES_BYP_EN_OUT (0x28)
+#define QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x2C)
+#define QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN (0x30)
+#define QSERDES_TX_L0_BIST_PATTERN1 (0x34)
+#define QSERDES_TX_L0_BIST_PATTERN2 (0x38)
+#define QSERDES_TX_L0_BIST_PATTERN3 (0x3C)
+#define QSERDES_TX_L0_BIST_PATTERN4 (0x40)
+#define QSERDES_TX_L0_BIST_PATTERN5 (0x44)
+#define QSERDES_TX_L0_BIST_PATTERN6 (0x48)
+#define QSERDES_TX_L0_BIST_PATTERN7 (0x4C)
+#define QSERDES_TX_L0_BIST_PATTERN8 (0x50)
+#define QSERDES_TX_L0_LANE_MODE (0x54)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE (0x58)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE_CONFIGURATION (0x5C)
+#define QSERDES_TX_L0_ATB_SEL1 (0x60)
+#define QSERDES_TX_L0_ATB_SEL2 (0x64)
+#define QSERDES_TX_L0_RCV_DETECT_LVL (0x68)
+#define QSERDES_TX_L0_PRBS_SEED1 (0x6C)
+#define QSERDES_TX_L0_PRBS_SEED2 (0x70)
+#define QSERDES_TX_L0_PRBS_SEED3 (0x74)
+#define QSERDES_TX_L0_PRBS_SEED4 (0x78)
+#define QSERDES_TX_L0_RESET_GEN (0x7C)
+#define QSERDES_TX_L0_TRAN_DRVR_EMP_EN (0x80)
+#define QSERDES_TX_L0_TX_INTERFACE_MODE (0x84)
+#define QSERDES_TX_L0_PWM_CTRL (0x88)
+#define QSERDES_TX_L0_PWM_DATA (0x8C)
+#define QSERDES_TX_L0_PWM_ENC_DIV_CTRL (0x90)
+#define QSERDES_TX_L0_VMODE_CTRL1 (0x94)
+#define QSERDES_TX_L0_VMODE_CTRL2 (0x98)
+#define QSERDES_TX_L0_VMODE_CTRL3 (0x9C)
+#define QSERDES_TX_L0_VMODE_CTRL4 (0xA0)
+#define QSERDES_TX_L0_VMODE_CTRL5 (0xA4)
+#define QSERDES_TX_L0_VMODE_CTRL6 (0xA8)
+#define QSERDES_TX_L0_VMODE_CTRL7 (0xAC)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV_CNTL (0xB0)
+#define QSERDES_TX_L0_BIST_STATUS (0xB4)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT1 (0xB8)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT2 (0xBC)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV (0xC0)
+#define QSERDES_TX_L0_PWM_DEC_STATUS (0xC4)
+
+/* Tx Channel 1 REGISTERS */
+#define QSERDES_TX_L1_BIST_MODE_LANENO (0x00)
+#define QSERDES_TX_L1_CLKBUF_ENABLE (0x04)
+#define QSERDES_TX_L1_TX_EMP_POST1_LVL (0x08)
+#define QSERDES_TX_L1_TX_DRV_LVL (0x0C)
+#define QSERDES_TX_L1_RESET_TSYNC_EN (0x10)
+#define QSERDES_TX_L1_LPB_EN (0x14)
+#define QSERDES_TX_L1_RES_CODE_UP (0x18)
+#define QSERDES_TX_L1_RES_CODE_DN (0x1C)
+#define QSERDES_TX_L1_PERL_LENGTH1 (0x20)
+#define QSERDES_TX_L1_PERL_LENGTH2 (0x24)
+#define QSERDES_TX_L1_SERDES_BYP_EN_OUT (0x28)
+#define QSERDES_TX_L1_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x2C)
+#define QSERDES_TX_L1_PARRATE_REC_DETECT_IDLE_EN (0x30)
+#define QSERDES_TX_L1_BIST_PATTERN1 (0x34)
+#define QSERDES_TX_L1_BIST_PATTERN2 (0x38)
+#define QSERDES_TX_L1_BIST_PATTERN3 (0x3C)
+#define QSERDES_TX_L1_BIST_PATTERN4 (0x40)
+#define QSERDES_TX_L1_BIST_PATTERN5 (0x44)
+#define QSERDES_TX_L1_BIST_PATTERN6 (0x48)
+#define QSERDES_TX_L1_BIST_PATTERN7 (0x4C)
+#define QSERDES_TX_L1_BIST_PATTERN8 (0x50)
+#define QSERDES_TX_L1_LANE_MODE (0x54)
+#define QSERDES_TX_L1_IDAC_CAL_LANE_MODE (0x58)
+#define QSERDES_TX_L1_IDAC_CAL_LANE_MODE_CONFIGURATION (0x5C)
+#define QSERDES_TX_L1_ATB_SEL1 (0x60)
+#define QSERDES_TX_L1_ATB_SEL2 (0x64)
+#define QSERDES_TX_L1_RCV_DETECT_LVL (0x68)
+#define QSERDES_TX_L1_PRBS_SEED1 (0x6C)
+#define QSERDES_TX_L1_PRBS_SEED2 (0x70)
+#define QSERDES_TX_L1_PRBS_SEED3 (0x74)
+#define QSERDES_TX_L1_PRBS_SEED4 (0x78)
+#define QSERDES_TX_L1_RESET_GEN (0x7C)
+#define QSERDES_TX_L1_TRAN_DRVR_EMP_EN (0x80)
+#define QSERDES_TX_L1_TX_INTERFACE_MODE (0x84)
+#define QSERDES_TX_L1_PWM_CTRL (0x88)
+#define QSERDES_TX_L1_PWM_DATA (0x8C)
+#define QSERDES_TX_L1_PWM_ENC_DIV_CTRL (0x90)
+#define QSERDES_TX_L1_VMODE_CTRL1 (0x94)
+#define QSERDES_TX_L1_VMODE_CTRL2 (0x98)
+#define QSERDES_TX_L1_VMODE_CTRL3 (0x9C)
+#define QSERDES_TX_L1_VMODE_CTRL4 (0xA0)
+#define QSERDES_TX_L1_VMODE_CTRL5 (0xA4)
+#define QSERDES_TX_L1_VMODE_CTRL6 (0xA8)
+#define QSERDES_TX_L1_VMODE_CTRL7 (0xAC)
+#define QSERDES_TX_L1_TX_ALOG_INTF_OBSV_CNTL (0xB0)
+#define QSERDES_TX_L1_BIST_STATUS (0xB4)
+#define QSERDES_TX_L1_BIST_ERROR_COUNT1 (0xB8)
+#define QSERDES_TX_L1_BIST_ERROR_COUNT2 (0xBC)
+#define QSERDES_TX_L1_TX_ALOG_INTF_OBSV (0xC0)
+#define QSERDES_TX_L1_PWM_DEC_STATUS (0xC4)
+
+/* Tx Channel 2 REGISERS */
+#define QSERDES_TX_L2_BIST_MODE_LANENO (0x00)
+#define QSERDES_TX_L2_CLKBUF_ENABLE (0x04)
+#define QSERDES_TX_L2_TX_EMP_POST1_LVL (0x08)
+#define QSERDES_TX_L2_TX_DRV_LVL (0x0C)
+#define QSERDES_TX_L2_RESET_TSYNC_EN (0x10)
+#define QSERDES_TX_L2_LPB_EN (0x14)
+#define QSERDES_TX_L2_RES_CODE_UP (0x18)
+#define QSERDES_TX_L2_RES_CODE_DN (0x1C)
+#define QSERDES_TX_L2_PERL_LENGTH1 (0x20)
+#define QSERDES_TX_L2_PERL_LENGTH2 (0x24)
+#define QSERDES_TX_L2_SERDES_BYP_EN_OUT (0x28)
+#define QSERDES_TX_L2_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x2C)
+#define QSERDES_TX_L2_PARRATE_REC_DETECT_IDLE_EN (0x30)
+#define QSERDES_TX_L2_BIST_PATTERN1 (0x34)
+#define QSERDES_TX_L2_BIST_PATTERN2 (0x38)
+#define QSERDES_TX_L2_BIST_PATTERN3 (0x3C)
+#define QSERDES_TX_L2_BIST_PATTERN4 (0x40)
+#define QSERDES_TX_L2_BIST_PATTERN5 (0x44)
+#define QSERDES_TX_L2_BIST_PATTERN6 (0x48)
+#define QSERDES_TX_L2_BIST_PATTERN7 (0x4C)
+#define QSERDES_TX_L2_BIST_PATTERN8 (0x50)
+#define QSERDES_TX_L2_LANE_MODE (0x54)
+#define QSERDES_TX_L2_IDAC_CAL_LANE_MODE (0x58)
+#define QSERDES_TX_L2_IDAC_CAL_LANE_MODE_CONFIGURATION (0x5C)
+#define QSERDES_TX_L2_ATB_SEL1 (0x60)
+#define QSERDES_TX_L2_ATB_SEL2 (0x64)
+#define QSERDES_TX_L2_RCV_DETECT_LVL (0x68)
+#define QSERDES_TX_L2_PRBS_SEED1 (0x6C)
+#define QSERDES_TX_L2_PRBS_SEED2 (0x70)
+#define QSERDES_TX_L2_PRBS_SEED3 (0x74)
+#define QSERDES_TX_L2_PRBS_SEED4 (0x78)
+#define QSERDES_TX_L2_RESET_GEN (0x7C)
+#define QSERDES_TX_L2_TRAN_DRVR_EMP_EN (0x80)
+#define QSERDES_TX_L2_TX_INTERFACE_MODE (0x84)
+#define QSERDES_TX_L2_PWM_CTRL (0x88)
+#define QSERDES_TX_L2_PWM_DATA (0x8C)
+#define QSERDES_TX_L2_PWM_ENC_DIV_CTRL (0x90)
+#define QSERDES_TX_L2_VMODE_CTRL1 (0x94)
+#define QSERDES_TX_L2_VMODE_CTRL2 (0x98)
+#define QSERDES_TX_L2_VMODE_CTRL3 (0x9C)
+#define QSERDES_TX_L2_VMODE_CTRL4 (0xA0)
+#define QSERDES_TX_L2_VMODE_CTRL5 (0xA4)
+#define QSERDES_TX_L2_VMODE_CTRL6 (0xA8)
+#define QSERDES_TX_L2_VMODE_CTRL7 (0xAC)
+#define QSERDES_TX_L2_TX_ALOG_INTF_OBSV_CNTL (0xB0)
+#define QSERDES_TX_L2_BIST_STATUS (0xB4)
+#define QSERDES_TX_L2_BIST_ERROR_COUNT1 (0xB8)
+#define QSERDES_TX_L2_BIST_ERROR_COUNT2 (0xBC)
+#define QSERDES_TX_L2_TX_ALOG_INTF_OBSV (0xC0)
+#define QSERDES_TX_L2_PWM_DEC_STATUS (0xC4)
+
+/* Tx Channel 3 REGISERS */
+#define QSERDES_TX_L3_BIST_MODE_LANENO (0x00)
+#define QSERDES_TX_L3_CLKBUF_ENABLE (0x04)
+#define QSERDES_TX_L3_TX_EMP_POST1_LVL (0x08)
+#define QSERDES_TX_L3_TX_DRV_LVL (0x0C)
+#define QSERDES_TX_L3_RESET_TSYNC_EN (0x10)
+#define QSERDES_TX_L3_LPB_EN (0x14)
+#define QSERDES_TX_L3_RES_CODE_UP (0x18)
+#define QSERDES_TX_L3_RES_CODE_DN (0x1C)
+#define QSERDES_TX_L3_PERL_LENGTH1 (0x20)
+#define QSERDES_TX_L3_PERL_LENGTH2 (0x24)
+#define QSERDES_TX_L3_SERDES_BYP_EN_OUT (0x28)
+#define QSERDES_TX_L3_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x2C)
+#define QSERDES_TX_L3_PARRATE_REC_DETECT_IDLE_EN (0x30)
+#define QSERDES_TX_L3_BIST_PATTERN1 (0x34)
+#define QSERDES_TX_L3_BIST_PATTERN2 (0x38)
+#define QSERDES_TX_L3_BIST_PATTERN3 (0x3C)
+#define QSERDES_TX_L3_BIST_PATTERN4 (0x40)
+#define QSERDES_TX_L3_BIST_PATTERN5 (0x44)
+#define QSERDES_TX_L3_BIST_PATTERN6 (0x48)
+#define QSERDES_TX_L3_BIST_PATTERN7 (0x4C)
+#define QSERDES_TX_L3_BIST_PATTERN8 (0x50)
+#define QSERDES_TX_L3_LANE_MODE (0x54)
+#define QSERDES_TX_L3_IDAC_CAL_LANE_MODE (0x58)
+#define QSERDES_TX_L3_IDAC_CAL_LANE_MODE_CONFIGURATION (0x5C)
+#define QSERDES_TX_L3_ATB_SEL1 (0x60)
+#define QSERDES_TX_L3_ATB_SEL2 (0x64)
+#define QSERDES_TX_L3_RCV_DETECT_LVL (0x68)
+#define QSERDES_TX_L3_PRBS_SEED1 (0x6C)
+#define QSERDES_TX_L3_PRBS_SEED2 (0x70)
+#define QSERDES_TX_L3_PRBS_SEED3 (0x74)
+#define QSERDES_TX_L3_PRBS_SEED4 (0x78)
+#define QSERDES_TX_L3_RESET_GEN (0x7C)
+#define QSERDES_TX_L3_TRAN_DRVR_EMP_EN (0x80)
+#define QSERDES_TX_L3_TX_INTERFACE_MODE (0x84)
+#define QSERDES_TX_L3_PWM_CTRL (0x88)
+#define QSERDES_TX_L3_PWM_DATA (0x8C)
+#define QSERDES_TX_L3_PWM_ENC_DIV_CTRL (0x90)
+#define QSERDES_TX_L3_VMODE_CTRL1 (0x94)
+#define QSERDES_TX_L3_VMODE_CTRL2 (0x98)
+#define QSERDES_TX_L3_VMODE_CTRL3 (0x9C)
+#define QSERDES_TX_L3_VMODE_CTRL4 (0xA0)
+#define QSERDES_TX_L3_VMODE_CTRL5 (0xA4)
+#define QSERDES_TX_L3_VMODE_CTRL6 (0xA8)
+#define QSERDES_TX_L3_VMODE_CTRL7 (0xAC)
+#define QSERDES_TX_L3_TX_ALOG_INTF_OBSV_CNTL (0xB0)
+#define QSERDES_TX_L3_BIST_STATUS (0xB4)
+#define QSERDES_TX_L3_BIST_ERROR_COUNT1 (0xB8)
+#define QSERDES_TX_L3_BIST_ERROR_COUNT2 (0xBC)
+#define QSERDES_TX_L3_TX_ALOG_INTF_OBSV (0xC0)
+#define QSERDES_TX_L3_PWM_DEC_STATUS (0xC4)
+
+/* HDMI PHY REGISTERS */
+#define HDMI_PHY_CFG (0x00)
+#define HDMI_PHY_PD_CTL (0x04)
+#define HDMI_PHY_MODE (0x08)
+#define HDMI_PHY_MISR_CLEAR (0x0C)
+#define HDMI_PHY_TX0_TX1_BIST_CFG0 (0x10)
+#define HDMI_PHY_TX0_TX1_BIST_CFG1 (0x14)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE0 (0x18)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE1 (0x1C)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE2 (0x20)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE3 (0x24)
+#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE0 (0x28)
+#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE1 (0x2C)
+#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE2 (0x30)
+#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE3 (0x34)
+#define HDMI_PHY_TX2_TX3_BIST_CFG0 (0x38)
+#define HDMI_PHY_TX2_TX3_BIST_CFG1 (0x3C)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE0 (0x40)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE1 (0x44)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE2 (0x48)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE3 (0x4C)
+#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE0 (0x50)
+#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE1 (0x54)
+#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE2 (0x58)
+#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE3 (0x5C)
+#define HDMI_PHY_DEBUG_BUS_SEL (0x60)
+#define HDMI_PHY_TXCAL_CFG0 (0x64)
+#define HDMI_PHY_TXCAL_CFG1 (0x68)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS0 (0x6C)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS1 (0x70)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS2 (0x74)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS0 (0x78)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS1 (0x7C)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS2 (0x80)
+#define HDMI_PHY_PRE_MISR_STATUS0 (0x84)
+#define HDMI_PHY_PRE_MISR_STATUS1 (0x88)
+#define HDMI_PHY_PRE_MISR_STATUS2 (0x8C)
+#define HDMI_PHY_PRE_MISR_STATUS3 (0x90)
+#define HDMI_PHY_POST_MISR_STATUS0 (0x94)
+#define HDMI_PHY_POST_MISR_STATUS1 (0x98)
+#define HDMI_PHY_POST_MISR_STATUS2 (0x9C)
+#define HDMI_PHY_POST_MISR_STATUS3 (0xA0)
+#define HDMI_PHY_STATUS (0xA4)
+#define HDMI_PHY_MISC3_STATUS (0xA8)
+#define HDMI_PHY_DEBUG_BUS0 (0xAC)
+#define HDMI_PHY_DEBUG_BUS1 (0xB0)
+#define HDMI_PHY_DEBUG_BUS2 (0xB4)
+#define HDMI_PHY_DEBUG_BUS3 (0xB8)
+#define HDMI_PHY_REVISION_ID0 (0xBC)
+#define HDMI_PHY_REVISION_ID1 (0xC0)
+#define HDMI_PHY_REVISION_ID2 (0xC4)
+#define HDMI_PHY_REVISION_ID3 (0xC8)
+
+#define HDMI_PLL_POLL_MAX_READS 2500
+#define HDMI_PLL_POLL_TIMEOUT_US 50
+
+static uint32_t clk_tbl[HDMI_PHY_CLK_SIZE] = {
+ 297000000, 268500000, 148500000, 74250000, 27000000, 27027000,
+ 25200000, 108108000, 54054000, 25175000, 31500000, 33750000,
+ 35500000, 36000000, 40000000, 49500000, 50000000, 56250000,
+ 65000000, 68250000, 71000000, 72000000, 73250000, 75000000,
+ 78750000, 79500000, 83500000, 85500000, 88750000, 94500000,
+ 101000000, 102250000, 106500000, 108000000, 115500000, 117500000,
+ 119000000, 121750000, 122500000, 135000000, 136750000, 140250000,
+ 146250000, 148250000, 25175000, 31469000, 33784000, 37762000,
+ 37800000, 40500000, 40541000, 44900000, 73515000, 74176000,
+ 91894000, 92720000, 92813000, 110272000, 111264000, 111375000,
+ 118681000, 118800000, 140250000, 148352000, 154000000, 156000000,
+ 157000000, 157500000, 162000000, 175500000, 178022000, 178200000,
+ 179500000, 182750000, 185440000, 185625000, 187000000, 187250000,
+ 189000000, 193250000, 202500000, 204750000, 208000000, 214750000,
+ 218250000, 222527000, 222750000, 229500000, 234000000, 245250000,
+ 245500000, 261000000, 268250000, 281250000, 288000000, 296703000,
+ 340000000,
+};
+
+/* one to one mapping with clk_tbl */
+static uint32_t clk_settings[CALC_MAX][HDMI_PHY_CLK_SIZE] = {
+ { /* CALC_QSERDES_COM_SYSCLK_EN_SEL_TXBAND */
+ 0x4A, 0x4A, 0x5A, 0x6A, 0x7A, 0x7A, 0x7A, 0x5A, 0x6A, 0x7A,
+ 0x7A, 0x7A, 0x7A, 0x7A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A,
+ 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x5A, 0x5A, 0x5A, 0x5A,
+ 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
+ 0x5A, 0x5A, 0x5A, 0x5A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x6A,
+ 0x6A, 0x6A, 0x6A, 0x6A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
+ 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x4A, 0x4A,
+ 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A,
+ 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A,
+ 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A
+ },
+ { /* CALC_QSERDES_COM_DIV_REF1 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ { /* CALC_QSERDES_COM_DIV_REF2 */
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00
+ },
+ { /* CALC_QSERDES_COM_KVCO_COUNT1 */
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x00
+ },
+ { /* CALC_QSERDES_COM_KVCO_COUNT2 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ { /* CALC_QSERDES_COM_KVCO_CAL_CNTRL */
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00
+ },
+ { /* CALC_QSERDES_COM_KVCO_CODE */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F
+ },
+ { /* CALC_QSERDES_COM_VREF_CFG3 */
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00
+ },
+ { /* CALC_QSERDES_COM_VREF_CFG4 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ { /* CALC_QSERDES_COM_VREF_CFG5 */
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
+ },
+ { /* CALC_QSERDES_COM_PLL_IP_SETI */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
+ },
+ { /* CALC_QSERDES_COM_PLL_CP_SETI */
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x2F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x2F, 0x2F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x2F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x2F, 0x2F, 0x3F, 0x3F
+ },
+ { /* CALC_QSERDES_COM_PLL_IP_SETP */
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
+ },
+ { /* CALC_QSERDES_COM_PLL_CP_SETP */
+ 0x17, 0x1F, 0x17, 0x17, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x17, 0x17, 0x17, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x17, 0x1F, 0x1F, 0x1F, 0x17, 0x17, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x17, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x17, 0x17, 0x17, 0x17, 0x17, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x17, 0x17
+ },
+ { /* CALC_QSERDES_COM_PLL_CRCTRL */
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0x77, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB
+ },
+ { /* CALC_QSERDES_COM_DIV_FRAC_START1 */
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0xE6, 0x80, 0xE6, 0xE6, 0xAB,
+ 0x80, 0x80, 0xD5, 0x80, 0xAB, 0x80, 0xD5, 0x80, 0xD5, 0x80,
+ 0xD5, 0x80, 0xD5, 0x80, 0x80, 0x80, 0xD5, 0x80, 0xD5, 0x80,
+ 0xAB, 0xD5, 0x80, 0x80, 0x80, 0xAB, 0xAB, 0xD5, 0xD5, 0x80,
+ 0xD5, 0x80, 0x80, 0xAB, 0xAB, 0xF7, 0xA2, 0xBC, 0x80, 0x80,
+ 0xEF, 0xD5, 0x80, 0xC4, 0x89, 0xAB, 0x91, 0xEF, 0xB3, 0x80,
+ 0xA2, 0x80, 0x80, 0xC4, 0xD5, 0x80, 0xD5, 0x80, 0x80, 0x80,
+ 0xA2, 0x80, 0xAB, 0xD5, 0xAB, 0x80, 0xAB, 0xD5, 0x80, 0xD5,
+ 0x80, 0x80, 0xAB, 0xAB, 0x80, 0xA2, 0x80, 0x80, 0x80, 0x80,
+ 0xAB, 0x80, 0xD5, 0x80, 0x80, 0xB3, 0xAB
+ },
+ { /* CALC_QSERDES_COM_DIV_FRAC_START2 */
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0xCC, 0x80, 0xCC, 0xCC, 0xD5,
+ 0x80, 0x80, 0xAA, 0x80, 0xD5, 0x80, 0xAA, 0x80, 0xAA, 0x80,
+ 0xAA, 0x80, 0xAA, 0x80, 0x80, 0x80, 0xAA, 0x80, 0xAA, 0x80,
+ 0xD5, 0xAA, 0x80, 0x80, 0x80, 0xD5, 0xD5, 0xAA, 0xAA, 0x80,
+ 0xAA, 0x80, 0x80, 0xD5, 0xD5, 0xEE, 0xC4, 0xF7, 0x80, 0x80,
+ 0xDD, 0xAA, 0x80, 0x88, 0x91, 0xD5, 0xE2, 0xDD, 0xE6, 0xC0,
+ 0x84, 0x80, 0x80, 0x88, 0xAA, 0x80, 0xAA, 0x80, 0x80, 0x80,
+ 0x84, 0x80, 0xD5, 0xEA, 0xD5, 0xE0, 0xD5, 0xEA, 0x80, 0xEA,
+ 0x80, 0xC0, 0xD5, 0x95, 0xC0, 0xE4, 0xC0, 0x80, 0x80, 0xC0,
+ 0xD5, 0x80, 0xEA, 0xC0, 0x80, 0x86, 0xD5
+ },
+ { /* CALC_QSERDES_COM_DIV_FRAC_START3 */
+ 0x56, 0x7B, 0x56, 0x56, 0x50, 0x53, 0x60, 0x53, 0x53, 0x5C,
+ 0x68, 0x54, 0x7D, 0x40, 0x6A, 0x64, 0x45, 0x66, 0x6D, 0x46,
+ 0x7D, 0x40, 0x53, 0x48, 0x42, 0x74, 0x5F, 0x62, 0x4E, 0x4E,
+ 0x66, 0x50, 0x5E, 0x50, 0x4A, 0x4C, 0x7E, 0x5A, 0x73, 0x54,
+ 0x4E, 0x43, 0x4B, 0x4D, 0x5C, 0x63, 0x58, 0x6A, 0x70, 0x4C,
+ 0x4E, 0x71, 0x65, 0x51, 0x77, 0x52, 0x55, 0x5B, 0x7C, 0x40,
+ 0x74, 0x78, 0x43, 0x51, 0x4D, 0x50, 0x71, 0x42, 0x4C, 0x6D,
+ 0x57, 0x5A, 0x6F, 0x65, 0x52, 0x55, 0x6C, 0x70, 0x4E, 0x54,
+ 0x6F, 0x54, 0x4A, 0x7B, 0x75, 0x7C, 0x40, 0x71, 0x7C, 0x77,
+ 0x7B, 0x7E, 0x76, 0x4F, 0x40, 0x51, 0x62
+ },
+ { /* CALC_QSERDES_COM_DEC_START1 */
+ 0xCD, 0xC5, 0xCD, 0xCD, 0xB8, 0xB8, 0xB4, 0xB8, 0xB8, 0xB4,
+ 0xC1, 0xC6, 0xC9, 0xCB, 0xA9, 0xB3, 0xB4, 0xBA, 0xC3, 0xC7,
+ 0xC9, 0xCB, 0xCC, 0xCE, 0xD2, 0xD2, 0xAB, 0xAC, 0xAE, 0xB1,
+ 0xB4, 0xB5, 0xB7, 0xB8, 0xBC, 0xBD, 0xBD, 0xBF, 0xBF, 0xC6,
+ 0xC7, 0xC9, 0xCC, 0xCD, 0xB4, 0xC1, 0xC6, 0xCE, 0xCE, 0xAA,
+ 0xAA, 0xAE, 0xCC, 0xCD, 0xAF, 0xB0, 0xB0, 0xB9, 0xB9, 0xBA,
+ 0xBD, 0xBD, 0xC9, 0xCD, 0xD0, 0xD1, 0xD1, 0xD2, 0xAA, 0xAD,
+ 0xAE, 0xAE, 0xAE, 0xAF, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB2,
+ 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBF,
+ 0xBF, 0xC3, 0xC5, 0xC9, 0xCB, 0xCD, 0xD8
+ },
+ { /*CALC_QSERDES_COM_DEC_START2 */
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
+ },
+ { /* CALC_QSERDES_COM_PLLLOCK_CMP1 */
+ 0xDF, 0xEF, 0xDF, 0xDF, 0xFF, 0x0B, 0xFF, 0x0B, 0x0B, 0xF4,
+ 0x7F, 0x3F, 0x2A, 0xFF, 0x54, 0x3F, 0xAA, 0xDF, 0x2A, 0xDF,
+ 0x2A, 0xFF, 0x0A, 0x7F, 0x9F, 0x3F, 0xCA, 0x9F, 0xFA, 0x5F,
+ 0x14, 0x9A, 0x5F, 0xFF, 0x1F, 0xF4, 0x94, 0xBA, 0x0A, 0x3F,
+ 0xFA, 0x6F, 0xEF, 0xC4, 0xF4, 0x72, 0x4E, 0xEF, 0xFF, 0xBF,
+ 0xC8, 0x6A, 0x42, 0xCF, 0x49, 0xA1, 0xAB, 0xF1, 0x5B, 0x67,
+ 0x72, 0x7F, 0x6F, 0xCF, 0x2A, 0xFF, 0x6A, 0x9F, 0xBF, 0x8F,
+ 0x16, 0x1F, 0x64, 0x12, 0xA1, 0xAB, 0xF4, 0x02, 0x5F, 0x42,
+ 0x2F, 0xA7, 0x54, 0xBC, 0x77, 0x5B, 0x67, 0xCF, 0xBF, 0x17,
+ 0x24, 0x5F, 0xE2, 0x97, 0xFF, 0xCF, 0xD4
+ },
+ { /* CALC_QSERDES_COM_PLLLOCK_CMP2 */
+ 0x3D, 0x37, 0x3D, 0x3D, 0x2C, 0x2D, 0x29, 0x2D, 0x2D, 0x29,
+ 0x34, 0x38, 0x3B, 0x3B, 0x21, 0x29, 0x29, 0x2E, 0x36, 0x38,
+ 0x3B, 0x3B, 0x3D, 0x3E, 0x41, 0x42, 0x22, 0x23, 0x24, 0x27,
+ 0x2A, 0x2A, 0x2C, 0x2C, 0x30, 0x30, 0x31, 0x32, 0x33, 0x38,
+ 0x38, 0x3A, 0x3C, 0x3D, 0x29, 0x34, 0x38, 0x3E, 0x3E, 0x21,
+ 0x21, 0x25, 0x3D, 0x3D, 0x26, 0x26, 0x26, 0x2D, 0x2E, 0x2E,
+ 0x31, 0x31, 0x3A, 0x3D, 0x40, 0x40, 0x41, 0x41, 0x21, 0x24,
+ 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x28,
+ 0x2A, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2E, 0x2F, 0x30, 0x33,
+ 0x33, 0x36, 0x37, 0x3A, 0x3B, 0x3D, 0x46
+ },
+ { /* CALC_QSERDES_COM_PLLLOCK_CMP3 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ { /* CALC_QSERDES_COM_PLLLOCK_CMP_EN */
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
+ },
+ { /* CALC_QSERDES_COM_RESETSM_CNTRL */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80
+ },
+ { /* CALC_HDMI_PHY_MODE */
+ 0x00, 0x00, 0x01, 0x02, 0x03, 0x03, 0x03, 0x01, 0x02, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ }
+};
+
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+
+void hdmi_phy_reset(void)
+{
+ uint32_t phy_reset_polarity = 0x0;
+ uint32_t pll_reset_polarity = 0x0;
+ uint32_t val;
+
+ val = readl(HDMI_PHY_CTRL);
+
+ phy_reset_polarity = val >> 3 & 0x1;
+ pll_reset_polarity = val >> 1 & 0x1;
+
+ if (phy_reset_polarity == 0)
+ writel(val | SW_RESET, HDMI_PHY_CTRL);
+ else
+ writel(val & (~SW_RESET), HDMI_PHY_CTRL);
+
+ if (pll_reset_polarity == 0)
+ writel(val | SW_RESET_PLL, HDMI_PHY_CTRL);
+ else
+ writel(val & (~SW_RESET_PLL), HDMI_PHY_CTRL);
+
+ if (phy_reset_polarity == 0)
+ writel(val & (~SW_RESET), HDMI_PHY_CTRL);
+ else
+ writel(val | SW_RESET, HDMI_PHY_CTRL);
+
+ if (pll_reset_polarity == 0)
+ writel(val & (~SW_RESET_PLL), HDMI_PHY_CTRL);
+ else
+ writel(val | SW_RESET_PLL, HDMI_PHY_CTRL);
+}
+
+static uint32_t hdmi_poll_status(void)
+{
+ uint32_t ready_poll;
+ uint32_t time_out_loop;
+ uint32_t time_out_max = HDMI_PLL_POLL_MAX_READS;
+
+ /* Poll for C_READY and PHY READY */
+ dprintf(SPEW, "%s: Waiting for PHY Ready\n", __func__);
+ time_out_loop = 0;
+ do {
+ if (time_out_loop)
+ udelay(HDMI_PLL_POLL_TIMEOUT_US);
+
+ ready_poll = readl(HDMI_PLL_BASE + QSERDES_COM_RESET_SM);
+ time_out_loop++;
+ } while (!(ready_poll & BIT(6)) &&
+ (time_out_loop < time_out_max));
+
+ if (time_out_loop >= time_out_max) {
+ dprintf(CRITICAL, "%s: C READY TIMEOUT\n", __func__);
+ return ERROR;
+ } else {
+ dprintf(SPEW, "%s: C READY\n", __func__);
+ }
+
+ /* Poll for PHY READY */
+ dprintf(SPEW, "%s: Waiting for PHY Ready\n", __func__);
+ time_out_loop = 0;
+ do {
+ udelay(HDMI_PLL_POLL_TIMEOUT_US);
+
+ ready_poll = readl(HDMI_PHY_BASE + HDMI_PHY_STATUS);
+ time_out_loop++;
+ } while (!(ready_poll & BIT(0)) && (time_out_loop < time_out_max));
+
+ if (time_out_loop >= time_out_max) {
+ dprintf(CRITICAL, "%s: PHY READY TIMEOUT\n", __func__);
+ return ERROR;
+ } else {
+ udelay(100);
+ dprintf(SPEW, "%s: HDMI PHY READY\n", __func__);
+ }
+
+ return NO_ERROR;
+}
+
+uint32_t hdmi_pll_config(uint32_t tmds_clk_rate)
+{
+ uint32_t clk_index;
+
+ /* Find clock target for reset sequence */
+ for (clk_index = 0; clk_index < HDMI_PHY_CLK_SIZE; clk_index++) {
+ if ((clk_tbl[clk_index] >= (tmds_clk_rate - 2000)) &&
+ (clk_tbl[clk_index] <= (tmds_clk_rate + 2000))) {
+ dprintf(SPEW, "%s: found clk %d\n", __func__,
+ tmds_clk_rate);
+ break;
+ }
+ }
+
+ if (clk_index >= HDMI_PHY_CLK_SIZE) {
+ dprintf(CRITICAL, "%s: pixel clock %d not valid\n",
+ __func__, tmds_clk_rate);
+ return ERROR;
+ }
+
+ /* Initially shut down PHY */
+ dprintf(SPEW, "%s: Disabling PHY\n", __func__);
+ writel(0x0, HDMI_PHY_BASE + HDMI_PHY_PD_CTL);
+ udelay(100);
+
+ /* power-up and recommended common block settings */
+ writel(0x1F, HDMI_PHY_BASE + HDMI_PHY_PD_CTL);
+ writel(0x01, HDMI_PHY_BASE + HDMI_PHY_CFG);
+ udelay(100);
+
+ writel(0x07, HDMI_PHY_BASE + HDMI_PHY_CFG);
+ udelay(100);
+
+ writel(0x05, HDMI_PHY_BASE + HDMI_PHY_CFG);
+ udelay(100);
+
+ writel(0x42, HDMI_PLL_BASE + QSERDES_COM_SYS_CLK_CTRL);
+ writel(0x03, HDMI_PLL_BASE + QSERDES_COM_PLL_VCOTAIL_EN);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_CMN_MODE);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_IE_TRIM);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_IP_TRIM);
+ writel(0x01, HDMI_PLL_BASE + QSERDES_COM_PLL_CNTRL);
+ writel(0x04, HDMI_PLL_BASE + QSERDES_COM_PLL_PHSEL_CONTROL);
+ writel(tmds_clk_rate > 148500000 ? 0x80 : 0xC0,
+ HDMI_PLL_BASE + QSERDES_COM_IPTAT_TRIM_VCCA_TX_SEL);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_PHSEL_DC);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_CORE_CLK_IN_SYNC_SEL);
+
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_BKG_KVCO_CAL_EN);
+
+ writel(0x0F, HDMI_PLL_BASE + QSERDES_COM_BIAS_EN_CLKBUFLR_EN);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_ATB_SEL1);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_ATB_SEL2);
+
+ writel(clk_settings[CALC_QSERDES_COM_SYSCLK_EN_SEL_TXBAND][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
+
+ writel(0x30, HDMI_PLL_BASE + QSERDES_COM_KVCO_CODE);
+ writel(0x0F, HDMI_PLL_BASE + QSERDES_COM_BGTC);
+
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_TEST_UPDN);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_VCO_TUNE);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_AMP_OS);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_SSC_EN_CENTER);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_UP);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_DN);
+
+ writel(0x77, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_CAL_CSR);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_RES_TRIM_EN_VCOCALDONE);
+ writel(0x00, HDMI_PLL_BASE + QSERDES_COM_FAUX_EN);
+ writel(0x0E, HDMI_PLL_BASE + QSERDES_COM_PLL_RXTXEPCLK_EN);
+
+ /* PLL loop bandwidth */
+ writel(0x01, HDMI_PLL_BASE + QSERDES_COM_PLL_IP_SETI);
+ writel(0x3F, HDMI_PLL_BASE + QSERDES_COM_PLL_CP_SETI);
+ writel(0x06, HDMI_PLL_BASE + QSERDES_COM_PLL_IP_SETP);
+ writel(0x1F, HDMI_PLL_BASE + QSERDES_COM_PLL_CP_SETP);
+ writel(0xBB, HDMI_PLL_BASE + QSERDES_COM_PLL_CRCTRL);
+
+ /* PLL calibration */
+ writel(clk_settings[CALC_QSERDES_COM_DIV_FRAC_START1][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_DIV_FRAC_START1);
+ writel(clk_settings[CALC_QSERDES_COM_DIV_FRAC_START2][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_DIV_FRAC_START2);
+ writel(clk_settings[CALC_QSERDES_COM_DIV_FRAC_START3][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_DIV_FRAC_START3);
+ writel(clk_settings[CALC_QSERDES_COM_DEC_START1][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_DEC_START1);
+ writel(clk_settings[CALC_QSERDES_COM_DEC_START2][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_DEC_START2);
+ writel(clk_settings[CALC_QSERDES_COM_PLLLOCK_CMP1][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_PLLLOCK_CMP1);
+ writel(clk_settings[CALC_QSERDES_COM_PLLLOCK_CMP2][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_PLLLOCK_CMP2);
+ writel(clk_settings[CALC_QSERDES_COM_PLLLOCK_CMP3][clk_index],
+ HDMI_PLL_BASE + QSERDES_COM_PLLLOCK_CMP3);
+ writel(0x01, HDMI_PLL_BASE + QSERDES_COM_PLLLOCK_CMP_EN);
+
+ /* Resistor calibration linear search */
+ writel(0x60, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_START_SEG1);
+ writel(0x60, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_START_SEG2);
+ writel(0x01, HDMI_PLL_BASE + QSERDES_COM_RES_TRIM_CONTROL);
+
+ /* Reset state machine control */
+ writel(0x80, HDMI_PLL_BASE + QSERDES_COM_RESETSM_CNTRL);
+ writel(0x07, HDMI_PLL_BASE + QSERDES_COM_RESETSM_CNTRL2);
+ udelay(100);
+
+ /* TX lanes (transceivers) power-up sequence */
+ writel(clk_settings[CALC_HDMI_PHY_MODE][clk_index],
+ HDMI_PHY_BASE + HDMI_PHY_MODE);
+
+ writel(0x03, HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_CLKBUF_ENABLE);
+ writel(0x03, HDMI_PLL_BASE + 0x600 + QSERDES_TX_L1_CLKBUF_ENABLE);
+ writel(0x03, HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_CLKBUF_ENABLE);
+ writel(0x03, HDMI_PLL_BASE + 0xA00 + QSERDES_TX_L3_CLKBUF_ENABLE);
+
+ writel(0x03, HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_TRAN_DRVR_EMP_EN);
+ writel(0x03, HDMI_PLL_BASE + 0x600 + QSERDES_TX_L1_TRAN_DRVR_EMP_EN);
+ writel(0x03, HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_TRAN_DRVR_EMP_EN);
+ writel(0x03, HDMI_PLL_BASE + 0xA00 + QSERDES_TX_L3_TRAN_DRVR_EMP_EN);
+
+ writel(0x6F, HDMI_PLL_BASE + 0x400 +
+ QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+ writel(0x6F, HDMI_PLL_BASE + 0x600 +
+ QSERDES_TX_L1_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+ writel(0x6F, HDMI_PLL_BASE + 0x800 +
+ QSERDES_TX_L2_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+ writel(0x6F, HDMI_PLL_BASE + 0xA00 +
+ QSERDES_TX_L3_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+
+ writel(tmds_clk_rate >= 74000000 ? 0x2F : 0x21,
+ HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_TX_EMP_POST1_LVL);
+ writel(tmds_clk_rate >= 74000000 ? 0xAF : 0xA1,
+ HDMI_PHY_BASE + HDMI_PHY_TXCAL_CFG0);
+
+ writel(tmds_clk_rate >= 74000000 ? 0x0C : 0x04,
+ HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL1);
+ writel(tmds_clk_rate >= 74000000 ? 0x0D : 0x05,
+ HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL1);
+ writel(tmds_clk_rate >= 74000000 ? 0x1F : 0x11,
+ HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_TX_DRV_LVL);
+ writel(tmds_clk_rate >= 74000000 ? 0x1F : 0x11,
+ HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_TX_DRV_LVL);
+ writel(0x80, HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL2);
+ writel(0x00, HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL2);
+ writel(tmds_clk_rate >= 74000000 ? 0x01 : 0x02,
+ HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL3);
+ writel(tmds_clk_rate >= 74000000 ? 0x00 : 0x02,
+ HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL3);
+ writel(tmds_clk_rate >= 74000000 ? 0x00 : 0xA0,
+ HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL5);
+ writel(tmds_clk_rate >= 74000000 ? 0x00 : 0xA0,
+ HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL5);
+ writel(0x00, HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL6);
+ writel(0x00, HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL6);
+
+ writel(0x40, HDMI_PLL_BASE + 0x400 +
+ QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN);
+ writel(0x00, HDMI_PLL_BASE + 0x400 +
+ QSERDES_TX_L0_TX_INTERFACE_MODE);
+ writel(0x40, HDMI_PLL_BASE + 0x600 +
+ QSERDES_TX_L1_PARRATE_REC_DETECT_IDLE_EN);
+ writel(0x00, HDMI_PLL_BASE + 0x600 +
+ QSERDES_TX_L1_TX_INTERFACE_MODE);
+ writel(0x40, HDMI_PLL_BASE + 0x800 +
+ QSERDES_TX_L2_PARRATE_REC_DETECT_IDLE_EN);
+ writel(0x00, HDMI_PLL_BASE + 0x800 +
+ QSERDES_TX_L2_TX_INTERFACE_MODE);
+ writel(0x40, HDMI_PLL_BASE + 0xA00 +
+ QSERDES_TX_L3_PARRATE_REC_DETECT_IDLE_EN);
+ writel(0x00, HDMI_PLL_BASE + 0xA00 +
+ QSERDES_TX_L3_TX_INTERFACE_MODE);
+
+ return NO_ERROR;
+}
+
+int hdmi_vco_enable(void)
+{
+ int rc;
+
+ writel(0x01, HDMI_PHY_BASE + HDMI_PHY_CFG);
+ udelay(100);
+
+ writel(0x03, HDMI_PHY_BASE + HDMI_PHY_CFG);
+ udelay(100);
+
+ writel(0x09, HDMI_PHY_BASE + HDMI_PHY_CFG);
+ udelay(100);
+
+ rc = hdmi_poll_status();
+
+ writel(0x08, HDMI_PHY_BASE + HDMI_PHY_CFG);
+ udelay(100);
+
+ writel(0x09, HDMI_PHY_BASE + HDMI_PHY_CFG);
+ udelay(100);
+
+ return rc;
+}
+
+void hdmi_vco_disable(void)
+{
+ writel(0x0, HDMI_PHY_BASE + HDMI_PHY_PD_CTL);
+ udelay(100);
+}
diff --git a/platform/msm_shared/include/mdp5.h b/platform/msm_shared/include/mdp5.h
index 9515354..465c4b8 100644
--- a/platform/msm_shared/include/mdp5.h
+++ b/platform/msm_shared/include/mdp5.h
@@ -209,6 +209,7 @@
int mdss_hdmi_init(void);
int mdss_hdmi_on(struct msm_panel_info *pinfo);
int mdss_hdmi_config(struct msm_panel_info *pinfo, struct fbcon_config *fb);
+void mdss_hdmi_get_vic(char *buf);
int msm_display_off();
void display_shutdown(void);
#endif
diff --git a/platform/msm_shared/include/mdss_hdmi.h b/platform/msm_shared/include/mdss_hdmi.h
new file mode 100644
index 0000000..6786a85
--- /dev/null
+++ b/platform/msm_shared/include/mdss_hdmi.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2015, 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
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PLATFORM_MSM_SHARED_MDSS_HDMI_H_
+#define _PLATFORM_MSM_SHARED_MDSS_HDMI_H_
+
+void hdmi_phy_reset(void);
+uint32_t hdmi_pll_config(uint32_t tmds_clk_rate);
+int hdmi_vco_enable(void);
+int hdmi_vco_disable(void);
+void mdss_hdmi_display_init(uint32_t rev, void *base);
+#endif
diff --git a/platform/msm_shared/include/msm_panel.h b/platform/msm_shared/include/msm_panel.h
index 4b09f69..75870a2 100755
--- a/platform/msm_shared/include/msm_panel.h
+++ b/platform/msm_shared/include/msm_panel.h
@@ -343,6 +343,7 @@
int (*dfps_func)(struct msm_panel_info *);
int (*post_power_func)(int enable);
int (*pre_init_func)(void);
+ int (*update_panel_info) (void);
};
#endif
diff --git a/platform/msm_shared/mdp5.c b/platform/msm_shared/mdp5.c
index b48efb7..82f049f 100755
--- a/platform/msm_shared/mdp5.c
+++ b/platform/msm_shared/mdp5.c
@@ -448,14 +448,14 @@
adjust_xres = pinfo->xres;
if (pinfo->lcdc.split_display) {
adjust_xres /= 2;
- if (intf_base == MDP_INTF_1_BASE) {
+ if (intf_base == (MDP_INTF_1_BASE + mdss_mdp_intf_offset())) {
writel(BIT(8), MDP_REG_SPLIT_DISPLAY_LOWER_PIPE_CTL);
writel(BIT(8), MDP_REG_SPLIT_DISPLAY_UPPER_PIPE_CTL);
writel(0x1, MDP_REG_SPLIT_DISPLAY_EN);
}
}
- if (pinfo->lcdc.dst_split && (intf_base == MDP_INTF_1_BASE)) {
+ if (pinfo->lcdc.dst_split && (intf_base == (MDP_INTF_1_BASE + mdss_mdp_intf_offset()))) {
uint32_t ppb_offset = mdss_mdp_get_ppb_offset();
writel(BIT(16), REG_MDP(ppb_offset + 0x4)); /* MMSS_MDP_PPB0_CNTL */
writel(BIT(5), REG_MDP(ppb_offset)); /* MMSS_MDP_PPB0_CONFIG */
@@ -497,7 +497,7 @@
display_vend = ((vsync_period - itp.v_front_porch) * hsync_period)
+ itp.hsync_skew - 1;
- if (intf_base == MDP_INTF_0_BASE) { /* eDP */
+ if (intf_base == (MDP_INTF_0_BASE + mdss_mdp_intf_offset())) { /* eDP */
display_vstart += itp.hsync_pulse_width + itp.h_back_porch;
display_vend -= itp.h_front_porch;
}
@@ -951,8 +951,10 @@
int mdss_hdmi_config(struct msm_panel_info *pinfo, struct fbcon_config *fb)
{
uint32_t left_pipe, right_pipe;
+ dprintf(SPEW, "ENTER: %s\n", __func__);
- mdss_intf_tg_setup(pinfo, MDP_INTF_3_BASE);
+ mdss_intf_tg_setup(pinfo, MDP_INTF_3_BASE + mdss_mdp_intf_offset());
+ pinfo->pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
mdp_select_pipe_type(pinfo, &left_pipe, &right_pipe);
mdp_clk_gating_ctrl();
diff --git a/platform/msm_shared/mdss_hdmi.c b/platform/msm_shared/mdss_hdmi.c
index e030410..0741308 100644
--- a/platform/msm_shared/mdss_hdmi.c
+++ b/platform/msm_shared/mdss_hdmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2015, 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
@@ -29,12 +29,77 @@
#include <err.h>
#include <debug.h>
#include <reg.h>
+#include <malloc.h>
+#include <string.h>
#include <msm_panel.h>
#include <platform/timer.h>
#include <platform/clock.h>
+#include "mdp5.h"
#include <platform/iomap.h>
+#include "mdss_hdmi.h"
+#include <target/display.h>
static struct msm_fb_panel_data panel;
+extern int msm_display_init(struct msm_fb_panel_data *pdata);
+static bool hdmi_power_enabled;
+static bool hdmi_panel_clock_enabled;
+static bool hdmi_pll_clock_enabled;
+
+/* Supported HDMI Audio channels */
+#define MSM_HDMI_AUDIO_CHANNEL_2 1
+#define MSM_HDMI_AUDIO_CHANNEL_MAX 8
+
+enum msm_hdmi_supported_audio_sample_rates {
+ AUDIO_SAMPLE_RATE_32KHZ,
+ AUDIO_SAMPLE_RATE_44_1KHZ,
+ AUDIO_SAMPLE_RATE_48KHZ,
+ AUDIO_SAMPLE_RATE_88_2KHZ,
+ AUDIO_SAMPLE_RATE_96KHZ,
+ AUDIO_SAMPLE_RATE_176_4KHZ,
+ AUDIO_SAMPLE_RATE_192KHZ,
+ AUDIO_SAMPLE_RATE_MAX
+};
+
+struct hdmi_msm_audio_acr {
+ uint32_t n; /* N parameter for clock regeneration */
+ uint32_t cts; /* CTS parameter for clock regeneration */
+};
+
+struct hdmi_msm_audio_arcs {
+ uint32_t pclk;
+ struct hdmi_msm_audio_acr lut[AUDIO_SAMPLE_RATE_MAX];
+};
+
+#define HDMI_MSM_AUDIO_ARCS(pclk, ...) { pclk, __VA_ARGS__ }
+
+/* Audio constants lookup table for hdmi_msm_audio_acr_setup */
+/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
+static struct hdmi_msm_audio_arcs hdmi_audio_acr_lut[] = {
+ /* 25.200MHz */
+ HDMI_MSM_AUDIO_ARCS(25200, {
+ {4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000},
+ {12288, 25200}, {25088, 28000}, {24576, 25200} }),
+ /* 27.000MHz */
+ HDMI_MSM_AUDIO_ARCS(27000, {
+ {4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000},
+ {12288, 27000}, {25088, 30000}, {24576, 27000} }),
+ /* 27.027MHz */
+ HDMI_MSM_AUDIO_ARCS(27030, {
+ {4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030},
+ {12288, 27027}, {25088, 30030}, {24576, 27027} }),
+ /* 74.250MHz */
+ HDMI_MSM_AUDIO_ARCS(74250, {
+ {4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500},
+ {12288, 74250}, {25088, 82500}, {24576, 74250} }),
+ /* 148.500MHz */
+ HDMI_MSM_AUDIO_ARCS(148500, {
+ {4096, 148500}, {6272, 165000}, {6144, 148500}, {12544, 165000},
+ {12288, 148500}, {25088, 165000}, {24576, 148500} }),
+ /* 297.000MHz */
+ HDMI_MSM_AUDIO_ARCS(297000, {
+ {3072, 222750}, {4704, 247500}, {5120, 247500}, {9408, 247500},
+ {10240, 247500}, {18816, 247500}, {20480, 247500} }),
+};
/* AVI INFOFRAME DATA */
#define NUM_MODES_AVI 20
@@ -74,6 +139,47 @@
#define LEFT_SHIFT_WORD(x) ((x) << 16)
#define LEFT_SHIFT_24BITS(x) ((x) << 24)
+#define MAX_AUDIO_DATA_BLOCK_SIZE 0x80
+#define DBC_START_OFFSET 4
+#define VIC_INDEX 3
+#define HDMI_VIC_STR_MAX 3
+
+enum edid_data_block_type {
+ RESERVED_DATA_BLOCK1 = 0,
+ AUDIO_DATA_BLOCK,
+ VIDEO_DATA_BLOCK,
+ VENDOR_SPECIFIC_DATA_BLOCK,
+ SPEAKER_ALLOCATION_DATA_BLOCK,
+ VESA_DTC_DATA_BLOCK,
+ RESERVED_DATA_BLOCK2,
+ USE_EXTENDED_TAG
+};
+
+/* video formats defined by CEA 861D */
+#define HDMI_VFRMT_UNKNOWN 0
+#define HDMI_VFRMT_640x480p60_4_3 1
+#define HDMI_VFRMT_1280x720p60_16_9 4
+#define HDMI_VFRMT_1920x1080p60_16_9 16
+#define HDMI_VFRMT_MAX 3
+
+#define DEFAULT_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9
+static uint8_t mdss_hdmi_video_fmt = HDMI_VFRMT_UNKNOWN;
+static uint8_t mdss_hdmi_pref_fmt = HDMI_VFRMT_UNKNOWN;
+static uint8_t pt_scan_info;
+static uint8_t it_scan_info;
+static uint8_t ce_scan_info;
+
+static uint8_t mdss_hdmi_edid_buf[0x80];
+
+enum aspect_ratio {
+ HDMI_RES_AR_INVALID,
+ HDMI_RES_AR_4_3,
+ HDMI_RES_AR_5_4,
+ HDMI_RES_AR_16_9,
+ HDMI_RES_AR_16_10,
+ HDMI_RES_AR_MAX,
+};
+
struct mdss_hdmi_timing_info {
uint32_t video_format;
uint32_t active_h;
@@ -92,65 +198,188 @@
uint32_t refresh_rate;
uint32_t interlaced;
uint32_t supported;
+ enum aspect_ratio ar;
};
-#define HDMI_VFRMT_1280x720p60_16_9 4
-#define HDMI_RESOLUTION_DATA HDMI_VFRMT_1280x720p60_16_9##_TIMING
+#define HDMI_VFRMT_640x480p60_4_3_TIMING \
+ {HDMI_VFRMT_640x480p60_4_3, 640, 16, 96, 48, true, \
+ 480, 10, 2, 33, true, 25200, 60000, false, true, HDMI_RES_AR_4_3}
#define HDMI_VFRMT_1280x720p60_16_9_TIMING \
{HDMI_VFRMT_1280x720p60_16_9, 1280, 110, 40, 220, false, \
- 720, 5, 5, 20, false, 74250, 60000, false, true}
+ 720, 5, 5, 20, false, 74250, 60000, false, true, HDMI_RES_AR_16_9}
-uint32_t mdss_hdmi_avi_info_db[] = {
- 0x10, 0x28, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0xD1, 0x02, 0x00, 0x00, 0x01, 0x05};
+#define HDMI_VFRMT_1920x1080p60_16_9_TIMING \
+ {HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, false, \
+ 1080, 4, 5, 36, false, 148500, 60000, false, true, HDMI_RES_AR_16_9}
-static void mdss_hdmi_audio_acr_setup(void)
+#define MSM_HDMI_MODES_GET_DETAILS(mode, MODE) do { \
+ struct mdss_hdmi_timing_info info = MODE##_TIMING; \
+ *mode = info; \
+ } while (0)
+
+static inline int mdss_hdmi_get_timing_info(
+ struct mdss_hdmi_timing_info *mode, int id)
{
- int n, cts, layout, multiplier;
- uint32_t aud_pck_ctrl_2_reg = 0, acr_pck_ctrl_reg = 0;
+ int ret = 0;
- /* 74.25MHz ACR settings */
- n = 4096;
- cts = 74250;
- layout = 0;
- multiplier = 1;
+ switch (id) {
+ case HDMI_VFRMT_640x480p60_4_3:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_640x480p60_4_3);
+ break;
+
+ case HDMI_VFRMT_1280x720p60_16_9:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_1280x720p60_16_9);
+ break;
+
+ case HDMI_VFRMT_1920x1080p60_16_9:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_1920x1080p60_16_9);
+ break;
+
+ default:
+ ret = ERROR;
+ }
+
+ return ret;
+}
+
+
+/*
+ * 13 Bytes of AVI infoframe data wrt each resolution
+ * Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0
+ * Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0
+ * Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0
+ * Data Byte 04: 0 VIC6 VIC5 VIC4 VIC3 VIC2 VIC1 VIC0
+ * Data Byte 05: 0 0 0 0 PR3 PR2 PR1 PR0
+ * Data Byte 06: LSB Line No of End of Top Bar
+ * Data Byte 07: MSB Line No of End of Top Bar
+ * Data Byte 08: LSB Line No of Start of Bottom Bar
+ * Data Byte 09: MSB Line No of Start of Bottom Bar
+ * Data Byte 10: LSB Pixel Number of End of Left Bar
+ * Data Byte 11: MSB Pixel Number of End of Left Bar
+ * Data Byte 12: LSB Pixel Number of Start of Right Bar
+ * Data Byte 13: MSB Pixel Number of Start of Right Bar
+ */
+static uint8_t mdss_hdmi_avi_info_db[HDMI_VFRMT_MAX][AVI_MAX_DATA_BYTES] = {
+ /* 480p */
+ {0x10, 0x18, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0xE1, 0x01, 0x00, 0x00, 0x81, 0x02},
+ /* 720p */
+ {0x10, 0x28, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xD1, 0x02, 0x00, 0x00, 0x01, 0x05},
+ /* 1080p */
+ {0x10, 0x28, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x39, 0x04, 0x00, 0x00, 0x81, 0x07},
+};
+
+static void mdss_hdmi_audio_acr_setup(uint32_t sample_rate)
+{
+ /* Read first before writing */
+ uint32_t acr_pck_ctrl_reg = readl(HDMI_ACR_PKT_CTRL);
+ struct mdss_hdmi_timing_info tinfo = {0};
+ uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
+ struct hdmi_msm_audio_arcs *audio_acr = &hdmi_audio_acr_lut[0];
+ uint32_t lut_size = sizeof(hdmi_audio_acr_lut)
+ / sizeof(*hdmi_audio_acr_lut);
+ uint32_t i, n, cts, layout, multiplier, aud_pck_ctrl_2_reg;
+ uint32_t channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
+
+ if (ret || !tinfo.supported) {
+ dprintf(CRITICAL, "%s: video format %d not supported\n",
+ __func__, mdss_hdmi_video_fmt);
+ return;
+ }
+
+ for (i = 0; i < lut_size; audio_acr = &hdmi_audio_acr_lut[++i]) {
+ if (audio_acr->pclk == tinfo.pixel_freq)
+ break;
+ }
+
+ if (i >= lut_size) {
+ dprintf(CRITICAL, "%s: pixel clk %d not supported\n", __func__,
+ tinfo.pixel_freq);
+ return;
+ }
+
+ n = audio_acr->lut[sample_rate].n;
+ cts = audio_acr->lut[sample_rate].cts;
+ layout = (MSM_HDMI_AUDIO_CHANNEL_2 == channel_num) ? 0 : 1;
+
+ if ((AUDIO_SAMPLE_RATE_192KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_176_4KHZ == sample_rate)) {
+ multiplier = 4;
+ n >>= 2; /* divide N by 4 and use multiplier */
+ } else if ((AUDIO_SAMPLE_RATE_96KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_88_2KHZ == sample_rate)) {
+ multiplier = 2;
+ n >>= 1; /* divide N by 2 and use multiplier */
+ } else {
+ multiplier = 1;
+ }
+
+ dprintf(SPEW, "%s: n=%u, cts=%u, layout=%u\n", __func__, n, cts,
+ layout);
/* AUDIO_PRIORITY | SOURCE */
acr_pck_ctrl_reg |= 0x80000100;
+ /* Reset multiplier bits */
+ acr_pck_ctrl_reg &= ~(7 << 16);
+
/* N_MULTIPLE(multiplier) */
acr_pck_ctrl_reg |= (multiplier & 7) << 16;
- /* SELECT(3) */
- acr_pck_ctrl_reg |= 3 << 4;
+ if ((AUDIO_SAMPLE_RATE_48KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_96KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_192KHZ == sample_rate)) {
+ /* SELECT(3) */
+ acr_pck_ctrl_reg |= 3 << 4;
+ /* CTS_48 */
+ cts <<= 12;
- /* CTS_48 */
- cts <<= 12;
+ /* CTS: need to determine how many fractional bits */
+ writel(cts, HDMI_ACR_48_0);
+ /* N */
+ writel(n, HDMI_ACR_48_1);
+ } else if ((AUDIO_SAMPLE_RATE_44_1KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_88_2KHZ == sample_rate) ||
+ (AUDIO_SAMPLE_RATE_176_4KHZ == sample_rate)) {
+ /* SELECT(2) */
+ acr_pck_ctrl_reg |= 2 << 4;
+ /* CTS_44 */
+ cts <<= 12;
- /* CTS: need to determine how many fractional bits */
- writel(cts, HDMI_ACR_48_0);
+ /* CTS: need to determine how many fractional bits */
+ writel(cts, HDMI_ACR_44_0);
+ /* N */
+ writel(n, HDMI_ACR_44_1);
+ } else { /* default to 32k */
+ /* SELECT(1) */
+ acr_pck_ctrl_reg |= 1 << 4;
+ /* CTS_32 */
+ cts <<= 12;
- /* N */
- /* HDMI_ACR_48_1 */
- writel(n, HDMI_ACR_48_1);
+ /* CTS: need to determine how many fractional bits */
+ writel(cts, HDMI_ACR_32_0);
+ /* N */
+ writel(n, HDMI_ACR_32_1);
+ }
/* Payload layout depends on number of audio channels */
+ /* LAYOUT_SEL(layout) */
aud_pck_ctrl_2_reg = 1 | (layout << 1);
-
/* override | layout */
writel(aud_pck_ctrl_2_reg, HDMI_AUDIO_PKT_CTRL2);
/* SEND | CONT */
- acr_pck_ctrl_reg |= 0x3;
+ acr_pck_ctrl_reg |= 0x00000003;
writel(acr_pck_ctrl_reg, HDMI_ACR_PKT_CTRL);
}
-static int mdss_hdmi_audio_info_setup(void)
+static void mdss_hdmi_audio_info_setup(void)
{
- uint32_t channel_count = 1; /* Default to 2 channels
- -> See Table 17 in CEA-D spec */
+ uint32_t channel_count = MSM_HDMI_AUDIO_CHANNEL_2;
uint32_t channel_allocation = 0;
uint32_t level_shift = 0;
uint32_t down_mix = 0;
@@ -159,7 +388,7 @@
uint32_t aud_pck_ctrl_2_reg;
uint32_t layout;
- layout = 0;
+ layout = (MSM_HDMI_AUDIO_CHANNEL_2 == channel_count) ? 0 : 1;;
aud_pck_ctrl_2_reg = 1 | (layout << 1);
writel(aud_pck_ctrl_2_reg, HDMI_AUDIO_PKT_CTRL2);
@@ -213,15 +442,91 @@
/* HDMI_INFOFRAME_CTRL0[0x002C] */
writel(audio_info_ctrl_reg, HDMI_INFOFRAME_CTRL0);
+}
- return 0;
+static uint8_t* hdmi_edid_find_block(uint32_t start_offset,
+ uint8_t type, uint8_t *len)
+{
+ /* the start of data block collection, start of Video Data Block */
+ uint8_t *in_buf = mdss_hdmi_edid_buf;
+ uint32_t offset = start_offset;
+ uint32_t end_dbc_offset = in_buf[2];
+
+ *len = 0;
+
+ /*
+ * edid buffer 1, byte 2 being 4 means no non-DTD/Data block collection
+ * present.
+ * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block collection
+ * present and no DTD data present.
+ */
+ if ((end_dbc_offset == 0) || (end_dbc_offset == 4))
+ return NULL;
+
+ while (offset < end_dbc_offset) {
+ uint8_t block_len = in_buf[offset] & 0x1F;
+ if ((in_buf[offset] >> 5) == type) {
+ *len = block_len;
+ dprintf(SPEW,
+ "EDID: block=%d found @ %d with length=%d\n",
+ type, offset, block_len);
+ return in_buf + offset;
+ }
+ offset += 1 + block_len;
+ }
+
+ return NULL;
+}
+
+static bool mdss_hdmi_is_audio_freq_supported(uint32_t freq)
+{
+ uint8_t *in_buf = mdss_hdmi_edid_buf;
+ const uint8_t *adb = NULL;
+ uint32_t adb_size = 0;
+ uint8_t len = 0, count = 0;
+ uint32_t next_offset = DBC_START_OFFSET;
+ uint8_t audio_data_block[MAX_AUDIO_DATA_BLOCK_SIZE];
+
+ do {
+ adb = hdmi_edid_find_block(next_offset,
+ AUDIO_DATA_BLOCK, &len);
+
+ if ((adb_size + len) > MAX_AUDIO_DATA_BLOCK_SIZE) {
+ dprintf(INFO, "%s: invalid adb length\n", __func__);
+ break;
+ }
+
+ if (!adb)
+ break;
+
+ memcpy((audio_data_block + adb_size), adb + 1, len);
+ next_offset = (adb - in_buf) + 1 + len;
+
+ adb_size += len;
+
+ } while (adb);
+
+ count = adb_size/3;
+ adb = audio_data_block;
+
+ while (count--) {
+ uint8_t freq_lst = *(adb + 1) & 0xFF;
+
+ if (freq_lst & BIT(freq))
+ return true;
+
+ adb += 3;
+ }
+
+ return false;
}
static void mdss_hdmi_audio_playback(void)
{
- uint32_t base_addr;
+ char *base_addr;
+ uint32_t sample_rate;
- base_addr = memalign(4096, 0x1000);
+ base_addr = (char *) memalign(4096, 0x1000);
if (base_addr == NULL) {
dprintf(CRITICAL, "%s: Error audio buffer alloc\n", __func__);
return;
@@ -237,7 +542,7 @@
writel(0x00002000, HDMI_VBI_PKT_CTRL);
writel(0x00000000, HDMI_GEN_PKT_CTRL);
writel(0x0000096E, LPASS_LPAIF_RDDMA_CTL0);
- writel(base_addr, LPASS_LPAIF_RDDMA_BASE0);
+ writel((uint32_t) base_addr, LPASS_LPAIF_RDDMA_BASE0);
writel(0x000005FF, LPASS_LPAIF_RDDMA_BUFF_LEN0);
writel(0x000005FF, LPASS_LPAIF_RDDMA_PER_LEN0);
writel(0x0000096F, LPASS_LPAIF_RDDMA_CTL0);
@@ -247,41 +552,70 @@
writel(0x00002030, HDMI_VBI_PKT_CTRL);
writel(0x00002030, HDMI_VBI_PKT_CTRL);
- mdss_hdmi_audio_acr_setup();
+ if (mdss_hdmi_is_audio_freq_supported(AUDIO_SAMPLE_RATE_48KHZ))
+ sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
+ else
+ sample_rate = AUDIO_SAMPLE_RATE_32KHZ;
+
+ mdss_hdmi_audio_acr_setup(sample_rate);
mdss_hdmi_audio_info_setup();
writel(0x00000010, HDMI_AUDIO_PKT_CTRL);
writel(0x00000080, HDMI_AUDIO_CFG);
writel(0x00000011, HDMI_AUDIO_PKT_CTRL);
writel(0x00000081, HDMI_AUDIO_CFG);
+
+ dprintf(SPEW, "audio sample rate %s\n",
+ sample_rate == AUDIO_SAMPLE_RATE_48KHZ ? "48KHz" : "32KHz");
}
-static int mdss_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
+static uint32_t mdss_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
{
- return target_hdmi_panel_clock(enable, pinfo);
+ int ret = NO_ERROR;
+ if (hdmi_panel_clock_enabled)
+ return ret;
+
+ ret = target_hdmi_panel_clock(enable, pinfo);
+
+ hdmi_panel_clock_enabled = enable;
+
+ return ret;
+}
+
+static uint32_t mdss_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+ int ret = NO_ERROR;
+
+ if (hdmi_pll_clock_enabled)
+ return ret;
+
+ ret = target_hdmi_pll_clock(enable, pinfo);
+
+ hdmi_pll_clock_enabled = enable;
+
+ return ret;
}
static int mdss_hdmi_enable_power(uint8_t enable, struct msm_panel_info *pinfo)
{
- int ret = NO_ERROR;
+ int ret = NO_ERROR;
- ret = target_ldo_ctrl(enable, pinfo);
- if (ret) {
- dprintf(CRITICAL, "LDO control enable failed\n");
- goto bail_ldo_fail;
- }
+ if (hdmi_power_enabled)
+ return ret;
ret = target_hdmi_regulator_ctrl(enable);
if (ret) {
dprintf(CRITICAL, "hdmi regulator control enable failed\n");
goto bail_regulator_fail;
- }
+ }
ret = target_hdmi_gpio_ctrl(enable);
if (ret) {
dprintf(CRITICAL, "hdmi gpio control enable failed\n");
goto bail_gpio_fail;
- }
+ }
+
+ hdmi_power_enabled = enable;
dprintf(SPEW, "HDMI Panel power %s done\n", enable ? "on" : "off");
@@ -291,55 +625,269 @@
target_hdmi_regulator_ctrl(0);
bail_regulator_fail:
- target_ldo_ctrl(0, pinfo);
-
-bail_ldo_fail:
return ret;
}
+static bool mdss_hdmi_is_dvi_mode(void)
+{
+ uint8_t len;
+ uint32_t ieee_tag;
+ const uint8_t *vsd = NULL;
+
+ vsd = hdmi_edid_find_block(DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
+
+ if (vsd == NULL || len == 0) {
+ dprintf(SPEW, "%s: Invalid VSDB\n", __func__);
+ return false;
+ }
+
+ ieee_tag = ((uint32_t) vsd[3] << 16) + ((uint32_t) vsd[2] << 8) +
+ (uint32_t) vsd[1];
+
+ if (ieee_tag == 0x0c03)
+ return false;
+ else
+ return true;
+}
+
static void mdss_hdmi_set_mode(bool on)
{
uint32_t val = 0;
if (on) {
- val = 0x3;
- writel(val, HDMI_CTRL);
- } else {
- writel(val, HDMI_CTRL);
+ /* tx on */
+ val = 0x1;
+
+ if (!mdss_hdmi_is_dvi_mode())
+ val |= 0x2;
}
+
+ writel(val, HDMI_CTRL);
+}
+
+
+static int mdss_hdmi_read_edid(void)
+{
+ uint8_t ndx;
+ uint32_t reg_val;
+ uint32_t dev_addr = 0xA0;
+ uint32_t len = 0x80;
+ uint32_t offset = 0x80;
+ uint32_t time_out;
+ uint32_t retry = 5;
+
+ dev_addr &= 0xFE;
+
+again:
+ time_out = 10;
+ writel(readl(HDMI_DDC_ARBITRATION) & ~BIT(4), HDMI_DDC_ARBITRATION);
+
+ /* Enable DDC Interrupts */
+ writel(BIT(1) | BIT(2), HDMI_DDC_INT_CTRL);
+
+ /* config DDC to read CEA block */
+ writel((10 << 16) | (2 << 0), HDMI_DDC_SPEED);
+ writel(0xFF000000, HDMI_DDC_SETUP);
+ writel((1 << 16) | (19 << 0), HDMI_DDC_REF);
+ writel(BIT(31) | (dev_addr << 8), HDMI_DDC_DATA);
+ writel(offset << 8, HDMI_DDC_DATA);
+ writel((dev_addr | BIT(0)) << 8, HDMI_DDC_DATA);
+ writel(BIT(12) | BIT(16), HDMI_DDC_TRANS0);
+ writel(BIT(0) | BIT(12) | BIT(13) | (len << 16), HDMI_DDC_TRANS1);
+ writel(BIT(0) | BIT(20), HDMI_DDC_CTRL);
+
+ /* poll for 100ms for read to complete */
+ reg_val = readl(HDMI_DDC_INT_CTRL);
+ while (!(reg_val & BIT(0)) && time_out) {
+ reg_val = readl(HDMI_DDC_INT_CTRL);
+ time_out--;
+ mdelay(10);
+ }
+
+ if (!time_out) {
+ dprintf(CRITICAL, "%s: Timeout reading EDID\n", __func__);
+ if (retry--)
+ goto again;
+ else
+ return ERROR;
+ }
+
+ /* clear interrupts */
+ writel(BIT(1), HDMI_DDC_INT_CTRL);
+
+ reg_val = readl(HDMI_DDC_SW_STATUS);
+ reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+ /* Check if any NACK occurred */
+ if (reg_val) {
+ /* SW_STATUS_RESET */
+ writel(BIT(3), HDMI_DDC_CTRL);
+
+ /* SOFT_RESET */
+ writel(BIT(1), HDMI_DDC_CTRL);
+
+ dprintf(CRITICAL, "%s: NACK reading EDID\n", __func__);
+
+ if (retry--)
+ goto again;
+ else
+ return ERROR;
+ }
+
+ /* Write this data to DDC buffer */
+ writel(BIT(0) | (3 << 16) | BIT(31), HDMI_DDC_DATA);
+
+ /* Discard first byte */
+ readl(HDMI_DDC_DATA);
+
+ for (ndx = 0; ndx < 0x80; ndx++) {
+ reg_val = readl(HDMI_DDC_DATA);
+ mdss_hdmi_edid_buf[ndx] = (uint8_t)((reg_val & 0x0000FF00) >> 8);
+ }
+
+ dprintf(INFO, "%s: EDID read successful\n", __func__);
+
+ return NO_ERROR;
+}
+
+static void mdss_hdmi_parse_res(void)
+{
+ uint8_t len, i;
+ uint32_t video_format;
+ struct mdss_hdmi_timing_info tinfo_fmt = {0};
+
+ uint8_t *svd = hdmi_edid_find_block(DBC_START_OFFSET,
+ VIDEO_DATA_BLOCK, &len);
+
+ mdss_hdmi_video_fmt = HDMI_VFRMT_UNKNOWN;
+
+ if (!svd) {
+ mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+ return;
+ }
+
+ ++svd;
+
+ for (i = 0; i < len; ++i, ++svd) {
+ struct mdss_hdmi_timing_info tinfo = {0};
+ uint32_t ret = 0;
+
+ video_format = (*svd & 0x7F);
+
+ if (i == 0)
+ mdss_hdmi_pref_fmt = video_format;
+
+ ret = mdss_hdmi_get_timing_info(&tinfo, video_format);
+
+ if (ret || !tinfo.supported)
+ continue;
+
+ if (!tinfo_fmt.video_format) {
+ memcpy(&tinfo_fmt, &tinfo, sizeof(tinfo));
+ mdss_hdmi_video_fmt = video_format;
+ continue;
+ }
+
+ if (tinfo.active_v > tinfo_fmt.active_v) {
+ memcpy(&tinfo_fmt, &tinfo, sizeof(tinfo));
+ mdss_hdmi_video_fmt = video_format;
+ }
+ }
+
+ if (mdss_hdmi_video_fmt == HDMI_VFRMT_UNKNOWN)
+ mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+}
+
+void mdss_hdmi_get_vic(char *buf)
+{
+ struct mdss_hdmi_timing_info tinfo = {0};
+ uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
+
+ if (ret)
+ snprintf(buf, HDMI_VIC_STR_MAX, "%d", HDMI_VFRMT_UNKNOWN);
+ else
+ snprintf(buf, HDMI_VIC_STR_MAX, "%d", tinfo.video_format);
+
}
static void mdss_hdmi_panel_init(struct msm_panel_info *pinfo)
{
- struct mdss_hdmi_timing_info tinfo = HDMI_RESOLUTION_DATA;
+ struct mdss_hdmi_timing_info tinfo = {0};
+ uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
- if (!pinfo)
+ if (!pinfo || ret)
return;
pinfo->xres = tinfo.active_h;
pinfo->yres = tinfo.active_v;
pinfo->bpp = 24;
pinfo->type = HDMI_PANEL;
+ pinfo->clk_rate = tinfo.pixel_freq * 1000;
- pinfo->lcdc.h_back_porch = tinfo.back_porch_h;
- pinfo->lcdc.h_front_porch = tinfo.front_porch_h;
- pinfo->lcdc.h_pulse_width = tinfo.pulse_width_h;
- pinfo->lcdc.v_back_porch = tinfo.back_porch_v;
- pinfo->lcdc.v_front_porch = tinfo.front_porch_v;
- pinfo->lcdc.v_pulse_width = tinfo.pulse_width_v;
+ pinfo->lcdc.h_back_porch = tinfo.back_porch_h;
+ pinfo->lcdc.h_front_porch = tinfo.front_porch_h;
+ pinfo->lcdc.h_pulse_width = tinfo.pulse_width_h;
+ pinfo->lcdc.v_back_porch = tinfo.back_porch_v;
+ pinfo->lcdc.v_front_porch = tinfo.front_porch_v;
+ pinfo->lcdc.v_pulse_width = tinfo.pulse_width_v;
- pinfo->lcdc.hsync_skew = 0;
- pinfo->lcdc.xres_pad = 0;
- pinfo->lcdc.yres_pad = 0;
- pinfo->lcdc.dual_pipe = 0;
+ pinfo->lcdc.hsync_skew = 0;
+ pinfo->lcdc.xres_pad = 0;
+ pinfo->lcdc.yres_pad = 0;
+ pinfo->lcdc.dual_pipe = 0;
}
-void mdss_hdmi_display_init(uint32_t rev, void *base)
+static uint8_t mdss_hdmi_cable_status(void)
{
- mdss_hdmi_panel_init(&(panel.panel_info));
+ uint32_t reg_val;
+ uint8_t cable_status;
- panel.clk_func = mdss_hdmi_panel_clock;
- panel.power_func = mdss_hdmi_enable_power;
+ mdss_hdmi_set_mode(true);
+
+ /* Enable USEC REF timer */
+ writel(0x0001001B, HDMI_USEC_REFTIMER);
+
+ /* set timeout to 4.1ms (max) for hardware debounce */
+ reg_val = readl(HDMI_HPD_CTRL) | 0x1FFF;
+
+ /* enable HPD circuit */
+ writel(reg_val | BIT(28), HDMI_HPD_CTRL);
+
+ writel(BIT(2) | BIT(1), HDMI_HPD_INT_CTRL);
+
+ /* Toggle HPD circuit to trigger HPD sense */
+ reg_val = readl(HDMI_HPD_CTRL) | 0x1FFF;
+ writel(reg_val & ~BIT(28), HDMI_HPD_CTRL);
+ writel(reg_val & BIT(28), HDMI_HPD_CTRL);
+
+ mdelay(20);
+
+ cable_status = (readl(HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+
+ dprintf(INFO, "hdmi cable %s\n",
+ cable_status ? "connected" : "not connected");
+
+ writel(BIT(0), HDMI_HPD_INT_CTRL);
+ writel(reg_val & ~BIT(28), HDMI_HPD_CTRL);
+
+ mdss_hdmi_set_mode(false);
+
+ return cable_status;
+}
+
+static int mdss_hdmi_update_panel_info(void)
+{
+ mdss_hdmi_set_mode(true);
+
+ if (!mdss_hdmi_read_edid())
+ mdss_hdmi_parse_res();
+ else
+ mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+
+ mdss_hdmi_set_mode(false);
+
+ mdss_hdmi_panel_init(&(panel.panel_info));
panel.fb.width = panel.panel_info.xres;
panel.fb.height = panel.panel_info.yres;
@@ -347,6 +895,16 @@
panel.fb.bpp = panel.panel_info.bpp;
panel.fb.format = FB_FORMAT_RGB888;
+ return NO_ERROR;
+}
+
+void mdss_hdmi_display_init(uint32_t rev, void *base)
+{
+ panel.power_func = mdss_hdmi_enable_power;
+ panel.clk_func = mdss_hdmi_panel_clock;
+ panel.update_panel_info = mdss_hdmi_update_panel_info;
+ panel.pll_clk_func = mdss_hdmi_pll_clock;
+
panel.fb.base = base;
panel.mdp_rev = rev;
@@ -362,7 +920,15 @@
uint32_t start_v = 0;
uint32_t end_v = 0;
- struct mdss_hdmi_timing_info tinfo = HDMI_RESOLUTION_DATA;
+ struct mdss_hdmi_timing_info tinfo = {0};
+ uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
+
+ if (ret)
+ return ERROR;
+
+ dprintf(INFO, "hdmi resolution %dx%d@p%dHz (%d)\n",
+ tinfo.active_h, tinfo.active_v, tinfo.refresh_rate/1000,
+ mdss_hdmi_video_fmt);
total_h = tinfo.active_h + tinfo.front_porch_h +
tinfo.back_porch_h + tinfo.pulse_width_h - 1;
@@ -412,43 +978,141 @@
return 0;
}
+static void mdss_hdmi_extract_extended_data_blocks(void)
+{
+ uint8_t len = 0;
+ uint32_t start_offset = DBC_START_OFFSET;
+ uint8_t const *etag = NULL;
+ uint8_t *in_buf = mdss_hdmi_edid_buf;
+
+ do {
+ /* A Tage code of 7 identifies extended data blocks */
+ etag = hdmi_edid_find_block(start_offset,
+ USE_EXTENDED_TAG, &len);
+
+ start_offset = etag - in_buf + len + 1;
+
+ /* The extended data block should at least be 2 bytes long */
+ if (len < 2) {
+ dprintf(SPEW, "%s: data block of len < 2 bytes\n",
+ __func__);
+ continue;
+ }
+
+ /*
+ * The second byte of the extended data block has the
+ * extended tag code
+ */
+ switch (etag[1]) {
+ case 0:
+ /*
+ * Check if the sink specifies underscan
+ * support for:
+ * BIT 5: preferred video format
+ * BIT 3: IT video format
+ * BIT 1: CE video format
+ */
+ pt_scan_info = (etag[2] & (BIT(4) | BIT(5))) >> 4;
+ it_scan_info = (etag[2] & (BIT(3) | BIT(2))) >> 2;
+ ce_scan_info = etag[2] & (BIT(1) | BIT(0));
+
+ dprintf(INFO, "scan Info (pt|it|ce): (%d|%d|%d)\n",
+ pt_scan_info, it_scan_info, ce_scan_info);
+ break;
+ default:
+ dprintf(SPEW, "%s: Tag Code %d not supported\n",
+ __func__, etag[1]);
+ break;
+ }
+ } while (etag != NULL);
+}
+
+/*
+ * If the sink specified support for both underscan/overscan then, by default,
+ * set the underscan bit. Only checking underscan support for preferred
+ * format and cea formats.
+ */
+uint8_t mdss_hdmi_get_scan_info(void)
+{
+ uint8_t scaninfo = 0;
+ bool use_ce_scan_info = true;
+
+ mdss_hdmi_extract_extended_data_blocks();
+
+ if (mdss_hdmi_video_fmt == mdss_hdmi_pref_fmt) {
+ use_ce_scan_info = false;
+
+ switch (pt_scan_info) {
+ case 0:
+ use_ce_scan_info = true;
+ break;
+ case 3:
+ scaninfo = BIT(1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (use_ce_scan_info) {
+ if (3 == ce_scan_info)
+ scaninfo |= BIT(1);
+ }
+
+ return scaninfo;
+}
+
void mdss_hdmi_avi_info_frame(void)
{
uint32_t sum;
uint32_t reg_val;
uint8_t checksum;
- uint32_t i;
+ uint8_t scaninfo;
+ uint32_t i, index;
+
+ scaninfo = mdss_hdmi_get_scan_info();
sum = IFRAME_PACKET_OFFSET + AVI_IFRAME_TYPE +
AVI_IFRAME_VERSION + AVI_MAX_DATA_BYTES;
+ for (index = 0; index < HDMI_VFRMT_MAX; index++) {
+ if (mdss_hdmi_avi_info_db[index][VIC_INDEX] == mdss_hdmi_video_fmt)
+ break;
+ }
+
+ if (index == VIC_INDEX)
+ return;
+
+ mdss_hdmi_avi_info_db[index][DATA_BYTE_1] |=
+ scaninfo & (BIT(1) | BIT(0));
+
for (i = 0; i < AVI_MAX_DATA_BYTES; i++)
- sum += mdss_hdmi_avi_info_db[i];
+ sum += mdss_hdmi_avi_info_db[index][i];
sum &= 0xFF;
sum = 256 - sum;
checksum = (uint8_t) sum;
reg_val = checksum |
- LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[DATA_BYTE_1]) |
- LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[DATA_BYTE_2]) |
- LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[DATA_BYTE_3]);
+ LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_1]) |
+ LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_2]) |
+ LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_3]);
writel(reg_val, HDMI_AVI_INFO0);
- reg_val = mdss_hdmi_avi_info_db[DATA_BYTE_4] |
- LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[DATA_BYTE_5]) |
- LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[DATA_BYTE_6]) |
- LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[DATA_BYTE_7]);
+ reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_4] |
+ LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_5]) |
+ LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_6]) |
+ LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_7]);
writel(reg_val, HDMI_AVI_INFO1);
- reg_val = mdss_hdmi_avi_info_db[DATA_BYTE_8] |
- LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[DATA_BYTE_9]) |
- LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[DATA_BYTE_10]) |
- LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[DATA_BYTE_11]);
+ reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_8] |
+ LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_9]) |
+ LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_10]) |
+ LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_11]);
writel(reg_val, HDMI_AVI_INFO2);
- reg_val = mdss_hdmi_avi_info_db[DATA_BYTE_12] |
- LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[DATA_BYTE_13]) |
+ reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_12] |
+ LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_13]) |
LEFT_SHIFT_24BITS(AVI_IFRAME_VERSION);
writel(reg_val, HDMI_AVI_INFO3);
@@ -459,23 +1123,20 @@
int mdss_hdmi_init(void)
{
- uint32_t hotplug_control;
+ bool is_dvi_mode = mdss_hdmi_is_dvi_mode();
mdss_hdmi_set_mode(false);
- hdmi_phy_init();
-
- /* Enable USEC REF timer */
- writel(0x0001001B, HDMI_USEC_REFTIMER);
-
/* Audio settings */
- mdss_hdmi_audio_playback();
+ if (!is_dvi_mode)
+ mdss_hdmi_audio_playback();
/* Video settings */
mdss_hdmi_video_setup();
/* AVI info settings */
- mdss_hdmi_avi_info_frame();
+ if (!is_dvi_mode)
+ mdss_hdmi_avi_info_frame();
/* Enable HDMI */
mdss_hdmi_set_mode(true);
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index fe90e5d..aad0a11 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -464,7 +464,9 @@
$(LOCAL_DIR)/mipi_dsi.o \
$(LOCAL_DIR)/mipi_dsi_phy.o \
$(LOCAL_DIR)/mipi_dsi_autopll.o \
- $(LOCAL_DIR)/mipi_dsi_autopll_20nm.o
+ $(LOCAL_DIR)/mipi_dsi_autopll_20nm.o \
+ $(LOCAL_DIR)/mdss_hdmi.o \
+ $(LOCAL_DIR)/hdmi_pll_20nm.o
endif
ifeq ($(PLATFORM),msm8909)
diff --git a/platform/msm_shared/smem.h b/platform/msm_shared/smem.h
index 3468435..fab80bb 100644
--- a/platform/msm_shared/smem.h
+++ b/platform/msm_shared/smem.h
@@ -382,7 +382,7 @@
MSM8236 = 242,
MSM8636 = 243,
MSM8909 = 245,
- MSMTHULIUM = 246,
+ MSM8996 = 246,
APQ8016 = 247,
MSM8216 = 248,
MSM8116 = 249,
diff --git a/platform/msm_shared/usb30_dwc.c b/platform/msm_shared/usb30_dwc.c
index 6f419cd..5ae8801 100644
--- a/platform/msm_shared/usb30_dwc.c
+++ b/platform/msm_shared/usb30_dwc.c
@@ -1730,7 +1730,7 @@
ep->bytes_queued = 0;
- if (ep->type == EP_TYPE_CONTROL)
+ if (ep->type == EP_TYPE_CONTROL || ep->type == EP_TYPE_INTERRUPT)
{
memset(trb, 0, sizeof(dwc_trb_t));
diff --git a/platform/msm_shared/usb30_dwc.h b/platform/msm_shared/usb30_dwc.h
index 1a69a61..14402e7 100644
--- a/platform/msm_shared/usb30_dwc.h
+++ b/platform/msm_shared/usb30_dwc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 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
@@ -379,7 +379,7 @@
} dwc_notify_event_t;
/* maximum number of endpoints supported. */
-#define DWC_MAX_NUM_OF_EP 4
+#define DWC_MAX_NUM_OF_EP 8
/* length of setup packet */
#define DWC_SETUP_PKT_LEN 8
diff --git a/platform/msm_shared/usb30_udc.c b/platform/msm_shared/usb30_udc.c
index 0e5e1b0..d9d18a2 100644
--- a/platform/msm_shared/usb30_udc.c
+++ b/platform/msm_shared/usb30_udc.c
@@ -559,7 +559,7 @@
ep->number = ept->num;
ep->dir = ept->in;
- ep->type = EP_TYPE_BULK; /* the only one supported */
+ ep->type = ept->type;
ep->max_pkt_size = ept->maxpkt;
ep->burst_size = ept->maxburst;
ep->zlp = 0; /* TODO: zlp could be made part of ept */
@@ -848,6 +848,7 @@
static struct udc_endpoint *_udc_endpoint_alloc(uint8_t num,
uint8_t in,
+ uint8_t type,
uint16_t max_pkt)
{
struct udc_endpoint *ept;
@@ -858,6 +859,7 @@
ept->maxpkt = max_pkt;
ept->num = num;
+ ept->type = type;
ept->in = !!in;
ept->maxburst = 4; /* no performance improvement is seen beyond burst size of 4 */
ept->trb_count = 66; /* each trb can transfer (16MB - 1). 65 for 1GB transfer + 1 for roundup/zero length pkt. */
@@ -881,8 +883,16 @@
if (type == UDC_TYPE_BULK_IN) {
in = 1;
+ type = EP_TYPE_BULK;
} else if (type == UDC_TYPE_BULK_OUT) {
in = 0;
+ type = EP_TYPE_BULK;
+ } else if (type == UDC_TYPE_INTR_IN) {
+ in = 1;
+ type = EP_TYPE_INTERRUPT;
+ } else if (type == UDC_TYPE_INTR_OUT){
+ in = 0;
+ type = EP_TYPE_INTERRUPT;
} else {
return 0;
}
@@ -891,7 +901,7 @@
uint32_t bit = in ? EPT_TX(n) : EPT_RX(n);
if (udc->ept_alloc_table & bit)
continue;
- ept = _udc_endpoint_alloc(n, in, maxpkt);
+ ept = _udc_endpoint_alloc(n, in, type, maxpkt);
if (ept)
udc->ept_alloc_table |= bit;
return ept;
diff --git a/platform/msm_shared/usb30_udc.h b/platform/msm_shared/usb30_udc.h
index 02e86fa..97ef7e8 100644
--- a/platform/msm_shared/usb30_udc.h
+++ b/platform/msm_shared/usb30_udc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, 2015 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
@@ -84,6 +84,7 @@
struct udc_endpoint {
struct udc_endpoint *next;
uint8_t num;
+ uint8_t type;
uint8_t in;
uint16_t maxpkt;
uint32_t maxburst; /* max pkts that this ep can transfer before waiting for ack. */
diff --git a/target/init.c b/target/init.c
index 97809cc..9191572 100644
--- a/target/init.c
+++ b/target/init.c
@@ -59,6 +59,11 @@
return 0;
}
+__WEAK int update_ubi_vol(void)
+{
+ return 0;
+}
+
__WEAK int target_is_emmc_boot(void)
{
#if _EMMC_BOOT
diff --git a/target/msm8994/include/target/display.h b/target/msm8994/include/target/display.h
index c426ee2..66d548f 100644
--- a/target/msm8994/include/target/display.h
+++ b/target/msm8994/include/target/display.h
@@ -33,6 +33,7 @@
/* HEADER files */
/*---------------------------------------------------------------------------*/
#include <display_resource.h>
+#include <msm_panel.h>
#define TOTAL_LDO_DEFINED 3
@@ -82,7 +83,8 @@
#define PWM_BL_LPG_CHAN_ID 4 /* lpg_out<3> */
#define HDMI_PANEL_NAME "hdmi"
-#define HDMI_CONTROLLER_STRING "hdmi:0"
+#define HDMI_CONTROLLER_STRING "hdmi:"
+#define HDMI_VIC_LEN 5
#endif
@@ -97,5 +99,9 @@
int target_display_get_base_offset(uint32_t base);
void target_force_cont_splash_disable(uint8_t override);
uint8_t target_panel_auto_detect_enabled();
+int target_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo);
+int target_hdmi_regulator_ctrl(uint8_t enable);
+int target_hdmi_gpio_ctrl(uint8_t enable);
+int target_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo);
diff --git a/target/msm8994/target_display.c b/target/msm8994/target_display.c
index 6cf3653..0b40e7d 100644
--- a/target/msm8994/target_display.c
+++ b/target/msm8994/target_display.c
@@ -33,6 +33,7 @@
#include <err.h>
#include <msm_panel.h>
#include <mipi_dsi.h>
+#include <mdss_hdmi.h>
#include <pm8x41.h>
#include <pm8x41_wled.h>
#include <qpnp_wled.h>
@@ -80,6 +81,50 @@
"pmi8994_gpios", 2, 3, 1, 0, 1
};
+/* gpio name, id, strength, direction, pull, state. */
+static struct gpio_pin hdmi_cec_gpio = { /* CEC */
+ "msmgpio", 31, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_ddc_clk_gpio = { /* DDC CLK */
+ "msmgpio", 32, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_ddc_data_gpio = { /* DDC DATA */
+ "msmgpio", 33, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_hpd_gpio = { /* HPD, input */
+ "msmgpio", 34, 7, 0, 1, 1
+};
+
+int target_hdmi_gpio_ctrl(uint8_t enable)
+{
+ gpio_tlmm_config(hdmi_cec_gpio.pin_id, 1, /* gpio 31, CEC */
+ hdmi_cec_gpio.pin_direction, hdmi_cec_gpio.pin_pull,
+ hdmi_cec_gpio.pin_strength, hdmi_cec_gpio.pin_state);
+
+ gpio_tlmm_config(hdmi_ddc_clk_gpio.pin_id, 1, /* gpio 32, DDC CLK */
+ hdmi_ddc_clk_gpio.pin_direction, hdmi_ddc_clk_gpio.pin_pull,
+ hdmi_ddc_clk_gpio.pin_strength, hdmi_ddc_clk_gpio.pin_state);
+
+
+ gpio_tlmm_config(hdmi_ddc_data_gpio.pin_id, 1, /* gpio 33, DDC DATA */
+ hdmi_ddc_data_gpio.pin_direction, hdmi_ddc_data_gpio.pin_pull,
+ hdmi_ddc_data_gpio.pin_strength, hdmi_ddc_data_gpio.pin_state);
+
+ gpio_tlmm_config(hdmi_hpd_gpio.pin_id, 1, /* gpio 34, HPD */
+ hdmi_hpd_gpio.pin_direction, hdmi_hpd_gpio.pin_pull,
+ hdmi_hpd_gpio.pin_strength, hdmi_hpd_gpio.pin_state);
+
+ gpio_set(hdmi_cec_gpio.pin_id, hdmi_cec_gpio.pin_direction);
+ gpio_set(hdmi_ddc_clk_gpio.pin_id, hdmi_ddc_clk_gpio.pin_direction);
+ gpio_set(hdmi_ddc_data_gpio.pin_id, hdmi_ddc_data_gpio.pin_direction);
+ gpio_set(hdmi_hpd_gpio.pin_id, hdmi_hpd_gpio.pin_direction);
+
+ return NO_ERROR;
+}
+
static uint32_t dsi_pll_20nm_enable_seq(uint32_t pll_base)
{
uint32_t pll_locked;
@@ -254,6 +299,22 @@
return ret;
}
+int target_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+ if (enable) {
+ hdmi_phy_reset();
+ hdmi_pll_config(pinfo->clk_rate);
+ hdmi_vco_enable();
+ hdmi_pixel_clk_enable(pinfo->clk_rate);
+ } else if(!target_cont_splash_screen()) {
+ /* Disable clocks if continuous splash off */
+ hdmi_pixel_clk_disable();
+ hdmi_vco_disable();
+ }
+
+ return NO_ERROR;
+}
+
int target_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
{
uint32_t ret = NO_ERROR;
@@ -454,6 +515,7 @@
{
int prefix_string_len = strlen(DISPLAY_CMDLINE_PREFIX);
bool ret = true;
+ char vic_buf[HDMI_VIC_LEN] = "0";
panel_name += strspn(panel_name, " ");
@@ -469,6 +531,9 @@
strlcat(pbuf, LK_OVERRIDE_PANEL, buf_size);
buf_size -= LK_OVERRIDE_PANEL_LEN;
strlcat(pbuf, HDMI_CONTROLLER_STRING, buf_size);
+ buf_size -= strlen(HDMI_CONTROLLER_STRING);
+ mdss_hdmi_get_vic(vic_buf);
+ strlcat(pbuf, vic_buf, buf_size);
} else {
ret = gcdb_display_cmdline_arg(panel_name, pbuf, buf_size);
}
diff --git a/target/msm8996/init.c b/target/msm8996/init.c
index 356ef5e..2fd32d8 100644
--- a/target/msm8996/init.c
+++ b/target/msm8996/init.c
@@ -282,7 +282,7 @@
platform = board->platform;
switch(platform) {
- case MSMTHULIUM:
+ case MSM8996:
if (board->platform_version == 0x10000)
board->baseband = BASEBAND_APQ;
else
diff --git a/target/target_display.c b/target/target_display.c
index ae014e1..fb96638 100644
--- a/target/target_display.c
+++ b/target/target_display.c
@@ -116,3 +116,8 @@
{
return 0;
}
+
+__WEAK int target_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+ return 0;
+}