Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/firmware/sigma.c
15109 views
1
/*
2
* Load Analog Devices SigmaStudio firmware files
3
*
4
* Copyright 2009-2011 Analog Devices Inc.
5
*
6
* Licensed under the GPL-2 or later.
7
*/
8
9
#include <linux/crc32.h>
10
#include <linux/delay.h>
11
#include <linux/firmware.h>
12
#include <linux/kernel.h>
13
#include <linux/i2c.h>
14
#include <linux/sigma.h>
15
16
/* Return: 0==OK, <0==error, =1 ==no more actions */
17
static int
18
process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
19
{
20
struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos);
21
size_t len = sigma_action_len(sa);
22
int ret = 0;
23
24
pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
25
sa->instr, sa->addr, len);
26
27
switch (sa->instr) {
28
case SIGMA_ACTION_WRITEXBYTES:
29
case SIGMA_ACTION_WRITESINGLE:
30
case SIGMA_ACTION_WRITESAFELOAD:
31
if (ssfw->fw->size < ssfw->pos + len)
32
return -EINVAL;
33
ret = i2c_master_send(client, (void *)&sa->addr, len);
34
if (ret < 0)
35
return -EINVAL;
36
break;
37
38
case SIGMA_ACTION_DELAY:
39
ret = 0;
40
udelay(len);
41
len = 0;
42
break;
43
44
case SIGMA_ACTION_END:
45
return 1;
46
47
default:
48
return -EINVAL;
49
}
50
51
/* when arrive here ret=0 or sent data */
52
ssfw->pos += sigma_action_size(sa, len);
53
return ssfw->pos == ssfw->fw->size;
54
}
55
56
static int
57
process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
58
{
59
pr_debug("%s: processing %p\n", __func__, ssfw);
60
61
while (1) {
62
int ret = process_sigma_action(client, ssfw);
63
pr_debug("%s: action returned %i\n", __func__, ret);
64
if (ret == 1)
65
return 0;
66
else if (ret)
67
return ret;
68
}
69
}
70
71
int process_sigma_firmware(struct i2c_client *client, const char *name)
72
{
73
int ret;
74
struct sigma_firmware_header *ssfw_head;
75
struct sigma_firmware ssfw;
76
const struct firmware *fw;
77
u32 crc;
78
79
pr_debug("%s: loading firmware %s\n", __func__, name);
80
81
/* first load the blob */
82
ret = request_firmware(&fw, name, &client->dev);
83
if (ret) {
84
pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
85
return ret;
86
}
87
ssfw.fw = fw;
88
89
/* then verify the header */
90
ret = -EINVAL;
91
if (fw->size < sizeof(*ssfw_head))
92
goto done;
93
94
ssfw_head = (void *)fw->data;
95
if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic)))
96
goto done;
97
98
crc = crc32(0, fw->data, fw->size);
99
pr_debug("%s: crc=%x\n", __func__, crc);
100
if (crc != ssfw_head->crc)
101
goto done;
102
103
ssfw.pos = sizeof(*ssfw_head);
104
105
/* finally process all of the actions */
106
ret = process_sigma_actions(client, &ssfw);
107
108
done:
109
release_firmware(fw);
110
111
pr_debug("%s: loaded %s\n", __func__, name);
112
113
return ret;
114
}
115
EXPORT_SYMBOL(process_sigma_firmware);
116
117