1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2014 The Android Open Source Project
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Licensed under the Apache License, Version 2.0 (the "License");
5*4882a593Smuzhiyun * you may not use this file except in compliance with the License.
6*4882a593Smuzhiyun * You may obtain a copy of the License at
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * http://www.apache.org/licenses/LICENSE-2.0
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Unless required by applicable law or agreed to in writing, software
11*4882a593Smuzhiyun * distributed under the License is distributed on an "AS IS" BASIS,
12*4882a593Smuzhiyun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4882a593Smuzhiyun * See the License for the specific language governing permissions and
14*4882a593Smuzhiyun * limitations under the License.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <errno.h>
18*4882a593Smuzhiyun #include <fcntl.h>
19*4882a593Smuzhiyun #include <stdbool.h>
20*4882a593Smuzhiyun #include <stdio.h>
21*4882a593Smuzhiyun #include <stdlib.h>
22*4882a593Smuzhiyun #include <unistd.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include <sys/cdefs.h>
25*4882a593Smuzhiyun #include <sys/mman.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include <adf/adf.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include "graphics.h"
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct adf_surface_pdata {
32*4882a593Smuzhiyun GRSurface base;
33*4882a593Smuzhiyun int fd;
34*4882a593Smuzhiyun __u32 offset;
35*4882a593Smuzhiyun __u32 pitch;
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun struct adf_pdata {
39*4882a593Smuzhiyun minui_backend base;
40*4882a593Smuzhiyun int intf_fd;
41*4882a593Smuzhiyun adf_id_t eng_id;
42*4882a593Smuzhiyun __u32 format;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun unsigned int current_surface;
45*4882a593Smuzhiyun unsigned int n_surfaces;
46*4882a593Smuzhiyun struct adf_surface_pdata surfaces[2];
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static gr_surface adf_flip(struct minui_backend *backend);
50*4882a593Smuzhiyun static void adf_blank(struct minui_backend *backend, bool blank);
51*4882a593Smuzhiyun
adf_surface_init(struct adf_pdata * pdata,struct drm_mode_modeinfo * mode,struct adf_surface_pdata * surf)52*4882a593Smuzhiyun static int adf_surface_init(struct adf_pdata *pdata,
53*4882a593Smuzhiyun struct drm_mode_modeinfo *mode, struct adf_surface_pdata *surf)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun memset(surf, 0, sizeof(*surf));
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay,
58*4882a593Smuzhiyun mode->vdisplay, pdata->format, &surf->offset, &surf->pitch);
59*4882a593Smuzhiyun if (surf->fd < 0)
60*4882a593Smuzhiyun return surf->fd;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun surf->base.width = mode->hdisplay;
63*4882a593Smuzhiyun surf->base.height = mode->vdisplay;
64*4882a593Smuzhiyun surf->base.row_bytes = surf->pitch;
65*4882a593Smuzhiyun surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun surf->base.data = mmap(NULL, surf->pitch * surf->base.height, PROT_WRITE,
68*4882a593Smuzhiyun MAP_SHARED, surf->fd, surf->offset);
69*4882a593Smuzhiyun if (surf->base.data == MAP_FAILED) {
70*4882a593Smuzhiyun close(surf->fd);
71*4882a593Smuzhiyun return -errno;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun return 0;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
adf_interface_init(struct adf_pdata * pdata)77*4882a593Smuzhiyun static int adf_interface_init(struct adf_pdata *pdata)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun struct adf_interface_data intf_data;
80*4882a593Smuzhiyun int ret = 0;
81*4882a593Smuzhiyun int err;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun err = adf_get_interface_data(pdata->intf_fd, &intf_data);
84*4882a593Smuzhiyun if (err < 0)
85*4882a593Smuzhiyun return err;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[0]);
88*4882a593Smuzhiyun if (err < 0) {
89*4882a593Smuzhiyun fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err));
90*4882a593Smuzhiyun ret = err;
91*4882a593Smuzhiyun goto done;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun err = adf_surface_init(pdata, &intf_data.current_mode,
95*4882a593Smuzhiyun &pdata->surfaces[1]);
96*4882a593Smuzhiyun if (err < 0) {
97*4882a593Smuzhiyun fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err));
98*4882a593Smuzhiyun memset(&pdata->surfaces[1], 0, sizeof(pdata->surfaces[1]));
99*4882a593Smuzhiyun pdata->n_surfaces = 1;
100*4882a593Smuzhiyun } else {
101*4882a593Smuzhiyun pdata->n_surfaces = 2;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun done:
105*4882a593Smuzhiyun adf_free_interface_data(&intf_data);
106*4882a593Smuzhiyun return ret;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
adf_device_init(struct adf_pdata * pdata,struct adf_device * dev)109*4882a593Smuzhiyun static int adf_device_init(struct adf_pdata *pdata, struct adf_device *dev)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun adf_id_t intf_id;
112*4882a593Smuzhiyun int intf_fd;
113*4882a593Smuzhiyun int err;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id,
116*4882a593Smuzhiyun &pdata->eng_id);
117*4882a593Smuzhiyun if (err < 0)
118*4882a593Smuzhiyun return err;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun err = adf_device_attach(dev, pdata->eng_id, intf_id);
121*4882a593Smuzhiyun if (err < 0 && err != -EALREADY)
122*4882a593Smuzhiyun return err;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR);
125*4882a593Smuzhiyun if (pdata->intf_fd < 0)
126*4882a593Smuzhiyun return pdata->intf_fd;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun err = adf_interface_init(pdata);
129*4882a593Smuzhiyun if (err < 0) {
130*4882a593Smuzhiyun close(pdata->intf_fd);
131*4882a593Smuzhiyun pdata->intf_fd = -1;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun return err;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
adf_init(minui_backend * backend)137*4882a593Smuzhiyun static gr_surface adf_init(minui_backend *backend)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun struct adf_pdata *pdata = (struct adf_pdata *)backend;
140*4882a593Smuzhiyun adf_id_t *dev_ids = NULL;
141*4882a593Smuzhiyun ssize_t n_dev_ids, i;
142*4882a593Smuzhiyun gr_surface ret;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun #if defined(RECOVERY_BGRA)
145*4882a593Smuzhiyun pdata->format = DRM_FORMAT_BGRA8888;
146*4882a593Smuzhiyun #elif defined(RECOVERY_RGBX)
147*4882a593Smuzhiyun pdata->format = DRM_FORMAT_RGBX8888;
148*4882a593Smuzhiyun #else
149*4882a593Smuzhiyun pdata->format = DRM_FORMAT_RGB565;
150*4882a593Smuzhiyun #endif
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun n_dev_ids = adf_devices(&dev_ids);
153*4882a593Smuzhiyun if (n_dev_ids == 0) {
154*4882a593Smuzhiyun return NULL;
155*4882a593Smuzhiyun } else if (n_dev_ids < 0) {
156*4882a593Smuzhiyun fprintf(stderr, "enumerating adf devices failed: %s\n",
157*4882a593Smuzhiyun strerror(-n_dev_ids));
158*4882a593Smuzhiyun return NULL;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun pdata->intf_fd = -1;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) {
164*4882a593Smuzhiyun struct adf_device dev;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun int err = adf_device_open(dev_ids[i], O_RDWR, &dev);
167*4882a593Smuzhiyun if (err < 0) {
168*4882a593Smuzhiyun fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i],
169*4882a593Smuzhiyun strerror(-err));
170*4882a593Smuzhiyun continue;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun err = adf_device_init(pdata, &dev);
174*4882a593Smuzhiyun if (err < 0)
175*4882a593Smuzhiyun fprintf(stderr, "initializing adf device %u failed: %s\n",
176*4882a593Smuzhiyun dev_ids[i], strerror(-err));
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun adf_device_close(&dev);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun free(dev_ids);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun if (pdata->intf_fd < 0)
184*4882a593Smuzhiyun return NULL;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun ret = adf_flip(backend);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun adf_blank(backend, true);
189*4882a593Smuzhiyun adf_blank(backend, false);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun return ret;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
adf_flip(struct minui_backend * backend)194*4882a593Smuzhiyun static gr_surface adf_flip(struct minui_backend *backend)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun struct adf_pdata *pdata = (struct adf_pdata *)backend;
197*4882a593Smuzhiyun struct adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface];
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id,
200*4882a593Smuzhiyun surf->base.width, surf->base.height, pdata->format, surf->fd,
201*4882a593Smuzhiyun surf->offset, surf->pitch, -1);
202*4882a593Smuzhiyun if (fence_fd >= 0)
203*4882a593Smuzhiyun close(fence_fd);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces;
206*4882a593Smuzhiyun return &pdata->surfaces[pdata->current_surface].base;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
adf_blank(struct minui_backend * backend,bool blank)209*4882a593Smuzhiyun static void adf_blank(struct minui_backend *backend, bool blank)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun struct adf_pdata *pdata = (struct adf_pdata *)backend;
212*4882a593Smuzhiyun adf_interface_blank(pdata->intf_fd,
213*4882a593Smuzhiyun blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
adf_surface_destroy(struct adf_surface_pdata * surf)216*4882a593Smuzhiyun static void adf_surface_destroy(struct adf_surface_pdata *surf)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun munmap(surf->base.data, surf->pitch * surf->base.height);
219*4882a593Smuzhiyun close(surf->fd);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
adf_exit(struct minui_backend * backend)222*4882a593Smuzhiyun static void adf_exit(struct minui_backend *backend)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun struct adf_pdata *pdata = (struct adf_pdata *)backend;
225*4882a593Smuzhiyun unsigned int i;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun for (i = 0; i < pdata->n_surfaces; i++)
228*4882a593Smuzhiyun adf_surface_destroy(&pdata->surfaces[i]);
229*4882a593Smuzhiyun if (pdata->intf_fd >= 0)
230*4882a593Smuzhiyun close(pdata->intf_fd);
231*4882a593Smuzhiyun free(pdata);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
open_adf()234*4882a593Smuzhiyun minui_backend *open_adf()
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct adf_pdata *pdata = calloc(1, sizeof(*pdata));
237*4882a593Smuzhiyun if (!pdata) {
238*4882a593Smuzhiyun perror("allocating adf backend failed");
239*4882a593Smuzhiyun return NULL;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun pdata->base.init = adf_init;
243*4882a593Smuzhiyun pdata->base.flip = adf_flip;
244*4882a593Smuzhiyun pdata->base.blank = adf_blank;
245*4882a593Smuzhiyun pdata->base.exit = adf_exit;
246*4882a593Smuzhiyun return &pdata->base;
247*4882a593Smuzhiyun }
248