diff --git a/bootloader/config/config.c b/bootloader/config/config.c
index 38f88db..810e2d3 100644
--- a/bootloader/config/config.c
+++ b/bootloader/config/config.c
@@ -42,6 +42,8 @@ void set_default_configuration()
h_cfg.backlight = 100;
h_cfg.autohosoff = 0;
h_cfg.autonogc = 1;
+ h_cfg.brand = NULL;
+ h_cfg.tagline = NULL;
h_cfg.errors = 0;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
h_cfg.rcm_patched = true;
@@ -104,6 +106,16 @@ int create_config_entry()
f_puts("\nautonogc=", &fp);
itoa(h_cfg.autonogc, lbuf, 10);
f_puts(lbuf, &fp);
+ if (h_cfg.brand)
+ {
+ f_puts("\nbrand=", &fp);
+ f_puts(h_cfg.brand, &fp);
+ }
+ if (h_cfg.tagline)
+ {
+ f_puts("\ntagline=", &fp);
+ f_puts(h_cfg.tagline, &fp);
+ }
f_puts("\n", &fp);
if (mainIniFound)
diff --git a/bootloader/config/config.h b/bootloader/config/config.h
index 435c1ee..c972765 100644
--- a/bootloader/config/config.h
+++ b/bootloader/config/config.h
@@ -29,6 +29,8 @@ typedef struct _hekate_config
u32 backlight;
u32 autohosoff;
u32 autonogc;
+ char *brand;
+ char *tagline;
// Global temporary config.
bool se_keygen_done;
u32 sbar_time_keeping;
diff --git a/bootloader/hos/hos.c b/bootloader/hos/hos.c
index 56ae936..aa39205 100644
--- a/bootloader/hos/hos.c
+++ b/bootloader/hos/hos.c
@@ -32,6 +32,7 @@
#include "../sec/se.h"
#include "../sec/se_t210.h"
#include "../sec/tsec.h"
+#include "../soc/bpmp.h"
#include "../soc/cluster.h"
#include "../soc/fuse.h"
#include "../soc/pmc.h"
@@ -677,6 +678,9 @@ int hos_launch(ini_sec_t *cfg)
// Clear EMC_SCRATCH0.
EMC(EMC_SCRATCH0) = 0;
+ // Flush cache and disable MMU.
+ bpmp_mmu_disable();
+ bpmp_clk_rate_set(BPMP_CLK_NORMAL);
minerva_change_freq(FREQ_800);
// Wait for secmon to get ready.
diff --git a/bootloader/main.c b/bootloader/main.c
index 36276fd..9cfe0a0 100644
--- a/bootloader/main.c
+++ b/bootloader/main.c
@@ -35,6 +35,7 @@
#include "mem/sdram.h"
#include "power/max77620.h"
#include "rtc/max77620-rtc.h"
+#include "soc/bpmp.h"
#include "soc/fuse.h"
#include "soc/hw_init.h"
#include "soc/i2c.h"
@@ -71,6 +72,8 @@ const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver
.rsvd1 = 0
};
+volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
+
bool sd_mount()
{
if (sd_mounted)
@@ -691,8 +694,56 @@ out:
btn_wait();
}
+void nyx_load_run()
+{
+ sd_mount();
+
+ u8 *nyx = sd_file_read("bootloader/sys/nyx.bin", false);
+ if (!nyx)
+ return;
+
+ sd_unmount();
+
+ gfx_clear_grey(0x1B);
+ u8 *BOOTLOGO = (void *)malloc(0x4000);
+ blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO);
+ gfx_set_rect_grey(BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544);
+ free(BOOTLOGO);
+ display_backlight_brightness(h_cfg.backlight, 1000);
+
+ nyx_str->cfg = 0;
+ if (b_cfg.extra_cfg & EXTRA_CFG_NYX_DUMP)
+ {
+ b_cfg.extra_cfg &= ~(EXTRA_CFG_NYX_DUMP);
+ nyx_str->cfg |= NYX_CFG_DUMP;
+ }
+ if (nyx_str->mtc_cfg.mtc_table)
+ nyx_str->cfg |= NYX_CFG_MINERVA;
+
+ nyx_str->version = ipl_ver.version - 0x303030;
+
+ memcpy((u8 *)nyx_str->irama, (void *)IRAM_BASE, 0x8000);
+ volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
+ memcpy((u8 *)nyx_str->hekate, (u8 *)reloc->start, reloc->end - reloc->start);
+
+ void (*nyx_ptr)() = (void *)nyx;
+
+ bpmp_mmu_disable();
+ bpmp_clk_rate_set(BPMP_CLK_NORMAL);
+ msleep(100);
+ minerva_periodic_training();
+
+ (*nyx_ptr)();
+}
+
void auto_launch_firmware()
{
+ if(!h_cfg.sept_run && (b_cfg.extra_cfg & EXTRA_CFG_NYX_DUMP))
+ {
+ EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD;
+ check_sept();
+ }
+
if (!h_cfg.sept_run)
auto_launch_update();
@@ -756,6 +807,16 @@ void auto_launch_firmware()
h_cfg.autohosoff = atoi(kv->val);
else if (!strcmp("autonogc", kv->key))
h_cfg.autonogc = atoi(kv->val);
+ else if (!strcmp("brand", kv->key))
+ {
+ h_cfg.brand = malloc(strlen(kv->val) + 1);
+ strcpy(h_cfg.brand, kv->val);
+ }
+ else if (!strcmp("tagline", kv->key))
+ {
+ h_cfg.tagline = malloc(strlen(kv->val) + 1);
+ strcpy(h_cfg.tagline, kv->val);
+ }
}
boot_entry_id++;
@@ -949,6 +1010,9 @@ out:
b_cfg.boot_cfg &= ~(BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_LAUNCH);
h_cfg.emummc_force_disable = false;
+
+ nyx_load_run();
+
sd_unmount();
}
@@ -1197,6 +1261,9 @@ void ipl_main()
display_backlight_pwm_init();
//display_backlight_brightness(h_cfg.backlight, 1000);
+ // Overclock BPMP.
+ bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
+
// Check if we had a panic while in CFW.
secmon_exo_check_panic();
diff --git a/bootloader/soc/bpmp.c b/bootloader/soc/bpmp.c
new file mode 100644
index 0000000..5fdc10e
--- /dev/null
+++ b/bootloader/soc/bpmp.c
@@ -0,0 +1,217 @@
+/*
+ * BPMP-Lite Cache/MMU driver for Tegra X1
+ *
+ * Copyright (c) 2019 CTCaer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "bpmp.h"
+#include "clock.h"
+#include "t210.h"
+#include "../utils/util.h"
+
+#define BPMP_CACHE_CONFIG 0x0
+#define CFG_ENABLE (1 << 0)
+#define CFG_FORCE_WRITE_THROUGH (1 << 3)
+#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
+#define CFG_DISABLE_READ_BUFFER (1 << 11)
+#define CFG_FULL_LINE_DIRTY (1 << 13)
+#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
+#define BPMP_CACHE_LOCK 0x4
+#define BPMP_CACHE_SIZE 0xC
+#define BPMP_CACHE_LFSR 0x10
+#define BPMP_CACHE_TAG_STATUS 0x14
+#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
+#define BPMP_CACHE_MAINT_ADDR 0x20
+#define BPMP_CACHE_MAINT_DATA 0x24
+#define BPMP_CACHE_MAINT_REQ 0x28
+#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
+
+#define BPMP_CACHE_INT_MASK 0x40
+#define BPMP_CACHE_INT_CLEAR 0x44
+#define INT_CLR_MAINT_DONE (1 << 0)
+
+#define BPMP_CACHE_INT_RAW_EVENT 0x48
+#define INT_RAW_EVENT_MAINT_DONE (1 << 0)
+#define BPMP_CACHE_INT_STATUS 0x4C
+
+#define BPMP_CACHE_RB_CFG 0x80
+#define BPMP_CACHE_WB_CFG 0x84
+
+#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
+#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
+#define BPMP_CACHE_MMU_CFG 0xAC
+#define MMU_CFG_SEQ_EN (1 << 1)
+#define MMU_CFG_TLB_EN (1 << 2)
+#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
+#define BPMP_CACHE_MMU_CMD 0xB0
+#define MMU_CMD_NOP 0
+#define MMU_CMD_INIT 1
+#define MMU_CMD_COPY_SHADOW 2
+#define BPMP_CACHE_MMU_ABORT_STAT 0xB4
+#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
+#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
+
+#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
+#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
+#define MMU_ENTRY_ADDR_MASK 0xFFFFFFE0
+
+#define MMU_EN_CACHED (1 << 0)
+#define MMU_EN_EXEC (1 << 1)
+#define MMU_EN_READ (1 << 2)
+#define MMU_EN_WRITE (1 << 3)
+
+bpmp_mmu_entry_t mmu_entries[] =
+{
+ { 0x80000000, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
+ { IPL_LOAD_ADDR, 0x40040000, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
+};
+
+void bpmp_mmu_maintenance(u32 op)
+{
+ if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
+ return;
+
+ //BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE;
+
+ // This is a blocking operation.
+ BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
+
+ //while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_RAW_EVENT_MAINT_DONE))
+ // ;
+
+ //BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
+}
+
+void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
+{
+ if (idx > 31)
+ return;
+
+ volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx);
+
+ if (entry->enable)
+ {
+ mmu_entry->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK;
+ mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK;
+ mmu_entry->attr = entry->attr;
+
+ BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
+
+ if (apply)
+ BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
+ }
+}
+
+void bpmp_mmu_enable()
+{
+ if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)
+ return;
+
+ // Init BPMP MMU.
+ BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT;
+ BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions.
+ BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST;
+
+ // Init BPMP MMU entries.
+ BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0;
+ for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++)
+ bpmp_mmu_set_entry(idx, &mmu_entries[idx], false);
+
+ BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
+
+ // Invalidate cache.
+ bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
+
+ // Enable cache.
+ BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR;
+
+ // HW bug. Invalidate cache again.
+ bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
+}
+
+void bpmp_mmu_disable()
+{
+ if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
+ return;
+
+ // Clean and invalidate cache.
+ bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
+
+ // Enable cache.
+ BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
+
+ // HW bug. Invalidate cache again.
+ bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
+}
+
+static u8 pllc4_divn[] = {
+ 0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
+ 85, // BPMP_CLK_LOW_BOOST: 544MHz 33% - 136MHz APB.
+ 90, // BPMP_CLK_MID_BOOST: 576MHz 41% - 144MHz APB.
+ 95 // BPMP_CLK_SUPER_BOOST: 608MHz 49% - 152MHz APB.
+};
+
+bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
+
+void bpmp_clk_rate_set(bpmp_freq_t fid)
+{
+ if (fid > (BPMP_CLK_MAX - 1))
+ fid = BPMP_CLK_MAX - 1;
+
+ if (bpmp_clock_set == fid)
+ return;
+
+ if (fid)
+ {
+ if (bpmp_clock_set)
+ {
+ // Restore to PLLP source during PLLC4 configuration.
+ CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) =
+ (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333; // PLLP_OUT.
+ // Wait a bit for clock source change.
+ msleep(10);
+ }
+
+ CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = (1 << 30);
+ CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | (1 << 30); // DIVM: 4, DIVP: 1.
+
+ while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & (1 << 27)))
+ ;
+
+ CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | (1 << 1); // 1.5 div.
+ CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= 1; // Get divider out of reset.
+
+ // Wait a bit for PLLC4 to stabilize.
+ msleep(10);
+ CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / 4.
+ CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) =
+ (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3323; // PLLC4_OUT3.
+
+ bpmp_clock_set = fid;
+ }
+ else
+ {
+ CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) =
+ (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333; // PLLP_OUT.
+
+ // Wait a bit for clock source change.
+ msleep(10);
+
+ CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / 3.
+ CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~(1<<30);
+ bpmp_clock_set = BPMP_CLK_NORMAL;
+ }
+}
+
diff --git a/bootloader/soc/bpmp.h b/bootloader/soc/bpmp.h
new file mode 100644
index 0000000..bacb2d1
--- /dev/null
+++ b/bootloader/soc/bpmp.h
@@ -0,0 +1,51 @@
+/*
+ * BPMP-Lite Cache/MMU driver for Tegra X1
+ *
+ * Copyright (c) 2019 CTCaer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef _BPMP_H_
+#define _BPMP_H_
+
+#include "../utils/types.h"
+
+#define BPMP_MMU_MAINT_CLEAN_WAY 17
+#define BPMP_MMU_MAINT_INVALID_WAY 18
+#define BPMP_MMU_MAINT_CLN_INV_WAY 19
+
+typedef struct _bpmp_mmu_entry_t
+{
+ u32 min_addr;
+ u32 max_addr;
+ u32 attr;
+ u32 enable;
+} bpmp_mmu_entry_t;
+
+typedef enum
+{
+ BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB.
+ BPMP_CLK_LOW_BOOST, // 544MHz 33% - 136MHz APB.
+ BPMP_CLK_MID_BOOST, // 576MHz 41% - 144MHz APB.
+ BPMP_CLK_SUPER_BOOST, // 608MHz 49% - 152MHz APB.
+ BPMP_CLK_MAX
+} bpmp_freq_t;
+
+void bpmp_mmu_maintenance(u32 op);
+void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
+void bpmp_mmu_enable();
+void bpmp_mmu_disable();
+void bpmp_clk_rate_set(bpmp_freq_t fid);
+
+#endif
diff --git a/bootloader/soc/hw_init.c b/bootloader/soc/hw_init.c
index 7d1f5f9..fd12236 100644
--- a/bootloader/soc/hw_init.c
+++ b/bootloader/soc/hw_init.c
@@ -18,6 +18,7 @@
#include
#include "hw_init.h"
+#include "bpmp.h"
#include "clock.h"
#include "fuse.h"
#include "gpio.h"
@@ -248,10 +249,15 @@ void config_hw()
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;
sdram_init();
+
+ bpmp_mmu_enable();
}
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
{
+ // Flush and disable MMU.
+ bpmp_mmu_disable();
+ bpmp_clk_rate_set(BPMP_CLK_NORMAL);
minerva_change_freq(FREQ_204);
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
diff --git a/bootloader/utils/types.h b/bootloader/utils/types.h
index abe237a..bbddae0 100644
--- a/bootloader/utils/types.h
+++ b/bootloader/utils/types.h
@@ -59,6 +59,9 @@ typedef int bool;
#define EXTRA_CFG_PAYLOAD (1 << 1)
#define EXTRA_CFG_MODULE (1 << 2)
+#define EXTRA_CFG_NYX_RELOAD (1 << 6)
+#define EXTRA_CFG_NYX_DUMP (1 << 7)
+
typedef struct __attribute__((__packed__)) _boot_cfg_t
{
u8 boot_cfg;
diff --git a/bootloader/utils/util.c b/bootloader/utils/util.c
index 4368a61..778db8e 100644
--- a/bootloader/utils/util.c
+++ b/bootloader/utils/util.c
@@ -19,6 +19,7 @@
#include "../gfx/di.h"
#include "../power/max77620.h"
#include "../rtc/max77620-rtc.h"
+#include "../soc/bpmp.h"
#include "../soc/i2c.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
@@ -78,6 +79,8 @@ void panic(u32 val)
void reboot_normal()
{
+ bpmp_mmu_disable();
+
sd_unmount();
display_end();
@@ -86,6 +89,8 @@ void reboot_normal()
void reboot_rcm()
{
+ bpmp_mmu_disable();
+
sd_unmount();
display_end();
diff --git a/bootloader/utils/util.h b/bootloader/utils/util.h
index f261035..ae736dd 100644
--- a/bootloader/utils/util.h
+++ b/bootloader/utils/util.h
@@ -19,6 +19,10 @@
#define _UTIL_H_
#include "types.h"
+#include "../mem/minerva.h"
+
+#define NYX_CFG_DUMP (1 << 7)
+#define NYX_CFG_MINERVA (1 << 8)
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
@@ -29,6 +33,16 @@ typedef struct _cfg_op_t
u32 val;
} cfg_op_t;
+typedef struct _nyx_storage_t
+{
+ u32 version;
+ u32 cfg;
+ u8 irama[0x8000];
+ u8 hekate[0x30000];
+ u8 rsvd[0x800000];
+ mtc_config_t mtc_cfg;
+} nyx_storage_t;
+
u32 get_tmr_us();
u32 get_tmr_ms();
u32 get_tmr_s();