2f6c5a4c3e1910b56d6982e75c762b0d5e16bb4e
[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 <linux/interrupt.h>
4 #include "rk_hdmi.h"
5
6 #define HDMI_MAX_TRY_TIMES      1
7 #define HDMI_MAX_ID 1
8
9 static char *envp[] = {"INTERFACE=HDMI", NULL};
10
11 static void hdmi_sys_show_state(struct hdmi *hdmi)
12 {
13         switch(hdmi->state)
14         {
15                 case HDMI_SLEEP:
16                         hdmi_dbg(hdmi->dev, "HDMI_SLEEP\n");
17                         break;
18                 case HDMI_INITIAL:
19                         hdmi_dbg(hdmi->dev, "HDMI_INITIAL\n");
20                         break;
21                 case WAIT_HOTPLUG:
22                         hdmi_dbg(hdmi->dev, "WAIT_HOTPLUG\n");
23                         break;
24                 case READ_PARSE_EDID:
25                         hdmi_dbg(hdmi->dev, "READ_PARSE_EDID\n");
26                         break;
27                 case WAIT_HDMI_ENABLE:
28                         hdmi_dbg(hdmi->dev, "WAIT_HDMI_ENABLE\n");
29                         break;
30                 case SYSTEM_CONFIG:
31                         hdmi_dbg(hdmi->dev, "SYSTEM_CONFIG\n");
32                         break;
33                 case CONFIG_VIDEO:
34                         hdmi_dbg(hdmi->dev, "CONFIG_VIDEO\n");
35                         break;
36                 case CONFIG_AUDIO:
37                         hdmi_dbg(hdmi->dev, "CONFIG_AUDIO\n");
38                         break;
39                 case PLAY_BACK:
40                         hdmi_dbg(hdmi->dev, "PLAY_BACK\n");
41                         break;
42                 default:
43                         hdmi_dbg(hdmi->dev, "Unkown State %d\n", state);
44                         break;
45         }
46 }
47
48 int hdmi_sys_init(struct hdmi *hdmi)
49 {
50         hdmi->hotplug                   = HDMI_HPD_REMOVED;
51         hdmi->state                             = HDMI_SLEEP;
52         hdmi->enable                    = HDMI_ENABLE;
53         hdmi->autoconfig                = HDMI_AUTO_CONFIGURE;
54         hdmi->display                   = HDMI_DISABLE;
55         
56         hdmi->vic                               = HDMI_VIDEO_DEFAULT_MODE;
57         hdmi->audio.channel     = HDMI_AUDIO_DEFAULT_CHANNEL;
58         hdmi->audio.rate                = HDMI_AUDIO_DEFAULT_RATE;
59         hdmi->audio.word_length = HDMI_AUDIO_DEFAULT_WORD_LENGTH;
60         
61         memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
62         INIT_LIST_HEAD(&hdmi->edid.modelist);
63         return 0;
64 }
65
66 void hdmi_sys_remove(struct hdmi *hdmi)
67 {
68         int audio_need;
69
70         audio_need = hdmi->edid.base_audio_support == 1 &&  hdmi->edid.sink_hdmi == 1;
71         
72         fb_destroy_modelist(&hdmi->edid.modelist);
73         if(hdmi->edid.audio)
74                 kfree(hdmi->edid.audio);
75         if(hdmi->edid.specs)
76         {
77                 if(hdmi->edid.specs->modedb)
78                         kfree(hdmi->edid.specs->modedb);
79                 kfree(hdmi->edid.specs);
80         }
81         memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
82         INIT_LIST_HEAD(&hdmi->edid.modelist);
83         hdmi->display   = HDMI_DISABLE;
84         if(hdmi->set_vif)
85                 hdmi->set_vif(hdmi,hdmi->lcdc->screen1,0);
86         rk_fb_switch_screen(hdmi->lcdc->screen1, 0, hdmi->lcdc->id);
87         kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp);
88
89         #ifdef CONFIG_SWITCH
90         if(audio_need)
91                 switch_set_state(&(hdmi->switch_hdmi), 0);
92         #endif
93 }
94
95 static void hdmi_sys_sleep(struct hdmi *hdmi)
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(hdmi);
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(struct hdmi *hdmi)
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(hdmi);
124                                         hdmi->state = HDMI_SLEEP;
125                                         hdmi->hotplug = HDMI_HPD_REMOVED;
126                                         hdmi->remove(hdmi);
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         struct delayed_work *delay_work = container_of(work, struct delayed_work, work);
174         struct hdmi *hdmi = container_of(delay_work, struct hdmi, delay_work);
175
176         mutex_lock(&work_mutex);
177         /* Process hdmi command */
178         hdmi->state = hdmi_process_command(hdmi);
179         
180         if(!hdmi->enable || hdmi->suspend) {
181                 mutex_unlock(&work_mutex);
182                 return;
183         }
184         hotplug = hdmi->detect_hotplug(hdmi);
185         hdmi_dbg(hdmi->dev, "[%s] hotplug %02x curvalue %d\n", __FUNCTION__, hotplug, hdmi->hotplug);
186         
187         if(hotplug != hdmi->hotplug)
188         {
189                 if(hotplug  == HDMI_HPD_ACTIVED){
190                         if(hdmi->insert)
191                                 hdmi->insert(hdmi);
192                         hdmi->state = READ_PARSE_EDID;
193                 }
194                 else if(hdmi->hotplug == HDMI_HPD_ACTIVED) {
195                         hdmi_sys_remove(hdmi);
196                         hdmi->hotplug = hotplug;
197                         if(hotplug == HDMI_HPD_REMOVED)
198                                 hdmi_sys_sleep(hdmi);
199                         else {
200                                 hdmi->state = WAIT_HOTPLUG;
201                                 hdmi->remove(hdmi);
202                         }
203                         if(hdmi->wait == 1) {
204                                 complete(&hdmi->complete);
205                                 hdmi->wait = 0; 
206                         }
207                         mutex_unlock(&work_mutex);
208                         return;
209                 }
210                 else if(hotplug == HDMI_HPD_REMOVED) {
211                         hdmi->state = HDMI_SLEEP;
212                         hdmi->remove(hdmi);
213                 }
214                 hdmi->hotplug  = hotplug;
215         }
216         else if(hotplug == HDMI_HPD_REMOVED)
217                 hdmi_sys_sleep(hdmi);
218         
219         do {
220                 hdmi_sys_show_state(hdmi);
221                 state_last = hdmi->state;
222                 switch(hdmi->state)
223                 {
224                         case READ_PARSE_EDID:
225                                 rc = hdmi_sys_parse_edid(hdmi);
226                                 if(rc == HDMI_ERROR_SUCESS)
227                                 {
228                                         hdmi->state = SYSTEM_CONFIG;    
229                                         kobject_uevent_env(&hdmi->dev->kobj, KOBJ_ADD, envp);
230                                         hdmi_dbg(hdmi->dev,"[%s] base_audio_support =%d,sink_hdmi = %d\n", __FUNCTION__, hdmi->edid.base_audio_support, hdmi->edid.sink_hdmi);
231                                         #ifdef CONFIG_SWITCH
232                                         if(hdmi->edid.base_audio_support == 1 &&  hdmi->edid.sink_hdmi == 1)
233                                                 switch_set_state(&(hdmi->switch_hdmi), 1);
234                                         #endif
235                                 }
236                                 break;
237                         case SYSTEM_CONFIG:
238                                 #ifdef CONFIG_HDMI_RK616
239                                 hdmi->remove(hdmi);
240                                 #endif
241                                 if(hdmi->autoconfig)    
242                                         hdmi->vic = hdmi_find_best_mode(hdmi, 0);
243                                 else
244                                         hdmi->vic = hdmi_find_best_mode(hdmi, hdmi->vic);
245                                 rc = hdmi_switch_fb(hdmi, hdmi->vic);
246                                 if(rc == HDMI_ERROR_SUCESS)
247                                         hdmi->state = CONFIG_VIDEO;
248                                 break;
249                         case CONFIG_VIDEO:
250                                 hdmi->display = HDMI_DISABLE;
251                                 video.vic = hdmi->vic;
252                                 video.input_mode = VIDEO_INPUT_RGB_YCBCR_444;
253                                 video.input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
254                                 video.output_mode = hdmi->edid.sink_hdmi;
255                                 
256                                 if(hdmi->edid.ycbcr444)
257                                         video.output_color = VIDEO_OUTPUT_YCBCR444;
258                                 else if(hdmi->edid.ycbcr422)
259                                         video.output_color = VIDEO_OUTPUT_YCBCR422;
260                                 else
261                                         video.output_color = VIDEO_OUTPUT_RGB444;
262                                 // For DVI, output RGB
263                                 if(hdmi->edid.sink_hdmi == 0)
264                                         video.output_color = VIDEO_OUTPUT_RGB444;
265                                 
266                                 rc = hdmi->config_video(hdmi, &video);
267                                 if(rc == HDMI_ERROR_SUCESS)
268                                 {
269                                         if(hdmi->edid.sink_hdmi)
270                                                 hdmi->state = CONFIG_AUDIO;
271                                         else
272                                                 hdmi->state = PLAY_BACK;
273                                 }
274                                 break;
275                         case CONFIG_AUDIO:
276                                 rc = hdmi->config_audio(hdmi, &(hdmi->audio));
277                                                         
278                                 if(rc == HDMI_ERROR_SUCESS)
279                                         hdmi->state = PLAY_BACK;
280                                 break;
281                         case PLAY_BACK:
282                                 if(hdmi->display != HDMI_ENABLE) {
283                                         hdmi->control_output(hdmi, HDMI_ENABLE);
284                                         hdmi->display = HDMI_ENABLE;
285                                         if(hdmi->hdcp_cb) {
286                                                 hdmi->hdcp_cb();
287                                         }
288                                 }
289                                 
290                                 if(hdmi->wait == 1) {   
291                                         complete(&hdmi->complete);
292                                         hdmi->wait = 0;                                         
293                                 }
294                                 break;
295                         default:
296                                 break;
297                 }
298                 if(rc != HDMI_ERROR_SUCESS)
299                 {
300                         trytimes++;
301                         msleep(10);
302                 }
303                 if(hdmi->state != state_last) 
304                         trytimes = 0;
305         
306         }while((hdmi->state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES);
307         
308         hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__);
309         mutex_unlock(&work_mutex);
310 }
311