1 /*
2 * Copyright (C) 2008 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
18 #define LOG_TAG "copybit"
19
20 #include <cutils/log.h>
21
22 #include <linux/msm_mdp.h>
23 #include <linux/fb.h>
24
25 #include <stdint.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <fcntl.h>
30
31 #include <sys/ioctl.h>
32 #include <sys/types.h>
33 #include <sys/mman.h>
34
35 #include <hardware/copybit.h>
36
37 /******************************************************************************/
38
39 /** State information for each device instance */
40 struct copybit_context_t {
41 struct copybit_device_t device;
42 int mFD;
43 uint8_t mAlpha;
44 uint8_t mFlags;
45 };
46
47 /**
48 * Common hardware methods
49 */
50
51 static int open_copybit(const struct hw_module_t* module, const char* name,
52 struct hw_device_t** device);
53
54 static struct hw_module_methods_t copybit_module_methods = {
55 .open = open_copybit
56 };
57
58 /*
59 * The COPYBIT Module
60 */
61 const struct copybit_module_t HAL_MODULE_INFO_SYM = {
62 .common = {
63 .tag = HARDWARE_MODULE_TAG,
64 .version_major = 1,
65 .version_minor = 0,
66 .id = COPYBIT_HARDWARE_MODULE_ID,
67 .name = "QCT MSM7K COPYBIT Module",
68 .author = "Google, Inc.",
69 .methods = ©bit_module_methods,
70 }
71 };
72
73 /******************************************************************************/
74
75 /** min of int a, b */
min(int a,int b)76 static inline int min(int a, int b) {
77 return (a<b) ? a : b;
78 }
79
80 /** max of int a, b */
max(int a,int b)81 static inline int max(int a, int b) {
82 return (a>b) ? a : b;
83 }
84
85 /** scale each parameter by mul/div. Assume div isn't 0 */
MULDIV(uint32_t * a,uint32_t * b,int mul,int div)86 static inline void MULDIV(uint32_t *a, uint32_t *b, int mul, int div) {
87 if (mul != div) {
88 *a = (mul * *a) / div;
89 *b = (mul * *b) / div;
90 }
91 }
92
93 /** Determine the intersection of lhs & rhs store in out */
intersect(struct copybit_rect_t * out,const struct copybit_rect_t * lhs,const struct copybit_rect_t * rhs)94 static void intersect(struct copybit_rect_t *out,
95 const struct copybit_rect_t *lhs,
96 const struct copybit_rect_t *rhs) {
97 out->l = max(lhs->l, rhs->l);
98 out->t = max(lhs->t, rhs->t);
99 out->r = min(lhs->r, rhs->r);
100 out->b = min(lhs->b, rhs->b);
101 }
102
103 /** convert COPYBIT_FORMAT to MDP format */
get_format(int format)104 static int get_format(int format) {
105 switch (format) {
106 case COPYBIT_FORMAT_RGBA_8888: return MDP_RGBA_8888;
107 case COPYBIT_FORMAT_BGRA_8888: return MDP_BGRA_8888;
108 case COPYBIT_FORMAT_RGB_565: return MDP_RGB_565;
109 case COPYBIT_FORMAT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1;
110 case COPYBIT_FORMAT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2;
111 }
112 return -1;
113 }
114
115 /** convert from copybit image to mdp image structure */
set_image(struct mdp_img * img,const struct copybit_image_t * rhs)116 static void set_image(struct mdp_img *img,
117 const struct copybit_image_t *rhs) {
118 img->width = rhs->w;
119 img->height = rhs->h;
120 img->format = get_format(rhs->format);
121 img->offset = rhs->offset;
122 img->memory_id = rhs->fd;
123 }
124
125 /** setup rectangles */
set_rects(struct copybit_context_t * dev,struct mdp_blit_req * e,const struct copybit_rect_t * dst,const struct copybit_rect_t * src,const struct copybit_rect_t * scissor)126 static void set_rects(struct copybit_context_t *dev,
127 struct mdp_blit_req *e,
128 const struct copybit_rect_t *dst,
129 const struct copybit_rect_t *src,
130 const struct copybit_rect_t *scissor) {
131 struct copybit_rect_t clip;
132 intersect(&clip, scissor, dst);
133
134 e->dst_rect.x = clip.l;
135 e->dst_rect.y = clip.t;
136 e->dst_rect.w = clip.r - clip.l;
137 e->dst_rect.h = clip.b - clip.t;
138
139 uint32_t W, H;
140 if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
141 e->src_rect.x = (clip.t - dst->t) + src->t;
142 e->src_rect.y = (dst->r - clip.r) + src->l;
143 e->src_rect.w = (clip.b - clip.t);
144 e->src_rect.h = (clip.r - clip.l);
145 W = dst->b - dst->t;
146 H = dst->r - dst->l;
147 } else {
148 e->src_rect.x = (clip.l - dst->l) + src->l;
149 e->src_rect.y = (clip.t - dst->t) + src->t;
150 e->src_rect.w = (clip.r - clip.l);
151 e->src_rect.h = (clip.b - clip.t);
152 W = dst->r - dst->l;
153 H = dst->b - dst->t;
154 }
155 MULDIV(&e->src_rect.x, &e->src_rect.w, src->r - src->l, W);
156 MULDIV(&e->src_rect.y, &e->src_rect.h, src->b - src->t, H);
157 if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) {
158 e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h);
159 }
160 if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) {
161 e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w);
162 }
163 }
164
165 /** setup mdp request */
set_infos(struct copybit_context_t * dev,struct mdp_blit_req * req)166 static void set_infos(struct copybit_context_t *dev, struct mdp_blit_req *req) {
167 req->alpha = dev->mAlpha;
168 req->transp_mask = MDP_TRANSP_NOP;
169 req->flags = dev->mFlags;
170 }
171
172 /** copy the bits */
msm_copybit(struct copybit_context_t * dev,void const * list)173 static int msm_copybit(struct copybit_context_t *dev, void const *list)
174 {
175 int err = ioctl(dev->mFD, MSMFB_BLIT,
176 (struct mdp_blit_req_list const*)list);
177 LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
178 if (err == 0)
179 return 0;
180 else
181 return -errno;
182 }
183
184 /*****************************************************************************/
185
186 /** Set a parameter to value */
set_parameter_copybit(struct copybit_device_t * dev,int name,int value)187 static int set_parameter_copybit(
188 struct copybit_device_t *dev,
189 int name,
190 int value)
191 {
192 struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
193 int status = 0;
194 if (ctx) {
195 switch(name) {
196 case COPYBIT_ROTATION_DEG:
197 switch (value) {
198 case 0:
199 ctx->mFlags &= ~0x7;
200 break;
201 case 90:
202 ctx->mFlags &= ~0x7;
203 ctx->mFlags |= MDP_ROT_90;
204 break;
205 case 180:
206 ctx->mFlags &= ~0x7;
207 ctx->mFlags |= MDP_ROT_180;
208 break;
209 case 270:
210 ctx->mFlags &= ~0x7;
211 ctx->mFlags |= MDP_ROT_270;
212 break;
213 default:
214 LOGE("Invalid value for COPYBIT_ROTATION_DEG");
215 status = -EINVAL;
216 break;
217 }
218 break;
219 case COPYBIT_PLANE_ALPHA:
220 if (value < 0) value = 0;
221 if (value >= 256) value = 255;
222 ctx->mAlpha = value;
223 break;
224 case COPYBIT_DITHER:
225 if (value == COPYBIT_ENABLE) {
226 ctx->mFlags |= MDP_DITHER;
227 } else if (value == COPYBIT_DISABLE) {
228 ctx->mFlags &= ~MDP_DITHER;
229 }
230 break;
231 case COPYBIT_BLUR:
232 if (value == COPYBIT_ENABLE) {
233 ctx->mFlags |= MDP_BLUR;
234 } else if (value == COPYBIT_DISABLE) {
235 ctx->mFlags &= ~MDP_BLUR;
236 }
237 break;
238 case COPYBIT_TRANSFORM:
239 ctx->mFlags &= ~0x7;
240 ctx->mFlags |= value & 0x7;
241 break;
242 default:
243 status = -EINVAL;
244 break;
245 }
246 } else {
247 status = -EINVAL;
248 }
249 return status;
250 }
251
252 /** Get a static info value */
get(struct copybit_device_t * dev,int name)253 static int get(struct copybit_device_t *dev, int name)
254 {
255 struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
256 int value;
257 if (ctx) {
258 switch(name) {
259 case COPYBIT_MINIFICATION_LIMIT:
260 value = 4;
261 break;
262 case COPYBIT_MAGNIFICATION_LIMIT:
263 value = 4;
264 break;
265 case COPYBIT_SCALING_FRAC_BITS:
266 value = 32;
267 break;
268 case COPYBIT_ROTATION_STEP_DEG:
269 value = 90;
270 break;
271 default:
272 value = -EINVAL;
273 }
274 } else {
275 value = -EINVAL;
276 }
277 return value;
278 }
279
280 /** do a stretch blit type operation */
stretch_copybit(struct copybit_device_t * dev,struct copybit_image_t const * dst,struct copybit_image_t const * src,struct copybit_rect_t const * dst_rect,struct copybit_rect_t const * src_rect,struct copybit_region_t const * region)281 static int stretch_copybit(
282 struct copybit_device_t *dev,
283 struct copybit_image_t const *dst,
284 struct copybit_image_t const *src,
285 struct copybit_rect_t const *dst_rect,
286 struct copybit_rect_t const *src_rect,
287 struct copybit_region_t const *region)
288 {
289 struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
290 int status = 0;
291 if (ctx) {
292 struct {
293 uint32_t count;
294 struct mdp_blit_req req[12];
295 } list;
296
297 if (ctx->mAlpha < 255) {
298 switch (src->format) {
299 // we don't support plane alpha with RGBA formats
300 case COPYBIT_FORMAT_RGBA_8888:
301 case COPYBIT_FORMAT_BGRA_8888:
302 case COPYBIT_FORMAT_RGBA_5551:
303 case COPYBIT_FORMAT_RGBA_4444:
304 return -EINVAL;
305 }
306 }
307
308 const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]);
309 const struct copybit_rect_t bounds = { 0, 0, dst->w, dst->h };
310 struct copybit_rect_t clip;
311 list.count = 0;
312 status = 0;
313 while ((status == 0) && region->next(region, &clip)) {
314 intersect(&clip, &bounds, &clip);
315 set_infos(ctx, &list.req[list.count]);
316 set_image(&list.req[list.count].dst, dst);
317 set_image(&list.req[list.count].src, src);
318 set_rects(ctx, &list.req[list.count], dst_rect, src_rect, &clip);
319 if (++list.count == maxCount) {
320 status = msm_copybit(ctx, &list);
321 list.count = 0;
322 }
323 }
324 if ((status == 0) && list.count) {
325 status = msm_copybit(ctx, &list);
326 }
327 } else {
328 status = -EINVAL;
329 }
330 return status;
331 }
332
333 /** Perform a blit type operation */
blit_copybit(struct copybit_device_t * dev,struct copybit_image_t const * dst,struct copybit_image_t const * src,struct copybit_region_t const * region)334 static int blit_copybit(
335 struct copybit_device_t *dev,
336 struct copybit_image_t const *dst,
337 struct copybit_image_t const *src,
338 struct copybit_region_t const *region)
339 {
340 struct copybit_rect_t dr = { 0, 0, dst->w, dst->h };
341 struct copybit_rect_t sr = { 0, 0, src->w, src->h };
342 return stretch_copybit(dev, dst, src, &dr, &sr, region);
343 }
344
345 /*****************************************************************************/
346
347 /** Close the copybit device */
close_copybit(struct hw_device_t * dev)348 static int close_copybit(struct hw_device_t *dev)
349 {
350 struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
351 if (ctx) {
352 close(ctx->mFD);
353 free(ctx);
354 }
355 return 0;
356 }
357
358 /** Open a new instance of a copybit device using name */
open_copybit(const struct hw_module_t * module,const char * name,struct hw_device_t ** device)359 static int open_copybit(const struct hw_module_t* module, const char* name,
360 struct hw_device_t** device)
361 {
362 int status = -EINVAL;
363 struct copybit_context_t *ctx = malloc(sizeof(struct copybit_context_t));
364 memset(ctx, 0, sizeof(*ctx));
365
366 ctx->device.common.tag = HARDWARE_DEVICE_TAG;
367 ctx->device.common.version = 0;
368 ctx->device.common.module = module;
369 ctx->device.common.close = close_copybit;
370 ctx->device.set_parameter = set_parameter_copybit;
371 ctx->device.get = get;
372 ctx->device.blit = blit_copybit;
373 ctx->device.stretch = stretch_copybit;
374 ctx->mAlpha = MDP_ALPHA_NOP;
375 ctx->mFlags = 0;
376 ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0);
377
378 if (ctx->mFD < 0) {
379 status = errno;
380 LOGE("Error opening frame buffer errno=%d (%s)",
381 status, strerror(status));
382 status = -status;
383 } else {
384 struct fb_fix_screeninfo finfo;
385 if (ioctl(ctx->mFD, FBIOGET_FSCREENINFO, &finfo) == 0) {
386 if (strcmp(finfo.id, "msmfb") == 0) {
387 /* Success */
388 status = 0;
389 } else {
390 LOGE("Error not msm frame buffer");
391 status = -EINVAL;
392 }
393 } else {
394 LOGE("Error executing ioctl for screen info");
395 status = -errno;
396 }
397 }
398
399 if (status == 0) {
400 *device = &ctx->device.common;
401 } else {
402 close_copybit(&ctx->device.common);
403 }
404 return status;
405 }
406