1 /*
2 * Allwinner SoCs display driver.
3 *
4 * Copyright (C) 2016 Allwinner.
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11 /*
12 Description: awf waveform file decoder
13 Version : v0.1
14 Author : oujunxi
15 Date : 2015/07/10
16 */
17
18 #include "disp_waveform.h"
19
20 #define DEBUG_WAVEFILE
21 #ifdef DEBUG_WAVEFILE
22 #define WF_DBG(msg, fmt...) printk(KERN_WARNING msg, ##fmt)
23 #define WF_INFO(msg, fmt...) printk(KERN_WARNING msg, ##fmt)
24 #define WF_WRN(msg, fmt...) printk(KERN_WARNING msg, ##fmt)
25 #define WF_ERR(msg, fmt...) printk(KERN_ERR msg, ##fmt)
26 #else
27 #define WF_DBG(msg, fmt...)
28 #define WF_INFO(msg, fmt...)
29 #define WF_WRN(msg, fmt...) printk(KERN_WARNING msg, ##fmt)
30 #define WF_ERR(msg, fmt...) printk(KERN_ERR msg, ##fmt)
31 #endif
32
33
34 #define C_HEADER_INFO_OFFSET 0
35 #define C_HEADER_TYPE_ID_OFFSET 0 /* eink type(eink id) */
36 #define C_HEADER_VERSION_STR_OFFSET 1
37 #define C_HEADER_INFO_SIZE 128 /* size of awf file header */
38 #define C_TEMP_TBL_OFFSET (C_HEADER_INFO_OFFSET+C_HEADER_INFO_SIZE)
39 /* temperature table offset from the beginning of the awf file */
40 #define C_TEMP_TBL_SIZE 32 /* temperature table size */
41
42 #define C_MODE_ADDR_TBL_OFFSET (C_TEMP_TBL_OFFSET+C_TEMP_TBL_SIZE)
43 /* mode address table offset */
44 #define C_MODE_ADDR_TBL_SIZE 64
45 #define C_INIT_MODE_ADDR_OFFSET C_MODE_ADDR_TBL_OFFSET
46 #define C_GC16_MODE_ADDR_OFFSET (C_MODE_ADDR_TBL_OFFSET+4)
47 #define C_GC4_MODE_ADDR_OFFSET (C_MODE_ADDR_TBL_OFFSET+8)
48 #define C_DU_MODE_ADDR_OFFSET (C_MODE_ADDR_TBL_OFFSET+12)
49 #define C_A2_MODE_ADDR_OFFSET (C_MODE_ADDR_TBL_OFFSET+16)
50 #define C_GC16_LOCAL_MODE_ADDR_OFFSET (C_MODE_ADDR_TBL_OFFSET+20)
51 #define C_GC4_LOCAL_MODE_ADDR_OFFSET (C_MODE_ADDR_TBL_OFFSET+24)
52 #define C_A2_IN_MODE_ADDR_OFFSET (C_MODE_ADDR_TBL_OFFSET+28)
53 #define C_A2_OUT_MODE_ADDR_OFFSET (C_MODE_ADDR_TBL_OFFSET+32)
54
55 #define C_INIT_MODE_OFFSET (C_MODE_ADDR_TBL_OFFSET+C_MODE_ADDR_TBL_SIZE)
56
57 #define C_REAL_TEMP_AREA_NUM 15 /* max temperature range number */
58 #define WF_MAX_COL 256 /* GC16, 16*16 = 256 */
59
60
61 typedef struct {
62 u8 load_flag; /* when awf has been loaded, init_flag = 1 */
63 char *p_wf_vaddr; /* virtual address of waveform file */
64 u32 p_wf_paddr; /* phy address of waveform file */
65 EINK_PANEL_TYPE eink_panel_type;/*eink type, example PVI, OED and etc*/
66 u8 wf_temp_area_tbl[C_TEMP_TBL_SIZE]; /* temperature table */
67
68 /*phy address*/
69 u32 p_init_wf; /* init mode address (include temperature table address) */
70 u32 p_gc16_wf; /* gc16 mode address (include temperature table address) */
71 u32 p_gc4_wf; /* gc4 mode address (include temperature table address) */
72 u32 p_du_wf; /* du mode address (include temperature table address) */
73 u32 p_A2_wf; /* A2 mode address (include temperature table address) */
74 u32 p_gc16_local_wf; /* gc16 local mode address (include temperature table address) */
75 u32 p_gc4_local_wf; /* gc4 local mode address (include temperature table address) */
76 u32 p_A2_in_wf; /* A2 in mode address (include temperature table address) */
77 u32 p_A2_out_wf; /* A2 out mode address (include temperature table address) */
78 } AWF_WAVEFILE;
79
80 static AWF_WAVEFILE g_waveform_file;
81
82 /*
83 *Description : get temperature range index from temperature table,
84 * if temperature match TBL[id] <= temperature < TBL[id + 1]
85 * condition, then temp range index = id
86 *Input : temperature -- temperature of eink panel
87 *Output : None
88 *Return : 0 & positive -- temperature range index, negative -- fail
89 */
get_temp_range_index(int temperature)90 static __s32 get_temp_range_index(int temperature)
91 {
92 __s32 index = -EINVAL;
93
94 for (index = 0; index < C_TEMP_TBL_SIZE; index++) {
95 if ((g_waveform_file.wf_temp_area_tbl[index] == 0) &&
96 (index > 0))
97 break;
98
99 if (temperature < g_waveform_file.wf_temp_area_tbl[index])
100 break;
101
102 }
103
104 if (index > 0)
105 index -= 1;
106
107 return index;
108 }
109
110 /*
111 Description : get mode address according to flush mode
112 Input : mode -- flush mode
113 Output : None
114 Return : NULL -- get mode address fail,
115 others -- get mode address successfully
116 */
get_mode_virt_address(enum eink_update_mode mode)117 static u8 *get_mode_virt_address(enum eink_update_mode mode)
118 {
119 u8 *p_wf_file = NULL;
120 u32 offset = 0;
121
122 switch (mode) {
123 case EINK_INIT_MODE:
124 {
125 offset = (u32)g_waveform_file.p_init_wf -
126 g_waveform_file.p_wf_paddr;
127 p_wf_file = (u8 *)g_waveform_file.p_wf_vaddr + offset;
128 break;
129 }
130
131 case EINK_DU_MODE:
132 case EINK_DU_RECT_MODE:
133 {
134 offset = (u32)g_waveform_file.p_du_wf -
135 g_waveform_file.p_wf_paddr;
136 p_wf_file = (u8 *)g_waveform_file.p_wf_vaddr + offset;
137 break;
138 }
139
140 case EINK_GC16_MODE:
141 case EINK_GC16_RECT_MODE:
142 {
143 offset = (u32)g_waveform_file.p_gc16_wf -
144 g_waveform_file.p_wf_paddr;
145 p_wf_file = (u8 *)g_waveform_file.p_wf_vaddr + offset;
146 break;
147 }
148
149 case EINK_A2_MODE:
150 case EINK_A2_RECT_MODE:
151 {
152 offset = (u32)g_waveform_file.p_A2_wf -
153 g_waveform_file.p_wf_paddr;
154 p_wf_file = (u8 *)g_waveform_file.p_wf_vaddr + offset;
155 break;
156 }
157
158 case EINK_GC16_LOCAL_MODE:
159 case EINK_GC16_LOCAL_RECT_MODE:
160 {
161 offset = (u32)g_waveform_file.p_gc16_local_wf -
162 g_waveform_file.p_wf_paddr;
163 p_wf_file = (u8 *)g_waveform_file.p_wf_vaddr + offset;
164 break;
165 }
166
167 default:
168 {
169 WF_WRN("unkown mode(0x%x)\n", mode);
170 p_wf_file = NULL;
171 break;
172 }
173 }
174
175 return p_wf_file;
176 }
177
178 /*
179 *Description : get mode address according to flush mode
180 *Input : mode -- flush mode
181 *Output : None
182 *Return : NULL -- get mode address fail,
183 * others -- get mode address successfully
184 */
get_mode_phy_address(enum eink_update_mode mode)185 static u32 get_mode_phy_address(enum eink_update_mode mode)
186 {
187 u32 phy_addr = 0;
188
189 switch (mode) {
190 case EINK_INIT_MODE:
191 {
192 phy_addr = g_waveform_file.p_init_wf;
193 break;
194 }
195
196 case EINK_DU_MODE:
197 case EINK_DU_RECT_MODE:
198 {
199 phy_addr = g_waveform_file.p_du_wf;
200 break;
201 }
202
203 case EINK_GC16_MODE:
204 case EINK_GC16_RECT_MODE:
205 {
206 phy_addr = g_waveform_file.p_gc16_wf;
207 break;
208 }
209
210 case EINK_A2_MODE:
211 case EINK_A2_RECT_MODE:
212 {
213 phy_addr = g_waveform_file.p_A2_wf;
214 break;
215 }
216
217 case EINK_GC16_LOCAL_MODE:
218 case EINK_GC16_LOCAL_RECT_MODE:
219 {
220 phy_addr = g_waveform_file.p_gc16_local_wf;
221 break;
222 }
223
224 default:
225 {
226 WF_WRN("unkown mode(0x%x)\n", mode);
227 phy_addr = 0;
228 break;
229 }
230 }
231
232 return phy_addr;
233 }
234
235
236 /*
237 Description : load waveform file to memory, and save each flush mode
238 of address. This function should be called before waveform
239 data has been used.
240 Input : path -- path of waveform file
241 Output : None
242 Return : 0 -- load waveform ok, others -- fail
243 */
244 extern void *disp_malloc(u32 num_bytes, void *phy_addr);
245
init_waveform(const char * path)246 __s32 init_waveform(const char *path)
247 {
248 struct file *fp = NULL;
249 __s32 file_len = 0;
250 __s32 read_len = 0;
251 mm_segment_t fs;
252 loff_t pos;
253 __u32 wf_buffer_len = 0; /* the len of waveform file */
254 u32 *pAddr = NULL;
255 __s32 ret = -EINVAL;
256
257 if (path == NULL) {
258 WF_ERR("path is null\n");
259 return -EINVAL;
260 }
261
262 WF_DBG("starting to load awf waveform file(%s)\n", path);
263 fp = filp_open(path, O_RDONLY, 0);
264 if (IS_ERR(fp)) {
265 WF_ERR("fail to open waveform file(%s)", path);
266 return -EBADF;
267 }
268
269 memset(&g_waveform_file, 0, sizeof(g_waveform_file));
270 fs = get_fs();
271 set_fs(KERNEL_DS);
272 pos = 0;
273 file_len = fp->f_path.dentry->d_inode->i_size;
274 wf_buffer_len = file_len+1023;
275
276 g_waveform_file.p_wf_vaddr = (char *)disp_malloc(wf_buffer_len,
277 (u32 *)(&g_waveform_file.p_wf_paddr));
278 /* waveform vaddr */
279 if (g_waveform_file.p_wf_vaddr == NULL) {
280 WF_ERR("fail to alloc memory for waveform file\n");
281 ret = -ENOMEM;
282 goto error;
283 }
284
285 read_len = vfs_read(fp, (char *)g_waveform_file.p_wf_vaddr, file_len, &pos);
286 if (read_len != file_len) {
287 WF_ERR("miss data(read=%d byte, file=%d byte) when read wavefile\n",
288 read_len, file_len);
289 ret = -EAGAIN;
290 goto error;
291 }
292
293 g_waveform_file.eink_panel_type = *((u8 *)g_waveform_file.p_wf_vaddr);
294 WF_DBG("eink type=0x%x\n", g_waveform_file.eink_panel_type);
295
296 /* starting to load data */
297 memcpy(g_waveform_file.wf_temp_area_tbl,
298 (g_waveform_file.p_wf_vaddr+C_TEMP_TBL_OFFSET),
299 C_TEMP_TBL_SIZE);
300
301 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr + C_INIT_MODE_ADDR_OFFSET);
302 g_waveform_file.p_init_wf = (u32)(g_waveform_file.p_wf_paddr + *pAddr);
303
304 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr + C_GC16_MODE_ADDR_OFFSET);
305 g_waveform_file.p_gc16_wf = (u32)(g_waveform_file.p_wf_paddr + *pAddr);
306
307 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr + C_GC4_MODE_ADDR_OFFSET);
308 g_waveform_file.p_gc4_wf = (u32)(g_waveform_file.p_wf_paddr + *pAddr);
309
310 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr + C_DU_MODE_ADDR_OFFSET);
311 g_waveform_file.p_du_wf = (u32)(g_waveform_file.p_wf_paddr + *pAddr);
312
313 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr + C_A2_MODE_ADDR_OFFSET);
314 g_waveform_file.p_A2_wf = (u32)(g_waveform_file.p_wf_paddr + *pAddr);
315
316 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr +
317 C_GC16_LOCAL_MODE_ADDR_OFFSET);
318 g_waveform_file.p_gc16_local_wf =
319 (u32)(g_waveform_file.p_wf_paddr + *pAddr);
320
321 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr +
322 C_GC4_LOCAL_MODE_ADDR_OFFSET);
323 g_waveform_file.p_gc4_local_wf =
324 (u32)(g_waveform_file.p_wf_paddr + *pAddr);
325
326 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr + C_A2_IN_MODE_ADDR_OFFSET);
327 g_waveform_file.p_A2_in_wf = (u32)(g_waveform_file.p_wf_paddr + *pAddr);
328
329 pAddr = (u32 *)(g_waveform_file.p_wf_vaddr + C_A2_OUT_MODE_ADDR_OFFSET);
330 g_waveform_file.p_A2_out_wf =
331 (u32)(g_waveform_file.p_wf_paddr + *pAddr);
332
333 if (fp) {
334 filp_close(fp, NULL);
335 set_fs(fs);
336 }
337
338 g_waveform_file.load_flag = 1;
339
340 WF_DBG("load waveform file(%s) successfully\n", path);
341 return 0;
342
343 error:
344 if (g_waveform_file.p_wf_vaddr != NULL) {
345 vfree(g_waveform_file.p_wf_vaddr);
346 g_waveform_file.p_wf_vaddr = NULL;
347 }
348
349 if (fp) {
350 filp_close(fp, NULL);
351 set_fs(fs);
352 }
353
354 return ret;
355 }
356
357 /*
358 Description: get eink panel type, for example, 3 stands for ED060XC3(4-bit),
359 4 stands for ED060XD4(5-bit)
360 Input: None
361 Output: type -- save the type of eink panel
362 Return: 0 -- get eink panel type successfully, others -- fail
363 */
get_eink_panel_type(EINK_PANEL_TYPE * type)364 int get_eink_panel_type(EINK_PANEL_TYPE *type)
365 {
366 if (g_waveform_file.load_flag != 1) {
367 WF_ERR("waveform hasn't init yet, pls init first\n");
368 return -EAGAIN;
369 }
370
371 if (type == NULL) {
372 WF_ERR("input param is null\n");
373 return -EINVAL;
374 }
375
376 *type = g_waveform_file.eink_panel_type;
377 return 0;
378 }
379
380 /*
381 Description: get bit number of eink panel, 4-bit stands for 16 grayscale,
382 5-bit stands for 32 grayscale
383 Input: None
384 Output: bit_num -- save the bit number of eink panel
385 Return: 0 -- get eink panel type successfully, others -- fail
386 */
get_eink_panel_bit_num(enum eink_bit_num * bit_num)387 int get_eink_panel_bit_num(enum eink_bit_num *bit_num)
388 {
389 if (g_waveform_file.load_flag != 1) {
390 WF_ERR("waveform hasn't init yet, pls init first\n");
391 return -EAGAIN;
392 }
393
394 if (bit_num == NULL) {
395 WF_ERR("input param is null\n");
396 return -EINVAL;
397 }
398
399 if (g_waveform_file.eink_panel_type == ED060XD4)
400 *bit_num = EINK_BIT_5;
401 else
402 *bit_num = EINK_BIT_4;
403
404 return 0;
405 }
406
407
408 /*
409 Description: get waveform data address according to mode and temperature
410 Input: None
411 Output: type -- save the type of eink panel
412 Return: 0 -- get eink panel type successfully, others -- fail
413 */
get_waveform_data(enum eink_update_mode mode,u32 temp,u32 * total_frames,u32 * wf_buf)414 int get_waveform_data(enum eink_update_mode mode, u32 temp,
415 u32 *total_frames, u32 *wf_buf)
416 {
417 u32 p_mode_phy_addr = 0;
418 u8 *p_mode_virt_addr = NULL;
419 u32 mode_temp_offset = 0;
420 u8 *p_mode_temp_addr = NULL;
421 /* u16 *p_pointer = NULL; */
422 u32 temp_range_id = 0;
423
424 if (g_waveform_file.load_flag != 1) {
425 WF_ERR("waveform hasn't init yet, pls init first\n");
426 return -EAGAIN;
427 }
428
429 if ((total_frames == NULL) || (wf_buf == NULL)) {
430 WF_ERR("input param is null\n");
431 return -EINVAL;
432 }
433
434 p_mode_virt_addr = get_mode_virt_address(mode);
435 if (p_mode_virt_addr == NULL) {
436 WF_ERR("get mode virturl address fail, mode=0x%x\n", mode);
437 return -EINVAL;
438 }
439
440 p_mode_phy_addr = get_mode_phy_address(mode);
441 if (p_mode_phy_addr == 0) {
442 WF_ERR("get mode phy address fail, mode=0x%x\n", mode);
443 return -EINVAL;
444 }
445
446 temp_range_id = get_temp_range_index(temp);
447 if (temp_range_id < 0) {
448 WF_ERR("get temp range index fail, temp=0x%x\n", temp);
449 return -EINVAL;
450 }
451
452 mode_temp_offset = *((u32 *)p_mode_virt_addr + temp_range_id);
453 p_mode_temp_addr = (u8 *)p_mode_virt_addr + mode_temp_offset;
454
455 *total_frames = *((u16 *)p_mode_temp_addr);
456 mode_temp_offset = mode_temp_offset + 4;
457 /* skip total frame(2 Byte) and dividor(2 Byte) */
458
459 *wf_buf = p_mode_phy_addr + mode_temp_offset;
460
461 return 0;
462 }
463
464
465 /*
466 Description : free memory that used by waveform file, after that, waveform
467 data cannot be used until init_waveform function has been
468 called. This function should be called when unload module.
469 Input : None
470 Output : None
471 Return : None
472 */
free_waveform(void)473 void free_waveform(void)
474 {
475 if (g_waveform_file.p_wf_vaddr != NULL) {
476 vfree(g_waveform_file.p_wf_vaddr);
477 g_waveform_file.p_wf_vaddr = NULL;
478 }
479
480 g_waveform_file.load_flag = 0;
481 return;
482 }
483
484
485