Merge "dev: pqnp_wled: change max precharge time to 500us"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 4f26616..fc41a24 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -117,6 +117,8 @@
#define EXPAND(NAME) #NAME
#define TARGET(NAME) EXPAND(NAME)
+#define DISPLAY_PANEL_HDMI "hdmi"
+
#ifdef MEMBASE
#define EMMC_BOOT_IMG_HEADER_ADDR (0xFF000+(MEMBASE))
#else
@@ -3815,6 +3817,11 @@
if (!check_alarm_boot()) {
#endif
dprintf(SPEW, "Display Init: Start\n");
+#if DISPLAY_HDMI_PRIMARY
+ if (!strlen(device.display_panel))
+ strlcpy(device.display_panel, DISPLAY_PANEL_HDMI,
+ sizeof(device.display_panel));
+#endif
#if ENABLE_WBC
/* Wait if the display shutdown is in progress */
while(pm_app_display_shutdown_in_prgs());
diff --git a/dev/pmic/pm8x41/include/pm_vadc_hc.h b/dev/pmic/pm8x41/include/pm_vadc_hc.h
new file mode 100644
index 0000000..8e0dba4
--- /dev/null
+++ b/dev/pmic/pm8x41/include/pm_vadc_hc.h
@@ -0,0 +1,243 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PM_VADC_HC_H_
+#define PM_VADC_HC_H_
+
+#include <sys/types.h>
+#include <bits.h>
+
+/* HC_ peripheral */
+#define HC_STATUS1 0x8
+
+#define HC_DATA_HOLD_CTL 0x3f
+#define HC_DATA_HOLD_CTL_FIELD BIT(1)
+
+#define HC_ADC_DIG_PARAM 0x42
+#define HC_CAL_VAL BIT(6)
+
+#define HC_CAL_VAL_SHIFT 6
+#define HC_CAL_SEL_MASK 0x30
+#define HC_CAL_SEL_SHIFT 4
+#define HC_DEC_RATIO_SEL 0xc
+#define HC_DEC_RATIO_SHIFT 2
+
+#define HC_FAST_AVG_CTL 0x43
+#define HC_FAST_AVG_SAMPLES_MASK 0x7
+
+#define HC_ADC_CH_SEL_CTL 0x44
+
+#define HC_DELAY_CTL 0x45
+#define HC_DELAY_CTL_MASK 0xf
+
+#define HC_EN_CTL1 0x46
+#define HC_ADC_EN BIT(7)
+
+#define HC_CONV_REQ 0x47
+#define HC_CONV_REQ_START BIT(7)
+
+#define HC_DATA0 0x50
+#define HC_DATA1 0x51
+
+#define HC_DATA_CHECK_USR 0x8000
+#define HC_CONV_TIME 250
+#define HC_ERR_COUNT 1600
+#define HC_VREF_CODE 0x4000
+
+enum adc_type {
+ PM_VADC_HC = 0,
+ PMI_VADC_HC = 1,
+ VADC_INVALID
+};
+
+struct adc_dev {
+ enum adc_type adc_type;
+};
+
+enum adc_fast_avg_sample {
+ AVG_1_SAMPLE = 0,
+ AVG_2_SAMPLES,
+ AVG_4_SAMPLES,
+ AVG_8_SAMPLES,
+ AVG_16_SAMPLES,
+ AVG_SAMPLES_INVALID
+};
+
+enum adc_channel_prediv_type {
+ SCALE_DIV1 = 0,
+ SCALE_DIV3,
+ SCALE_DIV4,
+ SCALE_DIV6,
+ SCALE_DIV20,
+ SCALE_DIV8,
+ SCALE10_DIV81,
+ SCALE_DIV10,
+};
+
+struct adc_pre_scale_ratio {
+ uint8_t num;
+ uint8_t den;
+};
+
+enum adc_dig_cal_sel {
+ HC_NO_CAL = 0,
+ HC_RATIO_CAL,
+ HC_ABS_CAL,
+ HC_CAL_INVALID
+};
+
+enum adc_hc_channel {
+ HC_VREF_GND = 0,
+ HC_CALIB_VREF_1P25 = 1,
+ HC_CALIB_VREF = 2,
+ HC_CALIB_VREF_1_DIV_3 = 0x82,
+ HC_VPH_PWR = 0x83,
+ HC_VBAT_SNS = 0x84,
+ HC_VCOIN = 0x85,
+ HC_DIE_TEMP = 6,
+ HC_CHG_TEMP = 7,
+ HC_USB_IN = 8,
+ HC_IREG_FB = 9,
+ /* External input connection */
+ HC_BAT_THERM = 0xa,
+ HC_BAT_ID = 0xb,
+ HC_XO_THERM = 0xc,
+ HC_AMUX_THM1 = 0xd,
+ HC_AMUX_THM2 = 0xe,
+ HC_AMUX_THM3 = 0xf,
+ HC_AMUX_THM4 = 0x10,
+ HC_AMUX_THM5 = 0x11,
+ HC_AMUX1_GPIO = 0x12,
+ HC_AMUX2_GPIO = 0x13,
+ HC_AMUX3_GPIO = 0x14,
+ HC_AMUX4_GPIO = 0x15,
+ HC_AMUX5_GPIO = 0x16,
+ HC_AMUX6_GPIO = 0x17,
+ HC_AMUX7_GPIO = 0x18,
+ HC_AMUX8_GPIO = 0x19,
+ HC_ATEST1 = 0x1a,
+ HC_ATEST2 = 0x1b,
+ HC_ATEST3 = 0x1c,
+ HC_ATEST4 = 0x1d,
+ HC_OFF = 0xff,
+ /* PU1 is 30K pull up */
+ HC_BAT_THERM_PU1 = 0x2a,
+ HC_BAT_ID_PU1 = 0x2b,
+ HC_XO_THERM_PU1 = 0x2c,
+ HC_AMUX_THM1_PU1 = 0x2d,
+ HC_AMUX_THM2_PU1 = 0x2e,
+ HC_AMUX_THM3_PU1 = 0x2f,
+ HC_AMUX_THM4_PU1 = 0x30,
+ HC_AMUX_THM5_PU1 = 0x31,
+ HC_AMUX1_GPIO_PU1 = 0x32,
+ HC_AMUX2_GPIO_PU1 = 0x33,
+ HC_AMUX3_GPIO_PU1 = 0x34,
+ HC_AMUX4_GPIO_PU1 = 0x35,
+ HC_AMUX5_GPIO_PU1 = 0x36,
+ HC_AMUX6_GPIO_PU1 = 0x37,
+ HC_AMUX7_GPIO_PU1 = 0x38,
+ HC_AMUX8_GPIO_PU1 = 0x39,
+ /* PU2 is 100K pull up */
+ HC_BAT_THERM_PU2 = 0x4a,
+ HC_BAT_ID_PU2 = 0x4b,
+ HC_XO_THERM_PU2 = 0x4c,
+ HC_AMUX_THM1_PU2 = 0x4d,
+ HC_AMUX_THM2_PU2 = 0x4e,
+ HC_AMUX_THM3_PU2 = 0x4f,
+ HC_AMUX_THM4_PU2 = 0x50,
+ HC_AMUX_THM5_PU2 = 0x51,
+ HC_AMUX1_GPIO_PU2 = 0x52,
+ HC_AMUX2_GPIO_PU2 = 0x53,
+ HC_AMUX3_GPIO_PU2 = 0x54,
+ HC_AMUX4_GPIO_PU2 = 0x55,
+ HC_AMUX5_GPIO_PU2 = 0x56,
+ HC_AMUX6_GPIO_PU2 = 0x57,
+ HC_AMUX7_GPIO_PU2 = 0x58,
+ HC_AMUX8_GPIO_PU2 = 0x59,
+ /* PU3 is 400K pull up */
+ HC_BAT_THERM_PU3 = 0x6a,
+ HC_BAT_ID_PU3 = 0x6b,
+ HC_XO_THERM_PU3 = 0x6c,
+ HC_AMUX_THM1_PU3 = 0x6d,
+ HC_AMUX_THM2_PU3 = 0x6e,
+ HC_AMUX_THM3_PU3 = 0x6f,
+ HC_AMUX_THM4_PU3 = 0x70,
+ HC_AMUX_THM5_PU3 = 0x71,
+ HC_AMUX1_GPIO_PU3 = 0x72,
+ HC_AMUX2_GPIO_PU3 = 0x73,
+ HC_AMUX3_GPIO_PU3 = 0x74,
+ HC_AMUX4_GPIO_PU3 = 0x75,
+ HC_AMUX5_GPIO_PU3 = 0x76,
+ HC_AMUX6_GPIO_PU3 = 0x77,
+ HC_AMUX7_GPIO_PU3 = 0x78,
+ HC_AMUX8_GPIO_PU3 = 0x79,
+ /* External input connection with 1/3 div */
+ HC_AMUX1_GPIO_DIV_3 = 0x92,
+ HC_AMUX2_GPIO_DIV_3 = 0x93,
+ HC_AMUX3_GPIO_DIV_3 = 0x94,
+ HC_AMUX4_GPIO_DIV_3 = 0x95,
+ HC_AMUX5_GPIO_DIV_3 = 0x96,
+ HC_AMUX6_GPIO_DIV_3 = 0x97,
+ HC_AMUX7_GPIO_DIV_3 = 0x98,
+ HC_AMUX8_GPIO_DIV_3 = 0x99,
+ HC_ATEST1_DIV_3 = 0x9a,
+ HC_ATEST2_DIV_3 = 0x9b,
+ HC_ATEST3_DIV_3 = 0x9c,
+ HC_ATEST4_DIV_3 = 0x9d,
+ HC_INVALID = 0xffff
+};
+
+enum adc_usr_delay_ctl {
+ HC_HW_SETTLE_DELAY_0US = 0,
+ HC_HW_SETTLE_DELAY_100US,
+ HC_HW_SETTLE_DELAY_200US,
+ HC_HW_SETTLE_DELAY_300US,
+ HC_HW_SETTLE_DELAY_400US,
+ HC_HW_SETTLE_DELAY_500US,
+ HC_HW_SETTLE_DELAY_600US,
+ HC_HW_SETTLE_DELAY_700US,
+ HC_HW_SETTLE_DELAY_800US,
+ HC_HW_SETTLE_DELAY_900US,
+ HC_HW_SETTLE_DELAY_1MS,
+ HC_HW_SETTLE_DELAY_2MS,
+ HC_HW_SETTLE_DELAY_4MS,
+ HC_HW_SETTLE_DELAY_6MS,
+ HC_HW_SETTLE_DELAY_8MS,
+ HC_HW_SETTLE_DELAY_10MS,
+ HC_HW_SETTLE_DELAY_INVALID
+};
+
+struct adc_result {
+ uint16_t adc_code;
+ int64_t physical;
+};
+
+int vadc_hc_read(struct adc_dev *dev, enum adc_hc_channel channel,
+ struct adc_result *result);
+
+#endif /* _PM_VADC_HC_H_ */
diff --git a/dev/pmic/pm8x41/pm_vadc_hc.c b/dev/pmic/pm8x41/pm_vadc_hc.c
new file mode 100644
index 0000000..7517a31
--- /dev/null
+++ b/dev/pmic/pm8x41/pm_vadc_hc.c
@@ -0,0 +1,322 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <spmi.h>
+#include <platform/timer.h>
+#include <pm_vadc_hc.h>
+#include <pm8x41_hw.h>
+
+static const struct adc_pre_scale_ratio vadc_hc_scale[] = {
+ [SCALE_DIV1] = {1, 1},
+ [SCALE_DIV3] = {1, 3},
+ [SCALE_DIV4] = {1, 4},
+ [SCALE_DIV6] = {1, 6},
+ [SCALE_DIV20] = {1, 20},
+ [SCALE_DIV8] = {1, 8},
+ [SCALE10_DIV81] = {10, 81},
+ [SCALE_DIV10] = {1, 10}
+};
+
+struct vadc_hc_periph_cfg {
+ /* Peripheral base address */
+ uint32_t base;
+ /* vdd_vref in millivolts */
+ uint32_t vdd_vref;
+ /* ADC reference code used in post scaling calculation */
+ uint32_t vref_code;
+ /* PM VADC /PMI VADC */
+ enum adc_type adc_type;
+};
+
+struct vadc_hc_channel_cfg {
+ /* Calibration type for the channel - absolute/ratiometric */
+ enum adc_dig_cal_sel cal_sel;
+ /* VADC channel number */
+ enum adc_hc_channel channel;
+ /* Hardware settling delay for the channel */
+ enum adc_usr_delay_ctl hw_settle;
+ /* Fast average sample value for the channel */
+ enum adc_fast_avg_sample avg_sample;
+ /*
+ * Pre scale ratio for the channel before ADC is measured.
+ * This is used while scaling the code to physical units by
+ * applying the respective pre-scale value.
+ */
+ struct adc_pre_scale_ratio pre_scale;
+ /*
+ * Scaling function used for converting the adc code to
+ * physical units based on channel properties
+ */
+ int (*scale)(struct vadc_hc_periph_cfg *adc_cfg,
+ uint16_t adc_code, struct adc_pre_scale_ratio *ratio,
+ int64_t *result);
+};
+
+static struct vadc_hc_periph_cfg vadc_pdata[] = {
+ {
+ .base = 0x3100,
+ .vdd_vref = 1875,
+ .vref_code = 0x4000,
+ .adc_type = PM_VADC_HC
+ },
+ {
+ .base = 0x23100,
+ .vdd_vref = 1875,
+ .vref_code = 0x4000,
+ .adc_type = PMI_VADC_HC
+ },
+};
+
+static int scale_default_voltage(struct vadc_hc_periph_cfg *adc_cfg,
+ uint16_t adc_code,
+ struct adc_pre_scale_ratio *ratio,
+ int64_t *result);
+
+/*
+ * This is an example of a container channel properties thats expected
+ * by the ADC driver. Clients can add channels based on the
+ * VADC channels supported by the target.
+ */
+static struct vadc_hc_channel_cfg channel_pdata[] = {
+ {
+ /* 1.25V reference channel */
+ HC_ABS_CAL,
+ HC_CALIB_VREF_1P25,
+ HC_HW_SETTLE_DELAY_0US,
+ AVG_1_SAMPLE,
+ {1, 1},
+ scale_default_voltage
+ },
+ {
+ /* vph_pwr channel */
+ HC_ABS_CAL,
+ HC_VPH_PWR,
+ HC_HW_SETTLE_DELAY_0US,
+ AVG_1_SAMPLE,
+ {1, 3},
+ scale_default_voltage
+ },
+};
+
+static void vadc_hc_reg_write(struct vadc_hc_periph_cfg *adc_cfg,
+ uint8_t offset, uint8_t val)
+{
+ REG_WRITE((adc_cfg->base + offset), val);
+}
+
+static void vadc_hc_reg_read(struct vadc_hc_periph_cfg *adc_cfg,
+ uint8_t offset, uint8_t *val)
+{
+ *val = REG_READ((adc_cfg->base + offset));
+}
+
+static int scale_default_voltage(struct vadc_hc_periph_cfg *adc_cfg,
+ uint16_t adc_code,
+ struct adc_pre_scale_ratio *ratio,
+ int64_t *result)
+{
+ int64_t voltage = 0, den = 0;
+
+ if (!ratio)
+ return -1;
+
+ voltage = (int64_t) adc_code;
+ voltage *= (int64_t) adc_cfg->vdd_vref * 1000;
+ den = (int64_t) adc_cfg->vref_code;
+ *result = voltage / den;
+ *result *= ratio->den;
+ *result = *result / ratio->num;
+
+ return 0;
+}
+
+static int vadc_hc_read_result(struct vadc_hc_periph_cfg *adc_cfg,
+ uint16_t *data)
+{
+ uint8_t code_lsb = 0, code_msb = 0, hold_bit = 0, en = 0;
+
+ /* Set hold bit */
+ vadc_hc_reg_read(adc_cfg, HC_DATA_HOLD_CTL, &hold_bit);
+ hold_bit |= HC_DATA_HOLD_CTL_FIELD;
+
+ /* Read LSB/MSB */
+ vadc_hc_reg_read(adc_cfg, HC_DATA0, &code_lsb);
+ vadc_hc_reg_read(adc_cfg, HC_DATA1, &code_msb);
+ *data = (code_msb << 8) | code_lsb;
+ if (*data == HC_DATA_CHECK_USR) {
+ dprintf(SPEW, "Invalid data :0x%x\n", *data);
+ return -1;
+ }
+
+ /* Disable peripheral */
+ vadc_hc_reg_write(adc_cfg, HC_EN_CTL1, en);
+
+ /* De-assert hold bit */
+ hold_bit &= ~HC_DATA_HOLD_CTL_FIELD;
+ vadc_hc_reg_read(adc_cfg, HC_DATA_HOLD_CTL, &hold_bit);
+
+ return 0;
+}
+
+static int32_t vadc_hc_check_completion(struct vadc_hc_periph_cfg *adc_cfg)
+{
+ int32_t i = 0;
+ uint8_t status_bit = 0;
+
+ for (i = 0; i < HC_ERR_COUNT; i++) {
+ vadc_hc_reg_read(adc_cfg, HC_STATUS1, &status_bit);
+ if (status_bit == 0x1)
+ return 0;
+
+ udelay(HC_CONV_TIME);
+ };
+
+ dprintf(SPEW, "Status bit not set with 0x%x\n", status_bit);
+
+ return -1;
+}
+
+static void vadc_hc_configure(struct vadc_hc_periph_cfg *adc_cfg,
+ struct vadc_hc_channel_cfg *ch_cfg)
+{
+ uint8_t cal = 0, avg_samples = 0;
+
+ /* Configure calibration select */
+ vadc_hc_reg_read(adc_cfg, HC_ADC_DIG_PARAM, &cal);
+ cal &= ~HC_CAL_SEL_MASK;
+ cal = cal | (ch_cfg->cal_sel << HC_CAL_SEL_SHIFT);
+ vadc_hc_reg_write(adc_cfg, HC_ADC_DIG_PARAM, cal);
+
+ /* Configure channel */
+ vadc_hc_reg_write(adc_cfg, HC_ADC_CH_SEL_CTL, ch_cfg->channel);
+
+ /* HW settle delay */
+ vadc_hc_reg_write(adc_cfg, HC_DELAY_CTL, ch_cfg->hw_settle);
+
+ /* Fast avg sample value */
+ vadc_hc_reg_read(adc_cfg, HC_FAST_AVG_CTL, &avg_samples);
+ avg_samples &= ~HC_FAST_AVG_SAMPLES_MASK;
+ avg_samples |= ch_cfg->avg_sample;
+ vadc_hc_reg_write(adc_cfg, HC_FAST_AVG_CTL, avg_samples);
+
+ /* Enable ADC */
+ vadc_hc_reg_write(adc_cfg, HC_EN_CTL1, HC_ADC_EN);
+
+ /* Request conversion */
+ vadc_hc_reg_write(adc_cfg, HC_CONV_REQ, HC_CONV_REQ_START);
+}
+
+static int vadc_check_channel_type(enum adc_hc_channel channel, int32_t *idx)
+{
+ uint32_t i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(channel_pdata); i++) {
+ if (channel_pdata[i].channel == channel) {
+ *idx = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(channel_pdata))
+ return -1;
+
+ return 0;
+}
+
+static int vadc_check_adc_type(struct adc_dev *dev)
+{
+ uint32_t i = 0;
+
+ if (dev->adc_type >= VADC_INVALID) {
+ dprintf(SPEW, "Invalid VADC_TYPE\n");
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(vadc_pdata); i++)
+ if (vadc_pdata[i].adc_type == dev->adc_type)
+ break;
+
+ if (i == ARRAY_SIZE(vadc_pdata))
+ return -1;
+
+ return 0;
+}
+
+int vadc_hc_read(struct adc_dev *dev, enum adc_hc_channel channel,
+ struct adc_result *result)
+{
+ struct vadc_hc_periph_cfg *adc_cfg;
+ struct vadc_hc_channel_cfg *chan_cfg;
+ int32_t rc = 0, idx = 0;
+ uint16_t adc_code;
+ int64_t converted_value;
+
+ if (!dev || channel >= HC_INVALID || !result) {
+ dprintf(SPEW, "Invalid params\n");
+ return -1;
+ }
+
+ rc = vadc_check_adc_type(dev);
+ if (rc) {
+ dprintf(SPEW, "Invalid adc_type params %d\n", dev->adc_type);
+ return -1;
+ }
+ adc_cfg = &vadc_pdata[dev->adc_type];
+
+ rc = vadc_check_channel_type(channel, &idx);
+ if (rc) {
+ dprintf(SPEW, "Channel pdata not present 0x%x\n", channel);
+ return -1;
+ }
+ chan_cfg = &channel_pdata[idx];
+
+ /* Configure ADC for the channel */
+ vadc_hc_configure(adc_cfg, chan_cfg);
+
+ /* Check completion */
+ rc = vadc_hc_check_completion(adc_cfg);
+ if (rc)
+ return -1;
+
+ /* Read ADC code */
+ rc = vadc_hc_read_result(adc_cfg, &adc_code);
+ if (rc)
+ return -1;
+ result->adc_code = adc_code;
+
+ dprintf(INFO, "adc_code:0x%x\n", adc_code);
+
+ /* Scale to physical units */
+ chan_cfg->scale(adc_cfg, adc_code, &chan_cfg->pre_scale,
+ &converted_value);
+ result->physical = converted_value;
+ dprintf(INFO, "converted value:%lld\n", converted_value);
+
+ return 0;
+}
diff --git a/dev/pmic/pm8x41/rules.mk b/dev/pmic/pm8x41/rules.mk
index a857013..19d15be 100644
--- a/dev/pmic/pm8x41/rules.mk
+++ b/dev/pmic/pm8x41/rules.mk
@@ -16,3 +16,8 @@
OBJS += \
$(LOCAL_DIR)/pm_pwm.o
endif
+
+ifeq ($(ENABLE_VADC_HC_SUPPORT),true)
+OBJS += \
+ $(LOCAL_DIR)/pm_vadc_hc.o
+endif
diff --git a/dev/qpnp_wled/include/qpnp_wled.h b/dev/qpnp_wled/include/qpnp_wled.h
index 32a58dc..4ca2379 100644
--- a/dev/qpnp_wled/include/qpnp_wled.h
+++ b/dev/qpnp_wled/include/qpnp_wled.h
@@ -47,8 +47,11 @@
#define QPNP_WLED_VLOOP_COMP_RES(b) (b + 0x55)
#define QPNP_WLED_VLOOP_COMP_GM(b) (b + 0x56)
#define QPNP_WLED_PSM_CTRL(b) (b + 0x5B)
-#define QPNP_WLED_TEST4(b) (b + 0xE5)
+#define QPNP_WLED_TEST4(b) (b + 0xE5)
+#define QPNP_WLED_CTRL_SPARE_REG(b) (b + 0xDF)
+#define QPNP_WLED_REF_7P7_TRIM_REG(b) (b + 0xF2)
+#define QPNP_WLED_7P7_TRIM_MASK 0xF
#define QPNP_WLED_EN_MASK 0x7F
#define QPNP_WLED_EN_SHIFT 7
#define QPNP_WLED_FDBK_OP_MASK 0xF8
@@ -188,6 +191,19 @@
#define PWRDN_DLY2_MASK 0x3
+#define NUM_SUPPORTED_AVDD_VOLTAGES 6
+
+/* Supported values 7900, 7600, 7300, 6400, 6100, 5800 */
+#if TARGET_QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV
+#define QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV TARGET_QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV
+#else
+#define QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV 7600
+#endif
+
+#define QPNP_WLED_AVDD_MIN_TRIM_VALUE 0x0
+#define QPNP_WLED_AVDD_MAX_TRIM_VALUE 0xF
+#define QPNP_WLED_AVDD_SET_BIT BIT(4)
+
/* output feedback mode */
enum qpnp_wled_fdbk_op {
QPNP_WLED_FDBK_AUTO,
diff --git a/dev/qpnp_wled/qpnp_wled.c b/dev/qpnp_wled/qpnp_wled.c
index 3575b5c..9282a7b 100644
--- a/dev/qpnp_wled/qpnp_wled.c
+++ b/dev/qpnp_wled/qpnp_wled.c
@@ -34,6 +34,18 @@
#include <pm8x41_wled.h>
#include <qtimer.h>
+static int qpnp_wled_avdd_target_voltages[NUM_SUPPORTED_AVDD_VOLTAGES] = {
+ 7900, 7600, 7300, 6400, 6100, 5800,
+};
+
+static uint8_t qpnp_wled_ovp_reg_settings[NUM_SUPPORTED_AVDD_VOLTAGES] = {
+ 0x0, 0x0, 0x1, 0x2, 0x2, 0x3,
+};
+
+static int qpnp_wled_avdd_trim_adjustments[NUM_SUPPORTED_AVDD_VOLTAGES] = {
+ 3, 0, -2, 7, 3, 3,
+};
+
static int fls(uint16_t n)
{
int i = 0;
@@ -311,6 +323,44 @@
reg |= temp;
pm8x41_wled_reg_write(QPNP_WLED_OVP_REG(wled->ctrl_base), reg);
+ if (wled->disp_type_amoled) {
+ for (i = 0; i < NUM_SUPPORTED_AVDD_VOLTAGES; i++) {
+ if (QPNP_WLED_AVDD_DEFAULT_VOLTAGE_MV == qpnp_wled_avdd_target_voltages[i])
+ break;
+ }
+ if (i == NUM_SUPPORTED_AVDD_VOLTAGES)
+ {
+ dprintf(CRITICAL, "Invalid avdd target voltage specified \n");
+ return ERR_NOT_VALID;
+ }
+ /* Update WLED_OVP register based on desired target voltage */
+ reg = qpnp_wled_ovp_reg_settings[i];
+ pm8x41_wled_reg_write(QPNP_WLED_OVP_REG(wled->ctrl_base), reg);
+ /* Update WLED_TRIM register based on desired target voltage */
+ reg = pm8x41_wled_reg_read(
+ QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
+ reg += qpnp_wled_avdd_trim_adjustments[i];
+ if ((int8_t)reg < QPNP_WLED_AVDD_MIN_TRIM_VALUE)
+ reg = QPNP_WLED_AVDD_MIN_TRIM_VALUE;
+ else if((int8_t)reg > QPNP_WLED_AVDD_MAX_TRIM_VALUE)
+ reg = QPNP_WLED_AVDD_MAX_TRIM_VALUE;
+
+ rc = qpnp_wled_sec_access(wled, wled->ctrl_base);
+ if (rc)
+ return rc;
+
+ temp = pm8x41_wled_reg_read(
+ QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base));
+ temp &= ~QPNP_WLED_7P7_TRIM_MASK;
+ temp |= (reg & QPNP_WLED_7P7_TRIM_MASK);
+ pm8x41_wled_reg_write(QPNP_WLED_REF_7P7_TRIM_REG(wled->ctrl_base), temp);
+ /* Write to spare to avoid reconfiguration in HLOS */
+ reg = pm8x41_wled_reg_read(
+ QPNP_WLED_CTRL_SPARE_REG(wled->ctrl_base));
+ reg |= QPNP_WLED_AVDD_SET_BIT;
+ pm8x41_wled_reg_write(QPNP_WLED_CTRL_SPARE_REG(wled->ctrl_base), reg);
+ }
+
/* Configure the MODULATION register */
if (wled->mod_freq_khz <= QPNP_WLED_MOD_FREQ_1200_KHZ) {
wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_1200_KHZ;
diff --git a/platform/msm8952/include/platform/iomap.h b/platform/msm8952/include/platform/iomap.h
index 8643113..5b9bab8 100644
--- a/platform/msm8952/include/platform/iomap.h
+++ b/platform/msm8952/include/platform/iomap.h
@@ -163,7 +163,7 @@
* as device memory, define the start address
* and size in MB
*/
-#define RPMB_SND_RCV_BUF 0x90000000
+#define RPMB_SND_RCV_BUF 0xA0000000
#define RPMB_SND_RCV_BUF_SZ 0x1
/* QSEECOM: Secure app region notification */
diff --git a/platform/msm8952/platform.c b/platform/msm8952/platform.c
index df7bbfa..242f4f4 100644
--- a/platform/msm8952/platform.c
+++ b/platform/msm8952/platform.c
@@ -66,7 +66,7 @@
{ MSM_IOMAP_BASE, MSM_IOMAP_BASE, MSM_IOMAP_SIZE, IOMAP_MEMORY},
{ APPS_SS_BASE, APPS_SS_BASE, APPS_SS_SIZE, IOMAP_MEMORY},
{ MSM_SHARED_IMEM_BASE, MSM_SHARED_IMEM_BASE, 1, COMMON_MEMORY},
- { SCRATCH_ADDR, SCRATCH_ADDR, 512, SCRATCH_MEMORY},
+ { SCRATCH_ADDR, SCRATCH_ADDR, 511, SCRATCH_MEMORY},
{ MIPI_FB_ADDR, MIPI_FB_ADDR, 20, COMMON_MEMORY},
{ RPMB_SND_RCV_BUF, RPMB_SND_RCV_BUF, RPMB_SND_RCV_BUF_SZ, IOMAP_MEMORY},
};
diff --git a/platform/msm8996/acpuclock.c b/platform/msm8996/acpuclock.c
index 5d2e7eb..c74e2e6 100644
--- a/platform/msm8996/acpuclock.c
+++ b/platform/msm8996/acpuclock.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -687,4 +687,45 @@
dprintf(CRITICAL, "Failed to enable %s\n", clk_name);
return;
}
-}
\ No newline at end of file
+}
+
+void hdmi_ahb_core_clk_enable(void)
+{
+ int ret;
+
+ /* Configure hdmi ahb clock */
+ ret = clk_get_set_enable("hdmi_ahb_clk", 0, 1);
+ if(ret) {
+ dprintf(CRITICAL, "failed to set hdmi_ahb_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
+
+ /* Configure hdmi core clock */
+ ret = clk_get_set_enable("hdmi_core_clk", 19200000, 1);
+ if(ret) {
+ dprintf(CRITICAL, "failed to set hdmi_core_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
+}
+
+void hdmi_pixel_clk_enable(uint32_t rate) {
+ int ret;
+
+ /* Configure hdmi pixel clock */
+ ret = clk_get_set_enable("hdmi_extp_clk", rate, 1);
+ if(ret) {
+ dprintf(CRITICAL, "failed to set hdmi_extp_clk ret = %d\n", ret);
+ ASSERT(0);
+ }
+}
+
+void hdmi_pixel_clk_disable(void)
+{
+ clk_disable(clk_get("hdmi_extp_clk"));
+}
+
+void hdmi_core_ahb_clk_disable(void)
+{
+ clk_disable(clk_get("hdmi_core_clk"));
+ clk_disable(clk_get("hdmi_ahb_clk"));
+}
diff --git a/platform/msm8996/include/platform/clock.h b/platform/msm8996/include/platform/clock.h
index 6ff55e2..f2b0455 100644
--- a/platform/msm8996/include/platform/clock.h
+++ b/platform/msm8996/include/platform/clock.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -58,6 +58,13 @@
#define MMSS_MMAGIC_AHB_CBCR REG_MM(0x5024)
#define SMMU_MDP_AHB_CBCR REG_MM(0x2454)
#define MDSS_AHB_CBCR REG_MM(0x2308)
+#define MDSS_HDMI_AHB_CBCR REG_MM(0x230C)
+#define MDSS_HDMI_CBCR REG_MM(0x2338)
+#define MDSS_EXTPCLK_CBCR REG_MM(0x2324)
+#define EXTPCLK_CMD_RCGR REG_MM(0x2060)
+#define EXTPCLK_CFG_RCGR REG_MM(0x2064)
+#define HDMI_CMD_RCGR REG_MM(0x2100)
+#define HDMI_CFG_RCGR REG_MM(0x2104)
#define AXI_CMD_RCGR REG_MM(0x5040)
#define AXI_CFG_RCGR REG_MM(0x5044)
@@ -126,4 +133,8 @@
void video_gdsc_disable();
void clock_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id);
+void hdmi_ahb_core_clk_enable(void);
+void hdmi_pixel_clk_enable(uint32_t rate);
+void hdmi_pixel_clk_disable(void);
+void hdmi_core_ahb_clk_disable(void);
#endif
diff --git a/platform/msm8996/include/platform/iomap.h b/platform/msm8996/include/platform/iomap.h
index 42ef8a7..63dca93 100644
--- a/platform/msm8996/include/platform/iomap.h
+++ b/platform/msm8996/include/platform/iomap.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -340,6 +340,11 @@
#endif
#define MDP_INTF_2_TIMING_ENGINE_EN REG_MDP(0x6C000)
+#ifdef MDP_INTF_3_TIMING_ENGINE_EN
+#undef MDP_INTF_3_TIMING_ENGINE_EN
+#endif
+#define MDP_INTF_3_TIMING_ENGINE_EN REG_MDP(0x6C800)
+
#ifdef MDP_CTL_0_BASE
#undef MDP_CTL_0_BASE
#endif
@@ -380,6 +385,11 @@
#endif
#define MDP_INTF_2_BASE REG_MDP(0x6c000)
+#ifdef MDP_INTF_3_BASE
+#undef MDP_INTF_3_BASE
+#endif
+#define MDP_INTF_3_BASE REG_MDP(0x6c800)
+
#ifdef MDP_CLK_CTRL0
#undef MDP_CLK_CTRL0
#endif
@@ -597,4 +607,77 @@
#define APPS_WDOG_RESET_REG (APSS_WDOG_BASE + 0x04)
#define APPS_WDOG_CTL_REG (APSS_WDOG_BASE + 0x08)
+/* HDMI reg addresses */
+#define HDMI_BASE 0x9A0000
+#define REG_HDMI(off) (HDMI_BASE + (off))
+
+#define HDMI_ACR_32_0 REG_HDMI(0xC4)
+#define HDMI_ACR_32_1 REG_HDMI(0xC8)
+#define HDMI_ACR_44_0 REG_HDMI(0xCC)
+#define HDMI_ACR_44_1 REG_HDMI(0xD0)
+#define HDMI_ACR_48_0 REG_HDMI(0xD4)
+#define HDMI_ACR_48_1 REG_HDMI(0xD8)
+#define HDMI_AUDIO_PKT_CTRL2 REG_HDMI(0x44)
+#define HDMI_ACR_PKT_CTRL REG_HDMI(0x24)
+#define HDMI_INFOFRAME_CTRL0 REG_HDMI(0x2C)
+#define HDMI_INFOFRAME_CTRL1 REG_HDMI(0x30)
+#define HDMI_AUDIO_INFO0 REG_HDMI(0xE4)
+#define HDMI_AUDIO_INFO1 REG_HDMI(0xE8)
+#define HDMI_AUDIO_PKT_CTRL REG_HDMI(0x20)
+#define HDMI_VBI_PKT_CTRL REG_HDMI(0x28)
+#define HDMI_GEN_PKT_CTRL REG_HDMI(0x34)
+#define HDMI_GC REG_HDMI(0x40)
+#define HDMI_AUDIO_CFG REG_HDMI(0x1D0)
+
+#define HDMI_DDC_SPEED REG_HDMI(0x220)
+#define HDMI_DDC_SETUP REG_HDMI(0x224)
+#define HDMI_DDC_REF REG_HDMI(0x27C)
+#define HDMI_DDC_DATA REG_HDMI(0x238)
+#define HDMI_DDC_TRANS0 REG_HDMI(0x228)
+#define HDMI_DDC_TRANS1 REG_HDMI(0x22C)
+#define HDMI_DDC_TRANS2 REG_HDMI(0x230)
+#define HDMI_DDC_TRANS3 REG_HDMI(0x234)
+#define HDMI_DDC_CTRL REG_HDMI(0x20C)
+#define HDMI_DDC_INT_CTRL REG_HDMI(0x214)
+#define HDMI_DDC_SW_STATUS REG_HDMI(0x218)
+#define HDMI_DDC_ARBITRATION REG_HDMI(0x210)
+#define HDMI_HW_DDC_CTRL REG_HDMI(0x4CC)
+#define HDMI_DDC_INT_CTRL0 REG_HDMI(0x430)
+#define HDMI_DDC_INT_CTRL1 REG_HDMI(0x434)
+#define HDMI_DDC_INT_CTRL2 REG_HDMI(0x438)
+#define HDMI_DDC_INT_CTRL3 REG_HDMI(0x43C)
+#define HDMI_DDC_INT_CTRL4 REG_HDMI(0x440)
+#define HDMI_DDC_INT_CTRL5 REG_HDMI(0x444)
+#define HDMI_DDC_HW_STATUS REG_HDMI(0x21C)
+#define HDMI_SCRAMBLER_STATUS_DDC_CTRL REG_HDMI(0x464)
+#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL REG_HDMI(0x468)
+#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL2 REG_HDMI(0x46C)
+#define HDMI_SCRAMBLER_STATUS_DDC_STATUS REG_HDMI(0x470)
+#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_STATUS REG_HDMI(0x474)
+#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_STATUS2 REG_HDMI(0x478)
+
+#define HDMI_USEC_REFTIMER REG_HDMI(0x208)
+#define HDMI_CTRL REG_HDMI(0x000)
+#define HDMI_VERSION REG_HDMI(0x2E4)
+#define HDMI_HPD_INT_STATUS REG_HDMI(0x250)
+#define HDMI_HPD_INT_CTRL REG_HDMI(0x254)
+#define HDMI_HPD_CTRL REG_HDMI(0x258)
+#define HDMI_PHY_CTRL REG_HDMI(0x2D4)
+#define HDMI_TOTAL REG_HDMI(0x2C0)
+#define HDMI_ACTIVE_H REG_HDMI(0x2B4)
+#define HDMI_ACTIVE_V REG_HDMI(0x2B8)
+#define HDMI_V_TOTAL_F2 REG_HDMI(0x2C4)
+#define HDMI_ACTIVE_V_F2 REG_HDMI(0x2BC)
+#define HDMI_FRAME_CTRL REG_HDMI(0x2C8)
+
+#define HDMI_AVI_INFO0 REG_HDMI(0x06C)
+#define HDMI_AVI_INFO1 REG_HDMI(0x070)
+#define HDMI_AVI_INFO2 REG_HDMI(0x074)
+#define HDMI_AVI_INFO3 REG_HDMI(0x078)
+
+#define LPASS_LPAIF_RDDMA_CTL0 0x0910D000
+#define LPASS_LPAIF_RDDMA_BASE0 0x0910D004
+#define LPASS_LPAIF_RDDMA_BUFF_LEN0 0x0910D008
+#define LPASS_LPAIF_RDDMA_PER_LEN0 0x0910D010
+#define LPASS_LPAIF_DEBUG_CTL 0x0910000C
#endif
diff --git a/platform/msm8996/msm8996-clock.c b/platform/msm8996/msm8996-clock.c
index 8a02900..c92974a 100644
--- a/platform/msm8996/msm8996-clock.c
+++ b/platform/msm8996/msm8996-clock.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -46,6 +46,7 @@
#define mmpll1_mm_source_val 2
#define mmpll3_mm_source_val 3
#define gpll0_mm_source_val 5
+#define hdmipll_mm_source_val 1
struct clk_freq_tbl rcg_dummy_freq = F_END;
@@ -813,6 +814,78 @@
},
};
+static struct branch_clk mdss_hdmi_ahb_clk = {
+ .cbcr_reg = (uint32_t *) MDSS_HDMI_AHB_CBCR,
+ .has_sibling = 1,
+ .c = {
+ .dbg_name = "mdss_hdmi_ahb_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
+static struct clk_freq_tbl ftbl_mdss_hdmi_clk[] = {
+ F_MM( 19200000, cxo, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk hdmi_clk_src = {
+ .cmd_reg = (uint32_t *) HDMI_CMD_RCGR,
+ .cfg_reg = (uint32_t *) HDMI_CFG_RCGR,
+ .set_rate = clock_lib2_rcg_set_rate_hid,
+ .freq_tbl = ftbl_mdss_hdmi_clk,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "hdmi_clk_src",
+ .ops = &clk_ops_rcg,
+ },
+};
+
+static struct branch_clk mdss_hdmi_clk = {
+ .cbcr_reg = (uint32_t *) MDSS_HDMI_CBCR,
+ .has_sibling = 0,
+ .parent = &hdmi_clk_src.c,
+ .c = {
+ .dbg_name = "mdss_hdmi_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
+static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
+ F_MDSS( 74250000, hdmipll, 1, 0, 0),
+ F_MDSS( 25200000, hdmipll, 1, 0, 0),
+ F_MDSS( 27000000, hdmipll, 1, 0, 0),
+ F_MDSS( 27030000, hdmipll, 1, 0, 0),
+ F_MDSS( 27070000, hdmipll, 1, 0, 0),
+ F_MDSS( 65000000, hdmipll, 1, 0, 0),
+ F_MDSS(108000000, hdmipll, 1, 0, 0),
+ F_MDSS(148500000, hdmipll, 1, 0, 0),
+ F_MDSS(268500000, hdmipll, 1, 0, 0),
+ F_MDSS(297000000, hdmipll, 1, 0, 0),
+ F_MDSS(594000000, hdmipll, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk extpclk_clk_src = {
+ .cmd_reg = (uint32_t *) EXTPCLK_CMD_RCGR,
+ .cfg_reg = (uint32_t *) EXTPCLK_CFG_RCGR,
+ .set_rate = clock_lib2_rcg_set_rate_hid,
+ .freq_tbl = ftbl_mdss_extpclk_clk,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "extpclk_clk_src",
+ .ops = &clk_ops_rcg,
+ },
+};
+
+static struct branch_clk mdss_extpclk_clk = {
+ .cbcr_reg = (uint32_t *) MDSS_EXTPCLK_CBCR,
+ .has_sibling = 0,
+ .parent = &extpclk_clk_src.c,
+ .c = {
+ .dbg_name = "mdss_extpclk_clk",
+ .ops = &clk_ops_branch,
+ },
+};
/* Clock lookup table */
static struct clk_lookup msm_msm8996_clocks[] =
@@ -863,6 +936,11 @@
gcc_blsp2_qup2_i2c_apps_clk_src.c),
CLK_LOOKUP("gcc_blsp2_qup2_i2c_apps_clk",
gcc_blsp2_qup2_i2c_apps_clk.c),
+
+ /* HDMI clocks*/
+ CLK_LOOKUP("hdmi_ahb_clk", mdss_hdmi_ahb_clk.c),
+ CLK_LOOKUP("hdmi_core_clk", mdss_hdmi_clk.c),
+ CLK_LOOKUP("hdmi_extp_clk", mdss_extpclk_clk.c),
};
void platform_clock_init(void)
diff --git a/platform/msm_shared/display.c b/platform/msm_shared/display.c
index fcf6ad3..8733afa 100644
--- a/platform/msm_shared/display.c
+++ b/platform/msm_shared/display.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -411,6 +411,11 @@
if (ret)
goto msm_display_off_out;
break;
+ case HDMI_PANEL:
+ dprintf(INFO, "Turn off HDMI PANEL.\n");
+ ret = mdss_hdmi_off(pinfo);
+ break;
+
#endif
#ifdef DISPLAY_TYPE_QPIC
case QPIC_PANEL:
diff --git a/platform/msm_shared/include/mdp4.h b/platform/msm_shared/include/mdp4.h
index ee4e4fc..e463302 100644
--- a/platform/msm_shared/include/mdp4.h
+++ b/platform/msm_shared/include/mdp4.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -122,5 +122,6 @@
int mdss_hdmi_init(void);
int mdss_hdmi_on(struct msm_panel_info *pinfo);
+int mdss_hdmi_off(struct msm_panel_info *pinfo);
int mdss_hdmi_config(struct msm_panel_info *pinfo, struct fbcon_config *fb);
#endif
diff --git a/platform/msm_shared/include/mdp5.h b/platform/msm_shared/include/mdp5.h
index 2a72772..00baac3 100644
--- a/platform/msm_shared/include/mdp5.h
+++ b/platform/msm_shared/include/mdp5.h
@@ -235,6 +235,15 @@
#define MDP_REG_PP_1_AUTOREFRESH_CONFIG REG_MDP(0x71830)
#define MDP_REG_PP_SLAVE_AUTOREFRESH_CONFIG REG_MDP(0x73030)
+/* Registers for programming the CDM hardware in bypass mode. */
+#define CDM_HDMI_PACK_OP_MODE REG_MDP(0x7A400)
+#define MDP_OUT_CTL_0 REG_MDP(0x01410)
+#define MDP_INTF_3_INTF_CONFIG REG_MDP(0x6C804)
+#define CDM_CDWN2_OUT_SIZE REG_MDP(0x7A330)
+#define CDM_CDWN2_OP_MODE REG_MDP(0x7A300)
+#define CDM_CDWN2_CLAMP_OUT REG_MDP(0x7A304)
+#define CDM_CSC_10_OP_MODE REG_MDP(0x7A200)
+
void mdp_set_revision(int rev);
int mdp_get_revision();
int mdp_dsi_video_config(struct msm_panel_info *pinfo, struct fbcon_config *fb);
@@ -256,9 +265,12 @@
int target_edp_panel_disable(void);
int target_edp_bl_ctrl(int enable);
int mdss_hdmi_init(void);
+void mdss_hdmi_display_init(uint32_t rev, void *base);
int mdss_hdmi_on(struct msm_panel_info *pinfo);
+int mdss_hdmi_off(struct msm_panel_info *pinfo);
int mdss_hdmi_config(struct msm_panel_info *pinfo, struct fbcon_config *fb);
void mdss_hdmi_get_vic(char *buf);
+void hdmi_phy_init(void);
int msm_display_off();
void display_shutdown(void);
diff --git a/platform/msm_shared/include/mdss_hdmi.h b/platform/msm_shared/include/mdss_hdmi.h
index 6786a85..e38f0d7 100644
--- a/platform/msm_shared/include/mdss_hdmi.h
+++ b/platform/msm_shared/include/mdss_hdmi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,7 +31,7 @@
#define _PLATFORM_MSM_SHARED_MDSS_HDMI_H_
void hdmi_phy_reset(void);
-uint32_t hdmi_pll_config(uint32_t tmds_clk_rate);
+int hdmi_pll_config(uint32_t tmds_clk_rate);
int hdmi_vco_enable(void);
int hdmi_vco_disable(void);
void mdss_hdmi_display_init(uint32_t rev, void *base);
diff --git a/platform/msm_shared/mdp5.c b/platform/msm_shared/mdp5.c
index 1bcb69f..a5db243 100755
--- a/platform/msm_shared/mdp5.c
+++ b/platform/msm_shared/mdp5.c
@@ -547,9 +547,8 @@
writel(BIT(16) | (0x3 << 20), REG_MDP(ppb_offset + 0x4)); /* MMSS_MDP_PPB0_CONFIG */
}
- if (pinfo->compression_mode == COMPRESSION_FBC)
- if (!pinfo->fbc.enabled || !pinfo->fbc.comp_ratio)
- pinfo->fbc.comp_ratio = 1;
+ if (!pinfo->fbc.enabled || !pinfo->fbc.comp_ratio)
+ pinfo->fbc.comp_ratio = 1;
itp.xres = (adjust_xres / pinfo->fbc.comp_ratio);
itp.yres = pinfo->yres;
@@ -1090,10 +1089,10 @@
int mdss_hdmi_config(struct msm_panel_info *pinfo, struct fbcon_config *fb)
{
- uint32_t left_pipe, right_pipe;
- dprintf(SPEW, "ENTER: %s\n", __func__);
+ uint32_t left_pipe, right_pipe, out_size;
mdss_intf_tg_setup(pinfo, MDP_INTF_3_BASE + mdss_mdp_intf_offset());
+ mdss_intf_fetch_start_config(pinfo, MDP_INTF_3_BASE + mdss_mdp_intf_offset());
pinfo->pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
mdp_select_pipe_type(pinfo, &left_pipe, &right_pipe);
@@ -1116,10 +1115,23 @@
writel(0x40, MDP_CTL_0_BASE + CTL_TOP);
writel(BIT(24) | BIT(25), MDP_DISP_INTF_SEL);
- writel(0x1111, MDP_VIDEO_INTF_UNDERFLOW_CTL);
+ writel(0x11111, MDP_VIDEO_INTF_UNDERFLOW_CTL);
writel(0x01, MDP_UPPER_NEW_ROI_PRIOR_RO_START);
writel(0x01, MDP_LOWER_NEW_ROI_PRIOR_TO_START);
+ /**
+ * Program the CDM hardware block in HDMI bypass mode, and enable
+ * the HDMI packer.
+ */
+ writel(0x01, CDM_HDMI_PACK_OP_MODE);
+ writel(0x00, MDP_OUT_CTL_0);
+ writel(0x00, MDP_INTF_3_INTF_CONFIG);
+ out_size = (pinfo->xres & 0xFFFF) | ((pinfo->yres & 0xFFFF) << 16);
+ writel(out_size, CDM_CDWN2_OUT_SIZE);
+ writel(0x80, CDM_CDWN2_OP_MODE);
+ writel(0x3FF0000, CDM_CDWN2_CLAMP_OUT);
+ writel(0x0, CDM_CSC_10_OP_MODE);
+
return 0;
}
@@ -1358,6 +1370,21 @@
return NO_ERROR;
}
+int mdss_hdmi_off(struct msm_panel_info *pinfo)
+{
+ if(!target_cont_splash_screen())
+ {
+ writel(0x00000000, MDP_INTF_3_TIMING_ENGINE_EN + mdss_mdp_intf_offset());
+ mdelay(60);
+ /* Underrun(Interface 0/1/2/3) VSYNC Interrupt Enable */
+ writel(0xFF777713, MDP_INTR_CLEAR);
+ }
+
+ writel(0x00000000, MDP_INTR_EN);
+
+ return NO_ERROR;
+}
+
int mdp_edp_off(void)
{
if (!target_cont_splash_screen()) {
diff --git a/platform/msm_shared/mdss_hdmi.c b/platform/msm_shared/mdss_hdmi.c
index 0741308..00bf5f1 100644
--- a/platform/msm_shared/mdss_hdmi.c
+++ b/platform/msm_shared/mdss_hdmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -99,8 +99,14 @@
HDMI_MSM_AUDIO_ARCS(297000, {
{3072, 222750}, {4704, 247500}, {5120, 247500}, {9408, 247500},
{10240, 247500}, {18816, 247500}, {20480, 247500} }),
+ /* 594.000MHz */
+ HDMI_MSM_AUDIO_ARCS(594000, {{3072, 445500}, {9408, 990000}, {6144, 594000},
+ {18816, 990000}, {12288, 594000}, {37632, 990000},
+ {24576, 594000} } ),
};
+extern int msm_display_init(struct msm_fb_panel_data *pdata);
+
/* AVI INFOFRAME DATA */
#define NUM_MODES_AVI 20
#define AVI_MAX_DATA_BYTES 13
@@ -135,6 +141,7 @@
*/
#define AVI_IFRAME_TYPE 0x2
#define AVI_IFRAME_VERSION 0x2
+#define AVI_IFRAME_LINE_NUMBER 1
#define LEFT_SHIFT_BYTE(x) ((x) << 8)
#define LEFT_SHIFT_WORD(x) ((x) << 16)
#define LEFT_SHIFT_24BITS(x) ((x) << 24)
@@ -142,7 +149,8 @@
#define MAX_AUDIO_DATA_BLOCK_SIZE 0x80
#define DBC_START_OFFSET 4
#define VIC_INDEX 3
-#define HDMI_VIC_STR_MAX 3
+#define HDMI_VIC_STR_MAX 4
+#define MAX_EDID_BLOCK_SIZE 0x80
enum edid_data_block_type {
RESERVED_DATA_BLOCK1 = 0,
@@ -160,7 +168,35 @@
#define HDMI_VFRMT_640x480p60_4_3 1
#define HDMI_VFRMT_1280x720p60_16_9 4
#define HDMI_VFRMT_1920x1080p60_16_9 16
-#define HDMI_VFRMT_MAX 3
+#define HDMI_VFRMT_4096x2160p24_256_135 98
+#define HDMI_VFRMT_4096x2160p25_256_135 99
+#define HDMI_VFRMT_4096x2160p30_256_135 100
+#define HDMI_VFRMT_3840x2160p24_64_27 103
+#define HDMI_VFRMT_3840x2160p25_64_27 104
+#define HDMI_VFRMT_3840x2160p30_64_27 105
+#define HDMI_EVFRMT_4096x2160p24_16_9 131
+#define HDMI_VFRMT_4096x2160p60_256_135 102
+#define HDMI_VFRMT_COUNT 11
+#define HDMI_VFRMT_END 127
+#define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \
+ (!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
+#define MSM_MDP_MAX_PIPE_WIDTH 2560
+/* TX major version that supports scrambling */
+#define HDMI_TX_SCRAMBLER_MIN_TX_VERSION 0x04
+#define HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ 340000
+#define HDMI_TX_SCRAMBLER_TIMEOUT_MSEC 200
+/* default hsyncs for 4k@60 for 200ms */
+#define HDMI_DEFAULT_TIMEOUT_HSYNC 28571
+#define HDMI_SCDC_TMDS_CONFIG 0x20
+#define HDMI_SCDC_CONFIG_0 0x30
+#define HDMI_SCDC_UNKNOWN_REGISTER "Unknown register"
+#define HDMI_SEC_TO_MS 1000
+#define HDMI_MS_TO_US 1000
+#define HDMI_SEC_TO_US (HDMI_SEC_TO_MS * HDMI_MS_TO_US)
+#define HDMI_KHZ_TO_HZ 1000
+#define HDMI_DDC_TRANSACTION_DELAY_US 468
+static uint8_t mdss_hdmi_video_formats[HDMI_VFRMT_COUNT];
+static uint8_t mdss_hdmi_mode_count;
#define DEFAULT_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9
static uint8_t mdss_hdmi_video_fmt = HDMI_VFRMT_UNKNOWN;
@@ -169,17 +205,98 @@
static uint8_t it_scan_info;
static uint8_t ce_scan_info;
-static uint8_t mdss_hdmi_edid_buf[0x80];
+static uint8_t mdss_hdmi_edid_buf[MAX_EDID_BLOCK_SIZE];
+
+enum scdc_access_type {
+ SCDC_SCRAMBLING_STATUS,
+ SCDC_SCRAMBLING_ENABLE,
+ SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE,
+ SCDC_CLOCK_DET_STATUS,
+ SCDC_CH0_LOCK_STATUS,
+ SCDC_CH1_LOCK_STATUS,
+ SCDC_CH2_LOCK_STATUS,
+ SCDC_CH0_ERROR_COUNT,
+ SCDC_CH1_ERROR_COUNT,
+ SCDC_CH2_ERROR_COUNT,
+ SCDC_READ_ENABLE,
+ SCDC_MAX,
+};
+
+enum ddc_timer_type {
+ DDC_TIMER_HDCP2P2_RD_MSG,
+ DDC_TIMER_SCRAMBLER_STATUS,
+ DDC_TIMER_UPDATE_FLAGS,
+ DDC_TIMER_STATUS_FLAGS,
+ DDC_TIMER_CED,
+ DDC_TIMER_MAX,
+};
+
+struct hdmi_tx_ddc_data {
+ char *what;
+ uint8_t *data_buf;
+ uint32_t data_len;
+ uint32_t dev_addr;
+ uint32_t offset;
+ uint32_t request_len;
+ uint32_t retry_align;
+ uint32_t hard_timeout;
+ uint32_t timeout_left;
+ int retry;
+};
+
+enum trigger_mode {
+ TRIGGER_WRITE,
+ TRIGGER_READ
+};
enum aspect_ratio {
HDMI_RES_AR_INVALID,
HDMI_RES_AR_4_3,
HDMI_RES_AR_5_4,
HDMI_RES_AR_16_9,
+ HDMI_RES_AR_64_27,
HDMI_RES_AR_16_10,
+ HDMI_RES_AR_256_135,
HDMI_RES_AR_MAX,
};
+enum hdmi_quantization_range {
+ HDMI_QUANTIZATION_DEFAULT,
+ HDMI_QUANTIZATION_LIMITED_RANGE,
+ HDMI_QUANTIZATION_FULL_RANGE
+};
+
+enum hdmi_scaling_info {
+ HDMI_SCALING_NONE,
+ HDMI_SCALING_HORZ,
+ HDMI_SCALING_VERT,
+ HDMI_SCALING_HORZ_VERT,
+};
+
+struct hdmi_avi_iframe_bar_info {
+ bool vert_binfo_present;
+ bool horz_binfo_present;
+ uint32_t end_of_top_bar;
+ uint32_t start_of_bottom_bar;
+ uint32_t end_of_left_bar;
+ uint32_t start_of_right_bar;
+};
+
+struct hdmi_avi_infoframe_config {
+ uint32_t pixel_format;
+ uint32_t scan_info;
+ bool act_fmt_info_present;
+ uint32_t colorimetry_info;
+ uint32_t ext_colorimetry_info;
+ uint32_t rgb_quantization_range;
+ uint32_t yuv_quantization_range;
+ uint32_t scaling_info;
+ bool is_it_content;
+ uint8_t content_type;
+ uint8_t pixel_rpt_factor;
+ struct hdmi_avi_iframe_bar_info bar_info;
+};
+
struct mdss_hdmi_timing_info {
uint32_t video_format;
uint32_t active_h;
@@ -213,6 +330,46 @@
{HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, false, \
1080, 4, 5, 36, false, 148500, 60000, false, true, HDMI_RES_AR_16_9}
+#define HDMI_VFRMT_4096x2160p24_256_135_TIMING \
+ {HDMI_VFRMT_4096x2160p24_256_135, 4096, 1020, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 24000, false, true, \
+ HDMI_RES_AR_256_135}
+
+#define HDMI_VFRMT_4096x2160p25_256_135_TIMING \
+ {HDMI_VFRMT_4096x2160p25_256_135, 4096, 968, 88, 128, false, \
+ 2160, 8, 10, 72, false, 297000, 25000, false, true, \
+ HDMI_RES_AR_256_135}
+
+#define HDMI_VFRMT_4096x2160p30_256_135_TIMING \
+ {HDMI_VFRMT_4096x2160p30_256_135, 4096, 88, 88, 128, false, \
+ 2160, 8, 10, 72, false, 297000, 30000, false, true, \
+ HDMI_RES_AR_256_135}
+
+#define HDMI_EVFRMT_4096x2160p24_16_9_TIMING \
+ {HDMI_EVFRMT_4096x2160p24_16_9, 4096, 1020, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 24000, false, true, \
+ HDMI_RES_AR_16_9}
+
+#define HDMI_VFRMT_3840x2160p24_64_27_TIMING \
+ {HDMI_VFRMT_3840x2160p24_64_27, 3840, 1276, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 24000, false, true, \
+ HDMI_RES_AR_64_27}
+
+#define HDMI_VFRMT_3840x2160p25_64_27_TIMING \
+ {HDMI_VFRMT_3840x2160p25_64_27, 3840, 1056, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 25000, false, true, \
+ HDMI_RES_AR_64_27}
+
+#define HDMI_VFRMT_3840x2160p30_64_27_TIMING \
+ {HDMI_VFRMT_3840x2160p30_64_27, 3840, 176, 88, 296, false, \
+ 2160, 8, 10, 72, false, 297000, 30000, false, true, \
+ HDMI_RES_AR_64_27}
+
+#define HDMI_VFRMT_4096x2160p60_256_135_TIMING \
+ {HDMI_VFRMT_4096x2160p60_256_135, 4096, 88, 88, 128, false, \
+ 2160, 8, 10, 72, false, 594000, 60000, false, true, \
+ HDMI_RES_AR_256_135}
+
#define MSM_HDMI_MODES_GET_DETAILS(mode, MODE) do { \
struct mdss_hdmi_timing_info info = MODE##_TIMING; \
*mode = info; \
@@ -236,6 +393,38 @@
MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_1920x1080p60_16_9);
break;
+ case HDMI_VFRMT_4096x2160p24_256_135:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p24_256_135);
+ break;
+
+ case HDMI_VFRMT_4096x2160p25_256_135:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p25_256_135);
+ break;
+
+ case HDMI_VFRMT_4096x2160p30_256_135:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p30_256_135);
+ break;
+
+ case HDMI_EVFRMT_4096x2160p24_16_9:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_EVFRMT_4096x2160p24_16_9);
+ break;
+
+ case HDMI_VFRMT_3840x2160p24_64_27:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p24_64_27);
+ break;
+
+ case HDMI_VFRMT_3840x2160p25_64_27:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p25_64_27);
+ break;
+
+ case HDMI_VFRMT_3840x2160p30_64_27:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p30_64_27);
+ break;
+
+ case HDMI_VFRMT_4096x2160p60_256_135:
+ MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p60_256_135);
+ break;
+
default:
ret = ERROR;
}
@@ -243,35 +432,6 @@
return ret;
}
-
-/*
- * 13 Bytes of AVI infoframe data wrt each resolution
- * Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0
- * Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0
- * Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0
- * Data Byte 04: 0 VIC6 VIC5 VIC4 VIC3 VIC2 VIC1 VIC0
- * Data Byte 05: 0 0 0 0 PR3 PR2 PR1 PR0
- * Data Byte 06: LSB Line No of End of Top Bar
- * Data Byte 07: MSB Line No of End of Top Bar
- * Data Byte 08: LSB Line No of Start of Bottom Bar
- * Data Byte 09: MSB Line No of Start of Bottom Bar
- * Data Byte 10: LSB Pixel Number of End of Left Bar
- * Data Byte 11: MSB Pixel Number of End of Left Bar
- * Data Byte 12: LSB Pixel Number of Start of Right Bar
- * Data Byte 13: MSB Pixel Number of Start of Right Bar
- */
-static uint8_t mdss_hdmi_avi_info_db[HDMI_VFRMT_MAX][AVI_MAX_DATA_BYTES] = {
- /* 480p */
- {0x10, 0x18, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0xE1, 0x01, 0x00, 0x00, 0x81, 0x02},
- /* 720p */
- {0x10, 0x28, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0xD1, 0x02, 0x00, 0x00, 0x01, 0x05},
- /* 1080p */
- {0x10, 0x28, 0x00, 0x10, 0x00, 0x00, 0x00,
- 0x39, 0x04, 0x00, 0x00, 0x81, 0x07},
-};
-
static void mdss_hdmi_audio_acr_setup(uint32_t sample_rate)
{
/* Read first before writing */
@@ -460,7 +620,8 @@
* edid buffer 1, byte 2 being 0 means no non-DTD/DATA block collection
* present and no DTD data present.
*/
- if ((end_dbc_offset == 0) || (end_dbc_offset == 4))
+ if ((end_dbc_offset == 0) || (end_dbc_offset == 4) ||
+ (end_dbc_offset >= MAX_EDID_BLOCK_SIZE))
return NULL;
while (offset < end_dbc_offset) {
@@ -654,13 +815,14 @@
static void mdss_hdmi_set_mode(bool on)
{
uint32_t val = 0;
-
if (on) {
/* tx on */
- val = 0x1;
+ val |= BIT(0);
+ /* hdcp legacy mode*/
+ val |= BIT(31);
if (!mdss_hdmi_is_dvi_mode())
- val |= 0x2;
+ val |= BIT(1);
}
writel(val, HDMI_CTRL);
@@ -751,19 +913,72 @@
return NO_ERROR;
}
-static void mdss_hdmi_parse_res(void)
+static void mdss_hdmi_add_video_format(uint32_t video_format)
+{
+ if (mdss_hdmi_mode_count >= HDMI_VFRMT_COUNT) {
+ dprintf(SPEW, "%s: unsupported format (%d)", __func__,
+ video_format);
+ return;
+ }
+
+ dprintf(SPEW, "%s: vic=%d\n", __func__, video_format);
+ mdss_hdmi_video_formats[mdss_hdmi_mode_count] = video_format;
+ mdss_hdmi_mode_count++;
+}
+
+static void mdss_hdmi_get_extended_video_formats()
+{
+ uint8_t db_len, offset, i;
+ uint8_t hdmi_vic_len;
+ uint32_t video_format;
+ const uint8_t *vsd = NULL;
+
+ vsd = hdmi_edid_find_block(DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &db_len);
+
+ if (!vsd || db_len == 0) {
+ dprintf(SPEW, "%s: No/Invalid Vendor Specific Data Block\n",
+ __func__);
+ return;
+ }
+
+ /* check if HDMI_Video_present flag is set or not */
+ if (!(vsd[8] & BIT(5))) {
+ dprintf(SPEW, "%s: extended vfmts not supported by the sink.\n",
+ __func__);
+ return;
+ }
+
+ offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
+
+ hdmi_vic_len = vsd[offset + 1] >> 5;
+ if (hdmi_vic_len) {
+ for (i = 0; i < hdmi_vic_len; i++) {
+ struct mdss_hdmi_timing_info tinfo = {0};
+ uint32_t ret = 0;
+
+ video_format = HDMI_VFRMT_END + vsd[offset + 2 + i];
+ ret = mdss_hdmi_get_timing_info(&tinfo, video_format);
+
+ if (ret || !tinfo.supported)
+ continue;
+
+ mdss_hdmi_add_video_format(video_format);
+ }
+ }
+}
+
+static void mdss_hdmi_get_cea_video_formats()
{
uint8_t len, i;
uint32_t video_format;
- struct mdss_hdmi_timing_info tinfo_fmt = {0};
uint8_t *svd = hdmi_edid_find_block(DBC_START_OFFSET,
VIDEO_DATA_BLOCK, &len);
- mdss_hdmi_video_fmt = HDMI_VFRMT_UNKNOWN;
-
- if (!svd) {
- mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+ if (!svd || len == 0) {
+ dprintf(SPEW, "%s: No/Invalid Video Data Block\n",
+ __func__);
return;
}
@@ -783,20 +998,55 @@
if (ret || !tinfo.supported)
continue;
- if (!tinfo_fmt.video_format) {
- memcpy(&tinfo_fmt, &tinfo, sizeof(tinfo));
- mdss_hdmi_video_fmt = video_format;
+ mdss_hdmi_add_video_format(video_format);
+ }
+}
+
+static void mdss_hdmi_parse_res(void)
+{
+ int index, ret;
+ uint8_t current_video_format;
+ struct mdss_hdmi_timing_info current_timing_info = {0};
+
+ mdss_hdmi_mode_count = 0;
+ mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+ current_video_format = mdss_hdmi_video_fmt;
+ mdss_hdmi_get_timing_info(¤t_timing_info, mdss_hdmi_video_fmt);
+
+ mdss_hdmi_get_extended_video_formats();
+ mdss_hdmi_get_cea_video_formats();
+
+ for (index = 0; index < mdss_hdmi_mode_count; index++) {
+ struct mdss_hdmi_timing_info new_timing_info = {0};
+
+ if (!mdss_hdmi_video_formats[index])
+ break;
+
+ ret = mdss_hdmi_get_timing_info(&new_timing_info, mdss_hdmi_video_formats[index]);
+ if (ret || !new_timing_info.supported)
continue;
+
+ if (new_timing_info.active_h > current_timing_info.active_h) {
+ current_video_format = mdss_hdmi_video_formats[index];
+ } else if (new_timing_info.active_h ==
+ current_timing_info.active_h) {
+ if (new_timing_info.active_v >
+ current_timing_info.active_v) {
+ current_video_format = mdss_hdmi_video_formats[index];
+ } else if (new_timing_info.active_v ==
+ current_timing_info.active_v) {
+ if (new_timing_info.refresh_rate >
+ current_timing_info.refresh_rate) {
+ current_video_format = mdss_hdmi_video_formats[index];
+ }
+ }
}
- if (tinfo.active_v > tinfo_fmt.active_v) {
- memcpy(&tinfo_fmt, &tinfo, sizeof(tinfo));
- mdss_hdmi_video_fmt = video_format;
- }
+ mdss_hdmi_get_timing_info(¤t_timing_info, current_video_format);
}
- if (mdss_hdmi_video_fmt == HDMI_VFRMT_UNKNOWN)
- mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+ if (mdss_hdmi_video_fmt != current_video_format)
+ mdss_hdmi_video_fmt = current_video_format;
}
void mdss_hdmi_get_vic(char *buf)
@@ -835,7 +1085,15 @@
pinfo->lcdc.hsync_skew = 0;
pinfo->lcdc.xres_pad = 0;
pinfo->lcdc.yres_pad = 0;
- pinfo->lcdc.dual_pipe = 0;
+
+ /* Add dual pipe configuration for resultions greater than
+ * MSM_MDP_MAX_PIPE_WIDTH.
+ */
+ if (pinfo->xres > MSM_MDP_MAX_PIPE_WIDTH) {
+ pinfo->lcdc.dual_pipe = 1;
+ pinfo->lm_split[0] = pinfo->xres / 2;
+ pinfo->lm_split[1] = pinfo->xres - pinfo->lm_split[0];
+ }
}
static uint8_t mdss_hdmi_cable_status(void)
@@ -1067,58 +1325,716 @@
uint32_t sum;
uint32_t reg_val;
uint8_t checksum;
- uint8_t scaninfo;
- uint32_t i, index;
+ uint32_t i;
+ struct hdmi_avi_infoframe_config avi_info = {0};
+ struct mdss_hdmi_timing_info tinfo = {0};
+ uint8_t avi_iframe[AVI_MAX_DATA_BYTES] = {0};
- scaninfo = mdss_hdmi_get_scan_info();
+ mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
+
+ /* Setup AVI Infoframe content */
+ avi_info.scan_info = mdss_hdmi_get_scan_info();
+ avi_info.bar_info.end_of_top_bar = 0x0;
+ avi_info.bar_info.start_of_bottom_bar = tinfo.active_v + 1;
+ avi_info.bar_info.end_of_left_bar = 0;
+ avi_info.bar_info.start_of_right_bar = tinfo.active_h + 1;
+ avi_info.act_fmt_info_present = true;
+ avi_info.rgb_quantization_range = HDMI_QUANTIZATION_DEFAULT;
+ avi_info.yuv_quantization_range = HDMI_QUANTIZATION_DEFAULT;
+ avi_info.scaling_info = HDMI_SCALING_NONE;
+ avi_info.colorimetry_info = 0;
+ avi_info.ext_colorimetry_info = 0;
+ avi_info.pixel_rpt_factor = 0;
+
+ /*
+ * BYTE - 1:
+ * 0:1 - Scan Information
+ * 2:3 - Bar Info
+ * 4 - Active Format Info present
+ * 5:6 - Pixel format type;
+ * 7 - Reserved;
+ */
+ avi_iframe[0] = (avi_info.scan_info & 0x3) |
+ (avi_info.bar_info.vert_binfo_present ? BIT(2) : 0) |
+ (avi_info.bar_info.horz_binfo_present ? BIT(3) : 0) |
+ (avi_info.act_fmt_info_present ? BIT(4) : 0);
+
+ /*
+ * BYTE - 2:
+ * 0:3 - Active format info
+ * 4:5 - Picture aspect ratio
+ * 6:7 - Colorimetry info
+ */
+ avi_iframe[1] |= 0x08;
+ if (tinfo.ar == HDMI_RES_AR_4_3)
+ avi_iframe[1] |= (0x1 << 4);
+ else if (tinfo.ar == HDMI_RES_AR_16_9)
+ avi_iframe[1] |= (0x2 << 4);
+
+ avi_iframe[1] |= (avi_info.colorimetry_info & 0x3) << 6;
+
+ /*
+ * BYTE - 3:
+ * 0:1 - Scaling info
+ * 2:3 - Quantization range
+ * 4:6 - Extended Colorimetry
+ * 7 - IT content
+ */
+ avi_iframe[2] |= (avi_info.scaling_info & 0x3) |
+ ((avi_info.rgb_quantization_range & 0x3) << 2) |
+ ((avi_info.ext_colorimetry_info & 0x7) << 4) |
+ ((avi_info.is_it_content ? 0x1 : 0x0) << 7);
+ /*
+ * BYTE - 4:
+ * 0:7 - VIC
+ */
+ if (tinfo.video_format < HDMI_VFRMT_END)
+ avi_iframe[3] = tinfo.video_format;
+
+ /*
+ * BYTE - 5:
+ * 0:3 - Pixel Repeat factor
+ * 4:5 - Content type
+ * 6:7 - YCC Quantization range
+ */
+ avi_iframe[4] = (avi_info.pixel_rpt_factor & 0xF) |
+ ((avi_info.content_type & 0x3) << 4) |
+ ((avi_info.yuv_quantization_range & 0x3) << 6);
+
+ /* BYTE - 6,7: End of top bar */
+ avi_iframe[5] = avi_info.bar_info.end_of_top_bar & 0xFF;
+ avi_iframe[6] = ((avi_info.bar_info.end_of_top_bar & 0xFF00) >> 8);
+
+ /* BYTE - 8,9: Start of bottom bar */
+ avi_iframe[7] = avi_info.bar_info.start_of_bottom_bar & 0xFF;
+ avi_iframe[8] = ((avi_info.bar_info.start_of_bottom_bar & 0xFF00) >> 8);
+
+ /* BYTE - 10,11: Endof of left bar */
+ avi_iframe[9] = avi_info.bar_info.end_of_left_bar & 0xFF;
+ avi_iframe[10] = ((avi_info.bar_info.end_of_left_bar & 0xFF00) >> 8);
+
+ /* BYTE - 12,13: Start of right bar */
+ avi_iframe[11] = avi_info.bar_info.start_of_right_bar & 0xFF;
+ avi_iframe[12] = ((avi_info.bar_info.start_of_right_bar & 0xFF00) >> 8);
sum = IFRAME_PACKET_OFFSET + AVI_IFRAME_TYPE +
AVI_IFRAME_VERSION + AVI_MAX_DATA_BYTES;
- for (index = 0; index < HDMI_VFRMT_MAX; index++) {
- if (mdss_hdmi_avi_info_db[index][VIC_INDEX] == mdss_hdmi_video_fmt)
- break;
- }
-
- if (index == VIC_INDEX)
- return;
-
- mdss_hdmi_avi_info_db[index][DATA_BYTE_1] |=
- scaninfo & (BIT(1) | BIT(0));
-
for (i = 0; i < AVI_MAX_DATA_BYTES; i++)
- sum += mdss_hdmi_avi_info_db[index][i];
-
+ sum += avi_iframe[i];
sum &= 0xFF;
sum = 256 - sum;
checksum = (uint8_t) sum;
reg_val = checksum |
- LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_1]) |
- LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_2]) |
- LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_3]);
+ LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_1]) |
+ LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_2]) |
+ LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_3]);
writel(reg_val, HDMI_AVI_INFO0);
- reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_4] |
- LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_5]) |
- LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_6]) |
- LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_7]);
+ reg_val = avi_iframe[DATA_BYTE_4] |
+ LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_5]) |
+ LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_6]) |
+ LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_7]);
writel(reg_val, HDMI_AVI_INFO1);
- reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_8] |
- LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_9]) |
- LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_10]) |
- LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_11]);
+ reg_val = avi_iframe[DATA_BYTE_8] |
+ LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_9]) |
+ LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_10]) |
+ LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_11]);
writel(reg_val, HDMI_AVI_INFO2);
- reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_12] |
- LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_13]) |
+ reg_val = avi_iframe[DATA_BYTE_12] |
+ LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_13]) |
LEFT_SHIFT_24BITS(AVI_IFRAME_VERSION);
writel(reg_val, HDMI_AVI_INFO3);
/* AVI InfFrame enable (every frame) */
writel(readl(HDMI_INFOFRAME_CTRL0) | BIT(1) | BIT(0),
- HDMI_INFOFRAME_CTRL0);
+ HDMI_INFOFRAME_CTRL0);
+
+ reg_val = readl(HDMI_INFOFRAME_CTRL1);
+ reg_val &= ~0x3F;
+ reg_val |= AVI_IFRAME_LINE_NUMBER;
+ writel(reg_val, HDMI_INFOFRAME_CTRL1);
+}
+
+static int mdss_hdmi_ddc_check_status(char *what)
+{
+ uint32_t reg_val;
+ int rc = 0;
+
+ /* Read DDC status */
+ reg_val = readl(HDMI_DDC_SW_STATUS);
+ reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+ /* Check if any NACK occurred */
+ if (reg_val) {
+ dprintf(SPEW, "%s: %s: NACK: HDMI_DDC_SW_STATUS 0x%x\n",
+ __func__, what, reg_val);
+
+ /* SW_STATUS_RESET, SOFT_RESET */
+ reg_val = BIT(3) | BIT(1);
+
+ writel(reg_val, HDMI_DDC_CTRL);
+
+ rc = ERROR;
+ }
+
+ return rc;
+}
+
+static void mdss_hdmi_ddc_trigger(struct hdmi_tx_ddc_data *ddc_data,
+ enum trigger_mode mode, bool seg)
+{
+ uint32_t const seg_addr = 0x60, seg_num = 0x01;
+ uint32_t ddc_ctrl_reg_val;
+
+ ddc_data->dev_addr &= 0xFE;
+
+ if (mode == TRIGGER_READ && seg) {
+ writel(BIT(31) | (seg_addr << 8), HDMI_DDC_DATA);
+ writel(seg_num << 8, HDMI_DDC_DATA);
+ }
+
+ /* handle portion #1 */
+ writel(BIT(31) | (ddc_data->dev_addr << 8), HDMI_DDC_DATA);
+
+ /* handle portion #2 */
+ writel(ddc_data->offset << 8, HDMI_DDC_DATA);
+
+ if (mode == TRIGGER_READ) {
+ /* handle portion #3 */
+ writel((ddc_data->dev_addr | BIT(0)) << 8, HDMI_DDC_DATA);
+
+ /* HDMI_I2C_TRANSACTION0 */
+ writel(BIT(12) | BIT(16), HDMI_DDC_TRANS0);
+
+ /* Write to HDMI_I2C_TRANSACTION1 */
+ if (seg) {
+ writel(BIT(12) | BIT(16), HDMI_DDC_TRANS1);
+ writel(BIT(0) | BIT(12) | BIT(13) |
+ (ddc_data->request_len << 16), HDMI_DDC_TRANS2);
+
+ ddc_ctrl_reg_val = BIT(0) | BIT(21);
+ } else {
+ writel(BIT(0) | BIT(12) | BIT(13) |
+ (ddc_data->request_len << 16), HDMI_DDC_TRANS1);
+
+ ddc_ctrl_reg_val = BIT(0) | BIT(20);
+ }
+ } else {
+ uint32_t ndx;
+
+ /* write buffer */
+ for (ndx = 0; ndx < ddc_data->data_len; ++ndx)
+ writel(((uint32_t)ddc_data->data_buf[ndx]) << 8,
+ HDMI_DDC_DATA);
+
+ writel((ddc_data->data_len + 1) << 16 | BIT(12) | BIT(13),
+ HDMI_DDC_TRANS0);
+
+ ddc_ctrl_reg_val = BIT(0);
+ }
+
+ /* Trigger the I2C transfer */
+ writel(ddc_ctrl_reg_val, HDMI_DDC_CTRL);
+}
+
+static int mdss_hdmi_ddc_clear_irq(char *what)
+{
+ uint32_t ddc_int_ctrl, ddc_status, in_use, timeout;
+ uint32_t sw_done_mask = BIT(2);
+ uint32_t sw_done_ack = BIT(1);
+ uint32_t in_use_by_sw = BIT(0);
+ uint32_t in_use_by_hw = BIT(1);
+
+ /* clear and enable interrutps */
+ ddc_int_ctrl = sw_done_mask | sw_done_ack;
+
+ writel(ddc_int_ctrl, HDMI_DDC_INT_CTRL);
+
+ /* wait until DDC HW is free */
+ timeout = 100;
+ do {
+ ddc_status = readl(HDMI_DDC_HW_STATUS);
+ in_use = ddc_status & (in_use_by_sw | in_use_by_hw);
+ if (in_use) {
+ dprintf(INFO, "%s: ddc is in use by %s, timeout(%d)\n",
+ __func__,
+ ddc_status & in_use_by_sw ? "sw" : "hw",
+ timeout);
+ udelay(100);
+ }
+ } while (in_use && --timeout);
+
+ if (!timeout) {
+ dprintf(CRITICAL, "%s: %s: timed out\n", __func__, what);
+ return ERROR;
+ }
+
+ return 0;
+}
+
+static int mdss_hdmi_ddc_read_retry(struct hdmi_tx_ddc_data *ddc_data)
+{
+ uint32_t reg_val, ndx;
+ int status, rc;
+
+ if (!ddc_data) {
+ dprintf(CRITICAL, "%s: invalid input\n", __func__);
+ return ERROR;
+ }
+
+ if (!ddc_data->data_buf) {
+ status = ERROR;
+ dprintf(CRITICAL, "%s: %s: invalid buf\n",
+ __func__, ddc_data->what);
+ goto error;
+ }
+
+ if (ddc_data->retry < 0) {
+ dprintf(CRITICAL, "%s: invalid no. of retries %d\n",
+ __func__, ddc_data->retry);
+ status = ERROR;
+ goto error;
+ }
+
+ do {
+ status = mdss_hdmi_ddc_clear_irq(ddc_data->what);
+ if (status)
+ continue;
+
+ mdss_hdmi_ddc_trigger(ddc_data, TRIGGER_READ, false);
+
+ dprintf(SPEW, "%s: ddc read done\n", __func__);
+
+ rc = mdss_hdmi_ddc_check_status(ddc_data->what);
+
+ if (!status)
+ status = rc;
+
+ udelay(HDMI_DDC_TRANSACTION_DELAY_US);
+ } while (status && ddc_data->retry--);
+
+ if (status)
+ goto error;
+
+ /* Write data to DDC buffer */
+ writel(BIT(0) | (3 << 16) | BIT(31), HDMI_DDC_DATA);
+
+ /* Discard first byte */
+ readl(HDMI_DDC_DATA);
+ for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
+ reg_val = readl(HDMI_DDC_DATA);
+ ddc_data->data_buf[ndx] = (uint8_t)((reg_val & 0x0000FF00) >> 8);
+ }
+
+ dprintf(SPEW, "%s: %s: success\n", __func__, ddc_data->what);
+error:
+ return status;
+}
+
+static int mdss_hdmi_ddc_read(struct hdmi_tx_ddc_data *ddc_data)
+{
+ int rc = 0;
+ int retry;
+
+ if (!ddc_data) {
+ dprintf(CRITICAL, "%s: invalid ddc data\n", __func__);
+ return ERROR;
+ }
+
+ retry = ddc_data->retry;
+
+ rc = mdss_hdmi_ddc_read_retry(ddc_data);
+ if (!rc)
+ return rc;
+
+ if (ddc_data->retry_align) {
+ ddc_data->retry = retry;
+
+ ddc_data->request_len = 32 * ((ddc_data->data_len + 31) / 32);
+ rc = mdss_hdmi_ddc_read_retry(ddc_data);
+ }
+
+ return rc;
+}
+
+static int mdss_hdmi_ddc_write(struct hdmi_tx_ddc_data *ddc_data)
+{
+ int status, rc;
+
+ if (!ddc_data->data_buf) {
+ status = ERROR;
+ dprintf(CRITICAL, "%s: %s: invalid buf\n",
+ __func__, ddc_data->what);
+ goto error;
+ }
+
+ if (ddc_data->retry < 0) {
+ dprintf(CRITICAL, "%s: invalid no. of retries %d\n",
+ __func__, ddc_data->retry);
+ status = ERROR;
+ goto error;
+ }
+
+ do {
+ status = mdss_hdmi_ddc_clear_irq(ddc_data->what);
+ if (status)
+ continue;
+
+ mdss_hdmi_ddc_trigger(ddc_data, TRIGGER_WRITE, false);
+
+ dprintf(SPEW, "%s: DDC write done\n", __func__);
+
+ rc = mdss_hdmi_ddc_check_status(ddc_data->what);
+
+ if (!status)
+ status = rc;
+
+ udelay(HDMI_DDC_TRANSACTION_DELAY_US);
+ } while (status && ddc_data->retry--);
+
+ if (status)
+ goto error;
+
+ dprintf(SPEW, "%s: %s: success\n", __func__, ddc_data->what);
+error:
+ return status;
+}
+
+static inline char *mdss_hdmi_scdc_reg2string(uint32_t type)
+{
+ switch (type) {
+ case SCDC_SCRAMBLING_STATUS:
+ return "SCDC_SCRAMBLING_STATUS";
+ case SCDC_SCRAMBLING_ENABLE:
+ return "SCDC_SCRAMBLING_ENABLE";
+ case SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE:
+ return "SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE";
+ case SCDC_CLOCK_DET_STATUS:
+ return "SCDC_CLOCK_DET_STATUS";
+ case SCDC_CH0_LOCK_STATUS:
+ return "SCDC_CH0_LOCK_STATUS";
+ case SCDC_CH1_LOCK_STATUS:
+ return "SCDC_CH1_LOCK_STATUS";
+ case SCDC_CH2_LOCK_STATUS:
+ return "SCDC_CH2_LOCK_STATUS";
+ case SCDC_CH0_ERROR_COUNT:
+ return "SCDC_CH0_ERROR_COUNT";
+ case SCDC_CH1_ERROR_COUNT:
+ return "SCDC_CH1_ERROR_COUNT";
+ case SCDC_CH2_ERROR_COUNT:
+ return "SCDC_CH2_ERROR_COUNT";
+ case SCDC_READ_ENABLE:
+ return"SCDC_READ_ENABLE";
+ default:
+ return HDMI_SCDC_UNKNOWN_REGISTER;
+ }
+}
+
+static int mdss_hdmi_scdc_write(uint32_t data_type, uint32_t val)
+{
+ struct hdmi_tx_ddc_data data = {0};
+ struct hdmi_tx_ddc_data rdata = {0};
+ int rc = 0;
+ uint8_t data_buf[2] = {0};
+ uint8_t read_val = 0;
+
+ if (data_type >= SCDC_MAX) {
+ dprintf(CRITICAL, "Unsupported data type\n");
+ return ERROR;
+ }
+
+ data.what = mdss_hdmi_scdc_reg2string(data_type);
+ data.dev_addr = 0xA8;
+ data.retry = 1;
+ data.data_buf = data_buf;
+
+ switch (data_type) {
+ case SCDC_SCRAMBLING_ENABLE:
+ case SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE:
+ rdata.what = "TMDS CONFIG";
+ rdata.dev_addr = 0xA8;
+ rdata.retry = 2;
+ rdata.data_buf = &read_val;
+ rdata.data_len = 1;
+ rdata.offset = HDMI_SCDC_TMDS_CONFIG;
+ rdata.request_len = 1;
+ rc = mdss_hdmi_ddc_read(&rdata);
+ if (rc) {
+ dprintf(CRITICAL, "scdc read failed\n");
+ return rc;
+ }
+ if (data_type == SCDC_SCRAMBLING_ENABLE) {
+ data_buf[0] = ((((uint8_t)(read_val & 0xFF)) & (~BIT(0))) |
+ ((uint8_t)(val & BIT(0))));
+ } else {
+ data_buf[0] = ((((uint8_t)(read_val & 0xFF)) & (~BIT(1))) |
+ (((uint8_t)(val & BIT(0))) << 1));
+ }
+ data.data_len = 1;
+ data.request_len = 1;
+ data.offset = HDMI_SCDC_TMDS_CONFIG;
+ break;
+ case SCDC_READ_ENABLE:
+ data.data_len = 1;
+ data.request_len = 1;
+ data.offset = HDMI_SCDC_CONFIG_0;
+ data_buf[0] = (uint8_t)(val & 0x1);
+ break;
+ default:
+ dprintf(CRITICAL, "Cannot write to read only reg (%d)\n",
+ data_type);
+ return ERROR;
+ }
+
+ rc = mdss_hdmi_ddc_write(&data);
+ if (rc) {
+ dprintf(CRITICAL, "DDC Read failed for %s\n", data.what);
+ return rc;
+ }
+
+ return 0;
+}
+
+static inline int mdss_hdmi_get_v_total(const struct mdss_hdmi_timing_info *t)
+{
+ if (t) {
+ return t->active_v + t->front_porch_v + t->pulse_width_v +
+ t->back_porch_v;
+ }
+
+ return 0;
+}
+
+static int mdss_hdmi_get_timeout_in_hysnc(struct mdss_hdmi_timing_info *timing,
+ uint32_t timeout_ms)
+{
+ uint32_t fps, v_total;
+ uint32_t time_taken_by_one_line_us, lines_needed_for_given_time;
+
+ if (!timing || !timeout_ms) {
+ dprintf(CRITICAL, "invalid input\n");
+ return ERROR;
+ }
+
+ fps = timing->refresh_rate / HDMI_KHZ_TO_HZ;
+ v_total = mdss_hdmi_get_v_total(timing);
+
+ /*
+ * pixel clock = h_total * v_total * fps
+ * 1 sec = pixel clock number of pixels are transmitted.
+ * time taken by one line (h_total) = 1 / (v_total * fps).
+ */
+ time_taken_by_one_line_us = HDMI_SEC_TO_US / (v_total * fps);
+ lines_needed_for_given_time = (timeout_ms * HDMI_MS_TO_US) /
+ time_taken_by_one_line_us;
+
+ return lines_needed_for_given_time;
+}
+
+static void mdss_hdmi_scrambler_ddc_reset()
+{
+ uint32_t reg_val;
+
+ /* clear ack and disable interrupts */
+ reg_val = BIT(14) | BIT(9) | BIT(5) | BIT(1);
+ writel(reg_val, HDMI_DDC_INT_CTRL2);
+
+ /* Reset DDC timers */
+ reg_val = BIT(0) | readl(HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+ writel(reg_val, HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+
+ reg_val = readl(HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+ reg_val &= ~BIT(0);
+ writel(reg_val, HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+}
+
+static void mdss_hdmi_scrambler_ddc_disable()
+{
+ uint32_t reg_val;
+
+ mdss_hdmi_scrambler_ddc_reset();
+
+ /* Disable HW DDC access to RxStatus register */
+ reg_val = readl(HDMI_HW_DDC_CTRL);
+ reg_val &= ~(BIT(8) | BIT(9));
+
+ writel(reg_val, HDMI_HW_DDC_CTRL);
+}
+
+static int mdss_hdmi_scrambler_ddc_check_status()
+{
+ int rc = 0;
+ uint32_t reg_val;
+
+ /* check for errors and clear status */
+ reg_val = readl(HDMI_SCRAMBLER_STATUS_DDC_STATUS);
+
+ if (reg_val & BIT(4)) {
+ dprintf(CRITICAL, "ddc aborted\n");
+ reg_val |= BIT(5);
+ rc = ERROR;
+ }
+
+ if (reg_val & BIT(8)) {
+ dprintf(CRITICAL, "timed out\n");
+ reg_val |= BIT(9);
+ rc = ERROR;
+ }
+
+ if (reg_val & BIT(12)) {
+ dprintf(CRITICAL, "NACK0\n");
+ reg_val |= BIT(13);
+ rc = ERROR;
+ }
+
+ if (reg_val & BIT(14)) {
+ dprintf(CRITICAL, "NACK1\n");
+ reg_val |= BIT(15);
+ rc = ERROR;
+ }
+
+ writel(reg_val, HDMI_SCRAMBLER_STATUS_DDC_STATUS);
+
+ return rc;
+}
+
+static int mdss_hdmi_scrambler_status_timer_setup(uint32_t timeout_hsync)
+{
+ uint32_t reg_val;
+ int rc;
+
+ mdss_hdmi_ddc_clear_irq("scrambler");
+
+ writel(timeout_hsync, HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL);
+ writel(timeout_hsync, HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL2);
+
+ reg_val = readl(HDMI_DDC_INT_CTRL5);
+ reg_val |= BIT(10);
+ writel(reg_val, HDMI_DDC_INT_CTRL5);
+
+ reg_val = readl(HDMI_DDC_INT_CTRL2);
+ /* Trigger interrupt if scrambler status is 0 or DDC failure */
+ reg_val |= BIT(10);
+ reg_val &= ~(BIT(15) | BIT(16));
+ reg_val |= BIT(16);
+ writel(reg_val, HDMI_DDC_INT_CTRL2);
+
+ /* Enable DDC access */
+ reg_val = readl(HDMI_HW_DDC_CTRL);
+
+ reg_val &= ~(BIT(8) | BIT(9));
+ reg_val |= BIT(8);
+ writel(reg_val, HDMI_HW_DDC_CTRL);
+
+ /* WAIT for 200ms as per HDMI 2.0 standard for sink to respond */
+ udelay(2000);
+
+ /* clear the scrambler status */
+ rc = mdss_hdmi_scrambler_ddc_check_status();
+ if (rc)
+ dprintf(CRITICAL, "scrambling ddc error %d\n", rc);
+
+ mdss_hdmi_scrambler_ddc_disable();
+
+ return rc;
+}
+
+static int mdss_hdmi_setup_ddc_timers(uint32_t type, uint32_t to_in_num_lines)
+{
+ if (type >= DDC_TIMER_MAX) {
+ dprintf(CRITICAL, "Invalid timer type %d\n", type);
+ return ERROR;
+ }
+
+ switch (type) {
+ case DDC_TIMER_SCRAMBLER_STATUS:
+ mdss_hdmi_scrambler_status_timer_setup(to_in_num_lines);
+ break;
+ default:
+ dprintf(CRITICAL, "%d type not supported\n", type);
+ return ERROR;
+ }
+
+ return 0;
+}
+
+static int mdss_hdmi_setup_scrambler()
+{
+ int rc = 0;
+ uint32_t reg_val = 0;
+ uint32_t tmds_clock_ratio = 0;
+ bool scrambler_on = false;
+ struct mdss_hdmi_timing_info timing = {0};
+ mdss_hdmi_get_timing_info(&timing, mdss_hdmi_video_fmt);
+ int timeout_hsync;
+
+ /* Scrambling is supported from HDMI TX 4.0 */
+ reg_val = readl(HDMI_VERSION);
+ reg_val = (reg_val & 0xF0000000) >> 28;
+ if (reg_val < HDMI_TX_SCRAMBLER_MIN_TX_VERSION) {
+ dprintf(INFO, "%s: HDMI TX does not support scrambling\n",
+ __func__);
+ return 0;
+ }
+
+ if (timing.pixel_freq > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) {
+ scrambler_on = true;
+ tmds_clock_ratio = 1;
+ }
+
+ dprintf(SPEW, "%s: freq=%d, scrambler=%d, clock_ratio=%d\n",
+ __func__, timing.pixel_freq, scrambler_on,
+ tmds_clock_ratio);
+
+ if (scrambler_on) {
+ rc = mdss_hdmi_scdc_write(SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE,
+ tmds_clock_ratio);
+ if (rc) {
+ dprintf(CRITICAL, "%s: TMDS CLK RATIO ERR\n", __func__);
+ return rc;
+ }
+
+ reg_val = readl(HDMI_CTRL);
+ reg_val |= BIT(31); /* Enable Update DATAPATH_MODE */
+ reg_val |= BIT(28); /* Set SCRAMBLER_EN bit */
+
+ writel(reg_val, HDMI_CTRL);
+
+ rc = mdss_hdmi_scdc_write(SCDC_SCRAMBLING_ENABLE, 0x1);
+ if (rc) {
+ dprintf(CRITICAL, "%s: failed to enable scrambling\n",
+ __func__);
+ return rc;
+ }
+
+ /*
+ * Setup hardware to periodically check for scrambler
+ * status bit on the sink. Sink should set this bit
+ * with in 200ms after scrambler is enabled.
+ */
+ timeout_hsync = mdss_hdmi_get_timeout_in_hysnc(&timing,
+ HDMI_TX_SCRAMBLER_TIMEOUT_MSEC);
+
+ if (timeout_hsync <= 0) {
+ dprintf(CRITICAL, "%s: err in timeout hsync calc\n",
+ __func__);
+ timeout_hsync = HDMI_DEFAULT_TIMEOUT_HSYNC;
+ }
+
+ dprintf(SPEW, "%s: timeout for scrambling en: %d hsyncs\n",
+ __func__, timeout_hsync);
+
+ rc = mdss_hdmi_setup_ddc_timers(DDC_TIMER_SCRAMBLER_STATUS,
+ timeout_hsync);
+ } else {
+ mdss_hdmi_scdc_write(SCDC_SCRAMBLING_ENABLE, 0x0);
+ }
+
+ return rc;
}
int mdss_hdmi_init(void)
@@ -1127,6 +2043,9 @@
mdss_hdmi_set_mode(false);
+ /* Enable USEC REF timer */
+ writel(0x0001001B, HDMI_USEC_REFTIMER);
+
/* Audio settings */
if (!is_dvi_mode)
mdss_hdmi_audio_playback();
@@ -1141,5 +2060,7 @@
/* Enable HDMI */
mdss_hdmi_set_mode(true);
+ mdss_hdmi_setup_scrambler();
+
return 0;
}
diff --git a/platform/msm_shared/mdss_hdmi_pll_8996.c b/platform/msm_shared/mdss_hdmi_pll_8996.c
new file mode 100644
index 0000000..ef0a6d9
--- /dev/null
+++ b/platform/msm_shared/mdss_hdmi_pll_8996.c
@@ -0,0 +1,910 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <err.h>
+#include <reg.h>
+#include <smem.h>
+#include <bits.h>
+#include <msm_panel.h>
+#include <platform/timer.h>
+#include <platform/iomap.h>
+
+/* PLL REGISTERS */
+#define HDMI_PLL_BASE_OFFSET (0x9A0600)
+#define QSERDES_COM_ATB_SEL1 (HDMI_PLL_BASE_OFFSET + 0x000)
+#define QSERDES_COM_ATB_SEL2 (HDMI_PLL_BASE_OFFSET + 0x004)
+#define QSERDES_COM_FREQ_UPDATE (HDMI_PLL_BASE_OFFSET + 0x008)
+#define QSERDES_COM_BG_TIMER (HDMI_PLL_BASE_OFFSET + 0x00C)
+#define QSERDES_COM_SSC_EN_CENTER (HDMI_PLL_BASE_OFFSET + 0x010)
+#define QSERDES_COM_SSC_ADJ_PER1 (HDMI_PLL_BASE_OFFSET + 0x014)
+#define QSERDES_COM_SSC_ADJ_PER2 (HDMI_PLL_BASE_OFFSET + 0x018)
+#define QSERDES_COM_SSC_PER1 (HDMI_PLL_BASE_OFFSET + 0x01C)
+#define QSERDES_COM_SSC_PER2 (HDMI_PLL_BASE_OFFSET + 0x020)
+#define QSERDES_COM_SSC_STEP_SIZE1 (HDMI_PLL_BASE_OFFSET + 0x024)
+#define QSERDES_COM_SSC_STEP_SIZE2 (HDMI_PLL_BASE_OFFSET + 0x028)
+#define QSERDES_COM_POST_DIV (HDMI_PLL_BASE_OFFSET + 0x02C)
+#define QSERDES_COM_POST_DIV_MUX (HDMI_PLL_BASE_OFFSET + 0x030)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (HDMI_PLL_BASE_OFFSET + 0x034)
+#define QSERDES_COM_CLK_ENABLE1 (HDMI_PLL_BASE_OFFSET + 0x038)
+#define QSERDES_COM_SYS_CLK_CTRL (HDMI_PLL_BASE_OFFSET + 0x03C)
+#define QSERDES_COM_SYSCLK_BUF_ENABLE (HDMI_PLL_BASE_OFFSET + 0x040)
+#define QSERDES_COM_PLL_EN (HDMI_PLL_BASE_OFFSET + 0x044)
+#define QSERDES_COM_PLL_IVCO (HDMI_PLL_BASE_OFFSET + 0x048)
+#define QSERDES_COM_LOCK_CMP1_MODE0 (HDMI_PLL_BASE_OFFSET + 0x04C)
+#define QSERDES_COM_LOCK_CMP2_MODE0 (HDMI_PLL_BASE_OFFSET + 0x050)
+#define QSERDES_COM_LOCK_CMP3_MODE0 (HDMI_PLL_BASE_OFFSET + 0x054)
+#define QSERDES_COM_LOCK_CMP1_MODE1 (HDMI_PLL_BASE_OFFSET + 0x058)
+#define QSERDES_COM_LOCK_CMP2_MODE1 (HDMI_PLL_BASE_OFFSET + 0x05C)
+#define QSERDES_COM_LOCK_CMP3_MODE1 (HDMI_PLL_BASE_OFFSET + 0x060)
+#define QSERDES_COM_LOCK_CMP1_MODE2 (HDMI_PLL_BASE_OFFSET + 0x064)
+#define QSERDES_COM_CMN_RSVD0 (HDMI_PLL_BASE_OFFSET + 0x064)
+#define QSERDES_COM_LOCK_CMP2_MODE2 (HDMI_PLL_BASE_OFFSET + 0x068)
+#define QSERDES_COM_EP_CLOCK_DETECT_CTRL (HDMI_PLL_BASE_OFFSET + 0x068)
+#define QSERDES_COM_LOCK_CMP3_MODE2 (HDMI_PLL_BASE_OFFSET + 0x06C)
+#define QSERDES_COM_SYSCLK_DET_COMP_STATUS (HDMI_PLL_BASE_OFFSET + 0x06C)
+#define QSERDES_COM_BG_TRIM (HDMI_PLL_BASE_OFFSET + 0x070)
+#define QSERDES_COM_CLK_EP_DIV (HDMI_PLL_BASE_OFFSET + 0x074)
+#define QSERDES_COM_CP_CTRL_MODE0 (HDMI_PLL_BASE_OFFSET + 0x078)
+#define QSERDES_COM_CP_CTRL_MODE1 (HDMI_PLL_BASE_OFFSET + 0x07C)
+#define QSERDES_COM_CP_CTRL_MODE2 (HDMI_PLL_BASE_OFFSET + 0x080)
+#define QSERDES_COM_CMN_RSVD1 (HDMI_PLL_BASE_OFFSET + 0x080)
+#define QSERDES_COM_PLL_RCTRL_MODE0 (HDMI_PLL_BASE_OFFSET + 0x084)
+#define QSERDES_COM_PLL_RCTRL_MODE1 (HDMI_PLL_BASE_OFFSET + 0x088)
+#define QSERDES_COM_PLL_RCTRL_MODE2 (HDMI_PLL_BASE_OFFSET + 0x08C)
+#define QSERDES_COM_CMN_RSVD2 (HDMI_PLL_BASE_OFFSET + 0x08C)
+#define QSERDES_COM_PLL_CCTRL_MODE0 (HDMI_PLL_BASE_OFFSET + 0x090)
+#define QSERDES_COM_PLL_CCTRL_MODE1 (HDMI_PLL_BASE_OFFSET + 0x094)
+#define QSERDES_COM_PLL_CCTRL_MODE2 (HDMI_PLL_BASE_OFFSET + 0x098)
+#define QSERDES_COM_CMN_RSVD3 (HDMI_PLL_BASE_OFFSET + 0x098)
+#define QSERDES_COM_PLL_CNTRL (HDMI_PLL_BASE_OFFSET + 0x09C)
+#define QSERDES_COM_PHASE_SEL_CTRL (HDMI_PLL_BASE_OFFSET + 0x0A0)
+#define QSERDES_COM_PHASE_SEL_DC (HDMI_PLL_BASE_OFFSET + 0x0A4)
+#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL (HDMI_PLL_BASE_OFFSET + 0x0A8)
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM (HDMI_PLL_BASE_OFFSET + 0x0A8)
+#define QSERDES_COM_SYSCLK_EN_SEL (HDMI_PLL_BASE_OFFSET + 0x0AC)
+#define QSERDES_COM_CML_SYSCLK_SEL (HDMI_PLL_BASE_OFFSET + 0x0B0)
+#define QSERDES_COM_RESETSM_CNTRL (HDMI_PLL_BASE_OFFSET + 0x0B4)
+#define QSERDES_COM_RESETSM_CNTRL2 (HDMI_PLL_BASE_OFFSET + 0x0B8)
+#define QSERDES_COM_RESTRIM_CTRL (HDMI_PLL_BASE_OFFSET + 0x0BC)
+#define QSERDES_COM_RESTRIM_CTRL2 (HDMI_PLL_BASE_OFFSET + 0x0C0)
+#define QSERDES_COM_RESCODE_DIV_NUM (HDMI_PLL_BASE_OFFSET + 0x0C4)
+#define QSERDES_COM_LOCK_CMP_EN (HDMI_PLL_BASE_OFFSET + 0x0C8)
+#define QSERDES_COM_LOCK_CMP_CFG (HDMI_PLL_BASE_OFFSET + 0x0CC)
+#define QSERDES_COM_DEC_START_MODE0 (HDMI_PLL_BASE_OFFSET + 0x0D0)
+#define QSERDES_COM_DEC_START_MODE1 (HDMI_PLL_BASE_OFFSET + 0x0D4)
+#define QSERDES_COM_DEC_START_MODE2 (HDMI_PLL_BASE_OFFSET + 0x0D8)
+#define QSERDES_COM_VCOCAL_DEADMAN_CTRL (HDMI_PLL_BASE_OFFSET + 0x0D8)
+#define QSERDES_COM_DIV_FRAC_START1_MODE0 (HDMI_PLL_BASE_OFFSET + 0x0DC)
+#define QSERDES_COM_DIV_FRAC_START2_MODE0 (HDMI_PLL_BASE_OFFSET + 0x0E0)
+#define QSERDES_COM_DIV_FRAC_START3_MODE0 (HDMI_PLL_BASE_OFFSET + 0x0E4)
+#define QSERDES_COM_DIV_FRAC_START1_MODE1 (HDMI_PLL_BASE_OFFSET + 0x0E8)
+#define QSERDES_COM_DIV_FRAC_START2_MODE1 (HDMI_PLL_BASE_OFFSET + 0x0EC)
+#define QSERDES_COM_DIV_FRAC_START3_MODE1 (HDMI_PLL_BASE_OFFSET + 0x0F0)
+#define QSERDES_COM_DIV_FRAC_START1_MODE2 (HDMI_PLL_BASE_OFFSET + 0x0F4)
+#define QSERDES_COM_VCO_TUNE_MINVAL1 (HDMI_PLL_BASE_OFFSET + 0x0F4)
+#define QSERDES_COM_DIV_FRAC_START2_MODE2 (HDMI_PLL_BASE_OFFSET + 0x0F8)
+#define QSERDES_COM_VCO_TUNE_MINVAL2 (HDMI_PLL_BASE_OFFSET + 0x0F8)
+#define QSERDES_COM_DIV_FRAC_START3_MODE2 (HDMI_PLL_BASE_OFFSET + 0x0FC)
+#define QSERDES_COM_CMN_RSVD4 (HDMI_PLL_BASE_OFFSET + 0x0FC)
+#define QSERDES_COM_INTEGLOOP_INITVAL (HDMI_PLL_BASE_OFFSET + 0x100)
+#define QSERDES_COM_INTEGLOOP_EN (HDMI_PLL_BASE_OFFSET + 0x104)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 (HDMI_PLL_BASE_OFFSET + 0x108)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 (HDMI_PLL_BASE_OFFSET + 0x10C)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 (HDMI_PLL_BASE_OFFSET + 0x110)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 (HDMI_PLL_BASE_OFFSET + 0x114)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE2 (HDMI_PLL_BASE_OFFSET + 0x118)
+#define QSERDES_COM_VCO_TUNE_MAXVAL1 (HDMI_PLL_BASE_OFFSET + 0x118)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE2 (HDMI_PLL_BASE_OFFSET + 0x11C)
+#define QSERDES_COM_VCO_TUNE_MAXVAL2 (HDMI_PLL_BASE_OFFSET + 0x11C)
+#define QSERDES_COM_RES_TRIM_CONTROL2 (HDMI_PLL_BASE_OFFSET + 0x120)
+#define QSERDES_COM_VCO_TUNE_CTRL (HDMI_PLL_BASE_OFFSET + 0x124)
+#define QSERDES_COM_VCO_TUNE_MAP (HDMI_PLL_BASE_OFFSET + 0x128)
+#define QSERDES_COM_VCO_TUNE1_MODE0 (HDMI_PLL_BASE_OFFSET + 0x12C)
+#define QSERDES_COM_VCO_TUNE2_MODE0 (HDMI_PLL_BASE_OFFSET + 0x130)
+#define QSERDES_COM_VCO_TUNE1_MODE1 (HDMI_PLL_BASE_OFFSET + 0x134)
+#define QSERDES_COM_VCO_TUNE2_MODE1 (HDMI_PLL_BASE_OFFSET + 0x138)
+#define QSERDES_COM_VCO_TUNE1_MODE2 (HDMI_PLL_BASE_OFFSET + 0x13C)
+#define QSERDES_COM_VCO_TUNE_INITVAL1 (HDMI_PLL_BASE_OFFSET + 0x13C)
+#define QSERDES_COM_VCO_TUNE2_MODE2 (HDMI_PLL_BASE_OFFSET + 0x140)
+#define QSERDES_COM_VCO_TUNE_INITVAL2 (HDMI_PLL_BASE_OFFSET + 0x140)
+#define QSERDES_COM_VCO_TUNE_TIMER1 (HDMI_PLL_BASE_OFFSET + 0x144)
+#define QSERDES_COM_VCO_TUNE_TIMER2 (HDMI_PLL_BASE_OFFSET + 0x148)
+#define QSERDES_COM_SAR (HDMI_PLL_BASE_OFFSET + 0x14C)
+#define QSERDES_COM_SAR_CLK (HDMI_PLL_BASE_OFFSET + 0x150)
+#define QSERDES_COM_SAR_CODE_OUT_STATUS (HDMI_PLL_BASE_OFFSET + 0x154)
+#define QSERDES_COM_SAR_CODE_READY_STATUS (HDMI_PLL_BASE_OFFSET + 0x158)
+#define QSERDES_COM_CMN_STATUS (HDMI_PLL_BASE_OFFSET + 0x15C)
+#define QSERDES_COM_RESET_SM_STATUS (HDMI_PLL_BASE_OFFSET + 0x160)
+#define QSERDES_COM_RESTRIM_CODE_STATUS (HDMI_PLL_BASE_OFFSET + 0x164)
+#define QSERDES_COM_PLLCAL_CODE1_STATUS (HDMI_PLL_BASE_OFFSET + 0x168)
+#define QSERDES_COM_PLLCAL_CODE2_STATUS (HDMI_PLL_BASE_OFFSET + 0x16C)
+#define QSERDES_COM_BG_CTRL (HDMI_PLL_BASE_OFFSET + 0x170)
+#define QSERDES_COM_CLK_SELECT (HDMI_PLL_BASE_OFFSET + 0x174)
+#define QSERDES_COM_HSCLK_SEL (HDMI_PLL_BASE_OFFSET + 0x178)
+#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS (HDMI_PLL_BASE_OFFSET + 0x17C)
+#define QSERDES_COM_PLL_ANALOG (HDMI_PLL_BASE_OFFSET + 0x180)
+#define QSERDES_COM_CORECLK_DIV (HDMI_PLL_BASE_OFFSET + 0x184)
+#define QSERDES_COM_SW_RESET (HDMI_PLL_BASE_OFFSET + 0x188)
+#define QSERDES_COM_CORE_CLK_EN (HDMI_PLL_BASE_OFFSET + 0x18C)
+#define QSERDES_COM_C_READY_STATUS (HDMI_PLL_BASE_OFFSET + 0x190)
+#define QSERDES_COM_CMN_CONFIG (HDMI_PLL_BASE_OFFSET + 0x194)
+#define QSERDES_COM_CMN_RATE_OVERRIDE (HDMI_PLL_BASE_OFFSET + 0x198)
+#define QSERDES_COM_SVS_MODE_CLK_SEL (HDMI_PLL_BASE_OFFSET + 0x19C)
+#define QSERDES_COM_DEBUG_BUS0 (HDMI_PLL_BASE_OFFSET + 0x1A0)
+#define QSERDES_COM_DEBUG_BUS1 (HDMI_PLL_BASE_OFFSET + 0x1A4)
+#define QSERDES_COM_DEBUG_BUS2 (HDMI_PLL_BASE_OFFSET + 0x1A8)
+#define QSERDES_COM_DEBUG_BUS3 (HDMI_PLL_BASE_OFFSET + 0x1AC)
+#define QSERDES_COM_DEBUG_BUS_SEL (HDMI_PLL_BASE_OFFSET + 0x1B0)
+#define QSERDES_COM_CMN_MISC1 (HDMI_PLL_BASE_OFFSET + 0x1B4)
+#define QSERDES_COM_CMN_MISC2 (HDMI_PLL_BASE_OFFSET + 0x1B8)
+#define QSERDES_COM_CORECLK_DIV_MODE1 (HDMI_PLL_BASE_OFFSET + 0x1BC)
+#define QSERDES_COM_CORECLK_DIV_MODE2 (HDMI_PLL_BASE_OFFSET + 0x1C0)
+#define QSERDES_COM_CMN_RSVD5 (HDMI_PLL_BASE_OFFSET + 0x1C0)
+
+/* Tx Channel base addresses */
+#define HDMI_TX_L0_BASE_OFFSET (HDMI_PLL_BASE_OFFSET + 0x400)
+#define HDMI_TX_L1_BASE_OFFSET (HDMI_PLL_BASE_OFFSET + 0x600)
+#define HDMI_TX_L2_BASE_OFFSET (HDMI_PLL_BASE_OFFSET + 0x800)
+#define HDMI_TX_L3_BASE_OFFSET (HDMI_PLL_BASE_OFFSET + 0xA00)
+
+/* Tx Channel PHY registers */
+#define QSERDES_TX_L0_BIST_MODE_LANENO (0x000)
+#define QSERDES_TX_L0_BIST_INVERT (0x004)
+#define QSERDES_TX_L0_CLKBUF_ENABLE (0x008)
+#define QSERDES_TX_L0_CMN_CONTROL_ONE (0x00C)
+#define QSERDES_TX_L0_CMN_CONTROL_TWO (0x010)
+#define QSERDES_TX_L0_CMN_CONTROL_THREE (0x014)
+#define QSERDES_TX_L0_TX_EMP_POST1_LVL (0x018)
+#define QSERDES_TX_L0_TX_POST2_EMPH (0x01C)
+#define QSERDES_TX_L0_TX_BOOST_LVL_UP_DN (0x020)
+#define QSERDES_TX_L0_HP_PD_ENABLES (0x024)
+#define QSERDES_TX_L0_TX_IDLE_LVL_LARGE_AMP (0x028)
+#define QSERDES_TX_L0_TX_DRV_LVL (0x02C)
+#define QSERDES_TX_L0_TX_DRV_LVL_OFFSET (0x030)
+#define QSERDES_TX_L0_RESET_TSYNC_EN (0x034)
+#define QSERDES_TX_L0_PRE_STALL_LDO_BOOST_EN (0x038)
+#define QSERDES_TX_L0_TX_BAND (0x03C)
+#define QSERDES_TX_L0_SLEW_CNTL (0x040)
+#define QSERDES_TX_L0_INTERFACE_SELECT (0x044)
+#define QSERDES_TX_L0_LPB_EN (0x048)
+#define QSERDES_TX_L0_RES_CODE_LANE_TX (0x04C)
+#define QSERDES_TX_L0_RES_CODE_LANE_RX (0x050)
+#define QSERDES_TX_L0_RES_CODE_LANE_OFFSET (0x054)
+#define QSERDES_TX_L0_PERL_LENGTH1 (0x058)
+#define QSERDES_TX_L0_PERL_LENGTH2 (0x05C)
+#define QSERDES_TX_L0_SERDES_BYP_EN_OUT (0x060)
+#define QSERDES_TX_L0_DEBUG_BUS_SEL (0x064)
+#define QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x068)
+#define QSERDES_TX_L0_TX_POL_INV (0x06C)
+#define QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN (0x070)
+#define QSERDES_TX_L0_BIST_PATTERN1 (0x074)
+#define QSERDES_TX_L0_BIST_PATTERN2 (0x078)
+#define QSERDES_TX_L0_BIST_PATTERN3 (0x07C)
+#define QSERDES_TX_L0_BIST_PATTERN4 (0x080)
+#define QSERDES_TX_L0_BIST_PATTERN5 (0x084)
+#define QSERDES_TX_L0_BIST_PATTERN6 (0x088)
+#define QSERDES_TX_L0_BIST_PATTERN7 (0x08C)
+#define QSERDES_TX_L0_BIST_PATTERN8 (0x090)
+#define QSERDES_TX_L0_LANE_MODE (0x094)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE (0x098)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE_CONFIGURATION (0x09C)
+#define QSERDES_TX_L0_ATB_SEL1 (0x0A0)
+#define QSERDES_TX_L0_ATB_SEL2 (0x0A4)
+#define QSERDES_TX_L0_RCV_DETECT_LVL (0x0A8)
+#define QSERDES_TX_L0_RCV_DETECT_LVL_2 (0x0AC)
+#define QSERDES_TX_L0_PRBS_SEED1 (0x0B0)
+#define QSERDES_TX_L0_PRBS_SEED2 (0x0B4)
+#define QSERDES_TX_L0_PRBS_SEED3 (0x0B8)
+#define QSERDES_TX_L0_PRBS_SEED4 (0x0BC)
+#define QSERDES_TX_L0_RESET_GEN (0x0C0)
+#define QSERDES_TX_L0_RESET_GEN_MUXES (0x0C4)
+#define QSERDES_TX_L0_TRAN_DRVR_EMP_EN (0x0C8)
+#define QSERDES_TX_L0_TX_INTERFACE_MODE (0x0CC)
+#define QSERDES_TX_L0_PWM_CTRL (0x0D0)
+#define QSERDES_TX_L0_PWM_ENCODED_OR_DATA (0x0D4)
+#define QSERDES_TX_L0_PWM_GEAR_1_DIVIDER_BAND2 (0x0D8)
+#define QSERDES_TX_L0_PWM_GEAR_2_DIVIDER_BAND2 (0x0DC)
+#define QSERDES_TX_L0_PWM_GEAR_3_DIVIDER_BAND2 (0x0E0)
+#define QSERDES_TX_L0_PWM_GEAR_4_DIVIDER_BAND2 (0x0E4)
+#define QSERDES_TX_L0_PWM_GEAR_1_DIVIDER_BAND0_1 (0x0E8)
+#define QSERDES_TX_L0_PWM_GEAR_2_DIVIDER_BAND0_1 (0x0EC)
+#define QSERDES_TX_L0_PWM_GEAR_3_DIVIDER_BAND0_1 (0x0F0)
+#define QSERDES_TX_L0_PWM_GEAR_4_DIVIDER_BAND0_1 (0x0F4)
+#define QSERDES_TX_L0_VMODE_CTRL1 (0x0F8)
+#define QSERDES_TX_L0_VMODE_CTRL2 (0x0FC)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV_CNTL (0x100)
+#define QSERDES_TX_L0_BIST_STATUS (0x104)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT1 (0x108)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT2 (0x10C)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV (0x110)
+
+/* HDMI PHY REGISTERS */
+#define HDMI_PHY_BASE_OFFSET (0x9A1200)
+#define HDMI_PHY_CFG (HDMI_PHY_BASE_OFFSET + 0x00)
+#define HDMI_PHY_PD_CTL (HDMI_PHY_BASE_OFFSET + 0x04)
+#define HDMI_PHY_MODE (HDMI_PHY_BASE_OFFSET + 0x08)
+#define HDMI_PHY_MISR_CLEAR (HDMI_PHY_BASE_OFFSET + 0x0C)
+#define HDMI_PHY_TX0_TX1_BIST_CFG0 (HDMI_PHY_BASE_OFFSET + 0x10)
+#define HDMI_PHY_TX0_TX1_BIST_CFG1 (HDMI_PHY_BASE_OFFSET + 0x14)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE0 (HDMI_PHY_BASE_OFFSET + 0x18)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE1 (HDMI_PHY_BASE_OFFSET + 0x1C)
+#define HDMI_PHY_TX0_TX1_BIST_PATTERN0 (HDMI_PHY_BASE_OFFSET + 0x20)
+#define HDMI_PHY_TX0_TX1_BIST_PATTERN1 (HDMI_PHY_BASE_OFFSET + 0x24)
+#define HDMI_PHY_TX2_TX3_BIST_CFG0 (HDMI_PHY_BASE_OFFSET + 0x28)
+#define HDMI_PHY_TX2_TX3_BIST_CFG1 (HDMI_PHY_BASE_OFFSET + 0x2C)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE0 (HDMI_PHY_BASE_OFFSET + 0x30)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE1 (HDMI_PHY_BASE_OFFSET + 0x34)
+#define HDMI_PHY_TX2_TX3_BIST_PATTERN0 (HDMI_PHY_BASE_OFFSET + 0x38)
+#define HDMI_PHY_TX2_TX3_BIST_PATTERN1 (HDMI_PHY_BASE_OFFSET + 0x3C)
+#define HDMI_PHY_DEBUG_BUS_SEL (HDMI_PHY_BASE_OFFSET + 0x40)
+#define HDMI_PHY_TXCAL_CFG0 (HDMI_PHY_BASE_OFFSET + 0x44)
+#define HDMI_PHY_TXCAL_CFG1 (HDMI_PHY_BASE_OFFSET + 0x48)
+#define HDMI_PHY_TX0_TX1_LANE_CTL (HDMI_PHY_BASE_OFFSET + 0x4C)
+#define HDMI_PHY_TX2_TX3_LANE_CTL (HDMI_PHY_BASE_OFFSET + 0x50)
+#define HDMI_PHY_LANE_BIST_CONFIG (HDMI_PHY_BASE_OFFSET + 0x54)
+#define HDMI_PHY_CLOCK (HDMI_PHY_BASE_OFFSET + 0x58)
+#define HDMI_PHY_MISC1 (HDMI_PHY_BASE_OFFSET + 0x5C)
+#define HDMI_PHY_MISC2 (HDMI_PHY_BASE_OFFSET + 0x60)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS0 (HDMI_PHY_BASE_OFFSET + 0x64)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS1 (HDMI_PHY_BASE_OFFSET + 0x68)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS2 (HDMI_PHY_BASE_OFFSET + 0x6C)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS0 (HDMI_PHY_BASE_OFFSET + 0x70)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS1 (HDMI_PHY_BASE_OFFSET + 0x74)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS2 (HDMI_PHY_BASE_OFFSET + 0x78)
+#define HDMI_PHY_PRE_MISR_STATUS0 (HDMI_PHY_BASE_OFFSET + 0x7C)
+#define HDMI_PHY_PRE_MISR_STATUS1 (HDMI_PHY_BASE_OFFSET + 0x80)
+#define HDMI_PHY_PRE_MISR_STATUS2 (HDMI_PHY_BASE_OFFSET + 0x84)
+#define HDMI_PHY_PRE_MISR_STATUS3 (HDMI_PHY_BASE_OFFSET + 0x88)
+#define HDMI_PHY_POST_MISR_STATUS0 (HDMI_PHY_BASE_OFFSET + 0x8C)
+#define HDMI_PHY_POST_MISR_STATUS1 (HDMI_PHY_BASE_OFFSET + 0x90)
+#define HDMI_PHY_POST_MISR_STATUS2 (HDMI_PHY_BASE_OFFSET + 0x94)
+#define HDMI_PHY_POST_MISR_STATUS3 (HDMI_PHY_BASE_OFFSET + 0x98)
+#define HDMI_PHY_STATUS (HDMI_PHY_BASE_OFFSET + 0x9C)
+#define HDMI_PHY_MISC3_STATUS (HDMI_PHY_BASE_OFFSET + 0xA0)
+#define HDMI_PHY_MISC4_STATUS (HDMI_PHY_BASE_OFFSET + 0xA4)
+#define HDMI_PHY_DEBUG_BUS0 (HDMI_PHY_BASE_OFFSET + 0xA8)
+#define HDMI_PHY_DEBUG_BUS1 (HDMI_PHY_BASE_OFFSET + 0xAC)
+#define HDMI_PHY_DEBUG_BUS2 (HDMI_PHY_BASE_OFFSET + 0xB0)
+#define HDMI_PHY_DEBUG_BUS3 (HDMI_PHY_BASE_OFFSET + 0xB4)
+#define HDMI_PHY_PHY_REVISION_ID0 (HDMI_PHY_BASE_OFFSET + 0xB8)
+#define HDMI_PHY_PHY_REVISION_ID1 (HDMI_PHY_BASE_OFFSET + 0xBC)
+#define HDMI_PHY_PHY_REVISION_ID2 (HDMI_PHY_BASE_OFFSET + 0xC0)
+#define HDMI_PHY_PHY_REVISION_ID3 (HDMI_PHY_BASE_OFFSET + 0xC4)
+
+#define HDMI_PLL_POLL_MAX_READS 2500
+#define HDMI_PLL_POLL_TIMEOUT_US 150000
+#define HDMI_CLK_RATE_148_MHZ 148500000
+#define HDMI_CLK_RATE_74_MHZ 74250000
+#define HDMI_CLK_RATE_25_MHZ 25200000
+#define HDMI_CLK_RATE_297_MHZ 297000000
+#define HDMI_CLK_RATE_594_MHZ 594000000
+
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+
+struct hdmi_8996_phy_pll_reg_cfg {
+ uint32_t tx_l0_lane_mode;
+ uint32_t tx_l2_lane_mode;
+ uint32_t tx_l0_tx_band;
+ uint32_t tx_l1_tx_band;
+ uint32_t tx_l2_tx_band;
+ uint32_t tx_l3_tx_band;
+ uint32_t com_svs_mode_clk_sel;
+ uint32_t com_hsclk_sel;
+ uint32_t com_pll_cctrl_mode0;
+ uint32_t com_pll_rctrl_mode0;
+ uint32_t com_cp_ctrl_mode0;
+ uint32_t com_dec_start_mode0;
+ uint32_t com_div_frac_start1_mode0;
+ uint32_t com_div_frac_start2_mode0;
+ uint32_t com_div_frac_start3_mode0;
+ uint32_t com_integloop_gain0_mode0;
+ uint32_t com_integloop_gain1_mode0;
+ uint32_t com_lock_cmp_en;
+ uint32_t com_lock_cmp1_mode0;
+ uint32_t com_lock_cmp2_mode0;
+ uint32_t com_lock_cmp3_mode0;
+ uint32_t com_core_clk_en;
+ uint32_t com_coreclk_div;
+ uint32_t com_restrim_ctrl;
+ uint32_t com_vco_tune_ctrl;
+ uint32_t tx_l0_tx_drv_lvl;
+ uint32_t tx_l0_tx_emp_post1_lvl;
+ uint32_t tx_l1_tx_drv_lvl;
+ uint32_t tx_l1_tx_emp_post1_lvl;
+ uint32_t tx_l2_tx_drv_lvl;
+ uint32_t tx_l2_tx_emp_post1_lvl;
+ uint32_t tx_l3_tx_drv_lvl;
+ uint32_t tx_l3_tx_emp_post1_lvl;
+ uint32_t tx_l0_vmode_ctrl1;
+ uint32_t tx_l0_vmode_ctrl2;
+ uint32_t tx_l1_vmode_ctrl1;
+ uint32_t tx_l1_vmode_ctrl2;
+ uint32_t tx_l2_vmode_ctrl1;
+ uint32_t tx_l2_vmode_ctrl2;
+ uint32_t tx_l3_vmode_ctrl1;
+ uint32_t tx_l3_vmode_ctrl2;
+ uint32_t tx_l0_res_code_lane_tx;
+ uint32_t tx_l1_res_code_lane_tx;
+ uint32_t tx_l2_res_code_lane_tx;
+ uint32_t tx_l3_res_code_lane_tx;
+ uint32_t phy_mode;
+};
+
+void hdmi_phy_reset(void)
+{
+ uint32_t phy_reset_polarity = 0x0;
+ uint32_t pll_reset_polarity = 0x0;
+ uint32_t val;
+
+ val = readl(HDMI_PHY_CTRL);
+
+ phy_reset_polarity = val >> 3 & 0x1;
+ pll_reset_polarity = val >> 1 & 0x1;
+
+ if (phy_reset_polarity == 0)
+ writel(val | SW_RESET, HDMI_PHY_CTRL);
+ else
+ writel(val & (~SW_RESET), HDMI_PHY_CTRL);
+
+ if (pll_reset_polarity == 0)
+ writel(val | SW_RESET_PLL, HDMI_PHY_CTRL);
+ else
+ writel(val & (~SW_RESET_PLL), HDMI_PHY_CTRL);
+
+ if (phy_reset_polarity == 0)
+ writel(val & (~SW_RESET), HDMI_PHY_CTRL);
+ else
+ writel(val | SW_RESET, HDMI_PHY_CTRL);
+
+ if (pll_reset_polarity == 0)
+ writel(val & (~SW_RESET_PLL), HDMI_PHY_CTRL);
+ else
+ writel(val | SW_RESET_PLL, HDMI_PHY_CTRL);
+
+ udelay(100);
+}
+
+static int get_pll_settings(uint32_t tmds_clk_rate,
+ struct hdmi_8996_phy_pll_reg_cfg *cfg)
+{
+ switch (tmds_clk_rate) {
+ case HDMI_CLK_RATE_148_MHZ:
+ cfg->tx_l0_lane_mode = 0x43;
+ cfg->tx_l2_lane_mode = 0x43;
+ cfg->tx_l0_tx_band = 0x04;
+ cfg->tx_l1_tx_band = 0x04;
+ cfg->tx_l2_tx_band = 0x04;
+ cfg->tx_l3_tx_band = 0x04;
+ cfg->com_svs_mode_clk_sel = 0x2;
+ cfg->com_hsclk_sel = 0x21;
+ cfg->com_pll_cctrl_mode0 = 0x28;
+ cfg->com_pll_rctrl_mode0 = 0x16;
+ cfg->com_cp_ctrl_mode0 = 0xb;
+ cfg->com_dec_start_mode0 = 0x74;
+ cfg->com_div_frac_start1_mode0 = 0x0;
+ cfg->com_div_frac_start2_mode0 = 0x40;
+ cfg->com_div_frac_start3_mode0 = 0x0;
+ cfg->com_integloop_gain0_mode0 = 0x0;
+ cfg->com_integloop_gain1_mode0 = 0x1;
+ cfg->com_lock_cmp_en = 0x0;
+ cfg->com_lock_cmp1_mode0 = 0xef;
+ cfg->com_lock_cmp2_mode0 = 0x1e;
+ cfg->com_lock_cmp3_mode0 = 0x0;
+ cfg->com_core_clk_en = 0x2c;
+ cfg->com_coreclk_div = 0x5;
+ cfg->com_restrim_ctrl = 0x0;
+ cfg->com_vco_tune_ctrl = 0x0;
+ cfg->tx_l0_tx_drv_lvl = 0x25;
+ cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l1_tx_drv_lvl = 0x25;
+ cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l2_tx_drv_lvl = 0x25;
+ cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l3_tx_drv_lvl = 0x25;
+ cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l0_vmode_ctrl1 = 0x0;
+ cfg->tx_l0_vmode_ctrl2 = 0xd;
+ cfg->tx_l1_vmode_ctrl1 = 0x0;
+ cfg->tx_l1_vmode_ctrl2 = 0xd;
+ cfg->tx_l2_vmode_ctrl1 = 0x0;
+ cfg->tx_l2_vmode_ctrl2 = 0xd;
+ cfg->tx_l3_vmode_ctrl1 = 0x0;
+ cfg->tx_l3_vmode_ctrl2 = 0x0;
+ cfg->tx_l0_res_code_lane_tx = 0x0;
+ cfg->tx_l1_res_code_lane_tx = 0x0;
+ cfg->tx_l2_res_code_lane_tx = 0x0;
+ cfg->tx_l3_res_code_lane_tx = 0x0;
+ cfg->phy_mode = 0x0;
+ break;
+ case HDMI_CLK_RATE_74_MHZ:
+ cfg->tx_l0_lane_mode = 0x43;
+ cfg->tx_l2_lane_mode = 0x43;
+ cfg->tx_l0_tx_band = 0x04;
+ cfg->tx_l1_tx_band = 0x04;
+ cfg->tx_l2_tx_band = 0x04;
+ cfg->tx_l3_tx_band = 0x04;
+ cfg->com_svs_mode_clk_sel = 0x2;
+ cfg->com_hsclk_sel = 0x29;
+ cfg->com_pll_cctrl_mode0 = 0x28;
+ cfg->com_pll_rctrl_mode0 = 0x16;
+ cfg->com_cp_ctrl_mode0 = 0xb;
+ cfg->com_dec_start_mode0 = 0x74;
+ cfg->com_div_frac_start1_mode0 = 0x0;
+ cfg->com_div_frac_start2_mode0 = 0x40;
+ cfg->com_div_frac_start3_mode0 = 0x0;
+ cfg->com_integloop_gain0_mode0 = 0x0;
+ cfg->com_integloop_gain1_mode0 = 0x1;
+ cfg->com_lock_cmp_en = 0x0;
+ cfg->com_lock_cmp1_mode0 = 0x77;
+ cfg->com_lock_cmp2_mode0 = 0xf;
+ cfg->com_lock_cmp3_mode0 = 0x0;
+ cfg->com_core_clk_en = 0x2c;
+ cfg->com_coreclk_div = 0x5;
+ cfg->com_restrim_ctrl = 0x0;
+ cfg->com_vco_tune_ctrl = 0x0;
+ cfg->tx_l0_tx_drv_lvl = 0x20;
+ cfg->tx_l0_tx_emp_post1_lvl = 0x20;
+ cfg->tx_l1_tx_drv_lvl = 0x20;
+ cfg->tx_l1_tx_emp_post1_lvl = 0x20;
+ cfg->tx_l2_tx_drv_lvl = 0x20;
+ cfg->tx_l2_tx_emp_post1_lvl = 0x20;
+ cfg->tx_l3_tx_drv_lvl = 0x20;
+ cfg->tx_l3_tx_emp_post1_lvl = 0x20;
+ cfg->tx_l0_vmode_ctrl1 = 0x0;
+ cfg->tx_l0_vmode_ctrl2 = 0xe;
+ cfg->tx_l1_vmode_ctrl1 = 0x0;
+ cfg->tx_l1_vmode_ctrl2 = 0xe;
+ cfg->tx_l2_vmode_ctrl1 = 0x0;
+ cfg->tx_l2_vmode_ctrl2 = 0xe;
+ cfg->tx_l3_vmode_ctrl1 = 0x0;
+ cfg->tx_l3_vmode_ctrl2 = 0xe;
+ cfg->tx_l0_res_code_lane_tx = 0x0;
+ cfg->tx_l1_res_code_lane_tx = 0x0;
+ cfg->tx_l2_res_code_lane_tx = 0x0;
+ cfg->tx_l3_res_code_lane_tx = 0x0;
+ cfg->phy_mode = 0x0;
+ break;
+ case HDMI_CLK_RATE_25_MHZ:
+ cfg->tx_l0_lane_mode = 0x43;
+ cfg->tx_l2_lane_mode = 0x43;
+ cfg->tx_l0_tx_band = 0x7;
+ cfg->tx_l1_tx_band = 0x7;
+ cfg->tx_l2_tx_band = 0x7;
+ cfg->tx_l3_tx_band = 0x7;
+ cfg->com_svs_mode_clk_sel = 0x2;
+ cfg->com_hsclk_sel = 0x28;
+ cfg->com_pll_cctrl_mode0 = 0x1;
+ cfg->com_pll_rctrl_mode0 = 0x10;
+ cfg->com_cp_ctrl_mode0 = 0x23;
+ cfg->com_dec_start_mode0 = 0x69;
+ cfg->com_div_frac_start1_mode0 = 0x0;
+ cfg->com_div_frac_start2_mode0 = 0x0;
+ cfg->com_div_frac_start3_mode0 = 0x0;
+ cfg->com_integloop_gain0_mode0 = 0x10;
+ cfg->com_integloop_gain1_mode0 = 0x3;
+ cfg->com_lock_cmp_en = 0x0;
+ cfg->com_lock_cmp1_mode0 = 0xff;
+ cfg->com_lock_cmp2_mode0 = 0x29;
+ cfg->com_lock_cmp3_mode0 = 0x0;
+ cfg->com_core_clk_en = 0x2c;
+ cfg->com_coreclk_div = 0x5;
+ cfg->com_restrim_ctrl = 0x0;
+ cfg->com_vco_tune_ctrl = 0x0;
+ cfg->tx_l0_tx_drv_lvl = 0x20;
+ cfg->tx_l0_tx_emp_post1_lvl = 0x20;
+ cfg->tx_l1_tx_drv_lvl = 0x20;
+ cfg->tx_l1_tx_emp_post1_lvl = 0x20;
+ cfg->tx_l2_tx_drv_lvl = 0x20;
+ cfg->tx_l2_tx_emp_post1_lvl = 0x20;
+ cfg->tx_l3_tx_drv_lvl = 0x20;
+ cfg->tx_l3_tx_emp_post1_lvl = 0x20;
+ cfg->tx_l0_vmode_ctrl1 = 0x0;
+ cfg->tx_l0_vmode_ctrl2 = 0xe;
+ cfg->tx_l1_vmode_ctrl1 = 0x0;
+ cfg->tx_l1_vmode_ctrl2 = 0xe;
+ cfg->tx_l2_vmode_ctrl1 = 0x0;
+ cfg->tx_l2_vmode_ctrl2 = 0xe;
+ cfg->tx_l3_vmode_ctrl1 = 0x0;
+ cfg->tx_l3_vmode_ctrl2 = 0xe;
+ cfg->tx_l0_res_code_lane_tx = 0x0;
+ cfg->tx_l1_res_code_lane_tx = 0x0;
+ cfg->tx_l2_res_code_lane_tx = 0x0;
+ cfg->tx_l3_res_code_lane_tx = 0x0;
+ cfg->phy_mode = 0x0;
+ break;
+ case HDMI_CLK_RATE_297_MHZ:
+ cfg->tx_l0_lane_mode = 0x43;
+ cfg->tx_l2_lane_mode = 0x43;
+ cfg->tx_l0_tx_band = 0x4;
+ cfg->tx_l1_tx_band = 0x4;
+ cfg->tx_l2_tx_band = 0x4;
+ cfg->tx_l3_tx_band = 0x4;
+ cfg->com_svs_mode_clk_sel = 0x1;
+ cfg->com_hsclk_sel = 0x24;
+ cfg->com_pll_cctrl_mode0 = 0x28;
+ cfg->com_pll_rctrl_mode0 = 0x16;
+ cfg->com_cp_ctrl_mode0 = 0xb;
+ cfg->com_dec_start_mode0 = 0x74;
+ cfg->com_div_frac_start1_mode0 = 0x0;
+ cfg->com_div_frac_start2_mode0 = 0x40;
+ cfg->com_div_frac_start3_mode0 = 0x0;
+ cfg->com_integloop_gain0_mode0 = 0x80;
+ cfg->com_integloop_gain1_mode0 = 0x0;
+ cfg->com_lock_cmp_en = 0x0;
+ cfg->com_lock_cmp1_mode0 = 0xdf;
+ cfg->com_lock_cmp2_mode0 = 0x3d;
+ cfg->com_lock_cmp3_mode0 = 0x0;
+ cfg->com_core_clk_en = 0x2c;
+ cfg->com_coreclk_div = 0x5;
+ cfg->com_restrim_ctrl = 0x0;
+ cfg->com_vco_tune_ctrl = 0x0;
+ cfg->tx_l0_tx_drv_lvl = 0x25;
+ cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l1_tx_drv_lvl = 0x25;
+ cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l2_tx_drv_lvl = 0x25;
+ cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l3_tx_drv_lvl = 0x25;
+ cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l0_vmode_ctrl1 = 0x0;
+ cfg->tx_l0_vmode_ctrl2 = 0xd;
+ cfg->tx_l1_vmode_ctrl1 = 0x0;
+ cfg->tx_l1_vmode_ctrl2 = 0xd;
+ cfg->tx_l2_vmode_ctrl1 = 0x0;
+ cfg->tx_l2_vmode_ctrl2 = 0xd;
+ cfg->tx_l3_vmode_ctrl1 = 0x0;
+ cfg->tx_l3_vmode_ctrl2 = 0x0;
+ cfg->tx_l0_res_code_lane_tx = 0x0;
+ cfg->tx_l1_res_code_lane_tx = 0x0;
+ cfg->tx_l2_res_code_lane_tx = 0x0;
+ cfg->tx_l3_res_code_lane_tx = 0x0;
+ cfg->phy_mode = 0x00;
+ break;
+ case HDMI_CLK_RATE_594_MHZ:
+ cfg->tx_l0_lane_mode = 0x43;
+ cfg->tx_l2_lane_mode = 0x43;
+ cfg->tx_l0_tx_band = 0x4;
+ cfg->tx_l1_tx_band = 0x4;
+ cfg->tx_l2_tx_band = 0x4;
+ cfg->tx_l3_tx_band = 0x4;
+ cfg->com_svs_mode_clk_sel = 0x1;
+ cfg->com_hsclk_sel = 0x20;
+ cfg->com_pll_cctrl_mode0 = 0x28;
+ cfg->com_pll_rctrl_mode0 = 0x16;
+ cfg->com_cp_ctrl_mode0 = 0xb;
+ cfg->com_dec_start_mode0 = 0x9a;
+ cfg->com_div_frac_start1_mode0 = 0x0;
+ cfg->com_div_frac_start2_mode0 = 0x0;
+ cfg->com_div_frac_start3_mode0 = 0xb;
+ cfg->com_integloop_gain0_mode0 = 0x80;
+ cfg->com_integloop_gain1_mode0 = 0x0;
+ cfg->com_lock_cmp_en = 0x0;
+ cfg->com_lock_cmp1_mode0 = 0xbf;
+ cfg->com_lock_cmp2_mode0 = 0x7b;
+ cfg->com_lock_cmp3_mode0 = 0x0;
+ cfg->com_core_clk_en = 0x2c;
+ cfg->com_coreclk_div = 0x5;
+ cfg->com_restrim_ctrl = 0x0;
+ cfg->com_vco_tune_ctrl = 0x0;
+ cfg->tx_l0_tx_drv_lvl = 0x25;
+ cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l1_tx_drv_lvl = 0x25;
+ cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l2_tx_drv_lvl = 0x25;
+ cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+ cfg->tx_l3_tx_drv_lvl = 0x22;
+ cfg->tx_l3_tx_emp_post1_lvl = 0x27;
+ cfg->tx_l0_vmode_ctrl1 = 0x0;
+ cfg->tx_l0_vmode_ctrl2 = 0xd;
+ cfg->tx_l1_vmode_ctrl1 = 0x0;
+ cfg->tx_l1_vmode_ctrl2 = 0xd;
+ cfg->tx_l2_vmode_ctrl1 = 0x0;
+ cfg->tx_l2_vmode_ctrl2 = 0xd;
+ cfg->tx_l3_vmode_ctrl1 = 0x0;
+ cfg->tx_l3_vmode_ctrl2 = 0x0;
+ cfg->tx_l0_res_code_lane_tx = 0x0;
+ cfg->tx_l1_res_code_lane_tx = 0x0;
+ cfg->tx_l2_res_code_lane_tx = 0x0;
+ cfg->tx_l3_res_code_lane_tx = 0x0;
+ cfg->phy_mode = 0x10;
+ break;
+ default:
+ return ERROR;
+ }
+
+ return NO_ERROR;
+
+}
+
+uint32_t hdmi_pll_config(uint32_t tmds_clk_rate)
+{
+ struct hdmi_8996_phy_pll_reg_cfg cfg = {0};
+ int rc = NO_ERROR;
+
+ rc = get_pll_settings(tmds_clk_rate, &cfg);
+ if (rc) {
+ dprintf(CRITICAL, "%s: Unsupported clock rate %u\n", __func__, tmds_clk_rate);
+ return rc;
+ }
+
+ /* Initially shut down PHY */
+ writel(0x0, HDMI_PHY_PD_CTL);
+ udelay(500);
+
+ /* Power up sequence */
+ writel(0x04, QSERDES_COM_BG_CTRL);
+
+ writel(0x1, HDMI_PHY_PD_CTL);
+ writel(0x20, QSERDES_COM_RESETSM_CNTRL);
+ writel(0x0F, HDMI_PHY_TX0_TX1_LANE_CTL);
+ writel(0x0F, HDMI_PHY_TX2_TX3_LANE_CTL);
+ writel(0x03, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_CLKBUF_ENABLE);
+ writel(0x03, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_CLKBUF_ENABLE);
+ writel(0x03, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_CLKBUF_ENABLE);
+ writel(0x03, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_CLKBUF_ENABLE);
+
+ writel(cfg.tx_l0_lane_mode, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_LANE_MODE);
+ writel(cfg.tx_l2_lane_mode, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_LANE_MODE);
+
+ writel(cfg.tx_l0_tx_band, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_TX_BAND);
+ writel(cfg.tx_l1_tx_band, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_TX_BAND);
+ writel(cfg.tx_l2_tx_band, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_TX_BAND);
+ writel(cfg.tx_l3_tx_band, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_TX_BAND);
+
+ writel(0x03, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_RESET_TSYNC_EN);
+ writel(0x03, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_RESET_TSYNC_EN);
+ writel(0x03, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_RESET_TSYNC_EN);
+ writel(0x03, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_RESET_TSYNC_EN);
+
+ writel(0x1E, QSERDES_COM_SYSCLK_BUF_ENABLE);
+ writel(0x07, QSERDES_COM_BIAS_EN_CLKBUFLR_EN);
+ writel(0x37, QSERDES_COM_SYSCLK_EN_SEL);
+ writel(0x02, QSERDES_COM_SYS_CLK_CTRL);
+ writel(0x0E, QSERDES_COM_CLK_ENABLE1);
+
+ /* Bypass VCO calibration */
+ writel(cfg.com_svs_mode_clk_sel, QSERDES_COM_SVS_MODE_CLK_SEL);
+
+ writel(0x0F, QSERDES_COM_BG_TRIM);
+ writel(0x0F, QSERDES_COM_PLL_IVCO);
+ writel(cfg.com_vco_tune_ctrl, QSERDES_COM_VCO_TUNE_CTRL);
+
+ writel(0x06, QSERDES_COM_BG_CTRL);
+
+ writel(0x30, QSERDES_COM_CLK_SELECT);
+ writel(cfg.com_hsclk_sel, QSERDES_COM_HSCLK_SEL);
+
+ writel(cfg.com_lock_cmp_en, QSERDES_COM_LOCK_CMP_EN);
+
+ writel(cfg.com_pll_cctrl_mode0, QSERDES_COM_PLL_CCTRL_MODE0);
+ writel(cfg.com_pll_rctrl_mode0, QSERDES_COM_PLL_RCTRL_MODE0);
+ writel(cfg.com_cp_ctrl_mode0, QSERDES_COM_CP_CTRL_MODE0);
+ writel(cfg.com_dec_start_mode0, QSERDES_COM_DEC_START_MODE0);
+ writel(cfg.com_div_frac_start1_mode0, QSERDES_COM_DIV_FRAC_START1_MODE0);
+ writel(cfg.com_div_frac_start2_mode0, QSERDES_COM_DIV_FRAC_START2_MODE0);
+ writel(cfg.com_div_frac_start3_mode0, QSERDES_COM_DIV_FRAC_START3_MODE0);
+
+ writel(cfg.com_integloop_gain0_mode0, QSERDES_COM_INTEGLOOP_GAIN0_MODE0);
+ writel(cfg.com_integloop_gain1_mode0, QSERDES_COM_INTEGLOOP_GAIN1_MODE0);
+
+ writel(cfg.com_lock_cmp1_mode0, QSERDES_COM_LOCK_CMP1_MODE0);
+ writel(cfg.com_lock_cmp2_mode0, QSERDES_COM_LOCK_CMP2_MODE0);
+ writel(cfg.com_lock_cmp3_mode0, QSERDES_COM_LOCK_CMP3_MODE0);
+
+ writel(0x00, QSERDES_COM_VCO_TUNE_MAP);
+ writel(cfg.com_core_clk_en, QSERDES_COM_CORE_CLK_EN);
+ writel(cfg.com_coreclk_div, QSERDES_COM_CORECLK_DIV);
+ writel(0x02, QSERDES_COM_CMN_CONFIG);
+
+ writel(0x15, QSERDES_COM_RESCODE_DIV_NUM);
+
+ /* TX lanes setup (TX 0/1/2/3) */
+ writel(cfg.tx_l0_tx_drv_lvl, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_TX_DRV_LVL);
+ writel(cfg.tx_l0_tx_emp_post1_lvl, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_TX_EMP_POST1_LVL);
+
+ writel(cfg.tx_l1_tx_drv_lvl, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_TX_DRV_LVL);
+ writel(cfg.tx_l1_tx_emp_post1_lvl, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_TX_EMP_POST1_LVL);
+
+ writel(cfg.tx_l2_tx_drv_lvl, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_TX_DRV_LVL);
+ writel(cfg.tx_l2_tx_emp_post1_lvl, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_TX_EMP_POST1_LVL);
+
+ writel(cfg.tx_l3_tx_drv_lvl, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_TX_DRV_LVL);
+ writel(cfg.tx_l3_tx_emp_post1_lvl, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_TX_EMP_POST1_LVL);
+
+ writel(cfg.tx_l0_vmode_ctrl1, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_VMODE_CTRL1);
+ writel(cfg.tx_l0_vmode_ctrl2, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_VMODE_CTRL2);
+
+ writel(cfg.tx_l1_vmode_ctrl1, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_VMODE_CTRL1);
+ writel(cfg.tx_l1_vmode_ctrl2, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_VMODE_CTRL2);
+
+ writel(cfg.tx_l2_vmode_ctrl1, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_VMODE_CTRL1);
+ writel(cfg.tx_l2_vmode_ctrl2, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_VMODE_CTRL2);
+
+ writel(cfg.tx_l3_vmode_ctrl1, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_VMODE_CTRL1);
+ writel(cfg.tx_l3_vmode_ctrl2, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_VMODE_CTRL2);
+
+ writel(0x00, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_TX_DRV_LVL_OFFSET);
+ writel(0x00, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_TX_DRV_LVL_OFFSET);
+ writel(0x00, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_TX_DRV_LVL_OFFSET);
+ writel(0x00, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_TX_DRV_LVL_OFFSET);
+
+ writel(0x00, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_RES_CODE_LANE_OFFSET);
+ writel(0x00, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_RES_CODE_LANE_OFFSET);
+ writel(0x00, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_RES_CODE_LANE_OFFSET);
+ writel(0x00, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_RES_CODE_LANE_OFFSET);
+
+ writel(cfg.phy_mode, HDMI_PHY_MODE);
+ writel(0x1F, HDMI_PHY_PD_CTL);
+
+ writel(0x03, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_TRAN_DRVR_EMP_EN);
+ writel(0x03, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_TRAN_DRVR_EMP_EN);
+ writel(0x03, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_TRAN_DRVR_EMP_EN);
+ writel(0x03, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_TRAN_DRVR_EMP_EN);
+
+ writel(0x40, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN);
+ writel(0x40, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN);
+ writel(0x40, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN);
+ writel(0x40, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN);
+
+ writel(0x0C, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_HP_PD_ENABLES);
+ writel(0x0C, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_HP_PD_ENABLES);
+ writel(0x0C, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_HP_PD_ENABLES);
+ writel(0x03, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_HP_PD_ENABLES);
+
+ return NO_ERROR;
+}
+
+int hdmi_vco_enable(void)
+{
+ uint32_t pll_locked = 0;
+ uint32_t phy_ready = 0;
+ uint32_t status = 0;
+ uint32_t num_reads = 0;
+
+ writel(0x1, HDMI_PHY_CFG);
+ udelay(100);
+
+ writel(0x19, HDMI_PHY_CFG);
+ udelay(100);
+
+ num_reads = HDMI_PLL_POLL_MAX_READS;
+ status = readl(QSERDES_COM_C_READY_STATUS);
+ while (!(status & BIT(0)) && num_reads) {
+ status = readl(QSERDES_COM_C_READY_STATUS);
+ num_reads--;
+ udelay(HDMI_PLL_POLL_TIMEOUT_US);
+ }
+
+ if ((status & BIT(0)) == 1 && num_reads) {
+ pll_locked = 1;
+ } else {
+ pll_locked = 0;
+ }
+
+ dprintf(INFO, "%s: pll_locked = %d\n", __func__, pll_locked);
+
+ writel(0x6F, HDMI_TX_L0_BASE_OFFSET +
+ QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+ writel(0x6F, HDMI_TX_L1_BASE_OFFSET +
+ QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+ writel(0x6F, HDMI_TX_L2_BASE_OFFSET +
+ QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+ writel(0x6F, HDMI_TX_L3_BASE_OFFSET +
+ QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+
+ /* Disable SSC */
+ writel(0x0, QSERDES_COM_SSC_PER1);
+ writel(0x0, QSERDES_COM_SSC_PER2);
+ writel(0x0, QSERDES_COM_SSC_STEP_SIZE1);
+ writel(0x0, QSERDES_COM_SSC_STEP_SIZE2);
+ writel(0x2, QSERDES_COM_SSC_EN_CENTER);
+
+ num_reads = HDMI_PLL_POLL_MAX_READS;
+ status = readl(HDMI_PHY_STATUS);
+ while (!(status & BIT(0)) && num_reads) {
+ status = readl(HDMI_PHY_STATUS);
+ num_reads--;
+ udelay(HDMI_PLL_POLL_TIMEOUT_US);
+ }
+
+ if ((status & BIT(0)) == 1 && num_reads) {
+ phy_ready = 1;
+ } else {
+ phy_ready = 0;
+ }
+
+ dprintf(INFO, "%s: phy_ready = %d\n", __func__, phy_ready);
+
+ /* Restart the retiming buffer */
+ writel(0x18, HDMI_PHY_CFG);
+ udelay(1);
+ writel(0x19, HDMI_PHY_CFG);
+
+ return NO_ERROR;
+}
+
+int hdmi_vco_disable(void)
+{
+ writel(0x0, HDMI_PHY_PD_CTL);
+ udelay(500);
+
+ return NO_ERROR;
+}
diff --git a/platform/msm_shared/reboot.c b/platform/msm_shared/reboot.c
index f3441cd..d9a1310 100644
--- a/platform/msm_shared/reboot.c
+++ b/platform/msm_shared/reboot.c
@@ -109,13 +109,16 @@
return;
}
+ if (reboot_reason != NORMAL_DLOAD && reboot_reason != EMERGENCY_DLOAD) {
#if USE_PON_REBOOT_REG
- value = REG_READ(PON_SOFT_RB_SPARE);
- value |= (reboot_reason << 2);
- REG_WRITE(PON_SOFT_RB_SPARE, value);
+ value = REG_READ(PON_SOFT_RB_SPARE);
+ value |= (reboot_reason << 2);
+ REG_WRITE(PON_SOFT_RB_SPARE, value);
#else
- writel(reboot_reason, RESTART_REASON_ADDR);
+ writel(reboot_reason, RESTART_REASON_ADDR);
#endif
+ }
+
/* For Dload cases do a warm reset
* For other cases do a hard reset
*/
diff --git a/platform/msm_shared/reboot.h b/platform/msm_shared/reboot.h
index 58085df..2794d72 100644
--- a/platform/msm_shared/reboot.h
+++ b/platform/msm_shared/reboot.h
@@ -48,7 +48,9 @@
DM_VERITY_ENFORCING = 0x77665509,
DM_VERITY_KEYSCLEAR = 0x7766550A,
#endif
- /* warm reset start from 0xF0000000 */
+ /* Don't write the reason to PON reg or SMEM
+ * if the value is more than 0xF0000000
+ */
NORMAL_DLOAD = 0xF0000001,
EMERGENCY_DLOAD,
};
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index f426e93..7a9e688 100755
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -582,7 +582,9 @@
$(LOCAL_DIR)/mipi_dsi_autopll_thulium.o \
$(LOCAL_DIR)/shutdown_detect.o \
$(LOCAL_DIR)/i2c_qup.o \
- $(LOCAL_DIR)/mipi_dsi_i2c.o
+ $(LOCAL_DIR)/mipi_dsi_i2c.o \
+ $(LOCAL_DIR)/mdss_hdmi.o \
+ $(LOCAL_DIR)/mdss_hdmi_pll_8996.o
endif
ifeq ($(ENABLE_UFS_SUPPORT), 1)
diff --git a/project/mdm9640.mk b/project/mdm9640.mk
index 2c81541..d72ee16 100644
--- a/project/mdm9640.mk
+++ b/project/mdm9640.mk
@@ -17,6 +17,7 @@
ENABLE_USB30_SUPPORT := 1
ENABLE_SDHCI_SUPPORT := 1
ENABLE_BOOT_CONFIG_SUPPORT := 1
+ENABLE_VADC_HC_SUPPORT := true
MODULES += app/aboot
diff --git a/target/msm8952/include/target/display.h b/target/msm8952/include/target/display.h
index 65f689a..97aadf2 100644
--- a/target/msm8952/include/target/display.h
+++ b/target/msm8952/include/target/display.h
@@ -81,7 +81,7 @@
/*---------------------------------------------------------------------------*/
#define DISPLAY_CMDLINE_PREFIX " mdss_mdp.panel="
-#define MIPI_FB_ADDR 0x8DD00000
+#define MIPI_FB_ADDR 0x90000000
#define MIPI_HSYNC_PULSE_WIDTH 12
#define MIPI_HSYNC_BACK_PORCH_DCLK 32
diff --git a/target/msm8952/meminfo.c b/target/msm8952/meminfo.c
index b2f46df..bb23004 100644
--- a/target/msm8952/meminfo.c
+++ b/target/msm8952/meminfo.c
@@ -81,5 +81,5 @@
unsigned target_get_max_flash_size(void)
{
- return (512 * 1024 * 1024);
+ return (511 * 1024 * 1024);
}
diff --git a/target/msm8952/rules.mk b/target/msm8952/rules.mk
index c199e56..e6ecd1b 100644
--- a/target/msm8952/rules.mk
+++ b/target/msm8952/rules.mk
@@ -12,7 +12,7 @@
MEMSIZE := 0x00300000 # 3MB
BASE_ADDR := 0x80000000
-SCRATCH_ADDR := 0x90100000
+SCRATCH_ADDR := 0xA0100000
DEFINES += DISPLAY_SPLASH_SCREEN=1
DEFINES += DISPLAY_TYPE_MIPI=1
diff --git a/target/msm8996/include/target/display.h b/target/msm8996/include/target/display.h
index 5b21a1f..9ee5ec3 100644
--- a/target/msm8996/include/target/display.h
+++ b/target/msm8996/include/target/display.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -33,6 +33,7 @@
/* HEADER files */
/*---------------------------------------------------------------------------*/
#include <display_resource.h>
+#include <msm_panel.h>
/*---------------------------------------------------------------------------*/
/* Target Physical configuration */
@@ -67,6 +68,7 @@
#define DISPLAY_CMDLINE_PREFIX " mdss_mdp.panel="
#define MIPI_FB_ADDR 0x83400000
+#define HDMI_FB_ADDR 0xB1C00000
#define MIPI_HSYNC_PULSE_WIDTH 16
#define MIPI_HSYNC_BACK_PORCH_DCLK 32
@@ -79,7 +81,8 @@
#define PWM_BL_LPG_CHAN_ID 4 /* lpg_out<3> */
#define HDMI_PANEL_NAME "hdmi"
-#define HDMI_CONTROLLER_STRING "hdmi:0"
+#define HDMI_CONTROLLER_STRING "hdmi:"
+#define HDMI_VIC_LEN 5
/*---------------------------------------------------------------------------*/
/* Functions */
@@ -93,5 +96,9 @@
void target_force_cont_splash_disable(uint8_t override);
uint8_t target_panel_auto_detect_enabled();
void target_set_switch_gpio(int enable_dsi2hdmibridge);
+int target_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo);
+int target_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo);
+int target_hdmi_regulator_ctrl(uint8_t enable);
+int target_hdmi_gpio_ctrl(uint8_t enable);
#endif
diff --git a/target/msm8996/regulator.c b/target/msm8996/regulator.c
index 909082d..a95a42f 100644
--- a/target/msm8996/regulator.c
+++ b/target/msm8996/regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -48,6 +48,23 @@
},
};
+static uint32_t ldo12[][11]=
+{
+ {
+ LDOA_RES_TYPE, 12,
+ KEY_SOFTWARE_ENABLE, 4, GENERIC_DISABLE,
+ KEY_MICRO_VOLT, 4, 0,
+ KEY_CURRENT, 4, 0,
+ },
+
+ {
+ LDOA_RES_TYPE, 12,
+ KEY_SOFTWARE_ENABLE, 4, GENERIC_ENABLE,
+ KEY_MICRO_VOLT, 4, 1800000,
+ KEY_CURRENT, 4, 11,
+ },
+};
+
static uint32_t ldo14[][11]=
{
{
@@ -88,6 +105,9 @@
if (enable & REG_LDO2)
rpm_send_data(&ldo2[GENERIC_ENABLE][0], 36, RPM_REQUEST_TYPE);
+ if (enable & REG_LDO12)
+ rpm_send_data(&ldo12[GENERIC_ENABLE][0], 36, RPM_REQUEST_TYPE);
+
if (enable & REG_LDO14)
rpm_send_data(&ldo14[GENERIC_ENABLE][0], 36, RPM_REQUEST_TYPE);
@@ -100,6 +120,9 @@
if (enable & REG_LDO2)
rpm_send_data(&ldo2[GENERIC_DISABLE][0], 36, RPM_REQUEST_TYPE);
+ if (enable & REG_LDO12)
+ rpm_send_data(&ldo12[GENERIC_DISABLE][0], 36, RPM_REQUEST_TYPE);
+
if (enable & REG_LDO14)
rpm_send_data(&ldo14[GENERIC_DISABLE][0], 36, RPM_REQUEST_TYPE);
diff --git a/target/msm8996/target_display.c b/target/msm8996/target_display.c
index 5086451..e7cc537 100644
--- a/target/msm8996/target_display.c
+++ b/target/msm8996/target_display.c
@@ -33,6 +33,7 @@
#include <err.h>
#include <msm_panel.h>
#include <mipi_dsi.h>
+#include <mdss_hdmi.h>
#include <pm8x41.h>
#include <pm8x41_wled.h>
#include <qpnp_wled.h>
@@ -92,6 +93,130 @@
"msmgpio", 105, 3, 1, 0, 1
};
+/* gpio name, id, strength, direction, pull, state. */
+static struct gpio_pin hdmi_cec_gpio = { /* CEC */
+ "msmgpio", 31, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_ddc_clk_gpio = { /* DDC CLK */
+ "msmgpio", 32, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_ddc_data_gpio = { /* DDC DATA */
+ "msmgpio", 33, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_hpd_gpio = { /* HPD, input */
+ "msmgpio", 34, 7, 0, 1, 1
+};
+
+static void target_hdmi_ldo_enable(uint8_t enable)
+{
+ if (enable)
+ regulator_enable(REG_LDO12);
+ else
+ regulator_disable(REG_LDO12);
+}
+
+static void target_hdmi_mpp4_enable(uint8_t enable)
+{
+ struct pm8x41_mpp mpp;
+
+ /* Enable MPP4 */
+ pmi8994_config_mpp_slave_id(0);
+
+ mpp.base = PM8x41_MMP4_BASE;
+ mpp.vin = MPP_VIN2;
+ mpp.mode = MPP_HIGH;;
+ if (enable) {
+ pm8x41_config_output_mpp(&mpp);
+ pm8x41_enable_mpp(&mpp, MPP_ENABLE);
+ } else {
+ pm8x41_enable_mpp(&mpp, MPP_DISABLE);
+ }
+
+ /* Need delay before power on regulators */
+ mdelay(20);
+}
+
+int target_hdmi_regulator_ctrl(uint8_t enable)
+{
+ target_hdmi_ldo_enable(enable);
+
+ target_hdmi_mpp4_enable(enable);
+
+ return 0;
+}
+
+int target_hdmi_gpio_ctrl(uint8_t enable)
+{
+ gpio_tlmm_config(hdmi_cec_gpio.pin_id, 1, /* gpio 31, CEC */
+ hdmi_cec_gpio.pin_direction, hdmi_cec_gpio.pin_pull,
+ hdmi_cec_gpio.pin_strength, hdmi_cec_gpio.pin_state);
+
+ gpio_tlmm_config(hdmi_ddc_clk_gpio.pin_id, 1, /* gpio 32, DDC CLK */
+ hdmi_ddc_clk_gpio.pin_direction, hdmi_ddc_clk_gpio.pin_pull,
+ hdmi_ddc_clk_gpio.pin_strength, hdmi_ddc_clk_gpio.pin_state);
+
+
+ gpio_tlmm_config(hdmi_ddc_data_gpio.pin_id, 1, /* gpio 33, DDC DATA */
+ hdmi_ddc_data_gpio.pin_direction, hdmi_ddc_data_gpio.pin_pull,
+ hdmi_ddc_data_gpio.pin_strength, hdmi_ddc_data_gpio.pin_state);
+
+ gpio_tlmm_config(hdmi_hpd_gpio.pin_id, 1, /* gpio 34, HPD */
+ hdmi_hpd_gpio.pin_direction, hdmi_hpd_gpio.pin_pull,
+ hdmi_hpd_gpio.pin_strength, hdmi_hpd_gpio.pin_state);
+
+ gpio_set(hdmi_cec_gpio.pin_id, hdmi_cec_gpio.pin_direction);
+ gpio_set(hdmi_ddc_clk_gpio.pin_id, hdmi_ddc_clk_gpio.pin_direction);
+ gpio_set(hdmi_ddc_data_gpio.pin_id, hdmi_ddc_data_gpio.pin_direction);
+ gpio_set(hdmi_hpd_gpio.pin_id, hdmi_hpd_gpio.pin_direction);
+
+ return NO_ERROR;
+}
+
+int target_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+ if (enable) {
+ hdmi_phy_reset();
+ hdmi_pll_config(pinfo->clk_rate);
+ hdmi_vco_enable();
+ hdmi_pixel_clk_enable(pinfo->clk_rate);
+ } else if(!target_cont_splash_screen()) {
+ /* Disable clocks if continuous splash off */
+ hdmi_pixel_clk_disable();
+ hdmi_vco_disable();
+ }
+
+ return NO_ERROR;
+}
+
+int target_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+ dprintf(SPEW, "%s: target_panel_clock\n", __func__);
+
+ uint32_t board_version = board_soc_version();
+
+ if (board_version == 0x20000 || board_version == 0x20001)
+ video_gdsc_enable();
+
+ if (enable) {
+ mmss_gdsc_enable();
+ mmss_bus_clock_enable();
+ mdp_clock_enable();
+ hdmi_ahb_core_clk_enable();
+ } else if(!target_cont_splash_screen()) {
+ hdmi_core_ahb_clk_disable();
+ mdp_clock_disable();
+ mmss_bus_clock_disable();
+ mmss_gdsc_disable();
+ if (board_version == 0x20000 || board_version == 0x20001)
+ video_gdsc_disable();
+ }
+
+ return NO_ERROR;
+}
+
static uint32_t thulium_dsi_pll_lock_status(uint32_t pll_base, uint32_t off,
uint32_t bit)
{
@@ -579,6 +704,7 @@
int prefix_string_len = strlen(DISPLAY_CMDLINE_PREFIX);
bool ret = true;
struct oem_panel_data oem = mdss_dsi_get_oem_data();
+ char vic_buf[HDMI_VIC_LEN] = "0";
if (!strcmp(oem.panel, HDMI_PANEL_NAME)) {
if (buf_size < (prefix_string_len + LK_OVERRIDE_PANEL_LEN +
@@ -592,6 +718,9 @@
strlcat(pbuf, LK_OVERRIDE_PANEL, buf_size);
buf_size -= LK_OVERRIDE_PANEL_LEN;
strlcat(pbuf, HDMI_CONTROLLER_STRING, buf_size);
+ buf_size -= strlen(HDMI_CONTROLLER_STRING);
+ mdss_hdmi_get_vic(vic_buf);
+ strlcat(pbuf, vic_buf, buf_size);
} else {
ret = gcdb_display_cmdline_arg(pbuf, buf_size);
}
@@ -629,6 +758,8 @@
oem.panel);
return;
} else if (!strcmp(oem.panel, HDMI_PANEL_NAME)) {
+ dprintf(INFO, "%s: HDMI is primary\n", __func__);
+ mdss_hdmi_display_init(MDP_REV_50, (void *) HDMI_FB_ADDR);
return;
}
@@ -645,5 +776,10 @@
void target_display_shutdown(void)
{
- gcdb_display_shutdown();
+ struct oem_panel_data oem = mdss_dsi_get_oem_data();
+ if (!strcmp(oem.panel, HDMI_PANEL_NAME)) {
+ msm_display_off();
+ } else {
+ gcdb_display_shutdown();
+ }
}