1 #define LOG_TAG "GRALLOC-ROCKCHIP"
2 
3 #include <cutils/log.h>
4 #include <stdlib.h>
5 #include <errno.h>
6 #include <drm.h>
7 #include <rockchip/rockchip_drmif.h>
8 
9 #include "gralloc_drm.h"
10 #include "gralloc_drm_priv.h"
11 
12 #define UNUSED(...) (void)(__VA_ARGS__)
13 
14 struct rockchip_info {
15 	struct gralloc_drm_drv_t base;
16 
17 	struct rockchip_device *rockchip;
18 	int fd;
19 };
20 
21 struct rockchip_buffer {
22 	struct gralloc_drm_bo_t base;
23 
24 	struct rockchip_bo *bo;
25 };
26 
drm_gem_rockchip_destroy(struct gralloc_drm_drv_t * drv)27 static void drm_gem_rockchip_destroy(struct gralloc_drm_drv_t *drv)
28 {
29 	struct rockchip_info *info = (struct rockchip_info *)drv;
30 
31 	if (info->rockchip)
32 		rockchip_device_destroy(info->rockchip);
33 	free(info);
34 }
35 
drm_gem_rockchip_alloc(struct gralloc_drm_drv_t * drv,struct gralloc_drm_handle_t * handle)36 static struct gralloc_drm_bo_t *drm_gem_rockchip_alloc(
37 		struct gralloc_drm_drv_t *drv,
38 		struct gralloc_drm_handle_t *handle)
39 {
40 	struct rockchip_info *info = (struct rockchip_info *)drv;
41 	struct rockchip_buffer *buf;
42 	struct drm_gem_close args;
43 	int ret, cpp, pitch, aligned_width, aligned_height;
44 	uint32_t size, gem_handle;
45 
46 	buf = calloc(1, sizeof(*buf));
47 	if (!buf) {
48 		ALOGE("Failed to allocate buffer wrapper\n");
49 		return NULL;
50 	}
51 
52 	cpp = gralloc_drm_get_bpp(handle->format);
53 	if (!cpp) {
54 		ALOGE("unrecognized format 0x%x", handle->format);
55 		return NULL;
56 	}
57 
58 	aligned_width = handle->width;
59 	aligned_height = handle->height;
60 	gralloc_drm_align_geometry(handle->format,
61 			&aligned_width, &aligned_height);
62 
63 	/* TODO: We need to sort out alignment */
64 	pitch = ALIGN(aligned_width * cpp, 64);
65 	size = aligned_height * pitch;
66 
67 	if (handle->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
68 		/*
69 		 * WAR for H264 decoder requiring additional space
70 		 * at the end of destination buffers.
71 		 */
72 		uint32_t w_mbs, h_mbs;
73 
74 		w_mbs = ALIGN(handle->width, 16) / 16;
75 		h_mbs = ALIGN(handle->height, 16) / 16;
76 		size += 64 * w_mbs * h_mbs;
77 	}
78 
79 	if (handle->prime_fd >= 0) {
80 		ret = drmPrimeFDToHandle(info->fd, handle->prime_fd,
81 			&gem_handle);
82 		if (ret) {
83 			char *c = NULL;
84 			ALOGE("failed to convert prime fd to handle %d ret=%d",
85 				handle->prime_fd, ret);
86 			*c = 0;
87 			goto err;
88 		}
89 		ALOGV("Got handle %d for fd %d\n", gem_handle, handle->prime_fd);
90 
91 		buf->bo = rockchip_bo_from_handle(info->rockchip, gem_handle,
92 			0, size);
93 		if (!buf->bo) {
94 			ALOGE("failed to wrap bo handle=%d size=%d\n",
95 				gem_handle, size);
96 
97 			memset(&args, 0, sizeof(args));
98 			args.handle = gem_handle;
99 			drmIoctl(info->fd, DRM_IOCTL_GEM_CLOSE, &args);
100 			return NULL;
101 		}
102 	} else {
103 		buf->bo = rockchip_bo_create(info->rockchip, size, 0);
104 		if (!buf->bo) {
105 			ALOGE("failed to allocate bo %dx%dx%dx%d\n",
106 				handle->height, pitch, cpp, size);
107 			goto err;
108 		}
109 
110 		gem_handle = rockchip_bo_handle(buf->bo);
111 		ret = drmPrimeHandleToFD(info->fd, gem_handle, 0,
112 			&handle->prime_fd);
113 		ALOGV("Got fd %d for handle %d\n", handle->prime_fd, gem_handle);
114 		if (ret) {
115 			ALOGE("failed to get prime fd %d", ret);
116 			goto err_unref;
117 		}
118 
119 		buf->base.fb_handle = gem_handle;
120 	}
121 
122 	handle->name = 0;
123 	handle->stride = pitch;
124 	buf->base.handle = handle;
125 
126 	return &buf->base;
127 
128 err_unref:
129 	rockchip_bo_destroy(buf->bo);
130 err:
131 	free(buf);
132 	return NULL;
133 }
134 
drm_gem_rockchip_free(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo)135 static void drm_gem_rockchip_free(struct gralloc_drm_drv_t *drv,
136 		struct gralloc_drm_bo_t *bo)
137 {
138 	struct rockchip_buffer *buf = (struct rockchip_buffer *)bo;
139 
140 	UNUSED(drv);
141 
142 	if (bo->handle && bo->handle->prime_fd)
143 		close(bo->handle->prime_fd);
144 
145 	/* TODO: Is destroy correct here? */
146 	rockchip_bo_destroy(buf->bo);
147 	free(buf);
148 }
149 
drm_gem_rockchip_map(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo,int x,int y,int w,int h,int enable_write,void ** addr)150 static int drm_gem_rockchip_map(struct gralloc_drm_drv_t *drv,
151 		struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
152 		int enable_write, void **addr)
153 {
154 	struct rockchip_buffer *buf = (struct rockchip_buffer *)bo;
155 
156 	UNUSED(drv, x, y, w, h, enable_write);
157 
158 	*addr = rockchip_bo_map(buf->bo);
159 	if (!*addr) {
160 		ALOGE("failed to map bo\n");
161 		return -1;
162 	}
163 
164 	return 0;
165 }
166 
drm_gem_rockchip_unmap(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo)167 static void drm_gem_rockchip_unmap(struct gralloc_drm_drv_t *drv,
168 		struct gralloc_drm_bo_t *bo)
169 {
170 	UNUSED(drv, bo);
171 }
172 
gralloc_drm_drv_create_for_rockchip(int fd)173 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_rockchip(int fd)
174 {
175 	struct rockchip_info *info;
176 	int ret;
177 
178 	info = calloc(1, sizeof(*info));
179 	if (!info) {
180 		ALOGE("Failed to allocate rockchip gralloc device\n");
181 		return NULL;
182 	}
183 
184 	info->rockchip = rockchip_device_create(fd);
185 	if (!info->rockchip) {
186 		ALOGE("Failed to create new rockchip instance\n");
187 		free(info);
188 		return NULL;
189 	}
190 
191 	info->fd = fd;
192 	info->base.destroy = drm_gem_rockchip_destroy;
193 	info->base.alloc = drm_gem_rockchip_alloc;
194 	info->base.free = drm_gem_rockchip_free;
195 	info->base.map = drm_gem_rockchip_map;
196 	info->base.unmap = drm_gem_rockchip_unmap;
197 
198 	return &info->base;
199 }
200