diff options
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 21 | ||||
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_g2d.c | 370 | ||||
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_gem.c | 21 | ||||
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_gem.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_vidi.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_mixer.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 13 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 3 | 
11 files changed, 384 insertions, 73 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 36493ce71f9..98cc14725ba 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -38,11 +38,12 @@  /* position control register for hardware window 0, 2 ~ 4.*/  #define VIDOSD_A(win)		(VIDOSD_BASE + 0x00 + (win) * 16)  #define VIDOSD_B(win)		(VIDOSD_BASE + 0x04 + (win) * 16) -/* size control register for hardware window 0. */ -#define VIDOSD_C_SIZE_W0	(VIDOSD_BASE + 0x08) -/* alpha control register for hardware window 1 ~ 4. */ -#define VIDOSD_C(win)		(VIDOSD_BASE + 0x18 + (win) * 16) -/* size control register for hardware window 1 ~ 4. */ +/* + * size control register for hardware windows 0 and alpha control register + * for hardware windows 1 ~ 4 + */ +#define VIDOSD_C(win)		(VIDOSD_BASE + 0x08 + (win) * 16) +/* size control register for hardware windows 1 ~ 2. */  #define VIDOSD_D(win)		(VIDOSD_BASE + 0x0C + (win) * 16)  #define VIDWx_BUF_START(win, buf)	(VIDW_BUF_START(buf) + (win) * 8) @@ -50,9 +51,9 @@  #define VIDWx_BUF_SIZE(win, buf)	(VIDW_BUF_SIZE(buf) + (win) * 4)  /* color key control register for hardware window 1 ~ 4. */ -#define WKEYCON0_BASE(x)		((WKEYCON0 + 0x140) + (x * 8)) +#define WKEYCON0_BASE(x)		((WKEYCON0 + 0x140) + ((x - 1) * 8))  /* color key value register for hardware window 1 ~ 4. */ -#define WKEYCON1_BASE(x)		((WKEYCON1 + 0x140) + (x * 8)) +#define WKEYCON1_BASE(x)		((WKEYCON1 + 0x140) + ((x - 1) * 8))  /* FIMD has totally five hardware windows. */  #define WINDOWS_NR	5 @@ -109,9 +110,9 @@ struct fimd_context {  #ifdef CONFIG_OF  static const struct of_device_id fimd_driver_dt_match[] = { -	{ .compatible = "samsung,exynos4-fimd", +	{ .compatible = "samsung,exynos4210-fimd",  	  .data = &exynos4_fimd_driver_data }, -	{ .compatible = "samsung,exynos5-fimd", +	{ .compatible = "samsung,exynos5250-fimd",  	  .data = &exynos5_fimd_driver_data },  	{},  }; @@ -581,7 +582,7 @@ static void fimd_win_commit(struct device *dev, int zpos)  	if (win != 3 && win != 4) {  		u32 offset = VIDOSD_D(win);  		if (win == 0) -			offset = VIDOSD_C_SIZE_W0; +			offset = VIDOSD_C(win);  		val = win_data->ovl_width * win_data->ovl_height;  		writel(val, ctx->regs + offset); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 3b0da0378ac..47a493c8a71 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -48,8 +48,14 @@  /* registers for base address */  #define G2D_SRC_BASE_ADDR		0x0304 +#define G2D_SRC_COLOR_MODE		0x030C +#define G2D_SRC_LEFT_TOP		0x0310 +#define G2D_SRC_RIGHT_BOTTOM		0x0314  #define G2D_SRC_PLANE2_BASE_ADDR	0x0318  #define G2D_DST_BASE_ADDR		0x0404 +#define G2D_DST_COLOR_MODE		0x040C +#define G2D_DST_LEFT_TOP		0x0410 +#define G2D_DST_RIGHT_BOTTOM		0x0414  #define G2D_DST_PLANE2_BASE_ADDR	0x0418  #define G2D_PAT_BASE_ADDR		0x0500  #define G2D_MSK_BASE_ADDR		0x0520 @@ -82,7 +88,7 @@  #define G2D_DMA_LIST_DONE_COUNT_OFFSET	17  /* G2D_DMA_HOLD_CMD */ -#define G2D_USET_HOLD			(1 << 2) +#define G2D_USER_HOLD			(1 << 2)  #define G2D_LIST_HOLD			(1 << 1)  #define G2D_BITBLT_HOLD			(1 << 0) @@ -91,13 +97,27 @@  #define G2D_START_NHOLT			(1 << 1)  #define G2D_START_BITBLT		(1 << 0) +/* buffer color format */ +#define G2D_FMT_XRGB8888		0 +#define G2D_FMT_ARGB8888		1 +#define G2D_FMT_RGB565			2 +#define G2D_FMT_XRGB1555		3 +#define G2D_FMT_ARGB1555		4 +#define G2D_FMT_XRGB4444		5 +#define G2D_FMT_ARGB4444		6 +#define G2D_FMT_PACKED_RGB888		7 +#define G2D_FMT_A8			11 +#define G2D_FMT_L8			12 + +/* buffer valid length */ +#define G2D_LEN_MIN			1 +#define G2D_LEN_MAX			8000 +  #define G2D_CMDLIST_SIZE		(PAGE_SIZE / 4)  #define G2D_CMDLIST_NUM			64  #define G2D_CMDLIST_POOL_SIZE		(G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)  #define G2D_CMDLIST_DATA_NUM		(G2D_CMDLIST_SIZE / sizeof(u32) - 2) -#define MAX_BUF_ADDR_NR			6 -  /* maximum buffer pool size of userptr is 64MB as default */  #define MAX_POOL		(64 * 1024 * 1024) @@ -106,6 +126,17 @@ enum {  	BUF_TYPE_USERPTR,  }; +enum g2d_reg_type { +	REG_TYPE_NONE = -1, +	REG_TYPE_SRC, +	REG_TYPE_SRC_PLANE2, +	REG_TYPE_DST, +	REG_TYPE_DST_PLANE2, +	REG_TYPE_PAT, +	REG_TYPE_MSK, +	MAX_REG_TYPE_NR +}; +  /* cmdlist data structure */  struct g2d_cmdlist {  	u32		head; @@ -113,6 +144,42 @@ struct g2d_cmdlist {  	u32		last;	/* last data offset */  }; +/* + * A structure of buffer description + * + * @format: color format + * @left_x: the x coordinates of left top corner + * @top_y: the y coordinates of left top corner + * @right_x: the x coordinates of right bottom corner + * @bottom_y: the y coordinates of right bottom corner + * + */ +struct g2d_buf_desc { +	unsigned int	format; +	unsigned int	left_x; +	unsigned int	top_y; +	unsigned int	right_x; +	unsigned int	bottom_y; +}; + +/* + * A structure of buffer information + * + * @map_nr: manages the number of mapped buffers + * @reg_types: stores regitster type in the order of requested command + * @handles: stores buffer handle in its reg_type position + * @types: stores buffer type in its reg_type position + * @descs: stores buffer description in its reg_type position + * + */ +struct g2d_buf_info { +	unsigned int		map_nr; +	enum g2d_reg_type	reg_types[MAX_REG_TYPE_NR]; +	unsigned long		handles[MAX_REG_TYPE_NR]; +	unsigned int		types[MAX_REG_TYPE_NR]; +	struct g2d_buf_desc	descs[MAX_REG_TYPE_NR]; +}; +  struct drm_exynos_pending_g2d_event {  	struct drm_pending_event	base;  	struct drm_exynos_g2d_event	event; @@ -131,14 +198,11 @@ struct g2d_cmdlist_userptr {  	bool			in_pool;  	bool			out_of_list;  }; -  struct g2d_cmdlist_node {  	struct list_head	list;  	struct g2d_cmdlist	*cmdlist; -	unsigned int		map_nr; -	unsigned long		handles[MAX_BUF_ADDR_NR]; -	unsigned int		obj_type[MAX_BUF_ADDR_NR];  	dma_addr_t		dma_addr; +	struct g2d_buf_info	buf_info;  	struct drm_exynos_pending_g2d_event	*event;  }; @@ -188,6 +252,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)  	struct exynos_drm_subdrv *subdrv = &g2d->subdrv;  	int nr;  	int ret; +	struct g2d_buf_info *buf_info;  	init_dma_attrs(&g2d->cmdlist_dma_attrs);  	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs); @@ -209,11 +274,17 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)  	}  	for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) { +		unsigned int i; +  		node[nr].cmdlist =  			g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE;  		node[nr].dma_addr =  			g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE; +		buf_info = &node[nr].buf_info; +		for (i = 0; i < MAX_REG_TYPE_NR; i++) +			buf_info->reg_types[i] = REG_TYPE_NONE; +  		list_add_tail(&node[nr].list, &g2d->free_cmdlist);  	} @@ -450,7 +521,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,  						DMA_BIDIRECTIONAL);  	if (ret < 0) {  		DRM_ERROR("failed to map sgt with dma region.\n"); -		goto err_free_sgt; +		goto err_sg_free_table;  	}  	g2d_userptr->dma_addr = sgt->sgl[0].dma_address; @@ -467,8 +538,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,  	return &g2d_userptr->dma_addr; -err_free_sgt: +err_sg_free_table:  	sg_free_table(sgt); + +err_free_sgt:  	kfree(sgt);  	sgt = NULL; @@ -506,36 +579,172 @@ static void g2d_userptr_free_all(struct drm_device *drm_dev,  	g2d->current_pool = 0;  } +static enum g2d_reg_type g2d_get_reg_type(int reg_offset) +{ +	enum g2d_reg_type reg_type; + +	switch (reg_offset) { +	case G2D_SRC_BASE_ADDR: +	case G2D_SRC_COLOR_MODE: +	case G2D_SRC_LEFT_TOP: +	case G2D_SRC_RIGHT_BOTTOM: +		reg_type = REG_TYPE_SRC; +		break; +	case G2D_SRC_PLANE2_BASE_ADDR: +		reg_type = REG_TYPE_SRC_PLANE2; +		break; +	case G2D_DST_BASE_ADDR: +	case G2D_DST_COLOR_MODE: +	case G2D_DST_LEFT_TOP: +	case G2D_DST_RIGHT_BOTTOM: +		reg_type = REG_TYPE_DST; +		break; +	case G2D_DST_PLANE2_BASE_ADDR: +		reg_type = REG_TYPE_DST_PLANE2; +		break; +	case G2D_PAT_BASE_ADDR: +		reg_type = REG_TYPE_PAT; +		break; +	case G2D_MSK_BASE_ADDR: +		reg_type = REG_TYPE_MSK; +		break; +	default: +		reg_type = REG_TYPE_NONE; +		DRM_ERROR("Unknown register offset![%d]\n", reg_offset); +		break; +	}; + +	return reg_type; +} + +static unsigned long g2d_get_buf_bpp(unsigned int format) +{ +	unsigned long bpp; + +	switch (format) { +	case G2D_FMT_XRGB8888: +	case G2D_FMT_ARGB8888: +		bpp = 4; +		break; +	case G2D_FMT_RGB565: +	case G2D_FMT_XRGB1555: +	case G2D_FMT_ARGB1555: +	case G2D_FMT_XRGB4444: +	case G2D_FMT_ARGB4444: +		bpp = 2; +		break; +	case G2D_FMT_PACKED_RGB888: +		bpp = 3; +		break; +	default: +		bpp = 1; +		break; +	} + +	return bpp; +} + +static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc, +						enum g2d_reg_type reg_type, +						unsigned long size) +{ +	unsigned int width, height; +	unsigned long area; + +	/* +	 * check source and destination buffers only. +	 * so the others are always valid. +	 */ +	if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST) +		return true; + +	width = buf_desc->right_x - buf_desc->left_x; +	if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) { +		DRM_ERROR("width[%u] is out of range!\n", width); +		return false; +	} + +	height = buf_desc->bottom_y - buf_desc->top_y; +	if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) { +		DRM_ERROR("height[%u] is out of range!\n", height); +		return false; +	} + +	area = (unsigned long)width * (unsigned long)height * +					g2d_get_buf_bpp(buf_desc->format); +	if (area > size) { +		DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size); +		return false; +	} + +	return true; +} +  static int g2d_map_cmdlist_gem(struct g2d_data *g2d,  				struct g2d_cmdlist_node *node,  				struct drm_device *drm_dev,  				struct drm_file *file)  {  	struct g2d_cmdlist *cmdlist = node->cmdlist; +	struct g2d_buf_info *buf_info = &node->buf_info;  	int offset; +	int ret;  	int i; -	for (i = 0; i < node->map_nr; i++) { +	for (i = 0; i < buf_info->map_nr; i++) { +		struct g2d_buf_desc *buf_desc; +		enum g2d_reg_type reg_type; +		int reg_pos;  		unsigned long handle;  		dma_addr_t *addr; -		offset = cmdlist->last - (i * 2 + 1); -		handle = cmdlist->data[offset]; +		reg_pos = cmdlist->last - 2 * (i + 1); + +		offset = cmdlist->data[reg_pos]; +		handle = cmdlist->data[reg_pos + 1]; + +		reg_type = g2d_get_reg_type(offset); +		if (reg_type == REG_TYPE_NONE) { +			ret = -EFAULT; +			goto err; +		} + +		buf_desc = &buf_info->descs[reg_type]; + +		if (buf_info->types[reg_type] == BUF_TYPE_GEM) { +			unsigned long size; + +			size = exynos_drm_gem_get_size(drm_dev, handle, file); +			if (!size) { +				ret = -EFAULT; +				goto err; +			} + +			if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, +									size)) { +				ret = -EFAULT; +				goto err; +			} -		if (node->obj_type[i] == BUF_TYPE_GEM) {  			addr = exynos_drm_gem_get_dma_addr(drm_dev, handle,  								file);  			if (IS_ERR(addr)) { -				node->map_nr = i; -				return -EFAULT; +				ret = -EFAULT; +				goto err;  			}  		} else {  			struct drm_exynos_g2d_userptr g2d_userptr;  			if (copy_from_user(&g2d_userptr, (void __user *)handle,  				sizeof(struct drm_exynos_g2d_userptr))) { -				node->map_nr = i; -				return -EFAULT; +				ret = -EFAULT; +				goto err; +			} + +			if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, +							g2d_userptr.size)) { +				ret = -EFAULT; +				goto err;  			}  			addr = g2d_userptr_get_dma_addr(drm_dev, @@ -544,16 +753,21 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,  							file,  							&handle);  			if (IS_ERR(addr)) { -				node->map_nr = i; -				return -EFAULT; +				ret = -EFAULT; +				goto err;  			}  		} -		cmdlist->data[offset] = *addr; -		node->handles[i] = handle; +		cmdlist->data[reg_pos + 1] = *addr; +		buf_info->reg_types[i] = reg_type; +		buf_info->handles[reg_type] = handle;  	}  	return 0; + +err: +	buf_info->map_nr = i; +	return ret;  }  static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, @@ -561,22 +775,33 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,  				  struct drm_file *filp)  {  	struct exynos_drm_subdrv *subdrv = &g2d->subdrv; +	struct g2d_buf_info *buf_info = &node->buf_info;  	int i; -	for (i = 0; i < node->map_nr; i++) { -		unsigned long handle = node->handles[i]; +	for (i = 0; i < buf_info->map_nr; i++) { +		struct g2d_buf_desc *buf_desc; +		enum g2d_reg_type reg_type; +		unsigned long handle; -		if (node->obj_type[i] == BUF_TYPE_GEM) +		reg_type = buf_info->reg_types[i]; + +		buf_desc = &buf_info->descs[reg_type]; +		handle = buf_info->handles[reg_type]; + +		if (buf_info->types[reg_type] == BUF_TYPE_GEM)  			exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle,  							filp);  		else  			g2d_userptr_put_dma_addr(subdrv->drm_dev, handle,  							false); -		node->handles[i] = 0; +		buf_info->reg_types[i] = REG_TYPE_NONE; +		buf_info->handles[reg_type] = 0; +		buf_info->types[reg_type] = 0; +		memset(buf_desc, 0x00, sizeof(*buf_desc));  	} -	node->map_nr = 0; +	buf_info->map_nr = 0;  }  static void g2d_dma_start(struct g2d_data *g2d, @@ -589,10 +814,6 @@ static void g2d_dma_start(struct g2d_data *g2d,  	pm_runtime_get_sync(g2d->dev);  	clk_enable(g2d->gate_clk); -	/* interrupt enable */ -	writel_relaxed(G2D_INTEN_ACF | G2D_INTEN_UCF | G2D_INTEN_GCF, -			g2d->regs + G2D_INTEN); -  	writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);  	writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);  } @@ -643,7 +864,6 @@ static void g2d_runqueue_worker(struct work_struct *work)  	struct g2d_data *g2d = container_of(work, struct g2d_data,  					    runqueue_work); -  	mutex_lock(&g2d->runqueue_mutex);  	clk_disable(g2d->gate_clk);  	pm_runtime_put_sync(g2d->dev); @@ -724,20 +944,14 @@ static int g2d_check_reg_offset(struct device *dev,  	int i;  	for (i = 0; i < nr; i++) { -		index = cmdlist->last - 2 * (i + 1); +		struct g2d_buf_info *buf_info = &node->buf_info; +		struct g2d_buf_desc *buf_desc; +		enum g2d_reg_type reg_type; +		unsigned long value; -		if (for_addr) { -			/* check userptr buffer type. */ -			reg_offset = (cmdlist->data[index] & -					~0x7fffffff) >> 31; -			if (reg_offset) { -				node->obj_type[i] = BUF_TYPE_USERPTR; -				cmdlist->data[index] &= ~G2D_BUF_USERPTR; -			} -		} +		index = cmdlist->last - 2 * (i + 1);  		reg_offset = cmdlist->data[index] & ~0xfffff000; -  		if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END)  			goto err;  		if (reg_offset % 4) @@ -753,8 +967,60 @@ static int g2d_check_reg_offset(struct device *dev,  			if (!for_addr)  				goto err; -			if (node->obj_type[i] != BUF_TYPE_USERPTR) -				node->obj_type[i] = BUF_TYPE_GEM; +			reg_type = g2d_get_reg_type(reg_offset); +			if (reg_type == REG_TYPE_NONE) +				goto err; + +			/* check userptr buffer type. */ +			if ((cmdlist->data[index] & ~0x7fffffff) >> 31) { +				buf_info->types[reg_type] = BUF_TYPE_USERPTR; +				cmdlist->data[index] &= ~G2D_BUF_USERPTR; +			} else +				buf_info->types[reg_type] = BUF_TYPE_GEM; +			break; +		case G2D_SRC_COLOR_MODE: +		case G2D_DST_COLOR_MODE: +			if (for_addr) +				goto err; + +			reg_type = g2d_get_reg_type(reg_offset); +			if (reg_type == REG_TYPE_NONE) +				goto err; + +			buf_desc = &buf_info->descs[reg_type]; +			value = cmdlist->data[index + 1]; + +			buf_desc->format = value & 0xf; +			break; +		case G2D_SRC_LEFT_TOP: +		case G2D_DST_LEFT_TOP: +			if (for_addr) +				goto err; + +			reg_type = g2d_get_reg_type(reg_offset); +			if (reg_type == REG_TYPE_NONE) +				goto err; + +			buf_desc = &buf_info->descs[reg_type]; +			value = cmdlist->data[index + 1]; + +			buf_desc->left_x = value & 0x1fff; +			buf_desc->top_y = (value & 0x1fff0000) >> 16; +			break; +		case G2D_SRC_RIGHT_BOTTOM: +		case G2D_DST_RIGHT_BOTTOM: +			if (for_addr) +				goto err; + +			reg_type = g2d_get_reg_type(reg_offset); +			if (reg_type == REG_TYPE_NONE) +				goto err; + +			buf_desc = &buf_info->descs[reg_type]; +			value = cmdlist->data[index + 1]; + +			buf_desc->right_x = value & 0x1fff; +			buf_desc->bottom_y = (value & 0x1fff0000) >> 16;  			break;  		default:  			if (for_addr) @@ -860,9 +1126,23 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  	cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR;  	cmdlist->data[cmdlist->last++] = 0; +	/* +	 * 'LIST_HOLD' command should be set to the DMA_HOLD_CMD_REG +	 * and GCF bit should be set to INTEN register if user wants +	 * G2D interrupt event once current command list execution is +	 * finished. +	 * Otherwise only ACF bit should be set to INTEN register so +	 * that one interrupt is occured after all command lists +	 * have been completed. +	 */  	if (node->event) { +		cmdlist->data[cmdlist->last++] = G2D_INTEN; +		cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF | G2D_INTEN_GCF;  		cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD;  		cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD; +	} else { +		cmdlist->data[cmdlist->last++] = G2D_INTEN; +		cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF;  	}  	/* Check size of cmdlist: last 2 is about G2D_BITBLT_START */ @@ -887,7 +1167,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,  	if (ret < 0)  		goto err_free_event; -	node->map_nr = req->cmd_buf_nr; +	node->buf_info.map_nr = req->cmd_buf_nr;  	if (req->cmd_buf_nr) {  		struct drm_exynos_g2d_cmd *cmd_buf; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 67e17ce112b..0e6fe000578 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -164,6 +164,27 @@ out:  	exynos_gem_obj = NULL;  } +unsigned long exynos_drm_gem_get_size(struct drm_device *dev, +						unsigned int gem_handle, +						struct drm_file *file_priv) +{ +	struct exynos_drm_gem_obj *exynos_gem_obj; +	struct drm_gem_object *obj; + +	obj = drm_gem_object_lookup(dev, file_priv, gem_handle); +	if (!obj) { +		DRM_ERROR("failed to lookup gem object.\n"); +		return 0; +	} + +	exynos_gem_obj = to_exynos_gem_obj(obj); + +	drm_gem_object_unreference_unlocked(obj); + +	return exynos_gem_obj->buffer->size; +} + +  struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,  						      unsigned long size)  { diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 35ebac47dc2..468766bee45 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -130,6 +130,11 @@ int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data,  int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,  				      struct drm_file *file_priv); +/* get buffer size to gem handle. */ +unsigned long exynos_drm_gem_get_size(struct drm_device *dev, +						unsigned int gem_handle, +						struct drm_file *file_priv); +  /* initialize gem object. */  int exynos_drm_gem_init_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 13ccbd4bcfa..9504b0cd825 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -117,13 +117,12 @@ static struct edid *vidi_get_edid(struct device *dev,  	}  	edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; -	edid = kzalloc(edid_len, GFP_KERNEL); +	edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);  	if (!edid) {  		DRM_DEBUG_KMS("failed to allocate edid\n");  		return ERR_PTR(-ENOMEM);  	} -	memcpy(edid, ctx->raw_edid, edid_len);  	return edid;  } @@ -563,12 +562,11 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,  			return -EINVAL;  		}  		edid_len = (1 + raw_edid->extensions) * EDID_LENGTH; -		ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL); +		ctx->raw_edid = kmemdup(raw_edid, edid_len, GFP_KERNEL);  		if (!ctx->raw_edid) {  			DRM_DEBUG_KMS("failed to allocate raw_edid.\n");  			return -ENOMEM;  		} -		memcpy(ctx->raw_edid, raw_edid, edid_len);  	} else {  		/*  		 * with connection = 0, free raw_edid diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e919aba29b3..2f4f72f0704 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -818,7 +818,7 @@ static void mixer_win_disable(void *ctx, int win)  	mixer_ctx->win_data[win].enabled = false;  } -int mixer_check_timing(void *ctx, struct fb_videomode *timing) +static int mixer_check_timing(void *ctx, struct fb_videomode *timing)  {  	struct mixer_context *mixer_ctx = ctx;  	u32 w, h; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0a8eceb7590..e9b57893db2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -125,6 +125,11 @@ MODULE_PARM_DESC(preliminary_hw_support,  		"Enable Haswell and ValleyView Support. "  		"(default: false)"); +int i915_disable_power_well __read_mostly = 0; +module_param_named(disable_power_well, i915_disable_power_well, int, 0600); +MODULE_PARM_DESC(disable_power_well, +		 "Disable the power well when possible (default: false)"); +  static struct drm_driver driver;  extern int intel_agp_enabled; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e95337c9745..01769e2a995 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1398,6 +1398,7 @@ extern int i915_enable_fbc __read_mostly;  extern bool i915_enable_hangcheck __read_mostly;  extern int i915_enable_ppgtt __read_mostly;  extern unsigned int i915_preliminary_hw_support __read_mostly; +extern int i915_disable_power_well __read_mostly;  extern int i915_suspend(struct drm_device *dev, pm_message_t state);  extern int i915_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 287b42c9d1a..b20d50192fc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5771,6 +5771,11 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,  		num_connectors++;  	} +	if (is_cpu_edp) +		intel_crtc->cpu_transcoder = TRANSCODER_EDP; +	else +		intel_crtc->cpu_transcoder = pipe; +  	/* We are not sure yet this won't happen. */  	WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n",  	     INTEL_PCH_TYPE(dev)); @@ -5837,11 +5842,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,  	int pipe = intel_crtc->pipe;  	int ret; -	if (IS_HASWELL(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) -		intel_crtc->cpu_transcoder = TRANSCODER_EDP; -	else -		intel_crtc->cpu_transcoder = pipe; -  	drm_vblank_pre_modeset(dev, pipe);  	ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a3730e0289e..bee8cb6108a 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -321,9 +321,6 @@ void intel_panel_enable_backlight(struct drm_device *dev,  	if (dev_priv->backlight_level == 0)  		dev_priv->backlight_level = intel_panel_get_max_backlight(dev); -	dev_priv->backlight_enabled = true; -	intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); -  	if (INTEL_INFO(dev)->gen >= 4) {  		uint32_t reg, tmp; @@ -359,12 +356,12 @@ void intel_panel_enable_backlight(struct drm_device *dev,  	}  set_level: -	/* Check the current backlight level and try to set again if it's zero. -	 * On some machines, BLC_PWM_CPU_CTL is cleared to zero automatically -	 * when BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1 are written. +	/* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. +	 * BLC_PWM_CPU_CTL may be cleared to zero automatically when these +	 * registers are set.  	 */ -	if (!intel_panel_get_backlight(dev)) -		intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); +	dev_priv->backlight_enabled = true; +	intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);  }  static void intel_panel_init_backlight(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a1794c6df1b..adca00783e6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4079,6 +4079,9 @@ void intel_set_power_well(struct drm_device *dev, bool enable)  	if (!IS_HASWELL(dev))  		return; +	if (!i915_disable_power_well && !enable) +		return; +  	tmp = I915_READ(HSW_PWR_WELL_DRIVER);  	is_enabled = tmp & HSW_PWR_WELL_STATE;  	enable_requested = tmp & HSW_PWR_WELL_ENABLE;  |