Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
6e9f798
Documentation
arch
block
crypto
drivers
accessibility
acpi
amba
ata
atm
auxdisplay
base
bcma
block
bluetooth
bus
cdrom
char
clk
clocksource
connector
cpufreq
cpuidle
crypto
dca
devfreq
dio
dma
edac
eisa
extcon
firewire
firmware
fmc
gpio
gpu
drm
armada
ast
bochs
bridge
cirrus
exynos
gma500
i2c
i810
i915
mga
mgag200
msm
nouveau
omapdrm
Kconfig
Makefile
TODO
omap_connector.c
omap_crtc.c
omap_debugfs.c
omap_dmm_priv.h
omap_dmm_tiler.c
omap_dmm_tiler.h
omap_drv.c
omap_drv.h
omap_encoder.c
omap_fb.c
omap_fbdev.c
omap_gem.c
omap_gem_dmabuf.c
omap_irq.c
omap_plane.c
tcm-sita.c
tcm-sita.h
tcm.h
panel
qxl
r128
radeon
rcar-du
savage
shmobile
sis
tdfx
tegra
tilcdc
ttm
udl
via
vmwgfx
Kconfig
Makefile
README.drm
ati_pcigart.c
drm_agpsupport.c
drm_auth.c
drm_buffer.c
drm_bufs.c
drm_cache.c
drm_context.c
drm_crtc.c
drm_crtc_helper.c
drm_crtc_internal.h
drm_debugfs.c
drm_dma.c
drm_dp_helper.c
drm_drv.c
drm_edid.c
drm_edid_load.c
drm_encoder_slave.c
drm_fb_cma_helper.c
drm_fb_helper.c
drm_flip_work.c
drm_fops.c
drm_gem.c
drm_gem_cma_helper.c
drm_global.c
drm_hashtab.c
drm_info.c
drm_ioc32.c
drm_ioctl.c
drm_irq.c
drm_lock.c
drm_memory.c
drm_mipi_dsi.c
drm_mm.c
drm_modes.c
drm_panel.c
drm_pci.c
drm_plane_helper.c
drm_platform.c
drm_prime.c
drm_probe_helper.c
drm_rect.c
drm_scatter.c
drm_stub.c
drm_sysfs.c
drm_trace.h
drm_trace_points.c
drm_usb.c
drm_vm.c
drm_vma_manager.c
host1x
vga
Makefile
hid
hsi
hv
hwmon
hwspinlock
i2c
ide
idle
iio
infiniband
input
iommu
ipack
irqchip
isdn
leds
lguest
macintosh
mailbox
mcb
md
media
memory
memstick
message
mfd
misc
mmc
mtd
net
nfc
ntb
nubus
of
oprofile
parisc
parport
pci
pcmcia
phy
pinctrl
platform
pnp
power
powercap
pps
ps3
ptp
pwm
rapidio
regulator
remoteproc
reset
rpmsg
rtc
s390
sbus
scsi
sfi
sh
sn
spi
spmi
ssb
staging
target
tc
thermal
tty
uio
usb
uwb
vfio
vhost
video
virt
virtio
vlynq
vme
w1
watchdog
xen
zorro
Kconfig
Makefile
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt/kvm
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
drivers
/
gpu
/
drm
/
omapdrm
/
omap_fb.c
Blame
Blame
Latest commit
History
History
485 lines (402 loc) · 13.1 KB
Breadcrumbs
linux
/
drivers
/
gpu
/
drm
/
omapdrm
/
omap_fb.c
Top
File metadata and controls
Code
Blame
485 lines (402 loc) · 13.1 KB
Raw
/* * drivers/gpu/drm/omapdrm/omap_fb.c * * Copyright (C) 2011 Texas Instruments * Author: Rob Clark <rob@ti.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "omap_drv.h" #include "omap_dmm_tiler.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" /* * framebuffer funcs */ /* per-format info: */ struct format { enum omap_color_mode dss_format; uint32_t pixel_format; struct { int stride_bpp; /* this times width is stride */ int sub_y; /* sub-sample in y dimension */ } planes[4]; bool yuv; }; static const struct format formats[] = { /* 16bpp [A]RGB: */ { OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565, {{2, 1}}, false }, /* RGB16-565 */ { OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */ { OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */ { OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */ { OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444, {{2, 1}}, false }, /* ARGB16-4444 */ { OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555, {{2, 1}}, false }, /* xRGB15-1555 */ { OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555, {{2, 1}}, false }, /* ARGB16-1555 */ /* 24bpp RGB: */ { OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888, {{3, 1}}, false }, /* RGB24-888 */ /* 32bpp [A]RGB: */ { OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888, {{4, 1}}, false }, /* RGBx24-8888 */ { OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888, {{4, 1}}, false }, /* xRGB24-8888 */ { OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888, {{4, 1}}, false }, /* RGBA32-8888 */ { OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888, {{4, 1}}, false }, /* ARGB32-8888 */ /* YUV: */ { OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12, {{1, 1}, {1, 2}}, true }, { OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV, {{2, 1}}, true }, { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY, {{2, 1}}, true }, }; /* convert from overlay's pixel formats bitmask to an array of fourcc's */ uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, uint32_t max_formats, enum omap_color_mode supported_modes) { uint32_t nformats = 0; int i = 0; for (i = 0; i < ARRAY_SIZE(formats) && nformats < max_formats; i++) if (formats[i].dss_format & supported_modes) pixel_formats[nformats++] = formats[i].pixel_format; return nformats; } /* per-plane info for the fb: */ struct plane { struct drm_gem_object *bo; uint32_t pitch; uint32_t offset; dma_addr_t paddr; }; #define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base) struct omap_framebuffer { struct drm_framebuffer base; const struct format *format; struct plane planes[4]; }; static int omap_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); return drm_gem_handle_create(file_priv, omap_fb->planes[0].bo, handle); } static void omap_framebuffer_destroy(struct drm_framebuffer *fb) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); int i, n = drm_format_num_planes(fb->pixel_format); DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); drm_framebuffer_cleanup(fb); for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; if (plane->bo) drm_gem_object_unreference_unlocked(plane->bo); } kfree(omap_fb); } static int omap_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips) { int i; drm_modeset_lock_all(fb->dev); for (i = 0; i < num_clips; i++) { omap_framebuffer_flush(fb, clips[i].x1, clips[i].y1, clips[i].x2 - clips[i].x1, clips[i].y2 - clips[i].y1); } drm_modeset_unlock_all(fb->dev); return 0; } static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .create_handle = omap_framebuffer_create_handle, .destroy = omap_framebuffer_destroy, .dirty = omap_framebuffer_dirty, }; static uint32_t get_linear_addr(struct plane *plane, const struct format *format, int n, int x, int y) { uint32_t offset; offset = plane->offset + (x * format->planes[n].stride_bpp) + (y * plane->pitch / format->planes[n].sub_y); return plane->paddr + offset; } /* update ovl info for scanout, handles cases of multi-planar fb's, etc. */ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, struct omap_drm_window *win, struct omap_overlay_info *info) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); const struct format *format = omap_fb->format; struct plane *plane = &omap_fb->planes[0]; uint32_t x, y, orient = 0; info->color_mode = format->dss_format; info->pos_x = win->crtc_x; info->pos_y = win->crtc_y; info->out_width = win->crtc_w; info->out_height = win->crtc_h; info->width = win->src_w; info->height = win->src_h; x = win->src_x; y = win->src_y; if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) { uint32_t w = win->src_w; uint32_t h = win->src_h; switch (win->rotation & 0xf) { default: dev_err(fb->dev->dev, "invalid rotation: %02x", (uint32_t)win->rotation); /* fallthru to default to no rotation */ case 0: case BIT(DRM_ROTATE_0): orient = 0; break; case BIT(DRM_ROTATE_90): orient = MASK_XY_FLIP | MASK_X_INVERT; break; case BIT(DRM_ROTATE_180): orient = MASK_X_INVERT | MASK_Y_INVERT; break; case BIT(DRM_ROTATE_270): orient = MASK_XY_FLIP | MASK_Y_INVERT; break; } if (win->rotation & BIT(DRM_REFLECT_X)) orient ^= MASK_X_INVERT; if (win->rotation & BIT(DRM_REFLECT_Y)) orient ^= MASK_Y_INVERT; /* adjust x,y offset for flip/invert: */ if (orient & MASK_XY_FLIP) swap(w, h); if (orient & MASK_Y_INVERT) y += h - 1; if (orient & MASK_X_INVERT) x += w - 1; omap_gem_rotated_paddr(plane->bo, orient, x, y, &info->paddr); info->rotation_type = OMAP_DSS_ROT_TILER; info->screen_width = omap_gem_tiled_stride(plane->bo, orient); } else { switch (win->rotation & 0xf) { case 0: case BIT(DRM_ROTATE_0): /* OK */ break; default: dev_warn(fb->dev->dev, "rotation '%d' ignored for non-tiled fb\n", win->rotation); win->rotation = 0; break; } info->paddr = get_linear_addr(plane, format, 0, x, y); info->rotation_type = OMAP_DSS_ROT_DMA; info->screen_width = plane->pitch; } /* convert to pixels: */ info->screen_width /= format->planes[0].stride_bpp; if (format->dss_format == OMAP_DSS_COLOR_NV12) { plane = &omap_fb->planes[1]; if (info->rotation_type == OMAP_DSS_ROT_TILER) { WARN_ON(!(omap_gem_flags(plane->bo) & OMAP_BO_TILED)); omap_gem_rotated_paddr(plane->bo, orient, x/2, y/2, &info->p_uv_addr); } else { info->p_uv_addr = get_linear_addr(plane, format, 1, x, y); } } else { info->p_uv_addr = 0; } } /* pin, prepare for scanout: */ int omap_framebuffer_pin(struct drm_framebuffer *fb) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); int ret, i, n = drm_format_num_planes(fb->pixel_format); for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true); if (ret) goto fail; omap_gem_dma_sync(plane->bo, DMA_TO_DEVICE); } return 0; fail: for (i--; i >= 0; i--) { struct plane *plane = &omap_fb->planes[i]; omap_gem_put_paddr(plane->bo); plane->paddr = 0; } return ret; } /* unpin, no longer being scanned out: */ int omap_framebuffer_unpin(struct drm_framebuffer *fb) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); int ret, i, n = drm_format_num_planes(fb->pixel_format); for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; ret = omap_gem_put_paddr(plane->bo); if (ret) goto fail; plane->paddr = 0; } return 0; fail: return ret; } struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); if (p >= drm_format_num_planes(fb->pixel_format)) return NULL; return omap_fb->planes[p].bo; } /* iterate thru all the connectors, returning ones that are attached * to the same fb.. */ struct drm_connector *omap_framebuffer_get_next_connector( struct drm_framebuffer *fb, struct drm_connector *from) { struct drm_device *dev = fb->dev; struct list_head *connector_list = &dev->mode_config.connector_list; struct drm_connector *connector = from; if (!from) return list_first_entry_or_null(connector_list, typeof(*from), head); list_for_each_entry_from(connector, connector_list, head) { if (connector != from) { struct drm_encoder *encoder = connector->encoder; struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; if (crtc && crtc->primary->fb == fb) return connector; } } return NULL; } /* flush an area of the framebuffer (in case of manual update display that * is not automatically flushed) */ void omap_framebuffer_flush(struct drm_framebuffer *fb, int x, int y, int w, int h) { struct drm_connector *connector = NULL; VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb); /* FIXME: This is racy - no protection against modeset config changes. */ while ((connector = omap_framebuffer_get_next_connector(fb, connector))) { /* only consider connectors that are part of a chain */ if (connector->encoder && connector->encoder->crtc) { /* TODO: maybe this should propagate thru the crtc who * could do the coordinate translation.. */ struct drm_crtc *crtc = connector->encoder->crtc; int cx = max(0, x - crtc->x); int cy = max(0, y - crtc->y); int cw = w + (x - crtc->x) - cx; int ch = h + (y - crtc->y) - cy; omap_connector_flush(connector, cx, cy, cw, ch); } } } #ifdef CONFIG_DEBUG_FS void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); int i, n = drm_format_num_planes(fb->pixel_format); seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height, (char *)&fb->pixel_format); for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; seq_printf(m, " %d: offset=%d pitch=%d, obj: ", i, plane->offset, plane->pitch); omap_gem_describe(plane->bo, m); } } #endif struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *bos[4]; struct drm_framebuffer *fb; int ret; ret = objects_lookup(dev, file, mode_cmd->pixel_format, bos, mode_cmd->handles); if (ret) return ERR_PTR(ret); fb = omap_framebuffer_init(dev, mode_cmd, bos); if (IS_ERR(fb)) { int i, n = drm_format_num_planes(mode_cmd->pixel_format); for (i = 0; i < n; i++) drm_gem_object_unreference_unlocked(bos[i]); return fb; } return fb; } struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) { struct omap_framebuffer *omap_fb; struct drm_framebuffer *fb = NULL; const struct format *format = NULL; int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", dev, mode_cmd, mode_cmd->width, mode_cmd->height, (char *)&mode_cmd->pixel_format); for (i = 0; i < ARRAY_SIZE(formats); i++) { if (formats[i].pixel_format == mode_cmd->pixel_format) { format = &formats[i]; break; } } if (!format) { dev_err(dev->dev, "unsupported pixel format: %4.4s\n", (char *)&mode_cmd->pixel_format); ret = -EINVAL; goto fail; } omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL); if (!omap_fb) { ret = -ENOMEM; goto fail; } fb = &omap_fb->base; omap_fb->format = format; for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; int size, pitch = mode_cmd->pitches[i]; if (pitch < (mode_cmd->width * format->planes[i].stride_bpp)) { dev_err(dev->dev, "provided buffer pitch is too small! %d < %d\n", pitch, mode_cmd->width * format->planes[i].stride_bpp); ret = -EINVAL; goto fail; } size = pitch * mode_cmd->height / format->planes[i].sub_y; if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) { dev_err(dev->dev, "provided buffer object is too small! %d < %d\n", bos[i]->size - mode_cmd->offsets[i], size); ret = -EINVAL; goto fail; } plane->bo = bos[i]; plane->offset = mode_cmd->offsets[i]; plane->pitch = pitch; plane->paddr = 0; } drm_helper_mode_fill_fb_struct(fb, mode_cmd); ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs); if (ret) { dev_err(dev->dev, "framebuffer init failed: %d\n", ret); goto fail; } DBG("create: FB ID: %d (%p)", fb->base.id, fb); return fb; fail: if (fb) omap_framebuffer_destroy(fb); return ERR_PTR(ret); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
You can’t perform that action at this time.