brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · a379c8c Raw
227 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* exynos_drm_fbdev.c3 *4 * Copyright (c) 2011 Samsung Electronics Co., Ltd.5 * Authors:6 *	Inki Dae <inki.dae@samsung.com>7 *	Joonyoung Shim <jy0922.shim@samsung.com>8 *	Seung-Woo Kim <sw0312.kim@samsung.com>9 */10 11#include <linux/fb.h>12 13#include <drm/drm_crtc_helper.h>14#include <drm/drm_drv.h>15#include <drm/drm_fb_helper.h>16#include <drm/drm_framebuffer.h>17#include <drm/drm_gem_framebuffer_helper.h>18#include <drm/drm_prime.h>19#include <drm/exynos_drm.h>20 21#include "exynos_drm_drv.h"22#include "exynos_drm_fb.h"23#include "exynos_drm_fbdev.h"24 25#define MAX_CONNECTOR		426#define PREFERRED_BPP		3227 28static int exynos_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)29{30	struct drm_fb_helper *helper = info->par;31	struct drm_gem_object *obj = drm_gem_fb_get_obj(helper->fb, 0);32 33	return drm_gem_prime_mmap(obj, vma);34}35 36static void exynos_drm_fb_destroy(struct fb_info *info)37{38	struct drm_fb_helper *fb_helper = info->par;39	struct drm_framebuffer *fb = fb_helper->fb;40 41	drm_fb_helper_fini(fb_helper);42 43	drm_framebuffer_remove(fb);44 45	drm_client_release(&fb_helper->client);46	drm_fb_helper_unprepare(fb_helper);47	kfree(fb_helper);48}49 50static const struct fb_ops exynos_drm_fb_ops = {51	.owner		= THIS_MODULE,52	__FB_DEFAULT_DMAMEM_OPS_RDWR,53	DRM_FB_HELPER_DEFAULT_OPS,54	__FB_DEFAULT_DMAMEM_OPS_DRAW,55	.fb_mmap        = exynos_drm_fb_mmap,56	.fb_destroy	= exynos_drm_fb_destroy,57};58 59static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,60				   struct drm_fb_helper_surface_size *sizes,61				   struct exynos_drm_gem *exynos_gem)62{63	struct fb_info *fbi;64	struct drm_framebuffer *fb = helper->fb;65	unsigned int size = fb->width * fb->height * fb->format->cpp[0];66	unsigned long offset;67 68	fbi = drm_fb_helper_alloc_info(helper);69	if (IS_ERR(fbi)) {70		DRM_DEV_ERROR(to_dma_dev(helper->dev),71			      "failed to allocate fb info.\n");72		return PTR_ERR(fbi);73	}74 75	fbi->fbops = &exynos_drm_fb_ops;76 77	drm_fb_helper_fill_info(fbi, helper, sizes);78 79	offset = fbi->var.xoffset * fb->format->cpp[0];80	offset += fbi->var.yoffset * fb->pitches[0];81 82	fbi->flags |= FBINFO_VIRTFB;83	fbi->screen_buffer = exynos_gem->kvaddr + offset;84	fbi->screen_size = size;85	fbi->fix.smem_len = size;86 87	return 0;88}89 90static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,91				    struct drm_fb_helper_surface_size *sizes)92{93	struct exynos_drm_gem *exynos_gem;94	struct drm_device *dev = helper->dev;95	struct drm_mode_fb_cmd2 mode_cmd = { 0 };96	unsigned long size;97	int ret;98 99	DRM_DEV_DEBUG_KMS(dev->dev,100			  "surface width(%d), height(%d) and bpp(%d\n",101			  sizes->surface_width, sizes->surface_height,102			  sizes->surface_bpp);103 104	mode_cmd.width = sizes->surface_width;105	mode_cmd.height = sizes->surface_height;106	mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);107	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,108							  sizes->surface_depth);109 110	size = mode_cmd.pitches[0] * mode_cmd.height;111 112	exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_WC, size, true);113	if (IS_ERR(exynos_gem))114		return PTR_ERR(exynos_gem);115 116	helper->fb =117		exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem, 1);118	if (IS_ERR(helper->fb)) {119		DRM_DEV_ERROR(dev->dev, "failed to create drm framebuffer.\n");120		ret = PTR_ERR(helper->fb);121		goto err_destroy_gem;122	}123 124	ret = exynos_drm_fbdev_update(helper, sizes, exynos_gem);125	if (ret < 0)126		goto err_destroy_framebuffer;127 128	return 0;129 130err_destroy_framebuffer:131	drm_framebuffer_cleanup(helper->fb);132	helper->fb = NULL;133err_destroy_gem:134	exynos_drm_gem_destroy(exynos_gem);135	return ret;136}137 138static const struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {139	.fb_probe =	exynos_drm_fbdev_create,140};141 142/*143 * struct drm_client144 */145 146static void exynos_drm_fbdev_client_unregister(struct drm_client_dev *client)147{148	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);149 150	if (fb_helper->info) {151		drm_fb_helper_unregister_info(fb_helper);152	} else {153		drm_client_release(&fb_helper->client);154		drm_fb_helper_unprepare(fb_helper);155		kfree(fb_helper);156	}157}158 159static int exynos_drm_fbdev_client_restore(struct drm_client_dev *client)160{161	drm_fb_helper_lastclose(client->dev);162 163	return 0;164}165 166static int exynos_drm_fbdev_client_hotplug(struct drm_client_dev *client)167{168	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);169	struct drm_device *dev = client->dev;170	int ret;171 172	if (dev->fb_helper)173		return drm_fb_helper_hotplug_event(dev->fb_helper);174 175	ret = drm_fb_helper_init(dev, fb_helper);176	if (ret)177		goto err_drm_err;178 179	if (!drm_drv_uses_atomic_modeset(dev))180		drm_helper_disable_unused_functions(dev);181 182	ret = drm_fb_helper_initial_config(fb_helper);183	if (ret)184		goto err_drm_fb_helper_fini;185 186	return 0;187 188err_drm_fb_helper_fini:189	drm_fb_helper_fini(fb_helper);190err_drm_err:191	drm_err(dev, "Failed to setup fbdev emulation (ret=%d)\n", ret);192	return ret;193}194 195static const struct drm_client_funcs exynos_drm_fbdev_client_funcs = {196	.owner		= THIS_MODULE,197	.unregister	= exynos_drm_fbdev_client_unregister,198	.restore	= exynos_drm_fbdev_client_restore,199	.hotplug	= exynos_drm_fbdev_client_hotplug,200};201 202void exynos_drm_fbdev_setup(struct drm_device *dev)203{204	struct drm_fb_helper *fb_helper;205	int ret;206 207	drm_WARN(dev, !dev->registered, "Device has not been registered.\n");208	drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");209 210	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);211	if (!fb_helper)212		return;213	drm_fb_helper_prepare(dev, fb_helper, PREFERRED_BPP, &exynos_drm_fb_helper_funcs);214 215	ret = drm_client_init(dev, &fb_helper->client, "fbdev", &exynos_drm_fbdev_client_funcs);216	if (ret)217		goto err_drm_client_init;218 219	drm_client_register(&fb_helper->client);220 221	return;222 223err_drm_client_init:224	drm_fb_helper_unprepare(fb_helper);225	kfree(fb_helper);226}227