Commit | Line | Data |
---|---|---|
96006a77 BG |
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 | */ | |
36 | struct 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 | */ | |
52 | struct 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 | ||
61 | static 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 | ||
67 | static const uint32_t *sti_cursor_get_formats(struct sti_layer *layer) | |
68 | { | |
69 | return cursor_supported_formats; | |
70 | } | |
71 | ||
72 | static unsigned int sti_cursor_get_nb_formats(struct sti_layer *layer) | |
73 | { | |
74 | return ARRAY_SIZE(cursor_supported_formats); | |
75 | } | |
76 | ||
77 | static 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 | ||
99 | static 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 | ||
166 | static 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 | ||
186 | static int sti_cursor_disable_layer(struct sti_layer *layer) | |
187 | { | |
188 | return 0; | |
189 | } | |
190 | ||
191 | static 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 | ||
208 | static 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 | ||
217 | struct 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 | } |