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

Archive Download this file



interactive