Linux Audio

Check our new training course

Linux BSP upgrade and security maintenance

Need help to get security updates for your Linux BSP?
Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (C) 2012 Russell King
  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#include <drm/drmP.h>
  9#include <drm/drm_crtc_helper.h>
 10#include <drm/drm_fb_helper.h>
 11#include "armada_drm.h"
 12#include "armada_fb.h"
 13#include "armada_gem.h"
 14#include "armada_hw.h"
 15
 16static void armada_fb_destroy(struct drm_framebuffer *fb)
 17{
 18	struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb);
 19
 20	drm_framebuffer_cleanup(&dfb->fb);
 21	drm_gem_object_unreference_unlocked(&dfb->obj->obj);
 22	kfree(dfb);
 23}
 24
 25static int armada_fb_create_handle(struct drm_framebuffer *fb,
 26	struct drm_file *dfile, unsigned int *handle)
 27{
 28	struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb);
 29	return drm_gem_handle_create(dfile, &dfb->obj->obj, handle);
 30}
 31
 32static const struct drm_framebuffer_funcs armada_fb_funcs = {
 33	.destroy	= armada_fb_destroy,
 34	.create_handle	= armada_fb_create_handle,
 35};
 36
 37struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev,
 38	const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
 39{
 40	struct armada_framebuffer *dfb;
 41	uint8_t format, config;
 42	int ret;
 43
 44	switch (mode->pixel_format) {
 45#define FMT(drm, fmt, mod)		\
 46	case DRM_FORMAT_##drm:		\
 47		format = CFG_##fmt;	\
 48		config = mod;		\
 49		break
 50	FMT(RGB565,	565,		CFG_SWAPRB);
 51	FMT(BGR565,	565,		0);
 52	FMT(ARGB1555,	1555,		CFG_SWAPRB);
 53	FMT(ABGR1555,	1555,		0);
 54	FMT(RGB888,	888PACK,	CFG_SWAPRB);
 55	FMT(BGR888,	888PACK,	0);
 56	FMT(XRGB8888,	X888,		CFG_SWAPRB);
 57	FMT(XBGR8888,	X888,		0);
 58	FMT(ARGB8888,	8888,		CFG_SWAPRB);
 59	FMT(ABGR8888,	8888,		0);
 60	FMT(YUYV,	422PACK,	CFG_YUV2RGB | CFG_SWAPYU | CFG_SWAPUV);
 61	FMT(UYVY,	422PACK,	CFG_YUV2RGB);
 62	FMT(VYUY,	422PACK,	CFG_YUV2RGB | CFG_SWAPUV);
 63	FMT(YVYU,	422PACK,	CFG_YUV2RGB | CFG_SWAPYU);
 64	FMT(YUV422,	422,		CFG_YUV2RGB);
 65	FMT(YVU422,	422,		CFG_YUV2RGB | CFG_SWAPUV);
 66	FMT(YUV420,	420,		CFG_YUV2RGB);
 67	FMT(YVU420,	420,		CFG_YUV2RGB | CFG_SWAPUV);
 68	FMT(C8,		PSEUDO8,	0);
 69#undef FMT
 70	default:
 71		return ERR_PTR(-EINVAL);
 72	}
 73
 74	dfb = kzalloc(sizeof(*dfb), GFP_KERNEL);
 75	if (!dfb) {
 76		DRM_ERROR("failed to allocate Armada fb object\n");
 77		return ERR_PTR(-ENOMEM);
 78	}
 79
 80	dfb->fmt = format;
 81	dfb->mod = config;
 82	dfb->obj = obj;
 83
 84	drm_helper_mode_fill_fb_struct(&dfb->fb, mode);
 85
 86	ret = drm_framebuffer_init(dev, &dfb->fb, &armada_fb_funcs);
 87	if (ret) {
 88		kfree(dfb);
 89		return ERR_PTR(ret);
 90	}
 91
 92	/*
 93	 * Take a reference on our object as we're successful - the
 94	 * caller already holds a reference, which keeps us safe for
 95	 * the above call, but the caller will drop their reference
 96	 * to it.  Hence we need to take our own reference.
 97	 */
 98	drm_gem_object_reference(&obj->obj);
 99
100	return dfb;
101}
102
103static struct drm_framebuffer *armada_fb_create(struct drm_device *dev,
104	struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode)
105{
106	struct armada_gem_object *obj;
107	struct armada_framebuffer *dfb;
108	int ret;
109
110	DRM_DEBUG_DRIVER("w%u h%u pf%08x f%u p%u,%u,%u\n",
111		mode->width, mode->height, mode->pixel_format,
112		mode->flags, mode->pitches[0], mode->pitches[1],
113		mode->pitches[2]);
114
115	/* We can only handle a single plane at the moment */
116	if (drm_format_num_planes(mode->pixel_format) > 1 &&
117	    (mode->handles[0] != mode->handles[1] ||
118	     mode->handles[0] != mode->handles[2])) {
119		ret = -EINVAL;
120		goto err;
121	}
122
123	obj = armada_gem_object_lookup(dev, dfile, mode->handles[0]);
124	if (!obj) {
125		ret = -ENOENT;
126		goto err;
127	}
128
129	if (obj->obj.import_attach && !obj->sgt) {
130		ret = armada_gem_map_import(obj);
131		if (ret)
132			goto err_unref;
133	}
134
135	/* Framebuffer objects must have a valid device address for scanout */
136	if (obj->dev_addr == DMA_ERROR_CODE) {
137		ret = -EINVAL;
138		goto err_unref;
139	}
140
141	dfb = armada_framebuffer_create(dev, mode, obj);
142	if (IS_ERR(dfb)) {
143		ret = PTR_ERR(dfb);
144		goto err;
145	}
146
147	drm_gem_object_unreference_unlocked(&obj->obj);
148
149	return &dfb->fb;
150
151 err_unref:
152	drm_gem_object_unreference_unlocked(&obj->obj);
153 err:
154	DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
155	return ERR_PTR(ret);
156}
157
158static void armada_output_poll_changed(struct drm_device *dev)
159{
160	struct armada_private *priv = dev->dev_private;
161	struct drm_fb_helper *fbh = priv->fbdev;
162
163	if (fbh)
164		drm_fb_helper_hotplug_event(fbh);
165}
166
167const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
168	.fb_create		= armada_fb_create,
169	.output_poll_changed	= armada_output_poll_changed,
170};