• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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