From 82bea6be8f65e48db783fc824a8fbbdffd4cc3cb Mon Sep 17 00:00:00 2001 From: shchmue Date: Sat, 14 Sep 2019 22:16:10 -0600 Subject: [PATCH] Add BPMP overclock, add hekate fixes, fix sprintf --- source/gfx/di.c | 112 ++++++++------- source/gfx/di.h | 6 +- source/gfx/di.inl | 8 +- source/gfx/gfx.c | 4 +- source/keys/keys.c | 2 +- source/libs/fatfs/ff.c | 28 +++- source/libs/fatfs/ff.h | 11 +- source/libs/fatfs/ffunicode.c | 2 - source/main.c | 5 +- source/mem/heap.c | 9 +- source/mem/heap.h | 1 - source/mem/mc.c | 2 +- source/mem/sdram.c | 10 +- source/power/max77620.h | 39 +++--- source/power/max7762x.h | 8 +- source/rtc/max77620-rtc.c | 2 +- source/rtc/max77620-rtc.h | 2 +- source/sec/se.c | 20 +-- source/sec/tsec.c | 14 +- source/soc/bpmp.c | 249 ++++++++++++++++++++++++++++++++++ source/soc/bpmp.h | 54 ++++++++ source/soc/clock.c | 63 ++++----- source/soc/clock.h | 28 +++- source/soc/cluster.c | 30 ++-- source/soc/cluster.h | 13 -- source/soc/hw_init.c | 206 ++++++++++++++++++---------- source/soc/i2c.c | 14 +- source/soc/pinmux.h | 69 ++++++---- source/soc/pmc.h | 4 + source/soc/t210.h | 32 +++++ source/storage/sdmmc.c | 166 +++++++++++++++-------- source/storage/sdmmc.h | 5 +- source/storage/sdmmc_driver.c | 95 ++++++++----- source/utils/btn.c | 2 +- source/utils/sprintf.c | 243 ++++++++++++++++----------------- source/utils/sprintf.h | 46 ++++--- source/utils/types.h | 18 ++- source/utils/util.c | 48 +++++-- source/utils/util.h | 4 +- 39 files changed, 1130 insertions(+), 544 deletions(-) create mode 100644 source/soc/bpmp.c create mode 100644 source/soc/bpmp.h diff --git a/source/gfx/di.c b/source/gfx/di.c index 5710ef1..1dcef3f 100644 --- a/source/gfx/di.c +++ b/source/gfx/di.c @@ -18,15 +18,16 @@ #include #include "di.h" -#include "../soc/t210.h" -#include "../utils/util.h" -#include "../soc/i2c.h" -#include "../soc/pmc.h" +#include "../gfx/gfx.h" #include "../power/max77620.h" #include "../power/max7762x.h" -#include "../soc/gpio.h" -#include "../soc/pinmux.h" #include "../soc/clock.h" +#include "../soc/gpio.h" +#include "../soc/i2c.h" +#include "../soc/pinmux.h" +#include "../soc/pmc.h" +#include "../soc/t210.h" +#include "../utils/util.h" #include "di.inl" @@ -46,54 +47,61 @@ void display_init() max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); - // Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA; + // Enable Display Interface specific clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL. - // DPD idle. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X. + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz). + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). + + // Disable deap power down. PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000; PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000; - // Config pins. + // Config LCD and Backlight pins. PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; - gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V. - gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V. + // Set Backlight +-5V pins mode and direction + gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); + + // Enable Backlight power. gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable. - usleep(10000); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable. - usleep(10000); - gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset. + // Configure Backlight pins (PWM, EN, RST). + gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable. + gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN. - // Config display interface and display. + // Power up supply regulator for display interface. MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0; + // Set DISP1 clock source and parrent clock. exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4); + + // Setup display communication interfaces. exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94); exec_cfg((u32 *)DSI_BASE, _display_config_3, 61); - usleep(10000); - gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable. - + // Enable Backlight Reset. + gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); usleep(60000); + // Setups DSI packet configuration and request display id. DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; @@ -122,19 +130,22 @@ void display_init() usleep(20000); + // Configure PLLD for DISP1. exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3); + + // Finalize DSI configuration. exec_cfg((u32 *)DSI_BASE, _display_config_5, 21); DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; exec_cfg((u32 *)DSI_BASE, _display_config_7, 10); - usleep(10000); + // Calibrate display communication pads. exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6); exec_cfg((u32 *)DSI_BASE, _display_config_9, 4); exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16); - usleep(10000); + // Enable video display controller. exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113); } @@ -142,11 +153,10 @@ void display_backlight_pwm_init() { clock_enable_pwm(); - PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM. - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source. + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source. gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode. - } void display_backlight(bool enable) @@ -167,7 +177,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) { for (u32 i = old_value; i < brightness + 1; i++) { - PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. usleep(step_delay); } } @@ -175,7 +185,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) { for (u32 i = old_value; i > brightness; i--) { - PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. usleep(step_delay); } } @@ -191,13 +201,14 @@ void display_end() DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX; - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet. + // De-initialize video controller. exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17); exec_cfg((u32 *)DSI_BASE, _display_config_13, 16); - usleep(10000); + // De-initialize display panel. if (_display_ver == 0x10) exec_cfg((u32 *)DSI_BASE, _display_config_14, 22); @@ -206,31 +217,31 @@ void display_end() usleep(50000); + // Disable display and backlight pins. gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable. - usleep(10000); gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable. - usleep(10000); gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable. - usleep(10000); - // Disable clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; + // Disable Display Interface specific clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X. + // Power down pads. DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; + // Switch to automatic function mode. gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1; } void display_color_screen(u32 color) @@ -243,7 +254,6 @@ void display_color_screen(u32 color) DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0; DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color; DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ; - usleep(35000); display_backlight(true); @@ -252,11 +262,11 @@ void display_color_screen(u32 color) u32 *display_init_framebuffer() { // Sanitize framebuffer area. - memset((u32 *)0xC0000000, 0, 0x3C0000); - // This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768). + memset((u32 *)FB_ADDRESS, 0, 0x3C0000); + // This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720). exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32); - usleep(35000); - return (u32 *)0xC0000000; + return (u32 *)FB_ADDRESS; } + diff --git a/source/gfx/di.h b/source/gfx/di.h index 898029d..69d231a 100644 --- a/source/gfx/di.h +++ b/source/gfx/di.h @@ -20,6 +20,8 @@ #include "../utils/types.h" +#define FB_ADDRESS 0xC0000000 + /*! Display registers. */ #define _DIREG(reg) ((reg) * 4) @@ -233,7 +235,7 @@ #define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) #define DC_WIN_DV_CONTROL 0x70E -// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). +/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */ #define DC_WINBUF_START_ADDR 0x800 #define DC_WINBUF_ADDR_H_OFFSET 0x806 #define DC_WINBUF_ADDR_V_OFFSET 0x808 @@ -333,7 +335,7 @@ #define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) #define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) -#define DSI_PAD_CONTROL_CD 0x4c +#define DSI_PAD_CONTROL_CD 0x4C #define DSI_VIDEO_MODE_CONTROL 0x4E #define DSI_PAD_CONTROL_1 0x4F diff --git a/source/gfx/di.inl b/source/gfx/di.inl index 3d2471b..48cea7b 100644 --- a/source/gfx/di.inl +++ b/source/gfx/di.inl @@ -122,7 +122,7 @@ static const cfg_op_t _display_config_2[94] = { {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ} }; @@ -405,7 +405,7 @@ static const cfg_op_t _display_config_11[113] = { {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {DC_CMD_STATE_ACCESS, 0}, @@ -455,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = { {DC_CMD_STATE_ACCESS, 0}, {DC_CMD_INT_ENABLE, 0}, {DC_CMD_CONT_SYNCPT_VSYNC, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, @@ -548,7 +548,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = { {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. {DC_WIN_BUFFER_CONTROL, 0}, {DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. - {DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address. + {DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address. {DC_WINBUF_ADDR_H_OFFSET, 0}, {DC_WINBUF_ADDR_V_OFFSET, 0}, {DC_WIN_WIN_OPTIONS, 0}, diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index fb0793c..62e60ca 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -128,12 +128,12 @@ void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) void gfx_clear_grey(u8 color) { - memset(gfx_ctxt.fb, color, 0x3C0000); + memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); } void gfx_clear_color(u32 color) { - for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++) + for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++) gfx_ctxt.fb[i] = color; } diff --git a/source/keys/keys.c b/source/keys/keys.c index a342c85..38d888a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -537,7 +537,7 @@ pkg2_done: FIL fp; // sysmodule NCAs only ever have one section (exefs) so 0x600 is sufficient u8 *dec_header = (u8*)malloc(0x600); - char path[100] = "sd:/test/nca1111111111111";//"emmc:/Contents/registered"; + char path[100] = "emmc:/Contents/registered"; u32 titles_found = 0, title_limit = 2, read_bytes = 0; if (!memcmp(pkg1_id->id, "2016", 4)) title_limit = 1; diff --git a/source/libs/fatfs/ff.c b/source/libs/fatfs/ff.c index 38d6422..c3e2ab9 100644 --- a/source/libs/fatfs/ff.c +++ b/source/libs/fatfs/ff.c @@ -1,10 +1,25 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-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 . + */ + /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.13c (p3) / +/ FatFs - Generic FAT Filesystem Module R0.13c (p4) / /-----------------------------------------------------------------------------/ / / Copyright (C) 2018, ChaN, all right reserved. -/ Copyright (c) 2018 naehrwert -/ Copyright (C) 2018-2019 CTCaer / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -3472,7 +3487,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ #if FF_FS_EXFAT - fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ + fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */ #endif #endif #if FF_FS_RPATH != 0 @@ -4243,9 +4258,9 @@ FRESULT f_getcwd ( TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; -#endif #if FF_STR_VOLUME_ID const char *vp; +#endif #endif FILINFO fno; DEF_NAMBUF @@ -4726,7 +4741,7 @@ FRESULT f_getfree ( /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { - *fatfs = fs; /* Return ptr to the fs object */ + if (fatfs) *fatfs = fs; /* Return ptr to the fs object */ /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; @@ -6632,4 +6647,3 @@ FRESULT f_setcp ( return FR_OK; } #endif /* FF_CODE_PAGE == 0 */ - diff --git a/source/libs/fatfs/ff.h b/source/libs/fatfs/ff.h index 41a6571..f867131 100644 --- a/source/libs/fatfs/ff.h +++ b/source/libs/fatfs/ff.h @@ -95,6 +95,7 @@ typedef DWORD FSIZE_t; /* Filesystem object structure (FATFS) */ typedef struct { + BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ @@ -137,8 +138,6 @@ typedef struct { DWORD bitbase; /* Allocation bitmap base sector */ #endif DWORD winsect; /* Current sector appearing in the win[] */ - DWORD padding; /* Ensure window is 16-aligned */ - BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; @@ -169,6 +168,9 @@ typedef struct { /* File object structure (FIL) */ typedef struct { +#if !FF_FS_TINY + BYTE buf[FF_MAX_SS]; /* File private data read/write window */ +#endif FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ @@ -179,9 +181,6 @@ typedef struct { DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ #endif -#if !FF_FS_TINY - BYTE buf[FF_MAX_SS]; /* File private data read/write window */ -#endif #if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif @@ -280,7 +279,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ diff --git a/source/libs/fatfs/ffunicode.c b/source/libs/fatfs/ffunicode.c index bc23f80..9f03963 100644 --- a/source/libs/fatfs/ffunicode.c +++ b/source/libs/fatfs/ffunicode.c @@ -34,7 +34,6 @@ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) - /*------------------------------------------------------------------------*/ /* Code Conversion Tables */ /*------------------------------------------------------------------------*/ @@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ return uni; } - #endif /* #if FF_USE_LFN */ diff --git a/source/main.c b/source/main.c index 64b9473..587d930 100644 --- a/source/main.c +++ b/source/main.c @@ -24,6 +24,7 @@ #include "mem/heap.h" #include "power/max77620.h" #include "rtc/max77620-rtc.h" +#include "soc/bpmp.h" #include "soc/hw_init.h" #include "storage/sdmmc.h" #include "utils/util.h" @@ -107,7 +108,7 @@ int sd_save_to_file(void *buf, u32 size, const char *filename) if (res) { EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename); - return 1; + return res; } f_write(&fp, buf, size, NULL); @@ -159,6 +160,8 @@ void ipl_main() gfx_con_init(); display_backlight_pwm_init(); + bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); + sd_mount(); dump_keys(); } diff --git a/source/mem/heap.c b/source/mem/heap.c index e637dd2..4971d8a 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -107,17 +107,12 @@ void heap_init(u32 base) void *malloc(u32 size) { - return (void *)_heap_alloc(&_heap, size, 0x10); -} - -void *memalign(u32 align, u32 size) -{ - return (void *)_heap_alloc(&_heap, size, align); + return (void *)_heap_alloc(&_heap, size, sizeof(hnode_t)); } void *calloc(u32 num, u32 size) { - void *res = (void *)_heap_alloc(&_heap, num * size, 0x10); + void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t)); memset(res, 0, num * size); return res; } diff --git a/source/mem/heap.h b/source/mem/heap.h index ad0783c..24cb64e 100644 --- a/source/mem/heap.h +++ b/source/mem/heap.h @@ -23,6 +23,5 @@ void heap_init(u32 base); void *malloc(u32 size); void *calloc(u32 num, u32 size); void free(void *buf); -void *memalign(u32 align, u32 size); #endif diff --git a/source/mem/mc.c b/source/mem/mc.c index c799573..dd508e2 100644 --- a/source/mem/mc.c +++ b/source/mem/mc.c @@ -127,7 +127,7 @@ void mc_disable_ahb_redirect() void mc_enable() { CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000; - // Enable MIPI CAL clock. + // Enable EMC clock. CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000; // Enable MC clock. CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1; diff --git a/source/mem/sdram.c b/source/mem/sdram.c index 96e1792..db9637a 100644 --- a/source/mem/sdram.c +++ b/source/mem/sdram.c @@ -39,7 +39,13 @@ static u32 _get_sdram_id() { - return (fuse_read_odm(4) & 0x38) >> 3; + u32 sdram_id = (fuse_read_odm(4) & 0x38) >> 3; + + // Check if id is proper. + if (sdram_id > 7) + sdram_id = 0; + + return sdram_id; } static void _sdram_config(const sdram_params_t *params) @@ -539,7 +545,7 @@ void sdram_init() const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); - max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); + max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); // Set DRAM voltage. PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; usleep(params->pmc_vddp_sel_wait); diff --git a/source/power/max77620.h b/source/power/max77620.h index fcce309..479661d 100644 --- a/source/power/max77620.h +++ b/source/power/max77620.h @@ -130,7 +130,7 @@ #define MAX77620_POWER_MODE_DISABLE 0 #define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) #define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) -#define MAX77620_LDO_CFG2_ADE_DISABLE 0 +#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) #define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) #define MAX77620_LDO_CFG2_SS_MASK (1 << 0) #define MAX77620_LDO_CFG2_SS_FAST (1 << 0) @@ -153,6 +153,24 @@ #define MAX77620_REG_PUE_GPIO 0x3E #define MAX77620_REG_PDE_GPIO 0x3F #define MAX77620_REG_AME_GPIO 0x40 +#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) +#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1) +#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3) +#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) +#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) +#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) +#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) +#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) +#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) +#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) +#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) #define MAX77620_REG_ONOFFCNFG1 0x41 #define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) @@ -259,25 +277,6 @@ #define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 #define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0 -#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) -#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) -#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0 -#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0 -#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) -#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) -#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) -#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) -#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) -#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) -#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) -#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) - #define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) #define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) #define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) diff --git a/source/power/max7762x.h b/source/power/max7762x.h index eefa112..3a0afe3 100644 --- a/source/power/max7762x.h +++ b/source/power/max7762x.h @@ -24,16 +24,16 @@ * Switch Power domains (max77620): * Name | Usage | uV step | uV min | uV default | uV max | Init *-------+---------------+---------+--------+------------+---------+------------------ -* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) +* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) * sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1) * sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv) * sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 | * ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1) * ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | -* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) +* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | -* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) +* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) * ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | @@ -71,6 +71,8 @@ /* MAX77621_VOUT */ #define MAX77621_VOUT_ENABLE (1 << 7) #define MAX77621_VOUT_MASK 0x7F +#define MAX77621_VOUT_0_95V 0x37 +#define MAX77621_VOUT_1_09V 0x4F /* MAX77621_VOUT_DVC_DVS */ #define MAX77621_DVS_VOUT_MASK 0x7F diff --git a/source/rtc/max77620-rtc.c b/source/rtc/max77620-rtc.c index 85895af..7e2d3af 100644 --- a/source/rtc/max77620-rtc.c +++ b/source/rtc/max77620-rtc.c @@ -52,7 +52,7 @@ void max77620_rtc_get_time(rtc_time_t *time) } // Get date. - time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; + time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1; time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000; } diff --git a/source/rtc/max77620-rtc.h b/source/rtc/max77620-rtc.h index 756e67c..981ccfe 100644 --- a/source/rtc/max77620-rtc.h +++ b/source/rtc/max77620-rtc.h @@ -64,7 +64,7 @@ typedef struct _rtc_time_t { u8 sec; u8 min; u8 hour; - u8 date; + u8 day; u8 month; u16 year; } rtc_time_t; diff --git a/source/sec/se.c b/source/sec/se.c index c9402c0..ab9d400 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -21,6 +21,7 @@ #include "../sec/se.h" #include "../mem/heap.h" +#include "../soc/bpmp.h" #include "../soc/t210.h" #include "../sec/se_t210.h" #include "../utils/util.h" @@ -108,10 +109,14 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0); SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET); - SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); + + SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); int res = _se_wait(); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); + if (src) free(ll_src); if (dst) @@ -227,18 +232,7 @@ int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) { - if (enc) - { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); - } - else - { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); - } - SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; - return _se_execute(OP_START, dst, 0x10, src, 0x10); + return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10); } int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr) diff --git a/source/sec/tsec.c b/source/sec/tsec.c index 9916882..55fb1b4 100644 --- a/source/sec/tsec.c +++ b/source/sec/tsec.c @@ -21,6 +21,7 @@ #include "../sec/tsec.h" #include "../sec/tsec_t210.h" #include "../sec/se_t210.h" +#include "../soc/bpmp.h" #include "../soc/clock.h" #include "../soc/smmu.h" #include "../soc/t210.h" @@ -64,8 +65,12 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; u32 *pkg11_magic_off; - //Enable clocks. + bpmp_mmu_disable(); + bpmp_clk_rate_set(BPMP_CLK_NORMAL); + + // Enable clocks. clock_enable_host1x(); + usleep(2); clock_enable_tsec(); clock_enable_sor_safe(); clock_enable_sor0(); @@ -170,7 +175,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } //Execute firmware. - HOST1X(0x3300) = 0x34C2E1DA; + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; TSEC(TSEC_STATUS) = 0; TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. TSEC(TSEC_BOOTVEC) = 0; @@ -247,7 +252,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } //Fetch result. - HOST1X(0x3300) = 0; + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; u32 buf[4]; buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); @@ -272,7 +277,8 @@ out:; clock_disable_sor0(); clock_disable_sor_safe(); clock_disable_tsec(); - clock_disable_host1x(); + bpmp_mmu_enable(); + bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); return res; } diff --git a/source/soc/bpmp.c b/source/soc/bpmp.c new file mode 100644 index 0000000..3d6091d --- /dev/null +++ b/source/soc/bpmp.c @@ -0,0 +1,249 @@ +/* + * BPMP-Lite Cache/MMU and Frequency 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); + + // Disable cache. + BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0; + + // HW bug. Invalidate cache again. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY); +} + +const 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. + 94 // BPMP_CLK_SUPER_BOOST: 602MHz 48% - 150MHz 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) = 0x20003333; // PLLP_OUT. + // Wait a bit for clock source change. + msleep(10); + } + + CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | PLL_BASE_ENABLE; // DIVM: 4, DIVP: 1. + + while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLC4_BASE_LOCK)) + ; + + CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | PLLC4_OUT3_CLKEN; // 1.5 div. + CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= PLLC4_OUT3_RSTN_CLR; // 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) = 0x20003323; // PLLC4_OUT3. + + bpmp_clock_set = fid; + } + else + { + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // 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) &= ~PLL_BASE_ENABLE; + bpmp_clock_set = BPMP_CLK_NORMAL; + } +} + +// The following functions halt BPMP to reduce power while sleeping. +// They are not as accurate as RTC at big values but they guarantee time+ delay. +void bpmp_usleep(u32 us) +{ + u32 delay; + + // Each iteration takes 1us. + while (us) + { + delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us; + us -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay; + } +} + +void bpmp_msleep(u32 ms) +{ + u32 delay; + + // Iteration time is variable. ~200 - 1000us. + while (ms) + { + delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms; + ms -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay; + } +} + +void bpmp_halt() +{ + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG; +} diff --git a/source/soc/bpmp.h b/source/soc/bpmp.h new file mode 100644 index 0000000..b45ab7a --- /dev/null +++ b/source/soc/bpmp.h @@ -0,0 +1,54 @@ +/* + * BPMP-Lite Cache/MMU and Frequency 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); +void bpmp_usleep(u32 us); +void bpmp_msleep(u32 ms); +void bpmp_halt(); + +#endif diff --git a/source/soc/clock.c b/source/soc/clock.c index f712935..73e5fb3 100644 --- a/source/soc/clock.c +++ b/source/soc/clock.c @@ -22,57 +22,58 @@ /* clock_t: reset, enable, source, index, clk_src, clk_div */ static const clock_t _clock_uart[] = { -/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 }, -/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 }, -/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 }, -/* UART D */ { 0 }, -/* UART E */ { 0 } +/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 }, +/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 }, +/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 }, +/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 }, +/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 } }; static const clock_t _clock_i2c[] = { -/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 }, +/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 6, 0 }, // 0, 19 }, // 100KHz /* I2C2 */ { 0 }, /* I2C3 */ { 0 }, /* I2C4 */ { 0 }, -/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 6, 0 }, +/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 6, 0 }, // 0, 4 }, // 400KHz /* I2C6 */ { 0 } }; static clock_t _clock_se = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0 }; -static clock_t _clock_unk2 = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 0x1E, 0, 0 + +static clock_t _clock_tzram = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0 }; static clock_t _clock_host1x = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3 + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3 }; static clock_t _clock_tsec = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2 + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2 }; static clock_t _clock_sor_safe = { - CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 0x1E, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0 }; static clock_t _clock_sor0 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 0x16, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0 }; static clock_t _clock_sor1 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2 + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2 }; static clock_t _clock_kfuse = { - CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0 }; static clock_t _clock_cl_dvfs = { - CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 0x1B, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0 }; static clock_t _clock_coresight = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4 + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4 }; static clock_t _clock_pwm = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 0x11, 6, 4 + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Freference: 6.2MHz. }; void clock_enable(const clock_t *clk) @@ -123,9 +124,9 @@ void clock_enable_se() clock_enable(&_clock_se); } -void clock_enable_unk2() +void clock_enable_tzram() { - clock_enable(&_clock_unk2); + clock_enable(&_clock_tzram); } void clock_enable_host1x() @@ -365,49 +366,49 @@ static void _clock_sdmmc_clear_enable(u32 id) static u32 _clock_sdmmc_table[8] = { 0 }; #define PLLP_OUT0 0x0 - static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val) { u32 divisor = 0; u32 source = PLLP_OUT0; + // Get IO clock divisor. switch (val) { case 25000: *pout = 24728; - divisor = 31; + divisor = 31; // 16.5 div. break; case 26000: *pout = 25500; - divisor = 30; + divisor = 30; // 16 div. break; case 40800: *pout = 40800; - divisor = 18; + divisor = 18; // 10 div. break; case 50000: *pout = 48000; - divisor = 15; + divisor = 15; // 8.5 div. break; case 52000: *pout = 51000; - divisor = 14; + divisor = 14; // 8 div. break; case 100000: *pout = 90667; - divisor = 7; + divisor = 7; // 4.5 div. break; case 200000: *pout = 163200; - divisor = 3; + divisor = 3; // 2.5 div. break; case 208000: *pout = 204000; - divisor = 2; + divisor = 2; // 2 div. break; default: *pout = 24728; - divisor = 31; + divisor = 31; // 16.5 div. } _clock_sdmmc_table[2 * id] = val; diff --git a/source/soc/clock.h b/source/soc/clock.h index 8e36069..db7a974 100644 --- a/source/soc/clock.h +++ b/source/soc/clock.h @@ -41,6 +41,8 @@ #define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C #define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 #define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 +#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 +#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC #define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 #define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 #define CLK_RST_CONTROLLER_PLLE_BASE 0xE8 @@ -50,6 +52,7 @@ #define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 +#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138 #define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154 @@ -57,11 +60,13 @@ #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178 #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C #define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198 +#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 #define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C #define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 #define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 #define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 @@ -95,9 +100,12 @@ #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 #define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 #define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 #define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C #define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 +#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 #define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 #define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C #define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 @@ -108,16 +116,30 @@ #define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 #define CLK_RST_CONTROLLER_SPARE_REG0 0x55C +#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 +#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8 +#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 #define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 #define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C #define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL 0x66C +#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 #define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 #define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 #define CLK_NO_SOURCE 0x0 +/*! PLL control and status bits */ +#define PLL_BASE_ENABLE (1 << 30) + +#define PLLC4_MISC_EN_LCKDET (1 << 30) +#define PLLC4_BASE_LOCK (1 << 27) +#define PLLC4_BASE_IDDQ (1 << 18) +#define PLLC4_OUT3_CLKEN (1 << 1) +#define PLLC4_OUT3_RSTN_CLR (1 << 0) + /*! Generic clock descriptor. */ typedef struct _clock_t { @@ -139,7 +161,7 @@ void clock_enable_uart(u32 idx); void clock_enable_i2c(u32 idx); void clock_disable_i2c(u32 idx); void clock_enable_se(); -void clock_enable_unk2(); +void clock_enable_tzram(); void clock_enable_host1x(); void clock_disable_host1x(); void clock_enable_tsec(); diff --git a/source/soc/cluster.c b/source/soc/cluster.c index 1976e11..0791d36 100644 --- a/source/soc/cluster.c +++ b/source/soc/cluster.c @@ -32,18 +32,21 @@ void _cluster_enable_power() // Enable cores power. // 1-3.x: MAX77621_NFSR_ENABLE. i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, - MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE); + MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US); // 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL. i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); } -int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable) +int _cluster_pmc_enable_partition(u32 part, int enable) { - // Check if the partition has already been turned on. - if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & part) + u32 part_mask = 1 << part; + u32 desired_state = enable << part; + + // Check if the partition has the state we want. + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) return 1; u32 i = 5001; @@ -55,12 +58,13 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable) return 0; } - PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0); + // Toggle power gating. + PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100; i = 5001; while (i > 0) { - if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part) + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) break; usleep(1); i--; @@ -103,11 +107,11 @@ void cluster_boot_cpu0(u32 entry) CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; // Enable CPU rail. - _cluster_pmc_enable_partition(1, 0, true); + _cluster_pmc_enable_partition(0, 1); // Enable cluster 0 non-CPU. - _cluster_pmc_enable_partition(0x8000, 15, true); + _cluster_pmc_enable_partition(15, 1); // Enable CE0. - _cluster_pmc_enable_partition(0x4000, 14, true); + _cluster_pmc_enable_partition(14, 1); // Request and wait for RAM repair. FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1; @@ -117,10 +121,10 @@ void cluster_boot_cpu0(u32 entry) EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0; // Set reset vector. - SB(SB_AA64_RESET_LOW) = entry | 1; + SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN; SB(SB_AA64_RESET_HIGH) = 0; // Non-secure reset vector write disable. - SB(SB_CSR) = 2; + SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS; (void)SB(SB_CSR); // Clear MSELECT reset. diff --git a/source/soc/cluster.h b/source/soc/cluster.h index 5cecd19..428c046 100644 --- a/source/soc/cluster.h +++ b/source/soc/cluster.h @@ -19,19 +19,6 @@ #include "../utils/types.h" -/*! Flow controller registers. */ -#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 -#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 -#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C -#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 -#define FLOW_CTLR_HALT_COP_EVENTS 0x4 -#define FLOW_CTLR_CPU0_CSR 0x8 -#define FLOW_CTLR_CPU1_CSR 0x18 -#define FLOW_CTLR_CPU2_CSR 0x20 -#define FLOW_CTLR_CPU3_CSR 0x28 -#define FLOW_CTLR_RAM_REPAIR 0x40 -#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 - void cluster_boot_cpu0(u32 entry); #endif diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index 294505f..d694b32 100644 --- a/source/soc/hw_init.c +++ b/source/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" @@ -38,22 +39,36 @@ extern sdmmc_t sd_sdmmc; extern boot_cfg_t b_cfg; +/* + * CLK_OSC - 38.4 MHz crystal. + * CLK_M - 19.2 MHz (osc/2). + * CLK_S - 32.768 KHz (from PMIC). + * SCLK - 204MHz init (-> 408MHz -> OC). + * HCLK - 204MHz init (-> 408MHz -> OC). + * PCLK - 68MHz init (-> 136MHz -> OC/4). + */ + void _config_oscillators() { - CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; - SYSCTR0(SYSCTR0_CNTFID0) = 19200000; - TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. - CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; - PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; - PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | 0x400000; - PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | 0x1000; - PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | 0x2000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; - CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; + CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2. + SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency. + TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. + CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength. + + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength. + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER; + PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN; + PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE. + + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable. + PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; - CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; + + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz). + CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. } void _config_gpios() @@ -61,11 +76,22 @@ void _config_gpios() PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; + // Set Joy-Con IsAttached direction. PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE; PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE; + // Set pin mode for Joy-Con IsAttached and UARTB/C TX pins. +#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); +#endif +#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); +#endif + // Set Joy-Con IsAttached mode. gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO); gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO); + + // Enable input logic for Joy-Con IsAttached and UARTB/C TX pins. gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE); gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); @@ -80,27 +106,36 @@ void _config_gpios() gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_X, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); + + // Configure HOME as inputs. + // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE; + // gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO); } void _config_pmc_scratch() { - PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; - PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; - PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10; + PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option. + PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL + PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT; } void _mbist_workaround() { CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + // Set mux output to SOR1 clock switch. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000u; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; + // Enabled PLLD and set csi to PLLD for test pattern generation. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000; + + // Clear per-clock resets. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. usleep(2); + // I2S channels to master and disable SLCG. I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN; I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE; I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN; @@ -111,30 +146,39 @@ void _mbist_workaround() I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE; I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN; I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE; - DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; + + DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE. VIC(0x8C) = 0xFFFFFFFF; usleep(2); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; + // Set per-clock reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC. + + // Enable specific clocks and disable all others. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE. + //CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USB data ON. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA. + + // Disable clock gate overrides. CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0; - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; + + // Set child clock sources. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. } void _config_se_brom() @@ -170,13 +214,59 @@ void _config_se_brom() APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10); } +void _config_regulators() +{ + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, + (1 << 6) | (1 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. + + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, + (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, + (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT)); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, + (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); + max77620_regulator_config_fps(REGULATOR_LDO4); + max77620_regulator_config_fps(REGULATOR_LDO8); + max77620_regulator_config_fps(REGULATOR_SD0); + max77620_regulator_config_fps(REGULATOR_SD1); + max77620_regulator_config_fps(REGULATOR_SD3); + + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, + (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ + + // Set vdd_core voltage to 1.125V + max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); + + // Fix CPU/GPU after a Linux warmboot. + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); + + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | + MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | + MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + + // Disable low battery shutdown monitor. + max77620_low_battery_monitor_config(); +} + void config_hw() { // Bootrom stuff we skipped by going through rcm. _config_se_brom(); //FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11; - SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; - PMC(APBDEV_PMC_SCRATCH49) = ((PMC(APBDEV_PMC_SCRATCH49) >> 1) << 1) & 0xFFFFFFFD; + SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN. + PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC; _mbist_workaround(); clock_enable_se(); @@ -197,49 +287,29 @@ void config_hw() clock_enable_i2c(I2C_1); clock_enable_i2c(I2C_5); - clock_enable_unk2(); + clock_enable_tzram(); i2c_init(I2C_1); i2c_init(I2C_5); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, - (1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. - - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT)); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, - (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); - max77620_regulator_config_fps(REGULATOR_LDO4); - max77620_regulator_config_fps(REGULATOR_LDO8); - max77620_regulator_config_fps(REGULATOR_SD0); - max77620_regulator_config_fps(REGULATOR_SD1); - max77620_regulator_config_fps(REGULATOR_SD3); - - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, - (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ - - max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); - - // Fix GPU after warmboot for Linux. - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); - - // Disable low battery shutdown monitor. - max77620_low_battery_monitor_config(); + _config_regulators(); _config_pmc_scratch(); // Missing from 4.x+ - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333; + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz). sdram_init(); + + bpmp_mmu_enable(); mc_enable_ahb_redirect(); } void reconfig_hw_workaround(bool extra_reconfig, u32 magic) { + // Flush and disable MMU. + bpmp_mmu_disable(); + bpmp_clk_rate_set(BPMP_CLK_NORMAL); + // Re-enable clocks to Audio Processing Engine as a workaround to hanging. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. diff --git a/source/soc/i2c.c b/source/soc/i2c.c index e845693..d06d64a 100644 --- a/source/soc/i2c.c +++ b/source/soc/i2c.c @@ -44,10 +44,10 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) memcpy(&tmp, buf, size); vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). - base[I2C_CMD_DATA1] = tmp; //Set value. - base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode. - _i2c_wait(base); //Kick transaction. + base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). + base[I2C_CMD_DATA1] = tmp; //Set value. + base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode. + _i2c_wait(base); //Kick transaction. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; while (base[I2C_STATUS] & 0x100) @@ -65,9 +65,9 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) return 0; vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode). - base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode. - _i2c_wait(base); // Kick transaction. + base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode). + base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode. + _i2c_wait(base); // Kick transaction. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; while (base[I2C_STATUS] & 0x100) diff --git a/source/soc/pinmux.h b/source/soc/pinmux.h index 26bab31..2db4a75 100644 --- a/source/soc/pinmux.h +++ b/source/soc/pinmux.h @@ -26,31 +26,50 @@ #define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74 /*! Pinmux registers. */ -#define PINMUX_AUX_SDMMC1_CLK 0x00 -#define PINMUX_AUX_SDMMC1_CMD 0x04 -#define PINMUX_AUX_SDMMC1_DAT3 0x08 -#define PINMUX_AUX_SDMMC1_DAT2 0x0C -#define PINMUX_AUX_SDMMC1_DAT1 0x10 -#define PINMUX_AUX_SDMMC1_DAT0 0x14 -#define PINMUX_AUX_SDMMC3_CLK 0x1C -#define PINMUX_AUX_SDMMC3_CMD 0x20 -#define PINMUX_AUX_SDMMC3_DAT0 0x24 -#define PINMUX_AUX_SDMMC3_DAT1 0x28 -#define PINMUX_AUX_SDMMC3_DAT2 0x2C -#define PINMUX_AUX_SDMMC3_DAT3 0x30 -#define PINMUX_AUX_DMIC3_CLK 0xB4 -#define PINMUX_AUX_UART2_TX 0xF4 -#define PINMUX_AUX_UART3_TX 0x104 -#define PINMUX_AUX_WIFI_EN 0x1B4 -#define PINMUX_AUX_WIFI_RST 0x1B8 -#define PINMUX_AUX_NFC_EN 0x1D0 -#define PINMUX_AUX_NFC_INT 0x1D4 -#define PINMUX_AUX_LCD_BL_PWM 0x1FC -#define PINMUX_AUX_LCD_BL_EN 0x200 -#define PINMUX_AUX_LCD_RST 0x204 -#define PINMUX_AUX_GPIO_PE6 0x248 -#define PINMUX_AUX_GPIO_PH6 0x250 -#define PINMUX_AUX_GPIO_PZ1 0x280 +#define PINMUX_AUX_SDMMC1_CLK 0x00 +#define PINMUX_AUX_SDMMC1_CMD 0x04 +#define PINMUX_AUX_SDMMC1_DAT3 0x08 +#define PINMUX_AUX_SDMMC1_DAT2 0x0C +#define PINMUX_AUX_SDMMC1_DAT1 0x10 +#define PINMUX_AUX_SDMMC1_DAT0 0x14 +#define PINMUX_AUX_SDMMC3_CLK 0x1C +#define PINMUX_AUX_SDMMC3_CMD 0x20 +#define PINMUX_AUX_SDMMC3_DAT0 0x24 +#define PINMUX_AUX_SDMMC3_DAT1 0x28 +#define PINMUX_AUX_SDMMC3_DAT2 0x2C +#define PINMUX_AUX_SDMMC3_DAT3 0x30 +#define PINMUX_AUX_SATA_LED_ACTIVE 0x4C +#define PINMUX_AUX_DMIC3_CLK 0xB4 +#define PINMUX_AUX_DMIC3_DAT 0xB8 +#define PINMUX_AUX_CAM_I2C_SCL 0xD4 +#define PINMUX_AUX_CAM_I2C_SDA 0xD8 +#define PINMUX_AUX_UART2_TX 0xF4 +#define PINMUX_AUX_UART3_TX 0x104 +#define PINMUX_AUX_DAP4_DIN 0x148 +#define PINMUX_AUX_DAP4_SCLK 0x150 +#define PINMUX_AUX_GPIO_X1_AUD 0x18C +#define PINMUX_AUX_GPIO_X3_AUD 0x190 +#define PINMUX_AUX_SPDIF_IN 0x1A4 +#define PINMUX_AUX_USB_VBUS_EN0 0x1A8 +#define PINMUX_AUX_USB_VBUS_EN1 0x1AC +#define PINMUX_AUX_WIFI_EN 0x1B4 +#define PINMUX_AUX_WIFI_RST 0x1B8 +#define PINMUX_AUX_AP_WAKE_NFC 0x1CC +#define PINMUX_AUX_NFC_EN 0x1D0 +#define PINMUX_AUX_NFC_INT 0x1D4 +#define PINMUX_AUX_CAM1_PWDN 0x1EC +#define PINMUX_AUX_CAM2_PWDN 0x1F0 +#define PINMUX_AUX_LCD_BL_PWM 0x1FC +#define PINMUX_AUX_LCD_BL_EN 0x200 +#define PINMUX_AUX_LCD_RST 0x204 +#define PINMUX_AUX_LCD_GPIO2 0x20C +#define PINMUX_AUX_TOUCH_INT 0x220 +#define PINMUX_AUX_MOTION_INT 0x224 +#define PINMUX_AUX_BUTTON_HOME 0x240 +#define PINMUX_AUX_GPIO_PE6 0x248 +#define PINMUX_AUX_GPIO_PH6 0x250 +#define PINMUX_AUX_GPIO_PK3 0x260 +#define PINMUX_AUX_GPIO_PZ1 0x280 /*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */ #define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x)) #define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x)) diff --git a/source/soc/pmc.h b/source/soc/pmc.h index ec8eb99..8cd9161 100644 --- a/source/soc/pmc.h +++ b/source/soc/pmc.h @@ -25,6 +25,7 @@ #define APBDEV_PMC_PWRGATE_TOGGLE 0x30 #define APBDEV_PMC_PWRGATE_STATUS 0x38 #define APBDEV_PMC_NO_IOPOWER 0x44 +#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12) #define APBDEV_PMC_SCRATCH0 0x50 #define APBDEV_PMC_SCRATCH1 0x54 #define APBDEV_PMC_SCRATCH20 0xA0 @@ -37,6 +38,7 @@ #define APBDEV_PMC_SCRATCH33 0x120 #define APBDEV_PMC_SCRATCH40 0x13C #define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 +#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000 #define APBDEV_PMC_RST_STATUS 0x1B4 #define APBDEV_PMC_IO_DPD_REQ 0x1B8 #define APBDEV_PMC_IO_DPD2_REQ 0x1C0 @@ -51,9 +53,11 @@ #define APBDEV_PMC_REG_SHORT 0x2CC #define APBDEV_PMC_SEC_DISABLE3 0x2D8 #define APBDEV_PMC_SECURE_SCRATCH21 0x334 +#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10 #define APBDEV_PMC_SECURE_SCRATCH32 0x360 #define APBDEV_PMC_SECURE_SCRATCH49 0x3A4 #define APBDEV_PMC_CNTRL2 0x440 +#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000 #define APBDEV_PMC_IO_DPD3_REQ 0x45C #define APBDEV_PMC_IO_DPD4_REQ 0x464 #define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4 diff --git a/source/soc/t210.h b/source/soc/t210.h index 1b11d72..2f7fadd 100644 --- a/source/soc/t210.h +++ b/source/soc/t210.h @@ -20,6 +20,7 @@ #include "../utils/types.h" #define BOOTROM_BASE 0x100000 +#define IRAM_BASE 0x40000000 #define HOST1X_BASE 0x50000000 #define BPMP_CACHE_BASE 0x50040000 #define DISPLAY_A_BASE 0x54200000 @@ -100,15 +101,22 @@ #define CL_DVFS(off) _REG(CL_DVFS_BASE, off) #define TEST_REG(off) _REG(0x0, off) +/* HOST1X registers. */ +#define HOST1X_CH0_SYNC_BASE 0x2100 +#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_BASE + 0xFA4) +#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_BASE + 0x1200) + /*! EVP registers. */ #define EVP_CPU_RESET_VECTOR 0x100 /*! Misc registers. */ #define APB_MISC_PP_STRAPPING_OPT_A 0x08 #define APB_MISC_PP_PINMUX_GLOBAL 0x40 +#define APB_MISC_GP_HIDREV 0x804 #define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 #define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 #define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 +#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC #define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 #define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 @@ -118,7 +126,10 @@ /*! Secure boot registers. */ #define SB_CSR 0x0 +#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1) +#define SB_CSR_PIROM_DISABLE (1 << 4) #define SB_AA64_RESET_LOW 0x30 +#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0) #define SB_AA64_RESET_HIGH 0x34 /*! SOR registers. */ @@ -182,10 +193,31 @@ /*! PWM registers. */ #define PWM_CONTROLLER_PWM_CSR_0 0x00 #define PWM_CONTROLLER_PWM_CSR_1 0x10 +#define PWM_CSR_EN (1 << 31) /*! Special registers. */ #define EMC_SCRATCH0 0x324 #define EMC_HEKA_UPD (1 << 30) #define EMC_SEPT_RUN (1 << 31) +/*! Flow controller registers. */ +#define FLOW_CTLR_HALT_COP_EVENTS 0x4 +#define HALT_COP_SEC (1 << 23) +#define HALT_COP_MSEC (1 << 24) +#define HALT_COP_USEC (1 << 25) +#define HALT_COP_JTAG (1 << 28) +#define HALT_COP_WAIT_EVENT (1 << 30) +#define HALT_COP_WAIT_IRQ (1 << 31) +#define HALT_COP_MAX_CNT 0xFF +#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 +#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 +#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C +#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 +#define FLOW_CTLR_CPU0_CSR 0x8 +#define FLOW_CTLR_CPU1_CSR 0x18 +#define FLOW_CTLR_CPU2_CSR 0x20 +#define FLOW_CTLR_CPU3_CSR 0x28 +#define FLOW_CTLR_RAM_REPAIR 0x40 +#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 + #endif diff --git a/source/storage/sdmmc.c b/source/storage/sdmmc.c index 585268b..8ec807c 100644 --- a/source/storage/sdmmc.c +++ b/source/storage/sdmmc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (C) 2018-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, @@ -26,8 +26,6 @@ //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) -extern boot_cfg_t b_cfg; - static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) { const u32 mask = (size < 32 ? 1 << size : 0) - 1; @@ -71,6 +69,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re if (_sdmmc_storage_check_result(*resp)) if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state) return 1; + return 0; } @@ -84,6 +83,7 @@ static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage) { sdmmc_cmd_t cmd; sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0); + return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0); } @@ -93,7 +93,9 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf) sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) return 0; + sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + return 1; } @@ -108,7 +110,9 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf) sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) return 0; + sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + return 1; } @@ -146,8 +150,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out u32 tmp = 0; sdmmc_stop_transmission(storage->sdmmc, &tmp); _sdmmc_storage_get_status(storage, &tmp, 0); + return 0; } + return 1; } @@ -155,7 +161,9 @@ int sdmmc_storage_end(sdmmc_storage_t *storage) { if (!_sdmmc_storage_go_idle_state(storage)) return 0; + sdmmc_end(storage->sdmmc); + return 1; } @@ -177,14 +185,16 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu msleep(100); } while (retries); + return 0; out:; - DPRINTF("readwrite: %08X\n", blkcnt); +DPRINTF("readwrite: %08X\n", blkcnt); sector += blkcnt; num_sectors -= blkcnt; bbuf += 512 * blkcnt; } + return 1; } @@ -235,14 +245,17 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) u32 cond = 0; if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) break; + if (cond & MMC_CARD_BUSY) { if (cond & 0x40000000) storage->has_sector_access = 1; + return 1; } if (get_tmr_ms() > timeout) break; + usleep(1000); } @@ -372,6 +385,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width) if (_sdmmc_storage_check_status(storage)) { sdmmc_set_bus_width(storage->sdmmc, bus_width); + return 1; } @@ -382,14 +396,19 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS))) return 0; + if (check && !_sdmmc_storage_check_status(storage)) return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 2)) return 0; - DPRINTF("[MMC] switched to HS\n"); + +DPRINTF("[MMC] switched to HS\n"); storage->csd.busspeed = 52; + if (check || _sdmmc_storage_check_status(storage)) return 1; + return 0; } @@ -397,12 +416,16 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200))) return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 3)) return 0; + if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200)) return 0; - DPRINTF("[MMC] switched to HS200\n"); + +DPRINTF("[MMC] switched to HS200\n"); storage->csd.busspeed = 200; + return _sdmmc_storage_check_status(storage); } @@ -410,17 +433,24 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage) { if (!_mmc_storage_enable_HS200(storage)) return 0; + sdmmc_get_venclkctl(storage->sdmmc); + if (!_mmc_storage_enable_HS(storage, 0)) return 0; + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8))) return 0; + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400))) return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 4)) return 0; - DPRINTF("[MMC] switched to HS400\n"); + +DPRINTF("[MMC] switched to HS400\n"); storage->csd.busspeed = 400; + return _sdmmc_storage_check_status(storage); } @@ -432,8 +462,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type goto out; if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 && - card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && - type == 4) + card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4) return _mmc_storage_enable_HS400(storage); if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 || @@ -445,6 +474,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type out:; if (card_type & EXT_CSD_CARD_TYPE_HS_52) return _mmc_storage_enable_HS(storage, 1); + return 1; } @@ -452,6 +482,7 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2))) return 0; + return _sdmmc_storage_check_status(storage); } @@ -463,42 +494,42 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0)) return 0; - DPRINTF("[MMC] after init\n"); +DPRINTF("[MMC] after init\n"); usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!_sdmmc_storage_go_idle_state(storage)) return 0; - DPRINTF("[MMC] went to idle state\n"); +DPRINTF("[MMC] went to idle state\n"); if (!_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8)) return 0; - DPRINTF("[MMC] got op cond\n"); +DPRINTF("[MMC] got op cond\n"); if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; - DPRINTF("[MMC] got cid\n"); +DPRINTF("[MMC] got cid\n"); if (!_mmc_storage_set_relative_addr(storage)) return 0; - DPRINTF("[MMC] set relative addr\n"); +DPRINTF("[MMC] set relative addr\n"); if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; - DPRINTF("[MMC] got csd\n"); +DPRINTF("[MMC] got csd\n"); _mmc_storage_parse_csd(storage); if (!sdmmc_setup_clock(storage->sdmmc, 1)) return 0; - DPRINTF("[MMC] after setup clock\n"); +DPRINTF("[MMC] after setup clock\n"); if (!_sdmmc_storage_select_card(storage)) return 0; - DPRINTF("[MMC] card selected\n"); +DPRINTF("[MMC] card selected\n"); if (!_sdmmc_storage_set_blocklen(storage, 512)) return 0; - DPRINTF("[MMC] set blocklen to 512\n"); +DPRINTF("[MMC] set blocklen to 512\n"); u32 *csd = (u32 *)storage->raw_csd; //Check system specification version, only version 4.0 and later support below features. @@ -510,7 +541,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (!_mmc_storage_switch_buswidth(storage, bus_width)) return 0; - DPRINTF("[MMC] switched buswidth\n"); +DPRINTF("[MMC] switched buswidth\n"); u8 *ext_csd = (u8 *)malloc(512); if (!_mmc_storage_get_ext_csd(storage, ext_csd)) @@ -519,7 +550,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; } free(ext_csd); - DPRINTF("[MMC] got ext_csd\n"); +DPRINTF("[MMC] got ext_csd\n"); _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd //gfx_hexdump(0, ext_csd, 512); @@ -529,16 +560,16 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0) { _mmc_storage_enable_bkops(storage); - DPRINTF("[MMC] BKOPS enabled\n"); +DPRINTF("[MMC] BKOPS enabled\n"); } else { - DPRINTF("[MMC] BKOPS disabled\n"); +DPRINTF("[MMC] BKOPS disabled\n"); } if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) return 0; - DPRINTF("[MMC] succesfully switched to highspeed mode\n"); +DPRINTF("[MMC] succesfully switched to highspeed mode\n"); sdmmc_sd_clock_ctrl(storage->sdmmc, 1); @@ -549,8 +580,10 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition))) return 0; + if (!_sdmmc_storage_check_status(storage)) return 0; + storage->partition = partition; return 1; } @@ -564,6 +597,7 @@ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_st u32 tmp; if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask)) return 0; + return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out); } @@ -571,6 +605,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp { if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN)) return 0; + return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0); } @@ -602,6 +637,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0)) return 0; + return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3); } @@ -629,7 +665,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i return 0; storage->is_low_voltage = 1; - DPRINTF("-> switched to low voltage\n"); +DPRINTF("-> switched to low voltage\n"); } } @@ -783,17 +819,17 @@ void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf) switch (pwr) { case SD_SET_CURRENT_LIMIT_800: - DPRINTF("[SD] Power limit raised to 800mA\n"); +DPRINTF("[SD] Power limit raised to 800mA\n"); break; case SD_SET_CURRENT_LIMIT_600: - DPRINTF("[SD] Power limit raised to 600mA\n"); +DPRINTF("[SD] Power limit raised to 600mA\n"); break; case SD_SET_CURRENT_LIMIT_400: - DPRINTF("[SD] Power limit raised to 800mA\n"); +DPRINTF("[SD] Power limit raised to 800mA\n"); break; default: case SD_SET_CURRENT_LIMIT_200: - DPRINTF("[SD] Power limit defaulted to 200mA\n"); +DPRINTF("[SD] Power limit defaulted to 200mA\n"); break; } } @@ -802,10 +838,12 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) { if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type)) return 0; +DPRINTF("[SD] SD supports switch to (U)HS check\n"); u32 type_out = buf[16] & 0xF; if (type_out != hs_type) return 0; +DPRINTF("[SD] SD supports selected (U)HS mode\n"); if ((((u16)buf[0] << 8) | buf[1]) < 0x320) { @@ -834,31 +872,31 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 u32 hs_type = 0; switch (type) { - case 11: + case 11: // SDR104. // Fall through if not supported. if (buf[13] & SD_MODE_UHS_SDR104) { type = 11; hs_type = UHS_SDR104_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR104\n"); +DPRINTF("[SD] Bus speed set to SDR104\n"); storage->csd.busspeed = 104; break; } - case 10: + case 10: // SDR50. if (buf[13] & SD_MODE_UHS_SDR50) { type = 10; hs_type = UHS_SDR50_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR50\n"); +DPRINTF("[SD] Bus speed set to SDR50\n"); storage->csd.busspeed = 50; break; } - case 8: + case 8: // SDR12. if (!(buf[13] & SD_MODE_UHS_SDR12)) return 0; type = 8; hs_type = UHS_SDR12_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR12\n"); +DPRINTF("[SD] Bus speed set to SDR12\n"); storage->csd.busspeed = 12; break; default: @@ -868,10 +906,13 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 if (!_sd_storage_enable_highspeed(storage, hs_type, buf)) return 0; +DPRINTF("[SD] SD card accepted UHS\n"); if (!sdmmc_setup_clock(storage->sdmmc, type)) return 0; +DPRINTF("[SD] setup clock\n"); if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) return 0; +DPRINTF("[SD] config tuning\n"); return _sdmmc_storage_check_status(storage); } @@ -885,8 +926,10 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf) if (!_sd_storage_enable_highspeed(storage, 1, buf)) return 0; + if (!_sdmmc_storage_check_status(storage)) return 0; + return sdmmc_setup_clock(storage->sdmmc, 7); } @@ -949,7 +992,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) if (!(storage->csd.cmdclass & CCC_APP_SPEC)) { - DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); +DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); return 0; } @@ -1011,49 +1054,54 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage) } } +void sdmmc_storage_init_wait_sd() +{ + u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start; + if (sd_poweroff_time < 100) + msleep(100 - sd_poweroff_time); +} + int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) { int is_version_1 = 0; - + // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. - u32 sd_poweroff_time = (u32)get_tmr_ms() - b_cfg.sd_timeoff; - if (id == SDMMC_1 && (sd_poweroff_time < 100)) - msleep(100 - sd_poweroff_time); + sdmmc_storage_init_wait_sd(); memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0)) return 0; - DPRINTF("[SD] after init\n"); +DPRINTF("[SD] after init\n"); usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!_sdmmc_storage_go_idle_state(storage)) return 0; - DPRINTF("[SD] went to idle state\n"); +DPRINTF("[SD] went to idle state\n"); is_version_1 = _sd_storage_send_if_cond(storage); if (is_version_1 == 2) return 0; - DPRINTF("[SD] after send if cond\n"); +DPRINTF("[SD] after send if cond\n"); if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11)) return 0; - DPRINTF("[SD] got op cond\n"); +DPRINTF("[SD] got op cond\n"); if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; - DPRINTF("[SD] got cid\n"); +DPRINTF("[SD] got cid\n"); _sd_storage_parse_cid(storage); if (!_sd_storage_get_rca(storage)) return 0; - DPRINTF("[SD] got rca (= %04X)\n", storage->rca); +DPRINTF("[SD] got rca (= %04X)\n", storage->rca); if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; - DPRINTF("[SD] got csd\n"); +DPRINTF("[SD] got csd\n"); //Parse CSD. _sd_storage_parse_csd(storage); @@ -1066,7 +1114,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 storage->sec_cnt = storage->csd.c_size << 10; break; default: - DPRINTF("[SD] Unknown CSD structure %d\n", storage->csd.structure); +DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); break; } @@ -1074,21 +1122,21 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 { if (!sdmmc_setup_clock(storage->sdmmc, 6)) return 0; - DPRINTF("[SD] after setup clock\n"); +DPRINTF("[SD] after setup clock\n"); } if (!_sdmmc_storage_select_card(storage)) return 0; - DPRINTF("[SD] card selected\n"); +DPRINTF("[SD] card selected\n"); if (!_sdmmc_storage_set_blocklen(storage, 512)) return 0; - DPRINTF("[SD] set blocklen to 512\n"); +DPRINTF("[SD] set blocklen to 512\n"); u32 tmp = 0; if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN)) return 0; - DPRINTF("[SD] cleared card detect\n"); +DPRINTF("[SD] cleared card detect\n"); u8 *buf = (u8 *)malloc(512); if (!_sd_storage_get_scr(storage, buf)) @@ -1098,7 +1146,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 } //gfx_hexdump(0, storage->raw_scr, 8); - DPRINTF("[SD] got scr\n"); +DPRINTF("[SD] got scr\n"); // Check if card supports a wider bus and if it's not SD Version 1.X if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) @@ -1109,11 +1157,11 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; } sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4); - DPRINTF("[SD] switched to wide bus width\n"); +DPRINTF("[SD] switched to wide bus width\n"); } else { - DPRINTF("[SD] SD does not support wide bus width\n"); +DPRINTF("[SD] SD does not support wide bus width\n"); } if (storage->is_low_voltage) @@ -1123,7 +1171,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 free(buf); return 0; } - DPRINTF("[SD] enabled highspeed (low voltage)\n"); +DPRINTF("[SD] enabled UHS\n"); } else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) { @@ -1132,7 +1180,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 free(buf); return 0; } - DPRINTF("[SD] enabled highspeed (high voltage)\n"); +DPRINTF("[SD] enabled HS\n"); storage->csd.busspeed = 25; } @@ -1141,7 +1189,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 // Parse additional card info from sd status. if (_sd_storage_get_ssr(storage, buf)) { - DPRINTF("[SD] got sd status\n"); +DPRINTF("[SD] got sd status\n"); } free(buf); @@ -1186,13 +1234,13 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0)) return 0; - DPRINTF("[gc] after init\n"); +DPRINTF("[gc] after init\n"); usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200)) return 0; - DPRINTF("[gc] after tuning\n"); +DPRINTF("[gc] after tuning\n"); sdmmc_sd_clock_ctrl(sdmmc, 1); diff --git a/source/storage/sdmmc.h b/source/storage/sdmmc.h index a144c12..fdc2bbb 100644 --- a/source/storage/sdmmc.h +++ b/source/storage/sdmmc.h @@ -21,6 +21,8 @@ #include "../utils/types.h" #include "sdmmc_driver.h" +u32 sd_power_cycle_time_start; + typedef struct _mmc_cid { u32 manfid; @@ -47,7 +49,7 @@ typedef struct _mmc_csd u32 read_blkbits; u32 write_blkbits; u32 capacity; - u8 write_protect; + u8 write_protect; u16 busspeed; } mmc_csd_t; @@ -107,6 +109,7 @@ int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, vo int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type); int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); +void sdmmc_storage_init_wait_sd(); int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type); int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); diff --git a/source/storage/sdmmc_driver.c b/source/storage/sdmmc_driver.c index 23f6c0d..0c0c2ff 100644 --- a/source/storage/sdmmc_driver.c +++ b/source/storage/sdmmc_driver.c @@ -21,6 +21,7 @@ #include "sdmmc.h" #include "../gfx/gfx.h" #include "../power/max7762x.h" +#include "../soc/bpmp.h" #include "../soc/clock.h" #include "../soc/gpio.h" #include "../soc/pinmux.h" @@ -31,8 +32,6 @@ //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) -extern boot_cfg_t b_cfg; - /*! SCMMC controller base addresses. */ static const u32 _sdmmc_bases[4] = { 0x700B0000, @@ -123,6 +122,7 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id) { if (!sdmmc->venclkctl_set) return 0; + tap_val = sdmmc->venclkctl_tap; } else @@ -201,7 +201,7 @@ out:; int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) { - //Disable the SD clock if it was enabled, and reenable it later. + // Disable the SD clock if it was enabled, and reenable it later. bool should_enable_sd_clock = false; if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) { @@ -217,7 +217,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) case 1: case 5: case 6: - sdmmc->regs->hostctl &= 0xFB; //Should this be 0xFFFB (~4) ? + sdmmc->regs->hostctl &= 0xFB; // Should this be 0xFFFB (~4) ? sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; break; case 2: @@ -233,7 +233,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; case 4: - //Non standard + // Non standard. sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; @@ -242,7 +242,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; case 10: - //T210 Errata for SDR50, the host must be set to SDR104. + // T210 Errata for SDR50, the host must be set to SDR104. sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; @@ -264,7 +264,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) divisor = div >> 8; sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6); - //Enable the SD clock again. + // Enable the SD clock again. if (should_enable_sd_clock) sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; @@ -398,7 +398,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; - while(sdmmc->regs->prnsts & 1) //CMD inhibit. + while(sdmmc->regs->prnsts & 1) // CMD inhibit. if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -408,7 +408,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) if (wait_dat) { timeout = get_tmr_ms() + 2000; - while (sdmmc->regs->prnsts & 2) //DAT inhibit. + while (sdmmc->regs->prnsts & 2) // DAT inhibit. if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -424,7 +424,7 @@ static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc) _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; - while (!(sdmmc->regs->prnsts & 0x100000)) //DAT0 line level. + while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level. if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -511,13 +511,17 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd) return 0; _sdmmc_setup_read_small_block(sdmmc); + sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY; sdmmc->regs->norintsts = sdmmc->regs->norintsts; sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + _sdmmc_parse_cmd_48(sdmmc, cmd); _sdmmc_get_clkcon(sdmmc); usleep(1); + _sdmmc_reset(sdmmc); + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; _sdmmc_get_clkcon(sdmmc); @@ -533,10 +537,13 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd) return 1; } } + _sdmmc_reset(sdmmc); + sdmmc->regs->norintstsen &= 0xFFDF; _sdmmc_get_clkcon(sdmmc); usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); + return 0; } @@ -563,8 +570,8 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd) return 0; } - sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; - sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries. + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier. sdmmc->regs->ventunctl0 |= 0x20000; sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; @@ -577,6 +584,7 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd) if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK) return 1; + return 0; } @@ -666,7 +674,7 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) { if (get_tmr_ms() > timeout) { - //In case autocalibration fails, we load suggested standard values. + // In case autocalibration fails, we load suggested standard values. _sdmmc_pad_config_fallback(sdmmc, power); sdmmc->regs->autocalcfg &= 0xDFFFFFFF; break; @@ -703,7 +711,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) if (pout) *pout = norintsts; - //Check for error interrupt. + // Check for error interrupt. if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) { sdmmc->regs->errintsts = errintsts; @@ -746,11 +754,14 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) return 0; _sdmmc_enable_interrupts(sdmmc); + cmd.cmd = MMC_STOP_TRANSMISSION; cmd.arg = 0; cmd.rsp_type = SDMMC_RSP_TYPE_1; cmd.check_busy = 1; + _sdmmc_parse_cmdbuf(sdmmc, &cmd, false); + int res = _sdmmc_wait_request(sdmmc); _sdmmc_mask_interrupts(sdmmc); @@ -758,6 +769,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) return 0; _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); + return _sdmmc_wait_prnsts_type1(sdmmc); } @@ -777,6 +789,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) int res = _sdmmc_stop_transmission_inner(sdmmc, rsp); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + if (should_disable_sd_clock) sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; @@ -793,7 +806,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) blkcnt = 0xFFFF; u32 admaaddr = (u32)req->buf; - //Check alignment. + // Check alignment. if (admaaddr << 29) return 0; @@ -817,7 +830,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; if (req->is_auto_cmd12) trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12; - + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); sdmmc->regs->trnmod = trnmode; return 1; @@ -836,15 +849,18 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc) while (1) { u16 intr = 0; - res = _sdmmc_check_mask_interrupt(sdmmc, &intr, + res = _sdmmc_check_mask_interrupt(sdmmc, &intr, TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT); if (res < 0) break; if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) - return 1; //Transfer complete. + { + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY); + return 1; // Transfer complete. + } if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) { - //Update DMA. + // Update DMA. sdmmc->regs->admaaddr = sdmmc->dma_addr_next; sdmmc->regs->admaaddr_hi = 0; sdmmc->dma_addr_next += 0x80000; @@ -906,6 +922,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ { if (blkcnt_out) *blkcnt_out = blkcnt; + if (req->is_auto_cmd12) sdmmc->rsp3 = sdmmc->regs->rspreg3; } @@ -919,12 +936,14 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ static int _sdmmc_config_sdmmc1() { - //Configure SD card detect. + // Configure SD card detect. PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; //GPIO control, pull up. APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0; gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); usleep(100); + + // Check if SD card is inserted. if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)) return 0; @@ -937,8 +956,8 @@ static int _sdmmc_config_sdmmc1() * APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK */ - //Configure SDMMC1 pinmux. - APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; + // Configure SDMMC1 pinmux. + APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Enable deep loopback for SDMMC1 CLK pad. PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED; PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; @@ -946,12 +965,12 @@ static int _sdmmc_config_sdmmc1() PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - //Make sure the SDMMC1 controller is powered. + // Make sure the SDMMC1 controller is powered. PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12); - //Assume 3.3V SD card voltage. + // Assume 3.3V SD card voltage. PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12); - //Set enable SD card power. + // Set enable SD card power. PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down. gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO); gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH); @@ -959,13 +978,13 @@ static int _sdmmc_config_sdmmc1() usleep(1000); - //Enable SD card power. + // Enable SD card power. max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); max77620_regulator_enable(REGULATOR_LDO2, 1); usleep(1000); - //For good measure. + // For good measure. APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000; usleep(1000); @@ -1009,18 +1028,23 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7; if (!_sdmmc_autocal_config_offset(sdmmc, power)) return 0; + _sdmmc_autocal_execute(sdmmc, power); + if (_sdmmc_enable_internal_clock(sdmmc)) { sdmmc_set_bus_width(sdmmc, bus_width); _sdmmc_set_voltage(sdmmc, power); + if (sdmmc_setup_clock(sdmmc, type)) { sdmmc_sd_clock_ctrl(sdmmc, no_sd); _sdmmc_sd_clock_enable(sdmmc); _sdmmc_get_clkcon(sdmmc); + return 1; } + return 0; } return 0; @@ -1039,8 +1063,8 @@ void sdmmc_end(sdmmc_t *sdmmc) { gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); max77620_regulator_enable(REGULATOR_LDO2, 0); - b_cfg.sd_timeoff = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle. - msleep(1); // To power cycle, min 1ms without power is needed. + sd_power_cycle_time_start = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle. + usleep(1000); // To power cycle, min 1ms without power is needed. } _sdmmc_get_clkcon(sdmmc); @@ -1062,7 +1086,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b if (!sdmmc->sd_clock_enabled) return 0; - //Recalibrate periodically for SDMMC1. + // Recalibrate periodically for SDMMC1. if (sdmmc->id == SDMMC_1 && sdmmc->no_sd) _sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc)); @@ -1077,6 +1101,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + if (should_disable_sd_clock) sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; @@ -1093,6 +1118,14 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) _sdmmc_get_clkcon(sdmmc); + // Enable schmitt trigger for better duty cycle and low jitter clock. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; + max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12); @@ -1106,7 +1139,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) { sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; _sdmmc_get_clkcon(sdmmc); - msleep(1); + usleep(1000); if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) return 1; } diff --git a/source/utils/btn.c b/source/utils/btn.c index ed1b39a..f0a8ffc 100644 --- a/source/utils/btn.c +++ b/source/utils/btn.c @@ -29,7 +29,7 @@ u8 btn_read() res |= BTN_VOL_DOWN; if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) res |= BTN_VOL_UP; - if (i2c_recv_byte(4, MAX77620_I2C_ADDR, 0x15) & 0x4) + if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4) res |= BTN_POWER; return res; } diff --git a/source/utils/sprintf.c b/source/utils/sprintf.c index 4708078..4dff822 100644 --- a/source/utils/sprintf.c +++ b/source/utils/sprintf.c @@ -1,122 +1,123 @@ -/* - * Copyright (c) 2019 shchmue - * - * 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 "types.h" - -#include - -static void _putc(char *buffer, const char c) { - *buffer = c; -} - -static u32 _puts(char *buffer, const char *s) { - u32 count = 0; - for (; *s; s++, count++) - _putc(buffer + count, *s); - return count; -} - -static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) { - char buf[0x121]; - static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - char *p; - int c = fcnt; - - if (base > 36) - return 0; - - p = buf + 0x120; - *p = 0; - do { - c--; - *--p = digits[v % base]; - v /= base; - } while (v); - - if (fill != 0) { - while (c > 0) { - *--p = fill; - c--; - } - } - - return _puts(buffer, p); -} - -u32 sprintf(char *buffer, const char *fmt, ...) { - va_list ap; - int fill, fcnt; - u32 count = 0; - - va_start(ap, fmt); - while(*fmt) { - if (*fmt == '%') { - fmt++; - fill = 0; - fcnt = 0; - if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') { - fcnt = *fmt; - fmt++; - if (*fmt >= '0' && *fmt <= '9') { - fill = fcnt; - fcnt = *fmt - '0'; - fmt++; - } else { - fill = ' '; - fcnt -= '0'; - } - } - switch (*fmt) { - case 'c': - _putc(buffer + count, va_arg(ap, u32)); - count++; - break; - case 's': - count += _puts(buffer + count, va_arg(ap, char *)); - break; - case 'd': - count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt); - break; - case 'p': - case 'P': - case 'x': - case 'X': - count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt); - break; - case '%': - _putc(buffer + count, '%'); - count++; - break; - case '\0': - goto out; - default: - _putc(buffer + count, '%'); - _putc(buffer + count, *fmt); - count += 2; - break; - } - } else { - _putc(buffer + count, *fmt); - count++; - } - fmt++; - } - - out: - buffer[count] = 0; - va_end(ap); - return count; +/* + * Copyright (c) 2019 shchmue + * + * 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 "sprintf.h" + +#include + +static void _putc(char *buffer, const char c) { + *buffer = c; +} + +static u32 _puts(char *buffer, const char *s) { + u32 count = 0; + for (; *s; s++, count++) + _putc(buffer + count, *s); + return count; +} + +static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) { + char buf[0x121]; + static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + char *p; + int c = fcnt; + + if (base > 36) + return 0; + + p = buf + 0x120; + *p = 0; + do { + c--; + *--p = digits[v % base]; + v /= base; + } while (v); + + if (fill != 0) { + while (c > 0) { + *--p = fill; + c--; + } + } + + return _puts(buffer, p); +} + +u32 sprintf(char *buffer, const char *fmt, ...) { + va_list ap; + int fill, fcnt; + u32 count = 0; + + va_start(ap, fmt); + while(*fmt) { + if (*fmt == '%') { + fmt++; + fill = 0; + fcnt = 0; + if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') { + fcnt = *fmt; + fmt++; + if (*fmt >= '0' && *fmt <= '9') { + fill = fcnt; + fcnt = *fmt - '0'; + fmt++; + } else { + fill = ' '; + fcnt -= '0'; + } + } + switch (*fmt) { + case 'c': + _putc(buffer + count, va_arg(ap, u32)); + count++; + break; + case 's': + count += _puts(buffer + count, va_arg(ap, char *)); + break; + case 'd': + count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt); + break; + case 'p': + case 'P': + case 'x': + case 'X': + count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt); + break; + case '%': + _putc(buffer + count, '%'); + count++; + break; + case '\0': + goto out; + default: + _putc(buffer + count, '%'); + count++; + _putc(buffer + count, *fmt); + count++; + break; + } + } else { + _putc(buffer + count, *fmt); + count++; + } + fmt++; + } + + out: + buffer[count] = 0; + va_end(ap); + return count; } \ No newline at end of file diff --git a/source/utils/sprintf.h b/source/utils/sprintf.h index 7cb94ef..9a06022 100644 --- a/source/utils/sprintf.h +++ b/source/utils/sprintf.h @@ -1,22 +1,24 @@ -/* - * Copyright (c) 2019 shchmue - * - * 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 _SPRINTF_H_ -#define _SPRINTF_H_ - -u32 sprintf(char *buffer, const char *fmt, ...); - -#endif +/* + * Copyright (c) 2019 shchmue + * + * 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 _SPRINTF_H_ +#define _SPRINTF_H_ + +#include "types.h" + +u32 sprintf(char *buffer, const char *fmt, ...); + +#endif diff --git a/source/utils/types.h b/source/utils/types.h index 505c536..579c274 100644 --- a/source/utils/types.h +++ b/source/utils/types.h @@ -78,12 +78,18 @@ typedef int bool; typedef struct __attribute__((__packed__)) _boot_cfg_t { - u8 boot_cfg; - u8 autoboot; - u8 autoboot_list; - u8 extra_cfg; - u32 sd_timeoff; - u8 rsvd[124]; + u8 boot_cfg; + u8 autoboot; + u8 autoboot_list; + u8 extra_cfg; + union + { + struct + { + char id[8]; + }; + u8 xt_str[0x80]; + }; } boot_cfg_t; typedef struct __attribute__((__packed__)) _reloc_meta_t diff --git a/source/utils/util.c b/source/utils/util.c index 6474d5a..a1dd7cc 100644 --- a/source/utils/util.c +++ b/source/utils/util.c @@ -19,10 +19,13 @@ #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" +#define USE_RTC_TIMER + extern void sd_unmount(); u32 get_tmr_s() @@ -34,7 +37,7 @@ u32 get_tmr_ms() { // The registers must be read with the following order: // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) - return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)); + return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)); } u32 get_tmr_us() @@ -42,19 +45,32 @@ u32 get_tmr_us() return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US } -void msleep(u32 milliseconds) +void msleep(u32 ms) { - u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10); - while (((RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds) +#ifdef USE_RTC_TIMER + u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000); + // Casting to u32 is important! + while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms) ; +#else + bpmp_msleep(ms); +#endif } -void usleep(u32 microseconds) +void usleep(u32 us) { +#ifdef USE_RTC_TIMER u32 start = TMR(TIMERUS_CNTR_1US); - // Casting to u32 is important! - while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds) - ; + + // Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately. + if ((start + us) < start) + bpmp_usleep(us); + else + while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important! + ; +#else + bpmp_usleep(us); +#endif } void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) @@ -72,12 +88,15 @@ void panic(u32 val) TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN; TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN; TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; - while (1) - ; + + while (true) + usleep(1); } void reboot_normal() { + bpmp_mmu_disable(); + sd_unmount(); display_end(); @@ -86,6 +105,8 @@ void reboot_normal() void reboot_rcm() { + bpmp_mmu_disable(); + sd_unmount(); display_end(); @@ -93,16 +114,19 @@ void reboot_rcm() PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; while (true) - usleep(1); + bpmp_halt(); } void power_off() { sd_unmount(); + display_end(); // Stop the alarm, in case we injected and powered off too fast. max77620_rtc_stop_alarm(); - //TODO: we should probably make sure all regulators are powered off properly. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); + + while (true) + bpmp_halt(); } diff --git a/source/utils/util.h b/source/utils/util.h index f261035..7186263 100644 --- a/source/utils/util.h +++ b/source/utils/util.h @@ -32,8 +32,8 @@ typedef struct _cfg_op_t u32 get_tmr_us(); u32 get_tmr_ms(); u32 get_tmr_s(); -void usleep(u32 ticks); -void msleep(u32 milliseconds); +void usleep(u32 us); +void msleep(u32 ms); void panic(u32 val); void reboot_normal(); void reboot_rcm();