These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / 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 = request_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                 return -EINVAL;
309
310         memcpy(fw->date, fw->fw->data + 0x00, 12);
311         fw->date[12] = '\0';
312
313         memcpy(&fw->version, fw->fw->data + 0x10, 4);
314
315         memcpy(&sig_off, fw->fw->data + 0x14, 4);
316         fw->sig = fw->fw->data + sig_off;
317         memcpy(&fw->sig_size, fw->fw->data + 0x18, 4);
318
319         memcpy(&image_off, fw->fw->data + 0x1C, 4);
320         fw->image = fw->fw->data + image_off;
321         memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4);
322
323         memcpy(&custom_sig_off, fw->fw->data + 0x24, 4);
324         fw->custom_sig = fw->fw->data + custom_sig_off;
325         memcpy(&fw->custom_sig_size, fw->fw->data + 0x28, 4);
326
327         return 0;
328 }
329
330 static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info)
331 {
332         release_firmware(fw_info->fw.fw);
333 }
334
335 static int s3fwrn5_fw_get_base_addr(
336         struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr)
337 {
338         int i;
339         struct {
340                 u8 version[4];
341                 u32 base_addr;
342         } match[] = {
343                 {{0x05, 0x00, 0x00, 0x00}, 0x00005000},
344                 {{0x05, 0x00, 0x00, 0x01}, 0x00003000},
345                 {{0x05, 0x00, 0x00, 0x02}, 0x00003000},
346                 {{0x05, 0x00, 0x00, 0x03}, 0x00003000},
347                 {{0x05, 0x00, 0x00, 0x05}, 0x00003000}
348         };
349
350         for (i = 0; i < ARRAY_SIZE(match); ++i)
351                 if (bootinfo->hw_version[0] == match[i].version[0] &&
352                         bootinfo->hw_version[1] == match[i].version[1] &&
353                         bootinfo->hw_version[3] == match[i].version[3]) {
354                         *base_addr = match[i].base_addr;
355                         return 0;
356                 }
357
358         return -EINVAL;
359 }
360
361 static inline bool
362 s3fwrn5_fw_is_custom(struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
363 {
364         return !!bootinfo->hw_version[2];
365 }
366
367 int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info)
368 {
369         struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo;
370         int ret;
371
372         /* Get firmware data */
373
374         ret = s3fwrn5_fw_request_firmware(fw_info);
375         if (ret < 0) {
376                 dev_err(&fw_info->ndev->nfc_dev->dev,
377                         "Failed to get fw file, ret=%02x\n", ret);
378                 return ret;
379         }
380
381         /* Get bootloader info */
382
383         ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo);
384         if (ret < 0) {
385                 dev_err(&fw_info->ndev->nfc_dev->dev,
386                         "Failed to get bootinfo, ret=%02x\n", ret);
387                 goto err;
388         }
389
390         /* Match hardware version to obtain firmware base address */
391
392         ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr);
393         if (ret < 0) {
394                 dev_err(&fw_info->ndev->nfc_dev->dev,
395                         "Unknown hardware version\n");
396                 goto err;
397         }
398
399         fw_info->sector_size = bootinfo.sector_size;
400
401         fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ?
402                 fw_info->fw.custom_sig_size : fw_info->fw.sig_size;
403         fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ?
404                 fw_info->fw.custom_sig : fw_info->fw.sig;
405
406         return 0;
407
408 err:
409         s3fwrn5_fw_release_firmware(fw_info);
410         return ret;
411 }
412
413 bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version)
414 {
415         struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version;
416         struct s3fwrn5_fw_version *old = (void *) &version;
417
418         if (new->major > old->major)
419                 return true;
420         if (new->build1 > old->build1)
421                 return true;
422         if (new->build2 > old->build2)
423                 return true;
424
425         return false;
426 }
427
428 int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
429 {
430         struct s3fwrn5_fw_image *fw = &fw_info->fw;
431         u8 hash_data[SHA1_DIGEST_SIZE];
432         struct scatterlist sg;
433         struct hash_desc desc;
434         u32 image_size, off;
435         int ret;
436
437         image_size = fw_info->sector_size * fw->image_sectors;
438
439         /* Compute SHA of firmware data */
440
441         sg_init_one(&sg, fw->image, image_size);
442         desc.tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
443         crypto_hash_init(&desc);
444         crypto_hash_update(&desc, &sg, image_size);
445         crypto_hash_final(&desc, hash_data);
446         crypto_free_hash(desc.tfm);
447
448         /* Firmware update process */
449
450         dev_info(&fw_info->ndev->nfc_dev->dev,
451                 "Firmware update: %s\n", fw_info->fw_name);
452
453         ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data,
454                 SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size);
455         if (ret < 0) {
456                 dev_err(&fw_info->ndev->nfc_dev->dev,
457                         "Unable to enter update mode\n");
458                 goto out;
459         }
460
461         for (off = 0; off < image_size; off += fw_info->sector_size) {
462                 ret = s3fwrn5_fw_update_sector(fw_info,
463                         fw_info->base_addr + off, fw->image + off);
464                 if (ret < 0) {
465                         dev_err(&fw_info->ndev->nfc_dev->dev,
466                                 "Firmware update error (code=%d)\n", ret);
467                         goto out;
468                 }
469         }
470
471         ret = s3fwrn5_fw_complete_update_mode(fw_info);
472         if (ret < 0) {
473                 dev_err(&fw_info->ndev->nfc_dev->dev,
474                         "Unable to complete update mode\n");
475                 goto out;
476         }
477
478         dev_info(&fw_info->ndev->nfc_dev->dev,
479                 "Firmware update: success\n");
480
481 out:
482         return ret;
483 }
484
485 void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name)
486 {
487         fw_info->parity = 0x00;
488         fw_info->rsp = NULL;
489         fw_info->fw.fw = NULL;
490         strcpy(fw_info->fw_name, fw_name);
491         init_completion(&fw_info->completion);
492 }
493
494 void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info)
495 {
496         s3fwrn5_fw_release_firmware(fw_info);
497 }
498
499 int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
500 {
501         struct s3fwrn5_info *info = nci_get_drvdata(ndev);
502         struct s3fwrn5_fw_info *fw_info = &info->fw_info;
503
504         BUG_ON(fw_info->rsp);
505
506         fw_info->rsp = skb;
507
508         complete(&fw_info->completion);
509
510         return 0;
511 }