1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Vincent Abriou <vincent.abriou@st.com>
4 *          Fabien Dessenne <fabien.dessenne@st.com>
5 *          for STMicroelectronics.
6 * License terms:  GNU General Public License (GPL), version 2
7 */
8#include <drm/drmP.h>
9
10#include "sti_cursor.h"
11#include "sti_layer.h"
12#include "sti_vtg.h"
13
14/* Registers */
15#define CUR_CTL             0x00
16#define CUR_VPO             0x0C
17#define CUR_PML             0x14
18#define CUR_PMP             0x18
19#define CUR_SIZE            0x1C
20#define CUR_CML             0x20
21#define CUR_AWS             0x28
22#define CUR_AWE             0x2C
23
24#define CUR_CTL_CLUT_UPDATE BIT(1)
25
26#define STI_CURS_MIN_SIZE   1
27#define STI_CURS_MAX_SIZE   128
28
29/*
30 * pixmap dma buffer stucture
31 *
32 * @paddr:  physical address
33 * @size:   buffer size
34 * @base:   virtual address
35 */
36struct dma_pixmap {
37	dma_addr_t paddr;
38	size_t size;
39	void *base;
40};
41
42/**
43 * STI Cursor structure
44 *
45 * @layer:      layer structure
46 * @width:      cursor width
47 * @height:     cursor height
48 * @clut:       color look up table
49 * @clut_paddr: color look up table physical address
50 * @pixmap:     pixmap dma buffer (clut8-format cursor)
51 */
52struct sti_cursor {
53	struct sti_layer layer;
54	unsigned int width;
55	unsigned int height;
56	unsigned short *clut;
57	dma_addr_t clut_paddr;
58	struct dma_pixmap pixmap;
59};
60
61static const uint32_t cursor_supported_formats[] = {
62	DRM_FORMAT_ARGB8888,
63};
64
65#define to_sti_cursor(x) container_of(x, struct sti_cursor, layer)
66
67static const uint32_t *sti_cursor_get_formats(struct sti_layer *layer)
68{
69	return cursor_supported_formats;
70}
71
72static unsigned int sti_cursor_get_nb_formats(struct sti_layer *layer)
73{
74	return ARRAY_SIZE(cursor_supported_formats);
75}
76
77static void sti_cursor_argb8888_to_clut8(struct sti_layer *layer)
78{
79	struct sti_cursor *cursor = to_sti_cursor(layer);
80	u32 *src = layer->vaddr;
81	u8  *dst = cursor->pixmap.base;
82	unsigned int i, j;
83	u32 a, r, g, b;
84
85	for (i = 0; i < cursor->height; i++) {
86		for (j = 0; j < cursor->width; j++) {
87			/* Pick the 2 higher bits of each component */
88			a = (*src >> 30) & 3;
89			r = (*src >> 22) & 3;
90			g = (*src >> 14) & 3;
91			b = (*src >> 6) & 3;
92			*dst = a << 6 | r << 4 | g << 2 | b;
93			src++;
94			dst++;
95		}
96	}
97}
98
99static int sti_cursor_prepare_layer(struct sti_layer *layer, bool first_prepare)
100{
101	struct sti_cursor *cursor = to_sti_cursor(layer);
102	struct drm_display_mode *mode = layer->mode;
103	u32 y, x;
104	u32 val;
105
106	DRM_DEBUG_DRIVER("\n");
107
108	dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
109
110	if (layer->src_w < STI_CURS_MIN_SIZE ||
111	    layer->src_h < STI_CURS_MIN_SIZE ||
112	    layer->src_w > STI_CURS_MAX_SIZE ||
113	    layer->src_h > STI_CURS_MAX_SIZE) {
114		DRM_ERROR("Invalid cursor size (%dx%d)\n",
115				layer->src_w, layer->src_h);
116		return -EINVAL;
117	}
118
119	/* If the cursor size has changed, re-allocated the pixmap */
120	if (!cursor->pixmap.base ||
121	    (cursor->width != layer->src_w) ||
122	    (cursor->height != layer->src_h)) {
123		cursor->width = layer->src_w;
124		cursor->height = layer->src_h;
125
126		if (cursor->pixmap.base)
127			dma_free_writecombine(layer->dev,
128					      cursor->pixmap.size,
129					      cursor->pixmap.base,
130					      cursor->pixmap.paddr);
131
132		cursor->pixmap.size = cursor->width * cursor->height;
133
134		cursor->pixmap.base = dma_alloc_writecombine(layer->dev,
135							cursor->pixmap.size,
136							&cursor->pixmap.paddr,
137							GFP_KERNEL | GFP_DMA);
138		if (!cursor->pixmap.base) {
139			DRM_ERROR("Failed to allocate memory for pixmap\n");
140			return -ENOMEM;
141		}
142	}
143
144	/* Convert ARGB8888 to CLUT8 */
145	sti_cursor_argb8888_to_clut8(layer);
146
147	/* AWS and AWE depend on the mode */
148	y = sti_vtg_get_line_number(*mode, 0);
149	x = sti_vtg_get_pixel_number(*mode, 0);
150	val = y << 16 | x;
151	writel(val, layer->regs + CUR_AWS);
152	y = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
153	x = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
154	val = y << 16 | x;
155	writel(val, layer->regs + CUR_AWE);
156
157	if (first_prepare) {
158		/* Set and fetch CLUT */
159		writel(cursor->clut_paddr, layer->regs + CUR_CML);
160		writel(CUR_CTL_CLUT_UPDATE, layer->regs + CUR_CTL);
161	}
162
163	return 0;
164}
165
166static int sti_cursor_commit_layer(struct sti_layer *layer)
167{
168	struct sti_cursor *cursor = to_sti_cursor(layer);
169	struct drm_display_mode *mode = layer->mode;
170	u32 ydo, xdo;
171
172	dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
173
174	/* Set memory location, size, and position */
175	writel(cursor->pixmap.paddr, layer->regs + CUR_PML);
176	writel(cursor->width, layer->regs + CUR_PMP);
177	writel(cursor->height << 16 | cursor->width, layer->regs + CUR_SIZE);
178
179	ydo = sti_vtg_get_line_number(*mode, layer->dst_y);
180	xdo = sti_vtg_get_pixel_number(*mode, layer->dst_y);
181	writel((ydo << 16) | xdo, layer->regs + CUR_VPO);
182
183	return 0;
184}
185
186static int sti_cursor_disable_layer(struct sti_layer *layer)
187{
188	return 0;
189}
190
191static void sti_cursor_init(struct sti_layer *layer)
192{
193	struct sti_cursor *cursor = to_sti_cursor(layer);
194	unsigned short *base = cursor->clut;
195	unsigned int a, r, g, b;
196
197	/* Assign CLUT values, ARGB444 format */
198	for (a = 0; a < 4; a++)
199		for (r = 0; r < 4; r++)
200			for (g = 0; g < 4; g++)
201				for (b = 0; b < 4; b++)
202					*base++ = (a * 5) << 12 |
203						  (r * 5) << 8 |
204						  (g * 5) << 4 |
205						  (b * 5);
206}
207
208static const struct sti_layer_funcs cursor_ops = {
209	.get_formats = sti_cursor_get_formats,
210	.get_nb_formats = sti_cursor_get_nb_formats,
211	.init = sti_cursor_init,
212	.prepare = sti_cursor_prepare_layer,
213	.commit = sti_cursor_commit_layer,
214	.disable = sti_cursor_disable_layer,
215};
216
217struct sti_layer *sti_cursor_create(struct device *dev)
218{
219	struct sti_cursor *cursor;
220
221	cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
222	if (!cursor) {
223		DRM_ERROR("Failed to allocate memory for cursor\n");
224		return NULL;
225	}
226
227	/* Allocate clut buffer */
228	cursor->clut = dma_alloc_writecombine(dev,
229			0x100 * sizeof(unsigned short),
230			&cursor->clut_paddr,
231			GFP_KERNEL | GFP_DMA);
232
233	if (!cursor->clut) {
234		DRM_ERROR("Failed to allocate memory for cursor clut\n");
235		devm_kfree(dev, cursor);
236		return NULL;
237	}
238
239	cursor->layer.ops = &cursor_ops;
240
241	return (struct sti_layer *)cursor;
242}
243