1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <drm/drmP.h>
19
20#include <linux/device.h>
21#include <linux/err.h>
22#include <linux/io.h>
23#include <linux/module.h>
24#include <linux/of_address.h>
25#include <linux/of_irq.h>
26#include <linux/slab.h>
27
28#include "xilinx_drm_drv.h"
29
30#include "xilinx_osd.h"
31
32
33#define OSD_CTL 0x000
34#define OSD_SS 0x020
35#define OSD_ENC 0x028
36#define OSD_BC0 0x100
37#define OSD_BC1 0x104
38#define OSD_BC2 0x108
39
40#define OSD_L0C 0x110
41
42
43#define OSD_LAYER_SIZE 0x10
44#define OSD_LXC 0x00
45#define OSD_LXP 0x04
46#define OSD_LXS 0x08
47
48
49#define OSD_CTL_RUE (1 << 1)
50#define OSD_CTL_EN (1 << 0)
51
52
53#define OSD_SS_YSIZE_MASK 0x0fff0000
54#define OSD_SS_YSIZE_SHIFT 16
55#define OSD_SS_XSIZE_MASK 0x00000fff
56
57
58#define OSD_VIDEO_FORMAT_MASK 0x0000000f
59
60
61#define OSD_BC0_YG_MASK 0x000000ff
62
63
64#define OSD_BC1_UCBB_MASK 0x000000ff
65
66
67#define OSD_BC2_VCRR_MASK 0x000000ff
68
69
70#define OSD_MAX_NUM_OF_LAYERS 8
71
72
73#define OSD_LXC_ALPHA_MASK 0x0fff0000
74#define OSD_LXC_ALPHA_SHIFT 16
75#define OSD_LXC_PRIORITY_MASK 0x00000700
76#define OSD_LXC_PRIORITY_SHIFT 8
77#define OSD_LXC_GALPHAEN (1 << 1)
78#define OSD_LXC_EN (1 << 0)
79
80
81#define OSD_LXP_YSTART_MASK 0x0fff0000
82#define OSD_LXP_YSTART_SHIFT 16
83#define OSD_LXP_XSTART_MASK 0x00000fff
84
85
86#define OSD_LXS_YSIZE_MASK 0x0fff0000
87#define OSD_LXS_YSIZE_SHIFT 16
88#define OSD_LXS_XSIZE_MASK 0x00000fff
89
90
91#define OSD_RST_RESET (1 << 31)
92
93
94
95
96
97
98
99
100
101struct xilinx_osd_layer {
102 void __iomem *base;
103 int id;
104 bool avail;
105 struct xilinx_osd *osd;
106};
107
108
109
110
111
112
113
114
115
116
117struct xilinx_osd {
118 void __iomem *base;
119 struct xilinx_osd_layer *layers[OSD_MAX_NUM_OF_LAYERS];
120 unsigned int num_layers;
121 unsigned int max_width;
122 unsigned int format;
123};
124
125
126
127void xilinx_osd_layer_set_alpha(struct xilinx_osd_layer *layer, u32 alpha)
128{
129 u32 value;
130
131 DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id);
132 DRM_DEBUG_DRIVER("alpha: 0x%08x\n", alpha);
133
134 value = xilinx_drm_readl(layer->base, OSD_LXC);
135 value &= ~OSD_LXC_ALPHA_MASK;
136 value |= (alpha << OSD_LXC_ALPHA_SHIFT) & OSD_LXC_ALPHA_MASK;
137 xilinx_drm_writel(layer->base, OSD_LXC, value);
138}
139
140void xilinx_osd_layer_enable_alpha(struct xilinx_osd_layer *layer, bool enable)
141{
142 u32 value;
143
144 DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id);
145 DRM_DEBUG_DRIVER("enable: %d\n", enable);
146
147 value = xilinx_drm_readl(layer->base, OSD_LXC);
148 value = enable ? (value | OSD_LXC_GALPHAEN) :
149 (value & ~OSD_LXC_GALPHAEN);
150 xilinx_drm_writel(layer->base, OSD_LXC, value);
151}
152
153
154void xilinx_osd_layer_set_priority(struct xilinx_osd_layer *layer, u32 prio)
155{
156 u32 value;
157
158 DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id);
159 DRM_DEBUG_DRIVER("prio: %d\n", prio);
160
161 value = xilinx_drm_readl(layer->base, OSD_LXC);
162 value &= ~OSD_LXC_PRIORITY_MASK;
163 value |= (prio << OSD_LXC_PRIORITY_SHIFT) & OSD_LXC_PRIORITY_MASK;
164 xilinx_drm_writel(layer->base, OSD_LXC, value);
165}
166
167
168void xilinx_osd_layer_set_dimension(struct xilinx_osd_layer *layer,
169 u16 xstart, u16 ystart,
170 u16 xsize, u16 ysize)
171{
172 u32 value;
173
174 DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id);
175 DRM_DEBUG_DRIVER("w: %d(%d), h: %d(%d)\n",
176 xsize, xstart, ysize, ystart);
177
178 value = xstart & OSD_LXP_XSTART_MASK;
179 value |= (ystart << OSD_LXP_YSTART_SHIFT) & OSD_LXP_YSTART_MASK;
180
181 xilinx_drm_writel(layer->base, OSD_LXP, value);
182
183 value = xsize & OSD_LXS_XSIZE_MASK;
184 value |= (ysize << OSD_LXS_YSIZE_SHIFT) & OSD_LXS_YSIZE_MASK;
185
186 xilinx_drm_writel(layer->base, OSD_LXS, value);
187}
188
189
190void xilinx_osd_layer_enable(struct xilinx_osd_layer *layer)
191{
192 u32 value;
193
194 DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id);
195
196 value = xilinx_drm_readl(layer->base, OSD_LXC);
197 value |= OSD_LXC_EN;
198 xilinx_drm_writel(layer->base, OSD_LXC, value);
199}
200
201
202void xilinx_osd_layer_disable(struct xilinx_osd_layer *layer)
203{
204 u32 value;
205
206 DRM_DEBUG_DRIVER("layer->id: %d\n", layer->id);
207
208 value = xilinx_drm_readl(layer->base, OSD_LXC);
209 value &= ~OSD_LXC_EN;
210 xilinx_drm_writel(layer->base, OSD_LXC, value);
211}
212
213
214struct xilinx_osd_layer *xilinx_osd_layer_get(struct xilinx_osd *osd)
215{
216 struct xilinx_osd_layer *layer = NULL;
217 int i;
218
219 for (i = 0; i < osd->num_layers; i++) {
220 if (osd->layers[i]->avail) {
221 layer = osd->layers[i];
222 layer->avail = false;
223 break;
224 }
225 }
226
227 if (!layer)
228 return ERR_PTR(-ENODEV);
229
230 DRM_DEBUG_DRIVER("layer id: %d\n", i);
231
232 return layer;
233}
234
235
236void xilinx_osd_layer_put(struct xilinx_osd_layer *layer)
237{
238 layer->avail = true;
239}
240
241
242
243void xilinx_osd_set_color(struct xilinx_osd *osd, u8 r, u8 g, u8 b)
244{
245 u32 value;
246
247 value = g;
248 xilinx_drm_writel(osd->base, OSD_BC0, value);
249 value = b;
250 xilinx_drm_writel(osd->base, OSD_BC1, value);
251 value = r;
252 xilinx_drm_writel(osd->base, OSD_BC2, value);
253}
254
255
256void xilinx_osd_set_dimension(struct xilinx_osd *osd, u32 width, u32 height)
257{
258 u32 value;
259
260 DRM_DEBUG_DRIVER("w: %d, h: %d\n", width, height);
261
262 value = width | ((height << OSD_SS_YSIZE_SHIFT) & OSD_SS_YSIZE_MASK);
263 xilinx_drm_writel(osd->base, OSD_SS, value);
264}
265
266
267unsigned int xilinx_osd_get_num_layers(struct xilinx_osd *osd)
268{
269 return osd->num_layers;
270}
271
272
273unsigned int xilinx_osd_get_max_width(struct xilinx_osd *osd)
274{
275 return osd->max_width;
276}
277
278
279unsigned int xilinx_osd_get_format(struct xilinx_osd *osd)
280{
281 return osd->format;
282}
283
284
285void xilinx_osd_reset(struct xilinx_osd *osd)
286{
287 xilinx_drm_writel(osd->base, OSD_CTL, OSD_RST_RESET);
288}
289
290
291void xilinx_osd_enable(struct xilinx_osd *osd)
292{
293 xilinx_drm_writel(osd->base, OSD_CTL,
294 xilinx_drm_readl(osd->base, OSD_CTL) | OSD_CTL_EN);
295}
296
297
298void xilinx_osd_disable(struct xilinx_osd *osd)
299{
300 xilinx_drm_writel(osd->base, OSD_CTL,
301 xilinx_drm_readl(osd->base, OSD_CTL) & ~OSD_CTL_EN);
302}
303
304
305void xilinx_osd_enable_rue(struct xilinx_osd *osd)
306{
307 xilinx_drm_writel(osd->base, OSD_CTL,
308 xilinx_drm_readl(osd->base, OSD_CTL) | OSD_CTL_RUE);
309}
310
311
312void xilinx_osd_disable_rue(struct xilinx_osd *osd)
313{
314 xilinx_drm_writel(osd->base, OSD_CTL,
315 xilinx_drm_readl(osd->base, OSD_CTL) & ~OSD_CTL_RUE);
316}
317
318static const struct of_device_id xilinx_osd_of_match[] = {
319 { .compatible = "xlnx,v-osd-5.01.a" },
320 { },
321};
322
323struct xilinx_osd *xilinx_osd_probe(struct device *dev,
324 struct device_node *node)
325{
326 struct xilinx_osd *osd;
327 struct xilinx_osd_layer *layer;
328 const struct of_device_id *match;
329 struct resource res;
330 int i;
331 int ret;
332
333 match = of_match_node(xilinx_osd_of_match, node);
334 if (!match) {
335 dev_err(dev, "failed to match the device node\n");
336 return ERR_PTR(-ENODEV);
337 }
338
339 osd = devm_kzalloc(dev, sizeof(*osd), GFP_KERNEL);
340 if (!osd)
341 return ERR_PTR(-ENOMEM);
342
343 ret = of_address_to_resource(node, 0, &res);
344 if (ret) {
345 dev_err(dev, "failed to of_address_to_resource\n");
346 return ERR_PTR(ret);
347 }
348
349 osd->base = devm_ioremap_resource(dev, &res);
350 if (IS_ERR(osd->base))
351 return ERR_CAST(osd->base);
352
353 ret = of_property_read_u32(node, "xlnx,num-layers", &osd->num_layers);
354 if (ret) {
355 dev_warn(dev, "failed to get num of layers prop\n");
356 return ERR_PTR(ret);
357 }
358
359 ret = of_property_read_u32(node, "xlnx,screen-width", &osd->max_width);
360 if (ret) {
361 dev_warn(dev, "failed to get screen width prop\n");
362 return ERR_PTR(ret);
363 }
364
365
366 osd->format = xilinx_drm_readl(osd->base, OSD_ENC) &
367 OSD_VIDEO_FORMAT_MASK;
368
369 for (i = 0; i < osd->num_layers; i++) {
370 layer = devm_kzalloc(dev, sizeof(*layer), GFP_KERNEL);
371 if (!layer)
372 return ERR_PTR(-ENOMEM);
373
374 layer->base = osd->base + OSD_L0C + OSD_LAYER_SIZE * i;
375 layer->id = i;
376 layer->osd = osd;
377 layer->avail = true;
378 osd->layers[i] = layer;
379 }
380
381 return osd;
382}
383