| /* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/err.h> |
| #include <linux/delay.h> |
| #include <linux/iopoll.h> |
| #include <linux/clk/msm-clk-provider.h> |
| #include <linux/clk/msm-clk.h> |
| #include <linux/clk/msm-clock-generic.h> |
| #include <dt-bindings/clock/msm-clocks-8996.h> |
| |
| #include "mdss-pll.h" |
| #include "mdss-hdmi-pll.h" |
| |
| /* CONSTANTS */ |
| #define HDMI_BIT_CLK_TO_PIX_CLK_RATIO 10 |
| #define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL |
| #define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL |
| #define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000 |
| #define HDMI_CLKS_PLL_DIVSEL 0 |
| #define HDMI_CORECLK_DIV 5 |
| #define HDMI_REF_CLOCK 19200000 |
| #define HDMI_64B_ERR_VAL 0xFFFFFFFFFFFFFFFF |
| #define HDMI_VERSION_8996_V1 1 |
| #define HDMI_VERSION_8996_V2 2 |
| #define HDMI_VERSION_8996_V3 3 |
| #define HDMI_VERSION_8996_V3_1_8 4 |
| |
| #define HDMI_VCO_MAX_FREQ 12000000000 |
| #define HDMI_VCO_MIN_FREQ 8000000000 |
| #define HDMI_2400MHZ_BIT_CLK_HZ 2400000000UL |
| #define HDMI_2250MHZ_BIT_CLK_HZ 2250000000UL |
| #define HDMI_2000MHZ_BIT_CLK_HZ 2000000000UL |
| #define HDMI_1700MHZ_BIT_CLK_HZ 1700000000UL |
| #define HDMI_1200MHZ_BIT_CLK_HZ 1200000000UL |
| #define HDMI_1334MHZ_BIT_CLK_HZ 1334000000UL |
| #define HDMI_1000MHZ_BIT_CLK_HZ 1000000000UL |
| #define HDMI_850MHZ_BIT_CLK_HZ 850000000 |
| #define HDMI_667MHZ_BIT_CLK_HZ 667000000 |
| #define HDMI_600MHZ_BIT_CLK_HZ 600000000 |
| #define HDMI_500MHZ_BIT_CLK_HZ 500000000 |
| #define HDMI_450MHZ_BIT_CLK_HZ 450000000 |
| #define HDMI_334MHZ_BIT_CLK_HZ 334000000 |
| #define HDMI_300MHZ_BIT_CLK_HZ 300000000 |
| #define HDMI_282MHZ_BIT_CLK_HZ 282000000 |
| #define HDMI_250MHZ_BIT_CLK_HZ 250000000 |
| #define HDMI_KHZ_TO_HZ 1000 |
| |
| /* PLL REGISTERS */ |
| #define QSERDES_COM_ATB_SEL1 (0x000) |
| #define QSERDES_COM_ATB_SEL2 (0x004) |
| #define QSERDES_COM_FREQ_UPDATE (0x008) |
| #define QSERDES_COM_BG_TIMER (0x00C) |
| #define QSERDES_COM_SSC_EN_CENTER (0x010) |
| #define QSERDES_COM_SSC_ADJ_PER1 (0x014) |
| #define QSERDES_COM_SSC_ADJ_PER2 (0x018) |
| #define QSERDES_COM_SSC_PER1 (0x01C) |
| #define QSERDES_COM_SSC_PER2 (0x020) |
| #define QSERDES_COM_SSC_STEP_SIZE1 (0x024) |
| #define QSERDES_COM_SSC_STEP_SIZE2 (0x028) |
| #define QSERDES_COM_POST_DIV (0x02C) |
| #define QSERDES_COM_POST_DIV_MUX (0x030) |
| #define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x034) |
| #define QSERDES_COM_CLK_ENABLE1 (0x038) |
| #define QSERDES_COM_SYS_CLK_CTRL (0x03C) |
| #define QSERDES_COM_SYSCLK_BUF_ENABLE (0x040) |
| #define QSERDES_COM_PLL_EN (0x044) |
| #define QSERDES_COM_PLL_IVCO (0x048) |
| #define QSERDES_COM_LOCK_CMP1_MODE0 (0x04C) |
| #define QSERDES_COM_LOCK_CMP2_MODE0 (0x050) |
| #define QSERDES_COM_LOCK_CMP3_MODE0 (0x054) |
| #define QSERDES_COM_LOCK_CMP1_MODE1 (0x058) |
| #define QSERDES_COM_LOCK_CMP2_MODE1 (0x05C) |
| #define QSERDES_COM_LOCK_CMP3_MODE1 (0x060) |
| #define QSERDES_COM_LOCK_CMP1_MODE2 (0x064) |
| #define QSERDES_COM_CMN_RSVD0 (0x064) |
| #define QSERDES_COM_LOCK_CMP2_MODE2 (0x068) |
| #define QSERDES_COM_EP_CLOCK_DETECT_CTRL (0x068) |
| #define QSERDES_COM_LOCK_CMP3_MODE2 (0x06C) |
| #define QSERDES_COM_SYSCLK_DET_COMP_STATUS (0x06C) |
| #define QSERDES_COM_BG_TRIM (0x070) |
| #define QSERDES_COM_CLK_EP_DIV (0x074) |
| #define QSERDES_COM_CP_CTRL_MODE0 (0x078) |
| #define QSERDES_COM_CP_CTRL_MODE1 (0x07C) |
| #define QSERDES_COM_CP_CTRL_MODE2 (0x080) |
| #define QSERDES_COM_CMN_RSVD1 (0x080) |
| #define QSERDES_COM_PLL_RCTRL_MODE0 (0x084) |
| #define QSERDES_COM_PLL_RCTRL_MODE1 (0x088) |
| #define QSERDES_COM_PLL_RCTRL_MODE2 (0x08C) |
| #define QSERDES_COM_CMN_RSVD2 (0x08C) |
| #define QSERDES_COM_PLL_CCTRL_MODE0 (0x090) |
| #define QSERDES_COM_PLL_CCTRL_MODE1 (0x094) |
| #define QSERDES_COM_PLL_CCTRL_MODE2 (0x098) |
| #define QSERDES_COM_CMN_RSVD3 (0x098) |
| #define QSERDES_COM_PLL_CNTRL (0x09C) |
| #define QSERDES_COM_PHASE_SEL_CTRL (0x0A0) |
| #define QSERDES_COM_PHASE_SEL_DC (0x0A4) |
| #define QSERDES_COM_CORE_CLK_IN_SYNC_SEL (0x0A8) |
| #define QSERDES_COM_BIAS_EN_CTRL_BY_PSM (0x0A8) |
| #define QSERDES_COM_SYSCLK_EN_SEL (0x0AC) |
| #define QSERDES_COM_CML_SYSCLK_SEL (0x0B0) |
| #define QSERDES_COM_RESETSM_CNTRL (0x0B4) |
| #define QSERDES_COM_RESETSM_CNTRL2 (0x0B8) |
| #define QSERDES_COM_RESTRIM_CTRL (0x0BC) |
| #define QSERDES_COM_RESTRIM_CTRL2 (0x0C0) |
| #define QSERDES_COM_RESCODE_DIV_NUM (0x0C4) |
| #define QSERDES_COM_LOCK_CMP_EN (0x0C8) |
| #define QSERDES_COM_LOCK_CMP_CFG (0x0CC) |
| #define QSERDES_COM_DEC_START_MODE0 (0x0D0) |
| #define QSERDES_COM_DEC_START_MODE1 (0x0D4) |
| #define QSERDES_COM_DEC_START_MODE2 (0x0D8) |
| #define QSERDES_COM_VCOCAL_DEADMAN_CTRL (0x0D8) |
| #define QSERDES_COM_DIV_FRAC_START1_MODE0 (0x0DC) |
| #define QSERDES_COM_DIV_FRAC_START2_MODE0 (0x0E0) |
| #define QSERDES_COM_DIV_FRAC_START3_MODE0 (0x0E4) |
| #define QSERDES_COM_DIV_FRAC_START1_MODE1 (0x0E8) |
| #define QSERDES_COM_DIV_FRAC_START2_MODE1 (0x0EC) |
| #define QSERDES_COM_DIV_FRAC_START3_MODE1 (0x0F0) |
| #define QSERDES_COM_DIV_FRAC_START1_MODE2 (0x0F4) |
| #define QSERDES_COM_VCO_TUNE_MINVAL1 (0x0F4) |
| #define QSERDES_COM_DIV_FRAC_START2_MODE2 (0x0F8) |
| #define QSERDES_COM_VCO_TUNE_MINVAL2 (0x0F8) |
| #define QSERDES_COM_DIV_FRAC_START3_MODE2 (0x0FC) |
| #define QSERDES_COM_CMN_RSVD4 (0x0FC) |
| #define QSERDES_COM_INTEGLOOP_INITVAL (0x100) |
| #define QSERDES_COM_INTEGLOOP_EN (0x104) |
| #define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 (0x108) |
| #define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 (0x10C) |
| #define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 (0x110) |
| #define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 (0x114) |
| #define QSERDES_COM_INTEGLOOP_GAIN0_MODE2 (0x118) |
| #define QSERDES_COM_VCO_TUNE_MAXVAL1 (0x118) |
| #define QSERDES_COM_INTEGLOOP_GAIN1_MODE2 (0x11C) |
| #define QSERDES_COM_VCO_TUNE_MAXVAL2 (0x11C) |
| #define QSERDES_COM_RES_TRIM_CONTROL2 (0x120) |
| #define QSERDES_COM_VCO_TUNE_CTRL (0x124) |
| #define QSERDES_COM_VCO_TUNE_MAP (0x128) |
| #define QSERDES_COM_VCO_TUNE1_MODE0 (0x12C) |
| #define QSERDES_COM_VCO_TUNE2_MODE0 (0x130) |
| #define QSERDES_COM_VCO_TUNE1_MODE1 (0x134) |
| #define QSERDES_COM_VCO_TUNE2_MODE1 (0x138) |
| #define QSERDES_COM_VCO_TUNE1_MODE2 (0x13C) |
| #define QSERDES_COM_VCO_TUNE_INITVAL1 (0x13C) |
| #define QSERDES_COM_VCO_TUNE2_MODE2 (0x140) |
| #define QSERDES_COM_VCO_TUNE_INITVAL2 (0x140) |
| #define QSERDES_COM_VCO_TUNE_TIMER1 (0x144) |
| #define QSERDES_COM_VCO_TUNE_TIMER2 (0x148) |
| #define QSERDES_COM_SAR (0x14C) |
| #define QSERDES_COM_SAR_CLK (0x150) |
| #define QSERDES_COM_SAR_CODE_OUT_STATUS (0x154) |
| #define QSERDES_COM_SAR_CODE_READY_STATUS (0x158) |
| #define QSERDES_COM_CMN_STATUS (0x15C) |
| #define QSERDES_COM_RESET_SM_STATUS (0x160) |
| #define QSERDES_COM_RESTRIM_CODE_STATUS (0x164) |
| #define QSERDES_COM_PLLCAL_CODE1_STATUS (0x168) |
| #define QSERDES_COM_PLLCAL_CODE2_STATUS (0x16C) |
| #define QSERDES_COM_BG_CTRL (0x170) |
| #define QSERDES_COM_CLK_SELECT (0x174) |
| #define QSERDES_COM_HSCLK_SEL (0x178) |
| #define QSERDES_COM_INTEGLOOP_BINCODE_STATUS (0x17C) |
| #define QSERDES_COM_PLL_ANALOG (0x180) |
| #define QSERDES_COM_CORECLK_DIV (0x184) |
| #define QSERDES_COM_SW_RESET (0x188) |
| #define QSERDES_COM_CORE_CLK_EN (0x18C) |
| #define QSERDES_COM_C_READY_STATUS (0x190) |
| #define QSERDES_COM_CMN_CONFIG (0x194) |
| #define QSERDES_COM_CMN_RATE_OVERRIDE (0x198) |
| #define QSERDES_COM_SVS_MODE_CLK_SEL (0x19C) |
| #define QSERDES_COM_DEBUG_BUS0 (0x1A0) |
| #define QSERDES_COM_DEBUG_BUS1 (0x1A4) |
| #define QSERDES_COM_DEBUG_BUS2 (0x1A8) |
| #define QSERDES_COM_DEBUG_BUS3 (0x1AC) |
| #define QSERDES_COM_DEBUG_BUS_SEL (0x1B0) |
| #define QSERDES_COM_CMN_MISC1 (0x1B4) |
| #define QSERDES_COM_CMN_MISC2 (0x1B8) |
| #define QSERDES_COM_CORECLK_DIV_MODE1 (0x1BC) |
| #define QSERDES_COM_CORECLK_DIV_MODE2 (0x1C0) |
| #define QSERDES_COM_CMN_RSVD5 (0x1C0) |
| |
| /* Tx Channel base addresses */ |
| #define HDMI_TX_L0_BASE_OFFSET (0x400) |
| #define HDMI_TX_L1_BASE_OFFSET (0x600) |
| #define HDMI_TX_L2_BASE_OFFSET (0x800) |
| #define HDMI_TX_L3_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 (0xC00) |
| |
| #define HDMI_PHY_CFG (0x00) |
| #define HDMI_PHY_PD_CTL (0x04) |
| #define HDMI_PHY_MODE (0x08) |
| #define HDMI_PHY_MISR_CLEAR (0x0C) |
| #define HDMI_PHY_TX0_TX1_BIST_CFG0 (0x10) |
| #define HDMI_PHY_TX0_TX1_BIST_CFG1 (0x14) |
| #define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE0 (0x18) |
| #define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE1 (0x1C) |
| #define HDMI_PHY_TX0_TX1_BIST_PATTERN0 (0x20) |
| #define HDMI_PHY_TX0_TX1_BIST_PATTERN1 (0x24) |
| #define HDMI_PHY_TX2_TX3_BIST_CFG0 (0x28) |
| #define HDMI_PHY_TX2_TX3_BIST_CFG1 (0x2C) |
| #define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE0 (0x30) |
| #define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE1 (0x34) |
| #define HDMI_PHY_TX2_TX3_BIST_PATTERN0 (0x38) |
| #define HDMI_PHY_TX2_TX3_BIST_PATTERN1 (0x3C) |
| #define HDMI_PHY_DEBUG_BUS_SEL (0x40) |
| #define HDMI_PHY_TXCAL_CFG0 (0x44) |
| #define HDMI_PHY_TXCAL_CFG1 (0x48) |
| #define HDMI_PHY_TX0_TX1_LANE_CTL (0x4C) |
| #define HDMI_PHY_TX2_TX3_LANE_CTL (0x50) |
| #define HDMI_PHY_LANE_BIST_CONFIG (0x54) |
| #define HDMI_PHY_CLOCK (0x58) |
| #define HDMI_PHY_MISC1 (0x5C) |
| #define HDMI_PHY_MISC2 (0x60) |
| #define HDMI_PHY_TX0_TX1_BIST_STATUS0 (0x64) |
| #define HDMI_PHY_TX0_TX1_BIST_STATUS1 (0x68) |
| #define HDMI_PHY_TX0_TX1_BIST_STATUS2 (0x6C) |
| #define HDMI_PHY_TX2_TX3_BIST_STATUS0 (0x70) |
| #define HDMI_PHY_TX2_TX3_BIST_STATUS1 (0x74) |
| #define HDMI_PHY_TX2_TX3_BIST_STATUS2 (0x78) |
| #define HDMI_PHY_PRE_MISR_STATUS0 (0x7C) |
| #define HDMI_PHY_PRE_MISR_STATUS1 (0x80) |
| #define HDMI_PHY_PRE_MISR_STATUS2 (0x84) |
| #define HDMI_PHY_PRE_MISR_STATUS3 (0x88) |
| #define HDMI_PHY_POST_MISR_STATUS0 (0x8C) |
| #define HDMI_PHY_POST_MISR_STATUS1 (0x90) |
| #define HDMI_PHY_POST_MISR_STATUS2 (0x94) |
| #define HDMI_PHY_POST_MISR_STATUS3 (0x98) |
| #define HDMI_PHY_STATUS (0x9C) |
| #define HDMI_PHY_MISC3_STATUS (0xA0) |
| #define HDMI_PHY_MISC4_STATUS (0xA4) |
| #define HDMI_PHY_DEBUG_BUS0 (0xA8) |
| #define HDMI_PHY_DEBUG_BUS1 (0xAC) |
| #define HDMI_PHY_DEBUG_BUS2 (0xB0) |
| #define HDMI_PHY_DEBUG_BUS3 (0xB4) |
| #define HDMI_PHY_PHY_REVISION_ID0 (0xB8) |
| #define HDMI_PHY_PHY_REVISION_ID1 (0xBC) |
| #define HDMI_PHY_PHY_REVISION_ID2 (0xC0) |
| #define HDMI_PHY_PHY_REVISION_ID3 (0xC4) |
| |
| #define HDMI_PLL_POLL_MAX_READS 100 |
| #define HDMI_PLL_POLL_TIMEOUT_US 1500 |
| |
| enum hdmi_pll_freqs { |
| HDMI_PCLK_25200_KHZ, |
| HDMI_PCLK_27027_KHZ, |
| HDMI_PCLK_27000_KHZ, |
| HDMI_PCLK_74250_KHZ, |
| HDMI_PCLK_148500_KHZ, |
| HDMI_PCLK_154000_KHZ, |
| HDMI_PCLK_268500_KHZ, |
| HDMI_PCLK_297000_KHZ, |
| HDMI_PCLK_594000_KHZ, |
| HDMI_PCLK_MAX |
| }; |
| |
| struct hdmi_8996_phy_pll_reg_cfg { |
| u32 tx_l0_lane_mode; |
| u32 tx_l2_lane_mode; |
| u32 tx_l0_tx_band; |
| u32 tx_l1_tx_band; |
| u32 tx_l2_tx_band; |
| u32 tx_l3_tx_band; |
| u32 com_svs_mode_clk_sel; |
| u32 com_hsclk_sel; |
| u32 com_pll_cctrl_mode0; |
| u32 com_pll_rctrl_mode0; |
| u32 com_cp_ctrl_mode0; |
| u32 com_dec_start_mode0; |
| u32 com_div_frac_start1_mode0; |
| u32 com_div_frac_start2_mode0; |
| u32 com_div_frac_start3_mode0; |
| u32 com_integloop_gain0_mode0; |
| u32 com_integloop_gain1_mode0; |
| u32 com_lock_cmp_en; |
| u32 com_lock_cmp1_mode0; |
| u32 com_lock_cmp2_mode0; |
| u32 com_lock_cmp3_mode0; |
| u32 com_core_clk_en; |
| u32 com_coreclk_div; |
| u32 com_restrim_ctrl; |
| u32 com_vco_tune_ctrl; |
| |
| u32 tx_l0_tx_drv_lvl; |
| u32 tx_l0_tx_emp_post1_lvl; |
| u32 tx_l1_tx_drv_lvl; |
| u32 tx_l1_tx_emp_post1_lvl; |
| u32 tx_l2_tx_drv_lvl; |
| u32 tx_l2_tx_emp_post1_lvl; |
| u32 tx_l3_tx_drv_lvl; |
| u32 tx_l3_tx_emp_post1_lvl; |
| u32 tx_l0_vmode_ctrl1; |
| u32 tx_l0_vmode_ctrl2; |
| u32 tx_l1_vmode_ctrl1; |
| u32 tx_l1_vmode_ctrl2; |
| u32 tx_l2_vmode_ctrl1; |
| u32 tx_l2_vmode_ctrl2; |
| u32 tx_l3_vmode_ctrl1; |
| u32 tx_l3_vmode_ctrl2; |
| u32 tx_l0_res_code_lane_tx; |
| u32 tx_l1_res_code_lane_tx; |
| u32 tx_l2_res_code_lane_tx; |
| u32 tx_l3_res_code_lane_tx; |
| |
| u32 phy_mode; |
| }; |
| |
| struct hdmi_8996_v3_post_divider { |
| u64 vco_freq; |
| u64 hsclk_divsel; |
| u64 vco_ratio; |
| u64 tx_band_sel; |
| u64 half_rate_mode; |
| }; |
| |
| static inline struct hdmi_pll_vco_clk *to_hdmi_8996_vco_clk(struct clk *clk) |
| { |
| return container_of(clk, struct hdmi_pll_vco_clk, c); |
| } |
| |
| static inline u64 hdmi_8996_v1_get_post_div_lt_2g(u64 bclk) |
| { |
| if (bclk >= HDMI_2400MHZ_BIT_CLK_HZ) |
| return 2; |
| else if (bclk >= HDMI_1700MHZ_BIT_CLK_HZ) |
| return 3; |
| else if (bclk >= HDMI_1200MHZ_BIT_CLK_HZ) |
| return 4; |
| else if (bclk >= HDMI_850MHZ_BIT_CLK_HZ) |
| return 3; |
| else if (bclk >= HDMI_600MHZ_BIT_CLK_HZ) |
| return 4; |
| else if (bclk >= HDMI_450MHZ_BIT_CLK_HZ) |
| return 3; |
| else if (bclk >= HDMI_300MHZ_BIT_CLK_HZ) |
| return 4; |
| |
| return HDMI_64B_ERR_VAL; |
| } |
| |
| static inline u64 hdmi_8996_v2_get_post_div_lt_2g(u64 bclk, u64 vco_range) |
| { |
| u64 hdmi_8ghz = vco_range; |
| u64 tmp_calc; |
| |
| hdmi_8ghz <<= 2; |
| tmp_calc = hdmi_8ghz; |
| do_div(tmp_calc, 6U); |
| |
| if (bclk >= vco_range) |
| return 2; |
| else if (bclk >= tmp_calc) |
| return 3; |
| else if (bclk >= vco_range >> 1) |
| return 4; |
| |
| tmp_calc = hdmi_8ghz; |
| do_div(tmp_calc, 12U); |
| if (bclk >= tmp_calc) |
| return 3; |
| else if (bclk >= vco_range >> 2) |
| return 4; |
| |
| tmp_calc = hdmi_8ghz; |
| do_div(tmp_calc, 24U); |
| if (bclk >= tmp_calc) |
| return 3; |
| else if (bclk >= vco_range >> 3) |
| return 4; |
| |
| return HDMI_64B_ERR_VAL; |
| } |
| |
| static inline u64 hdmi_8996_v2_get_post_div_gt_2g(u64 hsclk) |
| { |
| if (hsclk >= 0 && hsclk <= 3) |
| return hsclk + 1; |
| |
| return HDMI_64B_ERR_VAL; |
| } |
| |
| static inline u64 hdmi_8996_get_coreclk_div_lt_2g(u64 bclk) |
| { |
| if (bclk >= HDMI_1334MHZ_BIT_CLK_HZ) |
| return 1; |
| else if (bclk >= HDMI_1000MHZ_BIT_CLK_HZ) |
| return 1; |
| else if (bclk >= HDMI_667MHZ_BIT_CLK_HZ) |
| return 2; |
| else if (bclk >= HDMI_500MHZ_BIT_CLK_HZ) |
| return 2; |
| else if (bclk >= HDMI_334MHZ_BIT_CLK_HZ) |
| return 3; |
| else if (bclk >= HDMI_250MHZ_BIT_CLK_HZ) |
| return 3; |
| |
| return HDMI_64B_ERR_VAL; |
| } |
| |
| static inline u64 hdmi_8996_get_coreclk_div_ratio(u64 clks_pll_divsel, |
| u64 coreclk_div) |
| { |
| if (clks_pll_divsel == 0) |
| return coreclk_div*2; |
| else if (clks_pll_divsel == 1) |
| return coreclk_div*4; |
| |
| return HDMI_64B_ERR_VAL; |
| } |
| |
| static inline u64 hdmi_8996_v1_get_tx_band(u64 bclk) |
| { |
| if (bclk >= 2400000000UL) |
| return 0; |
| if (bclk >= 1200000000UL) |
| return 1; |
| if (bclk >= 600000000UL) |
| return 2; |
| if (bclk >= 300000000UL) |
| return 3; |
| |
| return HDMI_64B_ERR_VAL; |
| } |
| |
| static inline u64 hdmi_8996_v2_get_tx_band(u64 bclk, u64 vco_range) |
| { |
| if (bclk >= vco_range) |
| return 0; |
| else if (bclk >= vco_range >> 1) |
| return 1; |
| else if (bclk >= vco_range >> 2) |
| return 2; |
| else if (bclk >= vco_range >> 3) |
| return 3; |
| |
| return HDMI_64B_ERR_VAL; |
| } |
| |
| static inline u64 hdmi_8996_v1_get_hsclk(u64 fdata) |
| { |
| if (fdata >= 9600000000UL) |
| return 0; |
| else if (fdata >= 4800000000UL) |
| return 1; |
| else if (fdata >= 3200000000UL) |
| return 2; |
| else if (fdata >= 2400000000UL) |
| return 3; |
| |
| return HDMI_64B_ERR_VAL; |
| } |
| |
| static inline u64 hdmi_8996_v2_get_hsclk(u64 fdata, u64 vco_range) |
| { |
| u64 tmp_calc = vco_range; |
| |
| tmp_calc <<= 2; |
| do_div(tmp_calc, 3U); |
| if (fdata >= (vco_range << 2)) |
| return 0; |
| else if (fdata >= (vco_range << 1)) |
| return 1; |
| else if (fdata >= tmp_calc) |
| return 2; |
| else if (fdata >= vco_range) |
| return 3; |
| |
| return HDMI_64B_ERR_VAL; |
| |
| } |
| |
| static inline u64 hdmi_8996_v2_get_vco_freq(u64 bclk, u64 vco_range) |
| { |
| u64 tx_band_div_ratio = 1U << hdmi_8996_v2_get_tx_band(bclk, vco_range); |
| u64 pll_post_div_ratio; |
| |
| if (bclk >= vco_range) { |
| u64 hsclk = hdmi_8996_v2_get_hsclk(bclk, vco_range); |
| |
| pll_post_div_ratio = hdmi_8996_v2_get_post_div_gt_2g(hsclk); |
| } else { |
| pll_post_div_ratio = hdmi_8996_v2_get_post_div_lt_2g(bclk, |
| vco_range); |
| } |
| |
| return bclk * (pll_post_div_ratio * tx_band_div_ratio); |
| } |
| |
| static inline u64 hdmi_8996_v2_get_fdata(u64 bclk, u64 vco_range) |
| { |
| if (bclk >= vco_range) |
| return bclk; |
| |
| { |
| u64 tmp_calc = hdmi_8996_v2_get_vco_freq(bclk, vco_range); |
| u64 pll_post_div_ratio_lt_2g = hdmi_8996_v2_get_post_div_lt_2g( |
| bclk, vco_range); |
| if (pll_post_div_ratio_lt_2g == HDMI_64B_ERR_VAL) |
| return HDMI_64B_ERR_VAL; |
| |
| do_div(tmp_calc, pll_post_div_ratio_lt_2g); |
| return tmp_calc; |
| } |
| } |
| |
| static inline u64 hdmi_8996_get_cpctrl(u64 frac_start, bool gen_ssc) |
| { |
| if ((frac_start != 0) || |
| (gen_ssc == true)) |
| /* |
| * This should be ROUND(11/(19.2/20))). |
| * Since ref clock does not change, hardcoding to 11 |
| */ |
| return 0xB; |
| |
| return 0x23; |
| } |
| |
| static inline u64 hdmi_8996_get_rctrl(u64 frac_start, bool gen_ssc) |
| { |
| if ((frac_start != 0) || (gen_ssc == true)) |
| return 0x16; |
| |
| return 0x10; |
| } |
| |
| static inline u64 hdmi_8996_get_cctrl(u64 frac_start, bool gen_ssc) |
| { |
| if ((frac_start != 0) || (gen_ssc == true)) |
| return 0x28; |
| |
| return 0x1; |
| } |
| |
| static inline u64 hdmi_8996_get_integloop_gain(u64 frac_start, bool gen_ssc) |
| { |
| if ((frac_start != 0) || (gen_ssc == true)) |
| return 0x80; |
| |
| return 0xC4; |
| } |
| |
| static inline u64 hdmi_8996_v3_get_integloop_gain(u64 frac_start, u64 bclk, |
| bool gen_ssc) |
| { |
| u64 digclk_divsel = bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2; |
| u64 base = ((frac_start != 0) || (gen_ssc == true)) ? 0x40 : 0xC4; |
| |
| base <<= digclk_divsel; |
| |
| return (base <= 2046 ? base : 0x7FE); |
| } |
| |
| static inline u64 hdmi_8996_get_vco_tune(u64 fdata, u64 div) |
| { |
| u64 vco_tune; |
| |
| vco_tune = fdata * div; |
| do_div(vco_tune, 1000000); |
| vco_tune = 13000 - vco_tune - 256; |
| do_div(vco_tune, 5); |
| |
| return vco_tune; |
| } |
| |
| static inline u64 hdmi_8996_get_pll_cmp(u64 pll_cmp_cnt, u64 core_clk) |
| { |
| u64 pll_cmp; |
| u64 rem; |
| |
| pll_cmp = pll_cmp_cnt * core_clk; |
| rem = do_div(pll_cmp, HDMI_REF_CLOCK); |
| if (rem > (HDMI_REF_CLOCK >> 1)) |
| pll_cmp++; |
| pll_cmp -= 1; |
| |
| return pll_cmp; |
| } |
| |
| static inline u64 hdmi_8996_v3_get_pll_cmp(u64 pll_cmp_cnt, u64 fdata) |
| { |
| u64 dividend = pll_cmp_cnt * fdata; |
| u64 divisor = HDMI_REF_CLOCK * 10; |
| u64 rem; |
| |
| rem = do_div(dividend, divisor); |
| if (rem > (divisor >> 1)) |
| dividend++; |
| |
| return dividend - 1; |
| } |
| |
| static int hdmi_8996_v3_get_post_div(struct hdmi_8996_v3_post_divider *pd, |
| u64 bclk) |
| { |
| u32 ratio[] = {2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35}; |
| u32 tx_band_sel[] = {0, 1, 2, 3}; |
| u64 vco_freq[60]; |
| u64 vco, vco_optimal, half_rate_mode = 0; |
| int vco_optimal_index, vco_freq_index; |
| int i, j, k, x; |
| |
| for (i = 0; i <= 1; i++) { |
| vco_optimal = HDMI_VCO_MAX_FREQ; |
| vco_optimal_index = -1; |
| vco_freq_index = 0; |
| for (j = 0; j < 15; j++) { |
| for (k = 0; k < 4; k++) { |
| u64 ratio_mult = ratio[j] << tx_band_sel[k]; |
| |
| vco = bclk >> half_rate_mode; |
| vco *= ratio_mult; |
| vco_freq[vco_freq_index++] = vco; |
| } |
| } |
| |
| for (x = 0; x < 60; x++) { |
| u64 vco_tmp = vco_freq[x]; |
| |
| if ((vco_tmp >= HDMI_VCO_MIN_FREQ) && |
| (vco_tmp <= vco_optimal)) { |
| vco_optimal = vco_tmp; |
| vco_optimal_index = x; |
| } |
| } |
| |
| if (vco_optimal_index == -1) { |
| if (!half_rate_mode) |
| half_rate_mode++; |
| else |
| return -EINVAL; |
| } else { |
| pd->vco_freq = vco_optimal; |
| pd->tx_band_sel = tx_band_sel[vco_optimal_index % 4]; |
| pd->vco_ratio = ratio[vco_optimal_index / 4]; |
| break; |
| } |
| } |
| |
| switch (pd->vco_ratio) { |
| case 2: |
| pd->hsclk_divsel = 0; |
| break; |
| case 3: |
| pd->hsclk_divsel = 4; |
| break; |
| case 4: |
| pd->hsclk_divsel = 8; |
| break; |
| case 5: |
| pd->hsclk_divsel = 12; |
| break; |
| case 6: |
| pd->hsclk_divsel = 1; |
| break; |
| case 9: |
| pd->hsclk_divsel = 5; |
| break; |
| case 10: |
| pd->hsclk_divsel = 2; |
| break; |
| case 12: |
| pd->hsclk_divsel = 9; |
| break; |
| case 14: |
| pd->hsclk_divsel = 3; |
| break; |
| case 15: |
| pd->hsclk_divsel = 13; |
| break; |
| case 20: |
| pd->hsclk_divsel = 10; |
| break; |
| case 21: |
| pd->hsclk_divsel = 7; |
| break; |
| case 25: |
| pd->hsclk_divsel = 14; |
| break; |
| case 28: |
| pd->hsclk_divsel = 11; |
| break; |
| case 35: |
| pd->hsclk_divsel = 15; |
| break; |
| }; |
| |
| return 0; |
| } |
| |
| static int hdmi_8996_v1_calculate(u32 pix_clk, |
| struct hdmi_8996_phy_pll_reg_cfg *cfg) |
| { |
| int rc = -EINVAL; |
| u64 fdata, clk_divtx, tmds_clk; |
| u64 bclk; |
| u64 post_div_gt_2g; |
| u64 post_div_lt_2g; |
| u64 coreclk_div1_lt_2g; |
| u64 core_clk_div_ratio; |
| u64 core_clk; |
| u64 pll_cmp; |
| u64 tx_band; |
| u64 tx_band_div_ratio; |
| u64 hsclk; |
| u64 dec_start; |
| u64 frac_start; |
| u64 pll_divisor = 4 * HDMI_REF_CLOCK; |
| u64 cpctrl; |
| u64 rctrl; |
| u64 cctrl; |
| u64 integloop_gain; |
| u64 vco_tune; |
| u64 vco_freq; |
| u64 rem; |
| |
| /* FDATA, CLK_DIVTX, PIXEL_CLK, TMDS_CLK */ |
| bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; |
| |
| if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) |
| tmds_clk = bclk/4; |
| else |
| tmds_clk = bclk; |
| |
| post_div_lt_2g = hdmi_8996_v1_get_post_div_lt_2g(bclk); |
| if (post_div_lt_2g == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| coreclk_div1_lt_2g = hdmi_8996_get_coreclk_div_lt_2g(bclk); |
| |
| core_clk_div_ratio = hdmi_8996_get_coreclk_div_ratio( |
| HDMI_CLKS_PLL_DIVSEL, HDMI_CORECLK_DIV); |
| |
| tx_band = hdmi_8996_v1_get_tx_band(bclk); |
| if (tx_band == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| tx_band_div_ratio = 1 << tx_band; |
| |
| if (bclk >= HDMI_2400MHZ_BIT_CLK_HZ) { |
| fdata = bclk; |
| hsclk = hdmi_8996_v1_get_hsclk(fdata); |
| if (hsclk == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| post_div_gt_2g = (hsclk <= 3) ? (hsclk + 1) : HDMI_64B_ERR_VAL; |
| if (post_div_gt_2g == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| vco_freq = bclk * (post_div_gt_2g * tx_band_div_ratio); |
| clk_divtx = vco_freq; |
| do_div(clk_divtx, post_div_gt_2g); |
| } else { |
| vco_freq = bclk * (post_div_lt_2g * tx_band_div_ratio); |
| fdata = vco_freq; |
| do_div(fdata, post_div_lt_2g); |
| hsclk = hdmi_8996_v1_get_hsclk(fdata); |
| if (hsclk == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| clk_divtx = vco_freq; |
| do_div(clk_divtx, post_div_lt_2g); |
| post_div_gt_2g = (hsclk <= 3) ? (hsclk + 1) : HDMI_64B_ERR_VAL; |
| if (post_div_gt_2g == HDMI_64B_ERR_VAL) |
| goto fail; |
| } |
| |
| /* Decimal and fraction values */ |
| dec_start = fdata * post_div_gt_2g; |
| do_div(dec_start, pll_divisor); |
| frac_start = ((pll_divisor - (((dec_start + 1) * pll_divisor) - |
| (fdata * post_div_gt_2g))) * (1 << 20)); |
| rem = do_div(frac_start, pll_divisor); |
| /* Round off frac_start to closest integer */ |
| if (rem >= (pll_divisor >> 1)) |
| frac_start++; |
| |
| cpctrl = hdmi_8996_get_cpctrl(frac_start, false); |
| rctrl = hdmi_8996_get_rctrl(frac_start, false); |
| cctrl = hdmi_8996_get_cctrl(frac_start, false); |
| integloop_gain = hdmi_8996_get_integloop_gain(frac_start, false); |
| vco_tune = hdmi_8996_get_vco_tune(fdata, post_div_gt_2g); |
| |
| core_clk = clk_divtx; |
| do_div(core_clk, core_clk_div_ratio); |
| pll_cmp = hdmi_8996_get_pll_cmp(1024, core_clk); |
| |
| /* Debug dump */ |
| DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq); |
| DEV_DBG("%s: fdata: %llu\n", __func__, fdata); |
| DEV_DBG("%s: CLK_DIVTX: %llu\n", __func__, clk_divtx); |
| DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk); |
| DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk); |
| DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk); |
| DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start); |
| DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start); |
| DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl); |
| DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl); |
| DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl); |
| DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain); |
| DEV_DBG("%s: VCO_TUNE: %llu\n", __func__, vco_tune); |
| DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band); |
| DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); |
| |
| /* Convert these values to register specific values */ |
| cfg->tx_l0_lane_mode = 0x3; |
| cfg->tx_l2_lane_mode = 0x3; |
| cfg->tx_l0_tx_band = tx_band + 4; |
| cfg->tx_l1_tx_band = tx_band + 4; |
| cfg->tx_l2_tx_band = tx_band + 4; |
| cfg->tx_l3_tx_band = tx_band + 4; |
| cfg->tx_l0_res_code_lane_tx = 0x33; |
| cfg->tx_l1_res_code_lane_tx = 0x33; |
| cfg->tx_l2_res_code_lane_tx = 0x33; |
| cfg->tx_l3_res_code_lane_tx = 0x33; |
| cfg->com_restrim_ctrl = 0x0; |
| cfg->com_vco_tune_ctrl = 0x1C; |
| |
| cfg->com_svs_mode_clk_sel = |
| (bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2); |
| cfg->com_hsclk_sel = (0x28 | hsclk); |
| cfg->com_pll_cctrl_mode0 = cctrl; |
| cfg->com_pll_rctrl_mode0 = rctrl; |
| cfg->com_cp_ctrl_mode0 = cpctrl; |
| cfg->com_dec_start_mode0 = dec_start; |
| cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF); |
| cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8); |
| cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16); |
| cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF); |
| cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8); |
| cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF); |
| cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8); |
| cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16); |
| cfg->com_core_clk_en = (0x6C | (HDMI_CLKS_PLL_DIVSEL << 4)); |
| cfg->com_coreclk_div = HDMI_CORECLK_DIV; |
| |
| if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0D; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0D; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0D; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x00; |
| cfg->com_restrim_ctrl = 0x0; |
| } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0D; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0D; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0D; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x00; |
| cfg->com_restrim_ctrl = 0x0; |
| } else { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0E; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0E; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0E; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x0E; |
| cfg->com_restrim_ctrl = 0xD8; |
| } |
| |
| cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; |
| DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); |
| DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); |
| DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); |
| DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); |
| DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); |
| DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); |
| DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band); |
| DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n", |
| cfg->com_svs_mode_clk_sel); |
| DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel); |
| DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n", |
| cfg->com_pll_cctrl_mode0); |
| DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n", |
| cfg->com_pll_rctrl_mode0); |
| DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n", |
| cfg->com_cp_ctrl_mode0); |
| DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n", |
| cfg->com_dec_start_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n", |
| cfg->com_div_frac_start1_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n", |
| cfg->com_div_frac_start2_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n", |
| cfg->com_div_frac_start3_mode0); |
| DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n", |
| cfg->com_integloop_gain0_mode0); |
| DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n", |
| cfg->com_integloop_gain1_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n", |
| cfg->com_lock_cmp1_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n", |
| cfg->com_lock_cmp2_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n", |
| cfg->com_lock_cmp3_mode0); |
| DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en); |
| DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div); |
| DEV_DBG("PLL PARAM: com_restrim_ctrl = 0x%x\n", cfg->com_restrim_ctrl); |
| |
| DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l0_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l1_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l2_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l3_tx_emp_post1_lvl); |
| |
| DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: tx_l0_res_code_lane_tx = 0x%x\n", |
| cfg->tx_l0_res_code_lane_tx); |
| DEV_DBG("PLL PARAM: tx_l1_res_code_lane_tx = 0x%x\n", |
| cfg->tx_l1_res_code_lane_tx); |
| DEV_DBG("PLL PARAM: tx_l2_res_code_lane_tx = 0x%x\n", |
| cfg->tx_l2_res_code_lane_tx); |
| DEV_DBG("PLL PARAM: tx_l3_res_code_lane_tx = 0x%x\n", |
| cfg->tx_l3_res_code_lane_tx); |
| |
| DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode); |
| rc = 0; |
| fail: |
| return rc; |
| } |
| |
| static int hdmi_8996_v2_calculate(u32 pix_clk, |
| struct hdmi_8996_phy_pll_reg_cfg *cfg) |
| { |
| int rc = -EINVAL; |
| u64 fdata, clk_divtx, tmds_clk; |
| u64 bclk; |
| u64 post_div; |
| u64 core_clk_div; |
| u64 core_clk_div_ratio; |
| u64 core_clk; |
| u64 pll_cmp; |
| u64 tx_band; |
| u64 tx_band_div_ratio; |
| u64 hsclk; |
| u64 dec_start; |
| u64 frac_start; |
| u64 pll_divisor = 4 * HDMI_REF_CLOCK; |
| u64 cpctrl; |
| u64 rctrl; |
| u64 cctrl; |
| u64 integloop_gain; |
| u64 vco_tune; |
| u64 vco_freq; |
| u64 vco_range; |
| u64 rem; |
| |
| /* FDATA, CLK_DIVTX, PIXEL_CLK, TMDS_CLK */ |
| bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; |
| |
| if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) |
| tmds_clk = pix_clk >> 2; |
| else |
| tmds_clk = pix_clk; |
| |
| vco_range = bclk < HDMI_282MHZ_BIT_CLK_HZ ? HDMI_2000MHZ_BIT_CLK_HZ : |
| HDMI_2250MHZ_BIT_CLK_HZ; |
| |
| fdata = hdmi_8996_v2_get_fdata(bclk, vco_range); |
| if (fdata == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| hsclk = hdmi_8996_v2_get_hsclk(fdata, vco_range); |
| if (hsclk == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| if (bclk >= vco_range) |
| post_div = hdmi_8996_v2_get_post_div_gt_2g(hsclk); |
| else |
| post_div = hdmi_8996_v2_get_post_div_lt_2g(bclk, vco_range); |
| |
| if (post_div == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| core_clk_div = 5; |
| core_clk_div_ratio = core_clk_div * 2; |
| |
| tx_band = hdmi_8996_v2_get_tx_band(bclk, vco_range); |
| if (tx_band == HDMI_64B_ERR_VAL) |
| goto fail; |
| |
| tx_band_div_ratio = 1 << tx_band; |
| |
| vco_freq = hdmi_8996_v2_get_vco_freq(bclk, vco_range); |
| clk_divtx = vco_freq; |
| do_div(clk_divtx, post_div); |
| |
| /* Decimal and fraction values */ |
| dec_start = fdata * post_div; |
| do_div(dec_start, pll_divisor); |
| frac_start = ((pll_divisor - (((dec_start + 1) * pll_divisor) - |
| (fdata * post_div))) * (1 << 20)); |
| rem = do_div(frac_start, pll_divisor); |
| /* Round off frac_start to closest integer */ |
| if (rem >= (pll_divisor >> 1)) |
| frac_start++; |
| |
| cpctrl = hdmi_8996_get_cpctrl(frac_start, false); |
| rctrl = hdmi_8996_get_rctrl(frac_start, false); |
| cctrl = hdmi_8996_get_cctrl(frac_start, false); |
| integloop_gain = hdmi_8996_get_integloop_gain(frac_start, false); |
| vco_tune = hdmi_8996_get_vco_tune(fdata, post_div); |
| |
| core_clk = clk_divtx; |
| do_div(core_clk, core_clk_div_ratio); |
| pll_cmp = hdmi_8996_get_pll_cmp(1024, core_clk); |
| |
| /* Debug dump */ |
| DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq); |
| DEV_DBG("%s: fdata: %llu\n", __func__, fdata); |
| DEV_DBG("%s: CLK_DIVTX: %llu\n", __func__, clk_divtx); |
| DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk); |
| DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk); |
| DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk); |
| DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start); |
| DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start); |
| DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl); |
| DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl); |
| DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl); |
| DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain); |
| DEV_DBG("%s: VCO_TUNE: %llu\n", __func__, vco_tune); |
| DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band); |
| DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); |
| |
| /* Convert these values to register specific values */ |
| cfg->tx_l0_lane_mode = 0x3; |
| cfg->tx_l2_lane_mode = 0x3; |
| cfg->tx_l0_tx_band = tx_band + 4; |
| cfg->tx_l1_tx_band = tx_band + 4; |
| cfg->tx_l2_tx_band = tx_band + 4; |
| cfg->tx_l3_tx_band = tx_band + 4; |
| |
| if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) |
| cfg->com_svs_mode_clk_sel = 1; |
| else |
| cfg->com_svs_mode_clk_sel = 2; |
| |
| cfg->com_hsclk_sel = (0x28 | hsclk); |
| cfg->com_pll_cctrl_mode0 = cctrl; |
| cfg->com_pll_rctrl_mode0 = rctrl; |
| cfg->com_cp_ctrl_mode0 = cpctrl; |
| cfg->com_dec_start_mode0 = dec_start; |
| cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF); |
| cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8); |
| cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16); |
| cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF); |
| cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8); |
| cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF); |
| cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8); |
| cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16); |
| cfg->com_core_clk_en = (0x6C | (HDMI_CLKS_PLL_DIVSEL << 4)); |
| cfg->com_coreclk_div = HDMI_CORECLK_DIV; |
| cfg->com_vco_tune_ctrl = 0x0; |
| |
| if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0D; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0D; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0D; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x00; |
| cfg->tx_l0_res_code_lane_tx = 0x3F; |
| cfg->tx_l1_res_code_lane_tx = 0x3F; |
| cfg->tx_l2_res_code_lane_tx = 0x3F; |
| cfg->tx_l3_res_code_lane_tx = 0x3F; |
| cfg->com_restrim_ctrl = 0x0; |
| } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0D; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0D; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0D; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x00; |
| cfg->tx_l0_res_code_lane_tx = 0x39; |
| cfg->tx_l1_res_code_lane_tx = 0x39; |
| cfg->tx_l2_res_code_lane_tx = 0x39; |
| cfg->tx_l3_res_code_lane_tx = 0x39; |
| cfg->com_restrim_ctrl = 0x0; |
| } else { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0E; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0E; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0E; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x0E; |
| cfg->tx_l0_res_code_lane_tx = 0x3F; |
| cfg->tx_l1_res_code_lane_tx = 0x3F; |
| cfg->tx_l2_res_code_lane_tx = 0x3F; |
| cfg->tx_l3_res_code_lane_tx = 0x3F; |
| cfg->com_restrim_ctrl = 0xD8; |
| } |
| |
| cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; |
| DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); |
| DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); |
| DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); |
| DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); |
| DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); |
| DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); |
| DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band); |
| DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n", |
| cfg->com_svs_mode_clk_sel); |
| DEV_DBG("PLL PARAM: com_vco_tune_ctrl = 0x%x\n", |
| cfg->com_vco_tune_ctrl); |
| DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel); |
| DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en); |
| DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n", |
| cfg->com_pll_cctrl_mode0); |
| DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n", |
| cfg->com_pll_rctrl_mode0); |
| DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n", |
| cfg->com_cp_ctrl_mode0); |
| DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n", |
| cfg->com_dec_start_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n", |
| cfg->com_div_frac_start1_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n", |
| cfg->com_div_frac_start2_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n", |
| cfg->com_div_frac_start3_mode0); |
| DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n", |
| cfg->com_integloop_gain0_mode0); |
| DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n", |
| cfg->com_integloop_gain1_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n", |
| cfg->com_lock_cmp1_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n", |
| cfg->com_lock_cmp2_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n", |
| cfg->com_lock_cmp3_mode0); |
| DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en); |
| DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div); |
| |
| DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l0_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l1_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l2_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l3_tx_emp_post1_lvl); |
| |
| DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: tx_l0_res_code_lane_tx = 0x%x\n", |
| cfg->tx_l0_res_code_lane_tx); |
| DEV_DBG("PLL PARAM: tx_l1_res_code_lane_tx = 0x%x\n", |
| cfg->tx_l1_res_code_lane_tx); |
| DEV_DBG("PLL PARAM: tx_l2_res_code_lane_tx = 0x%x\n", |
| cfg->tx_l2_res_code_lane_tx); |
| DEV_DBG("PLL PARAM: tx_l3_res_code_lane_tx = 0x%x\n", |
| cfg->tx_l3_res_code_lane_tx); |
| DEV_DBG("PLL PARAM: com_restrim_ctrl = 0x%x\n", cfg->com_restrim_ctrl); |
| |
| DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode); |
| rc = 0; |
| fail: |
| return rc; |
| } |
| |
| static int hdmi_8996_v3_calculate(u32 pix_clk, |
| struct hdmi_8996_phy_pll_reg_cfg *cfg) |
| { |
| int rc = -EINVAL; |
| struct hdmi_8996_v3_post_divider pd; |
| u64 fdata, tmds_clk; |
| u64 bclk; |
| u64 pll_cmp; |
| u64 tx_band; |
| u64 hsclk; |
| u64 dec_start; |
| u64 frac_start; |
| u64 pll_divisor = 4 * HDMI_REF_CLOCK; |
| u64 cpctrl; |
| u64 rctrl; |
| u64 cctrl; |
| u64 integloop_gain; |
| u64 vco_freq; |
| u64 rem; |
| |
| /* FDATA, HSCLK, PIXEL_CLK, TMDS_CLK */ |
| bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; |
| |
| if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) |
| tmds_clk = pix_clk >> 2; |
| else |
| tmds_clk = pix_clk; |
| |
| if (hdmi_8996_v3_get_post_div(&pd, bclk) || pd.vco_ratio <= 0 || |
| pd.vco_freq <= 0) |
| goto fail; |
| |
| vco_freq = pd.vco_freq; |
| fdata = pd.vco_freq; |
| do_div(fdata, pd.vco_ratio); |
| |
| hsclk = pd.hsclk_divsel; |
| dec_start = vco_freq; |
| do_div(dec_start, pll_divisor); |
| |
| frac_start = vco_freq * (1 << 20); |
| rem = do_div(frac_start, pll_divisor); |
| frac_start -= dec_start * (1 << 20); |
| if (rem > (pll_divisor >> 1)) |
| frac_start++; |
| |
| cpctrl = hdmi_8996_get_cpctrl(frac_start, false); |
| rctrl = hdmi_8996_get_rctrl(frac_start, false); |
| cctrl = hdmi_8996_get_cctrl(frac_start, false); |
| integloop_gain = hdmi_8996_v3_get_integloop_gain(frac_start, bclk, |
| false); |
| pll_cmp = hdmi_8996_v3_get_pll_cmp(1024, fdata); |
| tx_band = pd.tx_band_sel; |
| |
| /* Debug dump */ |
| DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq); |
| DEV_DBG("%s: fdata: %llu\n", __func__, fdata); |
| DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk); |
| DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk); |
| DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk); |
| DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start); |
| DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start); |
| DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl); |
| DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl); |
| DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl); |
| DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain); |
| DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band); |
| DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); |
| |
| /* Convert these values to register specific values */ |
| cfg->tx_l0_tx_band = tx_band + 4; |
| cfg->tx_l1_tx_band = tx_band + 4; |
| cfg->tx_l2_tx_band = tx_band + 4; |
| cfg->tx_l3_tx_band = tx_band + 4; |
| |
| if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) |
| cfg->com_svs_mode_clk_sel = 1; |
| else |
| cfg->com_svs_mode_clk_sel = 2; |
| |
| cfg->com_hsclk_sel = (0x20 | hsclk); |
| cfg->com_pll_cctrl_mode0 = cctrl; |
| cfg->com_pll_rctrl_mode0 = rctrl; |
| cfg->com_cp_ctrl_mode0 = cpctrl; |
| cfg->com_dec_start_mode0 = dec_start; |
| cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF); |
| cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8); |
| cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16); |
| cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF); |
| cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8); |
| cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF); |
| cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8); |
| cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16); |
| cfg->com_lock_cmp_en = 0x04; |
| cfg->com_core_clk_en = 0x2C; |
| cfg->com_coreclk_div = HDMI_CORECLK_DIV; |
| cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; |
| cfg->com_vco_tune_ctrl = 0x0; |
| |
| cfg->tx_l0_lane_mode = 0x43; |
| cfg->tx_l2_lane_mode = 0x43; |
| |
| if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0D; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0D; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0D; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x00; |
| } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0D; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0D; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0D; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x00; |
| } else { |
| 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 = 0x00; |
| cfg->tx_l0_vmode_ctrl2 = 0x0E; |
| cfg->tx_l1_vmode_ctrl1 = 0x00; |
| cfg->tx_l1_vmode_ctrl2 = 0x0E; |
| cfg->tx_l2_vmode_ctrl1 = 0x00; |
| cfg->tx_l2_vmode_ctrl2 = 0x0E; |
| cfg->tx_l3_vmode_ctrl1 = 0x00; |
| cfg->tx_l3_vmode_ctrl2 = 0x0E; |
| } |
| |
| DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); |
| DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); |
| DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); |
| DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); |
| DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band); |
| DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n", |
| cfg->com_svs_mode_clk_sel); |
| DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel); |
| DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en); |
| DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n", |
| cfg->com_pll_cctrl_mode0); |
| DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n", |
| cfg->com_pll_rctrl_mode0); |
| DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n", |
| cfg->com_cp_ctrl_mode0); |
| DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n", |
| cfg->com_dec_start_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n", |
| cfg->com_div_frac_start1_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n", |
| cfg->com_div_frac_start2_mode0); |
| DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n", |
| cfg->com_div_frac_start3_mode0); |
| DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n", |
| cfg->com_integloop_gain0_mode0); |
| DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n", |
| cfg->com_integloop_gain1_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n", |
| cfg->com_lock_cmp1_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n", |
| cfg->com_lock_cmp2_mode0); |
| DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n", |
| cfg->com_lock_cmp3_mode0); |
| DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en); |
| DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div); |
| DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode); |
| |
| DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); |
| DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); |
| DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l0_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l1_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l2_tx_emp_post1_lvl); |
| DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl); |
| DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n", |
| cfg->tx_l3_tx_emp_post1_lvl); |
| |
| DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2); |
| DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1); |
| DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2); |
| rc = 0; |
| fail: |
| return rc; |
| } |
| |
| static int hdmi_8996_calculate(u32 pix_clk, |
| struct hdmi_8996_phy_pll_reg_cfg *cfg, u32 ver) |
| { |
| switch (ver) { |
| case HDMI_VERSION_8996_V3: |
| case HDMI_VERSION_8996_V3_1_8: |
| return hdmi_8996_v3_calculate(pix_clk, cfg); |
| case HDMI_VERSION_8996_V2: |
| return hdmi_8996_v2_calculate(pix_clk, cfg); |
| default: |
| return hdmi_8996_v1_calculate(pix_clk, cfg); |
| } |
| } |
| |
| static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver) |
| { |
| int rc = 0; |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| struct hdmi_8996_phy_pll_reg_cfg cfg = {0}; |
| |
| rc = hdmi_8996_calculate(tmds_clk, &cfg, ver); |
| if (rc) { |
| DEV_ERR("%s: PLL calculation failed\n", __func__); |
| return rc; |
| } |
| |
| /* Initially shut down PHY */ |
| DEV_DBG("%s: Disabling PHY\n", __func__); |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x0); |
| udelay(500); |
| |
| /* Power up sequence */ |
| switch (ver) { |
| case HDMI_VERSION_8996_V2: |
| case HDMI_VERSION_8996_V3: |
| case HDMI_VERSION_8996_V3_1_8: |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x04); |
| break; |
| }; |
| |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20); |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TX0_TX1_LANE_CTL, 0x0F); |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TX2_TX3_LANE_CTL, 0x0F); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_LANE_MODE, cfg.tx_l0_lane_mode); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_LANE_MODE, cfg.tx_l2_lane_mode); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_TX_BAND, cfg.tx_l0_tx_band); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_TX_BAND, cfg.tx_l1_tx_band); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_TX_BAND, cfg.tx_l2_tx_band); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_TX_BAND, cfg.tx_l3_tx_band); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_RESET_TSYNC_EN, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_RESET_TSYNC_EN, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_RESET_TSYNC_EN, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_RESET_TSYNC_EN, 0x03); |
| |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1E); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x07); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x37); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0E); |
| if (ver == HDMI_VERSION_8996_V1) |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06); |
| |
| /* Bypass VCO calibration */ |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, |
| cfg.com_svs_mode_clk_sel); |
| |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_TRIM, 0x0F); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_IVCO, 0x0F); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_CTRL, |
| cfg.com_vco_tune_ctrl); |
| |
| switch (ver) { |
| case HDMI_VERSION_8996_V1: |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, |
| cfg.com_svs_mode_clk_sel); |
| break; |
| default: |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06); |
| } |
| |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_SELECT, 0x30); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_HSCLK_SEL, |
| cfg.com_hsclk_sel); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_EN, |
| cfg.com_lock_cmp_en); |
| |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CCTRL_MODE0, |
| cfg.com_pll_cctrl_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_RCTRL_MODE0, |
| cfg.com_pll_rctrl_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CP_CTRL_MODE0, |
| cfg.com_cp_ctrl_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEC_START_MODE0, |
| cfg.com_dec_start_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START1_MODE0, |
| cfg.com_div_frac_start1_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START2_MODE0, |
| cfg.com_div_frac_start2_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START3_MODE0, |
| cfg.com_div_frac_start3_mode0); |
| |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_INTEGLOOP_GAIN0_MODE0, |
| cfg.com_integloop_gain0_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_INTEGLOOP_GAIN1_MODE0, |
| cfg.com_integloop_gain1_mode0); |
| |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP1_MODE0, |
| cfg.com_lock_cmp1_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP2_MODE0, |
| cfg.com_lock_cmp2_mode0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP3_MODE0, |
| cfg.com_lock_cmp3_mode0); |
| |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_MAP, 0x00); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORE_CLK_EN, |
| cfg.com_core_clk_en); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORECLK_DIV, |
| cfg.com_coreclk_div); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_CONFIG, 0x02); |
| |
| if (ver == HDMI_VERSION_8996_V3 || ver == HDMI_VERSION_8996_V3_1_8) |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESCODE_DIV_NUM, 0x15); |
| |
| /* TX lanes setup (TX 0/1/2/3) */ |
| if (ver == HDMI_VERSION_8996_V3_1_8) { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL, |
| 0x00000023); |
| } else { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL, |
| cfg.tx_l0_tx_drv_lvl); |
| } |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_TX_EMP_POST1_LVL, |
| cfg.tx_l0_tx_emp_post1_lvl); |
| |
| if (ver == HDMI_VERSION_8996_V3_1_8) { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL, |
| 0x00000023); |
| } else { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL, |
| cfg.tx_l1_tx_drv_lvl); |
| } |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_TX_EMP_POST1_LVL, |
| cfg.tx_l1_tx_emp_post1_lvl); |
| |
| if (ver == HDMI_VERSION_8996_V3_1_8) { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL, |
| 0x00000023); |
| } else { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL, |
| cfg.tx_l2_tx_drv_lvl); |
| } |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_TX_EMP_POST1_LVL, |
| cfg.tx_l2_tx_emp_post1_lvl); |
| |
| if (ver == HDMI_VERSION_8996_V3_1_8) { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL, |
| 0x00000020); |
| } else { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL, |
| cfg.tx_l3_tx_drv_lvl); |
| } |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_TX_EMP_POST1_LVL, |
| cfg.tx_l3_tx_emp_post1_lvl); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL1, |
| cfg.tx_l0_vmode_ctrl1); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL2, |
| cfg.tx_l0_vmode_ctrl2); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL1, |
| cfg.tx_l1_vmode_ctrl1); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL2, |
| cfg.tx_l1_vmode_ctrl2); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL1, |
| cfg.tx_l2_vmode_ctrl1); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL2, |
| cfg.tx_l2_vmode_ctrl2); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL1, |
| cfg.tx_l3_vmode_ctrl1); |
| if (ver == HDMI_VERSION_8996_V3_1_8) { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL2, |
| 0x0000000D); |
| } else { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_VMODE_CTRL2, |
| cfg.tx_l3_vmode_ctrl2); |
| } |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); |
| |
| if (ver < HDMI_VERSION_8996_V3) { |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_RES_CODE_LANE_TX, |
| cfg.tx_l0_res_code_lane_tx); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_RES_CODE_LANE_TX, |
| cfg.tx_l1_res_code_lane_tx); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_RES_CODE_LANE_TX, |
| cfg.tx_l2_res_code_lane_tx); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_RES_CODE_LANE_TX, |
| cfg.tx_l3_res_code_lane_tx); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESTRIM_CTRL, |
| cfg.com_restrim_ctrl); |
| |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG1, 0x05); |
| } |
| |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_MODE, cfg.phy_mode); |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1F); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_HP_PD_ENABLES, 0x0C); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_HP_PD_ENABLES, 0x0C); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_HP_PD_ENABLES, 0x0C); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_HP_PD_ENABLES, 0x03); |
| |
| if (ver == HDMI_VERSION_8996_V2) { |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x01); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x01); |
| } |
| /* |
| * Ensure that vco configuration gets flushed to hardware before |
| * enabling the PLL |
| */ |
| wmb(); |
| return 0; |
| } |
| |
| static int hdmi_8996_phy_ready_status(struct mdss_pll_resources *io) |
| { |
| u32 status = 0; |
| int phy_ready = 0; |
| int rc; |
| u32 read_count = 0; |
| |
| rc = mdss_pll_resource_enable(io, true); |
| if (rc) { |
| DEV_ERR("%s: pll resource can't be enabled\n", __func__); |
| return rc; |
| } |
| |
| DEV_DBG("%s: Waiting for PHY Ready\n", __func__); |
| |
| /* Poll for PHY read status */ |
| while (read_count < HDMI_PLL_POLL_MAX_READS) { |
| status = MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS); |
| if ((status & BIT(0)) == 1) { |
| phy_ready = 1; |
| DEV_DBG("%s: PHY READY\n", __func__); |
| break; |
| } |
| udelay(HDMI_PLL_POLL_TIMEOUT_US); |
| read_count++; |
| } |
| |
| if (read_count == HDMI_PLL_POLL_MAX_READS) { |
| phy_ready = 0; |
| DEV_DBG("%s: PHY READY TIMEOUT\n", __func__); |
| } |
| |
| mdss_pll_resource_enable(io, false); |
| |
| return phy_ready; |
| } |
| |
| static int hdmi_8996_pll_lock_status(struct mdss_pll_resources *io) |
| { |
| u32 status; |
| int pll_locked = 0; |
| int rc; |
| u32 read_count = 0; |
| |
| rc = mdss_pll_resource_enable(io, true); |
| if (rc) { |
| DEV_ERR("%s: pll resource can't be enabled\n", __func__); |
| return rc; |
| } |
| |
| DEV_DBG("%s: Waiting for PLL lock\n", __func__); |
| |
| while (read_count < HDMI_PLL_POLL_MAX_READS) { |
| status = MDSS_PLL_REG_R(io->pll_base, |
| QSERDES_COM_C_READY_STATUS); |
| if ((status & BIT(0)) == 1) { |
| pll_locked = 1; |
| DEV_DBG("%s: C READY\n", __func__); |
| break; |
| } |
| udelay(HDMI_PLL_POLL_TIMEOUT_US); |
| read_count++; |
| } |
| |
| if (read_count == HDMI_PLL_POLL_MAX_READS) { |
| pll_locked = 0; |
| DEV_DBG("%s: C READY TIMEOUT\n", __func__); |
| } |
| |
| mdss_pll_resource_enable(io, false); |
| |
| return pll_locked; |
| } |
| |
| static int hdmi_8996_v1_perform_sw_calibration(struct clk *c) |
| { |
| int rc = 0; |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| |
| u32 max_code = 0x190; |
| u32 min_code = 0x0; |
| u32 max_cnt = 0; |
| u32 min_cnt = 0; |
| u32 expected_counter_value = 0; |
| u32 step = 0; |
| u32 dbus_all = 0; |
| u32 dbus_sel = 0; |
| u32 vco_code = 0; |
| u32 val = 0; |
| |
| vco_code = 0xC8; |
| |
| DEV_DBG("%s: Starting SW calibration with vco_code = %d\n", __func__, |
| vco_code); |
| |
| expected_counter_value = |
| (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP3_MODE0) << 16) | |
| (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP2_MODE0) << 8) | |
| (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP1_MODE0)); |
| |
| DEV_DBG("%s: expected_counter_value = %d\n", __func__, |
| expected_counter_value); |
| |
| val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1); |
| val |= BIT(4); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val); |
| |
| val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1); |
| val |= BIT(3); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val); |
| |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEBUG_BUS_SEL, 0x4); |
| |
| val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG); |
| val |= BIT(1); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val); |
| |
| udelay(60); |
| |
| while (1) { |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE1_MODE0, |
| vco_code & 0xFF); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE2_MODE0, |
| (vco_code >> 8) & 0x3); |
| |
| udelay(20); |
| |
| val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG); |
| val &= ~BIT(1); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val); |
| |
| udelay(60); |
| |
| val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG); |
| val |= BIT(1); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val); |
| |
| udelay(60); |
| |
| dbus_all = |
| (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS3) << 24) | |
| (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS2) << 16) | |
| (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS1) << 8) | |
| (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS0)); |
| |
| dbus_sel = (dbus_all >> 9) & 0x3FFFF; |
| DEV_DBG("%s: loop[%d], dbus_all = 0x%x, dbus_sel = 0x%x\n", |
| __func__, step, dbus_all, dbus_sel); |
| if (dbus_sel == 0) |
| DEV_ERR("%s: CHECK HDMI REF CLK\n", __func__); |
| |
| if (dbus_sel == expected_counter_value) { |
| max_code = vco_code; |
| max_cnt = dbus_sel; |
| min_code = vco_code; |
| min_cnt = dbus_sel; |
| } else if (dbus_sel == 0) { |
| max_code = vco_code; |
| max_cnt = dbus_sel; |
| vco_code = (max_code + min_code)/2; |
| } else if (dbus_sel > expected_counter_value) { |
| min_code = vco_code; |
| min_cnt = dbus_sel; |
| vco_code = (max_code + min_code)/2; |
| } else if (dbus_sel < expected_counter_value) { |
| max_code = vco_code; |
| max_cnt = dbus_sel; |
| vco_code = (max_code + min_code)/2; |
| } |
| |
| step++; |
| |
| if ((vco_code == 0) || (vco_code == 0x3FF) || (step > 0x3FF)) { |
| DEV_ERR("%s: VCO tune code search failed\n", __func__); |
| rc = -ENOTSUPP; |
| break; |
| } |
| if ((max_code - min_code) <= 1) { |
| if ((max_code - min_code) == 1) { |
| if (abs((int)(max_cnt - expected_counter_value)) |
| < abs((int)(min_cnt - expected_counter_value |
| ))) { |
| vco_code = max_code; |
| } else { |
| vco_code = min_code; |
| } |
| } |
| break; |
| } |
| DEV_DBG("%s: loop[%d], new vco_code = %d\n", __func__, step, |
| vco_code); |
| } |
| |
| DEV_DBG("%s: CALIB done. vco_code = %d\n", __func__, vco_code); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE1_MODE0, |
| vco_code & 0xFF); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE2_MODE0, |
| (vco_code >> 8) & 0x3); |
| val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG); |
| val &= ~BIT(1); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val); |
| |
| val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1); |
| val |= BIT(4); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val); |
| |
| val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1); |
| val &= ~BIT(3); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val); |
| |
| return rc; |
| } |
| |
| static int hdmi_8996_v2_perform_sw_calibration(struct clk *c) |
| { |
| int rc = 0; |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| u32 vco_code1, vco_code2, integral_loop, ready_poll; |
| u32 read_count = 0; |
| |
| while (read_count < (HDMI_PLL_POLL_MAX_READS << 1)) { |
| ready_poll = MDSS_PLL_REG_R(io->pll_base, |
| QSERDES_COM_C_READY_STATUS); |
| if ((ready_poll & BIT(0)) == 1) { |
| ready_poll = 1; |
| DEV_DBG("%s: C READY\n", __func__); |
| break; |
| } |
| udelay(HDMI_PLL_POLL_TIMEOUT_US); |
| read_count++; |
| } |
| |
| if (read_count == (HDMI_PLL_POLL_MAX_READS << 1)) { |
| ready_poll = 0; |
| DEV_DBG("%s: C READY TIMEOUT, TRYING SW CALIBRATION\n", |
| __func__); |
| } |
| |
| vco_code1 = MDSS_PLL_REG_R(io->pll_base, |
| QSERDES_COM_PLLCAL_CODE1_STATUS); |
| vco_code2 = MDSS_PLL_REG_R(io->pll_base, |
| QSERDES_COM_PLLCAL_CODE2_STATUS); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEBUG_BUS_SEL, 0x5); |
| integral_loop = MDSS_PLL_REG_R(io->pll_base, |
| QSERDES_COM_DEBUG_BUS0); |
| |
| if (((ready_poll & 0x1) == 0) || (((ready_poll & 1) == 1) && |
| (vco_code1 == 0xFF) && ((vco_code2 & 0x3) == 0x1) && |
| (integral_loop > 0xC0))) { |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x04); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x00); |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x17); |
| udelay(100); |
| |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x11); |
| udelay(100); |
| |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19); |
| } |
| return rc; |
| } |
| |
| static int hdmi_8996_perform_sw_calibration(struct clk *c, u32 ver) |
| { |
| switch (ver) { |
| case HDMI_VERSION_8996_V1: |
| return hdmi_8996_v1_perform_sw_calibration(c); |
| case HDMI_VERSION_8996_V2: |
| return hdmi_8996_v2_perform_sw_calibration(c); |
| } |
| return 0; |
| } |
| |
| static int hdmi_8996_vco_enable(struct clk *c, u32 ver) |
| { |
| int rc = 0; |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x1); |
| udelay(100); |
| |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19); |
| udelay(100); |
| |
| rc = hdmi_8996_perform_sw_calibration(c, ver); |
| if (rc) { |
| DEV_ERR("%s: software calibration failed\n", __func__); |
| return rc; |
| } |
| |
| rc = hdmi_8996_pll_lock_status(io); |
| if (!rc) { |
| DEV_ERR("%s: PLL not locked\n", __func__); |
| return rc; |
| } |
| |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, |
| 0x6F); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, |
| QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, |
| 0x6F); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, |
| QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, |
| 0x6F); |
| MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, |
| QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, |
| 0x6F); |
| |
| /* Disable SSC */ |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_PER1, 0x0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_PER2, 0x0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_STEP_SIZE1, 0x0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_STEP_SIZE2, 0x0); |
| MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_EN_CENTER, 0x2); |
| |
| rc = hdmi_8996_phy_ready_status(io); |
| if (!rc) { |
| DEV_ERR("%s: PHY not READY\n", __func__); |
| return rc; |
| } |
| |
| /* Restart the retiming buffer */ |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x18); |
| udelay(1); |
| MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19); |
| |
| io->pll_on = true; |
| return 0; |
| } |
| |
| static int hdmi_8996_v1_vco_enable(struct clk *c) |
| { |
| return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V1); |
| } |
| |
| static int hdmi_8996_v2_vco_enable(struct clk *c) |
| { |
| return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V2); |
| } |
| |
| static int hdmi_8996_v3_vco_enable(struct clk *c) |
| { |
| return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3); |
| } |
| |
| static int hdmi_8996_v3_1p8_vco_enable(struct clk *c) |
| { |
| return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3_1_8); |
| } |
| |
| static int hdmi_8996_vco_get_lock_range(struct clk *c, unsigned long pixel_clk) |
| { |
| u32 rng = 64, cmp_cnt = 1024; |
| u32 coreclk_div = 5, clks_pll_divsel = 2; |
| u32 vco_freq, vco_ratio, ppm_range; |
| u64 bclk; |
| struct hdmi_8996_v3_post_divider pd; |
| |
| bclk = ((u64)pixel_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; |
| |
| DEV_DBG("%s: rate=%ld\n", __func__, pixel_clk); |
| |
| if (hdmi_8996_v3_get_post_div(&pd, bclk) || |
| pd.vco_ratio <= 0 || pd.vco_freq <= 0) { |
| DEV_ERR("%s: couldn't get post div\n", __func__); |
| return -EINVAL; |
| } |
| |
| do_div(pd.vco_freq, HDMI_KHZ_TO_HZ * HDMI_KHZ_TO_HZ); |
| |
| vco_freq = (u32) pd.vco_freq; |
| vco_ratio = (u32) pd.vco_ratio; |
| |
| DEV_DBG("%s: freq %d, ratio %d\n", __func__, |
| vco_freq, vco_ratio); |
| |
| ppm_range = (rng * HDMI_REF_CLOCK) / cmp_cnt; |
| ppm_range /= vco_freq / vco_ratio; |
| ppm_range *= coreclk_div * clks_pll_divsel; |
| |
| DEV_DBG("%s: ppm range: %d\n", __func__, ppm_range); |
| |
| return ppm_range; |
| } |
| |
| static int hdmi_8996_vco_rate_atomic_update(struct clk *c, |
| unsigned long rate, u32 ver) |
| { |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| void __iomem *pll; |
| struct hdmi_8996_phy_pll_reg_cfg cfg = {0}; |
| int rc = 0; |
| |
| rc = hdmi_8996_calculate(rate, &cfg, ver); |
| if (rc) { |
| DEV_ERR("%s: PLL calculation failed\n", __func__); |
| goto end; |
| } |
| |
| pll = io->pll_base; |
| |
| MDSS_PLL_REG_W(pll, QSERDES_COM_DEC_START_MODE0, |
| cfg.com_dec_start_mode0); |
| MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START1_MODE0, |
| cfg.com_div_frac_start1_mode0); |
| MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START2_MODE0, |
| cfg.com_div_frac_start2_mode0); |
| MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START3_MODE0, |
| cfg.com_div_frac_start3_mode0); |
| |
| MDSS_PLL_REG_W(pll, QSERDES_COM_FREQ_UPDATE, 0x01); |
| MDSS_PLL_REG_W(pll, QSERDES_COM_FREQ_UPDATE, 0x00); |
| |
| DEV_DBG("%s: updated to rate %ld\n", __func__, rate); |
| end: |
| return rc; |
| } |
| |
| static int hdmi_8996_vco_set_rate(struct clk *c, unsigned long rate, u32 ver) |
| { |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| unsigned int set_power_dwn = 0; |
| bool atomic_update = false; |
| int rc, pll_lock_range; |
| |
| rc = mdss_pll_resource_enable(io, true); |
| if (rc) { |
| DEV_ERR("pll resource can't be enabled\n"); |
| return rc; |
| } |
| |
| DEV_DBG("%s: rate %ld\n", __func__, rate); |
| |
| if (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_C_READY_STATUS) & BIT(0) && |
| MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS) & BIT(0)) { |
| pll_lock_range = hdmi_8996_vco_get_lock_range(c, vco->rate); |
| |
| if (pll_lock_range > 0 && vco->rate) { |
| u32 range_limit; |
| |
| range_limit = vco->rate * |
| (pll_lock_range / HDMI_KHZ_TO_HZ); |
| range_limit /= HDMI_KHZ_TO_HZ; |
| |
| DEV_DBG("%s: range limit %d\n", __func__, range_limit); |
| |
| if (abs(rate - vco->rate) < range_limit) |
| atomic_update = true; |
| } |
| } |
| |
| if (io->pll_on && !atomic_update) |
| set_power_dwn = 1; |
| |
| if (atomic_update) { |
| hdmi_8996_vco_rate_atomic_update(c, rate, ver); |
| } else { |
| rc = hdmi_8996_phy_pll_set_clk_rate(c, rate, ver); |
| if (rc) |
| DEV_ERR("%s: Failed to set clk rate\n", __func__); |
| } |
| |
| mdss_pll_resource_enable(io, false); |
| |
| if (set_power_dwn) |
| hdmi_8996_vco_enable(c, ver); |
| |
| vco->rate = rate; |
| vco->rate_set = true; |
| |
| return 0; |
| } |
| |
| static int hdmi_8996_v1_vco_set_rate(struct clk *c, unsigned long rate) |
| { |
| return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V1); |
| } |
| |
| static int hdmi_8996_v2_vco_set_rate(struct clk *c, unsigned long rate) |
| { |
| return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V2); |
| } |
| |
| static int hdmi_8996_v3_vco_set_rate(struct clk *c, unsigned long rate) |
| { |
| return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3); |
| } |
| |
| static int hdmi_8996_v3_1p8_vco_set_rate(struct clk *c, unsigned long rate) |
| { |
| return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3_1_8); |
| } |
| |
| static unsigned long hdmi_get_hsclk_sel_divisor(unsigned long hsclk_sel) |
| { |
| unsigned long divisor; |
| |
| switch (hsclk_sel) { |
| case 0: |
| divisor = 2; |
| break; |
| case 1: |
| divisor = 6; |
| break; |
| case 2: |
| divisor = 10; |
| break; |
| case 3: |
| divisor = 14; |
| break; |
| case 4: |
| divisor = 3; |
| break; |
| case 5: |
| divisor = 9; |
| break; |
| case 6: |
| case 13: |
| divisor = 15; |
| break; |
| case 7: |
| divisor = 21; |
| break; |
| case 8: |
| divisor = 4; |
| break; |
| case 9: |
| divisor = 12; |
| break; |
| case 10: |
| divisor = 20; |
| break; |
| case 11: |
| divisor = 28; |
| break; |
| case 12: |
| divisor = 5; |
| break; |
| case 14: |
| divisor = 25; |
| break; |
| case 15: |
| divisor = 35; |
| break; |
| default: |
| divisor = 1; |
| DEV_ERR("%s: invalid hsclk_sel value = %lu", |
| __func__, hsclk_sel); |
| break; |
| } |
| |
| return divisor; |
| } |
| |
| static unsigned long hdmi_8996_vco_get_rate(struct clk *c) |
| { |
| unsigned long freq = 0, hsclk_sel = 0, tx_band = 0, dec_start = 0, |
| div_frac_start = 0, vco_clock_freq = 0; |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| |
| if (mdss_pll_resource_enable(io, true)) { |
| DEV_ERR("%s: pll resource can't be enabled\n", __func__); |
| return freq; |
| } |
| |
| dec_start = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEC_START_MODE0); |
| |
| div_frac_start = |
| MDSS_PLL_REG_R(io->pll_base, |
| QSERDES_COM_DIV_FRAC_START1_MODE0) | |
| MDSS_PLL_REG_R(io->pll_base, |
| QSERDES_COM_DIV_FRAC_START2_MODE0) << 8 | |
| MDSS_PLL_REG_R(io->pll_base, |
| QSERDES_COM_DIV_FRAC_START3_MODE0) << 16; |
| |
| vco_clock_freq = (dec_start + (div_frac_start / (1 << 20))) |
| * 4 * (HDMI_REF_CLOCK); |
| |
| hsclk_sel = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_HSCLK_SEL) & 0x15; |
| hsclk_sel = hdmi_get_hsclk_sel_divisor(hsclk_sel); |
| tx_band = MDSS_PLL_REG_R(io->pll_base + HDMI_TX_L0_BASE_OFFSET, |
| QSERDES_TX_L0_TX_BAND) & 0x3; |
| |
| freq = vco_clock_freq / (10 * hsclk_sel * (1 << tx_band)); |
| |
| mdss_pll_resource_enable(io, false); |
| |
| DEV_DBG("%s: freq = %lu\n", __func__, freq); |
| |
| return freq; |
| } |
| |
| static long hdmi_8996_vco_round_rate(struct clk *c, unsigned long rate) |
| { |
| unsigned long rrate = rate; |
| |
| DEV_DBG("rrate=%ld\n", rrate); |
| |
| return rrate; |
| } |
| |
| static int hdmi_8996_vco_prepare(struct clk *c, u32 ver) |
| { |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| int ret = 0; |
| |
| DEV_DBG("rate=%ld\n", vco->rate); |
| |
| if (!vco->rate_set && vco->rate) |
| ret = hdmi_8996_vco_set_rate(c, vco->rate, ver); |
| |
| if (!ret) { |
| ret = mdss_pll_resource_enable(io, true); |
| if (ret) |
| DEV_ERR("pll resource can't be enabled\n"); |
| } |
| |
| return ret; |
| } |
| |
| static int hdmi_8996_v1_vco_prepare(struct clk *c) |
| { |
| return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V1); |
| } |
| |
| static int hdmi_8996_v2_vco_prepare(struct clk *c) |
| { |
| return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V2); |
| } |
| |
| static int hdmi_8996_v3_vco_prepare(struct clk *c) |
| { |
| return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3); |
| } |
| |
| static int hdmi_8996_v3_1p8_vco_prepare(struct clk *c) |
| { |
| return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3_1_8); |
| } |
| |
| static void hdmi_8996_vco_unprepare(struct clk *c) |
| { |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| |
| vco->rate_set = false; |
| |
| if (!io) { |
| DEV_ERR("Invalid input parameter\n"); |
| return; |
| } |
| |
| if (!io->pll_on && |
| mdss_pll_resource_enable(io, true)) { |
| DEV_ERR("pll resource can't be enabled\n"); |
| return; |
| } |
| |
| io->handoff_resources = false; |
| mdss_pll_resource_enable(io, false); |
| io->pll_on = false; |
| } |
| |
| static enum handoff hdmi_8996_vco_handoff(struct clk *c) |
| { |
| enum handoff ret = HANDOFF_DISABLED_CLK; |
| struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); |
| struct mdss_pll_resources *io = vco->priv; |
| |
| if (is_gdsc_disabled(io)) |
| return HANDOFF_DISABLED_CLK; |
| |
| if (mdss_pll_resource_enable(io, true)) { |
| DEV_ERR("pll resource can't be enabled\n"); |
| return ret; |
| } |
| |
| io->handoff_resources = true; |
| |
| if (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_C_READY_STATUS) & BIT(0)) { |
| if (MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS) & BIT(0)) { |
| io->pll_on = true; |
| c->rate = hdmi_8996_vco_get_rate(c); |
| vco->rate = c->rate; |
| ret = HANDOFF_ENABLED_CLK; |
| } else { |
| io->handoff_resources = false; |
| mdss_pll_resource_enable(io, false); |
| DEV_DBG("%s: PHY not ready\n", __func__); |
| } |
| } else { |
| io->handoff_resources = false; |
| mdss_pll_resource_enable(io, false); |
| DEV_DBG("%s: PLL not locked\n", __func__); |
| } |
| |
| DEV_DBG("done, ret=%d\n", ret); |
| return ret; |
| } |
| |
| const struct clk_ops hdmi_8996_v1_vco_clk_ops = { |
| .enable = hdmi_8996_v1_vco_enable, |
| .set_rate = hdmi_8996_v1_vco_set_rate, |
| .get_rate = hdmi_8996_vco_get_rate, |
| .round_rate = hdmi_8996_vco_round_rate, |
| .prepare = hdmi_8996_v1_vco_prepare, |
| .unprepare = hdmi_8996_vco_unprepare, |
| .handoff = hdmi_8996_vco_handoff, |
| }; |
| |
| const struct clk_ops hdmi_8996_v2_vco_clk_ops = { |
| .enable = hdmi_8996_v2_vco_enable, |
| .set_rate = hdmi_8996_v2_vco_set_rate, |
| .get_rate = hdmi_8996_vco_get_rate, |
| .round_rate = hdmi_8996_vco_round_rate, |
| .prepare = hdmi_8996_v2_vco_prepare, |
| .unprepare = hdmi_8996_vco_unprepare, |
| .handoff = hdmi_8996_vco_handoff, |
| }; |
| |
| const struct clk_ops hdmi_8996_v3_vco_clk_ops = { |
| .enable = hdmi_8996_v3_vco_enable, |
| .set_rate = hdmi_8996_v3_vco_set_rate, |
| .get_rate = hdmi_8996_vco_get_rate, |
| .round_rate = hdmi_8996_vco_round_rate, |
| .prepare = hdmi_8996_v3_vco_prepare, |
| .unprepare = hdmi_8996_vco_unprepare, |
| .handoff = hdmi_8996_vco_handoff, |
| }; |
| |
| const struct clk_ops hdmi_8996_v3_1p8_vco_clk_ops = { |
| .enable = hdmi_8996_v3_1p8_vco_enable, |
| .set_rate = hdmi_8996_v3_1p8_vco_set_rate, |
| .get_rate = hdmi_8996_vco_get_rate, |
| .round_rate = hdmi_8996_vco_round_rate, |
| .prepare = hdmi_8996_v3_1p8_vco_prepare, |
| .unprepare = hdmi_8996_vco_unprepare, |
| .handoff = hdmi_8996_vco_handoff, |
| }; |
| |
| |
| static struct hdmi_pll_vco_clk hdmi_vco_clk = { |
| .c = { |
| .dbg_name = "hdmi_8996_vco_clk", |
| .ops = &hdmi_8996_v1_vco_clk_ops, |
| .flags = CLKFLAG_NO_RATE_CACHE, |
| CLK_INIT(hdmi_vco_clk.c), |
| }, |
| }; |
| |
| static struct clk_lookup hdmipllcc_8996[] = { |
| CLK_LIST(hdmi_vco_clk), |
| }; |
| |
| int hdmi_8996_pll_clock_register(struct platform_device *pdev, |
| struct mdss_pll_resources *pll_res, u32 ver) |
| { |
| int rc = -ENOTSUPP; |
| |
| if (!pll_res || !pll_res->phy_base || !pll_res->pll_base) { |
| DEV_ERR("%s: Invalid input parameters\n", __func__); |
| return -EPROBE_DEFER; |
| } |
| |
| /* Set client data for vco, mux and div clocks */ |
| hdmi_vco_clk.priv = pll_res; |
| |
| switch (ver) { |
| case HDMI_VERSION_8996_V2: |
| hdmi_vco_clk.c.ops = &hdmi_8996_v2_vco_clk_ops; |
| break; |
| case HDMI_VERSION_8996_V3: |
| hdmi_vco_clk.c.ops = &hdmi_8996_v3_vco_clk_ops; |
| break; |
| case HDMI_VERSION_8996_V3_1_8: |
| hdmi_vco_clk.c.ops = &hdmi_8996_v3_1p8_vco_clk_ops; |
| break; |
| default: |
| hdmi_vco_clk.c.ops = &hdmi_8996_v1_vco_clk_ops; |
| break; |
| }; |
| |
| rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8996, |
| ARRAY_SIZE(hdmipllcc_8996)); |
| if (rc) { |
| DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc); |
| rc = -EPROBE_DEFER; |
| } else { |
| DEV_DBG("%s SUCCESS\n", __func__); |
| } |
| |
| return rc; |
| } |
| |
| int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev, |
| struct mdss_pll_resources *pll_res) |
| { |
| return hdmi_8996_pll_clock_register(pdev, pll_res, |
| HDMI_VERSION_8996_V1); |
| } |
| |
| int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev, |
| struct mdss_pll_resources *pll_res) |
| { |
| return hdmi_8996_pll_clock_register(pdev, pll_res, |
| HDMI_VERSION_8996_V2); |
| } |
| |
| int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev, |
| struct mdss_pll_resources *pll_res) |
| { |
| return hdmi_8996_pll_clock_register(pdev, pll_res, |
| HDMI_VERSION_8996_V3); |
| } |
| |
| int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev, |
| struct mdss_pll_resources *pll_res) |
| { |
| return hdmi_8996_pll_clock_register(pdev, pll_res, |
| HDMI_VERSION_8996_V3_1_8); |
| } |