2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-01-04 18:36:36 +01:00
/*
* Copyright ( c ) 2014 MediaTek Inc .
* Author : Jie Qiu < jie . qiu @ mediatek . com >
*/
2019-07-16 08:42:20 +02:00
# include <linux/clk.h>
2016-01-04 18:36:36 +01:00
# include <linux/component.h>
2019-07-16 08:42:20 +02:00
# include <linux/interrupt.h>
# include <linux/kernel.h>
2016-01-04 18:36:36 +01:00
# include <linux/of.h>
2018-10-03 11:41:42 +08:00
# include <linux/of_device.h>
2020-04-15 09:13:19 +08:00
# include <linux/of_gpio.h>
2016-01-04 18:36:36 +01:00
# include <linux/of_graph.h>
2020-04-15 09:13:19 +08:00
# include <linux/pinctrl/consumer.h>
2019-07-16 08:42:20 +02:00
# include <linux/platform_device.h>
2016-01-04 18:36:36 +01:00
# include <linux/types.h>
2019-07-16 08:42:20 +02:00
2018-03-31 20:17:58 +05:30
# include <video/videomode.h>
2016-01-04 18:36:36 +01:00
2019-07-16 08:42:20 +02:00
# include <drm/drm_atomic_helper.h>
2019-08-26 17:26:29 +02:00
# include <drm/drm_bridge.h>
2019-07-16 08:42:20 +02:00
# include <drm/drm_crtc.h>
# include <drm/drm_of.h>
2020-03-05 16:59:38 +01:00
# include <drm/drm_simple_kms_helper.h>
2019-07-16 08:42:20 +02:00
2016-01-04 18:36:36 +01:00
# include "mtk_dpi_regs.h"
# include "mtk_drm_ddp_comp.h"
enum mtk_dpi_out_bit_num {
MTK_DPI_OUT_BIT_NUM_8BITS ,
MTK_DPI_OUT_BIT_NUM_10BITS ,
MTK_DPI_OUT_BIT_NUM_12BITS ,
MTK_DPI_OUT_BIT_NUM_16BITS
} ;
enum mtk_dpi_out_yc_map {
MTK_DPI_OUT_YC_MAP_RGB ,
MTK_DPI_OUT_YC_MAP_CYCY ,
MTK_DPI_OUT_YC_MAP_YCYC ,
MTK_DPI_OUT_YC_MAP_CY ,
MTK_DPI_OUT_YC_MAP_YC
} ;
enum mtk_dpi_out_channel_swap {
MTK_DPI_OUT_CHANNEL_SWAP_RGB ,
MTK_DPI_OUT_CHANNEL_SWAP_GBR ,
MTK_DPI_OUT_CHANNEL_SWAP_BRG ,
MTK_DPI_OUT_CHANNEL_SWAP_RBG ,
MTK_DPI_OUT_CHANNEL_SWAP_GRB ,
MTK_DPI_OUT_CHANNEL_SWAP_BGR
} ;
enum mtk_dpi_out_color_format {
MTK_DPI_COLOR_FORMAT_RGB ,
MTK_DPI_COLOR_FORMAT_RGB_FULL ,
MTK_DPI_COLOR_FORMAT_YCBCR_444 ,
MTK_DPI_COLOR_FORMAT_YCBCR_422 ,
MTK_DPI_COLOR_FORMAT_XV_YCC ,
MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL ,
MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
} ;
struct mtk_dpi {
struct mtk_ddp_comp ddp_comp ;
struct drm_encoder encoder ;
2020-08-26 10:53:16 +02:00
struct drm_bridge * next_bridge ;
2016-01-04 18:36:36 +01:00
void __iomem * regs ;
struct device * dev ;
struct clk * engine_clk ;
struct clk * pixel_clk ;
struct clk * tvd_clk ;
int irq ;
struct drm_display_mode mode ;
2018-10-03 11:41:42 +08:00
const struct mtk_dpi_conf * conf ;
2016-01-04 18:36:36 +01:00
enum mtk_dpi_out_color_format color_format ;
enum mtk_dpi_out_yc_map yc_map ;
enum mtk_dpi_out_bit_num bit_num ;
enum mtk_dpi_out_channel_swap channel_swap ;
2020-04-15 09:13:19 +08:00
struct pinctrl * pinctrl ;
struct pinctrl_state * pins_gpio ;
struct pinctrl_state * pins_dpi ;
2018-10-03 11:41:41 +08:00
int refcount ;
2016-01-04 18:36:36 +01:00
} ;
static inline struct mtk_dpi * mtk_dpi_from_encoder ( struct drm_encoder * e )
{
return container_of ( e , struct mtk_dpi , encoder ) ;
}
enum mtk_dpi_polarity {
MTK_DPI_POLARITY_RISING ,
MTK_DPI_POLARITY_FALLING ,
} ;
struct mtk_dpi_polarities {
enum mtk_dpi_polarity de_pol ;
enum mtk_dpi_polarity ck_pol ;
enum mtk_dpi_polarity hsync_pol ;
enum mtk_dpi_polarity vsync_pol ;
} ;
struct mtk_dpi_sync_param {
u32 sync_width ;
u32 front_porch ;
u32 back_porch ;
bool shift_half_line ;
} ;
struct mtk_dpi_yc_limit {
u16 y_top ;
u16 y_bottom ;
u16 c_top ;
u16 c_bottom ;
} ;
2018-10-03 11:41:42 +08:00
struct mtk_dpi_conf {
2018-10-03 11:41:44 +08:00
unsigned int ( * cal_factor ) ( int clock ) ;
2018-10-03 11:41:42 +08:00
u32 reg_h_fre_con ;
2018-10-03 11:41:43 +08:00
bool edge_sel_en ;
2018-10-03 11:41:42 +08:00
} ;
2016-01-04 18:36:36 +01:00
static void mtk_dpi_mask ( struct mtk_dpi * dpi , u32 offset , u32 val , u32 mask )
{
u32 tmp = readl ( dpi - > regs + offset ) & ~ mask ;
tmp | = ( val & mask ) ;
writel ( tmp , dpi - > regs + offset ) ;
}
static void mtk_dpi_sw_reset ( struct mtk_dpi * dpi , bool reset )
{
mtk_dpi_mask ( dpi , DPI_RET , reset ? RST : 0 , RST ) ;
}
static void mtk_dpi_enable ( struct mtk_dpi * dpi )
{
mtk_dpi_mask ( dpi , DPI_EN , EN , EN ) ;
}
static void mtk_dpi_disable ( struct mtk_dpi * dpi )
{
mtk_dpi_mask ( dpi , DPI_EN , 0 , EN ) ;
}
static void mtk_dpi_config_hsync ( struct mtk_dpi * dpi ,
struct mtk_dpi_sync_param * sync )
{
mtk_dpi_mask ( dpi , DPI_TGEN_HWIDTH ,
sync - > sync_width < < HPW , HPW_MASK ) ;
mtk_dpi_mask ( dpi , DPI_TGEN_HPORCH ,
sync - > back_porch < < HBP , HBP_MASK ) ;
mtk_dpi_mask ( dpi , DPI_TGEN_HPORCH , sync - > front_porch < < HFP ,
HFP_MASK ) ;
}
static void mtk_dpi_config_vsync ( struct mtk_dpi * dpi ,
struct mtk_dpi_sync_param * sync ,
u32 width_addr , u32 porch_addr )
{
mtk_dpi_mask ( dpi , width_addr ,
sync - > sync_width < < VSYNC_WIDTH_SHIFT ,
VSYNC_WIDTH_MASK ) ;
mtk_dpi_mask ( dpi , width_addr ,
sync - > shift_half_line < < VSYNC_HALF_LINE_SHIFT ,
VSYNC_HALF_LINE_MASK ) ;
mtk_dpi_mask ( dpi , porch_addr ,
sync - > back_porch < < VSYNC_BACK_PORCH_SHIFT ,
VSYNC_BACK_PORCH_MASK ) ;
mtk_dpi_mask ( dpi , porch_addr ,
sync - > front_porch < < VSYNC_FRONT_PORCH_SHIFT ,
VSYNC_FRONT_PORCH_MASK ) ;
}
static void mtk_dpi_config_vsync_lodd ( struct mtk_dpi * dpi ,
struct mtk_dpi_sync_param * sync )
{
mtk_dpi_config_vsync ( dpi , sync , DPI_TGEN_VWIDTH , DPI_TGEN_VPORCH ) ;
}
static void mtk_dpi_config_vsync_leven ( struct mtk_dpi * dpi ,
struct mtk_dpi_sync_param * sync )
{
mtk_dpi_config_vsync ( dpi , sync , DPI_TGEN_VWIDTH_LEVEN ,
DPI_TGEN_VPORCH_LEVEN ) ;
}
static void mtk_dpi_config_vsync_rodd ( struct mtk_dpi * dpi ,
struct mtk_dpi_sync_param * sync )
{
mtk_dpi_config_vsync ( dpi , sync , DPI_TGEN_VWIDTH_RODD ,
DPI_TGEN_VPORCH_RODD ) ;
}
static void mtk_dpi_config_vsync_reven ( struct mtk_dpi * dpi ,
struct mtk_dpi_sync_param * sync )
{
mtk_dpi_config_vsync ( dpi , sync , DPI_TGEN_VWIDTH_REVEN ,
DPI_TGEN_VPORCH_REVEN ) ;
}
static void mtk_dpi_config_pol ( struct mtk_dpi * dpi ,
struct mtk_dpi_polarities * dpi_pol )
{
unsigned int pol ;
pol = ( dpi_pol - > ck_pol = = MTK_DPI_POLARITY_RISING ? 0 : CK_POL ) |
( dpi_pol - > de_pol = = MTK_DPI_POLARITY_RISING ? 0 : DE_POL ) |
( dpi_pol - > hsync_pol = = MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL ) |
( dpi_pol - > vsync_pol = = MTK_DPI_POLARITY_RISING ? 0 : VSYNC_POL ) ;
mtk_dpi_mask ( dpi , DPI_OUTPUT_SETTING , pol ,
CK_POL | DE_POL | HSYNC_POL | VSYNC_POL ) ;
}
static void mtk_dpi_config_3d ( struct mtk_dpi * dpi , bool en_3d )
{
mtk_dpi_mask ( dpi , DPI_CON , en_3d ? TDFP_EN : 0 , TDFP_EN ) ;
}
static void mtk_dpi_config_interface ( struct mtk_dpi * dpi , bool inter )
{
mtk_dpi_mask ( dpi , DPI_CON , inter ? INTL_EN : 0 , INTL_EN ) ;
}
static void mtk_dpi_config_fb_size ( struct mtk_dpi * dpi , u32 width , u32 height )
{
mtk_dpi_mask ( dpi , DPI_SIZE , width < < HSIZE , HSIZE_MASK ) ;
mtk_dpi_mask ( dpi , DPI_SIZE , height < < VSIZE , VSIZE_MASK ) ;
}
static void mtk_dpi_config_channel_limit ( struct mtk_dpi * dpi ,
struct mtk_dpi_yc_limit * limit )
{
mtk_dpi_mask ( dpi , DPI_Y_LIMIT , limit - > y_bottom < < Y_LIMINT_BOT ,
Y_LIMINT_BOT_MASK ) ;
mtk_dpi_mask ( dpi , DPI_Y_LIMIT , limit - > y_top < < Y_LIMINT_TOP ,
Y_LIMINT_TOP_MASK ) ;
mtk_dpi_mask ( dpi , DPI_C_LIMIT , limit - > c_bottom < < C_LIMIT_BOT ,
C_LIMIT_BOT_MASK ) ;
mtk_dpi_mask ( dpi , DPI_C_LIMIT , limit - > c_top < < C_LIMIT_TOP ,
C_LIMIT_TOP_MASK ) ;
}
static void mtk_dpi_config_bit_num ( struct mtk_dpi * dpi ,
enum mtk_dpi_out_bit_num num )
{
u32 val ;
switch ( num ) {
case MTK_DPI_OUT_BIT_NUM_8BITS :
val = OUT_BIT_8 ;
break ;
case MTK_DPI_OUT_BIT_NUM_10BITS :
val = OUT_BIT_10 ;
break ;
case MTK_DPI_OUT_BIT_NUM_12BITS :
val = OUT_BIT_12 ;
break ;
case MTK_DPI_OUT_BIT_NUM_16BITS :
val = OUT_BIT_16 ;
break ;
default :
val = OUT_BIT_8 ;
break ;
}
mtk_dpi_mask ( dpi , DPI_OUTPUT_SETTING , val < < OUT_BIT ,
OUT_BIT_MASK ) ;
}
static void mtk_dpi_config_yc_map ( struct mtk_dpi * dpi ,
enum mtk_dpi_out_yc_map map )
{
u32 val ;
switch ( map ) {
case MTK_DPI_OUT_YC_MAP_RGB :
val = YC_MAP_RGB ;
break ;
case MTK_DPI_OUT_YC_MAP_CYCY :
val = YC_MAP_CYCY ;
break ;
case MTK_DPI_OUT_YC_MAP_YCYC :
val = YC_MAP_YCYC ;
break ;
case MTK_DPI_OUT_YC_MAP_CY :
val = YC_MAP_CY ;
break ;
case MTK_DPI_OUT_YC_MAP_YC :
val = YC_MAP_YC ;
break ;
default :
val = YC_MAP_RGB ;
break ;
}
mtk_dpi_mask ( dpi , DPI_OUTPUT_SETTING , val < < YC_MAP , YC_MAP_MASK ) ;
}
static void mtk_dpi_config_channel_swap ( struct mtk_dpi * dpi ,
enum mtk_dpi_out_channel_swap swap )
{
u32 val ;
switch ( swap ) {
case MTK_DPI_OUT_CHANNEL_SWAP_RGB :
val = SWAP_RGB ;
break ;
case MTK_DPI_OUT_CHANNEL_SWAP_GBR :
val = SWAP_GBR ;
break ;
case MTK_DPI_OUT_CHANNEL_SWAP_BRG :
val = SWAP_BRG ;
break ;
case MTK_DPI_OUT_CHANNEL_SWAP_RBG :
val = SWAP_RBG ;
break ;
case MTK_DPI_OUT_CHANNEL_SWAP_GRB :
val = SWAP_GRB ;
break ;
case MTK_DPI_OUT_CHANNEL_SWAP_BGR :
val = SWAP_BGR ;
break ;
default :
val = SWAP_RGB ;
break ;
}
mtk_dpi_mask ( dpi , DPI_OUTPUT_SETTING , val < < CH_SWAP , CH_SWAP_MASK ) ;
}
static void mtk_dpi_config_yuv422_enable ( struct mtk_dpi * dpi , bool enable )
{
mtk_dpi_mask ( dpi , DPI_CON , enable ? YUV422_EN : 0 , YUV422_EN ) ;
}
static void mtk_dpi_config_csc_enable ( struct mtk_dpi * dpi , bool enable )
{
mtk_dpi_mask ( dpi , DPI_CON , enable ? CSC_ENABLE : 0 , CSC_ENABLE ) ;
}
static void mtk_dpi_config_swap_input ( struct mtk_dpi * dpi , bool enable )
{
mtk_dpi_mask ( dpi , DPI_CON , enable ? IN_RB_SWAP : 0 , IN_RB_SWAP ) ;
}
static void mtk_dpi_config_2n_h_fre ( struct mtk_dpi * dpi )
{
2018-10-03 11:41:42 +08:00
mtk_dpi_mask ( dpi , dpi - > conf - > reg_h_fre_con , H_FRE_2N , H_FRE_2N ) ;
2016-01-04 18:36:36 +01:00
}
2018-10-03 11:41:43 +08:00
static void mtk_dpi_config_disable_edge ( struct mtk_dpi * dpi )
{
if ( dpi - > conf - > edge_sel_en )
mtk_dpi_mask ( dpi , dpi - > conf - > reg_h_fre_con , 0 , EDGE_SEL_EN ) ;
}
2016-01-04 18:36:36 +01:00
static void mtk_dpi_config_color_format ( struct mtk_dpi * dpi ,
enum mtk_dpi_out_color_format format )
{
if ( ( format = = MTK_DPI_COLOR_FORMAT_YCBCR_444 ) | |
( format = = MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL ) ) {
mtk_dpi_config_yuv422_enable ( dpi , false ) ;
mtk_dpi_config_csc_enable ( dpi , true ) ;
mtk_dpi_config_swap_input ( dpi , false ) ;
mtk_dpi_config_channel_swap ( dpi , MTK_DPI_OUT_CHANNEL_SWAP_BGR ) ;
} else if ( ( format = = MTK_DPI_COLOR_FORMAT_YCBCR_422 ) | |
( format = = MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL ) ) {
mtk_dpi_config_yuv422_enable ( dpi , true ) ;
mtk_dpi_config_csc_enable ( dpi , true ) ;
mtk_dpi_config_swap_input ( dpi , true ) ;
mtk_dpi_config_channel_swap ( dpi , MTK_DPI_OUT_CHANNEL_SWAP_RGB ) ;
} else {
mtk_dpi_config_yuv422_enable ( dpi , false ) ;
mtk_dpi_config_csc_enable ( dpi , false ) ;
mtk_dpi_config_swap_input ( dpi , false ) ;
mtk_dpi_config_channel_swap ( dpi , MTK_DPI_OUT_CHANNEL_SWAP_RGB ) ;
}
}
2018-10-03 11:41:41 +08:00
static void mtk_dpi_power_off ( struct mtk_dpi * dpi )
2016-01-04 18:36:36 +01:00
{
2018-10-03 11:41:41 +08:00
if ( WARN_ON ( dpi - > refcount = = 0 ) )
2016-01-04 18:36:36 +01:00
return ;
2018-10-03 11:41:41 +08:00
if ( - - dpi - > refcount ! = 0 )
2016-01-04 18:36:36 +01:00
return ;
2020-04-15 09:13:19 +08:00
if ( dpi - > pinctrl & & dpi - > pins_gpio )
pinctrl_select_state ( dpi - > pinctrl , dpi - > pins_gpio ) ;
2016-01-04 18:36:36 +01:00
mtk_dpi_disable ( dpi ) ;
clk_disable_unprepare ( dpi - > pixel_clk ) ;
clk_disable_unprepare ( dpi - > engine_clk ) ;
}
2018-10-03 11:41:41 +08:00
static int mtk_dpi_power_on ( struct mtk_dpi * dpi )
2016-01-04 18:36:36 +01:00
{
int ret ;
2018-10-03 11:41:41 +08:00
if ( + + dpi - > refcount ! = 1 )
2016-01-04 18:36:36 +01:00
return 0 ;
ret = clk_prepare_enable ( dpi - > engine_clk ) ;
if ( ret ) {
dev_err ( dpi - > dev , " Failed to enable engine clock: %d \n " , ret ) ;
2018-10-03 11:41:41 +08:00
goto err_refcount ;
2016-01-04 18:36:36 +01:00
}
ret = clk_prepare_enable ( dpi - > pixel_clk ) ;
if ( ret ) {
dev_err ( dpi - > dev , " Failed to enable pixel clock: %d \n " , ret ) ;
goto err_pixel ;
}
2020-04-15 09:13:19 +08:00
if ( dpi - > pinctrl & & dpi - > pins_dpi )
pinctrl_select_state ( dpi - > pinctrl , dpi - > pins_dpi ) ;
2016-01-04 18:36:36 +01:00
mtk_dpi_enable ( dpi ) ;
return 0 ;
err_pixel :
clk_disable_unprepare ( dpi - > engine_clk ) ;
2018-10-03 11:41:41 +08:00
err_refcount :
dpi - > refcount - - ;
2016-01-04 18:36:36 +01:00
return ret ;
}
static int mtk_dpi_set_display_mode ( struct mtk_dpi * dpi ,
struct drm_display_mode * mode )
{
struct mtk_dpi_yc_limit limit ;
struct mtk_dpi_polarities dpi_pol ;
struct mtk_dpi_sync_param hsync ;
struct mtk_dpi_sync_param vsync_lodd = { 0 } ;
struct mtk_dpi_sync_param vsync_leven = { 0 } ;
struct mtk_dpi_sync_param vsync_rodd = { 0 } ;
struct mtk_dpi_sync_param vsync_reven = { 0 } ;
2018-03-31 20:17:58 +05:30
struct videomode vm = { 0 } ;
2016-01-04 18:36:36 +01:00
unsigned long pll_rate ;
unsigned int factor ;
2016-09-29 11:02:15 +08:00
/* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */
2018-10-03 11:41:44 +08:00
factor = dpi - > conf - > cal_factor ( mode - > clock ) ;
2018-03-31 20:17:58 +05:30
drm_display_mode_to_videomode ( mode , & vm ) ;
pll_rate = vm . pixelclock * factor ;
2016-01-04 18:36:36 +01:00
dev_dbg ( dpi - > dev , " Want PLL %lu Hz, pixel clock %lu Hz \n " ,
2018-03-31 20:17:58 +05:30
pll_rate , vm . pixelclock ) ;
2016-01-04 18:36:36 +01:00
clk_set_rate ( dpi - > tvd_clk , pll_rate ) ;
pll_rate = clk_get_rate ( dpi - > tvd_clk ) ;
2018-03-31 20:17:58 +05:30
vm . pixelclock = pll_rate / factor ;
clk_set_rate ( dpi - > pixel_clk , vm . pixelclock ) ;
vm . pixelclock = clk_get_rate ( dpi - > pixel_clk ) ;
2016-01-04 18:36:36 +01:00
dev_dbg ( dpi - > dev , " Got PLL %lu Hz, pixel clock %lu Hz \n " ,
2018-03-31 20:17:58 +05:30
pll_rate , vm . pixelclock ) ;
2016-01-04 18:36:36 +01:00
limit . c_bottom = 0x0010 ;
limit . c_top = 0x0FE0 ;
limit . y_bottom = 0x0010 ;
limit . y_top = 0x0FE0 ;
dpi_pol . ck_pol = MTK_DPI_POLARITY_FALLING ;
dpi_pol . de_pol = MTK_DPI_POLARITY_RISING ;
2018-03-31 20:17:58 +05:30
dpi_pol . hsync_pol = vm . flags & DISPLAY_FLAGS_HSYNC_HIGH ?
2016-01-04 18:36:36 +01:00
MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING ;
2018-03-31 20:17:58 +05:30
dpi_pol . vsync_pol = vm . flags & DISPLAY_FLAGS_VSYNC_HIGH ?
2016-01-04 18:36:36 +01:00
MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING ;
2018-03-31 20:17:58 +05:30
hsync . sync_width = vm . hsync_len ;
hsync . back_porch = vm . hback_porch ;
hsync . front_porch = vm . hfront_porch ;
2016-01-04 18:36:36 +01:00
hsync . shift_half_line = false ;
2018-03-31 20:17:58 +05:30
vsync_lodd . sync_width = vm . vsync_len ;
vsync_lodd . back_porch = vm . vback_porch ;
vsync_lodd . front_porch = vm . vfront_porch ;
2016-01-04 18:36:36 +01:00
vsync_lodd . shift_half_line = false ;
2018-03-31 20:17:58 +05:30
if ( vm . flags & DISPLAY_FLAGS_INTERLACED & &
2016-01-04 18:36:36 +01:00
mode - > flags & DRM_MODE_FLAG_3D_MASK ) {
vsync_leven = vsync_lodd ;
vsync_rodd = vsync_lodd ;
vsync_reven = vsync_lodd ;
vsync_leven . shift_half_line = true ;
vsync_reven . shift_half_line = true ;
2018-03-31 20:17:58 +05:30
} else if ( vm . flags & DISPLAY_FLAGS_INTERLACED & &
2016-01-04 18:36:36 +01:00
! ( mode - > flags & DRM_MODE_FLAG_3D_MASK ) ) {
vsync_leven = vsync_lodd ;
vsync_leven . shift_half_line = true ;
2018-03-31 20:17:58 +05:30
} else if ( ! ( vm . flags & DISPLAY_FLAGS_INTERLACED ) & &
2016-01-04 18:36:36 +01:00
mode - > flags & DRM_MODE_FLAG_3D_MASK ) {
vsync_rodd = vsync_lodd ;
}
mtk_dpi_sw_reset ( dpi , true ) ;
mtk_dpi_config_pol ( dpi , & dpi_pol ) ;
mtk_dpi_config_hsync ( dpi , & hsync ) ;
mtk_dpi_config_vsync_lodd ( dpi , & vsync_lodd ) ;
mtk_dpi_config_vsync_rodd ( dpi , & vsync_rodd ) ;
mtk_dpi_config_vsync_leven ( dpi , & vsync_leven ) ;
mtk_dpi_config_vsync_reven ( dpi , & vsync_reven ) ;
mtk_dpi_config_3d ( dpi , ! ! ( mode - > flags & DRM_MODE_FLAG_3D_MASK ) ) ;
2018-03-31 20:17:58 +05:30
mtk_dpi_config_interface ( dpi , ! ! ( vm . flags &
DISPLAY_FLAGS_INTERLACED ) ) ;
if ( vm . flags & DISPLAY_FLAGS_INTERLACED )
mtk_dpi_config_fb_size ( dpi , vm . hactive , vm . vactive > > 1 ) ;
2016-01-04 18:36:36 +01:00
else
2018-03-31 20:17:58 +05:30
mtk_dpi_config_fb_size ( dpi , vm . hactive , vm . vactive ) ;
2016-01-04 18:36:36 +01:00
mtk_dpi_config_channel_limit ( dpi , & limit ) ;
mtk_dpi_config_bit_num ( dpi , dpi - > bit_num ) ;
mtk_dpi_config_channel_swap ( dpi , dpi - > channel_swap ) ;
mtk_dpi_config_yc_map ( dpi , dpi - > yc_map ) ;
mtk_dpi_config_color_format ( dpi , dpi - > color_format ) ;
mtk_dpi_config_2n_h_fre ( dpi ) ;
2018-10-03 11:41:43 +08:00
mtk_dpi_config_disable_edge ( dpi ) ;
2016-01-04 18:36:36 +01:00
mtk_dpi_sw_reset ( dpi , false ) ;
return 0 ;
}
static bool mtk_dpi_encoder_mode_fixup ( struct drm_encoder * encoder ,
const struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
return true ;
}
static void mtk_dpi_encoder_mode_set ( struct drm_encoder * encoder ,
struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
struct mtk_dpi * dpi = mtk_dpi_from_encoder ( encoder ) ;
drm_mode_copy ( & dpi - > mode , adjusted_mode ) ;
}
static void mtk_dpi_encoder_disable ( struct drm_encoder * encoder )
{
struct mtk_dpi * dpi = mtk_dpi_from_encoder ( encoder ) ;
2018-10-03 11:41:41 +08:00
mtk_dpi_power_off ( dpi ) ;
2016-01-04 18:36:36 +01:00
}
static void mtk_dpi_encoder_enable ( struct drm_encoder * encoder )
{
struct mtk_dpi * dpi = mtk_dpi_from_encoder ( encoder ) ;
2018-10-03 11:41:41 +08:00
mtk_dpi_power_on ( dpi ) ;
2016-01-04 18:36:36 +01:00
mtk_dpi_set_display_mode ( dpi , & dpi - > mode ) ;
}
static int mtk_dpi_atomic_check ( struct drm_encoder * encoder ,
struct drm_crtc_state * crtc_state ,
struct drm_connector_state * conn_state )
{
return 0 ;
}
static const struct drm_encoder_helper_funcs mtk_dpi_encoder_helper_funcs = {
. mode_fixup = mtk_dpi_encoder_mode_fixup ,
. mode_set = mtk_dpi_encoder_mode_set ,
. disable = mtk_dpi_encoder_disable ,
. enable = mtk_dpi_encoder_enable ,
. atomic_check = mtk_dpi_atomic_check ,
} ;
static void mtk_dpi_start ( struct mtk_ddp_comp * comp )
{
struct mtk_dpi * dpi = container_of ( comp , struct mtk_dpi , ddp_comp ) ;
2018-10-03 11:41:41 +08:00
mtk_dpi_power_on ( dpi ) ;
2016-01-04 18:36:36 +01:00
}
static void mtk_dpi_stop ( struct mtk_ddp_comp * comp )
{
struct mtk_dpi * dpi = container_of ( comp , struct mtk_dpi , ddp_comp ) ;
2018-10-03 11:41:41 +08:00
mtk_dpi_power_off ( dpi ) ;
2016-01-04 18:36:36 +01:00
}
static const struct mtk_ddp_comp_funcs mtk_dpi_funcs = {
. start = mtk_dpi_start ,
. stop = mtk_dpi_stop ,
} ;
static int mtk_dpi_bind ( struct device * dev , struct device * master , void * data )
{
struct mtk_dpi * dpi = dev_get_drvdata ( dev ) ;
struct drm_device * drm_dev = data ;
int ret ;
ret = mtk_ddp_comp_register ( drm_dev , & dpi - > ddp_comp ) ;
if ( ret < 0 ) {
2017-07-18 16:43:04 -05:00
dev_err ( dev , " Failed to register component %pOF: %d \n " ,
dev - > of_node , ret ) ;
2016-01-04 18:36:36 +01:00
return ret ;
}
2020-03-05 16:59:38 +01:00
ret = drm_simple_encoder_init ( drm_dev , & dpi - > encoder ,
DRM_MODE_ENCODER_TMDS ) ;
2016-01-04 18:36:36 +01:00
if ( ret ) {
dev_err ( dev , " Failed to initialize decoder: %d \n " , ret ) ;
goto err_unregister ;
}
drm_encoder_helper_add ( & dpi - > encoder , & mtk_dpi_encoder_helper_funcs ) ;
2020-08-19 10:17:49 +02:00
dpi - > encoder . possible_crtcs = mtk_drm_find_possible_crtc_by_comp ( drm_dev , dpi - > ddp_comp ) ;
2016-01-04 18:36:36 +01:00
2020-08-26 10:53:16 +02:00
ret = drm_bridge_attach ( & dpi - > encoder , dpi - > next_bridge , NULL , 0 ) ;
2016-01-04 18:36:36 +01:00
if ( ret ) {
dev_err ( dev , " Failed to attach bridge: %d \n " , ret ) ;
goto err_cleanup ;
}
dpi - > bit_num = MTK_DPI_OUT_BIT_NUM_8BITS ;
dpi - > channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB ;
dpi - > yc_map = MTK_DPI_OUT_YC_MAP_RGB ;
dpi - > color_format = MTK_DPI_COLOR_FORMAT_RGB ;
return 0 ;
err_cleanup :
drm_encoder_cleanup ( & dpi - > encoder ) ;
err_unregister :
mtk_ddp_comp_unregister ( drm_dev , & dpi - > ddp_comp ) ;
return ret ;
}
static void mtk_dpi_unbind ( struct device * dev , struct device * master ,
void * data )
{
struct mtk_dpi * dpi = dev_get_drvdata ( dev ) ;
struct drm_device * drm_dev = data ;
drm_encoder_cleanup ( & dpi - > encoder ) ;
mtk_ddp_comp_unregister ( drm_dev , & dpi - > ddp_comp ) ;
}
static const struct component_ops mtk_dpi_component_ops = {
. bind = mtk_dpi_bind ,
. unbind = mtk_dpi_unbind ,
} ;
2018-10-03 11:41:44 +08:00
static unsigned int mt8173_calculate_factor ( int clock )
{
if ( clock < = 27000 )
return 3 < < 4 ;
else if ( clock < = 84000 )
return 3 < < 3 ;
else if ( clock < = 167000 )
return 3 < < 2 ;
else
return 3 < < 1 ;
}
2018-10-03 11:41:46 +08:00
static unsigned int mt2701_calculate_factor ( int clock )
{
if ( clock < = 64000 )
return 4 ;
2019-04-09 14:53:05 +08:00
else if ( clock < = 128000 )
2018-10-03 11:41:46 +08:00
return 2 ;
2019-04-09 14:53:05 +08:00
else
return 1 ;
2018-10-03 11:41:46 +08:00
}
2020-02-25 17:40:56 +08:00
static unsigned int mt8183_calculate_factor ( int clock )
{
if ( clock < = 27000 )
return 8 ;
else if ( clock < = 167000 )
return 4 ;
else
return 2 ;
}
2018-10-03 11:41:42 +08:00
static const struct mtk_dpi_conf mt8173_conf = {
2018-10-03 11:41:44 +08:00
. cal_factor = mt8173_calculate_factor ,
2018-10-03 11:41:42 +08:00
. reg_h_fre_con = 0xe0 ,
} ;
2018-10-03 11:41:46 +08:00
static const struct mtk_dpi_conf mt2701_conf = {
. cal_factor = mt2701_calculate_factor ,
. reg_h_fre_con = 0xb0 ,
. edge_sel_en = true ,
} ;
2020-02-25 17:40:56 +08:00
static const struct mtk_dpi_conf mt8183_conf = {
. cal_factor = mt8183_calculate_factor ,
. reg_h_fre_con = 0xe0 ,
} ;
2016-01-04 18:36:36 +01:00
static int mtk_dpi_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct mtk_dpi * dpi ;
struct resource * mem ;
int comp_id ;
int ret ;
dpi = devm_kzalloc ( dev , sizeof ( * dpi ) , GFP_KERNEL ) ;
if ( ! dpi )
return - ENOMEM ;
dpi - > dev = dev ;
2018-10-03 11:41:42 +08:00
dpi - > conf = ( struct mtk_dpi_conf * ) of_device_get_match_data ( dev ) ;
2016-01-04 18:36:36 +01:00
2020-04-15 09:13:19 +08:00
dpi - > pinctrl = devm_pinctrl_get ( & pdev - > dev ) ;
if ( IS_ERR ( dpi - > pinctrl ) ) {
dpi - > pinctrl = NULL ;
dev_dbg ( & pdev - > dev , " Cannot find pinctrl! \n " ) ;
}
if ( dpi - > pinctrl ) {
dpi - > pins_gpio = pinctrl_lookup_state ( dpi - > pinctrl , " sleep " ) ;
if ( IS_ERR ( dpi - > pins_gpio ) ) {
dpi - > pins_gpio = NULL ;
dev_dbg ( & pdev - > dev , " Cannot find pinctrl idle! \n " ) ;
}
if ( dpi - > pins_gpio )
pinctrl_select_state ( dpi - > pinctrl , dpi - > pins_gpio ) ;
dpi - > pins_dpi = pinctrl_lookup_state ( dpi - > pinctrl , " default " ) ;
if ( IS_ERR ( dpi - > pins_dpi ) ) {
dpi - > pins_dpi = NULL ;
dev_dbg ( & pdev - > dev , " Cannot find pinctrl active! \n " ) ;
}
}
2016-01-04 18:36:36 +01:00
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
dpi - > regs = devm_ioremap_resource ( dev , mem ) ;
if ( IS_ERR ( dpi - > regs ) ) {
ret = PTR_ERR ( dpi - > regs ) ;
dev_err ( dev , " Failed to ioremap mem resource: %d \n " , ret ) ;
return ret ;
}
dpi - > engine_clk = devm_clk_get ( dev , " engine " ) ;
if ( IS_ERR ( dpi - > engine_clk ) ) {
ret = PTR_ERR ( dpi - > engine_clk ) ;
2020-03-25 18:31:19 +01:00
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " Failed to get engine clock: %d \n " , ret ) ;
2016-01-04 18:36:36 +01:00
return ret ;
}
dpi - > pixel_clk = devm_clk_get ( dev , " pixel " ) ;
if ( IS_ERR ( dpi - > pixel_clk ) ) {
ret = PTR_ERR ( dpi - > pixel_clk ) ;
2020-03-25 18:31:19 +01:00
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " Failed to get pixel clock: %d \n " , ret ) ;
2016-01-04 18:36:36 +01:00
return ret ;
}
dpi - > tvd_clk = devm_clk_get ( dev , " pll " ) ;
if ( IS_ERR ( dpi - > tvd_clk ) ) {
ret = PTR_ERR ( dpi - > tvd_clk ) ;
2020-03-25 18:31:19 +01:00
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " Failed to get tvdpll clock: %d \n " , ret ) ;
2016-01-04 18:36:36 +01:00
return ret ;
}
dpi - > irq = platform_get_irq ( pdev , 0 ) ;
if ( dpi - > irq < = 0 ) {
dev_err ( dev , " Failed to get irq: %d \n " , dpi - > irq ) ;
return - EINVAL ;
}
2018-10-03 11:41:45 +08:00
ret = drm_of_find_panel_or_bridge ( dev - > of_node , 0 , 0 ,
2020-08-26 10:53:16 +02:00
NULL , & dpi - > next_bridge ) ;
2018-10-03 11:41:45 +08:00
if ( ret )
return ret ;
2016-01-04 18:36:36 +01:00
2020-08-26 10:53:16 +02:00
dev_info ( dev , " Found bridge node: %pOF \n " , dpi - > next_bridge - > of_node ) ;
2016-01-04 18:36:36 +01:00
comp_id = mtk_ddp_comp_get_id ( dev - > of_node , MTK_DPI ) ;
if ( comp_id < 0 ) {
dev_err ( dev , " Failed to identify by alias: %d \n " , comp_id ) ;
return comp_id ;
}
ret = mtk_ddp_comp_init ( dev , dev - > of_node , & dpi - > ddp_comp , comp_id ,
& mtk_dpi_funcs ) ;
if ( ret ) {
dev_err ( dev , " Failed to initialize component: %d \n " , ret ) ;
return ret ;
}
platform_set_drvdata ( pdev , dpi ) ;
ret = component_add ( dev , & mtk_dpi_component_ops ) ;
if ( ret ) {
dev_err ( dev , " Failed to add component: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
static int mtk_dpi_remove ( struct platform_device * pdev )
{
component_del ( & pdev - > dev , & mtk_dpi_component_ops ) ;
return 0 ;
}
static const struct of_device_id mtk_dpi_of_ids [ ] = {
2018-10-03 11:41:46 +08:00
{ . compatible = " mediatek,mt2701-dpi " ,
. data = & mt2701_conf ,
} ,
2018-10-03 11:41:42 +08:00
{ . compatible = " mediatek,mt8173-dpi " ,
. data = & mt8173_conf ,
} ,
2020-02-25 17:40:56 +08:00
{ . compatible = " mediatek,mt8183-dpi " ,
. data = & mt8183_conf ,
} ,
2018-10-03 11:41:42 +08:00
{ } ,
2016-01-04 18:36:36 +01:00
} ;
struct platform_driver mtk_dpi_driver = {
. probe = mtk_dpi_probe ,
. remove = mtk_dpi_remove ,
. driver = {
. name = " mediatek-dpi " ,
. of_match_table = mtk_dpi_of_ids ,
} ,
} ;