xref: /openbmc/linux/drivers/media/usb/as102/as102_fw.c (revision 4e95bc26)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Abilis Systems Single DVB-T Receiver
4  * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
5  * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
6  */
7 #include <linux/kernel.h>
8 #include <linux/errno.h>
9 #include <linux/ctype.h>
10 #include <linux/delay.h>
11 #include <linux/firmware.h>
12 
13 #include "as102_drv.h"
14 #include "as102_fw.h"
15 
16 static const char as102_st_fw1[] = "as102_data1_st.hex";
17 static const char as102_st_fw2[] = "as102_data2_st.hex";
18 static const char as102_dt_fw1[] = "as102_data1_dt.hex";
19 static const char as102_dt_fw2[] = "as102_data2_dt.hex";
20 
21 static unsigned char atohx(unsigned char *dst, char *src)
22 {
23 	unsigned char value = 0;
24 
25 	char msb = tolower(*src) - '0';
26 	char lsb = tolower(*(src + 1)) - '0';
27 
28 	if (msb > 9)
29 		msb -= 7;
30 	if (lsb > 9)
31 		lsb -= 7;
32 
33 	*dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
34 	return value;
35 }
36 
37 /*
38  * Parse INTEL HEX firmware file to extract address and data.
39  */
40 static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
41 			  unsigned char *data, int *dataLength,
42 			  unsigned char *addr_has_changed) {
43 
44 	int count = 0;
45 	unsigned char *src, dst;
46 
47 	if (*fw_data++ != ':') {
48 		pr_err("invalid firmware file\n");
49 		return -EFAULT;
50 	}
51 
52 	/* locate end of line */
53 	for (src = fw_data; *src != '\n'; src += 2) {
54 		atohx(&dst, src);
55 		/* parse line to split addr / data */
56 		switch (count) {
57 		case 0:
58 			*dataLength = dst;
59 			break;
60 		case 1:
61 			addr[2] = dst;
62 			break;
63 		case 2:
64 			addr[3] = dst;
65 			break;
66 		case 3:
67 			/* check if data is an address */
68 			if (dst == 0x04)
69 				*addr_has_changed = 1;
70 			else
71 				*addr_has_changed = 0;
72 			break;
73 		case  4:
74 		case  5:
75 			if (*addr_has_changed)
76 				addr[(count - 4)] = dst;
77 			else
78 				data[(count - 4)] = dst;
79 			break;
80 		default:
81 			data[(count - 4)] = dst;
82 			break;
83 		}
84 		count++;
85 	}
86 
87 	/* return read value + ':' + '\n' */
88 	return (count * 2) + 2;
89 }
90 
91 static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
92 				 unsigned char *cmd,
93 				 const struct firmware *firmware) {
94 
95 	struct as10x_fw_pkt_t *fw_pkt;
96 	int total_read_bytes = 0, errno = 0;
97 	unsigned char addr_has_changed = 0;
98 
99 	fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL);
100 	if (!fw_pkt)
101 		return -ENOMEM;
102 
103 
104 	for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
105 		int read_bytes = 0, data_len = 0;
106 
107 		/* parse intel hex line */
108 		read_bytes = parse_hex_line(
109 				(u8 *) (firmware->data + total_read_bytes),
110 				fw_pkt->raw.address,
111 				fw_pkt->raw.data,
112 				&data_len,
113 				&addr_has_changed);
114 
115 		if (read_bytes <= 0)
116 			goto error;
117 
118 		/* detect the end of file */
119 		total_read_bytes += read_bytes;
120 		if (total_read_bytes == firmware->size) {
121 			fw_pkt->u.request[0] = 0x00;
122 			fw_pkt->u.request[1] = 0x03;
123 
124 			/* send EOF command */
125 			errno = bus_adap->ops->upload_fw_pkt(bus_adap,
126 							     (uint8_t *)
127 							     fw_pkt, 2, 0);
128 			if (errno < 0)
129 				goto error;
130 		} else {
131 			if (!addr_has_changed) {
132 				/* prepare command to send */
133 				fw_pkt->u.request[0] = 0x00;
134 				fw_pkt->u.request[1] = 0x01;
135 
136 				data_len += sizeof(fw_pkt->u.request);
137 				data_len += sizeof(fw_pkt->raw.address);
138 
139 				/* send cmd to device */
140 				errno = bus_adap->ops->upload_fw_pkt(bus_adap,
141 								     (uint8_t *)
142 								     fw_pkt,
143 								     data_len,
144 								     0);
145 				if (errno < 0)
146 					goto error;
147 			}
148 		}
149 	}
150 error:
151 	kfree(fw_pkt);
152 	return (errno == 0) ? total_read_bytes : errno;
153 }
154 
155 int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
156 {
157 	int errno = -EFAULT;
158 	const struct firmware *firmware = NULL;
159 	unsigned char *cmd_buf = NULL;
160 	const char *fw1, *fw2;
161 	struct usb_device *dev = bus_adap->usb_dev;
162 
163 	/* select fw file to upload */
164 	if (dual_tuner) {
165 		fw1 = as102_dt_fw1;
166 		fw2 = as102_dt_fw2;
167 	} else {
168 		fw1 = as102_st_fw1;
169 		fw2 = as102_st_fw2;
170 	}
171 
172 	/* allocate buffer to store firmware upload command and data */
173 	cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
174 	if (cmd_buf == NULL) {
175 		errno = -ENOMEM;
176 		goto error;
177 	}
178 
179 	/* request kernel to locate firmware file: part1 */
180 	errno = request_firmware(&firmware, fw1, &dev->dev);
181 	if (errno < 0) {
182 		pr_err("%s: unable to locate firmware file: %s\n",
183 		       DRIVER_NAME, fw1);
184 		goto error;
185 	}
186 
187 	/* initiate firmware upload */
188 	errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
189 	if (errno < 0) {
190 		pr_err("%s: error during firmware upload part1\n",
191 		       DRIVER_NAME);
192 		goto error;
193 	}
194 
195 	pr_info("%s: firmware: %s loaded with success\n",
196 		DRIVER_NAME, fw1);
197 	release_firmware(firmware);
198 	firmware = NULL;
199 
200 	/* wait for boot to complete */
201 	mdelay(100);
202 
203 	/* request kernel to locate firmware file: part2 */
204 	errno = request_firmware(&firmware, fw2, &dev->dev);
205 	if (errno < 0) {
206 		pr_err("%s: unable to locate firmware file: %s\n",
207 		       DRIVER_NAME, fw2);
208 		goto error;
209 	}
210 
211 	/* initiate firmware upload */
212 	errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
213 	if (errno < 0) {
214 		pr_err("%s: error during firmware upload part2\n",
215 		       DRIVER_NAME);
216 		goto error;
217 	}
218 
219 	pr_info("%s: firmware: %s loaded with success\n",
220 		DRIVER_NAME, fw2);
221 error:
222 	kfree(cmd_buf);
223 	release_firmware(firmware);
224 
225 	return errno;
226 }
227