blob: aa223c56b2b6fea4dfbbff99fd5c36b1599a1f79 [file] [log] [blame]
Mike Frysingere359dc22011-03-22 16:34:40 -07001/*
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>
Randy Dunlap27c46a22011-07-25 17:13:21 -070014#include <linux/module.h>
Lars-Peter Clausen40216ce2011-11-28 09:44:17 +010015
16#include "sigmadsp.h"
Mike Frysingere359dc22011-03-22 16:34:40 -070017
Lars-Peter Clausena4c1d7e2011-11-28 09:44:19 +010018#define SIGMA_MAGIC "ADISIGM"
19
20struct sigma_firmware_header {
21 unsigned char magic[7];
22 u8 version;
23 __le32 crc;
24} __packed;
25
26enum {
27 SIGMA_ACTION_WRITEXBYTES = 0,
28 SIGMA_ACTION_WRITESINGLE,
29 SIGMA_ACTION_WRITESAFELOAD,
30 SIGMA_ACTION_DELAY,
31 SIGMA_ACTION_PLLWAIT,
32 SIGMA_ACTION_NOOP,
33 SIGMA_ACTION_END,
34};
35
36struct sigma_action {
37 u8 instr;
38 u8 len_hi;
39 __le16 len;
40 __be16 addr;
41 unsigned char payload[];
42} __packed;
43
44struct sigma_firmware {
45 const struct firmware *fw;
46 size_t pos;
47};
48
49static inline u32 sigma_action_len(struct sigma_action *sa)
50{
51 return (sa->len_hi << 16) | le16_to_cpu(sa->len);
52}
53
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +010054static size_t sigma_action_size(struct sigma_action *sa)
Mike Frysingere359dc22011-03-22 16:34:40 -070055{
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +010056 size_t payload = 0;
57
58 switch (sa->instr) {
59 case SIGMA_ACTION_WRITEXBYTES:
60 case SIGMA_ACTION_WRITESINGLE:
61 case SIGMA_ACTION_WRITESAFELOAD:
62 payload = sigma_action_len(sa);
63 break;
64 default:
65 break;
66 }
67
68 payload = ALIGN(payload, 2);
69
70 return payload + sizeof(struct sigma_action);
71}
72
73/*
74 * Returns a negative error value in case of an error, 0 if processing of
75 * the firmware should be stopped after this action, 1 otherwise.
76 */
77static int
78process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
79{
Mike Frysingere359dc22011-03-22 16:34:40 -070080 size_t len = sigma_action_len(sa);
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +010081 int ret;
Mike Frysingere359dc22011-03-22 16:34:40 -070082
83 pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
84 sa->instr, sa->addr, len);
85
86 switch (sa->instr) {
87 case SIGMA_ACTION_WRITEXBYTES:
88 case SIGMA_ACTION_WRITESINGLE:
89 case SIGMA_ACTION_WRITESAFELOAD:
Mike Frysingere359dc22011-03-22 16:34:40 -070090 ret = i2c_master_send(client, (void *)&sa->addr, len);
91 if (ret < 0)
92 return -EINVAL;
93 break;
Mike Frysingere359dc22011-03-22 16:34:40 -070094 case SIGMA_ACTION_DELAY:
Mike Frysingere359dc22011-03-22 16:34:40 -070095 udelay(len);
96 len = 0;
97 break;
Mike Frysingere359dc22011-03-22 16:34:40 -070098 case SIGMA_ACTION_END:
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +010099 return 0;
Mike Frysingere359dc22011-03-22 16:34:40 -0700100 default:
101 return -EINVAL;
102 }
103
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +0100104 return 1;
Mike Frysingere359dc22011-03-22 16:34:40 -0700105}
106
107static int
108process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
109{
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +0100110 struct sigma_action *sa;
111 size_t size;
112 int ret;
Mike Frysingere359dc22011-03-22 16:34:40 -0700113
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +0100114 while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
115 sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
116
117 size = sigma_action_size(sa);
118 ssfw->pos += size;
119 if (ssfw->pos > ssfw->fw->size || size == 0)
120 break;
121
122 ret = process_sigma_action(client, sa);
123
Mike Frysingere359dc22011-03-22 16:34:40 -0700124 pr_debug("%s: action returned %i\n", __func__, ret);
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +0100125
126 if (ret <= 0)
Mike Frysingere359dc22011-03-22 16:34:40 -0700127 return ret;
128 }
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +0100129
130 if (ssfw->pos != ssfw->fw->size)
131 return -EINVAL;
132
133 return 0;
Mike Frysingere359dc22011-03-22 16:34:40 -0700134}
135
136int process_sigma_firmware(struct i2c_client *client, const char *name)
137{
138 int ret;
139 struct sigma_firmware_header *ssfw_head;
140 struct sigma_firmware ssfw;
141 const struct firmware *fw;
142 u32 crc;
143
144 pr_debug("%s: loading firmware %s\n", __func__, name);
145
146 /* first load the blob */
147 ret = request_firmware(&fw, name, &client->dev);
148 if (ret) {
149 pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
150 return ret;
151 }
152 ssfw.fw = fw;
153
154 /* then verify the header */
155 ret = -EINVAL;
Lars-Peter Clausen4f718a22011-11-28 09:44:14 +0100156
157 /*
158 * Reject too small or unreasonable large files. The upper limit has been
159 * chosen a bit arbitrarily, but it should be enough for all practical
160 * purposes and having the limit makes it easier to avoid integer
161 * overflows later in the loading process.
162 */
Lars-Peter Clausen48afc522011-11-28 09:44:18 +0100163 if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
164 dev_err(&client->dev, "Failed to load firmware: Invalid size\n");
Mike Frysingere359dc22011-03-22 16:34:40 -0700165 goto done;
Lars-Peter Clausen48afc522011-11-28 09:44:18 +0100166 }
Mike Frysingere359dc22011-03-22 16:34:40 -0700167
168 ssfw_head = (void *)fw->data;
Lars-Peter Clausen48afc522011-11-28 09:44:18 +0100169 if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
170 dev_err(&client->dev, "Failed to load firmware: Invalid magic\n");
Mike Frysingere359dc22011-03-22 16:34:40 -0700171 goto done;
Lars-Peter Clausen48afc522011-11-28 09:44:18 +0100172 }
Mike Frysingere359dc22011-03-22 16:34:40 -0700173
Lars-Peter Clausenc56935b2011-11-28 09:44:15 +0100174 crc = crc32(0, fw->data + sizeof(*ssfw_head),
175 fw->size - sizeof(*ssfw_head));
Mike Frysingere359dc22011-03-22 16:34:40 -0700176 pr_debug("%s: crc=%x\n", __func__, crc);
Lars-Peter Clausen48afc522011-11-28 09:44:18 +0100177 if (crc != le32_to_cpu(ssfw_head->crc)) {
178 dev_err(&client->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
179 le32_to_cpu(ssfw_head->crc), crc);
Mike Frysingere359dc22011-03-22 16:34:40 -0700180 goto done;
Lars-Peter Clausen48afc522011-11-28 09:44:18 +0100181 }
Mike Frysingere359dc22011-03-22 16:34:40 -0700182
183 ssfw.pos = sizeof(*ssfw_head);
184
185 /* finally process all of the actions */
186 ret = process_sigma_actions(client, &ssfw);
187
188 done:
189 release_firmware(fw);
190
191 pr_debug("%s: loaded %s\n", __func__, name);
192
193 return ret;
194}
195EXPORT_SYMBOL(process_sigma_firmware);
Randy Dunlap27c46a22011-07-25 17:13:21 -0700196
197MODULE_LICENSE("GPL");