1 1.3 riastrad /* $NetBSD: drm_gem_framebuffer_helper.c,v 1.3 2021/12/19 09:49:17 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /*- 4 1.1 riastrad * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 1.1 riastrad * All rights reserved. 6 1.1 riastrad * 7 1.1 riastrad * This code is derived from software contributed to The NetBSD Foundation 8 1.1 riastrad * by Taylor R. Campbell. 9 1.1 riastrad * 10 1.1 riastrad * Redistribution and use in source and binary forms, with or without 11 1.1 riastrad * modification, are permitted provided that the following conditions 12 1.1 riastrad * are met: 13 1.1 riastrad * 1. Redistributions of source code must retain the above copyright 14 1.1 riastrad * notice, this list of conditions and the following disclaimer. 15 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 riastrad * notice, this list of conditions and the following disclaimer in the 17 1.1 riastrad * documentation and/or other materials provided with the distribution. 18 1.1 riastrad * 19 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE. 30 1.1 riastrad */ 31 1.1 riastrad 32 1.1 riastrad #include <sys/cdefs.h> 33 1.3 riastrad __KERNEL_RCSID(0, "$NetBSD: drm_gem_framebuffer_helper.c,v 1.3 2021/12/19 09:49:17 riastradh Exp $"); 34 1.1 riastrad 35 1.1 riastrad #include <linux/err.h> 36 1.1 riastrad #include <linux/slab.h> 37 1.1 riastrad 38 1.3 riastrad #include <drm/drm_print.h> 39 1.3 riastrad #include <drm/drm_fourcc.h> 40 1.1 riastrad #include <drm/drm_framebuffer.h> 41 1.1 riastrad #include <drm/drm_gem.h> 42 1.2 riastrad #include <drm/drm_gem_framebuffer_helper.h> 43 1.2 riastrad #include <drm/drm_modeset_helper.h> 44 1.1 riastrad 45 1.1 riastrad #include <uapi/drm/drm_mode.h> 46 1.1 riastrad 47 1.1 riastrad /* 48 1.1 riastrad * drm_gem_fb_destroy(fb) 49 1.1 riastrad * 50 1.1 riastrad * Release the objects in, clean up and, kfree a framebuffer 51 1.1 riastrad * allocated with drm_gem_fb_create_with_funcs. 52 1.1 riastrad * 53 1.1 riastrad * Fit for use as struct drm_framebuffer_funcs::destroy. Caller 54 1.1 riastrad * must guarantee that the struct drm_framebuffer is allocated 55 1.1 riastrad * with kmalloc. 56 1.1 riastrad */ 57 1.1 riastrad void 58 1.1 riastrad drm_gem_fb_destroy(struct drm_framebuffer *fb) 59 1.1 riastrad { 60 1.1 riastrad unsigned plane; 61 1.1 riastrad 62 1.1 riastrad for (plane = 0; plane < __arraycount(fb->obj); plane++) 63 1.1 riastrad drm_gem_object_put_unlocked(fb->obj[plane]); 64 1.1 riastrad drm_framebuffer_cleanup(fb); 65 1.1 riastrad kfree(fb); 66 1.1 riastrad } 67 1.1 riastrad 68 1.1 riastrad /* 69 1.1 riastrad * drm_gem_fb_create_handle(fb, file, handlep) 70 1.1 riastrad * 71 1.1 riastrad * Create a GEM handle for the object of the first plane (plane=0) 72 1.1 riastrad * of fb in the specified drm file namespace, and store it in 73 1.1 riastrad * *handlep. 74 1.1 riastrad * 75 1.1 riastrad * Returns 0 on success, negative error on failure. 76 1.1 riastrad */ 77 1.1 riastrad int 78 1.1 riastrad drm_gem_fb_create_handle(struct drm_framebuffer *fb, struct drm_file *file, 79 1.1 riastrad unsigned *handlep) 80 1.1 riastrad { 81 1.1 riastrad 82 1.1 riastrad return drm_gem_handle_create(file, fb->obj[0], handlep); 83 1.1 riastrad } 84 1.1 riastrad 85 1.1 riastrad /* 86 1.1 riastrad * drm_gem_fb_create_with_funcs(dev, file, mode_cmd, funcs) 87 1.1 riastrad * 88 1.1 riastrad * Create a framebuffer in the specified drm device from the given 89 1.1 riastrad * mode command, resolving mode_cmd's handles in the specified drm 90 1.1 riastrad * file. 91 1.1 riastrad * 92 1.1 riastrad * Returns pointer on success, ERR_PTR on failure. 93 1.1 riastrad * 94 1.1 riastrad * ENOENT missing handle 95 1.1 riastrad * EINVAL wrong size object, invalid mode format 96 1.1 riastrad */ 97 1.1 riastrad struct drm_framebuffer * 98 1.1 riastrad drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file, 99 1.1 riastrad const struct drm_mode_fb_cmd2 *mode_cmd, 100 1.1 riastrad const struct drm_framebuffer_funcs *funcs) 101 1.1 riastrad { 102 1.1 riastrad struct drm_framebuffer *fb; 103 1.1 riastrad unsigned plane; 104 1.1 riastrad int ret; 105 1.1 riastrad 106 1.1 riastrad /* Allocate a framebuffer object with kmalloc. */ 107 1.1 riastrad fb = kmalloc(sizeof(*fb), GFP_KERNEL); 108 1.1 riastrad if (fb == NULL) { 109 1.1 riastrad ret = -ENOMEM; 110 1.1 riastrad goto fail0; 111 1.1 riastrad } 112 1.1 riastrad 113 1.1 riastrad /* 114 1.1 riastrad * Fill framebuffer parameters from mode_cmd. If they're not 115 1.1 riastrad * valid, fail with EINVAL. 116 1.1 riastrad */ 117 1.1 riastrad drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); 118 1.1 riastrad if (fb->format == NULL) { 119 1.1 riastrad ret = -EINVAL; 120 1.1 riastrad goto fail1; 121 1.1 riastrad } 122 1.1 riastrad 123 1.1 riastrad /* Get the object for each plane. */ 124 1.1 riastrad for (plane = 0; plane < fb->format->num_planes; plane++) { 125 1.2 riastrad unsigned vsub = (plane > 0 ? fb->format->vsub : 1); /* XXX ? */ 126 1.2 riastrad unsigned hsub = (plane > 0 ? fb->format->hsub : 1); /* XXX ? */ 127 1.1 riastrad unsigned handle = mode_cmd->handles[plane]; 128 1.1 riastrad unsigned size; 129 1.1 riastrad 130 1.1 riastrad /* Look up the object for this plane. */ 131 1.1 riastrad fb->obj[plane] = drm_gem_object_lookup(file, handle); 132 1.1 riastrad if (fb->obj[plane] == NULL) { 133 1.1 riastrad ret = -ENOENT; 134 1.1 riastrad goto fail2; 135 1.1 riastrad } 136 1.1 riastrad 137 1.1 riastrad /* Confirm the object is large enough to handle it. */ 138 1.1 riastrad size = (mode_cmd->height/vsub - 1)*mode_cmd->pitches[plane] 139 1.1 riastrad + (mode_cmd->width/hsub)*fb->format->cpp[plane] 140 1.1 riastrad + mode_cmd->offsets[plane]; 141 1.1 riastrad if (fb->obj[plane]->size < size) { 142 1.1 riastrad ret = -EINVAL; 143 1.1 riastrad plane++; /* free this one too */ 144 1.1 riastrad goto fail2; 145 1.1 riastrad } 146 1.1 riastrad } 147 1.1 riastrad 148 1.1 riastrad /* Initialize the framebuffer. */ 149 1.1 riastrad ret = drm_framebuffer_init(dev, fb, funcs); 150 1.1 riastrad if (ret) 151 1.1 riastrad goto fail2; 152 1.1 riastrad 153 1.1 riastrad /* Success! */ 154 1.1 riastrad return fb; 155 1.1 riastrad 156 1.1 riastrad fail2: while (plane --> 0) 157 1.1 riastrad drm_gem_object_put_unlocked(fb->obj[plane]); 158 1.1 riastrad fail1: kmem_free(fb, sizeof(*fb)); 159 1.1 riastrad fail0: KASSERT(ret); 160 1.1 riastrad return ERR_PTR(ret); 161 1.1 riastrad } 162