Merge remote-tracking branch 'aosp/android-3.0' into develop-3.0
[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         rk_fb_switch_screen(hdmi->lcdc->screen1, 0, hdmi->lcdc->id);
84         kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp);
85         #ifdef CONFIG_SWITCH
86         switch_set_state(&(hdmi->switch_hdmi), 0);
87         #endif
88         #ifdef CONFIG_RK_HDMI_CTL_CODEC
89         codec_set_spk(1);
90         #endif
91 }
92
93 static void hdmi_sys_sleep(void)
94 {
95         mutex_lock(&hdmi->enable_mutex);
96         if(hdmi->enable && hdmi->irq)
97                 disable_irq(hdmi->irq);                         
98         hdmi->state = HDMI_SLEEP;
99         hdmi->remove();
100         if(hdmi->enable && hdmi->irq)
101                 enable_irq(hdmi->irq);
102         mutex_unlock(&hdmi->enable_mutex);
103 }
104
105 static int hdmi_process_command(void)
106 {
107         int change, state = hdmi->state;
108         
109         change = hdmi->command;
110         if(change != HDMI_CONFIG_NONE)  
111         {               
112                 hdmi->command = HDMI_CONFIG_NONE;
113                 switch(change)
114                 {       
115                         case HDMI_CONFIG_ENABLE:
116                                 /* disable HDMI */
117                                 mutex_lock(&hdmi->enable_mutex);
118                                 if(!hdmi->enable || hdmi->suspend)
119                                 {
120                                         if(hdmi->hotplug == HDMI_HPD_ACTIVED)
121                                                 hdmi_sys_remove();
122                                         hdmi->state = HDMI_SLEEP;
123                                         hdmi->hotplug = HDMI_HPD_REMOVED;
124                                         hdmi->remove();
125                                         state = HDMI_SLEEP;
126                                 }
127                                 mutex_unlock(&hdmi->enable_mutex);
128                                 if(hdmi->wait == 1) {
129                                         complete(&hdmi->complete);
130                                         hdmi->wait = 0; 
131                                 }
132                                 break;  
133                         case HDMI_CONFIG_COLOR:
134                                 if(state > CONFIG_VIDEO)
135                                         state = CONFIG_VIDEO;   
136                                 break;
137                         case HDMI_CONFIG_HDCP:
138                                 break;
139                         case HDMI_CONFIG_DISPLAY:
140                                 break;
141                         case HDMI_CONFIG_AUDIO:
142                                 if(state > CONFIG_AUDIO)
143                                         state = CONFIG_AUDIO;
144                                 break;
145                         case HDMI_CONFIG_VIDEO:
146                         default:
147                                 if(state > SYSTEM_CONFIG)
148                                         state = SYSTEM_CONFIG;
149                                 else
150                                 {
151                                         if(hdmi->wait == 1) {
152                                                 complete(&hdmi->complete);
153                                                 hdmi->wait = 0; 
154                                         }                                       
155                                 }
156                                 break;
157                 }
158         }
159         else if(state == HDMI_SLEEP)
160                 state = WAIT_HOTPLUG;
161         return state;
162 }
163
164 static DEFINE_MUTEX(work_mutex);
165
166 void hdmi_work(struct work_struct *work)
167 {
168         int hotplug, state_last;
169         int rc = HDMI_ERROR_SUCESS, trytimes = 0;
170         struct hdmi_video_para video;
171         
172         mutex_lock(&work_mutex);
173         /* Process hdmi command */
174         hdmi->state = hdmi_process_command();
175         
176         if(!hdmi->enable || hdmi->suspend) {
177                 mutex_unlock(&work_mutex);
178                 return;
179         }
180         hotplug = hdmi->detect_hotplug();
181         hdmi_dbg(hdmi->dev, "[%s] hotplug %02x curvalue %d\n", __FUNCTION__, hotplug, hdmi->hotplug);
182         
183         if(hotplug != hdmi->hotplug)
184         {
185                 if(hotplug  == HDMI_HPD_ACTIVED){
186                         if(hdmi->insert)
187                                 hdmi->insert();
188                         hdmi->state = READ_PARSE_EDID;
189                 }
190                 else if(hdmi->hotplug == HDMI_HPD_ACTIVED) {
191                         hdmi_sys_remove();
192                         hdmi->hotplug = hotplug;
193                         if(hotplug == HDMI_HPD_REMOVED)
194                                 hdmi_sys_sleep();
195                         else {
196                                 hdmi->state = WAIT_HOTPLUG;
197                                 hdmi->remove();
198                         }
199                         if(hdmi->wait == 1) {
200                                 complete(&hdmi->complete);
201                                 hdmi->wait = 0; 
202                         }
203                         mutex_unlock(&work_mutex);
204                         return;
205                 }
206                 else if(hotplug == HDMI_HPD_REMOVED) {
207                         hdmi->state = HDMI_SLEEP;
208                         hdmi->remove();
209                 }
210                 hdmi->hotplug  = hotplug;
211         }
212         else if(hotplug == HDMI_HPD_REMOVED)
213                 hdmi_sys_sleep();
214         
215         do {
216                 hdmi_sys_show_state(hdmi->state);
217                 state_last = hdmi->state;
218                 switch(hdmi->state)
219                 {
220                         case READ_PARSE_EDID:
221                                 rc = hdmi_sys_parse_edid(hdmi);
222                                 if(rc == HDMI_ERROR_SUCESS)
223                                 {
224                                         hdmi->state = SYSTEM_CONFIG;    
225                                         kobject_uevent_env(&hdmi->dev->kobj, KOBJ_ADD, envp);
226                                         #ifdef CONFIG_SWITCH
227                                         switch_set_state(&(hdmi->switch_hdmi), 1);
228                                         #endif
229                                         #ifdef CONFIG_RK_HDMI_CTL_CODEC
230                                         codec_set_spk(0);
231                                         #endif
232                                 }
233                                 break;
234                         case SYSTEM_CONFIG:
235                                 if(hdmi->autoconfig)    
236                                         hdmi->vic = hdmi_find_best_mode(hdmi, 0);
237                                 else
238                                         hdmi->vic = hdmi_find_best_mode(hdmi, hdmi->vic);
239                                 rc = hdmi_switch_fb(hdmi, hdmi->vic);
240                                 if(rc == HDMI_ERROR_SUCESS)
241                                         hdmi->state = CONFIG_VIDEO;
242                                 break;
243                         case CONFIG_VIDEO:
244                                 hdmi->display = HDMI_DISABLE;
245                                 video.vic = hdmi->vic;
246                                 video.input_mode = VIDEO_INPUT_RGB_YCBCR_444;
247                                 video.input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
248                                 video.output_mode = hdmi->edid.sink_hdmi;
249                                 
250                                 if(hdmi->edid.ycbcr444)
251                                         video.output_color = VIDEO_OUTPUT_YCBCR444;
252                                 else if(hdmi->edid.ycbcr422)
253                                         video.output_color = VIDEO_OUTPUT_YCBCR422;
254                                 else
255                                         video.output_color = VIDEO_OUTPUT_RGB444;
256                                 // For DVI, output RGB
257                                 if(hdmi->edid.sink_hdmi == 0)
258                                         video.output_color = VIDEO_OUTPUT_RGB444;
259                                 
260                                 rc = hdmi->config_video(&video);
261                                 if(rc == HDMI_ERROR_SUCESS)
262                                 {
263                                         if(hdmi->edid.sink_hdmi)
264                                                 hdmi->state = CONFIG_AUDIO;
265                                         else
266                                                 hdmi->state = PLAY_BACK;
267                                 }
268                                 break;
269                         case CONFIG_AUDIO:
270                                 rc = hdmi->config_audio(&(hdmi->audio));
271                                                         
272                                 if(rc == HDMI_ERROR_SUCESS)
273                                         hdmi->state = PLAY_BACK;
274                                 break;
275                         case PLAY_BACK:
276                                 if(hdmi->display != HDMI_ENABLE) {
277                                         hdmi->control_output(HDMI_ENABLE);
278                                         hdmi->display = HDMI_ENABLE;
279                                         if(hdmi->hdcp_cb) {
280                                                 hdmi->hdcp_cb();
281                                         }
282                                 }
283                                 
284                                 if(hdmi->wait == 1) {   
285                                         complete(&hdmi->complete);
286                                         hdmi->wait = 0;                                         
287                                 }
288                                 break;
289                         default:
290                                 break;
291                 }
292                 if(rc != HDMI_ERROR_SUCESS)
293                 {
294                         trytimes++;
295                         msleep(10);
296                 }
297                 if(hdmi->state != state_last) 
298                         trytimes = 0;
299         
300         }while((hdmi->state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES);
301         
302         hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__);
303         mutex_unlock(&work_mutex);
304 }
305