mfd:rk616:modify some operation for vif
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rk_hdmi_task.c
1 #include <linux/kernel.h>
2 #include <linux/delay.h>
3 #include "rk_hdmi.h"
4
5 #ifdef CONFIG_RK_HDMI_CTL_CODEC
6 extern void codec_set_spk(bool on);
7 #endif
8
9 #define HDMI_MAX_TRY_TIMES      1
10 #define HDMI_MAX_ID 1
11
12 static char *envp[] = {"INTERFACE=HDMI", NULL};
13
14 static void hdmi_sys_show_state(int state)
15 {
16         switch(state)
17         {
18                 case HDMI_SLEEP:
19                         hdmi_dbg(hdmi->dev, "HDMI_SLEEP\n");
20                         break;
21                 case HDMI_INITIAL:
22                         hdmi_dbg(hdmi->dev, "HDMI_INITIAL\n");
23                         break;
24                 case WAIT_HOTPLUG:
25                         hdmi_dbg(hdmi->dev, "WAIT_HOTPLUG\n");
26                         break;
27                 case READ_PARSE_EDID:
28                         hdmi_dbg(hdmi->dev, "READ_PARSE_EDID\n");
29                         break;
30                 case WAIT_HDMI_ENABLE:
31                         hdmi_dbg(hdmi->dev, "WAIT_HDMI_ENABLE\n");
32                         break;
33                 case SYSTEM_CONFIG:
34                         hdmi_dbg(hdmi->dev, "SYSTEM_CONFIG\n");
35                         break;
36                 case CONFIG_VIDEO:
37                         hdmi_dbg(hdmi->dev, "CONFIG_VIDEO\n");
38                         break;
39                 case CONFIG_AUDIO:
40                         hdmi_dbg(hdmi->dev, "CONFIG_AUDIO\n");
41                         break;
42                 case PLAY_BACK:
43                         hdmi_dbg(hdmi->dev, "PLAY_BACK\n");
44                         break;
45                 default:
46                         hdmi_dbg(hdmi->dev, "Unkown State %d\n", state);
47                         break;
48         }
49 }
50
51 int hdmi_sys_init(void)
52 {
53         hdmi->hotplug                   = HDMI_HPD_REMOVED;
54         hdmi->state                             = HDMI_SLEEP;
55         hdmi->enable                    = HDMI_ENABLE;
56         hdmi->autoconfig                = HDMI_AUTO_CONFIGURE;
57         hdmi->display                   = HDMI_DISABLE;
58         
59         hdmi->vic                               = HDMI_VIDEO_DEFAULT_MODE;
60         hdmi->audio.channel     = HDMI_AUDIO_DEFAULT_CHANNEL;
61         hdmi->audio.rate                = HDMI_AUDIO_DEFAULT_RATE;
62         hdmi->audio.word_length = HDMI_AUDIO_DEFAULT_WORD_LENGTH;
63         
64         memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
65         INIT_LIST_HEAD(&hdmi->edid.modelist);
66         return 0;
67 }
68
69 void hdmi_sys_remove(void)
70 {
71         fb_destroy_modelist(&hdmi->edid.modelist);
72         if(hdmi->edid.audio)
73                 kfree(hdmi->edid.audio);
74         if(hdmi->edid.specs)
75         {
76                 if(hdmi->edid.specs->modedb)
77                         kfree(hdmi->edid.specs->modedb);
78                 kfree(hdmi->edid.specs);
79         }
80         memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
81         INIT_LIST_HEAD(&hdmi->edid.modelist);
82         hdmi->display   = HDMI_DISABLE;
83         if(hdmi->set_vif)
84                 hdmi->set_vif(hdmi->lcdc->screen1,0);
85         rk_fb_switch_screen(hdmi->lcdc->screen1, 0, hdmi->lcdc->id);
86         kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp);
87         #ifdef CONFIG_SWITCH
88         switch_set_state(&(hdmi->switch_hdmi), 0);
89         #endif
90         #ifdef CONFIG_RK_HDMI_CTL_CODEC
91         codec_set_spk(1);
92         #endif
93 }
94
95 static void hdmi_sys_sleep(void)
96 {
97         mutex_lock(&hdmi->enable_mutex);
98         if(hdmi->enable && hdmi->irq)
99                 disable_irq(hdmi->irq);                         
100         hdmi->state = HDMI_SLEEP;
101         hdmi->remove();
102         if(hdmi->enable && hdmi->irq)
103                 enable_irq(hdmi->irq);
104         mutex_unlock(&hdmi->enable_mutex);
105 }
106
107 static int hdmi_process_command(void)
108 {
109         int change, state = hdmi->state;
110         
111         change = hdmi->command;
112         if(change != HDMI_CONFIG_NONE)  
113         {               
114                 hdmi->command = HDMI_CONFIG_NONE;
115                 switch(change)
116                 {       
117                         case HDMI_CONFIG_ENABLE:
118                                 /* disable HDMI */
119                                 mutex_lock(&hdmi->enable_mutex);
120                                 if(!hdmi->enable || hdmi->suspend)
121                                 {
122                                         if(hdmi->hotplug == HDMI_HPD_ACTIVED)
123                                                 hdmi_sys_remove();
124                                         hdmi->state = HDMI_SLEEP;
125                                         hdmi->hotplug = HDMI_HPD_REMOVED;
126                                         hdmi->remove();
127                                         state = HDMI_SLEEP;
128                                 }
129                                 mutex_unlock(&hdmi->enable_mutex);
130                                 if(hdmi->wait == 1) {
131                                         complete(&hdmi->complete);
132                                         hdmi->wait = 0; 
133                                 }
134                                 break;  
135                         case HDMI_CONFIG_COLOR:
136                                 if(state > CONFIG_VIDEO)
137                                         state = CONFIG_VIDEO;   
138                                 break;
139                         case HDMI_CONFIG_HDCP:
140                                 break;
141                         case HDMI_CONFIG_DISPLAY:
142                                 break;
143                         case HDMI_CONFIG_AUDIO:
144                                 if(state > CONFIG_AUDIO)
145                                         state = CONFIG_AUDIO;
146                                 break;
147                         case HDMI_CONFIG_VIDEO:
148                         default:
149                                 if(state > SYSTEM_CONFIG)
150                                         state = SYSTEM_CONFIG;
151                                 else
152                                 {
153                                         if(hdmi->wait == 1) {
154                                                 complete(&hdmi->complete);
155                                                 hdmi->wait = 0; 
156                                         }                                       
157                                 }
158                                 break;
159                 }
160         }
161         else if(state == HDMI_SLEEP)
162                 state = WAIT_HOTPLUG;
163         return state;
164 }
165
166 static DEFINE_MUTEX(work_mutex);
167
168 void hdmi_work(struct work_struct *work)
169 {
170         int hotplug, state_last;
171         int rc = HDMI_ERROR_SUCESS, trytimes = 0;
172         struct hdmi_video_para video;
173         
174         mutex_lock(&work_mutex);
175         /* Process hdmi command */
176         hdmi->state = hdmi_process_command();
177         
178         if(!hdmi->enable || hdmi->suspend) {
179                 mutex_unlock(&work_mutex);
180                 return;
181         }
182         hotplug = hdmi->detect_hotplug();
183         hdmi_dbg(hdmi->dev, "[%s] hotplug %02x curvalue %d\n", __FUNCTION__, hotplug, hdmi->hotplug);
184         
185         if(hotplug != hdmi->hotplug)
186         {
187                 if(hotplug  == HDMI_HPD_ACTIVED){
188                         if(hdmi->insert)
189                                 hdmi->insert();
190                         hdmi->state = READ_PARSE_EDID;
191                 }
192                 else if(hdmi->hotplug == HDMI_HPD_ACTIVED) {
193                         hdmi_sys_remove();
194                         hdmi->hotplug = hotplug;
195                         if(hotplug == HDMI_HPD_REMOVED)
196                                 hdmi_sys_sleep();
197                         else {
198                                 hdmi->state = WAIT_HOTPLUG;
199                                 hdmi->remove();
200                         }
201                         if(hdmi->wait == 1) {
202                                 complete(&hdmi->complete);
203                                 hdmi->wait = 0; 
204                         }
205                         mutex_unlock(&work_mutex);
206                         return;
207                 }
208                 else if(hotplug == HDMI_HPD_REMOVED) {
209                         hdmi->state = HDMI_SLEEP;
210                         hdmi->remove();
211                 }
212                 hdmi->hotplug  = hotplug;
213         }
214         else if(hotplug == HDMI_HPD_REMOVED)
215                 hdmi_sys_sleep();
216         
217         do {
218                 hdmi_sys_show_state(hdmi->state);
219                 state_last = hdmi->state;
220                 switch(hdmi->state)
221                 {
222                         case READ_PARSE_EDID:
223                                 rc = hdmi_sys_parse_edid(hdmi);
224                                 if(rc == HDMI_ERROR_SUCESS)
225                                 {
226                                         hdmi->state = SYSTEM_CONFIG;    
227                                         kobject_uevent_env(&hdmi->dev->kobj, KOBJ_ADD, envp);
228                                         #ifdef CONFIG_SWITCH
229                                         switch_set_state(&(hdmi->switch_hdmi), 1);
230                                         #endif
231                                         #ifdef CONFIG_RK_HDMI_CTL_CODEC
232                                         codec_set_spk(0);
233                                         #endif
234                                 }
235                                 break;
236                         case SYSTEM_CONFIG:
237                                 hdmi->remove();
238                                 if(hdmi->autoconfig)    
239                                         hdmi->vic = hdmi_find_best_mode(hdmi, 0);
240                                 else
241                                         hdmi->vic = hdmi_find_best_mode(hdmi, hdmi->vic);
242                                 rc = hdmi_switch_fb(hdmi, hdmi->vic);
243                                 if(rc == HDMI_ERROR_SUCESS)
244                                         hdmi->state = CONFIG_VIDEO;
245                                 break;
246                         case CONFIG_VIDEO:
247                                 hdmi->display = HDMI_DISABLE;
248                                 video.vic = hdmi->vic;
249                                 video.input_mode = VIDEO_INPUT_RGB_YCBCR_444;
250                                 video.input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
251                                 video.output_mode = hdmi->edid.sink_hdmi;
252                                 
253                                 if(hdmi->edid.ycbcr444)
254                                         video.output_color = VIDEO_OUTPUT_YCBCR444;
255                                 else if(hdmi->edid.ycbcr422)
256                                         video.output_color = VIDEO_OUTPUT_YCBCR422;
257                                 else
258                                         video.output_color = VIDEO_OUTPUT_RGB444;
259                                 // For DVI, output RGB
260                                 if(hdmi->edid.sink_hdmi == 0)
261                                         video.output_color = VIDEO_OUTPUT_RGB444;
262                                 
263                                 rc = hdmi->config_video(&video);
264                                 if(rc == HDMI_ERROR_SUCESS)
265                                 {
266                                         if(hdmi->edid.sink_hdmi)
267                                                 hdmi->state = CONFIG_AUDIO;
268                                         else
269                                                 hdmi->state = PLAY_BACK;
270                                 }
271                                 break;
272                         case CONFIG_AUDIO:
273                                 rc = hdmi->config_audio(&(hdmi->audio));
274                                                         
275                                 if(rc == HDMI_ERROR_SUCESS)
276                                         hdmi->state = PLAY_BACK;
277                                 break;
278                         case PLAY_BACK:
279                                 if(hdmi->display != HDMI_ENABLE) {
280                                         hdmi->control_output(HDMI_ENABLE);
281                                         hdmi->display = HDMI_ENABLE;
282                                         if(hdmi->hdcp_cb) {
283                                                 hdmi->hdcp_cb();
284                                         }
285                                 }
286                                 
287                                 if(hdmi->wait == 1) {   
288                                         complete(&hdmi->complete);
289                                         hdmi->wait = 0;                                         
290                                 }
291                                 break;
292                         default:
293                                 break;
294                 }
295                 if(rc != HDMI_ERROR_SUCESS)
296                 {
297                         trytimes++;
298                         msleep(10);
299                 }
300                 if(hdmi->state != state_last) 
301                         trytimes = 0;
302         
303         }while((hdmi->state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES);
304         
305         hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__);
306         mutex_unlock(&work_mutex);
307 }
308