1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include <linux/delay.h>
30#include <linux/device.h>
31#include <linux/firmware.h>
32#include <linux/usb/wusb.h>
33#include "i1480-dfu.h"
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51static
52int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size)
53{
54 int result;
55 struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf;
56 struct i1480_evt_confirm *reply = i1480->evt_buf;
57
58 BUG_ON(size > 480);
59 result = -ENOMEM;
60 cmd->rccb.bCommandType = i1480_CET_VS1;
61 cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE);
62 cmd->size = cpu_to_le16(size);
63 memcpy(cmd->data, data, size);
64 reply->rceb.bEventType = i1480_CET_VS1;
65 reply->rceb.wEvent = i1480_CMD_MPI_WRITE;
66 result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply));
67 if (result < 0)
68 goto out;
69 if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
70 dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n",
71 reply->bResultCode);
72 result = -EIO;
73 }
74out:
75 return result;
76}
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99static
100int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size)
101{
102 int result;
103 struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf;
104 struct i1480_evt_mpi_read *reply = i1480->evt_buf;
105 unsigned cnt;
106
107 memset(i1480->cmd_buf, 0x69, 512);
108 memset(i1480->evt_buf, 0x69, 512);
109
110 BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3);
111 result = -ENOMEM;
112 cmd->rccb.bCommandType = i1480_CET_VS1;
113 cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ);
114 cmd->size = cpu_to_le16(3*size);
115 for (cnt = 0; cnt < size; cnt++) {
116 cmd->data[cnt].page = (srcaddr + cnt) >> 8;
117 cmd->data[cnt].offset = (srcaddr + cnt) & 0xff;
118 }
119 reply->rceb.bEventType = i1480_CET_VS1;
120 reply->rceb.wEvent = i1480_CMD_MPI_READ;
121 result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size,
122 sizeof(*reply) + 3*size);
123 if (result < 0)
124 goto out;
125 if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
126 dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n",
127 reply->bResultCode);
128 result = -EIO;
129 }
130 for (cnt = 0; cnt < size; cnt++) {
131 if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
132 dev_err(i1480->dev, "MPI-READ: page inconsistency at "
133 "index %u: expected 0x%02x, got 0x%02x\n", cnt,
134 (srcaddr + cnt) >> 8, reply->data[cnt].page);
135 if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
136 dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
137 "index %u: expected 0x%02x, got 0x%02x\n", cnt,
138 (srcaddr + cnt) & 0x00ff,
139 reply->data[cnt].offset);
140 data[cnt] = reply->data[cnt].value;
141 }
142 result = 0;
143out:
144 return result;
145}
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162int i1480_phy_fw_upload(struct i1480 *i1480)
163{
164 int result;
165 const struct firmware *fw;
166 const char *data_itr, *data_top;
167 const size_t MAX_BLK_SIZE = 480;
168 size_t data_size;
169 u8 phy_stat;
170
171 result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
172 if (result < 0)
173 goto out;
174
175 for (data_itr = fw->data, data_top = data_itr + fw->size;
176 data_itr < data_top; data_itr += MAX_BLK_SIZE) {
177 data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
178 result = i1480_mpi_write(i1480, data_itr, data_size);
179 if (result < 0)
180 goto error_mpi_write;
181 }
182
183 result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
184 if (result < 0) {
185 dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
186 goto error_mpi_status;
187 }
188 if (phy_stat != 0) {
189 result = -ENODEV;
190 dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
191 goto error_phy_status;
192 }
193 dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
194error_phy_status:
195error_mpi_status:
196error_mpi_write:
197 release_firmware(fw);
198 if (result < 0)
199 dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
200 "power cycle device\n", i1480->phy_fw_name, result);
201out:
202 return result;
203}
204