video: tegra: dc: Add eDP support to dc
Mark Stadler [Thu, 2 Aug 2012 00:51:41 +0000 (17:51 -0700)]
Change-Id: I040963c38bf68f4ceb17aa7ce00ef65fd6ec5a7a
Tested-by: Chao Xu <cxu@nvidia.com>
Reviewed-by: Mark Stadler <mastadler@nvidia.com>
Signed-off-by: Chao Xu <cxu@nvidia.com>
Signed-off-by: Jin Qian <jqian@nvidia.com>
Reviewed-on: http://git-master/r/82945
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Signed-off-by: Mark Stadler <mastadler@nvidia.com>

drivers/video/tegra/Kconfig
drivers/video/tegra/dc/Makefile
drivers/video/tegra/dc/dc_priv.h
drivers/video/tegra/dc/dp.c [new file with mode: 0644]
drivers/video/tegra/dc/dp.h [new file with mode: 0644]
drivers/video/tegra/dc/dpaux_regs.h [new file with mode: 0644]
drivers/video/tegra/dc/sor.c [new file with mode: 0644]
drivers/video/tegra/dc/sor.h [new file with mode: 0644]
drivers/video/tegra/dc/sor_regs.h [new file with mode: 0644]

index a418d6d..dfc738b 100644 (file)
@@ -207,6 +207,12 @@ config TEGRA_DSI
        help
          Say Y here to enable the DSI panel.
 
+config TEGRA_DP
+       bool "Enable eDP panel."
+       default  n
+       help
+         Say Y here to enable eDP panel.
+
 config NVMAP_CONVERT_CARVEOUT_TO_IOVMM
        bool "Convert carveout to IOVMM"
        depends on TEGRA_NVMAP && IOMMU_API
index d1a75ef..02181e5 100644 (file)
@@ -12,4 +12,7 @@ obj-y += nvsd.o
 obj-y += dsi.o
 obj-y += dc_sysfs.o
 obj-y += dc_config.o
+obj-$(CONFIG_TEGRA_DP) += dp.o
+obj-$(CONFIG_TEGRA_DP) += sor.o
+obj-$(CONFIG_TEGRA_OVERLAY) += overlay.o
 obj-$(CONFIG_TEGRA_DC_EXTENSIONS) += ext/
index cf739db..2118675 100644 (file)
@@ -277,6 +277,9 @@ static inline bool tegra_dc_is_powered(struct tegra_dc *dc)
 extern struct tegra_dc_out_ops tegra_dc_rgb_ops;
 extern struct tegra_dc_out_ops tegra_dc_hdmi_ops;
 extern struct tegra_dc_out_ops tegra_dc_dsi_ops;
+#ifdef CONFIG_TEGRA_DP
+extern struct tegra_dc_out_ops tegra_dc_dp_ops;
+#endif
 
 /* defined in dc_sysfs.c, used by dc.c */
 void tegra_dc_remove_sysfs(struct device *dev);
diff --git a/drivers/video/tegra/dc/dp.c b/drivers/video/tegra/dc/dp.c
new file mode 100644 (file)
index 0000000..3546ec2
--- /dev/null
@@ -0,0 +1,1475 @@
+/*
+ * drivers/video/tegra/dc/dp.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/nvhost.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <mach/clk.h>
+#include <mach/dc.h>
+#include <mach/fb.h>
+
+#include "dp.h"
+#include "sor.h"
+#include "sor_regs.h"
+#include "dpaux_regs.h"
+#include "dc_priv.h"
+
+
+
+static inline unsigned long tegra_dpaux_readl(struct tegra_dc_dp_data *dp,
+       unsigned long reg)
+{
+       return readl(dp->aux_base + reg * 4);
+}
+
+static inline void tegra_dpaux_writel(struct tegra_dc_dp_data *dp,
+       unsigned long reg, unsigned long val)
+{
+       writel(val, dp->aux_base + reg * 4);
+}
+
+
+static unsigned long tegra_dc_dpaux_poll_register(struct tegra_dc_dp_data *dp,
+       u32 reg, u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_ms)
+{
+       unsigned long timeout_jf = jiffies + msecs_to_jiffies(timeout_ms);
+       u32 reg_val = 0;
+
+       do {
+               usleep(poll_interval_us);
+               reg_val = tegra_dpaux_readl(dp, reg);
+       } while (((reg_val & mask) != exp_val) &&
+               time_after(timeout_jf, jiffies));
+
+       if ((reg_val & mask) == exp_val)
+               return 0;       /* success */
+       dev_dbg(&dp->dc->ndev->dev,
+               "sor_poll_register 0x%x: timeout\n", reg);
+       return jiffies - timeout_jf + 1;
+}
+
+
+static int tegra_dpaux_wait_transaction(struct tegra_dc_dp_data *dp)
+{
+       /* According to DP spec, each aux transaction needs to finish
+          within 40ms. */
+       if (tegra_dc_dpaux_poll_register(dp, DPAUX_DP_AUXCTL,
+                       DPAUX_DP_AUXCTL_TRANSACTREQ_MASK,
+                       DPAUX_DP_AUXCTL_TRANSACTREQ_DONE,
+                       100, DP_AUX_TIMEOUT_MS) != 0) {
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: DPAUX transaction timeout\n");
+               return -EFAULT;
+       }
+       return 0;
+}
+
+
+static void tegra_dc_dpaux_enable(struct tegra_dc_dp_data *dp)
+{
+       unsigned long reg_val;
+
+       /* clear interrupt */
+       tegra_dpaux_writel(dp, DPAUX_INTR_AUX, 0xffffffff);
+       /* do not enable interrupt for now. Enable them when Isr in place */
+       tegra_dpaux_writel(dp, DPAUX_INTR_EN_AUX, 0x0);
+
+       /* Power up aux/hybrid pads */
+       /* TODO: this may not needed for t124 */
+       reg_val = DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP;
+       tegra_dpaux_writel(dp, DPAUX_HYBRID_SPARE, reg_val);
+
+       /* Put HYBRID PAD in AUX mode */
+       reg_val = tegra_dpaux_readl(dp, DPAUX_HYBRID_PADCTL);
+       reg_val &= ~DPAUX_HYBRID_PADCTL_MODE_I2C;
+       reg_val |= DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE;
+       reg_val &= ~DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_ENABLE;
+       reg_val &= ~DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_ENABLE;
+       tegra_dpaux_writel(dp, DPAUX_HYBRID_PADCTL, reg_val);
+
+}
+
+static void tegra_dc_dpaux_disable(struct tegra_dc_dp_data *dp)
+{
+       tegra_dpaux_writel(dp, NV_DPCD_SET_POWER,
+               NV_DPCD_SET_POWER_VAL_D3_PWRDWN);
+
+       /* TODO: power down DPAUX_HYBRID_SPARE too? */
+}
+
+
+static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
+       u32 addr, u8 *data, u32 *size, u32 *aux_stat)
+{
+       int             i;
+       unsigned long   reg_val;
+       u32             timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES;
+       u32             defer_retries   = DP_AUX_DEFER_MAX_TRIES;
+
+       if (*size >= DP_AUX_MAX_BYTES)
+               return -EINVAL; /* only write one chunk of data */
+
+       /* Make sure the command is write command */
+       switch (cmd) {
+       case DPAUX_DP_AUXCTL_CMD_I2CWR:
+       case DPAUX_DP_AUXCTL_CMD_MOTWR:
+       case DPAUX_DP_AUXCTL_CMD_AUXWR:
+               break;
+       default:
+               dev_err(&dp->dc->ndev->dev, "dp: aux write cmd 0x%x is invalid\n",
+                       cmd);
+               return -EINVAL;
+       }
+
+#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
+       *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+       if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
+               dev_err(&dp->dc->ndev->dev, "dp: HPD is not detected\n");
+               return -EFAULT;
+       }
+#endif
+
+       tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr);
+       for (i = 0; i < DP_AUX_MAX_BYTES/4; ++i) {
+               tegra_dpaux_writel(dp, DPAUX_DP_AUXDATA_WRITE_W(i),
+                       (unsigned long)*data);
+               data += 4;
+       }
+
+       reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL);
+       reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK;
+       reg_val |= (cmd << DPAUX_DP_AUXCTL_CMD_SHIFT);
+       reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD;
+       reg_val |= (*size << DPAUX_DP_AUXCTL_CMDLEN_SHIFT);
+
+       while ((timeout_retries > 0) && (defer_retries > 0)) {
+               /* Reset AUX first*/
+               reg_val |= DPAUX_DP_AUXCTL_RST_ASSERT;
+               tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
+               reg_val &= ~DPAUX_DP_AUXCTL_RST_ASSERT;
+               tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
+
+               if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) ||
+                   (defer_retries != DP_AUX_DEFER_MAX_TRIES))
+                       usleep(DP_DPCP_RETRY_SLEEP_NS);
+
+               reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING;
+               tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
+
+               if (tegra_dpaux_wait_transaction(dp))
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp: aux write transaction timeout\n");
+
+               *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+
+               if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) ||
+                       (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) ||
+                       (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) ||
+                       (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) {
+                       if (timeout_retries-- > 0) {
+                               dev_dbg(&dp->dc->ndev->dev,
+                                       "dp: aux write retry (0x%x) -- %d\n",
+                                       *aux_stat, timeout_retries);
+                               continue;
+                       } else {
+                               dev_err(&dp->dc->ndev->dev, "dp: aux write got error (0x%x)\n",
+                                       *aux_stat);
+                               return -EFAULT;
+                       }
+               }
+
+               if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) ||
+                       (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) {
+                       if (defer_retries-- > 0) {
+                               dev_dbg(&dp->dc->ndev->dev,
+                                       "dp: aux write defer (0x%x) -- %d\n",
+                                       *aux_stat, defer_retries);
+                               continue;
+                       } else {
+                               dev_err(&dp->dc->ndev->dev,
+                                       "dp: aux write defer exceeds max retries (0x%x)\n",
+                                       *aux_stat);
+                               return -EFAULT;
+                       }
+               }
+
+               if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) ==
+                       DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) {
+                       *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK);
+                       return 0;
+               } else {
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp: aux write failed (0x%x)\n", *aux_stat);
+                       return -EFAULT;
+               }
+       }
+       /* Should never come to here */
+       return -EFAULT;
+}
+
+static int tegra_dc_dpaux_write(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr,
+       u8 *data, u32 *size, u32 *aux_stat)
+{
+       u32     cur_size = 0;
+       u32     finished = 0;
+       int     ret      = 0;
+
+       do {
+               cur_size = *size - finished;
+               if (cur_size >= DP_AUX_MAX_BYTES)
+                       cur_size = DP_AUX_MAX_BYTES - 1;
+               ret = tegra_dc_dpaux_write_chunk(dp, cmd, addr,
+                       data, &cur_size, aux_stat);
+
+               finished += cur_size;
+               addr += cur_size;
+               data += cur_size;
+
+               if (ret)
+                       break;
+       } while (*size >= finished);
+
+       *size = finished;
+       return ret;
+}
+
+static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
+       u32 addr, u8 *data, u32 *size, u32 *aux_stat)
+{
+       unsigned long   reg_val;
+       u32             timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES;
+       u32             defer_retries   = DP_AUX_DEFER_MAX_TRIES;
+
+       if (*size >= DP_AUX_MAX_BYTES)
+               return -EINVAL; /* only read one chunk */
+
+       /* Check to make sure the command is read command */
+       switch (cmd) {
+       case DPAUX_DP_AUXCTL_CMD_I2CRD:
+       case DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT:
+       case DPAUX_DP_AUXCTL_CMD_MOTRD:
+       case DPAUX_DP_AUXCTL_CMD_AUXRD:
+               break;
+       default:
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: aux read cmd 0x%x is invalid\n", cmd);
+               return -EINVAL;
+       }
+
+#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
+       *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+       if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
+               dev_err(&dp->dc->ndev->dev, "dp: HPD is not detected\n");
+               return -EFAULT;
+       }
+#endif
+
+       tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr);
+
+       reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL);
+       reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK;
+       reg_val |= (cmd << DPAUX_DP_AUXCTL_CMD_SHIFT);
+       reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD;
+       reg_val |= (*size << DPAUX_DP_AUXCTL_CMDLEN_SHIFT);
+
+       while ((timeout_retries > 0) && (defer_retries > 0)) {
+               /* Reset AUX first*/
+               reg_val |= DPAUX_DP_AUXCTL_RST_ASSERT;
+               tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
+               reg_val &= ~DPAUX_DP_AUXCTL_RST_ASSERT;
+               tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
+
+               if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) ||
+                   (defer_retries != DP_AUX_DEFER_MAX_TRIES))
+                       usleep(DP_DPCP_RETRY_SLEEP_NS);
+
+
+               reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING;
+               tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
+
+               if (tegra_dpaux_wait_transaction(dp))
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp: aux read transaction timeout\n");
+
+               *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+
+               if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) ||
+                       (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) ||
+                       (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) ||
+                       (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) {
+                       if (timeout_retries-- > 0) {
+                               dev_dbg(&dp->dc->ndev->dev,
+                                       "dp: aux read retry (0x%x) -- %d\n",
+                                       *aux_stat, timeout_retries);
+                               continue; /* retry */
+                       } else {
+                               dev_err(&dp->dc->ndev->dev, "dp: aux read got error (0x%x)\n",
+                                       *aux_stat);
+                               return -EFAULT;
+                       }
+               }
+
+               if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) ||
+                       (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) {
+                       if (defer_retries-- > 0) {
+                               dev_dbg(&dp->dc->ndev->dev,
+                                       "dp: aux read defer (0x%x) -- %d\n",
+                                       *aux_stat, defer_retries);
+                               continue;
+                       } else {
+                               dev_err(&dp->dc->ndev->dev,
+                                       "dp: aux read defer exceeds max retries (0x%x)\n",
+                                       *aux_stat);
+                               return -EFAULT;
+                       }
+               }
+
+               if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) ==
+                       DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) {
+                       int i;
+                       u32 temp_data[4];
+
+                       for (i = 0; i < DP_AUX_MAX_BYTES/4; ++i)
+                               temp_data[i] = tegra_dpaux_readl(dp,
+                                       DPAUX_DP_AUXDATA_READ_W(i));
+
+                       *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK);
+                       memcpy(temp_data, data, *size);
+
+                       return 0;
+               } else {
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp: aux read failed (0x%x\n", *aux_stat);
+                       return -EFAULT;
+               }
+       }
+       /* Should never come to here */
+       return -EFAULT;
+}
+
+static int tegra_dc_dpaux_read(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr,
+       u8 *data, u32 *size, u32 *aux_stat)
+{
+       u32     finished = 0;
+       u32     cur_size;
+       int     ret      = 0;
+
+       do {
+               cur_size = *size - finished;
+               if (cur_size >= DP_AUX_MAX_BYTES)
+                       cur_size = DP_AUX_MAX_BYTES - 1;
+
+               ret = tegra_dc_dpaux_read_chunk(dp, cmd, addr,
+                       data, &cur_size, aux_stat);
+
+               /* cur_size should be the real size returned */
+               addr += cur_size;
+               data += cur_size;
+               finished += cur_size;
+
+               if (ret)
+                       break;
+       } while (*size >= finished);
+
+       *size = finished;
+       return ret;
+}
+
+static inline int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd,
+       u8 *data_ptr)
+{
+       u32 size = 0;
+       u32 status = 0;
+       int ret;
+
+       ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+               cmd, data_ptr, &size, &status);
+       if (!ret)
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n",
+                       cmd, status);
+
+       return ret;
+}
+
+static inline int tegra_dc_dp_dpcd_write(struct tegra_dc_dp_data *dp, u32 cmd,
+       u8 data)
+{
+       u32 size = 0;
+       u32 status = 0;
+       int ret;
+
+       ret = tegra_dc_dpaux_write_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXWR,
+               cmd, &data, &size, &status);
+       if (!ret)
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n",
+                       cmd, status);
+       return ret;
+}
+
+
+static inline u64 tegra_div64(u64 dividend, u32 divisor)
+{
+       do_div(dividend, divisor);
+       return dividend;
+}
+
+
+static int tegra_dc_init_max_link_cfg(struct tegra_dc_dp_data *dp,
+       struct tegra_dc_dp_link_config *cfg)
+{
+       u8     dpcd_data;
+       int    ret;
+
+       CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LANE_COUNT,
+                       &dpcd_data));
+       cfg->max_lane_count = dpcd_data & NV_DPCD_MAX_LANE_COUNT_MASK;
+
+       cfg->support_enhanced_framing =
+               (dpcd_data & NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ?
+               true : false;
+
+       CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_DOWNSPREAD,
+                       &dpcd_data));
+       cfg->downspread = (dpcd_data & NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT) ?
+               true : false;
+
+       CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LINK_BANDWIDTH,
+                       &cfg->max_link_bw));
+
+       cfg->bytes_per_pixel = dp->dc->pdata->fb->bits_per_pixel / 8;
+
+       CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_EDP_CONFIG_CAP,
+                       &dpcd_data));
+       cfg->alt_scramber_reset_cap =
+               (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES) ?
+               true : false;
+       cfg->only_enhanced_framing =
+               (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES) ?
+               true : false;
+
+       return 0;
+}
+
+static bool tegra_dc_dp_lower_config(struct tegra_dc_dp_data *dp,
+       struct tegra_dc_dp_link_config *cfg)
+{
+       if (cfg->link_bw == DP_LINK_SPEED_G1_62) {
+               if (cfg->max_link_bw > DP_LINK_SPEED_G1_62)
+                       cfg->link_bw = DP_LINK_SPEED_G2_7;
+               cfg->lane_count /= 2;
+       } else if (cfg->link_bw == DP_LINK_SPEED_G2_7)
+               cfg->link_bw = DP_LINK_SPEED_G1_62;
+       else if (cfg->link_bw == DP_LINK_SPEED_G5_4) {
+               if (cfg->lane_count == 1) {
+                       cfg->link_bw = DP_LINK_SPEED_G2_7;
+                       cfg->lane_count = cfg->max_lane_count;
+               } else
+                       cfg->lane_count /= 2;
+       } else {
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: Error link rate %d\n", cfg->link_bw);
+               return false;
+       }
+       return (cfg->lane_count > 0);
+}
+
+
+/* Calcuate if given cfg can meet the mode request. */
+/* Return true if mode is possible, false otherwise. */
+static bool tegra_dc_dp_calc_config(struct tegra_dc_dp_data *dp,
+       const struct tegra_dc_mode *mode,
+       struct tegra_dc_dp_link_config *cfg)
+{
+       const u32       link_rate = 27 * cfg->link_bw * 1000 * 1000;
+       const u64       f         = 100000;     /* precision factor */
+
+       u32     num_linkclk_line; /* Number of link clocks per line */
+       u64     ratio_f; /* Ratio of incoming to outgoing data rate */
+       u64     frac_f;
+       u64     activesym_f;    /* Activesym per TU */
+       u64     activecount_f;
+       u32     activecount;
+       u32     activepolarity;
+       u32     activefrac;
+       u64     approx_value_f;
+       u64     accumulated_error_f       = 0;
+       u32     lowest_neg_activecount    = 0;
+       u32     lowest_neg_activepolarity = 0;
+       u32     lowest_neg_tusize         = 64;
+       u32     num_symbols_per_line;
+       u64     lowest_neg_activefrac     = 0;
+       u64     lowest_neg_error_f        = 64 * f;
+       u64     watermark_f;
+
+       int     i;
+       bool    neg;
+
+
+       if (!link_rate || !cfg->lane_count || !mode->pclk ||
+               !cfg->bytes_per_pixel)
+               return false;
+
+       if (mode->pclk * cfg->bytes_per_pixel >=
+               8 * link_rate * cfg->lane_count)
+               return false;
+
+       num_linkclk_line = (u32)tegra_div64(
+               (u64)link_rate * mode->h_active, mode->pclk);
+
+       ratio_f = (u64)mode->pclk * cfg->bytes_per_pixel * f;
+       ratio_f /= 8;
+       ratio_f = tegra_div64(ratio_f, link_rate * cfg->lane_count);
+
+       for (i = 64; i >= 32; --i) {
+               activesym_f     = ratio_f * i;
+               activecount_f   = tegra_div64(activesym_f, (u32)f) * f;
+               frac_f          = activesym_f - activecount_f;
+               activecount     = (u32)tegra_div64(activecount_f, (u32)f);
+
+               if (frac_f < (f / 2)) /* fraction < 0.5 */
+                       activepolarity = 0;
+               else {
+                       activepolarity = 1;
+                       frac_f = f - frac_f;
+               }
+
+               if (frac_f != 0) {
+                       frac_f = tegra_div64((f * f),  frac_f); /* 1/fraction */
+                       if (frac_f > (15 * f))
+                               activefrac = activepolarity ? 1 : 15;
+                       else
+                               activefrac = activepolarity ?
+                                       (u32)tegra_div64(frac_f, (u32)f) + 1 :
+                                       (u32)tegra_div64(frac_f, (u32)f);
+               }
+
+               if (activefrac == 1)
+                       activepolarity = 0;
+
+               if (activepolarity == 1)
+                       approx_value_f = activefrac ? tegra_div64(
+                               activecount_f + (activefrac * f - f) * f,
+                               (activefrac * f)) :
+                               activecount_f + f;
+               else
+                       approx_value_f = activefrac ?
+                               activecount_f + tegra_div64(f, activefrac) :
+                               activecount_f;
+
+               if (activesym_f < approx_value_f) {
+                       accumulated_error_f = num_linkclk_line *
+                               tegra_div64(approx_value_f - activesym_f, i);
+                       neg = true;
+               } else {
+                       accumulated_error_f = num_linkclk_line *
+                               tegra_div64(activesym_f - approx_value_f, i);
+                       neg = false;
+               }
+
+               if ((neg && (lowest_neg_error_f > accumulated_error_f)) ||
+                       (accumulated_error_f == 0)) {
+                       lowest_neg_error_f = accumulated_error_f;
+                       lowest_neg_tusize = i;
+                       lowest_neg_activecount = activecount;
+                       lowest_neg_activepolarity = activepolarity;
+                       lowest_neg_activefrac = activefrac;
+
+                       if (accumulated_error_f == 0)
+                               break;
+               }
+       }
+
+       if (lowest_neg_activefrac == 0) {
+               cfg->activepolarity = 0;
+               cfg->active_count   = lowest_neg_activepolarity ?
+                       lowest_neg_activecount : lowest_neg_activecount - 1;
+               cfg->tu_size          = lowest_neg_tusize;
+               cfg->active_frac    = 1;
+       } else {
+               cfg->activepolarity = lowest_neg_activepolarity;
+               cfg->active_count   = (u32)lowest_neg_activecount;
+               cfg->tu_size          = lowest_neg_tusize;
+               cfg->active_frac    = (u32)lowest_neg_activefrac;
+       }
+
+       dev_dbg(&dp->dc->ndev->dev,
+               "dp: sor configuration: polarity: %d active count: %d "
+               "tu size: %d, active frac: %d\n",
+               cfg->activepolarity, cfg->active_count, cfg->tu_size,
+               cfg->active_frac);
+
+       watermark_f = ratio_f * cfg->tu_size * tegra_div64(f - ratio_f, f);
+       cfg->watermark = 2*((cfg->bytes_per_pixel) * f / 8) + watermark_f +
+               (u32)tegra_div64(lowest_neg_error_f, (u32)f) - 1;
+       num_symbols_per_line = (mode->h_active * cfg->bytes_per_pixel) /
+               (8 * cfg->lane_count);
+       if (cfg->watermark > 30) {
+               dev_dbg(&dp->dc->ndev->dev,
+                       "dp: sor setting: unable to get a good tusize, "
+                       "force watermark to 30.\n");
+               cfg->watermark = 30;
+               return false;
+       } else if (cfg->watermark > num_symbols_per_line) {
+               dev_dbg(&dp->dc->ndev->dev,
+                       "dp: sor setting: force watermark to the number "
+                       "of symbols in the line.\n");
+               cfg->watermark = num_symbols_per_line;
+               return false;
+       }
+
+       /* Refer to dev_disp.ref for more information. */
+       /* # symbols/hblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - */
+       /*                      SetRasterBlankStart.X - 7) * link_clk / pclk) */
+       /*                      - 3 * enhanced_framing - Y */
+       /* where Y = (# lanes == 4) 3 : (# lanes == 2) ? 6 : 12 */
+       cfg->hblank_sym = tegra_div64((u64)(mode->h_back_porch +
+                       mode->h_front_porch + mode->h_sync_width - 7)
+               * link_rate, mode->pclk)
+               - 3 * cfg->enhanced_framing - (12 / cfg->lane_count);
+
+       if (cfg->hblank_sym < 0)
+               cfg->hblank_sym = 0;
+
+
+       /* Refer to dev_disp.ref for more information. */
+       /* # symbols/vblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - */
+       /*                      SetRasterBlankStart.X - 7) * link_clk / pclk) */
+       /*                      - Y - 1; */
+       /* where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39 */
+       cfg->vblank_sym = tegra_div64((u64)(mode->v_back_porch +
+                       mode->v_front_porch + mode->v_sync_width - 25)
+               * link_rate, mode->pclk) - (36 / cfg->lane_count) - 4;
+
+       if (cfg->vblank_sym < 0)
+               cfg->vblank_sym = 0;
+       return true;
+}
+
+static int tegra_dc_dp_set_assr(struct tegra_dc_dp_data *dp, bool ena)
+{
+       int ret;
+
+       u8 dpcd_data = ena ?
+               NV_DPCD_EDP_CONFIG_SET_ASC_RESET_ENABLE :
+               NV_DPCD_EDP_CONFIG_SET_ASC_RESET_DISABLE;
+
+       CHECK_RET(tegra_dc_dp_dpcd_write(dp, NV_DPCD_EDP_CONFIG_SET,
+                       dpcd_data));
+
+       /* Also reset the scrambler to 0xfffe */
+       tegra_dc_sor_set_internal_panel(dp->sor, ena);
+       return 0;
+}
+
+
+static int tegra_dp_set_link_bandwidth(struct tegra_dc_dp_data *dp, u8 link_bw)
+{
+       tegra_dc_sor_set_link_bandwidth(dp->sor, link_bw);
+
+       /* Sink side */
+       return tegra_dc_dp_dpcd_write(dp, NV_DPCD_LINK_BANDWIDTH_SET, link_bw);
+}
+
+static int tegra_dp_set_lane_count(struct tegra_dc_dp_data *dp,
+       const struct tegra_dc_dp_link_config *cfg)
+{
+       u8      dpcd_data;
+       int     ret;
+
+       /* check if panel support enhanched_framing */
+       dpcd_data = cfg->lane_count;
+       if (cfg->enhanced_framing)
+               dpcd_data |= NV_DPCD_LANE_COUNT_SET_ENHANCEDFRAMING_T;
+       CHECK_RET(tegra_dc_dp_dpcd_write(dp, NV_DPCD_LANE_COUNT_SET,
+                       dpcd_data));
+
+       tegra_dc_sor_set_lane_count(dp->sor, cfg->lane_count);
+
+       /* Also power down lanes that will not be used */
+       return tegra_dc_sor_powerdown_dplanes(dp->sor, cfg->lane_count);
+}
+
+static int tegra_dc_dp_set_lane_config(struct tegra_dc_dp_data *dp,
+       u32 lane_count, const u8 *edc, const u8 *c2, u8 training_pattern)
+{
+       u32 lane;
+       u8  pre_emphasis;
+       u8  drive_current;
+       u8  post_cursor2;
+       u8  temp_edc[5];
+       u8  temp_c2[2];
+       u32 size;
+       u32 status;
+       int ret;
+
+       temp_c2[0] = temp_c2[1] = 0;
+       memset(temp_edc, 0, sizeof(temp_edc));
+       for (lane = 0; lane < lane_count; ++lane) {
+               if (lane & 1) { /* Lane 1, 3 */
+                       pre_emphasis = (edc[lane/2] &
+                               NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK) >>
+                               NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT;
+                       drive_current = (edc[lane/2] &
+                               NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK) >>
+                               NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT;
+               } else {        /* Lane 0, 2 */
+                       pre_emphasis = (edc[lane/2] &
+                               NV_DPCD_ADJUST_REQ_LANEX_PE_MASK) >>
+                               NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT;
+                       drive_current = (edc[lane/2] &
+                               NV_DPCD_ADJUST_REQ_LANEX_DC_MASK) >>
+                               NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT;
+               }
+               post_cursor2 = (*c2 >>
+                       NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(lane)) &
+                       NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK;
+
+               temp_edc[lane+1] = drive_current <<
+                       NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT;
+               if (drive_current == driveCurrent_Level3)
+                       temp_edc[lane+1] |=
+                               NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T;
+               temp_edc[lane+1] |=
+                       (pre_emphasis << NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT);
+               if (pre_emphasis == preEmphasis_Level3)
+                       temp_edc[lane+1] |=
+                               NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T;
+
+               if (lane & 1) { /* lane 1 and 3 */
+                       temp_c2[lane/2] |= post_cursor2 <<
+                               NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT;
+                       if (post_cursor2 == postCursor2_Level3)
+                               temp_c2[lane/2] |=
+                                    NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T;
+               } else {        /* lane 0 and 2 */
+                       temp_c2[lane/2] |= post_cursor2 <<
+                               NV_DPCD_LANEX_SET2_PC2_SHIFT;
+                       if (post_cursor2 == postCursor2_Level3)
+                               temp_c2[lane/2] |=
+                                       NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T;
+               }
+
+               tegra_dc_sor_set_dp_lanedata(dp->sor, lane_count, post_cursor2,
+                       pre_emphasis, drive_current);
+       }
+
+       usleep(10);
+
+       /* Now program the sink */
+       if (training_pattern != trainingPattern_None) {
+               tegra_dc_dp_dpcd_read(dp, NV_DPCD_TRAINING_PATTERN_SET,
+                       temp_edc);
+               temp_edc[0] &= NV_DPCD_TRAINING_PATTERN_SET_TPS_MASK;
+               temp_edc[0] |= (training_pattern &
+                       NV_DPCD_TRAINING_PATTERN_SET_TPS_MASK);
+
+               size = 4;
+               ret = tegra_dc_dpaux_write(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+                       NV_DPCD_TRAINING_PATTERN_SET, temp_edc, &size, &status);
+               if (ret) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "Failed to set NV_DPCD_TRAINING_PATTERN_SET\n");
+                       return ret;
+               }
+       } else {                /* No training pattern, only set LANE config */
+               size = 3;
+               ret = tegra_dc_dpaux_write(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+                       NV_DPCD_TRAINING_LANE0_SET, temp_edc+1, &size, &status);
+               if (ret) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "Failed to set NV_DPCD_TRAINING_LANE0_SET\n");
+                       return ret;
+               }
+       }
+
+       size = 1;
+       ret = tegra_dc_dpaux_write(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+               NV_DPCD_TRAINING_LANE0_1_SET2, temp_c2, &size, &status);
+       if (ret)
+               dev_err(&dp->dc->ndev->dev,
+                       "Failed to set NV_DPCD_TRAINING_LANE0_1_SET2\n");
+       return ret;
+}
+
+
+static int tegra_dc_dpcd_read_lane_request(struct tegra_dc_dp_data *dp,
+       u32 lane_count, u8 *edc, u8* c2)
+{
+       u32 size;
+       int ret;
+       u32 status;
+
+       /* read the new preemphasis & drive current values */
+       size = lane_count/2;
+       ret = tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+               NV_DPCD_LANE0_1_ADJUST_REQ, edc, &size, &status);
+       if (ret) {
+               dev_err(&dp->dc->ndev->dev,
+                       "Failed to read NV_DPCD_LANE0_1_ADJUST_REQ\n");
+               return ret;
+       }
+       return tegra_dc_dp_dpcd_read(dp, NV_DPCD_ADJUST_REQ_POST_CURSOR2, c2);
+}
+
+static int tegra_dc_dp_lt_clock_recovery(struct tegra_dc_dp_data *dp,
+       const struct tegra_dc_dp_link_config *cfg)
+{
+
+       int     ret;
+       u8      edc_data[2] = { 0, 0 };
+       u8      c2_data = 0;
+       u32     lane;
+       u8      temp_edc[4];
+       u8      data;
+       u32     cr_done;
+       bool    sl_changed;
+       u32     sl_max_count;
+       u32     sl_retry_count;
+       u8      mask;
+       u32     retry_count;
+
+
+       /* Set pattern on the source side */
+       tegra_dc_sor_set_dp_linkctl(dp->sor, true, trainingPattern_1,
+               cfg, false);
+
+       /* Now the sink side */
+       ret = tegra_dc_dp_set_lane_config(dp, cfg->lane_count, edc_data,
+               &c2_data, trainingPattern_1);
+       if (ret)
+               dev_dbg(&dp->dc->ndev->dev,
+                       "Failed to set the sink link for clock recovery\n");
+
+       sl_retry_count = 0;
+       retry_count = 0;
+       do {
+               usleep(100);
+               temp_edc[0] = edc_data[0];
+               temp_edc[1] = edc_data[1];
+
+               /* read lane registers for all the lanes */
+               for (lane = 0, cr_done = 0; lane < cfg->lane_count; ++lane) {
+                       ret = tegra_dc_dp_dpcd_read(dp,
+                               (lane/2) ? NV_DPCD_LANE2_3_STATUS :
+                               NV_DPCD_LANE0_1_STATUS, &data);
+                       if (ret)
+                               return ret;
+
+                       mask = (lane & 1) ?
+                               NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES :
+                               NV_DPCD_STATUS_LANEX_CR_DONE_YES;
+
+                       if (data & mask)
+                               cr_done++;
+                       else    /* no need to check the rest of the lanes */
+                               break;
+               }
+
+               if (cr_done == cfg->lane_count)
+                       break;  /* Success -- Done with clock recovery */
+
+               /* Check if the swing-levels changed or reached maxium */
+               sl_max_count = 0;
+               sl_changed = false;
+               for (lane = 0; lane < cfg->lane_count; ++lane) {
+                       mask = (lane & 1) ?
+                               NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK :
+                               NV_DPCD_ADJUST_REQ_LANEX_DC_MASK;
+                       if ((edc_data[lane/2] & mask) !=
+                               (temp_edc[lane/2] & mask)) {
+                               sl_changed = true;
+                               sl_retry_count = 0;
+                               break;
+                       }
+                       if ((edc_data[lane/2] & mask) == driveCurrent_Level3)
+                               sl_max_count++;
+               }
+
+               if (sl_max_count == cfg->lane_count) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "Reached MAX_SWING_LEVEL yet CR_LOCK failed\n");
+                       return -EFAULT;
+               }
+               if (!sl_changed && (sl_retry_count++ >
+                               DP_CLOCK_RECOVERY_MAX_TRIES)) {
+                       dev_err(&dp->dc->ndev->dev, "Exceeded max combination\n");
+                       return -EFAULT;
+               }
+
+               /* Read the config on the sink side */
+               ret = tegra_dc_dpcd_read_lane_request(dp, cfg->lane_count,
+                       edc_data, &c2_data);
+
+               /* Write the data */
+               ret = tegra_dc_dp_set_lane_config(dp, cfg->lane_count, edc_data,
+                       &c2_data, trainingPattern_None);
+               if (ret) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "Failed to update lane configuration");
+                       return ret;
+               }
+       } while (++retry_count < DP_CLOCK_RECOVERY_TOT_TRIES);
+
+       if (retry_count == DP_CLOCK_RECOVERY_TOT_TRIES) {
+               dev_err(&dp->dc->ndev->dev, "Exceeded max retry times\n");
+               return -EFAULT;
+       }
+       return ret;
+}
+
+static int tegra_dc_dp_lt_channel_equalization(struct tegra_dc_dp_data *dp,
+       const struct tegra_dc_dp_link_config *cfg)
+{
+       int ret;
+       u8  data;
+       u8  edc_data[2] = { 0, 0 };
+       u8  c2_data = 0;
+       u8  updated_status;
+       u32 tries;
+       u8  lane;
+       u32 ce_done;
+       u8  mask;
+
+
+       /* Set pattern on the source side */
+       tegra_dc_sor_set_dp_linkctl(dp->sor, true, trainingPattern_2,
+               cfg, true);
+
+       /* Now the sink side */
+       CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_TRAINING_PATTERN_SET,
+                       &data));
+
+       data &= ~NV_DPCD_TRAINING_PATTERN_SET_TPS_MASK;
+       data |= trainingPattern_2;
+
+       CHECK_RET(tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET,
+                       data));
+
+       usleep(400);
+
+       for (tries = 0; tries <= DP_CLOCK_RECOVERY_MAX_TRIES; ++tries) {
+               ret = tegra_dc_dpcd_read_lane_request(dp, cfg->lane_count,
+                       edc_data, &c2_data);
+               if (ret)
+                       return ret;
+               /* Write the data */
+               ret = tegra_dc_dp_set_lane_config(dp, cfg->lane_count, edc_data,
+                       &c2_data, trainingPattern_None);
+               if (ret) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "Failed to update lane configuration");
+                       return ret;
+               }
+
+               usleep(400);
+
+               CHECK_RET(tegra_dc_dp_dpcd_read(dp,
+                               NV_DPCD_LANE_ALIGN_STATUS_UPDATED,
+                               &updated_status));
+
+               for (lane = 0, ce_done = 0; lane < cfg->lane_count; ++lane) {
+                       CHECK_RET(tegra_dc_dp_dpcd_read(dp,
+                                       (lane/2) ? NV_DPCD_LANE2_3_STATUS :
+                                       NV_DPCD_LANE0_1_STATUS,
+                                       &data));
+
+                       mask = (lane & 1) ?
+                               NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES |
+                               NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES |
+                               NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES :
+                               NV_DPCD_STATUS_LANEX_CR_DONE_YES |
+                               NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES |
+                               NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES;
+
+                       if (((data & mask) == mask)
+                               && (updated_status &
+                                   NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES))
+                               ce_done++;
+                       else
+                               /* no need to check the rest of the lanes */
+                               break;
+               }
+
+               if ((data & NV_DPCD_STATUS_LANEX_CR_DONE_YES) == 0) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "Clock recovery has not been locked\n");
+                       return -EFAULT;
+               }
+
+               if (ce_done == cfg->lane_count) {
+                       /* All lanes done with training */
+                       dev_dbg(&dp->dc->ndev->dev,
+                               "Channel Equalization passed\n");
+                       return 0;
+               }
+       }
+
+       /* Reaches max tries */
+       dev_err(&dp->dc->ndev->dev,
+               "Channel Equalization exceeded max combinations\n");
+       return -EFAULT;
+}
+
+
+static int tegra_dc_dp_link_training(struct tegra_dc_dp_data *dp,
+       const struct tegra_dc_dp_link_config *cfg)
+{
+       int ret = tegra_dc_dp_lt_clock_recovery(dp, cfg);
+       if (ret)
+               dev_dbg(&dp->dc->ndev->dev,
+                       "DP: failed link training clock recovery with "
+                       "lane %d bw %d\n", cfg->lane_count, cfg->link_bw);
+       else {
+               ret = tegra_dc_dp_lt_channel_equalization(dp, cfg);
+
+               if (ret)
+                       dev_dbg(&dp->dc->ndev->dev,
+                               "DP: failed link training channel equal with "
+                               "lane %d bw %d\n",
+                               cfg->lane_count, cfg->link_bw);
+       }
+
+       /* TODO: read back the link status for debugging purpose */
+       return ret;
+}
+
+static bool tegra_dc_dp_link_trained(struct tegra_dc_dp_data *dp,
+       struct tegra_dc_dp_link_config *cfg)
+{
+       u32 lane;
+       u8  mask;
+       u8  data;
+       int ret;
+
+       for (lane = 0; lane < cfg->lane_count; ++lane) {
+               CHECK_RET(tegra_dc_dp_dpcd_read(dp, (lane/2) ?
+                               NV_DPCD_LANE2_3_STATUS : NV_DPCD_LANE0_1_STATUS,
+                               &data));
+               mask = (lane & 1) ?
+                       NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES |
+                       NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES |
+                       NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES :
+                       NV_DPCD_STATUS_LANEX_CR_DONE_YES |
+                       NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES |
+                       NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES;
+               if ((data & mask) != mask)
+                       return false;
+       }
+       return true;
+}
+
+
+static int tegra_dc_dp_fast_link_training(struct tegra_dc_dp_data *dp,
+       struct tegra_dc_dp_link_config *cfg)
+{
+       struct tegra_dc_sor_data *sor = dp->sor;
+       int ret;
+
+       tegra_dc_sor_set_link_bandwidth(sor, cfg->link_bw);
+       tegra_dc_sor_set_lane_count(sor, cfg->lane_count);
+
+       /* Send TP1 */
+       tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_1, cfg,
+               false);
+
+       usleep(500);
+       /* enable ASSR */
+       tegra_dc_dp_set_assr(dp, true);
+       tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_2, cfg,
+               true);
+
+       usleep(500);
+       tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_Disabled,
+               cfg, false);
+
+       ret = tegra_dc_dp_link_trained(dp, cfg);
+       if (!ret) {
+               tegra_dc_sor_read_link_config(dp->sor, &cfg->link_bw,
+                       &cfg->lane_count);
+       }
+       return ret;
+}
+
+static int tegra_dp_link_config(struct tegra_dc_dp_data *dp,
+       const struct tegra_dc_dp_link_config *cfg)
+{
+       u8      dpcd_data;
+       u8      link_bw;
+       u8      lane_count;
+       u32     retry;
+       int     ret;
+
+       if (cfg->lane_count == 0) {
+               /* TODO: shutdown the link */
+               return 0;
+       }
+
+       /* Set power state if it is not in normal level */
+       CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_SET_POWER, &dpcd_data));
+       if (dpcd_data == NV_DPCD_SET_POWER_VAL_D3_PWRDWN) {
+               dpcd_data = NV_DPCD_SET_POWER_VAL_D0_NORMAL;
+               retry = 3;      /* DP spec requires 3 retries */
+               do {
+                       ret = tegra_dc_dp_dpcd_write(dp,
+                               NV_DPCD_SET_POWER, dpcd_data);
+               } while ((--retry > 0) && (ret != 0));
+               if (ret) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp: Failed to set DP panel power\n");
+                       return ret;
+               }
+       }
+
+       /* Enable ASSR if possible */
+       if (cfg->alt_scramber_reset_cap)
+               CHECK_RET(tegra_dc_dp_set_assr(dp, true));
+
+       ret = tegra_dp_set_link_bandwidth(dp, cfg->link_bw);
+       if (ret) {
+               dev_err(&dp->dc->ndev->dev, "dp: Failed to set link bandwidth\n");
+               return ret;
+       }
+       ret = tegra_dp_set_lane_count(dp, cfg);
+       if (ret) {
+               dev_err(&dp->dc->ndev->dev, "dp: Failed to set lane count\n");
+               return ret;
+       }
+       tegra_dc_sor_set_dp_linkctl(dp->sor, true, trainingPattern_Disabled,
+               cfg, true);
+
+       /* Now do the link training */
+       ret = tegra_dc_dp_link_training(dp, cfg);
+       if (ret) {
+               dev_dbg(&dp->dc->ndev->dev, "dp: link training failed\n");
+               return ret;
+       }
+
+       /* Everything goes well, double check the link config */
+       /* TODO: record edc/c2 data for debugging */
+       tegra_dc_sor_read_link_config(dp->sor, &link_bw, &lane_count);
+
+       if ((cfg->link_bw == link_bw) && (cfg->lane_count == lane_count))
+               return 0;
+       else
+               return -EFAULT;
+}
+
+static int tegra_dc_dp_explore_link_cfg(struct tegra_dc_dp_data *dp,
+       struct tegra_dc_dp_link_config *cfg, struct tegra_dc_mode *mode)
+{
+       struct tegra_dc_dp_link_config temp_cfg;
+
+       if (!mode->pclk || !mode->h_active || !mode->v_active) {
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: error mode configuration");
+               return -EINVAL;
+       }
+       if (!cfg->max_link_bw || !cfg->max_lane_count) {
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: error link configuration");
+               return -EINVAL;
+       }
+
+       cfg->is_valid = false;
+       memcpy(cfg, &temp_cfg, sizeof(temp_cfg));
+
+       temp_cfg.link_bw    = temp_cfg.max_link_bw;
+       temp_cfg.lane_count = temp_cfg.max_lane_count;
+
+       while (tegra_dc_dp_calc_config(dp, mode, &temp_cfg) &&
+               tegra_dp_link_config(dp, &temp_cfg)) {
+               /* current link cfg is doable */
+               memcpy(&temp_cfg, cfg, sizeof(temp_cfg));
+               cfg->is_valid = true;
+
+               /* try to lower the config */
+               if (!tegra_dc_dp_lower_config(dp, &temp_cfg))
+                       break;
+       }
+
+       return cfg->is_valid ? 0 : -EFAULT;
+}
+
+static void tegra_dc_dp_lt_worker(struct work_struct *work)
+{
+       struct tegra_dc_dp_data *dp =
+               container_of(work, struct tegra_dc_dp_data, lt_work);
+
+       tegra_dc_disable(dp->dc);
+
+       if (!dp->link_cfg.is_valid ||
+               !tegra_dp_link_config(dp, &dp->link_cfg)) {
+               /* If current config is not valid or cannot be trained,
+                  needs to re-explore the possilbe config */
+               if (tegra_dc_init_max_link_cfg(dp, &dp->link_cfg))
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp: failed to init link configuration\n");
+               else if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg,
+                               dp->mode))
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp irq: cannot get working config\n");
+       }
+
+       tegra_dc_enable(dp->dc);
+}
+
+
+static irqreturn_t tegra_dc_dp_hpd_irq(int irq, void *ptr)
+{
+       struct tegra_dc         *dc = ptr;
+       struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc);
+       u8                       data;
+       u8                       clear_data = 0;
+
+       if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR,
+                       &data))
+               dev_err(&dc->ndev->dev, "dp: failed to read IRQ_VECTOR\n");
+
+       dev_dbg(&dc->ndev->dev,
+               "dp irq: Trying to handle HPD with DPCD_IRQ_VECTOR 0x%x\n",
+               data);
+
+       /* For eDP only answer auto_test_request */
+       if (data & NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_AUTO_TEST_YES &&
+               dp->link_cfg.is_valid) {
+               /* Schedule to do the link training */
+               schedule_work(&dp->lt_work);
+
+               /* Now clear auto_test bit */
+               clear_data |= NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_AUTO_TEST_YES;
+       }
+
+       if (clear_data)
+               tegra_dc_dp_dpcd_write(dp, NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR,
+                       clear_data);
+
+       return IRQ_HANDLED;
+}
+
+static int tegra_dc_dp_init(struct tegra_dc *dc)
+{
+       struct tegra_dc_dp_data *dp;
+       struct resource         *res;
+       struct resource         *base_res;
+       void __iomem            *base;
+       struct clk              *clk;
+       int                      err;
+
+
+       dp = kzalloc(sizeof(*dp), GFP_KERNEL);
+       if (!dp)
+               return -ENOMEM;
+
+       res = nvhost_get_resource_byname(dc->ndev, IORESOURCE_MEM, "dpaux");
+       if (!res) {
+               dev_err(&dc->ndev->dev, "dp: no mem resources for dpaux\n");
+               err = -EFAULT;
+               goto err_free_dp;
+       }
+
+       base_res = request_mem_region(res->start, resource_size(res),
+               dc->ndev->name);
+       if (!base_res) {
+               dev_err(&dc->ndev->dev, "dp: request_mem_region failed\n");
+               err = -EFAULT;
+               goto err_free_dp;
+       }
+
+       base = ioremap(res->start, resource_size(res));
+       if (!base) {
+               dev_err(&dc->ndev->dev, "dp: registers can't be mapped\n");
+               err = -EFAULT;
+               goto err_release_resource_reg;
+       }
+
+       clk = clk_get(&dc->ndev->dev, NULL);
+       if (IS_ERR_OR_NULL(clk)) {
+               dev_err(&dc->ndev->dev, "dp: dc clock %s unavailable\n",
+                       dev_name(&dc->ndev->dev));
+               err = -EFAULT;
+               goto err_iounmap_reg;
+       }
+
+       /* TODO: confirm interrupt num is acquired from gpio_to_irq,
+          Also how to differentiate them from HDMI HPD.
+        */
+       if (request_irq(gpio_to_irq(dc->out->hotplug_gpio), tegra_dc_dp_hpd_irq,
+                       IRQF_DISABLED | IRQF_TRIGGER_RISING |
+                       IRQF_TRIGGER_FALLING, dev_name(&dc->ndev->dev), dc)) {
+               dev_err(&dc->ndev->dev, "dp: request_irq %d failed\n",
+                       gpio_to_irq(dc->out->hotplug_gpio));
+               err = -EBUSY;
+               goto err_get_clk;
+       }
+
+
+       dp->dc           = dc;
+       dp->aux_base     = base;
+       dp->aux_base_res = base_res;
+       dp->clk          = clk;
+       dp->mode         = &dc->mode;
+       dp->sor          = tegra_dc_sor_init(dc, &dp->link_cfg);
+
+       if (IS_ERR_OR_NULL(dp->sor)) {
+               err = PTR_ERR(dp->sor);
+               dp->sor = NULL;
+               goto err_get_clk;
+       }
+
+       INIT_WORK(&dp->lt_work, tegra_dc_dp_lt_worker);
+
+       tegra_dc_set_outdata(dc, dp);
+
+       return 0;
+
+err_get_clk:
+       clk_put(clk);
+err_iounmap_reg:
+       iounmap(base);
+err_release_resource_reg:
+       release_resource(base_res);
+err_free_dp:
+       kfree(dp);
+
+       return err;
+}
+
+static void tegra_dc_dp_enable(struct tegra_dc *dc)
+{
+       struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc);
+       u8     data;
+       u32    retry;
+       int    ret;
+
+       tegra_dc_dpaux_enable(dp);
+
+       /* Power on panel */
+       tegra_dc_sor_set_panel_power(dp->sor, true);
+
+       /* TODO: power on lanes as well? */
+
+       /* Enable backlight -- TODO: need to go through I2C */
+
+       msleep(DP_LCDVCC_TO_HPD_DELAY_MS);
+
+       /* Write power on to DPCD */
+       data = NV_DPCD_SET_POWER_VAL_D0_NORMAL;
+       retry = 0;
+       do {
+               ret = tegra_dc_dp_dpcd_write(dp,
+                       NV_DPCD_SET_POWER, data);
+       } while ((retry++ < DP_POWER_ON_MAX_TRIES) && ret);
+
+       if (ret) {
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: failed to power on panel (0x%x)\n", ret);
+               return;
+       }
+
+       /* Confirm DP is plugging status */
+#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
+       if (!(tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT) &
+                       DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
+               dev_err(&dp->dc->ndev->dev, "dp: could not detect HPD\n");
+               return;
+       }
+#endif
+
+       /* Check DP version */
+       if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_REV, &dp->revision))
+               dev_err(&dp->dc->ndev->dev,
+                       "dp: failed to read the revision number from sink\n");
+
+       if (!dp->link_cfg.is_valid ||
+               tegra_dc_dp_fast_link_training(dp, &dp->link_cfg)) {
+               /* if valid link config is not ready yet, or current
+                  config cannot be link-trained, try to find the
+                  new minimal config */
+               if (tegra_dc_init_max_link_cfg(dp, &dp->link_cfg)) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp: failed to init link configuration\n");
+                       return;
+               }
+               if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, dp->mode) ||
+                       tegra_dc_dp_link_training(dp, &dp->link_cfg)) {
+                       dev_err(&dp->dc->ndev->dev,
+                               "dp: Current mode is not possible\n");
+                       return;
+               }
+       }
+
+       /* enable SOR by programming the watermark/v/hblank_sym etc */
+       tegra_dc_sor_enable(dp->sor);
+}
+
+static void tegra_dc_dp_destroy(struct tegra_dc *dc)
+{
+       struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc);
+
+       if (dp->sor)
+               tegra_dc_sor_destroy(dp->sor);
+       clk_put(dp->clk);
+       iounmap(dp->aux_base);
+       release_resource(dp->aux_base_res);
+
+       kfree(dp);
+}
+
+static void tegra_dc_dp_disable(struct tegra_dc *dc)
+{
+       struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc);
+
+       /* TODO: confirm that dpaux_disable is not needed for eDP */
+       tegra_dc_dpaux_disable(dp);
+
+       /* Power down SOR */
+       tegra_dc_sor_disable(dp->sor);
+
+       /* TODO: Now power down the panel -- through GPIO */
+       /* Make sure the timing meet the eDP specs */
+}
+
+
+
+static void tegra_dc_dp_suspend(struct tegra_dc *dc)
+{
+       /* TBD */
+}
+
+
+static void tegra_dc_dp_resume(struct tegra_dc *dc)
+{
+       /* TBD */
+}
+
+struct tegra_dc_out_ops tegra_dc_dp_ops = {
+       .init    = tegra_dc_dp_init,
+       .destroy = tegra_dc_dp_destroy,
+       .enable  = tegra_dc_dp_enable,
+       .disable = tegra_dc_dp_disable,
+       .suspend = tegra_dc_dp_suspend,
+       .resume  = tegra_dc_dp_resume,
+};
diff --git a/drivers/video/tegra/dc/dp.h b/drivers/video/tegra/dc/dp.h
new file mode 100644 (file)
index 0000000..138dc8a
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * drivers/video/tegra/dc/dp.h
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVER_VIDEO_TEGRA_DC_DP_H__
+#define __DRIVER_VIDEO_TEGRA_DC_DP_H__
+
+#include "sor.h"
+
+#define DP_AUX_DEFER_MAX_TRIES     7
+#define DP_AUX_TIMEOUT_MAX_TRIES    2
+#define DP_POWER_ON_MAX_TRIES      3
+#define DP_CLOCK_RECOVERY_MAX_TRIES 7
+#define DP_CLOCK_RECOVERY_TOT_TRIES 15
+
+#define DP_AUX_MAX_BYTES           16
+
+#define DP_LCDVCC_TO_HPD_DELAY_MS   200
+#define DP_AUX_TIMEOUT_MS          40
+#define DP_DPCP_RETRY_SLEEP_NS     400
+
+
+#define DP_LINK_SPEED_G1_62        6
+#define DP_LINK_SPEED_G2_7         10
+#define DP_LINK_SPEED_G5_4         20
+
+enum {
+       driveCurrent_Level0 = 0,
+       driveCurrent_Level1 = 1,
+       driveCurrent_Level2 = 2,
+       driveCurrent_Level3 = 3,
+};
+
+enum {
+       preEmphasis_Disabled = 0,
+       preEmphasis_Level1   = 1,
+       preEmphasis_Level2   = 2,
+       preEmphasis_Level3   = 3,
+};
+
+enum {
+       postCursor2_Level0 = 0,
+       postCursor2_Level1 = 1,
+       postCursor2_Level2 = 2,
+       postCursor2_Level3 = 3,
+       postCursor2_Supported
+};
+
+
+/* the +10ms is the time for power rail going up from 10-90% or
+   90%-10% on powerdown */
+/* Time from power-rail is turned on and aux/12c-over-aux is available */
+#define EDP_PWR_ON_TO_AUX_TIME_MS          (200+10)
+/* Time from power-rail is turned on and MainLink is available for LT */
+#define EDP_PWR_ON_TO_ML_TIME_MS           (200+10)
+/* Time from turning off power to turn-it on again (does not include post
+   poweron time) */
+#define EDP_PWR_OFF_TO_ON_TIME_MS          (500+10)
+
+struct tegra_dc_dp_data {
+       struct tegra_dc                 *dc;
+       struct tegra_dc_sor_data        *sor;
+
+       struct resource                 *aux_base_res;
+       void __iomem                    *aux_base;
+       struct clk                      *clk;   /* DC clock */
+
+       struct work_struct               lt_work;
+       u8                               revision;
+
+       struct tegra_dc_mode            *mode;
+       struct tegra_dc_dp_link_config   link_cfg;
+};
+
+
+/* DPCD definitions */
+#define NV_DPCD_REV                                    (0x00000000)
+#define NV_DPCD_REV_MAJOR_1                            (0x00000001)
+#define NV_DPCD_REV_MINOR_0                            (0x00000000)
+#define NV_DPCD_REV_MINOR_1                            (0x00000001)
+#define NV_DPCD_MAX_LINK_BANDWIDTH                     (0x00000001)
+#define NV_DPCD_MAX_LINK_BANDWIDTH_VAL_1_62_GPBS       (0x00000006)
+#define NV_DPCD_MAX_LINK_BANDWIDTH_VAL_2_70_GPBS       (0x0000000a)
+#define NV_DPCD_MAX_LINK_BANDWIDTH_VAL_5_40_GPBS       (0x00000014)
+#define NV_DPCD_MAX_LANE_COUNT                         (0x00000002)
+#define NV_DPCD_MAX_LANE_COUNT_MASK                    (0x1f)
+#define NV_DPCD_MAX_LANE_COUNT_LANE_1                  (0x00000001)
+#define NV_DPCD_MAX_LANE_COUNT_LANE_2                  (0x00000002)
+#define NV_DPCD_MAX_LANE_COUNT_LANE_4                  (0x00000004)
+#define NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_NO     (0x00000000 << 7)
+#define NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES    (0x00000001 << 7)
+#define NV_DPCD_MAX_DOWNSPREAD                         (0x00000003)
+#define NV_DPCD_MAX_DOWNSPREAD_VAL_NONE                        (0x00000000)
+#define NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT             (0x00000001)
+#define NV_DPCD_MAX_DOWNSPREAD_NO_AUX_HANDSHAKE_LT_F   (0x00000000)
+#define NV_DPCD_MAX_DOWNSPREAD_NO_AUX_HANDSHAKE_LT_T   (0x00000001)
+#define NV_DPCD_EDP_CONFIG_CAP                         (0x0000000D)
+#define NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_NO            (0x00000000)
+#define NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES           (0x00000001)
+#define NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_NO       (0x00000000)
+#define NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES      (0x00000001)
+#define NV_DPCD_LINK_BANDWIDTH_SET                     (0x00000100)
+#define NV_DPCD_LANE_COUNT_SET                         (0x00000101)
+#define NV_DPCD_LANE_COUNT_SET_ENHANCEDFRAMING_F       (0x00000000)
+#define NV_DPCD_LANE_COUNT_SET_ENHANCEDFRAMING_T       (0x00000001)
+#define NV_DPCD_TRAINING_PATTERN_SET                   (0x00000102)
+#define NV_DPCD_TRAINING_PATTERN_SET_TPS_MASK          0x3
+#define NV_DPCD_TRAINING_PATTERN_SET_TPS_NONE          (0x00000000)
+#define NV_DPCD_TRAINING_PATTERN_SET_TPS_TP1           (0x00000001)
+#define NV_DPCD_TRAINING_PATTERN_SET_TPS_TP2           (0x00000002)
+#define NV_DPCD_TRAINING_PATTERN_SET_TPS_TP3           (0x00000003)
+#define NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_F     (0x00000000)
+#define NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_T     (0x00000001)
+#define NV_DPCD_TRAINING_LANE0_SET                     (0x00000103)
+#define NV_DPCD_TRAINING_LANE1_SET                     (0x00000104)
+#define NV_DPCD_TRAINING_LANE2_SET                     (0x00000105)
+#define NV_DPCD_TRAINING_LANE3_SET                     (0x00000106)
+#define NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT            0
+#define NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T    (0x00000001 << 2)
+#define NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT            3
+#define NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T    (0x00000001 << 5)
+#define NV_DPCD_DOWNSPREAD_CTRL                                (0x00000107)
+#define NV_DPCD_DOWNSPREAD_CTRL_SPREAD_AMP_NONE                (0x00000000)
+#define NV_DPCD_DOWNSPREAD_CTRL_SPREAD_AMP_LT_0_5      (0x00000001)
+#define NV_DPCD_EDP_CONFIG_SET                         (0x0000010A)
+#define NV_DPCD_EDP_CONFIG_SET_ASC_RESET_DISABLE       (0x00000000)
+#define NV_DPCD_EDP_CONFIG_SET_ASC_RESET_ENABLE                (0x00000001)
+#define NV_DPCD_EDP_CONFIG_SET_FRAMING_CHANGE_DISABLE  (0x00000000)
+#define NV_DPCD_EDP_CONFIG_SET_FRAMING_CHANGE_ENABLE   (0x00000001)
+#define NV_DPCD_TRAINING_LANE0_1_SET2                  (0x0000010F)
+#define NV_DPCD_TRAINING_LANE2_3_SET2                  (0x00000110)
+#define NV_DPCD_LANEX_SET2_PC2_SHIFT                   0
+#define NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T           (0x00000001 << 2)
+#define NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT              4
+#define NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T      (0x00000001 << 6)
+#define NV_DPCD_SINK_COUNT                             (0x00000200)
+#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR              (0x00000201)
+#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_AUTO_TEST_NO (0x00000000 << 1)
+#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_AUTO_TEST_YES        (0x00000001 << 1)
+#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_CP_NO                (0x00000000 << 2)
+#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_CP_YES       (0x00000001 << 2)
+#define NV_DPCD_LANE0_1_STATUS                         (0x00000202)
+#define NV_DPCD_LANE2_3_STATUS                         (0x00000203)
+#define NV_DPCD_STATUS_LANEX_CR_DONE_SHIFT             0
+#define NV_DPCD_STATUS_LANEX_CR_DONE_NO                        (0x00000000)
+#define NV_DPCD_STATUS_LANEX_CR_DONE_YES               (0x00000001)
+#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT         1
+#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_NO            (0x00000000 << 1)
+#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES           (0x00000001 << 1)
+#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT       2
+#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_NO          (0x00000000 << 2)
+#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES         (0x00000001 << 2)
+#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_SHIFT                4
+#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_NO           (0x00000000 << 4)
+#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES          (0x00000001 << 4)
+#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT    5
+#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_NO       (0x00000000 << 5)
+#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES      (0x00000001 << 5)
+#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT  6
+#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_NO     (0x00000000 << 6)
+#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES    (0x00000001 << 6)
+#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED              (0x00000204)
+#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_NO      (0x00000000)
+#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES     (0x00000001)
+#define NV_DPCD_LANE0_1_ADJUST_REQ                     (0x00000206)
+#define NV_DPCD_LANE2_3_ADJUST_REQ                     (0x00000207)
+#define NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT              0
+#define NV_DPCD_ADJUST_REQ_LANEX_DC_MASK               0x3
+#define NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT              2
+#define NV_DPCD_ADJUST_REQ_LANEX_PE_MASK               (0x3 << 2)
+#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT         4
+#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK          (0x3 << 4)
+#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT         6
+#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK          (0x3 << 6)
+#define NV_DPCD_ADJUST_REQ_POST_CURSOR2                        (0x0000020C)
+#define NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK      0x3
+#define NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(i)  (i*2)
+#define NV_DPCD_TEST_REQUEST                           (0x00000218)
+#define NV_DPCD_SOURCE_IEEE_OUI                                (0x00000300)
+#define NV_DPCD_SINK_IEEE_OUI                          (0x00000400)
+#define NV_DPCD_BRANCH_IEEE_OUI                                (0x00000500)
+#define NV_DPCD_SET_POWER                              (0x00000600)
+#define NV_DPCD_SET_POWER_VAL_RESERVED                 (0x00000000)
+#define NV_DPCD_SET_POWER_VAL_D0_NORMAL                        (0x00000001)
+#define NV_DPCD_SET_POWER_VAL_D3_PWRDWN                        (0x00000002)
+#define NV_DPCD_HDCP_BKSV_OFFSET                       (0x00068000)
+#define NV_DPCD_HDCP_RPRIME_OFFSET                     (0x00068005)
+#define NV_DPCD_HDCP_AKSV_OFFSET                       (0x00068007)
+#define NV_DPCD_HDCP_AN_OFFSET                         (0x0006800C)
+#define NV_DPCD_HDCP_VPRIME_OFFSET                     (0x00068014)
+#define NV_DPCD_HDCP_BCAPS_OFFSET                      (0x00068028)
+#define NV_DPCD_HDCP_BSTATUS_OFFSET                    (0x00068029)
+#define NV_DPCD_HDCP_BINFO_OFFSET                      (0x0006802A)
+#define NV_DPCD_HDCP_KSV_FIFO_OFFSET                   (0x0006802C)
+#define NV_DPCD_HDCP_AINFO_OFFSET                      (0x0006803B)
+
+
+#endif
diff --git a/drivers/video/tegra/dc/dpaux_regs.h b/drivers/video/tegra/dc/dpaux_regs.h
new file mode 100644 (file)
index 0000000..6589fcb
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * drivers/video/tegra/dc/dpaux_regs.h
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVER_VIDEO_TEGRA_DC_DPAUX_REGS_H__
+#define __DRIVER_VIDEO_TEGRA_DC_DPAUX_REGS_H__
+
+
+#define DPAUX_INTR_EN_AUX                              (0x1)
+#define DPAUX_INTR_AUX                                 (0x5)
+#define DPAUX_DP_AUXDATA_WRITE_W(i)                 (0x9 + 4*(i))
+#define DPAUX_DP_AUXDATA_READ_W(i)                  (0x19 + 4*(i))
+#define DPAUX_DP_AUXADDR                               (0x29)
+#define DPAUX_DP_AUXCTL                                        (0x2d)
+#define DPAUX_DP_AUXCTL_CMDLEN_SHIFT                   (0)
+#define DPAUX_DP_AUXCTL_CMDLEN_FIELD                   (0xff)
+#define DPAUX_DP_AUXCTL_CMD_SHIFT                      (12)
+#define DPAUX_DP_AUXCTL_CMD_MASK                       (0xf << 12)
+#define DPAUX_DP_AUXCTL_CMD_I2CWR                      (0 << 12)
+#define DPAUX_DP_AUXCTL_CMD_I2CRD                      (1 << 12)
+#define DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT                        (2 << 12)
+#define DPAUX_DP_AUXCTL_CMD_MOTWR                      (4 << 12)
+#define DPAUX_DP_AUXCTL_CMD_MOTRD                      (5 << 12)
+#define DPAUX_DP_AUXCTL_CMD_MOTREQWSTAT                        (6 << 12)
+#define DPAUX_DP_AUXCTL_CMD_AUXWR                      (8 << 12)
+#define DPAUX_DP_AUXCTL_CMD_AUXRD                      (9 << 12)
+#define DPAUX_DP_AUXCTL_TRANSACTREQ_SHIFT              (16)
+#define DPAUX_DP_AUXCTL_TRANSACTREQ_MASK               (0x1 << 16)
+#define DPAUX_DP_AUXCTL_TRANSACTREQ_DONE               (0 << 16)
+#define DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING            (1 << 16)
+#define DPAUX_DP_AUXCTL_RST_SHIFT                      (31)
+#define DPAUX_DP_AUXCTL_RST_DEASSERT                   (0 << 31)
+#define DPAUX_DP_AUXCTL_RST_ASSERT                     (1 << 31)
+#define DPAUX_DP_AUXSTAT                               (0x31)
+#define DPAUX_DP_AUXSTAT_HPD_STATUS_SHIFT              (28)
+#define DPAUX_DP_AUXSTAT_HPD_STATUS_UNPLUG             (0 << 28)
+#define DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED            (1 << 28)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_SHIFT            (20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_MASK             (0xf << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_IDLE             (0 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_SYNC             (1 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_START1           (2 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_COMMAND          (3 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_ADDRESS          (4 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_LENGTH           (5 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_WRITE1           (6 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_READ1            (7 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_GET_M            (8 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_STOP1            (9 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_STOP2            (10 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_REPLY            (11 << 20)
+#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_CLEANUP          (12 << 20)
+#define DPAUX_DP_AUXSTAT_REPLYTYPE_SHIFT               (16)
+#define DPAUX_DP_AUXSTAT_REPLYTYPE_MASK                        (0xf << 16)
+#define DPAUX_DP_AUXSTAT_REPLYTYPE_ACK                 (0 << 16)
+#define DPAUX_DP_AUXSTAT_REPLYTYPE_NACK                        (1 << 16)
+#define DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER               (2 << 16)
+#define DPAUX_DP_AUXSTAT_REPLYTYPE_I2CNACK             (4 << 16)
+#define DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER            (8 << 16)
+#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_SHIFT           (11)
+#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_NOT_PENDING     (0 << 11)
+#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING         (1 << 11)
+#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_SHIFT          (10)
+#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_NOT_PENDING    (0 << 10)
+#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING                (1 << 10)
+#define DPAUX_DP_AUXSTAT_RX_ERROR_SHIFT                        (9)
+#define DPAUX_DP_AUXSTAT_RX_ERROR_NOT_PENDING          (0 << 9)
+#define DPAUX_DP_AUXSTAT_RX_ERROR_PENDING              (1 << 9)
+#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_SHIFT           (8)
+#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_NOT_PENDING     (0 << 8)
+#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING         (1 << 8)
+#define DPAUX_DP_AUXSTAT_REPLY_M_SHIFT                 (0)
+#define DPAUX_DP_AUXSTAT_REPLY_M_MASK                  (0xff << 0)
+#define DPAUX_HPD_CONFIG                               (0x3d)
+#define DPAUX_HPD_IRQ_CONFIG                           (0x41)
+#define DPAUX_DP_AUX_CONFIG                            (0x45)
+#define DPAUX_HYBRID_PADCTL                            (0x49)
+#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_SHIFT    (15)
+#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_DISABLE  (0 << 15)
+#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_ENABLE   (1 << 15)
+#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_SHIFT    (14)
+#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_DISABLE  (0 << 14)
+#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_ENABLE   (1 << 14)
+#define DPAUX_HYBRID_PADCTL_AUX_CMH_SHIFT              (12)
+#define DPAUX_HYBRID_PADCTL_AUX_CMH_DEFAULT_MASK       (0x3 << 12)
+#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_60              (0 << 12)
+#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_64              (1 << 12)
+#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70              (2 << 12)
+#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_56              (3 << 12)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_SHIFT             (8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_DEFAULT_MASK      (0x7 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_78            (0 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_60            (1 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_54            (2 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_45            (3 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50            (4 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_42            (5 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_39            (6 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_34            (7 << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT             (2)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVI_DEFAULT_MASK      (0x3f << 2)
+#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_SHIFT                (1)
+#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_DISABLE      (0 << 1)
+#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE       (1 << 1)
+#define DPAUX_HYBRID_PADCTL_MODE_SHIFT                 (0)
+#define DPAUX_HYBRID_PADCTL_MODE_AUX                   (0)
+#define DPAUX_HYBRID_PADCTL_MODE_I2C                   (1)
+#define DPAUX_HYBRID_SPARE                             (0x4d)
+#define DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP             (0)
+#define DPAUX_HYBRID_SPARE_PAD_PWR_POWERDOWN           (1)
+
+
+#endif
diff --git a/drivers/video/tegra/dc/sor.c b/drivers/video/tegra/dc/sor.c
new file mode 100644 (file)
index 0000000..cece381
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * drivers/video/tegra/dc/sor.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/nvhost.h>
+#include <linux/kernel.h>
+#include <linux/fb.h>
+
+#include <mach/clk.h>
+#include <mach/dc.h>
+
+#include "sor.h"
+#include "sor_regs.h"
+#include "dc_priv.h"
+
+
+struct tegra_dc_sor_data *tegra_dc_sor_init(struct tegra_dc *dc,
+       const struct tegra_dc_dp_link_config *cfg)
+{
+       struct tegra_dc_sor_data        *sor;
+       struct resource                 *res;
+       struct resource                 *base_res;
+       void __iomem                    *base;
+       struct clk                      *clk;
+       int                              err;
+
+       sor = kzalloc(sizeof(*sor), GFP_KERNEL);
+       if (!sor) {
+               err = -ENOMEM;
+               goto err_allocate;
+       }
+
+       res = nvhost_get_resource_byname(dc->ndev, IORESOURCE_MEM, "sor");
+       if (!res) {
+               dev_err(&dc->ndev->dev, "sor: no mem resource\n");
+               err = -ENOENT;
+               goto err_free_sor;
+       }
+
+       base_res = request_mem_region(res->start, resource_size(res),
+               dc->ndev->name);
+       if (!base_res) {
+               dev_err(&dc->ndev->dev, "sor: request_mem_region failed\n");
+               err = -EBUSY;
+               goto err_free_sor;
+       }
+
+       base = ioremap(res->start, resource_size(res));
+       if (!base) {
+               dev_err(&dc->ndev->dev, "sor: registers can't be mapped\n");
+               err = -ENOENT;
+               goto err_release_resource_reg;
+       }
+
+       clk = clk_get(&dc->ndev->dev, "sor");
+       if (IS_ERR_OR_NULL(clk)) {
+               dev_err(&dc->ndev->dev, "sor: can't get clock\n");
+               err = -ENOENT;
+               goto err_iounmap_reg;
+       }
+
+       sor->dc       = dc;
+       sor->base     = base;
+       sor->base_res = base_res;
+       sor->sor_clk  = clk;
+       sor->link_cfg = cfg;
+
+       return sor;
+
+
+err_iounmap_reg:
+       iounmap(base);
+err_release_resource_reg:
+       release_resource(base_res);
+err_free_sor:
+       kfree(sor);
+err_allocate:
+       return ERR_PTR(err);
+}
+
+static inline unsigned long tegra_sor_readl(struct tegra_dc_sor_data *sor,
+       unsigned long reg)
+{
+       return readl(sor->base + reg * 4);
+}
+
+static inline void tegra_sor_writel(struct tegra_dc_sor_data *sor,
+       unsigned long reg, unsigned long val)
+{
+       writel(val, sor->base + reg * 4);
+}
+
+
+static unsigned long tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor,
+       u32 reg, u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_ms)
+{
+       unsigned long timeout_jf = jiffies + msecs_to_jiffies(timeout_ms);
+       u32 reg_val = 0;
+
+       do {
+               usleep(poll_interval_us);
+               reg_val = tegra_sor_readl(sor, reg);
+       } while (((reg_val & mask) != exp_val) &&
+               time_after(timeout_jf, jiffies));
+
+       if ((reg_val & mask) == exp_val)
+               return 0;       /* success */
+       dev_dbg(&sor->dc->ndev->dev,
+               "sor_poll_register 0x%x: timeout\n", reg);
+       return jiffies - timeout_jf + 1;
+}
+
+
+static int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor,
+       int pu_pd)
+{
+       unsigned long reg_val;
+       unsigned long orig_val;
+
+       if (tegra_dc_sor_poll_register(sor, NV_SOR_SEQ_CTL,
+                       NV_SOR_SEQ_CTL_STATUS_MASK,
+                       NV_SOR_SEQ_CTL_STATUS_STOPPED,
+                       100, TEGRA_SOR_TIMEOUT_MS)) {
+               dev_err(&sor->dc->ndev->dev,
+                       "dc timeout waiting for SOR_SEQ_CT = STATUS_STOPPED\n");
+               return -EFAULT;
+       }
+
+       orig_val = tegra_sor_readl(sor, NV_SOR_PWR);
+
+       reg_val = pu_pd ? NV_SOR_PWR_NORMAL_STATE_PU :
+               NV_SOR_PWR_NORMAL_STATE_PD; /* normal state only */
+
+       if (reg_val == orig_val)
+               return 0;       /* No update needed */
+
+       reg_val |= NV_SOR_PWR_SETTING_NEW_TRIGGER;
+       tegra_sor_writel(sor, NV_SOR_PWR, reg_val);
+       return 0;
+}
+
+void tegra_dc_sor_disable(struct tegra_dc_sor_data *sor)
+{
+       /* Power down the SOR sequencer */
+       if ((tegra_dc_sor_set_power_state(sor, 0))) {
+               dev_err(&sor->dc->ndev->dev,
+                       "Failed to power down SOR sequencer\n");
+               return;
+       }
+
+       /* Power down DP lanes */
+       if (tegra_dc_sor_powerdown_dplanes(sor, 0)) {
+               dev_err(&sor->dc->ndev->dev,
+                       "Failed to power down dp lanes\n");
+               return;
+       }
+}
+EXPORT_SYMBOL(tegra_dc_sor_disable);
+
+void tegra_dc_sor_destroy(struct tegra_dc_sor_data *sor)
+{
+       clk_put(sor->sor_clk);
+       iounmap(sor->base);
+       release_resource(sor->base_res);
+       kfree(sor);
+}
+EXPORT_SYMBOL(tegra_dc_sor_destroy);
+
+void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, bool ena,
+       u8 training_pattern, const struct tegra_dc_dp_link_config *cfg,
+       bool use_scramble)
+{
+       unsigned long reg_val;
+
+       reg_val = tegra_sor_readl(sor, NV_SOR_DP_LINKCTL(sor->portnum));
+
+       if (ena)
+               reg_val |= NV_SOR_DP_LINKCTL_ENABLE_YES;
+       else
+               reg_val &= NV_SOR_DP_LINKCTL_ENABLE_NO;
+
+       reg_val |= (cfg->tu_size << NV_SOR_DP_LINKCTL_TUSIZE_SHIFT);
+
+       /* !!!TODO: fix the scrambler enabling */
+       if (use_scramble)
+               reg_val |= cfg->scramble_ena <<
+                       NV_SOR_DP_LINKCTL_SCRAMBLEREN_SHIFT;
+
+       if (cfg->enhanced_framing)
+               reg_val |= NV_SOR_DP_LINKCTL_ENHANCEDFRAME_ENABLE;
+       reg_val |= (training_pattern <<
+               NV_SOR_DP_LINKCTL_TRAININGPTTRN_SHIFT);
+
+       tegra_sor_writel(sor, NV_SOR_DP_LINKCTL(sor->portnum),
+               reg_val);
+}
+EXPORT_SYMBOL(tegra_dc_sor_set_dp_linkctl);
+
+void tegra_dc_sor_set_dp_lanedata(struct tegra_dc_sor_data *sor,
+       u32 lane, u32 pre_emphasis, u32 drive_current, u32 tx_pu)
+{
+       unsigned long d_cur;
+       unsigned long p_emp;
+       unsigned long p_ctl;
+
+
+       d_cur = tegra_sor_readl(sor, NV_SOR_DC(sor->portnum));
+       p_emp = tegra_sor_readl(sor, NV_SOR_PR(sor->portnum));
+       p_ctl = tegra_sor_readl(sor, NV_SOR_DP_PADCTL(sor->portnum));
+
+       switch (lane) {
+       case 0:
+               p_emp &= ~NV_SOR_PR_LANE2_DP_LANE0_MASK;
+               p_emp |= (pre_emphasis <<
+                       NV_SOR_PR_LANE2_DP_LANE0_SHIFT);
+               d_cur &= ~NV_SOR_DC_LANE2_DP_LANE0_MASK;
+               d_cur |= (drive_current <<
+                       NV_SOR_DC_LANE2_DP_LANE0_SHIFT);
+               break;
+       case 1:
+               p_emp &= ~NV_SOR_PR_LANE1_DP_LANE1_MASK;
+               p_emp |= (pre_emphasis <<
+                       NV_SOR_PR_LANE1_DP_LANE1_SHIFT);
+               d_cur &= ~NV_SOR_DC_LANE1_DP_LANE1_MASK;
+               d_cur |= (drive_current <<
+                       NV_SOR_DC_LANE1_DP_LANE1_SHIFT);
+               break;
+       case 2:
+               p_emp &= ~NV_SOR_PR_LANE0_DP_LANE2_MASK;
+               p_emp |= (pre_emphasis <<
+                       NV_SOR_PR_LANE0_DP_LANE2_SHIFT);
+               d_cur &= ~NV_SOR_DC_LANE0_DP_LANE2_MASK;
+               d_cur |= (drive_current <<
+                       NV_SOR_DC_LANE0_DP_LANE2_SHIFT);
+               break;
+       case 3:
+               p_emp &= ~NV_SOR_PR_LANE3_DP_LANE3_MASK;
+               p_emp |= (pre_emphasis <<
+                       NV_SOR_PR_LANE3_DP_LANE3_SHIFT);
+               d_cur &= ~NV_SOR_DC_LANE3_DP_LANE3_MASK;
+               d_cur |= (drive_current <<
+                       NV_SOR_DC_LANE3_DP_LANE3_SHIFT);
+       default:
+               dev_err(&sor->dc->ndev->dev,
+                       "dp: sor lane count %d is invalid\n", lane);
+       }
+
+       p_ctl &= ~NV_SOR_DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK;
+       p_ctl |= (tx_pu << NV_SOR_DP_PADCTL_TX_PU_VALUE_SHIFT);
+
+       tegra_sor_writel(sor, NV_SOR_DP_LINKCTL(sor->portnum), d_cur);
+       tegra_sor_writel(sor, NV_SOR_PR(sor->portnum),
+               p_emp);
+       tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum),
+               p_ctl);
+}
+EXPORT_SYMBOL(tegra_dc_sor_set_dp_lanedata);
+
+
+int tegra_dc_sor_powerdown_dplanes(struct tegra_dc_sor_data *sor,
+       u32 lane_count)
+{
+       unsigned long reg_val;
+
+       reg_val = tegra_sor_readl(sor, NV_SOR_DP_PADCTL(sor->portnum));
+
+       if (lane_count < 4)
+               reg_val &= (NV_SOR_DP_PADCTL_PD_TXD_3_YES |
+                       NV_SOR_DP_PADCTL_PD_TXD_2_YES);
+       if (lane_count < 2)
+               reg_val &= NV_SOR_DP_PADCTL_PD_TXD_1_YES;
+       if (lane_count < 1)
+               reg_val &= NV_SOR_DP_PADCTL_PD_TXD_0_YES;
+       tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum), reg_val);
+
+       /* SOR lane sequencer */
+       reg_val = tegra_sor_readl(sor, NV_SOR_LANE_SEQ_CTL);
+
+       reg_val |= NV_SOR_LANE_SEQ_CTL_SETTING_NEW_TRIGGER;
+       tegra_sor_writel(sor, NV_SOR_LANE_SEQ_CTL, reg_val);
+
+       if (tegra_dc_sor_poll_register(sor, NV_SOR_LANE_SEQ_CTL,
+                       NV_SOR_LANE_SEQ_CTL_SETTING_MASK, 0,
+                       100, TEGRA_SOR_TIMEOUT_MS)) {
+               dev_dbg(&sor->dc->ndev->dev,
+                       "dp: timeout while waiting for SOR lane sequencer "
+                       "to power down langes\n");
+               return -EFAULT;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(tegra_dc_sor_powerdown_dplanes);
+
+
+void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor,
+       bool power_up)
+{
+       unsigned long reg_val;
+
+       /* !!TODO: need to enable panel power through GPIO operations */
+       /* Check bug 790854 for HW progress */
+
+       reg_val = tegra_sor_readl(sor, NV_SOR_DP_PADCTL(sor->portnum));
+
+       if (power_up)
+               reg_val |= NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERUP;
+       else
+               reg_val &= ~NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERUP;
+
+       tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum), reg_val);
+}
+EXPORT_SYMBOL(tegra_dc_sor_set_panel_power);
+
+
+void tegra_dc_sor_config_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div,
+       u32 pwm_dutycycle, u32 pwm_clksrc)
+{
+       unsigned long reg_val;
+
+       tegra_sor_writel(sor, NV_SOR_PWM_DIV, pwm_div);
+
+       reg_val = pwm_dutycycle & NV_SOR_PWM_CTL_DUTY_CYCLE_MASK;
+       reg_val |= (pwm_clksrc << NV_SOR_PWM_CTL_DUTY_CYCLE_SHIFT);
+       reg_val |= NV_SOR_PWM_CTL_SETTING_NEW_TRIGGER;
+       tegra_sor_writel(sor, NV_SOR_PWM_CTL, reg_val);
+
+       if (tegra_dc_sor_poll_register(sor, NV_SOR_PWM_CTL,
+                       NV_SOR_PWM_CTL_SETTING_NEW_SHIFT,
+                       NV_SOR_PWM_CTL_SETTING_NEW_DONE,
+                       100, TEGRA_SOR_TIMEOUT_MS)) {
+               dev_dbg(&sor->dc->ndev->dev,
+                       "dp: timeout while waiting for SOR PWM setting\n");
+       }
+}
+EXPORT_SYMBOL(tegra_dc_sor_config_pwm);
+
+static void tegra_dc_sor_set_dp_mode(struct tegra_dc_sor_data *sor,
+       const struct tegra_dc_dp_link_config *cfg)
+{
+       unsigned long reg_val;
+
+       reg_val = NV_SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK;
+       reg_val |= (cfg->link_bw << NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT);
+       tegra_sor_writel(sor, NV_SOR_CLK_CNTRL, reg_val);
+
+       /* TODO: SOR_NV_PDISP_SOR_REFCL */
+       /* tegra_dc_sor_set_dp_linkctl(sor, true,
+          trainingPattern_Disabled, true); */
+       reg_val = tegra_sor_readl(sor,
+               NV_SOR_DP_CONFIG(sor->portnum));
+       reg_val &= NV_SOR_DP_CONFIG_WATERMARK_MASK;
+       reg_val |= cfg->watermark;
+       reg_val &= NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_MASK;
+       reg_val |= (cfg->active_count <<
+               NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_SHIFT);
+       reg_val &= NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_MASK;
+       reg_val |= (cfg->active_frac <<
+               NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_SHIFT);
+       if (cfg->activepolarity)
+               reg_val |= NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
+       else
+               reg_val &= ~NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
+       reg_val |= NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_ENABLE;
+
+       tegra_sor_writel(sor, NV_SOR_DP_CONFIG(sor->portnum),
+               reg_val);
+
+       /* program h/vblank sym */
+       reg_val = tegra_sor_readl(sor,
+               NV_SOR_DP_LINKCTL(sor->portnum));
+
+       reg_val = cfg->hblank_sym & NV_SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK;
+       tegra_sor_writel(sor, NV_SOR_DP_AUDIO_HBLANK_SYMBOLS,
+               reg_val);
+
+       reg_val = cfg->vblank_sym & NV_SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK;
+       tegra_sor_writel(sor, NV_SOR_DP_AUDIO_VBLANK_SYMBOLS,
+               reg_val);
+}
+
+void tegra_dc_sor_enable(struct tegra_dc_sor_data *sor)
+{
+       tegra_dc_sor_set_dp_mode(sor, sor->link_cfg);
+}
+EXPORT_SYMBOL(tegra_dc_sor_enable);
+
+
+int tegra_dc_sor_set_dp_packet(struct tegra_dc_sor_data *sor,
+       u8 *packet)
+{
+       /* No need to set the infoframe yet as there is no audio or
+          stereo support. This is a placeholder for now */
+       return 0;
+}
+
+
+void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, bool is_int)
+{
+       unsigned long reg_val;
+
+       reg_val = tegra_sor_readl(sor, NV_SOR_DP_SPARE(sor->portnum));
+       if (is_int)
+               reg_val |= NV_SOR_DP_SPARE_PANEL_INTERNAL;
+       else
+               reg_val &= ~NV_SOR_DP_SPARE_PANEL_INTERNAL;
+       tegra_sor_writel(sor, NV_SOR_DP_SPARE(sor->portnum), reg_val);
+}
+EXPORT_SYMBOL(tegra_dc_sor_set_internal_panel);
+
+void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw,
+                                  u8 *lane_count)
+{
+       unsigned long reg_val;
+
+       reg_val = tegra_sor_readl(sor, NV_SOR_CLK_CNTRL);
+       *link_bw = (reg_val & NV_SOR_CLK_CNTRL_DP_LINK_SPEED_MASK)
+               >> NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT;
+       reg_val = tegra_sor_readl(sor,
+               NV_SOR_DP_LINKCTL(sor->portnum));
+
+       switch (reg_val & NV_SOR_DP_LINKCTL_LANECOUNT_MASK) {
+       case NV_SOR_DP_LINKCTL_LANECOUNT_ZERO:
+               *lane_count = 0;
+               break;
+       case NV_SOR_DP_LINKCTL_LANECOUNT_ONE:
+               *lane_count = 1;
+               break;
+       case NV_SOR_DP_LINKCTL_LANECOUNT_TWO:
+               *lane_count = 2;
+               break;
+       case NV_SOR_DP_LINKCTL_LANECOUNT_FOUR:
+               *lane_count = 4;
+               break;
+       default:
+               dev_err(&sor->dc->ndev->dev, "Unknown lane count\n");
+       }
+}
+EXPORT_SYMBOL(tegra_dc_sor_read_link_config);
+
+void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor, u8 link_bw)
+{
+       unsigned long reg_val;
+
+       /* FIXME!!! make sure the clk (single/diff dpclk) is programmed */
+       reg_val = tegra_sor_readl(sor, NV_SOR_CLK_CNTRL);
+       reg_val &= ~NV_SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
+       reg_val |= link_bw << NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT;
+       tegra_sor_writel(sor, NV_SOR_CLK_CNTRL, reg_val);
+}
+EXPORT_SYMBOL(tegra_dc_sor_set_link_bandwidth);
+
+void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count)
+{
+       unsigned long reg_val;
+
+       reg_val = tegra_sor_readl(sor, NV_SOR_DP_LINKCTL(sor->portnum));
+       reg_val &= ~NV_SOR_DP_LINKCTL_LANECOUNT_MASK;
+       switch (lane_count) {
+       case 0:
+               break;
+       case 1:
+               reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_ONE;
+               break;
+       case 2:
+               reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_TWO;
+               break;
+       case 4:
+               reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_FOUR;
+               break;
+       default:
+               /* 0 should be handled earlier. */
+               dev_err(&sor->dc->ndev->dev, "dp: Invalid lane count %d\n",
+                       lane_count);
+               return;
+       }
+       reg_val |= (lane_count << NV_SOR_DP_LINKCTL_LANECOUNT_SHIFT);
+       tegra_sor_writel(sor, NV_SOR_DP_LINKCTL(sor->portnum),
+               reg_val);
+}
+EXPORT_SYMBOL(tegra_dc_sor_set_lane_count);
diff --git a/drivers/video/tegra/dc/sor.h b/drivers/video/tegra/dc/sor.h
new file mode 100644 (file)
index 0000000..5d05a60
--- /dev/null
@@ -0,0 +1,114 @@
+
+/*
+ * drivers/video/tegra/dc/sor.h
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_DC_SOR_H__
+#define __DRIVERS_VIDEO_TEGRA_DC_SOR_H__
+
+
+enum {
+       trainingPattern_Disabled        = 0,
+       trainingPattern_1               = 1,
+       trainingPattern_2               = 2,
+       trainingPattern_3               = 3,
+       trainingPattern_None            = 0xff
+};
+
+struct tegra_dc_dp_link_config {
+       bool    is_valid;
+
+       /* Supported configuration */
+       u8      max_link_bw;
+       u8      max_lane_count;
+       bool    downspread;
+       bool    support_enhanced_framing;
+       u32     bytes_per_pixel;
+       bool    alt_scramber_reset_cap; /* true for eDP */
+       bool    only_enhanced_framing;  /* enhanced_frame_en ignored */
+
+       /* Actual configuration */
+       u8      link_bw;
+       u8      lane_count;
+       bool    enhanced_framing;
+       bool    scramble_ena;
+
+       u32     activepolarity;
+       u32     active_count;
+       u32     tu_size;
+       u32     active_frac;
+       u32     watermark;
+
+       u32     hblank_sym;
+       u32     vblank_sym;
+};
+
+
+struct tegra_dc_sor_data {
+       struct tegra_dc *dc;
+
+       void __iomem    *base;
+       struct resource *base_res;
+       struct clk      *sor_clk;
+
+       u8                                       portnum;       /* 0 or 1 */
+       const struct tegra_dc_dp_link_config    *link_cfg;
+};
+
+#define TEGRA_SOR_TIMEOUT_MS  1000
+
+#define CHECK_RET(x)                   \
+       do {                            \
+               ret = (x);              \
+               if (ret != 0)           \
+                       return ret;     \
+       } while (0)
+
+
+static inline void usleep(unsigned int usecs)
+{
+       unsigned long timeout = usecs_to_jiffies(usecs) + 1;
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout_uninterruptible(timeout);
+}
+
+struct tegra_dc_sor_data *tegra_dc_sor_init(struct tegra_dc *dc,
+       const struct tegra_dc_dp_link_config *cfg);
+
+void tegra_dc_sor_destroy(struct tegra_dc_sor_data *sor);
+void tegra_dc_sor_enable(struct tegra_dc_sor_data *sor);
+void tegra_dc_sor_disable(struct tegra_dc_sor_data *sor);
+
+void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor,
+       bool is_int);
+void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor,
+       u8 *link_bw, u8 *lane_count);
+void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor,
+       u8 link_bw);
+void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count);
+void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor,
+       bool power_up);
+void tegra_dc_sor_set_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div,
+       u32 pwm_dutycycle, u32 pwm_clksrc);
+int  tegra_dc_sor_powerdown_dplanes(struct tegra_dc_sor_data *sor,
+       u32 lane_count);
+void tegra_dc_sor_set_dp_lanedata(struct tegra_dc_sor_data *sor,
+       u32 lane, u32 pre_emphasis, u32 drive_current, u32 tx_pu);
+void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, bool ena,
+       u8 training_pattern, const struct tegra_dc_dp_link_config *cfg,
+       bool use_scramble);
+
+#endif
diff --git a/drivers/video/tegra/dc/sor_regs.h b/drivers/video/tegra/dc/sor_regs.h
new file mode 100644 (file)
index 0000000..85054a0
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * drivers/video/tegra/dc/sor_regs.h
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVER_VIDEO_TEGRA_DC_SOR_REGS_H__
+#define __DRIVER_VIDEO_TEGRA_DC_SOR_REGS_H__
+
+
+#define NV_SOR_CLK_CNTRL                                       (0x7)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_SHIFT                      (0)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_MASK                       (0x3)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK                        (0)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK                  (1)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK               (2)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK                 (3)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT                   (2)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_MASK                    (0x1f << 2)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62                   (6 << 2)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_G2_7                    (10 << 2)
+#define NV_SOR_CAP                                             (0x1e)
+#define NV_SOR_CAP_DP_A_SHIFT                                  (24)
+#define NV_SOR_CAP_DP_A_DEFAULT_MASK                           (0x1 << 24)
+#define NV_SOR_CAP_DP_A_FALSE                                  (0 << 24)
+#define NV_SOR_CAP_DP_A_TRUE                                   (1 << 24)
+#define NV_SOR_CAP_DP_B_SHIFT                                  (25)
+#define NV_SOR_CAP_DP_B_DEFAULT_MASK                           (0x1 << 24)
+#define NV_SOR_CAP_DP_B_FALSE                                  (0 << 24)
+#define NV_SOR_CAP_DP_B_TRUE                                   (1 << 24)
+#define NV_SOR_PWR                                             (0x1f)
+#define NV_SOR_PWR_SETTING_NEW_SHIFT                           (31)
+#define NV_SOR_PWR_SETTING_NEW_DEFAULT_MASK                    (0x1 << 31)
+#define NV_SOR_PWR_SETTING_NEW_PENDING                         (1 << 31)
+#define NV_SOR_PWR_SETTING_NEW_TRIGGER                         (1 << 31)
+#define NV_SOR_PWR_MODE_SHIFT                                  (28)
+#define NV_SOR_PWR_MODE_DEFAULT_MASK                           (0x1 << 28)
+#define NV_SOR_PWR_MODE_NORMAL                                 (0 << 28)
+#define NV_SOR_PWR_MODE_SAFE                                   (1 << 28)
+#define NV_SOR_PWR_HALT_DELAY_SHIFT                            (24)
+#define NV_SOR_PWR_HALT_DELAY_DEFAULT_MASK                     (0x1 << 24)
+#define NV_SOR_PWR_HALT_DELAY_DONE                             (0 << 24)
+#define NV_SOR_PWR_HALT_DELAY_ACTIVE                           (1 << 24)
+#define NV_SOR_PWR_SAFE_START_SHIFT                            (17)
+#define NV_SOR_PWR_SAFE_START_DEFAULT_MASK                     (0x1 << 17)
+#define NV_SOR_PWR_SAFE_START_NORMAL                           (0 << 17)
+#define NV_SOR_PWR_SAFE_START_ALT                              (1 << 17)
+#define NV_SOR_PWR_SAFE_STATE_SHIFT                            (16)
+#define NV_SOR_PWR_SAFE_STATE_DEFAULT_MASK                     (0x1 << 16)
+#define NV_SOR_PWR_SAFE_STATE_PD                               (0 << 16)
+#define NV_SOR_PWR_SAFE_STATE_PU                               (1 << 16)
+#define NV_SOR_PWR_NORMAL_START_SHIFT                          (1)
+#define NV_SOR_PWR_NORMAL_START_DEFAULT_MASK                   (0x1 << 1)
+#define NV_SOR_PWR_NORMAL_START_NORMAL                         (0 << 16)
+#define NV_SOR_PWR_NORMAL_START_ALT                            (1 << 16)
+#define NV_SOR_PWR_NORMAL_STATE_SHIFT                          (0)
+#define NV_SOR_PWR_NORMAL_STATE_DEFAULT_MASK                   (0x1)
+#define NV_SOR_PWR_NORMAL_STATE_PD                             (0)
+#define NV_SOR_PWR_NORMAL_STATE_PU                             (1)
+#define NV_SOR_SEQ_CTL                                         (0x2c)
+#define NV_SOR_SEQ_CTL_SWITCH_SHIFT                            (30)
+#define NV_SOR_SEQ_CTL_SWITCH_MASK                             (0x1 << 30)
+#define NV_SOR_SEQ_CTL_SWITCH_WAIT                             (0 << 30)
+#define NV_SOR_SEQ_CTL_SWITCH_FORCE                            (1 << 30)
+#define NV_SOR_SEQ_CTL_STATUS_SHIFT                            (28)
+#define NV_SOR_SEQ_CTL_STATUS_MASK                             (0x1 << 28)
+#define NV_SOR_SEQ_CTL_STATUS_STOPPED                          (0 << 28)
+#define NV_SOR_SEQ_CTL_STATUS_RUNNING                          (1 << 28)
+#define NV_SOR_SEQ_CTL_PC_SHIFT                                        (16)
+#define NV_SOR_SEQ_CTL_PC_MASK                                 (0xf << 16)
+#define NV_SOR_SEQ_CTL_PD_PC_ALT_SHIFT                         (12)
+#define NV_SOR_SEQ_CTL_PD_PC_ALT_MASK                          (0xf << 12)
+#define NV_SOR_SEQ_CTL_PD_PC_SHIFT                             (8)
+#define NV_SOR_SEQ_CTL_PD_PC_MASK                              (0xf << 8)
+#define NV_SOR_SEQ_CTL_PU_PC_ALT_SHIFT                         (4)
+#define NV_SOR_SEQ_CTL_PU_PC_ALT_MASK                          (0xf << 4)
+#define NV_SOR_SEQ_CTL_PU_PC_SHIFT                             (0)
+#define NV_SOR_SEQ_CTL_PU_PC_MASK                              (0xf)
+#define NV_SOR_LANE_SEQ_CTL                                    (0x2d)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_NEW_SHIFT                  (31)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_MASK                       (1 << 31)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_NEW_PENDING                        (1 << 31)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_NEW_TRIGGER                        (1 << 31)
+#define NV_SOR_LANE_SEQ_CTL_SEQ_STATE_SHIFT                    (28)
+#define NV_SOR_LANE_SEQ_CTL_SEQ_STATE_IDLE                     (0 << 28)
+#define NV_SOR_LANE_SEQ_CTL_SEQ_STATE_BUSY                     (1 << 28)
+#define NV_SOR_LANE_SEQ_CTL_SEQUENCE_SHIFT                     (20)
+#define NV_SOR_LANE_SEQ_CTL_SEQUENCE_UP                                (0 << 20)
+#define NV_SOR_LANE_SEQ_CTL_SEQUENCE_DOWN                      (1 << 20)
+#define NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_SHIFT              (16)
+#define NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_PU                 (0 << 16)
+#define NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_PD                 (1 << 16)
+#define NV_SOR_LANE_SEQ_CTL_DELAY_SHIFT                                (12)
+#define NV_SOR_LANE_SEQ_CTL_DELAY_DEFAULT_MASK                 (0xf << 12)
+#define NV_SOR_LANE_SEQ_CTL_LANE9_STATE_SHIFT                  (9)
+#define NV_SOR_LANE_SEQ_CTL_LANE9_STATE_POWERUP                        (0 << 9)
+#define NV_SOR_LANE_SEQ_CTL_LANE9_STATE_POWERDOWN              (1 << 9)
+#define NV_SOR_LANE_SEQ_CTL_LANE8_STATE_SHIFT                  (8)
+#define NV_SOR_LANE_SEQ_CTL_LANE8_STATE_POWERUP                        (0 << 8)
+#define NV_SOR_LANE_SEQ_CTL_LANE8_STATE_POWERDOWN              (1 << 8)
+#define NV_SOR_LANE_SEQ_CTL_LANE7_STATE_SHIFT                  (7)
+#define NV_SOR_LANE_SEQ_CTL_LANE7_STATE_POWERUP                        (0 << 7)
+#define NV_SOR_LANE_SEQ_CTL_LANE7_STATE_POWERDOWN              (1 << 7)
+#define NV_SOR_LANE_SEQ_CTL_LANE6_STATE_SHIFT                  (6)
+#define NV_SOR_LANE_SEQ_CTL_LANE6_STATE_POWERUP                        (0 << 6)
+#define NV_SOR_LANE_SEQ_CTL_LANE6_STATE_POWERDOWN              (1 << 6)
+#define NV_SOR_LANE_SEQ_CTL_LANE5_STATE_SHIFT                  (5)
+#define NV_SOR_LANE_SEQ_CTL_LANE5_STATE_POWERUP                        (0 << 5)
+#define NV_SOR_LANE_SEQ_CTL_LANE5_STATE_POWERDOWN              (1 << 5)
+#define NV_SOR_LANE_SEQ_CTL_LANE4_STATE_SHIFT                  (4)
+#define NV_SOR_LANE_SEQ_CTL_LANE4_STATE_POWERUP                        (0 << 4)
+#define NV_SOR_LANE_SEQ_CTL_LANE4_STATE_POWERDOWN              (1 << 4)
+#define NV_SOR_LANE_SEQ_CTL_LANE3_STATE_SHIFT                  (3)
+#define NV_SOR_LANE_SEQ_CTL_LANE3_STATE_POWERUP                        (0 << 3)
+#define NV_SOR_LANE_SEQ_CTL_LANE3_STATE_POWERDOWN              (1 << 3)
+#define NV_SOR_LANE_SEQ_CTL_LANE2_STATE_SHIFT                  (2)
+#define NV_SOR_LANE_SEQ_CTL_LANE2_STATE_POWERUP                        (0 << 2)
+#define NV_SOR_LANE_SEQ_CTL_LANE2_STATE_POWERDOWN              (1 << 2)
+#define NV_SOR_LANE_SEQ_CTL_LANE1_STATE_SHIFT                  (1)
+#define NV_SOR_LANE_SEQ_CTL_LANE1_STATE_POWERUP                        (0 << 1)
+#define NV_SOR_LANE_SEQ_CTL_LANE1_STATE_POWERDOWN              (1 << 1)
+#define NV_SOR_LANE_SEQ_CTL_LANE0_STATE_SHIFT                  (0)
+#define NV_SOR_LANE_SEQ_CTL_LANE0_STATE_POWERUP                        (0)
+#define NV_SOR_LANE_SEQ_CTL_LANE0_STATE_POWERDOWN              (1)
+#define NV_SOR_PWM_DIV                                         (0x3e)
+#define SOR_NV_PDISP_SOR_PWM_DIV_0_DIVIDE_DEFAULT_MASK         (0xffffff)
+#define NV_SOR_PWM_CTL                                         (0x3f)
+#define NV_SOR_PWM_CTL_SETTING_NEW_SHIFT                       (31)
+#define NV_SOR_PWM_CTL_SETTING_NEW_DONE                                (0 << 31)
+#define NV_SOR_PWM_CTL_SETTING_NEW_PENDING                     (1 << 31)
+#define NV_SOR_PWM_CTL_SETTING_NEW_TRIGGER                     (1 << 31)
+#define NV_SOR_PWM_CTL_CLKSEL_SHIFT                            (30)
+#define NV_SOR_PWM_CTL_CLKSEL_PCLK                             (0 << 30)
+#define NV_SOR_PWM_CTL_CLKSEL_XTAL                             (1 << 30)
+#define NV_SOR_PWM_CTL_DUTY_CYCLE_SHIFT                                (0)
+#define NV_SOR_PWM_CTL_DUTY_CYCLE_MASK                         (0xffffff)
+#define NV_SOR_DP_LINKCTL(i)                                   (0x5a + (i))
+#define NV_SOR_DP_LINKCTL_FORCE_IDLEPTTRN_SHIFT                        (31)
+#define NV_SOR_DP_LINKCTL_FORCE_IDLEPTTRN_NO                   (0 << 31)
+#define NV_SOR_DP_LINKCTL_FORCE_IDLEPTTRN_YES                  (1 << 31)
+#define NV_SOR_DP_LINKCTL_COMPLIANCEPTTRN_SHIFT                        (28)
+#define NV_SOR_DP_LINKCTL_COMPLIANCEPTTRN_NOPATTERN            (0 << 28)
+#define NV_SOR_DP_LINKCTL_COMPLIANCEPTTRN_COLORSQARE           (1 << 28)
+#define NV_SOR_DP_LINKCTL_LINKQUALPTTRN_SHIFT                  (26)
+#define NV_SOR_DP_LINKCTL_LINKQUALPTTRN_MASK                   (0x3 << 26)
+#define NV_SOR_DP_LINKCTL_LINKQUALPTTRN_NOPATTERN              (0 << 26)
+#define NV_SOR_DP_LINKCTL_LINKQUALPTTRN_D102                   (1 << 26)
+#define NV_SOR_DP_LINKCTL_LINKQUALPTTRN_SBLERRRATE             (2 << 26)
+#define NV_SOR_DP_LINKCTL_LINKQUALPTTRN_PRBS7                  (3 << 26)
+#define NV_SOR_DP_LINKCTL_TRAININGPTTRN_SHIFT                  (24)
+#define NV_SOR_DP_LINKCTL_TRAININGPTTRN_MASK                   (0x3 << 24)
+#define NV_SOR_DP_LINKCTL_TRAININGPTTRN_NOPATTERN              (0 << 24)
+#define NV_SOR_DP_LINKCTL_TRAININGPTTRN_TRAINING1              (1 << 24)
+#define NV_SOR_DP_LINKCTL_TRAININGPTTRN_TRAINING2              (2 << 24)
+#define NV_SOR_DP_LINKCTL_CHANNELCODING_SHIFT                  (22)
+#define NV_SOR_DP_LINKCTL_CHANNELCODING_DISABLE                        (0 << 22)
+#define NV_SOR_DP_LINKCTL_CHANNELCODING_ENABLE                 (1 << 22)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_SHIFT                      (16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_MASK                       (0x1f << 16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_ZERO                       (0 << 16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_ONE                                (1 << 16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_TWO                                (3 << 16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_FOUR                       (15 << 16)
+#define NV_SOR_DP_LINKCTL_ENHANCEDFRAME_SHIFT                  (14)
+#define NV_SOR_DP_LINKCTL_ENHANCEDFRAME_DISABLE                        (0 << 14)
+#define NV_SOR_DP_LINKCTL_ENHANCEDFRAME_ENABLE                 (1 << 14)
+#define NV_SOR_DP_LINKCTL_SCRAMBLEREN_SHIFT                    (12)
+#define NV_SOR_DP_LINKCTL_SCRAMBLEREN_MASK                     (0x3 << 12)
+#define NV_SOR_DP_LINKCTL_SCRAMBLEREN_DISABLE                  (0 << 12)
+#define NV_SOR_DP_LINKCTL_SCRAMBLEREN_ENABLE_GALIOS            (1 << 12)
+#define NV_SOR_DP_LINKCTL_SCRAMBLEREN_ENABLE_FIBONACCI         (2 << 12)
+#define NV_SOR_DP_LINKCTL_SYNCMODE_SHIFT                       (10)
+#define NV_SOR_DP_LINKCTL_SYNCMODE_DISABLE                     (0 << 10)
+#define NV_SOR_DP_LINKCTL_SYNCMODE_ENABLE                      (1 << 10)
+#define NV_SOR_DP_LINKCTL_TUSIZE_SHIFT                         (2)
+#define NV_SOR_DP_LINKCTL_TUSIZE_MASK                          (0x7f << 2)
+#define NV_SOR_DP_LINKCTL_ENABLE_SHIFT                         (0)
+#define NV_SOR_DP_LINKCTL_ENABLE_NO                            (0)
+#define NV_SOR_DP_LINKCTL_ENABLE_YES                           (1)
+#define NV_SOR_DC(i)                                           (0x5c + (i))
+#define NV_SOR_DC_LANE3_DP_LANE3_SHIFT                         (24)
+#define NV_SOR_DC_LANE3_DP_LANE3_MASK                          (0xff << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P0_LEVEL0                     (17 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P1_LEVEL0                     (21 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P2_LEVEL0                     (26 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P3_LEVEL0                     (34 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P0_LEVEL1                     (26 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P1_LEVEL1                     (32 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P2_LEVEL1                     (39 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P0_LEVEL2                     (34 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P1_LEVEL2                     (43 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P0_LEVEL3                     (51 << 24)
+#define NV_SOR_DC_LANE2_DP_LANE0_SHIFT                         (16)
+#define NV_SOR_DC_LANE2_DP_LANE0_MASK                          (0xff << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P0_LEVEL0                     (17 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P1_LEVEL0                     (21 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P2_LEVEL0                     (26 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P3_LEVEL0                     (34 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P0_LEVEL1                     (26 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P1_LEVEL1                     (32 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P2_LEVEL1                     (39 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P0_LEVEL2                     (34 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P1_LEVEL2                     (43 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P0_LEVEL3                     (51 << 16)
+#define NV_SOR_DC_LANE1_DP_LANE1_SHIFT                         (8)
+#define NV_SOR_DC_LANE1_DP_LANE1_MASK                          (0xff << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P0_LEVEL0                     (17 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P1_LEVEL0                     (21 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P2_LEVEL0                     (26 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P3_LEVEL0                     (34 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P0_LEVEL1                     (26 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P1_LEVEL1                     (32 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P2_LEVEL1                     (39 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P0_LEVEL2                     (34 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P1_LEVEL2                     (43 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P0_LEVEL3                     (51 << 8)
+#define NV_SOR_DC_LANE0_DP_LANE2_SHIFT                         (0)
+#define NV_SOR_DC_LANE0_DP_LANE2_MASK                          (0xff)
+#define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL0                     (17)
+#define NV_SOR_DC_LANE0_DP_LANE2_P1_LEVEL0                     (21)
+#define NV_SOR_DC_LANE0_DP_LANE2_P2_LEVEL0                     (26)
+#define NV_SOR_DC_LANE0_DP_LANE2_P3_LEVEL0                     (34)
+#define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL1                     (26)
+#define NV_SOR_DC_LANE0_DP_LANE2_P1_LEVEL1                     (32)
+#define NV_SOR_DC_LANE0_DP_LANE2_P2_LEVEL1                     (39)
+#define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL2                     (34)
+#define NV_SOR_DC_LANE0_DP_LANE2_P1_LEVEL2                     (43)
+#define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL3                     (51)
+#define NV_SOR_LANE4_DRIVE_CURRENT(i)                          (0x5e + (i))
+#define NV_SOR_PR(i)                                           (0x60 + (i))
+#define NV_SOR_PR_LANE3_DP_LANE3_SHIFT                         (24)
+#define NV_SOR_PR_LANE3_DP_LANE3_MASK                          (0xff << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D0_LEVEL0                     (0 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D1_LEVEL0                     (0 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D2_LEVEL0                     (0 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D3_LEVEL0                     (0 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D0_LEVEL1                     (4 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D1_LEVEL1                     (6 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D2_LEVEL1                     (17 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D0_LEVEL2                     (8 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D1_LEVEL2                     (13 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D0_LEVEL3                     (17 << 24)
+#define NV_SOR_PR_LANE2_DP_LANE0_SHIFT                         (16)
+#define NV_SOR_PR_LANE2_DP_LANE0_MASK                          (0xff << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D0_LEVEL0                     (0 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D1_LEVEL0                     (0 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D2_LEVEL0                     (0 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D3_LEVEL0                     (0 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D0_LEVEL1                     (4 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D1_LEVEL1                     (6 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D2_LEVEL1                     (17 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D0_LEVEL2                     (8 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D1_LEVEL2                     (13 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D0_LEVEL3                     (17 << 16)
+#define NV_SOR_PR_LANE1_DP_LANE1_SHIFT                         (8)
+#define NV_SOR_PR_LANE1_DP_LANE1_MASK                          (0xff >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D0_LEVEL0                     (0 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D1_LEVEL0                     (0 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D2_LEVEL0                     (0 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D3_LEVEL0                     (0 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D0_LEVEL1                     (4 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D1_LEVEL1                     (6 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D2_LEVEL1                     (17 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D0_LEVEL2                     (8 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D1_LEVEL2                     (13 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D0_LEVEL3                     (17 >> 8)
+#define NV_SOR_PR_LANE0_DP_LANE2_SHIFT                         (0)
+#define NV_SOR_PR_LANE0_DP_LANE2_MASK                          (0xff)
+#define NV_SOR_PR_LANE0_DP_LANE2_D0_LEVEL0                     (0)
+#define NV_SOR_PR_LANE0_DP_LANE2_D1_LEVEL0                     (0)
+#define NV_SOR_PR_LANE0_DP_LANE2_D2_LEVEL0                     (0)
+#define NV_SOR_PR_LANE0_DP_LANE2_D3_LEVEL0                     (0)
+#define NV_SOR_PR_LANE0_DP_LANE2_D0_LEVEL1                     (4)
+#define NV_SOR_PR_LANE0_DP_LANE2_D1_LEVEL1                     (6)
+#define NV_SOR_PR_LANE0_DP_LANE2_D2_LEVEL1                     (17)
+#define NV_SOR_PR_LANE0_DP_LANE2_D0_LEVEL2                     (8)
+#define NV_SOR_PR_LANE0_DP_LANE2_D1_LEVEL2                     (13)
+#define NV_SOR_PR_LANE0_DP_LANE2_D0_LEVEL3                     (17)
+#define NV_SOR_LANE4_PREEMPHASIS(i)                            (0x62 + (i))
+#define NV_SOR_DP_CONFIG(i)                                    (0x64 + (i))
+#define NV_SOR_DP_CONFIG_RD_RESET_VAL_SHIFT                    (31)
+#define NV_SOR_DP_CONFIG_RD_RESET_VAL_POSITIVE                 (0 << 31)
+#define NV_SOR_DP_CONFIG_RD_RESET_VAL_NEGATIVE                 (1 << 31)
+#define NV_SOR_DP_CONFIG_IDLE_BEFORE_ATTACH_SHIFT              (28)
+#define NV_SOR_DP_CONFIG_IDLE_BEFORE_ATTACH_DISABLE            (0 << 28)
+#define NV_SOR_DP_CONFIG_IDLE_BEFORE_ATTACH_ENABLE             (1 << 28)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_SHIFT                  (26)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_DISABLE                        (0 << 26)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_ENABLE                 (1 << 26)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_SHIFT              (24)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_NEGATIVE           (0 << 24)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE           (1 << 24)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_SHIFT                  (16)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_MASK                   (0xf << 16)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_SHIFT                 (8)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_MASK                  (0x7f << 8)
+#define NV_SOR_DP_CONFIG_WATERMARK_SHIFT                       (0)
+#define NV_SOR_DP_CONFIG_WATERMARK_MASK                                (0x3f)
+#define NV_SOR_DP_PADCTL(i)                                    (0x68 + (i))
+#define NV_SOR_DP_PADCTL_SPARE_SHIFT                           (25)
+#define NV_SOR_DP_PADCTL_SPARE_DEFAULT_MASK                    (0x7f << 25)
+#define NV_SOR_DP_PADCTL_VCO_2X_SHIFT                          (24)
+#define NV_SOR_DP_PADCTL_VCO_2X_DISABLE                                (0 << 24)
+#define NV_SOR_DP_PADCTL_VCO_2X_ENABLE                         (1 << 24)
+#define NV_SOR_DP_PADCTL_PAD_CAL_PD_SHIFT                      (23)
+#define NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERUP                    (0 << 23)
+#define NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN                  (1 << 23)
+#define NV_SOR_DP_PADCTL_TX_PU_SHIFT                           (22)
+#define NV_SOR_DP_PADCTL_TX_PU_DISABLE                         (0 << 22)
+#define NV_SOR_DP_PADCTL_TX_PU_ENABLE                          (1 << 22)
+#define NV_SOR_DP_PADCTL_REG_CTRL_SHIFT                                (20)
+#define NV_SOR_DP_PADCTL_REG_CTRL_DEFAULT_MASK                 (0x3 << 20)
+#define NV_SOR_DP_PADCTL_VCMMODE_SHIFT                         (16)
+#define NV_SOR_DP_PADCTL_VCMMODE_DEFAULT_MASK                  (0xf << 16)
+#define NV_SOR_DP_PADCTL_VCMMODE_TRISTATE                      (0 << 16)
+#define NV_SOR_DP_PADCTL_VCMMODE_TEST_MUX                      (1 << 16)
+#define NV_SOR_DP_PADCTL_VCMMODE_WEAK_PULLDOWN                 (2 << 16)
+#define NV_SOR_DP_PADCTL_VCMMODE_STRONG_PULLDOWN               (4 << 16)
+#define NV_SOR_DP_PADCTL_TX_PU_VALUE_SHIFT                     (8)
+#define NV_SOR_DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK              (0xff << 8)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_3_DP_TXD_3_SHIFT       (7)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_3_DP_TXD_3_DISABLE     (0 << 7)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_3_DP_TXD_3_ENABLE      (1 << 7)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_2_DP_TXD_0_SHIFT       (6)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_2_DP_TXD_0_DISABLE     (0 << 6)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_2_DP_TXD_0_ENABLE      (1 << 6)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_1_DP_TXD_1_SHIFT       (5)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_1_DP_TXD_1_DISABLE     (0 << 5)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_1_DP_TXD_1_ENABLE      (1 << 5)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_0_DP_TXD_2_SHIFT       (4)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_0_DP_TXD_2_DISABLE     (0 << 4)
+#define NV_SOR_DP_PADCTL_COMMONMODE_TXD_0_DP_TXD_2_ENABLE      (1 << 4)
+#define NV_SOR_DP_PADCTL_PD_TXD_3_SHIFT                                (3)
+#define NV_SOR_DP_PADCTL_PD_TXD_3_YES                          (0 << 3)
+#define NV_SOR_DP_PADCTL_PD_TXD_3_NO                           (1 << 3)
+#define NV_SOR_DP_PADCTL_PD_TXD_0_SHIFT                                (2)
+#define NV_SOR_DP_PADCTL_PD_TXD_0_YES                          (0 << 2)
+#define NV_SOR_DP_PADCTL_PD_TXD_0_NO                           (1 << 2)
+#define NV_SOR_DP_PADCTL_PD_TXD_1_SHIFT                                (1)
+#define NV_SOR_DP_PADCTL_PD_TXD_1_YES                          (0 << 1)
+#define NV_SOR_DP_PADCTL_PD_TXD_1_NO                           (1 << 1)
+#define NV_SOR_DP_PADCTL_PD_TXD_2_SHIFT                                (0)
+#define NV_SOR_DP_PADCTL_PD_TXD_2_YES                          (0)
+#define NV_SOR_DP_PADCTL_PD_TXD_2_NO                           (1)
+#define NV_SOR_DP_SPARE(i)                                     (0x6c + (i))
+#define NV_SOR_DP_SPARE_PANEL_SHIFT                            (1)
+#define NV_SOR_DP_SPARE_PANEL_EXTERNAL                         (0 << 1)
+#define NV_SOR_DP_SPARE_PANEL_INTERNAL                         (1 << 1)
+#define NV_SOR_DP_SPARE_SEQ_ENABLE_SHIFT                       (0)
+#define NV_SOR_DP_SPARE_SEQ_ENABLE_NO                          (0)
+#define NV_SOR_DP_SPARE_SEQ_ENABLE_YES                         (1)
+#define NV_SOR_DP_AUDIO_HBLANK_SYMBOLS                         (0x6e)
+#define NV_SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK                    (0x1ffff)
+#define NV_SOR_DP_AUDIO_HBLANK_SYMBOLS_VALUE_SHIFT             (0)
+#define NV_SOR_DP_AUDIO_VBLANK_SYMBOLS                         (0x6f)
+#define NV_SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK                    (0x1ffff)
+#define NV_SOR_DP_AUDIO_VBLANK_SYMBOLS_SHIFT                   (0)
+#define NV_SOR_DP_GENERIC_INFOFRAME_HEADER                     (0x70)
+#define NV_SOR_DP_GENERIC_INFOFRAME_SUBPACK(i)                 (0x71 + (i))
+
+#endif