2023-02-16 17:02:27 +01:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2022 MediaTek Inc .
* Copyright ( c ) 2022 BayLibre , SAS
*/
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/mfd/syscon.h>
# include <linux/module.h>
# include <linux/phy/phy.h>
# include <linux/platform_device.h>
# include <linux/types.h>
# include <linux/units.h>
# include <linux/nvmem-consumer.h>
# include "phy-mtk-io.h"
# include "phy-mtk-hdmi.h"
# include "phy-mtk-hdmi-mt8195.h"
static void mtk_hdmi_ana_fifo_en ( struct mtk_hdmi_phy * hdmi_phy )
{
/* make data fifo writable for hdmi2.0 */
mtk_phy_set_bits ( hdmi_phy - > regs + HDMI_ANA_CTL , REG_ANA_HDMI20_FIFO_EN ) ;
}
static void
mtk_phy_tmds_clk_ratio ( struct mtk_hdmi_phy * hdmi_phy , bool enable )
{
void __iomem * regs = hdmi_phy - > regs ;
mtk_hdmi_ana_fifo_en ( hdmi_phy ) ;
/* HDMI 2.0 specification, 3.4Gbps <= TMDS Bit Rate <= 6G,
* clock bit ratio 1 : 40 , under 3.4 Gbps , clock bit ratio 1 : 10
*/
if ( enable )
mtk_phy_update_field ( regs + HDMI20_CLK_CFG , REG_TXC_DIV , 3 ) ;
else
mtk_phy_clear_bits ( regs + HDMI20_CLK_CFG , REG_TXC_DIV ) ;
}
static void mtk_hdmi_pll_sel_src ( struct clk_hw * hw )
{
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
void __iomem * regs = hdmi_phy - > regs ;
mtk_phy_clear_bits ( regs + HDMI_CTL_3 , REG_HDMITX_REF_XTAL_SEL ) ;
mtk_phy_clear_bits ( regs + HDMI_CTL_3 , REG_HDMITX_REF_RESPLL_SEL ) ;
/* DA_HDMITX21_REF_CK for TXPLL input source */
mtk_phy_clear_bits ( regs + HDMI_1_CFG_10 , RG_HDMITXPLL_REF_CK_SEL ) ;
}
static void mtk_hdmi_pll_perf ( struct clk_hw * hw )
{
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
void __iomem * regs = hdmi_phy - > regs ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_0 , RG_HDMITXPLL_BP2 ) ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_BC ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_IC , 0x1 ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_BR , 0x2 ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_IR , 0x2 ) ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_BP ) ;
mtk_phy_clear_bits ( regs + HDMI_1_PLL_CFG_0 , RG_HDMITXPLL_IBAND_FIX_EN ) ;
mtk_phy_clear_bits ( regs + HDMI_1_PLL_CFG_1 , RG_HDMITXPLL_RESERVE_BIT14 ) ;
mtk_phy_clear_bits ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_HIKVCO ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_0 , RG_HDMITXPLL_HREN , 0x1 ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_0 , RG_HDMITXPLL_LVR_SEL , 0x1 ) ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_1 , RG_HDMITXPLL_RESERVE_BIT12_11 ) ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_0 , RG_HDMITXPLL_TCL_EN ) ;
}
static int mtk_hdmi_pll_set_hw ( struct clk_hw * hw , u8 prediv ,
u8 fbkdiv_high ,
u32 fbkdiv_low ,
u8 fbkdiv_hs3 , u8 posdiv1 ,
u8 posdiv2 , u8 txprediv ,
u8 txposdiv ,
u8 digital_div )
{
u8 txposdiv_value ;
u8 div3_ctrl_value ;
u8 posdiv_vallue ;
u8 div_ctrl_value ;
u8 reserve_3_2_value ;
u8 prediv_value ;
u8 reserve13_value ;
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
void __iomem * regs = hdmi_phy - > regs ;
mtk_hdmi_pll_sel_src ( hw ) ;
mtk_hdmi_pll_perf ( hw ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_10 , RG_HDMITX21_BIAS_PE_BG_VREF_SEL , 0x2 ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_10 , RG_HDMITX21_VREF_SEL ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_9 , RG_HDMITX21_SLDO_VREF_SEL , 0x2 ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_10 , RG_HDMITX21_BIAS_PE_VREF_SELB ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_3 , RG_HDMITX21_SLDOLPF_EN ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_6 , RG_HDMITX21_INTR_CAL , 0x11 ) ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_PWD ) ;
/* TXPOSDIV */
txposdiv_value = ilog2 ( txposdiv ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_6 , RG_HDMITX21_TX_POSDIV , txposdiv_value ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_TX_POSDIV_EN ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_FRL_EN ) ;
/* TXPREDIV */
switch ( txprediv ) {
case 2 :
div3_ctrl_value = 0x0 ;
posdiv_vallue = 0x0 ;
break ;
case 4 :
div3_ctrl_value = 0x0 ;
posdiv_vallue = 0x1 ;
break ;
case 6 :
div3_ctrl_value = 0x1 ;
posdiv_vallue = 0x0 ;
break ;
case 12 :
div3_ctrl_value = 0x1 ;
posdiv_vallue = 0x1 ;
break ;
default :
return - EINVAL ;
}
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_4 , RG_HDMITXPLL_POSDIV_DIV3_CTRL , div3_ctrl_value ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_4 , RG_HDMITXPLL_POSDIV , posdiv_vallue ) ;
/* POSDIV1 */
switch ( posdiv1 ) {
case 5 :
div_ctrl_value = 0x0 ;
break ;
case 10 :
div_ctrl_value = 0x1 ;
break ;
case 12 :
div_ctrl_value = 0x2 ;
break ;
case 15 :
div_ctrl_value = 0x3 ;
break ;
default :
return - EINVAL ;
}
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_4 , RG_HDMITXPLL_DIV_CTRL , div_ctrl_value ) ;
/* DE add new setting */
mtk_phy_clear_bits ( regs + HDMI_1_PLL_CFG_1 , RG_HDMITXPLL_RESERVE_BIT14 ) ;
/* POSDIV2 */
switch ( posdiv2 ) {
case 1 :
reserve_3_2_value = 0x0 ;
break ;
case 2 :
reserve_3_2_value = 0x1 ;
break ;
case 4 :
reserve_3_2_value = 0x2 ;
break ;
case 6 :
reserve_3_2_value = 0x3 ;
break ;
default :
return - EINVAL ;
}
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_1 , RG_HDMITXPLL_RESERVE_BIT3_2 , reserve_3_2_value ) ;
/* DE add new setting */
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_1 , RG_HDMITXPLL_RESERVE_BIT1_0 , 0x2 ) ;
/* PREDIV */
prediv_value = ilog2 ( prediv ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_4 , RG_HDMITXPLL_PREDIV , prediv_value ) ;
/* FBKDIV_HS3 */
reserve13_value = ilog2 ( fbkdiv_hs3 ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_1 , RG_HDMITXPLL_RESERVE_BIT13 , reserve13_value ) ;
/* FBDIV */
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_4 , RG_HDMITXPLL_FBKDIV_HIGH , fbkdiv_high ) ;
mtk_phy_update_field ( regs + HDMI_1_PLL_CFG_3 , RG_HDMITXPLL_FBKDIV_LOW , fbkdiv_low ) ;
/* Digital DIVIDER */
mtk_phy_clear_bits ( regs + HDMI_CTL_3 , REG_PIXEL_CLOCK_SEL ) ;
if ( digital_div = = 1 ) {
mtk_phy_clear_bits ( regs + HDMI_CTL_3 , REG_HDMITX_PIXEL_CLOCK ) ;
} else {
mtk_phy_set_bits ( regs + HDMI_CTL_3 , REG_HDMITX_PIXEL_CLOCK ) ;
mtk_phy_update_field ( regs + HDMI_CTL_3 , REG_HDMITXPLL_DIV , digital_div - 1 ) ;
}
return 0 ;
}
static int mtk_hdmi_pll_calc ( struct mtk_hdmi_phy * hdmi_phy , struct clk_hw * hw ,
unsigned long rate , unsigned long parent_rate )
{
u8 digital_div , txprediv , txposdiv , fbkdiv_high , posdiv1 , posdiv2 ;
u64 tmds_clk , pixel_clk , da_hdmitx21_ref_ck , ns_hdmipll_ck , pcw ;
u8 txpredivs [ 4 ] = { 2 , 4 , 6 , 12 } ;
u32 fbkdiv_low ;
2023-04-14 18:07:46 +02:00
int i ;
2023-02-16 17:02:27 +01:00
pixel_clk = rate ;
tmds_clk = pixel_clk ;
if ( tmds_clk < 25 * MEGA | | tmds_clk > 594 * MEGA )
return - EINVAL ;
if ( tmds_clk > = 340 * MEGA )
hdmi_phy - > tmds_over_340M = true ;
else
hdmi_phy - > tmds_over_340M = false ;
/* in Hz */
da_hdmitx21_ref_ck = 26 * MEGA ;
/* TXPOSDIV stage treatment:
* 0 M < TMDS clk < 54 M / 8
* 54 M < = TMDS clk < 148.35 M / 4
* 148.35 M < = TMDS clk < 296.7 M / 2
* 296.7 < = TMDS clk < = 594 M / 1
*/
if ( tmds_clk < 54 * MEGA )
txposdiv = 8 ;
2023-05-02 10:50:05 -04:00
else if ( tmds_clk > = 54 * MEGA & & ( tmds_clk * 100 ) < 14835 * MEGA )
2023-02-16 17:02:27 +01:00
txposdiv = 4 ;
2023-05-02 10:50:05 -04:00
else if ( ( tmds_clk * 100 ) > = 14835 * MEGA & & ( tmds_clk * 10 ) < 2967 * MEGA )
2023-02-16 17:02:27 +01:00
txposdiv = 2 ;
2023-05-02 10:50:05 -04:00
else if ( ( tmds_clk * 10 ) > = 2967 * MEGA & & tmds_clk < = 594 * MEGA )
2023-02-16 17:02:27 +01:00
txposdiv = 1 ;
else
return - EINVAL ;
/* calculate txprediv: can be 2, 4, 6, 12
* ICO clk = 5 * TMDS_CLK * TXPOSDIV * TXPREDIV
* ICO clk constraint : 5 G = < ICO clk < = 12 G
*/
for ( i = 0 ; i < ARRAY_SIZE ( txpredivs ) ; i + + ) {
ns_hdmipll_ck = 5 * tmds_clk * txposdiv * txpredivs [ i ] ;
if ( ns_hdmipll_ck > = 5 * GIGA & &
2023-05-30 10:43:07 +02:00
ns_hdmipll_ck < = 12 * GIGA )
2023-02-16 17:02:27 +01:00
break ;
}
if ( i = = ( ARRAY_SIZE ( txpredivs ) - 1 ) & &
( ns_hdmipll_ck < 5 * GIGA | | ns_hdmipll_ck > 12 * GIGA ) ) {
return - EINVAL ;
}
if ( i = = ARRAY_SIZE ( txpredivs ) )
return - EINVAL ;
txprediv = txpredivs [ i ] ;
/* PCW calculation: FBKDIV
* formula : pcw = ( frequency_out * 2 ^ pcw_bit ) / frequency_in / FBKDIV_HS3 ;
* RG_HDMITXPLL_FBKDIV [ 32 : 0 ] :
* [ 32 , 24 ] 9 bit integer , [ 23 , 0 ] : 24 bit fraction
*/
pcw = div_u64 ( ( ( u64 ) ns_hdmipll_ck ) < < PCW_DECIMAL_WIDTH ,
2023-04-14 18:07:47 +02:00
da_hdmitx21_ref_ck * PLL_FBKDIV_HS3 ) ;
2023-02-16 17:02:27 +01:00
if ( pcw > GENMASK_ULL ( 32 , 0 ) )
return - EINVAL ;
fbkdiv_high = FIELD_GET ( GENMASK_ULL ( 63 , 32 ) , pcw ) ;
fbkdiv_low = FIELD_GET ( GENMASK ( 31 , 0 ) , pcw ) ;
/* posdiv1:
* posdiv1 stage treatment according to color_depth :
* 24 bit - > posdiv1 / 10 , 30 bit - > posdiv1 / 12.5 ,
* 36 bit - > posdiv1 / 15 , 48 bit - > posdiv1 / 10
*/
posdiv1 = 10 ;
posdiv2 = 1 ;
/* Digital clk divider, max /32 */
2023-04-14 18:07:47 +02:00
digital_div = div_u64 ( ns_hdmipll_ck , posdiv1 * posdiv2 * pixel_clk ) ;
2023-02-16 17:02:27 +01:00
if ( ! ( digital_div < = 32 & & digital_div > = 1 ) )
return - EINVAL ;
2023-04-14 18:07:46 +02:00
return mtk_hdmi_pll_set_hw ( hw , PLL_PREDIV , fbkdiv_high , fbkdiv_low ,
2023-02-16 17:02:27 +01:00
PLL_FBKDIV_HS3 , posdiv1 , posdiv2 , txprediv ,
txposdiv , digital_div ) ;
}
static int mtk_hdmi_pll_drv_setting ( struct clk_hw * hw )
{
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
void __iomem * regs = hdmi_phy - > regs ;
u8 data_channel_bias , clk_channel_bias ;
u8 impedance , impedance_en ;
u32 tmds_clk ;
u32 pixel_clk = hdmi_phy - > pll_rate ;
tmds_clk = pixel_clk ;
/* bias & impedance setting:
* 3 G < data rate < = 6 G : enable impedance 100 ohm ,
* data channel bias 24 mA , clock channel bias 20 mA
* pixel clk > = HD , 74.175 MHZ < = pixel clk < = 300 MHZ :
* enalbe impedance 100 ohm
* data channel 20 mA , clock channel 16 mA
* 27 M = < pixel clk < 74.175 : disable impedance
* data channel & clock channel bias 10 mA
*/
/* 3G < data rate <= 6G, 300M < tmds rate <= 594M */
if ( tmds_clk > 300 * MEGA & & tmds_clk < = 594 * MEGA ) {
data_channel_bias = 0x3c ; /* 24mA */
clk_channel_bias = 0x34 ; /* 20mA */
impedance_en = 0xf ;
impedance = 0x36 ; /* 100ohm */
2023-05-02 10:50:05 -04:00
} else if ( ( ( u64 ) pixel_clk * 1000 ) > = 74175 * MEGA & & pixel_clk < = 300 * MEGA ) {
2023-02-16 17:02:27 +01:00
data_channel_bias = 0x34 ; /* 20mA */
clk_channel_bias = 0x2c ; /* 16mA */
impedance_en = 0xf ;
impedance = 0x36 ; /* 100ohm */
2023-05-02 10:50:05 -04:00
} else if ( pixel_clk > = 27 * MEGA & & ( ( u64 ) pixel_clk * 1000 ) < 74175 * MEGA ) {
2023-02-16 17:02:27 +01:00
data_channel_bias = 0x14 ; /* 10mA */
clk_channel_bias = 0x14 ; /* 10mA */
impedance_en = 0x0 ;
impedance = 0x0 ;
} else {
return - EINVAL ;
}
/* bias */
mtk_phy_update_field ( regs + HDMI_1_CFG_1 , RG_HDMITX21_DRV_IBIAS_D0 , data_channel_bias ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_1 , RG_HDMITX21_DRV_IBIAS_D1 , data_channel_bias ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_1 , RG_HDMITX21_DRV_IBIAS_D2 , data_channel_bias ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_0 , RG_HDMITX21_DRV_IBIAS_CLK , clk_channel_bias ) ;
/* impedance */
mtk_phy_update_field ( regs + HDMI_1_CFG_0 , RG_HDMITX21_DRV_IMP_EN , impedance_en ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_2 , RG_HDMITX21_DRV_IMP_D0_EN1 , impedance ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_2 , RG_HDMITX21_DRV_IMP_D1_EN1 , impedance ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_2 , RG_HDMITX21_DRV_IMP_D2_EN1 , impedance ) ;
mtk_phy_update_field ( regs + HDMI_1_CFG_2 , RG_HDMITX21_DRV_IMP_CLK_EN1 , impedance ) ;
return 0 ;
}
static int mtk_hdmi_pll_prepare ( struct clk_hw * hw )
{
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
void __iomem * regs = hdmi_phy - > regs ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_TX_POSDIV_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_0 , RG_HDMITX21_SER_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_D0_DRV_OP_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_D1_DRV_OP_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_D2_DRV_OP_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_CK_DRV_OP_EN ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_FRL_D0_EN ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_FRL_D1_EN ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_FRL_D2_EN ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_FRL_CK_EN ) ;
mtk_hdmi_pll_drv_setting ( hw ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_10 , RG_HDMITX21_BG_PWD ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_BIAS_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_3 , RG_HDMITX21_CKLDO_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_3 , RG_HDMITX21_SLDO_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_4 , DA_HDMITXPLL_PWR_ON ) ;
usleep_range ( 5 , 10 ) ;
mtk_phy_clear_bits ( regs + HDMI_1_PLL_CFG_4 , DA_HDMITXPLL_ISO_EN ) ;
usleep_range ( 5 , 10 ) ;
mtk_phy_clear_bits ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_PWD ) ;
usleep_range ( 30 , 50 ) ;
return 0 ;
}
static void mtk_hdmi_pll_unprepare ( struct clk_hw * hw )
{
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
void __iomem * regs = hdmi_phy - > regs ;
mtk_phy_set_bits ( regs + HDMI_1_CFG_10 , RG_HDMITX21_BG_PWD ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_6 , RG_HDMITX21_BIAS_EN ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_3 , RG_HDMITX21_CKLDO_EN ) ;
mtk_phy_clear_bits ( regs + HDMI_1_CFG_3 , RG_HDMITX21_SLDO_EN ) ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_2 , RG_HDMITXPLL_PWD ) ;
usleep_range ( 10 , 20 ) ;
mtk_phy_set_bits ( regs + HDMI_1_PLL_CFG_4 , DA_HDMITXPLL_ISO_EN ) ;
usleep_range ( 10 , 20 ) ;
mtk_phy_clear_bits ( regs + HDMI_1_PLL_CFG_4 , DA_HDMITXPLL_PWR_ON ) ;
}
static int mtk_hdmi_pll_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
dev_dbg ( hdmi_phy - > dev , " %s: %lu Hz, parent: %lu Hz \n " , __func__ , rate ,
parent_rate ) ;
return mtk_hdmi_pll_calc ( hdmi_phy , hw , rate , parent_rate ) ;
}
static long mtk_hdmi_pll_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * parent_rate )
{
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
hdmi_phy - > pll_rate = rate ;
return rate ;
}
static unsigned long mtk_hdmi_pll_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct mtk_hdmi_phy * hdmi_phy = to_mtk_hdmi_phy ( hw ) ;
return hdmi_phy - > pll_rate ;
}
static const struct clk_ops mtk_hdmi_pll_ops = {
. prepare = mtk_hdmi_pll_prepare ,
. unprepare = mtk_hdmi_pll_unprepare ,
. set_rate = mtk_hdmi_pll_set_rate ,
. round_rate = mtk_hdmi_pll_round_rate ,
. recalc_rate = mtk_hdmi_pll_recalc_rate ,
} ;
static void vtx_signal_en ( struct mtk_hdmi_phy * hdmi_phy , bool on )
{
void __iomem * regs = hdmi_phy - > regs ;
if ( on )
mtk_phy_set_bits ( regs + HDMI_1_CFG_0 , RG_HDMITX21_DRV_EN ) ;
else
mtk_phy_clear_bits ( regs + HDMI_1_CFG_0 , RG_HDMITX21_DRV_EN ) ;
}
static void mtk_hdmi_phy_enable_tmds ( struct mtk_hdmi_phy * hdmi_phy )
{
vtx_signal_en ( hdmi_phy , true ) ;
usleep_range ( 100 , 150 ) ;
}
static void mtk_hdmi_phy_disable_tmds ( struct mtk_hdmi_phy * hdmi_phy )
{
vtx_signal_en ( hdmi_phy , false ) ;
}
static int mtk_hdmi_phy_configure ( struct phy * phy , union phy_configure_opts * opts )
{
struct phy_configure_opts_dp * dp_opts = & opts - > dp ;
struct mtk_hdmi_phy * hdmi_phy = phy_get_drvdata ( phy ) ;
int ret ;
ret = clk_set_rate ( hdmi_phy - > pll , dp_opts - > link_rate ) ;
if ( ret )
return ret ;
mtk_phy_tmds_clk_ratio ( hdmi_phy , hdmi_phy - > tmds_over_340M ) ;
return ret ;
}
struct mtk_hdmi_phy_conf mtk_hdmi_phy_8195_conf = {
. flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE ,
. hdmi_phy_clk_ops = & mtk_hdmi_pll_ops ,
. hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds ,
. hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds ,
. hdmi_phy_configure = mtk_hdmi_phy_configure ,
} ;
MODULE_AUTHOR ( " Can Zeng <can.zeng@mediatek.com> " ) ;
MODULE_DESCRIPTION ( " MediaTek MT8195 HDMI PHY Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;