tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / char / modem_interface / boot_protocol.c
1 /*
2  *  kernel/driver/char/modem_interface/boot_protocol.c
3  *
4  *  Generic modem boot protocol
5  *
6  *  Author:     Jiayong Yang(Jiayong.Yang@spreadtrum.com)
7  *  Created:    Jul 27, 2012
8  *  Copyright:  Spreadtrum Inc.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License version 2 as
12  *  published by the Free Software Foundation.
13  */
14 /* #define DEBUG */
15 /* #define VERBOSE_DEBUG */
16
17 #include <linux/init.h>
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/semaphore.h>
21 #include <linux/irqflags.h>
22 #include "modem_buffer.h"
23 #include "modem_interface_driver.h"
24
25 #define SETUP_PACKET_SIZE 8
26 #define ACK_PACKET_SIZE 6
27 typedef struct dl_setup_packet{
28         unsigned short  data_packet_size;
29         unsigned short  data_type;
30         unsigned short  data_check_sum;
31         unsigned short  setup_check_sum;
32 }       SETUP_PACKET_T;
33 typedef enum   MBUS_DL_status{
34         MBUS_DL_IDLE,
35         MBUS_DL_WAIT_REQ,
36         MBUS_DL_WAIT_RTS,
37         MBUS_DL_SETUP,
38         MBUS_DL_SETUP_COMP,
39         MBUS_DL_DATA,
40         MBUS_DL_DATA_COMP,
41         MBUS_DL_ACK
42 }DL_STATUS_E;
43
44
45 extern void modem_intf_ctrl_gpio_handle_boot(int status);
46 extern int dloader_abort();
47
48 char *boot_status_string(DL_STATUS_E status)
49 {
50         switch(status){
51                 case MBUS_DL_IDLE: return "DL_IDLE";
52                 case MBUS_DL_WAIT_REQ: return "DL_WAIT_REQ";
53                 case MBUS_DL_WAIT_RTS: return "DL_WAIT_RTS";
54                 case MBUS_DL_SETUP: return "DL_SETUP";
55                 case MBUS_DL_SETUP_COMP: return "DL_SETUP_COMP";
56                 case MBUS_DL_DATA: return "DL_DATA";
57                 case MBUS_DL_DATA_COMP: return "DL_DATA_COMP";
58                 case MBUS_DL_ACK: return "DL_ACK";
59                 default: break;
60         }
61         return "UNKNOWN status";
62 }
63
64
65
66 static void boot_idle(struct modem_message_node *msg,struct modem_intf_device *device)
67 {
68         int send_bffer_index=0xFF;
69         switch(msg->type){
70                 case MODEM_SLAVE_RTS:
71                         device->status = (int)MBUS_DL_WAIT_REQ;
72                 break;
73                 case MODEM_TRANSFER_REQ:
74                         send_bffer_index = pingpang_buffer_send(&device->send_buffer);
75                         if (send_bffer_index!= 0xFF) {
76                                 device->out_transfering = send_bffer_index;
77                                 device->status = (int)MBUS_DL_WAIT_RTS;
78                         }
79                 break;
80                 case MODEM_SET_MODE:
81             modem_intf_set_mode(msg->parameter2, 1);
82                         device->status = (int)MBUS_DL_IDLE;
83                         device->out_transfering = 0;
84                         dloader_abort();
85                 break;
86                 default:
87                 break;
88         }
89 }
90 static void boot_wait_request(struct modem_message_node *msg,struct modem_intf_device *device)
91 {
92         int send_bffer_index=0xFF;
93         switch(msg->type){
94                 case MODEM_TRANSFER_REQ:
95                         send_bffer_index = pingpang_buffer_send(&device->send_buffer);
96                         if(send_bffer_index!= 0xFF){
97                                 device->out_transfering = send_bffer_index;
98                                 device->op->write(device->send_buffer.buffer[send_bffer_index].addr,SETUP_PACKET_SIZE);
99                                 device->status = (int)MBUS_DL_SETUP;
100                         }
101                 break;
102                 case MODEM_SET_MODE:
103                         modem_intf_set_mode(msg->parameter2, 1);
104                         device->status = (int)MBUS_DL_IDLE;
105                         device->out_transfering = 0;
106                         dloader_abort();
107                 break;
108                 case MODEM_TRANSFER_END:
109                 break;
110                 default:
111                 break;
112         }
113 }
114 static void boot_wait_RTS(struct modem_message_node *msg,struct modem_intf_device *device)
115 {
116         int send_bffer_index=0xFF;
117         unsigned short *data;
118         switch(msg->type){
119                 case MODEM_SLAVE_RTS:
120                         if(device->out_transfering < 2){
121                                 send_bffer_index = device->out_transfering;
122                                 data = (unsigned short *)device->send_buffer.buffer[send_bffer_index].addr;
123                                 device->op->write((char *)data,SETUP_PACKET_SIZE);
124                                 device->status = (int)MBUS_DL_SETUP;
125                         }
126                 break;
127                 case MODEM_TRANSFER_REQ:
128                         device->out_transfer_pending = 1;
129                 break;
130                 case MODEM_SET_MODE:
131                         modem_intf_set_mode(msg->parameter2, 1);
132                         device->status = (int)MBUS_DL_IDLE;
133                         device->out_transfering = 0;
134                         dloader_abort();
135                 break;
136                 default:
137                 break;
138         }
139 }
140 static void boot_setup(struct modem_message_node *msg,struct modem_intf_device *device)
141 {
142         int send_bffer_index=0xFF;
143         char *buffer;
144         int size;
145         switch(msg->type){
146                 case MODEM_TRANSFER_END:
147                         device->status = (int)MBUS_DL_SETUP_COMP;
148                 break;
149                 case MODEM_TRANSFER_REQ:
150                         device->out_transfer_pending = 1;
151                 break;
152                 case MODEM_SLAVE_RTS:
153                         if(device->out_transfering < 2){
154                                 send_bffer_index = device->out_transfering;
155                                 buffer = &device->send_buffer.buffer[send_bffer_index].addr[SETUP_PACKET_SIZE];
156                                 size = device->send_buffer.buffer[send_bffer_index].write_point;
157                                 if (size <= SETUP_PACKET_SIZE)
158                                         size =  12;
159                                         device->op->write(buffer,size - SETUP_PACKET_SIZE);
160                                         pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
161                                         device->out_transfering = 0xFF;
162                                         device->status = (int)MBUS_DL_DATA;
163                                 }
164                                 if(device->out_transfer_pending){
165                                         send_bffer_index = pingpang_buffer_send(&device->send_buffer);
166                                         if(send_bffer_index!= 0xFF){
167                                                 device->out_transfering = send_bffer_index;
168                                                 size = device->send_buffer.buffer[send_bffer_index].write_point;
169                                                 device->op->write(device->send_buffer.buffer[send_bffer_index].addr,size);
170                                         }
171                                         device->out_transfer_pending = 0;
172                                 }
173                 break;
174                 case MODEM_SET_MODE:
175                         modem_intf_set_mode(msg->parameter2, 1);
176                         device->status = (int)MBUS_DL_IDLE;
177                         device->out_transfering = 0;
178                         dloader_abort();
179                 break;
180                 default:
181                 break;
182         }
183 }
184
185 static void boot_setup_comp(struct modem_message_node *msg,struct modem_intf_device *device)
186 {
187         int send_bffer_index=0xFF;
188         char *buffer;
189         int size;
190
191         switch(msg->type){
192                 case MODEM_SLAVE_RTS:
193                         if(device->out_transfering < 2){
194                                 send_bffer_index = device->out_transfering;
195                                 buffer = &device->send_buffer.buffer[send_bffer_index].addr[SETUP_PACKET_SIZE];
196                                 size = device->send_buffer.buffer[send_bffer_index].write_point;
197                                 if (size <= SETUP_PACKET_SIZE)
198                                         size =  12;
199                                 device->op->write(buffer,size - SETUP_PACKET_SIZE);
200                                 device->status = (int)MBUS_DL_DATA;
201                                 if(device->out_transfer_pending){
202                                         pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
203                                         device->out_transfering = 0xFF;
204                                         send_bffer_index = pingpang_buffer_send(&device->send_buffer);
205                                         if(send_bffer_index!= 0xFF){
206                                                 device->out_transfering = send_bffer_index;
207                                                 size = device->send_buffer.buffer[send_bffer_index].write_point;
208                                                 device->op->write(device->send_buffer.buffer[send_bffer_index].addr,size);
209                                         }
210                                         device->out_transfer_pending = 0;
211                                 }
212                         }
213                 break;
214                 case MODEM_TRANSFER_REQ:
215                         device->out_transfer_pending = 1;
216                 break;
217                 case MODEM_SET_MODE:
218                         modem_intf_set_mode(msg->parameter2, 1);
219                         device->status = (int)MBUS_DL_IDLE;
220                         device->out_transfering = 0;
221                         dloader_abort();
222                 break;
223                 default:
224                 break;
225
226         }
227 }
228 static void boot_data(struct modem_message_node *msg,struct modem_intf_device *device)
229 {
230         unsigned short *data;
231         int send_bffer_index=0xFF;
232         char *buffer;
233         int size;
234         switch(msg->type){
235                 case MODEM_TRANSFER_END:
236                         if(device->out_transfering < 2){
237                                 pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
238                                 device->out_transfering = 0xFF;
239                                 device->status = (int)MBUS_DL_DATA_COMP;
240                         }
241                 break;
242                 case MODEM_TRANSFER_REQ:
243                         if(device->out_transfering < 2){
244                                 pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
245                                 device->out_transfering = 0xFF;
246                         }
247                         send_bffer_index = pingpang_buffer_send(&device->send_buffer);
248                         if(send_bffer_index!= 0xFF){
249                                 device->out_transfering = send_bffer_index;
250                                 size = device->send_buffer.buffer[send_bffer_index].write_point;
251                                 device->op->write(device->send_buffer.buffer[send_bffer_index].addr,size);
252                         }
253                 break;
254                 case MODEM_SLAVE_RTS:
255                         pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
256                         device->op->read(device->recv_buffer.buffer[1].addr,8);
257                         device->out_transfering = 0xFF;
258                         data = (unsigned short *)device->recv_buffer.buffer[1].addr;
259                         device->status = (int)MBUS_DL_ACK;
260                         if(device->out_transfer_pending){
261                                 send_bffer_index = pingpang_buffer_send(&device->send_buffer);
262                                 if(send_bffer_index!= 0xFF){
263                                         device->out_transfering = send_bffer_index;
264                                         size = device->send_buffer.buffer[send_bffer_index].write_point;
265                                         device->op->write(device->send_buffer.buffer[send_bffer_index].addr,size);
266                                 }
267                                 device->out_transfer_pending = 0;
268                         }
269                 break;
270                 case MODEM_SET_MODE:
271                         modem_intf_set_mode(msg->parameter2, 1);
272                         device->status = (int)MBUS_DL_IDLE;
273                         device->out_transfering = 0;
274                         dloader_abort();
275                 break;
276                 default:
277                 break;
278         }
279 }
280 static void boot_data_comp(struct modem_message_node *msg,struct modem_intf_device *device)
281 {
282         unsigned short *data;
283         switch(msg->type){
284                 case MODEM_SLAVE_RTS:
285                         device->op->read(device->recv_buffer.buffer[1].addr,8);
286                         data = (unsigned short *)device->recv_buffer.buffer[1].addr;
287                         device->status = (int)MBUS_DL_ACK;
288                 break;
289                 case MODEM_TRANSFER_REQ:
290                         device->out_transfer_pending = 1;
291                 break;
292                 case MODEM_SET_MODE:
293                         modem_intf_set_mode(msg->parameter2, 1);
294                         device->status = (int)MBUS_DL_IDLE;
295                         device->out_transfering = 0;
296                         dloader_abort();
297                 break;
298                 default:
299                 break;
300         }
301 }
302 static void boot_ack(struct modem_message_node *msg,struct modem_intf_device *device)
303 {
304         int send_bffer_index=0xFF;
305         unsigned short *data;
306
307         switch(msg->type){
308                 case MODEM_TRANSFER_END:
309                         save_to_receive_buffer(&device->recv_buffer,device->recv_buffer.buffer[1].addr,ACK_PACKET_SIZE);
310                         if(device->out_transfer_pending){
311                                 device->out_transfer_pending = 0;
312                                 device->out_transfering = send_bffer_index = pingpang_buffer_send(&device->send_buffer);
313                                 if(device->out_transfering!=0xff){
314                                         device->status = (int)MBUS_DL_WAIT_RTS;
315                                         break;
316                                 }
317                         }
318                         device->status = (int)MBUS_DL_IDLE;
319                 break;
320                 case MODEM_TRANSFER_REQ:
321                         device->out_transfer_pending = 1;
322                 break;
323                 case MODEM_SLAVE_RTS:
324                         data = (unsigned short *)device->recv_buffer.buffer[1].addr;
325                         save_to_receive_buffer(&device->recv_buffer,data,ACK_PACKET_SIZE);
326                         if(device->out_transfer_pending){
327                                 device->out_transfer_pending = 0;
328                                 device->out_transfering = send_bffer_index = pingpang_buffer_send(&device->send_buffer);
329
330                                 data = (unsigned short *)device->send_buffer.buffer[send_bffer_index].addr;
331                                 device->op->write((char *)data,SETUP_PACKET_SIZE);
332
333                                 device->status = (int)MBUS_DL_SETUP;
334                         } else {
335                                 device->status = (int)MBUS_DL_WAIT_REQ;
336                         }
337                 break;
338                 case MODEM_SET_MODE:
339                         modem_intf_set_mode(msg->parameter2, 1);
340                         device->status = (int)MBUS_DL_IDLE;
341                         device->out_transfering = 0;
342                         dloader_abort();
343                 break;
344                 default:
345                 break;
346         }
347 }
348 extern unsigned long sprd_get_system_tick(void);
349 extern void dloader_record_timestamp(unsigned long time);
350
351 void boot_protocol_process_dl_messages(struct modem_intf_device *device,
352     struct modem_message_node *msg)
353 {
354     DL_STATUS_E status;
355
356     status =(DL_STATUS_E) device->status;
357
358     switch(status){
359                 case MBUS_DL_IDLE:
360                         boot_idle(msg,device);
361                 break;
362                 case MBUS_DL_SETUP:
363                         boot_setup(msg,device);
364                 break;
365                 case MBUS_DL_WAIT_REQ:
366                         boot_wait_request(msg,device);
367                 break;
368                 case MBUS_DL_WAIT_RTS:
369                         boot_wait_RTS(msg,device);
370                 break;
371                 case MBUS_DL_SETUP_COMP:
372                         boot_setup_comp(msg,device);
373                 break;
374                 case MBUS_DL_DATA:
375                         boot_data(msg,device);
376                 break;
377                 case MBUS_DL_DATA_COMP:
378                         boot_data_comp(msg,device);
379                 break;
380                 case MBUS_DL_ACK:
381                         boot_ack(msg,device);
382                 break;
383         }
384 }
385
386 void boot_protocol(struct modem_message_node *msg)
387 {
388         struct modem_intf_device *device;
389
390         if((msg == NULL)||(msg->parameter1==0))
391                 return;
392
393         device = (struct modem_intf_device *)msg->parameter1;
394
395         printk(">>boot entry(%d,%d) status: %s message: %s \n",
396         device->out_transfer_pending,device->out_transfering,
397         boot_status_string((DL_STATUS_E )device->status),
398         modem_intf_msg_string(msg->type));
399
400     //filter messages
401     switch(msg->type){
402         case MODEM_CTRL_GPIO_CHG:
403             modem_intf_ctrl_gpio_handle_boot(msg->parameter2);
404             break;
405         case MODEM_USER_REQ:
406             //now, just ignore user req in boot mode
407             break;
408         case MODEM_BOOT_CMP:
409             modem_intf_set_mode(MODEM_MODE_BOOTCOMP, 0);
410             break;
411         default:
412             //all other messages
413             boot_protocol_process_dl_messages(device, msg);
414             break;
415     }
416
417 }