Hi,

On 02/24/2015 03:18 AM, Siarhei Siamashka wrote:
The FEL BROM code has the MMU enabled for some reason (while
I-cache and D-cache are disabled). Most likely the intention was
to get a somewhat better performance. Everything is mapped as
TEXCB=00000 (strongly ordered), except for the 0x00000000 (SRAM)
and 0xFFF00000 (BROM) sections, which are mapped as TEXCB=00100
(normal uncached memory).

This becomes a problem for the A13 SoC, because it has less SRAM
than the other chips. A13 stores the MMU addresses translation
table at 0x8000 and uses up 16 KiB of the SRAM space there (while
the A10, A20 and A31s keep the MMU table in the secure SRAM at
0x20000). And because the 'spl' command needs space for backing
up the FEL stacks, it was clashing with the MMU table.

The solution is simple. We just backup the addresses translation
table and disable the MMU before running the SPL. And then restore
it back to the original state. This fixes problems on A13.

Re-enabling the MMU in the end is only necessary to avoid performance
losses. For example, the transfer speed of the 'fel write' command
on A20 would drop from ~320 KB/s to ~260 KB/s without MMU.

Signed-off-by: Siarhei Siamashka <siarhei.siamas...@gmail.com>

Hmm, this is not ideal, but seems to be the only way, so:

Acked-by: Hans de Goede <hdego...@redhat.com>

Regards,

Hans


---
  fel.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 127 insertions(+)

diff --git a/fel.c b/fel.c
index 0942deb..e4d01a1 100644
--- a/fel.c
+++ b/fel.c
@@ -429,6 +429,126 @@ static uint32_t fel_to_spl_thunk[] = {
        #include "fel-to-spl-thunk.h"
  };

+#define        FEL_EXEC_SCRATCH_AREA   0x2000
+#define        DRAM_BASE               0x40000000
+#define        DRAM_SIZE               0x80000000
+
+uint32_t aw_get_ttbr0(libusb_device_handle *usb)
+{
+       uint32_t ttbr0 = 0;
+       uint32_t arm_code[] = {
+               htole32(0xee122f10), /* mrc        15, 0, r2, cr2, cr0, {0}  */
+               htole32(0xe58f2008), /* str        r2, [pc, #8]              */
+               htole32(0xe12fff1e), /* bx         lr                        */
+       };
+
+       aw_fel_write(usb, arm_code, FEL_EXEC_SCRATCH_AREA, sizeof(arm_code));
+       aw_fel_execute(usb, FEL_EXEC_SCRATCH_AREA);
+       aw_fel_read(usb, 0x2014, &ttbr0, sizeof(ttbr0));
+       ttbr0 = le32toh(ttbr0);
+       return ttbr0;
+}
+
+uint32_t aw_get_sctlr(libusb_device_handle *usb)
+{
+       uint32_t sctlr = 0;
+       uint32_t arm_code[] = {
+               htole32(0xee112f10), /* mrc        15, 0, r2, cr1, cr0, {0}  */
+               htole32(0xe58f2008), /* str        r2, [pc, #8]              */
+               htole32(0xe12fff1e), /* bx         lr                        */
+       };
+
+       aw_fel_write(usb, arm_code, FEL_EXEC_SCRATCH_AREA, sizeof(arm_code));
+       aw_fel_execute(usb, FEL_EXEC_SCRATCH_AREA);
+       aw_fel_read(usb, 0x2014, &sctlr, sizeof(sctlr));
+       sctlr = le32toh(sctlr);
+       return sctlr;
+}
+
+uint32_t *aw_backup_and_disable_mmu(libusb_device_handle *usb)
+{
+       uint32_t *tt = malloc(16 * 1024);
+       uint32_t ttbr0 = aw_get_ttbr0(usb);
+       uint32_t sctlr = aw_get_sctlr(usb);
+       uint32_t i;
+
+       uint32_t arm_code[] = {
+               /* Disable MMU */
+               htole32(0xee110f10), /* mrc        15, 0, r0, cr1, cr0, {0}  */
+               htole32(0xe3c00001), /* bic        r0, r0, #1                */
+               htole32(0xee010f10), /* mcr        15, 0, r0, cr1, cr0, {0}  */
+               /* Return back to FEL */
+               htole32(0xe12fff1e), /* bx         lr                        */
+       };
+
+       if (!(sctlr & 1)) {
+               fprintf(stderr, "MMU is not enabled by BROM\n");
+               exit(1);
+       }
+
+       if ((sctlr >> 28) & 1) {
+               fprintf(stderr, "TEX remap is enabled!\n");
+               exit(1);
+       }
+
+       if (ttbr0 & 0x3FFF) {
+               fprintf(stderr, "Unexpected TTBR0 (%08X)\n", ttbr0);
+               exit(1);
+       }
+
+       pr_info("Reading the MMU translation table from 0x%08X\n", ttbr0);
+       aw_fel_read(usb, ttbr0, tt, 16 * 1024);
+       for (i = 0; i < 4096; i++)
+               tt[i] = le32toh(tt[i]);
+
+       /* Basic sanity checks to be sure that this is a valid table */
+       for (i = 0; i < 4096; i++) {
+               if (((tt[i] >> 1) & 1) != 1 || ((tt[i] >> 18) & 1) != 0) {
+                       fprintf(stderr, "MMU: not a section descriptor\n");
+                       exit(1);
+               }
+               if ((tt[i] >> 20) != i) {
+                       fprintf(stderr, "MMU: not a direct mapping\n");
+                       exit(1);
+               }
+       }
+
+       pr_info("Disabling MMU...");
+       aw_fel_write(usb, arm_code, FEL_EXEC_SCRATCH_AREA, sizeof(arm_code));
+       aw_fel_execute(usb, FEL_EXEC_SCRATCH_AREA);
+       pr_info(" done.\n");
+
+       return tt;
+}
+
+void aw_restore_and_enable_mmu(libusb_device_handle *usb, uint32_t *tt)
+{
+       uint32_t i;
+       uint32_t ttbr0 = aw_get_ttbr0(usb);
+
+       uint32_t arm_code[] = {
+               /* Enable MMU */
+               htole32(0xee110f10), /* mrc        15, 0, r0, cr1, cr0, {0}  */
+               htole32(0xe3800001), /* orr        r0, r0, #1                */
+               htole32(0xee010f10), /* mcr        15, 0, r0, cr1, cr0, {0}  */
+               /* Return back to FEL */
+               htole32(0xe12fff1e), /* bx         lr                        */
+       };
+
+       pr_info("Writing back the MMU translation table.\n");
+       for (i = 0; i < 4096; i++)
+               tt[i] = htole32(tt[i]);
+       aw_fel_write(usb, tt, ttbr0, 16 * 1024);
+
+       pr_info("Enabling MMU...");
+       aw_fel_write(usb, arm_code, FEL_EXEC_SCRATCH_AREA, sizeof(arm_code));
+       aw_fel_execute(usb, FEL_EXEC_SCRATCH_AREA);
+       pr_info(" done.\n");
+
+       free(tt);
+}
+
+
  void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
                                  uint8_t *buf, size_t len)
  {
@@ -440,6 +560,7 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
        uint32_t spl_checksum, spl_len, spl_len_limit = 0x8000;
        uint32_t *buf32 = (uint32_t *)buf;
        uint32_t written = 0;
+       uint32_t *tt = NULL;

        if (!sram_info || !sram_info->swap_buffers) {
                fprintf(stderr, "SPL: Unsupported SoC type\n");
@@ -468,6 +589,8 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
                exit(1);
        }

+       tt = aw_backup_and_disable_mmu(usb);
+
        swap_buffers = sram_info->swap_buffers;
        for (i = 0; swap_buffers[i].size; i++) {
                if (swap_buffers[i].buf2 < spl_len_limit)
@@ -522,8 +645,10 @@ void aw_fel_write_and_execute_spl(libusb_device_handle 
*usb,
        for (i = 0; i < thunk_size / sizeof(uint32_t); i++)
                thunk_buf[i] = htole32(thunk_buf[i]);

+       pr_info("=> Executing the SPL...");
        aw_fel_write(usb, thunk_buf, sram_info->thunk_addr, thunk_size);
        aw_fel_execute(usb, sram_info->thunk_addr);
+       pr_info(" done.\n");

        free(thunk_buf);

@@ -537,6 +662,8 @@ void aw_fel_write_and_execute_spl(libusb_device_handle *usb,
                        header_signature);
                exit(1);
        }
+
+       aw_restore_and_enable_mmu(usb, tt);
  }

  static int aw_fel_get_endpoint(libusb_device_handle *usb)


--
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to