1 /*
2 *
3 * Copyright (c) 2021 Allwinnertech Co., Ltd.
4 * Author: libairong <libairong@allwinnertech.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10 #include <linux/of.h>
11 #include <linux/of_device.h>
12 #include <linux/of_address.h>
13 #include <linux/of_irq.h>
14
15 #include "super_lcd_driver.h"
16 #include "../of_service.h"
17
18 #define DP printk("[DEBUG] %s, %s, %d \n", __FILE__, __func__, __LINE__);
19
20 #define GAMMA_TBL_ROW 30
21 #define GAMMA_TBL_COLUMN 2
22
get_gamma_tbl_from_dts(char * node_name,char * subname,u8 * ptbl,int * row_size)23 static int get_gamma_tbl_from_dts(char *node_name, char *subname, u8 *ptbl, int *row_size)
24 {
25 int ret;
26 struct device_node *lcd0_node;
27 // Get property, that is flag property from lcd0
28 char command_name[32];
29 int command_len;
30 int i;
31 u32 data[2];
32
33 lcd0_node = get_node_by_name(node_name);
34
35 for (i = 0; ; i++) {
36 // Get property
37 command_len = sprintf(command_name, "%s_%d", subname, i);
38
39 if (command_len > 32) {
40 printk("[WARN] command_name is too long \n");
41 }
42
43 ret = of_property_read_variable_u32_array(lcd0_node, command_name, data, 0, ARRAY_SIZE(data));
44
45 if (ret < 0) {
46 // printk("[ERR]property %s is not found \n", command_name);
47 break;
48 }
49
50 *(ptbl + i * GAMMA_TBL_COLUMN + 0) = (u8) data[0];
51 *(ptbl + i * GAMMA_TBL_COLUMN + 1) = (u8) data[1];
52
53 }
54
55 *row_size = i;
56 return 0;
57 }
58
lcd_cfg_panel_info(struct panel_extend_para * info)59 static void lcd_cfg_panel_info(struct panel_extend_para *info)
60 {
61 u32 i = 0, j = 0;
62 u32 items;
63 u8 lcd_gamma_tbl[GAMMA_TBL_ROW][GAMMA_TBL_COLUMN];
64 int gamma_tbl_row_size = 0;
65 int ret;
66
67 u32 lcd_cmap_tbl[2][3][4] = {
68 {
69 {LCD_CMAP_G0, LCD_CMAP_B1, LCD_CMAP_G2, LCD_CMAP_B3},
70 {LCD_CMAP_B0, LCD_CMAP_R1, LCD_CMAP_B2, LCD_CMAP_R3},
71 {LCD_CMAP_R0, LCD_CMAP_G1, LCD_CMAP_R2, LCD_CMAP_G3},
72 },
73 {
74 {LCD_CMAP_B3, LCD_CMAP_G2, LCD_CMAP_B1, LCD_CMAP_G0},
75 {LCD_CMAP_R3, LCD_CMAP_B2, LCD_CMAP_R1, LCD_CMAP_B0},
76 {LCD_CMAP_G3, LCD_CMAP_R2, LCD_CMAP_G1, LCD_CMAP_R0},
77 },
78 };
79
80 ret = get_gamma_tbl_from_dts("lcd0", "lcd_gamma", (u8 *)lcd_gamma_tbl, &gamma_tbl_row_size);
81
82 items = gamma_tbl_row_size;
83
84 if (items < 1) {
85 printk("the size of lcd_gamma table is less then 1 \n");
86 return;
87 }
88
89 for (i = 0; i < items - 1; i++) {
90 u32 num = lcd_gamma_tbl[i+1][0] - lcd_gamma_tbl[i][0];
91
92 for (j = 0; j < num; j++) {
93 u32 value = 0;
94
95 value = lcd_gamma_tbl[i][1] +
96 ((lcd_gamma_tbl[i+1][1] - lcd_gamma_tbl[i][1])
97 * j) / num;
98 info->lcd_gamma_tbl[lcd_gamma_tbl[i][0] + j] =
99 (value<<16)
100 + (value<<8) + value;
101 }
102 }
103 info->lcd_gamma_tbl[255] = (lcd_gamma_tbl[items-1][1]<<16) +
104 (lcd_gamma_tbl[items-1][1]<<8)
105 + lcd_gamma_tbl[items-1][1];
106
107 memcpy(info->lcd_cmap_tbl, lcd_cmap_tbl, sizeof(lcd_cmap_tbl));
108
109 }
110
get_func_pointer(u32 opcode)111 unsigned long get_func_pointer(u32 opcode)
112 {
113 int func_table_line;
114 int i;
115
116 func_table_line = sizeof(lcd_func_table) / 2 / 8;
117
118 for (i = 0; i < func_table_line; i++) {
119 if (lcd_func_table[i][0] == opcode) {
120 return lcd_func_table[i][1];
121 }
122 }
123
124 return 0;
125
126 }
127
handle_data(u32 sel,u32 * data)128 void handle_data(u32 sel, u32 *data)
129 {
130 u32 opcode = *data;
131 unsigned long p_func_addr;
132 u32 cmd_count;
133 u8 cmd_params[15] = {0};
134 int i;
135
136 p_func_addr = get_func_pointer(opcode);
137
138 if (p_func_addr == 0) {
139 printk("[ERR] not found function in func_table by opcode \n");
140 return;
141 }
142
143 // Get function and exec by opcode
144 if (opcode < 10) {
145 void (*p_func)(u32) = (void *)p_func_addr;
146 (*p_func)(sel);
147 } else if (opcode < 20) {
148 s32 (*p_func)(u32) = (void *)p_func_addr;
149 (*p_func)(sel);
150 } else if (opcode < 30) {
151 // void (*p_func)(u32, u32, u32) = (void *)p_func_addr;
152 // (*p_func)(sel, );
153 } else if (opcode < 40) {
154 s32 (*p_func)(u32) = (void *)p_func_addr;
155 (*p_func)((*(data + 1)));
156 } else if (opcode < 50) {
157 void (*p_func)(u32, u32) = (void *)p_func_addr;
158 (*p_func)(sel, (*(data + 1)));
159 } else if (opcode < 70) {
160 s32 (*p_func)(u32, u32, u32) = (void *)p_func_addr;
161 (*p_func)(sel, (*(data + 1)), (*(data + 2)));
162 } else if (opcode < 80) {
163 // s32 (*p_func)(u32, u8 *, u32) = (void *)p_func_addr;
164 // (*p_func)(sel, );
165 } else if (opcode < 90) {
166 // s32 (*p_func)(u32 sel, u8, u8 *, u32 *) = (void *)p_func;
167 } else if (opcode < 100) {
168 s32 (*p_func)(u32, u8, u8 *, u32) = (void *)p_func_addr;
169 // data : [opcode cmd param_count params]
170
171 cmd_count = (*(data + 2));
172
173 if (cmd_count > 15) {
174 printk("[EER] paras are more then 15 \n");
175 return;
176 }
177
178 for (i = 0; i < cmd_count; i++) {
179 cmd_params[i] = *(data + 3 + i);
180 }
181
182 (*p_func)(sel, (u8)(*(data + 1)), cmd_params, cmd_count);
183 } else {
184 printk("[WRN] opcode can not be exec \n");
185 }
186
187 }
188
exec_command(u32 sel,char * node_name,char * subname)189 void exec_command(u32 sel, char *node_name, char *subname)
190 {
191 int ret;
192 struct device_node *lcd0_node;
193 // Get property, that is flag property from lcd0
194 char command_name[32];
195 int command_len;
196 int i;
197 u32 data[20]; // Should define a macro
198
199 lcd0_node = get_node_by_name(node_name);
200
201 for (i = 0; ; i++) {
202 // Get property
203 command_len = sprintf(command_name, "%s_%d", subname, i);
204
205 if (command_len > 32) {
206 printk("[WARN] command_name is too long \n");
207 }
208
209 ret = of_property_read_variable_u32_array(lcd0_node, command_name, data, 0, ARRAY_SIZE(data));
210 // printk("ret = %d, command_namd : %s \n", ret, command_name);
211
212 if (ret < 0) {
213 // printk("[INFO]property %s is not found \n", node_name);
214 break;
215 }
216
217 handle_data(sel, data);
218 }
219
220 }
221
lcd_open_flow(u32 sel)222 static s32 lcd_open_flow(u32 sel)
223 {
224 exec_command(sel, "lcd0", "lcd_open_command");
225
226 return 0;
227 }
228
lcd_close_flow(u32 sel)229 static s32 lcd_close_flow(u32 sel)
230 {
231 exec_command(sel, "lcd0", "lcd_close_command");
232
233 return 0;
234 }
235
lcd_user_defined_func(u32 sel,u32 para1,u32 para2,u32 para3)236 static s32 lcd_user_defined_func(u32 sel, u32 para1, u32 para2, u32 para3)
237 {
238 return 0;
239 }
240
241 struct __lcd_panel super_lcd_panel = {
242 .name = "super_lcd_driver",
243 .func = {
244 .cfg_panel_info = lcd_cfg_panel_info,
245 .cfg_open_flow = lcd_open_flow,
246 .cfg_close_flow = lcd_close_flow,
247 .lcd_user_defined_func = lcd_user_defined_func,
248 },
249 };
250