The BROM in newer SoC variants doesn't enable MMU by default anymore.
So in order to benefit from e4b3da2b17ee9d7c5cab9b80e708b3a309fc4c96
("fel: Faster USB transfers via 'fel write' to DRAM"), we need to
be able to enable it from the 'sunxi-fel' tool.

Signed-off-by: Siarhei Siamashka <siarhei.siamas...@gmail.com>
---
 fel.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/fel.c b/fel.c
index e9f6450..916afdf 100644
--- a/fel.c
+++ b/fel.c
@@ -388,6 +388,18 @@ typedef struct {
  * Note: the entries in the 'swap_buffers' tables need to be sorted by 'buf1'
  * addresses. And the 'buf1' addresses are the BROM data buffers, while 'buf2'
  * addresses are the intended backup locations.
+ *
+ * Also for performance reasons, we want to have MMU enabled with optimal
+ * section attributes configured (the code from the BROM should use I-cache,
+ * writing data to the DRAM area should use write combining). The reason is
+ * that the BROM FEL protocol implementation relies on a memcpy loop somewhere
+ * on the perfromance critical path when transferring data over USB. The older
+ * SoC variants (A10/A13/A20/A31/A23) already have MMU enabled and we only need
+ * to adjust section attributes. The BROM in newer SoC variants (A33/A83T/H3)
+ * doesn't enable MMU anymore, so we need to find some 16K of spare space in
+ * SRAM to place the translation table there and specify it as the 
'mmu_tt_addr'
+ * field in the 'soc_sram_info' structure. This is only an optional performance
+ * feature.
  */
 typedef struct {
        uint32_t           soc_id;       /* ID of the SoC */
@@ -396,6 +408,7 @@ typedef struct {
        uint32_t           thunk_addr;   /* Address of the thunk code */
        uint32_t           thunk_size;   /* Maximal size of the thunk code */
        uint32_t           needs_l2en;   /* Set the L2EN bit */
+       uint32_t           mmu_tt_addr;  /* MMU translation table address */
        sram_swap_buffers *swap_buffers;
 } soc_sram_info;
 
@@ -600,6 +613,21 @@ uint32_t aw_get_ttbr0(libusb_device_handle *usb, 
soc_sram_info *sram_info)
        return ttbr0;
 }
 
+void aw_set_ttbr0(libusb_device_handle *usb, soc_sram_info *sram_info,
+                 uint32_t ttbr0)
+{
+       uint32_t arm_code[] = {
+               htole32(0xe59f200c), /* ldr        r2, [pc, #12]             */
+               htole32(0xee022f10), /* mcr        15, 0, r2, cr2, cr0, {0}  */
+               htole32(0xe12fff1e), /* bx         lr                        */
+       };
+
+       ttbr0 = htole32(ttbr0);
+       aw_fel_write(usb, arm_code, sram_info->scratch_addr, sizeof(arm_code));
+       aw_fel_write(usb, &ttbr0, sram_info->scratch_addr + 0x14, 
sizeof(ttbr0));
+       aw_fel_execute(usb, sram_info->scratch_addr);
+}
+
 uint32_t aw_get_sctlr(libusb_device_handle *usb, soc_sram_info *sram_info)
 {
        uint32_t sctlr = 0;
@@ -616,6 +644,20 @@ uint32_t aw_get_sctlr(libusb_device_handle *usb, 
soc_sram_info *sram_info)
        return sctlr;
 }
 
+uint32_t *aw_generate_mmu_translation_table(void)
+{
+       uint32_t *tt = malloc(16 * 1024);
+       uint32_t i;
+
+       /* The same MMU translation table as used by the A20 BROM */
+       for (i = 0; i < 4096; i++)
+               tt[i] = 0x00000DE2 | (i << 20);
+       tt[0x000] |= 0x1000;
+       tt[0xFFF] |= 0x1000;
+
+       return tt;
+}
+
 uint32_t *aw_backup_and_disable_mmu(libusb_device_handle *usb,
                                     soc_sram_info *sram_info)
 {
@@ -786,6 +828,12 @@ void aw_fel_write_and_execute_spl(libusb_device_handle 
*usb,
        pr_info("Stack pointers: sp_irq=0x%08X, sp=0x%08X\n", sp_irq, sp);
 
        tt = aw_backup_and_disable_mmu(usb, sram_info);
+       if (!tt && sram_info->mmu_tt_addr) {
+               pr_info("Generating the new MMU translation table at 0x%08X\n",
+                       sram_info->mmu_tt_addr);
+               tt = aw_generate_mmu_translation_table();
+               aw_set_ttbr0(usb, sram_info, sram_info->mmu_tt_addr);
+       }
 
        swap_buffers = sram_info->swap_buffers;
        for (i = 0; swap_buffers[i].size; i++) {
-- 
2.4.10

-- 
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