uplift bdk

Signed-off-by: Damien Zhao <zdm65477730@126.com>
This commit is contained in:
Damien Zhao
2024-10-21 16:21:40 +08:00
parent cd38dbc1ae
commit 22b1fda1d5
64 changed files with 1289 additions and 808 deletions

View File

@@ -49,6 +49,7 @@
#include <soc/gpio.h>
#include <soc/hw_init.h>
#include <soc/i2c.h>
#include <soc/irq.h>
#include <soc/kfuse.h>
#include <soc/pinmux.h>
#include <soc/pmc.h>
@@ -76,4 +77,4 @@
#include <gfx_utils.h>
#endif
#endif

View File

@@ -59,7 +59,7 @@ void display_wait_interrupt(u32 intr)
// Interrupts are masked. Poll status register for checking if fired.
while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & intr))
;
;
}
static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
@@ -373,24 +373,10 @@ void display_init()
// Get Chip ID.
bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;
// T210B01: Power on SD2 regulator for supplying LDO0.
if (!tegra_t210)
{
// Set SD2 regulator voltage.
max7762x_regulator_set_voltage(REGULATOR_SD2, 1325000);
// Set slew rate and enable SD2 regulator.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD2_CFG, (1 << MAX77620_SD_SR_SHIFT) | MAX77620_SD_CFG1_FSRADE_SD_ENABLE);
max7762x_regulator_enable(REGULATOR_SD2, true);
}
// Enable LCD DVDD.
// Enable DSI AVDD.
max7762x_regulator_set_voltage(REGULATOR_LDO0, 1200000);
max7762x_regulator_enable(REGULATOR_LDO0, true);
if (tegra_t210)
max77620_config_gpio(7, MAX77620_GPIO_OUTPUT_ENABLE); // T210: LD0 -> GPIO7 -> LCD.
// Enable Display Interface specific clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI);
@@ -398,7 +384,7 @@ void display_init()
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_DISP1);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_UART_FST_MIPI_CAL);
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = CLK_SRC_DIV(6); // Set PLLP_OUT3 and div 6 (17MHz).
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = CLK_SRC_DIV(6); // Set PLLP_OUT3 and div 6 (68MHz).
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_DSIA_LP);
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = CLK_SRC_DIV(6); // Set PLLP_OUT and div 6 (68MHz).
@@ -448,26 +434,19 @@ void display_init()
clock_enable_plld(3, 20, true, tegra_t210);
// Setup Display Interface initial window configuration.
exec_cfg((u32 *)DISPLAY_A_BASE, _di_dc_setup_win_config, CFG_SIZE(_di_dc_setup_win_config));
reg_write_array((u32 *)DISPLAY_A_BASE, _di_dc_setup_win_config, ARRAY_SIZE(_di_dc_setup_win_config));
// Setup dsi init sequence packets.
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_irq_pkt_config0, CFG_SIZE(_di_dsi_init_irq_pkt_config0));
if (tegra_t210)
DSI(_DSIREG(DSI_INIT_SEQ_DATA_15)) = 0;
else
DSI(_DSIREG(DSI_INIT_SEQ_DATA_15_B01)) = 0;
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_irq_pkt_config1, CFG_SIZE(_di_dsi_init_irq_pkt_config1));
reg_write_array((u32 *)DSI_BASE, _di_dsi_seq_pkt_reset_config0, ARRAY_SIZE(_di_dsi_seq_pkt_reset_config0));
DSI(_DSIREG(tegra_t210 ? DSI_INIT_SEQ_DATA_15 : DSI_INIT_SEQ_DATA_15_B01)) = 0;
reg_write_array((u32 *)DSI_BASE, _di_dsi_seq_pkt_reset_config1, ARRAY_SIZE(_di_dsi_seq_pkt_reset_config1));
// Reset pad trimmers for T210B01.
if (!tegra_t210)
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_pads_t210b01, CFG_SIZE(_di_dsi_init_pads_t210b01));
reg_write_array((u32 *)DSI_BASE, _di_dsi_init_pads_t210b01, ARRAY_SIZE(_di_dsi_init_pads_t210b01));
// Setup init sequence packets and timings.
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_timing_pkt_config2, CFG_SIZE(_di_dsi_init_timing_pkt_config2));
DSI(_DSIREG(DSI_PHY_TIMING_0)) = tegra_t210 ? 0x6070601 : 0x6070603; // DSI_THSPREPR: 1 : 3.
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_timing_pwrctrl_config, CFG_SIZE(_di_dsi_init_timing_pwrctrl_config));
DSI(_DSIREG(DSI_PHY_TIMING_0)) = tegra_t210 ? 0x6070601 : 0x6070603; // DSI_THSPREPR: 1 : 3.
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_timing_pkt_config3, CFG_SIZE(_di_dsi_init_timing_pkt_config3));
// Setup init seq packet lengths, timings and power on DSI.
reg_write_array((u32 *)DSI_BASE, _di_dsi_init_config, ARRAY_SIZE(_di_dsi_init_config));
usleep(10000);
// Enable LCD Reset.
@@ -505,9 +484,9 @@ void display_init()
{
case PANEL_SAM_AMS699VC01:
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000);
// Set color mode to natural. Stock is Saturated (0x00). (Reset value is 0x20).
// Set color mode to basic (natural). Stock is Saturated (0x00). (Reset value is 0x20).
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM,
MIPI_DCS_PRIV_SM_SET_COLOR_MODE | (DCS_SM_COLOR_MODE_NATURAL << 8), 0);
MIPI_DCS_PRIV_SM_SET_COLOR_MODE | (DCS_SM_COLOR_MODE_BASIC << 8), 0);
// Enable backlight and smooth PWM.
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM,
MIPI_DCS_SET_CONTROL_DISPLAY | ((DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL | DCS_CONTROL_DISPLAY_DIMMING_CTRL) << 8), 0);
@@ -537,7 +516,7 @@ void display_init()
break;
case PANEL_JDI_XXX062M:
exec_cfg((u32 *)DSI_BASE, _di_dsi_panel_init_config_jdi, CFG_SIZE(_di_dsi_panel_init_config_jdi));
reg_write_array((u32 *)DSI_BASE, _di_dsi_panel_init_config_jdi, ARRAY_SIZE(_di_dsi_panel_init_config_jdi));
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000);
break;
@@ -578,21 +557,24 @@ void display_init()
clock_enable_plld(1, 24, false, tegra_t210);
// Finalize DSI init packet sequence configuration.
DSI(_DSIREG(DSI_PAD_CONTROL_1)) = 0;
DSI(_DSIREG(DSI_PHY_TIMING_0)) = tegra_t210 ? 0x6070601 : 0x6070603;
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_seq_pkt_final_config, CFG_SIZE(_di_dsi_init_seq_pkt_final_config));
reg_write_array((u32 *)DSI_BASE, _di_dsi_seq_pkt_video_non_burst_no_eot_config, ARRAY_SIZE(_di_dsi_seq_pkt_video_non_burst_no_eot_config));
// Set 1-by-1 pixel/clock and pixel clock to 234 / 3 = 78 MHz. For 60 Hz refresh rate.
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4); // 4: div3.
// Set DSI mode.
exec_cfg((u32 *)DSI_BASE, _di_dsi_mode_config, CFG_SIZE(_di_dsi_mode_config));
// Set DSI mode to HOST.
reg_write_array((u32 *)DSI_BASE, _di_dsi_host_mode_config, ARRAY_SIZE(_di_dsi_host_mode_config));
usleep(10000);
// Calibrate display communication pads.
u32 loops = tegra_t210 ? 1 : 2; // Calibrate pads 2 times on T210B01.
exec_cfg((u32 *)MIPI_CAL_BASE, _di_mipi_pad_cal_config, CFG_SIZE(_di_mipi_pad_cal_config));
for (u32 i = 0; i < loops; i++)
/*
* Calibrate display communication pads.
* When switching to the 16ff pad brick, the clock lane termination control
* is separated from data lane termination. This change of the mipi cal
* brings in a bug that the DSI pad clock termination code can't be loaded
* in one time calibration. Trigger calibration twice.
*/
reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_pad_cal_config, ARRAY_SIZE(_di_mipi_pad_cal_config));
for (u32 i = 0; i < 2; i++)
{
// Set MIPI bias pad config.
MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0x10010;
@@ -601,22 +583,25 @@ void display_init()
// Set pad trimmers and set MIPI DSI cal offsets.
if (tegra_t210)
{
exec_cfg((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210, CFG_SIZE(_di_dsi_pad_cal_config_t210));
exec_cfg((u32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_offsets_config_t210, CFG_SIZE(_di_mipi_dsi_cal_offsets_config_t210));
reg_write_array((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210, ARRAY_SIZE(_di_dsi_pad_cal_config_t210));
reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_prod_config_t210, ARRAY_SIZE(_di_mipi_dsi_cal_prod_config_t210));
}
else
{
exec_cfg((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210b01, CFG_SIZE(_di_dsi_pad_cal_config_t210b01));
exec_cfg((u32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_offsets_config_t210b01, CFG_SIZE(_di_mipi_dsi_cal_offsets_config_t210b01));
reg_write_array((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210b01, ARRAY_SIZE(_di_dsi_pad_cal_config_t210b01));
reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_prod_config_t210b01, ARRAY_SIZE(_di_mipi_dsi_cal_prod_config_t210b01));
}
// Reset all MIPI cal offsets and start calibration.
exec_cfg((u32 *)MIPI_CAL_BASE, _di_mipi_start_dsi_cal_config, CFG_SIZE(_di_mipi_start_dsi_cal_config));
// Reset all unused MIPI cal offsets.
reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_unused_config, ARRAY_SIZE(_di_mipi_dsi_cal_unused_config));
// Set Prescale/filter and start calibration.
MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_CAL_CTRL)) = 0x2A000001;
}
usleep(10000);
// Enable video display controller.
exec_cfg((u32 *)DISPLAY_A_BASE, _di_dc_video_enable_config, CFG_SIZE(_di_dc_video_enable_config));
reg_write_array((u32 *)DISPLAY_A_BASE, _di_dc_video_enable_config, ARRAY_SIZE(_di_dc_video_enable_config));
}
void display_backlight_pwm_init()
@@ -624,12 +609,15 @@ void display_backlight_pwm_init()
if (_display_id == PANEL_SAM_AMS699VC01)
return;
// Enable PWM clock.
clock_enable_pwm();
// Enable PWM and set it to 25KHz PFM. 29.5KHz is stock.
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN;
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_FUNC_MASK) | 1; // Set PWM0 mode.
usleep(2);
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
}
@@ -650,9 +638,9 @@ static void _display_dsi_backlight_brightness(u32 duty)
u16 bl_ctrl = byte_swap_16((u16)candela);
display_dsi_vblank_write(MIPI_DCS_SET_BRIGHTNESS, 2, &bl_ctrl);
// Wait for backlight to completely turn off. 6+1 frames.
// Wait for backlight to completely turn off. 6 frames.
if (!duty)
usleep(120000);
usleep(100000);
_dsi_bl = duty;
}
@@ -696,7 +684,10 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
u32 display_get_backlight_brightness()
{
return ((PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF);
if (_display_id != PANEL_SAM_AMS699VC01)
return ((PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF);
else
return _dsi_bl;
}
static void _display_panel_and_hw_end(bool no_panel_deinit)
@@ -713,14 +704,15 @@ static void _display_panel_and_hw_end(bool no_panel_deinit)
DSI(_DSIREG(DSI_WR_DATA)) = (MIPI_DCS_SET_DISPLAY_OFF << 8) | MIPI_DSI_DCS_SHORT_WRITE;
// Wait for 5 frames (HOST1X_CH0_SYNC_SYNCPT_9).
// Not here.
// Not here. Wait for 1 frame manually.
usleep(20000);
// Propagate changes to all register buffers and disable host cmd packets during video.
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX_ACTIVE | WRITE_MUX_ACTIVE;
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
// De-initialize video controller.
exec_cfg((u32 *)DISPLAY_A_BASE, _di_dc_video_disable_config, CFG_SIZE(_di_dc_video_disable_config));
reg_write_array((u32 *)DISPLAY_A_BASE, _di_dc_video_disable_config, ARRAY_SIZE(_di_dc_video_disable_config));
// Set DISP1 clock source, parent clock and DSI/PCLK to low power mode.
// T210: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-PCLK): 50.0 MHz. (PCLK: 16.66 MHz)
@@ -728,7 +720,7 @@ static void _display_panel_and_hw_end(bool no_panel_deinit)
clock_enable_plld(3, 20, true, hw_get_chip_id() == GP_HIDREV_MAJOR_T210);
// Set timings for lowpower clocks.
exec_cfg((u32 *)DSI_BASE, _di_dsi_timing_deinit_config, CFG_SIZE(_di_dsi_timing_deinit_config));
reg_write_array((u32 *)DSI_BASE, _di_dsi_timing_deinit_config, ARRAY_SIZE(_di_dsi_timing_deinit_config));
if (_display_id != PANEL_SAM_AMS699VC01)
usleep(10000);
@@ -737,11 +729,12 @@ static void _display_panel_and_hw_end(bool no_panel_deinit)
switch (_display_id)
{
case PANEL_JDI_XXX062M:
exec_cfg((u32 *)DSI_BASE, _di_dsi_panel_deinit_config_jdi, CFG_SIZE(_di_dsi_panel_deinit_config_jdi));
reg_write_array((u32 *)DSI_BASE, _di_dsi_panel_deinit_config_jdi, ARRAY_SIZE(_di_dsi_panel_deinit_config_jdi));
break;
case PANEL_AUO_A062TAN01:
exec_cfg((u32 *)DSI_BASE, _di_dsi_panel_deinit_config_auo, CFG_SIZE(_di_dsi_panel_deinit_config_auo));
reg_write_array((u32 *)DSI_BASE, _di_dsi_panel_deinit_config_auo, ARRAY_SIZE(_di_dsi_panel_deinit_config_auo));
usleep(5000);
break;
case PANEL_INL_2J055IA_27A:
@@ -796,6 +789,10 @@ skip_panel_deinit:
{
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); // LCD AVDD -5.4V disable.
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); // LCD AVDD +5.4V disable.
// Make sure LCD PWM backlight pin is in PWM0 mode.
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = PINMUX_TRISTATE | PINMUX_PULL_DOWN | 1; // Set PWM0 mode.
}
usleep(10000);
@@ -810,14 +807,7 @@ skip_panel_deinit:
DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
// Switch LCD PWM backlight pin to special function mode and enable PWM0 mode.
if (!_nx_aula)
{
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = PINMUX_TRISTATE | PINMUX_PULL_DOWN | 1; // Set PWM0 mode.
}
// Disable LCD DVDD.
// Disable DSI AVDD.
max7762x_regulator_enable(REGULATOR_LDO0, false);
}
@@ -846,14 +836,15 @@ void display_set_decoded_panel_id(u32 id)
void display_color_screen(u32 color)
{
exec_cfg((u32 *)DISPLAY_A_BASE, _di_win_one_color, CFG_SIZE(_di_win_one_color));
// Disable all windows.
reg_write_array((u32 *)DISPLAY_A_BASE, _di_win_one_color, ARRAY_SIZE(_di_win_one_color));
// Configure display to show single color.
DISPLAY_A(_DIREG(DC_WIN_AD_WIN_OPTIONS)) = 0;
DISPLAY_A(_DIREG(DC_WIN_BD_WIN_OPTIONS)) = 0;
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;
// Arm and activate changes.
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE | WIN_D_UPDATE;
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ;
usleep(35000); // Wait 2 frames. No need on Aula.
if (_display_id != PANEL_SAM_AMS699VC01)
@@ -862,58 +853,108 @@ void display_color_screen(u32 color)
display_backlight_brightness(150, 0);
}
u32 *display_init_framebuffer_pitch()
u32 *display_init_window_a_pitch()
{
// Sanitize framebuffer area.
memset((u32 *)IPL_FB_ADDRESS, 0, IPL_FB_SZ);
// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 720x1280 (line stride 720).
exec_cfg((u32 *)DISPLAY_A_BASE, _di_win_framebuffer_pitch, CFG_SIZE(_di_win_framebuffer_pitch));
reg_write_array((u32 *)DISPLAY_A_BASE, _di_winA_pitch, ARRAY_SIZE(_di_winA_pitch));
//usleep(35000); // Wait 2 frames. No need on Aula.
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR));
}
u32 *display_init_framebuffer_pitch_vic()
u32 *display_init_window_a_pitch_vic()
{
// This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280 (line stride 720).
if (_display_id != PANEL_SAM_AMS699VC01)
usleep(8000); // Wait half frame for PWM to apply.
exec_cfg((u32 *)DISPLAY_A_BASE, _di_win_framebuffer_pitch_vic, CFG_SIZE(_di_win_framebuffer_pitch_vic));
reg_write_array((u32 *)DISPLAY_A_BASE, _di_winA_pitch_vic, ARRAY_SIZE(_di_winA_pitch_vic));
if (_display_id != PANEL_SAM_AMS699VC01)
usleep(35000); // Wait 2 frames.
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR));
}
u32 *display_init_framebuffer_pitch_inv()
u32 *display_init_window_a_pitch_inv()
{
// This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280 (line stride 720).
exec_cfg((u32 *)DISPLAY_A_BASE, _di_win_framebuffer_pitch_inv, CFG_SIZE(_di_win_framebuffer_pitch_inv));
reg_write_array((u32 *)DISPLAY_A_BASE, _di_winA_pitch_inv, ARRAY_SIZE(_di_winA_pitch_inv));
usleep(35000); // Wait 2 frames. No need on Aula.
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR));
}
u32 *display_init_framebuffer_block()
u32 *display_init_window_a_block()
{
// This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280.
exec_cfg((u32 *)DISPLAY_A_BASE, _di_win_framebuffer_block, CFG_SIZE(_di_win_framebuffer_block));
reg_write_array((u32 *)DISPLAY_A_BASE, _di_winA_block, ARRAY_SIZE(_di_winA_block));
usleep(35000); // Wait 2 frames. No need on Aula.
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR));
}
u32 *display_init_framebuffer_log()
u32 *display_init_window_d_console()
{
// This configures the framebuffer @ LOG_FB_ADDRESS with a resolution of 1280x720 (line stride 720).
exec_cfg((u32 *)DISPLAY_A_BASE, _di_win_framebuffer_log, CFG_SIZE(_di_win_framebuffer_log));
reg_write_array((u32 *)DISPLAY_A_BASE, _di_winD_log, ARRAY_SIZE(_di_winD_log));
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR));
}
void display_activate_console()
void display_window_disable(u32 window)
{
// Select window C.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = BIT(WINDOW_SELECT + window);
// Disable window C.
DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = 0;
// Arm and activate changes.
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | BIT(WIN_UPDATE + window);
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window);
}
void display_set_framebuffer(u32 window, void *fb)
{
// Select window.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = BIT(WINDOW_SELECT + window);
// Set new fb address.
DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)) = (u32)fb;
// Arm and activate changes.
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | BIT(WIN_UPDATE + window);
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window);
}
void display_move_framebuffer(u32 window, void *fb)
{
// Select window.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = BIT(WINDOW_SELECT + window);
// Get current framebuffer address.
const void *fb_curr = (void *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR));
u32 win_size = DISPLAY_A(_DIREG(DC_WIN_PRESCALED_SIZE));
win_size = (win_size & 0x7FFF) * ((win_size >> 16) & 0x1FFF);
// Copy fb over.
memcpy(fb, fb_curr, win_size);
// Set new fb address.
DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)) = (u32)fb;
// Arm and activate changes.
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | BIT(WIN_UPDATE + window);
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window);
}
void display_window_d_console_enable()
{
// Only update active registers on vsync.
DISPLAY_A(_DIREG(DC_CMD_REG_ACT_CONTROL)) = DISPLAY_A(_DIREG(DC_CMD_REG_ACT_CONTROL)) & ~WIN_D_ACT_HCNTR_SEL;
// Select window D.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT;
@@ -942,12 +983,9 @@ void display_activate_console()
// Arm and activate changes.
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE;
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ;
// Re-select window A.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_A_SELECT;
}
void display_deactivate_console()
void display_window_d_console_disable()
{
// Select window D.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT;
@@ -965,18 +1003,15 @@ void display_deactivate_console()
}
// Disable window D.
DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0;
DISPLAY_A(_DIREG(DC_WIN_POSITION)) = 0;
DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = 0;
// Arm and activate changes.
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE;
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | WIN_D_ACT_REQ;
// Re-select window A.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_A_SELECT;
}
void display_init_cursor(void *crs_fb, u32 size)
void display_cursor_init(void *crs_fb, u32 size)
{
// Setup cursor.
DISPLAY_A(_DIREG(DC_DISP_CURSOR_START_ADDR)) = CURSOR_CLIPPING(CURSOR_CLIP_WIN_A) | size | ((u32)crs_fb >> 10);
@@ -992,7 +1027,7 @@ void display_init_cursor(void *crs_fb, u32 size)
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ;
}
void display_set_pos_cursor(u32 x, u32 y)
void display_cursor_set_pos(u32 x, u32 y)
{
// Set cursor position.
DISPLAY_A(_DIREG(DC_DISP_CURSOR_POSITION)) = x | (y << 16);
@@ -1002,7 +1037,7 @@ void display_set_pos_cursor(u32 x, u32 y)
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ;
}
void display_deinit_cursor()
void display_cursor_deinit()
{
DISPLAY_A(_DIREG(DC_DISP_BLEND_CURSOR_CONTROL)) = 0;
DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) &= ~CURSOR_ENABLE;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2023 CTCaer
* Copyright (c) 2018-2024 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,
@@ -24,6 +24,11 @@
#define DSI_VIDEO_DISABLED 0
#define DSI_VIDEO_ENABLED 1
#define WINDOW_A 0
#define WINDOW_B 1
#define WINDOW_C 2
#define WINDOW_D 3
/*! Display registers. */
#define _DIREG(reg) ((reg) * 4)
@@ -43,8 +48,8 @@
// DC_CMD non-shadowed command/sync registers.
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00
#define SYNCPT_GENERAL_INDX(x) (((x) & 0xff) << 0)
#define SYNCPT_GENERAL_COND(x) (((x) & 0xff) << 8)
#define SYNCPT_GENERAL_INDX(x) (((x) & 0xFF) << 0)
#define SYNCPT_GENERAL_COND(x) (((x) & 0xFF) << 8)
#define COND_REG_WR_SAFE 3
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01
@@ -52,7 +57,7 @@
#define SYNCPT_CNTRL_NO_STALL BIT(8)
#define DC_CMD_CONT_SYNCPT_VSYNC 0x28
#define SYNCPT_VSYNC_INDX(x) (((x) & 0xff) << 0)
#define SYNCPT_VSYNC_INDX(x) (((x) & 0xFF) << 0)
#define SYNCPT_VSYNC_ENABLE BIT(8)
#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
@@ -77,19 +82,24 @@
#define DC_CMD_INT_ENABLE 0x39
#define DC_CMD_INT_FRAME_END_INT BIT(1)
#define DC_CMD_INT_V_BLANK_INT BIT(2)
#define DC_CMD_INT_POLARITY 0x3B
#define DC_CMD_STATE_ACCESS 0x40
#define READ_MUX BIT(0)
#define WRITE_MUX BIT(2)
#define READ_MUX_ASSEMBLY 0x0
#define WRITE_MUX_ASSEMBLY 0x0
#define READ_MUX_ACTIVE BIT(0)
#define WRITE_MUX_ACTIVE BIT(2)
#define DC_CMD_STATE_CONTROL 0x41
#define GENERAL_ACT_REQ BIT(0)
#define WIN_ACT_REQ 1
#define WIN_A_ACT_REQ BIT(1)
#define WIN_B_ACT_REQ BIT(2)
#define WIN_C_ACT_REQ BIT(3)
#define WIN_D_ACT_REQ BIT(4)
#define CURSOR_ACT_REQ BIT(7)
#define GENERAL_UPDATE BIT(8)
#define WIN_UPDATE 9
#define WIN_A_UPDATE BIT(9)
#define WIN_B_UPDATE BIT(10)
#define WIN_C_UPDATE BIT(11)
@@ -98,6 +108,7 @@
#define NC_HOST_TRIG BIT(24)
#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42
#define WINDOW_SELECT 4
#define WINDOW_A_SELECT BIT(4)
#define WINDOW_B_SELECT BIT(5)
#define WINDOW_C_SELECT BIT(6)
@@ -137,6 +148,31 @@
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
#define LSC0_OUTPUT_POLARITY_LOW BIT(24)
// CMU registers.
#define DC_COM_CMU_CSC_KRR 0x32A
#define DC_COM_CMU_CSC_KGR 0x32B
#define DC_COM_CMU_CSC_KBR 0x32C
#define DC_COM_CMU_CSC_KRG 0x32D
#define DC_COM_CMU_CSC_KGG 0x32E
#define DC_COM_CMU_CSC_KBG 0x32F
#define DC_COM_CMU_CSC_KRB 0x330
#define DC_COM_CMU_CSC_KGB 0x331
#define DC_COM_CMU_CSC_KBB 0x332
#define DC_COM_CMU_LUT1 0x336
#define LUT1_ADDR(x) ((x) & 0xFF)
#define LUT1_DATA(x) (((x) & 0xFFF) << 16)
#define LUT1_READ_DATA(x) (((x) >> 16) & 0xFFF)
#define DC_COM_CMU_LUT2 0x337
#define LUT2_ADDR(x) ((x) & 0x3FF)
#define LUT2_DATA(x) (((x) & 0xFF) << 16)
#define LUT2_READ_DATA(x) (((x) >> 16) & 0xFF)
#define DC_COM_CMU_LUT1_READ 0x338
#define LUT1_READ_ADDR(x) (((x) & 0xFF) << 8)
#define LUT1_READ_EN BIT(0)
#define DC_COM_CMU_LUT2_READ 0x339
#define LUT2_READ_ADDR(x) (((x) & 0x3FF) << 8)
#define LUT2_READ_EN BIT(0)
#define DC_COM_DSC_TOP_CTL 0x33E
// DC_DISP shadowed registers.
@@ -153,30 +189,30 @@
#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404
#define DC_DISP_DISP_TIMING_OPTIONS 0x405
#define VSYNC_H_POSITION(x) (((x) & 0x1fff) << 0)
#define VSYNC_H_POSITION(x) (((x) & 0x1FFF) << 0)
#define DC_DISP_REF_TO_SYNC 0x406
#define H_REF_TO_SYNC(x) (((x) & 0x1fff) << 0) // Min 0 pixel clock.
#define V_REF_TO_SYNC(x) (((x) & 0x1fff) << 16) // Min 1 line clock.
#define H_REF_TO_SYNC(x) (((x) & 0x1FFF) << 0) // Min 0 pixel clock.
#define V_REF_TO_SYNC(x) (((x) & 0x1FFF) << 16) // Min 1 line clock.
#define DC_DISP_SYNC_WIDTH 0x407
#define H_SYNC_WIDTH(x) (((x) & 0x1fff) << 0) // Min 1 pixel clock.
#define V_SYNC_WIDTH(x) (((x) & 0x1fff) << 16) // Min 1 line clock.
#define H_SYNC_WIDTH(x) (((x) & 0x1FFF) << 0) // Min 1 pixel clock.
#define V_SYNC_WIDTH(x) (((x) & 0x1FFF) << 16) // Min 1 line clock.
#define DC_DISP_BACK_PORCH 0x408
#define H_BACK_PORCH(x) (((x) & 0x1fff) << 0)
#define V_BACK_PORCH(x) (((x) & 0x1fff) << 16)
#define H_BACK_PORCH(x) (((x) & 0x1FFF) << 0)
#define V_BACK_PORCH(x) (((x) & 0x1FFF) << 16)
#define DC_DISP_ACTIVE 0x409
#define H_DISP_ACTIVE(x) (((x) & 0x1fff) << 0) // Min 16 pixel clock.
#define V_DISP_ACTIVE(x) (((x) & 0x1fff) << 16) // Min 16 line clock.
#define H_DISP_ACTIVE(x) (((x) & 0x1FFF) << 0) // Min 16 pixel clock.
#define V_DISP_ACTIVE(x) (((x) & 0x1FFF) << 16) // Min 16 line clock.
#define DC_DISP_FRONT_PORCH 0x40A
#define H_FRONT_PORCH(x) (((x) & 0x1fff) << 0) // Min -=PS_=-H_REF_TO_SYNC + 1
#define V_FRONT_PORCH(x) (((x) & 0x1fff) << 16) // Min -=PS_=-V_REF_TO_SYNC + 1
#define H_FRONT_PORCH(x) (((x) & 0x1FFF) << 0) // Min -=PS_=-H_REF_TO_SYNC + 1
#define V_FRONT_PORCH(x) (((x) & 0x1FFF) << 16) // Min -=PS_=-V_REF_TO_SYNC + 1
#define DC_DISP_DISP_CLOCK_CONTROL 0x42E
#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
#define SHIFT_CLK_DIVIDER(x) ((x) & 0xFF)
#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8)
#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
@@ -207,11 +243,7 @@
#define DISP_ORDER_BLUE_RED (1 << 9)
#define DC_DISP_DISP_COLOR_CONTROL 0x430
#define DITHER_CONTROL_MASK (3 << 8)
#define DITHER_CONTROL_DISABLE (0 << 8)
#define DITHER_CONTROL_ORDERED (2 << 8)
#define DITHER_CONTROL_ERRDIFF (3 << 8)
#define BASE_COLOR_SIZE_MASK (0xf << 0)
#define BASE_COLOR_SIZE_MASK (0xF << 0)
#define BASE_COLOR_SIZE_666 (0 << 0)
#define BASE_COLOR_SIZE_111 (1 << 0)
#define BASE_COLOR_SIZE_222 (2 << 0)
@@ -221,6 +253,13 @@
#define BASE_COLOR_SIZE_565 (6 << 0)
#define BASE_COLOR_SIZE_332 (7 << 0)
#define BASE_COLOR_SIZE_888 (8 << 0)
#define DITHER_CONTROL_MASK (3 << 8)
#define DITHER_CONTROL_DISABLE (0 << 8)
#define DITHER_CONTROL_ORDERED (2 << 8)
#define DITHER_CONTROL_ERRDIFF (3 << 8)
#define DISP_COLOR_SWAP BIT(16)
#define BLANK_COLOR_WHITE BIT(17)
#define CMU_ENABLE BIT(20)
#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
#define SC0_H_QUALIFIER_NONE BIT(0)
@@ -242,6 +281,7 @@
#define CURSOR_COLOR(r,g,b) (((r) & 0xFF) | (((g) & 0xFF) << 8) | (((b) & 0xFF) << 16))
#define DC_DISP_CURSOR_START_ADDR 0x43E
#define DC_DISP_CURSOR_START_ADDR_NS 0x43F
#define CURSOR_CLIPPING(w) ((w) << 28)
#define CURSOR_CLIP_WIN_A 1
#define CURSOR_CLIP_WIN_B 2
@@ -253,6 +293,7 @@
#define DC_DISP_CURSOR_POSITION 0x440
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4
#define DC_DISP_CURSOR_START_ADDR_HI 0x4EC
#define DC_DISP_CURSOR_START_ADDR_HI_NS 0x4ED
#define DC_DISP_BLEND_CURSOR_CONTROL 0x4F1
#define CURSOR_BLEND_2BIT (0 << 24)
#define CURSOR_BLEND_R8G8B8A8 (1 << 24)
@@ -269,17 +310,22 @@
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4
#define DC_WINC_COLOR_PALETTE 0x500
#define DC_WINC_COLOR_PALETTE_IDX(off) (DC_WINC_COLOR_PALETTE + (off))
#define COLOR_PALETTE_IDX(off) (DC_WINC_COLOR_PALETTE + (off))
#define COLOR_PALETTE_RGB(rgb) (byte_swap_32(rgb) >> 8)
#define DC_WINC_PALETTE_COLOR_EXT 0x600
#define DC_WIN_CSC_YOF 0x611
#define DC_WIN_CSC_KYRGB 0x612
#define DC_WIN_CSC_KUR 0x613
#define DC_WIN_CSC_KVR 0x614
#define DC_WIN_CSC_KUG 0x615
#define DC_WIN_CSC_KVG 0x616
#define DC_WIN_CSC_KUB 0x617
#define DC_WIN_CSC_KVB 0x618
#define DC_WINC_H_FILTER_P(p) (0x601 + (p))
#define DC_WINC_V_FILTER_P(p) (0x619 + (p))
#define DC_WINC_H_FILTER_HI_P(p) (0x629 + (p))
#define DC_WINC_CSC_YOF 0x611
#define DC_WINC_CSC_KYRGB 0x612
#define DC_WINC_CSC_KUR 0x613
#define DC_WINC_CSC_KVR 0x614
#define DC_WINC_CSC_KUG 0x615
#define DC_WINC_CSC_KVG 0x616
#define DC_WINC_CSC_KUB 0x617
#define DC_WINC_CSC_KVB 0x618
#define DC_WIN_AD_WIN_OPTIONS 0xB80
#define DC_WIN_BD_WIN_OPTIONS 0xD80
#define DC_WIN_CD_WIN_OPTIONS 0xF80
@@ -290,15 +336,17 @@
#define V_DIRECTION BIT(2)
#define SCAN_COLUMN BIT(4)
#define COLOR_EXPAND BIT(6)
#define H_FILTER_ENABLE BIT(8)
#define V_FILTER_ENABLE BIT(10)
#define COLOR_PALETTE_ENABLE BIT(16)
#define CSC_ENABLE BIT(18)
#define DV_ENABLE BIT(20)
#define WIN_ENABLE BIT(30)
#define H_FILTER_EXPAND BIT(31)
#define DC_WIN_BUFFER_CONTROL 0x702
#define BUFFER_CONTROL_HOST 0
#define BUFFER_CONTROL_VI 1
#define BUFFER_CONTROL_EPP 2
#define BUFFER_CONTROL_MPEGE 3
#define BUFFER_CONTROL_SB2D 4
#define DC_WIN_COLOR_DEPTH 0x703
@@ -324,6 +372,10 @@
#define WIN_COLOR_DEPTH_YUV422R 0x17
#define WIN_COLOR_DEPTH_YCbCr422RA 0x18
#define WIN_COLOR_DEPTH_YUV422RA 0x19
#define WIN_COLOR_DEPTH_X1R5G5B5 0x1E
#define WIN_COLOR_DEPTH_R5G5B5X1 0x1F
#define WIN_COLOR_DEPTH_X1B5G5R5 0x20
#define WIN_COLOR_DEPTH_B5G5R5X1 0x21
#define WIN_COLOR_DEPTH_YCbCr444P 0x29
#define WIN_COLOR_DEPTH_YCrCb420SP 0x2A
#define WIN_COLOR_DEPTH_YCbCr420SP 0x2B
@@ -338,33 +390,37 @@
#define WIN_COLOR_DEPTH_YUV444SP 0x3C
#define DC_WIN_POSITION 0x704
#define H_POSITION(x) (((x) & 0xffff) << 0) // Support negative.
#define V_POSITION(x) (((x) & 0xffff) << 16) // Support negative.
#define H_POSITION(x) (((x) & 0xFFFF) << 0) // Support negative.
#define V_POSITION(x) (((x) & 0xFFFF) << 16) // Support negative.
#define DC_WIN_SIZE 0x705
#define H_SIZE(x) (((x) & 0x1fff) << 0)
#define V_SIZE(x) (((x) & 0x1fff) << 16)
#define H_SIZE(x) (((x) & 0x1FFF) << 0)
#define V_SIZE(x) (((x) & 0x1FFF) << 16)
#define DC_WIN_PRESCALED_SIZE 0x706
#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0)
#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16)
#define H_PRESCALED_SIZE(x) (((x) & 0x7FFF) << 0)
#define V_PRESCALED_SIZE(x) (((x) & 0x1FFF) << 16)
#define DC_WIN_H_INITIAL_DDA 0x707
#define DC_WIN_V_INITIAL_DDA 0x708
#define DC_WIN_DDA_INC 0x709
#define H_DDA_INC(x) (((x) & 0xffff) << 0)
#define V_DDA_INC(x) (((x) & 0xffff) << 16)
#define H_DDA_INC(x) (((x) & 0xFFFF) << 0)
#define V_DDA_INC(x) (((x) & 0xFFFF) << 16)
#define DC_WIN_LINE_STRIDE 0x70A
#define LINE_STRIDE(x) (x)
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
#define UV_LINE_STRIDE(x) (((x) & 0xFFFF) << 16)
#define DC_WIN_DV_CONTROL 0x70E
#define DV_CTRL_R(r) (((r) & 7) << 16)
#define DV_CTRL_G(g) (((g) & 7) << 8)
#define DV_CTRL_B(b) (((b) & 7) << 0)
#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716
#define WIN_BLEND_DEPTH(x) (((x) & 0xff) << 0)
#define WIN_K1(x) (((x) & 0xff) << 8)
#define WIN_K2(x) (((x) & 0xff) << 16)
#define WIN_BLEND_DEPTH(x) (((x) & 0xFF) << 0)
#define WIN_K1(x) (((x) & 0xFF) << 8)
#define WIN_K2(x) (((x) & 0xFF) << 16)
#define WIN_BLEND_ENABLE (0 << 24)
#define WIN_BLEND_BYPASS (1 << 24)
@@ -395,8 +451,8 @@
#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_K2 (3 << 12)
#define DC_WINBUF_BLEND_ALPHA_1BIT 0x719
#define WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xff) << 0)
#define WIN_ALPHA_1BIT_WEIGHT1(x) (((x) & 0xff) << 8)
#define WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xFF) << 0)
#define WIN_ALPHA_1BIT_WEIGHT1(x) (((x) & 0xFF) << 8)
/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
#define DC_WINBUF_START_ADDR 0x800
@@ -408,6 +464,8 @@
#define BLOCK (2 << 0)
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
#define DC_WINBUF_MEMFETCH_CONTROL 0x82B
/*! Display serial interface registers. */
#define _DSIREG(reg) ((reg) * 4)
@@ -486,8 +544,8 @@
#define DSI_PKT_LEN_2_3 0x35
#define DSI_PKT_LEN_4_5 0x36
#define DSI_PKT_LEN_6_7 0x37
#define PKT0_LEN(x) (((x) & 0xffff) << 0)
#define PKT1_LEN(x) (((x) & 0xffff) << 16)
#define PKT0_LEN(x) (((x) & 0xFFFF) << 0)
#define PKT1_LEN(x) (((x) & 0xFFFF) << 16)
#define DSI_PHY_TIMING_0 0x3C
#define DSI_PHY_TIMING_1 0x3D
@@ -495,20 +553,20 @@
#define DSI_BTA_TIMING 0x3F
#define DSI_TIMEOUT_0 0x44
#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0)
#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16)
#define DSI_TIMEOUT_HTX(x) (((x) & 0xFFFF) << 0)
#define DSI_TIMEOUT_LRX(x) (((x) & 0xFFFF) << 16)
#define DSI_TIMEOUT_1 0x45
#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0)
#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16)
#define DSI_TIMEOUT_TA(x) (((x) & 0xFFFF) << 0)
#define DSI_TIMEOUT_PR(x) (((x) & 0xFFFF) << 16)
#define DSI_TO_TALLY 0x46
#define DSI_PAD_CONTROL_0 0x4B
#define DSI_PAD_CONTROL_VS1_PDIO_CLK BIT(8)
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xF) << 0)
#define DSI_PAD_CONTROL_VS1_PULLDN_CLK BIT(24)
#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16)
#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xF) << 16)
#define DSI_PAD_CONTROL_CD 0x4C
#define DSI_VIDEO_MODE_CONTROL 0x4E
@@ -810,6 +868,12 @@ void display_wait_interrupt(u32 intr);
u16 display_get_decoded_panel_id();
void display_set_decoded_panel_id(u32 id);
/*! MIPI DCS register management */
int display_dsi_read(u8 cmd, u32 len, void *data);
int display_dsi_vblank_read(u8 cmd, u32 len, void *data);
void display_dsi_write(u8 cmd, u32 len, void *data);
void display_dsi_vblank_write(u8 cmd, u32 len, void *data);
/*! Show one single color on the display. */
void display_color_screen(u32 color);
@@ -818,21 +882,22 @@ void display_backlight(bool enable);
void display_backlight_brightness(u32 brightness, u32 step_delay);
u32 display_get_backlight_brightness();
/*! Init display in full 720x1280 resolution (B8G8R8A8, line stride 720, framebuffer size = 720*1280*4 bytes). */
u32 *display_init_framebuffer_pitch();
u32 *display_init_framebuffer_pitch_vic();
u32 *display_init_framebuffer_pitch_inv();
u32 *display_init_framebuffer_block();
u32 *display_init_framebuffer_log();
void display_activate_console();
void display_deactivate_console();
void display_init_cursor(void *crs_fb, u32 size);
void display_set_pos_cursor(u32 x, u32 y);
void display_deinit_cursor();
u32 *display_init_window_a_pitch();
u32 *display_init_window_a_pitch_vic();
u32 *display_init_window_a_pitch_inv();
u32 *display_init_window_a_block();
u32 *display_init_window_d_console();
int display_dsi_read(u8 cmd, u32 len, void *data);
int display_dsi_vblank_read(u8 cmd, u32 len, void *data);
void display_dsi_write(u8 cmd, u32 len, void *data);
void display_dsi_vblank_write(u8 cmd, u32 len, void *data);
void display_window_disable(u32 window);
void display_set_framebuffer(u32 window, void *fb);
void display_move_framebuffer(u32 window, void *fb);
void display_window_d_console_enable();
void display_window_d_console_disable();
void display_cursor_init(void *crs_fb, u32 size);
void display_cursor_set_pos(u32 x, u32 y);
void display_cursor_deinit();
#endif

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2022 CTCaer
* Copyright (c) 2018-2024 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,
@@ -16,37 +16,35 @@
*/
// Display A config.
static const cfg_op_t _di_dc_setup_win_config[] = {
{DC_CMD_STATE_ACCESS, 0},
static const reg_cfg_t _di_dc_setup_win_config[] = {
{DC_CMD_STATE_ACCESS, READ_MUX_ASSEMBLY | WRITE_MUX_ASSEMBLY},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_REG_ACT_CONTROL, WIN_A_ACT_HCNTR_SEL | WIN_B_ACT_HCNTR_SEL | WIN_C_ACT_HCNTR_SEL},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
{DC_DISP_DC_MCCIF_FIFOCTRL, 0},
{DC_DISP_DISP_MEM_HIGH_PRIORITY, 0},
{DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0},
{DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE},
{DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL},
{DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | SYNCPT_VSYNC_INDX(9)},
{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},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE | WIN_D_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ},
/* Setup Windows A/B/C */
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT | WINDOW_D_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_DV_CONTROL, 0},
/* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0},
{DC_WINC_CSC_YOF, 0xF0},
{DC_WINC_CSC_KYRGB, 0x12A},
{DC_WINC_CSC_KUR, 0},
{DC_WINC_CSC_KVR, 0x198},
{DC_WINC_CSC_KUG, 0x39B},
{DC_WINC_CSC_KVG, 0x32F},
{DC_WINC_CSC_KUB, 0x204},
{DC_WINC_CSC_KVB, 0},
/* End of color coefficients */
{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
@@ -55,21 +53,18 @@ static const cfg_op_t _di_dc_setup_win_config[] = {
{DC_COM_PIN_OUTPUT_POLARITY(3), 0},
{DC_DISP_BLEND_BACKGROUND_COLOR, 0},
{DC_COM_CRC_CONTROL, 0},
{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_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE | WIN_D_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ},
{DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_BYPASS | WIN_BLEND_DEPTH(255)},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, 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_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE | WIN_D_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ}
};
// DSI Init config.
static const cfg_op_t _di_dsi_init_irq_pkt_config0[] = {
static const reg_cfg_t _di_dsi_seq_pkt_reset_config0[] = {
{DSI_WR_DATA, 0},
{DSI_INT_ENABLE, 0},
{DSI_INT_STATUS, 0},
@@ -79,7 +74,7 @@ static const cfg_op_t _di_dsi_init_irq_pkt_config0[] = {
{DSI_INIT_SEQ_DATA_2, 0},
{DSI_INIT_SEQ_DATA_3, 0}
};
static const cfg_op_t _di_dsi_init_irq_pkt_config1[] = {
static const reg_cfg_t _di_dsi_seq_pkt_reset_config1[] = {
{DSI_DCS_CMDS, 0},
{DSI_PKT_SEQ_0_LO, 0},
{DSI_PKT_SEQ_1_LO, 0},
@@ -95,7 +90,7 @@ static const cfg_op_t _di_dsi_init_irq_pkt_config1[] = {
{DSI_PKT_SEQ_5_HI, 0},
{DSI_CONTROL, 0}
};
static const cfg_op_t _di_dsi_init_pads_t210b01[] = {
static const reg_cfg_t _di_dsi_init_pads_t210b01[] = {
{DSI_PAD_CONTROL_1, 0},
{DSI_PAD_CONTROL_2, 0},
{DSI_PAD_CONTROL_3, 0},
@@ -104,39 +99,47 @@ static const cfg_op_t _di_dsi_init_pads_t210b01[] = {
{DSI_PAD_CONTROL_6_B01, 0},
{DSI_PAD_CONTROL_7_B01, 0}
};
static const cfg_op_t _di_dsi_init_timing_pkt_config2[] = {
static const reg_cfg_t _di_dsi_init_config[] = {
{DSI_PAD_CONTROL_CD, 0},
{DSI_SOL_DELAY, 24},
{DSI_MAX_THRESHOLD, 480},
{DSI_TRIGGER, 0},
{DSI_INIT_SEQ_CONTROL, 0},
{DSI_PKT_LEN_0_1, 0},
{DSI_PKT_LEN_2_3, 0},
{DSI_PKT_LEN_4_5, 0},
{DSI_PKT_LEN_6_7, 0},
{DSI_PAD_CONTROL_1, 0}
};
static const cfg_op_t _di_dsi_init_timing_pwrctrl_config[] = {
{DSI_PAD_CONTROL_1, 0},
/* DSI PHY timings */
{DSI_PHY_TIMING_0, 0x6070603},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30109},
{DSI_BTA_TIMING, 0x190A14},
/* DSI timeout */
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable
{DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Power up.
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_POWER_CONTROL, 0},
{DSI_POWER_CONTROL, 0},
{DSI_PAD_CONTROL_1, 0}
};
static const cfg_op_t _di_dsi_init_timing_pkt_config3[] = {
{DSI_PAD_CONTROL_1, 0},
/* DSI PHY timings */
{DSI_PHY_TIMING_0, 0x6070603},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30118},
{DSI_BTA_TIMING, 0x190A14},
/* DSI timeout */
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
{DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
@@ -148,7 +151,7 @@ static const cfg_op_t _di_dsi_init_timing_pkt_config3[] = {
};
// DSI panel JDI config.
static const cfg_op_t _di_dsi_panel_init_config_jdi[] = {
static const reg_cfg_t _di_dsi_panel_init_config_jdi[] = {
{DSI_WR_DATA, 0x0439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).
{DSI_TRIGGER, DSI_TRIGGER_HOST},
@@ -195,13 +198,19 @@ static const cfg_op_t _di_dsi_panel_init_config_jdi[] = {
};
// DSI packet config.
static const cfg_op_t _di_dsi_init_seq_pkt_final_config[] = {
static const reg_cfg_t _di_dsi_seq_pkt_video_non_burst_no_eot_config[] = {
{DSI_PAD_CONTROL_1, 0},
/* DSI PHY timings */
{DSI_PHY_TIMING_0, 0x6070603},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30172},
{DSI_BTA_TIMING, 0x190A14},
/* DSI timeout */
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_PKT_SEQ_0_LO, 0x40000208},
{DSI_PKT_SEQ_2_LO, 0x40000308},
{DSI_PKT_SEQ_4_LO, 0x40000308},
@@ -218,7 +227,7 @@ static const cfg_op_t _di_dsi_init_seq_pkt_final_config[] = {
};
// DSI mode config.
static const cfg_op_t _di_dsi_mode_config[] = {
static const reg_cfg_t _di_dsi_host_mode_config[] = {
{DSI_TRIGGER, 0},
{DSI_CONTROL, 0},
{DSI_SOL_DELAY, 6},
@@ -232,7 +241,7 @@ static const cfg_op_t _di_dsi_mode_config[] = {
};
// MIPI CAL config.
static const cfg_op_t _di_mipi_pad_cal_config[] = {
static const reg_cfg_t _di_mipi_pad_cal_config[] = {
{MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0},
{MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000},
{MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0},
@@ -240,13 +249,13 @@ static const cfg_op_t _di_mipi_pad_cal_config[] = {
};
// DSI pad config.
static const cfg_op_t _di_dsi_pad_cal_config_t210[] = {
static const reg_cfg_t _di_dsi_pad_cal_config_t210[] = {
{DSI_PAD_CONTROL_1, 0},
{DSI_PAD_CONTROL_2, 0},
{DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)},
{DSI_PAD_CONTROL_4, 0}
};
static const cfg_op_t _di_dsi_pad_cal_config_t210b01[] = {
static const reg_cfg_t _di_dsi_pad_cal_config_t210b01[] = {
{DSI_PAD_CONTROL_1, 0},
{DSI_PAD_CONTROL_2, 0},
{DSI_PAD_CONTROL_3, 0},
@@ -257,19 +266,19 @@ static const cfg_op_t _di_dsi_pad_cal_config_t210b01[] = {
};
// MIPI CAL config.
static const cfg_op_t _di_mipi_dsi_cal_offsets_config_t210[] = {
static const reg_cfg_t _di_mipi_dsi_cal_prod_config_t210[] = {
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200},
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200},
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002},
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002}
};
static const cfg_op_t _di_mipi_dsi_cal_offsets_config_t210b01[] = {
static const reg_cfg_t _di_mipi_dsi_cal_prod_config_t210b01[] = {
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200006},
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006},
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000},
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x260000}
};
static const cfg_op_t _di_mipi_start_dsi_cal_config[] = {
static const reg_cfg_t _di_mipi_dsi_cal_unused_config[] = {
{MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0},
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
{MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0},
@@ -280,48 +289,11 @@ static const cfg_op_t _di_mipi_start_dsi_cal_config[] = {
{MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0},
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0},
{MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0},
{MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0},
{MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001} // Set Prescale and filter and start calibration.
{MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0}
};
// Display A enable config.
static const cfg_op_t _di_dc_video_enable_config[] = {
{DC_CMD_STATE_ACCESS, 0},
/* Setup Windows A/B/C */
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_DV_CONTROL, 0},
/* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0},
/* End of color coefficients */
{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
{DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
{DC_COM_PIN_OUTPUT_POLARITY(1), LSC0_OUTPUT_POLARITY_LOW},
{DC_COM_PIN_OUTPUT_POLARITY(3), 0},
{DC_DISP_BLEND_BACKGROUND_COLOR, 0},
{DC_COM_CRC_CONTROL, 0},
{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_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
{DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_BYPASS | WIN_BLEND_DEPTH(255)},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, 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},
static const reg_cfg_t _di_dc_video_enable_config[] = {
/* Set panel timings */
{DC_DISP_DISP_TIMING_OPTIONS, VSYNC_H_POSITION(0)},
{DC_DISP_REF_TO_SYNC, V_REF_TO_SYNC(1) | H_REF_TO_SYNC(0)},
@@ -334,59 +306,60 @@ static const cfg_op_t _di_dc_video_enable_config[] = {
{DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
{DC_COM_PIN_OUTPUT_ENABLE(1), 0},
{DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL},
{DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},
{DC_DISP_DISP_CLOCK_CONTROL, 0},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, 0},
/* Start continuous display. */
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX},
{DC_DISP_FRONT_PORCH, V_FRONT_PORCH(10) | H_FRONT_PORCH(136)},
{DC_CMD_STATE_ACCESS, 0},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)},
{DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_STATE_ACCESS, 0},
{DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)},
{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0}
{DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)}, // 4: div3.
};
// Display A disable config.
static const cfg_op_t _di_dc_video_disable_config[] = {
{DC_DISP_FRONT_PORCH, V_FRONT_PORCH(10) | H_FRONT_PORCH(136)},
static const reg_cfg_t _di_dc_video_disable_config[] = {
{DC_CMD_INT_MASK, 0},
{DC_CMD_STATE_ACCESS, 0},
{DC_CMD_STATE_ACCESS, READ_MUX_ASSEMBLY | WRITE_MUX_ASSEMBLY},
{DC_CMD_INT_ENABLE, 0},
{DC_CMD_CONT_SYNCPT_VSYNC, 0},
/* Stop display. */
{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},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
{DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)},
{DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
// LCD panels should sleep for 40ms here.
// TODO: LCD panels should sleep for 40ms here.
{DC_CMD_DISPLAY_POWER_CONTROL, 0},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
};
// DSI deinit config.
static const cfg_op_t _di_dsi_timing_deinit_config[] = {
static const reg_cfg_t _di_dsi_timing_deinit_config[] = {
{DSI_POWER_CONTROL, 0},
{DSI_PAD_CONTROL_1, 0},
{DSI_PHY_TIMING_0, 0x6070601}, //mariko changes
/* DSI PHY timings */
{DSI_PHY_TIMING_0, 0x6070603},
{DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30118},
{DSI_BTA_TIMING, 0x190A14},
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) },
/* DSI timeout */
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0},
{DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},
{DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
@@ -397,7 +370,7 @@ static const cfg_op_t _di_dsi_timing_deinit_config[] = {
};
// DSI panel JDI deinit config.
static const cfg_op_t _di_dsi_panel_deinit_config_jdi[] = {
static const reg_cfg_t _di_dsi_panel_deinit_config_jdi[] = {
{DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).
{DSI_TRIGGER, DSI_TRIGGER_HOST},
@@ -423,7 +396,7 @@ static const cfg_op_t _di_dsi_panel_deinit_config_jdi[] = {
};
// DSI panel AUO deinit config.
static const cfg_op_t _di_dsi_panel_deinit_config_auo[] = {
static const reg_cfg_t _di_dsi_panel_deinit_config_auo[] = {
{DSI_WR_DATA, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).
{DSI_TRIGGER, DSI_TRIGGER_HOST},
@@ -464,24 +437,24 @@ static const cfg_op_t _di_dsi_panel_deinit_config_auo[] = {
{DSI_TRIGGER, DSI_TRIGGER_HOST}
};
static const cfg_op_t _di_init_config_invert[] = {
/*
static const reg_cfg_t _di_init_config_invert[] = {
{DSI_WR_DATA, 0x239},
{DSI_WR_DATA, 0x02C1}, // INV_EN.
{DSI_TRIGGER, DSI_TRIGGER_HOST},
};
*/
// Display A Window A one color config.
static const cfg_op_t _di_win_one_color[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT},
static const reg_cfg_t _di_win_one_color[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT | WINDOW_D_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display.
};
// Display A Window A linear pitch config.
static const cfg_op_t _di_win_framebuffer_pitch[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT | WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
static const reg_cfg_t _di_winA_pitch[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
@@ -500,14 +473,12 @@ static const cfg_op_t _di_win_framebuffer_pitch[] = {
{DC_WINBUF_ADDR_V_OFFSET, 0},
{DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD.
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
};
// Display A Window A linear pitch + Win D support config.
static const cfg_op_t _di_win_framebuffer_pitch_vic[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT | WINDOW_C_SELECT | WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
static const reg_cfg_t _di_winA_pitch_vic[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
@@ -526,14 +497,12 @@ static const cfg_op_t _di_win_framebuffer_pitch_vic[] = {
{DC_WINBUF_ADDR_V_OFFSET, 0},
{DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD.
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
};
// Display A Window A linear pitch inverse + Win D support config.
static const cfg_op_t _di_win_framebuffer_pitch_inv[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT | WINDOW_C_SELECT | WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
static const reg_cfg_t _di_winA_pitch_inv[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
@@ -552,14 +521,12 @@ static const cfg_op_t _di_win_framebuffer_pitch_inv[] = {
{DC_WINBUF_ADDR_V_OFFSET, 1279}, // Linear: 1279, Block: 0.
{DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, // Enable window AD.
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
};
// Display A Window A block linear config.
static const cfg_op_t _di_win_framebuffer_block[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT | WINDOW_C_SELECT | WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
static const reg_cfg_t _di_winA_block[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
@@ -578,12 +545,12 @@ static const cfg_op_t _di_win_framebuffer_block[] = {
{DC_WINBUF_ADDR_V_OFFSET, 0}, // Linear: 1279, Block: 0.
{DC_WIN_WIN_OPTIONS, WIN_ENABLE | SCAN_COLUMN | H_DIRECTION}, // Enable window AD. | SCAN_COLUMN | H_DIRECTION.
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
};
// Display A Window D config.
static const cfg_op_t _di_win_framebuffer_log[] = {
static const reg_cfg_t _di_winD_log[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8},
@@ -601,6 +568,6 @@ static const cfg_op_t _di_win_framebuffer_log[] = {
{DC_WINBUF_ADDR_V_OFFSET, 0},
{DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_ENABLE | WIN_K1(200) | WIN_BLEND_DEPTH(0)},
{DC_WINBUF_BLEND_MATCH_SELECT, WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 | WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_D_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_D_ACT_REQ}
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_D_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_D_ACT_REQ},
};

View File

@@ -1,7 +1,7 @@
/*
* VIC driver for Tegra X1
*
* Copyright (c) 2018-2023 CTCaer
* Copyright (c) 2018-2024 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,
@@ -390,7 +390,7 @@ static int _vic_wait_idle()
return 0;
}
void vic_set_surface(vic_surface_t *sfc)
void vic_set_surface(const vic_surface_t *sfc)
{
u32 flip_x = 0;
u32 flip_y = 0;
@@ -406,6 +406,9 @@ void vic_set_surface(vic_surface_t *sfc)
// Get format alpha type.
switch (sfc->pix_fmt)
{
case VIC_PIX_FORMAT_L8:
case VIC_PIX_FORMAT_X1B5G5R5:
case VIC_PIX_FORMAT_B5G5R5X1:
case VIC_PIX_FORMAT_X8B8G8R8:
case VIC_PIX_FORMAT_X8R8G8B8:
case VIC_PIX_FORMAT_B8G8R8X8:
@@ -536,14 +539,8 @@ int vic_compose()
int vic_init()
{
// Ease the stress to APB.
bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
clock_enable_vic();
// Restore sys clock.
bpmp_clk_rate_set(prev_fid);
// Load Fetch Control Engine microcode.
for (u32 i = 0; i < sizeof(vic_fce_ucode) / sizeof(u32); i++)
{

View File

@@ -33,6 +33,10 @@ typedef enum _vic_rotation_t
typedef enum _vic_pix_format_t
{
VIC_PIX_FORMAT_L8 = 1, // 8-bit LUT.
VIC_PIX_FORMAT_X1B5G5R5 = 21, // 16-bit XBGR.
VIC_PIX_FORMAT_B5G5R5X1 = 23, // 16-bit BGRX.
VIC_PIX_FORMAT_A8B8G8R8 = 31, // 32-bit ABGR.
VIC_PIX_FORMAT_A8R8G8B8 = 32, // 32-bit ARGB.
VIC_PIX_FORMAT_B8G8R8A8 = 33, // 32-bit BGRA.
@@ -42,7 +46,6 @@ typedef enum _vic_pix_format_t
VIC_PIX_FORMAT_X8R8G8B8 = 36, // 32-bit XRGB.
VIC_PIX_FORMAT_B8G8R8X8 = 37, // 32-bit BGRX.
VIC_PIX_FORMAT_R8G8B8X8 = 38, // 32-bit RGBX.
} vic_pix_format_t;
typedef struct _vic_surface_t
@@ -55,7 +58,7 @@ typedef struct _vic_surface_t
u32 rotation;
} vic_surface_t;
void vic_set_surface(vic_surface_t *sfc);
void vic_set_surface(const vic_surface_t *sfc);
int vic_compose();
int vic_init();
void vic_end();

View File

@@ -45,7 +45,7 @@ typedef struct _opt_win_cal_t
} opt_win_cal_t;
// Nintendo Switch Icosa/Iowa Optical Window calibration.
const opt_win_cal_t opt_win_cal_default[] = {
static const opt_win_cal_t opt_win_cal_default[] = {
{ 500, 5002, 7502 },
{ 754, 2250, 2000 },
{ 1029, 1999, 1667 },
@@ -54,14 +54,14 @@ const opt_win_cal_t opt_win_cal_default[] = {
};
// Nintendo Switch Aula Optical Window calibration.
const opt_win_cal_t opt_win_cal_aula[] = {
static const opt_win_cal_t opt_win_cal_aula[] = {
{ 231, 9697, 30300 },
{ 993, 3333, 2778 },
{ 1478, 1621, 1053 },
{ 7500, 81, 10 }
};
const u32 als_gain_idx_tbl[4] = { 1, 2, 64, 128 };
static const u32 als_gain_idx_tbl[4] = { 1, 2, 64, 128 };
void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle)
{

View File

@@ -1,7 +1,7 @@
/*
* Joy-Con UART driver for Nintendo Switch
*
* Copyright (c) 2019-2023 CTCaer
* Copyright (c) 2019-2024 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,
@@ -22,7 +22,6 @@
#include <gfx_utils.h>
#include <power/max17050.h>
#include <power/regulator_5v.h>
#include <soc/bpmp.h>
#include <soc/clock.h>
#include <soc/fuse.h>
#include <soc/gpio.h>
@@ -104,10 +103,10 @@ enum
enum
{
JC_BATT_EMTPY = 0,
JC_BATT_CRIT = 2,
JC_BATT_LOW = 4,
JC_BATT_MID = 6,
JC_BATT_FULL = 8
JC_BATT_CRIT = 1,
JC_BATT_LOW = 2,
JC_BATT_MID = 3,
JC_BATT_FULL = 4
};
static const u8 sio_init[] = {
@@ -223,8 +222,8 @@ typedef struct _jc_hid_in_rpt_t
{
u8 cmd;
u8 pkt_id;
u8 conn_info:4;
u8 batt_info:4;
u8 conn_info:4; // Connection detect.
u8 batt_info:4; // Power info.
u8 btn_right;
u8 btn_shared;
u8 btn_left;
@@ -234,7 +233,7 @@ typedef struct _jc_hid_in_rpt_t
u8 stick_h_right;
u8 stick_m_right;
u8 stick_v_right;
u8 vib_decider; // right:8, left:8. (bit3 en, bit2-0 buffer avail).
u8 vib_decider; // right:4, left:4 (bit3 en, bit2-0 buffer avail).
u8 submcd_ack;
u8 subcmd;
u8 subcmd_data[];
@@ -317,9 +316,10 @@ typedef struct _joycon_ctxt_t
u8 uart;
u8 type;
u8 state;
u8 mac[6];
u32 last_received_time;
u32 last_status_req_time;
u8 mac[6];
u8 pkt_id;
u8 rumble_sent;
u8 connected;
u8 detected;
@@ -330,11 +330,10 @@ static joycon_ctxt_t jc_l = {0};
static joycon_ctxt_t jc_r = {0};
static bool jc_init_done = false;
static u32 hid_pkt_inc = 0;
static jc_gamepad_rpt_t jc_gamepad;
static u8 _jc_crc(u8 *data, u16 len, u8 init)
static u8 _jc_crc(const u8 *data, u16 len, u8 init)
{
u8 crc = init;
for (u16 i = 0; i < len; i++)
@@ -407,12 +406,16 @@ static void _jc_detect()
if (!jc_gamepad.sio_mode)
{
// Turn on Joy-Con detect. (UARTB/C TX). UART CTS also if HW flow control and irq is enabled.
PINMUX_AUX(PINMUX_AUX_UART2_TX) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_UART3_TX) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
PINMUX_AUX(PINMUX_AUX_UART2_TX) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_UART3_TX) = PINMUX_INPUT_ENABLE;
gpio_direction_input(GPIO_PORT_G, GPIO_PIN_0);
gpio_direction_input(GPIO_PORT_D, GPIO_PIN_1);
usleep(20);
//! HW BUG: Unlatch gpio buffer.
(void)gpio_read(GPIO_PORT_H, GPIO_PIN_6);
(void)gpio_read(GPIO_PORT_E, GPIO_PIN_6);
// Read H6/E6 which are shared with UART TX pins.
jc_r.detected = !gpio_read(GPIO_PORT_H, GPIO_PIN_6);
jc_l.detected = !gpio_read(GPIO_PORT_E, GPIO_PIN_6);
@@ -444,7 +447,7 @@ static void _jc_conn_check()
if (jc_l.connected)
_jc_power_supply(UART_C, false);
hid_pkt_inc = 0;
jc_l.pkt_id = 0;
jc_l.connected = false;
jc_l.rumble_sent = false;
@@ -461,7 +464,7 @@ static void _jc_conn_check()
if (jc_r.connected)
_jc_power_supply(UART_B, false);
hid_pkt_inc = 0;
jc_r.pkt_id = 0;
jc_r.connected = false;
jc_r.rumble_sent = false;
@@ -480,7 +483,7 @@ static void _joycon_send_raw(u8 uart_port, const u8 *buf, u16 size)
uart_wait_xfer(uart_port, UART_TX_IDLE);
}
static u16 _jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u16 size, bool crc)
static u16 _jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, const u8 *data, u16 size, bool crc)
{
out->uart_hdr.magic[0] = 0x19;
out->uart_hdr.magic[1] = 0x01;
@@ -500,7 +503,7 @@ static u16 _jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data,
return sizeof(jc_wired_hdr_t);
}
static u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size, bool crc)
static u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, const u8 *payload, u16 size, bool crc)
{
u16 pkt_size = _jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0, crc);
pkt_size += size;
@@ -515,25 +518,21 @@ static u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size,
return pkt_size;
}
static void _jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size, bool crc)
static void _jc_send_hid_output_rpt(joycon_ctxt_t *jc, jc_hid_out_rpt_t *hid_pkt, u16 size, bool crc)
{
u8 rpt[0x50];
memset(rpt, 0, sizeof(rpt));
u32 rpt_size = _jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size, crc);
hid_pkt->pkt_id = (jc->pkt_id++ & 0xF);
u32 rpt_size = _jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, (u8 *)hid_pkt, size, crc);
_joycon_send_raw(uart, rpt, rpt_size);
_joycon_send_raw(jc->uart, rpt, rpt_size);
}
static u8 _jc_hid_pkt_id_incr()
static void _jc_send_hid_cmd(joycon_ctxt_t *jc, u8 subcmd, const u8 *data, u16 size)
{
return (hid_pkt_inc++ & 0xF);
}
static void _jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
{
const u8 rumble_neutral[8] = { 0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40 };
const u8 rumble_init[8] = { 0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72 };
static const u8 rumble_neutral[8] = { 0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40 };
static const u8 rumble_init[8] = { 0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72 };
u8 temp[0x30] = {0};
@@ -547,47 +546,43 @@ static void _jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
// Enable rumble.
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
hid_pkt->subcmd_data[0] = 1;
if (send_r_rumble)
_jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10, false);
_jc_send_hid_output_rpt(&jc_r, hid_pkt, 0x10, false);
if (send_l_rumble)
_jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10, false);
_jc_send_hid_output_rpt(&jc_l, hid_pkt, 0x10, false);
// Send rumble.
hid_pkt->cmd = JC_HID_RUMBLE_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
hid_pkt->cmd = JC_HID_RUMBLE_RPT;
memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init));
if (send_r_rumble)
_jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 10, false);
_jc_send_hid_output_rpt(&jc_r, hid_pkt, 10, false);
if (send_l_rumble)
_jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10, false);
_jc_send_hid_output_rpt(&jc_l, hid_pkt, 10, false);
msleep(15);
// Disable rumble.
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
hid_pkt->subcmd_data[0] = 0;
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
if (send_r_rumble)
_jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10, false);
_jc_send_hid_output_rpt(&jc_r, hid_pkt, 0x10, false);
if (send_l_rumble)
_jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10, false);
_jc_send_hid_output_rpt(&jc_l, hid_pkt, 0x10, false);
}
else
{
bool crc_needed = (jc_l.uart == uart) ? (jc_l.type & JC_ID_HORI) : (jc_r.type & JC_ID_HORI);
bool crc_needed = jc->type & JC_ID_HORI;
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
hid_pkt->subcmd = subcmd;
if (data)
memcpy(hid_pkt->subcmd_data, data, size);
_jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, sizeof(jc_hid_out_rpt_t) + size, crc_needed);
_jc_send_hid_output_rpt(jc, hid_pkt, sizeof(jc_hid_out_rpt_t) + size, crc_needed);
}
}
@@ -596,13 +591,13 @@ static void _jc_charging_decider(u8 batt, u8 uart)
u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000;
// Power supply control based on battery levels and charging.
if ((batt >> 1 << 1) < JC_BATT_LOW) // Level without checking charging.
if ((batt >> 1) < JC_BATT_LOW) // Level without checking charging.
_jc_power_supply(uart, true);
else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID)) // Addresses the charging bit.
else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID) << 1) // Addresses the charging bit.
_jc_power_supply(uart, false);
}
static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size)
static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8 *packet, int size)
{
u32 btn_tmp;
jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;
@@ -610,7 +605,14 @@ static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size)
switch (hid_pkt->cmd)
{
case JC_HORI_INPUT_RPT:
if (!(jc->type & JC_ID_HORI))
return;
case JC_HID_INPUT_RPT:
// Discard incomplete hid packets.
if (size < 12)
break;
btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16;
if (jc->type & JC_ID_L)
@@ -670,8 +672,12 @@ static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size)
}
}
static void _jc_parse_wired_init(joycon_ctxt_t *jc, const u8* data, u32 size)
static void _jc_parse_wired_init(joycon_ctxt_t *jc, const u8 *data, int size)
{
// Discard empty packets.
if (size <= 0)
return;
switch (data[0])
{
case JC_WIRED_CMD_GET_INFO:
@@ -694,13 +700,13 @@ static void _jc_parse_wired_init(joycon_ctxt_t *jc, const u8* data, u32 size)
}
}
static void _jc_uart_pkt_parse(joycon_ctxt_t *jc, const jc_wired_hdr_t *pkt, size_t size)
static void _jc_uart_pkt_parse(joycon_ctxt_t *jc, const jc_wired_hdr_t *pkt, int size)
{
switch (pkt->cmd)
{
case JC_HORI_INPUT_RPT_CMD:
case JC_WIRED_HID:
_jc_parse_wired_hid(jc, pkt->payload, (pkt->data[0] << 8) | pkt->data[1]);
_jc_parse_wired_hid(jc, pkt->payload, size - sizeof(jc_wired_hdr_t));
break;
case JC_WIRED_INIT_REPLY:
_jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1);
@@ -715,11 +721,15 @@ static void _jc_uart_pkt_parse(joycon_ctxt_t *jc, const jc_wired_hdr_t *pkt, siz
jc->last_received_time = get_tmr_ms();
}
static void _jc_sio_parse_payload(joycon_ctxt_t *jc, u8 cmd, const u8* payload, u32 size)
static void _jc_sio_parse_payload(joycon_ctxt_t *jc, u8 cmd, const u8 *payload, int size)
{
switch (cmd)
{
case JC_SIO_CMD_STATUS:
// Discard incomplete packets.
if (size < 12)
break;
jc_sio_hid_in_rpt_t *hid_pkt = (jc_sio_hid_in_rpt_t *)payload;
jc_gamepad.buttons = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16;
jc_gamepad.home = !gpio_read(GPIO_PORT_V, GPIO_PIN_3);
@@ -740,7 +750,7 @@ static void _jc_sio_parse_payload(joycon_ctxt_t *jc, u8 cmd, const u8* payload,
}
}
static void _jc_sio_uart_pkt_parse(joycon_ctxt_t *jc, const jc_sio_in_rpt_t *pkt, u32 size)
static void _jc_sio_uart_pkt_parse(joycon_ctxt_t *jc, const jc_sio_in_rpt_t *pkt, int size)
{
if (pkt->crc_hdr != _jc_crc((u8 *)pkt, sizeof(jc_sio_in_rpt_t) - 1, 0))
return;
@@ -757,7 +767,7 @@ static void _jc_sio_uart_pkt_parse(joycon_ctxt_t *jc, const jc_sio_in_rpt_t *pkt
break;
case JC_SIO_CMD_IAP_VER:
case JC_SIO_CMD_STATUS:
_jc_sio_parse_payload(jc, cmd, pkt->payload, pkt->payload_size);
_jc_sio_parse_payload(jc, cmd, pkt->payload, size - sizeof(jc_sio_in_rpt_t));
break;
case JC_SIO_CMD_UNK02:
case JC_SIO_CMD_UNK20:
@@ -784,7 +794,7 @@ static void _jc_rcv_pkt(joycon_ctxt_t *jc)
jc_wired_hdr_t *jc_pkt = (jc_wired_hdr_t *)jc->buf;
if (!jc->sio_mode && !memcmp(jc_pkt->uart_hdr.magic, "\x19\x81\x03", 3))
{
_jc_uart_pkt_parse(jc, jc_pkt, jc_pkt->uart_hdr.total_size_lsb + sizeof(jc_uart_hdr_t));
_jc_uart_pkt_parse(jc, jc_pkt, len);
return;
}
@@ -793,7 +803,7 @@ static void _jc_rcv_pkt(joycon_ctxt_t *jc)
jc_sio_in_rpt_t *sio_pkt = (jc_sio_in_rpt_t *)(jc->buf);
if (jc->sio_mode && sio_pkt->cmd == JC_SIO_INPUT_RPT && (sio_pkt->ack & JC_SIO_CMD_ACK) == JC_SIO_CMD_ACK)
{
_jc_sio_uart_pkt_parse(jc, sio_pkt, sio_pkt->payload_size + sizeof(jc_sio_in_rpt_t));
_jc_sio_uart_pkt_parse(jc, sio_pkt, len);
return;
}
@@ -804,7 +814,7 @@ static bool _jc_send_init_rumble(joycon_ctxt_t *jc)
// Send init rumble or request nx pad status report.
if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent))
{
_jc_send_hid_cmd(jc->uart, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
_jc_send_hid_cmd(jc, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
if (jc_l.connected)
jc_l.rumble_sent = true;
@@ -842,10 +852,10 @@ static void _jc_req_nx_pad_status(joycon_ctxt_t *jc)
else
_joycon_send_raw(jc->uart, hori_pad_status, sizeof(hori_pad_status));
jc->last_status_req_time = get_tmr_ms() + 15;
jc->last_status_req_time = get_tmr_ms() + (!jc->sio_mode ? 15 : 7);
}
static bool _jc_validate_pairing_info(u8 *buf, bool *is_hos)
static bool _jc_validate_pairing_info(const u8 *buf, bool *is_hos)
{
u8 crc = 0;
for (u32 i = 0; i < 0x22; i++)
@@ -914,13 +924,13 @@ retry:
{
if (!jc_l_found)
{
_jc_send_hid_cmd(jc_l.uart, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_l, 5);
_jc_send_hid_cmd(&jc_l, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_l, 5);
jc_l.last_status_req_time = get_tmr_ms() + 15;
}
if (!jc_r_found)
{
_jc_send_hid_cmd(jc_r.uart, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_r, 5);
_jc_send_hid_cmd(&jc_r, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_r, 5);
jc_r.last_status_req_time = get_tmr_ms() + 15;
}
@@ -1111,7 +1121,7 @@ static void _jc_init_conn(joycon_ctxt_t *jc)
// Initialize the controller.
u32 retries = 10;
while (!jc->connected)
while (!jc->connected && retries)
{
_joycon_send_raw(jc->uart, sio_init, sizeof(sio_init));
msleep(5);
@@ -1196,17 +1206,11 @@ void jc_init_hw()
pinmux_config_uart(UART_B);
pinmux_config_uart(UART_C);
// Ease the stress to APB.
bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
// Enable UART B and C clocks.
if (!jc_gamepad.sio_mode)
clock_enable_uart(UART_B);
clock_enable_uart(UART_C);
// Restore OC.
bpmp_clk_rate_set(prev_fid);
jc_init_done = true;
#endif
}
@@ -1226,12 +1230,12 @@ void jc_deinit()
u8 data = HCI_STATE_SLEEP;
if (jc_r.connected && !(jc_r.type & JC_ID_HORI))
{
_jc_send_hid_cmd(UART_B, JC_HID_SUBCMD_HCI_STATE, &data, 1);
_jc_send_hid_cmd(&jc_r, JC_HID_SUBCMD_HCI_STATE, &data, 1);
_jc_rcv_pkt(&jc_r);
}
if (jc_l.connected && !(jc_l.type & JC_ID_HORI))
{
_jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 1);
_jc_send_hid_cmd(&jc_l, JC_HID_SUBCMD_HCI_STATE, &data, 1);
_jc_rcv_pkt(&jc_l);
}
}

View File

@@ -43,34 +43,34 @@ typedef struct _jc_gamepad_rpt_t
struct
{
// Joy-Con (R).
u32 y:1;
u32 x:1;
u32 b:1;
u32 a:1;
u32 sr_r:1;
u32 sl_r:1;
u32 r:1;
u32 zr:1;
/*00*/ u32 y:1;
/*01*/ u32 x:1;
/*02*/ u32 b:1;
/*03*/ u32 a:1;
/*04*/ u32 sr_r:1;
/*05*/ u32 sl_r:1;
/*06*/ u32 r:1;
/*07*/ u32 zr:1;
// Shared
u32 minus:1;
u32 plus:1;
u32 r3:1;
u32 l3:1;
u32 home:1;
u32 cap:1;
u32 pad:1;
u32 wired:1;
/*08*/ u32 minus:1;
/*09*/ u32 plus:1;
/*10*/ u32 r3:1;
/*11*/ u32 l3:1;
/*12*/ u32 home:1;
/*13*/ u32 cap:1;
/*14*/ u32 pad:1;
/*15*/ u32 wired:1;
// Joy-Con (L).
u32 down:1;
u32 up:1;
u32 right:1;
u32 left:1;
u32 sr_l:1;
u32 sl_l:1;
u32 l:1;
u32 zl:1;
/*16*/ u32 down:1;
/*17*/ u32 up:1;
/*18*/ u32 right:1;
/*19*/ u32 left:1;
/*20*/ u32 sr_l:1;
/*21*/ u32 sl_l:1;
/*22*/ u32 l:1;
/*23*/ u32 zl:1;
};
u32 buttons;
};
@@ -105,4 +105,4 @@ void jc_deinit();
jc_gamepad_rpt_t *joycon_poll();
jc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos);
#endif
#endif

View File

@@ -20,33 +20,33 @@
#include "blz.h"
const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter)
const blz_footer *blz_get_footer(const u8 *comp_data, u32 comp_data_size, blz_footer *out_footer)
{
if (compDataLen < sizeof(blz_footer))
if (comp_data_size < sizeof(blz_footer))
return NULL;
const blz_footer *srcFooter = (const blz_footer*)&compData[compDataLen - sizeof(blz_footer)];
if (outFooter != NULL)
memcpy(outFooter, srcFooter, sizeof(blz_footer)); // Must be a memcpy because no umaligned accesses on ARMv4.
const blz_footer *src_footer = (const blz_footer *)&comp_data[comp_data_size - sizeof(blz_footer)];
if (out_footer)
memcpy(out_footer, src_footer, sizeof(blz_footer)); // Must be a memcpy because no unaligned accesses on ARMv4.
return srcFooter;
return src_footer;
}
// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM!
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer)
int blz_uncompress_inplace(u8 *data, u32 comp_size, const blz_footer *footer)
{
u32 addl_size = footer->addl_size;
u32 header_size = footer->header_size;
u32 cmp_and_hdr_size = footer->cmp_and_hdr_size;
unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size;
u8 *cmp_start = &data[comp_size] - cmp_and_hdr_size;
u32 cmp_ofs = cmp_and_hdr_size - header_size;
u32 out_ofs = cmp_and_hdr_size + addl_size;
while (out_ofs)
{
unsigned char control = cmp_start[--cmp_ofs];
for (unsigned int i=0; i<8; i++)
u8 control = cmp_start[--cmp_ofs];
for (u32 i = 0; i < 8; i++)
{
if (control & 0x80)
{
@@ -54,45 +54,48 @@ int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const
return 0; // Out of bounds.
cmp_ofs -= 2;
u16 seg_val = ((unsigned int)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs];
u16 seg_val = ((u32)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs];
u32 seg_size = ((seg_val >> 12) & 0xF) + 3;
u32 seg_ofs = (seg_val & 0x0FFF) + 3;
if (out_ofs < seg_size) // Kernel restricts segment copy to stay in bounds.
// Kernel restricts segment copy to stay in bounds.
if (out_ofs < seg_size)
seg_size = out_ofs;
out_ofs -= seg_size;
for (unsigned int j = 0; j < seg_size; j++)
for (u32 j = 0; j < seg_size; j++)
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
}
else
else // Copy directly.
{
// Copy directly.
if (cmp_ofs < 1)
return 0; //out of bounds
return 0; // Out of bounds.
cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
}
control <<= 1;
if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done.
if (!out_ofs) // Blz works backwards, so if it reaches byte 0, it's done.
return 1;
}
}
}
return 1;
}
int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize)
int blz_uncompress_srcdest(const u8 *comp_data, u32 comp_data_size, u8 *dst_data, u32 dst_size)
{
blz_footer footer;
const blz_footer *compFooterPtr = blz_get_footer(compData, compDataLen, &footer);
if (compFooterPtr == NULL)
const blz_footer *comp_footer = blz_get_footer(comp_data, comp_data_size, &footer);
if (!comp_footer)
return 0;
// Decompression must be done in-place, so need to copy the relevant compressed data first.
unsigned int numCompBytes = (const unsigned char*)(compFooterPtr)-compData;
memcpy(dstData, compData, numCompBytes);
memset(&dstData[numCompBytes], 0, dstSize - numCompBytes);
// Decompression happens in-place, so need to copy the relevant compressed data first.
u32 comp_bytes = (const u8 *)comp_footer - comp_data;
memcpy(dst_data, comp_data, comp_bytes);
memset(&dst_data[comp_bytes], 0, dst_size - comp_bytes);
return blz_uncompress_inplace(dstData, compDataLen, &footer);
return blz_uncompress_inplace(dst_data, comp_data_size, &footer);
}

View File

@@ -26,11 +26,11 @@ typedef struct _blz_footer
u32 addl_size;
} blz_footer;
// Returns pointer to footer in compData if present, additionally copies it to outFooter if not NULL.
const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int compDataLen, blz_footer *outFooter);
// Returns pointer to footer in comp_data if present, additionally copies it to out_footer if not NULL.
const blz_footer *blz_get_footer(const u8 *comp_data, u32 comp_data_size, blz_footer *out_footer);
// Returns 0 on failure.
int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer);
int blz_uncompress_inplace(u8 *data, u32 comp_size, const blz_footer *footer);
// Returns 0 on failure.
int blz_uncompress_srcdest(const unsigned char *compData, unsigned int compDataLen, unsigned char *dstData, unsigned int dstSize);
int blz_uncompress_srcdest(const u8 *comp_data, u32 comp_data_size, u8 *dst_data, u32 dst_size);
#endif

View File

@@ -92,16 +92,6 @@
# define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static
#endif
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
# define expect(expr,value) (__builtin_expect ((expr),(value)) )
#else
# define expect(expr,value) (expr)
#endif
#define likely(expr) expect((expr) != 0, 1)
#define unlikely(expr) expect((expr) != 0, 0)
/*-************************************
* Memory routines
**************************************/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2021 CTCaer
* Copyright (c) 2018-2022 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,

View File

@@ -292,7 +292,7 @@ FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous
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 */
FRESULT f_fdisk_mod (BYTE pdrv, const DWORD* szt, void* work); // Modded version of f_fdisk that works:tm:
FRESULT f_fdisk_mod (BYTE pdrv, const DWORD* szt, void* work); /* Modded version of f_fdisk that works:tm: */
FRESULT f_setcp (WORD cp); /* Set current code page */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */

View File

@@ -126,7 +126,7 @@
#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/
/*Text settings*/
#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */
#define LV_TXT_UTF8 0 /*Enable UTF-8 coded Unicode character usage */
#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/
#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */

View File

@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/tegra21_emc.h
*
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2019-2020, CTCaer.
* Copyright (c) 2019-2024, CTCaer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#ifndef _EMC_H_
#define _EMC_H_
#define EMC_INTSTATUS 0x0
#define EMC_DBG 0x8
#define EMC_CFG 0xC
#define EMC_CONFIG_SAMPLE_DELAY 0x5f0

View File

@@ -38,7 +38,7 @@ typedef struct
bool emc_2X_clk_src_is_pllmb;
bool fsp_for_src_freq;
bool train_ram_patterns;
bool init_done;
u32 init_done;
} mtc_config_t;
enum train_mode_t

View File

@@ -34,8 +34,6 @@
#include <soc/timer.h>
#include <soc/t210.h>
#define CONFIG_SDRAM_KEEP_ALIVE
#define DRAM_ID(x) BIT(x)
#define DRAM_CC(x) BIT(x)
@@ -184,16 +182,68 @@ emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
return data;
}
void sdram_src_pllc(bool enable)
{
static bool enabled = false;
if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210 || enable == enabled)
return;
enabled = enable;
// Clear CC interrupt.
EMC(EMC_INTSTATUS) = BIT(4);
(void)EMC(EMC_INTSTATUS);
u32 clk_src_emc = _dram_cfg_08_10_12_14_samsung_hynix_4gb.emc_clock_source;
if (enable)
{
// Check if clock source is not the expected one.
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) != clk_src_emc)
return;
// Set source as PLLC_OUT0.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = 0x20188004;
}
else
{
// Restore MC/EMC clock.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = clk_src_emc;
}
// Wait for CC interrupt.
while (!(EMC(EMC_INTSTATUS) & BIT(4)))
usleep(1);
}
static void _sdram_config_t210(const sdram_params_t210_t *params)
{
// VDDP Select.
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
usleep(params->pmc_vddp_sel_wait);
// Set DDR pad voltage.
PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); // Normally params->pmc_ddr_pwr.
// Turn on MEM IO Power.
PMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_SDMMC1; // Only keep SDMMC1 state. (Was params->pmc_no_io_power).
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
// Patch 1 using BCT spare variables
if (params->emc_bct_spare0)
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;
// Program DPD3/DPD4 regs (coldboot path).
// Enable sel_dpd on unused pins.
u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | (2 << 30u);
u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | PMC_IO_DPD_REQ_DPD_ON;
PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
usleep(params->pmc_io_dpd3_req_wait);
// Disable e_dpd_vttgen.
dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | (2 << 30u);
dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | PMC_IO_DPD_REQ_DPD_ON;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000;
usleep(params->pmc_io_dpd4_req_wait);
@@ -204,28 +254,24 @@ static void _sdram_config_t210(const sdram_params_t210_t *params)
PMC(APBDEV_PMC_WEAK_BIAS) = 0;
usleep(1);
// Start clocks.
// Start PLLM.
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
#ifdef CONFIG_SDRAM_KEEP_ALIVE
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) =
(params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20) | PLLCX_BASE_ENABLE;
#else
u32 pllm_div = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div;
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLLCX_BASE_ENABLE;
#endif
u32 wait_end = get_tmr_us() + 300;
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000))
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & BIT(27)))
{
if (get_tmr_us() >= wait_end)
goto break_nosleep;
goto lock_timeout;
}
usleep(10);
break_nosleep:
lock_timeout:
// Set clock sources.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);
if (params->emc_clock_source_dll)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
@@ -237,12 +283,13 @@ break_nosleep:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL);
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM);
// Set pad macros.
// Set pad vtt levels.
EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;
EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;
EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Trigger timing update so above writes take place.
EMC(EMC_TIMING_CONTROL) = 1;
usleep(10); // Ensure the regulators settle.
// Select EMC write mux.
@@ -279,6 +326,7 @@ break_nosleep:
// This is required to do any reads from the pad macros.
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
// Set data pipes mode.
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
// Set swizzle for Rank 0.
@@ -296,12 +344,12 @@ break_nosleep:
if (params->emc_bct_spare6)
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;
// Set pad controls.
// Program calibration impedance.
EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;
// Program Autocal controls with shadowed register fields.
// Program Autocal controls.
EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
@@ -310,6 +358,7 @@ break_nosleep:
EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;
// Program termination and drive strength
EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term;
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
@@ -318,10 +367,12 @@ break_nosleep:
EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
// Program dll config.
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;
// Program barrelshift.
EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
@@ -335,6 +386,7 @@ break_nosleep:
EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;
// Program pad macros controls and termination.
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40;
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
@@ -349,6 +401,7 @@ break_nosleep:
EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode;
EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl;
// Program pad macro pins/bytes.
EMC(EMC_CFG_3) = params->emc_cfg3;
EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0;
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
@@ -369,12 +422,15 @@ break_nosleep:
EMC(EMC_PMACRO_CMD_CTRL_0) = params->emc_pmacro_cmd_ctrl0;
EMC(EMC_PMACRO_CMD_CTRL_1) = params->emc_pmacro_cmd_ctrl1;
EMC(EMC_PMACRO_CMD_CTRL_2) = params->emc_pmacro_cmd_ctrl2;
// Program inbound vref setting.
EMC(EMC_PMACRO_IB_VREF_DQ_0) = params->emc_pmacro_ib_vref_dq_0;
EMC(EMC_PMACRO_IB_VREF_DQ_1) = params->emc_pmacro_ib_vref_dq_1;
EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0;
EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt;
// Program quse trimmers.
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
@@ -389,6 +445,7 @@ break_nosleep:
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;
// Program outbound trimmers.
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
@@ -423,6 +480,7 @@ break_nosleep:
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;
// Program clock trimmers.
EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0;
EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1;
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
@@ -439,7 +497,8 @@ break_nosleep:
if (params->emc_bct_spare4)
*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Trigger timing update so above writes take place.
EMC(EMC_TIMING_CONTROL) = 1;
// Initialize MC VPR settings.
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
@@ -504,7 +563,8 @@ break_nosleep:
MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
MC(MC_DA_CONFIG0) = params->mc_da_cfg0;
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
// Trigger MC timing update.
MC(MC_TIMING_CONTROL) = 1;
// Program second-level clock enable overrides.
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
@@ -526,6 +586,7 @@ break_nosleep:
EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;
// Program/Start auto calibration.
EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
usleep(params->emc_auto_cal_wait);
@@ -583,10 +644,12 @@ break_nosleep:
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl;
EMC(EMC_DBG) = params->emc_dbg;
// Clear read fifo.
EMC(EMC_QRST) = params->emc_qrst;
EMC(EMC_ISSUE_QRST) = 1;
EMC(EMC_ISSUE_QRST) = 0;
// Program the rest of EMC timing configuration.
EMC(EMC_QSAFE) = params->emc_qsafe;
EMC(EMC_RDV) = params->emc_rdv;
EMC(EMC_RDV_MASK) = params->emc_rdv_mask;
@@ -635,14 +698,16 @@ break_nosleep:
if (params->boot_rom_patch_control & BIT(31))
{
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
// Trigger MC timing update.
MC(MC_TIMING_CONTROL) = 1;
}
// Release SEL_DPD_CMD.
PMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | (1 << 30u);
PMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | PMC_IO_DPD_REQ_DPD_OFF;
usleep(params->pmc_io_dpd3_req_wait);
// Set autocal interval if not configured.
// Stall auto call measurements if periodic calibration is disabled.
if (!params->emc_auto_cal_interval)
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
@@ -655,7 +720,8 @@ break_nosleep:
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
}
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Trigger timing update so above writes take place.
EMC(EMC_TIMING_CONTROL) = 1;
usleep(params->emc_timing_control_wait);
// Deassert HOLD_CKE_LOW.
@@ -724,7 +790,8 @@ break_nosleep:
if (params->emc_bct_spare12)
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Trigger timing update so above writes take place.
EMC(EMC_TIMING_CONTROL) = 1;
if (params->emc_extra_refresh_num)
EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3;
@@ -742,7 +809,8 @@ break_nosleep:
// Write addr swizzle lock bit.
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | BIT(1);
EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions.
// Re-trigger timing to latch power saving functions.
EMC(EMC_TIMING_CONTROL) = 1;
// Enable EMC pipe clock gating.
EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;
@@ -764,8 +832,19 @@ break_nosleep:
static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
{
u32 pmc_scratch1 = ~params->emc_pmc_scratch1;
u32 pmc_scratch2 = ~params->emc_pmc_scratch2;
// VDDP Select.
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
usleep(params->pmc_vddp_sel_wait);
// Turn on MEM IO Power.
PMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_SDMMC1; // Only keep SDMMC1 state. (Was params->pmc_no_io_power).
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
// Patch 1 using BCT spare variables
if (params->emc_bct_spare0)
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;
// Override HW FSM if needed.
if (params->clk_rst_pllm_misc20_override_enable)
@@ -773,16 +852,18 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
// Program DPD3/DPD4 regs (coldboot path).
// Enable sel_dpd on unused pins.
u32 pmc_scratch1 = ~params->emc_pmc_scratch1;
PMC(APBDEV_PMC_WEAK_BIAS) = (pmc_scratch1 & 0x1000) << 19 | (pmc_scratch1 & 0xFFF) << 18 | (pmc_scratch1 & 0x8000) << 15;
PMC(APBDEV_PMC_IO_DPD3_REQ) = (pmc_scratch1 & 0x9FFF) | (2 << 30u);
PMC(APBDEV_PMC_IO_DPD3_REQ) = (pmc_scratch1 & 0x9FFF) | PMC_IO_DPD_REQ_DPD_ON;
usleep(params->pmc_io_dpd3_req_wait);
// Disable e_dpd_vttgen.
PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x3FFF0000) | (2 << 30u);
u32 pmc_scratch2 = ~params->emc_pmc_scratch2;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x3FFF0000) | PMC_IO_DPD_REQ_DPD_ON;
usleep(params->pmc_io_dpd4_req_wait);
// Disable e_dpd_bg.
PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x1FFF) | (2 << 30u);
PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x1FFF) | PMC_IO_DPD_REQ_DPD_ON;
usleep(1);
// Program CMD mapping. Required before brick mapping, else
@@ -823,7 +904,8 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare_secure4)
*(vu32 *)params->emc_bct_spare_secure4 = params->emc_bct_spare_secure5;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Trigger timing update so above writes take place.
EMC(EMC_TIMING_CONTROL) = 1;
usleep(params->pmc_vddp_sel_wait + 2); // Ensure the regulators settle.
// Set clock sources.
@@ -840,6 +922,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
// This is required to do any reads from the pad macros.
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
// Set data pipes mode.
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
// Set swizzle for Rank 0.
@@ -857,12 +940,12 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare6)
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;
// Set pad controls.
// Program calibration impedance.
EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;
// Program Autocal controls with shadowed register fields.
// Program Autocal controls.
EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
@@ -871,6 +954,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;
// Program termination and drive strength
EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term;
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
@@ -879,10 +963,12 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
// Program dll config.
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;
// Program barrelshift.
EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
@@ -896,6 +982,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;
// Program pad macros controls and termination.
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
@@ -909,6 +996,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode;
EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl & 0xEFFFFFFF;
// Program pad macro pins/bytes.
EMC(EMC_CFG_3) = params->emc_cfg3;
EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0;
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
@@ -952,12 +1040,15 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_PMACRO_CMD_CTRL_0) = params->emc_pmacro_cmd_ctrl0;
EMC(EMC_PMACRO_CMD_CTRL_1) = params->emc_pmacro_cmd_ctrl1;
EMC(EMC_PMACRO_CMD_CTRL_2) = params->emc_pmacro_cmd_ctrl2;
// Program inbound vref setting.
EMC(EMC_PMACRO_IB_VREF_DQ_0) = params->emc_pmacro_ib_vref_dq_0;
EMC(EMC_PMACRO_IB_VREF_DQ_1) = params->emc_pmacro_ib_vref_dq_1;
EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0;
EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt;
// Program quse trimmers.
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
@@ -971,6 +1062,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4;
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;
// Program outbound trimmers.
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
@@ -1005,6 +1097,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;
// Program clock trimmers.
EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0;
EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1;
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
@@ -1029,7 +1122,8 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare_secure10)
*(vu32 *)params->emc_bct_spare_secure10 = params->emc_bct_spare_secure11;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Trigger timing update so above writes take place.
EMC(EMC_TIMING_CONTROL) = 1;
// Initialize MC VPR settings.
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
@@ -1094,7 +1188,8 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
MC(MC_DA_CONFIG0) = params->mc_da_cfg0;
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
// Trigger MC timing update.
MC(MC_TIMING_CONTROL) = 1;
// Program second-level clock enable overrides.
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
@@ -1116,6 +1211,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;
// Program/Start auto calibration.
EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
usleep(params->emc_auto_cal_wait);
@@ -1179,10 +1275,12 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_DBG) = params->emc_dbg;
// Clear read fifo.
EMC(EMC_QRST) = params->emc_qrst;
EMC(EMC_ISSUE_QRST) = 1;
EMC(EMC_ISSUE_QRST) = 0;
// Program the rest of EMC timing configuration.
EMC(EMC_QSAFE) = params->emc_qsafe;
EMC(EMC_RDV) = params->emc_rdv;
EMC(EMC_RDV_MASK) = params->emc_rdv_mask;
@@ -1232,7 +1330,9 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->boot_rom_patch_control)
{
*(vu32 *)params->boot_rom_patch_control = params->boot_rom_patch_data;
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
// Trigger MC timing update.
MC(MC_TIMING_CONTROL) = 1;
}
// Patch 7 to 9 using BCT spare secure variables.
@@ -1244,7 +1344,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
*(vu32 *)params->emc_bct_spare_secure16 = params->emc_bct_spare_secure17;
// Release SEL_DPD_CMD.
PMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | (1 << 30u);
PMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | PMC_IO_DPD_REQ_DPD_OFF;
usleep(params->pmc_io_dpd3_req_wait);
// Set transmission pad control parameters.
@@ -1257,7 +1357,8 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
}
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Trigger timing update so above writes take place.
EMC(EMC_TIMING_CONTROL) = 1;
usleep(params->emc_timing_control_wait);
// Deassert HOLD_CKE_LOW.
@@ -1334,7 +1435,8 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare12)
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Trigger timing update so above writes take place.
EMC(EMC_TIMING_CONTROL) = 1;
if (params->emc_extra_refresh_num)
EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 253) | (params->emc_dev_select << 30);
@@ -1351,7 +1453,8 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
// Write addr swizzle lock bit.
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | BIT(1);
EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions.
// Re-trigger timing to latch power saving functions.
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_CFG_UPDATE) = params->emc_cfg_update;
@@ -1452,65 +1555,28 @@ void *sdram_get_params_patched()
return (void *)sdram_params;
}
static void _sdram_init_t210()
{
const sdram_params_t210_t *params = (const sdram_params_t210_t *)_sdram_get_params_t210();
if (params->memory_type != MEMORY_TYPE_LPDDR4)
return;
// Set DRAM voltage.
max7762x_regulator_set_voltage(REGULATOR_SD1, 1125000); // HOS: 1.125V. Bootloader: 1.1V.
// VDDP Select.
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
usleep(params->pmc_vddp_sel_wait);
// Set DDR pad voltage.
PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); // Normally params->pmc_ddr_pwr.
// Turn on MEM IO Power.
PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power;
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
// Patch 1 using BCT spare variables
if (params->emc_bct_spare0)
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;
_sdram_config_t210(params);
}
static void _sdram_init_t210b01()
{
const sdram_params_t210b01_t *params = (const sdram_params_t210b01_t *)sdram_get_params_t210b01();
if (params->memory_type != MEMORY_TYPE_LPDDR4)
return;
// VDDP Select.
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
usleep(params->pmc_vddp_sel_wait);
// Turn on MEM IO Power.
PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power;
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
// Patch 1 using BCT spare variables
if (params->emc_bct_spare0)
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;
_sdram_config_t210b01(params);
}
void sdram_init()
{
// Disable remote sense for SD1.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, MAX77620_SD_CNF2_ROVS_EN_SD0 | MAX77620_SD_CNF2_RSVD);
if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)
_sdram_init_t210();
{
const sdram_params_t210_t *params = (const sdram_params_t210_t *)_sdram_get_params_t210();
if (params->memory_type != MEMORY_TYPE_LPDDR4)
return;
// Set DRAM voltage.
max7762x_regulator_set_voltage(REGULATOR_SD1, 1125000); // HOS: 1.125V. Bootloader: 1.1V.
_sdram_config_t210(params);
}
else
_sdram_init_t210b01();
{
const sdram_params_t210b01_t *params = (const sdram_params_t210b01_t *)sdram_get_params_t210b01();
if (params->memory_type != MEMORY_TYPE_LPDDR4)
return;
_sdram_config_t210b01(params);
}
}

View File

@@ -48,7 +48,14 @@ enum sdram_ids_erista
LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4, // Die-C. (2y-01).
// Custom hekate/L4T supported 8GB. 7 dram id can be easily applied in fuses.
/*
* Custom hekate/L4T supported 8GB. 7 dram id can be easily applied in fuses.
*
* 4GB modules:
* Samsung K4FBE3D4HM-MGCH/CJ/CL. MG/TF/GF/TH/GH: Package + Temperature.
* Hynix H9HCNNNCPUMLXR-NME/NEE/NEI. E/I: Temperature.
* Hynix H54G56BYYVX046/QX046/PX046. V/Q/P: Package + Temperature.
*/
LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX = 7, // XX: CH/CJ/CL.
};
@@ -128,6 +135,7 @@ void sdram_init();
void *sdram_get_params_patched();
void *sdram_get_params_t210b01();
void sdram_lp0_save_params(const void *params);
void sdram_src_pllc(bool enable);
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx);
#endif

View File

@@ -75,7 +75,7 @@ void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd)
{
memset(buf, 0, sizeof(buf));
_bm92t36_read_reg(buf, 2, STATUS1_REG);
*inserted = buf[0] & STATUS1_INSERT ? true : false;
*inserted = (buf[0] & STATUS1_INSERT) ? true : false;
}
if (usb_pd)

View File

@@ -32,24 +32,24 @@ void regulator_5v_enable(u8 dev)
// The power supply selection from battery or USB is automatic.
if (!reg_5v_dev)
{
// Fan and Rail power from battery 5V regulator.
// Fan and Rail power from battery 5V regulator EN.
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1;
gpio_direction_output(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH);
// Only Icosa has USB 5V VBUS rails.
if (tegra_t210)
{
// Fan and Rail power from USB 5V VBUS.
// Fan and Rail power from USB 5V VBUS EN.
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1;
gpio_direction_output(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW);
}
// Make sure GPIO IO power is enabled.
PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO_IO_EN;
PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO;
(void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write.
// Override power detect for GPIO AO IO rails.
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_GPIO_IO_EN;
// Inform GPIO IO pads that we switched to 1.8V.
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_33V_GPIO;
(void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write.
usb_src = false;

View File

@@ -33,6 +33,9 @@ typedef struct _se_ll_t
vu32 size;
} se_ll_t;
static u32 _se_rsa_mod_sizes[SE_RSA_KEYSLOT_COUNT];
static u32 _se_rsa_exp_sizes[SE_RSA_KEYSLOT_COUNT];
se_ll_t ll_src, ll_dst;
se_ll_t *ll_src_ptr, *ll_dst_ptr; // Must be u32 aligned.
@@ -194,7 +197,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
return res;
}
static void _se_aes_ctr_set(void *ctr)
static void _se_aes_ctr_set(const void *ctr)
{
u32 data[SE_AES_IV_SIZE / 4];
memcpy(data, ctr, SE_AES_IV_SIZE);
@@ -213,6 +216,66 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags)
SE(SE_RSA_SECURITY_PERKEY_REG) &= ~BIT(rs);
}
// se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size)
{
u32 *data = (u32 *)mod;
for (u32 i = 0; i < mod_size / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_MOD) | i;
SE(SE_RSA_KEYTABLE_DATA_REG) = byte_swap_32(data[mod_size / 4 - i - 1]);
}
data = (u32 *)exp;
for (u32 i = 0; i < exp_size / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_EXP) | i;
SE(SE_RSA_KEYTABLE_DATA_REG) = byte_swap_32(data[exp_size / 4 - i - 1]);
}
_se_rsa_mod_sizes[ks] = mod_size;
_se_rsa_exp_sizes[ks] = exp_size;
}
// se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot
void se_rsa_key_clear(u32 ks)
{
for (u32 i = 0; i < SE_RSA2048_DIGEST_SIZE / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_MOD) | i;
SE(SE_RSA_KEYTABLE_DATA_REG) = 0;
}
for (u32 i = 0; i < SE_RSA2048_DIGEST_SIZE / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_EXP) | i;
SE(SE_RSA_KEYTABLE_DATA_REG) = 0;
}
}
// se_rsa_exp_mod() was derived from Atmosphère's se_synchronous_exp_mod and se_get_exp_mod_output
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
{
int res;
u8 stack_buf[SE_RSA2048_DIGEST_SIZE];
for (u32 i = 0; i < src_size; i++)
stack_buf[i] = *((u8 *)src + src_size - i - 1);
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG);
SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks);
SE(SE_RSA_KEY_SIZE_REG) = (_se_rsa_mod_sizes[ks] >> 6) - 1;
SE(SE_RSA_EXP_SIZE_REG) = _se_rsa_exp_sizes[ks] >> 2;
res = _se_execute_oneshot(SE_OP_START, NULL, 0, stack_buf, src_size);
// Copy output hash.
u32 *dst32 = (u32 *)dst;
for (u32 i = 0; i < dst_size / 4; i++)
dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT_REG + (i * 4)));
return res;
}
void se_key_acc_ctrl(u32 ks, u32 flags)
{
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
@@ -226,7 +289,7 @@ u32 se_key_acc_ctrl_get(u32 ks)
return SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + 4 * ks);
}
void se_aes_key_set(u32 ks, void *key, u32 size)
void se_aes_key_set(u32 ks, const void *key, u32 size)
{
u32 data[SE_AES_MAX_KEY_SIZE / 4];
memcpy(data, key, size);
@@ -238,7 +301,13 @@ void se_aes_key_set(u32 ks, void *key, u32 size)
}
}
void se_aes_iv_set(u32 ks, void *iv)
void se_aes_key_partial_set(u32 ks, u32 index, u32 data)
{
SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | index;
SE(SE_CRYPTO_KEYTABLE_DATA_REG) = data;
}
void se_aes_iv_set(u32 ks, const void *iv)
{
u32 data[SE_AES_IV_SIZE / 4];
memcpy(data, iv, SE_AES_IV_SIZE);

View File

@@ -22,11 +22,15 @@
#include <utils/types.h>
void se_rsa_acc_ctrl(u32 rs, u32 flags);
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size);
void se_rsa_key_clear(u32 ks);
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
void se_key_acc_ctrl(u32 ks, u32 flags);
u32 se_key_acc_ctrl_get(u32 ks);
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize);
void se_aes_key_set(u32 ks, void *key, u32 size);
void se_aes_iv_set(u32 ks, void *iv);
void se_aes_key_set(u32 ks, const void *key, u32 size);
void se_aes_iv_set(u32 ks, const void *iv);
void se_aes_key_partial_set(u32 ks, u32 index, u32 data);
void se_aes_key_get(u32 ks, void *key, u32 size);
void se_aes_key_clear(u32 ks);
void se_aes_iv_clear(u32 ks);

View File

@@ -75,7 +75,7 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
void *ptb;
bpmp_mmu_disable();
bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
bpmp_clk_rate_relaxed(true);
// Enable clocks.
clock_enable_tsec();
@@ -305,7 +305,7 @@ out:
clock_disable_sor_safe();
clock_disable_tsec();
bpmp_mmu_enable();
bpmp_clk_rate_set(prev_fid);
bpmp_clk_rate_relaxed(false);
#ifdef BDK_MC_ENABLE_AHB_REDIRECT
// Re-enable AHB aperture.

View File

@@ -1,7 +1,7 @@
/*
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
*
* Copyright (c) 2019-2023 CTCaer
* Copyright (c) 2019-2024 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,
@@ -118,7 +118,7 @@
#define MMU_EN_READ BIT(2)
#define MMU_EN_WRITE BIT(3)
bpmp_mmu_entry_t mmu_entries[] =
static const bpmp_mmu_entry_t mmu_entries[] =
{
{ DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
{ IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
@@ -140,7 +140,7 @@ void bpmp_mmu_maintenance(u32 op, bool force)
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)
void bpmp_mmu_set_entry(int idx, const bpmp_mmu_entry_t *entry, bool apply)
{
if (idx > 31)
return;
@@ -200,10 +200,45 @@ void bpmp_mmu_disable()
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
}
/*
* CLK_RST_CONTROLLER_SCLK_BURST_POLICY:
* 0 = CLKM
* 1 = PLLC_OUT1
* 2 = PLLC4_OUT3
* 3 = PLLP_OUT0
* 4 = PLLP_OUT2
* 5 = PLLC4_OUT1
* 6 = CLK_S
* 7 = PLLC4_OUT2
*/
bpmp_freq_t bpmp_fid_current = BPMP_CLK_NORMAL;
void bpmp_clk_rate_relaxed(bool enable)
{
// This is a glitch-free way to reduce the SCLK timings.
if (enable)
{
// Restore to PLLP source during PLLC configuration.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT.
usleep(100); // Wait a bit for clock source change.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
}
else if (bpmp_fid_current)
{
// Restore to PLLC_OUT1.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 and CLKM for idle.
usleep(100); // Wait a bit for clock source change.
}
}
// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
// I2C host, DC/DSI/DISP. UART gives extra stress.
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.
const u8 pll_divn[] = {
// APB clock max is supposed to be 204 MHz though.
static const u8 pll_divn[] = {
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
88, // BPMP_CLK_HIGH2_BOOST: 563MHz 38% - 141MHz APB.
@@ -213,8 +248,6 @@ const u8 pll_divn[] = {
//95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB.
};
bpmp_freq_t bpmp_fid_current = BPMP_CLK_NORMAL;
void bpmp_clk_rate_get()
{
bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3;
@@ -237,45 +270,42 @@ void bpmp_clk_rate_get()
}
}
bpmp_freq_t bpmp_clk_rate_set(bpmp_freq_t fid)
void bpmp_clk_rate_set(bpmp_freq_t fid)
{
bpmp_freq_t prev_fid = bpmp_fid_current;
if (fid > (BPMP_CLK_MAX - 1))
fid = BPMP_CLK_MAX - 1;
if (prev_fid == fid)
return prev_fid;
if (bpmp_fid_current == fid)
return;
bpmp_fid_current = fid;
if (fid)
{
if (prev_fid)
{
// Restore to PLLP source during PLLC configuration.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
msleep(1); // Wait a bit for clock source change.
}
// Use default SCLK / HCLK / PCLK clocks.
bpmp_clk_rate_relaxed(true);
// Configure and enable PLLC.
clock_enable_pllc(pll_divn[fid]);
// Set SCLK / HCLK / PCLK.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle.
// Set new source and SCLK / HCLK / PCLK dividers.
bpmp_clk_rate_relaxed(false);
}
else
{
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle.
msleep(1); // Wait a bit for clock source change.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
// Use default SCLK / HCLK / PCLK clocks.
bpmp_clk_rate_relaxed(true);
// Disable PLLC to save power.
clock_disable_pllc();
}
bpmp_fid_current = fid;
}
// Return old fid in case of temporary swap.
return prev_fid;
// State is reset to RUN on any clock or source set via SW.
void bpmp_state_set(bpmp_state_t state)
{
u32 cfg = CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & ~0xF0000000u;
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = cfg | (state << 28u);
}
// The following functions halt BPMP to reduce power while sleeping.

View File

@@ -1,7 +1,7 @@
/*
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
*
* Copyright (c) 2019-2023 CTCaer
* Copyright (c) 2019-2024 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,
@@ -54,16 +54,28 @@ typedef enum
BPMP_CLK_MAX
} bpmp_freq_t;
typedef enum
{
BPMP_STATE_STANDBY = 0, // 32KHz.
BPMP_STATE_IDLE = 1,
BPMP_STATE_RUN = 2,
BPMP_STATE_IRQ = BIT(2),
BPMP_STATE_FIQ = BIT(3),
} bpmp_state_t;
#define BPMP_CLK_LOWEST_BOOST BPMP_CLK_HIGH2_BOOST
#define BPMP_CLK_LOWER_BOOST BPMP_CLK_SUPER_BOOST
#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST
void bpmp_mmu_maintenance(u32 op, bool force);
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
void bpmp_mmu_set_entry(int idx, const bpmp_mmu_entry_t *entry, bool apply);
void bpmp_mmu_enable();
void bpmp_mmu_disable();
void bpmp_clk_rate_relaxed(bool enable);
void bpmp_clk_rate_get();
bpmp_freq_t bpmp_clk_rate_set(bpmp_freq_t fid);
void bpmp_clk_rate_set(bpmp_freq_t fid);
void bpmp_state_set(bpmp_state_t state);
void bpmp_usleep(u32 us);
void bpmp_msleep(u32 ms);
void bpmp_halt();

View File

@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <soc/bpmp.h>
#include <soc/clock.h>
#include <soc/hw_init.h>
#include <soc/pmc.h>
@@ -153,7 +154,13 @@ void clock_enable_fuse(bool enable)
void clock_enable_uart(u32 idx)
{
// Ease the stress to APB.
bpmp_clk_rate_relaxed(true);
clock_enable(&_clock_uart[idx]);
// Restore OC.
bpmp_clk_rate_relaxed(false);
}
void clock_disable_uart(u32 idx)
@@ -247,7 +254,13 @@ void clock_disable_nvjpg()
void clock_enable_vic()
{
// Ease the stress to APB.
bpmp_clk_rate_relaxed(true);
clock_enable(&_clock_vic);
// Restore sys clock.
bpmp_clk_rate_relaxed(false);
}
void clock_disable_vic()
@@ -323,7 +336,13 @@ void clock_disable_coresight()
void clock_enable_pwm()
{
// Ease the stress to APB.
bpmp_clk_rate_relaxed(true);
clock_enable(&_clock_pwm);
// Restore OC.
bpmp_clk_rate_relaxed(false);
}
void clock_disable_pwm()
@@ -398,10 +417,8 @@ void clock_enable_plld(u32 divp, u32 divn, bool lowpower, bool tegra_t210)
if (lowpower && tegra_t210)
misc = 0x2D0000 | 0x0AAA; // Clock enable and PLLD_SDM_DIN: 2730 -> DIVN + 0.833.
// Set DISP1 clock source and parent clock.
if (lowpower)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = (2 << 29u) | CLK_SRC_DIV(1); // PLLD_OUT0.
// Set DISP1 clock source.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 2 << 29u; // PLLD_OUT0.
// Set dividers and enable PLLD.
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div;
@@ -464,10 +481,10 @@ void clock_enable_pllc(u32 divn)
;
// Disable PLLC_OUT1, enable reset and set div to 1.5.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = BIT(8);
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = 1 << 8;
// Enable PLLC_OUT1 and bring it out of reset.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR;
msleep(1); // Wait a bit for PLL to stabilize.
}
@@ -684,7 +701,7 @@ static void _clock_sdmmc_clear_enable(u32 id)
static void _clock_sdmmc_config_legacy_tm()
{
clk_rst_t *clk = &_clock_sdmmc_legacy_tm;
const clk_rst_t *clk = &_clock_sdmmc_legacy_tm;
if (!(CLOCK(clk->enable) & BIT(clk->index)))
clock_enable(clk);
}

View File

@@ -47,6 +47,7 @@
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
#define CLK_RST_CONTROLLER_PLLP_OUTB 0xA8
#define CLK_RST_CONTROLLER_PLLA_BASE 0xB0
#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4
#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8
@@ -149,6 +150,7 @@
#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
#define CLK_RST_CONTROLLER_PLLMB_MISC1 0x5EC
#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS 0x608
#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV 0x60C
#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS 0x610

View File

@@ -86,6 +86,15 @@ u32 fuse_read_odm_keygen_rev()
return 0;
}
u32 fuse_read_bootrom_rev()
{
u32 rev = FUSE(FUSE_SOC_SPEEDO_1_CALIB);
if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)
return rev;
else
return rev | (1 << 12);
}
u32 fuse_read_dramid(bool raw_id)
{
bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;
@@ -189,7 +198,7 @@ void fuse_read_array(u32 *words)
words[i] = fuse_read(i);
}
static u32 _parity32_even(u32 *words, u32 count)
static u32 _parity32_even(const u32 *words, u32 count)
{
u32 acc = words[0];
for (u32 i = 1; i < count; i++)
@@ -303,7 +312,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 word0;
u32 total_read = 0;
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
@@ -363,7 +372,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 word0;
u32 total_read = 0;
int evp_thunk_written = 0;
void *evp_thunk_dst_addr = 0;

View File

@@ -304,6 +304,7 @@ enum
void fuse_disable_program();
u32 fuse_read_odm(u32 idx);
u32 fuse_read_odm_keygen_rev();
u32 fuse_read_bootrom_rev();
u32 fuse_read_dramid(bool raw_id);
u32 fuse_read_hw_state();
u32 fuse_read_hw_type();

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2023 CTCaer
* Copyright (c) 2018-2024 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,
@@ -93,6 +93,24 @@ static void _config_oscillators()
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3.
}
void hw_config_arbiter(bool reset)
{
if (reset)
{
ARB_PRI(ARB_PRIO_CPU_PRIORITY) = 0x0040090;
ARB_PRI(ARB_PRIO_COP_PRIORITY) = 0x12024C2;
ARB_PRI(ARB_PRIO_VCP_PRIORITY) = 0x2201209;
ARB_PRI(ARB_PRIO_DMA_PRIORITY) = 0x320365B;
}
else
{
ARB_PRI(ARB_PRIO_CPU_PRIORITY) = 0x12412D1;
ARB_PRI(ARB_PRIO_COP_PRIORITY) = 0x0000000;
ARB_PRI(ARB_PRIO_VCP_PRIORITY) = 0x220244A;
ARB_PRI(ARB_PRIO_DMA_PRIORITY) = 0x320369B;
}
}
// The uart is skipped for Copper, Hoag and Calcio. Used in Icosa, Iowa and Aula.
static void _config_gpios(bool nx_hoag)
{
@@ -268,7 +286,7 @@ static void _config_se_brom()
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
}
static void _config_regulators(bool tegra_t210)
static void _config_regulators(bool tegra_t210, bool nx_hoag)
{
// Set RTC/AO domain to POR voltage.
if (tegra_t210)
@@ -277,22 +295,26 @@ static void _config_regulators(bool tegra_t210)
// Disable low battery shutdown monitor.
max77620_low_battery_monitor_config(false);
// Disable SDMMC1 IO/Core power.
// Power on all relevant rails in case we came out of warmboot. Only keep MEM/MEM_COMP and SDMMC1 states.
PMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_MEM_COMP | PMC_NO_IOPOWER_SDMMC1 | PMC_NO_IOPOWER_MEM;
// Make sure SDMMC1 IO/Core are powered off.
max7762x_regulator_enable(REGULATOR_LDO2, false);
gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW);
PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1;
(void)PMC(APBDEV_PMC_NO_IOPOWER);
sd_power_cycle_time_start = get_tmr_ms();
// Disable LCD DVDD to make sure it's in a reset state.
max7762x_regulator_enable(REGULATOR_LDO0, false);
// Disable backup battery charger.
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,
MAX77620_ONOFFCNFG1_RSVD | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
// Set PWR delay for forced shutdown off to 6s.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_RSVD | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT));
if (tegra_t210)
{
// Configure all Flexible Power Sequencers for MAX77620.
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_CFG0, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (0 << MAX77620_FPS_EN_SRC_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);
@@ -301,13 +323,13 @@ static void _config_regulators(bool tegra_t210)
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 GPIO3 to FPS0 for SYS 3V3 EN. Enabled when FPS0 is enabled.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, (4 << MAX77620_FPS_PU_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT));
// Set vdd_core voltage to 1.125V.
max7762x_regulator_set_voltage(REGULATOR_SD0, 1125000);
// Fix CPU/GPU after L4T warmboot.
// Power down CPU/GPU regulators after L4T warmboot.
max77620_config_gpio(5, MAX77620_GPIO_OUTPUT_DISABLE);
max77620_config_gpio(6, MAX77620_GPIO_OUTPUT_DISABLE);
@@ -315,8 +337,26 @@ static void _config_regulators(bool tegra_t210)
max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_POR_CFG);
max77621_config_default(REGULATOR_GPU0, MAX77621_CTRL_POR_CFG);
}
else // Tegra X1+ set vdd_core voltage to 1.05V.
else
{
// Tegra X1+ set vdd_core voltage to 1.05V.
max7762x_regulator_set_voltage(REGULATOR_SD0, 1050000);
// Power on SD2 regulator for supplying LDO0/1/8.
max7762x_regulator_set_voltage(REGULATOR_SD2, 1325000);
// Set slew rate and enable SD2 regulator.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD2_CFG, (1 << MAX77620_SD_SR_SHIFT) |
(MAX77620_POWER_MODE_NORMAL << MAX77620_SD_POWER_MODE_SHIFT) |
MAX77620_SD_CFG1_FSRADE_SD_ENABLE);
// Enable LDO8 on HOAG as it also powers I2C1 IO pads.
if (nx_hoag)
{
max7762x_regulator_set_voltage(REGULATOR_LDO8, 2800000);
max7762x_regulator_enable(REGULATOR_LDO8, true);
}
}
}
void hw_init()
@@ -337,6 +377,9 @@ void hw_init()
if (tegra_t210)
_mbist_workaround();
// Make sure PLLP_OUT3/4 is set to 408 MHz and enabled.
CLOCK(CLK_RST_CONTROLLER_PLLP_OUTB) = 0x30003;
// Enable Security Engine clock.
clock_enable_se();
@@ -355,18 +398,6 @@ void hw_init()
// Initialize pin configuration.
_config_gpios(nx_hoag);
#ifdef DEBUG_UART_PORT
#if (DEBUG_UART_PORT == UART_B)
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
#elif (DEBUG_UART_PORT == UART_C)
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
#endif
pinmux_config_uart(DEBUG_UART_PORT);
clock_enable_uart(DEBUG_UART_PORT);
uart_init(DEBUG_UART_PORT, DEBUG_UART_BAUDRATE, UART_AO_TX_AO_RX);
uart_invert(DEBUG_UART_PORT, DEBUG_UART_INVERT, UART_INVERT_TXD);
#endif
// Enable CL-DVFS clock unconditionally to avoid issues with I2C5 sharing.
clock_enable_cl_dvfs();
@@ -380,19 +411,12 @@ void hw_init()
// Initialize I2C5, mandatory for PMIC.
i2c_init(I2C_5);
// Enable LDO8 on HOAG as it also powers I2C1 IO pads.
if (nx_hoag)
{
max7762x_regulator_set_voltage(REGULATOR_LDO8, 2800000);
max7762x_regulator_enable(REGULATOR_LDO8, true);
}
// Initialize various regulators based on Erista/Mariko platform.
_config_regulators(tegra_t210, nx_hoag);
// Initialize I2C1 for various power related devices.
i2c_init(I2C_1);
// Initialize various regulators based on Erista/Mariko platform.
_config_regulators(tegra_t210);
_config_pmc_scratch(); // Missing from 4.x+
// Set BPMP/SCLK to PLLP_OUT (408MHz).
@@ -406,6 +430,9 @@ void hw_init()
PMC(APBDEV_PMC_TZRAM_SEC_DISABLE) = PMC_TZRAM_DISABLE_REG_WRITE | PMC_TZRAM_DISABLE_REG_READ;
}
// Set arbiter.
hw_config_arbiter(false);
// Initialize External memory controller and configure DRAM parameters.
sdram_init();
@@ -413,9 +440,22 @@ void hw_init()
// Enable HOST1X used by every display module (DC, VIC, NVDEC, NVENC, TSEC, etc).
clock_enable_host1x();
#ifdef DEBUG_UART_PORT
// Setup debug uart port.
#if (DEBUG_UART_PORT == UART_B)
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
#elif (DEBUG_UART_PORT == UART_C)
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
#endif
pinmux_config_uart(DEBUG_UART_PORT);
clock_enable_uart(DEBUG_UART_PORT);
uart_init(DEBUG_UART_PORT, DEBUG_UART_BAUDRATE, UART_AO_TX_AO_RX);
uart_invert(DEBUG_UART_PORT, DEBUG_UART_INVERT, UART_INVERT_TXD);
#endif
}
void hw_reinit_workaround(bool coreboot, u32 bl_magic)
void hw_deinit(bool coreboot, u32 bl_magic)
{
bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;
@@ -426,7 +466,7 @@ void hw_reinit_workaround(bool coreboot, u32 bl_magic)
// Disable temperature sensor, touchscreen, 5V regulators, Joy-Con and VIC.
vic_end();
tmp451_end();
set_fan_duty(0);
fan_set_duty(0);
touch_power_off();
jc_deinit();
regulator_5v_disable(REGULATOR_5V_ALL);
@@ -439,6 +479,9 @@ void hw_reinit_workaround(bool coreboot, u32 bl_magic)
// Flush/disable MMU cache.
bpmp_mmu_disable();
// Reset arbiter.
hw_config_arbiter(true);
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
if (tegra_t210)
{
@@ -458,7 +501,7 @@ void hw_reinit_workaround(bool coreboot, u32 bl_magic)
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
// Reinstate SD controller power.
PMC(APBDEV_PMC_NO_IOPOWER) &= ~(PMC_NO_IOPOWER_SDMMC1_IO_EN);
PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_SDMMC1;
}
// Seamless display or display power off.

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2021 CTCaer
* Copyright (c) 2018-2024 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,
@@ -27,7 +27,8 @@ extern u32 hw_rst_status;
extern u32 hw_rst_reason;
void hw_init();
void hw_reinit_workaround(bool coreboot, u32 magic);
void hw_deinit(bool coreboot, u32 magic);
void hw_config_arbiter(bool reset);
u32 hw_get_chip_id();
#endif

View File

@@ -96,7 +96,7 @@ static void _i2c_load_cfg_wait(vu32 *base)
}
}
static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size)
static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size)
{
if (size > 8)
return 0;
@@ -384,7 +384,7 @@ int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)
return _i2c_recv_pkt(i2c_idx, buf, size, dev_addr, reg);
}
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size)
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size)
{
u8 tmp[8];

View File

@@ -31,7 +31,7 @@ void i2c_init(u32 i2c_idx);
int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr);
int i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size);
int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg);
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size);
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size);
int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg);
int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val);
u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg);

View File

@@ -1,7 +1,7 @@
/*
* BPMP-Lite IRQ driver for Tegra X1
*
* Copyright (c) 2019 CTCaer
* Copyright (c) 2019-2024 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,
@@ -71,19 +71,9 @@ static void _irq_disable_and_ack_all()
{
u32 enabled_irqs = ICTLR(ctrl_idx, PRI_ICTLR_COP_IER);
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = enabled_irqs;
ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = enabled_irqs;
}
}
static void _irq_ack_source(u32 irq)
{
u32 ctrl_idx = irq >> 5;
u32 bit = irq % 32;
// Force stop the interrupt as it's serviced here.
ICTLR(ctrl_idx, PRI_ICTLR_FIR_CLR) = BIT(bit);
}
void irq_free(u32 irq)
{
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
@@ -121,7 +111,6 @@ static irq_status_t _irq_handle_source(u32 irq)
int status = IRQ_NONE;
_irq_disable_source(irq);
_irq_ack_source(irq);
u32 idx;
for (idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
@@ -135,8 +124,8 @@ static irq_status_t _irq_handle_source(u32 irq)
}
}
// Do not re-enable if not handled.
if (status == IRQ_NONE)
// Do not re-enable if not handled or error.
if (status != IRQ_HANDLED)
return status;
if (irqs[idx].flags & IRQ_FLAG_ONE_OFF)
@@ -155,7 +144,6 @@ void irq_handler()
if (!irq_init_done)
{
_irq_disable_source(irq);
_irq_ack_source(irq);
return;
}
@@ -197,7 +185,6 @@ void irq_wait_event(u32 irq)
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_STOP_UNTIL_IRQ;
_irq_disable_source(irq);
_irq_ack_source(irq);
irq_enable_cpu_irq_exceptions();
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2024 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,
@@ -30,3 +31,11 @@ void pinmux_config_i2c(u32 idx)
PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = PINMUX_INPUT_ENABLE;
}
void pinmux_config_i2s(u32 idx)
{
PINMUX_AUX(PINMUX_AUX_X_I2S_LRCK(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN;
PINMUX_AUX(PINMUX_AUX_X_I2C_DIN(idx)) = PINMUX_DRIVE_4X | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_DOWN;
PINMUX_AUX(PINMUX_AUX_X_I2C_DOUT(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN;
PINMUX_AUX(PINMUX_AUX_X_I2C_BCLK(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN;
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2024 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,
@@ -50,6 +51,7 @@
#define PINMUX_AUX_DAP4_DOUT 0x14C
#define PINMUX_AUX_DAP4_SCLK 0x150
#define PINMUX_AUX_CLK_32K_OUT 0x164
#define PINMUX_AUX_AUD_MCLK 0x180
#define PINMUX_AUX_GPIO_X1_AUD 0x18C
#define PINMUX_AUX_GPIO_X3_AUD 0x190
#define PINMUX_AUX_SPDIF_IN 0x1A4
@@ -69,6 +71,7 @@
#define PINMUX_AUX_LCD_RST 0x204
#define PINMUX_AUX_LCD_GPIO1 0x208
#define PINMUX_AUX_LCD_GPIO2 0x20C
#define PINMUX_AUX_TOUCH_RST 0x214
#define PINMUX_AUX_TOUCH_CLK 0x218
#define PINMUX_AUX_TOUCH_INT 0x220
#define PINMUX_AUX_MOTION_INT 0x224
@@ -81,6 +84,7 @@
#define PINMUX_AUX_GPIO_PK3 0x260
#define PINMUX_AUX_GPIO_PK7 0x270
#define PINMUX_AUX_GPIO_PZ1 0x280
#define PINMUX_AUX_GPIO_PZ4 0x28C
/* Only in T210B01 */
#define PINMUX_AUX_SDMMC2_DAT0 0x294
#define PINMUX_AUX_SDMMC2_DAT1 0x298
@@ -101,6 +105,11 @@
/*! 0:GEN1, 1:GEN2, 2:GEN3, 3:CAM, 4:PWR */
#define PINMUX_AUX_X_I2C_SCL(x) (0xBC + 8 * (x))
#define PINMUX_AUX_X_I2C_SDA(x) (0xC0 + 8 * (x))
/*! 0:I2S1, 1:I2S2 */
#define PINMUX_AUX_X_I2S_LRCK(x) (0x124 + 0x10 * (x))
#define PINMUX_AUX_X_I2C_DIN(x) (0x128 + 0x10 * (x))
#define PINMUX_AUX_X_I2C_DOUT(x) (0x12c + 0x10 * (x))
#define PINMUX_AUX_X_I2C_BCLK(x) (0x130 + 0x10 * (x))
#define PINMUX_FUNC_MASK (3 << 0)
@@ -130,5 +139,6 @@
void pinmux_config_uart(u32 idx);
void pinmux_config_i2c(u32 idx);
void pinmux_config_i2s(u32 idx);
#endif

View File

@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018-2022 CTCaer
* Copyright (c) 2018-2024 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,
@@ -39,10 +39,12 @@
#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 BIT(12)
#define PMC_NO_IOPOWER_SDMMC4_IO_EN BIT(14)
#define PMC_NO_IOPOWER_MEM BIT(7)
#define PMC_NO_IOPOWER_SDMMC1 BIT(12)
#define PMC_NO_IOPOWER_SDMMC4 BIT(14)
#define PMC_NO_IOPOWER_MEM_COMP BIT(16)
#define PMC_NO_IOPOWER_AUDIO_HV BIT(18)
#define PMC_NO_IOPOWER_GPIO_IO_EN BIT(21)
#define PMC_NO_IOPOWER_GPIO BIT(21)
#define APBDEV_PMC_SCRATCH0 0x50
#define PMC_SCRATCH0_MODE_WARMBOOT BIT(0)
#define PMC_SCRATCH0_MODE_RCM BIT(1)
@@ -61,9 +63,9 @@
#define APBDEV_PMC_SECURE_SCRATCH4 0xC0
#define APBDEV_PMC_SECURE_SCRATCH5 0xC4
#define APBDEV_PMC_PWR_DET_VAL 0xE4
#define PMC_PWR_DET_SDMMC1_IO_EN BIT(12)
#define PMC_PWR_DET_AUDIO_HV BIT(18)
#define PMC_PWR_DET_GPIO_IO_EN BIT(21)
#define PMC_PWR_DET_33V_SDMMC1 BIT(12)
#define PMC_PWR_DET_33V_AUDIO_HV BIT(18)
#define PMC_PWR_DET_33V_GPIO BIT(21)
#define APBDEV_PMC_DDR_PWR 0xE8
#define APBDEV_PMC_USB_AO 0xF0
#define APBDEV_PMC_CRYPTO_OP 0xF4
@@ -99,7 +101,9 @@
#define PMC_RST_STATUS_LP0 4
#define PMC_RST_STATUS_AOTAG 5
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
#define PMC_IO_DPD_REQ_DPD_OFF BIT(30)
#define PMC_IO_DPD_REQ_DPD_IDLE (0 << 30u)
#define PMC_IO_DPD_REQ_DPD_OFF (1 << 30u)
#define PMC_IO_DPD_REQ_DPD_ON (2 << 30u)
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
#define APBDEV_PMC_VDDP_SEL 0x1CC
#define APBDEV_PMC_DDR_CFG 0x1D0

View File

@@ -40,7 +40,7 @@
#define GPU_USER_BASE 0x58000000
#define RES_SEMAPH_BASE 0x60001000
#define ARB_SEMAPH_BASE 0x60002000
#define ARBPRI_BASE 0x60003000
#define ARB_PRI_BASE 0x60003000
#define ICTLR_BASE 0x60004000
#define TMR_BASE 0x60005000
#define CLOCK_BASE 0x60006000
@@ -81,6 +81,7 @@
#define CL_DVFS_BASE 0x70110000
#define APE_BASE 0x702C0000
#define AHUB_BASE 0x702D0000
#define ADMAIF_BASE 0x702D0000
#define AXBAR_BASE 0x702D0800
#define I2S_BASE 0x702D1000
#define ADMA_BASE 0x702E2000
@@ -112,6 +113,7 @@
#define SOR1(off) MMIO_REG32(SOR1_BASE, off)
#define GPU(off) MMIO_REG32(GPU_BASE, off)
#define GPU_USER(off) MMIO_REG32(GPU_USER_BASE, off)
#define ARB_PRI(off) MMIO_REG32(ARB_PRI_BASE, off)
#define ICTLR(cidx, off) MMIO_REG32(ICTLR_BASE + (0x100 * (cidx)), off)
#define TMR(off) MMIO_REG32(TMR_BASE, off)
#define CLOCK(off) MMIO_REG32(CLOCK_BASE, off)
@@ -174,6 +176,7 @@
#define EVP_COP_IRQ_STS 0x220
/*! Primary Interrupt Controller registers. */
#define PRI_ICTLR_ISR 0x10
#define PRI_ICTLR_FIR 0x14
#define PRI_ICTLR_FIR_SET 0x18
#define PRI_ICTLR_FIR_CLR 0x1C
@@ -186,6 +189,13 @@
#define PRI_ICTLR_COP_IER_CLR 0x38
#define PRI_ICTLR_COP_IEP_CLASS 0x3C
/* Arbiter registers */
#define ARB_PRIO_CPU_PRIORITY 0x0
#define ARB_PRIO_COP_PRIORITY 0x4
#define ARB_PRIO_VCP_PRIORITY 0x8
#define ARB_PRIO_DMA_PRIORITY 0xC
#define ARB_PRIO_UCQ_PRIORITY 0x10
/*! AHB Gizmo registers. */
#define AHB_ARBITRATION_PRIORITY_CTRL 0x8
#define PRIORITY_CTRL_WEIGHT(x) (((x) & 7) << 29)

View File

@@ -25,6 +25,8 @@
#define EXCP_TYPE_ADDR 0x4003FFF8
#define EXCP_TYPE_WDT 0x544457 // "WDT".
#define USE_RTC_TIMER
u32 get_tmr_s()
{
(void)RTC(APBDEV_RTC_MILLI_SECONDS);
@@ -118,4 +120,4 @@ bool watchdog_fired()
{
// Return if watchdog got fired. User handles clearing.
return (*(u32 *)EXCP_TYPE_ADDR == EXCP_TYPE_WDT);
}
}

View File

@@ -174,14 +174,14 @@ void uart_empty_fifo(u32 idx, u32 which)
(void)uart->UART_SPR;
usleep(96);
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | which;
(void)uart->UART_SPR;
usleep(18);
u32 tries = 0;
if (UART_IIR_FCR_TX_CLR & which)
{
while (tries < 10 && uart->UART_LSR & UART_LSR_TMTY)
while (tries < 10 && !(uart->UART_LSR & UART_LSR_TMTY))
{
tries++;
usleep(100);
@@ -191,7 +191,7 @@ void uart_empty_fifo(u32 idx, u32 which)
if (UART_IIR_FCR_RX_CLR & which)
{
while (tries < 10 && !uart->UART_LSR & UART_LSR_RDR)
while (tries < 10 && (uart->UART_LSR & UART_LSR_RDR))
{
tries++;
usleep(100);

View File

@@ -274,7 +274,7 @@ void *sd_file_read(const char *path, u32 *fsize)
return buf;
}
int sd_save_to_file(void *buf, u32 size, const char *filename)
int sd_save_to_file(const void *buf, u32 size, const char *filename)
{
FIL fp;
u32 res = 0;

View File

@@ -61,6 +61,6 @@ void sd_unmount();
void sd_end();
bool sd_is_gpt();
void *sd_file_read(const char *path, u32 *fsize);
int sd_save_to_file(void *buf, u32 size, const char *filename);
int sd_save_to_file(const void *buf, u32 size, const char *filename);
#endif

View File

@@ -46,7 +46,7 @@
/* OCR bit definitions */
#define SD_OCR_VDD_18 (1U << 7) /* VDD voltage 1.8 */
#define SD_VHD_27_36 (1U << 8) /* VDD voltage 2.7 ~ 3.6 */
#define SD_VHS_27_36 (1U << 8) /* VDD voltage 2.7 ~ 3.6 */
#define SD_OCR_VDD_32_33 (1U << 20) /* VDD voltage 3.2 ~ 3.3 */
#define SD_OCR_S18R (1U << 24) /* 1.8V switching request */
#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */

View File

@@ -34,7 +34,7 @@
u32 sd_power_cycle_time_start;
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
static inline u32 unstuff_bits(const u32 *resp, u32 start, u32 size)
{
const u32 mask = (size < 32 ? 1 << size : 0) - 1;
const u32 off = 3 - ((start) / 32);
@@ -234,6 +234,8 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
int sdmmc_storage_end(sdmmc_storage_t *storage)
{
DPRINTF("[SDMMC%d] end\n", storage->sdmmc->id);
if (!_sdmmc_storage_go_idle_state(storage))
return 0;
@@ -276,7 +278,7 @@ reinit_try:
// Disk IO failure! Reinit SD/EMMC to a lower speed.
if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4)
{
int res;
int res = 0;
if (storage->sdmmc->id == SDMMC_1)
{
@@ -782,7 +784,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp
}
#ifdef SDMMC_DEBUG_PRINT_SD_REGS
void _sd_storage_debug_print_cid(u32 *raw_cid)
void _sd_storage_debug_print_cid(const u32 *raw_cid)
{
gfx_printf("Card Identification\n");
@@ -798,7 +800,7 @@ void _sd_storage_debug_print_cid(u32 *raw_cid)
gfx_printf("--RSVD-- %X\n", unstuff_bits(raw_cid, 20, 4));
}
void _sd_storage_debug_print_csd(u32 *raw_csd)
void _sd_storage_debug_print_csd(const u32 *raw_csd)
{
gfx_printf("\n");
@@ -835,7 +837,7 @@ void _sd_storage_debug_print_csd(u32 *raw_csd)
unstuff_bits(raw_csd, 16, 5), unstuff_bits(raw_csd, 8, 2));
}
void _sd_storage_debug_print_scr(u32 *raw_scr)
void _sd_storage_debug_print_scr(const u32 *raw_scr)
{
u32 resp[4];
memcpy(&resp[2], raw_scr, 8);
@@ -856,7 +858,7 @@ void _sd_storage_debug_print_scr(u32 *raw_scr)
gfx_printf("--RSVD-- %X\n", unstuff_bits(resp, 36, 2));
}
void _sd_storage_debug_print_ssr(u8 *raw_ssr)
void _sd_storage_debug_print_ssr(const u8 *raw_ssr)
{
u32 raw_ssr0[4]; // 511:384.
u32 raw_ssr1[4]; // 383:256.
@@ -911,7 +913,7 @@ void _sd_storage_debug_print_ssr(u8 *raw_ssr)
static int _sd_storage_send_if_cond(sdmmc_storage_t *storage, bool *is_sdsc)
{
sdmmc_cmd_t cmdbuf;
u16 vhd_pattern = SD_VHD_27_36 | 0xAA;
u16 vhd_pattern = SD_VHS_27_36 | 0xAA;
sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, vhd_pattern, SDMMC_RSP_TYPE_5, 0);
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
{
@@ -1133,17 +1135,20 @@ static void _sd_storage_set_power_limit(sdmmc_storage_t *storage, u16 power_limi
u32 pwr = SD_SET_POWER_LIMIT_0_72;
// If UHS-I only, anything above 1.44W defaults to 1.44W.
/*
if (power_limit & SD_MAX_POWER_2_88)
pwr = SD_SET_POWER_LIMIT_2_88;
else if (power_limit & SD_MAX_POWER_2_16)
pwr = SD_SET_POWER_LIMIT_2_16;
else if (power_limit & SD_MAX_POWER_1_44)
*/
if (power_limit & SD_MAX_POWER_1_44)
pwr = SD_SET_POWER_LIMIT_1_44;
_sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_PWRLIM, pwr);
switch ((buf[15] >> 4) & 0x0F)
{
/*
case SD_SET_POWER_LIMIT_2_88:
DPRINTF("[SD] power limit raised to 2880 mW\n");
break;
@@ -1151,7 +1156,7 @@ static void _sd_storage_set_power_limit(sdmmc_storage_t *storage, u16 power_limi
case SD_SET_POWER_LIMIT_2_16:
DPRINTF("[SD] power limit raised to 2160 mW\n");
break;
*/
case SD_SET_POWER_LIMIT_1_44:
DPRINTF("[SD] power limit raised to 1440 mW\n");
break;
@@ -1397,7 +1402,7 @@ static int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u
}
// Try to raise the power limit to let the card perform better.
if (hs_type != UHS_SDR25_BUS_SPEED)
if (hs_type != UHS_SDR25_BUS_SPEED) // Not applicable for SDR12/SDR25.
_sd_storage_set_power_limit(storage, fmodes.power_limit, buf);
// Setup and set selected card and bus speed.
@@ -1425,9 +1430,6 @@ static int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
DPRINTF("[SD] access: %02X, power: %02X\n", fmodes.access_mode, fmodes.power_limit);
// Try to raise the power limit to let the card perform better.
_sd_storage_set_power_limit(storage, fmodes.power_limit, buf);
if (!(fmodes.access_mode & SD_MODE_HIGH_SPEED))
return 1;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2023 CTCaer
* Copyright (c) 2018-2024 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,
@@ -109,8 +109,8 @@ void sdmmc_save_tap_value(sdmmc_t *sdmmc)
static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type)
{
const u32 dqs_trim_val = 40; // 24 if HS533/HS667.
const u8 tap_values_t210[4] = { 4, 0, 3, 0 };
static const u32 dqs_trim_val = 40; // 24 if HS533/HS667.
static const u8 tap_values_t210[4] = { 4, 0, 3, 0 };
u32 tap_val = 0;
@@ -222,6 +222,9 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
{
sdmmc->regs->autocalcfg &= ~SDHCI_TEGRA_AUTOCAL_ENABLE;
_sdmmc_pad_config_fallback(sdmmc, power);
#ifdef ERROR_EXTRA_PRINTING
EPRINTFARGS("SDMMC%d: Comp Pad cal timeout!", sdmmc->id + 1);
#endif
}
// Disable E_INPUT (SD) or enable E_PWRD (eMMC) to conserve power.
@@ -403,7 +406,7 @@ static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc)
sdmmc->card_clock_enabled = 1;
}
static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc)
static void _sdmmc_card_clock_disable(sdmmc_t *sdmmc)
{
sdmmc->card_clock_enabled = 0;
sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;
@@ -572,7 +575,7 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc)
return 1;
}
static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present)
static int _sdmmc_send_cmd(sdmmc_t *sdmmc, const sdmmc_cmd_t *cmd, bool is_data_present)
{
u16 cmdflags = 0;
@@ -934,7 +937,7 @@ static u32 _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
if (norintsts & SDHCI_INT_ERROR)
{
#ifdef ERROR_EXTRA_PRINTING
EPRINTFARGS("SDMMC%d: norintsts %08X, errintsts %08X\n", sdmmc->id + 1, norintsts, errintsts);
EPRINTFARGS("SDMMC%d: norintsts %08X, errintsts %08X", sdmmc->id + 1, norintsts, errintsts);
#endif
sdmmc->regs->errintsts = errintsts;
return SDMMC_MASKINT_ERROR;
@@ -1022,7 +1025,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
return result;
}
static int _sdmmc_config_sdma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
static int _sdmmc_config_sdma(sdmmc_t *sdmmc, u32 *blkcnt_out, const sdmmc_req_t *req)
{
if (!req->blksize || !req->num_sectors)
return 0;
@@ -1152,7 +1155,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
int result = _sdmmc_wait_response(sdmmc);
#ifdef ERROR_EXTRA_PRINTING
if (!result)
EPRINTFARGS("SDMMC%d: Transfer timeout!", sdmmc->id + 1);
EPRINTFARGS("SDMMC%d: Transfer error!", sdmmc->id + 1);
#endif
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result,
sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3);
@@ -1273,16 +1276,7 @@ static int _sdmmc_config_sdmmc1(bool t210b01)
if (!sdmmc_get_sd_inserted())
return 0;
/*
* Pinmux config:
* DRV_TYPE = DRIVE_2X (for 33 Ohm driver)
* E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V)
* E_INPUT = ENABLE
* TRISTATE = PASSTHROUGH
* APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK
*/
// Enable deep loopback for SDMMC1 CLK pad.
// Enable deep loopback for SDMMC1 CLK pad so reads work.
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1;
// Configure SDMMC1 CLK pinmux, based on state and SoC type.
@@ -1302,18 +1296,18 @@ static int _sdmmc_config_sdmmc1(bool t210b01)
_sdmmc_config_sdmmc1_schmitt();
// Make sure the SDMMC1 controller is powered.
PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1_IO_EN;
PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1;
usleep(1000);
PMC(APBDEV_PMC_NO_IOPOWER) &= ~(PMC_NO_IOPOWER_SDMMC1_IO_EN);
PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_SDMMC1;
(void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write.
// Set enable SD card power.
// Enable SD card power. Powers LDO2 also.
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2;
gpio_direction_output(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH);
usleep(10000);
// Inform IO pads that voltage is gonna be 3.3V.
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN;
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_33V_SDMMC1;
(void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write.
// Enable SD card IO power.
@@ -1366,8 +1360,8 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type)
u16 divisor;
u8 vref_sel = 7;
const u8 trim_values_t210[4] = { 2, 8, 3, 8 };
const u8 trim_values_t210b01[4] = { 14, 13, 15, 13 };
static const u8 trim_values_t210[4] = { 2, 8, 3, 8 };
static const u8 trim_values_t210b01[4] = { 14, 13, 15, 13 };
const u8 *trim_values;
if (id > SDMMC_4 || id == SDMMC_3)
@@ -1403,19 +1397,18 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type)
// Disable clock if enabled.
if (clock_sdmmc_is_not_reset_and_enabled(id))
{
_sdmmc_sd_clock_disable(sdmmc);
_sdmmc_card_clock_disable(sdmmc);
_sdmmc_commit_changes(sdmmc);
}
// Configure and enable selected clock.
clock_sdmmc_get_card_clock_div(&clock, &divisor, type);
clock_sdmmc_enable(id, clock);
sdmmc->clock_stopped = 0;
// Make sure all sdmmc registers are reset.
_sdmmc_reset_all(sdmmc);
sdmmc->clock_stopped = 0;
// Set default pad IO trimming configuration.
sdmmc->regs->iospare |= BIT(19); // Enable 1 cycle delayed cmd_oen.
sdmmc->regs->veniotrimctl &= ~BIT(2); // Set Band Gap VREG to supply DLL.
@@ -1456,23 +1449,23 @@ void sdmmc1_disable_power()
// T210B01 WAR: Set pads to discharge state.
_sdmmc_config_sdmmc1_pads(true);
// Disable SD card IO power regulator.
// Disable SD card IO power.
max7762x_regulator_enable(REGULATOR_LDO2, false);
usleep(4000);
// Disable SD card IO power pin.
// Disable SD card power.
gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW);
// T210/T210B01 WAR: Set start timer for IO and Controller power discharge.
sd_power_cycle_time_start = get_tmr_ms();
usleep(1000); // To power cycle, min 1ms without power is needed.
usleep(10000); // To power cycle, min 1ms without power is needed.
// Disable SDMMC1 controller power.
PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1_IO_EN;
PMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1;
(void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write.
// Inform IO pads that next voltage might be 3.3V.
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN;
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_33V_SDMMC1;
(void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write.
// T210B01 WAR: Restore pads to reset state.
@@ -1486,7 +1479,7 @@ void sdmmc_end(sdmmc_t *sdmmc)
{
if (!sdmmc->clock_stopped)
{
_sdmmc_sd_clock_disable(sdmmc);
_sdmmc_card_clock_disable(sdmmc);
// Disable SDMMC power.
_sdmmc_set_io_power(sdmmc, SDMMC_POWER_OFF);
_sdmmc_commit_changes(sdmmc);
@@ -1547,7 +1540,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
usleep(150);
// Inform IO pads that we switched to 1.8V.
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(PMC_PWR_DET_SDMMC1_IO_EN);
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_33V_SDMMC1;
(void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write.
// Enable schmitt trigger for better duty cycle and low jitter clock.

View File

@@ -1,7 +1,7 @@
/*
* Fan driver for Nintendo Switch
*
* Copyright (c) 2018-2023 CTCaer
* Copyright (c) 2018-2024 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,
@@ -27,7 +27,7 @@
#include <soc/timer.h>
#include <soc/t210.h>
void set_fan_duty(u32 duty)
void fan_set_duty(u32 duty)
{
static bool fan_init = false;
static u16 curr_duty = -1;
@@ -49,16 +49,8 @@ void set_fan_duty(u32 duty)
// Enable PWM if disabled.
if (fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA)
{
// Ease the stress to APB.
bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
clock_enable_pwm();
// Restore OC.
bpmp_clk_rate_set(prev_fid);
}
PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Max PWM to disable fan.
PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1.
@@ -91,7 +83,7 @@ void set_fan_duty(u32 duty)
}
}
void get_fan_speed(u32 *duty, u32 *rpm)
void fan_get_speed(u32 *duty, u32 *rpm)
{
if (rpm)
{
@@ -122,3 +114,15 @@ void get_fan_speed(u32 *duty, u32 *rpm)
if (duty)
*duty = 236 - ((PWM(PWM_CONTROLLER_PWM_CSR_1) >> 16) & 0xFF);
}
void fan_set_from_temp(u32 temp)
{
if (temp >= 52)
fan_set_duty(102);
else if (temp >= 47)
fan_set_duty(76);
else if (temp >= 42)
fan_set_duty(51);
else if (temp <= 39)
fan_set_duty(0);
}

View File

@@ -1,7 +1,7 @@
/*
* Fan driver for Nintendo Switch
*
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2024 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,
@@ -22,8 +22,10 @@
#include <utils/types.h>
// Disable: 0 (0 RPM), min duty: 1 (960 RPM), max duty 235 (11000 RPM).
void set_fan_duty(u32 duty);
// Passing NULL ptr on either of the two, disables parsing of it.
void get_fan_speed(u32 *duty, u32 *rpm);
void fan_set_duty(u32 duty);
// Passing NULL ptr on either of the two, disables results.
void fan_get_speed(u32 *duty, u32 *rpm);
void fan_set_from_temp(u32 temp);
#endif /* __FAN_H_ */

View File

@@ -71,10 +71,16 @@ typedef struct _jc_cal_t
u16 cry_min;
} jc_cal_t;
enum {
INPUT_POLL_HAS_PACKET,
INPUT_POLL_NO_PACKET,
INPUT_POLL_EXIT,
};
static jc_cal_t jc_cal_ctx;
static usb_ops_t usb_ops;
static bool _jc_calibration(jc_gamepad_rpt_t *jc_pad)
static bool _jc_calibration(const jc_gamepad_rpt_t *jc_pad)
{
// Calibrate left stick.
if (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS)
@@ -119,22 +125,24 @@ static bool _jc_calibration(jc_gamepad_rpt_t *jc_pad)
return true;
}
static bool _jc_poll(gamepad_report_t *rpt)
static int _jc_poll(gamepad_report_t *rpt)
{
static gamepad_report_t prev_rpt = {0};
// Poll Joy-Con.
jc_gamepad_rpt_t *jc_pad = joycon_poll();
if (!jc_pad)
return false;
return INPUT_POLL_NO_PACKET;
// Exit emulation if Left stick and Home are pressed.
if (jc_pad->l3 && jc_pad->home)
return true;
return INPUT_POLL_EXIT;
if (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS || jc_cal_ctx.cr_step != JC_CAL_MAX_STEPS)
{
if (!_jc_calibration(jc_pad))
return false;
return INPUT_POLL_NO_PACKET;
}
// Re-calibrate on disconnection.
@@ -282,7 +290,12 @@ static bool _jc_poll(gamepad_report_t *rpt)
//rpt->btn13 = jc_pad->cap;
//rpt->btn14 = jc_pad->home;
return false;
if (!memcmp(rpt, &prev_rpt, sizeof(gamepad_report_t)))
return INPUT_POLL_NO_PACKET;
memcpy(&prev_rpt, rpt, sizeof(gamepad_report_t));
return INPUT_POLL_HAS_PACKET;
}
typedef struct _touchpad_report_t
@@ -351,12 +364,14 @@ static u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len)
static bool _hid_poll_jc(usb_ctxt_t *usbs)
{
if (_jc_poll((gamepad_report_t *)USB_EP_BULK_IN_BUF_ADDR))
int res = _jc_poll((gamepad_report_t *)USB_EP_BULK_IN_BUF_ADDR);
if (res == INPUT_POLL_EXIT)
return true;
// Send HID report.
if (_hid_transfer_start(usbs, sizeof(gamepad_report_t)))
return true; // EP Error.
if (res == INPUT_POLL_HAS_PACKET)
if (_hid_transfer_start(usbs, sizeof(gamepad_report_t)))
return true; // EP Error.
return false;
}

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2003-2008 Alan Stern
* Copyright (c) 2009 Samsung Electronics
* Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
* Copyright (c) 2019-2023 CTCaer
* Copyright (c) 2019-2024 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,
@@ -32,6 +32,7 @@
#include <storage/sdmmc_driver.h>
#include <utils/btn.h>
#include <utils/sprintf.h>
#include <utils/util.h>
#include <memory_map.h>
@@ -758,7 +759,7 @@ static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
buf += 4;
s_printf((char *)buf, "%04X%s",
ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC ");
ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC ");
switch (ums->lun.partition)
{
@@ -803,15 +804,15 @@ static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
break;
case EMMC_GPP + 1:
s_printf((char *)buf, "%s%s",
ums->lun.type == MMC_SD ? "SD " : "eMMC ", "GPP");
ums->lun.type == MMC_SD ? "SD " : "eMMC ", "GPP");
break;
case EMMC_BOOT0 + 1:
s_printf((char *)buf, "%s%s",
ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT0");
ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT0");
break;
case EMMC_BOOT1 + 1:
s_printf((char *)buf, "%s%s",
ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT1");
ums->lun.type == MMC_SD ? "SD " : "eMMC ", "BOOT1");
break;
}
@@ -1843,10 +1844,11 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
ums.bulk_ctxt.bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR;
// Set LUN parameters.
ums.lun.ro = usbs->ro;
ums.lun.type = usbs->type;
ums.lun.partition = usbs->partition;
ums.lun.offset = usbs->offset;
ums.lun.ro = usbs->ro;
ums.lun.type = usbs->type;
ums.lun.partition = usbs->partition;
ums.lun.num_sectors = usbs->sectors;
ums.lun.offset = usbs->offset;
ums.lun.removable = 1; // Always removable to force OSes to use prevent media removal.
ums.lun.unit_attention_data = SS_RESET_OCCURRED;
@@ -1899,10 +1901,14 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
ums.set_text(ums.label, "#C7EA46 状态:#开启UMS");
if (usbs->sectors)
ums.lun.num_sectors = usbs->sectors;
else
ums.lun.num_sectors = ums.lun.storage->sec_cnt;
// If partition sectors are not set get them from hardware.
if (!ums.lun.num_sectors)
{
if (usbs->type == MMC_EMMC && (ums.lun.partition - 1)) // eMMC BOOT0/1.
ums.lun.num_sectors = emmc_storage.ext_csd.boot_mult << 8;
else
ums.lun.num_sectors = ums.lun.storage->sec_cnt; // eMMC GPP or SD.
}
do
{
@@ -1932,7 +1938,9 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
_handle_ep0_ctrl(&ums);
if (_parse_scsi_cmd(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL))
_parse_scsi_cmd(&ums, &ums.bulk_ctxt);
if (ums.state > UMS_STATE_NORMAL)
continue;
_handle_ep0_ctrl(&ums);

View File

@@ -1,7 +1,7 @@
/*
* Enhanced USB Device (EDCI) driver for Tegra X1
*
* Copyright (c) 2019-2023 CTCaer
* Copyright (c) 2019-2024 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,
@@ -355,9 +355,15 @@ int usb_device_init()
if (usb_init_done)
return USB_RES_OK;
// Ease the stress to APB.
bpmp_clk_rate_relaxed(true);
// Initialize USB2 controller PHY.
_usb_init_phy();
// Restore OC.
bpmp_clk_rate_relaxed(false);
// AHB USB performance cfg.
AHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_DONT_SPLIT_AHB_WR | AHB_MEM_ENB_FAST_REARBITRATE;
AHB_GIZMO(AHB_GIZMO_USB) |= AHB_GIZMO_IMMEDIATE;

View File

@@ -1,7 +1,7 @@
/*
* eXtensible USB Device driver (XDCI) for Tegra X1
*
* Copyright (c) 2020-2022 CTCaer
* Copyright (c) 2020-2024 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,
@@ -883,6 +883,9 @@ static void _xusbd_init_device_clocks()
int xusb_device_init()
{
// Ease the stress to APB.
bpmp_clk_rate_relaxed(true);
// Disable USB2 device controller clocks.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_USBD);
@@ -920,6 +923,9 @@ int xusb_device_init()
// Initialize device clocks.
_xusbd_init_device_clocks();
// Restore OC.
bpmp_clk_rate_relaxed(false);
// Enable AHB redirect for access to IRAM for Event/EP ring buffers.
mc_enable_ahb_redirect();
@@ -1005,7 +1011,7 @@ static void _xusb_device_power_down()
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB);
}
static int _xusb_queue_trb(u32 ep_idx, void *trb, bool ring_doorbell)
static int _xusb_queue_trb(u32 ep_idx, const void *trb, bool ring_doorbell)
{
int res = USB_RES_OK;
data_trb_t *next_trb;
@@ -1220,7 +1226,7 @@ static int _xusb_wait_ep_stopped(u32 endpoint)
return USB_RES_OK;
}
static int _xusb_handle_transfer_event(transfer_event_trb_t *trb)
static int _xusb_handle_transfer_event(const transfer_event_trb_t *trb)
{
// Advance dequeue list.
data_trb_t *next_trb;
@@ -1455,7 +1461,7 @@ static int _xusb_handle_get_ep_status(u32 ep_idx)
return _xusb_issue_data_trb(xusb_ep_status_descriptor, 2, USB_DIR_IN);
}
static int _xusb_handle_get_class_request(usb_ctrl_setup_t *ctrl_setup)
static int _xusb_handle_get_class_request(const usb_ctrl_setup_t *ctrl_setup)
{
u8 _bRequest = ctrl_setup->bRequest;
u16 _wIndex = ctrl_setup->wIndex;
@@ -1486,7 +1492,7 @@ stall:
return USB_RES_OK;
}
static int _xusb_handle_get_descriptor(usb_ctrl_setup_t *ctrl_setup)
static int _xusb_handle_get_descriptor(const usb_ctrl_setup_t *ctrl_setup)
{
u32 size;
void *descriptor;
@@ -1615,7 +1621,7 @@ static int _xusb_handle_get_descriptor(usb_ctrl_setup_t *ctrl_setup)
return _xusb_issue_data_trb(descriptor, size, USB_DIR_IN);
}
static void _xusb_handle_set_request_dev_address(usb_ctrl_setup_t *ctrl_setup)
static void _xusb_handle_set_request_dev_address(const usb_ctrl_setup_t *ctrl_setup)
{
u32 addr = ctrl_setup->wValue & 0xFF;
@@ -1627,7 +1633,7 @@ static void _xusb_handle_set_request_dev_address(usb_ctrl_setup_t *ctrl_setup)
usbd_xotg->device_state = XUSB_ADDRESSED_STS_WAIT;
}
static void _xusb_handle_set_request_configuration(usb_ctrl_setup_t *ctrl_setup)
static void _xusb_handle_set_request_configuration(const usb_ctrl_setup_t *ctrl_setup)
{
usbd_xotg->config_num = ctrl_setup->wValue;

View File

@@ -17,21 +17,23 @@
#include <string.h>
#include <stdlib.h>
#include "dirlist.h"
#include <libs/fatfs/ff.h>
#include <mem/heap.h>
#include <utils/types.h>
#define MAX_ENTRIES 64
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs)
dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs)
{
int res = 0;
u32 i = 0, j = 0, k = 0;
u32 k = 0;
DIR dir;
FILINFO fno;
char *dir_entries = (char *)zalloc(MAX_ENTRIES * 256);
char *temp = (char *)zalloc(256);
dirlist_t *dir_entries = (dirlist_t *)malloc(sizeof(dirlist_t));
// Setup pointer tree.
for (u32 i = 0; i < DIR_MAX_ENTRIES; i++)
dir_entries->name[i] = &dir_entries->data[i * 256];
if (!pattern && !f_opendir(&dir, directory))
{
@@ -47,9 +49,8 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
{
if ((fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
strcpy(dir_entries + (k * 256), fno.fname);
k++;
if (k > (MAX_ENTRIES - 1))
strcpy(&dir_entries->data[k * 256], fno.fname);
if (++k >= DIR_MAX_ENTRIES)
break;
}
}
@@ -62,9 +63,8 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
{
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
strcpy(dir_entries + (k * 256), fno.fname);
k++;
if (k > (MAX_ENTRIES - 1))
strcpy(&dir_entries->data[k * 256], fno.fname);
if (++k >= DIR_MAX_ENTRIES)
break;
}
res = f_findnext(&dir, &fno);
@@ -74,27 +74,27 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
if (!k)
{
free(temp);
free(dir_entries);
return NULL;
}
// Terminate name list.
dir_entries->name[k] = NULL;
// Reorder ini files by ASCII ordering.
for (i = 0; i < k - 1 ; i++)
for (u32 i = 0; i < k - 1 ; i++)
{
for (j = i + 1; j < k; j++)
for (u32 j = i + 1; j < k; j++)
{
if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0)
if (strcmp(dir_entries->name[i], dir_entries->name[j]) > 0)
{
strcpy(temp, &dir_entries[i * 256]);
strcpy(&dir_entries[i * 256], &dir_entries[j * 256]);
strcpy(&dir_entries[j * 256], temp);
char *tmp = dir_entries->name[i];
dir_entries->name[i] = dir_entries->name[j];
dir_entries->name[j] = tmp;
}
}
}
free(temp);
return dir_entries;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2024 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,
@@ -16,4 +16,12 @@
#include <utils/types.h>
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs);
#define DIR_MAX_ENTRIES 64
typedef struct _dirlist_t
{
char *name[DIR_MAX_ENTRIES];
char data[DIR_MAX_ENTRIES * 256];
} dirlist_t;
dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs);

View File

@@ -53,7 +53,7 @@ ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type
return csec;
}
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
int ini_parse(link_t *dst, const char *ini_path, bool is_dir)
{
FIL fp;
u32 lblen;
@@ -62,7 +62,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
ini_sec_t *csec = NULL;
char *lbuf = NULL;
char *filelist = NULL;
dirlist_t *filelist = NULL;
char *filename = (char *)malloc(256);
strcpy(filename, ini_path);
@@ -85,9 +85,9 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
// Copy ini filename in path string.
if (is_dir)
{
if (filelist[k * 256])
if (filelist->name[k])
{
strcpy(filename + pathlen, &filelist[k * 256]);
strcpy(filename + pathlen, filelist->name[k]);
k++;
}
else

View File

@@ -43,7 +43,7 @@ typedef struct _ini_sec_t
u32 color;
} ini_sec_t;
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
int ini_parse(link_t *dst, const char *ini_path, bool is_dir);
char *ini_check_special_section(ini_sec_t *cfg);
void ini_free(link_t *src);

View File

@@ -28,10 +28,32 @@ static void _s_putc(char c)
*sout_buf += 1;
}
static void _s_puts(char *s)
static void _s_putspace(int fcnt)
{
if (fcnt <= 0)
return;
for (int i = 0; i < fcnt; i++)
_s_putc(' ');
}
static void _s_puts(char *s, char fill, int fcnt)
{
if (fcnt)
{
fcnt = fcnt - strlen(s);
// Left padding. Check if padding is not space based (dot counts as such).
if (fill != '.')
_s_putspace(fcnt);
}
for (; *s; s++)
_s_putc(*s);
// Right padding. Check if padding is space based (dot counts as such).
if (fill == '.')
_s_putspace(fcnt);
}
static void _s_putn(u32 v, int base, char fill, int fcnt)
@@ -75,9 +97,28 @@ static void _s_putn(u32 v, int base, char fill, int fcnt)
}
}
_s_puts(p);
_s_puts(p, 0, 0);
}
/*
* Padding:
* Numbers:
* %3d: Fill: ' ', Count: 3.
* % 3d: Fill: ' ', Count: 3.
* %.3d: Fill: '.', Count: 3.
* %23d: Fill: '2', Count: 3.
* % 23d: Fill: ' ', Count: 23.
* %223d: Fill: '2', Count: 23.
*
* Strings, Fill: ' ':
* %3s: Count: 5, Left.
* %23s: Count: 5, Left.
* %223s: Count: 25, Left.
* %.3s: Count: 5, Right.
* %.23s: Count: 25, Right.
* %.223s: Count: 225, Right.
*/
void s_printf(char *out_buf, const char *fmt, ...)
{
va_list ap;
@@ -94,8 +135,8 @@ void s_printf(char *out_buf, const char *fmt, ...)
fill = 0;
fcnt = 0;
// Check for padding. Number or space based.
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')
// Check for padding. Number or space based (dot count as space for string).
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ' || *fmt == '.')
{
fcnt = *fmt; // Padding size or padding type.
fmt++;
@@ -132,7 +173,7 @@ parse_padding_dec:
break;
case 's':
_s_puts(va_arg(ap, char *));
_s_puts(va_arg(ap, char *), fill, fcnt);
break;
case 'd':
@@ -221,7 +262,7 @@ parse_padding_dec:
break;
case 's':
_s_puts(va_arg(ap, char *));
_s_puts(va_arg(ap, char *), fill, fcnt);
break;
case 'd':

View File

@@ -21,7 +21,25 @@
#include <utils/types.h>
/*
* Padding:
* Numbers:
* %3d: Fill: ' ', Count: 3.
* % 3d: Fill: ' ', Count: 3.
* %23d: Fill: '2', Count: 3.
* % 23d: Fill: ' ', Count: 23.
* %223d: Fill: '2', Count: 23.
*
* Strings, Fill: ' ':
* %3s: Count: 5, Left.
* %23s: Count: 5, Left.
* %223s: Count: 25, Left.
* %.3s: Count: 5, Right.
* %.23s: Count: 25, Right.
* %.223s: Count: 225, Right.
*/
void s_printf(char *out_buf, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
void s_vprintf(char *out_buf, const char *fmt, va_list ap);
#endif
#endif

View File

@@ -98,10 +98,12 @@ typedef unsigned long uptr;
#define OFFSET_OF(t, m) ((uptr)&((t *)NULL)->m)
#define CONTAINER_OF(mp, t, mn) ((t *)((uptr)mp - OFFSET_OF(t, mn)))
#define byte_swap_16(num) ((((num) >> 8) & 0xff) | (((num) << 8) & 0xff00))
#define byte_swap_32(num) ((((num) >> 24) & 0xff) | (((num) << 8) & 0xff0000) | \
(((num) >> 8 ) & 0xff00) | (((num) << 24) & 0xff000000))
#define byte_swap_16(num) ((((num) >> 8) & 0xFF) | (((num) & 0xFF) << 8))
#define byte_swap_32(num) ((((num) >> 24) & 0xFF) | (((num) & 0xFF00) << 8 ) | \
(((num) >> 8 ) & 0xFF00) | (((num) & 0xFF) << 24))
#define likely(x) (__builtin_expect((x) != 0, 1))
#define unlikely(x) (__builtin_expect((x) != 0, 0))
/* Bootloader/Nyx */
#define BOOT_CFG_AUTOBOOT_EN BIT(0)

View File

@@ -29,8 +29,6 @@
#include <storage/sd.h>
#include <utils/util.h>
#define USE_RTC_TIMER
u8 bit_count(u32 val)
{
u8 cnt = 0;
@@ -197,10 +195,32 @@ int atoi(const char *nptr)
return (int)strtol(nptr, (char **)NULL, 10);
}
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
void reg_write_array(u32 *base, const reg_cfg_t *cfg, u32 num_cfg)
{
for (u32 i = 0; i < num_ops; i++)
base[ops[i].off] = ops[i].val;
// Expected register offset is a u32 array index.
for (u32 i = 0; i < num_cfg; i++)
base[cfg[i].idx] = cfg[i].val;
}
u16 crc16_calc(const u8 *buf, u32 len)
{
const u8 *p, *q;
u16 crc = 0x55aa;
static u16 table[16] = {
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
};
q = buf + len;
for (p = buf; p < q; p++)
{
u8 oct = *p;
crc = (crc >> 4) ^ table[crc & 0xf] ^ table[(oct >> 0) & 0xf];
crc = (crc >> 4) ^ table[crc & 0xf] ^ table[(oct >> 4) & 0xf];
}
return crc;
}
u32 crc32_calc(u32 crc, const u8 *buf, u32 len)
@@ -262,7 +282,7 @@ void power_set_state(power_state_t state)
sd_end();
// De-initialize and power down various hardware.
hw_reinit_workaround(false, 0);
hw_deinit(false, 0);
// Set power state.
switch (state)

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2022 CTCaer
* Copyright (c) 2018-2024 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,
@@ -21,8 +21,6 @@
#include <utils/types.h>
#include <mem/minerva.h>
#define CFG_SIZE(array) (sizeof(array) / sizeof(cfg_op_t))
#define NYX_NEW_INFO 0x3058594E
typedef enum
@@ -59,6 +57,12 @@ typedef struct _cfg_op_t
u32 val;
} cfg_op_t;
typedef struct _reg_cfg_t
{
u32 idx;
u32 val;
} reg_cfg_t;
typedef struct _nyx_info_t
{
u32 magic;
@@ -88,7 +92,9 @@ u64 sqrt64(u64 num);
long strtol(const char *nptr, char **endptr, register int base);
int atoi(const char *nptr);
void reg_write_array(u32 *base, const reg_cfg_t *cfg, u32 num_cfg);
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
u16 crc16_calc(const u8 *buf, u32 len);
u32 crc32_calc(u32 crc, const u8 *buf, u32 len);
void panic(u32 val);

View File

@@ -175,7 +175,7 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
hw_reinit_workaround(false, 0);
hw_deinit(false, 0);
(*sept)();

View File

@@ -138,12 +138,12 @@ int launch_payload(char *path)
{
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
hw_reinit_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
hw_deinit(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
}
else
{
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
hw_reinit_workaround(true, 0);
hw_deinit(true, 0);
}
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
@@ -233,7 +233,7 @@ void ipl_main()
pivot_stack(IPL_STACK_TOP);
// Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between.
heap_init(IPL_HEAP_START);
heap_init((void *)IPL_HEAP_START);
#ifdef DEBUG_UART_PORT
uart_send(DEBUG_UART_PORT, (u8 *)"hekate: Hello!\r\n", 16);
@@ -256,7 +256,7 @@ void ipl_main()
display_init();
u32 *fb = display_init_framebuffer_pitch();
u32 *fb = display_init_window_a_pitch();
gfx_init_ctxt(fb, 720, 1280, 720);
gfx_con_init();

View File

@@ -146,7 +146,7 @@ Vector_t runLexer(const char* in, u32 len) {
if (negative)
parse *= -1;
vecAddElement(&vec, makeLexarToken(IntLit, parse));
vecAddElement(&vec, makeLexarToken(IntLit, (char *)parse));
continue;
}
ELIFC('(') {