GNU Linux-libre 4.4.288-gnu1
[releases.git] / drivers / nfc / s3fwrn5 / firmware.c
1 /*
2  * NCI based driver for Samsung S3FWRN5 NFC chip
3  *
4  * Copyright (C) 2015 Samsung Electrnoics
5  * Robert Baldyga <r.baldyga@samsung.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU General Public License,
9  * version 2 or later, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <linux/completion.h>
21 #include <linux/firmware.h>
22 #include <linux/crypto.h>
23 #include <crypto/sha.h>
24
25 #include "s3fwrn5.h"
26 #include "firmware.h"
27
28 struct s3fwrn5_fw_version {
29         __u8 major;
30         __u8 build1;
31         __u8 build2;
32         __u8 target;
33 };
34
35 static int s3fwrn5_fw_send_msg(struct s3fwrn5_fw_info *fw_info,
36         struct sk_buff *msg, struct sk_buff **rsp)
37 {
38         struct s3fwrn5_info *info =
39                 container_of(fw_info, struct s3fwrn5_info, fw_info);
40         long ret;
41
42         reinit_completion(&fw_info->completion);
43
44         ret = s3fwrn5_write(info, msg);
45         if (ret < 0)
46                 return ret;
47
48         ret = wait_for_completion_interruptible_timeout(
49                 &fw_info->completion, msecs_to_jiffies(1000));
50         if (ret < 0)
51                 return ret;
52         else if (ret == 0)
53                 return -ENXIO;
54
55         if (!fw_info->rsp)
56                 return -EINVAL;
57
58         *rsp = fw_info->rsp;
59         fw_info->rsp = NULL;
60
61         return 0;
62 }
63
64 static int s3fwrn5_fw_prep_msg(struct s3fwrn5_fw_info *fw_info,
65         struct sk_buff **msg, u8 type, u8 code, const void *data, u16 len)
66 {
67         struct s3fwrn5_fw_header hdr;
68         struct sk_buff *skb;
69
70         hdr.type = type | fw_info->parity;
71         fw_info->parity ^= 0x80;
72         hdr.code = code;
73         hdr.len = len;
74
75         skb = alloc_skb(S3FWRN5_FW_HDR_SIZE + len, GFP_KERNEL);
76         if (!skb)
77                 return -ENOMEM;
78
79         memcpy(skb_put(skb, S3FWRN5_FW_HDR_SIZE), &hdr, S3FWRN5_FW_HDR_SIZE);
80         if (len)
81                 memcpy(skb_put(skb, len), data, len);
82
83         *msg = skb;
84
85         return 0;
86 }
87
88 static int s3fwrn5_fw_get_bootinfo(struct s3fwrn5_fw_info *fw_info,
89         struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
90 {
91         struct sk_buff *msg, *rsp = NULL;
92         struct s3fwrn5_fw_header *hdr;
93         int ret;
94
95         /* Send GET_BOOTINFO command */
96
97         ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
98                 S3FWRN5_FW_CMD_GET_BOOTINFO, NULL, 0);
99         if (ret < 0)
100                 return ret;
101
102         ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
103         kfree_skb(msg);
104         if (ret < 0)
105                 return ret;
106
107         hdr = (struct s3fwrn5_fw_header *) rsp->data;
108         if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
109                 ret = -EINVAL;
110                 goto out;
111         }
112
113         memcpy(bootinfo, rsp->data + S3FWRN5_FW_HDR_SIZE, 10);
114
115 out:
116         kfree_skb(rsp);
117         return ret;
118 }
119
120 static int s3fwrn5_fw_enter_update_mode(struct s3fwrn5_fw_info *fw_info,
121         const void *hash_data, u16 hash_size,
122         const void *sig_data, u16 sig_size)
123 {
124         struct s3fwrn5_fw_cmd_enter_updatemode args;
125         struct sk_buff *msg, *rsp = NULL;
126         struct s3fwrn5_fw_header *hdr;
127         int ret;
128
129         /* Send ENTER_UPDATE_MODE command */
130
131         args.hashcode_size = hash_size;
132         args.signature_size = sig_size;
133
134         ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
135                 S3FWRN5_FW_CMD_ENTER_UPDATE_MODE, &args, sizeof(args));
136         if (ret < 0)
137                 return ret;
138
139         ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
140         kfree_skb(msg);
141         if (ret < 0)
142                 return ret;
143
144         hdr = (struct s3fwrn5_fw_header *) rsp->data;
145         if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
146                 ret = -EPROTO;
147                 goto out;
148         }
149
150         kfree_skb(rsp);
151
152         /* Send hashcode data */
153
154         ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0,
155                 hash_data, hash_size);
156         if (ret < 0)
157                 return ret;
158
159         ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
160         kfree_skb(msg);
161         if (ret < 0)
162                 return ret;
163
164         hdr = (struct s3fwrn5_fw_header *) rsp->data;
165         if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
166                 ret = -EPROTO;
167                 goto out;
168         }
169
170         kfree_skb(rsp);
171
172         /* Send signature data */
173
174         ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0,
175                 sig_data, sig_size);
176         if (ret < 0)
177                 return ret;
178
179         ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
180         kfree_skb(msg);
181         if (ret < 0)
182                 return ret;
183
184         hdr = (struct s3fwrn5_fw_header *) rsp->data;
185         if (hdr->code != S3FWRN5_FW_RET_SUCCESS)
186                 ret = -EPROTO;
187
188 out:
189         kfree_skb(rsp);
190         return ret;
191 }
192
193 static int s3fwrn5_fw_update_sector(struct s3fwrn5_fw_info *fw_info,
194         u32 base_addr, const void *data)
195 {
196         struct s3fwrn5_fw_cmd_update_sector args;
197         struct sk_buff *msg, *rsp = NULL;
198         struct s3fwrn5_fw_header *hdr;
199         int ret, i;
200
201         /* Send UPDATE_SECTOR command */
202
203         args.base_address = base_addr;
204
205         ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
206                 S3FWRN5_FW_CMD_UPDATE_SECTOR, &args, sizeof(args));
207         if (ret < 0)
208                 return ret;
209
210         ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
211         kfree_skb(msg);
212         if (ret < 0)
213                 return ret;
214
215         hdr = (struct s3fwrn5_fw_header *) rsp->data;
216         if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
217                 ret = -EPROTO;
218                 goto err;
219         }
220
221         kfree_skb(rsp);
222
223         /* Send data split into 256-byte packets */
224
225         for (i = 0; i < 16; ++i) {
226                 ret = s3fwrn5_fw_prep_msg(fw_info, &msg,
227                         S3FWRN5_FW_MSG_DATA, 0, data+256*i, 256);
228                 if (ret < 0)
229                         break;
230
231                 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
232                 kfree_skb(msg);
233                 if (ret < 0)
234                         break;
235
236                 hdr = (struct s3fwrn5_fw_header *) rsp->data;
237                 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
238                         ret = -EPROTO;
239                         goto err;
240                 }
241
242                 kfree_skb(rsp);
243         }
244
245         return ret;
246
247 err:
248         kfree_skb(rsp);
249         return ret;
250 }
251
252 static int s3fwrn5_fw_complete_update_mode(struct s3fwrn5_fw_info *fw_info)
253 {
254         struct sk_buff *msg, *rsp = NULL;
255         struct s3fwrn5_fw_header *hdr;
256         int ret;
257
258         /* Send COMPLETE_UPDATE_MODE command */
259
260         ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
261                 S3FWRN5_FW_CMD_COMPLETE_UPDATE_MODE, NULL, 0);
262         if (ret < 0)
263                 return ret;
264
265         ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
266         kfree_skb(msg);
267         if (ret < 0)
268                 return ret;
269
270         hdr = (struct s3fwrn5_fw_header *) rsp->data;
271         if (hdr->code != S3FWRN5_FW_RET_SUCCESS)
272                 ret = -EPROTO;
273
274         kfree_skb(rsp);
275
276         return ret;
277 }
278
279 /*
280  * Firmware header stucture:
281  *
282  * 0x00 - 0x0B : Date and time string (w/o NUL termination)
283  * 0x10 - 0x13 : Firmware version
284  * 0x14 - 0x17 : Signature address
285  * 0x18 - 0x1B : Signature size
286  * 0x1C - 0x1F : Firmware image address
287  * 0x20 - 0x23 : Firmware sectors count
288  * 0x24 - 0x27 : Custom signature address
289  * 0x28 - 0x2B : Custom signature size
290  */
291
292 #define S3FWRN5_FW_IMAGE_HEADER_SIZE 44
293
294 static int s3fwrn5_fw_request_firmware(struct s3fwrn5_fw_info *fw_info)
295 {
296         struct s3fwrn5_fw_image *fw = &fw_info->fw;
297         u32 sig_off;
298         u32 image_off;
299         u32 custom_sig_off;
300         int ret;
301
302         ret = reject_firmware(&fw->fw, fw_info->fw_name,
303                 &fw_info->ndev->nfc_dev->dev);
304         if (ret < 0)
305                 return ret;
306
307         if (fw->fw->size < S3FWRN5_FW_IMAGE_HEADER_SIZE) {
308                 release_firmware(fw->fw);
309                 return -EINVAL;
310         }
311
312         memcpy(fw->date, fw->fw->data + 0x00, 12);
313         fw->date[12] = '\0';
314
315         memcpy(&fw->version, fw->fw->data + 0x10, 4);
316
317         memcpy(&sig_off, fw->fw->data + 0x14, 4);
318         fw->sig = fw->fw->data + sig_off;
319         memcpy(&fw->sig_size, fw->fw->data + 0x18, 4);
320
321         memcpy(&image_off, fw->fw->data + 0x1C, 4);
322         fw->image = fw->fw->data + image_off;
323         memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4);
324
325         memcpy(&custom_sig_off, fw->fw->data + 0x24, 4);
326         fw->custom_sig = fw->fw->data + custom_sig_off;
327         memcpy(&fw->custom_sig_size, fw->fw->data + 0x28, 4);
328
329         return 0;
330 }
331
332 static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info)
333 {
334         release_firmware(fw_info->fw.fw);
335 }
336
337 static int s3fwrn5_fw_get_base_addr(
338         struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr)
339 {
340         int i;
341         struct {
342                 u8 version[4];
343                 u32 base_addr;
344         } match[] = {
345                 {{0x05, 0x00, 0x00, 0x00}, 0x00005000},
346                 {{0x05, 0x00, 0x00, 0x01}, 0x00003000},
347                 {{0x05, 0x00, 0x00, 0x02}, 0x00003000},
348                 {{0x05, 0x00, 0x00, 0x03}, 0x00003000},
349                 {{0x05, 0x00, 0x00, 0x05}, 0x00003000}
350         };
351
352         for (i = 0; i < ARRAY_SIZE(match); ++i)
353                 if (bootinfo->hw_version[0] == match[i].version[0] &&
354                         bootinfo->hw_version[1] == match[i].version[1] &&
355                         bootinfo->hw_version[3] == match[i].version[3]) {
356                         *base_addr = match[i].base_addr;
357                         return 0;
358                 }
359
360         return -EINVAL;
361 }
362
363 static inline bool
364 s3fwrn5_fw_is_custom(struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
365 {
366         return !!bootinfo->hw_version[2];
367 }
368
369 int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info)
370 {
371         struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo;
372         int ret;
373
374         /* Get firmware data */
375
376         ret = s3fwrn5_fw_request_firmware(fw_info);
377         if (ret < 0) {
378                 dev_err(&fw_info->ndev->nfc_dev->dev,
379                         "Failed to get fw file, ret=%02x\n", ret);
380                 return ret;
381         }
382
383         /* Get bootloader info */
384
385         ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo);
386         if (ret < 0) {
387                 dev_err(&fw_info->ndev->nfc_dev->dev,
388                         "Failed to get bootinfo, ret=%02x\n", ret);
389                 goto err;
390         }
391
392         /* Match hardware version to obtain firmware base address */
393
394         ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr);
395         if (ret < 0) {
396                 dev_err(&fw_info->ndev->nfc_dev->dev,
397                         "Unknown hardware version\n");
398                 goto err;
399         }
400
401         fw_info->sector_size = bootinfo.sector_size;
402
403         fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ?
404                 fw_info->fw.custom_sig_size : fw_info->fw.sig_size;
405         fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ?
406                 fw_info->fw.custom_sig : fw_info->fw.sig;
407
408         return 0;
409
410 err:
411         s3fwrn5_fw_release_firmware(fw_info);
412         return ret;
413 }
414
415 bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version)
416 {
417         struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version;
418         struct s3fwrn5_fw_version *old = (void *) &version;
419
420         if (new->major > old->major)
421                 return true;
422         if (new->build1 > old->build1)
423                 return true;
424         if (new->build2 > old->build2)
425                 return true;
426
427         return false;
428 }
429
430 int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
431 {
432         struct s3fwrn5_fw_image *fw = &fw_info->fw;
433         u8 hash_data[SHA1_DIGEST_SIZE];
434         struct scatterlist sg;
435         struct hash_desc desc;
436         u32 image_size, off;
437         int ret;
438
439         image_size = fw_info->sector_size * fw->image_sectors;
440
441         /* Compute SHA of firmware data */
442
443         sg_init_one(&sg, fw->image, image_size);
444         desc.tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
445         crypto_hash_init(&desc);
446         crypto_hash_update(&desc, &sg, image_size);
447         crypto_hash_final(&desc, hash_data);
448         crypto_free_hash(desc.tfm);
449
450         /* Firmware update process */
451
452         dev_info(&fw_info->ndev->nfc_dev->dev,
453                 "Firmware update: %s\n", fw_info->fw_name);
454
455         ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data,
456                 SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size);
457         if (ret < 0) {
458                 dev_err(&fw_info->ndev->nfc_dev->dev,
459                         "Unable to enter update mode\n");
460                 goto out;
461         }
462
463         for (off = 0; off < image_size; off += fw_info->sector_size) {
464                 ret = s3fwrn5_fw_update_sector(fw_info,
465                         fw_info->base_addr + off, fw->image + off);
466                 if (ret < 0) {
467                         dev_err(&fw_info->ndev->nfc_dev->dev,
468                                 "Firmware update error (code=%d)\n", ret);
469                         goto out;
470                 }
471         }
472
473         ret = s3fwrn5_fw_complete_update_mode(fw_info);
474         if (ret < 0) {
475                 dev_err(&fw_info->ndev->nfc_dev->dev,
476                         "Unable to complete update mode\n");
477                 goto out;
478         }
479
480         dev_info(&fw_info->ndev->nfc_dev->dev,
481                 "Firmware update: success\n");
482
483 out:
484         return ret;
485 }
486
487 void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name)
488 {
489         fw_info->parity = 0x00;
490         fw_info->rsp = NULL;
491         fw_info->fw.fw = NULL;
492         strcpy(fw_info->fw_name, fw_name);
493         init_completion(&fw_info->completion);
494 }
495
496 void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info)
497 {
498         s3fwrn5_fw_release_firmware(fw_info);
499 }
500
501 int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
502 {
503         struct s3fwrn5_info *info = nci_get_drvdata(ndev);
504         struct s3fwrn5_fw_info *fw_info = &info->fw_info;
505
506         BUG_ON(fw_info->rsp);
507
508         fw_info->rsp = skb;
509
510         complete(&fw_info->completion);
511
512         return 0;
513 }