blob: 3c3541094ea4353a19a57d40a212743276a112e2 [file] [log] [blame]
Greg Hackmann41909dd2014-04-25 10:39:50 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <fcntl.h>
19#include <stdbool.h>
20#include <stdio.h>
21#include <stdlib.h>
Elliott Hughescd3c55a2015-01-29 20:50:08 -080022#include <string.h>
Greg Hackmann41909dd2014-04-25 10:39:50 -070023#include <unistd.h>
24
25#include <sys/cdefs.h>
26#include <sys/mman.h>
27
28#include <adf/adf.h>
xinglong.zhuc4fa2c22016-08-05 14:52:22 +080029#include <sync/sync.h>
Greg Hackmann41909dd2014-04-25 10:39:50 -070030
31#include "graphics.h"
32
33struct adf_surface_pdata {
34 GRSurface base;
xinglong.zhuc4fa2c22016-08-05 14:52:22 +080035 int fence_fd;
Greg Hackmann41909dd2014-04-25 10:39:50 -070036 int fd;
37 __u32 offset;
38 __u32 pitch;
39};
40
41struct adf_pdata {
42 minui_backend base;
43 int intf_fd;
44 adf_id_t eng_id;
45 __u32 format;
46
Jonathan Hamiltonbab6e492016-05-05 15:30:57 -070047 adf_device dev;
48
Greg Hackmann41909dd2014-04-25 10:39:50 -070049 unsigned int current_surface;
50 unsigned int n_surfaces;
Elliott Hughes07cfb8f2015-04-10 13:12:05 -070051 adf_surface_pdata surfaces[2];
Greg Hackmann41909dd2014-04-25 10:39:50 -070052};
53
Elliott Hughes0a5cb0c2015-04-15 10:58:56 -070054static GRSurface* adf_flip(minui_backend *backend);
Elliott Hughes07cfb8f2015-04-10 13:12:05 -070055static void adf_blank(minui_backend *backend, bool blank);
Greg Hackmann41909dd2014-04-25 10:39:50 -070056
Elliott Hughes07cfb8f2015-04-10 13:12:05 -070057static int adf_surface_init(adf_pdata *pdata, drm_mode_modeinfo *mode, adf_surface_pdata *surf) {
Greg Hackmann41909dd2014-04-25 10:39:50 -070058 memset(surf, 0, sizeof(*surf));
59
xinglong.zhuc4fa2c22016-08-05 14:52:22 +080060 surf->fence_fd = -1;
Greg Hackmann41909dd2014-04-25 10:39:50 -070061 surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay,
62 mode->vdisplay, pdata->format, &surf->offset, &surf->pitch);
63 if (surf->fd < 0)
64 return surf->fd;
65
66 surf->base.width = mode->hdisplay;
67 surf->base.height = mode->vdisplay;
68 surf->base.row_bytes = surf->pitch;
69 surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4;
70
Elliott Hughes07cfb8f2015-04-10 13:12:05 -070071 surf->base.data = reinterpret_cast<uint8_t*>(mmap(NULL,
72 surf->pitch * surf->base.height, PROT_WRITE,
73 MAP_SHARED, surf->fd, surf->offset));
Greg Hackmann41909dd2014-04-25 10:39:50 -070074 if (surf->base.data == MAP_FAILED) {
75 close(surf->fd);
76 return -errno;
77 }
78
79 return 0;
80}
81
Elliott Hughes07cfb8f2015-04-10 13:12:05 -070082static int adf_interface_init(adf_pdata *pdata)
Greg Hackmann41909dd2014-04-25 10:39:50 -070083{
Elliott Hughes07cfb8f2015-04-10 13:12:05 -070084 adf_interface_data intf_data;
Greg Hackmann41909dd2014-04-25 10:39:50 -070085 int ret = 0;
86 int err;
87
88 err = adf_get_interface_data(pdata->intf_fd, &intf_data);
89 if (err < 0)
90 return err;
91
92 err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[0]);
93 if (err < 0) {
94 fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err));
95 ret = err;
96 goto done;
97 }
98
99 err = adf_surface_init(pdata, &intf_data.current_mode,
100 &pdata->surfaces[1]);
101 if (err < 0) {
102 fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err));
103 memset(&pdata->surfaces[1], 0, sizeof(pdata->surfaces[1]));
104 pdata->n_surfaces = 1;
105 } else {
106 pdata->n_surfaces = 2;
107 }
108
109done:
110 adf_free_interface_data(&intf_data);
111 return ret;
112}
113
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700114static int adf_device_init(adf_pdata *pdata, adf_device *dev)
Greg Hackmann41909dd2014-04-25 10:39:50 -0700115{
116 adf_id_t intf_id;
117 int intf_fd;
118 int err;
119
120 err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id,
121 &pdata->eng_id);
122 if (err < 0)
123 return err;
124
125 err = adf_device_attach(dev, pdata->eng_id, intf_id);
126 if (err < 0 && err != -EALREADY)
127 return err;
128
129 pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR);
130 if (pdata->intf_fd < 0)
131 return pdata->intf_fd;
132
133 err = adf_interface_init(pdata);
134 if (err < 0) {
135 close(pdata->intf_fd);
136 pdata->intf_fd = -1;
137 }
138
139 return err;
140}
141
Elliott Hughes0a5cb0c2015-04-15 10:58:56 -0700142static GRSurface* adf_init(minui_backend *backend)
Greg Hackmann41909dd2014-04-25 10:39:50 -0700143{
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700144 adf_pdata *pdata = (adf_pdata *)backend;
Greg Hackmann41909dd2014-04-25 10:39:50 -0700145 adf_id_t *dev_ids = NULL;
146 ssize_t n_dev_ids, i;
Elliott Hughes0a5cb0c2015-04-15 10:58:56 -0700147 GRSurface* ret;
Greg Hackmann41909dd2014-04-25 10:39:50 -0700148
Tony Kuofd778e32015-02-05 21:25:56 +0800149#if defined(RECOVERY_ABGR)
150 pdata->format = DRM_FORMAT_ABGR8888;
151#elif defined(RECOVERY_BGRA)
Greg Hackmann41909dd2014-04-25 10:39:50 -0700152 pdata->format = DRM_FORMAT_BGRA8888;
153#elif defined(RECOVERY_RGBX)
154 pdata->format = DRM_FORMAT_RGBX8888;
155#else
156 pdata->format = DRM_FORMAT_RGB565;
157#endif
158
159 n_dev_ids = adf_devices(&dev_ids);
160 if (n_dev_ids == 0) {
161 return NULL;
162 } else if (n_dev_ids < 0) {
163 fprintf(stderr, "enumerating adf devices failed: %s\n",
164 strerror(-n_dev_ids));
165 return NULL;
166 }
167
168 pdata->intf_fd = -1;
169
170 for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) {
Greg Hackmann41909dd2014-04-25 10:39:50 -0700171
Jonathan Hamiltonbab6e492016-05-05 15:30:57 -0700172 int err = adf_device_open(dev_ids[i], O_RDWR, &pdata->dev);
Greg Hackmann41909dd2014-04-25 10:39:50 -0700173 if (err < 0) {
174 fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i],
175 strerror(-err));
176 continue;
177 }
178
Jonathan Hamiltonbab6e492016-05-05 15:30:57 -0700179 err = adf_device_init(pdata, &pdata->dev);
180 if (err < 0) {
Greg Hackmann41909dd2014-04-25 10:39:50 -0700181 fprintf(stderr, "initializing adf device %u failed: %s\n",
182 dev_ids[i], strerror(-err));
Jonathan Hamiltonbab6e492016-05-05 15:30:57 -0700183 adf_device_close(&pdata->dev);
184 }
Greg Hackmann41909dd2014-04-25 10:39:50 -0700185 }
186
187 free(dev_ids);
188
189 if (pdata->intf_fd < 0)
190 return NULL;
191
192 ret = adf_flip(backend);
193
194 adf_blank(backend, true);
195 adf_blank(backend, false);
196
197 return ret;
198}
199
xinglong.zhuc4fa2c22016-08-05 14:52:22 +0800200static void adf_sync(adf_surface_pdata *surf)
201{
202 unsigned int warningTimeout = 3000;
203
204 if (surf == NULL)
205 return;
206
207 if (surf->fence_fd >= 0){
208 int err = sync_wait(surf->fence_fd, warningTimeout);
209 if (err < 0)
210 perror("adf sync fence wait error\n");
211
212 close(surf->fence_fd);
213 surf->fence_fd = -1;
214 }
215}
216
Elliott Hughes0a5cb0c2015-04-15 10:58:56 -0700217static GRSurface* adf_flip(minui_backend *backend)
Greg Hackmann41909dd2014-04-25 10:39:50 -0700218{
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700219 adf_pdata *pdata = (adf_pdata *)backend;
220 adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface];
Greg Hackmann41909dd2014-04-25 10:39:50 -0700221
222 int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id,
223 surf->base.width, surf->base.height, pdata->format, surf->fd,
224 surf->offset, surf->pitch, -1);
225 if (fence_fd >= 0)
xinglong.zhuc4fa2c22016-08-05 14:52:22 +0800226 surf->fence_fd = fence_fd;
Greg Hackmann41909dd2014-04-25 10:39:50 -0700227
228 pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces;
xinglong.zhuc4fa2c22016-08-05 14:52:22 +0800229 adf_sync(&pdata->surfaces[pdata->current_surface]);
Greg Hackmann41909dd2014-04-25 10:39:50 -0700230 return &pdata->surfaces[pdata->current_surface].base;
231}
232
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700233static void adf_blank(minui_backend *backend, bool blank)
Greg Hackmann41909dd2014-04-25 10:39:50 -0700234{
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700235 adf_pdata *pdata = (adf_pdata *)backend;
Greg Hackmann41909dd2014-04-25 10:39:50 -0700236 adf_interface_blank(pdata->intf_fd,
237 blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON);
238}
239
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700240static void adf_surface_destroy(adf_surface_pdata *surf)
Greg Hackmann41909dd2014-04-25 10:39:50 -0700241{
242 munmap(surf->base.data, surf->pitch * surf->base.height);
xinglong.zhuc4fa2c22016-08-05 14:52:22 +0800243 close(surf->fence_fd);
Greg Hackmann41909dd2014-04-25 10:39:50 -0700244 close(surf->fd);
245}
246
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700247static void adf_exit(minui_backend *backend)
Greg Hackmann41909dd2014-04-25 10:39:50 -0700248{
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700249 adf_pdata *pdata = (adf_pdata *)backend;
Greg Hackmann41909dd2014-04-25 10:39:50 -0700250 unsigned int i;
251
Jonathan Hamiltonbab6e492016-05-05 15:30:57 -0700252 adf_device_close(&pdata->dev);
Greg Hackmann41909dd2014-04-25 10:39:50 -0700253 for (i = 0; i < pdata->n_surfaces; i++)
254 adf_surface_destroy(&pdata->surfaces[i]);
255 if (pdata->intf_fd >= 0)
256 close(pdata->intf_fd);
257 free(pdata);
258}
259
260minui_backend *open_adf()
261{
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700262 adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
Greg Hackmann41909dd2014-04-25 10:39:50 -0700263 if (!pdata) {
264 perror("allocating adf backend failed");
265 return NULL;
266 }
267
268 pdata->base.init = adf_init;
269 pdata->base.flip = adf_flip;
270 pdata->base.blank = adf_blank;
271 pdata->base.exit = adf_exit;
272 return &pdata->base;
273}