2013-01-08 15:04:28 -06:00
/*
* Copyright ( C ) 2012 Texas Instruments
* Author : Rob Clark < robdclark @ gmail . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License 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 .
*
* You should have received a copy of the GNU General Public License along with
* this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2016-09-21 06:14:53 -07:00
# include <drm/drm_atomic.h>
2016-04-07 15:05:16 +03:00
# include <drm/drm_atomic_helper.h>
2016-09-21 06:14:53 -07:00
# include <drm/drm_crtc.h>
# include <drm/drm_flip_work.h>
# include <drm/drm_plane_helper.h>
2016-09-06 22:55:33 +03:00
# include <linux/workqueue.h>
2016-10-31 15:19:26 +01:00
# include <linux/completion.h>
# include <linux/dma-mapping.h>
2017-03-22 08:26:06 -05:00
# include <linux/of_graph.h>
2017-10-12 12:19:46 +03:00
# include <linux/math64.h>
2013-01-08 15:04:28 -06:00
# include "tilcdc_drv.h"
# include "tilcdc_regs.h"
2016-10-31 15:19:26 +01:00
# define TILCDC_VBLANK_SAFETY_THRESHOLD_US 1000
2016-11-15 23:37:24 +02:00
# define TILCDC_PALETTE_SIZE 32
# define TILCDC_PALETTE_FIRST_ENTRY 0x4000
2015-11-03 12:00:51 +02:00
2013-01-08 15:04:28 -06:00
struct tilcdc_crtc {
struct drm_crtc base ;
2016-04-07 15:04:18 +03:00
struct drm_plane primary ;
2013-01-08 15:04:28 -06:00
const struct tilcdc_panel_info * info ;
struct drm_pending_vblank_event * event ;
2016-10-25 12:27:31 +03:00
struct mutex enable_lock ;
2016-06-22 16:27:54 +03:00
bool enabled ;
2016-10-25 12:27:31 +03:00
bool shutdown ;
2013-01-08 15:04:28 -06:00
wait_queue_head_t frame_done_wq ;
bool frame_done ;
2015-11-03 12:00:51 +02:00
spinlock_t irq_lock ;
2016-09-06 16:19:54 +03:00
unsigned int lcd_fck_rate ;
2015-11-03 12:00:51 +02:00
ktime_t last_vblank ;
2017-10-12 12:19:46 +03:00
unsigned int hvtotal_us ;
2013-01-08 15:04:28 -06:00
2015-11-03 12:00:51 +02:00
struct drm_framebuffer * next_fb ;
2013-01-08 15:04:28 -06:00
2015-02-10 14:13:23 +02:00
/* Only set if an external encoder is connected */
bool simulate_vesa_sync ;
2016-01-08 14:33:09 +02:00
int sync_lost_count ;
bool frame_intact ;
2016-04-06 14:02:38 +03:00
struct work_struct recover_work ;
2016-10-31 15:19:26 +01:00
dma_addr_t palette_dma_handle ;
2016-11-15 23:37:24 +02:00
u16 * palette_base ;
2016-10-31 15:19:26 +01:00
struct completion palette_loaded ;
2013-01-08 15:04:28 -06:00
} ;
# define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base)
2015-10-20 09:37:27 +03:00
static void set_scanout ( struct drm_crtc * crtc , struct drm_framebuffer * fb )
2013-01-08 15:04:28 -06:00
{
struct drm_device * dev = crtc - > dev ;
2016-10-28 13:52:41 +02:00
struct tilcdc_drm_private * priv = dev - > dev_private ;
2013-01-08 15:04:28 -06:00
struct drm_gem_cma_object * gem ;
2015-10-20 09:37:27 +03:00
dma_addr_t start , end ;
2016-08-26 15:10:14 +03:00
u64 dma_base_and_ceiling ;
2013-01-08 15:04:28 -06:00
gem = drm_fb_cma_get_gem_obj ( fb , 0 ) ;
2015-10-20 09:37:27 +03:00
start = gem - > paddr + fb - > offsets [ 0 ] +
crtc - > y * fb - > pitches [ 0 ] +
2016-12-14 23:30:57 +02:00
crtc - > x * fb - > format - > cpp [ 0 ] ;
2013-01-08 15:04:28 -06:00
2015-10-20 09:37:27 +03:00
end = start + ( crtc - > mode . vdisplay * fb - > pitches [ 0 ] ) ;
2013-01-08 15:04:28 -06:00
2016-08-26 15:10:14 +03:00
/* Write LCDC_DMA_FB_BASE_ADDR_0_REG and LCDC_DMA_FB_CEILING_ADDR_0_REG
* with a single insruction , if available . This should make it more
* unlikely that LCDC would fetch the DMA addresses in the middle of
* an update .
*/
2016-10-28 13:52:41 +02:00
if ( priv - > rev = = 1 )
end - = 1 ;
dma_base_and_ceiling = ( u64 ) end < < 32 | start ;
2016-08-26 15:10:14 +03:00
tilcdc_write64 ( dev , LCDC_DMA_FB_BASE_ADDR_0_REG , dma_base_and_ceiling ) ;
2013-01-08 15:04:28 -06:00
}
2016-10-31 15:19:26 +01:00
/*
2016-11-15 23:37:24 +02:00
* The driver currently only supports only true color formats . For
* true color the palette block is bypassed , but a 32 byte palette
* should still be loaded . The first 16 - bit entry must be 0x4000 while
* all other entries must be zeroed .
2016-10-31 15:19:26 +01:00
*/
static void tilcdc_crtc_load_palette ( struct drm_crtc * crtc )
{
2016-11-15 23:37:24 +02:00
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct tilcdc_drm_private * priv = dev - > dev_private ;
2016-11-17 18:46:16 +02:00
int ret ;
2016-10-31 15:19:26 +01:00
2016-11-15 23:57:42 +02:00
reinit_completion ( & tilcdc_crtc - > palette_loaded ) ;
2016-10-31 15:19:26 +01:00
/* Tell the LCDC where the palette is located. */
tilcdc_write ( dev , LCDC_DMA_FB_BASE_ADDR_0_REG ,
tilcdc_crtc - > palette_dma_handle ) ;
tilcdc_write ( dev , LCDC_DMA_FB_CEILING_ADDR_0_REG ,
2016-11-15 23:37:24 +02:00
( u32 ) tilcdc_crtc - > palette_dma_handle +
TILCDC_PALETTE_SIZE - 1 ) ;
2016-10-31 15:19:26 +01:00
2016-11-15 23:37:24 +02:00
/* Set dma load mode for palette loading only. */
tilcdc_write_mask ( dev , LCDC_RASTER_CTRL_REG ,
LCDC_PALETTE_LOAD_MODE ( PALETTE_ONLY ) ,
LCDC_PALETTE_LOAD_MODE_MASK ) ;
/* Enable DMA Palette Loaded Interrupt */
if ( priv - > rev = = 1 )
tilcdc_set ( dev , LCDC_RASTER_CTRL_REG , LCDC_V1_PL_INT_ENA ) ;
else
tilcdc_write ( dev , LCDC_INT_ENABLE_SET_REG , LCDC_V2_PL_INT_ENA ) ;
2016-10-31 15:19:26 +01:00
2016-11-15 23:37:24 +02:00
/* Enable LCDC DMA and wait for palette to be loaded. */
tilcdc_clear_irqstatus ( dev , 0xffffffff ) ;
2016-10-31 15:19:26 +01:00
tilcdc_set ( dev , LCDC_RASTER_CTRL_REG , LCDC_RASTER_ENABLE ) ;
2016-11-17 18:46:16 +02:00
ret = wait_for_completion_timeout ( & tilcdc_crtc - > palette_loaded ,
msecs_to_jiffies ( 50 ) ) ;
if ( ret = = 0 )
dev_err ( dev - > dev , " %s: Palette loading timeout " , __func__ ) ;
2016-10-31 15:19:26 +01:00
2016-11-15 23:37:24 +02:00
/* Disable LCDC DMA and DMA Palette Loaded Interrupt. */
2016-10-31 15:19:26 +01:00
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG , LCDC_RASTER_ENABLE ) ;
2016-11-15 23:37:24 +02:00
if ( priv - > rev = = 1 )
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG , LCDC_V1_PL_INT_ENA ) ;
else
tilcdc_write ( dev , LCDC_INT_ENABLE_CLR_REG , LCDC_V2_PL_INT_ENA ) ;
2016-10-31 15:19:26 +01:00
}
2016-06-21 16:00:44 +03:00
static void tilcdc_crtc_enable_irqs ( struct drm_device * dev )
{
struct tilcdc_drm_private * priv = dev - > dev_private ;
tilcdc_clear_irqstatus ( dev , 0xffffffff ) ;
if ( priv - > rev = = 1 ) {
tilcdc_set ( dev , LCDC_RASTER_CTRL_REG ,
2016-11-21 18:30:19 +02:00
LCDC_V1_SYNC_LOST_INT_ENA | LCDC_V1_FRAME_DONE_INT_ENA |
2016-06-21 16:00:44 +03:00
LCDC_V1_UNDERFLOW_INT_ENA ) ;
2016-08-23 12:57:00 +00:00
tilcdc_set ( dev , LCDC_DMA_CTRL_REG ,
LCDC_V1_END_OF_FRAME_INT_ENA ) ;
2016-06-21 16:00:44 +03:00
} else {
tilcdc_write ( dev , LCDC_INT_ENABLE_SET_REG ,
LCDC_V2_UNDERFLOW_INT_ENA |
LCDC_V2_END_OF_FRAME0_INT_ENA |
LCDC_FRAME_DONE | LCDC_SYNC_LOST ) ;
}
}
static void tilcdc_crtc_disable_irqs ( struct drm_device * dev )
{
struct tilcdc_drm_private * priv = dev - > dev_private ;
/* disable irqs that we might have enabled: */
if ( priv - > rev = = 1 ) {
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG ,
2016-11-21 18:30:19 +02:00
LCDC_V1_SYNC_LOST_INT_ENA | LCDC_V1_FRAME_DONE_INT_ENA |
2016-06-21 16:00:44 +03:00
LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA ) ;
tilcdc_clear ( dev , LCDC_DMA_CTRL_REG ,
LCDC_V1_END_OF_FRAME_INT_ENA ) ;
} else {
tilcdc_write ( dev , LCDC_INT_ENABLE_CLR_REG ,
LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA |
LCDC_V2_END_OF_FRAME0_INT_ENA |
LCDC_FRAME_DONE | LCDC_SYNC_LOST ) ;
}
}
2015-10-20 09:37:27 +03:00
static void reset ( struct drm_crtc * crtc )
2013-01-08 15:04:28 -06:00
{
struct drm_device * dev = crtc - > dev ;
struct tilcdc_drm_private * priv = dev - > dev_private ;
2015-10-20 09:37:27 +03:00
if ( priv - > rev ! = 2 )
return ;
tilcdc_set ( dev , LCDC_CLK_RESET_REG , LCDC_CLK_MAIN_RESET ) ;
usleep_range ( 250 , 1000 ) ;
tilcdc_clear ( dev , LCDC_CLK_RESET_REG , LCDC_CLK_MAIN_RESET ) ;
}
2016-09-29 18:43:57 +02:00
/*
* Calculate the percentage difference between the requested pixel clock rate
* and the effective rate resulting from calculating the clock divider value .
*/
static unsigned int tilcdc_pclk_diff ( unsigned long rate ,
unsigned long real_rate )
{
int r = rate / 100 , rr = real_rate / 100 ;
return ( unsigned int ) ( abs ( ( ( rr - r ) * 100 ) / r ) ) ;
}
2016-09-06 16:19:54 +03:00
static void tilcdc_crtc_set_clk ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct tilcdc_drm_private * priv = dev - > dev_private ;
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
2016-09-29 18:43:57 +02:00
unsigned long clk_rate , real_rate , req_rate ;
unsigned int clkdiv ;
2016-09-06 16:19:54 +03:00
int ret ;
2016-09-29 18:43:57 +02:00
clkdiv = 2 ; /* first try using a standard divider of 2 */
2016-09-06 16:19:54 +03:00
/* mode.clock is in KHz, set_rate wants parameter in Hz */
2016-09-29 18:43:57 +02:00
req_rate = crtc - > mode . clock * 1000 ;
ret = clk_set_rate ( priv - > clk , req_rate * clkdiv ) ;
clk_rate = clk_get_rate ( priv - > clk ) ;
2018-03-14 17:58:45 -05:00
if ( ret < 0 | | tilcdc_pclk_diff ( req_rate , clk_rate ) > 5 ) {
2016-09-29 18:43:57 +02:00
/*
* If we fail to set the clock rate ( some architectures don ' t
* use the common clock framework yet and may not implement
* all the clk API calls for every clock ) , try the next best
* thing : adjusting the clock divider , unless clk_get_rate ( )
* failed as well .
*/
if ( ! clk_rate ) {
/* Nothing more we can do. Just bail out. */
dev_err ( dev - > dev ,
" failed to set the pixel clock - unable to read current lcdc clock rate \n " ) ;
return ;
}
clkdiv = DIV_ROUND_CLOSEST ( clk_rate , req_rate ) ;
/*
* Emit a warning if the real clock rate resulting from the
* calculated divider differs much from the requested rate .
*
* 5 % is an arbitrary value - LCDs are usually quite tolerant
* about pixel clock rates .
*/
real_rate = clkdiv * req_rate ;
if ( tilcdc_pclk_diff ( clk_rate , real_rate ) > 5 ) {
dev_warn ( dev - > dev ,
" effective pixel clock rate (%luHz) differs from the calculated rate (%luHz) \n " ,
clk_rate , real_rate ) ;
}
2016-09-06 16:19:54 +03:00
}
2016-09-29 18:43:57 +02:00
tilcdc_crtc - > lcd_fck_rate = clk_rate ;
2016-09-06 16:19:54 +03:00
DBG ( " lcd_clk=%u, mode clock=%d, div=%u " ,
tilcdc_crtc - > lcd_fck_rate , crtc - > mode . clock , clkdiv ) ;
/* Configure the LCD clock divisor. */
tilcdc_write ( dev , LCDC_CTRL_REG , LCDC_CLK_DIVISOR ( clkdiv ) |
LCDC_RASTER_MODE ) ;
if ( priv - > rev = = 2 )
tilcdc_set ( dev , LCDC_CLK_ENABLE_REG ,
LCDC_V2_DMA_CLK_EN | LCDC_V2_LIDD_CLK_EN |
LCDC_V2_CORE_CLK_EN ) ;
}
2017-12-02 19:24:22 +08:00
static uint tilcdc_mode_hvtotal ( const struct drm_display_mode * mode )
2017-10-12 12:19:46 +03:00
{
return ( uint ) div_u64 ( 1000llu * mode - > htotal * mode - > vtotal ,
mode - > clock ) ;
}
2016-11-24 23:25:08 +02:00
static void tilcdc_crtc_set_mode ( struct drm_crtc * crtc )
2016-04-07 15:09:50 +03:00
{
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct tilcdc_drm_private * priv = dev - > dev_private ;
const struct tilcdc_panel_info * info = tilcdc_crtc - > info ;
uint32_t reg , hbp , hfp , hsw , vbp , vfp , vsw ;
struct drm_display_mode * mode = & crtc - > state - > adjusted_mode ;
struct drm_framebuffer * fb = crtc - > primary - > state - > fb ;
if ( WARN_ON ( ! info ) )
return ;
if ( WARN_ON ( ! fb ) )
return ;
/* Configure the Burst Size and fifo threshold of DMA: */
reg = tilcdc_read ( dev , LCDC_DMA_CTRL_REG ) & ~ 0x00000770 ;
switch ( info - > dma_burst_sz ) {
case 1 :
reg | = LCDC_DMA_BURST_SIZE ( LCDC_DMA_BURST_1 ) ;
break ;
case 2 :
reg | = LCDC_DMA_BURST_SIZE ( LCDC_DMA_BURST_2 ) ;
break ;
case 4 :
reg | = LCDC_DMA_BURST_SIZE ( LCDC_DMA_BURST_4 ) ;
break ;
case 8 :
reg | = LCDC_DMA_BURST_SIZE ( LCDC_DMA_BURST_8 ) ;
break ;
case 16 :
reg | = LCDC_DMA_BURST_SIZE ( LCDC_DMA_BURST_16 ) ;
break ;
default :
dev_err ( dev - > dev , " invalid burst size \n " ) ;
return ;
}
reg | = ( info - > fifo_th < < 8 ) ;
tilcdc_write ( dev , LCDC_DMA_CTRL_REG , reg ) ;
/* Configure timings: */
hbp = mode - > htotal - mode - > hsync_end ;
hfp = mode - > hsync_start - mode - > hdisplay ;
hsw = mode - > hsync_end - mode - > hsync_start ;
vbp = mode - > vtotal - mode - > vsync_end ;
vfp = mode - > vsync_start - mode - > vdisplay ;
vsw = mode - > vsync_end - mode - > vsync_start ;
DBG ( " %dx%d, hbp=%u, hfp=%u, hsw=%u, vbp=%u, vfp=%u, vsw=%u " ,
mode - > hdisplay , mode - > vdisplay , hbp , hfp , hsw , vbp , vfp , vsw ) ;
/* Set AC Bias Period and Number of Transitions per Interrupt: */
reg = tilcdc_read ( dev , LCDC_RASTER_TIMING_2_REG ) & ~ 0x000fff00 ;
reg | = LCDC_AC_BIAS_FREQUENCY ( info - > ac_bias ) |
LCDC_AC_BIAS_TRANSITIONS_PER_INT ( info - > ac_bias_intrpt ) ;
/*
* subtract one from hfp , hbp , hsw because the hardware uses
* a value of 0 as 1
*/
if ( priv - > rev = = 2 ) {
/* clear bits we're going to set */
reg & = ~ 0x78000033 ;
reg | = ( ( hfp - 1 ) & 0x300 ) > > 8 ;
reg | = ( ( hbp - 1 ) & 0x300 ) > > 4 ;
reg | = ( ( hsw - 1 ) & 0x3c0 ) < < 21 ;
}
tilcdc_write ( dev , LCDC_RASTER_TIMING_2_REG , reg ) ;
reg = ( ( ( mode - > hdisplay > > 4 ) - 1 ) < < 4 ) |
( ( ( hbp - 1 ) & 0xff ) < < 24 ) |
( ( ( hfp - 1 ) & 0xff ) < < 16 ) |
( ( ( hsw - 1 ) & 0x3f ) < < 10 ) ;
if ( priv - > rev = = 2 )
reg | = ( ( ( mode - > hdisplay > > 4 ) - 1 ) & 0x40 ) > > 3 ;
tilcdc_write ( dev , LCDC_RASTER_TIMING_0_REG , reg ) ;
reg = ( ( mode - > vdisplay - 1 ) & 0x3ff ) |
( ( vbp & 0xff ) < < 24 ) |
( ( vfp & 0xff ) < < 16 ) |
( ( ( vsw - 1 ) & 0x3f ) < < 10 ) ;
tilcdc_write ( dev , LCDC_RASTER_TIMING_1_REG , reg ) ;
/*
* be sure to set Bit 10 for the V2 LCDC controller ,
* otherwise limited to 1024 pixels width , stopping
* 1920 x1080 being supported .
*/
if ( priv - > rev = = 2 ) {
if ( ( mode - > vdisplay - 1 ) & 0x400 ) {
tilcdc_set ( dev , LCDC_RASTER_TIMING_2_REG ,
LCDC_LPP_B10 ) ;
} else {
tilcdc_clear ( dev , LCDC_RASTER_TIMING_2_REG ,
LCDC_LPP_B10 ) ;
}
}
/* Configure display type: */
reg = tilcdc_read ( dev , LCDC_RASTER_CTRL_REG ) &
~ ( LCDC_TFT_MODE | LCDC_MONO_8BIT_MODE | LCDC_MONOCHROME_MODE |
LCDC_V2_TFT_24BPP_MODE | LCDC_V2_TFT_24BPP_UNPACK |
0x000ff000 /* Palette Loading Delay bits */ ) ;
reg | = LCDC_TFT_MODE ; /* no monochrome/passive support */
if ( info - > tft_alt_mode )
reg | = LCDC_TFT_ALT_ENABLE ;
if ( priv - > rev = = 2 ) {
2016-12-14 23:32:55 +02:00
switch ( fb - > format - > format ) {
2016-10-18 01:41:14 +03:00
case DRM_FORMAT_BGR565 :
case DRM_FORMAT_RGB565 :
2016-04-07 15:09:50 +03:00
break ;
2016-10-18 01:41:14 +03:00
case DRM_FORMAT_XBGR8888 :
case DRM_FORMAT_XRGB8888 :
2016-04-07 15:09:50 +03:00
reg | = LCDC_V2_TFT_24BPP_UNPACK ;
/* fallthrough */
2016-10-18 01:41:14 +03:00
case DRM_FORMAT_BGR888 :
case DRM_FORMAT_RGB888 :
2016-04-07 15:09:50 +03:00
reg | = LCDC_V2_TFT_24BPP_MODE ;
break ;
default :
dev_err ( dev - > dev , " invalid pixel format \n " ) ;
return ;
}
}
reg | = info - > fdd < 12 ;
tilcdc_write ( dev , LCDC_RASTER_CTRL_REG , reg ) ;
if ( info - > invert_pxl_clk )
tilcdc_set ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_INVERT_PIXEL_CLOCK ) ;
else
tilcdc_clear ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_INVERT_PIXEL_CLOCK ) ;
if ( info - > sync_ctrl )
tilcdc_set ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_SYNC_CTRL ) ;
else
tilcdc_clear ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_SYNC_CTRL ) ;
if ( info - > sync_edge )
tilcdc_set ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_SYNC_EDGE ) ;
else
tilcdc_clear ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_SYNC_EDGE ) ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC )
tilcdc_set ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_INVERT_HSYNC ) ;
else
tilcdc_clear ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_INVERT_HSYNC ) ;
if ( mode - > flags & DRM_MODE_FLAG_NVSYNC )
tilcdc_set ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_INVERT_VSYNC ) ;
else
tilcdc_clear ( dev , LCDC_RASTER_TIMING_2_REG , LCDC_INVERT_VSYNC ) ;
if ( info - > raster_order )
tilcdc_set ( dev , LCDC_RASTER_CTRL_REG , LCDC_RASTER_ORDER ) ;
else
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG , LCDC_RASTER_ORDER ) ;
2016-09-06 16:19:54 +03:00
tilcdc_crtc_set_clk ( crtc ) ;
2016-04-07 15:09:50 +03:00
2016-11-15 23:57:42 +02:00
tilcdc_crtc_load_palette ( crtc ) ;
set_scanout ( crtc , fb ) ;
2016-04-07 15:09:50 +03:00
crtc - > hwmode = crtc - > state - > adjusted_mode ;
2017-10-12 12:19:46 +03:00
tilcdc_crtc - > hvtotal_us =
tilcdc_mode_hvtotal ( & crtc - > hwmode ) ;
2016-04-07 15:09:50 +03:00
}
2016-11-24 23:25:08 +02:00
static void tilcdc_crtc_enable ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
2017-03-01 10:30:28 +02:00
unsigned long flags ;
2016-11-24 23:25:08 +02:00
mutex_lock ( & tilcdc_crtc - > enable_lock ) ;
if ( tilcdc_crtc - > enabled | | tilcdc_crtc - > shutdown ) {
mutex_unlock ( & tilcdc_crtc - > enable_lock ) ;
return ;
}
pm_runtime_get_sync ( dev - > dev ) ;
reset ( crtc ) ;
tilcdc_crtc_set_mode ( crtc ) ;
tilcdc_crtc_enable_irqs ( dev ) ;
tilcdc_clear ( dev , LCDC_DMA_CTRL_REG , LCDC_DUAL_FRAME_BUFFER_ENABLE ) ;
tilcdc_write_mask ( dev , LCDC_RASTER_CTRL_REG ,
LCDC_PALETTE_LOAD_MODE ( DATA_ONLY ) ,
LCDC_PALETTE_LOAD_MODE_MASK ) ;
2017-03-01 10:30:28 +02:00
/* There is no real chance for a race here as the time stamp
* is taken before the raster DMA is started . The spin - lock is
* taken to have a memory barrier after taking the time - stamp
* and to avoid a context switch between taking the stamp and
* enabling the raster .
*/
spin_lock_irqsave ( & tilcdc_crtc - > irq_lock , flags ) ;
tilcdc_crtc - > last_vblank = ktime_get ( ) ;
2016-11-24 23:25:08 +02:00
tilcdc_set ( dev , LCDC_RASTER_CTRL_REG , LCDC_RASTER_ENABLE ) ;
2017-03-01 10:30:28 +02:00
spin_unlock_irqrestore ( & tilcdc_crtc - > irq_lock , flags ) ;
2016-11-24 23:25:08 +02:00
drm_crtc_vblank_on ( crtc ) ;
tilcdc_crtc - > enabled = true ;
mutex_unlock ( & tilcdc_crtc - > enable_lock ) ;
}
2017-06-30 12:36:44 +03:00
static void tilcdc_crtc_atomic_enable ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_state )
{
tilcdc_crtc_enable ( crtc ) ;
}
2016-11-24 23:25:08 +02:00
static void tilcdc_crtc_off ( struct drm_crtc * crtc , bool shutdown )
{
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
int ret ;
mutex_lock ( & tilcdc_crtc - > enable_lock ) ;
if ( shutdown )
tilcdc_crtc - > shutdown = true ;
if ( ! tilcdc_crtc - > enabled ) {
mutex_unlock ( & tilcdc_crtc - > enable_lock ) ;
return ;
}
tilcdc_crtc - > frame_done = false ;
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG , LCDC_RASTER_ENABLE ) ;
/*
* Wait for framedone irq which will still come before putting
* things to sleep . .
*/
ret = wait_event_timeout ( tilcdc_crtc - > frame_done_wq ,
tilcdc_crtc - > frame_done ,
msecs_to_jiffies ( 500 ) ) ;
if ( ret = = 0 )
dev_err ( dev - > dev , " %s: timeout waiting for framedone \n " ,
__func__ ) ;
drm_crtc_vblank_off ( crtc ) ;
tilcdc_crtc_disable_irqs ( dev ) ;
pm_runtime_put_sync ( dev - > dev ) ;
tilcdc_crtc - > enabled = false ;
mutex_unlock ( & tilcdc_crtc - > enable_lock ) ;
}
static void tilcdc_crtc_disable ( struct drm_crtc * crtc )
{
tilcdc_crtc_off ( crtc , false ) ;
}
2017-06-30 12:36:45 +03:00
static void tilcdc_crtc_atomic_disable ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_state )
{
tilcdc_crtc_disable ( crtc ) ;
}
2016-11-24 23:25:08 +02:00
void tilcdc_crtc_shutdown ( struct drm_crtc * crtc )
{
tilcdc_crtc_off ( crtc , true ) ;
}
static bool tilcdc_crtc_is_on ( struct drm_crtc * crtc )
{
return crtc - > state & & crtc - > state - > enable & & crtc - > state - > active ;
}
static void tilcdc_crtc_recover_work ( struct work_struct * work )
{
struct tilcdc_crtc * tilcdc_crtc =
container_of ( work , struct tilcdc_crtc , recover_work ) ;
struct drm_crtc * crtc = & tilcdc_crtc - > base ;
dev_info ( crtc - > dev - > dev , " %s: Reset CRTC " , __func__ ) ;
2017-03-22 22:50:47 +01:00
drm_modeset_lock ( & crtc - > mutex , NULL ) ;
2016-11-24 23:25:08 +02:00
if ( ! tilcdc_crtc_is_on ( crtc ) )
goto out ;
tilcdc_crtc_disable ( crtc ) ;
tilcdc_crtc_enable ( crtc ) ;
out :
2017-03-22 22:50:47 +01:00
drm_modeset_unlock ( & crtc - > mutex ) ;
2016-11-24 23:25:08 +02:00
}
static void tilcdc_crtc_destroy ( struct drm_crtc * crtc )
{
struct tilcdc_drm_private * priv = crtc - > dev - > dev_private ;
2017-05-29 22:09:44 +03:00
tilcdc_crtc_shutdown ( crtc ) ;
2016-11-24 23:25:08 +02:00
flush_workqueue ( priv - > wq ) ;
of_node_put ( crtc - > port ) ;
drm_crtc_cleanup ( crtc ) ;
}
int tilcdc_crtc_update_fb ( struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
struct drm_pending_vblank_event * event )
{
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
if ( tilcdc_crtc - > event ) {
dev_err ( dev - > dev , " already pending page flip! \n " ) ;
return - EBUSY ;
}
2017-03-01 10:30:28 +02:00
tilcdc_crtc - > event = event ;
2016-11-24 23:25:08 +02:00
2017-03-01 10:30:28 +02:00
mutex_lock ( & tilcdc_crtc - > enable_lock ) ;
2016-11-24 23:25:08 +02:00
2017-03-01 10:30:28 +02:00
if ( tilcdc_crtc - > enabled ) {
unsigned long flags ;
2016-11-24 23:25:08 +02:00
ktime_t next_vblank ;
s64 tdiff ;
2017-03-01 10:30:28 +02:00
spin_lock_irqsave ( & tilcdc_crtc - > irq_lock , flags ) ;
2016-11-24 23:25:08 +02:00
2017-03-01 10:30:28 +02:00
next_vblank = ktime_add_us ( tilcdc_crtc - > last_vblank ,
2017-10-12 12:19:46 +03:00
tilcdc_crtc - > hvtotal_us ) ;
2016-11-24 23:25:08 +02:00
tdiff = ktime_to_us ( ktime_sub ( next_vblank , ktime_get ( ) ) ) ;
if ( tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US )
tilcdc_crtc - > next_fb = fb ;
2017-03-01 10:30:28 +02:00
else
set_scanout ( crtc , fb ) ;
2016-11-24 23:25:08 +02:00
2017-03-01 10:30:28 +02:00
spin_unlock_irqrestore ( & tilcdc_crtc - > irq_lock , flags ) ;
}
2016-11-24 23:25:08 +02:00
2017-03-01 10:30:28 +02:00
mutex_unlock ( & tilcdc_crtc - > enable_lock ) ;
2016-11-24 23:25:08 +02:00
return 0 ;
}
static bool tilcdc_crtc_mode_fixup ( struct drm_crtc * crtc ,
const struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
if ( ! tilcdc_crtc - > simulate_vesa_sync )
return true ;
/*
* tilcdc does not generate VESA - compliant sync but aligns
* VS on the second edge of HS instead of first edge .
* We use adjusted_mode , to fixup sync by aligning both rising
* edges and add HSKEW offset to fix the sync .
*/
adjusted_mode - > hskew = mode - > hsync_end - mode - > hsync_start ;
adjusted_mode - > flags | = DRM_MODE_FLAG_HSKEW ;
if ( mode - > flags & DRM_MODE_FLAG_NHSYNC ) {
adjusted_mode - > flags | = DRM_MODE_FLAG_PHSYNC ;
adjusted_mode - > flags & = ~ DRM_MODE_FLAG_NHSYNC ;
} else {
adjusted_mode - > flags | = DRM_MODE_FLAG_NHSYNC ;
adjusted_mode - > flags & = ~ DRM_MODE_FLAG_PHSYNC ;
}
return true ;
}
2016-04-07 15:10:23 +03:00
static int tilcdc_crtc_atomic_check ( struct drm_crtc * crtc ,
struct drm_crtc_state * state )
{
struct drm_display_mode * mode = & state - > mode ;
int ret ;
/* If we are not active we don't care */
if ( ! state - > active )
return 0 ;
if ( state - > state - > planes [ 0 ] . ptr ! = crtc - > primary | |
state - > state - > planes [ 0 ] . state = = NULL | |
state - > state - > planes [ 0 ] . state - > crtc ! = crtc ) {
dev_dbg ( crtc - > dev - > dev , " CRTC primary plane must be present " ) ;
return - EINVAL ;
}
ret = tilcdc_crtc_mode_valid ( crtc , mode ) ;
if ( ret ) {
dev_dbg ( crtc - > dev - > dev , " Mode \" %s \" not valid " , mode - > name ) ;
return - EINVAL ;
}
return 0 ;
}
2017-02-07 17:16:33 +08:00
static int tilcdc_crtc_enable_vblank ( struct drm_crtc * crtc )
{
return 0 ;
}
static void tilcdc_crtc_disable_vblank ( struct drm_crtc * crtc )
{
}
2017-05-26 13:20:17 +03:00
static void tilcdc_crtc_reset ( struct drm_crtc * crtc )
{
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
int ret ;
drm_atomic_helper_crtc_reset ( crtc ) ;
/* Turn the raster off if it for some reason is on. */
pm_runtime_get_sync ( dev - > dev ) ;
if ( tilcdc_read ( dev , LCDC_RASTER_CTRL_REG ) & LCDC_RASTER_ENABLE ) {
/* Enable DMA Frame Done Interrupt */
tilcdc_write ( dev , LCDC_INT_ENABLE_SET_REG , LCDC_FRAME_DONE ) ;
tilcdc_clear_irqstatus ( dev , 0xffffffff ) ;
tilcdc_crtc - > frame_done = false ;
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG , LCDC_RASTER_ENABLE ) ;
ret = wait_event_timeout ( tilcdc_crtc - > frame_done_wq ,
tilcdc_crtc - > frame_done ,
msecs_to_jiffies ( 500 ) ) ;
if ( ret = = 0 )
dev_err ( dev - > dev , " %s: timeout waiting for framedone \n " ,
__func__ ) ;
}
pm_runtime_put_sync ( dev - > dev ) ;
}
2013-01-08 15:04:28 -06:00
static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
2016-04-07 15:05:16 +03:00
. destroy = tilcdc_crtc_destroy ,
. set_config = drm_atomic_helper_set_config ,
. page_flip = drm_atomic_helper_page_flip ,
2017-05-26 13:20:17 +03:00
. reset = tilcdc_crtc_reset ,
2016-04-07 15:05:16 +03:00
. atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_crtc_destroy_state ,
2017-02-07 17:16:33 +08:00
. enable_vblank = tilcdc_crtc_enable_vblank ,
. disable_vblank = tilcdc_crtc_disable_vblank ,
2013-01-08 15:04:28 -06:00
} ;
static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = {
. mode_fixup = tilcdc_crtc_mode_fixup ,
2016-04-07 15:10:23 +03:00
. atomic_check = tilcdc_crtc_atomic_check ,
2017-06-30 12:36:44 +03:00
. atomic_enable = tilcdc_crtc_atomic_enable ,
2017-06-30 12:36:45 +03:00
. atomic_disable = tilcdc_crtc_atomic_disable ,
2013-01-08 15:04:28 -06:00
} ;
int tilcdc_crtc_max_width ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct tilcdc_drm_private * priv = dev - > dev_private ;
int max_width = 0 ;
if ( priv - > rev = = 1 )
max_width = 1024 ;
else if ( priv - > rev = = 2 )
max_width = 2048 ;
return max_width ;
}
int tilcdc_crtc_mode_valid ( struct drm_crtc * crtc , struct drm_display_mode * mode )
{
struct tilcdc_drm_private * priv = crtc - > dev - > dev_private ;
unsigned int bandwidth ;
2013-06-21 13:52:25 -05:00
uint32_t hbp , hfp , hsw , vbp , vfp , vsw ;
2013-01-08 15:04:28 -06:00
2013-06-21 13:52:25 -05:00
/*
* check to see if the width is within the range that
* the LCD Controller physically supports
*/
2013-01-08 15:04:28 -06:00
if ( mode - > hdisplay > tilcdc_crtc_max_width ( crtc ) )
return MODE_VIRTUAL_X ;
/* width must be multiple of 16 */
if ( mode - > hdisplay & 0xf )
return MODE_VIRTUAL_X ;
if ( mode - > vdisplay > 2048 )
return MODE_VIRTUAL_Y ;
2013-06-21 13:52:25 -05:00
DBG ( " Processing mode %dx%d@%d with pixel clock %d " ,
mode - > hdisplay , mode - > vdisplay ,
drm_mode_vrefresh ( mode ) , mode - > clock ) ;
hbp = mode - > htotal - mode - > hsync_end ;
hfp = mode - > hsync_start - mode - > hdisplay ;
hsw = mode - > hsync_end - mode - > hsync_start ;
vbp = mode - > vtotal - mode - > vsync_end ;
vfp = mode - > vsync_start - mode - > vdisplay ;
vsw = mode - > vsync_end - mode - > vsync_start ;
if ( ( hbp - 1 ) & ~ 0x3ff ) {
DBG ( " Pruning mode: Horizontal Back Porch out of range " ) ;
return MODE_HBLANK_WIDE ;
}
if ( ( hfp - 1 ) & ~ 0x3ff ) {
DBG ( " Pruning mode: Horizontal Front Porch out of range " ) ;
return MODE_HBLANK_WIDE ;
}
if ( ( hsw - 1 ) & ~ 0x3ff ) {
DBG ( " Pruning mode: Horizontal Sync Width out of range " ) ;
return MODE_HSYNC_WIDE ;
}
if ( vbp & ~ 0xff ) {
DBG ( " Pruning mode: Vertical Back Porch out of range " ) ;
return MODE_VBLANK_WIDE ;
}
if ( vfp & ~ 0xff ) {
DBG ( " Pruning mode: Vertical Front Porch out of range " ) ;
return MODE_VBLANK_WIDE ;
}
if ( ( vsw - 1 ) & ~ 0x3f ) {
DBG ( " Pruning mode: Vertical Sync Width out of range " ) ;
return MODE_VSYNC_WIDE ;
}
2013-06-21 13:52:23 -05:00
/*
* some devices have a maximum allowed pixel clock
* configured from the DT
*/
if ( mode - > clock > priv - > max_pixelclock ) {
2013-06-21 13:52:26 -05:00
DBG ( " Pruning mode: pixel clock too high " ) ;
2013-06-21 13:52:23 -05:00
return MODE_CLOCK_HIGH ;
}
/*
* some devices further limit the max horizontal resolution
* configured from the DT
*/
if ( mode - > hdisplay > priv - > max_width )
return MODE_BAD_WIDTH ;
2013-01-08 15:04:28 -06:00
/* filter out modes that would require too much memory bandwidth: */
2013-06-21 13:52:23 -05:00
bandwidth = mode - > hdisplay * mode - > vdisplay *
drm_mode_vrefresh ( mode ) ;
if ( bandwidth > priv - > max_bandwidth ) {
2013-06-21 13:52:26 -05:00
DBG ( " Pruning mode: exceeds defined bandwidth limit " ) ;
2013-01-08 15:04:28 -06:00
return MODE_BAD ;
2013-06-21 13:52:23 -05:00
}
2013-01-08 15:04:28 -06:00
return MODE_OK ;
}
void tilcdc_crtc_set_panel_info ( struct drm_crtc * crtc ,
const struct tilcdc_panel_info * info )
{
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
tilcdc_crtc - > info = info ;
}
2015-02-10 14:13:23 +02:00
void tilcdc_crtc_set_simulate_vesa_sync ( struct drm_crtc * crtc ,
bool simulate_vesa_sync )
{
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
tilcdc_crtc - > simulate_vesa_sync = simulate_vesa_sync ;
}
2013-01-08 15:04:28 -06:00
void tilcdc_crtc_update_clk ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct tilcdc_drm_private * priv = dev - > dev_private ;
2016-09-06 16:19:54 +03:00
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
2013-01-08 15:04:28 -06:00
2017-03-22 22:50:47 +01:00
drm_modeset_lock ( & crtc - > mutex , NULL ) ;
2016-09-06 16:19:54 +03:00
if ( tilcdc_crtc - > lcd_fck_rate ! = clk_get_rate ( priv - > clk ) ) {
if ( tilcdc_crtc_is_on ( crtc ) ) {
pm_runtime_get_sync ( dev - > dev ) ;
tilcdc_crtc_disable ( crtc ) ;
2013-01-08 15:04:28 -06:00
2016-09-06 16:19:54 +03:00
tilcdc_crtc_set_clk ( crtc ) ;
2013-01-08 15:04:28 -06:00
2016-09-06 16:19:54 +03:00
tilcdc_crtc_enable ( crtc ) ;
pm_runtime_put_sync ( dev - > dev ) ;
}
2013-01-08 15:04:28 -06:00
}
2017-03-22 22:50:47 +01:00
drm_modeset_unlock ( & crtc - > mutex ) ;
2013-01-08 15:04:28 -06:00
}
2016-01-08 14:33:09 +02:00
# define SYNC_LOST_COUNT_LIMIT 50
2013-01-08 15:04:28 -06:00
irqreturn_t tilcdc_crtc_irq ( struct drm_crtc * crtc )
{
struct tilcdc_crtc * tilcdc_crtc = to_tilcdc_crtc ( crtc ) ;
struct drm_device * dev = crtc - > dev ;
struct tilcdc_drm_private * priv = dev - > dev_private ;
2016-12-19 15:47:14 +01:00
uint32_t stat , reg ;
2013-01-08 15:04:28 -06:00
2015-10-20 12:08:03 +03:00
stat = tilcdc_read_irqstatus ( dev ) ;
tilcdc_clear_irqstatus ( dev , stat ) ;
2015-10-20 09:37:27 +03:00
if ( stat & LCDC_END_OF_FRAME0 ) {
2013-01-08 15:04:28 -06:00
unsigned long flags ;
2015-11-03 12:00:51 +02:00
bool skip_event = false ;
ktime_t now ;
now = ktime_get ( ) ;
2013-01-08 15:04:28 -06:00
2015-11-03 12:00:51 +02:00
spin_lock_irqsave ( & tilcdc_crtc - > irq_lock , flags ) ;
tilcdc_crtc - > last_vblank = now ;
if ( tilcdc_crtc - > next_fb ) {
set_scanout ( crtc , tilcdc_crtc - > next_fb ) ;
tilcdc_crtc - > next_fb = NULL ;
skip_event = true ;
}
spin_unlock_irqrestore ( & tilcdc_crtc - > irq_lock , flags ) ;
2016-07-04 21:04:52 -03:00
drm_crtc_handle_vblank ( crtc ) ;
2013-01-08 15:04:28 -06:00
2015-11-03 12:00:51 +02:00
if ( ! skip_event ) {
struct drm_pending_vblank_event * event ;
2013-01-08 15:04:28 -06:00
2015-11-03 12:00:51 +02:00
spin_lock_irqsave ( & dev - > event_lock , flags ) ;
event = tilcdc_crtc - > event ;
2015-10-20 09:37:27 +03:00
tilcdc_crtc - > event = NULL ;
2015-11-03 12:00:51 +02:00
if ( event )
2016-04-14 10:48:22 -07:00
drm_crtc_send_vblank_event ( crtc , event ) ;
2015-10-20 09:37:27 +03:00
2015-11-03 12:00:51 +02:00
spin_unlock_irqrestore ( & dev - > event_lock , flags ) ;
}
2016-01-08 14:33:09 +02:00
if ( tilcdc_crtc - > frame_intact )
tilcdc_crtc - > sync_lost_count = 0 ;
else
tilcdc_crtc - > frame_intact = true ;
2013-01-08 15:04:28 -06:00
}
2016-04-07 20:36:48 +03:00
if ( stat & LCDC_FIFO_UNDERFLOW )
2016-10-28 13:52:42 +02:00
dev_err_ratelimited ( dev - > dev , " %s(0x%08x): FIFO underflow " ,
2016-04-07 20:36:48 +03:00
__func__ , stat ) ;
2016-11-15 23:37:24 +02:00
if ( stat & LCDC_PL_LOAD_DONE ) {
complete ( & tilcdc_crtc - > palette_loaded ) ;
if ( priv - > rev = = 1 )
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG ,
LCDC_V1_PL_INT_ENA ) ;
else
tilcdc_write ( dev , LCDC_INT_ENABLE_CLR_REG ,
LCDC_V2_PL_INT_ENA ) ;
2016-10-31 15:19:26 +01:00
}
2016-11-16 00:12:27 +02:00
if ( stat & LCDC_SYNC_LOST ) {
dev_err_ratelimited ( dev - > dev , " %s(0x%08x): Sync lost " ,
__func__ , stat ) ;
tilcdc_crtc - > frame_intact = false ;
2016-12-19 15:47:14 +01:00
if ( priv - > rev = = 1 ) {
reg = tilcdc_read ( dev , LCDC_RASTER_CTRL_REG ) ;
if ( reg & LCDC_RASTER_ENABLE ) {
2016-11-16 00:12:27 +02:00
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG ,
2016-12-19 15:47:14 +01:00
LCDC_RASTER_ENABLE ) ;
tilcdc_set ( dev , LCDC_RASTER_CTRL_REG ,
LCDC_RASTER_ENABLE ) ;
}
} else {
if ( tilcdc_crtc - > sync_lost_count + + >
SYNC_LOST_COUNT_LIMIT ) {
dev_err ( dev - > dev ,
" %s(0x%08x): Sync lost flood detected, recovering " ,
__func__ , stat ) ;
queue_work ( system_wq ,
& tilcdc_crtc - > recover_work ) ;
2016-11-16 00:12:27 +02:00
tilcdc_write ( dev , LCDC_INT_ENABLE_CLR_REG ,
LCDC_SYNC_LOST ) ;
2016-12-19 15:47:14 +01:00
tilcdc_crtc - > sync_lost_count = 0 ;
}
2016-11-16 00:12:27 +02:00
}
}
2016-11-21 18:30:19 +02:00
if ( stat & LCDC_FRAME_DONE ) {
tilcdc_crtc - > frame_done = true ;
wake_up ( & tilcdc_crtc - > frame_done_wq ) ;
/* rev 1 lcdc appears to hang if irq is not disbaled here */
if ( priv - > rev = = 1 )
tilcdc_clear ( dev , LCDC_RASTER_CTRL_REG ,
LCDC_V1_FRAME_DONE_INT_ENA ) ;
}
2016-04-07 20:36:48 +03:00
/* For revision 2 only */
2013-01-08 15:04:28 -06:00
if ( priv - > rev = = 2 ) {
2016-04-07 20:36:48 +03:00
/* Indicate to LCDC that the interrupt service routine has
* completed , see 13.3 .6 .1 .6 in AM335x TRM .
*/
tilcdc_write ( dev , LCDC_END_OF_INT_IND_REG , 0 ) ;
}
2015-12-18 13:07:52 +02:00
2013-01-08 15:04:28 -06:00
return IRQ_HANDLED ;
}
2016-11-15 22:56:46 +02:00
int tilcdc_crtc_create ( struct drm_device * dev )
2013-01-08 15:04:28 -06:00
{
2015-05-27 11:58:37 +03:00
struct tilcdc_drm_private * priv = dev - > dev_private ;
2013-01-08 15:04:28 -06:00
struct tilcdc_crtc * tilcdc_crtc ;
struct drm_crtc * crtc ;
int ret ;
2016-02-23 12:44:27 +02:00
tilcdc_crtc = devm_kzalloc ( dev - > dev , sizeof ( * tilcdc_crtc ) , GFP_KERNEL ) ;
2018-02-06 21:51:15 +01:00
if ( ! tilcdc_crtc )
2016-11-15 22:56:46 +02:00
return - ENOMEM ;
2013-01-08 15:04:28 -06:00
2016-11-15 23:37:24 +02:00
init_completion ( & tilcdc_crtc - > palette_loaded ) ;
tilcdc_crtc - > palette_base = dmam_alloc_coherent ( dev - > dev ,
TILCDC_PALETTE_SIZE ,
2016-10-31 15:19:26 +01:00
& tilcdc_crtc - > palette_dma_handle ,
GFP_KERNEL | __GFP_ZERO ) ;
2016-11-15 23:37:24 +02:00
if ( ! tilcdc_crtc - > palette_base )
return - ENOMEM ;
* tilcdc_crtc - > palette_base = TILCDC_PALETTE_FIRST_ENTRY ;
2016-10-31 15:19:26 +01:00
2013-01-08 15:04:28 -06:00
crtc = & tilcdc_crtc - > base ;
2016-04-07 15:04:18 +03:00
ret = tilcdc_plane_init ( dev , & tilcdc_crtc - > primary ) ;
if ( ret < 0 )
goto fail ;
2016-10-25 12:27:31 +03:00
mutex_init ( & tilcdc_crtc - > enable_lock ) ;
2013-01-08 15:04:28 -06:00
init_waitqueue_head ( & tilcdc_crtc - > frame_done_wq ) ;
2015-11-03 12:00:51 +02:00
spin_lock_init ( & tilcdc_crtc - > irq_lock ) ;
2016-04-06 14:02:38 +03:00
INIT_WORK ( & tilcdc_crtc - > recover_work , tilcdc_crtc_recover_work ) ;
2015-11-03 12:00:51 +02:00
2016-04-07 15:04:18 +03:00
ret = drm_crtc_init_with_planes ( dev , crtc ,
& tilcdc_crtc - > primary ,
NULL ,
& tilcdc_crtc_funcs ,
" tilcdc crtc " ) ;
2013-01-08 15:04:28 -06:00
if ( ret < 0 )
goto fail ;
drm_crtc_helper_add ( crtc , & tilcdc_crtc_helper_funcs ) ;
2015-05-27 11:58:37 +03:00
if ( priv - > is_componentized ) {
2017-03-22 08:26:06 -05:00
crtc - > port = of_graph_get_port_by_id ( dev - > dev - > of_node , 0 ) ;
2015-05-27 11:58:37 +03:00
if ( ! crtc - > port ) { /* This should never happen */
2017-07-18 16:43:04 -05:00
dev_err ( dev - > dev , " Port node not found in %pOF \n " ,
dev - > dev - > of_node ) ;
2016-11-15 22:56:46 +02:00
ret = - EINVAL ;
2015-05-27 11:58:37 +03:00
goto fail ;
}
}
2016-11-15 22:56:46 +02:00
priv - > crtc = crtc ;
return 0 ;
2013-01-08 15:04:28 -06:00
fail :
tilcdc_crtc_destroy ( crtc ) ;
2017-01-31 16:18:42 +02:00
return ret ;
2013-01-08 15:04:28 -06:00
}