drivers: video: rockchip: hdmi: modify RAYKEN5.46 pixclock
[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 = NULL, *d1 = NULL, *d2 = NULL;
78         uint8_t *dst = NULL, *yrgb = NULL, *uv = NULL, *y1 = NULL, *y2 = NULL;
79         int y = 0, u = 0, v = 0, r = 0, g = 0, b = 0;
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         int stride;
307         char *cmap_base;
308         char *src = bmp_addr;
309         char *dst = pdst;
310         int i;
311         bool flip = false;
312
313         memcpy(&header, src, sizeof(header));
314         src += sizeof(header);
315
316         if (header.type != 0x4d42) {
317                 pr_err("not bmp file type[%x], can't support\n", header.type);
318                 return -1;
319         }
320         memcpy(&infoheader, src, sizeof(infoheader));
321         *width = infoheader.width;
322         *height = infoheader.height;
323
324         if (*height < 0)
325                 *height = 0 - *height;
326         else
327                 flip = true;
328
329         size = header.size - header.offset;
330         linesize = *width * infoheader.bitcount >> 3;
331         cmap_base = src + sizeof(infoheader);
332         src = bmp_addr + header.offset;
333
334         switch (infoheader.bitcount) {
335         case 8:
336                 bmp_logo_palette = kmalloc(sizeof(bmp_logo_palette) * 256, GFP_KERNEL);
337
338                 /* Set color map */
339                 for (i = 0; i < 256; i++) {
340                         ushort colreg = ((cmap_base[2] << 8) & 0xf800) |
341                                         ((cmap_base[1] << 3) & 0x07e0) |
342                                         ((cmap_base[0] >> 3) & 0x001f) ;
343                         cmap_base += 4;
344                         bmp_logo_palette[i] = colreg;
345                 }
346
347                 /*
348                  * only support convert 8bit bmap file to RGB565.
349                  */
350                 decode_rle8_bitmap(src, dst, bmp_logo_palette,
351                                    infoheader.width, infoheader.height,
352                                    infoheader.bitcount, 0, 0, flip);
353                 kfree(bmp_logo_palette);
354                 *bits = 16;
355                 break;
356         case 16:
357                 /*
358                  * Todo
359                  */
360                 pr_info("unsupport bit=%d now\n", infoheader.bitcount);
361                 break;
362         case 24:
363                 stride = ALIGN(*width * 3, 4);
364                 if (flip)
365                         src += stride * (*height - 1);
366
367                 for (i = 0; i < *height; i++) {
368                         memcpy(dst, src, 3 * (*width));
369                         dst += stride;
370                         src += stride;
371                         if (flip)
372                                 src -= stride * 2;
373                 }
374
375                 *bits = 24;
376                 break;
377         case 32:
378                 /*
379                  * Todo
380                  */
381                 pr_info("unsupport bit=%d now\n", infoheader.bitcount);
382                 break;
383         default:
384                 pr_info("unsupport bit=%d now\n", infoheader.bitcount);
385                 break;
386         }
387
388         return 0;
389 }