Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (c) 2015 MediaTek Inc.
  3 *
  4 * This program is free software; you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License version 2 as
  6 * published by the Free Software Foundation.
  7 *
  8 * This program is distributed in the hope that it will be useful,
  9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11 * GNU General Public License for more details.
 12 */
 13
 14#include <drm/drmP.h>
 15#include <drm/drm_crtc_helper.h>
 16#include <drm/drm_fb_helper.h>
 17#include <drm/drm_gem.h>
 18#include <linux/dma-buf.h>
 19#include <linux/reservation.h>
 20
 21#include "mtk_drm_drv.h"
 22#include "mtk_drm_fb.h"
 23#include "mtk_drm_gem.h"
 24
 25/*
 26 * mtk specific framebuffer structure.
 27 *
 28 * @fb: drm framebuffer object.
 29 * @gem_obj: array of gem objects.
 30 */
 31struct mtk_drm_fb {
 32	struct drm_framebuffer	base;
 33	/* For now we only support a single plane */
 34	struct drm_gem_object	*gem_obj;
 35};
 36
 37#define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base)
 38
 39struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb)
 40{
 41	struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
 42
 43	return mtk_fb->gem_obj;
 44}
 45
 46static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb,
 47				    struct drm_file *file_priv,
 48				    unsigned int *handle)
 49{
 50	struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
 51
 52	return drm_gem_handle_create(file_priv, mtk_fb->gem_obj, handle);
 53}
 54
 55static void mtk_drm_fb_destroy(struct drm_framebuffer *fb)
 56{
 57	struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
 58
 59	drm_framebuffer_cleanup(fb);
 60
 61	drm_gem_object_put_unlocked(mtk_fb->gem_obj);
 62
 63	kfree(mtk_fb);
 64}
 65
 66static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
 67	.create_handle = mtk_drm_fb_create_handle,
 68	.destroy = mtk_drm_fb_destroy,
 69};
 70
 71static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev,
 72					const struct drm_mode_fb_cmd2 *mode,
 73					struct drm_gem_object *obj)
 74{
 75	struct mtk_drm_fb *mtk_fb;
 76	int ret;
 77
 78	if (drm_format_num_planes(mode->pixel_format) != 1)
 79		return ERR_PTR(-EINVAL);
 80
 81	mtk_fb = kzalloc(sizeof(*mtk_fb), GFP_KERNEL);
 82	if (!mtk_fb)
 83		return ERR_PTR(-ENOMEM);
 84
 85	drm_helper_mode_fill_fb_struct(dev, &mtk_fb->base, mode);
 86
 87	mtk_fb->gem_obj = obj;
 88
 89	ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs);
 90	if (ret) {
 91		DRM_ERROR("failed to initialize framebuffer\n");
 92		kfree(mtk_fb);
 93		return ERR_PTR(ret);
 94	}
 95
 96	return mtk_fb;
 97}
 98
 99/*
100 * Wait for any exclusive fence in fb's gem object's reservation object.
101 *
102 * Returns -ERESTARTSYS if interrupted, else 0.
103 */
104int mtk_fb_wait(struct drm_framebuffer *fb)
105{
106	struct drm_gem_object *gem;
107	struct reservation_object *resv;
108	long ret;
109
110	if (!fb)
111		return 0;
112
113	gem = mtk_fb_get_gem_obj(fb);
114	if (!gem || !gem->dma_buf || !gem->dma_buf->resv)
115		return 0;
116
117	resv = gem->dma_buf->resv;
118	ret = reservation_object_wait_timeout_rcu(resv, false, true,
119						  MAX_SCHEDULE_TIMEOUT);
120	/* MAX_SCHEDULE_TIMEOUT on success, -ERESTARTSYS if interrupted */
121	if (WARN_ON(ret < 0))
122		return ret;
123
124	return 0;
125}
126
127struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
128					       struct drm_file *file,
129					       const struct drm_mode_fb_cmd2 *cmd)
130{
131	struct mtk_drm_fb *mtk_fb;
132	struct drm_gem_object *gem;
133	unsigned int width = cmd->width;
134	unsigned int height = cmd->height;
135	unsigned int size, bpp;
136	int ret;
137
138	if (drm_format_num_planes(cmd->pixel_format) != 1)
139		return ERR_PTR(-EINVAL);
140
141	gem = drm_gem_object_lookup(file, cmd->handles[0]);
142	if (!gem)
143		return ERR_PTR(-ENOENT);
144
145	bpp = drm_format_plane_cpp(cmd->pixel_format, 0);
146	size = (height - 1) * cmd->pitches[0] + width * bpp;
147	size += cmd->offsets[0];
148
149	if (gem->size < size) {
150		ret = -EINVAL;
151		goto unreference;
152	}
153
154	mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);
155	if (IS_ERR(mtk_fb)) {
156		ret = PTR_ERR(mtk_fb);
157		goto unreference;
158	}
159
160	return &mtk_fb->base;
161
162unreference:
163	drm_gem_object_put_unlocked(gem);
164	return ERR_PTR(ret);
165}