xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/sti/sti_cursor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) STMicroelectronics SA 2014
4*4882a593Smuzhiyun  * Authors: Vincent Abriou <vincent.abriou@st.com>
5*4882a593Smuzhiyun  *          Fabien Dessenne <fabien.dessenne@st.com>
6*4882a593Smuzhiyun  *          for STMicroelectronics.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/dma-mapping.h>
10*4882a593Smuzhiyun #include <linux/seq_file.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <drm/drm_atomic.h>
13*4882a593Smuzhiyun #include <drm/drm_device.h>
14*4882a593Smuzhiyun #include <drm/drm_fb_cma_helper.h>
15*4882a593Smuzhiyun #include <drm/drm_gem_cma_helper.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "sti_compositor.h"
18*4882a593Smuzhiyun #include "sti_cursor.h"
19*4882a593Smuzhiyun #include "sti_plane.h"
20*4882a593Smuzhiyun #include "sti_vtg.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /* Registers */
23*4882a593Smuzhiyun #define CUR_CTL             0x00
24*4882a593Smuzhiyun #define CUR_VPO             0x0C
25*4882a593Smuzhiyun #define CUR_PML             0x14
26*4882a593Smuzhiyun #define CUR_PMP             0x18
27*4882a593Smuzhiyun #define CUR_SIZE            0x1C
28*4882a593Smuzhiyun #define CUR_CML             0x20
29*4882a593Smuzhiyun #define CUR_AWS             0x28
30*4882a593Smuzhiyun #define CUR_AWE             0x2C
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define CUR_CTL_CLUT_UPDATE BIT(1)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define STI_CURS_MIN_SIZE   1
35*4882a593Smuzhiyun #define STI_CURS_MAX_SIZE   128
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun  * pixmap dma buffer structure
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * @paddr:  physical address
41*4882a593Smuzhiyun  * @size:   buffer size
42*4882a593Smuzhiyun  * @base:   virtual address
43*4882a593Smuzhiyun  */
44*4882a593Smuzhiyun struct dma_pixmap {
45*4882a593Smuzhiyun 	dma_addr_t paddr;
46*4882a593Smuzhiyun 	size_t size;
47*4882a593Smuzhiyun 	void *base;
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun  * STI Cursor structure
52*4882a593Smuzhiyun  *
53*4882a593Smuzhiyun  * @sti_plane:    sti_plane structure
54*4882a593Smuzhiyun  * @dev:          driver device
55*4882a593Smuzhiyun  * @regs:         cursor registers
56*4882a593Smuzhiyun  * @width:        cursor width
57*4882a593Smuzhiyun  * @height:       cursor height
58*4882a593Smuzhiyun  * @clut:         color look up table
59*4882a593Smuzhiyun  * @clut_paddr:   color look up table physical address
60*4882a593Smuzhiyun  * @pixmap:       pixmap dma buffer (clut8-format cursor)
61*4882a593Smuzhiyun  */
62*4882a593Smuzhiyun struct sti_cursor {
63*4882a593Smuzhiyun 	struct sti_plane plane;
64*4882a593Smuzhiyun 	struct device *dev;
65*4882a593Smuzhiyun 	void __iomem *regs;
66*4882a593Smuzhiyun 	unsigned int width;
67*4882a593Smuzhiyun 	unsigned int height;
68*4882a593Smuzhiyun 	unsigned short *clut;
69*4882a593Smuzhiyun 	dma_addr_t clut_paddr;
70*4882a593Smuzhiyun 	struct dma_pixmap pixmap;
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static const uint32_t cursor_supported_formats[] = {
74*4882a593Smuzhiyun 	DRM_FORMAT_ARGB8888,
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun #define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
80*4882a593Smuzhiyun 				   readl(cursor->regs + reg))
81*4882a593Smuzhiyun 
cursor_dbg_vpo(struct seq_file * s,u32 val)82*4882a593Smuzhiyun static void cursor_dbg_vpo(struct seq_file *s, u32 val)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
cursor_dbg_size(struct seq_file * s,u32 val)87*4882a593Smuzhiyun static void cursor_dbg_size(struct seq_file *s, u32 val)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	seq_printf(s, "\t%d x %d", val & 0x07FF, (val >> 16) & 0x07FF);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
cursor_dbg_pml(struct seq_file * s,struct sti_cursor * cursor,u32 val)92*4882a593Smuzhiyun static void cursor_dbg_pml(struct seq_file *s,
93*4882a593Smuzhiyun 			   struct sti_cursor *cursor, u32 val)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	if (cursor->pixmap.paddr == val)
96*4882a593Smuzhiyun 		seq_printf(s, "\tVirt @: %p", cursor->pixmap.base);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
cursor_dbg_cml(struct seq_file * s,struct sti_cursor * cursor,u32 val)99*4882a593Smuzhiyun static void cursor_dbg_cml(struct seq_file *s,
100*4882a593Smuzhiyun 			   struct sti_cursor *cursor, u32 val)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	if (cursor->clut_paddr == val)
103*4882a593Smuzhiyun 		seq_printf(s, "\tVirt @: %p", cursor->clut);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
cursor_dbg_show(struct seq_file * s,void * data)106*4882a593Smuzhiyun static int cursor_dbg_show(struct seq_file *s, void *data)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct drm_info_node *node = s->private;
109*4882a593Smuzhiyun 	struct sti_cursor *cursor = (struct sti_cursor *)node->info_ent->data;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	seq_printf(s, "%s: (vaddr = 0x%p)",
112*4882a593Smuzhiyun 		   sti_plane_to_str(&cursor->plane), cursor->regs);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	DBGFS_DUMP(CUR_CTL);
115*4882a593Smuzhiyun 	DBGFS_DUMP(CUR_VPO);
116*4882a593Smuzhiyun 	cursor_dbg_vpo(s, readl(cursor->regs + CUR_VPO));
117*4882a593Smuzhiyun 	DBGFS_DUMP(CUR_PML);
118*4882a593Smuzhiyun 	cursor_dbg_pml(s, cursor, readl(cursor->regs + CUR_PML));
119*4882a593Smuzhiyun 	DBGFS_DUMP(CUR_PMP);
120*4882a593Smuzhiyun 	DBGFS_DUMP(CUR_SIZE);
121*4882a593Smuzhiyun 	cursor_dbg_size(s, readl(cursor->regs + CUR_SIZE));
122*4882a593Smuzhiyun 	DBGFS_DUMP(CUR_CML);
123*4882a593Smuzhiyun 	cursor_dbg_cml(s, cursor, readl(cursor->regs + CUR_CML));
124*4882a593Smuzhiyun 	DBGFS_DUMP(CUR_AWS);
125*4882a593Smuzhiyun 	DBGFS_DUMP(CUR_AWE);
126*4882a593Smuzhiyun 	seq_putc(s, '\n');
127*4882a593Smuzhiyun 	return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun static struct drm_info_list cursor_debugfs_files[] = {
131*4882a593Smuzhiyun 	{ "cursor", cursor_dbg_show, 0, NULL },
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun 
cursor_debugfs_init(struct sti_cursor * cursor,struct drm_minor * minor)134*4882a593Smuzhiyun static void cursor_debugfs_init(struct sti_cursor *cursor,
135*4882a593Smuzhiyun 				struct drm_minor *minor)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	unsigned int i;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(cursor_debugfs_files); i++)
140*4882a593Smuzhiyun 		cursor_debugfs_files[i].data = cursor;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	drm_debugfs_create_files(cursor_debugfs_files,
143*4882a593Smuzhiyun 				 ARRAY_SIZE(cursor_debugfs_files),
144*4882a593Smuzhiyun 				 minor->debugfs_root, minor);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
sti_cursor_argb8888_to_clut8(struct sti_cursor * cursor,u32 * src)147*4882a593Smuzhiyun static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	u8  *dst = cursor->pixmap.base;
150*4882a593Smuzhiyun 	unsigned int i, j;
151*4882a593Smuzhiyun 	u32 a, r, g, b;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	for (i = 0; i < cursor->height; i++) {
154*4882a593Smuzhiyun 		for (j = 0; j < cursor->width; j++) {
155*4882a593Smuzhiyun 			/* Pick the 2 higher bits of each component */
156*4882a593Smuzhiyun 			a = (*src >> 30) & 3;
157*4882a593Smuzhiyun 			r = (*src >> 22) & 3;
158*4882a593Smuzhiyun 			g = (*src >> 14) & 3;
159*4882a593Smuzhiyun 			b = (*src >> 6) & 3;
160*4882a593Smuzhiyun 			*dst = a << 6 | r << 4 | g << 2 | b;
161*4882a593Smuzhiyun 			src++;
162*4882a593Smuzhiyun 			dst++;
163*4882a593Smuzhiyun 		}
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
sti_cursor_init(struct sti_cursor * cursor)167*4882a593Smuzhiyun static void sti_cursor_init(struct sti_cursor *cursor)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	unsigned short *base = cursor->clut;
170*4882a593Smuzhiyun 	unsigned int a, r, g, b;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	/* Assign CLUT values, ARGB444 format */
173*4882a593Smuzhiyun 	for (a = 0; a < 4; a++)
174*4882a593Smuzhiyun 		for (r = 0; r < 4; r++)
175*4882a593Smuzhiyun 			for (g = 0; g < 4; g++)
176*4882a593Smuzhiyun 				for (b = 0; b < 4; b++)
177*4882a593Smuzhiyun 					*base++ = (a * 5) << 12 |
178*4882a593Smuzhiyun 						  (r * 5) << 8 |
179*4882a593Smuzhiyun 						  (g * 5) << 4 |
180*4882a593Smuzhiyun 						  (b * 5);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
sti_cursor_atomic_check(struct drm_plane * drm_plane,struct drm_plane_state * state)183*4882a593Smuzhiyun static int sti_cursor_atomic_check(struct drm_plane *drm_plane,
184*4882a593Smuzhiyun 				   struct drm_plane_state *state)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	struct sti_plane *plane = to_sti_plane(drm_plane);
187*4882a593Smuzhiyun 	struct sti_cursor *cursor = to_sti_cursor(plane);
188*4882a593Smuzhiyun 	struct drm_crtc *crtc = state->crtc;
189*4882a593Smuzhiyun 	struct drm_framebuffer *fb = state->fb;
190*4882a593Smuzhiyun 	struct drm_crtc_state *crtc_state;
191*4882a593Smuzhiyun 	struct drm_display_mode *mode;
192*4882a593Smuzhiyun 	int dst_x, dst_y, dst_w, dst_h;
193*4882a593Smuzhiyun 	int src_w, src_h;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	/* no need for further checks if the plane is being disabled */
196*4882a593Smuzhiyun 	if (!crtc || !fb)
197*4882a593Smuzhiyun 		return 0;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
200*4882a593Smuzhiyun 	mode = &crtc_state->mode;
201*4882a593Smuzhiyun 	dst_x = state->crtc_x;
202*4882a593Smuzhiyun 	dst_y = state->crtc_y;
203*4882a593Smuzhiyun 	dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
204*4882a593Smuzhiyun 	dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
205*4882a593Smuzhiyun 	/* src_x are in 16.16 format */
206*4882a593Smuzhiyun 	src_w = state->src_w >> 16;
207*4882a593Smuzhiyun 	src_h = state->src_h >> 16;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if (src_w < STI_CURS_MIN_SIZE ||
210*4882a593Smuzhiyun 	    src_h < STI_CURS_MIN_SIZE ||
211*4882a593Smuzhiyun 	    src_w > STI_CURS_MAX_SIZE ||
212*4882a593Smuzhiyun 	    src_h > STI_CURS_MAX_SIZE) {
213*4882a593Smuzhiyun 		DRM_ERROR("Invalid cursor size (%dx%d)\n",
214*4882a593Smuzhiyun 				src_w, src_h);
215*4882a593Smuzhiyun 		return -EINVAL;
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	/* If the cursor size has changed, re-allocated the pixmap */
219*4882a593Smuzhiyun 	if (!cursor->pixmap.base ||
220*4882a593Smuzhiyun 	    (cursor->width != src_w) ||
221*4882a593Smuzhiyun 	    (cursor->height != src_h)) {
222*4882a593Smuzhiyun 		cursor->width = src_w;
223*4882a593Smuzhiyun 		cursor->height = src_h;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 		if (cursor->pixmap.base)
226*4882a593Smuzhiyun 			dma_free_wc(cursor->dev, cursor->pixmap.size,
227*4882a593Smuzhiyun 				    cursor->pixmap.base, cursor->pixmap.paddr);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		cursor->pixmap.size = cursor->width * cursor->height;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 		cursor->pixmap.base = dma_alloc_wc(cursor->dev,
232*4882a593Smuzhiyun 						   cursor->pixmap.size,
233*4882a593Smuzhiyun 						   &cursor->pixmap.paddr,
234*4882a593Smuzhiyun 						   GFP_KERNEL | GFP_DMA);
235*4882a593Smuzhiyun 		if (!cursor->pixmap.base) {
236*4882a593Smuzhiyun 			DRM_ERROR("Failed to allocate memory for pixmap\n");
237*4882a593Smuzhiyun 			return -EINVAL;
238*4882a593Smuzhiyun 		}
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if (!drm_fb_cma_get_gem_obj(fb, 0)) {
242*4882a593Smuzhiyun 		DRM_ERROR("Can't get CMA GEM object for fb\n");
243*4882a593Smuzhiyun 		return -EINVAL;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
247*4882a593Smuzhiyun 		      crtc->base.id, sti_mixer_to_str(to_sti_mixer(crtc)),
248*4882a593Smuzhiyun 		      drm_plane->base.id, sti_plane_to_str(plane));
249*4882a593Smuzhiyun 	DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	return 0;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
sti_cursor_atomic_update(struct drm_plane * drm_plane,struct drm_plane_state * oldstate)254*4882a593Smuzhiyun static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
255*4882a593Smuzhiyun 				     struct drm_plane_state *oldstate)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	struct drm_plane_state *state = drm_plane->state;
258*4882a593Smuzhiyun 	struct sti_plane *plane = to_sti_plane(drm_plane);
259*4882a593Smuzhiyun 	struct sti_cursor *cursor = to_sti_cursor(plane);
260*4882a593Smuzhiyun 	struct drm_crtc *crtc = state->crtc;
261*4882a593Smuzhiyun 	struct drm_framebuffer *fb = state->fb;
262*4882a593Smuzhiyun 	struct drm_display_mode *mode;
263*4882a593Smuzhiyun 	int dst_x, dst_y;
264*4882a593Smuzhiyun 	struct drm_gem_cma_object *cma_obj;
265*4882a593Smuzhiyun 	u32 y, x;
266*4882a593Smuzhiyun 	u32 val;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	if (!crtc || !fb)
269*4882a593Smuzhiyun 		return;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	mode = &crtc->mode;
272*4882a593Smuzhiyun 	dst_x = state->crtc_x;
273*4882a593Smuzhiyun 	dst_y = state->crtc_y;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	/* Convert ARGB8888 to CLUT8 */
278*4882a593Smuzhiyun 	sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/* AWS and AWE depend on the mode */
281*4882a593Smuzhiyun 	y = sti_vtg_get_line_number(*mode, 0);
282*4882a593Smuzhiyun 	x = sti_vtg_get_pixel_number(*mode, 0);
283*4882a593Smuzhiyun 	val = y << 16 | x;
284*4882a593Smuzhiyun 	writel(val, cursor->regs + CUR_AWS);
285*4882a593Smuzhiyun 	y = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
286*4882a593Smuzhiyun 	x = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
287*4882a593Smuzhiyun 	val = y << 16 | x;
288*4882a593Smuzhiyun 	writel(val, cursor->regs + CUR_AWE);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	/* Set memory location, size, and position */
291*4882a593Smuzhiyun 	writel(cursor->pixmap.paddr, cursor->regs + CUR_PML);
292*4882a593Smuzhiyun 	writel(cursor->width, cursor->regs + CUR_PMP);
293*4882a593Smuzhiyun 	writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	y = sti_vtg_get_line_number(*mode, dst_y);
296*4882a593Smuzhiyun 	x = sti_vtg_get_pixel_number(*mode, dst_x);
297*4882a593Smuzhiyun 	writel((y << 16) | x, cursor->regs + CUR_VPO);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	/* Set and fetch CLUT */
300*4882a593Smuzhiyun 	writel(cursor->clut_paddr, cursor->regs + CUR_CML);
301*4882a593Smuzhiyun 	writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	sti_plane_update_fps(plane, true, false);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	plane->status = STI_PLANE_UPDATED;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
sti_cursor_atomic_disable(struct drm_plane * drm_plane,struct drm_plane_state * oldstate)308*4882a593Smuzhiyun static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
309*4882a593Smuzhiyun 				      struct drm_plane_state *oldstate)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	struct sti_plane *plane = to_sti_plane(drm_plane);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	if (!oldstate->crtc) {
314*4882a593Smuzhiyun 		DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
315*4882a593Smuzhiyun 				 drm_plane->base.id);
316*4882a593Smuzhiyun 		return;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
320*4882a593Smuzhiyun 			 oldstate->crtc->base.id,
321*4882a593Smuzhiyun 			 sti_mixer_to_str(to_sti_mixer(oldstate->crtc)),
322*4882a593Smuzhiyun 			 drm_plane->base.id, sti_plane_to_str(plane));
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	plane->status = STI_PLANE_DISABLING;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
328*4882a593Smuzhiyun 	.atomic_check = sti_cursor_atomic_check,
329*4882a593Smuzhiyun 	.atomic_update = sti_cursor_atomic_update,
330*4882a593Smuzhiyun 	.atomic_disable = sti_cursor_atomic_disable,
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun 
sti_cursor_destroy(struct drm_plane * drm_plane)333*4882a593Smuzhiyun static void sti_cursor_destroy(struct drm_plane *drm_plane)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun 	DRM_DEBUG_DRIVER("\n");
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	drm_plane_cleanup(drm_plane);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
sti_cursor_late_register(struct drm_plane * drm_plane)340*4882a593Smuzhiyun static int sti_cursor_late_register(struct drm_plane *drm_plane)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	struct sti_plane *plane = to_sti_plane(drm_plane);
343*4882a593Smuzhiyun 	struct sti_cursor *cursor = to_sti_cursor(plane);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	cursor_debugfs_init(cursor, drm_plane->dev->primary);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun static const struct drm_plane_funcs sti_cursor_plane_helpers_funcs = {
351*4882a593Smuzhiyun 	.update_plane = drm_atomic_helper_update_plane,
352*4882a593Smuzhiyun 	.disable_plane = drm_atomic_helper_disable_plane,
353*4882a593Smuzhiyun 	.destroy = sti_cursor_destroy,
354*4882a593Smuzhiyun 	.reset = sti_plane_reset,
355*4882a593Smuzhiyun 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
356*4882a593Smuzhiyun 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
357*4882a593Smuzhiyun 	.late_register = sti_cursor_late_register,
358*4882a593Smuzhiyun };
359*4882a593Smuzhiyun 
sti_cursor_create(struct drm_device * drm_dev,struct device * dev,int desc,void __iomem * baseaddr,unsigned int possible_crtcs)360*4882a593Smuzhiyun struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
361*4882a593Smuzhiyun 				    struct device *dev, int desc,
362*4882a593Smuzhiyun 				    void __iomem *baseaddr,
363*4882a593Smuzhiyun 				    unsigned int possible_crtcs)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	struct sti_cursor *cursor;
366*4882a593Smuzhiyun 	size_t size;
367*4882a593Smuzhiyun 	int res;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
370*4882a593Smuzhiyun 	if (!cursor) {
371*4882a593Smuzhiyun 		DRM_ERROR("Failed to allocate memory for cursor\n");
372*4882a593Smuzhiyun 		return NULL;
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	/* Allocate clut buffer */
376*4882a593Smuzhiyun 	size = 0x100 * sizeof(unsigned short);
377*4882a593Smuzhiyun 	cursor->clut = dma_alloc_wc(dev, size, &cursor->clut_paddr,
378*4882a593Smuzhiyun 				    GFP_KERNEL | GFP_DMA);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (!cursor->clut) {
381*4882a593Smuzhiyun 		DRM_ERROR("Failed to allocate memory for cursor clut\n");
382*4882a593Smuzhiyun 		goto err_clut;
383*4882a593Smuzhiyun 	}
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	cursor->dev = dev;
386*4882a593Smuzhiyun 	cursor->regs = baseaddr;
387*4882a593Smuzhiyun 	cursor->plane.desc = desc;
388*4882a593Smuzhiyun 	cursor->plane.status = STI_PLANE_DISABLED;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	sti_cursor_init(cursor);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane,
393*4882a593Smuzhiyun 				       possible_crtcs,
394*4882a593Smuzhiyun 				       &sti_cursor_plane_helpers_funcs,
395*4882a593Smuzhiyun 				       cursor_supported_formats,
396*4882a593Smuzhiyun 				       ARRAY_SIZE(cursor_supported_formats),
397*4882a593Smuzhiyun 				       NULL, DRM_PLANE_TYPE_CURSOR, NULL);
398*4882a593Smuzhiyun 	if (res) {
399*4882a593Smuzhiyun 		DRM_ERROR("Failed to initialize universal plane\n");
400*4882a593Smuzhiyun 		goto err_plane;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	drm_plane_helper_add(&cursor->plane.drm_plane,
404*4882a593Smuzhiyun 			     &sti_cursor_helpers_funcs);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	return &cursor->plane.drm_plane;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun err_plane:
411*4882a593Smuzhiyun 	dma_free_wc(dev, size, cursor->clut, cursor->clut_paddr);
412*4882a593Smuzhiyun err_clut:
413*4882a593Smuzhiyun 	devm_kfree(dev, cursor);
414*4882a593Smuzhiyun 	return NULL;
415*4882a593Smuzhiyun }
416