diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-05 21:17:26 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-05 21:17:26 +0400 |
commit | a09e9a7a4b907f2dfa9bdb2b98a1828ab4b340b2 (patch) | |
tree | c7a2df4e887573648eeaf8f7939889046990d3f6 /drivers/gpu/drm/msm/msm_fb.c | |
parent | 9ab073bc45b8b523cc39658925bb44bef35ca657 (diff) | |
parent | 86a7e1224a68511d3a1ae0b7e11581b9d37723ae (diff) | |
download | linux-a09e9a7a4b907f2dfa9bdb2b98a1828ab4b340b2.tar.xz |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm tree changes from Dave Airlie:
"This is the main drm pull request, I have some overlap with sound and
arm-soc, the sound patch is acked and may conflict based on -next
reports but should be a trivial fixup, which I'll leave to you!
Highlights:
- new drivers:
MSM driver from Rob Clark
- non-drm:
switcheroo and hdmi audio driver support for secondary GPU
poweroff, so drivers can use runtime PM to poweroff the GPUs. This
can save 5 or 6W on some optimus laptops.
- drm core:
combined GEM and TTM VMA manager
per-filp mmap permission tracking
initial rendernode support (via a runtime enable for now, until we get api stable),
remove old proc support,
lots of cleanups of legacy code
hdmi vendor infoframes and 4k modes
lots of gem/prime locking and races fixes
async pageflip scaffolding
drm bridge objects
- i915:
Haswell PC8+ support and eLLC support, HDMI 4K support, initial
per-process VMA pieces, watermark reworks, convert to generic hdmi
infoframes, encoder reworking, fastboot support,
- radeon:
CIK PM support, remove 3d blit code in favour of DMA engines,
Berlin GPU support, HDMI audio fixes
- nouveau:
secondary GPU power down support for optimus laptops, lots of
fixes, use MSI, VP3 engine support
- exynos:
runtime pm support for g2d, DT support, remove non-DT,
- tda998x i2c driver:
lots of fixes for sync issues
- gma500:
lots of cleanups
- rcar:
add LVDS support, fbdev emulation,
- tegra:
just minor fixes"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (684 commits)
drm/exynos: Fix build error with exynos_drm_connector.c
drm/exynos: Remove non-DT support in exynos_drm_fimd
drm/exynos: Remove non-DT support in exynos_hdmi
drm/exynos: Remove non-DT support in exynos_drm_g2d
drm/exynos: Remove non-DT support in exynos_hdmiphy
drm/exynos: Remove non-DT support in exynos_ddc
drm/exynos: Make Exynos DRM drivers depend on OF
drm/exynos: Consider fallback option to allocation fail
drm/exynos: fimd: move platform data parsing to separate function
drm/exynos: fimd: get signal polarities from device tree
drm/exynos: fimd: replace struct fb_videomode with videomode
drm/exynos: check a pixel format to a particular window layer
drm/exynos: fix fimd pixel format setting
drm/exynos: Add NULL pointer check
drm/exynos: Remove redundant error messages
drm/exynos: Add missing of.h header include
drm/exynos: Remove redundant NULL check in exynos_drm_buf
drm/exynos: add device tree support for rotator
drm/exynos: Add missing includes
drm/exynos: add runtime pm interfaces to g2d driver
...
Diffstat (limited to 'drivers/gpu/drm/msm/msm_fb.c')
-rw-r--r-- | drivers/gpu/drm/msm/msm_fb.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c new file mode 100644 index 000000000000..0286c0eeb10c --- /dev/null +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.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 "msm_drv.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +struct msm_framebuffer { + struct drm_framebuffer base; + const struct msm_format *format; + struct drm_gem_object *planes[2]; +}; +#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base) + + +static int msm_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); + return drm_gem_handle_create(file_priv, + msm_fb->planes[0], handle); +} + +static void msm_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct msm_framebuffer *msm_fb = to_msm_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 drm_gem_object *bo = msm_fb->planes[i]; + if (bo) + drm_gem_object_unreference_unlocked(bo); + } + + kfree(msm_fb); +} + +static int msm_framebuffer_dirty(struct drm_framebuffer *fb, + struct drm_file *file_priv, unsigned flags, unsigned color, + struct drm_clip_rect *clips, unsigned num_clips) +{ + return 0; +} + +static const struct drm_framebuffer_funcs msm_framebuffer_funcs = { + .create_handle = msm_framebuffer_create_handle, + .destroy = msm_framebuffer_destroy, + .dirty = msm_framebuffer_dirty, +}; + +#ifdef CONFIG_DEBUG_FS +void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) +{ + struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); + int i, n = drm_format_num_planes(fb->pixel_format); + + seq_printf(m, "fb: %dx%d@%4.4s (%2d, ID:%d)\n", + fb->width, fb->height, (char *)&fb->pixel_format, + fb->refcount.refcount.counter, fb->base.id); + + for (i = 0; i < n; i++) { + seq_printf(m, " %d: offset=%d pitch=%d, obj: ", + i, fb->offsets[i], fb->pitches[i]); + msm_gem_describe(msm_fb->planes[i], m); + } +} +#endif + +struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane) +{ + struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); + return msm_fb->planes[plane]; +} + +const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb) +{ + struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); + return msm_fb->format; +} + +struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, + struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_gem_object *bos[4] = {0}; + struct drm_framebuffer *fb; + int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); + + for (i = 0; i < n; i++) { + bos[i] = drm_gem_object_lookup(dev, file, + mode_cmd->handles[i]); + if (!bos[i]) { + ret = -ENXIO; + goto out_unref; + } + } + + fb = msm_framebuffer_init(dev, mode_cmd, bos); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); + goto out_unref; + } + + return fb; + +out_unref: + for (i = 0; i < n; i++) + drm_gem_object_unreference_unlocked(bos[i]); + return ERR_PTR(ret); +} + +struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, + struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + struct msm_framebuffer *msm_fb; + struct drm_framebuffer *fb = NULL; + const struct msm_format *format; + int ret, i, n; + unsigned int hsub, vsub; + + 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); + + n = drm_format_num_planes(mode_cmd->pixel_format); + hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); + vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); + + format = kms->funcs->get_format(kms, mode_cmd->pixel_format); + if (!format) { + dev_err(dev->dev, "unsupported pixel format: %4.4s\n", + (char *)&mode_cmd->pixel_format); + ret = -EINVAL; + goto fail; + } + + msm_fb = kzalloc(sizeof(*msm_fb), GFP_KERNEL); + if (!msm_fb) { + ret = -ENOMEM; + goto fail; + } + + fb = &msm_fb->base; + + msm_fb->format = format; + + for (i = 0; i < n; i++) { + unsigned int width = mode_cmd->width / (i ? hsub : 1); + unsigned int height = mode_cmd->height / (i ? vsub : 1); + unsigned int min_size; + + min_size = (height - 1) * mode_cmd->pitches[i] + + width * drm_format_plane_cpp(mode_cmd->pixel_format, i) + + mode_cmd->offsets[i]; + + if (bos[i]->size < min_size) { + ret = -EINVAL; + goto fail; + } + + msm_fb->planes[i] = bos[i]; + } + + drm_helper_mode_fill_fb_struct(fb, mode_cmd); + + ret = drm_framebuffer_init(dev, fb, &msm_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) + msm_framebuffer_destroy(fb); + + return ERR_PTR(ret); +} |