16
#include <kernel/thread/sync/mutex.h>
17
#include <kernel/printk.h>
18
#include <lib/libds/dlist.h>
22
#include <drivers/video/fb.h>
24
#include <framework/mod/options.h>
25
#include <mem/misc/pool.h>
27
#define MODOPS_FB_AMOUNT OPTION_GET(NUMBER, fb_amount)
30
struct dlist_head link;
34
static int fb_update_current_var(struct fb_info *info);
36
static void fb_default_copyarea(struct fb_info *info, const struct fb_copyarea *area);
37
static void fb_default_cursor(struct fb_info *info, const struct fb_cursor *cursor);
38
static void fb_default_imageblit(struct fb_info *info, const struct fb_image *image);
39
static void fb_default_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
41
struct mutex fb_static = MUTEX_INIT_STATIC;
42
POOL_DEF(fb_pool, struct fb_dev, MODOPS_FB_AMOUNT);
43
static DLIST_DEFINE(fb_list);
44
static unsigned int fb_count = 0;
46
#define fb_readb(addr) (*(uint8_t *) (addr))
47
#define fb_readw(addr) (*(uint16_t *) (addr))
48
#define fb_readl(addr) (*(uint32_t *) (addr))
49
#define fb_writeb(val, addr) (*(uint8_t *) (addr) = (val))
50
#define fb_writew(val, addr) (*(uint16_t *) (addr) = (val))
51
#define fb_writel(val, addr) (*(uint32_t *) (addr) = (val))
52
#define fb_memset memset
53
#define fb_memcpy_fromfb memcpy
54
#define fb_memcpy_tofb memcpy
56
static void fb_ops_fixup(struct fb_ops *ops) {
57
if (!ops->fb_copyarea) {
58
ops->fb_copyarea = fb_default_copyarea;
60
if (!ops->fb_imageblit) {
61
ops->fb_imageblit = fb_default_imageblit;
63
if (!ops->fb_fillrect) {
64
ops->fb_fillrect = fb_default_fillrect;
66
if (!ops->fb_cursor) {
67
ops->fb_cursor = fb_default_cursor;
71
struct fb_info *fb_create(const struct fb_ops *ops, char *map_base, size_t map_size) {
73
struct fb_info *info = NULL;
77
mutex_lock(&fb_static);
79
dev = pool_alloc(&fb_pool);
81
log_error("Failed to create framebuffer");
87
info->id = fb_count++;
88
dlist_init(&dev->link);
89
dlist_add_next(&dev->link, &fb_list);
90
info->screen_base = map_base;
91
info->screen_size = map_size;
93
memcpy(&info->ops, ops, sizeof(struct fb_ops));
94
fb_ops_fixup(&info->ops);
95
fb_update_current_var(info);
96
fb_devfs_create(info, map_base, map_size);
99
mutex_unlock(&fb_static);
104
void fb_delete(struct fb_info *info) {
105
struct fb_dev *dev = member_cast_out(info, struct fb_dev, info);
108
mutex_lock(&fb_static);
110
dlist_del(&dev->link);
111
pool_free(&fb_pool, dev);
113
mutex_unlock(&fb_static);
117
struct fb_info *fb_lookup(int id) {
121
mutex_lock(&fb_static);
123
struct fb_dev *fb_dev;
124
dlist_foreach_entry(fb_dev, &fb_list, link) {
125
if (fb_dev->info.id == id) {
131
mutex_unlock(&fb_static);
135
int fb_set_var(struct fb_info *info, const struct fb_var_screeninfo *var) {
138
assert(info != NULL);
141
if (info->ops.fb_set_var != NULL) {
142
ret = info->ops.fb_set_var(info, var);
146
memcpy(&info->var, var, sizeof(struct fb_var_screeninfo));
152
int fb_get_var(struct fb_info *info, struct fb_var_screeninfo *var) {
153
memcpy(var, &info->var, sizeof(struct fb_var_screeninfo));
157
void fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) {
158
info->ops.fb_copyarea(info, area);
161
void fb_cursor(struct fb_info *info, const struct fb_cursor *cursor) {
162
info->ops.fb_cursor(info, cursor);
165
void fb_imageblit(struct fb_info *info, const struct fb_image *image) {
166
info->ops.fb_imageblit(info, image);
169
#define _val_fixup(x, low, high) (min((high), max((low), (x))))
170
void fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) {
175
struct fb_fillrect r = *rect;
176
r.dx = _val_fixup(rect->dx, 0, info->var.xres);
177
r.dy = _val_fixup(rect->dy, 0, info->var.yres);
178
r.width = _val_fixup(rect->width, 0, info->var.xres - r.dx);
179
r.height = _val_fixup(rect->height, 0, info->var.yres - r.dy);
181
info->ops.fb_fillrect(info, &r);
184
static int fb_update_current_var(struct fb_info *info) {
185
if (info->ops.fb_get_var != NULL) {
186
return info->ops.fb_get_var(info, &info->var);
191
static void bitcpy(uint32_t *dst, uint32_t dstn, uint32_t *src, uint32_t srcn,
193
uint32_t mask1, mask2, loff, roff, lval, rval, left;
199
if (len == 0) return;
201
mask1 = ~(uint32_t)0 << dstn;
202
mask2 = ~(~(uint32_t)0 << (dstn + len) % (sizeof(*dst) * CHAR_BIT));
206
if (dstn + len <= sizeof(*dst) * CHAR_BIT) {
207
mask1 &= mask2 != 0 ? mask2 : mask1;
208
fb_writel((fb_readl(src) & mask1) | (fb_readl(dst) & ~mask1), dst);
212
fb_writel((fb_readl(src) & mask1) | (fb_readl(dst) & ~mask1), dst);
214
len -= sizeof(*dst) * CHAR_BIT - dstn;
217
len /= sizeof(*dst) * CHAR_BIT;
219
fb_writel(fb_readl(src), dst);
224
fb_writel((fb_readl(src) & mask2) | (fb_readl(dst) & ~mask2), dst);
228
loff = (uint32_t)-shift % (sizeof(*dst) * CHAR_BIT);
229
roff = (uint32_t)shift % (sizeof(*dst) * CHAR_BIT);
231
if (dstn + len <= sizeof(*dst) * CHAR_BIT) {
232
mask1 &= mask2 != 0 ? mask2 : mask1;
234
fb_writel(((fb_readl(src) >> roff) & mask1) | (fb_readl(dst) & ~mask1), dst);
235
else if (srcn + len <= sizeof(*dst) * CHAR_BIT)
236
fb_writel(((fb_readl(src) << loff) & mask1) | (fb_readl(dst) & ~mask1), dst);
238
lval = fb_readl(src);
240
rval = fb_readl(src);
241
fb_writel((((lval << loff) | (rval >> roff)) & mask1) | (fb_readl(dst) & ~mask1), dst);
245
lval = fb_readl(src);
248
fb_writel(((lval >> roff) & mask1) | (fb_readl(dst) & ~mask1), dst);
250
len -= sizeof(*dst) * CHAR_BIT - dstn;
253
rval = fb_readl(src);
255
fb_writel((((lval << loff) | (fb_readl(dst) >> roff)) & mask1) | (fb_readl(dst) & ~mask1), dst);
258
len -= sizeof(*dst) * CHAR_BIT - dstn;
261
left = len % (sizeof(*dst) * CHAR_BIT);
262
len /= sizeof(*dst) * CHAR_BIT;
264
rval = fb_readl(src);
266
fb_writel((lval << loff) | (rval >> roff), dst);
272
fb_writel(((lval << loff) & mask2) | (fb_readl(dst) & ~mask2), dst);
274
rval = fb_readl(src);
275
fb_writel((((lval << loff) | (rval >> roff)) & mask2) | (fb_readl(dst) & ~mask2), dst);
281
static void bitcpy_rev(uint32_t *dst, uint32_t dstn, uint32_t *src,
282
uint32_t srcn, uint32_t len) {
283
uint32_t mask1, mask2, roff, loff, rval, lval, left;
289
if (len == 0) return;
291
dst += (len - 1) / (sizeof(*dst) * CHAR_BIT);
292
src += (len - 1) / (sizeof(*src) * CHAR_BIT);
293
if ((len - 1) % (sizeof(*dst) * CHAR_BIT) != 0) {
294
dstn += (len - 1) % (sizeof(*dst) * CHAR_BIT);
295
dst += dstn / (sizeof(*dst) * CHAR_BIT);
296
dstn %= sizeof(*dst) * CHAR_BIT;
297
srcn += (len - 1) % (sizeof(*src) * CHAR_BIT);
298
src += srcn / (sizeof(*src) * CHAR_BIT);
299
srcn %= sizeof(*src) * CHAR_BIT;
302
mask1 = ~(uint32_t)0 >> (sizeof(*dst) * CHAR_BIT - 1 - dstn);
303
mask2 = ~(~(uint32_t)0 >> (sizeof(*dst) * CHAR_BIT - 1 - (dstn - len) % (sizeof(*dst) * CHAR_BIT)));
307
if (dstn + 1 >= len) {
308
mask1 &= mask2 != 0 ? mask2 : mask1;
309
fb_writel((fb_readl(src) & mask1) | (fb_readl(dst) & ~mask1), dst);
313
fb_writel((fb_readl(src) & mask1) | (fb_readl(dst) & ~mask1), dst);
319
len /= sizeof(*dst) * CHAR_BIT;
321
fb_writel(fb_readl(src), dst);
326
fb_writel((fb_readl(src) & mask2) | (fb_readl(dst) & ~mask2), dst);
330
roff = (uint32_t)shift % (sizeof(*dst) * CHAR_BIT);
331
loff = (uint32_t)-shift % (sizeof(*dst) * CHAR_BIT);
333
if (dstn + 1 >= len) {
334
mask1 &= mask2 != 0 ? mask2 : mask1;
336
fb_writel(((fb_readl(src) << loff) & mask1) | (fb_readl(dst) & ~mask1), dst);
337
else if (srcn + 1 >= len)
338
fb_writel(((fb_readl(src) >> roff) & mask1) | (fb_readl(dst) & ~mask1), dst);
340
rval = fb_readl(src);
342
lval = fb_readl(src);
343
fb_writel((((rval >> roff) | (lval << loff)) & mask1) | (fb_readl(dst) & ~mask1), dst);
347
rval = fb_readl(src);
350
fb_writel(((rval << loff) & mask1) | (fb_readl(dst) & ~mask1), dst);
355
lval = fb_readl(src);
357
fb_writel((((rval >> roff) | (lval << loff)) & mask1) | (fb_readl(dst) & ~mask1), dst);
363
left = len % (sizeof(*dst) * CHAR_BIT);
364
len /= sizeof(*dst) * CHAR_BIT;
366
lval = fb_readl(src);
368
fb_writel((rval >> roff) | (lval << loff), dst);
374
fb_writel(((rval >> roff) & mask2) | (fb_readl(dst) & ~mask2), dst);
376
lval = fb_readl(src);
377
fb_writel((((rval << roff) | (lval >> loff)) & mask2) | (fb_readl(dst) & ~mask2), dst);
383
static void fb_default_copyarea(struct fb_info *info, const struct fb_copyarea *area) {
384
uint32_t width, height, *dst, dstn, *src, srcn;
386
assert(info != NULL);
387
assert(area != NULL);
389
if ((area->dx >= info->var.xres) || (area->dy >= info->var.yres)
390
|| (area->sx >= info->var.xres) || (area->sy >= info->var.yres)) return;
392
width = min(area->width, info->var.xres - max(area->sx, area->dx));
393
height = min(area->height, info->var.yres - max(area->sy, area->dy));
395
assert(info->screen_base != NULL);
396
dstn = srcn = (uintptr_t)info->screen_base % sizeof(*dst);
397
dst = src = (uint32_t *)((uintptr_t)info->screen_base - dstn);
398
dstn = dstn * CHAR_BIT + (area->dy * info->var.xres
399
+ area->dx) * info->var.bits_per_pixel;
400
srcn = srcn * CHAR_BIT + (area->sy * info->var.xres
401
+ area->sx) * info->var.bits_per_pixel;
403
if (((area->dy == area->sy) && (area->dx > area->sx))
404
|| (area->dy > area->sy)) {
405
dstn += height * info->var.xres * info->var.bits_per_pixel;
406
srcn += height * info->var.xres * info->var.bits_per_pixel;
407
while (height-- != 0) {
408
dstn -= info->var.xres * info->var.bits_per_pixel;
409
dst += dstn / (sizeof(*dst) * CHAR_BIT);
410
dstn %= sizeof(*dst) * CHAR_BIT;
411
srcn -= info->var.xres * info->var.bits_per_pixel;
412
src += srcn / (sizeof(*src) * CHAR_BIT);
413
srcn %= sizeof(*src) * CHAR_BIT;
414
bitcpy_rev(dst, dstn, src, srcn, width * info->var.bits_per_pixel);
418
while (height-- != 0) {
419
dst += dstn / (sizeof(*dst) * CHAR_BIT);
420
dstn %= sizeof(*dst) * CHAR_BIT;
421
src += srcn / (sizeof(*src) * CHAR_BIT);
422
srcn %= sizeof(*src) * CHAR_BIT;
423
bitcpy(dst, dstn, src, srcn, width * info->var.bits_per_pixel);
424
dstn += info->var.xres * info->var.bits_per_pixel;
425
srcn += info->var.xres * info->var.bits_per_pixel;
430
static uint32_t pixel_to_pat(uint32_t bpp, uint32_t pixel) {
431
pixel &= ~((uint32_t )-1 << bpp);
432
return bpp == 1 ? 0xffffffffUL * pixel
433
: bpp == 2 ? 0x55555555UL * pixel
434
: bpp == 4 ? 0x11111111UL * pixel
435
: bpp == 8 ? 0x01010101UL * pixel
436
: bpp == 12 ? 0x01001001UL * pixel
437
: bpp == 16 ? 0x00010001UL * pixel
438
: bpp == 24 ? 0x01000001UL * pixel
439
: bpp == 32 ? 0x00000001UL * pixel
443
static void bitfill(uint32_t *dst, uint32_t dstn, uint32_t pat,
444
uint32_t loff, uint32_t roff, uint32_t len) {
445
uint32_t mask1, mask2;
449
if (len == 0) return;
451
mask1 = ~(uint32_t)0 << dstn;
452
mask2 = ~(~(uint32_t)0 << (dstn + len) % (sizeof(*dst) * CHAR_BIT));
454
if (dstn + len <= sizeof(*dst) * CHAR_BIT) {
455
mask1 &= mask2 != 0 ? mask2 : mask1;
456
fb_writel((pat & mask1) | (fb_readl(dst) & ~mask1), dst);
460
fb_writel((pat & mask1) | (fb_readl(dst) & ~mask1), dst);
462
pat = (pat << loff) | (pat >> roff);
463
len -= sizeof(*dst) * CHAR_BIT - dstn;
466
len /= sizeof(*dst) * CHAR_BIT;
470
pat = (pat << loff) | (pat >> roff);
473
fb_writel((pat & mask2) | (fb_readl(dst) & ~mask2), dst);
477
static void bitfill_rev(uint32_t *dst, uint32_t dstn, uint32_t pat,
478
uint32_t loff, uint32_t roff, uint32_t len) {
479
uint32_t mask1, mask2;
483
if (len == 0) return;
485
mask1 = ~(uint32_t)0 << dstn;
486
mask2 = ~(~(uint32_t)0 << (dstn + len) % (sizeof(*dst) * CHAR_BIT));
488
if (dstn + len <= sizeof(*dst) * CHAR_BIT) {
489
mask1 &= mask2 != 0 ? mask2 : mask1;
490
fb_writel(((fb_readl(dst) ^ pat) & mask1) | (fb_readl(dst) & ~mask1), dst);
494
fb_writel(((fb_readl(dst) ^ pat) & mask1) | (fb_readl(dst) & ~mask1), dst);
496
pat = (pat << loff) | (pat >> roff);
497
len -= sizeof(*dst) * CHAR_BIT - dstn;
500
len /= sizeof(*dst) * CHAR_BIT;
502
fb_writel(fb_readl(dst) ^ pat, dst);
504
pat = (pat << loff) | (pat >> roff);
505
fb_writel(fb_readl(dst) ^ pat, dst);
507
pat = (pat << loff) | (pat >> roff);
508
fb_writel(fb_readl(dst) ^ pat, dst);
510
pat = (pat << loff) | (pat >> roff);
511
fb_writel(fb_readl(dst) ^ pat, dst);
513
pat = (pat << loff) | (pat >> roff);
517
fb_writel(fb_readl(dst) ^ pat, dst);
518
pat = (pat << loff) | (pat >> roff);
521
fb_writel(((fb_readl(dst) ^ pat) & mask2) | (fb_readl(dst) & ~mask2), dst);
525
static void fb_default_fillrect(struct fb_info *info, const struct fb_fillrect *rect) {
526
uint32_t width, height, pat_orig, pat, *dst, dstn, loff, roff;
527
void (*fill_op)(uint32_t *dst, uint32_t dstn, uint32_t pat,
528
uint32_t loff, uint32_t roff, uint32_t len);
530
assert(info != NULL);
531
assert(rect != NULL);
533
if ((rect->dx >= info->var.xres) || (rect->dy >= info->var.yres)) return;
535
width = min(rect->width, info->var.xres - rect->dx);
536
height = min(rect->height, info->var.yres - rect->dy);
538
pat_orig = pixel_to_pat(info->var.bits_per_pixel, rect->color);
540
assert(info->screen_base != NULL);
541
dstn = (uintptr_t)info->screen_base % sizeof(*dst);
542
dst = (uint32_t *)((uintptr_t)info->screen_base - dstn);
543
dstn = dstn * CHAR_BIT + (rect->dy * info->var.xres
544
+ rect->dx) * info->var.bits_per_pixel;
545
roff = sizeof(*dst) * CHAR_BIT % info->var.bits_per_pixel;
546
loff = info->var.bits_per_pixel - roff;
548
fill_op = rect->rop == ROP_COPY ? &bitfill : &bitfill_rev;
550
while (height-- != 0) {
551
dst += dstn / (sizeof(*dst) * CHAR_BIT);
552
dstn %= sizeof(*dst) * CHAR_BIT;
554
pat = roff == 0 ? pat_orig : (pat_orig << (dstn % info->var.bits_per_pixel))
555
| (pat_orig >> (info->var.bits_per_pixel - dstn % info->var.bits_per_pixel));
557
fill_op(dst, dstn, pat, loff, roff, width * info->var.bits_per_pixel);
558
dstn += info->var.xres * info->var.bits_per_pixel;
562
static void fb_default_imageblit(struct fb_info *info, const struct fb_image *image) {
565
struct fb_fillrect rect;
567
assert(info != NULL);
568
assert(image != NULL);
569
assert(image->depth == 1);
570
assert(image->width == 8);
572
rect.width = rect.height = 1;
574
for (j = 0; j < image->height; ++j) {
575
rect.dy = image->dy + j * rect.height;
576
for (i = 0; i < image->width; ++i) {
577
rect.dx = image->dx + i * rect.width;
578
rect.color = *(uint8_t *)(image->data + j) & (1 << ((image->width - i - 1)))
579
? image->fg_color : image->bg_color;
580
info->ops.fb_fillrect(info, &rect);
585
static void fb_default_cursor(struct fb_info *info, const struct fb_cursor *cursor) {
587
struct fb_fillrect rect;
589
assert(info != NULL);
590
assert(cursor != NULL);
592
if (!cursor->enable) return;
594
rect.width = rect.height = 1;
595
rect.rop = cursor->rop;
596
rect.color = cursor->image.fg_color;
597
for (j = 0; j < cursor->image.height; ++j) {
598
rect.dy = cursor->hot.y * cursor->image.height + j * rect.height;
599
for (i = 0; i < cursor->image.width; ++i) {
600
rect.dx = cursor->hot.x * cursor->image.width + i * rect.width;
601
info->ops.fb_fillrect(info, &rect);
606
int pix_fmt_has_alpha(enum pix_fmt fmt) {
607
return (fmt == RGBA8888) || (fmt == BGRA8888);
610
int pix_fmt_bpp(enum pix_fmt fmt) {
621
log_error("Wrong pixel format=%d, assume bpp=1", fmt);
626
int pix_fmt_chan_bits(enum pix_fmt fmt, enum pix_chan chan) {
630
if (chan == ALPHA_CHAN)
638
if (chan == ALPHA_CHAN)
640
if (chan == GREEN_CHAN)
644
log_error("Wrong pixel format=%d", fmt);
651
static const struct fb_rgb_conv {
652
uint8_t sr, sg, sb, sa, dr, dg, db, da;
654
[RGB888] = { 0, 8, 16, 24, 8, 8, 8, 0, },
655
[BGR888] = { 16, 8, 0, 24, 8, 8, 8, 0, },
656
[RGBA8888] = { 0, 8, 16, 24, 8, 8, 8, 8, },
657
[BGRA8888] = { 16, 8, 0, 24, 8, 8, 8, 8, },
658
[RGB565] = { 0, 5, 11, 16, 5, 6, 5, 0, },
659
[BGR565] = { 11, 5, 0, 16, 5, 6, 5, 0, },
662
static inline int fb_fmt_supported(enum pix_fmt fmt) {
664
(fmt == RGB888) || (fmt == BGR888) || (fmt == RGBA8888) ||
665
(fmt == BGRA8888) || (fmt == RGB565) || (fmt == BGR565);
668
static inline int fb_component_conv(int c, int in_dx, int out_dx) {
669
if (in_dx > out_dx) {
670
return c >> (in_dx - out_dx);
672
return c << (out_dx - in_dx);
676
static inline void fb_copy_pixel(char *dst, int px, int bpp) {
681
*(uint8_t *)dst = px;
684
*(uint16_t *)dst = px;
687
*(uint32_t *)dst = px;
690
for (i = 0; i < bpp; i++) {
698
int pix_fmt_convert(void *src, void *dst, int n,
699
enum pix_fmt in, enum pix_fmt out) {
700
int i, a, r, g, b, src_bpp, dst_bpp;
701
uint32_t in_px, out_px;
702
struct fb_rgb_conv in_cv, out_cv;
704
if (!fb_fmt_supported(in) || !fb_fmt_supported(out)) {
708
in_cv = rgb_conv[in];
709
out_cv = rgb_conv[out];
711
src_bpp = (in_cv.da + in_cv.dr + in_cv.dg + in_cv.db) / 8;
712
dst_bpp = (out_cv.da + out_cv.dr + out_cv.dg + out_cv.db) / 8;
714
for (i = 0; i < n; i++) {
715
in_px = *(uint32_t *)src;
717
a = ((in_px >> in_cv.sa) & 0xff) >> (8 - in_cv.da);
718
r = ((in_px >> in_cv.sr) & 0xff) >> (8 - in_cv.dr);
719
g = ((in_px >> in_cv.sg) & 0xff) >> (8 - in_cv.dg);
720
b = ((in_px >> in_cv.sb) & 0xff) >> (8 - in_cv.db);
727
a = fb_component_conv(a, in_cv.da, out_cv.da);
729
r = fb_component_conv(r, in_cv.dr, out_cv.dr);
730
g = fb_component_conv(g, in_cv.dg, out_cv.dg);
731
b = fb_component_conv(b, in_cv.db, out_cv.db);
733
out_px = (a << out_cv.sa) | (r << out_cv.sr) |
734
(g << out_cv.sg) | (b << out_cv.sb);
736
fb_copy_pixel(dst, out_px, dst_bpp);