Root/usbboot/src/ingenic_usb.c

1/*
2 * Copyright(C) 2009 Qi Hardware Inc.,
3 * Authors: Xiangfu Liu <xiangfu@sharism.cc>
4 * Marek Lindner <lindner_marek@yahoo.de>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <stdio.h>
21#include <string.h>
22#include <usb.h>
23#include "usb_boot_defines.h"
24#include "ingenic_usb.h"
25#include "ingenic_request.h"
26
27extern unsigned int total_size;
28
29static int get_ingenic_device(struct ingenic_dev *id)
30{
31    struct usb_bus *ub, *usb_bus;
32    struct usb_device *usb_dev;
33    int count = 0;
34
35    ub = usb_get_busses();
36
37    for (usb_bus = ub; usb_bus != NULL; usb_bus = usb_bus->next) {
38        for (usb_dev = usb_bus->devices; usb_dev != NULL;
39             usb_dev = usb_dev->next) {
40
41            if ((usb_dev->descriptor.idVendor == VENDOR_ID) &&
42                (usb_dev->descriptor.idProduct == PRODUCT_ID_4740 ||
43                usb_dev->descriptor.idProduct == PRODUCT_ID_4760)) {
44                id->usb_dev = usb_dev;
45                count++;
46            }
47
48        }
49    }
50
51    return count;
52}
53
54static int get_ingenic_interface(struct ingenic_dev *id)
55{
56    struct usb_config_descriptor *usb_config_desc;
57    struct usb_interface_descriptor *usb_if_desc;
58    struct usb_interface *usb_if;
59    int config_index, if_index, alt_index;
60
61    for (config_index = 0;
62         config_index < id->usb_dev->descriptor.bNumConfigurations;
63         config_index++) {
64        usb_config_desc = &id->usb_dev->config[config_index];
65
66        if (!usb_config_desc)
67            return 0;
68
69        for (if_index = 0; if_index < usb_config_desc->bNumInterfaces;
70             if_index++) {
71            usb_if = &usb_config_desc->interface[if_index];
72
73            if (!usb_if)
74                return 0;
75
76            for (alt_index = 0; alt_index < usb_if->num_altsetting;
77                 alt_index++) {
78                usb_if_desc = &usb_if->altsetting[alt_index];
79
80                if (!usb_if_desc)
81                    return 0;
82
83                if ((usb_if_desc->bInterfaceClass == 0xff) &&
84                    (usb_if_desc->bInterfaceSubClass == 0)) {
85                    id->interface =
86                        usb_if_desc->bInterfaceNumber;
87                    return 1;
88                }
89            }
90        }
91    }
92
93    return 0;
94}
95
96int usb_ingenic_init(struct ingenic_dev *id)
97{
98    int num_ingenic, status = -1;
99
100    memset(id, 0, sizeof(struct ingenic_dev));
101
102    usb_init();
103     /* usb_set_debug(255); */
104    usb_find_busses();
105    usb_find_devices();
106
107    num_ingenic = get_ingenic_device(id);
108
109    if (num_ingenic == 0) {
110        fprintf(stderr, "Error - no XBurst device found\n");
111        goto out;
112    }
113
114    if (num_ingenic > 1) {
115        fprintf(stderr, "Error - too many XBurst devices found: %i\n",
116            num_ingenic);
117        goto out;
118    }
119
120    id->usb_handle = usb_open(id->usb_dev);
121    if (!id->usb_handle) {
122        fprintf(stderr, "Error - can't open XBurst device: %s\n",
123            usb_strerror());
124        goto out;
125    }
126
127    if (get_ingenic_interface(id) < 1) {
128        fprintf(stderr, "Error - can't find XBurst interface\n");
129        goto out;
130    }
131
132    if (usb_claim_interface(id->usb_handle, id->interface)
133        < 0) {
134        fprintf(stderr, "Error - can't claim XBurst interface: %s\n",
135            usb_strerror());
136        goto out;
137    }
138
139    status = 1;
140
141out:
142    return status;
143}
144
145int usb_get_ingenic_cpu(struct ingenic_dev *id)
146{
147    int status;
148
149    memset(&id->cpu_info_buff, 0,
150           ARRAY_SIZE(id->cpu_info_buff));
151
152    sleep(1);
153    status = usb_control_msg(id->usb_handle,
154      /* bmRequestType */ USB_ENDPOINT_IN | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
155      /* bRequest */ VR_GET_CPU_INFO,
156      /* wValue */ 0,
157      /* wIndex */ 0,
158      /* Data */ id->cpu_info_buff,
159      /* wLength */ 8,
160                  USB_TIMEOUT);
161
162    if (status != sizeof(id->cpu_info_buff) - 1 ) {
163        fprintf(stderr, "Error - "
164            "can't retrieve XBurst CPU information: %i\n", status);
165        return status;
166    }
167
168    id->cpu_info_buff[8] = '\0';
169    printf(" CPU data: %s\n", id->cpu_info_buff);
170
171    if (!strcmp(id->cpu_info_buff,"JZ4740V1")) return JZ4740V1;
172    if (!strcmp(id->cpu_info_buff,"JZ4750V1")) return JZ4750V1;
173    if (!strcmp(id->cpu_info_buff,"JZ4760V1")) return JZ4760V1;
174    if (!strcmp(id->cpu_info_buff,"Boot4740")) return BOOT4740;
175    if (!strcmp(id->cpu_info_buff,"Boot4750")) return BOOT4750;
176    if (!strcmp(id->cpu_info_buff,"Boot4760")) return BOOT4760;
177
178    return -1;
179}
180
181int usb_ingenic_flush_cache(struct ingenic_dev *id)
182{
183    int status;
184
185    status = usb_control_msg(id->usb_handle,
186      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
187      /* bRequest */ VR_FLUSH_CACHES,
188      /* wValue */ 0,
189      /* wIndex */ 0,
190      /* Data */ 0,
191      /* wLength */ 0,
192                  USB_TIMEOUT);
193
194    if (status != 0) {
195        fprintf(stderr, "Error - can't flush cache: %i\n", status);
196        return status;
197    }
198
199    return 1;
200}
201
202int usb_send_data_length_to_ingenic(struct ingenic_dev *id, int len)
203{
204    int status;
205    /* tell the device the length of the file to be uploaded */
206    status = usb_control_msg(id->usb_handle,
207      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
208      /* bRequest */ VR_SET_DATA_LENGTH,
209      /* wValue */ STAGE_ADDR_MSB(len),
210      /* wIndex */ STAGE_ADDR_LSB(len),
211      /* Data */ 0,
212      /* wLength */ 0,
213                  USB_TIMEOUT);
214
215    if (status != 0) {
216        fprintf(stderr, "Error - "
217            "can't set data length on Ingenic device: %i\n", status);
218        return -1;
219    }
220
221    return 1;
222}
223
224int usb_send_data_address_to_ingenic(struct ingenic_dev *id,
225                     unsigned int stage_addr)
226{
227    int status;
228    /* tell the device the RAM address to store the file */
229    status = usb_control_msg(id->usb_handle,
230      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
231      /* bRequest */ VR_SET_DATA_ADDRESS,
232      /* wValue */ STAGE_ADDR_MSB(stage_addr),
233      /* wIndex */ STAGE_ADDR_LSB(stage_addr),
234      /* Data */ 0,
235      /* wLength */ 0,
236                  USB_TIMEOUT);
237
238    if (status != 0) {
239        fprintf(stderr, "Error - "
240            "can't set the address on Ingenic device: %i\n", status);
241        return -1;
242    }
243
244    return 1;
245}
246
247int usb_send_data_to_ingenic(struct ingenic_dev *id)
248{
249    int status;
250    status = usb_bulk_write(id->usb_handle,
251    /* endpoint */ INGENIC_OUT_ENDPOINT,
252    /* bulk data */ (char *)id->file_buff,
253    /* bulk data length */ id->file_len,
254                   USB_TIMEOUT);
255    if (status < (int)id->file_len) {
256        fprintf(stderr, "Error - "
257            "can't send bulk data to Ingenic CPU: %i %s\n", status, usb_strerror());
258        return -1;
259    }
260
261    return 1;
262}
263
264int usb_read_data_from_ingenic(struct ingenic_dev *id,
265                   unsigned char *buff, unsigned int len)
266{
267    int status;
268    status = usb_bulk_read(id->usb_handle,
269    /* endpoint */ INGENIC_IN_ENDPOINT,
270    /* bulk data */ (char *)buff,
271    /* bulk data length */ len,
272                   USB_TIMEOUT);
273
274    if (status < (int)len) {
275        fprintf(stderr, "Error - "
276            "can't read bulk data from Ingenic device:%i\n", status);
277        return -1;
278    }
279
280    return 1;
281}
282
283int usb_ingenic_start(struct ingenic_dev *id, int rqst, unsigned int stage_addr)
284{
285    int status;
286
287    /* tell the device to start the uploaded device */
288    status = usb_control_msg(id->usb_handle,
289      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
290      /* bRequest */ rqst,
291      /* wValue */ STAGE_ADDR_MSB(stage_addr),
292      /* wIndex */ STAGE_ADDR_LSB(stage_addr),
293      /* Data */ 0,
294      /* wLength */ 0,
295                  USB_TIMEOUT);
296
297    if (status != 0) {
298        fprintf(stderr, "Error - can't start the uploaded binary "
299            "on the Ingenic device: %i\n", status);
300        return status;
301    }
302    return 1;
303}
304
305int usb_ingenic_upload(struct ingenic_dev *id, int stage)
306{
307    unsigned int stage_addr;
308    unsigned int stage2_addr;
309    int rqst = VR_PROGRAM_START1;
310
311    stage2_addr = 0x80000000 + total_size - CODE_SIZE;
312    stage_addr = (stage == 1 ? 0x80002000 : stage2_addr);
313
314    usb_send_data_address_to_ingenic(id, stage_addr);
315    printf(" Download stage %d program and execute at 0x%08x\n",
316           stage, (stage_addr));
317    usb_send_data_to_ingenic(id);
318
319    if (stage == 2) {
320        if (usb_get_ingenic_cpu(id) < 1)
321            return -1;
322        usb_ingenic_flush_cache(id);
323        rqst = VR_PROGRAM_START2;
324    }
325
326    usleep(100);
327    if (usb_ingenic_start(id, rqst, stage_addr) < 1)
328        return -1;
329    usleep(100);
330    if (usb_get_ingenic_cpu(id) < 1)
331        return -1;
332
333    return 1;
334}
335
336void usb_ingenic_cleanup(struct ingenic_dev *id)
337{
338    if ((id->usb_handle) && (id->interface))
339        usb_release_interface(id->usb_handle,
340                      id->interface);
341
342    if (id->usb_handle)
343        usb_close(id->usb_handle);
344}
345
346int usb_ingenic_nand_ops(struct ingenic_dev *id, int ops)
347{
348    int status;
349    status = usb_control_msg(id->usb_handle,
350      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
351      /* bRequest */ VR_NAND_OPS,
352      /* wValue */ ops & 0xffff,
353      /* wIndex */ 0,
354      /* Data */ 0,
355      /* wLength */ 0,
356                  USB_TIMEOUT);
357
358    if (status != 0) {
359        fprintf(stderr, "Error - "
360            "can't set Ingenic device nand ops: %i\n", status);
361        return -1;
362    }
363
364    return 1;
365}
366
367int usb_ingenic_configration(struct ingenic_dev *id, int ops)
368{
369    int status;
370    status = usb_control_msg(id->usb_handle,
371      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
372      /* bRequest */ VR_CONFIGRATION,
373      /* wValue */ ops,
374      /* wIndex */ 0,
375      /* Data */ 0,
376      /* wLength */ 0,
377                  USB_TIMEOUT);
378
379    if (status != 0) {
380        fprintf(stderr, "Error - "
381            "can't init Ingenic configration: %i\n", status);
382        return -1;
383    }
384
385    return 1;
386}
387
388int usb_ingenic_sdram_ops(struct ingenic_dev *id, int ops)
389{
390    int status;
391    status = usb_control_msg(id->usb_handle,
392      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
393      /* bRequest */ VR_SDRAM_OPS,
394      /* wValue */ ops,
395      /* wIndex */ 0,
396      /* Data */ 0,
397      /* wLength */ 0,
398                  USB_TIMEOUT);
399
400    if (status != 0) {
401        fprintf(stderr, "Error - "
402            "Device can't load file to sdram: %i\n", status);
403        return -1;
404    }
405
406    return 1;
407}
408
409int usb_ingenic_reset(struct ingenic_dev *id, int ops)
410{
411    int status;
412    status = usb_control_msg(id->usb_handle,
413      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
414      /* bRequest */ VR_RESET,
415      /* wValue */ ops,
416      /* wIndex */ 0,
417      /* Data */ 0,
418      /* wLength */ 0,
419                  USB_TIMEOUT);
420
421    if (status != 0) {
422        fprintf(stderr, "Error - "
423            "reset XBurst device: %i\n", status);
424        return -1;
425    }
426
427    return 1;
428}
429

Archive Download this file



interactive