Merge tag 'v4.4-rc6'
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / bmp_helper.c
1 /*
2  * linux/drivers/video/rockchip/bmp_helper.c
3  *
4  * Copyright (C) 2012 Rockchip Corporation
5  * Author: Mark Yao <mark.yao@rock-chips.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <linux/sysfs.h>
21 #include <linux/uaccess.h>
22 #include <linux/kernel.h>
23 #include <linux/rk_fb.h>
24
25 #include "bmp_helper.h"
26
27 static void draw_unencoded_bitmap(uint16_t **dst, uint8_t *bmap, uint16_t *cmap,
28                                   uint32_t cnt)
29 {
30         while (cnt > 0) {
31                 *(*dst)++ = cmap[*bmap++];
32                 cnt--;
33         }
34 }
35
36 static void draw_encoded_bitmap(uint16_t **dst, uint16_t c, uint32_t cnt)
37 {
38         uint16_t *fb = *dst;
39         int cnt_8copy = cnt >> 3;
40
41         cnt -= cnt_8copy << 3;
42         while (cnt_8copy > 0) {
43                 *fb++ = c;
44                 *fb++ = c;
45                 *fb++ = c;
46                 *fb++ = c;
47                 *fb++ = c;
48                 *fb++ = c;
49                 *fb++ = c;
50                 *fb++ = c;
51                 cnt_8copy--;
52         }
53         while (cnt > 0) {
54                 *fb++ = c;
55                 cnt--;
56         }
57         *dst = fb;
58 }
59
60 static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
61 {
62         int rdif, invgdif, bdif;
63
64         u -= 128;
65         v -= 128;
66         rdif = v + ((v * 103) >> 8);
67         invgdif = ((u * 88) >> 8) + ((v * 183) >> 8);
68         bdif = u + ((u*198) >> 8);
69         *r = range(y + rdif, 0, 0xff);
70         *g = range(y - invgdif, 0, 0xff);
71         *b = range(y + bdif, 0, 0xff);
72 }
73
74 int bmpencoder(void *__iomem *vaddr, int width, int height, u8 data_format,
75                void *data, void (*fn)(void *, void *, int))
76 {
77         uint32_t *d, *d1, *d2;
78         uint8_t *dst, *yrgb, *uv, *y1, *y2;
79         int y, u, v, r, g, b;
80
81         int yu = width * 4 % 4;
82         int byteperline;
83         unsigned int size;
84         BITMAPHEADER header;
85         BITMAPINFOHEADER infoheader;
86         void *buf;
87         int i, j;
88
89         yu = yu != 0 ? 4 - yu : yu;
90         byteperline = width * 4 + yu;
91         size = byteperline * height + 54;
92         memset(&header, 0, sizeof(header));
93         memset(&infoheader, 0, sizeof(infoheader));
94         header.type = 'M'<<8|'B';
95         header.size = size;
96         header.offset = 54;
97
98         infoheader.size = 40;
99         infoheader.width = width;
100         infoheader.height = 0 - height;
101         infoheader.bitcount = 4 * 8;
102         infoheader.compression = 0;
103         infoheader.imagesize = byteperline * height;
104         infoheader.xpelspermeter = 0;
105         infoheader.ypelspermeter = 0;
106         infoheader.colors = 0;
107         infoheader.colorsimportant = 0;
108         fn(data, (void *)&header, sizeof(header));
109         fn(data, (void *)&infoheader, sizeof(infoheader));
110
111         /*
112          * if data_format is ARGB888 or XRGB888, not need convert.
113          */
114         if (data_format == ARGB888 || data_format == XRGB888) {
115                 fn(data, (char *)vaddr, width * height * 4);
116                 return 0;
117         }
118         /*
119          * alloc 2 line buffer.
120          */
121         buf = kmalloc(width * 2 * 4, GFP_KERNEL);
122         if (!buf)
123                 return -ENOMEM;
124         yrgb = (uint8_t *)vaddr;
125         uv = yrgb + width * height;
126         for (j = 0; j < height; j++) {
127                 if (j % 2 == 0) {
128                         dst = buf;
129                         y1 = yrgb + j * width;
130                         y2 = y1 + width;
131                         d1 = buf;
132                         d2 = d1 + width;
133                 }
134
135                 for (i = 0; i < width; i++) {
136                         switch (data_format) {
137                         case XBGR888:
138                         case ABGR888:
139                                 dst[0] = yrgb[2];
140                                 dst[1] = yrgb[1];
141                                 dst[2] = yrgb[0];
142                                 dst[3] = yrgb[3];
143                                 dst += 4;
144                                 yrgb += 4;
145                                 break;
146                         case RGB888:
147                                 dst[0] = yrgb[0];
148                                 dst[1] = yrgb[1];
149                                 dst[2] = yrgb[2];
150                                 dst[3] = 0xff;
151                                 dst += 4;
152                                 yrgb += 3;
153                                 break;
154                         case RGB565:
155                                 dst[0] = (yrgb[0] & 0x1f) << 3;
156                                 dst[1] = (yrgb[0] & 0xe0) >> 3 |
157                                                 (yrgb[1] & 0x7) << 5;
158                                 dst[2] = yrgb[1] & 0xf8;
159                                 dst[3] = 0xff;
160                                 dst += 4;
161                                 yrgb += 2;
162                                 break;
163                         case YUV420:
164                         case YUV422:
165                         case YUV444:
166                                 if (data_format == YUV420) {
167                                         if (i % 2 == 0) {
168                                                 d = d1++;
169                                                 y = *y1++;
170                                         } else {
171                                                 d = d2++;
172                                                 y = *y2++;
173                                         }
174                                         if (i % 4 == 0) {
175                                                 u = *uv++;
176                                                 v = *uv++;
177                                         }
178                                 } else if (data_format == YUV422) {
179                                         if (i % 2 == 0) {
180                                                 u = *uv++;
181                                                 v = *uv++;
182                                         }
183                                         d = d1++;
184                                 } else {
185                                         u = *uv++;
186                                         v = *uv++;
187                                         d = d1++;
188                                 }
189                                 yuv_to_rgb(y, u, v, &r, &g, &b);
190                                 *d = 0xff<<24 | r << 16 | g << 8 | b;
191                                 break;
192                         case YUV422_A:
193                         case YUV444_A:
194                         default:
195                                 pr_err("unsupport now\n");
196                                 return -EINVAL;
197                         }
198                 }
199                 if (j % 2 == 1)
200                         fn(data, (char *)buf, 2 * width * 4);
201         }
202
203         return 0;
204 }
205
206 static void decode_rle8_bitmap(uint8_t *psrc, uint8_t *pdst, uint16_t *cmap,
207                                unsigned int width, unsigned int height,
208                                int bits, int x_off, int y_off, bool flip)
209 {
210         uint32_t cnt, runlen;
211         int x = 0, y = 0;
212         int decode = 1;
213         uint8_t *bmap = psrc;
214         uint8_t *dst = pdst;
215         int linesize = width * 2;
216
217         if (flip) {
218                 y = height - 1;
219                 dst = pdst + y * linesize;
220         }
221
222         while (decode) {
223                 if (bmap[0] == BMP_RLE8_ESCAPE) {
224                         switch (bmap[1]) {
225                         case BMP_RLE8_EOL:
226                                 /* end of line */
227                                 bmap += 2;
228                                 x = 0;
229                                 if (flip) {
230                                         y--;
231                                         dst -= linesize * 2;
232                                 } else {
233                                         y++;
234                                 }
235                                 break;
236                         case BMP_RLE8_EOBMP:
237                                 /* end of bitmap */
238                                 decode = 0;
239                                 break;
240                         case BMP_RLE8_DELTA:
241                                 /* delta run */
242                                 x += bmap[2];
243                                 if (flip) {
244                                         y -= bmap[3];
245                                         dst -= bmap[3] * linesize;
246                                         dst += bmap[2] * 2;
247                                 } else {
248                                         y += bmap[3];
249                                         dst += bmap[3] * linesize;
250                                         dst += bmap[2] * 2;
251                                 }
252                                 bmap += 4;
253                                 break;
254                         default:
255                                 /* unencoded run */
256                                 runlen = bmap[1];
257                                 bmap += 2;
258                                 if (y >= height || x >= width) {
259                                         decode = 0;
260                                         break;
261                                 }
262                                 if (x + runlen > width)
263                                         cnt = width - x;
264                                 else
265                                         cnt = runlen;
266                                 draw_unencoded_bitmap((uint16_t **)&dst, bmap,
267                                                       cmap, cnt);
268                                 x += runlen;
269                                 bmap += runlen;
270                                 if (runlen & 1)
271                                         bmap++;
272                         }
273                 } else {
274                         /* encoded run */
275                         if (y < height) {
276                                 runlen = bmap[0];
277                                 if (x < width) {
278                                         /* aggregate the same code */
279                                         while (bmap[0] == 0xff &&
280                                                bmap[2] != BMP_RLE8_ESCAPE &&
281                                                bmap[1] == bmap[3]) {
282                                                 runlen += bmap[2];
283                                                 bmap += 2;
284                                         }
285                                         if (x + runlen > width)
286                                                 cnt = width - x;
287                                         else
288                                                 cnt = runlen;
289                                         draw_encoded_bitmap((uint16_t **)&dst,
290                                                             cmap[bmap[1]], cnt);
291                                 }
292                                 x += runlen;
293                         }
294                         bmap += 2;
295                 }
296         }
297 }
298
299 int bmpdecoder(void *bmp_addr, void *pdst, int *width, int *height, int *bits)
300 {
301         BITMAPHEADER header;
302         BITMAPINFOHEADER infoheader;
303         uint16_t *bmp_logo_palette;
304         uint32_t size;
305         uint16_t linesize;
306         char *cmap_base;
307         char *src = bmp_addr;
308         char *dst = pdst;
309         int i;
310         bool flip = false;
311
312         memcpy(&header, src, sizeof(header));
313         src += sizeof(header);
314
315         if (header.type != 0x4d42) {
316                 pr_err("not bmp file type[%x], can't support\n", header.type);
317                 return -1;
318         }
319         memcpy(&infoheader, src, sizeof(infoheader));
320         *width = infoheader.width;
321         *height = infoheader.height;
322
323         if (*height < 0)
324                 *height = 0 - *height;
325         else
326                 flip = true;
327
328         size = header.size - header.offset;
329         linesize = *width * infoheader.bitcount >> 3;
330         cmap_base = src + sizeof(infoheader);
331         src = bmp_addr + header.offset;
332
333         switch (infoheader.bitcount) {
334         case 8:
335                 bmp_logo_palette = kmalloc(sizeof(bmp_logo_palette) * 256, GFP_KERNEL);
336
337                 /* Set color map */
338                 for (i = 0; i < 256; i++) {
339                         ushort colreg = ((cmap_base[2] << 8) & 0xf800) |
340                                         ((cmap_base[1] << 3) & 0x07e0) |
341                                         ((cmap_base[0] >> 3) & 0x001f) ;
342                         cmap_base += 4;
343                         bmp_logo_palette[i] = colreg;
344                 }
345
346                 /*
347                  * only support convert 8bit bmap file to RGB565.
348                  */
349                 decode_rle8_bitmap(src, dst, bmp_logo_palette,
350                                    infoheader.width, infoheader.height,
351                                    infoheader.bitcount, 0, 0, flip);
352                 kfree(bmp_logo_palette);
353                 *bits = 16;
354                 break;
355         case 16:
356                 /*
357                  * Todo
358                  */
359                 pr_info("unsupport bit=%d now\n", infoheader.bitcount);
360                 break;
361         case 24:
362                 if (flip)
363                         src += (*width) * (*height - 1) * 3;
364
365                 for (i = 0; i < *height; i++) {
366                         memcpy(dst, src, 3 * (*width));
367                         dst += *width * 3;
368                         src += *width * 3;
369                         if (flip)
370                                 src -= *width * 3 * 2;
371                 }
372
373                 *bits = 24;
374                 break;
375         case 32:
376                 /*
377                  * Todo
378                  */
379                 pr_info("unsupport bit=%d now\n", infoheader.bitcount);
380                 break;
381         default:
382                 pr_info("unsupport bit=%d now\n", infoheader.bitcount);
383                 break;
384         }
385
386         return 0;
387 }