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

msm_fbdev.c (4796B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2013 Red Hat
      4 * Author: Rob Clark <robdclark@gmail.com>
      5 */
      6
      7#include <drm/drm_aperture.h>
      8#include <drm/drm_crtc.h>
      9#include <drm/drm_fb_helper.h>
     10#include <drm/drm_fourcc.h>
     11#include <drm/drm_prime.h>
     12
     13#include "msm_drv.h"
     14#include "msm_gem.h"
     15#include "msm_kms.h"
     16
     17static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma);
     18
     19/*
     20 * fbdev funcs, to implement legacy fbdev interface on top of drm driver
     21 */
     22
     23#define to_msm_fbdev(x) container_of(x, struct msm_fbdev, base)
     24
     25struct msm_fbdev {
     26	struct drm_fb_helper base;
     27	struct drm_framebuffer *fb;
     28};
     29
     30static const struct fb_ops msm_fb_ops = {
     31	.owner = THIS_MODULE,
     32	DRM_FB_HELPER_DEFAULT_OPS,
     33
     34	/* Note: to properly handle manual update displays, we wrap the
     35	 * basic fbdev ops which write to the framebuffer
     36	 */
     37	.fb_read = drm_fb_helper_sys_read,
     38	.fb_write = drm_fb_helper_sys_write,
     39	.fb_fillrect = drm_fb_helper_sys_fillrect,
     40	.fb_copyarea = drm_fb_helper_sys_copyarea,
     41	.fb_imageblit = drm_fb_helper_sys_imageblit,
     42	.fb_mmap = msm_fbdev_mmap,
     43};
     44
     45static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
     46{
     47	struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par;
     48	struct msm_fbdev *fbdev = to_msm_fbdev(helper);
     49	struct drm_gem_object *bo = msm_framebuffer_bo(fbdev->fb, 0);
     50
     51	return drm_gem_prime_mmap(bo, vma);
     52}
     53
     54static int msm_fbdev_create(struct drm_fb_helper *helper,
     55		struct drm_fb_helper_surface_size *sizes)
     56{
     57	struct msm_fbdev *fbdev = to_msm_fbdev(helper);
     58	struct drm_device *dev = helper->dev;
     59	struct msm_drm_private *priv = dev->dev_private;
     60	struct drm_framebuffer *fb = NULL;
     61	struct drm_gem_object *bo;
     62	struct fb_info *fbi = NULL;
     63	uint64_t paddr;
     64	uint32_t format;
     65	int ret, pitch;
     66
     67	format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
     68
     69	DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
     70			sizes->surface_height, sizes->surface_bpp,
     71			sizes->fb_width, sizes->fb_height);
     72
     73	pitch = align_pitch(sizes->surface_width, sizes->surface_bpp);
     74	fb = msm_alloc_stolen_fb(dev, sizes->surface_width,
     75			sizes->surface_height, pitch, format);
     76
     77	if (IS_ERR(fb)) {
     78		DRM_DEV_ERROR(dev->dev, "failed to allocate fb\n");
     79		return PTR_ERR(fb);
     80	}
     81
     82	bo = msm_framebuffer_bo(fb, 0);
     83
     84	/*
     85	 * NOTE: if we can be guaranteed to be able to map buffer
     86	 * in panic (ie. lock-safe, etc) we could avoid pinning the
     87	 * buffer now:
     88	 */
     89	ret = msm_gem_get_and_pin_iova(bo, priv->kms->aspace, &paddr);
     90	if (ret) {
     91		DRM_DEV_ERROR(dev->dev, "failed to get buffer obj iova: %d\n", ret);
     92		goto fail;
     93	}
     94
     95	fbi = drm_fb_helper_alloc_fbi(helper);
     96	if (IS_ERR(fbi)) {
     97		DRM_DEV_ERROR(dev->dev, "failed to allocate fb info\n");
     98		ret = PTR_ERR(fbi);
     99		goto fail;
    100	}
    101
    102	DBG("fbi=%p, dev=%p", fbi, dev);
    103
    104	fbdev->fb = fb;
    105	helper->fb = fb;
    106
    107	fbi->fbops = &msm_fb_ops;
    108
    109	drm_fb_helper_fill_info(fbi, helper, sizes);
    110
    111	dev->mode_config.fb_base = paddr;
    112
    113	fbi->screen_base = msm_gem_get_vaddr(bo);
    114	if (IS_ERR(fbi->screen_base)) {
    115		ret = PTR_ERR(fbi->screen_base);
    116		goto fail;
    117	}
    118	fbi->screen_size = bo->size;
    119	fbi->fix.smem_start = paddr;
    120	fbi->fix.smem_len = bo->size;
    121
    122	DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres);
    123	DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height);
    124
    125	return 0;
    126
    127fail:
    128	drm_framebuffer_remove(fb);
    129	return ret;
    130}
    131
    132static const struct drm_fb_helper_funcs msm_fb_helper_funcs = {
    133	.fb_probe = msm_fbdev_create,
    134};
    135
    136/* initialize fbdev helper */
    137struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev)
    138{
    139	struct msm_drm_private *priv = dev->dev_private;
    140	struct msm_fbdev *fbdev = NULL;
    141	struct drm_fb_helper *helper;
    142	int ret;
    143
    144	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
    145	if (!fbdev)
    146		goto fail;
    147
    148	helper = &fbdev->base;
    149
    150	drm_fb_helper_prepare(dev, helper, &msm_fb_helper_funcs);
    151
    152	ret = drm_fb_helper_init(dev, helper);
    153	if (ret) {
    154		DRM_DEV_ERROR(dev->dev, "could not init fbdev: ret=%d\n", ret);
    155		goto fail;
    156	}
    157
    158	/* the fw fb could be anywhere in memory */
    159	ret = drm_aperture_remove_framebuffers(false, dev->driver);
    160	if (ret)
    161		goto fini;
    162
    163	ret = drm_fb_helper_initial_config(helper, 32);
    164	if (ret)
    165		goto fini;
    166
    167	priv->fbdev = helper;
    168
    169	return helper;
    170
    171fini:
    172	drm_fb_helper_fini(helper);
    173fail:
    174	kfree(fbdev);
    175	return NULL;
    176}
    177
    178void msm_fbdev_free(struct drm_device *dev)
    179{
    180	struct msm_drm_private *priv = dev->dev_private;
    181	struct drm_fb_helper *helper = priv->fbdev;
    182	struct msm_fbdev *fbdev;
    183
    184	DBG();
    185
    186	drm_fb_helper_unregister_fbi(helper);
    187
    188	drm_fb_helper_fini(helper);
    189
    190	fbdev = to_msm_fbdev(priv->fbdev);
    191
    192	/* this will free the backing object */
    193	if (fbdev->fb) {
    194		struct drm_gem_object *bo =
    195			msm_framebuffer_bo(fbdev->fb, 0);
    196		msm_gem_put_vaddr(bo);
    197		drm_framebuffer_remove(fbdev->fb);
    198	}
    199
    200	kfree(fbdev);
    201
    202	priv->fbdev = NULL;
    203}