cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

exynos_drm_fbdev.c (5565B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* exynos_drm_fbdev.c
      3 *
      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/console.h>
     12#include <linux/dma-mapping.h>
     13#include <linux/vmalloc.h>
     14
     15#include <drm/drm_crtc.h>
     16#include <drm/drm_fb_helper.h>
     17#include <drm/drm_fourcc.h>
     18#include <drm/drm_prime.h>
     19#include <drm/drm_probe_helper.h>
     20#include <drm/exynos_drm.h>
     21
     22#include "exynos_drm_drv.h"
     23#include "exynos_drm_fb.h"
     24#include "exynos_drm_fbdev.h"
     25
     26#define MAX_CONNECTOR		4
     27#define PREFERRED_BPP		32
     28
     29#define to_exynos_fbdev(x)	container_of(x, struct exynos_drm_fbdev,\
     30				drm_fb_helper)
     31
     32struct exynos_drm_fbdev {
     33	struct drm_fb_helper	drm_fb_helper;
     34	struct exynos_drm_gem	*exynos_gem;
     35};
     36
     37static int exynos_drm_fb_mmap(struct fb_info *info,
     38			struct vm_area_struct *vma)
     39{
     40	struct drm_fb_helper *helper = info->par;
     41	struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper);
     42	struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem;
     43
     44	return drm_gem_prime_mmap(&exynos_gem->base, vma);
     45}
     46
     47static const struct fb_ops exynos_drm_fb_ops = {
     48	.owner		= THIS_MODULE,
     49	DRM_FB_HELPER_DEFAULT_OPS,
     50	.fb_mmap        = exynos_drm_fb_mmap,
     51	.fb_fillrect	= drm_fb_helper_cfb_fillrect,
     52	.fb_copyarea	= drm_fb_helper_cfb_copyarea,
     53	.fb_imageblit	= drm_fb_helper_cfb_imageblit,
     54};
     55
     56static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
     57				   struct drm_fb_helper_surface_size *sizes,
     58				   struct exynos_drm_gem *exynos_gem)
     59{
     60	struct fb_info *fbi;
     61	struct drm_framebuffer *fb = helper->fb;
     62	unsigned int size = fb->width * fb->height * fb->format->cpp[0];
     63	unsigned long offset;
     64
     65	fbi = drm_fb_helper_alloc_fbi(helper);
     66	if (IS_ERR(fbi)) {
     67		DRM_DEV_ERROR(to_dma_dev(helper->dev),
     68			      "failed to allocate fb info.\n");
     69		return PTR_ERR(fbi);
     70	}
     71
     72	fbi->fbops = &exynos_drm_fb_ops;
     73
     74	drm_fb_helper_fill_info(fbi, helper, sizes);
     75
     76	offset = fbi->var.xoffset * fb->format->cpp[0];
     77	offset += fbi->var.yoffset * fb->pitches[0];
     78
     79	fbi->screen_buffer = exynos_gem->kvaddr + offset;
     80	fbi->screen_size = size;
     81	fbi->fix.smem_len = size;
     82
     83	return 0;
     84}
     85
     86static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
     87				    struct drm_fb_helper_surface_size *sizes)
     88{
     89	struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
     90	struct exynos_drm_gem *exynos_gem;
     91	struct drm_device *dev = helper->dev;
     92	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
     93	unsigned long size;
     94	int ret;
     95
     96	DRM_DEV_DEBUG_KMS(dev->dev,
     97			  "surface width(%d), height(%d) and bpp(%d\n",
     98			  sizes->surface_width, sizes->surface_height,
     99			  sizes->surface_bpp);
    100
    101	mode_cmd.width = sizes->surface_width;
    102	mode_cmd.height = sizes->surface_height;
    103	mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
    104	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
    105							  sizes->surface_depth);
    106
    107	size = mode_cmd.pitches[0] * mode_cmd.height;
    108
    109	exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_WC, size, true);
    110	if (IS_ERR(exynos_gem))
    111		return PTR_ERR(exynos_gem);
    112
    113	exynos_fbdev->exynos_gem = exynos_gem;
    114
    115	helper->fb =
    116		exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem, 1);
    117	if (IS_ERR(helper->fb)) {
    118		DRM_DEV_ERROR(dev->dev, "failed to create drm framebuffer.\n");
    119		ret = PTR_ERR(helper->fb);
    120		goto err_destroy_gem;
    121	}
    122
    123	ret = exynos_drm_fbdev_update(helper, sizes, exynos_gem);
    124	if (ret < 0)
    125		goto err_destroy_framebuffer;
    126
    127	return ret;
    128
    129err_destroy_framebuffer:
    130	drm_framebuffer_cleanup(helper->fb);
    131err_destroy_gem:
    132	exynos_drm_gem_destroy(exynos_gem);
    133
    134	/*
    135	 * if failed, all resources allocated above would be released by
    136	 * drm_mode_config_cleanup() when drm_load() had been called prior
    137	 * to any specific driver such as fimd or hdmi driver.
    138	 */
    139
    140	return ret;
    141}
    142
    143static const struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {
    144	.fb_probe =	exynos_drm_fbdev_create,
    145};
    146
    147int exynos_drm_fbdev_init(struct drm_device *dev)
    148{
    149	struct exynos_drm_fbdev *fbdev;
    150	struct exynos_drm_private *private = dev->dev_private;
    151	struct drm_fb_helper *helper;
    152	int ret;
    153
    154	if (!dev->mode_config.num_crtc)
    155		return 0;
    156
    157	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
    158	if (!fbdev)
    159		return -ENOMEM;
    160
    161	private->fb_helper = helper = &fbdev->drm_fb_helper;
    162
    163	drm_fb_helper_prepare(dev, helper, &exynos_drm_fb_helper_funcs);
    164
    165	ret = drm_fb_helper_init(dev, helper);
    166	if (ret < 0) {
    167		DRM_DEV_ERROR(dev->dev,
    168			      "failed to initialize drm fb helper.\n");
    169		goto err_init;
    170	}
    171
    172	ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP);
    173	if (ret < 0) {
    174		DRM_DEV_ERROR(dev->dev,
    175			      "failed to set up hw configuration.\n");
    176		goto err_setup;
    177	}
    178
    179	return 0;
    180
    181err_setup:
    182	drm_fb_helper_fini(helper);
    183
    184err_init:
    185	private->fb_helper = NULL;
    186	kfree(fbdev);
    187
    188	return ret;
    189}
    190
    191static void exynos_drm_fbdev_destroy(struct drm_device *dev,
    192				      struct drm_fb_helper *fb_helper)
    193{
    194	struct drm_framebuffer *fb;
    195
    196	/* release drm framebuffer and real buffer */
    197	if (fb_helper->fb && fb_helper->fb->funcs) {
    198		fb = fb_helper->fb;
    199		if (fb)
    200			drm_framebuffer_remove(fb);
    201	}
    202
    203	drm_fb_helper_unregister_fbi(fb_helper);
    204
    205	drm_fb_helper_fini(fb_helper);
    206}
    207
    208void exynos_drm_fbdev_fini(struct drm_device *dev)
    209{
    210	struct exynos_drm_private *private = dev->dev_private;
    211	struct exynos_drm_fbdev *fbdev;
    212
    213	if (!private || !private->fb_helper)
    214		return;
    215
    216	fbdev = to_exynos_fbdev(private->fb_helper);
    217
    218	exynos_drm_fbdev_destroy(dev, private->fb_helper);
    219	kfree(fbdev);
    220	private->fb_helper = NULL;
    221}
    222