xref: /linux/drivers/dpll/zl3073x/fw.c (revision 55a42f78ffd386e01a5404419f8c5ded7db70a21)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #include <linux/array_size.h>
4 #include <linux/build_bug.h>
5 #include <linux/dev_printk.h>
6 #include <linux/err.h>
7 #include <linux/errno.h>
8 #include <linux/netlink.h>
9 #include <linux/slab.h>
10 #include <linux/string.h>
11 
12 #include "core.h"
13 #include "flash.h"
14 #include "fw.h"
15 
16 #define ZL3073X_FW_ERR_PFX "FW load failed: "
17 #define ZL3073X_FW_ERR_MSG(_extack, _msg, ...)				\
18 	NL_SET_ERR_MSG_FMT_MOD((_extack), ZL3073X_FW_ERR_PFX _msg,	\
19 			       ## __VA_ARGS__)
20 
21 enum zl3073x_flash_type {
22 	ZL3073X_FLASH_TYPE_NONE = 0,
23 	ZL3073X_FLASH_TYPE_SECTORS,
24 	ZL3073X_FLASH_TYPE_PAGE,
25 	ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
26 };
27 
28 struct zl3073x_fw_component_info {
29 	const char		*name;
30 	size_t			max_size;
31 	enum zl3073x_flash_type	flash_type;
32 	u32			load_addr;
33 	u32			dest_page;
34 	u32			copy_page;
35 };
36 
37 static const struct zl3073x_fw_component_info component_info[] = {
38 	[ZL_FW_COMPONENT_UTIL] = {
39 		.name		= "utility",
40 		.max_size	= 0x2300,
41 		.load_addr	= 0x20000000,
42 		.flash_type	= ZL3073X_FLASH_TYPE_NONE,
43 	},
44 	[ZL_FW_COMPONENT_FW1] = {
45 		.name		= "firmware1",
46 		.max_size	= 0x35000,
47 		.load_addr	= 0x20002000,
48 		.flash_type	= ZL3073X_FLASH_TYPE_SECTORS,
49 		.dest_page	= 0x020,
50 	},
51 	[ZL_FW_COMPONENT_FW2] = {
52 		.name		= "firmware2",
53 		.max_size	= 0x0040,
54 		.load_addr	= 0x20000000,
55 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
56 		.dest_page	= 0x3e0,
57 		.copy_page	= 0x000,
58 	},
59 	[ZL_FW_COMPONENT_FW3] = {
60 		.name		= "firmware3",
61 		.max_size	= 0x0248,
62 		.load_addr	= 0x20000400,
63 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE_AND_COPY,
64 		.dest_page	= 0x3e4,
65 		.copy_page	= 0x004,
66 	},
67 	[ZL_FW_COMPONENT_CFG0] = {
68 		.name		= "config0",
69 		.max_size	= 0x1000,
70 		.load_addr	= 0x20000000,
71 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE,
72 		.dest_page	= 0x3d0,
73 	},
74 	[ZL_FW_COMPONENT_CFG1] = {
75 		.name		= "config1",
76 		.max_size	= 0x1000,
77 		.load_addr	= 0x20000000,
78 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE,
79 		.dest_page	= 0x3c0,
80 	},
81 	[ZL_FW_COMPONENT_CFG2] = {
82 		.name		= "config2",
83 		.max_size	= 0x1000,
84 		.load_addr	= 0x20000000,
85 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE,
86 		.dest_page	= 0x3b0,
87 	},
88 	[ZL_FW_COMPONENT_CFG3] = {
89 		.name		= "config3",
90 		.max_size	= 0x1000,
91 		.load_addr	= 0x20000000,
92 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE,
93 		.dest_page	= 0x3a0,
94 	},
95 	[ZL_FW_COMPONENT_CFG4] = {
96 		.name		= "config4",
97 		.max_size	= 0x1000,
98 		.load_addr	= 0x20000000,
99 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE,
100 		.dest_page	= 0x390,
101 	},
102 	[ZL_FW_COMPONENT_CFG5] = {
103 		.name		= "config5",
104 		.max_size	= 0x1000,
105 		.load_addr	= 0x20000000,
106 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE,
107 		.dest_page	= 0x380,
108 	},
109 	[ZL_FW_COMPONENT_CFG6] = {
110 		.name		= "config6",
111 		.max_size	= 0x1000,
112 		.load_addr	= 0x20000000,
113 		.flash_type	= ZL3073X_FLASH_TYPE_PAGE,
114 		.dest_page	= 0x370,
115 	},
116 };
117 
118 /* Sanity check */
119 static_assert(ARRAY_SIZE(component_info) == ZL_FW_NUM_COMPONENTS);
120 
121 /**
122  * zl3073x_fw_component_alloc - Alloc structure to hold firmware component
123  * @size: size of buffer to store data
124  *
125  * Return: pointer to allocated component structure or NULL on error.
126  */
127 static struct zl3073x_fw_component *
128 zl3073x_fw_component_alloc(size_t size)
129 {
130 	struct zl3073x_fw_component *comp;
131 
132 	comp = kzalloc(sizeof(*comp), GFP_KERNEL);
133 	if (!comp)
134 		return NULL;
135 
136 	comp->size = size;
137 	comp->data = kzalloc(size, GFP_KERNEL);
138 	if (!comp->data) {
139 		kfree(comp);
140 		return NULL;
141 	}
142 
143 	return comp;
144 }
145 
146 /**
147  * zl3073x_fw_component_free - Free allocated component structure
148  * @comp: pointer to allocated component
149  */
150 static void
151 zl3073x_fw_component_free(struct zl3073x_fw_component *comp)
152 {
153 	if (comp)
154 		kfree(comp->data);
155 
156 	kfree(comp);
157 }
158 
159 /**
160  * zl3073x_fw_component_id_get - Get ID for firmware component name
161  * @name: input firmware component name
162  *
163  * Return:
164  * - ZL3073X_FW_COMPONENT_* ID for known component name
165  * - ZL3073X_FW_COMPONENT_INVALID if the given name is unknown
166  */
167 static enum zl3073x_fw_component_id
168 zl3073x_fw_component_id_get(const char *name)
169 {
170 	enum zl3073x_fw_component_id id;
171 
172 	for (id = 0; id < ZL_FW_NUM_COMPONENTS; id++)
173 		if (!strcasecmp(name, component_info[id].name))
174 			return id;
175 
176 	return ZL_FW_COMPONENT_INVALID;
177 }
178 
179 /**
180  * zl3073x_fw_component_load - Load component from firmware source
181  * @zldev: zl3073x device structure
182  * @pcomp: pointer to loaded component
183  * @psrc: data pointer to load component from
184  * @psize: remaining bytes in buffer
185  * @extack: netlink extack pointer to report errors
186  *
187  * The function allocates single firmware component and loads the data from
188  * the buffer specified by @psrc and @psize. Pointer to allocated component
189  * is stored in output @pcomp. Source data pointer @psrc and remaining bytes
190  * @psize are updated accordingly.
191  *
192  * Return:
193  * * 1 when component was allocated and loaded
194  * * 0 when there is no component to load
195  * * <0 on error
196  */
197 static ssize_t
198 zl3073x_fw_component_load(struct zl3073x_dev *zldev,
199 			  struct zl3073x_fw_component **pcomp,
200 			  const char **psrc, size_t *psize,
201 			  struct netlink_ext_ack *extack)
202 {
203 	const struct zl3073x_fw_component_info *info;
204 	struct zl3073x_fw_component *comp = NULL;
205 	struct device *dev = zldev->dev;
206 	enum zl3073x_fw_component_id id;
207 	char buf[32], name[16];
208 	u32 count, size, *dest;
209 	int pos, rc;
210 
211 	/* Fetch image name and size from input */
212 	strscpy(buf, *psrc, min(sizeof(buf), *psize));
213 	rc = sscanf(buf, "%15s %u %n", name, &count, &pos);
214 	if (!rc) {
215 		/* No more data */
216 		return 0;
217 	} else if (rc == 1 || count > U32_MAX / sizeof(u32)) {
218 		ZL3073X_FW_ERR_MSG(extack, "invalid component size");
219 		return -EINVAL;
220 	}
221 	*psrc += pos;
222 	*psize -= pos;
223 
224 	dev_dbg(dev, "Firmware component '%s' found\n", name);
225 
226 	id = zl3073x_fw_component_id_get(name);
227 	if (id == ZL_FW_COMPONENT_INVALID) {
228 		ZL3073X_FW_ERR_MSG(extack, "unknown component type '%s'", name);
229 		return -EINVAL;
230 	}
231 
232 	info = &component_info[id];
233 	size = count * sizeof(u32); /* get size in bytes */
234 
235 	/* Check image size validity */
236 	if (size > component_info[id].max_size) {
237 		ZL3073X_FW_ERR_MSG(extack,
238 				   "[%s] component is too big (%u bytes)\n",
239 				   info->name, size);
240 		return -EINVAL;
241 	}
242 
243 	dev_dbg(dev, "Indicated component image size: %u bytes\n", size);
244 
245 	/* Alloc component */
246 	comp = zl3073x_fw_component_alloc(size);
247 	if (!comp) {
248 		ZL3073X_FW_ERR_MSG(extack, "failed to alloc memory");
249 		return -ENOMEM;
250 	}
251 	comp->id = id;
252 
253 	/* Load component data from firmware source */
254 	for (dest = comp->data; count; count--, dest++) {
255 		strscpy(buf, *psrc, min(sizeof(buf), *psize));
256 		rc = sscanf(buf, "%x %n", dest, &pos);
257 		if (!rc)
258 			goto err_data;
259 
260 		*psrc += pos;
261 		*psize -= pos;
262 	}
263 
264 	*pcomp = comp;
265 
266 	return 1;
267 
268 err_data:
269 	ZL3073X_FW_ERR_MSG(extack, "[%s] invalid or missing data", info->name);
270 
271 	zl3073x_fw_component_free(comp);
272 
273 	return -ENODATA;
274 }
275 
276 /**
277  * zl3073x_fw_free - Free allocated firmware
278  * @fw: firmware pointer
279  *
280  * The function frees existing firmware allocated by @zl3073x_fw_load.
281  */
282 void zl3073x_fw_free(struct zl3073x_fw *fw)
283 {
284 	size_t i;
285 
286 	if (!fw)
287 		return;
288 
289 	for (i = 0; i < ZL_FW_NUM_COMPONENTS; i++)
290 		zl3073x_fw_component_free(fw->component[i]);
291 
292 	kfree(fw);
293 }
294 
295 /**
296  * zl3073x_fw_load - Load all components from source
297  * @zldev: zl3073x device structure
298  * @data: source buffer pointer
299  * @size: size of source buffer
300  * @extack: netlink extack pointer to report errors
301  *
302  * The functions allocate firmware structure and loads all components from
303  * the given buffer specified by @data and @size.
304  *
305  * Return: pointer to firmware on success, error pointer on error
306  */
307 struct zl3073x_fw *zl3073x_fw_load(struct zl3073x_dev *zldev, const char *data,
308 				   size_t size, struct netlink_ext_ack *extack)
309 {
310 	struct zl3073x_fw_component *comp;
311 	enum zl3073x_fw_component_id id;
312 	struct zl3073x_fw *fw;
313 	ssize_t rc;
314 
315 	/* Allocate firmware structure */
316 	fw = kzalloc(sizeof(*fw), GFP_KERNEL);
317 	if (!fw)
318 		return ERR_PTR(-ENOMEM);
319 
320 	do {
321 		/* Load single component */
322 		rc = zl3073x_fw_component_load(zldev, &comp, &data, &size,
323 					       extack);
324 		if (rc <= 0)
325 			/* Everything was read or error occurred */
326 			break;
327 
328 		id = comp->id;
329 
330 		/* Report error if the given component is present twice
331 		 * or more.
332 		 */
333 		if (fw->component[id]) {
334 			ZL3073X_FW_ERR_MSG(extack,
335 					   "duplicate component '%s' detected",
336 					   component_info[id].name);
337 			zl3073x_fw_component_free(comp);
338 			rc = -EINVAL;
339 			break;
340 		}
341 
342 		fw->component[id] = comp;
343 	} while (true);
344 
345 	if (rc) {
346 		/* Free allocated firmware in case of error */
347 		zl3073x_fw_free(fw);
348 		return ERR_PTR(rc);
349 	}
350 
351 	return fw;
352 }
353 
354 /**
355  * zl3073x_flash_bundle_flash - Flash all components
356  * @zldev: zl3073x device structure
357  * @components: pointer to components array
358  * @extack: netlink extack pointer to report errors
359  *
360  * Returns 0 in case of success or negative number otherwise.
361  */
362 static int
363 zl3073x_fw_component_flash(struct zl3073x_dev *zldev,
364 			   struct zl3073x_fw_component *comp,
365 			   struct netlink_ext_ack *extack)
366 {
367 	const struct zl3073x_fw_component_info *info;
368 	int rc;
369 
370 	info = &component_info[comp->id];
371 
372 	switch (info->flash_type) {
373 	case ZL3073X_FLASH_TYPE_NONE:
374 		/* Non-flashable component - used for utility */
375 		return 0;
376 	case ZL3073X_FLASH_TYPE_SECTORS:
377 		rc = zl3073x_flash_sectors(zldev, info->name, info->dest_page,
378 					   info->load_addr, comp->data,
379 					   comp->size, extack);
380 		break;
381 	case ZL3073X_FLASH_TYPE_PAGE:
382 		rc = zl3073x_flash_page(zldev, info->name, info->dest_page,
383 					info->load_addr, comp->data, comp->size,
384 					extack);
385 		break;
386 	case ZL3073X_FLASH_TYPE_PAGE_AND_COPY:
387 		rc = zl3073x_flash_page(zldev, info->name, info->dest_page,
388 					info->load_addr, comp->data, comp->size,
389 					extack);
390 		if (!rc)
391 			rc = zl3073x_flash_page_copy(zldev, info->name,
392 						     info->dest_page,
393 						     info->copy_page, extack);
394 		break;
395 	}
396 	if (rc)
397 		ZL3073X_FW_ERR_MSG(extack, "Failed to flash component '%s'",
398 				   info->name);
399 
400 	return rc;
401 }
402 
403 int zl3073x_fw_flash(struct zl3073x_dev *zldev, struct zl3073x_fw *zlfw,
404 		     struct netlink_ext_ack *extack)
405 {
406 	int i, rc = 0;
407 
408 	for (i = 0; i < ZL_FW_NUM_COMPONENTS; i++) {
409 		if (!zlfw->component[i])
410 			continue; /* Component is not present */
411 
412 		rc = zl3073x_fw_component_flash(zldev, zlfw->component[i],
413 						extack);
414 		if (rc)
415 			break;
416 	}
417 
418 	return rc;
419 }
420