diff options
Diffstat (limited to 'rbutil/jztool/src/x1000.c')
-rw-r--r-- | rbutil/jztool/src/x1000.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/rbutil/jztool/src/x1000.c b/rbutil/jztool/src/x1000.c new file mode 100644 index 0000000000..049344e5e6 --- /dev/null +++ b/rbutil/jztool/src/x1000.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "jztool_private.h" | ||
23 | #include "../../../firmware/target/mips/ingenic_x1000/spl-x1000-defs.h" | ||
24 | #include "../../../firmware/target/mips/ingenic_x1000/nand-x1000-err.h" | ||
25 | #include <endian.h> // TODO: portability | ||
26 | #include <string.h> | ||
27 | |||
28 | static const char* jz_x1000_nand_strerror(int rc) | ||
29 | { | ||
30 | switch(rc) { | ||
31 | case NANDERR_CHIP_UNSUPPORTED: | ||
32 | return "Chip unsupported"; | ||
33 | case NANDERR_WRITE_PROTECTED: | ||
34 | return "Operation forbidden by write-protect"; | ||
35 | case NANDERR_UNALIGNED_ADDRESS: | ||
36 | return "Improperly aligned address"; | ||
37 | case NANDERR_UNALIGNED_LENGTH: | ||
38 | return "Improperly aligned length"; | ||
39 | case NANDERR_READ_FAILED: | ||
40 | return "Read operation failed"; | ||
41 | case NANDERR_ECC_FAILED: | ||
42 | return "Uncorrectable ECC error on read"; | ||
43 | case NANDERR_ERASE_FAILED: | ||
44 | return "Erase operation failed"; | ||
45 | case NANDERR_PROGRAM_FAILED: | ||
46 | return "Program operation failed"; | ||
47 | case NANDERR_COMMAND_FAILED: | ||
48 | return "NAND command failed"; | ||
49 | default: | ||
50 | return "Unknown NAND error"; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | |||
55 | static int jz_x1000_send_args(jz_usbdev* dev, struct x1000_spl_arguments* args) | ||
56 | { | ||
57 | args->command = htole32(args->command); | ||
58 | args->param1 = htole32(args->param1); | ||
59 | args->param2 = htole32(args->param2); | ||
60 | args->flags = htole32(args->flags); | ||
61 | return jz_usb_send(dev, SPL_ARGUMENTS_ADDRESS, sizeof(*args), args); | ||
62 | } | ||
63 | |||
64 | static int jz_x1000_recv_status(jz_usbdev* dev, struct x1000_spl_status* status) | ||
65 | { | ||
66 | int rc = jz_usb_recv(dev, SPL_STATUS_ADDRESS, sizeof(*status), status); | ||
67 | if(rc < 0) | ||
68 | return rc; | ||
69 | |||
70 | status->err_code = le32toh(status->err_code); | ||
71 | status->reserved = le32toh(status->reserved); | ||
72 | return JZ_SUCCESS; | ||
73 | } | ||
74 | |||
75 | int jz_x1000_setup(jz_usbdev* dev, size_t spl_len, const void* spl_data) | ||
76 | { | ||
77 | int rc = jz_identify_x1000_spl(spl_data, spl_len); | ||
78 | if(rc < 0) | ||
79 | return JZ_ERR_BAD_FILE_FORMAT; | ||
80 | if(spl_len > SPL_MAX_SIZE) | ||
81 | return JZ_ERR_BAD_FILE_FORMAT; | ||
82 | |||
83 | rc = jz_usb_send(dev, SPL_LOAD_ADDRESS, spl_len, spl_data); | ||
84 | if(rc < 0) | ||
85 | return rc; | ||
86 | |||
87 | struct x1000_spl_arguments args; | ||
88 | args.command = SPL_CMD_BOOT; | ||
89 | args.param1 = SPL_BOOTOPT_NONE; | ||
90 | args.param2 = 0; | ||
91 | args.flags = 0; | ||
92 | rc = jz_x1000_send_args(dev, &args); | ||
93 | if(rc < 0) | ||
94 | return rc; | ||
95 | |||
96 | rc = jz_usb_start1(dev, SPL_EXEC_ADDRESS); | ||
97 | if(rc < 0) | ||
98 | return rc; | ||
99 | |||
100 | jz_sleepms(100); | ||
101 | |||
102 | struct x1000_spl_status status; | ||
103 | rc = jz_x1000_recv_status(dev, &status); | ||
104 | if(rc < 0) | ||
105 | return rc; | ||
106 | |||
107 | if(status.err_code != 0) { | ||
108 | jz_log(dev->jz, JZ_LOG_ERROR, "X1000 device init error: %d", status.err_code); | ||
109 | return JZ_ERR_OTHER; | ||
110 | } | ||
111 | |||
112 | return JZ_SUCCESS; | ||
113 | } | ||
114 | |||
115 | int jz_x1000_read_flash(jz_usbdev* dev, uint32_t addr, size_t len, void* data) | ||
116 | { | ||
117 | struct x1000_spl_arguments args; | ||
118 | args.command = SPL_CMD_FLASH_READ; | ||
119 | args.param1 = addr; | ||
120 | args.param2 = len; | ||
121 | args.flags = SPL_FLAG_SKIP_INIT; | ||
122 | int rc = jz_x1000_send_args(dev, &args); | ||
123 | if(rc < 0) | ||
124 | return rc; | ||
125 | |||
126 | rc = jz_usb_start1(dev, SPL_EXEC_ADDRESS); | ||
127 | if(rc < 0) | ||
128 | return rc; | ||
129 | |||
130 | jz_sleepms(500); | ||
131 | |||
132 | struct x1000_spl_status status; | ||
133 | rc = jz_x1000_recv_status(dev, &status); | ||
134 | if(rc < 0) | ||
135 | return rc; | ||
136 | |||
137 | if(status.err_code != 0) { | ||
138 | jz_log(dev->jz, JZ_LOG_ERROR, "X1000 flash read error: %s", | ||
139 | jz_x1000_nand_strerror(status.err_code)); | ||
140 | return JZ_ERR_FLASH_ERROR; | ||
141 | } | ||
142 | |||
143 | return jz_usb_recv(dev, SPL_BUFFER_ADDRESS, len, data); | ||
144 | } | ||
145 | |||
146 | int jz_x1000_write_flash(jz_usbdev* dev, uint32_t addr, size_t len, const void* data) | ||
147 | { | ||
148 | int rc = jz_usb_send(dev, SPL_BUFFER_ADDRESS, len, data); | ||
149 | if(rc < 0) | ||
150 | return rc; | ||
151 | |||
152 | struct x1000_spl_arguments args; | ||
153 | args.command = SPL_CMD_FLASH_WRITE; | ||
154 | args.param1 = addr; | ||
155 | args.param2 = len; | ||
156 | args.flags = SPL_FLAG_SKIP_INIT; | ||
157 | rc = jz_x1000_send_args(dev, &args); | ||
158 | if(rc < 0) | ||
159 | return rc; | ||
160 | |||
161 | rc = jz_usb_start1(dev, SPL_EXEC_ADDRESS); | ||
162 | if(rc < 0) | ||
163 | return rc; | ||
164 | |||
165 | jz_sleepms(500); | ||
166 | |||
167 | struct x1000_spl_status status; | ||
168 | rc = jz_x1000_recv_status(dev, &status); | ||
169 | if(rc < 0) | ||
170 | return rc; | ||
171 | |||
172 | if(status.err_code != 0) { | ||
173 | jz_log(dev->jz, JZ_LOG_ERROR, "X1000 flash write error: %s", | ||
174 | jz_x1000_nand_strerror(status.err_code)); | ||
175 | return JZ_ERR_FLASH_ERROR; | ||
176 | } | ||
177 | |||
178 | return JZ_SUCCESS; | ||
179 | } | ||
180 | |||
181 | int jz_x1000_boot_rockbox(jz_usbdev* dev) | ||
182 | { | ||
183 | struct x1000_spl_arguments args; | ||
184 | args.command = SPL_CMD_BOOT; | ||
185 | args.param1 = SPL_BOOTOPT_ROCKBOX; | ||
186 | args.param2 = 0; | ||
187 | args.flags = 0; | ||
188 | int rc = jz_x1000_send_args(dev, &args); | ||
189 | if(rc < 0) | ||
190 | return rc; | ||
191 | |||
192 | return jz_usb_start1(dev, SPL_EXEC_ADDRESS); | ||
193 | } | ||