Root/usbboot/src/ingenic_usb.c

1/*
2 * Copyright(C) 2009 Qi Hardware Inc.,
3 * Authors: Xiangfu Liu <xiangfu@qi-hardware.com>
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)) {
42                ingenic_dev->usb_dev = usb_dev;
43                count++;
44                break;
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 -1;
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 -1;
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 -1;
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 0;
87                }
88            }
89        }
90    }
91
92    return 0;
93}
94
95int usb_ingenic_init(struct ingenic_dev *ingenic_dev)
96{
97    int num_ingenic;
98    int ret = -1;
99
100    memset(ingenic_dev, 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(ingenic_dev);
108
109    if (num_ingenic == 0) {
110        fprintf(stderr, "Error - no XBurst device found\n");
111        goto err;
112    }
113
114    if (num_ingenic > 1) {
115        fprintf(stderr, "Error - too many XBurst devices found: %d\n",
116            num_ingenic);
117        goto err;
118    }
119
120    ingenic_dev->usb_handle = usb_open(ingenic_dev->usb_dev);
121    if (!ingenic_dev->usb_handle) {
122        fprintf(stderr, "Error - can't open XBurst device: %s\n",
123            usb_strerror());
124        goto err;
125    }
126
127    ret = get_ingenic_interface(ingenic_dev);
128    if (ret < 0) {
129        fprintf(stderr, "Error - can't find XBurst interface\n");
130        goto err;
131    }
132
133    ret = usb_claim_interface(ingenic_dev->usb_handle, ingenic_dev->interface);
134    if (ret < 0) {
135        fprintf(stderr, "Error - can't claim XBurst interface: %s\n",
136            usb_strerror());
137        goto err;
138    }
139
140    return 0;
141err:
142    return ret;
143}
144
145int usb_get_ingenic_cpu(struct ingenic_dev *ingenic_dev)
146{
147    int ret;
148    char buf[9];
149
150    sleep(1);
151    ret = usb_control_msg(ingenic_dev->usb_handle,
152      /* bmRequestType */ USB_ENDPOINT_IN | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
153      /* bRequest */ VR_GET_CPU_INFO,
154      /* wValue */ 0,
155      /* wIndex */ 0,
156      /* Data */ buf,
157      /* wLength */ 8,
158                  USB_TIMEOUT);
159
160    if (ret != 8) {
161        fprintf(stderr, "Error - "
162            "can't retrieve XBurst CPU information: %d\n", ret);
163        return ret;
164    }
165
166    buf[8] = '\0';
167    printf(" CPU data: %s\n", buf);
168
169    if (!strcmp(buf, "JZ4740V1"))
170        return INGENIC_CPU_JZ4740V1;
171    if (!strcmp(buf, "JZ4750V1"))
172        return INGENIC_CPU_JZ4750V1;
173    if (!strcmp(buf, "Boot4740"))
174        return INGENIC_CPU_JZ4740;
175    if (!strcmp(buf, "Boot4750"))
176        return INGENIC_CPU_JZ4750;
177
178    return INGENIC_CPU_UNKOWN;
179}
180
181int usb_send_data_to_ingenic(struct ingenic_dev *ingenic_dev, const char *data,
182                             int size)
183{
184    int ret;
185    ret = usb_bulk_write(ingenic_dev->usb_handle,
186    /* endpoint */ INGENIC_OUT_ENDPOINT,
187    /* bulk data */ data,
188    /* bulk data length */ size,
189                USB_TIMEOUT);
190
191    if (ret < 0) {
192        fprintf(stderr, "Error - "
193            "Can't send bulk data to Ingenic CPU: %d\n", ret);
194        return ret;
195    }
196
197    return size;
198}
199
200int usb_read_data_from_ingenic(struct ingenic_dev *ingenic_dev,
201                   char *data, int size)
202{
203    int ret;
204    ret = usb_bulk_read(ingenic_dev->usb_handle,
205    /* endpoint */ INGENIC_IN_ENDPOINT,
206    /* bulk data */ data,
207    /* bulk data length */ size,
208                USB_TIMEOUT);
209
210    if (ret < 0) {
211        fprintf(stderr, "Error - "
212            "Can't read bulk data from Ingenic device: %d\n", ret);
213        return ret;
214    }
215
216    return size;
217}
218
219int usb_ingenic_start(struct ingenic_dev *ingenic_dev, int rqst, int stage_addr)
220{
221    int ret;
222
223    /* tell the device to start the uploaded device */
224    ret = usb_control_msg(ingenic_dev->usb_handle,
225      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
226      /* bRequest */ rqst,
227      /* wValue */ STAGE_ADDR_MSB(stage_addr),
228      /* wIndex */ STAGE_ADDR_LSB(stage_addr),
229      /* Data */ 0,
230      /* wLength */ 0,
231                          USB_TIMEOUT);
232
233    if (ret != 0) {
234        fprintf(stderr, "Error - can't start the uploaded binary "
235            "on the Ingenic device: %d\n", ret);
236    }
237    return ret;
238}
239
240int usb_send_data_length_to_ingenic(struct ingenic_dev *ingenic_dev, unsigned int len)
241{
242    int ret;
243
244    /* tell the device the length of the file to be uploaded */
245    ret = usb_control_msg(ingenic_dev->usb_handle,
246      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
247      /* bRequest */ VR_SET_DATA_LENGTH,
248      /* wValue */ STAGE_ADDR_MSB(len),
249      /* wIndex */ STAGE_ADDR_LSB(len),
250      /* Data */ 0,
251      /* wLength */ 0,
252                  USB_TIMEOUT);
253
254    if (ret != 0) {
255        fprintf(stderr, "Error - "
256            "can't set data length on Ingenic device: %d\n", ret);
257    }
258
259    return ret;
260}
261
262int usb_send_data_address_to_ingenic(struct ingenic_dev *ingenic_dev, uint32_t addr)
263{
264    int ret;
265
266    /* tell the device the RAM address to store the file */
267    ret = usb_control_msg(ingenic_dev->usb_handle,
268      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
269      /* bRequest */ VR_SET_DATA_ADDRESS,
270      /* wValue */ STAGE_ADDR_MSB(addr),
271      /* wIndex */ STAGE_ADDR_LSB(addr),
272      /* Data */ 0,
273      /* wLength */ 0,
274                  USB_TIMEOUT);
275
276    if (ret != 0) {
277        fprintf(stderr, "Error - "
278            "Can't set the address on Ingenic device: %d\n", ret);
279    }
280
281    return ret;
282}
283
284
285int usb_ingenic_upload(struct ingenic_dev *ingenic_dev, int stage,
286                       const char *buf, int size)
287{
288    uint32_t stage_addr;
289    int request;
290    int ret;
291
292    if (stage == 1) {
293        stage_addr = 0x80002000;
294        request = VR_PROGRAM_START1;
295    } else {
296        stage_addr = 0x80000000 + total_size - CODE_SIZE;
297        request = VR_PROGRAM_START2;
298    }
299
300
301    usb_send_data_address_to_ingenic(ingenic_dev, stage_addr);
302    printf("Download stage %d program and execute at 0x%08x\n",
303           stage, stage_addr);
304    usb_send_data_to_ingenic(ingenic_dev, buf, size);
305
306    if (stage == 2) {
307        ret = usb_get_ingenic_cpu(ingenic_dev);
308        if (ret < 0)
309            return ret;
310        usb_ingenic_flush_cache(ingenic_dev);
311    }
312
313    ret = usb_ingenic_start(ingenic_dev, request, stage_addr);
314    if (ret)
315        return ret;
316    ret = usb_get_ingenic_cpu(ingenic_dev);
317    if (ret)
318        return ret;
319
320    return 0;
321}
322
323void usb_ingenic_cleanup(struct ingenic_dev *ingenic_dev)
324{
325    if (ingenic_dev->usb_handle) {
326        if (ingenic_dev->interface) {
327            usb_release_interface(ingenic_dev->usb_handle,
328                                  ingenic_dev->interface);
329        }
330
331        usb_close(ingenic_dev->usb_handle);
332    }
333
334}
335
336static int usb_ingenic_ops(struct ingenic_dev *ingenic_dev, uint32_t type,
337                           uint32_t ops)
338{
339    int ret;
340    ret = usb_control_msg(ingenic_dev->usb_handle,
341      /* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
342      /* bRequest */ type,
343      /* wValue */ ops,
344      /* wIndex */ 0,
345      /* Data */ 0,
346      /* wLength */ 0,
347                  USB_TIMEOUT);
348
349    return ret;
350}
351
352int usb_ingenic_flush_cache(struct ingenic_dev *ingenic_dev)
353{
354    int ret;
355    ret = usb_ingenic_ops(ingenic_dev, VR_FLUSH_CACHES, 0);
356
357    if (ret != 0) {
358        fprintf(stderr, "Error - can't flush cache: %d\n", ret);
359    }
360
361    return ret;
362}
363
364
365int usb_ingenic_nand_ops(struct ingenic_dev *ingenic_dev, int ops)
366{
367    int ret;
368    ret = usb_ingenic_ops(ingenic_dev, VR_NAND_OPS, ops);
369
370    if (ret != 0) {
371        fprintf(stderr, "Error - "
372            "can't set Ingenic device nand ops: %d\n", ret);
373    }
374
375    return ret;
376}
377
378int usb_ingenic_mem_ops(struct ingenic_dev *ingenic_dev, int ops)
379{
380    int ret;
381    ret = usb_ingenic_ops(ingenic_dev, VR_MEM_OPS, ops);
382
383    if (ret != 0) {
384        fprintf(stderr, "Error - "
385            "can't set Ingenic device nand ops: %d\n", ret);
386    }
387
388    return ret;
389}
390
391
392int usb_ingenic_configration(struct ingenic_dev *ingenic_dev, int ops)
393{
394    int ret;
395    ret = usb_ingenic_ops(ingenic_dev, VR_CONFIGURATION, ops);
396
397    if (ret != 0) {
398        fprintf(stderr, "Error - "
399            "can't init Ingenic configration: %d\n", ret);
400    }
401
402    return ret;
403}
404
405int usb_ingenic_sdram_ops(struct ingenic_dev *ingenic_dev, int ops)
406{
407    int ret;
408
409    ret = usb_ingenic_ops(ingenic_dev, VR_SDRAM_OPS, ops);
410
411    if (ret != 0) {
412        fprintf(stderr, "Error - "
413            "Device can't load file to sdram: %d\n", ret);
414    }
415
416    return ret;
417}
418

Archive Download this file



interactive