GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / net / phy / aquantia / aquantia_firmware.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/bitfield.h>
4 #include <linux/of.h>
5 #include <linux/firmware.h>
6 #include <linux/crc-itu-t.h>
7 #include <linux/nvmem-consumer.h>
8
9 #include <asm/unaligned.h>
10
11 #include "aquantia.h"
12
13 #define UP_RESET_SLEEP          100
14
15 /* addresses of memory segments in the phy */
16 #define DRAM_BASE_ADDR          0x3FFE0000
17 #define IRAM_BASE_ADDR          0x40000000
18
19 /* firmware image format constants */
20 #define VERSION_STRING_SIZE             0x40
21 #define VERSION_STRING_OFFSET           0x0200
22 /* primary offset is written at an offset from the start of the fw blob */
23 #define PRIMARY_OFFSET_OFFSET           0x8
24 /* primary offset needs to be then added to a base offset */
25 #define PRIMARY_OFFSET_SHIFT            12
26 #define PRIMARY_OFFSET(x)               ((x) << PRIMARY_OFFSET_SHIFT)
27 #define HEADER_OFFSET                   0x300
28
29 struct aqr_fw_header {
30         u32 padding;
31         u8 iram_offset[3];
32         u8 iram_size[3];
33         u8 dram_offset[3];
34         u8 dram_size[3];
35 } __packed;
36
37 enum aqr_fw_src {
38         AQR_FW_SRC_NVMEM = 0,
39         AQR_FW_SRC_FS,
40 };
41
42 static const char * const aqr_fw_src_string[] = {
43         [AQR_FW_SRC_NVMEM] = "NVMEM",
44         [AQR_FW_SRC_FS] = "FS",
45 };
46
47 /* AQR firmware doesn't have fixed offsets for iram and dram section
48  * but instead provide an header with the offset to use on reading
49  * and parsing the firmware.
50  *
51  * AQR firmware can't be trusted and each offset is validated to be
52  * not negative and be in the size of the firmware itself.
53  */
54 static bool aqr_fw_validate_get(size_t size, size_t offset, size_t get_size)
55 {
56         return offset + get_size <= size;
57 }
58
59 static int aqr_fw_get_be16(const u8 *data, size_t offset, size_t size, u16 *value)
60 {
61         if (!aqr_fw_validate_get(size, offset, sizeof(u16)))
62                 return -EINVAL;
63
64         *value = get_unaligned_be16(data + offset);
65
66         return 0;
67 }
68
69 static int aqr_fw_get_le16(const u8 *data, size_t offset, size_t size, u16 *value)
70 {
71         if (!aqr_fw_validate_get(size, offset, sizeof(u16)))
72                 return -EINVAL;
73
74         *value = get_unaligned_le16(data + offset);
75
76         return 0;
77 }
78
79 static int aqr_fw_get_le24(const u8 *data, size_t offset, size_t size, u32 *value)
80 {
81         if (!aqr_fw_validate_get(size, offset, sizeof(u8) * 3))
82                 return -EINVAL;
83
84         *value = get_unaligned_le24(data + offset);
85
86         return 0;
87 }
88
89 /* load data into the phy's memory */
90 static int aqr_fw_load_memory(struct phy_device *phydev, u32 addr,
91                               const u8 *data, size_t len)
92 {
93         u16 crc = 0, up_crc;
94         size_t pos;
95
96         phy_write_mmd(phydev, MDIO_MMD_VEND1,
97                       VEND1_GLOBAL_MAILBOX_INTERFACE1,
98                       VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET);
99         phy_write_mmd(phydev, MDIO_MMD_VEND1,
100                       VEND1_GLOBAL_MAILBOX_INTERFACE3,
101                       VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR(addr));
102         phy_write_mmd(phydev, MDIO_MMD_VEND1,
103                       VEND1_GLOBAL_MAILBOX_INTERFACE4,
104                       VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR(addr));
105
106         /* We assume and enforce the size to be word aligned.
107          * If a firmware that is not word aligned is found, please report upstream.
108          */
109         for (pos = 0; pos < len; pos += sizeof(u32)) {
110                 u8 crc_data[4];
111                 u32 word;
112
113                 /* FW data is always stored in little-endian */
114                 word = get_unaligned_le32((const u32 *)(data + pos));
115
116                 phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE5,
117                               VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(word));
118                 phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE6,
119                               VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(word));
120
121                 phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE1,
122                               VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE |
123                               VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE);
124
125                 /* Word is swapped internally and MAILBOX CRC is calculated
126                  * using big-endian order. Mimic what the PHY does to have a
127                  * matching CRC...
128                  */
129                 crc_data[0] = word >> 24;
130                 crc_data[1] = word >> 16;
131                 crc_data[2] = word >> 8;
132                 crc_data[3] = word;
133
134                 /* ...calculate CRC as we load data... */
135                 crc = crc_itu_t(crc, crc_data, sizeof(crc_data));
136         }
137         /* ...gets CRC from MAILBOX after we have loaded the entire section... */
138         up_crc = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE2);
139         /* ...and make sure it does match our calculated CRC */
140         if (crc != up_crc) {
141                 phydev_err(phydev, "CRC mismatch: calculated 0x%04x PHY 0x%04x\n",
142                            crc, up_crc);
143                 return -EINVAL;
144         }
145
146         return 0;
147 }
148
149 static int aqr_fw_boot(struct phy_device *phydev, const u8 *data, size_t size,
150                        enum aqr_fw_src fw_src)
151 {
152         u16 calculated_crc, read_crc, read_primary_offset;
153         u32 iram_offset = 0, iram_size = 0;
154         u32 dram_offset = 0, dram_size = 0;
155         char version[VERSION_STRING_SIZE];
156         u32 primary_offset = 0;
157         int ret;
158
159         /* extract saved CRC at the end of the fw
160          * CRC is saved in big-endian as PHY is BE
161          */
162         ret = aqr_fw_get_be16(data, size - sizeof(u16), size, &read_crc);
163         if (ret) {
164                 phydev_err(phydev, "bad firmware CRC in firmware\n");
165                 return ret;
166         }
167         calculated_crc = crc_itu_t(0, data, size - sizeof(u16));
168         if (read_crc != calculated_crc) {
169                 phydev_err(phydev, "bad firmware CRC: file 0x%04x calculated 0x%04x\n",
170                            read_crc, calculated_crc);
171                 return -EINVAL;
172         }
173
174         /* Get the primary offset to extract DRAM and IRAM sections. */
175         ret = aqr_fw_get_le16(data, PRIMARY_OFFSET_OFFSET, size, &read_primary_offset);
176         if (ret) {
177                 phydev_err(phydev, "bad primary offset in firmware\n");
178                 return ret;
179         }
180         primary_offset = PRIMARY_OFFSET(read_primary_offset);
181
182         /* Find the DRAM and IRAM sections within the firmware file.
183          * Make sure the fw_header is correctly in the firmware.
184          */
185         if (!aqr_fw_validate_get(size, primary_offset + HEADER_OFFSET,
186                                  sizeof(struct aqr_fw_header))) {
187                 phydev_err(phydev, "bad fw_header in firmware\n");
188                 return -EINVAL;
189         }
190
191         /* offset are in LE and values needs to be converted to cpu endian */
192         ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
193                               offsetof(struct aqr_fw_header, iram_offset),
194                               size, &iram_offset);
195         if (ret) {
196                 phydev_err(phydev, "bad iram offset in firmware\n");
197                 return ret;
198         }
199         ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
200                               offsetof(struct aqr_fw_header, iram_size),
201                               size, &iram_size);
202         if (ret) {
203                 phydev_err(phydev, "invalid iram size in firmware\n");
204                 return ret;
205         }
206         ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
207                               offsetof(struct aqr_fw_header, dram_offset),
208                               size, &dram_offset);
209         if (ret) {
210                 phydev_err(phydev, "bad dram offset in firmware\n");
211                 return ret;
212         }
213         ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
214                               offsetof(struct aqr_fw_header, dram_size),
215                               size, &dram_size);
216         if (ret) {
217                 phydev_err(phydev, "invalid dram size in firmware\n");
218                 return ret;
219         }
220
221         /* Increment the offset with the primary offset.
222          * Validate iram/dram offset and size.
223          */
224         iram_offset += primary_offset;
225         if (iram_size % sizeof(u32)) {
226                 phydev_err(phydev, "iram size if not aligned to word size. Please report this upstream!\n");
227                 return -EINVAL;
228         }
229         if (!aqr_fw_validate_get(size, iram_offset, iram_size)) {
230                 phydev_err(phydev, "invalid iram offset for iram size\n");
231                 return -EINVAL;
232         }
233
234         dram_offset += primary_offset;
235         if (dram_size % sizeof(u32)) {
236                 phydev_err(phydev, "dram size if not aligned to word size. Please report this upstream!\n");
237                 return -EINVAL;
238         }
239         if (!aqr_fw_validate_get(size, dram_offset, dram_size)) {
240                 phydev_err(phydev, "invalid iram offset for iram size\n");
241                 return -EINVAL;
242         }
243
244         phydev_dbg(phydev, "primary %d IRAM offset=%d size=%d DRAM offset=%d size=%d\n",
245                    primary_offset, iram_offset, iram_size, dram_offset, dram_size);
246
247         if (!aqr_fw_validate_get(size, dram_offset + VERSION_STRING_OFFSET,
248                                  VERSION_STRING_SIZE)) {
249                 phydev_err(phydev, "invalid version in firmware\n");
250                 return -EINVAL;
251         }
252         strscpy(version, (char *)data + dram_offset + VERSION_STRING_OFFSET,
253                 VERSION_STRING_SIZE);
254         if (version[0] == '\0') {
255                 phydev_err(phydev, "invalid version in firmware\n");
256                 return -EINVAL;
257         }
258         phydev_info(phydev, "loading firmware version '%s' from '%s'\n", version,
259                     aqr_fw_src_string[fw_src]);
260
261         /* stall the microcprocessor */
262         phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
263                       VEND1_GLOBAL_CONTROL2_UP_RUN_STALL | VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD);
264
265         phydev_dbg(phydev, "loading DRAM 0x%08x from offset=%d size=%d\n",
266                    DRAM_BASE_ADDR, dram_offset, dram_size);
267         ret = aqr_fw_load_memory(phydev, DRAM_BASE_ADDR, data + dram_offset,
268                                  dram_size);
269         if (ret)
270                 return ret;
271
272         phydev_dbg(phydev, "loading IRAM 0x%08x from offset=%d size=%d\n",
273                    IRAM_BASE_ADDR, iram_offset, iram_size);
274         ret = aqr_fw_load_memory(phydev, IRAM_BASE_ADDR, data + iram_offset,
275                                  iram_size);
276         if (ret)
277                 return ret;
278
279         /* make sure soft reset and low power mode are clear */
280         phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_SC,
281                            VEND1_GLOBAL_SC_SOFT_RESET | VEND1_GLOBAL_SC_LOW_POWER);
282
283         /* Release the microprocessor. UP_RESET must be held for 100 usec. */
284         phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
285                       VEND1_GLOBAL_CONTROL2_UP_RUN_STALL |
286                       VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD |
287                       VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_RST);
288         usleep_range(UP_RESET_SLEEP, UP_RESET_SLEEP * 2);
289
290         phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
291                       VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD);
292
293         return 0;
294 }
295
296 static int aqr_firmware_load_nvmem(struct phy_device *phydev)
297 {
298         struct nvmem_cell *cell;
299         size_t size;
300         u8 *buf;
301         int ret;
302
303         cell = nvmem_cell_get(&phydev->mdio.dev, "firmware");
304         if (IS_ERR(cell))
305                 return PTR_ERR(cell);
306
307         buf = nvmem_cell_read(cell, &size);
308         if (IS_ERR(buf)) {
309                 ret = PTR_ERR(buf);
310                 goto exit;
311         }
312
313         ret = aqr_fw_boot(phydev, buf, size, AQR_FW_SRC_NVMEM);
314         if (ret)
315                 phydev_err(phydev, "firmware loading failed: %d\n", ret);
316
317         kfree(buf);
318 exit:
319         nvmem_cell_put(cell);
320
321         return ret;
322 }
323
324 static int aqr_firmware_load_fs(struct phy_device *phydev)
325 {
326         struct device *dev = &phydev->mdio.dev;
327         const struct firmware *fw;
328         const char *fw_name;
329         int ret;
330
331         ret = of_property_read_string(dev->of_node, "firmware-name",
332                                       &fw_name);
333         if (ret)
334                 return ret;
335
336         ret = reject_firmware(&fw, fw_name, dev);
337         if (ret) {
338                 phydev_err(phydev, "failed to find FW file %s (%d)\n",
339                            fw_name, ret);
340                 return ret;
341         }
342
343         ret = aqr_fw_boot(phydev, fw->data, fw->size, AQR_FW_SRC_FS);
344         if (ret)
345                 phydev_err(phydev, "firmware loading failed: %d\n", ret);
346
347         release_firmware(fw);
348
349         return ret;
350 }
351
352 int aqr_firmware_load(struct phy_device *phydev)
353 {
354         int ret;
355
356         /* Check if the firmware is not already loaded by pooling
357          * the current version returned by the PHY. If 0 is returned,
358          * no firmware is loaded.
359          */
360         ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID);
361         if (ret > 0)
362                 goto exit;
363
364         ret = aqr_firmware_load_nvmem(phydev);
365         if (!ret)
366                 goto exit;
367
368         ret = aqr_firmware_load_fs(phydev);
369         if (ret)
370                 return ret;
371
372 exit:
373         return 0;
374 }