Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2012 Russell King
  4 */
  5
  6#include <drm/drm_modeset_helper.h>
  7#include <drm/drm_fb_helper.h>
  8#include <drm/drm_fourcc.h>
  9#include <drm/drm_gem_framebuffer_helper.h>
 10
 11#include "armada_drm.h"
 12#include "armada_fb.h"
 13#include "armada_gem.h"
 14#include "armada_hw.h"
 15
 16static const struct drm_framebuffer_funcs armada_fb_funcs = {
 17	.destroy	= drm_gem_fb_destroy,
 18	.create_handle	= drm_gem_fb_create_handle,
 19};
 20
 21struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev,
 22	const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
 23{
 24	struct armada_framebuffer *dfb;
 25	uint8_t format, config;
 26	int ret;
 27
 28	switch (mode->pixel_format) {
 29#define FMT(drm, fmt, mod)		\
 30	case DRM_FORMAT_##drm:		\
 31		format = CFG_##fmt;	\
 32		config = mod;		\
 33		break
 34	FMT(RGB565,	565,		CFG_SWAPRB);
 35	FMT(BGR565,	565,		0);
 36	FMT(ARGB1555,	1555,		CFG_SWAPRB);
 37	FMT(ABGR1555,	1555,		0);
 38	FMT(RGB888,	888PACK,	CFG_SWAPRB);
 39	FMT(BGR888,	888PACK,	0);
 40	FMT(XRGB8888,	X888,		CFG_SWAPRB);
 41	FMT(XBGR8888,	X888,		0);
 42	FMT(ARGB8888,	8888,		CFG_SWAPRB);
 43	FMT(ABGR8888,	8888,		0);
 44	FMT(YUYV,	422PACK,	CFG_YUV2RGB | CFG_SWAPYU | CFG_SWAPUV);
 45	FMT(UYVY,	422PACK,	CFG_YUV2RGB);
 46	FMT(VYUY,	422PACK,	CFG_YUV2RGB | CFG_SWAPUV);
 47	FMT(YVYU,	422PACK,	CFG_YUV2RGB | CFG_SWAPYU);
 48	FMT(YUV422,	422,		CFG_YUV2RGB);
 49	FMT(YVU422,	422,		CFG_YUV2RGB | CFG_SWAPUV);
 50	FMT(YUV420,	420,		CFG_YUV2RGB);
 51	FMT(YVU420,	420,		CFG_YUV2RGB | CFG_SWAPUV);
 52	FMT(C8,		PSEUDO8,	0);
 53#undef FMT
 54	default:
 55		return ERR_PTR(-EINVAL);
 56	}
 57
 58	dfb = kzalloc(sizeof(*dfb), GFP_KERNEL);
 59	if (!dfb) {
 60		DRM_ERROR("failed to allocate Armada fb object\n");
 61		return ERR_PTR(-ENOMEM);
 62	}
 63
 64	dfb->fmt = format;
 65	dfb->mod = config;
 66	dfb->fb.obj[0] = &obj->obj;
 67
 68	drm_helper_mode_fill_fb_struct(dev, &dfb->fb, mode);
 69
 70	ret = drm_framebuffer_init(dev, &dfb->fb, &armada_fb_funcs);
 71	if (ret) {
 72		kfree(dfb);
 73		return ERR_PTR(ret);
 74	}
 75
 76	/*
 77	 * Take a reference on our object as we're successful - the
 78	 * caller already holds a reference, which keeps us safe for
 79	 * the above call, but the caller will drop their reference
 80	 * to it.  Hence we need to take our own reference.
 81	 */
 82	drm_gem_object_get(&obj->obj);
 83
 84	return dfb;
 85}
 86
 87struct drm_framebuffer *armada_fb_create(struct drm_device *dev,
 88	struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode)
 89{
 90	const struct drm_format_info *info = drm_get_format_info(dev, mode);
 91	struct armada_gem_object *obj;
 92	struct armada_framebuffer *dfb;
 93	int ret;
 94
 95	DRM_DEBUG_DRIVER("w%u h%u pf%08x f%u p%u,%u,%u\n",
 96		mode->width, mode->height, mode->pixel_format,
 97		mode->flags, mode->pitches[0], mode->pitches[1],
 98		mode->pitches[2]);
 99
100	/* We can only handle a single plane at the moment */
101	if (info->num_planes > 1 &&
102	    (mode->handles[0] != mode->handles[1] ||
103	     mode->handles[0] != mode->handles[2])) {
104		ret = -EINVAL;
105		goto err;
106	}
107
108	obj = armada_gem_object_lookup(dfile, mode->handles[0]);
109	if (!obj) {
110		ret = -ENOENT;
111		goto err;
112	}
113
114	if (obj->obj.import_attach && !obj->sgt) {
115		ret = armada_gem_map_import(obj);
116		if (ret)
117			goto err_unref;
118	}
119
120	/* Framebuffer objects must have a valid device address for scanout */
121	if (!obj->mapped) {
122		ret = -EINVAL;
123		goto err_unref;
124	}
125
126	dfb = armada_framebuffer_create(dev, mode, obj);
127	if (IS_ERR(dfb)) {
128		ret = PTR_ERR(dfb);
129		goto err;
130	}
131
132	drm_gem_object_put(&obj->obj);
133
134	return &dfb->fb;
135
136 err_unref:
137	drm_gem_object_put(&obj->obj);
138 err:
139	DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
140	return ERR_PTR(ret);
141}