2022-06-24 14:27:25 +08:00
// SPDX-License-Identifier: GPL-2.0
/*
* MediaTek DisplayPort PHY driver
*
* Copyright ( c ) 2022 , BayLibre Inc .
* Copyright ( c ) 2022 , MediaTek Inc .
*/
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/mfd/syscon.h>
# include <linux/of.h>
# include <linux/phy/phy.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# define PHY_OFFSET 0x1000
# define MTK_DP_PHY_DIG_PLL_CTL_1 (PHY_OFFSET + 0x14)
# define TPLL_SSC_EN BIT(3)
# define MTK_DP_PHY_DIG_BIT_RATE (PHY_OFFSET + 0x3C)
# define BIT_RATE_RBR 0
# define BIT_RATE_HBR 1
# define BIT_RATE_HBR2 2
# define BIT_RATE_HBR3 3
# define MTK_DP_PHY_DIG_SW_RST (PHY_OFFSET + 0x38)
# define DP_GLB_SW_RST_PHYD BIT(0)
# define MTK_DP_LANE0_DRIVING_PARAM_3 (PHY_OFFSET + 0x138)
# define MTK_DP_LANE1_DRIVING_PARAM_3 (PHY_OFFSET + 0x238)
# define MTK_DP_LANE2_DRIVING_PARAM_3 (PHY_OFFSET + 0x338)
# define MTK_DP_LANE3_DRIVING_PARAM_3 (PHY_OFFSET + 0x438)
# define XTP_LN_TX_LCTXC0_SW0_PRE0_DEFAULT BIT(4)
# define XTP_LN_TX_LCTXC0_SW0_PRE1_DEFAULT (BIT(10) | BIT(12))
# define XTP_LN_TX_LCTXC0_SW0_PRE2_DEFAULT GENMASK(20, 19)
# define XTP_LN_TX_LCTXC0_SW0_PRE3_DEFAULT GENMASK(29, 29)
# define DRIVING_PARAM_3_DEFAULT (XTP_LN_TX_LCTXC0_SW0_PRE0_DEFAULT | \
XTP_LN_TX_LCTXC0_SW0_PRE1_DEFAULT | \
XTP_LN_TX_LCTXC0_SW0_PRE2_DEFAULT | \
XTP_LN_TX_LCTXC0_SW0_PRE3_DEFAULT )
# define XTP_LN_TX_LCTXC0_SW1_PRE0_DEFAULT GENMASK(4, 3)
# define XTP_LN_TX_LCTXC0_SW1_PRE1_DEFAULT GENMASK(12, 9)
# define XTP_LN_TX_LCTXC0_SW1_PRE2_DEFAULT (BIT(18) | BIT(21))
# define XTP_LN_TX_LCTXC0_SW2_PRE0_DEFAULT GENMASK(29, 29)
# define DRIVING_PARAM_4_DEFAULT (XTP_LN_TX_LCTXC0_SW1_PRE0_DEFAULT | \
XTP_LN_TX_LCTXC0_SW1_PRE1_DEFAULT | \
XTP_LN_TX_LCTXC0_SW1_PRE2_DEFAULT | \
XTP_LN_TX_LCTXC0_SW2_PRE0_DEFAULT )
# define XTP_LN_TX_LCTXC0_SW2_PRE1_DEFAULT (BIT(3) | BIT(5))
# define XTP_LN_TX_LCTXC0_SW3_PRE0_DEFAULT GENMASK(13, 12)
# define DRIVING_PARAM_5_DEFAULT (XTP_LN_TX_LCTXC0_SW2_PRE1_DEFAULT | \
XTP_LN_TX_LCTXC0_SW3_PRE0_DEFAULT )
# define XTP_LN_TX_LCTXCP1_SW0_PRE0_DEFAULT 0
# define XTP_LN_TX_LCTXCP1_SW0_PRE1_DEFAULT GENMASK(10, 10)
# define XTP_LN_TX_LCTXCP1_SW0_PRE2_DEFAULT GENMASK(19, 19)
# define XTP_LN_TX_LCTXCP1_SW0_PRE3_DEFAULT GENMASK(28, 28)
# define DRIVING_PARAM_6_DEFAULT (XTP_LN_TX_LCTXCP1_SW0_PRE0_DEFAULT | \
XTP_LN_TX_LCTXCP1_SW0_PRE1_DEFAULT | \
XTP_LN_TX_LCTXCP1_SW0_PRE2_DEFAULT | \
XTP_LN_TX_LCTXCP1_SW0_PRE3_DEFAULT )
# define XTP_LN_TX_LCTXCP1_SW1_PRE0_DEFAULT 0
# define XTP_LN_TX_LCTXCP1_SW1_PRE1_DEFAULT GENMASK(10, 9)
# define XTP_LN_TX_LCTXCP1_SW1_PRE2_DEFAULT GENMASK(19, 18)
# define XTP_LN_TX_LCTXCP1_SW2_PRE0_DEFAULT 0
# define DRIVING_PARAM_7_DEFAULT (XTP_LN_TX_LCTXCP1_SW1_PRE0_DEFAULT | \
XTP_LN_TX_LCTXCP1_SW1_PRE1_DEFAULT | \
XTP_LN_TX_LCTXCP1_SW1_PRE2_DEFAULT | \
XTP_LN_TX_LCTXCP1_SW2_PRE0_DEFAULT )
# define XTP_LN_TX_LCTXCP1_SW2_PRE1_DEFAULT GENMASK(3, 3)
# define XTP_LN_TX_LCTXCP1_SW3_PRE0_DEFAULT 0
# define DRIVING_PARAM_8_DEFAULT (XTP_LN_TX_LCTXCP1_SW2_PRE1_DEFAULT | \
XTP_LN_TX_LCTXCP1_SW3_PRE0_DEFAULT )
struct mtk_dp_phy {
struct regmap * regs ;
} ;
static int mtk_dp_phy_init ( struct phy * phy )
{
struct mtk_dp_phy * dp_phy = phy_get_drvdata ( phy ) ;
u32 driving_params [ ] = {
DRIVING_PARAM_3_DEFAULT ,
DRIVING_PARAM_4_DEFAULT ,
DRIVING_PARAM_5_DEFAULT ,
DRIVING_PARAM_6_DEFAULT ,
DRIVING_PARAM_7_DEFAULT ,
DRIVING_PARAM_8_DEFAULT
} ;
regmap_bulk_write ( dp_phy - > regs , MTK_DP_LANE0_DRIVING_PARAM_3 ,
driving_params , ARRAY_SIZE ( driving_params ) ) ;
regmap_bulk_write ( dp_phy - > regs , MTK_DP_LANE1_DRIVING_PARAM_3 ,
driving_params , ARRAY_SIZE ( driving_params ) ) ;
regmap_bulk_write ( dp_phy - > regs , MTK_DP_LANE2_DRIVING_PARAM_3 ,
driving_params , ARRAY_SIZE ( driving_params ) ) ;
regmap_bulk_write ( dp_phy - > regs , MTK_DP_LANE3_DRIVING_PARAM_3 ,
driving_params , ARRAY_SIZE ( driving_params ) ) ;
return 0 ;
}
static int mtk_dp_phy_configure ( struct phy * phy , union phy_configure_opts * opts )
{
struct mtk_dp_phy * dp_phy = phy_get_drvdata ( phy ) ;
u32 val ;
if ( opts - > dp . set_rate ) {
switch ( opts - > dp . link_rate ) {
default :
dev_err ( & phy - > dev ,
" Implementation error, unknown linkrate %x \n " ,
opts - > dp . link_rate ) ;
return - EINVAL ;
case 1620 :
val = BIT_RATE_RBR ;
break ;
case 2700 :
val = BIT_RATE_HBR ;
break ;
case 5400 :
val = BIT_RATE_HBR2 ;
break ;
case 8100 :
val = BIT_RATE_HBR3 ;
break ;
}
regmap_write ( dp_phy - > regs , MTK_DP_PHY_DIG_BIT_RATE , val ) ;
}
regmap_update_bits ( dp_phy - > regs , MTK_DP_PHY_DIG_PLL_CTL_1 ,
TPLL_SSC_EN , opts - > dp . ssc ? TPLL_SSC_EN : 0 ) ;
return 0 ;
}
static int mtk_dp_phy_reset ( struct phy * phy )
{
struct mtk_dp_phy * dp_phy = phy_get_drvdata ( phy ) ;
regmap_update_bits ( dp_phy - > regs , MTK_DP_PHY_DIG_SW_RST ,
DP_GLB_SW_RST_PHYD , 0 ) ;
usleep_range ( 50 , 200 ) ;
regmap_update_bits ( dp_phy - > regs , MTK_DP_PHY_DIG_SW_RST ,
DP_GLB_SW_RST_PHYD , 1 ) ;
return 0 ;
}
static const struct phy_ops mtk_dp_phy_dev_ops = {
. init = mtk_dp_phy_init ,
. configure = mtk_dp_phy_configure ,
. reset = mtk_dp_phy_reset ,
. owner = THIS_MODULE ,
} ;
static int mtk_dp_phy_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct mtk_dp_phy * dp_phy ;
struct phy * phy ;
struct regmap * regs ;
regs = * ( struct regmap * * ) dev - > platform_data ;
if ( ! regs )
return dev_err_probe ( dev , EINVAL ,
" No data passed, requires struct regmap** \n " ) ;
dp_phy = devm_kzalloc ( dev , sizeof ( * dp_phy ) , GFP_KERNEL ) ;
if ( ! dp_phy )
return - ENOMEM ;
dp_phy - > regs = regs ;
phy = devm_phy_create ( dev , NULL , & mtk_dp_phy_dev_ops ) ;
if ( IS_ERR ( phy ) )
return dev_err_probe ( dev , PTR_ERR ( phy ) ,
" Failed to create DP PHY \n " ) ;
phy_set_drvdata ( phy , dp_phy ) ;
if ( ! dev - > of_node )
phy_create_lookup ( phy , " dp " , dev_name ( dev ) ) ;
return 0 ;
}
2022-07-07 21:53:09 +08:00
static struct platform_driver mtk_dp_phy_driver = {
2022-06-24 14:27:25 +08:00
. probe = mtk_dp_phy_probe ,
. driver = {
. name = " mediatek-dp-phy " ,
} ,
} ;
module_platform_driver ( mtk_dp_phy_driver ) ;
MODULE_AUTHOR ( " Markus Schneider-Pargmann <msp@baylibre.com> " ) ;
MODULE_DESCRIPTION ( " MediaTek DP PHY Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;