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