source: mainline/uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.c

Last change on this file was 7470d97, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Add GC operation to set clipping rectangle

The number of changed files is due to the proliferation of GC
implementations, mostly these are just dummies in unit tests.
Definitely need to tame those in the future.

  • Property mode set to 100644
File size: 15.6 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * Copyright (c) 2013 Jan Vesely
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup amdm37x_dispc
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <align.h>
38#include <as.h>
39#include <assert.h>
40#include <errno.h>
41#include <ddev_srv.h>
42#include <ddev/info.h>
43#include <ddf/driver.h>
44#include <ddf/log.h>
45#include <ddi.h>
46#include <gfx/color.h>
47#include <io/pixelmap.h>
48
49#include "amdm37x_dispc.h"
50
51#ifndef CONFIG_BFB_BPP
52#define CONFIG_BFB_BPP 24
53#endif
54
55#ifndef CONFIG_BFB_WIDTH
56#define CONFIG_BFB_WIDTH 1024
57#endif
58
59#ifndef CONFIG_BFB_HEIGHT
60#define CONFIG_BFB_HEIGHT 768
61#endif
62
63static errno_t amdm37x_change_mode(amdm37x_dispc_t *, unsigned, unsigned,
64 visual_t);
65
66static errno_t amdm37x_ddev_get_gc(void *, sysarg_t *, sysarg_t *);
67static errno_t amdm37x_ddev_get_info(void *, ddev_info_t *);
68
69static errno_t amdm37x_gc_set_clip_rect(void *, gfx_rect_t *);
70static errno_t amdm37x_gc_set_color(void *, gfx_color_t *);
71static errno_t amdm37x_gc_fill_rect(void *, gfx_rect_t *);
72static errno_t amdm37x_gc_bitmap_create(void *, gfx_bitmap_params_t *,
73 gfx_bitmap_alloc_t *, void **);
74static errno_t amdm37x_gc_bitmap_destroy(void *);
75static errno_t amdm37x_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
76static errno_t amdm37x_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
77
78ddev_ops_t amdm37x_ddev_ops = {
79 .get_gc = amdm37x_ddev_get_gc,
80 .get_info = amdm37x_ddev_get_info
81};
82
83gfx_context_ops_t amdm37x_gc_ops = {
84 .set_clip_rect = amdm37x_gc_set_clip_rect,
85 .set_color = amdm37x_gc_set_color,
86 .fill_rect = amdm37x_gc_fill_rect,
87 .bitmap_create = amdm37x_gc_bitmap_create,
88 .bitmap_destroy = amdm37x_gc_bitmap_destroy,
89 .bitmap_render = amdm37x_gc_bitmap_render,
90 .bitmap_get_alloc = amdm37x_gc_bitmap_get_alloc
91};
92
93static const struct {
94 unsigned bpp;
95 pixel2visual_t func;
96} pixel2visual_table[] = {
97 [VISUAL_INDIRECT_8] = { .bpp = 1, .func = pixel2bgr_323 },
98 [VISUAL_RGB_5_5_5_LE] = { .bpp = 2, .func = pixel2rgb_555_le },
99 [VISUAL_RGB_5_5_5_BE] = { .bpp = 2, .func = pixel2rgb_555_be },
100 [VISUAL_RGB_5_6_5_LE] = { .bpp = 2, .func = pixel2rgb_565_le },
101 [VISUAL_RGB_5_6_5_BE] = { .bpp = 2, .func = pixel2rgb_565_be },
102 [VISUAL_BGR_8_8_8] = { .bpp = 3, .func = pixel2bgr_888 },
103 [VISUAL_RGB_8_8_8] = { .bpp = 3, .func = pixel2rgb_888 },
104 [VISUAL_BGR_0_8_8_8] = { .bpp = 4, .func = pixel2rgb_0888 },
105 [VISUAL_BGR_8_8_8_0] = { .bpp = 4, .func = pixel2bgr_8880 },
106 [VISUAL_ABGR_8_8_8_8] = { .bpp = 4, .func = pixel2abgr_8888 },
107 [VISUAL_BGRA_8_8_8_8] = { .bpp = 4, .func = pixel2bgra_8888 },
108 [VISUAL_RGB_0_8_8_8] = { .bpp = 4, .func = pixel2rgb_0888 },
109 [VISUAL_RGB_8_8_8_0] = { .bpp = 4, .func = pixel2rgb_8880 },
110 [VISUAL_ARGB_8_8_8_8] = { .bpp = 4, .func = pixel2argb_8888 },
111 [VISUAL_RGBA_8_8_8_8] = { .bpp = 4, .func = pixel2rgba_8888 },
112};
113
114errno_t amdm37x_dispc_init(amdm37x_dispc_t *instance, ddf_fun_t *fun)
115{
116 instance->fun = fun;
117 instance->fb_data = NULL;
118 instance->size = 0;
119
120 /* Default is 24bpp, use config option if available */
121 visual_t visual = VISUAL_BGR_8_8_8;
122 switch (CONFIG_BFB_BPP) {
123 case 8:
124 visual = VISUAL_INDIRECT_8;
125 break;
126 case 16:
127 visual = VISUAL_RGB_5_6_5_LE;
128 break;
129 case 24:
130 visual = VISUAL_BGR_8_8_8;
131 break;
132 case 32:
133 visual = VISUAL_RGB_8_8_8_0;
134 break;
135 default:
136 return EINVAL;
137 }
138
139 errno_t ret = pio_enable((void *)AMDM37x_DISPC_BASE_ADDRESS,
140 AMDM37x_DISPC_SIZE, (void **)&instance->regs);
141 if (ret != EOK) {
142 return EIO;
143 }
144
145 ret = amdm37x_change_mode(instance, CONFIG_BFB_WIDTH,
146 CONFIG_BFB_HEIGHT, visual);
147 if (ret != EOK)
148 return EIO;
149
150 return EOK;
151}
152
153errno_t amdm37x_dispc_fini(amdm37x_dispc_t *instance)
154{
155 return EOK;
156}
157
158static errno_t amdm37x_dispc_setup_fb(amdm37x_dispc_regs_t *regs,
159 unsigned x, unsigned y, unsigned bpp, uint32_t pa)
160{
161 assert(regs);
162 /*
163 * Init sequence for dispc is in chapter 7.6.5.1.4 p. 1810,
164 * no idea what parts of that work.
165 */
166
167 /* Disable all interrupts */
168 regs->irqenable = 0;
169
170 /* Pixel format specifics */
171 uint32_t attrib_pixel_format = 0;
172 uint32_t control_data_lanes = 0;
173 switch (bpp) {
174 case 32:
175 attrib_pixel_format = AMDM37X_DISPC_GFX_ATTRIBUTES_FORMAT_RGBX;
176 control_data_lanes = AMDM37X_DISPC_CONTROL_TFTDATALINES_24B;
177 break;
178 case 24:
179 attrib_pixel_format = AMDM37X_DISPC_GFX_ATTRIBUTES_FORMAT_RGB24;
180 control_data_lanes = AMDM37X_DISPC_CONTROL_TFTDATALINES_24B;
181 break;
182 case 16:
183 attrib_pixel_format = AMDM37X_DISPC_GFX_ATTRIBUTES_FORMAT_RGB16;
184 control_data_lanes = AMDM37X_DISPC_CONTROL_TFTDATALINES_16B;
185 break;
186 default:
187 return EINVAL;
188 }
189
190 /* Prepare sizes */
191 const uint32_t size_reg =
192 (((x - 1) & AMDM37X_DISPC_SIZE_WIDTH_MASK) <<
193 AMDM37X_DISPC_SIZE_WIDTH_SHIFT) |
194 (((y - 1) & AMDM37X_DISPC_SIZE_HEIGHT_MASK) <<
195 AMDM37X_DISPC_SIZE_HEIGHT_SHIFT);
196
197 /* modes taken from u-boot, for 1024x768 */
198 // TODO replace magic values with actual correct values
199#if 0
200 regs->timing_h = 0x1a4024c9;
201 regs->timing_v = 0x02c00509;
202 regs->pol_freq = 0x00007028;
203 regs->divisor = 0x00010001;
204#endif
205
206 /* setup output */
207 regs->size_lcd = size_reg;
208 regs->size_dig = size_reg;
209
210 /* Nice blue default color */
211 regs->default_color[0] = 0x0000ff;
212 regs->default_color[1] = 0x0000ff;
213
214 /* Setup control register */
215 uint32_t control = 0 |
216 AMDM37X_DISPC_CONTROL_PCKFREEENABLE_FLAG |
217 (control_data_lanes << AMDM37X_DISPC_CONTROL_TFTDATALINES_SHIFT) |
218 AMDM37X_DISPC_CONTROL_GPOUT0_FLAG |
219 AMDM37X_DISPC_CONTROL_GPOUT1_FLAG;
220 regs->control = control;
221
222 /* No gamma stuff only data */
223 uint32_t config = (AMDM37X_DISPC_CONFIG_LOADMODE_DATAEVERYFRAME <<
224 AMDM37X_DISPC_CONFIG_LOADMODE_SHIFT);
225 regs->config = config;
226
227 /* Set framebuffer base address */
228 regs->gfx.ba[0] = pa;
229 regs->gfx.ba[1] = pa;
230 regs->gfx.position = 0;
231
232 /* Setup fb size */
233 regs->gfx.size = size_reg;
234
235 /* Set pixel format */
236 uint32_t attribs = 0 |
237 (attrib_pixel_format << AMDM37X_DISPC_GFX_ATTRIBUTES_FORMAT_SHIFT);
238 regs->gfx.attributes = attribs;
239
240 /* 0x03ff03c0 is the default */
241 regs->gfx.fifo_threshold = 0x03ff03c0;
242 /*
243 * This value should be stride - width, 1 means next pixel i.e.
244 * stride == width
245 */
246 regs->gfx.row_inc = 1;
247 /* number of bytes to next pixel in BPP multiples */
248 regs->gfx.pixel_inc = 1;
249 /* only used if video is played over fb */
250 regs->gfx.window_skip = 0;
251 /* Gamma and palette table */
252 regs->gfx.table_ba = 0;
253
254 /* enable frame buffer graphics */
255 regs->gfx.attributes |= AMDM37X_DISPC_GFX_ATTRIBUTES_ENABLE_FLAG;
256 /* Update register values */
257 regs->control |= AMDM37X_DISPC_CONTROL_GOLCD_FLAG;
258 regs->control |= AMDM37X_DISPC_CONTROL_GODIGITAL_FLAG;
259 /* Enable output */
260 regs->control |= AMDM37X_DISPC_CONTROL_LCD_ENABLE_FLAG;
261 regs->control |= AMDM37X_DISPC_CONTROL_DIGITAL_ENABLE_FLAG;
262 return EOK;
263}
264
265static errno_t amdm37x_change_mode(amdm37x_dispc_t *dispc, unsigned x,
266 unsigned y, visual_t visual)
267{
268 assert((size_t)visual < sizeof(pixel2visual_table) / sizeof(pixel2visual_table[0]));
269 const unsigned bpp = pixel2visual_table[visual].bpp;
270 pixel2visual_t p2v = pixel2visual_table[visual].func;
271 ddf_log_note("Setting mode: %ux%ux%u\n", x, y, bpp * 8);
272 const size_t size = ALIGN_UP(x * y * bpp, PAGE_SIZE);
273 uintptr_t pa;
274 void *buffer = AS_AREA_ANY;
275 errno_t ret = dmamem_map_anonymous(size, DMAMEM_4GiB,
276 AS_AREA_READ | AS_AREA_WRITE, 0, &pa, &buffer);
277 if (ret != EOK) {
278 ddf_log_error("Failed to get new FB\n");
279 return ret;
280 }
281 if (dispc->fb_data)
282 dmamem_unmap_anonymous(dispc->fb_data);
283
284 dispc->fb_data = buffer;
285 amdm37x_dispc_setup_fb(dispc->regs, x, y, bpp * 8, (uint32_t)pa);
286 dispc->active_fb.width = x;
287 dispc->active_fb.height = y;
288 dispc->active_fb.pitch = 0;
289 dispc->active_fb.bpp = bpp;
290 dispc->active_fb.pixel2visual = p2v;
291 dispc->rect.p0.x = 0;
292 dispc->rect.p0.y = 0;
293 dispc->rect.p1.x = x;
294 dispc->rect.p1.y = y;
295 dispc->clip_rect = dispc->rect;
296 dispc->size = size;
297
298 return EOK;
299}
300
301#define FB_POS(d, x, y) \
302 (((y) * ((d)->active_fb.width + (d)->active_fb.pitch) + (x)) \
303 * (d)->active_fb.bpp)
304
305static errno_t amdm37x_ddev_get_gc(void *arg, sysarg_t *arg2, sysarg_t *arg3)
306{
307 amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
308
309 *arg2 = ddf_fun_get_handle(dispc->fun);
310 *arg3 = 42;
311 return EOK;
312}
313
314static errno_t amdm37x_ddev_get_info(void *arg, ddev_info_t *info)
315{
316 amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
317
318 ddev_info_init(info);
319 info->rect.p0.x = 0;
320 info->rect.p0.y = 0;
321 info->rect.p1.x = dispc->active_fb.width;
322 info->rect.p1.y = dispc->active_fb.height;
323 return EOK;
324}
325
326/** Set clipping rectangle on AMDM37x display controller.
327 *
328 * @param arg AMDM37x display controller
329 * @param rect Rectangle
330 *
331 * @return EOK on success or an error code
332 */
333static errno_t amdm37x_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
334{
335 amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
336
337 if (rect != NULL)
338 gfx_rect_clip(rect, &dispc->rect, &dispc->clip_rect);
339 else
340 dispc->clip_rect = dispc->rect;
341
342 return EOK;
343}
344
345/** Set color on AMDM37x display controller.
346 *
347 * Set drawing color on AMDM37x GC.
348 *
349 * @param arg AMDM37x display controller
350 * @param color Color
351 *
352 * @return EOK on success or an error code
353 */
354static errno_t amdm37x_gc_set_color(void *arg, gfx_color_t *color)
355{
356 amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
357 uint16_t r, g, b;
358
359 gfx_color_get_rgb_i16(color, &r, &g, &b);
360 dispc->color = PIXEL(0, r >> 8, g >> 8, b >> 8);
361 return EOK;
362}
363
364/** Fill rectangle on AMDM37x display controller.
365 *
366 * @param arg AMDM37x display controller
367 * @param rect Rectangle
368 *
369 * @return EOK on success or an error code
370 */
371static errno_t amdm37x_gc_fill_rect(void *arg, gfx_rect_t *rect)
372{
373 amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
374 gfx_rect_t crect;
375 gfx_coord_t x, y;
376
377 /* Make sure we have a sorted, clipped rectangle */
378 gfx_rect_clip(rect, &dispc->clip_rect, &crect);
379
380 for (y = crect.p0.y; y < crect.p1.y; y++) {
381 for (x = crect.p0.x; x < crect.p1.x; x++) {
382 dispc->active_fb.pixel2visual(dispc->fb_data +
383 FB_POS(dispc, x, y), dispc->color);
384 }
385 }
386
387 return EOK;
388}
389
390/** Create bitmap in AMDM37x GC.
391 *
392 * @param arg AMDM37x display controller
393 * @param params Bitmap params
394 * @param alloc Bitmap allocation info or @c NULL
395 * @param rbm Place to store pointer to new bitmap
396 * @return EOK on success or an error code
397 */
398errno_t amdm37x_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
399 gfx_bitmap_alloc_t *alloc, void **rbm)
400{
401 amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
402 amdm37x_bitmap_t *dcbm = NULL;
403 gfx_coord2_t dim;
404 errno_t rc;
405
406 /* Check that we support all required flags */
407 if ((params->flags & ~(bmpf_color_key | bmpf_colorize)) != 0)
408 return ENOTSUP;
409
410 dcbm = calloc(1, sizeof(amdm37x_bitmap_t));
411 if (dcbm == NULL)
412 return ENOMEM;
413
414 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
415 dcbm->rect = params->rect;
416 dcbm->flags = params->flags;
417
418 if (alloc == NULL) {
419 dcbm->alloc.pitch = dim.x * sizeof(uint32_t);
420 dcbm->alloc.off0 = 0;
421 dcbm->alloc.pixels = malloc(dcbm->alloc.pitch * dim.y);
422 dcbm->myalloc = true;
423
424 if (dcbm->alloc.pixels == NULL) {
425 rc = ENOMEM;
426 goto error;
427 }
428 } else {
429 dcbm->alloc = *alloc;
430 }
431
432 dcbm->dispc = dispc;
433 *rbm = (void *)dcbm;
434 return EOK;
435error:
436 if (rbm != NULL)
437 free(dcbm);
438 return rc;
439}
440
441/** Destroy bitmap in AMDM37x GC.
442 *
443 * @param bm Bitmap
444 * @return EOK on success or an error code
445 */
446static errno_t amdm37x_gc_bitmap_destroy(void *bm)
447{
448 amdm37x_bitmap_t *dcbm = (amdm37x_bitmap_t *)bm;
449 if (dcbm->myalloc)
450 free(dcbm->alloc.pixels);
451 free(dcbm);
452 return EOK;
453}
454
455/** Render bitmap in AMDM37x GC.
456 *
457 * @param bm Bitmap
458 * @param srect0 Source rectangle or @c NULL
459 * @param offs0 Offset or @c NULL
460 * @return EOK on success or an error code
461 */
462static errno_t amdm37x_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
463 gfx_coord2_t *offs0)
464{
465 amdm37x_bitmap_t *dcbm = (amdm37x_bitmap_t *)bm;
466 amdm37x_dispc_t *dispc = dcbm->dispc;
467 gfx_rect_t srect;
468 gfx_rect_t drect;
469 gfx_rect_t skfbrect;
470 gfx_rect_t crect;
471 gfx_coord2_t offs;
472 gfx_coord2_t bmdim;
473 gfx_coord2_t dim;
474 gfx_coord2_t sp;
475 gfx_coord2_t dp;
476 gfx_coord2_t pos;
477 pixelmap_t pbm;
478 pixel_t color;
479
480 /* Clip source rectangle to bitmap bounds */
481
482 if (srect0 != NULL)
483 gfx_rect_clip(srect0, &dcbm->rect, &srect);
484 else
485 srect = dcbm->rect;
486
487 if (offs0 != NULL) {
488 offs = *offs0;
489 } else {
490 offs.x = 0;
491 offs.y = 0;
492 }
493
494 /* Destination rectangle */
495 gfx_rect_translate(&offs, &srect, &drect);
496 gfx_coord2_subtract(&drect.p1, &drect.p0, &dim);
497 gfx_coord2_subtract(&dcbm->rect.p1, &dcbm->rect.p0, &bmdim);
498
499 pbm.width = bmdim.x;
500 pbm.height = bmdim.y;
501 pbm.data = dcbm->alloc.pixels;
502
503 /* Transform AMDM37x clipping rectangle back to bitmap coordinate system */
504 gfx_rect_rtranslate(&offs, &dispc->clip_rect, &skfbrect);
505
506 /*
507 * Make sure we have a sorted source rectangle, clipped so that
508 * destination lies within AMDM37x bounding rectangle
509 */
510 gfx_rect_clip(&srect, &skfbrect, &crect);
511
512 if ((dcbm->flags & bmpf_color_key) == 0) {
513 /* Simple copy */
514 for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
515 for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
516 gfx_coord2_subtract(&pos, &dcbm->rect.p0, &sp);
517 gfx_coord2_add(&pos, &offs, &dp);
518
519 color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
520 dispc->active_fb.pixel2visual(dispc->fb_data +
521 FB_POS(dispc, dp.x, dp.y), color);
522 }
523 }
524 } else if ((dcbm->flags & bmpf_colorize) == 0) {
525 /* Color key */
526 for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
527 for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
528 gfx_coord2_subtract(&pos, &dcbm->rect.p0, &sp);
529 gfx_coord2_add(&pos, &offs, &dp);
530
531 color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
532 if (color != dcbm->key_color) {
533 dispc->active_fb.pixel2visual(dispc->fb_data +
534 FB_POS(dispc, dp.x, dp.y), color);
535 }
536 }
537 }
538 } else {
539 /* Color key & colorize */
540 for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
541 for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
542 gfx_coord2_subtract(&pos, &dcbm->rect.p0, &sp);
543 gfx_coord2_add(&pos, &offs, &dp);
544
545 color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
546 if (color != dcbm->key_color) {
547 dispc->active_fb.pixel2visual(dispc->fb_data +
548 FB_POS(dispc, dp.x, dp.y),
549 dcbm->dispc->color);
550 }
551 }
552 }
553 }
554
555 return EOK;
556}
557
558/** Get allocation info for bitmap in AMDM37x GC.
559 *
560 * @param bm Bitmap
561 * @param alloc Place to store allocation info
562 * @return EOK on success or an error code
563 */
564static errno_t amdm37x_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
565{
566 amdm37x_bitmap_t *dcbm = (amdm37x_bitmap_t *)bm;
567 *alloc = dcbm->alloc;
568 return EOK;
569}
570
571/**
572 * @}
573 */
Note: See TracBrowser for help on using the repository browser.