1 /*
2  * Copyright (C) 2021 Icecream95
3  * Copyright (C) 2019 Google LLC
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include "drm-shim/drm_shim.h"
29 #include "drm-uapi/panfrost_drm.h"
30 
31 #include "util/u_math.h"
32 
33 /* Default GPU ID if PAN_GPU_ID is not set. This defaults to Mali-G52. */
34 #define PAN_GPU_ID_DEFAULT (0x7212)
35 
36 bool drm_shim_driver_prefers_first_render_node = true;
37 
38 static int
pan_ioctl_noop(int fd, unsigned long request, void *arg)39 pan_ioctl_noop(int fd, unsigned long request, void *arg)
40 {
41    return 0;
42 }
43 
44 static int
pan_ioctl_get_param(int fd, unsigned long request, void *arg)45 pan_ioctl_get_param(int fd, unsigned long request, void *arg)
46 {
47    struct drm_panfrost_get_param *gp = arg;
48 
49    switch (gp->param) {
50    case DRM_PANFROST_PARAM_GPU_PROD_ID:
51    {
52       char *override_version = getenv("PAN_GPU_ID");
53 
54       if (override_version)
55          gp->value = strtol(override_version, NULL, 16);
56       else
57          gp->value = PAN_GPU_ID_DEFAULT;
58 
59       return 0;
60    }
61 
62    case DRM_PANFROST_PARAM_SHADER_PRESENT:
63       /* Assume an MP4 GPU */
64       gp->value = 0xF;
65       return 0;
66    case DRM_PANFROST_PARAM_TILER_FEATURES:
67       gp->value = 0x809;
68       return 0;
69    case DRM_PANFROST_PARAM_TEXTURE_FEATURES0:
70    case DRM_PANFROST_PARAM_TEXTURE_FEATURES1:
71       /* Allow all compressed textures */
72       gp->value = ~0;
73       return 0;
74    case DRM_PANFROST_PARAM_GPU_REVISION:
75    case DRM_PANFROST_PARAM_THREAD_TLS_ALLOC:
76    case DRM_PANFROST_PARAM_AFBC_FEATURES:
77       gp->value = 0;
78       return 0;
79    default:
80       fprintf(stderr, "Unknown DRM_IOCTL_PANFROST_GET_PARAM %d\n", gp->param);
81       return -1;
82    }
83 }
84 
85 static int
pan_ioctl_create_bo(int fd, unsigned long request, void *arg)86 pan_ioctl_create_bo(int fd, unsigned long request, void *arg)
87 {
88    struct drm_panfrost_create_bo *create = arg;
89 
90    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
91    struct shim_bo *bo = calloc(1, sizeof(*bo));
92    size_t size = ALIGN(create->size, 4096);
93 
94    drm_shim_bo_init(bo, size);
95 
96    create->handle = drm_shim_bo_get_handle(shim_fd, bo);
97    create->offset = bo->mem_addr;
98 
99    drm_shim_bo_put(bo);
100 
101    return 0;
102 }
103 
104 static int
pan_ioctl_mmap_bo(int fd, unsigned long request, void *arg)105 pan_ioctl_mmap_bo(int fd, unsigned long request, void *arg)
106 {
107    struct drm_panfrost_mmap_bo *mmap_bo = arg;
108 
109    struct shim_fd *shim_fd = drm_shim_fd_lookup(fd);
110    struct shim_bo *bo = drm_shim_bo_lookup(shim_fd, mmap_bo->handle);
111 
112    mmap_bo->offset = drm_shim_bo_get_mmap_offset(shim_fd, bo);
113 
114    return 0;
115 }
116 
117 static int
pan_ioctl_madvise(int fd, unsigned long request, void *arg)118 pan_ioctl_madvise(int fd, unsigned long request, void *arg)
119 {
120    struct drm_panfrost_madvise *madvise = arg;
121 
122    madvise->retained = 1;
123 
124    return 0;
125 }
126 
127 static ioctl_fn_t driver_ioctls[] = {
128    [DRM_PANFROST_SUBMIT] = pan_ioctl_noop,
129    [DRM_PANFROST_WAIT_BO] = pan_ioctl_noop,
130    [DRM_PANFROST_CREATE_BO] = pan_ioctl_create_bo,
131    [DRM_PANFROST_MMAP_BO] = pan_ioctl_mmap_bo,
132    [DRM_PANFROST_GET_PARAM] = pan_ioctl_get_param,
133    [DRM_PANFROST_GET_BO_OFFSET] = pan_ioctl_noop,
134    [DRM_PANFROST_PERFCNT_ENABLE] = pan_ioctl_noop,
135    [DRM_PANFROST_PERFCNT_DUMP] = pan_ioctl_noop,
136    [DRM_PANFROST_MADVISE] = pan_ioctl_madvise,
137 };
138 
139 void
drm_shim_driver_init(void)140 drm_shim_driver_init(void)
141 {
142    shim_device.bus_type = DRM_BUS_PLATFORM;
143    shim_device.driver_name = "panfrost";
144    shim_device.driver_ioctls = driver_ioctls;
145    shim_device.driver_ioctl_count = ARRAY_SIZE(driver_ioctls);
146 
147    /* panfrost uses the DRM version to expose features, instead of getparam. */
148    shim_device.version_major = 1;
149    shim_device.version_minor = 1;
150    shim_device.version_patchlevel = 0;
151 
152    drm_shim_override_file("DRIVER=panfrost\n"
153                           "OF_FULLNAME=/soc/mali\n"
154                           "OF_COMPATIBLE_0=arm,mali-t860\n"
155                           "OF_COMPATIBLE_N=1\n",
156                           "/sys/dev/char/%d:%d/device/uevent", DRM_MAJOR,
157                           render_node_minor);
158 }
159