diff options
Diffstat (limited to 'drivers/gpu/drm/kmb')
| -rw-r--r-- | drivers/gpu/drm/kmb/kmb_crtc.c | 41 | ||||
| -rw-r--r-- | drivers/gpu/drm/kmb/kmb_drv.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/kmb/kmb_drv.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/kmb/kmb_dsi.c | 25 | ||||
| -rw-r--r-- | drivers/gpu/drm/kmb/kmb_dsi.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/kmb/kmb_plane.c | 43 | ||||
| -rw-r--r-- | drivers/gpu/drm/kmb/kmb_plane.h | 6 | 
7 files changed, 112 insertions, 17 deletions
| diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c index 44327bc629ca..06613ffeaaf8 100644 --- a/drivers/gpu/drm/kmb/kmb_crtc.c +++ b/drivers/gpu/drm/kmb/kmb_crtc.c @@ -66,7 +66,8 @@ static const struct drm_crtc_funcs kmb_crtc_funcs = {  	.disable_vblank = kmb_crtc_disable_vblank,  }; -static void kmb_crtc_set_mode(struct drm_crtc *crtc) +static void kmb_crtc_set_mode(struct drm_crtc *crtc, +			      struct drm_atomic_state *old_state)  {  	struct drm_device *dev = crtc->dev;  	struct drm_display_mode *m = &crtc->state->adjusted_mode; @@ -75,7 +76,7 @@ static void kmb_crtc_set_mode(struct drm_crtc *crtc)  	unsigned int val = 0;  	/* Initialize mipi */ -	kmb_dsi_mode_set(kmb->kmb_dsi, m, kmb->sys_clk_mhz); +	kmb_dsi_mode_set(kmb->kmb_dsi, m, kmb->sys_clk_mhz, old_state);  	drm_info(dev,  		 "vfp= %d vbp= %d vsync_len=%d hfp=%d hbp=%d hsync_len=%d\n",  		 m->crtc_vsync_start - m->crtc_vdisplay, @@ -138,7 +139,7 @@ static void kmb_crtc_atomic_enable(struct drm_crtc *crtc,  	struct kmb_drm_private *kmb = crtc_to_kmb_priv(crtc);  	clk_prepare_enable(kmb->kmb_clk.clk_lcd); -	kmb_crtc_set_mode(crtc); +	kmb_crtc_set_mode(crtc, state);  	drm_crtc_vblank_on(crtc);  } @@ -185,11 +186,45 @@ static void kmb_crtc_atomic_flush(struct drm_crtc *crtc,  	spin_unlock_irq(&crtc->dev->event_lock);  } +static enum drm_mode_status +		kmb_crtc_mode_valid(struct drm_crtc *crtc, +				    const struct drm_display_mode *mode) +{ +	int refresh; +	struct drm_device *dev = crtc->dev; +	int vfp = mode->vsync_start - mode->vdisplay; + +	if (mode->vdisplay < KMB_CRTC_MAX_HEIGHT) { +		drm_dbg(dev, "height = %d less than %d", +			mode->vdisplay, KMB_CRTC_MAX_HEIGHT); +		return MODE_BAD_VVALUE; +	} +	if (mode->hdisplay < KMB_CRTC_MAX_WIDTH) { +		drm_dbg(dev, "width = %d less than %d", +			mode->hdisplay, KMB_CRTC_MAX_WIDTH); +		return MODE_BAD_HVALUE; +	} +	refresh = drm_mode_vrefresh(mode); +	if (refresh < KMB_MIN_VREFRESH || refresh > KMB_MAX_VREFRESH) { +		drm_dbg(dev, "refresh = %d less than %d or greater than %d", +			refresh, KMB_MIN_VREFRESH, KMB_MAX_VREFRESH); +		return MODE_BAD; +	} + +	if (vfp < KMB_CRTC_MIN_VFP) { +		drm_dbg(dev, "vfp = %d less than %d", vfp, KMB_CRTC_MIN_VFP); +		return MODE_BAD; +	} + +	return MODE_OK; +} +  static const struct drm_crtc_helper_funcs kmb_crtc_helper_funcs = {  	.atomic_begin = kmb_crtc_atomic_begin,  	.atomic_enable = kmb_crtc_atomic_enable,  	.atomic_disable = kmb_crtc_atomic_disable,  	.atomic_flush = kmb_crtc_atomic_flush, +	.mode_valid = kmb_crtc_mode_valid,  };  int kmb_setup_crtc(struct drm_device *drm) diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 12ce669650cc..961ac6fb5fcf 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -380,7 +380,7 @@ static irqreturn_t handle_lcd_irq(struct drm_device *dev)  		if (val & LAYER3_DMA_FIFO_UNDERFLOW)  			drm_dbg(&kmb->drm,  				"LAYER3:GL1 DMA UNDERFLOW val = 0x%lx", val); -		if (val & LAYER3_DMA_FIFO_UNDERFLOW) +		if (val & LAYER3_DMA_FIFO_OVERFLOW)  			drm_dbg(&kmb->drm,  				"LAYER3:GL1 DMA OVERFLOW val = 0x%lx", val);  	} diff --git a/drivers/gpu/drm/kmb/kmb_drv.h b/drivers/gpu/drm/kmb/kmb_drv.h index 69a62e2d03ff..bf085e95b28f 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.h +++ b/drivers/gpu/drm/kmb/kmb_drv.h @@ -20,11 +20,18 @@  #define DRIVER_MAJOR			1  #define DRIVER_MINOR			1 +/* Platform definitions */ +#define KMB_CRTC_MIN_VFP		4 +#define KMB_CRTC_MAX_WIDTH		1920 /* max width in pixels */ +#define KMB_CRTC_MAX_HEIGHT		1080 /* max height in pixels */ +#define KMB_CRTC_MIN_WIDTH		1920 +#define KMB_CRTC_MIN_HEIGHT		1080  #define KMB_FB_MAX_WIDTH		1920  #define KMB_FB_MAX_HEIGHT		1080  #define KMB_FB_MIN_WIDTH		1  #define KMB_FB_MIN_HEIGHT		1 - +#define KMB_MIN_VREFRESH		59    /*vertical refresh in Hz */ +#define KMB_MAX_VREFRESH		60    /*vertical refresh in Hz */  #define KMB_LCD_DEFAULT_CLK		200000000  #define KMB_SYS_CLK_MHZ			500 @@ -50,6 +57,7 @@ struct kmb_drm_private {  	spinlock_t			irq_lock;  	int				irq_lcd;  	int				sys_clk_mhz; +	struct disp_cfg			init_disp_cfg[KMB_MAX_PLANES];  	struct layer_status		plane_status[KMB_MAX_PLANES];  	int				kmb_under_flow;  	int				kmb_flush_done; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c index 1793cd31b117..f6071882054c 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.c +++ b/drivers/gpu/drm/kmb/kmb_dsi.c @@ -482,6 +482,10 @@ static u32 mipi_tx_fg_section_cfg(struct kmb_dsi *kmb_dsi,  	return 0;  } +#define CLK_DIFF_LOW 50 +#define CLK_DIFF_HI 60 +#define SYSCLK_500  500 +  static void mipi_tx_fg_cfg_regs(struct kmb_dsi *kmb_dsi, u8 frame_gen,  				struct mipi_tx_frame_timing_cfg *fg_cfg)  { @@ -492,7 +496,12 @@ static void mipi_tx_fg_cfg_regs(struct kmb_dsi *kmb_dsi, u8 frame_gen,  	/* 500 Mhz system clock minus 50 to account for the difference in  	 * MIPI clock speed in RTL tests  	 */ -	sysclk = kmb_dsi->sys_clk_mhz - 50; +	if (kmb_dsi->sys_clk_mhz == SYSCLK_500) { +		sysclk = kmb_dsi->sys_clk_mhz - CLK_DIFF_LOW; +	} else { +		/* 700 Mhz clk*/ +		sysclk = kmb_dsi->sys_clk_mhz - CLK_DIFF_HI; +	}  	/* PPL-Pixel Packing Layer, LLP-Low Level Protocol  	 * Frame genartor timing parameters are clocked on the system clock, @@ -1322,7 +1331,8 @@ static u32 mipi_tx_init_dphy(struct kmb_dsi *kmb_dsi,  	return 0;  } -static void connect_lcd_to_mipi(struct kmb_dsi *kmb_dsi) +static void connect_lcd_to_mipi(struct kmb_dsi *kmb_dsi, +				struct drm_atomic_state *old_state)  {  	struct regmap *msscam; @@ -1331,7 +1341,7 @@ static void connect_lcd_to_mipi(struct kmb_dsi *kmb_dsi)  		dev_dbg(kmb_dsi->dev, "failed to get msscam syscon");  		return;  	} - +	drm_atomic_bridge_chain_enable(adv_bridge, old_state);  	/* DISABLE MIPI->CIF CONNECTION */  	regmap_write(msscam, MSS_MIPI_CIF_CFG, 0); @@ -1342,7 +1352,7 @@ static void connect_lcd_to_mipi(struct kmb_dsi *kmb_dsi)  }  int kmb_dsi_mode_set(struct kmb_dsi *kmb_dsi, struct drm_display_mode *mode, -		     int sys_clk_mhz) +		     int sys_clk_mhz, struct drm_atomic_state *old_state)  {  	u64 data_rate; @@ -1384,18 +1394,13 @@ int kmb_dsi_mode_set(struct kmb_dsi *kmb_dsi, struct drm_display_mode *mode,  		mipi_tx_init_cfg.lane_rate_mbps = data_rate;  	} -	kmb_write_mipi(kmb_dsi, DPHY_ENABLE, 0); -	kmb_write_mipi(kmb_dsi, DPHY_INIT_CTRL0, 0); -	kmb_write_mipi(kmb_dsi, DPHY_INIT_CTRL1, 0); -	kmb_write_mipi(kmb_dsi, DPHY_INIT_CTRL2, 0); -  	/* Initialize mipi controller */  	mipi_tx_init_cntrl(kmb_dsi, &mipi_tx_init_cfg);  	/* Dphy initialization */  	mipi_tx_init_dphy(kmb_dsi, &mipi_tx_init_cfg); -	connect_lcd_to_mipi(kmb_dsi); +	connect_lcd_to_mipi(kmb_dsi, old_state);  	dev_info(kmb_dsi->dev, "mipi hw initialized");  	return 0; diff --git a/drivers/gpu/drm/kmb/kmb_dsi.h b/drivers/gpu/drm/kmb/kmb_dsi.h index 66b7c500d9bc..09dc88743d77 100644 --- a/drivers/gpu/drm/kmb/kmb_dsi.h +++ b/drivers/gpu/drm/kmb/kmb_dsi.h @@ -380,7 +380,7 @@ int kmb_dsi_host_bridge_init(struct device *dev);  struct kmb_dsi *kmb_dsi_init(struct platform_device *pdev);  void kmb_dsi_host_unregister(struct kmb_dsi *kmb_dsi);  int kmb_dsi_mode_set(struct kmb_dsi *kmb_dsi, struct drm_display_mode *mode, -		     int sys_clk_mhz); +		     int sys_clk_mhz, struct drm_atomic_state *old_state);  int kmb_dsi_map_mmio(struct kmb_dsi *kmb_dsi);  int kmb_dsi_clk_init(struct kmb_dsi *kmb_dsi);  int kmb_dsi_encoder_init(struct drm_device *dev, struct kmb_dsi *kmb_dsi); diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 06b0c42c9e91..00404ba4126d 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -67,8 +67,21 @@ static const u32 kmb_formats_v[] = {  static unsigned int check_pixel_format(struct drm_plane *plane, u32 format)  { +	struct kmb_drm_private *kmb; +	struct kmb_plane *kmb_plane = to_kmb_plane(plane);  	int i; +	int plane_id = kmb_plane->id; +	struct disp_cfg init_disp_cfg; +	kmb = to_kmb(plane->dev); +	init_disp_cfg = kmb->init_disp_cfg[plane_id]; +	/* Due to HW limitations, changing pixel format after initial +	 * plane configuration is not supported. +	 */ +	if (init_disp_cfg.format && init_disp_cfg.format != format) { +		drm_dbg(&kmb->drm, "Cannot change format after initial plane configuration"); +		return -EINVAL; +	}  	for (i = 0; i < plane->format_count; i++) {  		if (plane->format_types[i] == format)  			return 0; @@ -81,11 +94,17 @@ static int kmb_plane_atomic_check(struct drm_plane *plane,  {  	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,  										 plane); +	struct kmb_drm_private *kmb; +	struct kmb_plane *kmb_plane = to_kmb_plane(plane); +	int plane_id = kmb_plane->id; +	struct disp_cfg init_disp_cfg;  	struct drm_framebuffer *fb;  	int ret;  	struct drm_crtc_state *crtc_state;  	bool can_position; +	kmb = to_kmb(plane->dev); +	init_disp_cfg = kmb->init_disp_cfg[plane_id];  	fb = new_plane_state->fb;  	if (!fb || !new_plane_state->crtc)  		return 0; @@ -99,6 +118,16 @@ static int kmb_plane_atomic_check(struct drm_plane *plane,  	    new_plane_state->crtc_w < KMB_FB_MIN_WIDTH ||  	    new_plane_state->crtc_h < KMB_FB_MIN_HEIGHT)  		return -EINVAL; + +	/* Due to HW limitations, changing plane height or width after +	 * initial plane configuration is not supported. +	 */ +	if ((init_disp_cfg.width && init_disp_cfg.height) && +	    (init_disp_cfg.width != fb->width || +	    init_disp_cfg.height != fb->height)) { +		drm_dbg(&kmb->drm, "Cannot change plane height or width after initial configuration"); +		return -EINVAL; +	}  	can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);  	crtc_state =  		drm_atomic_get_existing_crtc_state(state, @@ -335,6 +364,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  	unsigned char plane_id;  	int num_planes;  	static dma_addr_t addr[MAX_SUB_PLANES]; +	struct disp_cfg *init_disp_cfg;  	if (!plane || !new_plane_state || !old_plane_state)  		return; @@ -357,7 +387,8 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  	}  	spin_unlock_irq(&kmb->irq_lock); -	src_w = (new_plane_state->src_w >> 16); +	init_disp_cfg = &kmb->init_disp_cfg[plane_id]; +	src_w = new_plane_state->src_w >> 16;  	src_h = new_plane_state->src_h >> 16;  	crtc_x = new_plane_state->crtc_x;  	crtc_y = new_plane_state->crtc_y; @@ -500,6 +531,16 @@ static void kmb_plane_atomic_update(struct drm_plane *plane,  	/* Enable DMA */  	kmb_write_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id), dma_cfg); + +	/* Save initial display config */ +	if (!init_disp_cfg->width || +	    !init_disp_cfg->height || +	    !init_disp_cfg->format) { +		init_disp_cfg->width = width; +		init_disp_cfg->height = height; +		init_disp_cfg->format = fb->format->format; +	} +  	drm_dbg(&kmb->drm, "dma_cfg=0x%x LCD_DMA_CFG=0x%x\n", dma_cfg,  		kmb_read_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id))); diff --git a/drivers/gpu/drm/kmb/kmb_plane.h b/drivers/gpu/drm/kmb/kmb_plane.h index 6e8d22cf8819..b51144044fe8 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.h +++ b/drivers/gpu/drm/kmb/kmb_plane.h @@ -63,6 +63,12 @@ struct layer_status {  	u32 ctrl;  }; +struct disp_cfg { +	unsigned int width; +	unsigned int height; +	unsigned int format; +}; +  struct kmb_plane *kmb_plane_init(struct drm_device *drm);  void kmb_plane_destroy(struct drm_plane *plane);  #endif /* __KMB_PLANE_H__ */ |