1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <drm/drmP.h>
18
19#include <linux/device.h>
20#include <linux/err.h>
21#include <linux/io.h>
22#include <linux/module.h>
23#include <linux/of_address.h>
24#include <linux/of_device.h>
25#include <linux/of_irq.h>
26#include <linux/slab.h>
27
28#include <video/videomode.h>
29
30#include "xylon_drv.h"
31#include "xylon_logicvc_helper.h"
32#include "xylon_logicvc_hw.h"
33#include "xylon_logicvc_layer.h"
34
35
36
37
38
39#define LOGICVC_REG_STRIDE 8
40#define LOGICVC_HSYNC_FRONT_PORCH_ROFF (0 * LOGICVC_REG_STRIDE)
41#define LOGICVC_HSYNC_ROFF (1 * LOGICVC_REG_STRIDE)
42#define LOGICVC_HSYNC_BACK_PORCH_ROFF (2 * LOGICVC_REG_STRIDE)
43#define LOGICVC_HRES_ROFF (3 * LOGICVC_REG_STRIDE)
44#define LOGICVC_VSYNC_FRONT_PORCH_ROFF (4 * LOGICVC_REG_STRIDE)
45#define LOGICVC_VSYNC_ROFF (5 * LOGICVC_REG_STRIDE)
46#define LOGICVC_VSYNC_BACK_PORCH_ROFF (6 * LOGICVC_REG_STRIDE)
47#define LOGICVC_VRES_ROFF (7 * LOGICVC_REG_STRIDE)
48#define LOGICVC_CTRL_ROFF (8 * LOGICVC_REG_STRIDE)
49#define LOGICVC_DTYPE_ROFF (9 * LOGICVC_REG_STRIDE)
50#define LOGICVC_BACKGROUND_COLOR_ROFF (10 * LOGICVC_REG_STRIDE)
51#define LOGICVC_DOUBLE_CLUT_ROFF (12 * LOGICVC_REG_STRIDE)
52#define LOGICVC_INT_STAT_ROFF (13 * LOGICVC_REG_STRIDE)
53#define LOGICVC_INT_MASK_ROFF (14 * LOGICVC_REG_STRIDE)
54#define LOGICVC_POWER_CTRL_ROFF (15 * LOGICVC_REG_STRIDE)
55#define LOGICVC_IP_VERSION_ROFF (31 * LOGICVC_REG_STRIDE)
56
57
58
59
60
61
62#define LOGICVC_LAYER_ADDR_ROFF (0 * LOGICVC_REG_STRIDE)
63#define LOGICVC_LAYER_HPOS_ROFF (2 * LOGICVC_REG_STRIDE)
64#define LOGICVC_LAYER_VPOS_ROFF (3 * LOGICVC_REG_STRIDE)
65#define LOGICVC_LAYER_HSIZE_ROFF (4 * LOGICVC_REG_STRIDE)
66#define LOGICVC_LAYER_VSIZE_ROFF (5 * LOGICVC_REG_STRIDE)
67#define LOGICVC_LAYER_ALPHA_ROFF (6 * LOGICVC_REG_STRIDE)
68#define LOGICVC_LAYER_CTRL_ROFF (7 * LOGICVC_REG_STRIDE)
69#define LOGICVC_LAYER_TRANSP_COLOR_ROFF (8 * LOGICVC_REG_STRIDE)
70
71
72#define LOGICVC_INT_ALL \
73 (LOGICVC_INT_L0_UPDATED | LOGICVC_INT_L1_UPDATED | \
74 LOGICVC_INT_L2_UPDATED | LOGICVC_INT_L3_UPDATED | \
75 LOGICVC_INT_L4_UPDATED | LOGICVC_INT_V_SYNC | \
76 LOGICVC_INT_E_VIDEO_VALID | LOGICVC_INT_FIFO_UNDERRUN | \
77 LOGICVC_INT_L0_CLUT_SW | LOGICVC_INT_L1_CLUT_SW | \
78 LOGICVC_INT_L2_CLUT_SW | LOGICVC_INT_L3_CLUT_SW | \
79 LOGICVC_INT_L4_CLUT_SW)
80#define LOGICVC_INT_GENERAL \
81 (LOGICVC_INT_L0_UPDATED | LOGICVC_INT_L1_UPDATED | \
82 LOGICVC_INT_L2_UPDATED | LOGICVC_INT_L3_UPDATED | \
83 LOGICVC_INT_L4_UPDATED | LOGICVC_INT_FIFO_UNDERRUN)
84
85
86#define LOGICVC_LAYER_OFFSET 0x80
87#define LOGICVC_LAYER_BASE_OFFSET 0x100
88#define LOGICVC_LAYER_0_OFFSET (0 * LOGICVC_LAYER_OFFSET)
89#define LOGICVC_LAYER_1_OFFSET (1 * LOGICVC_LAYER_OFFSET)
90#define LOGICVC_LAYER_2_OFFSET (2 * LOGICVC_LAYER_OFFSET)
91#define LOGICVC_LAYER_3_OFFSET (3 * LOGICVC_LAYER_OFFSET)
92#define LOGICVC_LAYER_4_OFFSET (4 * LOGICVC_LAYER_OFFSET)
93
94
95
96
97#define LOGICVC_CLUT_OFFSET 0x800
98#define LOGICVC_CLUT_BASE_OFFSET 0x1000
99#define LOGICVC_CLUT_L0_CLUT_0_OFFSET (0 * LOGICVC_CLUT_OFFSET)
100#define LOGICVC_CLUT_L0_CLUT_1_OFFSET (1 * LOGICVC_CLUT_OFFSET)
101#define LOGICVC_CLUT_L1_CLUT_0_OFFSET (2 * LOGICVC_CLUT_OFFSET)
102#define LOGICVC_CLUT_L1_CLUT_1_OFFSET (3 * LOGICVC_CLUT_OFFSET)
103#define LOGICVC_CLUT_L2_CLUT_0_OFFSET (4 * LOGICVC_CLUT_OFFSET)
104#define LOGICVC_CLUT_L2_CLUT_1_OFFSET (5 * LOGICVC_CLUT_OFFSET)
105#define LOGICVC_CLUT_L3_CLUT_0_OFFSET (6 * LOGICVC_CLUT_OFFSET)
106#define LOGICVC_CLUT_L3_CLUT_1_OFFSET (7 * LOGICVC_CLUT_OFFSET)
107#define LOGICVC_CLUT_L4_CLUT_0_OFFSET (8 * LOGICVC_CLUT_OFFSET)
108#define LOGICVC_CLUT_L4_CLUT_1_OFFSET (9 * LOGICVC_CLUT_OFFSET)
109#define LOGICVC_CLUT_REGISTER_SIZE 8
110#define LOGICVC_CLUT_0_INDEX_OFFSET 2
111#define LOGICVC_CLUT_1_INDEX_OFFSET 1
112
113
114#define LOGICVC_CTRL_HSYNC (1 << 0)
115#define LOGICVC_CTRL_HSYNC_INVERT (1 << 1)
116#define LOGICVC_CTRL_VSYNC (1 << 2)
117#define LOGICVC_CTRL_VSYNC_INVERT (1 << 3)
118#define LOGICVC_CTRL_DATA_ENABLE (1 << 4)
119#define LOGICVC_CTRL_DATA_ENABLE_INVERT (1 << 5)
120#define LOGICVC_CTRL_PIXEL_DATA_INVERT (1 << 7)
121#define LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT (1 << 8)
122#define LOGICVC_CTRL_DISABLE_LAYER_UPDATE (1 << 9)
123
124
125#define LOGICVC_LAYER_CTRL_ENABLE (1 << 0)
126#define LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_BIT (1 << 1)
127#define LOGICVC_LAYER_CTRL_INTERLACE_BIT (1 << 3)
128
129
130#define LOGICVC_DTYPE_REG_INIT 0
131
132
133#define LOGICVC_MAJOR_REVISION_SHIFT 11
134#define LOGICVC_MAJOR_REVISION_MASK 0x3F
135#define LOGICVC_MINOR_REVISION_SHIFT 5
136#define LOGICVC_MINOR_REVISION_MASK 0x3F
137#define LOGICVC_PATCH_LEVEL_MASK 0x1F
138
139#define LOGICVC_MIN_HRES 64
140#define LOGICVC_MIN_VRES 1
141#define LOGICVC_MAX_HRES 2048
142#define LOGICVC_MAX_VRES 2048
143#define LOGICVC_MAX_LINES 4096
144#define LOGICVC_MAX_LAYERS 5
145
146#define LOGICVC_FLAGS_READABLE_REGS (1 << 0)
147#define LOGICVC_FLAGS_SIZE_POSITION (1 << 1)
148#define LOGICVC_FLAGS_BACKGROUND_LAYER (1 << 2)
149#define LOGICVC_FLAGS_BACKGROUND_LAYER_RGB (1 << 3)
150#define LOGICVC_FLAGS_BACKGROUND_LAYER_YUV (1 << 4)
151
152#define LOGICVC_COLOR_RGB_BLACK 0
153#define LOGICVC_COLOR_RGB_WHITE 0xFFFFFF
154#define LOGICVC_COLOR_RGB565_WHITE 0xFFFF
155#define LOGICVC_COLOR_YUV888_BLACK 0x8080
156#define LOGICVC_COLOR_YUV888_WHITE 0xFF8080
157
158enum xylon_cvc_layer_type {
159 LOGICVC_LAYER_RGB,
160 LOGICVC_LAYER_YUV
161};
162
163enum xylon_cvc_layer_alpha_type {
164 LOGICVC_ALPHA_LAYER,
165 LOGICVC_ALPHA_PIXEL,
166 LOGICVC_ALPHA_CLUT_16BPP,
167 LOGICVC_ALPHA_CLUT_32BPP
168};
169
170enum xylon_cvc_display_color_space {
171 LOGICVC_DCS_RGB,
172 LOGICVC_DCS_YUV422,
173 LOGICVC_DCS_YUV444
174};
175
176struct xylon_cvc_layer_data;
177
178struct xylon_cvc_register_access {
179 u32 (*xylon_cvc_get_reg_val)(void __iomem *reg_base_virt,
180 unsigned int offset,
181 struct xylon_cvc_layer_data *layer_data);
182 void (*xylon_cvc_set_reg_val)(u32 value, void __iomem *reg_base_virt,
183 unsigned int offset,
184 struct xylon_cvc_layer_data *layer_data);
185};
186
187struct xylon_cvc_registers {
188 u32 ctrl;
189 u32 dtype;
190 u32 bg;
191 u32 unused[3];
192 u32 imr;
193};
194
195struct xylon_cvc_layer_fix_data {
196 unsigned int id;
197 u32 address;
198 u32 bpp;
199 u32 type;
200 u32 transparency;
201 u32 width;
202};
203
204struct xylon_cvc_layer_registers {
205 u32 addr;
206 u32 unused;
207 u32 hpos;
208 u32 vpos;
209 u32 hsize;
210 u32 vsize;
211 u32 alpha;
212 u32 ctrl;
213 u32 transp;
214};
215
216struct xylon_cvc_layer_data {
217 struct xylon_cvc_layer_fix_data fix_data;
218 struct xylon_cvc_layer_registers regs;
219 void __iomem *base;
220 void __iomem *clut_base;
221 dma_addr_t vmem_pbase;
222 struct xylon_cvc *cvc;
223};
224
225struct xylon_cvc {
226 struct device_node *dn;
227 void __iomem *base;
228 struct videomode *vmode;
229 struct xylon_cvc_register_access reg_access;
230 struct xylon_cvc_registers regs;
231 struct xylon_cvc_layer_data *layer_data[LOGICVC_MAX_LAYERS];
232 unsigned int flags;
233 unsigned int irq;
234 unsigned int layers;
235 unsigned int power_on_delay;
236 unsigned int signal_on_delay;
237 u32 bg_layer_bpp;
238 u32 ctrl;
239 u32 pixel_stride;
240};
241
242static u32 xylon_cvc_get_reg(void __iomem *base,
243 unsigned int offset,
244 struct xylon_cvc_layer_data *layer_data)
245{
246 return readl(base + offset);
247}
248
249static void xylon_cvc_set_reg(u32 value, void __iomem *base,
250 unsigned int offset,
251 struct xylon_cvc_layer_data *layer_data)
252{
253 writel(value, base + offset);
254}
255
256static unsigned long
257xylon_cvc_get_reg_mem_addr(void __iomem *base, unsigned int offset,
258 struct xylon_cvc_layer_data *layer_data)
259{
260 unsigned int ordinal = offset / LOGICVC_REG_STRIDE;
261
262 if ((unsigned long)base - (unsigned long)layer_data->cvc->base) {
263 return (unsigned long)(&layer_data->regs) +
264 (ordinal * sizeof(u32));
265 } else {
266 ordinal -= (LOGICVC_CTRL_ROFF / LOGICVC_REG_STRIDE);
267 return (unsigned long)(&layer_data->cvc->regs) +
268 (ordinal * sizeof(u32));
269 }
270}
271
272static u32 xylon_cvc_get_reg_mem(void __iomem *base, unsigned int offset,
273 struct xylon_cvc_layer_data *layer_data)
274{
275 return *((unsigned long *)xylon_cvc_get_reg_mem_addr(base, offset,
276 layer_data));
277}
278
279static void xylon_cvc_set_reg_mem(u32 value, void __iomem *base,
280 unsigned int offset,
281 struct xylon_cvc_layer_data *layer_data)
282{
283 unsigned long *reg_mem_addr =
284 (unsigned long *)xylon_cvc_get_reg_mem_addr(base, offset,
285 layer_data);
286 *reg_mem_addr = value;
287 writel((*reg_mem_addr), (base + offset));
288}
289
290unsigned int xylon_cvc_layer_get_total_count(struct xylon_cvc *cvc)
291{
292 return cvc->layers;
293}
294
295u32 xylon_cvc_layer_get_format(struct xylon_cvc *cvc, int id)
296{
297 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
298 u32 drm_format = 0;
299 u32 bpp = layer_data->fix_data.bpp;
300 u32 transp = layer_data->fix_data.transparency;
301
302 switch (layer_data->fix_data.type) {
303 case LOGICVC_LAYER_RGB:
304 if (bpp == 16 && transp == LOGICVC_ALPHA_LAYER)
305 drm_format = DRM_FORMAT_RGB565;
306 else if (bpp == 32 && transp == LOGICVC_ALPHA_LAYER)
307 drm_format = DRM_FORMAT_XRGB8888;
308 else if (bpp == 32 && transp == LOGICVC_ALPHA_PIXEL)
309 drm_format = DRM_FORMAT_ARGB8888;
310 break;
311 case LOGICVC_LAYER_YUV:
312 if (bpp == 16 && transp == LOGICVC_ALPHA_LAYER)
313 drm_format = DRM_FORMAT_YUYV;
314 else if (bpp == 32 && transp == LOGICVC_ALPHA_LAYER)
315 drm_format = DRM_FORMAT_YUYV;
316 break;
317 default:
318 DRM_ERROR("unsupported layer format\n");
319 }
320
321 return drm_format;
322}
323
324unsigned int xylon_cvc_layer_get_bits_per_pixel(struct xylon_cvc *cvc, int id)
325{
326 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
327
328 return layer_data->fix_data.bpp;
329}
330
331void xylon_cvc_layer_set_alpha(struct xylon_cvc *cvc, int id, u8 alpha)
332{
333 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
334 struct xylon_cvc_layer_fix_data *fix_data = &layer_data->fix_data;
335 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
336 u32 alpha32 = alpha;
337
338 if (fix_data->transparency == LOGICVC_ALPHA_LAYER)
339 reg_access->xylon_cvc_set_reg_val(alpha32, layer_data->base,
340 LOGICVC_LAYER_ALPHA_ROFF,
341 layer_data);
342}
343
344int xylon_cvc_layer_set_size_position(struct xylon_cvc *cvc, int id,
345 int src_x, int src_y,
346 unsigned int src_x_size,
347 unsigned int src_y_size,
348 int dst_x, int dst_y,
349 unsigned int dst_x_size,
350 unsigned int dst_y_size)
351{
352 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
353 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
354 void __iomem *base = layer_data->base;
355 u32 hres, vres;
356
357 DRM_DEBUG("%d-%d(%d-%d), %d-%d(%d-%d)\n",
358 src_x, dst_x, src_x_size, dst_x_size,
359 src_y, dst_y, src_y_size, dst_y_size);
360
361 if (src_x_size != dst_x_size || src_y_size != dst_y_size) {
362 DRM_ERROR("invalid source coordinates\n");
363 return -EINVAL;
364 }
365
366 if (cvc->vmode) {
367 hres = cvc->vmode->hactive;
368 vres = cvc->vmode->vactive;
369
370 if ((dst_x + dst_x_size) > hres ||
371 (dst_y + dst_y_size) > vres) {
372 DRM_ERROR("invalid rectangle width\n");
373 return -EINVAL;
374 }
375
376 reg_access->xylon_cvc_set_reg_val(hres - dst_x - 1,
377 base,
378 LOGICVC_LAYER_HPOS_ROFF,
379 layer_data);
380 reg_access->xylon_cvc_set_reg_val(vres - dst_y - 1,
381 base,
382 LOGICVC_LAYER_VPOS_ROFF,
383 layer_data);
384 reg_access->xylon_cvc_set_reg_val(dst_x_size - 1,
385 base,
386 LOGICVC_LAYER_HSIZE_ROFF,
387 layer_data);
388 reg_access->xylon_cvc_set_reg_val(dst_y_size - 1,
389 base,
390 LOGICVC_LAYER_VSIZE_ROFF,
391 layer_data);
392 }
393
394 return 0;
395}
396
397void xylon_cvc_layer_set_address(struct xylon_cvc *cvc, int id,
398 dma_addr_t paddr, u32 x, u32 y)
399{
400 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
401 u32 vmem_offset;
402
403 vmem_offset = (x * (layer_data->fix_data.bpp / 8)) +
404 (y * layer_data->fix_data.width *
405 (layer_data->fix_data.bpp / 8));
406
407 layer_data->vmem_pbase = paddr + vmem_offset;
408}
409
410void xylon_cvc_layer_enable(struct xylon_cvc *cvc, int id)
411{
412 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
413 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
414 u32 regval = reg_access->xylon_cvc_get_reg_val(layer_data->base,
415 LOGICVC_LAYER_CTRL_ROFF,
416 layer_data);
417
418 regval |= LOGICVC_LAYER_CTRL_ENABLE;
419 reg_access->xylon_cvc_set_reg_val(regval,
420 layer_data->base,
421 LOGICVC_LAYER_CTRL_ROFF,
422 layer_data);
423}
424
425void xylon_cvc_layer_disable(struct xylon_cvc *cvc, int id)
426{
427 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
428 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
429 u32 regval = reg_access->xylon_cvc_get_reg_val(layer_data->base,
430 LOGICVC_LAYER_CTRL_ROFF,
431 layer_data);
432
433 regval &= (~LOGICVC_LAYER_CTRL_ENABLE);
434 reg_access->xylon_cvc_set_reg_val(regval,
435 layer_data->base,
436 LOGICVC_LAYER_CTRL_ROFF,
437 layer_data);
438}
439
440void xylon_cvc_layer_update(struct xylon_cvc *cvc, int id)
441{
442 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
443 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
444
445 reg_access->xylon_cvc_set_reg_val(layer_data->vmem_pbase,
446 layer_data->base,
447 LOGICVC_LAYER_ADDR_ROFF,
448 layer_data);
449}
450
451void xylon_cvc_layer_ctrl(struct xylon_cvc *cvc, int id,
452 enum xylon_cvc_layer_control op)
453{
454 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
455 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
456 u32 regval = reg_access->xylon_cvc_get_reg_val(layer_data->base,
457 LOGICVC_LAYER_CTRL_ROFF,
458 layer_data);
459
460 switch (op) {
461 case LOGICVC_LAYER_COLOR_TRANSPARENCY_DISABLE:
462 regval |= LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_BIT;
463 break;
464 case LOGICVC_LAYER_COLOR_TRANSPARENCY_ENABLE:
465 regval &= ~LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_BIT;
466 break;
467 case LOGICVC_LAYER_INTERLACE_DISABLE:
468 regval |= LOGICVC_LAYER_CTRL_INTERLACE_BIT;
469 break;
470 case LOGICVC_LAYER_INTERLACE_ENABLE:
471 regval &= ~LOGICVC_LAYER_CTRL_INTERLACE_BIT;
472 break;
473 default:
474 return;
475 }
476
477 reg_access->xylon_cvc_set_reg_val(regval,
478 layer_data->base,
479 LOGICVC_LAYER_CTRL_ROFF,
480 layer_data);
481}
482
483void xylon_cvc_layer_set_color_reg(struct xylon_cvc *cvc, int id, u32 color)
484{
485 struct xylon_cvc_layer_data *layer_data;
486 void __iomem *base;
487 unsigned int layer_bpp;
488 unsigned long offset;
489 u8 r, g, b;
490 bool bg = false;
491
492 if (id == BACKGROUND_LAYER_ID)
493 bg = true;
494
495 if (bg) {
496 if (!(cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER))
497 return;
498 layer_data = cvc->layer_data[0];
499 layer_bpp = cvc->bg_layer_bpp;
500 } else {
501 layer_data = cvc->layer_data[id];
502 layer_bpp = layer_data->fix_data.bpp;
503 }
504
505 switch (layer_bpp) {
506 case 16:
507 color &= LOGICVC_COLOR_RGB_WHITE;
508 if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER_RGB &&
509 (color != LOGICVC_COLOR_RGB_BLACK)) {
510 if (color != LOGICVC_COLOR_RGB_WHITE) {
511 r = color >> 16;
512 g = color >> 8;
513 b = color;
514
515 color = ((r & 0xF8) << 8) |
516 ((g & 0xFC) << 3) |
517 ((b & 0xF8) >> 3);
518 } else {
519 color = LOGICVC_COLOR_RGB565_WHITE;
520 }
521 }
522 break;
523 case 32:
524 if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER_YUV) {
525 if (color == LOGICVC_COLOR_RGB_BLACK)
526 color = LOGICVC_COLOR_YUV888_BLACK;
527 else if (color == LOGICVC_COLOR_RGB_WHITE)
528 color = LOGICVC_COLOR_YUV888_WHITE;
529 }
530 break;
531 default:
532 if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER_YUV)
533 color = LOGICVC_COLOR_YUV888_BLACK;
534 else
535 color = LOGICVC_COLOR_RGB_BLACK;
536 DRM_INFO("unsupported bg layer bpp\n");
537 return;
538 }
539
540 if (bg) {
541 base = cvc->base;
542 offset = LOGICVC_BACKGROUND_COLOR_ROFF;
543 } else {
544 base = layer_data->base;
545 offset = LOGICVC_LAYER_TRANSP_COLOR_ROFF;
546 }
547 cvc->reg_access.xylon_cvc_set_reg_val(color,
548 base, offset,
549 layer_data);
550}
551
552void xylon_cvc_int_state(struct xylon_cvc *cvc, unsigned int type,
553 bool enabled)
554{
555 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
556 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
557 void __iomem *base = cvc->base;
558 u32 imr = reg_access->xylon_cvc_get_reg_val(base,
559 LOGICVC_INT_MASK_ROFF,
560 layer_data);
561 if (enabled)
562 imr &= ~type;
563 else
564 imr |= type;
565
566 reg_access->xylon_cvc_set_reg_val(imr, base,
567 LOGICVC_INT_MASK_ROFF,
568 layer_data);
569}
570
571u32 xylon_cvc_int_get_active(struct xylon_cvc *cvc)
572{
573 return readl(cvc->base + LOGICVC_INT_STAT_ROFF);
574}
575
576void xylon_cvc_int_clear_active(struct xylon_cvc *cvc, u32 active)
577{
578 writel(active, cvc->base + LOGICVC_INT_STAT_ROFF);
579}
580
581void xylon_cvc_int_hw_enable(struct xylon_cvc *cvc)
582{
583 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
584 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
585 void __iomem *base = cvc->base;
586
587 reg_access->xylon_cvc_set_reg_val(LOGICVC_INT_GENERAL, base,
588 LOGICVC_INT_MASK_ROFF,
589 layer_data);
590 writel(LOGICVC_INT_ALL, base + LOGICVC_INT_STAT_ROFF);
591}
592
593void xylon_cvc_int_hw_disable(struct xylon_cvc *cvc)
594{
595 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
596 struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
597 void __iomem *base = cvc->base;
598
599 reg_access->xylon_cvc_set_reg_val(LOGICVC_INT_ALL, base,
600 LOGICVC_INT_MASK_ROFF,
601 layer_data);
602 writel(LOGICVC_INT_ALL, base + LOGICVC_INT_STAT_ROFF);
603}
604
605int xylon_cvc_int_request(struct xylon_cvc *cvc, unsigned long flags,
606 irq_handler_t handler, void *dev)
607{
608 struct device_node *dn = cvc->dn;
609 int irq;
610
611 irq = of_irq_to_resource(dn, 0, NULL);
612 if (irq < 0) {
613 DRM_ERROR("failed get irq resource\n");
614 return irq;
615 }
616
617 cvc->irq = irq;
618
619 return request_irq(irq, handler, flags, dn->name, dev);
620}
621
622void xylon_cvc_int_free(struct xylon_cvc *cvc, void *dev)
623{
624 free_irq(cvc->irq, dev);
625}
626
627void xylon_cvc_ctrl(struct xylon_cvc *cvc, enum xylon_cvc_control ctrl,
628 bool val)
629{
630 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
631
632 switch (ctrl) {
633 case LOGICVC_LAYER_UPDATE:
634 if (val)
635 cvc->ctrl &= ~LOGICVC_CTRL_DISABLE_LAYER_UPDATE;
636 else
637 cvc->ctrl |= LOGICVC_CTRL_DISABLE_LAYER_UPDATE;
638 break;
639 case LOGICVC_PIXEL_DATA_TRIGGER_INVERT:
640 if (val)
641 cvc->ctrl |= LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT;
642 else
643 cvc->ctrl &= ~LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT;
644 break;
645 case LOGICVC_PIXEL_DATA_INVERT:
646 if (val)
647 cvc->ctrl |= LOGICVC_CTRL_PIXEL_DATA_INVERT;
648 else
649 cvc->ctrl &= ~LOGICVC_CTRL_PIXEL_DATA_INVERT;
650 break;
651 }
652
653 cvc->reg_access.xylon_cvc_set_reg_val(cvc->ctrl, cvc->base,
654 LOGICVC_CTRL_ROFF,
655 layer_data);
656}
657
658void xylon_cvc_enable(struct xylon_cvc *cvc, struct videomode *vmode)
659{
660 void __iomem *base = cvc->base;
661 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
662 struct videomode *vm;
663
664 if (vmode) {
665 cvc->vmode = vmode;
666 vm = vmode;
667 } else {
668 vm = cvc->vmode;
669 }
670
671 writel(vm->hfront_porch - 1, base + LOGICVC_HSYNC_FRONT_PORCH_ROFF);
672 writel(vm->hsync_len - 1, base + LOGICVC_HSYNC_ROFF);
673 writel(vm->hback_porch - 1, base + LOGICVC_HSYNC_BACK_PORCH_ROFF);
674 writel(vm->hactive - 1, base + LOGICVC_HRES_ROFF);
675 writel(vm->vfront_porch - 1, base + LOGICVC_VSYNC_FRONT_PORCH_ROFF);
676 writel(vm->vsync_len - 1, base + LOGICVC_VSYNC_ROFF);
677 writel(vm->vback_porch - 1, base + LOGICVC_VSYNC_BACK_PORCH_ROFF);
678 writel(vm->vactive - 1, base + LOGICVC_VRES_ROFF);
679
680 cvc->reg_access.xylon_cvc_set_reg_val(cvc->ctrl, base,
681 LOGICVC_CTRL_ROFF,
682 layer_data);
683
684 writel(LOGICVC_DTYPE_REG_INIT, base + LOGICVC_DTYPE_ROFF);
685}
686
687void xylon_cvc_disable(struct xylon_cvc *cvc)
688{
689 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
690 int i;
691
692 if (layer_data)
693 for (i = 0; i < cvc->layers; i++)
694 xylon_cvc_layer_disable(cvc, i);
695}
696
697static int xylon_parse_hw_info(struct device_node *dn, struct xylon_cvc *cvc)
698{
699 int ret;
700 const char *string;
701
702 if (of_property_read_bool(dn, "background-layer-bits-per-pixel")) {
703 ret = of_property_read_u32(dn,
704 "background-layer-bits-per-pixel",
705 &cvc->bg_layer_bpp);
706 if (ret) {
707 DRM_ERROR("failed get bg-layer-bits-per-pixel\n");
708 return ret;
709 }
710 cvc->flags |= LOGICVC_FLAGS_BACKGROUND_LAYER;
711
712 ret = of_property_read_string(dn, "background-layer-type",
713 &string);
714 if (ret) {
715 DRM_ERROR("failed get bg-layer-type\n");
716 return ret;
717 }
718 if (!strcmp(string, "rgb")) {
719 cvc->flags |= LOGICVC_FLAGS_BACKGROUND_LAYER_RGB;
720 } else if (!strcmp(string, "yuv")) {
721 cvc->flags |= LOGICVC_FLAGS_BACKGROUND_LAYER_YUV;
722 } else {
723 DRM_ERROR("unsupported bg layer type\n");
724 return -EINVAL;
725 }
726 }
727
728 if (of_property_read_bool(dn, "readable-regs"))
729 cvc->flags |= LOGICVC_FLAGS_READABLE_REGS;
730 else
731 DRM_INFO("logicvc registers not readable\n");
732
733 if (of_property_read_bool(dn, "size-position"))
734 cvc->flags |= LOGICVC_FLAGS_SIZE_POSITION;
735 else
736 DRM_INFO("logicvc size-position disabled\n");
737
738 ret = of_property_read_u32(dn, "pixel-stride", &cvc->pixel_stride);
739 if (ret) {
740 DRM_ERROR("failed get pixel-stride\n");
741 return ret;
742 }
743
744 return 0;
745}
746
747static int xylonfb_parse_layer_info(struct device *dev,
748 struct device_node *parent_dn,
749 struct xylon_cvc *cvc, int id)
750{
751 struct device_node *dn;
752 struct xylon_cvc_layer_data *layer_data;
753 int ret;
754 char layer_name[10];
755 const char *string;
756
757 snprintf(layer_name, sizeof(layer_name), "layer_%d", id);
758 dn = of_get_child_by_name(parent_dn, layer_name);
759 if (!dn)
760 return 0;
761
762 cvc->layers++;
763
764 layer_data = devm_kzalloc(dev, sizeof(*layer_data), GFP_KERNEL);
765 if (!layer_data) {
766 DRM_ERROR("failed allocate layer data id %d\n", id);
767 return -ENOMEM;
768 }
769 layer_data->cvc = cvc;
770 layer_data->fix_data.id = id;
771
772 cvc->layer_data[id] = layer_data;
773
774 if (of_property_read_bool(dn, "address")) {
775 ret = of_property_read_u32(dn, "address",
776 &layer_data->fix_data.address);
777 if (ret) {
778 DRM_ERROR("failed get address\n");
779 return ret;
780 }
781 }
782
783 ret = of_property_read_u32(dn, "bits-per-pixel",
784 &layer_data->fix_data.bpp);
785 if (ret) {
786 DRM_ERROR("failed get bits-per-pixel\n");
787 return ret;
788 }
789
790 ret = of_property_read_string(dn, "type", &string);
791 if (ret) {
792 DRM_ERROR("failed get type\n");
793 return ret;
794 }
795 if (!strcmp(string, "rgb")) {
796 layer_data->fix_data.type = LOGICVC_LAYER_RGB;
797 } else if (!strcmp(string, "yuv")) {
798 layer_data->fix_data.type = LOGICVC_LAYER_YUV;
799 } else {
800 DRM_ERROR("unsupported layer type\n");
801 return -EINVAL;
802 }
803
804 ret = of_property_read_string(dn, "transparency", &string);
805 if (ret) {
806 DRM_ERROR("failed get transparency\n");
807 return ret;
808 }
809 if (!strcmp(string, "layer")) {
810 layer_data->fix_data.transparency = LOGICVC_ALPHA_LAYER;
811 } else if (!strcmp(string, "pixel")) {
812 layer_data->fix_data.transparency = LOGICVC_ALPHA_PIXEL;
813 } else {
814 DRM_ERROR("unsupported layer transparency\n");
815 return -EINVAL;
816 }
817
818 layer_data->fix_data.width = cvc->pixel_stride;
819
820 return id + 1;
821}
822
823static void xylon_cvc_init_ctrl(struct device_node *dn, u32 *ctrl)
824{
825 u32 ctrl_reg = (LOGICVC_CTRL_HSYNC | LOGICVC_CTRL_VSYNC |
826 LOGICVC_CTRL_DATA_ENABLE);
827
828 if (of_property_read_bool(dn, "hsync-active-low"))
829 ctrl_reg |= LOGICVC_CTRL_HSYNC_INVERT;
830 if (of_property_read_bool(dn, "vsync-active-low"))
831 ctrl_reg |= LOGICVC_CTRL_HSYNC_INVERT;
832 if (of_property_read_bool(dn, "pixel-data-invert"))
833 ctrl_reg |= LOGICVC_CTRL_PIXEL_DATA_INVERT;
834 if (of_property_read_bool(dn, "pixel-data-output-trigger-high"))
835 ctrl_reg |= LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT;
836
837 *ctrl = ctrl_reg;
838}
839
840bool xylon_cvc_get_info(struct xylon_cvc *cvc, enum xylon_cvc_info info,
841 unsigned int param)
842{
843 struct xylon_cvc_layer_data *layer_data;
844 struct xylon_cvc_register_access *reg_access;
845
846 switch (info) {
847 case LOGICVC_INFO_BACKGROUND_LAYER:
848 if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER)
849 return true;
850 break;
851 case LOGICVC_INFO_LAST_LAYER:
852 if (param == (cvc->layers - 1))
853 return true;
854 break;
855 case LOGICVC_INFO_LAYER_COLOR_TRANSPARENCY:
856 layer_data = cvc->layer_data[param];
857 reg_access = &cvc->reg_access;
858 if (!(reg_access->xylon_cvc_get_reg_val(layer_data->base,
859 LOGICVC_LAYER_CTRL_ROFF,
860 layer_data) &
861 LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_BIT))
862 return true;
863 break;
864 case LOGICVC_INFO_LAYER_UPDATE:
865 if (!(cvc->ctrl & LOGICVC_CTRL_DISABLE_LAYER_UPDATE))
866 return true;
867 break;
868 case LOGICVC_INFO_PIXEL_DATA_INVERT:
869 if (cvc->ctrl & LOGICVC_CTRL_PIXEL_DATA_INVERT)
870 return true;
871 break;
872 case LOGICVC_INFO_PIXEL_DATA_TRIGGER_INVERT:
873 if (cvc->ctrl & LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT)
874 return true;
875 break;
876 case LOGICVC_INFO_SIZE_POSITION:
877 if (cvc->flags & LOGICVC_FLAGS_SIZE_POSITION)
878 return true;
879 break;
880 }
881
882 return false;
883}
884
885void xylon_cvc_get_fix_parameters(struct xylon_cvc *cvc,
886 struct xylon_cvc_fix *cvc_fix)
887{
888 struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
889 struct xylon_cvc_layer_fix_data *fix_data = &layer_data->fix_data;
890
891 cvc_fix->hres_min = LOGICVC_MIN_HRES;
892 cvc_fix->vres_min = LOGICVC_MIN_VRES;
893 cvc_fix->hres_max = LOGICVC_MAX_HRES;
894 cvc_fix->vres_max = LOGICVC_MAX_VRES;
895 cvc_fix->x_min = LOGICVC_MIN_HRES;
896 cvc_fix->y_min = LOGICVC_MIN_VRES;
897 cvc_fix->x_max = fix_data->width;
898 cvc_fix->y_max = LOGICVC_MAX_LINES;
899}
900
901static const struct of_device_id cvc_of_match[] = {
902 { .compatible = "xylon,logicvc-4.00.a" },
903 { .compatible = "xylon,logicvc-5.0" },
904 {}
905};
906
907struct xylon_cvc *xylon_cvc_probe(struct device *dev, struct device_node *dn)
908{
909 struct xylon_cvc *cvc;
910 const struct of_device_id *match;
911 __force const void *err;
912 struct resource res;
913 u32 ip_ver;
914 int ret, i;
915 unsigned short xylon_cvc_layer_base_off[] = {
916 (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_0_OFFSET),
917 (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_1_OFFSET),
918 (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_2_OFFSET),
919 (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_3_OFFSET),
920 (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_4_OFFSET)
921 };
922 unsigned short xylon_cvc_clut_base_off[] = {
923 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L0_CLUT_0_OFFSET),
924 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L0_CLUT_1_OFFSET),
925 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L1_CLUT_0_OFFSET),
926 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L1_CLUT_1_OFFSET),
927 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L2_CLUT_0_OFFSET),
928 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L2_CLUT_1_OFFSET),
929 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L3_CLUT_0_OFFSET),
930 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L3_CLUT_1_OFFSET),
931 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L4_CLUT_0_OFFSET),
932 (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L4_CLUT_1_OFFSET)
933 };
934
935 match = of_match_node(cvc_of_match, dn);
936 if (!match) {
937 DRM_ERROR("failed match cvc\n");
938 return ERR_PTR(-ENODEV);
939 }
940
941 cvc = devm_kzalloc(dev, sizeof(*cvc), GFP_KERNEL);
942 if (!cvc) {
943 DRM_ERROR("failed allocate cvc\n");
944 return ERR_PTR(-ENOMEM);
945 }
946 cvc->dn = dn;
947
948 ret = of_address_to_resource(dn, 0, &res);
949 if (ret) {
950 DRM_ERROR("failed get mem resource\n");
951 return ERR_PTR(ret);
952 }
953
954 cvc->base = devm_ioremap_resource(dev, &res);
955 err = (__force const void *)cvc->base;
956 if (IS_ERR(err)) {
957 DRM_ERROR("failed remap resource\n");
958 return ERR_CAST(err);
959 }
960
961 ip_ver = readl(cvc->base + LOGICVC_IP_VERSION_ROFF);
962 DRM_INFO("logiCVC IP core %d.%02d.%c\n",
963 ((ip_ver >> LOGICVC_MAJOR_REVISION_SHIFT) &
964 LOGICVC_MAJOR_REVISION_MASK),
965 ((ip_ver >> LOGICVC_MINOR_REVISION_SHIFT) &
966 LOGICVC_MINOR_REVISION_MASK),
967 ((ip_ver & LOGICVC_PATCH_LEVEL_MASK) + 'a'));
968
969 ret = xylon_parse_hw_info(dn, cvc);
970 if (ret)
971 return ERR_PTR(ret);
972
973 for (i = 0; i < LOGICVC_MAX_LAYERS; i++) {
974 ret = xylonfb_parse_layer_info(dev, dn, cvc, i);
975 if (ret < 0)
976 return ERR_PTR(ret);
977 if (ret == 0)
978 break;
979
980 cvc->layer_data[i]->base =
981 cvc->base + xylon_cvc_layer_base_off[i];
982 cvc->layer_data[i]->clut_base =
983 cvc->base + xylon_cvc_clut_base_off[i];
984 }
985
986 xylon_cvc_init_ctrl(dn, &cvc->ctrl);
987
988 if (cvc->flags & LOGICVC_FLAGS_READABLE_REGS) {
989 cvc->reg_access.xylon_cvc_get_reg_val = xylon_cvc_get_reg;
990 cvc->reg_access.xylon_cvc_set_reg_val = xylon_cvc_set_reg;
991 } else {
992 cvc->reg_access.xylon_cvc_get_reg_val = xylon_cvc_get_reg_mem;
993 cvc->reg_access.xylon_cvc_set_reg_val = xylon_cvc_set_reg_mem;
994 }
995
996 if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER)
997 xylon_cvc_layer_set_color_reg(cvc, BACKGROUND_LAYER_ID,
998 LOGICVC_COLOR_RGB_BLACK);
999
1000 return cvc;
1001}
1002