summaryrefslogtreecommitdiff
path: root/rbutil/jztool/src/x1000.c
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/jztool/src/x1000.c')
-rw-r--r--rbutil/jztool/src/x1000.c193
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
28static 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
55static 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
64static 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
75int 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
115int 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
146int 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
181int 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}