2017-12-06 12:29:47 +01:00
// SPDX-License-Identifier: GPL-2.0
2014-07-31 09:39:11 +02:00
/*
* Copyright ( C ) STMicroelectronics SA 2014
* Authors : Benjamin Gaignard < benjamin . gaignard @ st . com >
* Fabien Dessenne < fabien . dessenne @ st . com >
* for STMicroelectronics .
*/
# include <linux/clk.h>
# include <drm/drmP.h>
2015-03-19 13:35:16 +01:00
# include <drm/drm_atomic.h>
# include <drm/drm_atomic_helper.h>
2014-10-29 10:03:57 +01:00
# include <drm/drm_plane_helper.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2014-07-31 09:39:11 +02:00
# include "sti_compositor.h"
2015-07-31 11:32:34 +02:00
# include "sti_crtc.h"
# include "sti_drv.h"
2015-08-03 14:22:16 +02:00
# include "sti_vid.h"
2014-07-31 09:39:11 +02:00
# include "sti_vtg.h"
2017-06-30 12:36:44 +03:00
static void sti_crtc_atomic_enable ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_state )
2014-07-31 09:39:11 +02:00
{
struct sti_mixer * mixer = to_sti_mixer ( crtc ) ;
2015-08-03 14:22:16 +02:00
DRM_DEBUG_DRIVER ( " \n " ) ;
mixer - > status = STI_MIXER_READY ;
2014-07-31 09:39:11 +02:00
2015-08-03 14:22:16 +02:00
drm_crtc_vblank_on ( crtc ) ;
2014-07-31 09:39:11 +02:00
}
2017-06-30 12:36:45 +03:00
static void sti_crtc_atomic_disable ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_state )
2014-07-31 09:39:11 +02:00
{
struct sti_mixer * mixer = to_sti_mixer ( crtc ) ;
2015-08-03 14:22:16 +02:00
DRM_DEBUG_DRIVER ( " \n " ) ;
2014-12-04 11:27:45 +01:00
2015-08-03 14:22:16 +02:00
mixer - > status = STI_MIXER_DISABLING ;
2018-10-12 11:46:38 +02:00
drm_crtc_wait_one_vblank ( crtc ) ;
2014-07-31 09:39:11 +02:00
}
static int
2015-07-31 11:32:34 +02:00
sti_crtc_mode_set ( struct drm_crtc * crtc , struct drm_display_mode * mode )
2014-07-31 09:39:11 +02:00
{
struct sti_mixer * mixer = to_sti_mixer ( crtc ) ;
struct device * dev = mixer - > dev ;
struct sti_compositor * compo = dev_get_drvdata ( dev ) ;
2016-05-26 10:39:20 +02:00
struct clk * compo_clk , * pix_clk ;
2014-07-31 09:39:11 +02:00
int rate = mode - > clock * 1000 ;
2018-12-20 10:27:30 -02:00
DRM_DEBUG_KMS ( " CRTC:%d (%s) mode: (%s) \n " ,
crtc - > base . id , sti_mixer_to_str ( mixer ) , mode - > name ) ;
DRM_DEBUG_KMS ( DRM_MODE_FMT " \n " , DRM_MODE_ARG ( mode ) ) ;
2014-07-31 09:39:11 +02:00
2016-05-26 10:39:20 +02:00
if ( mixer - > id = = STI_MIXER_MAIN ) {
compo_clk = compo - > clk_compo_main ;
pix_clk = compo - > clk_pix_main ;
} else {
compo_clk = compo - > clk_compo_aux ;
pix_clk = compo - > clk_pix_aux ;
}
/* Prepare and enable the compo IP clock */
if ( clk_prepare_enable ( compo_clk ) ) {
DRM_INFO ( " Failed to prepare/enable compositor clk \n " ) ;
goto compo_error ;
}
2014-07-31 09:39:11 +02:00
2016-05-26 10:39:20 +02:00
/* Set rate and prepare/enable pixel clock */
if ( clk_set_rate ( pix_clk , rate ) < 0 ) {
2014-07-31 09:39:11 +02:00
DRM_ERROR ( " Cannot set rate (%dHz) for pix clk \n " , rate ) ;
2016-05-26 10:39:20 +02:00
goto pix_error ;
2014-07-31 09:39:11 +02:00
}
2016-05-26 10:39:20 +02:00
if ( clk_prepare_enable ( pix_clk ) ) {
2014-07-31 09:39:11 +02:00
DRM_ERROR ( " Failed to prepare/enable pix clk \n " ) ;
2016-05-26 10:39:20 +02:00
goto pix_error ;
2014-07-31 09:39:11 +02:00
}
2016-09-06 09:42:25 +02:00
sti_vtg_set_config ( compo - > vtg [ mixer - > id ] , & crtc - > mode ) ;
2014-07-31 09:39:11 +02:00
2016-05-26 10:39:20 +02:00
if ( sti_mixer_active_video_area ( mixer , & crtc - > mode ) ) {
2015-07-31 11:32:13 +02:00
DRM_ERROR ( " Can't set active video area \n " ) ;
2016-05-26 10:39:20 +02:00
goto mixer_error ;
2014-07-31 09:39:11 +02:00
}
2016-05-26 10:39:20 +02:00
return 0 ;
mixer_error :
clk_disable_unprepare ( pix_clk ) ;
pix_error :
clk_disable_unprepare ( compo_clk ) ;
compo_error :
return - EINVAL ;
2014-07-31 09:39:11 +02:00
}
2015-07-31 11:32:34 +02:00
static void sti_crtc_disable ( struct drm_crtc * crtc )
2014-07-31 09:39:11 +02:00
{
struct sti_mixer * mixer = to_sti_mixer ( crtc ) ;
struct device * dev = mixer - > dev ;
struct sti_compositor * compo = dev_get_drvdata ( dev ) ;
DRM_DEBUG_KMS ( " CRTC:%d (%s) \n " , crtc - > base . id , sti_mixer_to_str ( mixer ) ) ;
/* Disable Background */
sti_mixer_set_background_status ( mixer , false ) ;
2014-12-04 11:27:45 +01:00
drm_crtc_vblank_off ( crtc ) ;
2014-07-31 09:39:11 +02:00
/* Disable pixel clock and compo IP clocks */
if ( mixer - > id = = STI_MIXER_MAIN ) {
clk_disable_unprepare ( compo - > clk_pix_main ) ;
clk_disable_unprepare ( compo - > clk_compo_main ) ;
} else {
clk_disable_unprepare ( compo - > clk_pix_aux ) ;
clk_disable_unprepare ( compo - > clk_compo_aux ) ;
}
2015-08-03 14:22:16 +02:00
mixer - > status = STI_MIXER_DISABLED ;
2014-07-31 09:39:11 +02:00
}
2015-03-19 13:35:16 +01:00
static void
2015-07-31 11:32:34 +02:00
sti_crtc_mode_set_nofb ( struct drm_crtc * crtc )
2015-03-19 13:35:16 +01:00
{
2015-07-31 11:32:34 +02:00
sti_crtc_mode_set ( crtc , & crtc - > state - > adjusted_mode ) ;
2015-03-19 13:35:16 +01:00
}
2014-07-31 09:39:11 +02:00
2015-08-14 10:14:23 +10:00
static void sti_crtc_atomic_flush ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_crtc_state )
2015-03-19 13:35:16 +01:00
{
2015-08-03 14:22:16 +02:00
struct drm_device * drm_dev = crtc - > dev ;
struct sti_mixer * mixer = to_sti_mixer ( crtc ) ;
struct sti_compositor * compo = dev_get_drvdata ( mixer - > dev ) ;
struct drm_plane * p ;
2017-01-12 17:27:36 +01:00
struct drm_pending_vblank_event * event ;
unsigned long flags ;
2015-08-03 14:22:16 +02:00
DRM_DEBUG_DRIVER ( " \n " ) ;
/* perform plane actions */
list_for_each_entry ( p , & drm_dev - > mode_config . plane_list , head ) {
struct sti_plane * plane = to_sti_plane ( p ) ;
switch ( plane - > status ) {
case STI_PLANE_UPDATED :
2016-09-06 09:42:39 +02:00
/* ignore update for other CRTC */
if ( p - > state - > crtc ! = crtc )
continue ;
2015-08-03 14:22:16 +02:00
/* update planes tag as updated */
DRM_DEBUG_DRIVER ( " update plane %s \n " ,
sti_plane_to_str ( plane ) ) ;
if ( sti_mixer_set_plane_depth ( mixer , plane ) ) {
DRM_ERROR ( " Cannot set plane %s depth \n " ,
sti_plane_to_str ( plane ) ) ;
break ;
}
if ( sti_mixer_set_plane_status ( mixer , plane , true ) ) {
DRM_ERROR ( " Cannot enable plane %s at mixer \n " ,
sti_plane_to_str ( plane ) ) ;
break ;
}
/* if plane is HQVDP_0 then commit the vid[0] */
if ( plane - > desc = = STI_HQVDP_0 )
sti_vid_commit ( compo - > vid [ 0 ] , p - > state ) ;
plane - > status = STI_PLANE_READY ;
break ;
case STI_PLANE_DISABLING :
/* disabling sequence for planes tag as disabling */
DRM_DEBUG_DRIVER ( " disable plane %s from mixer \n " ,
sti_plane_to_str ( plane ) ) ;
if ( sti_mixer_set_plane_status ( mixer , plane , false ) ) {
DRM_ERROR ( " Cannot disable plane %s at mixer \n " ,
sti_plane_to_str ( plane ) ) ;
continue ;
}
if ( plane - > desc = = STI_CURSOR )
/* tag plane status for disabled */
plane - > status = STI_PLANE_DISABLED ;
else
/* tag plane status for flushing */
plane - > status = STI_PLANE_FLUSHING ;
/* if plane is HQVDP_0 then disable the vid[0] */
if ( plane - > desc = = STI_HQVDP_0 )
sti_vid_disable ( compo - > vid [ 0 ] ) ;
break ;
default :
/* Other status case are not handled */
break ;
}
}
2017-01-12 17:27:36 +01:00
event = crtc - > state - > event ;
if ( event ) {
crtc - > state - > event = NULL ;
spin_lock_irqsave ( & crtc - > dev - > event_lock , flags ) ;
if ( drm_crtc_vblank_get ( crtc ) = = 0 )
drm_crtc_arm_vblank_event ( crtc , event ) ;
else
drm_crtc_send_vblank_event ( crtc , event ) ;
spin_unlock_irqrestore ( & crtc - > dev - > event_lock , flags ) ;
}
2014-07-31 09:39:11 +02:00
}
2015-09-02 13:44:15 +03:00
static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
2015-07-31 11:32:34 +02:00
. mode_set_nofb = sti_crtc_mode_set_nofb ,
. atomic_flush = sti_crtc_atomic_flush ,
2017-06-30 12:36:44 +03:00
. atomic_enable = sti_crtc_atomic_enable ,
2017-06-30 12:36:45 +03:00
. atomic_disable = sti_crtc_atomic_disable ,
2015-03-19 13:35:16 +01:00
} ;
2015-07-31 11:32:34 +02:00
static void sti_crtc_destroy ( struct drm_crtc * crtc )
2014-07-31 09:39:11 +02:00
{
DRM_DEBUG_KMS ( " \n " ) ;
drm_crtc_cleanup ( crtc ) ;
}
2015-07-31 11:32:34 +02:00
static int sti_crtc_set_property ( struct drm_crtc * crtc ,
struct drm_property * property ,
uint64_t val )
2014-07-31 09:39:11 +02:00
{
DRM_DEBUG_KMS ( " \n " ) ;
return 0 ;
}
2015-07-31 11:32:34 +02:00
int sti_crtc_vblank_cb ( struct notifier_block * nb ,
unsigned long event , void * data )
2014-07-31 09:39:11 +02:00
{
2016-09-06 09:42:13 +02:00
struct sti_compositor * compo ;
2015-09-24 18:35:38 +02:00
struct drm_crtc * crtc = data ;
struct sti_mixer * mixer ;
unsigned int pipe ;
2014-07-31 09:39:11 +02:00
2015-09-24 18:35:38 +02:00
pipe = drm_crtc_index ( crtc ) ;
2016-09-06 09:42:13 +02:00
compo = container_of ( nb , struct sti_compositor , vtg_vblank_nb [ pipe ] ) ;
2015-09-24 18:35:38 +02:00
mixer = compo - > mixer [ pipe ] ;
2014-07-31 09:39:11 +02:00
if ( ( event ! = VTG_TOP_FIELD_EVENT ) & &
( event ! = VTG_BOTTOM_FIELD_EVENT ) ) {
DRM_ERROR ( " unknown event: %lu \n " , event ) ;
return - EINVAL ;
}
2015-09-24 18:35:38 +02:00
drm_crtc_handle_vblank ( crtc ) ;
2014-07-31 09:39:11 +02:00
2015-09-24 18:35:38 +02:00
if ( mixer - > status = = STI_MIXER_DISABLING ) {
2015-08-03 14:22:16 +02:00
struct drm_plane * p ;
/* Disable mixer only if all overlay planes (GDP and VDP)
* are disabled */
2015-09-24 18:35:38 +02:00
list_for_each_entry ( p , & crtc - > dev - > mode_config . plane_list ,
head ) {
2015-08-03 14:22:16 +02:00
struct sti_plane * plane = to_sti_plane ( p ) ;
if ( ( plane - > desc & STI_PLANE_TYPE_MASK ) < = STI_VDP )
if ( plane - > status ! = STI_PLANE_DISABLED )
return 0 ;
}
2015-09-24 18:35:38 +02:00
sti_crtc_disable ( crtc ) ;
2015-08-03 14:22:16 +02:00
}
2014-07-31 09:39:11 +02:00
return 0 ;
}
2015-09-24 18:35:31 +02:00
int sti_crtc_enable_vblank ( struct drm_device * dev , unsigned int pipe )
2014-07-31 09:39:11 +02:00
{
2015-07-31 11:32:34 +02:00
struct sti_private * dev_priv = dev - > dev_private ;
2014-07-31 09:39:11 +02:00
struct sti_compositor * compo = dev_priv - > compo ;
2016-09-06 09:42:13 +02:00
struct notifier_block * vtg_vblank_nb = & compo - > vtg_vblank_nb [ pipe ] ;
2015-09-24 18:35:38 +02:00
struct drm_crtc * crtc = & compo - > mixer [ pipe ] - > drm_crtc ;
2016-09-06 09:42:25 +02:00
struct sti_vtg * vtg = compo - > vtg [ pipe ] ;
2014-07-31 09:39:11 +02:00
2015-07-31 11:32:13 +02:00
DRM_DEBUG_DRIVER ( " \n " ) ;
2016-09-06 09:42:25 +02:00
if ( sti_vtg_register_client ( vtg , vtg_vblank_nb , crtc ) ) {
2014-07-31 09:39:11 +02:00
DRM_ERROR ( " Cannot register VTG notifier \n " ) ;
return - EINVAL ;
}
return 0 ;
}
2015-09-24 18:35:31 +02:00
void sti_crtc_disable_vblank ( struct drm_device * drm_dev , unsigned int pipe )
2014-07-31 09:39:11 +02:00
{
2015-08-03 14:22:16 +02:00
struct sti_private * priv = drm_dev - > dev_private ;
2014-07-31 09:39:11 +02:00
struct sti_compositor * compo = priv - > compo ;
2016-09-06 09:42:13 +02:00
struct notifier_block * vtg_vblank_nb = & compo - > vtg_vblank_nb [ pipe ] ;
2016-09-06 09:42:25 +02:00
struct sti_vtg * vtg = compo - > vtg [ pipe ] ;
2014-07-31 09:39:11 +02:00
DRM_DEBUG_DRIVER ( " \n " ) ;
2016-09-06 09:42:25 +02:00
if ( sti_vtg_unregister_client ( vtg , vtg_vblank_nb ) )
2014-07-31 09:39:11 +02:00
DRM_DEBUG_DRIVER ( " Warning: cannot unregister VTG notifier \n " ) ;
}
2016-06-21 15:09:39 +02:00
static int sti_crtc_late_register ( struct drm_crtc * crtc )
{
struct sti_mixer * mixer = to_sti_mixer ( crtc ) ;
struct sti_compositor * compo = dev_get_drvdata ( mixer - > dev ) ;
if ( drm_crtc_index ( crtc ) = = 0 )
2016-09-15 17:11:07 +02:00
return sti_compositor_debugfs_init ( compo , crtc - > dev - > primary ) ;
2016-06-21 15:09:39 +02:00
return 0 ;
}
2015-09-02 13:44:15 +03:00
static const struct drm_crtc_funcs sti_crtc_funcs = {
2015-03-19 13:35:16 +01:00
. set_config = drm_atomic_helper_set_config ,
. page_flip = drm_atomic_helper_page_flip ,
2015-07-31 11:32:34 +02:00
. destroy = sti_crtc_destroy ,
. set_property = sti_crtc_set_property ,
2015-03-19 13:35:16 +01:00
. reset = drm_atomic_helper_crtc_reset ,
. atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_crtc_destroy_state ,
2016-06-21 15:09:39 +02:00
. late_register = sti_crtc_late_register ,
2014-07-31 09:39:11 +02:00
} ;
2015-07-31 11:32:34 +02:00
bool sti_crtc_is_main ( struct drm_crtc * crtc )
2014-07-31 09:39:11 +02:00
{
struct sti_mixer * mixer = to_sti_mixer ( crtc ) ;
if ( mixer - > id = = STI_MIXER_MAIN )
return true ;
return false ;
}
2015-07-31 11:32:34 +02:00
int sti_crtc_init ( struct drm_device * drm_dev , struct sti_mixer * mixer ,
struct drm_plane * primary , struct drm_plane * cursor )
2014-07-31 09:39:11 +02:00
{
struct drm_crtc * crtc = & mixer - > drm_crtc ;
int res ;
res = drm_crtc_init_with_planes ( drm_dev , crtc , primary , cursor ,
drm: Pass 'name' to drm_crtc_init_with_planes()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
I didn't convert drm_crtc_init() since passing the varargs through
would mean either cpp macros or va_list, and I figured we don't
care about these legacy functions enough to warrant the extra pain.
@@
identifier dev, crtc, primary, cursor, funcs;
@@
int drm_crtc_init_with_planes(struct drm_device *dev,
struct drm_crtc *crtc,
struct drm_plane *primary, struct drm_plane *cursor,
const struct drm_crtc_funcs *funcs
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, crtc, primary, cursor, funcs;
@@
int drm_crtc_init_with_planes(struct drm_device *dev,
struct drm_crtc *crtc,
struct drm_plane *primary, struct drm_plane *cursor,
const struct drm_crtc_funcs *funcs
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4, E5;
@@
drm_crtc_init_with_planes(E1, E2, E3, E4, E5
+ ,NULL
)
v2: Split crtc and plane changes apart
Pass NULL for no-name instead of ""
Leave drm_crtc_init() alone
v3: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670771-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:19:31 +02:00
& sti_crtc_funcs , NULL ) ;
2014-07-31 09:39:11 +02:00
if ( res ) {
2018-05-02 11:10:48 +01:00
DRM_ERROR ( " Can't initialize CRTC \n " ) ;
2014-07-31 09:39:11 +02:00
return - EINVAL ;
}
drm_crtc_helper_add ( crtc , & sti_crtc_helper_funcs ) ;
DRM_DEBUG_DRIVER ( " drm CRTC:%d mapped to %s \n " ,
crtc - > base . id , sti_mixer_to_str ( mixer ) ) ;
return 0 ;
}