06a2b90f961e7186a21aa952f3f859235125c365
[libsamsung-ipc.git] / samsung-ipc / devices / xmm6260 / xmm6260_mipi.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com>
5  * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr>
6  *
7  * Based on the incomplete C++ implementation which is:
8  * Copyright (C) 2012 Sergey Gridasov <grindars@gmail.com>
9  *
10  * libsamsung-ipc is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * libsamsung-ipc is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <sys/select.h>
29
30 #include <samsung-ipc.h>
31 #include <utils.h>
32
33 #include "xmm6260.h"
34 #include "xmm6260_mipi.h"
35
36 int xmm6260_mipi_crc_calculate(void *buffer, int length)
37 {
38     unsigned char crc;
39     int mipi_crc;
40
41     crc = xmm6260_crc_calculate(buffer, length);
42     mipi_crc = (crc << 24) | 0xffffff;
43
44     return mipi_crc;
45 }
46
47 int xmm6260_mipi_ack_read(int device_fd, unsigned short ack)
48 {
49     struct timeval timeout;
50     fd_set fds;
51
52     unsigned int value;
53     int rc;
54     int i;
55
56     timeout.tv_sec = 1;
57     timeout.tv_usec = 0;
58
59     FD_ZERO(&fds);
60     FD_SET(device_fd, &fds);
61
62     for (i = 0; i < 50; i++) {
63         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
64         if (rc <= 0)
65             return -1;
66
67         value = 0;
68         rc = read(device_fd, &value, sizeof(value));
69         if (rc < (int) sizeof(value))
70             continue;
71
72         if ((value & 0xffff) == ack)
73             return 0;
74     }
75
76     return -1;
77 }
78
79 int xmm6260_mipi_psi_send(struct ipc_client *client, int device_fd,
80     void *psi_data, unsigned short psi_size)
81 {
82     struct xmm6260_mipi_psi_header psi_header;
83     char at[] = XMM6260_AT;
84     int psi_crc;
85
86     struct timeval timeout;
87     fd_set fds;
88     int wc;
89
90     unsigned char *p;
91     int length;
92     int rc;
93     int i;
94
95     if (client == NULL || device_fd < 0 || psi_data == NULL || psi_size == 0)
96         return -1;
97
98     FD_ZERO(&fds);
99
100     i = 0;
101     length = strlen(at);
102
103     do {
104         FD_SET(device_fd, &fds);
105
106         timeout.tv_sec = 0;
107         timeout.tv_usec = 100000;
108
109         rc = write(device_fd, at, length);
110         if (rc < length) {
111             ipc_client_log(client, "Writing ATAT in ASCII failed");
112             goto error;
113         }
114         ipc_client_log(client, "Wrote ATAT in ASCII");
115
116         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
117         if (rc < 0) {
118             ipc_client_log(client, "Waiting for bootup failed");
119             goto error;
120         }
121
122         if (i++ > 50) {
123             ipc_client_log(client, "Waiting for bootup failed");
124             goto error;
125         }
126     } while(rc == 0);
127
128     rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_BOOT0_ACK);
129     if (rc < 0) {
130         ipc_client_log(client, "Reading boot ACK failed");
131         goto error;
132     }
133
134     psi_header.padding = XMM6260_PSI_PADDING;
135     psi_header.length = ((psi_size >> 8) & 0xff) | ((psi_size & 0xff) << 8);
136     psi_header.magic = XMM6260_PSI_MAGIC;
137
138     rc = write(device_fd, &psi_header, sizeof(psi_header));
139     if (rc < (int) sizeof(psi_header)) {
140         ipc_client_log(client, "Writing PSI header failed");
141         goto error;
142     }
143     ipc_client_log(client, "Wrote PSI header");
144
145     p = (unsigned char *) psi_data;
146
147     wc = 0;
148     while (wc < psi_size) {
149         rc = write(device_fd, (void *) p, psi_size - wc);
150         if (rc < 0) {
151             ipc_client_log(client, "Writing PSI failed");
152             goto error;
153         }
154
155         p += rc;
156         wc += rc;
157     }
158
159     psi_crc = xmm6260_mipi_crc_calculate(psi_data, psi_size);
160
161     ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc);
162
163     rc = write(device_fd, &psi_crc, sizeof(psi_crc));
164     if (rc < (int) sizeof(psi_crc)) {
165         ipc_client_log(client, "Writing PSI CRC failed");
166         goto error;
167     }
168     ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc);
169
170     rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_PSI_ACK);
171     if (rc < 0) {
172         ipc_client_log(client, "Reading PSI ACK failed");
173         goto error;
174     }
175
176     rc = 0;
177     goto complete;
178
179 error:
180     rc = -1;
181
182 complete:
183     return rc;
184 }
185
186 int xmm6260_mipi_ebl_send(struct ipc_client *client, int device_fd,
187     void *ebl_data, int ebl_size)
188 {
189     unsigned short boot_magic[4];
190     unsigned char ebl_crc;
191
192     int chunk;
193     int count;
194     int wc;
195
196     unsigned char *p;
197     int length;
198     int rc;
199
200     if (client == NULL || device_fd < 0 || ebl_data == NULL || ebl_size <= 0)
201         return -1;
202
203     boot_magic[0] = 0;
204     boot_magic[1] = 0;
205     boot_magic[2] = XMM6260_MIPI_BOOT1_MAGIC;
206     boot_magic[3] = XMM6260_MIPI_BOOT1_MAGIC;
207
208     length = sizeof(boot_magic);
209
210     rc = write(device_fd, &length, sizeof(length));
211     if (rc < (int) sizeof(length)) {
212         ipc_client_log(client, "Writing boot magic length failed");
213         goto error;
214     }
215
216     rc = write(device_fd, &boot_magic, length);
217     if (rc < length) {
218         ipc_client_log(client, "Writing boot magic failed");
219         goto error;
220     }
221     ipc_client_log(client, "Wrote boot magic");
222
223     rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_BOOT1_ACK);
224     if (rc < 0) {
225         ipc_client_log(client, "Reading boot magic ACK failed");
226         goto error;
227     }
228
229     length = sizeof(ebl_size);
230
231     rc = write(device_fd, &length, sizeof(length));
232     if (rc < (int) sizeof(length)) {
233         ipc_client_log(client, "Writing EBL size length failed");
234         goto error;
235     }
236
237     rc = write(device_fd, &ebl_size, length);
238     if (rc < length) {
239         ipc_client_log(client, "Writing EBL size failed");
240         goto error;
241     }
242     ipc_client_log(client, "Wrote EBL size");
243
244     rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_EBL_SIZE_ACK);
245     if (rc < 0) {
246         ipc_client_log(client, "Reading EBL size ACK failed");
247         goto error;
248     }
249
250     ebl_size++;
251
252     rc = write(device_fd, &ebl_size, length);
253     if (rc < length) {
254         ipc_client_log(client, "Writing EBL size failed");
255         goto error;
256     }
257
258     ebl_size--;
259
260     p = (unsigned char *) ebl_data;
261
262     chunk = XMM6260_MIPI_EBL_CHUNK;
263     wc = 0;
264     while (wc < ebl_size) {
265         count = chunk < ebl_size - wc ? chunk : ebl_size - wc;
266
267         rc = write(device_fd, (void *) p, count);
268         if (rc < 0) {
269             ipc_client_log(client, "Writing EBL failed");
270             goto error;
271         }
272
273         p += rc;
274         wc += rc;
275     }
276
277     ebl_crc = xmm6260_crc_calculate(ebl_data, ebl_size);
278
279     ipc_client_log(client, "Wrote EBL, CRC is 0x%x", ebl_crc);
280
281     rc = write(device_fd, &ebl_crc, sizeof(ebl_crc));
282     if (rc < (int) sizeof(ebl_crc)) {
283         ipc_client_log(client, "Writing EBL CRC failed");
284         goto error;
285     }
286     ipc_client_log(client, "Wrote EBL CRC (0x%x)", ebl_crc);
287
288     rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_EBL_ACK);
289     if (rc < 0) {
290         ipc_client_log(client, "Reading EBL ACK failed");
291         goto error;
292     }
293
294     rc = 0;
295     goto complete;
296
297 error:
298     rc = -1;
299
300 complete:
301     return rc;
302 }
303
304 int xmm6260_mipi_command_send(int device_fd, unsigned short code,
305     void *data, int size, int ack, int short_footer)
306 {
307     struct xmm6260_mipi_command_header header;
308     struct xmm6260_mipi_command_footer footer;
309     int footer_size;
310     void *buffer = NULL;
311     int length;
312
313     struct timeval timeout;
314     fd_set fds;
315     int chunk;
316     int c;
317
318     unsigned char *p;
319     int rc;
320     int i;
321
322     if (device_fd < 0 || data == NULL || size <= 0)
323         return -1;
324
325     header.size = size + sizeof(header);
326     header.magic = XMM6260_MIPI_COMMAND_HEADER_MAGIC;
327     header.code = code;
328     header.data_size = size;
329
330     footer.checksum = (size & 0xffff) + code;
331     footer.magic = XMM6260_MIPI_COMMAND_FOOTER_MAGIC;
332     footer.unknown = XMM6260_MIPI_COMMAND_FOOTER_UNKNOWN;
333
334     p = (unsigned char *) data;
335
336     for (i = 0; i < size; i++)
337         footer.checksum += *p++;
338
339     footer_size = sizeof(footer);
340     if (short_footer)
341         footer_size -= sizeof(short);
342
343     length = sizeof(header) + size + footer_size;
344     buffer = malloc(length);
345
346     p = (unsigned char *) buffer;
347     memcpy(p, &header, sizeof(header));
348     p += sizeof(header);
349     memcpy(p, data, size);
350     p += size;
351     memcpy(p, &footer, footer_size);
352
353     rc = write(device_fd, buffer, length);
354     if (rc < length)
355         goto error;
356
357     free(buffer);
358     buffer = NULL;
359
360     if (!ack) {
361         rc = 0;
362         goto complete;
363     }
364
365     FD_ZERO(&fds);
366     FD_SET(device_fd, &fds);
367
368     timeout.tv_sec = 1;
369     timeout.tv_usec = 0;
370
371     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
372     if (rc <= 0)
373         goto error;
374
375     rc = read(device_fd, &length, sizeof(length));
376     if (rc < (int) sizeof(length) || length <= 0)
377         goto error;
378
379     length += sizeof(unsigned int);
380     if (length % 4 != 0)
381         length += length % 4;
382
383     if (length < (int) sizeof(buffer))
384         goto error;
385
386     buffer = malloc(length);
387
388     p = (unsigned char *) buffer;
389     memcpy(p, &length, sizeof(length));
390     p += sizeof(length);
391
392     chunk = 4;
393     c = sizeof(length);
394     while (c < length) {
395         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
396         if (rc <= 0)
397             goto error;
398
399         rc = read(device_fd, (void *) p, chunk);
400         if (rc < chunk)
401             goto error;
402
403         p += rc;
404         c += rc;
405     }
406
407     memcpy(&header, buffer, sizeof(header));
408     if (header.code != code)
409         goto error;
410
411     rc = 0;
412     goto complete;
413
414 error:
415     rc = -1;
416
417 complete:
418     if (buffer != NULL)
419         free(buffer);
420
421     return rc;
422 }
423
424 int xmm6260_mipi_modem_data_send(int device_fd, void *data, int size, int address)
425 {
426     int chunk;
427     int count;
428     int c;
429
430     unsigned char *p;
431     int rc;
432
433     if (device_fd < 0 || data == NULL || size <= 0)
434         return -1;
435
436     rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_FLASH_SET_ADDRESS, &address, sizeof(address), 1, 0);
437     if (rc < 0)
438         goto error;
439
440     p = (unsigned char *) data;
441
442     chunk = XMM6260_MIPI_MODEM_DATA_CHUNK;
443     c = 0;
444     while (c < size) {
445         count = chunk < size - c ? chunk : size - c;
446
447         rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_FLASH_WRITE_BLOCK, p, count, 1, 1);
448         if (rc < 0)
449             goto error;
450
451         p += count;
452         c += count;
453     }
454
455     rc = 0;
456     goto complete;
457
458 error:
459     rc = -1;
460
461 complete:
462     return rc;
463 }
464
465 int xmm6260_mipi_port_config_send(struct ipc_client *client, int device_fd)
466 {
467     void *buffer = NULL;
468     int length;
469
470     struct timeval timeout;
471     fd_set fds;
472     int chunk;
473     int count;
474     int c;
475
476     unsigned char *p;
477     int rc;
478
479     if (client == NULL || device_fd < 0)
480         return -1;
481
482     FD_ZERO(&fds);
483     FD_SET(device_fd, &fds);
484
485     timeout.tv_sec = 2;
486     timeout.tv_usec = 0;
487
488     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
489     if (rc <= 0)
490         goto error;
491
492     rc = read(device_fd, &length, sizeof(length));
493     if (rc < (int) sizeof(length) || length <= 0) {
494         ipc_client_log(client, "Reading port config length failed");
495         goto error;
496     }
497     ipc_client_log(client, "Read port config length (0x%x)", length);
498
499     buffer = malloc(length);
500
501     p = (unsigned char *) buffer;
502
503     chunk = 4;
504     c = 0;
505     while (c < length) {
506         count = chunk < length - c ? chunk : length - c;
507
508         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
509         if (rc <= 0)
510             goto error;
511
512         rc = read(device_fd, p, count);
513         if (rc < count) {
514             ipc_client_log(client, "Reading port config failed");
515             goto error;
516         }
517
518         p += count;
519         c += count;
520     }
521     ipc_client_log(client, "Read port config");
522
523     rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SET_PORT_CONFIG, buffer, length, 1, 0);
524     if (rc < 0) {
525         ipc_client_log(client, "Sending port config command failed");
526         goto error;
527     }
528
529     rc = 0;
530     goto complete;
531
532 error:
533     rc = -1;
534
535 complete:
536     if (buffer != NULL)
537         free(buffer);
538
539     return rc;
540 }
541
542 int xmm6260_mipi_sec_start_send(struct ipc_client *client, int device_fd,
543     void *sec_data, int sec_size)
544 {
545     int rc;
546
547     if (client == NULL || device_fd < 0 || sec_data == NULL || sec_size <= 0)
548         return -1;
549
550     rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SEC_START, sec_data, sec_size, 1, 0);
551     if (rc < 0)
552         return -1;
553
554     return 0;
555 }
556
557 int xmm6260_mipi_sec_end_send(struct ipc_client *client, int device_fd)
558 {
559     unsigned short sec_data;
560     int sec_size;
561     int rc;
562
563     if (client == NULL || device_fd < 0)
564         return -1;
565
566     sec_data = XMM6260_SEC_END_MAGIC;
567     sec_size = sizeof(sec_data);
568
569     rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SEC_END, &sec_data, sec_size, 1, 1);
570     if (rc < 0)
571         return -1;
572
573     return 0;
574 }
575
576 int xmm6260_mipi_firmware_send(struct ipc_client *client, int device_fd,
577     void *firmware_data, int firmware_size)
578 {
579     int rc;
580
581     if (client == NULL || device_fd < 0 || firmware_data == NULL || firmware_size <= 0)
582         return -1;
583
584     rc = xmm6260_mipi_modem_data_send(device_fd, firmware_data, firmware_size, XMM6260_FIRMWARE_ADDRESS);
585     if (rc < 0)
586         return -1;
587
588     return 0;
589 }
590
591 int xmm6260_mipi_nv_data_send(struct ipc_client *client, int device_fd)
592 {
593     void *nv_data = NULL;
594     int nv_size;
595     int rc;
596
597     if (client == NULL || device_fd < 0)
598         return -1;
599
600     rc = nv_data_check(client);
601     if (rc < 0) {
602         ipc_client_log(client, "Checking nv_data failed");
603         goto error;
604     }
605     ipc_client_log(client, "Checked nv_data");
606
607     rc = nv_data_md5_check(client);
608     if (rc < 0) {
609         ipc_client_log(client, "Checking nv_data md5 failed");
610         goto error;
611     }
612     ipc_client_log(client, "Checked nv_data md5");
613
614     nv_data = file_data_read(ipc_client_nv_data_path(client), ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
615     if (nv_data == NULL) {
616         ipc_client_log(client, "Reading nv_data failed");
617         goto error;
618     }
619     ipc_client_log(client, "Read nv_data");
620
621     nv_size = ipc_client_nv_data_size(client);
622
623     rc = xmm6260_mipi_modem_data_send(device_fd, nv_data, nv_size, XMM6260_NV_DATA_ADDRESS);
624     if (rc < 0)
625         goto error;
626
627     rc = 0;
628     goto complete;
629
630 error:
631     rc = -1;
632
633 complete:
634     if (nv_data != NULL)
635         free(nv_data);
636
637     return rc;
638 }
639
640 int xmm6260_mipi_mps_data_send(struct ipc_client *client, int device_fd,
641     void *mps_data, int mps_size)
642 {
643     int rc;
644
645     if (client == NULL || device_fd < 0 || mps_data == NULL || mps_size <= 0)
646         return -1;
647
648     rc = xmm6260_mipi_modem_data_send(device_fd, mps_data, mps_size, XMM6260_MPS_DATA_ADDRESS);
649     if (rc < 0)
650         return -1;
651
652     return 0;
653 }
654
655 int xmm6260_mipi_hw_reset_send(struct ipc_client *client, int device_fd)
656 {
657     unsigned int hw_reset_data;
658     int hw_reset_size;
659     int rc;
660
661     if (client == NULL || device_fd < 0)
662         return -1;
663
664     hw_reset_data = XMM6260_HW_RESET_MAGIC;
665     hw_reset_size = sizeof(hw_reset_data);
666
667     rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_HW_RESET, &hw_reset_data, hw_reset_size, 0, 1);
668     if (rc < 0)
669         return -1;
670
671     return 0;
672 }
673
674 // vim:ts=4:sw=4:expandtab