Advertisement
Guest User

uboot for allwinner v3

a guest
Jul 27th, 2016
462
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 59.37 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17.  
  18. #include <libusb.h>
  19. #include <stdint.h>
  20. #include <stdbool.h>
  21. #include <assert.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <stdarg.h>
  27. #include <errno.h>
  28. #include <unistd.h>
  29. #include <sys/stat.h>
  30.  
  31. #include "portable_endian.h"
  32. #include "progress.h"
  33.  
  34. static const uint16_t AW_USB_VENDOR_ID = 0x1F3A;
  35. static const uint16_t AW_USB_PRODUCT_ID = 0xEFE8;
  36.  
  37. /* a helper function to report libusb errors */
  38. void usb_error(int rc, const char *caption, int exitcode)
  39. {
  40. if (caption)
  41. fprintf(stderr, "%s ", caption);
  42.  
  43. #if defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102)
  44. fprintf(stderr, "ERROR %d: %s\n", rc, libusb_strerror(rc));
  45. #else
  46. /* assume that libusb_strerror() is missing in the libusb API */
  47. fprintf(stderr, "ERROR %d\n", rc);
  48. #endif
  49.  
  50. if (exitcode != 0)
  51. exit(exitcode);
  52. }
  53.  
  54. struct aw_usb_request {
  55. char signature[8];
  56. uint32_t length;
  57. uint32_t unknown1; /* 0x0c000000 */
  58. uint16_t request;
  59. uint32_t length2; /* Same as length */
  60. char pad[10];
  61. } __attribute__((packed));
  62.  
  63. struct aw_fel_version {
  64. char signature[8];
  65. uint32_t soc_id; /* 0x00162300 */
  66. uint32_t unknown_0a; /* 1 */
  67. uint16_t protocol; /* 1 */
  68. uint8_t unknown_12; /* 0x44 */
  69. uint8_t unknown_13; /* 0x08 */
  70. uint32_t scratchpad; /* 0x7e00 */
  71. uint32_t pad[2]; /* unused */
  72. } __attribute__((packed));
  73.  
  74. static const int AW_USB_READ = 0x11;
  75. static const int AW_USB_WRITE = 0x12;
  76.  
  77. static int AW_USB_FEL_BULK_EP_OUT;
  78. static int AW_USB_FEL_BULK_EP_IN;
  79. static int timeout = 60000;
  80. static bool verbose = false; /* If set, makes the 'fel' tool more talkative */
  81. static uint32_t uboot_entry = 0; /* entry point (address) of U-Boot */
  82. static uint32_t uboot_size = 0; /* size of U-Boot binary */
  83.  
  84. static void pr_info(const char *fmt, ...)
  85. {
  86. va_list arglist;
  87. if (verbose) {
  88. va_start(arglist, fmt);
  89. vprintf(fmt, arglist);
  90. va_end(arglist);
  91. }
  92. }
  93.  
  94. static const int AW_USB_MAX_BULK_SEND = 4 * 1024 * 1024; /* 4 MiB per bulk request */
  95.  
  96. void usb_bulk_send(libusb_device_handle *usb, int ep, const void *data,
  97. size_t length, bool progress)
  98. {
  99. /*
  100. * With no progress notifications, we'll use the maximum chunk size.
  101. * Otherwise, it's useful to lower the size (have more chunks) to get
  102. * more frequent status updates. 128 KiB per request seem suitable.
  103. */
  104. size_t max_chunk = progress ? 128 * 1024 : AW_USB_MAX_BULK_SEND;
  105.  
  106. size_t chunk;
  107. int rc, sent;
  108. while (length > 0) {
  109. chunk = length < max_chunk ? length : max_chunk;
  110. rc = libusb_bulk_transfer(usb, ep, (void *)data, chunk, &sent, timeout);
  111. if (rc != 0)
  112. usb_error(rc, "usb_bulk_send()", 2);
  113. length -= sent;
  114. data += sent;
  115.  
  116. if (progress)
  117. progress_update(sent); /* notification after each chunk */
  118. }
  119. }
  120.  
  121. void usb_bulk_recv(libusb_device_handle *usb, int ep, void *data, int length)
  122. {
  123. int rc, recv;
  124. while (length > 0) {
  125. rc = libusb_bulk_transfer(usb, ep, data, length, &recv, timeout);
  126. if (rc != 0)
  127. usb_error(rc, "usb_bulk_recv()", 2);
  128. length -= recv;
  129. data += recv;
  130. }
  131. }
  132.  
  133. /* Constants taken from ${U-BOOT}/include/image.h */
  134. #define IH_MAGIC 0x27051956 /* Image Magic Number */
  135. #define IH_ARCH_ARM 2 /* ARM */
  136. #define IH_TYPE_INVALID 0 /* Invalid Image */
  137. #define IH_TYPE_FIRMWARE 5 /* Firmware Image */
  138. #define IH_TYPE_SCRIPT 6 /* Script file */
  139. #define IH_NMLEN 32 /* Image Name Length */
  140.  
  141. /* Additional error codes, newly introduced for get_image_type() */
  142. #define IH_TYPE_ARCH_MISMATCH -1
  143.  
  144. #define HEADER_NAME_OFFSET 32 /* offset of name field */
  145. #define HEADER_SIZE (HEADER_NAME_OFFSET + IH_NMLEN)
  146.  
  147. /*
  148. * Utility function to determine the image type from a mkimage-compatible
  149. * header at given buffer (address).
  150. *
  151. * For invalid headers (insufficient size or 'magic' mismatch) the function
  152. * will return IH_TYPE_INVALID. Negative return values might indicate
  153. * special error conditions, e.g. IH_TYPE_ARCH_MISMATCH signals that the
  154. * image doesn't match the expected (ARM) architecture.
  155. * Otherwise the function will return the "ih_type" field for valid headers.
  156. */
  157. int get_image_type(const uint8_t *buf, size_t len)
  158. {
  159. uint32_t *buf32 = (uint32_t *)buf;
  160.  
  161. if (len <= HEADER_SIZE) /* insufficient length/size */
  162. return IH_TYPE_INVALID;
  163. if (be32toh(buf32[0]) != IH_MAGIC) /* signature mismatch */
  164. return IH_TYPE_INVALID;
  165. /* For sunxi, we always expect ARM architecture here */
  166. if (buf[29] != IH_ARCH_ARM)
  167. return IH_TYPE_ARCH_MISMATCH;
  168.  
  169. /* assume a valid header, and return ih_type */
  170. return buf[30];
  171. }
  172.  
  173. void aw_send_usb_request(libusb_device_handle *usb, int type, int length)
  174. {
  175. struct aw_usb_request req = {
  176. .signature = "AWUC",
  177. .request = htole16(type),
  178. .length = htole32(length),
  179. .unknown1 = htole32(0x0c000000)
  180. };
  181. req.length2 = req.length;
  182. usb_bulk_send(usb, AW_USB_FEL_BULK_EP_OUT, &req, sizeof(req), false);
  183. }
  184.  
  185. void aw_read_usb_response(libusb_device_handle *usb)
  186. {
  187. char buf[13];
  188. usb_bulk_recv(usb, AW_USB_FEL_BULK_EP_IN, &buf, sizeof(buf));
  189. assert(strcmp(buf, "AWUS") == 0);
  190. }
  191.  
  192. void aw_usb_write(libusb_device_handle *usb, const void *data, size_t len,
  193. bool progress)
  194. {
  195. aw_send_usb_request(usb, AW_USB_WRITE, len);
  196. usb_bulk_send(usb, AW_USB_FEL_BULK_EP_OUT, data, len, progress);
  197. aw_read_usb_response(usb);
  198. }
  199.  
  200. void aw_usb_read(libusb_device_handle *usb, const void *data, size_t len)
  201. {
  202. aw_send_usb_request(usb, AW_USB_READ, len);
  203. usb_bulk_send(usb, AW_USB_FEL_BULK_EP_IN, data, len, false);
  204. aw_read_usb_response(usb);
  205. }
  206.  
  207. struct aw_fel_request {
  208. uint32_t request;
  209. uint32_t address;
  210. uint32_t length;
  211. uint32_t pad;
  212. };
  213.  
  214. static const int AW_FEL_VERSION = 0x001;
  215. static const int AW_FEL_1_WRITE = 0x101;
  216. static const int AW_FEL_1_EXEC = 0x102;
  217. static const int AW_FEL_1_READ = 0x103;
  218.  
  219. void aw_send_fel_request(libusb_device_handle *usb, int type, uint32_t addr, uint32_t length)
  220. {
  221. struct aw_fel_request req = {
  222. .request = htole32(type),
  223. .address = htole32(addr),
  224. .length = htole32(length)
  225. };
  226. aw_usb_write(usb, &req, sizeof(req), false);
  227. }
  228.  
  229. void aw_read_fel_status(libusb_device_handle *usb)
  230. {
  231. char buf[8];
  232. aw_usb_read(usb, &buf, sizeof(buf));
  233. }
  234.  
  235. void aw_fel_get_version(libusb_device_handle *usb, struct aw_fel_version *buf)
  236. {
  237. aw_send_fel_request(usb, AW_FEL_VERSION, 0, 0);
  238. aw_usb_read(usb, buf, sizeof(*buf));
  239. aw_read_fel_status(usb);
  240.  
  241. buf->soc_id = (le32toh(buf->soc_id) >> 8) & 0xFFFF;
  242. buf->unknown_0a = le32toh(buf->unknown_0a);
  243. buf->protocol = le32toh(buf->protocol);
  244. buf->scratchpad = le16toh(buf->scratchpad);
  245. buf->pad[0] = le32toh(buf->pad[0]);
  246. buf->pad[1] = le32toh(buf->pad[1]);
  247. }
  248.  
  249. void aw_fel_print_version(libusb_device_handle *usb)
  250. {
  251. struct aw_fel_version buf;
  252. aw_fel_get_version(usb, &buf);
  253.  
  254. const char *soc_name="unknown";
  255. switch (buf.soc_id) {
  256. case 0x1623: soc_name="A10"; break;
  257. case 0x1625: soc_name="A13"; break;
  258. case 0x1633: soc_name="A31"; break;
  259. case 0x1651: soc_name="A20"; break;
  260. case 0x1650: soc_name="A23"; break;
  261. case 0x1689: soc_name="A64"; break;
  262. case 0x1639: soc_name="A80"; break;
  263. case 0x1667: soc_name="A33"; break;
  264. case 0x1673: soc_name="A83T"; break;
  265. case 0x1680: soc_name="H3"; break;
  266. case 0x1681: soc_name="V3"; break;
  267. }
  268.  
  269. printf("%.8s soc=%08x(%s) %08x ver=%04x %02x %02x scratchpad=%08x %08x %08x\n",
  270. buf.signature, buf.soc_id, soc_name, buf.unknown_0a,
  271. buf.protocol, buf.unknown_12, buf.unknown_13,
  272. buf.scratchpad, buf.pad[0], buf.pad[1]);
  273. }
  274.  
  275. void aw_fel_read(libusb_device_handle *usb, uint32_t offset, void *buf, size_t len)
  276. {
  277. aw_send_fel_request(usb, AW_FEL_1_READ, offset, len);
  278. aw_usb_read(usb, buf, len);
  279. aw_read_fel_status(usb);
  280. }
  281.  
  282. void aw_fel_write(libusb_device_handle *usb, void *buf, uint32_t offset, size_t len)
  283. {
  284. aw_send_fel_request(usb, AW_FEL_1_WRITE, offset, len);
  285. aw_usb_write(usb, buf, len, false);
  286. aw_read_fel_status(usb);
  287. }
  288.  
  289. void aw_fel_execute(libusb_device_handle *usb, uint32_t offset)
  290. {
  291. aw_send_fel_request(usb, AW_FEL_1_EXEC, offset, 0);
  292. aw_read_fel_status(usb);
  293. }
  294.  
  295. /*
  296. * This function is a higher-level wrapper for the FEL write functionality.
  297. * Unlike aw_fel_write() above - which is reserved for internal use - this
  298. * routine is meant to be called from "user" code, and supports (= allows)
  299. * progress callbacks.
  300. * The return value represents elapsed time in seconds (needed for execution).
  301. */
  302. double aw_write_buffer(libusb_device_handle *usb, void *buf, uint32_t offset,
  303. size_t len, bool progress)
  304. {
  305. /* safeguard against overwriting an already loaded U-Boot binary */
  306. if (uboot_size > 0 && offset <= uboot_entry + uboot_size
  307. && offset + len >= uboot_entry)
  308. {
  309. fprintf(stderr, "ERROR: Attempt to overwrite U-Boot! "
  310. "Request 0x%08X-0x%08X overlaps 0x%08X-0x%08X.\n",
  311. offset, (uint32_t)(offset + len),
  312. uboot_entry, uboot_entry + uboot_size);
  313. exit(1);
  314. }
  315. double start = gettime();
  316. aw_send_fel_request(usb, AW_FEL_1_WRITE, offset, len);
  317. aw_usb_write(usb, buf, len, progress);
  318. aw_read_fel_status(usb);
  319. return gettime() - start;
  320. }
  321.  
  322. void hexdump(void *data, uint32_t offset, size_t size)
  323. {
  324. size_t j;
  325. unsigned char *buf = data;
  326. for (j = 0; j < size; j+=16) {
  327. size_t i;
  328. printf("%08lx: ",(long int)offset + j);
  329. for (i = 0; i < 16; i++) {
  330. if (j + i < size)
  331. printf("%02x ", buf[j+i]);
  332. else
  333. printf("__ ");
  334. }
  335. putchar(' ');
  336. for (i = 0; i < 16; i++) {
  337. if (j + i >= size)
  338. putchar('.');
  339. else
  340. putchar(isprint(buf[j+i]) ? buf[j+i] : '.');
  341. }
  342. putchar('\n');
  343. }
  344. }
  345.  
  346. unsigned int file_size(const char *filename)
  347. {
  348. struct stat st;
  349. if (stat(filename, &st) != 0) {
  350. fprintf(stderr, "stat() error on file \"%s\": %s\n", filename,
  351. strerror(errno));
  352. exit(1);
  353. }
  354. if (!S_ISREG(st.st_mode)) {
  355. fprintf(stderr, "error: \"%s\" is not a regular file\n", filename);
  356. exit(1);
  357. }
  358. return st.st_size;
  359. }
  360.  
  361. int save_file(const char *name, void *data, size_t size)
  362. {
  363. FILE *out = fopen(name, "wb");
  364. int rc;
  365. if (!out) {
  366. perror("Failed to open output file");
  367. exit(1);
  368. }
  369. rc = fwrite(data, size, 1, out);
  370. fclose(out);
  371. return rc;
  372. }
  373.  
  374. void *load_file(const char *name, size_t *size)
  375. {
  376. size_t bufsize = 8192;
  377. size_t offset = 0;
  378. char *buf = malloc(bufsize);
  379. FILE *in;
  380. if (strcmp(name, "-") == 0)
  381. in = stdin;
  382. else
  383. in = fopen(name, "rb");
  384. if (!in) {
  385. perror("Failed to open input file");
  386. exit(1);
  387. }
  388.  
  389. while (true) {
  390. ssize_t len = bufsize - offset;
  391. ssize_t n = fread(buf+offset, 1, len, in);
  392. offset += n;
  393. if (n < len)
  394. break;
  395. bufsize <<= 1;
  396. buf = realloc(buf, bufsize);
  397. }
  398. if (size)
  399. *size = offset;
  400. if (in != stdin)
  401. fclose(in);
  402. return buf;
  403. }
  404.  
  405. void aw_fel_hexdump(libusb_device_handle *usb, uint32_t offset, size_t size)
  406. {
  407. unsigned char buf[size];
  408. aw_fel_read(usb, offset, buf, size);
  409. hexdump(buf, offset, size);
  410. }
  411.  
  412. void aw_fel_dump(libusb_device_handle *usb, uint32_t offset, size_t size)
  413. {
  414. unsigned char buf[size];
  415. aw_fel_read(usb, offset, buf, size);
  416. fwrite(buf, size, 1, stdout);
  417. }
  418. void aw_fel_fill(libusb_device_handle *usb, uint32_t offset, size_t size, unsigned char value)
  419. {
  420. unsigned char buf[size];
  421. memset(buf, value, size);
  422. aw_write_buffer(usb, buf, offset, size, false);
  423. }
  424.  
  425. /*
  426. * The 'sram_swap_buffers' structure is used to describe information about
  427. * two buffers in SRAM, the content of which needs to be exchanged before
  428. * calling the U-Boot SPL code and then exchanged again before returning
  429. * control back to the FEL code from the BROM.
  430. */
  431.  
  432. typedef struct {
  433. uint32_t buf1; /* BROM buffer */
  434. uint32_t buf2; /* backup storage location */
  435. uint32_t size; /* buffer size */
  436. } sram_swap_buffers;
  437.  
  438. /*
  439. * Each SoC variant may have its own list of memory buffers to be exchanged
  440. * and the information about the placement of the thunk code, which handles
  441. * the transition of execution from the BROM FEL code to the U-Boot SPL and
  442. * back.
  443. *
  444. * Note: the entries in the 'swap_buffers' tables need to be sorted by 'buf1'
  445. * addresses. And the 'buf1' addresses are the BROM data buffers, while 'buf2'
  446. * addresses are the intended backup locations.
  447. *
  448. * Also for performance reasons, we optionally want to have MMU enabled with
  449. * optimal section attributes configured (the code from the BROM should use
  450. * I-cache, writing data to the DRAM area should use write combining). The
  451. * reason is that the BROM FEL protocol implementation moves data using the
  452. * CPU somewhere on the performance critical path when transferring data over
  453. * USB. The older SoC variants (A10/A13/A20/A31/A23) already have MMU enabled
  454. * and we only need to adjust section attributes. The BROM in newer SoC variants
  455. * (A33/A83T/H3) doesn't enable MMU anymore, so we need to find some 16K of
  456. * spare space in SRAM to place the translation table there and specify it as
  457. * the 'mmu_tt_addr' field in the 'soc_sram_info' structure. The 'mmu_tt_addr'
  458. * address must be 16K aligned.
  459. */
  460. typedef struct {
  461. uint32_t soc_id; /* ID of the SoC */
  462. uint32_t spl_addr; /* SPL load address */
  463. uint32_t scratch_addr; /* A safe place to upload & run code */
  464. uint32_t thunk_addr; /* Address of the thunk code */
  465. uint32_t thunk_size; /* Maximal size of the thunk code */
  466. bool needs_l2en; /* Set the L2EN bit */
  467. uint32_t mmu_tt_addr; /* MMU translation table address */
  468. uint32_t sid_addr; /* base address for SID_KEY[0-3] registers */
  469. uint32_t rvbar_reg; /* MMIO address of RVBARADDR0_L register */
  470. sram_swap_buffers *swap_buffers;
  471. } soc_sram_info;
  472.  
  473. /*
  474. * The FEL code from BROM in A10/A13/A20 sets up two stacks for itself. One
  475. * at 0x2000 (and growing down) for the IRQ handler. And another one at 0x7000
  476. * (and also growing down) for the regular code. In order to use the whole
  477. * 32 KiB in the A1/A2 sections of SRAM, we need to temporarily move these
  478. * stacks elsewhere. And the addresses 0x7D00-0x7FFF contain something
  479. * importantant too (overwriting them kills FEL). On A10/A13/A20 we can use
  480. * the SRAM sections A3/A4 (0x8000-0xBFFF) for this purpose.
  481. */
  482. sram_swap_buffers a10_a13_a20_sram_swap_buffers[] = {
  483. /* 0x1C00-0x1FFF (IRQ stack) */
  484. { .buf1 = 0x01C00, .buf2 = 0xA400, .size = 0x0400 },
  485. /* 0x5C00-0x6FFF (Stack) */
  486. { .buf1 = 0x05C00, .buf2 = 0xA800, .size = 0x1400 },
  487. /* 0x7C00-0x7FFF (Something important) */
  488. { .buf1 = 0x07C00, .buf2 = 0xBC00, .size = 0x0400 },
  489. { .size = 0 } /* End of the table */
  490. };
  491.  
  492. /*
  493. * A31 is very similar to A10/A13/A20, except that it has no SRAM at 0x8000.
  494. * So we use the SRAM section B at 0x20000-0x2FFFF instead. In the FEL mode,
  495. * the MMU translation table is allocated by the BROM at 0x20000. But we can
  496. * also safely use it as the backup storage because the MMU is temporarily
  497. * disabled during the time of the SPL execution.
  498. */
  499. sram_swap_buffers a31_sram_swap_buffers[] = {
  500. { .buf1 = 0x01800, .buf2 = 0x20000, .size = 0x800 },
  501. { .buf1 = 0x05C00, .buf2 = 0x20800, .size = 0x8000 - 0x5C00 },
  502. { .size = 0 } /* End of the table */
  503. };
  504.  
  505. /*
  506. * A64 has 32KiB of SRAM A at 0x10000 and a large SRAM C at 0x18000. SRAM A
  507. * and SRAM C reside in the address space back-to-back without any gaps, thus
  508. * representing a singe large contiguous area. Everything is the same as on
  509. * A10/A13/A20, but just shifted by 0x10000.
  510. */
  511. sram_swap_buffers a64_sram_swap_buffers[] = {
  512. /* 0x11C00-0x11FFF (IRQ stack) */
  513. { .buf1 = 0x11C00, .buf2 = 0x1A400, .size = 0x0400 },
  514. /* 0x15C00-0x16FFF (Stack) */
  515. { .buf1 = 0x15C00, .buf2 = 0x1A800, .size = 0x1400 },
  516. /* 0x17C00-0x17FFF (Something important) */
  517. { .buf1 = 0x17C00, .buf2 = 0x1BC00, .size = 0x0400 },
  518. { .size = 0 } /* End of the table */
  519. };
  520.  
  521. /*
  522. * Use the SRAM section at 0x44000 as the backup storage. This is the memory,
  523. * which is normally shared with the OpenRISC core (should we do an extra check
  524. * to ensure that this core is powered off and can't interfere?).
  525. */
  526. sram_swap_buffers ar100_abusing_sram_swap_buffers[] = {
  527. { .buf1 = 0x01800, .buf2 = 0x44000, .size = 0x800 },
  528. { .buf1 = 0x05C00, .buf2 = 0x44800, .size = 0x8000 - 0x5C00 },
  529. { .size = 0 } /* End of the table */
  530. };
  531.  
  532. /*
  533. * A80 has 40KiB SRAM A1 at 0x10000 where the SPL has to be loaded to. The
  534. * secure SRAM B at 0x20000 is used as backup area for FEL stacks and data.
  535. */
  536. sram_swap_buffers a80_sram_swap_buffers[] = {
  537. { .buf1 = 0x11800, .buf2 = 0x20000, .size = 0x800 },
  538. { .buf1 = 0x15400, .buf2 = 0x20800, .size = 0x18000 - 0x15400 },
  539. { .size = 0 } /* End of the table */
  540. };
  541.  
  542. soc_sram_info soc_sram_info_table[] = {
  543. {
  544. .soc_id = 0x1623, /* Allwinner A10 */
  545. .scratch_addr = 0x1000,
  546. .thunk_addr = 0xA200, .thunk_size = 0x200,
  547. .swap_buffers = a10_a13_a20_sram_swap_buffers,
  548. .needs_l2en = true,
  549. .sid_addr = 0x01C23800,
  550. },
  551. {
  552. .soc_id = 0x1625, /* Allwinner A13 */
  553. .scratch_addr = 0x1000,
  554. .thunk_addr = 0xA200, .thunk_size = 0x200,
  555. .swap_buffers = a10_a13_a20_sram_swap_buffers,
  556. .needs_l2en = true,
  557. .sid_addr = 0x01C23800,
  558. },
  559. {
  560. .soc_id = 0x1651, /* Allwinner A20 */
  561. .scratch_addr = 0x1000,
  562. .thunk_addr = 0xA200, .thunk_size = 0x200,
  563. .swap_buffers = a10_a13_a20_sram_swap_buffers,
  564. .sid_addr = 0x01C23800,
  565. },
  566. {
  567. .soc_id = 0x1650, /* Allwinner A23 */
  568. .scratch_addr = 0x1000,
  569. .thunk_addr = 0x46E00, .thunk_size = 0x200,
  570. .swap_buffers = ar100_abusing_sram_swap_buffers,
  571. .sid_addr = 0x01C23800,
  572. },
  573. {
  574. .soc_id = 0x1633, /* Allwinner A31 */
  575. .scratch_addr = 0x1000,
  576. .thunk_addr = 0x22E00, .thunk_size = 0x200,
  577. .swap_buffers = a31_sram_swap_buffers,
  578. },
  579. {
  580. .soc_id = 0x1667, /* Allwinner A33 */
  581. .scratch_addr = 0x1000,
  582. .thunk_addr = 0x46E00, .thunk_size = 0x200,
  583. .swap_buffers = ar100_abusing_sram_swap_buffers,
  584. .sid_addr = 0x01C23800,
  585. },
  586. {
  587. .soc_id = 0x1689, /* Allwinner A64 */
  588. .spl_addr = 0x10000,
  589. .scratch_addr = 0x11000,
  590. .thunk_addr = 0x1A200, .thunk_size = 0x200,
  591. .swap_buffers = a64_sram_swap_buffers,
  592. .sid_addr = 0x01C14200,
  593. .rvbar_reg = 0x017000A0,
  594. },
  595. {
  596. .soc_id = 0x1673, /* Allwinner A83T */
  597. .scratch_addr = 0x1000,
  598. .thunk_addr = 0x46E00, .thunk_size = 0x200,
  599. .swap_buffers = ar100_abusing_sram_swap_buffers,
  600. .sid_addr = 0x01C14200,
  601. },
  602. {
  603. .soc_id = 0x1680, /* Allwinner H3 */
  604. .scratch_addr = 0x1000,
  605. .mmu_tt_addr = 0x8000,
  606. .thunk_addr = 0xA200, .thunk_size = 0x200,
  607. .swap_buffers = a10_a13_a20_sram_swap_buffers,
  608. .sid_addr = 0x01C14200,
  609. },
  610. {
  611. .soc_id = 0x1681, /* Allwinner V3 */
  612. .scratch_addr = 0x1000,
  613. .mmu_tt_addr = 0x8000,
  614. .thunk_addr = 0xA200, .thunk_size = 0x200,
  615. .swap_buffers = a10_a13_a20_sram_swap_buffers,
  616. .sid_addr = 0x01C14200,
  617. },
  618. {
  619. .soc_id = 0x1639, /* Allwinner A80 */
  620. .spl_addr = 0x10000,
  621. .scratch_addr = 0x11000,
  622. .thunk_addr = 0x23400, .thunk_size = 0x200,
  623. .swap_buffers = a80_sram_swap_buffers,
  624. },
  625. { .swap_buffers = NULL } /* End of the table */
  626. };
  627.  
  628. /*
  629. * This generic record assumes BROM with similar properties to A10/A13/A20/A31,
  630. * but no extra SRAM sections beyond 0x8000. It also assumes that the IRQ
  631. * handler stack usage never exceeds 0x400 bytes.
  632. *
  633. * The users may or may not hope that the 0x7000-0x8000 area is also unused
  634. * by the BROM and re-purpose it for the SPL stack.
  635. *
  636. * The size limit for the ".text + .data" sections is ~21 KiB.
  637. */
  638. sram_swap_buffers generic_sram_swap_buffers[] = {
  639. { .buf1 = 0x01C00, .buf2 = 0x5800, .size = 0x400 },
  640. { .size = 0 } /* End of the table */
  641. };
  642.  
  643. soc_sram_info generic_sram_info = {
  644. .scratch_addr = 0x1000,
  645. .thunk_addr = 0x5680, .thunk_size = 0x180,
  646. .swap_buffers = generic_sram_swap_buffers,
  647. };
  648.  
  649. soc_sram_info *aw_fel_get_sram_info(libusb_device_handle *usb)
  650. {
  651. /* persistent sram_info, retrieves result pointer once and caches it */
  652. static soc_sram_info *result = NULL;
  653. if (result == NULL) {
  654. int i;
  655.  
  656. struct aw_fel_version buf;
  657. aw_fel_get_version(usb, &buf);
  658.  
  659. for (i = 0; soc_sram_info_table[i].swap_buffers; i++)
  660. if (soc_sram_info_table[i].soc_id == buf.soc_id) {
  661. result = &soc_sram_info_table[i];
  662. break;
  663. }
  664.  
  665. if (!result) {
  666. printf("Warning: no 'soc_sram_info' data for your SoC (id=%04X)\n",
  667. buf.soc_id);
  668. result = &generic_sram_info;
  669. }
  670. }
  671. return result;
  672. }
  673.  
  674. static uint32_t fel_to_spl_thunk[] = {
  675. #include "fel-to-spl-thunk.h"
  676. };
  677.  
  678. #define DRAM_BASE 0x40000000
  679. #define DRAM_SIZE 0x80000000
  680.  
  681. uint32_t aw_read_arm_cp_reg(libusb_device_handle *usb, soc_sram_info *sram_info,
  682. uint32_t coproc, uint32_t opc1, uint32_t crn,
  683. uint32_t crm, uint32_t opc2)
  684. {
  685. uint32_t val = 0;
  686. uint32_t opcode = 0xEE000000 | (1 << 20) | (1 << 4) |
  687. ((opc1 & 7) << 21) |
  688. ((crn & 15) << 16) |
  689. ((coproc & 15) << 8) |
  690. ((opc2 & 7) << 5) |
  691. (crm & 15);
  692. uint32_t arm_code[] = {
  693. htole32(opcode), /* mrc coproc, opc1, r0, crn, crm, opc2 */
  694. htole32(0xe58f0000), /* str r0, [pc] */
  695. htole32(0xe12fff1e), /* bx lr */
  696. };
  697. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  698. aw_fel_execute(usb, sram_info->scratch_addr);
  699. aw_fel_read(usb, sram_info->scratch_addr + 12, &val, sizeof(val));
  700. return le32toh(val);
  701. }
  702.  
  703. void aw_write_arm_cp_reg(libusb_device_handle *usb, soc_sram_info *sram_info,
  704. uint32_t coproc, uint32_t opc1, uint32_t crn,
  705. uint32_t crm, uint32_t opc2, uint32_t val)
  706. {
  707. uint32_t opcode = 0xEE000000 | (0 << 20) | (1 << 4) |
  708. ((opc1 & 7) << 21) |
  709. ((crn & 15) << 16) |
  710. ((coproc & 15) << 8) |
  711. ((opc2 & 7) << 5) |
  712. (crm & 15);
  713. uint32_t arm_code[] = {
  714. htole32(0xe59f000c), /* ldr r0, [pc, #12] */
  715. htole32(opcode), /* mcr coproc, opc1, r0, crn, crm, opc2 */
  716. htole32(0xf57ff04f), /* dsb sy */
  717. htole32(0xf57ff06f), /* isb sy */
  718. htole32(0xe12fff1e), /* bx lr */
  719. htole32(val)
  720. };
  721. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  722. aw_fel_execute(usb, sram_info->scratch_addr);
  723. }
  724.  
  725. /* multiple "readl" from sequential addresses to a destination buffer */
  726. void aw_fel_readl_n(libusb_device_handle *usb, uint32_t addr,
  727. uint32_t *dst, size_t count)
  728. {
  729. soc_sram_info *sram_info = aw_fel_get_sram_info(usb);
  730. uint32_t val;
  731. uint32_t arm_code[] = {
  732. htole32(0xe59f0010), /* ldr r0, [pc, #16] */
  733. htole32(0xe5901000), /* ldr r1, [r0] */
  734. htole32(0xe58f100c), /* str r1, [pc, #12] */
  735. htole32(0xe2800004), /* add r0, r0, #4 */
  736. htole32(0xe58f0000), /* str r0, [pc] */
  737. htole32(0xe12fff1e), /* bx lr */
  738. htole32(addr),
  739. /* value goes here */
  740. };
  741. /* scratch buffer setup: transfers ARM code and also sets the addr */
  742. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  743. while (count-- > 0) {
  744. /*
  745. * Since the scratch code auto-increments addr, we can simply
  746. * execute it repeatedly for sequential "readl"s; retrieving
  747. * one uint32_t each time.
  748. */
  749. aw_fel_execute(usb, sram_info->scratch_addr);
  750. aw_fel_read(usb, sram_info->scratch_addr + 28, &val, sizeof(val));
  751. *dst++ = le32toh(val);
  752. }
  753. }
  754.  
  755. /* "readl" of a single value */
  756. uint32_t aw_fel_readl(libusb_device_handle *usb, uint32_t addr)
  757. {
  758. uint32_t val;
  759. aw_fel_readl_n(usb, addr, &val, 1);
  760. return val;
  761. }
  762.  
  763. /* multiple "writel" from a source buffer to sequential addresses */
  764. void aw_fel_writel_n(libusb_device_handle *usb, uint32_t addr,
  765. uint32_t *src, size_t count)
  766. {
  767. if (count == 0) return; /* on zero count, do not access *src at all */
  768.  
  769. soc_sram_info *sram_info = aw_fel_get_sram_info(usb);
  770. uint32_t arm_code[] = {
  771. htole32(0xe59f0010), /* ldr r0, [pc, #16] */
  772. htole32(0xe59f1010), /* ldr r1, [pc, #16] */
  773. htole32(0xe5801000), /* str r1, [r0] */
  774. htole32(0xe2800004), /* add r0, r0, #4 */
  775. htole32(0xe58f0000), /* str r0, [pc] */
  776. htole32(0xe12fff1e), /* bx lr */
  777. htole32(addr),
  778. htole32(*src++)
  779. };
  780. /* scratch buffer setup: transfers ARM code, addr and first value */
  781. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  782. aw_fel_execute(usb, sram_info->scratch_addr); /* stores first value */
  783. while (--count > 0) {
  784. /*
  785. * Subsequent transfers only need to set up the next value
  786. * to store (since the scratch code auto-increments addr).
  787. */
  788. aw_fel_write(usb, src++, sram_info->scratch_addr + 28, sizeof(uint32_t));
  789. aw_fel_execute(usb, sram_info->scratch_addr);
  790. }
  791. }
  792.  
  793. /* "writel" of a single value */
  794. void aw_fel_writel(libusb_device_handle *usb, uint32_t addr, uint32_t val)
  795. {
  796. aw_fel_writel_n(usb, addr, &val, 1);
  797. }
  798.  
  799. void aw_fel_print_sid(libusb_device_handle *usb)
  800. {
  801. soc_sram_info *soc_info = aw_fel_get_sram_info(usb);
  802. if (soc_info->sid_addr) {
  803. pr_info("SID key (e-fuses) at 0x%08X\n", soc_info->sid_addr);
  804.  
  805. uint32_t key[4];
  806. aw_fel_readl_n(usb, soc_info->sid_addr, key, 4);
  807.  
  808. unsigned int i;
  809. /* output SID in "xxxxxxxx:xxxxxxxx:xxxxxxxx:xxxxxxxx" format */
  810. for (i = 0; i <= 3; i++)
  811. printf("%08x%c", key[i], i < 3 ? ':' : '\n');
  812. } else {
  813. printf("SID registers for your SoC (id=%04X) are unknown or inaccessible.\n",
  814. soc_info->soc_id);
  815. }
  816. }
  817.  
  818. void aw_enable_l2_cache(libusb_device_handle *usb, soc_sram_info *sram_info)
  819. {
  820. uint32_t arm_code[] = {
  821. htole32(0xee112f30), /* mrc 15, 0, r2, cr1, cr0, {1} */
  822. htole32(0xe3822002), /* orr r2, r2, #2 */
  823. htole32(0xee012f30), /* mcr 15, 0, r2, cr1, cr0, {1} */
  824. htole32(0xe12fff1e), /* bx lr */
  825. };
  826.  
  827. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  828. aw_fel_execute(usb, sram_info->scratch_addr);
  829. }
  830.  
  831. void aw_get_stackinfo(libusb_device_handle *usb, soc_sram_info *sram_info,
  832. uint32_t *sp_irq, uint32_t *sp)
  833. {
  834. uint32_t results[2] = { 0 };
  835. #if 0
  836. /* Does not work on Cortex-A8 (needs Virtualization Extensions) */
  837. uint32_t arm_code[] = {
  838. htole32(0xe1010300), /* mrs r0, SP_irq */
  839. htole32(0xe58f0004), /* str r0, [pc, #4] */
  840. htole32(0xe58fd004), /* str sp, [pc, #4] */
  841. htole32(0xe12fff1e), /* bx lr */
  842. };
  843.  
  844. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  845. aw_fel_execute(usb, sram_info->scratch_addr);
  846. aw_fel_read(usb, sram_info->scratch_addr + 0x10, results, 8);
  847. #else
  848. /* Works everywhere */
  849. uint32_t arm_code[] = {
  850. htole32(0xe10f0000), /* mrs r0, CPSR */
  851. htole32(0xe3c0101f), /* bic r1, r0, #31 */
  852. htole32(0xe3811012), /* orr r1, r1, #18 */
  853. htole32(0xe121f001), /* msr CPSR_c, r1 */
  854. htole32(0xe1a0100d), /* mov r1, sp */
  855. htole32(0xe121f000), /* msr CPSR_c, r0 */
  856. htole32(0xe58f1004), /* str r1, [pc, #4] */
  857. htole32(0xe58fd004), /* str sp, [pc, #4] */
  858. htole32(0xe12fff1e), /* bx lr */
  859. };
  860.  
  861. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  862. aw_fel_execute(usb, sram_info->scratch_addr);
  863. aw_fel_read(usb, sram_info->scratch_addr + 0x24, results, 8);
  864. #endif
  865. *sp_irq = le32toh(results[0]);
  866. *sp = le32toh(results[1]);
  867. }
  868.  
  869. uint32_t aw_get_ttbr0(libusb_device_handle *usb, soc_sram_info *sram_info)
  870. {
  871. return aw_read_arm_cp_reg(usb, sram_info, 15, 0, 2, 0, 0);
  872. }
  873.  
  874. uint32_t aw_get_ttbcr(libusb_device_handle *usb, soc_sram_info *sram_info)
  875. {
  876. return aw_read_arm_cp_reg(usb, sram_info, 15, 0, 2, 0, 2);
  877. }
  878.  
  879. uint32_t aw_get_dacr(libusb_device_handle *usb, soc_sram_info *sram_info)
  880. {
  881. return aw_read_arm_cp_reg(usb, sram_info, 15, 0, 3, 0, 0);
  882. }
  883.  
  884. uint32_t aw_get_sctlr(libusb_device_handle *usb, soc_sram_info *sram_info)
  885. {
  886. return aw_read_arm_cp_reg(usb, sram_info, 15, 0, 1, 0, 0);
  887. }
  888.  
  889. void aw_set_ttbr0(libusb_device_handle *usb, soc_sram_info *sram_info,
  890. uint32_t ttbr0)
  891. {
  892. return aw_write_arm_cp_reg(usb, sram_info, 15, 0, 2, 0, 0, ttbr0);
  893. }
  894.  
  895. void aw_set_ttbcr(libusb_device_handle *usb, soc_sram_info *sram_info,
  896. uint32_t ttbcr)
  897. {
  898. return aw_write_arm_cp_reg(usb, sram_info, 15, 0, 2, 0, 2, ttbcr);
  899. }
  900.  
  901. void aw_set_dacr(libusb_device_handle *usb, soc_sram_info *sram_info,
  902. uint32_t dacr)
  903. {
  904. aw_write_arm_cp_reg(usb, sram_info, 15, 0, 3, 0, 0, dacr);
  905. }
  906.  
  907. void aw_set_sctlr(libusb_device_handle *usb, soc_sram_info *sram_info,
  908. uint32_t sctlr)
  909. {
  910. aw_write_arm_cp_reg(usb, sram_info, 15, 0, 1, 0, 0, sctlr);
  911. }
  912.  
  913. /*
  914. * Reconstruct the same MMU translation table as used by the A20 BROM.
  915. * We are basically reverting the changes, introduced in newer SoC
  916. * variants. This works fine for the SoC variants with the memory
  917. * layout similar to A20 (the SRAM is in the first megabyte of the
  918. * address space and the BROM is in the last megabyte of the address
  919. * space).
  920. */
  921. uint32_t *aw_generate_mmu_translation_table(void)
  922. {
  923. uint32_t *tt = malloc(4096 * sizeof(uint32_t));
  924. uint32_t i;
  925.  
  926. /*
  927. * Direct mapping using 1MB sections with TEXCB=00000 (Strongly
  928. * ordered) for all memory except the first and the last sections,
  929. * which have TEXCB=00100 (Normal). Domain bits are set to 1111
  930. * and AP bits are set to 11, but this is mostly irrelevant.
  931. */
  932. for (i = 0; i < 4096; i++)
  933. tt[i] = 0x00000DE2 | (i << 20);
  934. tt[0x000] |= 0x1000;
  935. tt[0xFFF] |= 0x1000;
  936.  
  937. return tt;
  938. }
  939.  
  940. uint32_t *aw_backup_and_disable_mmu(libusb_device_handle *usb,
  941. soc_sram_info *sram_info)
  942. {
  943. uint32_t *tt = NULL;
  944. uint32_t sctlr, ttbr0, ttbcr, dacr;
  945. uint32_t i;
  946.  
  947. uint32_t arm_code[] = {
  948. /* Disable I-cache, MMU and branch prediction */
  949. htole32(0xee110f10), /* mrc 15, 0, r0, cr1, cr0, {0} */
  950. htole32(0xe3c00001), /* bic r0, r0, #1 */
  951. htole32(0xe3c00a01), /* bic r0, r0, #4096 */
  952. htole32(0xe3c00b02), /* bic r0, r0, #2048 */
  953. htole32(0xee010f10), /* mcr 15, 0, r0, cr1, cr0, {0} */
  954. /* Return back to FEL */
  955. htole32(0xe12fff1e), /* bx lr */
  956. };
  957.  
  958. /*
  959. * Below are some checks for the register values, which are known
  960. * to be initialized in this particular way by the existing BROM
  961. * implementations. We don't strictly need them to exactly match,
  962. * but still have these safety guards in place in order to detect
  963. * and review any potential configuration changes in future SoC
  964. * variants (if one of these checks fails, then it is not a serious
  965. * problem but more likely just an indication that one of these
  966. * checks needs to be relaxed).
  967. */
  968.  
  969. /* Basically, ignore M/Z/I/V/UNK bits and expect no TEX remap */
  970. sctlr = aw_get_sctlr(usb, sram_info);
  971. if ((sctlr & ~((0x7 << 11) | (1 << 6) | 1)) != 0x00C50038) {
  972. fprintf(stderr, "Unexpected SCTLR (%08X)\n", sctlr);
  973. exit(1);
  974. }
  975.  
  976. if (!(sctlr & 1)) {
  977. pr_info("MMU is not enabled by BROM\n");
  978. return NULL;
  979. }
  980.  
  981. dacr = aw_get_dacr(usb, sram_info);
  982. if (dacr != 0x55555555) {
  983. fprintf(stderr, "Unexpected DACR (%08X)\n", dacr);
  984. exit(1);
  985. }
  986.  
  987. ttbcr = aw_get_ttbcr(usb, sram_info);
  988. if (ttbcr != 0x00000000) {
  989. fprintf(stderr, "Unexpected TTBCR (%08X)\n", ttbcr);
  990. exit(1);
  991. }
  992.  
  993. ttbr0 = aw_get_ttbr0(usb, sram_info);
  994. if (ttbr0 & 0x3FFF) {
  995. fprintf(stderr, "Unexpected TTBR0 (%08X)\n", ttbr0);
  996. exit(1);
  997. }
  998.  
  999. tt = malloc(16 * 1024);
  1000. pr_info("Reading the MMU translation table from 0x%08X\n", ttbr0);
  1001. aw_fel_read(usb, ttbr0, tt, 16 * 1024);
  1002. for (i = 0; i < 4096; i++)
  1003. tt[i] = le32toh(tt[i]);
  1004.  
  1005. /* Basic sanity checks to be sure that this is a valid table */
  1006. for (i = 0; i < 4096; i++) {
  1007. if (((tt[i] >> 1) & 1) != 1 || ((tt[i] >> 18) & 1) != 0) {
  1008. fprintf(stderr, "MMU: not a section descriptor\n");
  1009. exit(1);
  1010. }
  1011. if ((tt[i] >> 20) != i) {
  1012. fprintf(stderr, "MMU: not a direct mapping\n");
  1013. exit(1);
  1014. }
  1015. }
  1016.  
  1017. pr_info("Disabling I-cache, MMU and branch prediction...");
  1018. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  1019. aw_fel_execute(usb, sram_info->scratch_addr);
  1020. pr_info(" done.\n");
  1021.  
  1022. return tt;
  1023. }
  1024.  
  1025. void aw_restore_and_enable_mmu(libusb_device_handle *usb,
  1026. soc_sram_info *sram_info,
  1027. uint32_t *tt)
  1028. {
  1029. uint32_t i;
  1030. uint32_t ttbr0 = aw_get_ttbr0(usb, sram_info);
  1031.  
  1032. uint32_t arm_code[] = {
  1033. /* Invalidate I-cache, TLB and BTB */
  1034. htole32(0xe3a00000), /* mov r0, #0 */
  1035. htole32(0xee080f17), /* mcr 15, 0, r0, cr8, cr7, {0} */
  1036. htole32(0xee070f15), /* mcr 15, 0, r0, cr7, cr5, {0} */
  1037. htole32(0xee070fd5), /* mcr 15, 0, r0, cr7, cr5, {6} */
  1038. htole32(0xf57ff04f), /* dsb sy */
  1039. htole32(0xf57ff06f), /* isb sy */
  1040. /* Enable I-cache, MMU and branch prediction */
  1041. htole32(0xee110f10), /* mrc 15, 0, r0, cr1, cr0, {0} */
  1042. htole32(0xe3800001), /* orr r0, r0, #1 */
  1043. htole32(0xe3800a01), /* orr r0, r0, #4096 */
  1044. htole32(0xe3800b02), /* orr r0, r0, #2048 */
  1045. htole32(0xee010f10), /* mcr 15, 0, r0, cr1, cr0, {0} */
  1046. /* Return back to FEL */
  1047. htole32(0xe12fff1e), /* bx lr */
  1048. };
  1049.  
  1050. pr_info("Setting write-combine mapping for DRAM.\n");
  1051. for (i = (DRAM_BASE >> 20); i < ((DRAM_BASE + DRAM_SIZE) >> 20); i++) {
  1052. /* Clear TEXCB bits */
  1053. tt[i] &= ~((7 << 12) | (1 << 3) | (1 << 2));
  1054. /* Set TEXCB to 00100 (Normal uncached mapping) */
  1055. tt[i] |= (1 << 12);
  1056. }
  1057.  
  1058. pr_info("Setting cached mapping for BROM.\n");
  1059. /* Clear TEXCB bits first */
  1060. tt[0xFFF] &= ~((7 << 12) | (1 << 3) | (1 << 2));
  1061. /* Set TEXCB to 00111 (Normal write-back cached mapping) */
  1062. tt[0xFFF] |= (1 << 12) | /* TEX */
  1063. (1 << 3) | /* C */
  1064. (1 << 2); /* B */
  1065.  
  1066. pr_info("Writing back the MMU translation table.\n");
  1067. for (i = 0; i < 4096; i++)
  1068. tt[i] = htole32(tt[i]);
  1069. aw_fel_write(usb, tt, ttbr0, 16 * 1024);
  1070.  
  1071. pr_info("Enabling I-cache, MMU and branch prediction...");
  1072. aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
  1073. aw_fel_execute(usb, sram_info->scratch_addr);
  1074. pr_info(" done.\n");
  1075.  
  1076. free(tt);
  1077. }
  1078.  
  1079. /*
  1080. * Maximum size of SPL, at the same time this is the start offset
  1081. * of the main U-Boot image within u-boot-sunxi-with-spl.bin
  1082. */
  1083. #define SPL_LEN_LIMIT 0x8000
  1084.  
  1085. void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
  1086. uint8_t *buf, size_t len)
  1087. {
  1088. soc_sram_info *sram_info = aw_fel_get_sram_info(usb);
  1089. sram_swap_buffers *swap_buffers;
  1090. char header_signature[9] = { 0 };
  1091. size_t i, thunk_size;
  1092. uint32_t *thunk_buf;
  1093. uint32_t sp, sp_irq;
  1094. uint32_t spl_checksum, spl_len, spl_len_limit = SPL_LEN_LIMIT;
  1095. uint32_t *buf32 = (uint32_t *)buf;
  1096. uint32_t cur_addr = sram_info->spl_addr;
  1097. uint32_t *tt = NULL;
  1098.  
  1099. if (!sram_info || !sram_info->swap_buffers) {
  1100. fprintf(stderr, "SPL: Unsupported SoC type\n");
  1101. exit(1);
  1102. }
  1103.  
  1104. if (len < 32 || memcmp(buf + 4, "eGON.BT0", 8) != 0) {
  1105. fprintf(stderr, "SPL: eGON header is not found\n");
  1106. exit(1);
  1107. }
  1108.  
  1109. spl_checksum = 2 * le32toh(buf32[3]) - 0x5F0A6C39;
  1110. spl_len = le32toh(buf32[4]);
  1111.  
  1112. if (spl_len > len || (spl_len % 4) != 0) {
  1113. fprintf(stderr, "SPL: bad length in the eGON header\n");
  1114. exit(1);
  1115. }
  1116.  
  1117. len = spl_len;
  1118. for (i = 0; i < len / 4; i++)
  1119. spl_checksum -= le32toh(buf32[i]);
  1120.  
  1121. if (spl_checksum != 0) {
  1122. fprintf(stderr, "SPL: checksum check failed\n");
  1123. exit(1);
  1124. }
  1125.  
  1126. if (sram_info->needs_l2en) {
  1127. pr_info("Enabling the L2 cache\n");
  1128. aw_enable_l2_cache(usb, sram_info);
  1129. }
  1130.  
  1131. aw_get_stackinfo(usb, sram_info, &sp_irq, &sp);
  1132. pr_info("Stack pointers: sp_irq=0x%08X, sp=0x%08X\n", sp_irq, sp);
  1133.  
  1134. tt = aw_backup_and_disable_mmu(usb, sram_info);
  1135. if (!tt && sram_info->mmu_tt_addr) {
  1136. if (sram_info->mmu_tt_addr & 0x3FFF) {
  1137. fprintf(stderr, "SPL: 'mmu_tt_addr' must be 16K aligned\n");
  1138. exit(1);
  1139. }
  1140. pr_info("Generating the new MMU translation table at 0x%08X\n",
  1141. sram_info->mmu_tt_addr);
  1142. /*
  1143. * These settings are used by the BROM in A10/A13/A20 and
  1144. * we replicate them here when enabling the MMU. The DACR
  1145. * value 0x55555555 means that accesses are checked against
  1146. * the permission bits in the translation tables for all
  1147. * domains. The TTBCR value 0x00000000 means that the short
  1148. * descriptor translation table format is used, TTBR0 is used
  1149. * for all the possible virtual addresses (N=0) and that the
  1150. * translation table must be aligned at a 16K boundary.
  1151. */
  1152. aw_set_dacr(usb, sram_info, 0x55555555);
  1153. aw_set_ttbcr(usb, sram_info, 0x00000000);
  1154. aw_set_ttbr0(usb, sram_info, sram_info->mmu_tt_addr);
  1155. tt = aw_generate_mmu_translation_table();
  1156. }
  1157.  
  1158. swap_buffers = sram_info->swap_buffers;
  1159. for (i = 0; swap_buffers[i].size; i++) {
  1160. if ((swap_buffers[i].buf2 >= sram_info->spl_addr) &&
  1161. (swap_buffers[i].buf2 < sram_info->spl_addr + spl_len_limit))
  1162. spl_len_limit = swap_buffers[i].buf2 - sram_info->spl_addr;
  1163. if (len > 0 && cur_addr < swap_buffers[i].buf1) {
  1164. uint32_t tmp = swap_buffers[i].buf1 - cur_addr;
  1165. if (tmp > len)
  1166. tmp = len;
  1167. aw_fel_write(usb, buf, cur_addr, tmp);
  1168. cur_addr += tmp;
  1169. buf += tmp;
  1170. len -= tmp;
  1171. }
  1172. if (len > 0 && cur_addr == swap_buffers[i].buf1) {
  1173. uint32_t tmp = swap_buffers[i].size;
  1174. if (tmp > len)
  1175. tmp = len;
  1176. aw_fel_write(usb, buf, swap_buffers[i].buf2, tmp);
  1177. cur_addr += tmp;
  1178. buf += tmp;
  1179. len -= tmp;
  1180. }
  1181. }
  1182.  
  1183. /* Clarify the SPL size limitations, and bail out if they are not met */
  1184. if (sram_info->thunk_addr < spl_len_limit)
  1185. spl_len_limit = sram_info->thunk_addr;
  1186.  
  1187. if (spl_len > spl_len_limit) {
  1188. fprintf(stderr, "SPL: too large (need %d, have %d)\n",
  1189. (int)spl_len, (int)spl_len_limit);
  1190. exit(1);
  1191. }
  1192.  
  1193. /* Write the remaining part of the SPL */
  1194. if (len > 0)
  1195. aw_fel_write(usb, buf, cur_addr, len);
  1196.  
  1197. thunk_size = sizeof(fel_to_spl_thunk) + sizeof(sram_info->spl_addr) +
  1198. (i + 1) * sizeof(*swap_buffers);
  1199.  
  1200. if (thunk_size > sram_info->thunk_size) {
  1201. fprintf(stderr, "SPL: bad thunk size (need %d, have %d)\n",
  1202. (int)sizeof(fel_to_spl_thunk), sram_info->thunk_size);
  1203. exit(1);
  1204. }
  1205.  
  1206. thunk_buf = malloc(thunk_size);
  1207. memcpy(thunk_buf, fel_to_spl_thunk, sizeof(fel_to_spl_thunk));
  1208. memcpy(thunk_buf + sizeof(fel_to_spl_thunk) / sizeof(uint32_t),
  1209. &sram_info->spl_addr, sizeof(sram_info->spl_addr));
  1210. memcpy(thunk_buf + sizeof(fel_to_spl_thunk) / sizeof(uint32_t) + 1,
  1211. swap_buffers, (i + 1) * sizeof(*swap_buffers));
  1212.  
  1213. for (i = 0; i < thunk_size / sizeof(uint32_t); i++)
  1214. thunk_buf[i] = htole32(thunk_buf[i]);
  1215.  
  1216. pr_info("=> Executing the SPL...");
  1217. aw_fel_write(usb, thunk_buf, sram_info->thunk_addr, thunk_size);
  1218. aw_fel_execute(usb, sram_info->thunk_addr);
  1219. pr_info(" done.\n");
  1220.  
  1221. free(thunk_buf);
  1222.  
  1223. /* TODO: Try to find and fix the bug, which needs this workaround */
  1224. usleep(250000);
  1225.  
  1226. /* Read back the result and check if everything was fine */
  1227. aw_fel_read(usb, sram_info->spl_addr + 4, header_signature, 8);
  1228. if (strcmp(header_signature, "eGON.FEL") != 0) {
  1229. fprintf(stderr, "SPL: failure code '%s'\n",
  1230. header_signature);
  1231. exit(1);
  1232. }
  1233.  
  1234. /* re-enable the MMU if it was enabled by BROM */
  1235. if (tt != NULL)
  1236. aw_restore_and_enable_mmu(usb, sram_info, tt);
  1237. }
  1238.  
  1239. /*
  1240. * This function tests a given buffer address and length for a valid U-Boot
  1241. * image. Upon success, the image data gets transferred to the default memory
  1242. * address stored within the image header; and the function preserves the
  1243. * U-Boot entry point (offset) and size values.
  1244. */
  1245. void aw_fel_write_uboot_image(libusb_device_handle *usb,
  1246. uint8_t *buf, size_t len)
  1247. {
  1248. if (len <= HEADER_SIZE)
  1249. return; /* Insufficient size (no actual data), just bail out */
  1250.  
  1251. uint32_t *buf32 = (uint32_t *)buf;
  1252.  
  1253. /* Check for a valid mkimage header */
  1254. int image_type = get_image_type(buf, len);
  1255. if (image_type <= IH_TYPE_INVALID) {
  1256. switch (image_type) {
  1257. case IH_TYPE_INVALID:
  1258. fprintf(stderr, "Invalid U-Boot image: bad size or signature\n");
  1259. break;
  1260. case IH_TYPE_ARCH_MISMATCH:
  1261. fprintf(stderr, "Invalid U-Boot image: wrong architecture\n");
  1262. break;
  1263. default:
  1264. fprintf(stderr, "Invalid U-Boot image: error code %d\n",
  1265. image_type);
  1266. }
  1267. exit(1);
  1268. }
  1269. if (image_type != IH_TYPE_FIRMWARE) {
  1270. fprintf(stderr, "U-Boot image type mismatch: "
  1271. "expected IH_TYPE_FIRMWARE, got %02X\n", image_type);
  1272. exit(1);
  1273. }
  1274. uint32_t data_size = be32toh(buf32[3]); /* Image Data Size */
  1275. uint32_t load_addr = be32toh(buf32[4]); /* Data Load Address */
  1276. if (data_size != len - HEADER_SIZE) {
  1277. fprintf(stderr, "U-Boot image data size mismatch: "
  1278. "expected %zu, got %u\n", len - HEADER_SIZE, data_size);
  1279. exit(1);
  1280. }
  1281. /* TODO: Verify image data integrity using the checksum field ih_dcrc,
  1282. * available from be32toh(buf32[6])
  1283. *
  1284. * However, this requires CRC routines that mimic their U-Boot
  1285. * counterparts, namely image_check_dcrc() in ${U-BOOT}/common/image.c
  1286. * and crc_wd() in ${U-BOOT}/lib/crc32.c
  1287. *
  1288. * It should be investigated if existing CRC routines in sunxi-tools
  1289. * could be factored out and reused for this purpose - e.g. calc_crc32()
  1290. * from nand-part-main.c
  1291. */
  1292.  
  1293. /* If we get here, we're "good to go" (i.e. actually write the data) */
  1294. pr_info("Writing image \"%.*s\", %u bytes @ 0x%08X.\n",
  1295. IH_NMLEN, buf + HEADER_NAME_OFFSET, data_size, load_addr);
  1296.  
  1297. aw_write_buffer(usb, buf + HEADER_SIZE, load_addr, data_size, false);
  1298.  
  1299. /* keep track of U-Boot memory region in global vars */
  1300. uboot_entry = load_addr;
  1301. uboot_size = data_size;
  1302. }
  1303.  
  1304. /*
  1305. * This function handles the common part of both "spl" and "uboot" commands.
  1306. */
  1307. void aw_fel_process_spl_and_uboot(libusb_device_handle *usb,
  1308. const char *filename)
  1309. {
  1310. /* load file into memory buffer */
  1311. size_t size;
  1312. uint8_t *buf = load_file(filename, &size);
  1313. /* write and execute the SPL from the buffer */
  1314. aw_fel_write_and_execute_spl(usb, buf, size);
  1315. /* check for optional main U-Boot binary (and transfer it, if applicable) */
  1316. if (size > SPL_LEN_LIMIT)
  1317. aw_fel_write_uboot_image(usb, buf + SPL_LEN_LIMIT, size - SPL_LEN_LIMIT);
  1318. free(buf);
  1319. }
  1320.  
  1321. /*
  1322. * Test the SPL header for our "sunxi" variant. We want to make sure that
  1323. * we can safely use specific header fields to pass information to U-Boot.
  1324. * In case of a missing signature (e.g. Allwinner boot0) or header version
  1325. * mismatch, this function will return "false". If all seems fine,
  1326. * the result is "true".
  1327. */
  1328. #define SPL_SIGNATURE "SPL" /* marks "sunxi" header */
  1329. #define SPL_MIN_VERSION 1 /* minimum required version */
  1330. #define SPL_MAX_VERSION 1 /* maximum supported version */
  1331. bool have_sunxi_spl(libusb_device_handle *usb, uint32_t spl_addr)
  1332. {
  1333. uint8_t spl_signature[4];
  1334.  
  1335. aw_fel_read(usb, spl_addr + 0x14,
  1336. &spl_signature, sizeof(spl_signature));
  1337.  
  1338. if (memcmp(spl_signature, SPL_SIGNATURE, 3) != 0)
  1339. return false; /* signature mismatch, no "sunxi" SPL */
  1340.  
  1341. if (spl_signature[3] < SPL_MIN_VERSION) {
  1342. fprintf(stderr, "sunxi SPL version mismatch: "
  1343. "found 0x%02X < required minimum 0x%02X\n",
  1344. spl_signature[3], SPL_MIN_VERSION);
  1345. fprintf(stderr, "You need to update your U-Boot (mksunxiboot) to a more recent version.\n");
  1346. return false;
  1347. }
  1348. if (spl_signature[3] > SPL_MAX_VERSION) {
  1349. fprintf(stderr, "sunxi SPL version mismatch: "
  1350. "found 0x%02X > maximum supported 0x%02X\n",
  1351. spl_signature[3], SPL_MAX_VERSION);
  1352. fprintf(stderr, "You need a more recent version of this (sunxi-tools) fel utility.\n");
  1353. return false;
  1354. }
  1355. return true; /* sunxi SPL and suitable version */
  1356. }
  1357.  
  1358. /*
  1359. * Pass information to U-Boot via specialized fields in the SPL header
  1360. * (see "boot_file_head" in ${U-BOOT}/arch/arm/include/asm/arch-sunxi/spl.h),
  1361. * providing the boot script address (DRAM location of boot.scr).
  1362. */
  1363. void pass_fel_information(libusb_device_handle *usb, uint32_t script_address)
  1364. {
  1365. soc_sram_info *sram_info = aw_fel_get_sram_info(usb);
  1366.  
  1367. /* write something _only_ if we have a suitable SPL header */
  1368. if (have_sunxi_spl(usb, sram_info->spl_addr)) {
  1369. pr_info("Passing boot info via sunxi SPL: script address = 0x%08X\n",
  1370. script_address);
  1371. aw_fel_write(usb, &script_address,
  1372. sram_info->spl_addr + 0x18, sizeof(script_address));
  1373. }
  1374. }
  1375.  
  1376. static int aw_fel_get_endpoint(libusb_device_handle *usb)
  1377. {
  1378. struct libusb_device *dev = libusb_get_device(usb);
  1379. struct libusb_config_descriptor *config;
  1380. int if_idx, set_idx, ep_idx, ret;
  1381.  
  1382. ret = libusb_get_active_config_descriptor(dev, &config);
  1383. if (ret)
  1384. return ret;
  1385.  
  1386. for (if_idx = 0; if_idx < config->bNumInterfaces; if_idx++) {
  1387. const struct libusb_interface *iface = config->interface + if_idx;
  1388.  
  1389. for (set_idx = 0; set_idx < iface->num_altsetting; set_idx++) {
  1390. const struct libusb_interface_descriptor *setting =
  1391. iface->altsetting + set_idx;
  1392.  
  1393. for (ep_idx = 0; ep_idx < setting->bNumEndpoints; ep_idx++) {
  1394. const struct libusb_endpoint_descriptor *ep =
  1395. setting->endpoint + ep_idx;
  1396.  
  1397. /* Test for bulk transfer endpoint */
  1398. if ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) !=
  1399. LIBUSB_TRANSFER_TYPE_BULK)
  1400. continue;
  1401.  
  1402. if ((ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
  1403. LIBUSB_ENDPOINT_IN)
  1404. AW_USB_FEL_BULK_EP_IN = ep->bEndpointAddress;
  1405. else
  1406. AW_USB_FEL_BULK_EP_OUT = ep->bEndpointAddress;
  1407. }
  1408. }
  1409. }
  1410.  
  1411. libusb_free_config_descriptor(config);
  1412.  
  1413. return 0;
  1414. }
  1415.  
  1416. /*
  1417. * This function stores a given entry point to the RVBAR address for CPU0,
  1418. * and then writes the Reset Management Register to request a warm boot.
  1419. * It is useful with some AArch64 transitions, e.g. when passing control to
  1420. * ARM Trusted Firmware (ATF) during the boot process of Pine64.
  1421. *
  1422. * The code was inspired by
  1423. * https://github.com/apritzel/u-boot/commit/fda6bd1bf285c44f30ea15c7e6231bf53c31d4a8
  1424. */
  1425. void aw_rmr_request(libusb_device_handle *usb, uint32_t entry_point, bool aarch64)
  1426. {
  1427. soc_sram_info *soc_info = aw_fel_get_sram_info(usb);
  1428. if (!soc_info->rvbar_reg) {
  1429. fprintf(stderr, "ERROR: Can't issue RMR request!\n"
  1430. "RVBAR is not supported or unknown for your SoC (id=%04X).\n",
  1431. soc_info->soc_id);
  1432. return;
  1433. }
  1434.  
  1435. uint32_t rmr_mode = (1 << 1) | (aarch64 ? 1 : 0); /* RR, AA64 flag */
  1436. uint32_t arm_code[] = {
  1437. htole32(0xe59f0028), /* ldr r0, [rvbar_reg] */
  1438. htole32(0xe59f1028), /* ldr r1, [entry_point] */
  1439. htole32(0xe5801000), /* str r1, [r0] */
  1440. htole32(0xf57ff04f), /* dsb sy */
  1441. htole32(0xf57ff06f), /* isb sy */
  1442.  
  1443. htole32(0xe59f101c), /* ldr r1, [rmr_mode] */
  1444. htole32(0xee1c0f50), /* mrc 15, 0, r0, cr12, cr0, {2}*/
  1445. htole32(0xe1800001), /* orr r0, r0, r1 */
  1446. htole32(0xee0c0f50), /* mcr 15, 0, r0, cr12, cr0, {2}*/
  1447. htole32(0xf57ff06f), /* isb sy */
  1448.  
  1449. htole32(0xe320f003), /* loop: wfi */
  1450. htole32(0xeafffffd), /* b <loop> */
  1451.  
  1452. htole32(soc_info->rvbar_reg),
  1453. htole32(entry_point),
  1454. htole32(rmr_mode)
  1455. };
  1456. /* scratch buffer setup: transfers ARM code and parameter values */
  1457. aw_fel_write(usb, arm_code, soc_info->scratch_addr, sizeof(arm_code));
  1458. /* execute the thunk code (triggering a warm reset on the SoC) */
  1459. pr_info("Store entry point 0x%08X to RVBAR 0x%08X, "
  1460. "and request warm reset with RMR mode %u...",
  1461. entry_point, soc_info->rvbar_reg, rmr_mode);
  1462. aw_fel_execute(usb, soc_info->scratch_addr);
  1463. pr_info(" done.\n");
  1464. }
  1465.  
  1466. /* private helper function, gets used for "write*" and "multi*" transfers */
  1467. static unsigned int file_upload(libusb_device_handle *handle, size_t count,
  1468. size_t argc, char **argv, progress_cb_t progress)
  1469. {
  1470. if (argc < count * 2) {
  1471. fprintf(stderr, "error: too few arguments for uploading %zu files\n",
  1472. count);
  1473. exit(1);
  1474. }
  1475.  
  1476. /* get all file sizes, keeping track of total bytes */
  1477. size_t size = 0;
  1478. unsigned int i;
  1479. for (i = 0; i < count; i++)
  1480. size += file_size(argv[i * 2 + 1]);
  1481.  
  1482. progress_start(progress, size); /* set total size and progress callback */
  1483.  
  1484. /* now transfer each file in turn */
  1485. for (i = 0; i < count; i++) {
  1486. void *buf = load_file(argv[i * 2 + 1], &size);
  1487. if (size > 0) {
  1488. uint32_t offset = strtoul(argv[i * 2], NULL, 0);
  1489. aw_write_buffer(handle, buf, offset, size, true);
  1490.  
  1491. /* If we transferred a script, try to inform U-Boot about its address. */
  1492. if (get_image_type(buf, size) == IH_TYPE_SCRIPT)
  1493. pass_fel_information(handle, offset);
  1494. }
  1495. free(buf);
  1496. }
  1497.  
  1498. return i; /* return number of files that were processed */
  1499. }
  1500.  
  1501. /* open libusb handle to desired FEL device */
  1502. static libusb_device_handle *open_fel_device(int busnum, int devnum,
  1503. uint16_t vendor_id, uint16_t product_id)
  1504. {
  1505. libusb_device_handle *result = NULL;
  1506.  
  1507. if (busnum < 0 || devnum < 0) {
  1508. /* With the default values (busnum -1, devnum -1) we don't care
  1509. * for a specific USB device; so let libusb open the first
  1510. * device that matches VID/PID.
  1511. */
  1512. result = libusb_open_device_with_vid_pid(NULL, vendor_id, product_id);
  1513. if (!result) {
  1514. switch (errno) {
  1515. case EACCES:
  1516. fprintf(stderr, "ERROR: You don't have permission to access Allwinner USB FEL device\n");
  1517. break;
  1518. default:
  1519. fprintf(stderr, "ERROR: Allwinner USB FEL device not found!\n");
  1520. break;
  1521. }
  1522. exit(1);
  1523. }
  1524. return result;
  1525. }
  1526.  
  1527. /* look for specific bus and device number */
  1528. pr_info("Selecting USB Bus %03d Device %03d\n", busnum, devnum);
  1529. bool found = false;
  1530. ssize_t rc, i;
  1531. libusb_device **list;
  1532.  
  1533. rc = libusb_get_device_list(NULL, &list);
  1534. if (rc < 0)
  1535. usb_error(rc, "libusb_get_device_list()", 1);
  1536. for (i = 0; i < rc; i++) {
  1537. if (libusb_get_bus_number(list[i]) == busnum
  1538. && libusb_get_device_address(list[i]) == devnum) {
  1539. found = true; /* bus:devnum matched */
  1540. struct libusb_device_descriptor desc;
  1541. libusb_get_device_descriptor(list[i], &desc);
  1542. if (desc.idVendor != vendor_id
  1543. || desc.idProduct != product_id) {
  1544. fprintf(stderr, "ERROR: Bus %03d Device %03d not a FEL device "
  1545. "(expected %04x:%04x, got %04x:%04x)\n", busnum, devnum,
  1546. vendor_id, product_id, desc.idVendor, desc.idProduct);
  1547. exit(1);
  1548. }
  1549. /* open handle to this specific device (incrementing its refcount) */
  1550. rc = libusb_open(list[i], &result);
  1551. if (rc != 0)
  1552. usb_error(rc, "libusb_open()", 1);
  1553. break;
  1554. }
  1555. }
  1556. libusb_free_device_list(list, true);
  1557.  
  1558. if (!found) {
  1559. fprintf(stderr, "ERROR: Bus %03d Device %03d not found in libusb device list\n",
  1560. busnum, devnum);
  1561. exit(1);
  1562. }
  1563. return result;
  1564. }
  1565.  
  1566. int main(int argc, char **argv)
  1567. {
  1568. bool uboot_autostart = false; /* flag for "uboot" command = U-Boot autostart */
  1569. bool pflag_active = false; /* -p switch, causing "write" to output progress */
  1570. libusb_device_handle *handle;
  1571. int busnum = -1, devnum = -1;
  1572. #if defined(__linux__)
  1573. int iface_detached = -1;
  1574. #endif
  1575.  
  1576. if (argc <= 1) {
  1577. printf("Usage: %s [options] command arguments... [command...]\n"
  1578. " -v, --verbose Verbose logging\n"
  1579. " -p, --progress \"write\" transfers show a progress bar\n"
  1580. " -d, --dev bus:devnum Use specific USB bus and device number\n"
  1581. "\n"
  1582. " spl file Load and execute U-Boot SPL\n"
  1583. " If file additionally contains a main U-Boot binary\n"
  1584. " (u-boot-sunxi-with-spl.bin), this command also transfers that\n"
  1585. " to memory (default address from image), but won't execute it.\n"
  1586. "\n"
  1587. " uboot file-with-spl like \"spl\", but actually starts U-Boot\n"
  1588. " U-Boot execution will take place when the fel utility exits.\n"
  1589. " This allows combining \"uboot\" with further \"write\" commands\n"
  1590. " (to transfer other files needed for the boot).\n"
  1591. "\n"
  1592. " hex[dump] address length Dumps memory region in hex\n"
  1593. " dump address length Binary memory dump\n"
  1594. " exe[cute] address Call function address\n"
  1595. " reset64 address RMR request for AArch64 warm boot\n"
  1596. " readl address Read 32-bit value from device memory\n"
  1597. " writel address value Write 32-bit value to device memory\n"
  1598. " read address length file Write memory contents into file\n"
  1599. " write address file Store file contents into memory\n"
  1600. " write-with-progress addr file \"write\" with progress bar\n"
  1601. " write-with-gauge addr file Output progress for \"dialog --gauge\"\n"
  1602. " write-with-xgauge addr file Extended gauge output (updates prompt)\n"
  1603. " multi[write] # addr file ... \"write-with-progress\" multiple files,\n"
  1604. " sharing a common progress status\n"
  1605. " multi[write]-with-gauge ... like their \"write-with-*\" counterpart,\n"
  1606. " multi[write]-with-xgauge ... but following the 'multi' syntax:\n"
  1607. " <#> addr file [addr file [...]]\n"
  1608. " echo-gauge \"some text\" Update prompt/caption for gauge output\n"
  1609. " ver[sion] Show BROM version\n"
  1610. " sid Retrieve and output 128-bit SID key\n"
  1611. " clear address length Clear memory\n"
  1612. " fill address length value Fill memory\n"
  1613. , argv[0]
  1614. );
  1615. exit(0);
  1616. }
  1617.  
  1618. /* process all "prefix"-type arguments first */
  1619. while (argc > 1) {
  1620. if (strcmp(argv[1], "--verbose") == 0 || strcmp(argv[1], "-v") == 0)
  1621. verbose = true;
  1622. else if (strcmp(argv[1], "--progress") == 0 || strcmp(argv[1], "-p") == 0)
  1623. pflag_active = true;
  1624. else if (strncmp(argv[1], "--dev", 5) == 0 || strncmp(argv[1], "-d", 2) == 0) {
  1625. char *dev_arg = argv[1];
  1626. dev_arg += strspn(dev_arg, "-dev="); /* skip option chars, ignore '=' */
  1627. if (*dev_arg == 0 && argc > 2) { /* at end of argument, use the next one instead */
  1628. dev_arg = argv[2];
  1629. argc -= 1;
  1630. argv += 1;
  1631. }
  1632. if (sscanf(dev_arg, "%d:%d", &busnum, &devnum) != 2
  1633. || busnum <= 0 || devnum <= 0) {
  1634. fprintf(stderr, "ERROR: Expected 'bus:devnum', got '%s'.\n", dev_arg);
  1635. exit(1);
  1636. }
  1637. } else
  1638. break; /* no valid (prefix) option detected, exit loop */
  1639. argc -= 1;
  1640. argv += 1;
  1641. }
  1642.  
  1643. int rc = libusb_init(NULL);
  1644. assert(rc == 0);
  1645. handle = open_fel_device(busnum, devnum, AW_USB_VENDOR_ID, AW_USB_PRODUCT_ID);
  1646. assert(handle != NULL);
  1647. rc = libusb_claim_interface(handle, 0);
  1648. #if defined(__linux__)
  1649. if (rc != LIBUSB_SUCCESS) {
  1650. libusb_detach_kernel_driver(handle, 0);
  1651. iface_detached = 0;
  1652. rc = libusb_claim_interface(handle, 0);
  1653. }
  1654. #endif
  1655. assert(rc == 0);
  1656.  
  1657. if (aw_fel_get_endpoint(handle)) {
  1658. fprintf(stderr, "ERROR: Failed to get FEL mode endpoint addresses!\n");
  1659. exit(1);
  1660. }
  1661.  
  1662. while (argc > 1 ) {
  1663. int skip = 1;
  1664.  
  1665. if (strncmp(argv[1], "hex", 3) == 0 && argc > 3) {
  1666. aw_fel_hexdump(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0));
  1667. skip = 3;
  1668. } else if (strncmp(argv[1], "dump", 4) == 0 && argc > 3) {
  1669. aw_fel_dump(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0));
  1670. skip = 3;
  1671. } else if (strcmp(argv[1], "readl") == 0 && argc > 2) {
  1672. printf("0x%08x\n", aw_fel_readl(handle, strtoul(argv[2], NULL, 0)));
  1673. skip = 2;
  1674. } else if (strcmp(argv[1], "writel") == 0 && argc > 3) {
  1675. aw_fel_writel(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0));
  1676. skip = 3;
  1677. } else if (strncmp(argv[1], "exe", 3) == 0 && argc > 2) {
  1678. aw_fel_execute(handle, strtoul(argv[2], NULL, 0));
  1679. skip=3;
  1680. } else if (strcmp(argv[1], "reset64") == 0 && argc > 2) {
  1681. aw_rmr_request(handle, strtoul(argv[2], NULL, 0), true);
  1682. /* Cancel U-Boot autostart, and stop processing args */
  1683. uboot_autostart = false;
  1684. break;
  1685. } else if (strncmp(argv[1], "ver", 3) == 0) {
  1686. aw_fel_print_version(handle);
  1687. } else if (strcmp(argv[1], "sid") == 0) {
  1688. aw_fel_print_sid(handle);
  1689. } else if (strcmp(argv[1], "write") == 0 && argc > 3) {
  1690. skip += 2 * file_upload(handle, 1, argc - 2, argv + 2,
  1691. pflag_active ? progress_bar : NULL);
  1692. } else if (strcmp(argv[1], "write-with-progress") == 0 && argc > 3) {
  1693. skip += 2 * file_upload(handle, 1, argc - 2, argv + 2,
  1694. progress_bar);
  1695. } else if (strcmp(argv[1], "write-with-gauge") == 0 && argc > 3) {
  1696. skip += 2 * file_upload(handle, 1, argc - 2, argv + 2,
  1697. progress_gauge);
  1698. } else if (strcmp(argv[1], "write-with-xgauge") == 0 && argc > 3) {
  1699. skip += 2 * file_upload(handle, 1, argc - 2, argv + 2,
  1700. progress_gauge_xxx);
  1701. } else if ((strcmp(argv[1], "multiwrite") == 0 ||
  1702. strcmp(argv[1], "multi") == 0) && argc > 4) {
  1703. size_t count = strtoul(argv[2], NULL, 0); /* file count */
  1704. skip = 2 + 2 * file_upload(handle, count, argc - 3,
  1705. argv + 3, progress_bar);
  1706. } else if ((strcmp(argv[1], "multiwrite-with-gauge") == 0 ||
  1707. strcmp(argv[1], "multi-with-gauge") == 0) && argc > 4) {
  1708. size_t count = strtoul(argv[2], NULL, 0); /* file count */
  1709. skip = 2 + 2 * file_upload(handle, count, argc - 3,
  1710. argv + 3, progress_gauge);
  1711. } else if ((strcmp(argv[1], "multiwrite-with-xgauge") == 0 ||
  1712. strcmp(argv[1], "multi-with-xgauge") == 0) && argc > 4) {
  1713. size_t count = strtoul(argv[2], NULL, 0); /* file count */
  1714. skip = 2 + 2 * file_upload(handle, count, argc - 3,
  1715. argv + 3, progress_gauge_xxx);
  1716. } else if ((strcmp(argv[1], "echo-gauge") == 0) && argc > 2) {
  1717. skip = 2;
  1718. printf("XXX\n0\n%s\nXXX\n", argv[2]);
  1719. fflush(stdout);
  1720. } else if (strcmp(argv[1], "read") == 0 && argc > 4) {
  1721. size_t size = strtoul(argv[3], NULL, 0);
  1722. void *buf = malloc(size);
  1723. aw_fel_read(handle, strtoul(argv[2], NULL, 0), buf, size);
  1724. save_file(argv[4], buf, size);
  1725. free(buf);
  1726. skip=4;
  1727. } else if (strcmp(argv[1], "clear") == 0 && argc > 2) {
  1728. aw_fel_fill(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0), 0);
  1729. skip=3;
  1730. } else if (strcmp(argv[1], "fill") == 0 && argc > 3) {
  1731. aw_fel_fill(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0), (unsigned char)strtoul(argv[4], NULL, 0));
  1732. skip=4;
  1733. } else if (strcmp(argv[1], "spl") == 0 && argc > 2) {
  1734. aw_fel_process_spl_and_uboot(handle, argv[2]);
  1735. skip=2;
  1736. } else if (strcmp(argv[1], "uboot") == 0 && argc > 2) {
  1737. aw_fel_process_spl_and_uboot(handle, argv[2]);
  1738. uboot_autostart = (uboot_entry > 0 && uboot_size > 0);
  1739. if (!uboot_autostart)
  1740. printf("Warning: \"uboot\" command failed to detect image! Can't execute U-Boot.\n");
  1741. skip=2;
  1742. } else {
  1743. fprintf(stderr,"Invalid command %s\n", argv[1]);
  1744. exit(1);
  1745. }
  1746. argc-=skip;
  1747. argv+=skip;
  1748. }
  1749.  
  1750. /* auto-start U-Boot if requested (by the "uboot" command) */
  1751. if (uboot_autostart) {
  1752. pr_info("Starting U-Boot (0x%08X).\n", uboot_entry);
  1753. aw_fel_execute(handle, uboot_entry);
  1754. }
  1755.  
  1756. libusb_release_interface(handle, 0);
  1757. #if defined(__linux__)
  1758. if (iface_detached >= 0)
  1759. libusb_attach_kernel_driver(handle, iface_detached);
  1760. #endif
  1761. libusb_close(handle);
  1762. libusb_exit(NULL);
  1763.  
  1764. return 0;
  1765. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement