13 Commits

Author SHA1 Message Date
zdm65477730
1a6eea1ebf Delete .github/workflows/builder.yml 2025-11-21 23:29:06 +08:00
zdm65477730
22b32c2d3c Update main.yml 2025-11-21 23:28:29 +08:00
Damien Zhao
ec6518ccbf uplift libbdk
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2025-11-21 22:20:38 +08:00
Damien Zhao
3454c13e4a update main.yaml
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2025-05-16 18:39:36 +08:00
Damien Zhao
796a70aabc update workflow yaml
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2025-05-16 18:36:29 +08:00
Damien Zhao
099588665a add release workflow
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2025-05-16 18:14:00 +08:00
Damien Zhao
246486a46e update bdk
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2025-05-13 19:49:02 +08:00
Damien Zhao
22b1fda1d5 uplift bdk
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2024-10-21 16:21:40 +08:00
Damien Zhao
cd38dbc1ae restore fonts
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2024-04-13 12:38:24 +08:00
Damien Zhao
029b32f722 uplift bdk
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2024-04-13 12:27:17 +08:00
Damien Zhao
cf9ec7683b min update
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2023-04-02 17:26:51 +08:00
Damien Zhao
a093a1fbba min update
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2023-04-02 16:37:24 +08:00
Damien Zhao
c9b22b2a36 uplift bdk
Signed-off-by: Damien Zhao <zdm65477730@126.com>
2023-04-02 13:21:57 +08:00
165 changed files with 9856 additions and 4246 deletions

View File

@@ -1,19 +0,0 @@
name: PCR builder
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
container: devkitpro/devkita64_devkitarm
steps:
- uses: actions/checkout@v1
- name: Build PCR
run: make -j$(nproc)
- uses: actions/upload-artifact@master
with:
name: CommonProblemResolver
path: output/CommonProblemResolver.bin

52
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: Release
on:
issue_comment:
types: [ created ]
jobs:
build_and_release:
name: Build and release
runs-on: ubuntu-latest
container: devkitpro/devkita64:latest
if: contains(github.event.comment.body, '/release-action')
steps:
- name: Update latest libnx
run: |
git config --global --add safe.directory "*"
git clone --recurse-submodules https://github.com/zdm65477730/libnx.git
cd libnx
make install -j$(nproc)
shell: bash
- name: Checkout latest code
uses: actions/checkout@v5
with:
ref: master
clean: true
fetch-depth: 0
fetch-tags: true
submodules: recursive
- name: Setup ENV parameters
run: |
VER_FILE=Makefile
VERSION=$(awk '/^LPVERSION_MAJOR/{print $3}' $VER_FILE).$(awk '/^LPVERSION_MINOR/{print $3}' $VER_FILE).$(awk '/^LPVERSION_BUGFX/{print $3}' $VER_FILE)
echo "TAG=${VERSION}" >> "${GITHUB_ENV}"
echo "RELEASE_NAME=CommonProblemResolver ${VERSION}" >> "${GITHUB_ENV}"
shell: bash
- name: Build
run: |
export DEVKITPRO=/opt/devkitpro
make all
shell: bash
- name: Upload Release Asset
uses: softprops/action-gh-release@v2.0.9
with:
name: ${{ env.RELEASE_NAME }}
tag_name: ${{ env.TAG }}
draft: false
prerelease: false
generate_release_notes: yes
make_latest: true
files: |
output/CommonProblemResolver.bin

View File

@@ -24,7 +24,7 @@
#include <input/als.h> #include <input/als.h>
#include <input/joycon.h> #include <input/joycon.h>
#include <input/touch.h> #include <input/touch.h>
#include <mem/emc.h> #include <mem/emc_t210.h>
#include <mem/heap.h> #include <mem/heap.h>
#include <mem/mc.h> #include <mem/mc.h>
#include <mem/minerva.h> #include <mem/minerva.h>
@@ -49,6 +49,7 @@
#include <soc/gpio.h> #include <soc/gpio.h>
#include <soc/hw_init.h> #include <soc/hw_init.h>
#include <soc/i2c.h> #include <soc/i2c.h>
#include <soc/irq.h>
#include <soc/kfuse.h> #include <soc/kfuse.h>
#include <soc/pinmux.h> #include <soc/pinmux.h>
#include <soc/pmc.h> #include <soc/pmc.h>
@@ -57,7 +58,7 @@
#include <soc/uart.h> #include <soc/uart.h>
#include <storage/emmc.h> #include <storage/emmc.h>
#include <storage/mbr_gpt.h> #include <storage/mbr_gpt.h>
#include <storage/mmc.h> #include <storage/mmc_def.h>
#include <storage/nx_emmc_bis.h> #include <storage/nx_emmc_bis.h>
#include <storage/ramdisk.h> #include <storage/ramdisk.h>
#include <storage/sd.h> #include <storage/sd.h>
@@ -71,9 +72,11 @@
#include <utils/ini.h> #include <utils/ini.h>
#include <utils/list.h> #include <utils/list.h>
#include <utils/sprintf.h> #include <utils/sprintf.h>
#include <utils/tegra_bct.h>
#include <utils/tegra_bit.h>
#include <utils/types.h> #include <utils/types.h>
#include <utils/util.h> #include <utils/util.h>
#include <gfx_utils.h> #include <gfx_utils.h>
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2023 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -20,7 +20,6 @@
#include "di.h" #include "di.h"
#include <power/max77620.h> #include <power/max77620.h>
#include <power/max7762x.h> #include <power/max7762x.h>
#include <mem/heap.h>
#include <soc/clock.h> #include <soc/clock.h>
#include <soc/fuse.h> #include <soc/fuse.h>
#include <soc/gpio.h> #include <soc/gpio.h>
@@ -37,11 +36,31 @@
extern volatile nyx_storage_t *nyx_str; extern volatile nyx_storage_t *nyx_str;
static u32 _display_id = 0; static u32 _display_id = 0;
static u32 _dsi_bl = -1; static u32 _dsi_bl = -1;
static bool _nx_aula = false; static bool _nx_aula = false;
static void _display_panel_and_hw_end(bool no_panel_deinit); static void _display_panel_and_hw_end(bool no_panel_deinit);
void display_enable_interrupt(u32 intr)
{
DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) |= intr;
}
void display_disable_interrupt(u32 intr)
{
DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) &= ~intr;
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = intr;
}
void display_wait_interrupt(u32 intr)
{
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = 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) static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
{ {
u32 end = get_tmr_us() + timeout; u32 end = get_tmr_us() + timeout;
@@ -64,22 +83,18 @@ static void _display_dsi_wait_vblank(bool enable)
if (enable) if (enable)
{ {
// Enable vblank interrupt. // Enable vblank interrupt.
DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = DC_CMD_INT_FRAME_END_INT; display_enable_interrupt(DC_CMD_INT_FRAME_END_INT);
// Use the 4th line to transmit the host cmd packet. // Use the 4th line to transmit the host cmd packet.
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE | DSI_DSI_LINE_TYPE(4); DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = DSI_CMD_PKT_VID_ENABLE | DSI_DSI_LINE_TYPE(4);
// Wait for vblank before starting the transfer. // Wait for vblank before starting the transfer.
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. display_wait_interrupt(DC_CMD_INT_FRAME_END_INT);
while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT))
;
} }
else else
{ {
// Wait for vblank before reseting sync points. // Wait for vblank before resetting sync points.
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT; // Clear interrupt. display_wait_interrupt(DC_CMD_INT_FRAME_END_INT);
while (!(DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) & DC_CMD_INT_FRAME_END_INT))
;
usleep(14); usleep(14);
// Reset all states of syncpt block. // Reset all states of syncpt block.
@@ -94,8 +109,7 @@ static void _display_dsi_wait_vblank(bool enable)
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
// Disable and clear vblank interrupt. // Disable and clear vblank interrupt.
DISPLAY_A(_DIREG(DC_CMD_INT_ENABLE)) = 0; display_disable_interrupt(DC_CMD_INT_FRAME_END_INT);
DISPLAY_A(_DIREG(DC_CMD_INT_STATUS)) = DC_CMD_INT_FRAME_END_INT;
} }
} }
@@ -117,7 +131,6 @@ static void _display_dsi_read_rx_fifo(u32 *data)
int display_dsi_read(u8 cmd, u32 len, void *data) int display_dsi_read(u8 cmd, u32 len, void *data)
{ {
int res = 0;
u32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0}; u32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0};
// Drain RX FIFO. // Drain RX FIFO.
@@ -166,14 +179,13 @@ int display_dsi_read(u8 cmd, u32 len, void *data)
case ACK_ERROR_RES: case ACK_ERROR_RES:
default: default:
res = 1; return 1;
break;
} }
} }
else else
res = 1; return 1;
return res; return 0;
} }
int display_dsi_vblank_read(u8 cmd, u32 len, void *data) int display_dsi_vblank_read(u8 cmd, u32 len, void *data)
@@ -250,16 +262,9 @@ int display_dsi_vblank_read(u8 cmd, u32 len, void *data)
void display_dsi_write(u8 cmd, u32 len, void *data) void display_dsi_write(u8 cmd, u32 len, void *data)
{ {
static u8 *fifo8 = NULL;
static u32 *fifo32 = NULL;
u32 host_control; u32 host_control;
u32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0};
// Allocate fifo buffer. u8 *fifo8 = (u8 *)fifo32;
if (!fifo32)
{
fifo32 = malloc(DSI_STATUS_RX_FIFO_SIZE * 8 * sizeof(u32));
fifo8 = (u8 *)fifo32;
}
// Prepare data for long write. // Prepare data for long write.
if (len >= 2) if (len >= 2)
@@ -304,15 +309,8 @@ void display_dsi_write(u8 cmd, u32 len, void *data)
void display_dsi_vblank_write(u8 cmd, u32 len, void *data) void display_dsi_vblank_write(u8 cmd, u32 len, void *data)
{ {
static u8 *fifo8 = NULL; u32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0};
static u32 *fifo32 = NULL; u8 *fifo8 = (u8 *)fifo32;
// Allocate fifo buffer.
if (!fifo32)
{
fifo32 = malloc(DSI_STATUS_RX_FIFO_SIZE * 8 * sizeof(u32));
fifo8 = (u8 *)fifo32;
}
// Prepare data for long write. // Prepare data for long write.
if (len >= 2) if (len >= 2)
@@ -358,24 +356,10 @@ void display_init()
// Get Chip ID. // Get Chip ID.
bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;
// T210B01: Power on SD2 regulator for supplying LDO0. // Enable DSI AVDD.
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.
max7762x_regulator_set_voltage(REGULATOR_LDO0, 1200000); max7762x_regulator_set_voltage(REGULATOR_LDO0, 1200000);
max7762x_regulator_enable(REGULATOR_LDO0, true); 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. // 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_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); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI);
@@ -383,12 +367,12 @@ void display_init()
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_DISP1); 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_ENB_X_SET) = BIT(CLK_X_UART_FST_MIPI_CAL);
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz). CLOCK(CLK_RST_CONTROLLER_CLK_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_ENB_W_SET) = BIT(CLK_W_DSIA_LP);
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = CLK_SRC_DIV(6); // Set PLLP_OUT and div 6 (68MHz).
// Bring every IO rail out of deep power down. // Bring every IO rail out of deep power down. (Though no rail bit is set.)
PMC(APBDEV_PMC_IO_DPD_REQ) = PMC_IO_DPD_REQ_DPD_OFF; PMC(APBDEV_PMC_IO_DPD_REQ) = PMC_IO_DPD_REQ_DPD_OFF;
PMC(APBDEV_PMC_IO_DPD2_REQ) = PMC_IO_DPD_REQ_DPD_OFF; PMC(APBDEV_PMC_IO_DPD2_REQ) = PMC_IO_DPD_REQ_DPD_OFF;
@@ -427,32 +411,25 @@ void display_init()
APB_MISC(APB_MISC_GP_DSI_PAD_CONTROL) = 0; APB_MISC(APB_MISC_GP_DSI_PAD_CONTROL) = 0;
} }
// Set DISP1 clock source, parent clock and DSI/PCLK to low power mode. // Set DISP1 clock source, parent clock and DSI/PCLK to command mode.
// T210: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-PCLK): 50.0 MHz. (PCLK: 16.66 MHz) // T210: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-BCLK): 50.0 MHz. (PCLK: 16.66 MHz)
// T210B01: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 97.8 MHz, PLLD_OUT0 (DSI-PCLK): 48.9 MHz. (PCLK: 16.30 MHz) // T210B01: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 97.8 MHz, PLLD_OUT0 (DSI-BCLK): 48.9 MHz. (PCLK: 16.30 MHz)
clock_enable_plld(3, 20, true, tegra_t210); clock_enable_plld(3, 20, true, tegra_t210);
// Setup Display Interface initial window configuration. // 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. // Setup dsi init sequence packets.
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_irq_pkt_config0, CFG_SIZE(_di_dsi_init_irq_pkt_config0)); reg_write_array((u32 *)DSI_BASE, _di_dsi_seq_pkt_reset_config0, ARRAY_SIZE(_di_dsi_seq_pkt_reset_config0));
if (tegra_t210) DSI(_DSIREG(tegra_t210 ? DSI_INIT_SEQ_DATA_15 : DSI_INIT_SEQ_DATA_15_B01)) = 0;
DSI(_DSIREG(DSI_INIT_SEQ_DATA_15)) = 0; reg_write_array((u32 *)DSI_BASE, _di_dsi_seq_pkt_reset_config1, ARRAY_SIZE(_di_dsi_seq_pkt_reset_config1));
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));
// Reset pad trimmers for T210B01. // Reset pad trimmers for T210B01.
if (!tegra_t210) 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. // Setup init seq packet lengths, timings and power on DSI.
exec_cfg((u32 *)DSI_BASE, _di_dsi_init_timing_pkt_config2, CFG_SIZE(_di_dsi_init_timing_pkt_config2)); reg_write_array((u32 *)DSI_BASE, _di_dsi_init_config, ARRAY_SIZE(_di_dsi_init_config));
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));
usleep(10000); usleep(10000);
// Enable LCD Reset. // Enable LCD Reset.
@@ -490,9 +467,9 @@ void display_init()
{ {
case PANEL_SAM_AMS699VC01: case PANEL_SAM_AMS699VC01:
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000); _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, _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. // Enable backlight and smooth PWM.
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, _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); MIPI_DCS_SET_CONTROL_DISPLAY | ((DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL | DCS_CONTROL_DISPLAY_DIMMING_CTRL) << 8), 0);
@@ -522,7 +499,7 @@ void display_init()
break; break;
case PANEL_JDI_XXX062M: 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); _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000);
break; break;
@@ -558,26 +535,29 @@ void display_init()
// Unblank display. // Unblank display.
_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000); _display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000);
// Setup final dsi clock. // Switch to DSI HS mode.
// DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 468.0 MHz, PLLD_OUT0 (DSI): 234.0 MHz. // DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 468.0 MHz, PLLD_OUT0 (DSI-BCLK): 234.0 MHz. (PCLK: 78 MHz)
clock_enable_plld(1, 24, false, tegra_t210); clock_enable_plld(1, 24, false, tegra_t210);
// Finalize DSI init packet sequence configuration. // Set HS PHY timing and finalize DSI packet sequence configuration.
DSI(_DSIREG(DSI_PAD_CONTROL_1)) = 0; 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));
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));
// Set 1-by-1 pixel/clock and pixel clock to 234 / 3 = 78 MHz. For 60 Hz refresh rate. // 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. DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4); // 4: div3.
// Set DSI mode. // Set DSI mode to HOST.
exec_cfg((u32 *)DSI_BASE, _di_dsi_mode_config, CFG_SIZE(_di_dsi_mode_config)); reg_write_array((u32 *)DSI_BASE, _di_dsi_host_mode_config, ARRAY_SIZE(_di_dsi_host_mode_config));
usleep(10000); usleep(10000);
// Calibrate display communication pads. /*
u32 loops = tegra_t210 ? 1 : 2; // Calibrate pads 2 times on T210B01. * Calibrate display communication pads.
exec_cfg((u32 *)MIPI_CAL_BASE, _di_mipi_pad_cal_config, CFG_SIZE(_di_mipi_pad_cal_config)); * When switching to the 16ff pad brick, the clock lane termination control
for (u32 i = 0; i < loops; i++) * 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 on T210B01. 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. // Set MIPI bias pad config.
MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0x10010; MIPI_CAL(_DSIREG(MIPI_CAL_MIPI_BIAS_PAD_CFG2)) = 0x10010;
@@ -586,22 +566,25 @@ void display_init()
// Set pad trimmers and set MIPI DSI cal offsets. // Set pad trimmers and set MIPI DSI cal offsets.
if (tegra_t210) if (tegra_t210)
{ {
exec_cfg((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210, CFG_SIZE(_di_dsi_pad_cal_config_t210)); reg_write_array((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210, ARRAY_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 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_prod_config_t210, ARRAY_SIZE(_di_mipi_dsi_cal_prod_config_t210));
} }
else else
{ {
exec_cfg((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210b01, CFG_SIZE(_di_dsi_pad_cal_config_t210b01)); reg_write_array((u32 *)DSI_BASE, _di_dsi_pad_cal_config_t210b01, ARRAY_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 *)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. // Reset all unused MIPI cal offsets.
exec_cfg((u32 *)MIPI_CAL_BASE, _di_mipi_start_dsi_cal_config, CFG_SIZE(_di_mipi_start_dsi_cal_config)); 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); usleep(10000);
// Enable video display controller. // 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() void display_backlight_pwm_init()
@@ -609,12 +592,15 @@ void display_backlight_pwm_init()
if (_display_id == PANEL_SAM_AMS699VC01) if (_display_id == PANEL_SAM_AMS699VC01)
return; return;
// Enable PWM clock.
clock_enable_pwm(); clock_enable_pwm();
// Enable PWM and set it to 25KHz PFM. 29.5KHz is stock. // Enable PWM and set it to 25KHz PFM. 29.5KHz is stock.
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; 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. 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. gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
} }
@@ -635,9 +621,9 @@ static void _display_dsi_backlight_brightness(u32 duty)
u16 bl_ctrl = byte_swap_16((u16)candela); u16 bl_ctrl = byte_swap_16((u16)candela);
display_dsi_vblank_write(MIPI_DCS_SET_BRIGHTNESS, 2, &bl_ctrl); 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) if (!duty)
usleep(120000); usleep(100000);
_dsi_bl = duty; _dsi_bl = duty;
} }
@@ -681,7 +667,10 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
u32 display_get_backlight_brightness() 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) static void _display_panel_and_hw_end(bool no_panel_deinit)
@@ -698,22 +687,23 @@ 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; 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). // 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. // 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; DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
// De-initialize video controller. // 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. // Set DISP1 clock source, parent clock and DSI/PCLK to command mode.
// T210: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-PCLK): 50.0 MHz. (PCLK: 16.66 MHz) // T210: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-BCLK): 50.0 MHz. (PCLK: 16.66 MHz)
// T210B01: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 97.8 MHz, PLLD_OUT0 (DSI-PCLK): 48.9 MHz. (PCLK: 16.30 MHz) // T210B01: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 97.8 MHz, PLLD_OUT0 (DSI-BCLK): 48.9 MHz. (PCLK: 16.30 MHz)
clock_enable_plld(3, 20, true, hw_get_chip_id() == GP_HIDREV_MAJOR_T210); clock_enable_plld(3, 20, true, hw_get_chip_id() == GP_HIDREV_MAJOR_T210);
// Set timings for lowpower clocks. // 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) if (_display_id != PANEL_SAM_AMS699VC01)
usleep(10000); usleep(10000);
@@ -722,11 +712,12 @@ static void _display_panel_and_hw_end(bool no_panel_deinit)
switch (_display_id) switch (_display_id)
{ {
case PANEL_JDI_XXX062M: 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; break;
case PANEL_AUO_A062TAN01: 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; break;
case PANEL_INL_2J055IA_27A: case PANEL_INL_2J055IA_27A:
@@ -781,6 +772,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_1, GPIO_LOW); // LCD AVDD -5.4V disable.
gpio_write(GPIO_PORT_I, GPIO_PIN_0, 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); usleep(10000);
@@ -795,14 +790,7 @@ skip_panel_deinit:
DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
// Switch LCD PWM backlight pin to special function mode and enable PWM0 mode. // Disable DSI AVDD.
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.
max7762x_regulator_enable(REGULATOR_LDO0, false); max7762x_regulator_enable(REGULATOR_LDO0, false);
} }
@@ -831,14 +819,15 @@ void display_set_decoded_panel_id(u32 id)
void display_color_screen(u32 color) 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. // 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_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. usleep(35000); // Wait 2 frames. No need on Aula.
if (_display_id != PANEL_SAM_AMS699VC01) if (_display_id != PANEL_SAM_AMS699VC01)
@@ -847,58 +836,108 @@ void display_color_screen(u32 color)
display_backlight_brightness(150, 0); display_backlight_brightness(150, 0);
} }
u32 *display_init_framebuffer_pitch() u32 *display_init_window_a_pitch()
{ {
// Sanitize framebuffer area. // Sanitize framebuffer area.
memset((u32 *)IPL_FB_ADDRESS, 0, IPL_FB_SZ); memset((u32 *)IPL_FB_ADDRESS, 0, IPL_FB_SZ);
// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 720x1280 (line stride 720). // 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. //usleep(35000); // Wait 2 frames. No need on Aula.
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); 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). // This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280 (line stride 720).
if (_display_id != PANEL_SAM_AMS699VC01) if (_display_id != PANEL_SAM_AMS699VC01)
usleep(8000); // Wait half frame for PWM to apply. 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) if (_display_id != PANEL_SAM_AMS699VC01)
usleep(35000); // Wait 2 frames. usleep(35000); // Wait 2 frames.
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); 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). // 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. usleep(35000); // Wait 2 frames. No need on Aula.
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); 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. // 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. usleep(35000); // Wait 2 frames. No need on Aula.
return (u32 *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR)); 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). // 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)); 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. // Select window D.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT;
@@ -927,12 +966,9 @@ void display_activate_console()
// Arm and activate changes. // Arm and activate changes.
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; 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; 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. // Select window D.
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT; DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = WINDOW_D_SELECT;
@@ -950,18 +986,15 @@ void display_deactivate_console()
} }
// Disable window D. // 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; DISPLAY_A(_DIREG(DC_WIN_WIN_OPTIONS)) = 0;
// Arm and activate changes. // Arm and activate changes.
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_UPDATE | WIN_D_UPDATE; 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; 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. // Setup cursor.
DISPLAY_A(_DIREG(DC_DISP_CURSOR_START_ADDR)) = CURSOR_CLIPPING(CURSOR_CLIP_WIN_A) | size | ((u32)crs_fb >> 10); DISPLAY_A(_DIREG(DC_DISP_CURSOR_START_ADDR)) = CURSOR_CLIPPING(CURSOR_CLIP_WIN_A) | size | ((u32)crs_fb >> 10);
@@ -977,7 +1010,7 @@ void display_init_cursor(void *crs_fb, u32 size)
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; 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. // Set cursor position.
DISPLAY_A(_DIREG(DC_DISP_CURSOR_POSITION)) = x | (y << 16); DISPLAY_A(_DIREG(DC_DISP_CURSOR_POSITION)) = x | (y << 16);
@@ -987,7 +1020,7 @@ void display_set_pos_cursor(u32 x, u32 y)
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = GENERAL_ACT_REQ | CURSOR_ACT_REQ; 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_BLEND_CURSOR_CONTROL)) = 0;
DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) &= ~CURSOR_ENABLE; DISPLAY_A(_DIREG(DC_DISP_DISP_WIN_OPTIONS)) &= ~CURSOR_ENABLE;

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2023 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -24,6 +24,11 @@
#define DSI_VIDEO_DISABLED 0 #define DSI_VIDEO_DISABLED 0
#define DSI_VIDEO_ENABLED 1 #define DSI_VIDEO_ENABLED 1
#define WINDOW_A 0
#define WINDOW_B 1
#define WINDOW_C 2
#define WINDOW_D 3
/*! Display registers. */ /*! Display registers. */
#define _DIREG(reg) ((reg) * 4) #define _DIREG(reg) ((reg) * 4)
@@ -43,8 +48,8 @@
// DC_CMD non-shadowed command/sync registers. // DC_CMD non-shadowed command/sync registers.
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00 #define DC_CMD_GENERAL_INCR_SYNCPT 0x00
#define SYNCPT_GENERAL_INDX(x) (((x) & 0xff) << 0) #define SYNCPT_GENERAL_INDX(x) (((x) & 0xFF) << 0)
#define SYNCPT_GENERAL_COND(x) (((x) & 0xff) << 8) #define SYNCPT_GENERAL_COND(x) (((x) & 0xFF) << 8)
#define COND_REG_WR_SAFE 3 #define COND_REG_WR_SAFE 3
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01
@@ -52,7 +57,7 @@
#define SYNCPT_CNTRL_NO_STALL BIT(8) #define SYNCPT_CNTRL_NO_STALL BIT(8)
#define DC_CMD_CONT_SYNCPT_VSYNC 0x28 #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 SYNCPT_VSYNC_ENABLE BIT(8)
#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 #define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
@@ -77,19 +82,24 @@
#define DC_CMD_INT_ENABLE 0x39 #define DC_CMD_INT_ENABLE 0x39
#define DC_CMD_INT_FRAME_END_INT BIT(1) #define DC_CMD_INT_FRAME_END_INT BIT(1)
#define DC_CMD_INT_V_BLANK_INT BIT(2) #define DC_CMD_INT_V_BLANK_INT BIT(2)
#define DC_CMD_INT_POLARITY 0x3B
#define DC_CMD_STATE_ACCESS 0x40 #define DC_CMD_STATE_ACCESS 0x40
#define READ_MUX BIT(0) #define READ_MUX_ASSEMBLY 0x0
#define WRITE_MUX BIT(2) #define WRITE_MUX_ASSEMBLY 0x0
#define READ_MUX_ACTIVE BIT(0)
#define WRITE_MUX_ACTIVE BIT(2)
#define DC_CMD_STATE_CONTROL 0x41 #define DC_CMD_STATE_CONTROL 0x41
#define GENERAL_ACT_REQ BIT(0) #define GENERAL_ACT_REQ BIT(0)
#define WIN_ACT_REQ 1
#define WIN_A_ACT_REQ BIT(1) #define WIN_A_ACT_REQ BIT(1)
#define WIN_B_ACT_REQ BIT(2) #define WIN_B_ACT_REQ BIT(2)
#define WIN_C_ACT_REQ BIT(3) #define WIN_C_ACT_REQ BIT(3)
#define WIN_D_ACT_REQ BIT(4) #define WIN_D_ACT_REQ BIT(4)
#define CURSOR_ACT_REQ BIT(7) #define CURSOR_ACT_REQ BIT(7)
#define GENERAL_UPDATE BIT(8) #define GENERAL_UPDATE BIT(8)
#define WIN_UPDATE 9
#define WIN_A_UPDATE BIT(9) #define WIN_A_UPDATE BIT(9)
#define WIN_B_UPDATE BIT(10) #define WIN_B_UPDATE BIT(10)
#define WIN_C_UPDATE BIT(11) #define WIN_C_UPDATE BIT(11)
@@ -98,6 +108,7 @@
#define NC_HOST_TRIG BIT(24) #define NC_HOST_TRIG BIT(24)
#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42 #define DC_CMD_DISPLAY_WINDOW_HEADER 0x42
#define WINDOW_SELECT 4
#define WINDOW_A_SELECT BIT(4) #define WINDOW_A_SELECT BIT(4)
#define WINDOW_B_SELECT BIT(5) #define WINDOW_B_SELECT BIT(5)
#define WINDOW_C_SELECT BIT(6) #define WINDOW_C_SELECT BIT(6)
@@ -137,6 +148,31 @@
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) #define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
#define LSC0_OUTPUT_POLARITY_LOW BIT(24) #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 #define DC_COM_DSC_TOP_CTL 0x33E
// DC_DISP shadowed registers. // DC_DISP shadowed registers.
@@ -153,30 +189,30 @@
#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 #define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404
#define DC_DISP_DISP_TIMING_OPTIONS 0x405 #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 DC_DISP_REF_TO_SYNC 0x406
#define H_REF_TO_SYNC(x) (((x) & 0x1fff) << 0) // Min 0 pixel 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 V_REF_TO_SYNC(x) (((x) & 0x1FFF) << 16) // Min 1 line clock.
#define DC_DISP_SYNC_WIDTH 0x407 #define DC_DISP_SYNC_WIDTH 0x407
#define H_SYNC_WIDTH(x) (((x) & 0x1fff) << 0) // Min 1 pixel 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 V_SYNC_WIDTH(x) (((x) & 0x1FFF) << 16) // Min 1 line clock.
#define DC_DISP_BACK_PORCH 0x408 #define DC_DISP_BACK_PORCH 0x408
#define H_BACK_PORCH(x) (((x) & 0x1fff) << 0) #define H_BACK_PORCH(x) (((x) & 0x1FFF) << 0)
#define V_BACK_PORCH(x) (((x) & 0x1fff) << 16) #define V_BACK_PORCH(x) (((x) & 0x1FFF) << 16)
#define DC_DISP_ACTIVE 0x409 #define DC_DISP_ACTIVE 0x409
#define H_DISP_ACTIVE(x) (((x) & 0x1fff) << 0) // Min 16 pixel 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 V_DISP_ACTIVE(x) (((x) & 0x1FFF) << 16) // Min 16 line clock.
#define DC_DISP_FRONT_PORCH 0x40A #define DC_DISP_FRONT_PORCH 0x40A
#define H_FRONT_PORCH(x) (((x) & 0x1fff) << 0) // Min -=PS_=-H_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 V_FRONT_PORCH(x) (((x) & 0x1FFF) << 16) // Min -=PS_=-V_REF_TO_SYNC + 1
#define DC_DISP_DISP_CLOCK_CONTROL 0x42E #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_PCD1 (0 << 8)
#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) #define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) #define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
@@ -207,11 +243,7 @@
#define DISP_ORDER_BLUE_RED (1 << 9) #define DISP_ORDER_BLUE_RED (1 << 9)
#define DC_DISP_DISP_COLOR_CONTROL 0x430 #define DC_DISP_DISP_COLOR_CONTROL 0x430
#define DITHER_CONTROL_MASK (3 << 8) #define BASE_COLOR_SIZE_MASK (0xF << 0)
#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_666 (0 << 0) #define BASE_COLOR_SIZE_666 (0 << 0)
#define BASE_COLOR_SIZE_111 (1 << 0) #define BASE_COLOR_SIZE_111 (1 << 0)
#define BASE_COLOR_SIZE_222 (2 << 0) #define BASE_COLOR_SIZE_222 (2 << 0)
@@ -221,6 +253,13 @@
#define BASE_COLOR_SIZE_565 (6 << 0) #define BASE_COLOR_SIZE_565 (6 << 0)
#define BASE_COLOR_SIZE_332 (7 << 0) #define BASE_COLOR_SIZE_332 (7 << 0)
#define BASE_COLOR_SIZE_888 (8 << 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 DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
#define SC0_H_QUALIFIER_NONE BIT(0) #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 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 0x43E
#define DC_DISP_CURSOR_START_ADDR_NS 0x43F
#define CURSOR_CLIPPING(w) ((w) << 28) #define CURSOR_CLIPPING(w) ((w) << 28)
#define CURSOR_CLIP_WIN_A 1 #define CURSOR_CLIP_WIN_A 1
#define CURSOR_CLIP_WIN_B 2 #define CURSOR_CLIP_WIN_B 2
@@ -253,6 +293,7 @@
#define DC_DISP_CURSOR_POSITION 0x440 #define DC_DISP_CURSOR_POSITION 0x440
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 #define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4
#define DC_DISP_CURSOR_START_ADDR_HI 0x4EC #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 DC_DISP_BLEND_CURSOR_CONTROL 0x4F1
#define CURSOR_BLEND_2BIT (0 << 24) #define CURSOR_BLEND_2BIT (0 << 24)
#define CURSOR_BLEND_R8G8B8A8 (1 << 24) #define CURSOR_BLEND_R8G8B8A8 (1 << 24)
@@ -269,17 +310,22 @@
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 #define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4
#define DC_WINC_COLOR_PALETTE 0x500 #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_WINC_PALETTE_COLOR_EXT 0x600
#define DC_WIN_CSC_YOF 0x611 #define DC_WINC_H_FILTER_P(p) (0x601 + (p))
#define DC_WIN_CSC_KYRGB 0x612 #define DC_WINC_V_FILTER_P(p) (0x619 + (p))
#define DC_WIN_CSC_KUR 0x613 #define DC_WINC_H_FILTER_HI_P(p) (0x629 + (p))
#define DC_WIN_CSC_KVR 0x614
#define DC_WIN_CSC_KUG 0x615 #define DC_WINC_CSC_YOF 0x611
#define DC_WIN_CSC_KVG 0x616 #define DC_WINC_CSC_KYRGB 0x612
#define DC_WIN_CSC_KUB 0x617 #define DC_WINC_CSC_KUR 0x613
#define DC_WIN_CSC_KVB 0x618 #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_AD_WIN_OPTIONS 0xB80
#define DC_WIN_BD_WIN_OPTIONS 0xD80 #define DC_WIN_BD_WIN_OPTIONS 0xD80
#define DC_WIN_CD_WIN_OPTIONS 0xF80 #define DC_WIN_CD_WIN_OPTIONS 0xF80
@@ -290,15 +336,17 @@
#define V_DIRECTION BIT(2) #define V_DIRECTION BIT(2)
#define SCAN_COLUMN BIT(4) #define SCAN_COLUMN BIT(4)
#define COLOR_EXPAND BIT(6) #define COLOR_EXPAND BIT(6)
#define H_FILTER_ENABLE BIT(8)
#define V_FILTER_ENABLE BIT(10)
#define COLOR_PALETTE_ENABLE BIT(16) #define COLOR_PALETTE_ENABLE BIT(16)
#define CSC_ENABLE BIT(18) #define CSC_ENABLE BIT(18)
#define DV_ENABLE BIT(20)
#define WIN_ENABLE BIT(30) #define WIN_ENABLE BIT(30)
#define H_FILTER_EXPAND BIT(31)
#define DC_WIN_BUFFER_CONTROL 0x702 #define DC_WIN_BUFFER_CONTROL 0x702
#define BUFFER_CONTROL_HOST 0 #define BUFFER_CONTROL_HOST 0
#define BUFFER_CONTROL_VI 1 #define BUFFER_CONTROL_VI 1
#define BUFFER_CONTROL_EPP 2
#define BUFFER_CONTROL_MPEGE 3
#define BUFFER_CONTROL_SB2D 4 #define BUFFER_CONTROL_SB2D 4
#define DC_WIN_COLOR_DEPTH 0x703 #define DC_WIN_COLOR_DEPTH 0x703
@@ -324,6 +372,10 @@
#define WIN_COLOR_DEPTH_YUV422R 0x17 #define WIN_COLOR_DEPTH_YUV422R 0x17
#define WIN_COLOR_DEPTH_YCbCr422RA 0x18 #define WIN_COLOR_DEPTH_YCbCr422RA 0x18
#define WIN_COLOR_DEPTH_YUV422RA 0x19 #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_YCbCr444P 0x29
#define WIN_COLOR_DEPTH_YCrCb420SP 0x2A #define WIN_COLOR_DEPTH_YCrCb420SP 0x2A
#define WIN_COLOR_DEPTH_YCbCr420SP 0x2B #define WIN_COLOR_DEPTH_YCbCr420SP 0x2B
@@ -338,33 +390,37 @@
#define WIN_COLOR_DEPTH_YUV444SP 0x3C #define WIN_COLOR_DEPTH_YUV444SP 0x3C
#define DC_WIN_POSITION 0x704 #define DC_WIN_POSITION 0x704
#define H_POSITION(x) (((x) & 0xffff) << 0) // Support negative. #define H_POSITION(x) (((x) & 0xFFFF) << 0) // Support negative.
#define V_POSITION(x) (((x) & 0xffff) << 16) // Support negative. #define V_POSITION(x) (((x) & 0xFFFF) << 16) // Support negative.
#define DC_WIN_SIZE 0x705 #define DC_WIN_SIZE 0x705
#define H_SIZE(x) (((x) & 0x1fff) << 0) #define H_SIZE(x) (((x) & 0x1FFF) << 0)
#define V_SIZE(x) (((x) & 0x1fff) << 16) #define V_SIZE(x) (((x) & 0x1FFF) << 16)
#define DC_WIN_PRESCALED_SIZE 0x706 #define DC_WIN_PRESCALED_SIZE 0x706
#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) #define H_PRESCALED_SIZE(x) (((x) & 0x7FFF) << 0)
#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) #define V_PRESCALED_SIZE(x) (((x) & 0x1FFF) << 16)
#define DC_WIN_H_INITIAL_DDA 0x707 #define DC_WIN_H_INITIAL_DDA 0x707
#define DC_WIN_V_INITIAL_DDA 0x708 #define DC_WIN_V_INITIAL_DDA 0x708
#define DC_WIN_DDA_INC 0x709 #define DC_WIN_DDA_INC 0x709
#define H_DDA_INC(x) (((x) & 0xffff) << 0) #define H_DDA_INC(x) (((x) & 0xFFFF) << 0)
#define V_DDA_INC(x) (((x) & 0xffff) << 16) #define V_DDA_INC(x) (((x) & 0xFFFF) << 16)
#define DC_WIN_LINE_STRIDE 0x70A #define DC_WIN_LINE_STRIDE 0x70A
#define LINE_STRIDE(x) (x) #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 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 DC_WINBUF_BLEND_LAYER_CONTROL 0x716
#define WIN_BLEND_DEPTH(x) (((x) & 0xff) << 0) #define WIN_BLEND_DEPTH(x) (((x) & 0xFF) << 0)
#define WIN_K1(x) (((x) & 0xff) << 8) #define WIN_K1(x) (((x) & 0xFF) << 8)
#define WIN_K2(x) (((x) & 0xff) << 16) #define WIN_K2(x) (((x) & 0xFF) << 16)
#define WIN_BLEND_ENABLE (0 << 24) #define WIN_BLEND_ENABLE (0 << 24)
#define WIN_BLEND_BYPASS (1 << 24) #define WIN_BLEND_BYPASS (1 << 24)
@@ -395,8 +451,8 @@
#define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_K2 (3 << 12) #define WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_K2 (3 << 12)
#define DC_WINBUF_BLEND_ALPHA_1BIT 0x719 #define DC_WINBUF_BLEND_ALPHA_1BIT 0x719
#define WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xff) << 0) #define WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xFF) << 0)
#define WIN_ALPHA_1BIT_WEIGHT1(x) (((x) & 0xff) << 8) #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). */ /*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
#define DC_WINBUF_START_ADDR 0x800 #define DC_WINBUF_START_ADDR 0x800
@@ -408,6 +464,8 @@
#define BLOCK (2 << 0) #define BLOCK (2 << 0)
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4) #define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
#define DC_WINBUF_MEMFETCH_CONTROL 0x82B
/*! Display serial interface registers. */ /*! Display serial interface registers. */
#define _DSIREG(reg) ((reg) * 4) #define _DSIREG(reg) ((reg) * 4)
@@ -462,6 +520,7 @@
#define DSI_STATUS 0x15 #define DSI_STATUS 0x15
#define DSI_STATUS_RX_FIFO_SIZE 0x1F #define DSI_STATUS_RX_FIFO_SIZE 0x1F
#define DSI_STATUS_TX_FIFO_SIZE 0x20 // Actual depth is 64.
#define DSI_INIT_SEQ_CONTROL 0x1A #define DSI_INIT_SEQ_CONTROL 0x1A
#define DSI_INIT_SEQ_DATA_0 0x1B #define DSI_INIT_SEQ_DATA_0 0x1B
@@ -486,8 +545,8 @@
#define DSI_PKT_LEN_2_3 0x35 #define DSI_PKT_LEN_2_3 0x35
#define DSI_PKT_LEN_4_5 0x36 #define DSI_PKT_LEN_4_5 0x36
#define DSI_PKT_LEN_6_7 0x37 #define DSI_PKT_LEN_6_7 0x37
#define PKT0_LEN(x) (((x) & 0xffff) << 0) #define PKT0_LEN(x) (((x) & 0xFFFF) << 0)
#define PKT1_LEN(x) (((x) & 0xffff) << 16) #define PKT1_LEN(x) (((x) & 0xFFFF) << 16)
#define DSI_PHY_TIMING_0 0x3C #define DSI_PHY_TIMING_0 0x3C
#define DSI_PHY_TIMING_1 0x3D #define DSI_PHY_TIMING_1 0x3D
@@ -495,20 +554,20 @@
#define DSI_BTA_TIMING 0x3F #define DSI_BTA_TIMING 0x3F
#define DSI_TIMEOUT_0 0x44 #define DSI_TIMEOUT_0 0x44
#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) #define DSI_TIMEOUT_HTX(x) (((x) & 0xFFFF) << 0)
#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_LRX(x) (((x) & 0xFFFF) << 16)
#define DSI_TIMEOUT_1 0x45 #define DSI_TIMEOUT_1 0x45
#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) #define DSI_TIMEOUT_TA(x) (((x) & 0xFFFF) << 0)
#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_PR(x) (((x) & 0xFFFF) << 16)
#define DSI_TO_TALLY 0x46 #define DSI_TO_TALLY 0x46
#define DSI_PAD_CONTROL_0 0x4B #define DSI_PAD_CONTROL_0 0x4B
#define DSI_PAD_CONTROL_VS1_PDIO_CLK BIT(8) #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_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_PAD_CONTROL_CD 0x4C
#define DSI_VIDEO_MODE_CONTROL 0x4E #define DSI_VIDEO_MODE_CONTROL 0x4E
@@ -659,7 +718,7 @@
#define MIPI_DCS_READ_DDB_CONTINUE 0xA8 // 0x100 size. #define MIPI_DCS_READ_DDB_CONTINUE 0xA8 // 0x100 size.
/*! MIPI DCS Panel Private CMDs. */ /*! MIPI DCS Panel Private CMDs. */
#define MIPI_DCS_PRIV_SM_SET_COLOR_MODE 0xA0 #define MIPI_DCS_PRIV_SM_SET_COLOR_MODE 0xA0 // 43 bytes.
#define MIPI_DCS_PRIV_SM_SET_REG_OFFSET 0xB0 #define MIPI_DCS_PRIV_SM_SET_REG_OFFSET 0xB0
#define MIPI_DCS_PRIV_SM_SET_ELVSS 0xB1 // OLED backlight tuning. Byte7: PWM transition time in frames. #define MIPI_DCS_PRIV_SM_SET_ELVSS 0xB1 // OLED backlight tuning. Byte7: PWM transition time in frames.
#define MIPI_DCS_PRIV_SET_POWER_CONTROL 0xB1 #define MIPI_DCS_PRIV_SET_POWER_CONTROL 0xB1
@@ -669,8 +728,9 @@
#define MIPI_DCS_PRIV_UNK_D6 0xD6 #define MIPI_DCS_PRIV_UNK_D6 0xD6
#define MIPI_DCS_PRIV_UNK_D8 0xD8 #define MIPI_DCS_PRIV_UNK_D8 0xD8
#define MIPI_DCS_PRIV_UNK_D9 0xD9 #define MIPI_DCS_PRIV_UNK_D9 0xD9
#define MIPI_DCS_PRIV_SM_DISPLAY_ID 0xDD
// LVL1 LVL2 LVL3 UNK0 UNK1 // LVL1 LVL2 LVL3 UNK0 UNK1
#define MIPI_DCS_PRIV_SM_SET_REGS_LOCK 0xE2 // Samsung: Lock (default): 5A5A A5A5 A5A5 A500 A500. Unlock: A5A5 5A5A 5A5A UNK UNK. #define MIPI_DCS_PRIV_SM_SET_REGS_LOCK 0xE2 // Samsung: Lock (default): 5A5A A5A5 A5A5 A500 A500. Lock/Unlock: A5/5A. LVL1 group is normal registers.
#define MIPI_DCS_PRIV_READ_EXTC_CMD_SPI 0xFE // Read EXTC Command In SPI. 1 byte. 0-6: EXT_SPI_CNT, 7:EXT_SP. #define MIPI_DCS_PRIV_READ_EXTC_CMD_SPI 0xFE // Read EXTC Command In SPI. 1 byte. 0-6: EXT_SPI_CNT, 7:EXT_SP.
#define MIPI_DCS_PRIV_SET_EXTC_CMD_REG 0xFF // EXTC Command Set enable register. 5 bytes. Pass: FF 98 06 04, PAGE. #define MIPI_DCS_PRIV_SET_EXTC_CMD_REG 0xFF // EXTC Command Set enable register. 5 bytes. Pass: FF 98 06 04, PAGE.
@@ -707,19 +767,21 @@
#define DCS_CONTROL_DISPLAY_SM_FLASHLIGHT BIT(2) #define DCS_CONTROL_DISPLAY_SM_FLASHLIGHT BIT(2)
#define DCS_CONTROL_DISPLAY_BACKLIGHT_CTRL BIT(2) #define DCS_CONTROL_DISPLAY_BACKLIGHT_CTRL BIT(2)
#define DCS_CONTROL_DISPLAY_DIMMING_CTRL BIT(3) #define DCS_CONTROL_DISPLAY_DIMMING_CTRL BIT(3) // Transition fading.
#define DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL BIT(5) #define DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL BIT(5)
#define DCS_CONTROL_DISPLAY_HBM_CTRL0 BIT(6)
#define DCS_CONTROL_DISPLAY_HBM_CTRL1 BIT(7)
#define DCS_SM_COLOR_MODE_SATURATED 0x00 // Disabled. Similar to vivid but over-saturated. Wide gamut? #define DCS_SM_COLOR_MODE_SATURATED 0x00 // Disabled. Based on Vivid but over-saturated.
#define DCS_SM_COLOR_MODE_WASHED 0x45 #define DCS_SM_COLOR_MODE_WASHED 0x45
#define DCS_SM_COLOR_MODE_BASIC 0x03 #define DCS_SM_COLOR_MODE_BASIC 0x03 // Real natural profile.
#define DCS_SM_COLOR_MODE_POR_RESET 0x20 // Reset value on power on. #define DCS_SM_COLOR_MODE_POR_RESET 0x20 // Reset value on power on.
#define DCS_SM_COLOR_MODE_NATURAL 0x23 // Not actually natural.. #define DCS_SM_COLOR_MODE_NATURAL 0x23 // Not actually natural.. Extra saturation.
#define DCS_SM_COLOR_MODE_VIVID 0x65 #define DCS_SM_COLOR_MODE_VIVID 0x65 // Saturated.
#define DCS_SM_COLOR_MODE_NIGHT0 0x43 // Based on washed out. #define DCS_SM_COLOR_MODE_NIGHT0 0x43 // Based on Washed Out.
#define DCS_SM_COLOR_MODE_NIGHT1 0x15 // Based on basic. #define DCS_SM_COLOR_MODE_NIGHT1 0x15 // Based on Basic.
#define DCS_SM_COLOR_MODE_NIGHT2 0x35 // Based on natural. #define DCS_SM_COLOR_MODE_NIGHT2 0x35 // Based on Natural.
#define DCS_SM_COLOR_MODE_NIGHT3 0x75 // Based on vivid. #define DCS_SM_COLOR_MODE_NIGHT3 0x75 // Based on Vivid.
#define DCS_SM_COLOR_MODE_ENABLE BIT(0) #define DCS_SM_COLOR_MODE_ENABLE BIT(0)
@@ -732,9 +794,10 @@
* [10] 96 [09]: JDI LAM062M109A * [10] 96 [09]: JDI LAM062M109A
* [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1) * [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1)
* [20] 95 [0F]: InnoLux P062CCA-AZ2 (Rev B1) * [20] 95 [0F]: InnoLux P062CCA-AZ2 (Rev B1)
* [20] 96 [0F]: InnoLux P062CCA-AZ3 (Rev XX) [UNCONFIRMED MODEL+REV] * [20] 96 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV]
* [20] 97 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV] * [20] 97 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV]
* [20] 98 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV] * [20] 98 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV]
* [20] 99 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV]
* [30] 93 [0F]: AUO A062TAN00 (59.06A33.000) * [30] 93 [0F]: AUO A062TAN00 (59.06A33.000)
* [30] 94 [0F]: AUO A062TAN01 (59.06A33.001) * [30] 94 [0F]: AUO A062TAN01 (59.06A33.001)
* [30] 95 [0F]: AUO A062TAN02 (59.06A33.002) * [30] 95 [0F]: AUO A062TAN02 (59.06A33.002)
@@ -779,24 +842,44 @@
enum enum
{ {
PANEL_JDI_XXX062M = 0x10, PANEL_JDI_XXX062M = 0x10,
PANEL_JDI_LAM062M109A = 0x0910, PANEL_JDI_LAM062M109A = 0x0910, // SI.
PANEL_JDI_LPM062M326A = 0x2610, PANEL_JDI_LPM062M326A = 0x2610, // LTPS.
PANEL_INL_P062CCA_AZ1 = 0x0F20, PANEL_INL_P062CCA_AZ1 = 0x0F20,
PANEL_AUO_A062TAN01 = 0x0F30, PANEL_AUO_A062TAN01 = 0x0F30,
PANEL_INL_2J055IA_27A = 0x1020, PANEL_INL_2J055IA_27A = 0x1020,
PANEL_AUO_A055TAN01 = 0x1030, PANEL_AUO_A055TAN01 = 0x1030,
PANEL_SHP_LQ055T1SW10 = 0x1040, PANEL_SHP_LQ055T1SW10 = 0x1040,
PANEL_SAM_AMS699VC01 = 0x2050 PANEL_SAM_AMS699VC01 = 0x2050,
// Found on 6/2" clones. Unknown markings. Clone of AUO A062TAN01.
// Quality seems JDI like. Has bad low backlight scaling. ID: [83] 94 [0F]. Sometimes reports [30] 94 [0F]. Both IDs have correct CRC16.
PANEL_OEM_CLONE_6_2 = 0x0F83,
// Found on 5.5" clones with AUO A055TAN02 (59.05A30.001) fake markings.
PANEL_OEM_CLONE_5_5 = 0x00B3,
// Found on 5.5" clones with AUO A055TAN02 (59.05A30.001) fake markings.
PANEL_OEM_CLONE = 0x0000
//0x0F40 [40] 94 [0F], 5.5" clone
}; };
void display_init(); void display_init();
void display_backlight_pwm_init(); void display_backlight_pwm_init();
void display_end(); void display_end();
/*! Interrupt management. */
void display_enable_interrupt(u32 intr);
void display_disable_interrupt(u32 intr);
void display_wait_interrupt(u32 intr);
/*! Get/Set Display panel ID. */ /*! Get/Set Display panel ID. */
u16 display_get_decoded_panel_id(); u16 display_get_decoded_panel_id();
void display_set_decoded_panel_id(u32 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. */ /*! Show one single color on the display. */
void display_color_screen(u32 color); void display_color_screen(u32 color);
@@ -805,21 +888,22 @@ void display_backlight(bool enable);
void display_backlight_brightness(u32 brightness, u32 step_delay); void display_backlight_brightness(u32 brightness, u32 step_delay);
u32 display_get_backlight_brightness(); u32 display_get_backlight_brightness();
/*! Init display in full 720x1280 resolution (B8G8R8A8, line stride 720, framebuffer size = 720*1280*4 bytes). */ u32 *display_init_window_a_pitch();
u32 *display_init_framebuffer_pitch(); u32 *display_init_window_a_pitch_vic();
u32 *display_init_framebuffer_pitch_vic(); u32 *display_init_window_a_pitch_inv();
u32 *display_init_framebuffer_pitch_inv(); u32 *display_init_window_a_block();
u32 *display_init_framebuffer_block(); u32 *display_init_window_d_console();
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();
int display_dsi_read(u8 cmd, u32 len, void *data); void display_window_disable(u32 window);
int display_dsi_vblank_read(u8 cmd, u32 len, void *data);
void display_dsi_write(u8 cmd, u32 len, void *data); void display_set_framebuffer(u32 window, void *fb);
void display_dsi_vblank_write(u8 cmd, u32 len, void *data); 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 #endif

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -16,37 +16,35 @@
*/ */
// Display A config. // Display A config.
static const cfg_op_t _di_dc_setup_win_config[] = { static const reg_cfg_t _di_dc_setup_win_config[] = {
{DC_CMD_STATE_ACCESS, 0}, {DC_CMD_STATE_ACCESS, READ_MUX_ASSEMBLY | WRITE_MUX_ASSEMBLY},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {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_REG_ACT_CONTROL, WIN_A_ACT_HCNTR_SEL | WIN_B_ACT_HCNTR_SEL | WIN_C_ACT_HCNTR_SEL | WIN_D_ACT_HCNTR_SEL},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {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_DC_MCCIF_FIFOCTRL, 0},
{DC_DISP_DISP_MEM_HIGH_PRIORITY, 0}, {DC_DISP_DISP_MEM_HIGH_PRIORITY, 0},
{DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 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_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_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL},
{DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | SYNCPT_VSYNC_INDX(9)}, {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_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}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ},
{DC_CMD_STATE_ACCESS, 0},
/* Setup Windows A/B/C */ /* 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_WIN_OPTIONS, 0},
{DC_WIN_DV_CONTROL, 0}, {DC_WIN_DV_CONTROL, 0},
/* Setup default YUV colorspace conversion coefficients */ /* Setup default YUV colorspace conversion coefficients */
{DC_WIN_CSC_YOF, 0xF0}, {DC_WINC_CSC_YOF, 0xF0},
{DC_WIN_CSC_KYRGB, 0x12A}, {DC_WINC_CSC_KYRGB, 0x12A},
{DC_WIN_CSC_KUR, 0}, {DC_WINC_CSC_KUR, 0},
{DC_WIN_CSC_KVR, 0x198}, {DC_WINC_CSC_KVR, 0x198},
{DC_WIN_CSC_KUG, 0x39B}, {DC_WINC_CSC_KUG, 0x39B},
{DC_WIN_CSC_KVG, 0x32F}, {DC_WINC_CSC_KVG, 0x32F},
{DC_WIN_CSC_KUB, 0x204}, {DC_WINC_CSC_KUB, 0x204},
{DC_WIN_CSC_KVB, 0}, {DC_WINC_CSC_KVB, 0},
/* End of color coefficients */ /* End of color coefficients */
{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, {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_COM_PIN_OUTPUT_POLARITY(3), 0},
{DC_DISP_BLEND_BACKGROUND_COLOR, 0}, {DC_DISP_BLEND_BACKGROUND_COLOR, 0},
{DC_COM_CRC_CONTROL, 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_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}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_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_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_BYPASS | WIN_BLEND_DEPTH(255)},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 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}, {DC_DISP_DISP_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {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_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} {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. // 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_WR_DATA, 0},
{DSI_INT_ENABLE, 0}, {DSI_INT_ENABLE, 0},
{DSI_INT_STATUS, 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_2, 0},
{DSI_INIT_SEQ_DATA_3, 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_DCS_CMDS, 0},
{DSI_PKT_SEQ_0_LO, 0}, {DSI_PKT_SEQ_0_LO, 0},
{DSI_PKT_SEQ_1_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_PKT_SEQ_5_HI, 0},
{DSI_CONTROL, 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_1, 0},
{DSI_PAD_CONTROL_2, 0}, {DSI_PAD_CONTROL_2, 0},
{DSI_PAD_CONTROL_3, 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_6_B01, 0},
{DSI_PAD_CONTROL_7_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_PAD_CONTROL_CD, 0},
{DSI_SOL_DELAY, 24}, {DSI_SOL_DELAY, 24},
{DSI_MAX_THRESHOLD, 480}, {DSI_MAX_THRESHOLD, 480},
{DSI_TRIGGER, 0}, {DSI_TRIGGER, 0},
{DSI_INIT_SEQ_CONTROL, 0}, {DSI_INIT_SEQ_CONTROL, 0},
{DSI_PKT_LEN_0_1, 0}, {DSI_PKT_LEN_0_1, 0},
{DSI_PKT_LEN_2_3, 0}, {DSI_PKT_LEN_2_3, 0},
{DSI_PKT_LEN_4_5, 0}, {DSI_PKT_LEN_4_5, 0},
{DSI_PKT_LEN_6_7, 0}, {DSI_PKT_LEN_6_7, 0},
{DSI_PAD_CONTROL_1, 0}
}; {DSI_PAD_CONTROL_1, 0},
static const cfg_op_t _di_dsi_init_timing_pwrctrl_config[] = {
/* DSI PHY timings */
{DSI_PHY_TIMING_0, 0x6070603},
{DSI_PHY_TIMING_1, 0x40A0E05}, {DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30109}, {DSI_PHY_TIMING_2, 0x30109},
{DSI_BTA_TIMING, 0x190A14}, {DSI_BTA_TIMING, 0x190A14},
/* DSI timeout */
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)}, {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0}, {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, DSI_POWER_CONTROL_ENABLE}, {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
{DSI_POWER_CONTROL, 0}, {DSI_POWER_CONTROL, 0},
{DSI_POWER_CONTROL, 0}, {DSI_POWER_CONTROL, 0},
{DSI_PAD_CONTROL_1, 0} {DSI_PAD_CONTROL_1, 0},
};
static const cfg_op_t _di_dsi_init_timing_pkt_config3[] = { /* DSI PHY timings */
{DSI_PHY_TIMING_0, 0x6070603},
{DSI_PHY_TIMING_1, 0x40A0E05}, {DSI_PHY_TIMING_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30118}, {DSI_PHY_TIMING_2, 0x30118},
{DSI_BTA_TIMING, 0x190A14}, {DSI_BTA_TIMING, 0x190A14},
/* DSI timeout */
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0}, {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_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_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_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. // 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, 0x0439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).
{DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_TRIGGER, DSI_TRIGGER_HOST},
@@ -194,14 +197,21 @@ static const cfg_op_t _di_dsi_panel_init_config_jdi[] = {
{DSI_TRIGGER, DSI_TRIGGER_HOST} {DSI_TRIGGER, DSI_TRIGGER_HOST}
}; };
// DSI packet config. // DSI HS 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_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30172}, {DSI_PHY_TIMING_2, 0x30172},
{DSI_BTA_TIMING, 0x190A14}, {DSI_BTA_TIMING, 0x190A14},
/* DSI timeout */
{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)}, {DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)},
{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)}, {DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0}, {DSI_TO_TALLY, 0},
/* DSI packet sequence */
{DSI_PKT_SEQ_0_LO, 0x40000208}, {DSI_PKT_SEQ_0_LO, 0x40000208},
{DSI_PKT_SEQ_2_LO, 0x40000308}, {DSI_PKT_SEQ_2_LO, 0x40000308},
{DSI_PKT_SEQ_4_LO, 0x40000308}, {DSI_PKT_SEQ_4_LO, 0x40000308},
@@ -218,7 +228,7 @@ static const cfg_op_t _di_dsi_init_seq_pkt_final_config[] = {
}; };
// DSI mode 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_TRIGGER, 0},
{DSI_CONTROL, 0}, {DSI_CONTROL, 0},
{DSI_SOL_DELAY, 6}, {DSI_SOL_DELAY, 6},
@@ -232,7 +242,7 @@ static const cfg_op_t _di_dsi_mode_config[] = {
}; };
// MIPI CAL 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_MIPI_BIAS_PAD_CFG2, 0},
{MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000}, {MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000},
{MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0}, {MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0},
@@ -240,13 +250,13 @@ static const cfg_op_t _di_mipi_pad_cal_config[] = {
}; };
// DSI pad 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_1, 0},
{DSI_PAD_CONTROL_2, 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_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} {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_1, 0},
{DSI_PAD_CONTROL_2, 0}, {DSI_PAD_CONTROL_2, 0},
{DSI_PAD_CONTROL_3, 0}, {DSI_PAD_CONTROL_3, 0},
@@ -257,19 +267,19 @@ static const cfg_op_t _di_dsi_pad_cal_config_t210b01[] = {
}; };
// MIPI CAL config. // 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_DSIA_MIPI_CAL_CONFIG, 0x200200},
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200},
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002}, {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002},
{MIPI_CAL_DSIB_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_DSIA_MIPI_CAL_CONFIG, 0x200006},
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006},
{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000}, {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000},
{MIPI_CAL_DSIB_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_CILA_MIPI_CAL_CONFIG, 0},
{MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0},
{MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0},
@@ -280,48 +290,11 @@ static const cfg_op_t _di_mipi_start_dsi_cal_config[] = {
{MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0},
{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0},
{MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0}, {MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0},
{MIPI_CAL_DSID_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.
}; };
// Display A enable config. // Display A enable config.
static const cfg_op_t _di_dc_video_enable_config[] = { static const reg_cfg_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},
/* Set panel timings */ /* Set panel timings */
{DC_DISP_DISP_TIMING_OPTIONS, VSYNC_H_POSITION(0)}, {DC_DISP_DISP_TIMING_OPTIONS, VSYNC_H_POSITION(0)},
{DC_DISP_REF_TO_SYNC, V_REF_TO_SYNC(1) | H_REF_TO_SYNC(0)}, {DC_DISP_REF_TO_SYNC, V_REF_TO_SYNC(1) | H_REF_TO_SYNC(0)},
@@ -334,59 +307,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_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
{DC_COM_PIN_OUTPUT_ENABLE(1), 0}, {DC_COM_PIN_OUTPUT_ENABLE(1), 0},
{DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL}, {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_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}, /* Start continuous display. */
{DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {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_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {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_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_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {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_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)}, // 4: div3.
{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},
{DC_CMD_DISPLAY_COMMAND_OPTION0, 0}
}; };
// Display A disable config. // Display A disable config.
static const cfg_op_t _di_dc_video_disable_config[] = { static const reg_cfg_t _di_dc_video_disable_config[] = {
{DC_DISP_FRONT_PORCH, V_FRONT_PORCH(10) | H_FRONT_PORCH(136)},
{DC_CMD_INT_MASK, 0}, {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_INT_ENABLE, 0},
{DC_CMD_CONT_SYNCPT_VSYNC, 0}, {DC_CMD_CONT_SYNCPT_VSYNC, 0},
/* Stop display. */
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {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_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_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {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_DISPLAY_POWER_CONTROL, 0},
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
}; };
// DSI deinit config. // 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_POWER_CONTROL, 0},
{DSI_PAD_CONTROL_1, 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_1, 0x40A0E05},
{DSI_PHY_TIMING_2, 0x30118}, {DSI_PHY_TIMING_2, 0x30118},
{DSI_BTA_TIMING, 0x190A14}, {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_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)},
{DSI_TO_TALLY, 0}, {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_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_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},
{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},
@@ -397,7 +371,7 @@ static const cfg_op_t _di_dsi_timing_deinit_config[] = {
}; };
// DSI panel JDI 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, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).
{DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_TRIGGER, DSI_TRIGGER_HOST},
@@ -423,7 +397,7 @@ static const cfg_op_t _di_dsi_panel_deinit_config_jdi[] = {
}; };
// DSI panel AUO deinit config. // 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, 0x439}, // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.
{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94). {DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).
{DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_TRIGGER, DSI_TRIGGER_HOST},
@@ -464,24 +438,24 @@ static const cfg_op_t _di_dsi_panel_deinit_config_auo[] = {
{DSI_TRIGGER, DSI_TRIGGER_HOST} {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, 0x239},
{DSI_WR_DATA, 0x02C1}, // INV_EN. {DSI_WR_DATA, 0x02C1}, // INV_EN.
{DSI_TRIGGER, DSI_TRIGGER_HOST}, {DSI_TRIGGER, DSI_TRIGGER_HOST},
}; };
*/
// Display A Window A one color config. // Display A Window A one color config.
static const cfg_op_t _di_win_one_color[] = { static const reg_cfg_t _di_win_one_color[] = {
{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_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display. {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display.
}; };
// Display A Window A linear pitch config. // Display A Window A linear pitch config.
static const cfg_op_t _di_win_framebuffer_pitch[] = { static const reg_cfg_t _di_winA_pitch[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT | WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
@@ -500,14 +474,12 @@ static const cfg_op_t _di_win_framebuffer_pitch[] = {
{DC_WINBUF_ADDR_V_OFFSET, 0}, {DC_WINBUF_ADDR_V_OFFSET, 0},
{DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD. {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD.
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. {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} {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
}; };
// Display A Window A linear pitch + Win D support config. // Display A Window A linear pitch + Win D support config.
static const cfg_op_t _di_win_framebuffer_pitch_vic[] = { static const reg_cfg_t _di_winA_pitch_vic[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT | WINDOW_C_SELECT | WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
@@ -526,14 +498,12 @@ static const cfg_op_t _di_win_framebuffer_pitch_vic[] = {
{DC_WINBUF_ADDR_V_OFFSET, 0}, {DC_WINBUF_ADDR_V_OFFSET, 0},
{DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD. {DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD.
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. {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} {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
}; };
// Display A Window A linear pitch inverse + Win D support config. // Display A Window A linear pitch inverse + Win D support config.
static const cfg_op_t _di_win_framebuffer_pitch_inv[] = { static const reg_cfg_t _di_winA_pitch_inv[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT | WINDOW_C_SELECT | WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
@@ -552,14 +522,12 @@ static const cfg_op_t _di_win_framebuffer_pitch_inv[] = {
{DC_WINBUF_ADDR_V_OFFSET, 1279}, // Linear: 1279, Block: 0. {DC_WINBUF_ADDR_V_OFFSET, 1279}, // Linear: 1279, Block: 0.
{DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, // Enable window AD. {DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, // Enable window AD.
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display. {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} {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
}; };
// Display A Window A block linear config. // Display A Window A block linear config.
static const cfg_op_t _di_win_framebuffer_block[] = { static const reg_cfg_t _di_winA_block[] = {
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT | WINDOW_C_SELECT | WINDOW_B_SELECT},
{DC_WIN_WIN_OPTIONS, 0},
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_WIN_OPTIONS, 0},
{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, {DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},
@@ -578,12 +546,12 @@ static const cfg_op_t _di_win_framebuffer_block[] = {
{DC_WINBUF_ADDR_V_OFFSET, 0}, // Linear: 1279, Block: 0. {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_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_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} {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}
}; };
// Display A Window D config. // 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_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT},
{DC_WIN_WIN_OPTIONS, 0}, {DC_WIN_WIN_OPTIONS, 0},
{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, {DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8},
@@ -601,6 +569,6 @@ static const cfg_op_t _di_win_framebuffer_log[] = {
{DC_WINBUF_ADDR_V_OFFSET, 0}, {DC_WINBUF_ADDR_V_OFFSET, 0},
{DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_ENABLE | WIN_K1(200) | WIN_BLEND_DEPTH(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_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_UPDATE | WIN_D_UPDATE},
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_D_ACT_REQ} {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_D_ACT_REQ},
}; };

View File

@@ -1,7 +1,7 @@
/* /*
* VIC driver for Tegra X1 * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -390,7 +390,7 @@ static int _vic_wait_idle()
return 0; 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_x = 0;
u32 flip_y = 0; u32 flip_y = 0;
@@ -406,6 +406,9 @@ void vic_set_surface(vic_surface_t *sfc)
// Get format alpha type. // Get format alpha type.
switch (sfc->pix_fmt) 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_X8B8G8R8:
case VIC_PIX_FORMAT_X8R8G8B8: case VIC_PIX_FORMAT_X8R8G8B8:
case VIC_PIX_FORMAT_B8G8R8X8: case VIC_PIX_FORMAT_B8G8R8X8:
@@ -536,14 +539,8 @@ int vic_compose()
int vic_init() int vic_init()
{ {
// Ease the stress to APB.
bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
clock_enable_vic(); clock_enable_vic();
// Restore sys clock.
bpmp_clk_rate_set(prev_fid);
// Load Fetch Control Engine microcode. // Load Fetch Control Engine microcode.
for (u32 i = 0; i < sizeof(vic_fce_ucode) / sizeof(u32); i++) 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 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_A8B8G8R8 = 31, // 32-bit ABGR.
VIC_PIX_FORMAT_A8R8G8B8 = 32, // 32-bit ARGB. VIC_PIX_FORMAT_A8R8G8B8 = 32, // 32-bit ARGB.
VIC_PIX_FORMAT_B8G8R8A8 = 33, // 32-bit BGRA. 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_X8R8G8B8 = 36, // 32-bit XRGB.
VIC_PIX_FORMAT_B8G8R8X8 = 37, // 32-bit BGRX. VIC_PIX_FORMAT_B8G8R8X8 = 37, // 32-bit BGRX.
VIC_PIX_FORMAT_R8G8B8X8 = 38, // 32-bit RGBX. VIC_PIX_FORMAT_R8G8B8X8 = 38, // 32-bit RGBX.
} vic_pix_format_t; } vic_pix_format_t;
typedef struct _vic_surface_t typedef struct _vic_surface_t
@@ -55,7 +58,7 @@ typedef struct _vic_surface_t
u32 rotation; u32 rotation;
} vic_surface_t; } 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_compose();
int vic_init(); int vic_init();
void vic_end(); void vic_end();

View File

@@ -38,7 +38,7 @@
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
#define FF_USE_MKFS 1 #define FF_USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#if FF_USE_MKFS #if FF_USE_MKFS

View File

@@ -45,7 +45,7 @@ typedef struct _opt_win_cal_t
} opt_win_cal_t; } opt_win_cal_t;
// Nintendo Switch Icosa/Iowa Optical Window calibration. // 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 }, { 500, 5002, 7502 },
{ 754, 2250, 2000 }, { 754, 2250, 2000 },
{ 1029, 1999, 1667 }, { 1029, 1999, 1667 },
@@ -54,14 +54,14 @@ const opt_win_cal_t opt_win_cal_default[] = {
}; };
// Nintendo Switch Aula Optical Window calibration. // 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 }, { 231, 9697, 30300 },
{ 993, 3333, 2778 }, { 993, 3333, 2778 },
{ 1478, 1621, 1053 }, { 1478, 1621, 1053 },
{ 7500, 81, 10 } { 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) void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle)
{ {
@@ -70,8 +70,6 @@ void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle)
if (!cycle) if (!cycle)
cycle = 1; cycle = 1;
else if (cycle > 255)
cycle = 255;
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain); i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain);
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle)); i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle));

View File

@@ -1,7 +1,7 @@
/* /*
* Joy-Con UART driver for Nintendo Switch * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -22,7 +22,6 @@
#include <gfx_utils.h> #include <gfx_utils.h>
#include <power/max17050.h> #include <power/max17050.h>
#include <power/regulator_5v.h> #include <power/regulator_5v.h>
#include <soc/bpmp.h>
#include <soc/clock.h> #include <soc/clock.h>
#include <soc/fuse.h> #include <soc/fuse.h>
#include <soc/gpio.h> #include <soc/gpio.h>
@@ -43,7 +42,9 @@
#define JC_HORI_INPUT_RPT 0x00 #define JC_HORI_INPUT_RPT 0x00
#define JC_WIRED_CMD_GET_INFO 0x01 #define JC_WIRED_CMD_GET_INFO 0x01
#define JC_WIRED_CMD_CHRG_CFG 0x02 #define JC_WIRED_CMD_SET_CHARGER 0x02
#define JC_WIRED_CMD_GET_CHARGER 0x03
#define JC_WIRED_CMD_BATT_VOLT 0x06
#define JC_WIRED_CMD_WAKE_REASON 0x07 #define JC_WIRED_CMD_WAKE_REASON 0x07
#define JC_WIRED_CMD_HID_CONN 0x10 #define JC_WIRED_CMD_HID_CONN 0x10
#define JC_WIRED_CMD_HID_DISC 0x11 #define JC_WIRED_CMD_HID_DISC 0x11
@@ -102,10 +103,10 @@ enum
enum enum
{ {
JC_BATT_EMTPY = 0, JC_BATT_EMTPY = 0,
JC_BATT_CRIT = 2, JC_BATT_CRIT = 1,
JC_BATT_LOW = 4, JC_BATT_LOW = 2,
JC_BATT_MID = 6, JC_BATT_MID = 3,
JC_BATT_FULL = 8 JC_BATT_FULL = 4
}; };
static const u8 sio_init[] = { static const u8 sio_init[] = {
@@ -221,8 +222,8 @@ typedef struct _jc_hid_in_rpt_t
{ {
u8 cmd; u8 cmd;
u8 pkt_id; u8 pkt_id;
u8 conn_info:4; u8 conn_info:4; // Connection detect.
u8 batt_info:4; u8 batt_info:4; // Power info.
u8 btn_right; u8 btn_right;
u8 btn_shared; u8 btn_shared;
u8 btn_left; u8 btn_left;
@@ -232,7 +233,7 @@ typedef struct _jc_hid_in_rpt_t
u8 stick_h_right; u8 stick_h_right;
u8 stick_m_right; u8 stick_m_right;
u8 stick_v_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 submcd_ack;
u8 subcmd; u8 subcmd;
u8 subcmd_data[]; u8 subcmd_data[];
@@ -304,7 +305,7 @@ typedef struct _jc_sio_hid_in_rpt_t
u8 stick_h_right; u8 stick_h_right;
u8 stick_m_right; u8 stick_m_right;
u8 stick_v_right; u8 stick_v_right;
u8 siaxis_rpt_num; // Max 15. u8 siaxis_rpt; // bit0-3: report num. bit4-7: imu type.
// Each report is 800 us? // Each report is 800 us?
jc_hid_in_sixaxis_rpt_t sixaxis[15]; jc_hid_in_sixaxis_rpt_t sixaxis[15];
} jc_sio_hid_in_rpt_t; } jc_sio_hid_in_rpt_t;
@@ -315,9 +316,10 @@ typedef struct _joycon_ctxt_t
u8 uart; u8 uart;
u8 type; u8 type;
u8 state; u8 state;
u8 mac[6];
u32 last_received_time; u32 last_received_time;
u32 last_status_req_time; u32 last_status_req_time;
u8 mac[6];
u8 pkt_id;
u8 rumble_sent; u8 rumble_sent;
u8 connected; u8 connected;
u8 detected; u8 detected;
@@ -328,11 +330,10 @@ static joycon_ctxt_t jc_l = {0};
static joycon_ctxt_t jc_r = {0}; static joycon_ctxt_t jc_r = {0};
static bool jc_init_done = false; static bool jc_init_done = false;
static u32 hid_pkt_inc = 0;
static jc_gamepad_rpt_t jc_gamepad; 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; u8 crc = init;
for (u16 i = 0; i < len; i++) for (u16 i = 0; i < len; i++)
@@ -405,12 +406,16 @@ static void _jc_detect()
if (!jc_gamepad.sio_mode) if (!jc_gamepad.sio_mode)
{ {
// Turn on Joy-Con detect. (UARTB/C TX). UART CTS also if HW flow control and irq is enabled. // 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_UART2_TX) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_UART3_TX) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_UART3_TX) = PINMUX_INPUT_ENABLE;
gpio_direction_input(GPIO_PORT_G, GPIO_PIN_0); gpio_direction_input(GPIO_PORT_G, GPIO_PIN_0);
gpio_direction_input(GPIO_PORT_D, GPIO_PIN_1); gpio_direction_input(GPIO_PORT_D, GPIO_PIN_1);
usleep(20); 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. // Read H6/E6 which are shared with UART TX pins.
jc_r.detected = !gpio_read(GPIO_PORT_H, GPIO_PIN_6); jc_r.detected = !gpio_read(GPIO_PORT_H, GPIO_PIN_6);
jc_l.detected = !gpio_read(GPIO_PORT_E, GPIO_PIN_6); jc_l.detected = !gpio_read(GPIO_PORT_E, GPIO_PIN_6);
@@ -442,7 +447,7 @@ static void _jc_conn_check()
if (jc_l.connected) if (jc_l.connected)
_jc_power_supply(UART_C, false); _jc_power_supply(UART_C, false);
hid_pkt_inc = 0; jc_l.pkt_id = 0;
jc_l.connected = false; jc_l.connected = false;
jc_l.rumble_sent = false; jc_l.rumble_sent = false;
@@ -459,7 +464,7 @@ static void _jc_conn_check()
if (jc_r.connected) if (jc_r.connected)
_jc_power_supply(UART_B, false); _jc_power_supply(UART_B, false);
hid_pkt_inc = 0; jc_r.pkt_id = 0;
jc_r.connected = false; jc_r.connected = false;
jc_r.rumble_sent = false; jc_r.rumble_sent = false;
@@ -478,7 +483,7 @@ static void _joycon_send_raw(u8 uart_port, const u8 *buf, u16 size)
uart_wait_xfer(uart_port, UART_TX_IDLE); 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[0] = 0x19;
out->uart_hdr.magic[1] = 0x01; out->uart_hdr.magic[1] = 0x01;
@@ -498,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); 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); u16 pkt_size = _jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0, crc);
pkt_size += size; pkt_size += size;
@@ -513,25 +518,21 @@ static u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size,
return pkt_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]; u8 rpt[0x50];
memset(rpt, 0, sizeof(rpt)); 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 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 };
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 };
u8 temp[0x30] = {0}; u8 temp[0x30] = {0};
@@ -545,47 +546,43 @@ static void _jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
// Enable rumble. // Enable rumble.
hid_pkt->cmd = JC_HID_OUTPUT_RPT; 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 = JC_HID_SUBCMD_RUMBLE_CTL;
hid_pkt->subcmd_data[0] = 1; hid_pkt->subcmd_data[0] = 1;
if (send_r_rumble) 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) 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. // Send rumble.
hid_pkt->cmd = JC_HID_RUMBLE_RPT; hid_pkt->cmd = JC_HID_RUMBLE_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init)); memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init));
if (send_r_rumble) 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) 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); msleep(15);
// Disable rumble. // Disable rumble.
hid_pkt->cmd = JC_HID_OUTPUT_RPT; 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 = JC_HID_SUBCMD_RUMBLE_CTL;
hid_pkt->subcmd_data[0] = 0; hid_pkt->subcmd_data[0] = 0;
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral)); memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
if (send_r_rumble) 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) 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 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->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
hid_pkt->subcmd = subcmd; hid_pkt->subcmd = subcmd;
if (data) if (data)
memcpy(hid_pkt->subcmd_data, data, size); 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);
} }
} }
@@ -594,13 +591,13 @@ static void _jc_charging_decider(u8 batt, u8 uart)
u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000; u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000;
// Power supply control based on battery levels and charging. // 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); _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); _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; u32 btn_tmp;
jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet; jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;
@@ -608,7 +605,14 @@ static void _jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size)
switch (hid_pkt->cmd) switch (hid_pkt->cmd)
{ {
case JC_HORI_INPUT_RPT: case JC_HORI_INPUT_RPT:
if (!(jc->type & JC_ID_HORI))
return;
case JC_HID_INPUT_RPT: 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; btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16;
if (jc->type & JC_ID_L) if (jc->type & JC_ID_L)
@@ -668,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]) switch (data[0])
{ {
case JC_WIRED_CMD_GET_INFO: case JC_WIRED_CMD_GET_INFO:
@@ -692,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) switch (pkt->cmd)
{ {
case JC_HORI_INPUT_RPT_CMD: case JC_HORI_INPUT_RPT_CMD:
case JC_WIRED_HID: 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; break;
case JC_WIRED_INIT_REPLY: case JC_WIRED_INIT_REPLY:
_jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1); _jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1);
@@ -713,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(); 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) switch (cmd)
{ {
case JC_SIO_CMD_STATUS: 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_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.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); jc_gamepad.home = !gpio_read(GPIO_PORT_V, GPIO_PIN_3);
@@ -738,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)) if (pkt->crc_hdr != _jc_crc((u8 *)pkt, sizeof(jc_sio_in_rpt_t) - 1, 0))
return; return;
@@ -755,7 +767,7 @@ static void _jc_sio_uart_pkt_parse(joycon_ctxt_t *jc, const jc_sio_in_rpt_t *pkt
break; break;
case JC_SIO_CMD_IAP_VER: case JC_SIO_CMD_IAP_VER:
case JC_SIO_CMD_STATUS: 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; break;
case JC_SIO_CMD_UNK02: case JC_SIO_CMD_UNK02:
case JC_SIO_CMD_UNK20: case JC_SIO_CMD_UNK20:
@@ -782,7 +794,7 @@ static void _jc_rcv_pkt(joycon_ctxt_t *jc)
jc_wired_hdr_t *jc_pkt = (jc_wired_hdr_t *)jc->buf; 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)) 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; return;
} }
@@ -791,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); 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) 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; return;
} }
@@ -802,7 +814,7 @@ static bool _jc_send_init_rumble(joycon_ctxt_t *jc)
// Send init rumble or request nx pad status report. // Send init rumble or request nx pad status report.
if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent)) 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) if (jc_l.connected)
jc_l.rumble_sent = true; jc_l.rumble_sent = true;
@@ -840,10 +852,10 @@ static void _jc_req_nx_pad_status(joycon_ctxt_t *jc)
else else
_joycon_send_raw(jc->uart, hori_pad_status, sizeof(hori_pad_status)); _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; u8 crc = 0;
for (u32 i = 0; i < 0x22; i++) for (u32 i = 0; i < 0x22; i++)
@@ -912,13 +924,13 @@ retry:
{ {
if (!jc_l_found) 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; jc_l.last_status_req_time = get_tmr_ms() + 15;
} }
if (!jc_r_found) 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; jc_r.last_status_req_time = get_tmr_ms() + 15;
} }
@@ -1109,7 +1121,7 @@ static void _jc_init_conn(joycon_ctxt_t *jc)
// Initialize the controller. // Initialize the controller.
u32 retries = 10; u32 retries = 10;
while (!jc->connected) while (!jc->connected && retries)
{ {
_joycon_send_raw(jc->uart, sio_init, sizeof(sio_init)); _joycon_send_raw(jc->uart, sio_init, sizeof(sio_init));
msleep(5); msleep(5);
@@ -1194,17 +1206,11 @@ void jc_init_hw()
pinmux_config_uart(UART_B); pinmux_config_uart(UART_B);
pinmux_config_uart(UART_C); 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. // Enable UART B and C clocks.
if (!jc_gamepad.sio_mode) if (!jc_gamepad.sio_mode)
clock_enable_uart(UART_B); clock_enable_uart(UART_B);
clock_enable_uart(UART_C); clock_enable_uart(UART_C);
// Restore OC.
bpmp_clk_rate_set(prev_fid);
jc_init_done = true; jc_init_done = true;
#endif #endif
} }
@@ -1224,12 +1230,12 @@ void jc_deinit()
u8 data = HCI_STATE_SLEEP; u8 data = HCI_STATE_SLEEP;
if (jc_r.connected && !(jc_r.type & JC_ID_HORI)) 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); _jc_rcv_pkt(&jc_r);
} }
if (jc_l.connected && !(jc_l.type & JC_ID_HORI)) 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); _jc_rcv_pkt(&jc_l);
} }
} }

View File

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

View File

@@ -1,5 +1,5 @@
/* /*
* Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller * Touch driver for Nintendo Switch's STM FingerTip S (FTM4CD60DA1BE/FTM4CD50TA1BE) touch controller
* *
* Copyright (c) 2018 langerhans * Copyright (c) 2018 langerhans
* Copyright (c) 2018-2023 CTCaer * Copyright (c) 2018-2023 CTCaer
@@ -39,7 +39,7 @@ static touch_panel_info_t _panels[] =
{ 1, 0, 1, 1, "GiS GGM6 B2X" },// 1. { 1, 0, 1, 1, "GiS GGM6 B2X" },// 1.
{ 2, 0, 0, 0, "NISSHA NBF-K9A" },// 3. { 2, 0, 0, 0, "NISSHA NBF-K9A" },// 3.
{ 3, 1, 0, 0, "GiS 5.5\"" },// 4. { 3, 1, 0, 0, "GiS 5.5\"" },// 4.
{ 4, 0, 0, 1, "Samsung BH2109" },// 5? { 4, 0, 0, 1, "Samsung TSP" },// 5?
{ -1, 1, 0, 1, "GiS VA 6.2\"" } // 2. { -1, 1, 0, 1, "GiS VA 6.2\"" } // 2.
}; };
@@ -401,23 +401,29 @@ static int touch_init()
int touch_power_on() int touch_power_on()
{ {
// Enable LDO6 for touchscreen AVDD supply.
max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000);
max7762x_regulator_enable(REGULATOR_LDO6, true);
// Configure touchscreen VDD GPIO.
PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1;
gpio_direction_output(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH);
// Configure Touscreen and GCAsic shared GPIO. // Configure Touscreen and GCAsic shared GPIO.
PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_LPDR | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 2; PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_LPDR | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 2;
PINMUX_AUX(PINMUX_AUX_CAM_I2C_SCL) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_TRISTATE | PINMUX_PULL_DOWN | 2; PINMUX_AUX(PINMUX_AUX_CAM_I2C_SCL) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_TRISTATE | PINMUX_PULL_DOWN | 2; // Unused.
gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); // GC detect. gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); // GC detect.
// Configure touchscreen Touch Reset pin.
PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1;
gpio_direction_output(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW);
usleep(20);
// Enable LDO6 for touchscreen AVDD and DVDD supply.
max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000);
max7762x_regulator_enable(REGULATOR_LDO6, true);
// Initialize I2C3. // Initialize I2C3.
pinmux_config_i2c(I2C_3); pinmux_config_i2c(I2C_3);
clock_enable_i2c(I2C_3); clock_enable_i2c(I2C_3);
i2c_init(I2C_3); i2c_init(I2C_3);
usleep(1000);
// Set Touch Reset pin.
gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH);
usleep(10000);
// Wait for the touchscreen module to get ready. // Wait for the touchscreen module to get ready.
touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20, NULL); touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20, NULL);
@@ -452,4 +458,4 @@ void touch_power_off()
max7762x_regulator_enable(REGULATOR_LDO6, false); max7762x_regulator_enable(REGULATOR_LDO6, false);
clock_disable_i2c(I2C_3); clock_disable_i2c(I2C_3);
} }

View File

@@ -20,33 +20,33 @@
#include "blz.h" #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; return NULL;
const blz_footer *srcFooter = (const blz_footer*)&compData[compDataLen - sizeof(blz_footer)]; const blz_footer *src_footer = (const blz_footer *)&comp_data[comp_data_size - sizeof(blz_footer)];
if (outFooter != NULL) if (out_footer)
memcpy(outFooter, srcFooter, sizeof(blz_footer)); // Must be a memcpy because no umaligned accesses on ARMv4. 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! // 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 addl_size = footer->addl_size;
u32 header_size = footer->header_size; u32 header_size = footer->header_size;
u32 cmp_and_hdr_size = footer->cmp_and_hdr_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 cmp_ofs = cmp_and_hdr_size - header_size;
u32 out_ofs = cmp_and_hdr_size + addl_size; u32 out_ofs = cmp_and_hdr_size + addl_size;
while (out_ofs) while (out_ofs)
{ {
unsigned char control = cmp_start[--cmp_ofs]; u8 control = cmp_start[--cmp_ofs];
for (unsigned int i=0; i<8; i++) for (u32 i = 0; i < 8; i++)
{ {
if (control & 0x80) if (control & 0x80)
{ {
@@ -54,45 +54,48 @@ int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const
return 0; // Out of bounds. return 0; // Out of bounds.
cmp_ofs -= 2; 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_size = ((seg_val >> 12) & 0xF) + 3;
u32 seg_ofs = (seg_val & 0x0FFF) + 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; seg_size = out_ofs;
out_ofs -= seg_size; 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]; cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
} }
else else // Copy directly.
{ {
// Copy directly.
if (cmp_ofs < 1) if (cmp_ofs < 1)
return 0; //out of bounds return 0; // Out of bounds.
cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
} }
control <<= 1; 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;
}
} }
}
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; blz_footer footer;
const blz_footer *compFooterPtr = blz_get_footer(compData, compDataLen, &footer); const blz_footer *comp_footer = blz_get_footer(comp_data, comp_data_size, &footer);
if (compFooterPtr == NULL) if (!comp_footer)
return 0; return 0;
// Decompression must be done in-place, so need to copy the relevant compressed data first. // Decompression happens in-place, so need to copy the relevant compressed data first.
unsigned int numCompBytes = (const unsigned char*)(compFooterPtr)-compData; u32 comp_bytes = (const u8 *)comp_footer - comp_data;
memcpy(dstData, compData, numCompBytes); memcpy(dst_data, comp_data, comp_bytes);
memset(&dstData[numCompBytes], 0, dstSize - numCompBytes); 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; u32 addl_size;
} blz_footer; } blz_footer;
// Returns pointer to footer in compData if present, additionally copies it to outFooter if not NULL. // 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 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);
// Returns 0 on failure. // 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. // 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 #endif

View File

@@ -92,22 +92,12 @@
# define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static # define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static
#endif #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 * Memory routines
**************************************/ **************************************/
#include <mem/heap.h> /* malloc, calloc, free */ #include <mem/heap.h> /* malloc, calloc, free */
#define ALLOC(s) malloc(s) #define ALLOC(s) malloc(s)
#define ALLOC_AND_ZERO(s) calloc(1,s) #define ALLOC_AND_ZERO(s) zalloc(s)
#define FREEMEM free #define FREEMEM free
#include <string.h> /* memset, memcpy */ #include <string.h> /* memset, memcpy */
#define MEM_INIT memset #define MEM_INIT memset

View File

@@ -61,27 +61,7 @@ DRESULT disk_set_info (BYTE pdrv, BYTE cmd, void *buff);
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
#define SET_SECTOR_OFFSET 5 /* Set media logical offset */ #define SET_SECTOR_OFFSET 5 /* Set media logical offset */
#define SET_WRITE_PROTECT 6 /* Lock/Unlock media removal */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2021 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -39,6 +39,7 @@
#include "ff.h" /* Declarations of FatFs API */ #include "ff.h" /* Declarations of FatFs API */
#include "diskio.h" /* Declarations of device I/O functions */ #include "diskio.h" /* Declarations of device I/O functions */
#include <storage/mbr_gpt.h> #include <storage/mbr_gpt.h>
#include <utils/util.h>
#include <gfx_utils.h> #include <gfx_utils.h>
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); #define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
@@ -4698,13 +4699,20 @@ FRESULT f_lseek (
DWORD *f_expand_cltbl ( DWORD *f_expand_cltbl (
FIL* fp, /* Pointer to the file object */ FIL* fp, /* Pointer to the file object */
UINT tblsz, /* Size of table */ UINT tblsz, /* Size of table (2 DWORDs + 2 DWORDs per fragment) */
FSIZE_t ofs /* File pointer from top of file */ FSIZE_t ofs /* File pointer from top of file */
) )
{ {
/*
* Cluster table structure:
* Size (DWORD)
* Padding (DWORD)
* (Cluster Offset (DWORD) + Sequential clusters (DWORD)) * Fragments
*/
if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */ if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */
if (!fp->cltbl) { /* Allocate memory for cluster link table */ if (!fp->cltbl) { /* Allocate memory for cluster link table */
fp->cltbl = (DWORD *)ff_memalloc(tblsz); fp->cltbl = (DWORD *)ff_memalloc(tblsz);
if (!fp->cltbl) return (void *)0;
fp->cltbl[0] = tblsz; fp->cltbl[0] = tblsz;
} }
if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */ if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */
@@ -6111,10 +6119,26 @@ FRESULT f_mkfs (
for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */
} }
n_clst = sz_vol / pau; /* Number of clusters */ n_clst = sz_vol / pau; /* Number of clusters */
sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ while (1) {
sz_rsv = 32; /* Number of reserved sectors */ /* Do not account for reserved/root cluster on FAT size for better alignment. */
sz_dir = 0; /* No static directory */ sz_fat = (n_clst * 4 + ss - 1) / ss; /* FAT size [sector]. */
if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); sz_rsv = 2048; /* Number of reserved sectors. Use 1MB for better performance (for flash memory media) */
sz_dir = 0; /* No static directory */
if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED);
b_fat = b_vol + sz_rsv; /* FAT base */
b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */
/* Align data base to erase block boundary (for flash memory media) */
n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */
b_fat += n; /* FAT32: Move FAT base */
/* Make sure FAT base is aligned to reserved size for performance (PRF2SAFE min cluster alignment) */
if ((b_fat & (sz_rsv - 1) || (n_fats == 2 && sz_fat & (sz_rsv - 1)))) {
n_clst++; /* FAT size must always be bigger than real free size */
continue;
}
sz_rsv += n;
break;
}
} else { /* FAT volume */ } else { /* FAT volume */
if (pau == 0) { /* au auto-selection */ if (pau == 0) { /* au auto-selection */
n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ n = sz_vol / 0x1000; /* Volume size in unit of 4KS */
@@ -6130,17 +6154,13 @@ FRESULT f_mkfs (
sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */
sz_rsv = 1; /* Number of reserved sectors */ sz_rsv = 1; /* Number of reserved sectors */
sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */
} b_fat = b_vol + sz_rsv; /* FAT base */
b_fat = b_vol + sz_rsv; /* FAT base */ b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */
b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */
/* Align data base to erase block boundary (for flash memory media) */ /* Align data base to erase block boundary (for flash memory media) */
n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */
if (fmt == FS_FAT32) { /* FAT32: Move FAT base */
sz_rsv += n; b_fat += n;
} else { /* FAT: Expand FAT size */
if (n % n_fats) { /* Adjust fractional error if needed */ if (n % n_fats) { /* Adjust fractional error if needed */
n--; sz_rsv++; b_fat++; n--; sz_rsv++; b_fat++; /* FAT: Expand FAT size */
} }
sz_fat += n / n_fats; sz_fat += n / n_fats;
} }
@@ -6183,7 +6203,7 @@ FRESULT f_mkfs (
/* Create FAT VBR */ /* Create FAT VBR */
mem_set(buf, 0, ss); mem_set(buf, 0, ss);
/* Boot jump code (x86), OEM name */ /* Boot jump code (x86), OEM name */
if (!(opt & FM_PRF2)) mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "NYX1.0.0", 11); if (!(opt & FM_PRF2)) mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "NYX1.8.0", 11);
else mem_cpy(buf + BS_JmpBoot, "\xEB\xE9\x90\x00\x00\x00\x00\x00\x00\x00\x00", 11); else mem_cpy(buf + BS_JmpBoot, "\xEB\xE9\x90\x00\x00\x00\x00\x00\x00\x00\x00", 11);
st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */
buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */
@@ -6240,21 +6260,10 @@ FRESULT f_mkfs (
disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */
} }
/* Create PRF2SAFE info */ /* Clear PRF2SAFE info so PrFILE2 can recreate it and upgrade it if old */
if (fmt == FS_FAT32 && opt & FM_PRF2) { if (fmt == FS_FAT32 && opt & FM_PRF2) {
mem_set(buf, 0, ss); mem_set(buf, 0, ss);
st_dword(buf + 0, 0x32465250); /* Magic PRF2 */ disk_write(pdrv, buf, b_vol + 3, 1); /* Write PRF2SAFE info (VBR + 3) */
st_dword(buf + 4, 0x45464153); /* Magic SAFE */
buf[16] = 0x64; /* Record type */
st_dword(buf + 32, 0x03); /* Unknown. SYSTEM: 0x3F00. USER: 0x03. Volatile. */
if (sz_vol < 0x1000000) {
st_dword(buf + 36, 21 + 1); /* 22 Entries. */
st_dword(buf + 508, 0x90BB2F39); /* Sector CRC32 */
} else {
st_dword(buf + 36, 21 + 2); /* 23 Entries. */
st_dword(buf + 508, 0x5EA8AFC8); /* Sector CRC32 */
}
disk_write(pdrv, buf, b_vol + 3, 1); /* Write PRF2SAFE info (VBR + 3) */
} }
/* Initialize FAT area */ /* Initialize FAT area */

57
bdk/libs/fatfs/ffsystem.c Normal file
View File

@@ -0,0 +1,57 @@
/*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */
/* (C) ChaN, 2018 */
/* (C) CTCaer, 2018-2024 */
/*------------------------------------------------------------------------*/
#include <bdk.h>
#include <libs/fatfs/ff.h>
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */
)
{
// Ensure size is aligned to SDMMC block size.
return malloc(ALIGN(msize, SDMMC_DAT_BLOCKSIZE)); /* Allocate a new memory block with POSIX API */
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
)
{
free(mblock); /* Free the memory block with POSIX API */
}
#endif
#if FF_FS_NORTC == 0
/*------------------------------------------------------------------------*/
/* Get real time clock */
/*------------------------------------------------------------------------*/
DWORD get_fattime (
void
)
{
rtc_time_t time;
max77620_rtc_get_time_adjusted(&time);
return (((DWORD)(time.year - 1980) << 25) | ((DWORD)time.month << 21) | ((DWORD)time.day << 16) |
((DWORD)time.hour << 11) | ((DWORD)time.min << 5) | (time.sec >> 1));
}
#endif

View File

@@ -17,7 +17,7 @@
#ifndef LV_CONF_H #ifndef LV_CONF_H
#define LV_CONF_H #define LV_CONF_H
#include <utils/types.h> #include <soc/timer.h>
#include <memory_map.h> #include <memory_map.h>
/*=================== /*===================
Dynamic memory Dynamic memory
@@ -116,8 +116,8 @@
#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ #define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/
#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ #define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */
#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */ #define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */
#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ #define LV_INDEV_LONG_PRESS_TIME 5000 /*Long press time in milliseconds*/
#define LV_INDEV_LONG_PRESS_REP_TIME 1000 //Fix keyb /*Repeated trigger period in long press [ms] */ #define LV_INDEV_LONG_PRESS_REP_TIME 1000 //Fix lv_kb /*Repeated trigger period in long press [ms] */
/*Color settings*/ /*Color settings*/
#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/32*/ #define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/32*/
@@ -147,10 +147,10 @@
#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ #define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/
/*HAL settings*/ /*HAL settings*/
#define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ #define LV_TICK_CUSTOM 1 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */
#if LV_TICK_CUSTOM == 1 #if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE <utils/util.h> /*Header for the sys time function*/ #define LV_TICK_CUSTOM_INCLUDE <soc/timer.h> /*Header for the sys time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (get_tmr_ms()) /*Expression evaluating to current systime in ms*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((u32)get_tmr_ms()) /*Expression evaluating to current systime in ms*/
#endif /*LV_TICK_CUSTOM*/ #endif /*LV_TICK_CUSTOM*/
@@ -296,6 +296,9 @@
/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ /*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/
#define USE_LV_MBOX 1 #define USE_LV_MBOX 1
#if USE_LV_MBOX != 0
# define LV_MBOX_CLOSE_ANIM_TIME 200 /*ms*/
#endif
/*Text area (dependencies: lv_label, lv_page)*/ /*Text area (dependencies: lv_label, lv_page)*/
#define USE_LV_TA 1 #define USE_LV_TA 1

View File

@@ -546,8 +546,8 @@ static void obj_to_foreground(lv_obj_t * obj)
/*Move the last_top object to the foreground*/ /*Move the last_top object to the foreground*/
lv_obj_t * par = lv_obj_get_parent(last_top); lv_obj_t * par = lv_obj_get_parent(last_top);
/*After list change it will be the new head*/ /*After list change it will be the new head*/
lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top); if (lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top))
lv_obj_invalidate(last_top); lv_obj_invalidate(last_top); /*Only invalidate if not top*/
} }
} }

View File

@@ -646,8 +646,8 @@ static void indev_proc_press(lv_indev_proc_t * proc)
/*Move the last_top object to the foreground*/ /*Move the last_top object to the foreground*/
lv_obj_t * par = lv_obj_get_parent(last_top); lv_obj_t * par = lv_obj_get_parent(last_top);
/*After list change it will be the new head*/ /*After list change it will be the new head*/
lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top); if (lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top))
lv_obj_invalidate(last_top); lv_obj_invalidate(last_top); /*Only invalidate if not top*/
} }
/*Send a signal about the press*/ /*Send a signal about the press*/

View File

@@ -412,17 +412,17 @@ static inline uint8_t lv_color_brightness(lv_color_t color)
#endif #endif
#if LV_COLOR_DEPTH == 32 // Concatenate into one 32-bit set. #if LV_COLOR_DEPTH == 32 // Concatenate into one 32-bit set.
#define LV_COLOR_HEX(c) ((lv_color_t){.full = (c | 0xFF000000)}) #define LV_COLOR_HEX(c) ((lv_color_t){.full = ((c) | 0xFF000000)})
#else #else
#define LV_COLOR_HEX(c) LV_COLOR_MAKE(((uint32_t)((uint32_t)c >> 16) & 0xFF), \ #define LV_COLOR_HEX(c) LV_COLOR_MAKE(((uint32_t)((uint32_t)(c) >> 16) & 0xFF), \
((uint32_t)((uint32_t)c >> 8) & 0xFF), \ ((uint32_t)((uint32_t)(c) >> 8) & 0xFF), \
((uint32_t) c & 0xFF)) ((uint32_t) (c) & 0xFF))
#endif #endif
/*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/ /*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/
#define LV_COLOR_HEX3(c) LV_COLOR_MAKE((((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), \ #define LV_COLOR_HEX3(c) LV_COLOR_MAKE(((((c) >> 4) & 0xF0) | (((c) >> 8) & 0xF)), \
((uint32_t)(c & 0xF0) | ((c & 0xF0) >> 4)), \ ((uint32_t)((c) & 0xF0) | (((c) & 0xF0) >> 4)), \
((uint32_t)(c & 0xF) | ((c & 0xF) << 4))) ((uint32_t)((c) & 0xF) | (((c) & 0xF) << 4)))
/** /**

View File

@@ -215,9 +215,12 @@ void lv_ll_clear(lv_ll_t * ll_p)
* @param ll_ori_p pointer to the original (old) linked list * @param ll_ori_p pointer to the original (old) linked list
* @param ll_new_p pointer to the new linked list * @param ll_new_p pointer to the new linked list
* @param node pointer to a node * @param node pointer to a node
* @return head changed
*/ */
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node) bool lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node)
{ {
bool changed = ll_new_p->head != node;
lv_ll_rem(ll_ori_p, node); lv_ll_rem(ll_ori_p, node);
/*Set node as head*/ /*Set node as head*/
@@ -232,6 +235,8 @@ void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node)
if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/ if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/
ll_new_p->tail = node; ll_new_p->tail = node;
} }
return changed;
} }
/** /**

View File

@@ -89,8 +89,9 @@ void lv_ll_clear(lv_ll_t * ll_p);
* @param ll_ori_p pointer to the original (old) linked list * @param ll_ori_p pointer to the original (old) linked list
* @param ll_new_p pointer to the new linked list * @param ll_new_p pointer to the new linked list
* @param node pointer to a node * @param node pointer to a node
* @return head changed
*/ */
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node); bool lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node);
/** /**
* Return with head node of the linked list * Return with head node of the linked list

View File

@@ -316,7 +316,8 @@ static bool lv_task_exec(lv_task_t * lv_task_p)
lv_task_p->last_run = lv_tick_get(); lv_task_p->last_run = lv_tick_get();
task_deleted = false; task_deleted = false;
task_created = false; task_created = false;
lv_task_p->task(lv_task_p->param); if (lv_task_p->task)
lv_task_p->task(lv_task_p->param);
/*Delete if it was a one shot lv_task*/ /*Delete if it was a one shot lv_task*/
if(task_deleted == false) { /*The task might be deleted by itself as well*/ if(task_deleted == false) { /*The task might be deleted by itself as well*/

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018-2022 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -32,13 +32,16 @@
#define COLOR_HOS_TEAL_LIGHT (lv_color_hsv_to_rgb(_hue, 100, 72)) // 0x00B78F #define COLOR_HOS_TEAL_LIGHT (lv_color_hsv_to_rgb(_hue, 100, 72)) // 0x00B78F
#define COLOR_HOS_TEAL (lv_color_hsv_to_rgb(_hue, 100, 64)) // 0x00A273 #define COLOR_HOS_TEAL (lv_color_hsv_to_rgb(_hue, 100, 64)) // 0x00A273
#define COLOR_HOS_ORANGE LV_COLOR_HEX(0xFF5500) #define COLOR_HOS_ORANGE LV_COLOR_HEX(0xFF5500)
#define COLOR_HOS_BG_DARKER LV_COLOR_HEX(0x1B1B1B)
#define COLOR_HOS_BG_DARK LV_COLOR_HEX(0x222222)
#define COLOR_HOS_BG LV_COLOR_HEX(0x2D2D2D)
#define COLOR_HOS_BG_LIGHT LV_COLOR_HEX(0x3D3D3D)
#define COLOR_HOS_LIGHT_BORDER LV_COLOR_HEX(0x4D4D4D)
#define COLOR_HOS_TXT_WHITE LV_COLOR_HEX(0xFBFBFB) #define COLOR_HOS_TXT_WHITE LV_COLOR_HEX(0xFBFBFB)
#define COLOR_BG_DARKER LV_COLOR_HEX(theme_bg_color ? (theme_bg_color - 0x121212) : 0x0B0B0B) // 0x1B1B1B.
#define COLOR_BG_DARK LV_COLOR_HEX(theme_bg_color ? (theme_bg_color - 0x0B0B0B) : 0x121212) // 0x222222.
#define COLOR_BG LV_COLOR_HEX(theme_bg_color) // 0x2D2D2D.
#define COLOR_BG_LIGHT LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x101010) : 0x2D2D2D) // 0x3D3D3D.
#define COLOR_BG_LIGHTER LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x191919) : 0x363636) // 0x464646.
#define COLOR_LIGHT_BORDER LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x202020) : 0x3D3D3D) // 0x4D4D4D.
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
@@ -57,8 +60,9 @@ static lv_style_t def;
static lv_style_t sb; static lv_style_t sb;
/*Saved input parameters*/ /*Saved input parameters*/
static uint16_t _hue; static uint16_t _hue;
static lv_font_t * _font; static lv_font_t * _font;
uint32_t theme_bg_color;
/********************** /**********************
* MACROS * MACROS
@@ -80,18 +84,17 @@ static void basic_init(void)
//def.image.opa = LV_OPA_COVER; //def.image.opa = LV_OPA_COVER;
lv_style_copy(&bg, &def); lv_style_copy(&bg, &def);
bg.body.main_color = COLOR_HOS_BG; bg.body.main_color = COLOR_BG;
//bg.body.main_color = LV_COLOR_BLACK;
bg.body.grad_color = bg.body.main_color; bg.body.grad_color = bg.body.main_color;
bg.body.radius = 0; bg.body.radius = 0;
bg.body.empty = 1; bg.body.empty = 1;
lv_style_copy(&panel, &def); lv_style_copy(&panel, &def);
panel.body.radius = DEF_RADIUS; panel.body.radius = DEF_RADIUS;
panel.body.main_color = COLOR_HOS_BG; panel.body.main_color = COLOR_BG;
panel.body.grad_color = COLOR_HOS_BG; panel.body.grad_color = COLOR_BG;
panel.body.border.width = 1; panel.body.border.width = 1;
panel.body.border.color = COLOR_HOS_LIGHT_BORDER; panel.body.border.color = COLOR_LIGHT_BORDER;
panel.body.border.opa = LV_OPA_COVER; panel.body.border.opa = LV_OPA_COVER;
panel.body.shadow.color = COLOR_SHADOW_LIGHT; panel.body.shadow.color = COLOR_SHADOW_LIGHT;
panel.body.shadow.type = LV_SHADOW_BOTTOM; panel.body.shadow.type = LV_SHADOW_BOTTOM;
@@ -129,7 +132,7 @@ static void btn_init(void)
static lv_style_t rel, pr, tgl_rel, tgl_pr, ina; static lv_style_t rel, pr, tgl_rel, tgl_pr, ina;
lv_style_copy(&rel, &def); lv_style_copy(&rel, &def);
rel.body.main_color = COLOR_HOS_BG_LIGHT; rel.body.main_color = COLOR_BG_LIGHT;
rel.body.grad_color = rel.body.main_color; rel.body.grad_color = rel.body.main_color;
rel.body.radius = 6; rel.body.radius = 6;
rel.body.padding.hor = LV_DPI / 3; rel.body.padding.hor = LV_DPI / 3;
@@ -139,7 +142,7 @@ static void btn_init(void)
rel.body.shadow.type = LV_SHADOW_BOTTOM; rel.body.shadow.type = LV_SHADOW_BOTTOM;
rel.body.shadow.width = 6; rel.body.shadow.width = 6;
rel.body.border.width = 0; rel.body.border.width = 0;
rel.body.border.color = COLOR_HOS_BG_LIGHT; rel.body.border.color = COLOR_BG_LIGHT;
rel.body.border.part = LV_BORDER_FULL; rel.body.border.part = LV_BORDER_FULL;
//rel.text.color = COLOR_HOS_TXT_WHITE; //rel.text.color = COLOR_HOS_TXT_WHITE;
@@ -162,7 +165,7 @@ static void btn_init(void)
tgl_pr.body.shadow.width = 0; tgl_pr.body.shadow.width = 0;
lv_style_copy(&ina, &rel); lv_style_copy(&ina, &rel);
ina.body.main_color = COLOR_HOS_BG_DARK; ina.body.main_color = COLOR_BG_DARK;
ina.body.grad_color = ina.body.main_color; ina.body.grad_color = ina.body.main_color;
//ina.body.shadow.width = 0; //ina.body.shadow.width = 0;
ina.text.color = LV_COLOR_HEX(0x888888); ina.text.color = LV_COLOR_HEX(0x888888);
@@ -207,7 +210,7 @@ static void img_init(void)
img_light.image.intense = LV_OPA_80; img_light.image.intense = LV_OPA_80;
lv_style_copy(&img_dark, &def); lv_style_copy(&img_dark, &def);
img_dark.image.color = COLOR_HOS_BG_DARKER; img_dark.image.color = COLOR_BG_DARKER;
img_dark.image.intense = LV_OPA_80; img_dark.image.intense = LV_OPA_80;
@@ -250,7 +253,7 @@ static void bar_init(void)
static lv_style_t bar_bg, bar_indic; static lv_style_t bar_bg, bar_indic;
lv_style_copy(&bar_bg, &def); lv_style_copy(&bar_bg, &def);
bar_bg.body.main_color = COLOR_HOS_LIGHT_BORDER; bar_bg.body.main_color = COLOR_LIGHT_BORDER;
bar_bg.body.grad_color = bar_bg.body.main_color; bar_bg.body.grad_color = bar_bg.body.main_color;
bar_bg.body.radius = 3; bar_bg.body.radius = 3;
bar_bg.body.border.width = 0; bar_bg.body.border.width = 0;
@@ -536,9 +539,9 @@ static void mbox_init(void)
static lv_style_t bg; static lv_style_t bg;
lv_style_copy(&bg, theme.panel); lv_style_copy(&bg, theme.panel);
bg.body.main_color = LV_COLOR_HEX(0x464646); bg.body.main_color = COLOR_BG_LIGHTER;
bg.body.grad_color = bg.body.main_color; bg.body.grad_color = bg.body.main_color;
bg.body.shadow.color = COLOR_HOS_BG; bg.body.shadow.color = COLOR_BG;
bg.body.shadow.type = LV_SHADOW_FULL; bg.body.shadow.type = LV_SHADOW_FULL;
bg.body.shadow.width = 8; bg.body.shadow.width = 8;
@@ -628,7 +631,7 @@ static void list_init(void)
// pr.text.font = _font; // pr.text.font = _font;
lv_style_copy(&tgl_rel, &pr); lv_style_copy(&tgl_rel, &pr);
tgl_rel.body.main_color = COLOR_HOS_BG_LIGHT; tgl_rel.body.main_color = COLOR_BG_LIGHT;
tgl_rel.body.grad_color = tgl_rel.body.main_color; tgl_rel.body.grad_color = tgl_rel.body.main_color;
//tgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95); //tgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95);
tgl_rel.text.color = COLOR_HOS_TEAL_LIGHTER; tgl_rel.text.color = COLOR_HOS_TEAL_LIGHTER;
@@ -639,7 +642,7 @@ static void list_init(void)
tgl_pr.body.border.width = 0; tgl_pr.body.border.width = 0;
lv_style_copy(&ina, &pr); lv_style_copy(&ina, &pr);
ina.body.main_color = COLOR_HOS_BG_DARK; ina.body.main_color = COLOR_BG_DARK;
ina.body.grad_color = ina.body.main_color; ina.body.grad_color = ina.body.main_color;
theme.list.sb = &sb; theme.list.sb = &sb;
@@ -667,7 +670,7 @@ static void ddlist_init(void)
bg.text.color = COLOR_HOS_TURQUOISE; bg.text.color = COLOR_HOS_TURQUOISE;
lv_style_copy(&sel, &bg); lv_style_copy(&sel, &bg);
sel.body.main_color = COLOR_HOS_BG_LIGHT; sel.body.main_color = COLOR_BG_LIGHT;
sel.body.grad_color = sel.body.main_color; sel.body.grad_color = sel.body.main_color;
theme.ddlist.bg = &bg; theme.ddlist.bg = &bg;
@@ -713,7 +716,7 @@ static void tabview_init(void)
indic.body.opa = LV_OPA_0; indic.body.opa = LV_OPA_0;
lv_style_copy(&btn_bg, &def); lv_style_copy(&btn_bg, &def);
btn_bg.body.main_color = COLOR_HOS_BG; btn_bg.body.main_color = COLOR_BG;
btn_bg.body.grad_color = btn_bg.body.main_color; btn_bg.body.grad_color = btn_bg.body.main_color;
btn_bg.body.radius = 0; btn_bg.body.radius = 0;
btn_bg.body.empty = 1; btn_bg.body.empty = 1;
@@ -734,7 +737,7 @@ static void tabview_init(void)
rel.text.font = _font; rel.text.font = _font;
lv_style_copy(&pr, &def); lv_style_copy(&pr, &def);
pr.body.main_color = COLOR_HOS_BG_LIGHT; pr.body.main_color = COLOR_BG_LIGHT;
pr.body.grad_color = pr.body.main_color; pr.body.grad_color = pr.body.main_color;
pr.body.border.width = 0; pr.body.border.width = 0;
pr.body.empty = 0; pr.body.empty = 0;
@@ -750,7 +753,7 @@ static void tabview_init(void)
tgl_rel.text.color = COLOR_HOS_TURQUOISE; tgl_rel.text.color = COLOR_HOS_TURQUOISE;
lv_style_copy(&tgl_pr, &def); lv_style_copy(&tgl_pr, &def);
tgl_pr.body.main_color = COLOR_HOS_BG_LIGHT; tgl_pr.body.main_color = COLOR_BG_LIGHT;
tgl_pr.body.grad_color = tgl_pr.body.main_color; tgl_pr.body.grad_color = tgl_pr.body.main_color;
tgl_pr.body.border.width = 0; tgl_pr.body.border.width = 0;
tgl_pr.body.empty = 0; tgl_pr.body.empty = 0;
@@ -797,7 +800,7 @@ static void win_init(void)
static lv_style_t header, rel, pr; static lv_style_t header, rel, pr;
lv_style_copy(&header, &def); lv_style_copy(&header, &def);
header.body.main_color = COLOR_HOS_BG; header.body.main_color = COLOR_BG;
header.body.grad_color = header.body.main_color; header.body.grad_color = header.body.main_color;
header.body.radius = 0; header.body.radius = 0;
header.body.border.width = 0; header.body.border.width = 0;
@@ -843,10 +846,11 @@ static void win_init(void)
* @param font pointer to a font (NULL to use the default) * @param font pointer to a font (NULL to use the default)
* @return pointer to the initialized theme * @return pointer to the initialized theme
*/ */
lv_theme_t * lv_theme_hekate_init(uint16_t hue, lv_font_t * font) lv_theme_t * lv_theme_hekate_init(uint32_t bg_color, uint16_t hue, lv_font_t * font)
{ {
if(font == NULL) font = LV_FONT_DEFAULT; if(font == NULL) font = LV_FONT_DEFAULT;
theme_bg_color = bg_color;
_hue = hue; _hue = hue;
_font = font; _font = font;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018-2022 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -35,6 +35,14 @@ extern "C" {
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
#define COLOR_HOS_BG_BASE_DEFAULT 0x1B1B1B
#define COLOR_HOS_BG_BASE_BLACK 0x000000
#define COLOR_HOS_BG_DARKER 0x1B1B1B
#define COLOR_HOS_BG_DARK 0x222222
#define COLOR_HOS_BG 0x2D2D2D
#define COLOR_HOS_BG_LIGHT 0x3D3D3D
#define COLOR_HOS_LIGHT_BORDER 0x4D4D4D
/********************** /**********************
* TYPEDEFS * TYPEDEFS
@@ -44,13 +52,15 @@ extern "C" {
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
extern uint32_t theme_bg_color;
/** /**
* Initialize the material theme * Initialize the material theme
* @param hue [0..360] hue value from HSV color space to define the theme's base color * @param hue [0..360] hue value from HSV color space to define the theme's base color
* @param font pointer to a font (NULL to use the default) * @param font pointer to a font (NULL to use the default)
* @return pointer to the initialized theme * @return pointer to the initialized theme
*/ */
lv_theme_t * lv_theme_hekate_init(uint16_t hue, lv_font_t *font); lv_theme_t * lv_theme_hekate_init(uint32_t bg_color, uint16_t hue, lv_font_t *font);
/** /**
* Get a pointer to the theme * Get a pointer to the theme

View File

@@ -70,89 +70,89 @@ typedef struct {
allocation_table_header_t *header; allocation_table_header_t *header;
} allocation_table_ctx_t; } allocation_table_ctx_t;
static ALWAYS_INLINE uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) { static inline __attribute__((always_inline)) uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) {
return entry_index - 1; return entry_index - 1;
} }
static ALWAYS_INLINE uint32_t allocation_table_block_to_entry_index(uint32_t block_index) { static inline __attribute__((always_inline)) uint32_t allocation_table_block_to_entry_index(uint32_t block_index) {
return block_index + 1; return block_index + 1;
} }
static ALWAYS_INLINE int allocation_table_get_prev(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) int allocation_table_get_prev(allocation_table_entry_t *entry) {
return entry->prev & 0x7FFFFFFF; return entry->prev & 0x7FFFFFFF;
} }
static ALWAYS_INLINE int allocation_table_get_next(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) int allocation_table_get_next(allocation_table_entry_t *entry) {
return entry->next & 0x7FFFFFFF; return entry->next & 0x7FFFFFFF;
} }
static ALWAYS_INLINE int allocation_table_is_list_start(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) int allocation_table_is_list_start(allocation_table_entry_t *entry) {
return entry->prev == 0x80000000; return entry->prev == 0x80000000;
} }
static ALWAYS_INLINE int allocation_table_is_list_end(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) int allocation_table_is_list_end(allocation_table_entry_t *entry) {
return (entry->next & 0x7FFFFFFF) == 0; return (entry->next & 0x7FFFFFFF) == 0;
} }
static ALWAYS_INLINE bool allocation_table_is_multi_block_segment(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) bool allocation_table_is_multi_block_segment(allocation_table_entry_t *entry) {
return entry->next & 0x80000000; return entry->next & 0x80000000;
} }
static ALWAYS_INLINE void allocation_table_make_multi_block_segment(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) void allocation_table_make_multi_block_segment(allocation_table_entry_t *entry) {
entry->next |= 0x80000000; entry->next |= 0x80000000;
} }
static ALWAYS_INLINE void allocation_table_make_single_block_segment(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) void allocation_table_make_single_block_segment(allocation_table_entry_t *entry) {
entry->next &= 0x7FFFFFFF; entry->next &= 0x7FFFFFFF;
} }
static ALWAYS_INLINE bool allocation_table_is_single_block_segment(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) bool allocation_table_is_single_block_segment(allocation_table_entry_t *entry) {
return (entry->next & 0x80000000) == 0; return (entry->next & 0x80000000) == 0;
} }
static ALWAYS_INLINE void allocation_table_make_list_start(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) void allocation_table_make_list_start(allocation_table_entry_t *entry) {
entry->prev = 0x80000000; entry->prev = 0x80000000;
} }
static ALWAYS_INLINE bool allocation_table_is_range_entry(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) bool allocation_table_is_range_entry(allocation_table_entry_t *entry) {
return (entry->prev & 0x80000000) == 0x80000000 && entry->prev != 0x80000000; return (entry->prev & 0x80000000) == 0x80000000 && entry->prev != 0x80000000;
} }
static ALWAYS_INLINE void allocation_table_make_range_entry(allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) void allocation_table_make_range_entry(allocation_table_entry_t *entry) {
entry->prev |= 0x80000000; entry->prev |= 0x80000000;
} }
static ALWAYS_INLINE void allocation_table_set_next(allocation_table_entry_t *entry, int val) { static inline __attribute__((always_inline)) void allocation_table_set_next(allocation_table_entry_t *entry, int val) {
entry->next = (entry->next & 0x80000000) | val; entry->next = (entry->next & 0x80000000) | val;
} }
static ALWAYS_INLINE void allocation_table_set_prev(allocation_table_entry_t *entry, int val) { static inline __attribute__((always_inline)) void allocation_table_set_prev(allocation_table_entry_t *entry, int val) {
entry->prev = val; entry->prev = val;
} }
static ALWAYS_INLINE void allocation_table_set_range(allocation_table_entry_t *entry, int start_index, int end_index) { static inline __attribute__((always_inline)) void allocation_table_set_range(allocation_table_entry_t *entry, int start_index, int end_index) {
entry->next = end_index; entry->next = end_index;
entry->prev = start_index; entry->prev = start_index;
allocation_table_make_range_entry(entry); allocation_table_make_range_entry(entry);
} }
static ALWAYS_INLINE uint64_t allocation_table_query_size(uint32_t block_count) { static inline __attribute__((always_inline)) uint64_t allocation_table_query_size(uint32_t block_count) {
return SAVE_FAT_ENTRY_SIZE * allocation_table_block_to_entry_index(block_count); return SAVE_FAT_ENTRY_SIZE * allocation_table_block_to_entry_index(block_count);
} }
static ALWAYS_INLINE allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) { static inline __attribute__((always_inline)) allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) {
return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE); return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE);
} }
static ALWAYS_INLINE void save_allocation_table_write_entry(allocation_table_ctx_t *ctx, uint32_t entry_index, allocation_table_entry_t *entry) { static inline __attribute__((always_inline)) void save_allocation_table_write_entry(allocation_table_ctx_t *ctx, uint32_t entry_index, allocation_table_entry_t *entry) {
memcpy((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE, entry, SAVE_FAT_ENTRY_SIZE); memcpy((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE, entry, SAVE_FAT_ENTRY_SIZE);
} }
static ALWAYS_INLINE uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) { static inline __attribute__((always_inline)) uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) {
return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index)); return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index));
} }
static ALWAYS_INLINE uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) { static inline __attribute__((always_inline)) uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) {
return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx)); return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx));
} }

View File

@@ -48,7 +48,7 @@ typedef struct {
uint64_t _length; uint64_t _length;
} allocation_table_storage_ctx_t; } allocation_table_storage_ctx_t;
static ALWAYS_INLINE void save_allocation_table_storage_get_size(allocation_table_storage_ctx_t *ctx, uint64_t *out_size) { static inline __attribute__((always_inline)) void save_allocation_table_storage_get_size(allocation_table_storage_ctx_t *ctx, uint64_t *out_size) {
*out_size = ctx->_length; *out_size = ctx->_length;
} }

View File

@@ -39,7 +39,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <string.h> #include <string.h>
static ALWAYS_INLINE cache_block_t *cache_block_init(cached_storage_ctx_t *ctx) { static inline __attribute__((always_inline)) cache_block_t *cache_block_init(cached_storage_ctx_t *ctx) {
cache_block_t *block = calloc(1, sizeof(cache_block_t)); cache_block_t *block = calloc(1, sizeof(cache_block_t));
block->buffer = malloc(ctx->block_size); block->buffer = malloc(ctx->block_size);
block->index = -1; block->index = -1;

View File

@@ -57,15 +57,15 @@ typedef struct {
substorage base_storage; substorage base_storage;
} duplex_storage_ctx_t; } duplex_storage_ctx_t;
static ALWAYS_INLINE void save_bitmap_set_bit(void *buffer, uint64_t bit_offset) { static inline __attribute__((always_inline)) void save_bitmap_set_bit(void *buffer, uint64_t bit_offset) {
*((uint8_t *)buffer + (bit_offset >> 3)) |= 1 << (bit_offset & 7); *((uint8_t *)buffer + (bit_offset >> 3)) |= 1 << (bit_offset & 7);
} }
static ALWAYS_INLINE void save_bitmap_clear_bit(void *buffer, uint64_t bit_offset) { static inline __attribute__((always_inline)) void save_bitmap_clear_bit(void *buffer, uint64_t bit_offset) {
*((uint8_t *)buffer + (bit_offset >> 3)) &= ~(uint8_t)(1 << (bit_offset & 7)); *((uint8_t *)buffer + (bit_offset >> 3)) &= ~(uint8_t)(1 << (bit_offset & 7));
} }
static ALWAYS_INLINE uint8_t save_bitmap_check_bit(const void *buffer, uint64_t bit_offset) { static inline __attribute__((always_inline)) uint8_t save_bitmap_check_bit(const void *buffer, uint64_t bit_offset) {
return *((uint8_t *)buffer + (bit_offset >> 3)) & (1 << (bit_offset & 7)); return *((uint8_t *)buffer + (bit_offset >> 3)) & (1 << (bit_offset & 7));
} }

View File

@@ -28,12 +28,12 @@ typedef struct {
uint32_t high; uint32_t high;
} fs_int64_t; } fs_int64_t;
static ALWAYS_INLINE void fs_int64_set(fs_int64_t *i, int64_t val) { static inline __attribute__((always_inline)) void fs_int64_set(fs_int64_t *i, int64_t val) {
i->low = (uint32_t)((val & (uint64_t)(0x00000000FFFFFFFFul)) >> 0); i->low = (uint32_t)((val & (uint64_t)(0x00000000FFFFFFFFul)) >> 0);
i->high = (uint32_t)((val & (uint64_t)(0xFFFFFFFF00000000ul)) >> 32); i->high = (uint32_t)((val & (uint64_t)(0xFFFFFFFF00000000ul)) >> 32);
} }
static ALWAYS_INLINE const int64_t fs_int64_get(fs_int64_t *i) { static inline __attribute__((always_inline)) const int64_t fs_int64_get(fs_int64_t *i) {
return ((int64_t)(i->high) << 32) | ((int64_t)i->low); return ((int64_t)(i->high) << 32) | ((int64_t)i->low);
} }

View File

@@ -41,6 +41,52 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <string.h> #include <string.h>
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size)
{
int res = 0;
u8 tmp1[0x40] = {0};
u8 tmp2[0x40 + src_size];
u8 tmp3[0x60] = {0};
memset(tmp2, 0, 0x40 + src_size);
u8 *secret = (u8 *)tmp1;
u8 *ipad = (u8 *)tmp2;
u8 *opad = (u8 *)tmp3;
if (key_size > 0x40)
{
if (!se_calc_sha256_oneshot(secret, key, key_size))
goto out;
memset(secret + 0x20, 0, 0x20);
}
else
{
memcpy(secret, key, key_size);
memset(secret + key_size, 0, 0x40 - key_size);
}
u32 *secret32 = (u32 *)secret;
u32 *ipad32 = (u32 *)ipad;
u32 *opad32 = (u32 *)opad;
for (u32 i = 0; i < 0x10; i++)
{
ipad32[i] = secret32[i] ^ 0x36363636;
opad32[i] = secret32[i] ^ 0x5C5C5C5C;
}
memcpy(ipad + 0x40, src, src_size);
if (!se_calc_sha256_oneshot(dst, ipad, 0x40 + src_size))
goto out;
memcpy(opad + 0x40, dst, 0x20);
if (!se_calc_sha256_oneshot(dst, opad, 0x60))
goto out;
res = 1;
out:;
return res;
}
void save_hierarchical_integrity_verification_storage_control_area_query_size(ivfc_size_set_t *out, const ivfc_storage_control_input_param_t *input_param, int32_t layer_count, uint64_t data_size) { void save_hierarchical_integrity_verification_storage_control_area_query_size(ivfc_size_set_t *out, const ivfc_storage_control_input_param_t *input_param, int32_t layer_count, uint64_t data_size) {
int64_t level_size[IVFC_MAX_LEVEL + 1]; int64_t level_size[IVFC_MAX_LEVEL + 1];
int32_t level = layer_count - 1; int32_t level = layer_count - 1;

View File

@@ -311,7 +311,7 @@ bool save_hierarchical_file_table_rename_file(hierarchical_save_file_table_ctx_t
return save_fs_list_change_key(&ctx->file_table, &old_key, &new_key); return save_fs_list_change_key(&ctx->file_table, &old_key, &new_key);
} }
static ALWAYS_INLINE bool save_is_sub_path(const char *path1, const char *path2) { static inline __attribute__((always_inline)) bool save_is_sub_path(const char *path1, const char *path2) {
/* Check if either path is subpath of the other. */ /* Check if either path is subpath of the other. */
uint64_t path1_len = strlen(path1), path2_len = strlen(path2); uint64_t path1_len = strlen(path1), path2_len = strlen(path2);
if (path1_len == 0 || path2_len == 0) if (path1_len == 0 || path2_len == 0)

View File

@@ -50,13 +50,13 @@ void save_ivfc_storage_init(integrity_verification_storage_ctx_t *ctx, integrity
} }
/* buffer must have size count + 0x20 for salt to by copied in at offset 0. */ /* buffer must have size count + 0x20 for salt to by copied in at offset 0. */
static ALWAYS_INLINE void save_ivfc_storage_do_hash(integrity_verification_storage_ctx_t *ctx, uint8_t *out_hash, void *buffer, uint64_t count) { static inline __attribute__((always_inline)) void save_ivfc_storage_do_hash(integrity_verification_storage_ctx_t *ctx, uint8_t *out_hash, void *buffer, uint64_t count) {
memcpy(buffer, ctx->salt, sizeof(ctx->salt)); memcpy(buffer, ctx->salt, sizeof(ctx->salt));
se_calc_sha256_oneshot(out_hash, buffer, count + sizeof(ctx->salt)); se_calc_sha256_oneshot(out_hash, buffer, count + sizeof(ctx->salt));
out_hash[0x1F] |= 0x80; out_hash[0x1F] |= 0x80;
} }
static ALWAYS_INLINE bool is_empty(const void *buffer, uint64_t count) { static inline __attribute__((always_inline)) bool is_empty(const void *buffer, uint64_t count) {
bool empty = true; bool empty = true;
const uint8_t *buf = (const uint8_t *)buffer; const uint8_t *buf = (const uint8_t *)buffer;
for (uint64_t i = 0; i < count; i++) { for (uint64_t i = 0; i < count; i++) {

View File

@@ -39,6 +39,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <stdint.h> #include <stdint.h>
typedef enum
{
VALIDITY_UNCHECKED = 0,
VALIDITY_INVALID,
VALIDITY_VALID
} validity_t;
typedef struct { typedef struct {
substorage hash_storage; substorage hash_storage;
int integrity_check_level; int integrity_check_level;

View File

@@ -71,11 +71,11 @@ typedef struct {
uint8_t *free_blocks; uint8_t *free_blocks;
} journal_map_ctx_t; } journal_map_ctx_t;
static ALWAYS_INLINE uint32_t save_journal_map_entry_make_physical_index(uint32_t index) { static inline __attribute__((always_inline)) uint32_t save_journal_map_entry_make_physical_index(uint32_t index) {
return index | 0x80000000; return index | 0x80000000;
} }
static ALWAYS_INLINE uint32_t save_journal_map_entry_get_physical_index(uint32_t index) { static inline __attribute__((always_inline)) uint32_t save_journal_map_entry_get_physical_index(uint32_t index) {
return index & 0x7FFFFFFF; return index & 0x7FFFFFFF;
} }

View File

@@ -47,7 +47,7 @@ typedef struct {
bool _finished; bool _finished;
} path_parser_ctx_t; } path_parser_ctx_t;
static ALWAYS_INLINE bool save_path_parser_is_finished(path_parser_ctx_t *ctx) { static inline __attribute__((always_inline)) bool save_path_parser_is_finished(path_parser_ctx_t *ctx) {
return ctx->_finished; return ctx->_finished;
} }

View File

@@ -80,7 +80,7 @@ remap_segment_ctx_t *save_remap_storage_init_segments(remap_storage_ctx_t *ctx)
return segments; return segments;
} }
static ALWAYS_INLINE remap_entry_ctx_t *save_remap_storage_get_map_entry(remap_storage_ctx_t *ctx, uint64_t offset) { static inline __attribute__((always_inline)) remap_entry_ctx_t *save_remap_storage_get_map_entry(remap_storage_ctx_t *ctx, uint64_t offset) {
uint32_t segment_idx = save_remap_get_segment_from_virtual_offset(ctx->header, offset); uint32_t segment_idx = save_remap_get_segment_from_virtual_offset(ctx->header, offset);
if (segment_idx < ctx->header->map_segment_count) { if (segment_idx < ctx->header->map_segment_count) {
for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++) { for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++) {

View File

@@ -89,11 +89,11 @@ typedef struct {
substorage base_storage; substorage base_storage;
} remap_storage_ctx_t; } remap_storage_ctx_t;
static ALWAYS_INLINE uint32_t save_remap_get_segment_from_virtual_offset(remap_header_t *header, uint64_t offset) { static inline __attribute__((always_inline)) uint32_t save_remap_get_segment_from_virtual_offset(remap_header_t *header, uint64_t offset) {
return (uint32_t)(offset >> (64 - header->segment_bits)); return (uint32_t)(offset >> (64 - header->segment_bits));
} }
static ALWAYS_INLINE uint64_t save_remap_get_virtual_offset(remap_header_t *header, uint64_t segment) { static inline __attribute__((always_inline)) uint64_t save_remap_get_virtual_offset(remap_header_t *header, uint64_t segment) {
return segment << (64 - header->segment_bits); return segment << (64 - header->segment_bits);
} }

View File

@@ -106,7 +106,7 @@ static bool save_process_header(save_ctx_t *ctx) {
uint8_t cmac[0x10] __attribute__((aligned(4))); uint8_t cmac[0x10] __attribute__((aligned(4)));
se_aes_key_set(10, ctx->save_mac_key, 0x10); se_aes_key_set(10, ctx->save_mac_key, 0x10);
se_aes_cmac(10, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); se_aes_cmac_128(10, cmac, &ctx->header.layout, sizeof(ctx->header.layout));
if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) { if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) {
ctx->header_cmac_validity = VALIDITY_VALID; ctx->header_cmac_validity = VALIDITY_VALID;
} else { } else {
@@ -298,7 +298,7 @@ void save_free_contexts(save_ctx_t *ctx) {
free(ctx->fat_storage); free(ctx->fat_storage);
} }
static ALWAYS_INLINE bool save_flush(save_ctx_t *ctx) { static inline __attribute__((always_inline)) bool save_flush(save_ctx_t *ctx) {
if (ctx->header.layout.version < VERSION_DISF_5) { if (ctx->header.layout.version < VERSION_DISF_5) {
if (!save_cached_storage_flush(ctx->core_data_ivfc_storage.data_level)) { if (!save_cached_storage_flush(ctx->core_data_ivfc_storage.data_level)) {
EPRINTF("Failed to flush cached storage!"); EPRINTF("Failed to flush cached storage!");
@@ -329,7 +329,7 @@ bool save_commit(save_ctx_t *ctx) {
se_calc_sha256_oneshot(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size); se_calc_sha256_oneshot(ctx->header.layout.hash, header + hashed_data_offset, hashed_data_size);
se_aes_key_set(10, ctx->save_mac_key, 0x10); se_aes_key_set(10, ctx->save_mac_key, 0x10);
se_aes_cmac(10, ctx->header.cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout)); se_aes_cmac_128(10, ctx->header.cmac, &ctx->header.layout, sizeof(ctx->header.layout));
if (substorage_write(&ctx->base_storage, &ctx->header, 0, sizeof(ctx->header)) != sizeof(ctx->header)) { if (substorage_write(&ctx->base_storage, &ctx->header, 0, sizeof(ctx->header)) != sizeof(ctx->header)) {
EPRINTF("Failed to write save header!"); EPRINTF("Failed to write save header!");

View File

@@ -95,7 +95,7 @@ typedef struct {
static_assert(sizeof(save_data_creation_info_t) == 0x40, "Save data creation info size is wrong!"); static_assert(sizeof(save_data_creation_info_t) == 0x40, "Save data creation info size is wrong!");
static ALWAYS_INLINE uint32_t save_calc_map_entry_storage_size(int32_t entry_count) { static inline __attribute__((always_inline)) uint32_t save_calc_map_entry_storage_size(int32_t entry_count) {
int32_t val = entry_count < 1 ? entry_count : entry_count - 1; int32_t val = entry_count < 1 ? entry_count : entry_count - 1;
return (entry_count + (val >> 1)) * sizeof(remap_entry_t); return (entry_count + (val >> 1)) * sizeof(remap_entry_t);
} }
@@ -107,47 +107,47 @@ bool save_create_system_save_data(save_ctx_t *ctx, uint32_t version, const char
void save_free_contexts(save_ctx_t *ctx); void save_free_contexts(save_ctx_t *ctx);
bool save_commit(save_ctx_t *ctx); bool save_commit(save_ctx_t *ctx);
static ALWAYS_INLINE bool save_create_directory(save_ctx_t *ctx, const char *path) { static inline __attribute__((always_inline)) bool save_create_directory(save_ctx_t *ctx, const char *path) {
return save_data_file_system_core_create_directory(&ctx->save_filesystem_core, path); return save_data_file_system_core_create_directory(&ctx->save_filesystem_core, path);
} }
static ALWAYS_INLINE bool save_create_file(save_ctx_t *ctx, const char *path, uint64_t size) { static inline __attribute__((always_inline)) bool save_create_file(save_ctx_t *ctx, const char *path, uint64_t size) {
return save_data_file_system_core_create_file(&ctx->save_filesystem_core, path, size); return save_data_file_system_core_create_file(&ctx->save_filesystem_core, path, size);
} }
static ALWAYS_INLINE bool save_delete_directory(save_ctx_t *ctx, const char *path) { static inline __attribute__((always_inline)) bool save_delete_directory(save_ctx_t *ctx, const char *path) {
return save_data_file_system_core_delete_directory(&ctx->save_filesystem_core,path); return save_data_file_system_core_delete_directory(&ctx->save_filesystem_core,path);
} }
static ALWAYS_INLINE bool save_delete_file(save_ctx_t *ctx, const char *path) { static inline __attribute__((always_inline)) bool save_delete_file(save_ctx_t *ctx, const char *path) {
return save_data_file_system_core_delete_file(&ctx->save_filesystem_core, path); return save_data_file_system_core_delete_file(&ctx->save_filesystem_core, path);
} }
static ALWAYS_INLINE bool save_open_directory(save_ctx_t *ctx, save_data_directory_ctx_t *directory, const char *path, open_directory_mode_t mode) { static inline __attribute__((always_inline)) bool save_open_directory(save_ctx_t *ctx, save_data_directory_ctx_t *directory, const char *path, open_directory_mode_t mode) {
return save_data_file_system_core_open_directory(&ctx->save_filesystem_core, directory, path, mode); return save_data_file_system_core_open_directory(&ctx->save_filesystem_core, directory, path, mode);
} }
static ALWAYS_INLINE bool save_open_file(save_ctx_t *ctx, save_data_file_ctx_t *file, const char *path, open_mode_t mode) { static inline __attribute__((always_inline)) bool save_open_file(save_ctx_t *ctx, save_data_file_ctx_t *file, const char *path, open_mode_t mode) {
return save_data_file_system_core_open_file(&ctx->save_filesystem_core, file, path, mode); return save_data_file_system_core_open_file(&ctx->save_filesystem_core, file, path, mode);
} }
static ALWAYS_INLINE bool save_rename_directory(save_ctx_t *ctx, const char *old_path, const char *new_path) { static inline __attribute__((always_inline)) bool save_rename_directory(save_ctx_t *ctx, const char *old_path, const char *new_path) {
return save_data_file_system_core_rename_directory(&ctx->save_filesystem_core, old_path, new_path); return save_data_file_system_core_rename_directory(&ctx->save_filesystem_core, old_path, new_path);
} }
static ALWAYS_INLINE bool save_rename_file(save_ctx_t *ctx, const char *old_path, const char *new_path) { static inline __attribute__((always_inline)) bool save_rename_file(save_ctx_t *ctx, const char *old_path, const char *new_path) {
return save_data_file_system_core_rename_file(&ctx->save_filesystem_core, old_path, new_path); return save_data_file_system_core_rename_file(&ctx->save_filesystem_core, old_path, new_path);
} }
static ALWAYS_INLINE bool save_get_entry_type(save_ctx_t *ctx, directory_entry_type_t *out_entry_type, const char *path) { static inline __attribute__((always_inline)) bool save_get_entry_type(save_ctx_t *ctx, directory_entry_type_t *out_entry_type, const char *path) {
return save_data_file_system_core_get_entry_type(&ctx->save_filesystem_core, out_entry_type, path); return save_data_file_system_core_get_entry_type(&ctx->save_filesystem_core, out_entry_type, path);
} }
static ALWAYS_INLINE void save_get_free_space_size(save_ctx_t *ctx, uint64_t *out_free_space) { static inline __attribute__((always_inline)) void save_get_free_space_size(save_ctx_t *ctx, uint64_t *out_free_space) {
return save_data_file_system_core_get_free_space_size(&ctx->save_filesystem_core, out_free_space); return save_data_file_system_core_get_free_space_size(&ctx->save_filesystem_core, out_free_space);
} }
static ALWAYS_INLINE void save_get_total_space_size(save_ctx_t *ctx, uint64_t *out_total_size) { static inline __attribute__((always_inline)) void save_get_total_space_size(save_ctx_t *ctx, uint64_t *out_total_size) {
return save_data_file_system_core_get_total_space_size(&ctx->save_filesystem_core, out_total_size); return save_data_file_system_core_get_total_space_size(&ctx->save_filesystem_core, out_total_size);
} }

View File

@@ -42,6 +42,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <stdint.h> #include <stdint.h>
typedef enum
{
OPEN_MODE_READ = 1,
OPEN_MODE_WRITE = 2,
OPEN_MODE_ALLOW_APPEND = 4,
OPEN_MODE_READ_WRITE = OPEN_MODE_READ | OPEN_MODE_WRITE,
OPEN_MODE_ALL = OPEN_MODE_READ | OPEN_MODE_WRITE | OPEN_MODE_ALLOW_APPEND
} open_mode_t;
typedef struct { typedef struct {
allocation_table_storage_ctx_t base_storage; allocation_table_storage_ctx_t base_storage;
const char *path; const char *path;
@@ -50,7 +59,7 @@ typedef struct {
open_mode_t mode; open_mode_t mode;
} save_data_file_ctx_t; } save_data_file_ctx_t;
static ALWAYS_INLINE void save_data_file_get_size(save_data_file_ctx_t *ctx, uint64_t *out_size) { static inline __attribute__((always_inline)) void save_data_file_get_size(save_data_file_ctx_t *ctx, uint64_t *out_size) {
*out_size = ctx->size; *out_size = ctx->size;
} }

View File

@@ -41,7 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <gfx_utils.h> #include <gfx_utils.h>
#include <mem/heap.h> #include <mem/heap.h>
static ALWAYS_INLINE bool save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) { static inline __attribute__((always_inline)) bool save_data_file_system_core_open_fat_storage(save_data_file_system_core_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) {
return save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index); return save_allocation_table_storage_init(storage_ctx, ctx->base_storage, &ctx->allocation_table, (uint32_t)ctx->header->block_size, block_index);
} }

View File

@@ -49,20 +49,20 @@ typedef struct {
hierarchical_save_file_table_ctx_t file_table; hierarchical_save_file_table_ctx_t file_table;
} save_data_file_system_core_ctx_t; } save_data_file_system_core_ctx_t;
static ALWAYS_INLINE bool save_data_file_system_core_rename_directory(save_data_file_system_core_ctx_t *ctx, const char *old_path, const char *new_path) { static inline __attribute__((always_inline)) bool save_data_file_system_core_rename_directory(save_data_file_system_core_ctx_t *ctx, const char *old_path, const char *new_path) {
return save_hierarchical_file_table_rename_directory(&ctx->file_table, old_path, new_path); return save_hierarchical_file_table_rename_directory(&ctx->file_table, old_path, new_path);
} }
static ALWAYS_INLINE bool save_data_file_system_core_rename_file(save_data_file_system_core_ctx_t *ctx, const char *old_path, const char *new_path) { static inline __attribute__((always_inline)) bool save_data_file_system_core_rename_file(save_data_file_system_core_ctx_t *ctx, const char *old_path, const char *new_path) {
return save_hierarchical_file_table_rename_file(&ctx->file_table, old_path, new_path); return save_hierarchical_file_table_rename_file(&ctx->file_table, old_path, new_path);
} }
static ALWAYS_INLINE void save_data_file_system_core_get_free_space_size(save_data_file_system_core_ctx_t *ctx, uint64_t *out_free_space) { static inline __attribute__((always_inline)) void save_data_file_system_core_get_free_space_size(save_data_file_system_core_ctx_t *ctx, uint64_t *out_free_space) {
uint32_t free_block_count = save_allocation_table_get_free_list_length(&ctx->allocation_table); uint32_t free_block_count = save_allocation_table_get_free_list_length(&ctx->allocation_table);
*out_free_space = ctx->header->block_size * free_block_count; *out_free_space = ctx->header->block_size * free_block_count;
} }
static ALWAYS_INLINE void save_data_file_system_core_get_total_space_size(save_data_file_system_core_ctx_t *ctx, uint64_t *out_total_space) { static inline __attribute__((always_inline)) void save_data_file_system_core_get_total_space_size(save_data_file_system_core_ctx_t *ctx, uint64_t *out_total_space) {
*out_total_space = ctx->header->block_size * ctx->header->block_count; *out_total_space = ctx->header->block_size * ctx->header->block_count;
} }

View File

@@ -43,7 +43,7 @@ void save_fs_list_init(save_filesystem_list_ctx_t *ctx) {
ctx->used_list_head_index = 1; ctx->used_list_head_index = 1;
} }
static ALWAYS_INLINE uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx_t *ctx) { static inline __attribute__((always_inline)) uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx_t *ctx) {
uint32_t capacity; uint32_t capacity;
if (save_allocation_table_storage_read(&ctx->storage, &capacity, 4, 4) != 4) { if (save_allocation_table_storage_read(&ctx->storage, &capacity, 4, 4) != 4) {
EPRINTF("Failed to read FS list capacity!"); EPRINTF("Failed to read FS list capacity!");
@@ -52,7 +52,7 @@ static ALWAYS_INLINE uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx
return capacity; return capacity;
} }
static ALWAYS_INLINE uint32_t save_fs_list_get_length(save_filesystem_list_ctx_t *ctx) { static inline __attribute__((always_inline)) uint32_t save_fs_list_get_length(save_filesystem_list_ctx_t *ctx) {
uint32_t length; uint32_t length;
if (save_allocation_table_storage_read(&ctx->storage, &length, 0, 4) != 4) { if (save_allocation_table_storage_read(&ctx->storage, &length, 0, 4) != 4) {
EPRINTF("Failed to read FS list length!"); EPRINTF("Failed to read FS list length!");
@@ -61,11 +61,11 @@ static ALWAYS_INLINE uint32_t save_fs_list_get_length(save_filesystem_list_ctx_t
return length; return length;
} }
static ALWAYS_INLINE bool save_fs_list_set_capacity(save_filesystem_list_ctx_t *ctx, uint32_t capacity) { static inline __attribute__((always_inline)) bool save_fs_list_set_capacity(save_filesystem_list_ctx_t *ctx, uint32_t capacity) {
return save_allocation_table_storage_write(&ctx->storage, &capacity, 4, 4) == 4; return save_allocation_table_storage_write(&ctx->storage, &capacity, 4, 4) == 4;
} }
static ALWAYS_INLINE bool save_fs_list_set_length(save_filesystem_list_ctx_t *ctx, uint32_t length) { static inline __attribute__((always_inline)) bool save_fs_list_set_length(save_filesystem_list_ctx_t *ctx, uint32_t length) {
return save_allocation_table_storage_write(&ctx->storage, &length, 0, 4) == 4; return save_allocation_table_storage_write(&ctx->storage, &length, 0, 4) == 4;
} }

View File

@@ -76,11 +76,11 @@ typedef struct {
static_assert(sizeof(save_fs_list_entry_t) == 0x60, "Save filesystem list entry size is wrong!"); static_assert(sizeof(save_fs_list_entry_t) == 0x60, "Save filesystem list entry size is wrong!");
static ALWAYS_INLINE uint32_t save_fs_list_read_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, void *entry) { static inline __attribute__((always_inline)) uint32_t save_fs_list_read_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, void *entry) {
return save_allocation_table_storage_read(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE); return save_allocation_table_storage_read(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE);
} }
static ALWAYS_INLINE uint32_t save_fs_list_write_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, const void *entry) { static inline __attribute__((always_inline)) uint32_t save_fs_list_write_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, const void *entry) {
return save_allocation_table_storage_write(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE); return save_allocation_table_storage_write(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE);
} }

View File

@@ -39,6 +39,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <utils/types.h> #include <utils/types.h>
#define DIV_ROUND_UP(a, b) ((a + b - 1) / b)
typedef struct { typedef struct {
uint32_t (*read)(void *ctx, void *buffer, uint64_t offset, uint64_t count); uint32_t (*read)(void *ctx, void *buffer, uint64_t offset, uint64_t count);
uint32_t (*write)(void *ctx, const void *buffer, uint64_t offset, uint64_t count); uint32_t (*write)(void *ctx, const void *buffer, uint64_t offset, uint64_t count);
@@ -51,7 +53,7 @@ typedef struct {
void *ctx; void *ctx;
} storage; } storage;
static void ALWAYS_INLINE storage_init(storage *this, const storage_vt *vt, void *ctx) { static void inline __attribute__((always_inline)) storage_init(storage *this, const storage_vt *vt, void *ctx) {
this->vt = vt; this->vt = vt;
this->ctx = ctx; this->ctx = ctx;
} }
@@ -65,15 +67,15 @@ typedef struct {
void substorage_init(substorage *this, const storage_vt *vt, void *ctx, uint64_t offset, uint64_t length); void substorage_init(substorage *this, const storage_vt *vt, void *ctx, uint64_t offset, uint64_t length);
bool substorage_init_from_other(substorage *this, const substorage *other, uint64_t offset, uint64_t length); bool substorage_init_from_other(substorage *this, const substorage *other, uint64_t offset, uint64_t length);
static ALWAYS_INLINE uint32_t substorage_read(substorage *ctx, void *buffer, uint64_t offset, uint64_t count) { static inline __attribute__((always_inline)) uint32_t substorage_read(substorage *ctx, void *buffer, uint64_t offset, uint64_t count) {
return ctx->base_storage.vt->read(ctx->base_storage.ctx, buffer, ctx->offset + offset, count); return ctx->base_storage.vt->read(ctx->base_storage.ctx, buffer, ctx->offset + offset, count);
} }
static ALWAYS_INLINE uint32_t substorage_write(substorage *ctx, const void *buffer, uint64_t offset, uint64_t count) { static inline __attribute__((always_inline)) uint32_t substorage_write(substorage *ctx, const void *buffer, uint64_t offset, uint64_t count) {
return ctx->base_storage.vt->write(ctx->base_storage.ctx, buffer, ctx->offset + offset, count); return ctx->base_storage.vt->write(ctx->base_storage.ctx, buffer, ctx->offset + offset, count);
} }
static ALWAYS_INLINE void substorage_get_size(substorage *ctx, uint64_t *out_size) { static inline __attribute__((always_inline)) void substorage_get_size(substorage *ctx, uint64_t *out_size) {
ctx->base_storage.vt->get_size(ctx->base_storage.ctx, out_size); ctx->base_storage.vt->get_size(ctx->base_storage.ctx, out_size);
} }
@@ -162,7 +164,7 @@ static const storage_vt hierarchical_duplex_storage_vt = {
save_hierarchical_duplex_storage_get_size_wrapper save_hierarchical_duplex_storage_get_size_wrapper
}; };
static ALWAYS_INLINE bool is_range_valid(uint64_t offset, uint64_t size, uint64_t total_size) { static inline __attribute__((always_inline)) bool is_range_valid(uint64_t offset, uint64_t size, uint64_t total_size) {
return offset >= 0 && return offset >= 0 &&
size >= 0 && size >= 0 &&
size <= total_size && size <= total_size &&

View File

@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/tegra21_emc.h * arch/arm/mach-tegra/tegra21_emc.h
* *
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. * 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 * 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 * it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#ifndef _EMC_H_ #ifndef _EMC_H_
#define _EMC_H_ #define _EMC_H_
#define EMC_INTSTATUS 0x0
#define EMC_DBG 0x8 #define EMC_DBG 0x8
#define EMC_CFG 0xC #define EMC_CFG 0xC
#define EMC_CONFIG_SAMPLE_DELAY 0x5f0 #define EMC_CONFIG_SAMPLE_DELAY 0x5f0
@@ -698,6 +699,8 @@
typedef enum _emc_mr_t typedef enum _emc_mr_t
{ {
MR0_FEAT = 0,
MR4_TEMP = 4,
MR5_MAN_ID = 5, MR5_MAN_ID = 5,
MR6_REV_ID1 = 6, MR6_REV_ID1 = 6,
MR7_REV_ID2 = 7, MR7_REV_ID2 = 7,
@@ -710,7 +713,7 @@ enum
EMC_CHAN1 = 1 EMC_CHAN1 = 1
}; };
typedef struct _emc_mr_data_t typedef struct _emc_mr_chip_data_t
{ {
// Device 0. // Device 0.
u8 rank0_ch0; u8 rank0_ch0;
@@ -719,6 +722,12 @@ typedef struct _emc_mr_data_t
// Device 1. // Device 1.
u8 rank1_ch0; u8 rank1_ch0;
u8 rank1_ch1; u8 rank1_ch1;
} emc_mr_chip_data_t;
typedef struct _emc_mr_data_t
{
emc_mr_chip_data_t chip0;
emc_mr_chip_data_t chip1;
} emc_mr_data_t; } emc_mr_data_t;
#endif #endif

1528
bdk/mem/emc_t210.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer * Copyright (c) 2018-2024 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -159,6 +159,13 @@ void *calloc(u32 num, u32 size)
return res; return res;
} }
void *zalloc(u32 size)
{
void *res = (void *)_heap_alloc(size);
memset(res, 0, ALIGN(size, sizeof(hnode_t))); // Clear the aligned size.
return res;
}
void free(void *buf) void free(void *buf)
{ {
if (buf >= _heap.start) if (buf >= _heap.start)

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer * Copyright (c) 2018-2024 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -48,6 +48,7 @@ void heap_init(void *base);
void heap_set(heap_t *heap); void heap_set(heap_t *heap);
void *malloc(u32 size); void *malloc(u32 size);
void *calloc(u32 num, u32 size); void *calloc(u32 num, u32 size);
void *zalloc(u32 size);
void free(void *buf); void free(void *buf);
void heap_monitor(heap_monitor_t *mon, bool print_node_stats); void heap_monitor(heap_monitor_t *mon, bool print_node_stats);

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2022 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -17,115 +17,99 @@
#include <memory_map.h> #include <memory_map.h>
#include <mem/mc.h> #include <mem/mc.h>
#include <soc/bpmp.h>
#include <soc/timer.h> #include <soc/timer.h>
#include <soc/t210.h> #include <soc/t210.h>
#include <soc/clock.h> #include <soc/clock.h>
void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock) #define HOS_WPR1_BASE 0x80020000
{
MC(MC_SEC_CARVEOUT_BOM) = bom;
MC(MC_SEC_CARVEOUT_SIZE_MB) = size1mb;
if (lock)
MC(MC_SEC_CARVEOUT_REG_CTRL) = 1;
}
void mc_config_carveout() void mc_config_carveout_hos()
{ {
*(vu32 *)0x8005FFFC = 0xC0EDBBCC; // Enable ACR GSR3 and flush data to ram.
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = 1; *(u32 *)(HOS_WPR1_BASE + SZ_256K - sizeof(u32)) = ACR_GSC3_ENABLE_MAGIC;
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
// Set VPR CYA TRUSTED DEFAULT.
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = VPR_OVR0_CYA_TRUST_DEFAULT;
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = 0; MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = 0;
MC(MC_VIDEO_PROTECT_BOM) = 0;
MC(MC_VIDEO_PROTECT_SIZE_MB) = 0;
MC(MC_VIDEO_PROTECT_REG_CTRL) = 1;
// Configure TSEC carveout @ 0x90000000, 1MB. // Disable VPR carveout.
//mc_config_tsec_carveout(0x90000000, 1, false); MC(MC_VIDEO_PROTECT_BOM) = 0;
mc_config_tsec_carveout(0, 0, true); MC(MC_VIDEO_PROTECT_SIZE_MB) = 0;
MC(MC_VIDEO_PROTECT_REG_CTRL) = VPR_CTRL_LOCKED;
MC(MC_MTS_CARVEOUT_BOM) = 0; // Disable TZDRAM carveout.
MC(MC_MTS_CARVEOUT_SIZE_MB) = 0; MC(MC_SEC_CARVEOUT_BOM) = 0;
MC(MC_MTS_CARVEOUT_ADR_HI) = 0; MC(MC_SEC_CARVEOUT_SIZE_MB) = 0;
MC(MC_MTS_CARVEOUT_REG_CTRL) = 1; MC(MC_SEC_CARVEOUT_REG_CTRL) = BIT(0);
MC(MC_SECURITY_CARVEOUT1_BOM) = 0; // Disable CPU FW carveout.
MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0; MC(MC_MTS_CARVEOUT_BOM) = 0;
MC(MC_MTS_CARVEOUT_SIZE_MB) = 0;
MC(MC_MTS_CARVEOUT_REG_CTRL) = BIT(0);
// Disable GEN1 carveout.
MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0; MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0;
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = 0; MC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_LOCKED |
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = 0; SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = 0; SEC_CARVEOUT_CFG_APERTURE_ID(0) |
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = 0; SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT1_CFG0) = 0x4000006;
MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000; // Enable GEN2 carveout as WPR1.
MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0; MC(MC_SECURITY_CARVEOUT2_BOM) = HOS_WPR1_BASE;
MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2; MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = SZ_256K / SZ_128K;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0; MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU | SEC_CARVEOUT_CA2_R_TSEC;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0; MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3100000; MC(MC_SECURITY_CARVEOUT2_CFG0) = SEC_CARVEOUT_CFG_LOCKED |
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0; SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300; SEC_CARVEOUT_CFG_RD_NS |
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; SEC_CARVEOUT_CFG_RD_SEC |
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; SEC_CARVEOUT_CFG_RD_FALCON_LS |
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; SEC_CARVEOUT_CFG_RD_FALCON_HS |
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; SEC_CARVEOUT_CFG_WR_FALCON_LS |
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; SEC_CARVEOUT_CFG_WR_FALCON_HS |
MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E; SEC_CARVEOUT_CFG_APERTURE_ID(2) |
SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU |
SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;
MC(MC_SECURITY_CARVEOUT3_BOM) = 0; // Prepare GEN3 carveout as WPR2.
MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0; MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0;
MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0) = 0; MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU;
MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1) = 0; MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2;
MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = 0x3000000; MC(MC_SECURITY_CARVEOUT3_CFG0) = SEC_CARVEOUT_CFG_LOCKED |
MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3) = 0; SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |
MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = 0x300; SEC_CARVEOUT_CFG_RD_NS |
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; SEC_CARVEOUT_CFG_RD_SEC |
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; SEC_CARVEOUT_CFG_RD_FALCON_LS |
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; SEC_CARVEOUT_CFG_RD_FALCON_HS |
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; SEC_CARVEOUT_CFG_WR_FALCON_LS |
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; SEC_CARVEOUT_CFG_WR_FALCON_HS |
MC(MC_SECURITY_CARVEOUT3_CFG0) = 0x4401E7E; SEC_CARVEOUT_CFG_APERTURE_ID(3) |
SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU |
SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;
MC(MC_SECURITY_CARVEOUT4_BOM) = 0; // Disable GEN4 carveout.
MC(MC_SECURITY_CARVEOUT4_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0; MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0;
MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0) = 0; MC(MC_SECURITY_CARVEOUT4_CFG0) = SEC_CARVEOUT_CFG_TZ_SECURE |
MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1) = 0; SEC_CARVEOUT_CFG_LOCKED |
MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2) = 0; SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |
MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3) = 0; SEC_CARVEOUT_CFG_RD_NS |
MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4) = 0; SEC_CARVEOUT_CFG_WR_NS;
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT4_CFG0) = 0x8F;
MC(MC_SECURITY_CARVEOUT5_BOM) = 0; // Disable GEN5 carveout.
MC(MC_SECURITY_CARVEOUT5_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0; MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0;
MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0) = 0; MC(MC_SECURITY_CARVEOUT5_CFG0) = SEC_CARVEOUT_CFG_TZ_SECURE |
MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1) = 0; SEC_CARVEOUT_CFG_LOCKED |
MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2) = 0; SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |
MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3) = 0; SEC_CARVEOUT_CFG_RD_NS |
MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4) = 0; SEC_CARVEOUT_CFG_WR_NS;
MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT5_CFG0) = 0x8F;
} }
// SDMMC, TSEC, XUSB and probably more need it to access < DRAM_START.
void mc_enable_ahb_redirect() void mc_enable_ahb_redirect()
{ {
// Enable ARC_CLK_OVR_ON. // Bypass ARC clock gating.
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) |= BIT(19); CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) |= BIT(19);
//MC(MC_IRAM_REG_CTRL) &= ~BIT(0); //MC(MC_IRAM_REG_CTRL) &= ~BIT(0);
MC(MC_IRAM_BOM) = IRAM_BASE; MC(MC_IRAM_BOM) = IRAM_BASE;
@@ -138,7 +122,7 @@ void mc_disable_ahb_redirect()
MC(MC_IRAM_TOM) = 0; MC(MC_IRAM_TOM) = 0;
// Disable IRAM_CFG_WRITE_ACCESS (sticky). // Disable IRAM_CFG_WRITE_ACCESS (sticky).
//MC(MC_IRAM_REG_CTRL) |= BIT(0); //MC(MC_IRAM_REG_CTRL) |= BIT(0);
// Disable ARC_CLK_OVR_ON. // Set ARC clock gating to automatic.
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= ~BIT(19); CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= ~BIT(19);
} }
@@ -157,12 +141,11 @@ bool mc_client_has_access(void *address)
void mc_enable() void mc_enable()
{ {
// Reset EMC source to PLLP. // Reset EMC source to PLLP.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | (2 << 29); CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | (2 << 29u);
// Enable memory clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC); // Enable and clear reset for memory clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_MEM); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL);
// Clear clock resets for memory.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM);
usleep(5); usleep(5);

View File

@@ -21,8 +21,7 @@
#include <mem/mc_t210.h> #include <mem/mc_t210.h>
void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock); void mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock);
void mc_config_carveout(); void mc_config_carveout_hos();
void mc_config_carveout_finalize();
void mc_enable_ahb_redirect(); void mc_enable_ahb_redirect();
void mc_disable_ahb_redirect(); void mc_disable_ahb_redirect();
bool mc_client_has_access(void *address); bool mc_client_has_access(void *address);

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022 CTCaer * Copyright (c) 2019-2024 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -20,20 +20,25 @@
#include "minerva.h" #include "minerva.h"
#include <ianos/ianos.h> #include <ianos/ianos.h>
#include <mem/emc.h> #include <mem/emc_t210.h>
#include <soc/clock.h> #include <soc/clock.h>
#include <soc/fuse.h> #include <soc/fuse.h>
#include <soc/hw_init.h> #include <soc/hw_init.h>
#include <soc/t210.h> #include <soc/t210.h>
#include <utils/util.h> #include <utils/util.h>
#define TABLE_FREQ_KHZ_OFFSET 0x40
#define TABLE_LA_REGS_T210_OFFSET 0x1284
#define TABLE_LA_REGS_T210B01_OFFSET 0xFA4
#define LA_SDMMC1_INDEX 6
extern volatile nyx_storage_t *nyx_str; extern volatile nyx_storage_t *nyx_str;
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
u32 minerva_init() u32 minerva_init()
{ {
u32 curr_ram_idx = 0; u32 tbl_idx = 0;
minerva_cfg = NULL; minerva_cfg = NULL;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
@@ -98,13 +103,13 @@ u32 minerva_init()
// Get current frequency // Get current frequency
u32 current_emc_clk_src = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC); u32 current_emc_clk_src = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC);
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++) for (tbl_idx = 0; tbl_idx < mtc_cfg->table_entries; tbl_idx++)
{ {
if (current_emc_clk_src == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc) if (current_emc_clk_src == mtc_cfg->mtc_table[tbl_idx].clk_src_emc)
break; break;
} }
mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz; mtc_cfg->rate_from = mtc_cfg->mtc_table[tbl_idx].rate_khz;
mtc_cfg->rate_to = FREQ_204; mtc_cfg->rate_to = FREQ_204;
mtc_cfg->train_mode = OP_TRAIN; mtc_cfg->train_mode = OP_TRAIN;
minerva_cfg(mtc_cfg, NULL); minerva_cfg(mtc_cfg, NULL);
@@ -140,6 +145,26 @@ void minerva_change_freq(minerva_freq_t freq)
} }
} }
void minerva_sdmmc_la_program(void *table, bool t210b01)
{
u32 freq = *(u32 *)(table + TABLE_FREQ_KHZ_OFFSET);
u32 *la_scale_regs = (u32 *)(table + (t210b01 ? TABLE_LA_REGS_T210B01_OFFSET : TABLE_LA_REGS_T210_OFFSET));
// Adjust SDMMC1 latency allowance.
switch (freq)
{
case 204000:
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 50;
break;
case 408000:
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 25;
break;
default:
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 20;
break;
}
}
void minerva_prep_boot_freq() void minerva_prep_boot_freq()
{ {
if (!minerva_cfg) if (!minerva_cfg)
@@ -157,23 +182,47 @@ void minerva_prep_boot_freq()
minerva_change_freq(FREQ_800); minerva_change_freq(FREQ_800);
} }
void minerva_prep_boot_l4t(int oc_freq) void minerva_prep_boot_l4t(u32 oc_freq, u32 opt_custom, bool prg_sdmmc_la)
{ {
if (!minerva_cfg) if (!minerva_cfg)
return; return;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
// Program SDMMC LA regs.
if (prg_sdmmc_la)
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
minerva_sdmmc_la_program(&mtc_cfg->mtc_table[i], false);
// Add OC frequency. // Add OC frequency.
if (oc_freq && mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600) if (oc_freq && mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600)
{ {
memcpy(&mtc_cfg->mtc_table[mtc_cfg->table_entries], memcpy(&mtc_cfg->mtc_table[mtc_cfg->table_entries],
&mtc_cfg->mtc_table[mtc_cfg->table_entries - 1], &mtc_cfg->mtc_table[mtc_cfg->table_entries - 1],
sizeof(emc_table_t)); sizeof(emc_table_t));
mtc_cfg->mtc_table[mtc_cfg->table_entries].rate_khz = oc_freq;
mtc_cfg->mtc_table[mtc_cfg->table_entries].opt_custom = opt_custom;
mtc_cfg->mtc_table[mtc_cfg->table_entries].rate_khz = oc_freq;
mtc_cfg->table_entries++; mtc_cfg->table_entries++;
} }
// Trim table.
int entries = 0;
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
{
// Copy frequencies from 204/408/800 MHz and 1333+ MHz.
int rate = mtc_cfg->mtc_table[i].rate_khz;
if (rate == FREQ_204 ||
rate == FREQ_408 ||
rate == FREQ_800 ||
rate >= FREQ_1333)
{
memcpy(&mtc_cfg->mtc_table[entries], &mtc_cfg->mtc_table[i], sizeof(emc_table_t));
entries++;
}
}
mtc_cfg->table_entries = entries;
// Set init frequency. // Set init frequency.
minerva_change_freq(FREQ_204); minerva_change_freq(FREQ_204);
@@ -181,35 +230,21 @@ void minerva_prep_boot_l4t(int oc_freq)
mtc_cfg->train_mode = OP_TRAIN; mtc_cfg->train_mode = OP_TRAIN;
for (u32 i = 0; i < mtc_cfg->table_entries; i++) for (u32 i = 0; i < mtc_cfg->table_entries; i++)
{ {
mtc_cfg->rate_to = mtc_cfg->mtc_table[i].rate_khz; // Skip already trained frequencies and OC freq (Arachne handles it).
// Skip already trained frequencies. if (mtc_cfg->mtc_table[i].trained || mtc_cfg->rate_to == oc_freq)
if (mtc_cfg->rate_to == FREQ_204 || mtc_cfg->rate_to == FREQ_800 || mtc_cfg->rate_to == FREQ_1600)
continue; continue;
// Train frequency. // Train frequency.
mtc_cfg->rate_to = mtc_cfg->mtc_table[i].rate_khz;
minerva_cfg(mtc_cfg, NULL); minerva_cfg(mtc_cfg, NULL);
} }
// Do FSP WAR and scale to 800 MHz as boot freq. // Do FSP WAR and scale to 800 MHz as boot freq.
bool fsp_opwr_disabled = !(EMC(EMC_MRW3) & 0xC0); bool fsp_opwr_disabled = !(EMC(EMC_MRW3) & 0xC0);
if (fsp_opwr_disabled) if (fsp_opwr_disabled)
minerva_change_freq(FREQ_666); minerva_change_freq(FREQ_1333);
minerva_change_freq(FREQ_800); minerva_change_freq(FREQ_800);
// Trim table.
int entries = 0;
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
{
// Copy freqs from 204 MHz to 800 MHz and 1600 MHz and above.
int rate = mtc_cfg->mtc_table[i].rate_khz;
if ((rate >= FREQ_204 && rate <= FREQ_800) || rate >= FREQ_1600)
{
memcpy(&mtc_cfg->mtc_table[entries], &mtc_cfg->mtc_table[i], sizeof(emc_table_t));
entries++;
}
}
mtc_cfg->table_entries = entries;
// Do not let other mtc ops. // Do not let other mtc ops.
mtc_cfg->init_done = 0; mtc_cfg->init_done = 0;
} }

View File

@@ -38,7 +38,7 @@ typedef struct
bool emc_2X_clk_src_is_pllmb; bool emc_2X_clk_src_is_pllmb;
bool fsp_for_src_freq; bool fsp_for_src_freq;
bool train_ram_patterns; bool train_ram_patterns;
bool init_done; u32 init_done;
} mtc_config_t; } mtc_config_t;
enum train_mode_t enum train_mode_t
@@ -53,16 +53,18 @@ enum train_mode_t
typedef enum typedef enum
{ {
FREQ_204 = 204000, FREQ_204 = 204000,
FREQ_666 = 665600, FREQ_408 = 408000,
FREQ_800 = 800000, FREQ_800 = 800000,
FREQ_1333 = 1331200,
FREQ_1600 = 1600000 FREQ_1600 = 1600000
} minerva_freq_t; } minerva_freq_t;
extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
u32 minerva_init(); u32 minerva_init();
void minerva_change_freq(minerva_freq_t freq); void minerva_change_freq(minerva_freq_t freq);
void minerva_sdmmc_la_program(void *table, bool t210b01);
void minerva_prep_boot_freq(); void minerva_prep_boot_freq();
void minerva_prep_boot_l4t(int oc_freq); void minerva_prep_boot_l4t(u32 oc_freq, u32 opt_custom, bool prg_sdmmc_la);
void minerva_periodic_training(); void minerva_periodic_training();
emc_table_t *minerva_get_mtc_table(); emc_table_t *minerva_get_mtc_table();
int minerva_get_mtc_table_entries(); int minerva_get_mtc_table_entries();

View File

@@ -481,7 +481,8 @@ typedef struct
u32 rate_khz; u32 rate_khz;
u32 min_volt; u32 min_volt;
u32 gpu_min_volt; u32 gpu_min_volt;
char clock_src[32]; char clock_src[28];
u32 opt_custom;
u32 clk_src_emc; u32 clk_src_emc;
u32 needs_training; u32 needs_training;
u32 training_pattern; u32 training_pattern;

View File

@@ -19,7 +19,7 @@
#include <string.h> #include <string.h>
#include <mem/mc.h> #include <mem/mc.h>
#include <mem/emc.h> #include <mem/emc_t210.h>
#include <mem/sdram.h> #include <mem/sdram.h>
#include <mem/sdram_param_t210.h> #include <mem/sdram_param_t210.h>
#include <mem/sdram_param_t210b01.h> #include <mem/sdram_param_t210b01.h>
@@ -34,16 +34,14 @@
#include <soc/timer.h> #include <soc/timer.h>
#include <soc/t210.h> #include <soc/t210.h>
#define CONFIG_SDRAM_KEEP_ALIVE
#define DRAM_ID(x) BIT(x) #define DRAM_ID(x) BIT(x)
#define DRAM_CC(x) BIT(x) #define DRAM_CC(x) BIT(x)
typedef struct _sdram_vendor_patch_t typedef struct _sdram_vendor_patch_t
{ {
u32 val; u32 val;
u32 offset:16;
u32 dramcf:16; u32 dramcf:16;
u32 offset:16;
} sdram_vendor_patch_t; } sdram_vendor_patch_t;
static const u8 dram_encoding_t210b01[] = { static const u8 dram_encoding_t210b01[] = {
@@ -67,21 +65,21 @@ static const u8 dram_encoding_t210b01[] = {
/* 17 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, /* 17 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL,
/* 18 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, /* 18 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL,
/* 19 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, /* 19 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL,
/* 20 */ LPDDR4X_4GB_SAMSUNG_1Z, /* 20 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL,
/* 21 */ LPDDR4X_4GB_SAMSUNG_1Z, /* 21 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL,
/* 22 */ LPDDR4X_4GB_SAMSUNG_1Z, /* 22 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL,
/* 23 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, /* 23 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL,
/* 24 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL, /* 24 */ LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL,
/* 25 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, /* 25 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF,
/* 26 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, /* 26 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF,
/* 27 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF, /* 27 */ LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF,
/* 28 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL, /* 28 */ LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL,
/* 29 */ LPDDR4X_4GB_HYNIX_1A, /* 29 */ LPDDR4X_4GB_HYNIX_H54G46CYRBX267,
/* 30 */ LPDDR4X_4GB_HYNIX_1A, /* 30 */ LPDDR4X_4GB_HYNIX_H54G46CYRBX267,
/* 31 */ LPDDR4X_4GB_HYNIX_1A, /* 31 */ LPDDR4X_4GB_HYNIX_H54G46CYRBX267,
/* 32 */ LPDDR4X_4GB_MICRON_1A, /* 32 */ LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB,
/* 33 */ LPDDR4X_4GB_MICRON_1A, /* 33 */ LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB,
/* 34 */ LPDDR4X_4GB_MICRON_1A, /* 34 */ LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB,
}; };
#include "sdram_config.inl" #include "sdram_config.inl"
@@ -127,15 +125,19 @@ static void _sdram_req_mrr_data(u32 data, bool dual_channel)
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx) emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
{ {
emc_mr_data_t data; emc_mr_data_t data;
u32 dual_channel = (EMC(EMC_FBIO_CFG7) >> 2) & 1; u32 mrr;
bool dual_rank = EMC(EMC_ADR_CFG) & 1;
bool dual_channel = (EMC(EMC_FBIO_CFG7) >> 2) & 1; // Each EMC channel is a RAM chip module.
// Clear left overs. // Clear left overs.
for (u32 i = 0; i < 32; i++) for (u32 i = 0; i < 16; i++)
{ {
(void)EMC(EMC_MRR); (void)EMC(EMC_MRR);
usleep(1); usleep(1);
} }
memset(&data, 0xFF, sizeof(emc_mr_data_t));
/* /*
* When a dram chip has only one rank, then the info from the 2 ranks differs. * When a dram chip has only one rank, then the info from the 2 ranks differs.
* Info not matching is only allowed on different channels. * Info not matching is only allowed on different channels.
@@ -143,36 +145,105 @@ emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
// Get Device 0 (Rank 0) info from both dram chips (channels). // Get Device 0 (Rank 0) info from both dram chips (channels).
_sdram_req_mrr_data((2u << 30) | (mrx << 16), dual_channel); _sdram_req_mrr_data((2u << 30) | (mrx << 16), dual_channel);
data.rank0_ch0 = EMC(EMC_MRR) & 0xFF;
data.rank0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8); // Ram module 0 info.
mrr = EMC_CH0(EMC_MRR);
data.chip0.rank0_ch0 = mrr & 0xFF;
data.chip0.rank0_ch1 = (mrr & 0xFF00 >> 8);
// Ram module 1 info.
if (dual_channel)
{
mrr = EMC_CH1(EMC_MRR);
data.chip1.rank0_ch0 = mrr & 0xFF;
data.chip1.rank0_ch1 = (mrr & 0xFF00 >> 8);
}
// If Rank 1 exists, get info. // If Rank 1 exists, get info.
if (EMC(EMC_ADR_CFG) & 1) if (dual_rank)
{ {
// Get Device 1 (Rank 1) info from both dram chips (channels). // Get Device 1 (Rank 1) info from both dram chips (channels).
_sdram_req_mrr_data((1u << 30) | (mrx << 16), dual_channel); _sdram_req_mrr_data((1u << 30) | (mrx << 16), dual_channel);
data.rank1_ch0 = EMC(EMC_MRR) & 0xFF;
data.rank1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8); // Ram module 0 info.
} mrr = EMC_CH0(EMC_MRR);
else data.chip0.rank1_ch0 = mrr & 0xFF;
{ data.chip0.rank1_ch1 = (mrr & 0xFF00 >> 8);
data.rank1_ch0 = 0xFF;
data.rank1_ch1 = 0xFF; // Ram module 1 info.
if (dual_channel)
{
mrr = EMC_CH1(EMC_MRR);
data.chip1.rank1_ch0 = mrr & 0xFF;
data.chip1.rank1_ch1 = (mrr & 0xFF00 >> 8);
}
} }
return data; 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) 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). // Program DPD3/DPD4 regs (coldboot path).
// Enable sel_dpd on unused pins. // Enable sel_dpd on unused pins.
u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000; u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | PMC_IO_DPD_REQ_DPD_ON;
PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
usleep(params->pmc_io_dpd3_req_wait); usleep(params->pmc_io_dpd3_req_wait);
// Disable e_dpd_vttgen. // Disable e_dpd_vttgen.
dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000; dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | PMC_IO_DPD_REQ_DPD_ON;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000; PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000;
usleep(params->pmc_io_dpd4_req_wait); usleep(params->pmc_io_dpd4_req_wait);
@@ -183,45 +254,42 @@ static void _sdram_config_t210(const sdram_params_t210_t *params)
PMC(APBDEV_PMC_WEAK_BIAS) = 0; PMC(APBDEV_PMC_WEAK_BIAS) = 0;
usleep(1); usleep(1);
// Start clocks. // Start PLLM.
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control; CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0; 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); 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;
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLL_BASE_ENABLE;
#endif
u32 wait_end = get_tmr_us() + 300; 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) if (get_tmr_us() >= wait_end)
goto break_nosleep; goto lock_timeout;
} }
usleep(10); 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); 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) if (params->emc_clock_source_dll)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
if (params->clear_clock2_mc1) if (params->clear_clock2_mc1)
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; // Clear Reset to MC1. CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_MC1); // Clear Reset to MC1.
// Enable and clear reset for memory clocks. // Enable and clear reset for memory clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL); 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); 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_0) = params->emc_pmacro_vttgen_ctrl0;
EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1; EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;
EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2; 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. usleep(10); // Ensure the regulators settle.
// Select EMC write mux. // Select EMC write mux.
@@ -233,7 +301,7 @@ break_nosleep:
// Program CMD mapping. Required before brick mapping, else // Program CMD mapping. Required before brick mapping, else
// we can't guarantee CK will be differential at all times. // we can't guarantee CK will be differential at all times.
EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7; EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7;
EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0; EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0;
EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1; EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1;
EMC(EMC_CMD_MAPPING_CMD0_2) = params->emc_cmd_mapping_cmd0_2; EMC(EMC_CMD_MAPPING_CMD0_2) = params->emc_cmd_mapping_cmd0_2;
@@ -246,7 +314,7 @@ break_nosleep:
EMC(EMC_CMD_MAPPING_CMD3_0) = params->emc_cmd_mapping_cmd3_0; EMC(EMC_CMD_MAPPING_CMD3_0) = params->emc_cmd_mapping_cmd3_0;
EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1; EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1;
EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2; EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2;
EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte; EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte;
// Program brick mapping. // Program brick mapping.
EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0; EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0;
@@ -258,6 +326,7 @@ break_nosleep:
// This is required to do any reads from the pad macros. // This is required to do any reads from the pad macros.
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
// Set data pipes mode.
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
// Set swizzle for Rank 0. // Set swizzle for Rank 0.
@@ -275,12 +344,12 @@ break_nosleep:
if (params->emc_bct_spare6) if (params->emc_bct_spare6)
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; *(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_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2; EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3; 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_CONFIG2) = params->emc_auto_cal_config2;
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3; EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4; EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
@@ -289,18 +358,21 @@ break_nosleep:
EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7; EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8; EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;
EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term; // Program termination and drive strength
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive; EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term;
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive; EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
EMC(EMC_PMACRO_CMD_TX_DRV) = params->emc_pmacro_cmd_tx_drive; EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
EMC(EMC_PMACRO_CMD_TX_DRV) = params->emc_pmacro_cmd_tx_drive;
EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common; EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common;
EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel; EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl; EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
// Program dll config.
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0; EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1; EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1; 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_0) = params->emc_data_brlshft0;
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1; EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0; EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
@@ -314,6 +386,7 @@ break_nosleep:
EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2; EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3; 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_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40;
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl; EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
@@ -328,7 +401,8 @@ break_nosleep:
EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode; 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; EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl;
EMC(EMC_CFG_3) = params->emc_cfg3; // 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_0) = params->emc_pmacro_tx_pwrd0;
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1; EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
EMC(EMC_PMACRO_TX_PWRD_2) = params->emc_pmacro_tx_pwrd2; EMC(EMC_PMACRO_TX_PWRD_2) = params->emc_pmacro_tx_pwrd2;
@@ -348,12 +422,15 @@ break_nosleep:
EMC(EMC_PMACRO_CMD_CTRL_0) = params->emc_pmacro_cmd_ctrl0; 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_1) = params->emc_pmacro_cmd_ctrl1;
EMC(EMC_PMACRO_CMD_CTRL_2) = params->emc_pmacro_cmd_ctrl2; 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_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_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_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_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt; 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_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_1) = params->emc_pmacro_quse_ddll_rank0_1;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2; EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
@@ -368,6 +445,7 @@ break_nosleep:
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5; 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; 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_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_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; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
@@ -402,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_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; 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_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_1) = params->emc_pmacro_ddll_long_cmd_1;
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2; EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
@@ -418,7 +497,8 @@ break_nosleep:
if (params->emc_bct_spare4) if (params->emc_bct_spare4)
*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; *(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. // Initialize MC VPR settings.
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom; MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
@@ -483,7 +563,8 @@ break_nosleep:
MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv; MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
MC(MC_DA_CONFIG0) = params->mc_da_cfg0; 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. // Program second-level clock enable overrides.
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
@@ -505,6 +586,7 @@ break_nosleep:
EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0; 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; 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_INTERVAL) = params->emc_auto_cal_interval;
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
usleep(params->emc_auto_cal_wait); usleep(params->emc_auto_cal_wait);
@@ -561,9 +643,13 @@ break_nosleep:
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl; EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl;
EMC(EMC_DBG) = params->emc_dbg; EMC(EMC_DBG) = params->emc_dbg;
// Clear read fifo.
EMC(EMC_QRST) = params->emc_qrst; EMC(EMC_QRST) = params->emc_qrst;
EMC(EMC_ISSUE_QRST) = 1; EMC(EMC_ISSUE_QRST) = 1;
EMC(EMC_ISSUE_QRST) = 0; EMC(EMC_ISSUE_QRST) = 0;
// Program the rest of EMC timing configuration.
EMC(EMC_QSAFE) = params->emc_qsafe; EMC(EMC_QSAFE) = params->emc_qsafe;
EMC(EMC_RDV) = params->emc_rdv; EMC(EMC_RDV) = params->emc_rdv;
EMC(EMC_RDV_MASK) = params->emc_rdv_mask; EMC(EMC_RDV_MASK) = params->emc_rdv_mask;
@@ -612,14 +698,16 @@ break_nosleep:
if (params->boot_rom_patch_control & BIT(31)) if (params->boot_rom_patch_control & BIT(31))
{ {
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data; *(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. // Release SEL_DPD_CMD.
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000; PMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | PMC_IO_DPD_REQ_DPD_OFF;
usleep(params->pmc_io_dpd3_req_wait); 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) if (!params->emc_auto_cal_interval)
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200; EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
@@ -632,7 +720,8 @@ break_nosleep:
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; 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); usleep(params->emc_timing_control_wait);
// Deassert HOLD_CKE_LOW. // Deassert HOLD_CKE_LOW.
@@ -701,13 +790,14 @@ break_nosleep:
if (params->emc_bct_spare12) if (params->emc_bct_spare12)
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; *(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) if (params->emc_extra_refresh_num)
EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3; EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3;
// Enable refresh. // Enable refresh.
EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000; EMC(EMC_REFCTRL) = params->emc_dev_select | BIT(31);
EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control; EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;
EMC(EMC_CFG_UPDATE) = params->emc_cfg_update; EMC(EMC_CFG_UPDATE) = params->emc_cfg_update;
@@ -717,9 +807,10 @@ break_nosleep:
EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl; EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl;
// Write addr swizzle lock bit. // Write addr swizzle lock bit.
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; 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. // Enable EMC pipe clock gating.
EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;
@@ -741,8 +832,19 @@ break_nosleep:
static void _sdram_config_t210b01(const sdram_params_t210b01_t *params) static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
{ {
u32 pmc_scratch1 = ~params->emc_pmc_scratch1; // VDDP Select.
u32 pmc_scratch2 = ~params->emc_pmc_scratch2; 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. // Override HW FSM if needed.
if (params->clk_rst_pllm_misc20_override_enable) if (params->clk_rst_pllm_misc20_override_enable)
@@ -750,16 +852,18 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
// Program DPD3/DPD4 regs (coldboot path). // Program DPD3/DPD4 regs (coldboot path).
// Enable sel_dpd on unused pins. // 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_WEAK_BIAS) = (pmc_scratch1 & 0x1000) << 19 | (pmc_scratch1 & 0xFFF) << 18 | (pmc_scratch1 & 0x8000) << 15;
PMC(APBDEV_PMC_IO_DPD3_REQ) = (pmc_scratch1 & 0x9FFF) + 0x80000000; PMC(APBDEV_PMC_IO_DPD3_REQ) = (pmc_scratch1 & 0x9FFF) | PMC_IO_DPD_REQ_DPD_ON;
usleep(params->pmc_io_dpd3_req_wait); usleep(params->pmc_io_dpd3_req_wait);
// Disable e_dpd_vttgen. // Disable e_dpd_vttgen.
PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x3FFF0000) | 0x80000000; 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); usleep(params->pmc_io_dpd4_req_wait);
// Disable e_dpd_bg. // Disable e_dpd_bg.
PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x1FFF) | 0x80000000; PMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x1FFF) | PMC_IO_DPD_REQ_DPD_ON;
usleep(1); usleep(1);
// Program CMD mapping. Required before brick mapping, else // Program CMD mapping. Required before brick mapping, else
@@ -800,7 +904,8 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare_secure4) if (params->emc_bct_spare_secure4)
*(vu32 *)params->emc_bct_spare_secure4 = params->emc_bct_spare_secure5; *(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. usleep(params->pmc_vddp_sel_wait + 2); // Ensure the regulators settle.
// Set clock sources. // Set clock sources.
@@ -817,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. // This is required to do any reads from the pad macros.
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
// Set data pipes mode.
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
// Set swizzle for Rank 0. // Set swizzle for Rank 0.
@@ -834,12 +940,12 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare6) if (params->emc_bct_spare6)
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; *(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_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2; EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3; 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_CONFIG2) = params->emc_auto_cal_config2;
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3; EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4; EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
@@ -848,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_CONFIG7) = params->emc_auto_cal_config7;
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8; 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_RX_TERM) = params->emc_pmacro_rx_term;
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive; EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive; EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
@@ -856,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_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl; EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
// Program dll config.
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0; EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1; EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1; 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_0) = params->emc_data_brlshft0;
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1; EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0; EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
@@ -873,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_2) = params->emc_quse_brlshft2;
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3; 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_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl; EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
@@ -886,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_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; 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_CFG_3) = params->emc_cfg3;
EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0; EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0;
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1; EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
@@ -901,26 +1012,26 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_PMACRO_TX_SEL_CLK_SRC_5) = params->emc_pmacro_tx_sel_clk_src5; EMC(EMC_PMACRO_TX_SEL_CLK_SRC_5) = params->emc_pmacro_tx_sel_clk_src5;
// Program per bit pad macros. // Program per bit pad macros.
EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_0) = params->emc_pmacro_perbit_fgcg_ctrl0; EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_0_B01) = params->emc_pmacro_perbit_fgcg_ctrl0;
EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_1) = params->emc_pmacro_perbit_fgcg_ctrl1; EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_1_B01) = params->emc_pmacro_perbit_fgcg_ctrl1;
EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_2) = params->emc_pmacro_perbit_fgcg_ctrl2; EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_2_B01) = params->emc_pmacro_perbit_fgcg_ctrl2;
EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_3) = params->emc_pmacro_perbit_fgcg_ctrl3; EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_3_B01) = params->emc_pmacro_perbit_fgcg_ctrl3;
EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_4) = params->emc_pmacro_perbit_fgcg_ctrl4; EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_4_B01) = params->emc_pmacro_perbit_fgcg_ctrl4;
EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_5) = params->emc_pmacro_perbit_fgcg_ctrl5; EMC(EMC_PMACRO_PERBIT_FGCG_CTRL_5_B01) = params->emc_pmacro_perbit_fgcg_ctrl5;
EMC(EMC_PMACRO_PERBIT_RFU_CTRL_0) = params->emc_pmacro_perbit_rfu_ctrl0; EMC(EMC_PMACRO_PERBIT_RFU_CTRL_0_B01) = params->emc_pmacro_perbit_rfu_ctrl0;
EMC(EMC_PMACRO_PERBIT_RFU_CTRL_1) = params->emc_pmacro_perbit_rfu_ctrl1; EMC(EMC_PMACRO_PERBIT_RFU_CTRL_1_B01) = params->emc_pmacro_perbit_rfu_ctrl1;
EMC(EMC_PMACRO_PERBIT_RFU_CTRL_2) = params->emc_pmacro_perbit_rfu_ctrl2; EMC(EMC_PMACRO_PERBIT_RFU_CTRL_2_B01) = params->emc_pmacro_perbit_rfu_ctrl2;
EMC(EMC_PMACRO_PERBIT_RFU_CTRL_3) = params->emc_pmacro_perbit_rfu_ctrl3; EMC(EMC_PMACRO_PERBIT_RFU_CTRL_3_B01) = params->emc_pmacro_perbit_rfu_ctrl3;
EMC(EMC_PMACRO_PERBIT_RFU_CTRL_4) = params->emc_pmacro_perbit_rfu_ctrl4; EMC(EMC_PMACRO_PERBIT_RFU_CTRL_4_B01) = params->emc_pmacro_perbit_rfu_ctrl4;
EMC(EMC_PMACRO_PERBIT_RFU_CTRL_5) = params->emc_pmacro_perbit_rfu_ctrl5; EMC(EMC_PMACRO_PERBIT_RFU_CTRL_5_B01) = params->emc_pmacro_perbit_rfu_ctrl5;
EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_0) = params->emc_pmacro_perbit_rfu1_ctrl0; EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_0_B01) = params->emc_pmacro_perbit_rfu1_ctrl0;
EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_1) = params->emc_pmacro_perbit_rfu1_ctrl1; EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_1_B01) = params->emc_pmacro_perbit_rfu1_ctrl1;
EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_2) = params->emc_pmacro_perbit_rfu1_ctrl2; EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_2_B01) = params->emc_pmacro_perbit_rfu1_ctrl2;
EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_3) = params->emc_pmacro_perbit_rfu1_ctrl3; EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_3_B01) = params->emc_pmacro_perbit_rfu1_ctrl3;
EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_4) = params->emc_pmacro_perbit_rfu1_ctrl4; EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_4_B01) = params->emc_pmacro_perbit_rfu1_ctrl4;
EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_5) = params->emc_pmacro_perbit_rfu1_ctrl5; EMC(EMC_PMACRO_PERBIT_RFU1_CTRL_5_B01) = params->emc_pmacro_perbit_rfu1_ctrl5;
EMC(EMC_PMACRO_DATA_PI_CTRL) = params->emc_pmacro_data_pi_ctrl; EMC(EMC_PMACRO_DATA_PI_CTRL_B01) = params->emc_pmacro_data_pi_ctrl;
EMC(EMC_PMACRO_CMD_PI_CTRL) = params->emc_pmacro_cmd_pi_ctrl; EMC(EMC_PMACRO_CMD_PI_CTRL_B01) = params->emc_pmacro_cmd_pi_ctrl;
EMC(EMC_PMACRO_DDLL_BYPASS) = params->emc_pmacro_ddll_bypass; EMC(EMC_PMACRO_DDLL_BYPASS) = params->emc_pmacro_ddll_bypass;
EMC(EMC_PMACRO_DDLL_PWRD_0) = params->emc_pmacro_ddll_pwrd0; EMC(EMC_PMACRO_DDLL_PWRD_0) = params->emc_pmacro_ddll_pwrd0;
@@ -929,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_0) = params->emc_pmacro_cmd_ctrl0;
EMC(EMC_PMACRO_CMD_CTRL_1) = params->emc_pmacro_cmd_ctrl1; EMC(EMC_PMACRO_CMD_CTRL_1) = params->emc_pmacro_cmd_ctrl1;
EMC(EMC_PMACRO_CMD_CTRL_2) = params->emc_pmacro_cmd_ctrl2; 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_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_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_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_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt; 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_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_1) = params->emc_pmacro_quse_ddll_rank0_1;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2; EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
@@ -948,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_4) = params->emc_pmacro_quse_ddll_rank1_4;
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5; 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_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_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; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
@@ -982,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_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; 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_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_1) = params->emc_pmacro_ddll_long_cmd_1;
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2; EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
@@ -1006,7 +1122,8 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare_secure10) if (params->emc_bct_spare_secure10)
*(vu32 *)params->emc_bct_spare_secure10 = params->emc_bct_spare_secure11; *(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. // Initialize MC VPR settings.
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom; MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
@@ -1071,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_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
MC(MC_DA_CONFIG0) = params->mc_da_cfg0; 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. // Program second-level clock enable overrides.
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
@@ -1093,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_0) = params->emc_auto_cal_vref_sel0;
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1; 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_INTERVAL) = params->emc_auto_cal_interval;
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
usleep(params->emc_auto_cal_wait); usleep(params->emc_auto_cal_wait);
@@ -1101,7 +1220,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare8) if (params->emc_bct_spare8)
*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;
EMC(EMC_AUTO_CAL_CONFIG9) = params->emc_auto_cal_config9; EMC(EMC_AUTO_CAL_CONFIG9_B01) = params->emc_auto_cal_config9;
// Program EMC timing configuration. // Program EMC timing configuration.
EMC(EMC_CFG_2) = params->emc_cfg2; EMC(EMC_CFG_2) = params->emc_cfg2;
@@ -1121,11 +1240,11 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_RAS) = params->emc_ras; EMC(EMC_RAS) = params->emc_ras;
EMC(EMC_RP) = params->emc_rp; EMC(EMC_RP) = params->emc_rp;
EMC(EMC_TPPD) = params->emc_tppd; EMC(EMC_TPPD) = params->emc_tppd;
EMC(EMC_CTT) = params->emc_trtm; EMC(EMC_TRTM_B01) = params->emc_trtm;
EMC(EMC_FBIO_TWTM) = params->emc_twtm; EMC(EMC_TWTM_B01) = params->emc_twtm;
EMC(EMC_FBIO_TRATM) = params->emc_tratm; EMC(EMC_TRATM_B01) = params->emc_tratm;
EMC(EMC_FBIO_TWATM) = params->emc_twatm; EMC(EMC_TWATM_B01) = params->emc_twatm;
EMC(EMC_FBIO_TR2REF) = params->emc_tr2ref; EMC(EMC_TR2REF_B01) = params->emc_tr2ref;
EMC(EMC_R2R) = params->emc_r2r; EMC(EMC_R2R) = params->emc_r2r;
EMC(EMC_W2W) = params->emc_w2w; EMC(EMC_W2W) = params->emc_w2w;
EMC(EMC_R2W) = params->emc_r2w; EMC(EMC_R2W) = params->emc_r2w;
@@ -1155,9 +1274,13 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width; EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width;
EMC(EMC_DBG) = params->emc_dbg; EMC(EMC_DBG) = params->emc_dbg;
// Clear read fifo.
EMC(EMC_QRST) = params->emc_qrst; EMC(EMC_QRST) = params->emc_qrst;
EMC(EMC_ISSUE_QRST) = 1; EMC(EMC_ISSUE_QRST) = 1;
EMC(EMC_ISSUE_QRST) = 0; EMC(EMC_ISSUE_QRST) = 0;
// Program the rest of EMC timing configuration.
EMC(EMC_QSAFE) = params->emc_qsafe; EMC(EMC_QSAFE) = params->emc_qsafe;
EMC(EMC_RDV) = params->emc_rdv; EMC(EMC_RDV) = params->emc_rdv;
EMC(EMC_RDV_MASK) = params->emc_rdv_mask; EMC(EMC_RDV_MASK) = params->emc_rdv_mask;
@@ -1198,7 +1321,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3; EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3;
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control; EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen; EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
EMC(EMC_PMACRO_DSR_VTTGEN_CTRL0) = params->emc_pmacro_dsr_vttgen_ctrl0; EMC(EMC_PMACRO_DSR_VTTGEN_CTRL_0_B01) = params->emc_pmacro_dsr_vttgen_ctrl0;
// Set pipe bypass enable bits before sending any DRAM commands. // Set pipe bypass enable bits before sending any DRAM commands.
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
@@ -1207,7 +1330,9 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->boot_rom_patch_control) if (params->boot_rom_patch_control)
{ {
*(vu32 *)params->boot_rom_patch_control = params->boot_rom_patch_data; *(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. // Patch 7 to 9 using BCT spare secure variables.
@@ -1219,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; *(vu32 *)params->emc_bct_spare_secure16 = params->emc_bct_spare_secure17;
// Release SEL_DPD_CMD. // Release SEL_DPD_CMD.
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000; PMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | PMC_IO_DPD_REQ_DPD_OFF;
usleep(params->pmc_io_dpd3_req_wait); usleep(params->pmc_io_dpd3_req_wait);
// Set transmission pad control parameters. // Set transmission pad control parameters.
@@ -1232,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_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); usleep(params->emc_timing_control_wait);
// Deassert HOLD_CKE_LOW. // Deassert HOLD_CKE_LOW.
@@ -1309,13 +1435,14 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
if (params->emc_bct_spare12) if (params->emc_bct_spare12)
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; *(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) if (params->emc_extra_refresh_num)
EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 253) | (params->emc_dev_select << 30); EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 253) | (params->emc_dev_select << 30);
// Enable refresh. // Enable refresh.
EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000; EMC(EMC_REFCTRL) = params->emc_dev_select | BIT(31);
EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control; EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;
EMC(EMC_CFG) = params->emc_cfg; EMC(EMC_CFG) = params->emc_cfg;
@@ -1324,9 +1451,10 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl; EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl;
// Write addr swizzle lock bit. // Write addr swizzle lock bit.
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; 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; EMC(EMC_CFG_UPDATE) = params->emc_cfg_update;
@@ -1337,7 +1465,7 @@ static void _sdram_config_t210b01(const sdram_params_t210b01_t *params)
EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp;
// Set untranslated region requirements. // Set untranslated region requirements.
MC(MC_UNTRANSLATED_REGION_CHECK) = params->mc_untranslated_region_check; MC(MC_UNTRANSLATED_REGION_CHECK_B01) = params->mc_untranslated_region_check;
// Lock carveouts per BCT cfg. // Lock carveouts per BCT cfg.
MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access; MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;
@@ -1427,65 +1555,28 @@ void *sdram_get_params_patched()
return (void *)sdram_params; 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() void sdram_init()
{ {
// Disable remote sense for SD1. // 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); 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) 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 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

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2020-2023 CTCaer * Copyright (c) 2020-2024 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -18,86 +18,98 @@
#ifndef _SDRAM_H_ #ifndef _SDRAM_H_
#define _SDRAM_H_ #define _SDRAM_H_
#include <mem/emc.h> #include <mem/emc_t210.h>
/* /*
* Tegra X1/X1+ EMC/DRAM Bandwidth Chart: * Tegra X1/X1+ EMC/DRAM Bandwidth Chart:
* *
* Note: BWbits T210 = Hz x ddr x bus width x channels = Hz x 2 x 32 x 2. * Note: Max BWbits = Hz x ddr x bus width x channels = Hz x 2 x 32 x 2.
* BWbits T210B01 = Hz x ddr x bus width x channels = Hz x 2 x 64 x 2. * Max BWbits = Hz x ddr x bus width x channels = Hz x 2 x 64 x 1.
* Both assume that both sub-partitions are used and thus reaching max * Configurations supported: 1x32, 2x32, 1x64.
* bandwidth per channel. (T210: 2x16-bit, T210B01: 2x32-bit). * x64 ram modules can be used by combining the 2 32-bit channels into one.
* Retail Mariko use one sub-partition, in order to meet Erista perf.
*
* T210 T210B01
* 40.8 MHz: 0.61 1.22 GiB/s
* 68.0 MHz: 1.01 2.02 GiB/s
* 102.0 MHz: 1.52 3.04 GiB/s
* 204.0 MHz: 3.04 6.08 GiB/s <-- Tegra X1/X1+ Init/SC7 Frequency
* 408.0 MHz: 6.08 12.16 GiB/s
* 665.6 MHz: 9.92 19.84 GiB/s
* 800.0 MHz: 11.92 23.84 GiB/s <-- Tegra X1/X1+ Nvidia OS Boot Frequency
* 1065.6 MHz: 15.89 31.78 GiB/s
* 1331.2 MHz: 19.84 39.68 GiB/s
* 1600.0 MHz: 23.84 47.68 GiB/s <-- Tegra X1/X1+ HOS Max Frequency
* 1862.4 MHz: 27.75 55.50 GiB/s <-- Tegra X1 Official Max Frequency
* 2131.2 MHz: 31.76 63.52 GiB/s <-- Tegra X1+ Official Max Frequency
* *
* 204.0 MHz: 3.04 <-- Tegra X1/X1+ Init/SC7 Frequency
* 408.0 MHz: 6.08
* 665.6 MHz: 9.92
* 800.0 MHz: 11.92 <-- Tegra X1/X1+ Nvidia OS Boot Frequency
* 1065.6 MHz: 15.89
* 1331.2 MHz: 19.84
* 1600.0 MHz: 23.84
* 1862.4 MHz: 27.75 <-- Tegra X1 Official Max Frequency
* 2131.2 MHz: 31.76 <-- Tegra X1+ Official Max Frequency. Not all regs have support for > 2046 MHz.
*/ */
enum sdram_ids_erista enum sdram_ids_erista
{ {
// LPDDR4 3200Mbps. // LPDDR4 3200Mbps.
LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0, LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH = 0, // Die-B. (2y-01).
LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1, LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE = 1, // Die-M. (2y-01).
LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WT = 2, // WT:C. LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC = 2, // Die-C. (2y-01).
LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH = 4, 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.
*
* 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.
}; };
enum sdram_ids_mariko enum sdram_ids_mariko
{ {
/*
* Nintendo Switch LPDRR4X generations:
* - 1x nm are 1st-gen
* - 1y nm are 2nd-gen
* - 1z/a nm are 3rd-gen
*/
// LPDDR4X 4266Mbps. // LPDDR4X 4266Mbps.
LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 3, // Replaced from Copper. Die-M. (1y-01). LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 3, // Die-M. (1y-01).
LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 5, // Replaced from Copper. Die-M. (1y-01). LPDDR4X_AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 5, // Die-M. (1y-01).
LPDDR4X_AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 6, // Replaced from Copper. Die-M. (1y-01). LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 6, // Die-M. (1y-01).
// LPDDR4X 3733Mbps. // LPDDR4X 3733Mbps.
LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8, // Die-M. 1st gen. 8 banks. 3733Mbps. LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 8, // Die-M. (1x-03).
LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9, // Die-M. LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 9, // Die-M. (1x-03).
LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10, // Die-M. LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 10, // Die-M. (1x-03).
LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE = 11, // 4266Mbps. Die-E. LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE = 11, // Die-E. (1x-03). D9WGB. 4266Mbps.
LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12, // Die-M. 1st gen. 8 banks. 3733Mbps. LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ = 12, // Die-M. (1x-03).
LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13, // Die-M. LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ = 13, // Die-M. (1x-03).
LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14, // Die-M. LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME = 14, // Die-M. (1x-03).
LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE = 15, // 4266Mbps. Die-E. LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE = 15, // Die-E. (1x-03). D9WGB. 4266Mbps.
// LPDDR4X 4266Mbps. // LPDDR4X 4266Mbps.
LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 17, // Die-A. (1y-X03). 2nd gen. 8 banks. 4266Mbps. LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 17, // Die-A. (1y-X03).
LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 18, // Die-A. (1y-X03). LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 18, // Die-A. (1y-X03).
LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 19, // Die-A. (1y-X03). 2nd gen. 8 banks. 4266Mbps. LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 19, // Die-A. (1y-X03).
LPDDR4X_IOWA_4GB_SAMSUNG_1Z = 20, // 1z nm. 40% lower power usage. (1z-01). LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 20, // Die-B. (1z-01). 40% lp.
LPDDR4X_HOAG_4GB_SAMSUNG_1Z = 21, // 1z nm. 40% lower power usage. (1z-01). LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 21, // Die-B. (1z-01). 40% lp.
LPDDR4X_AULA_4GB_SAMSUNG_1Z = 22, // 1z nm. 40% lower power usage. (1z-01). LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 22, // Die-B. (1z-01). 40% lp.
LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 23, // Die-A. (1y-X03). LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 23, // Die-A. (1y-X03).
LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 24, // Die-A. (1y-X03). 2nd gen. 8 banks. 4266Mbps. LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 24, // Die-A. (1y-X03).
LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 25, // 4266Mbps. Die-F. D9XRR. 10nm-class (1y-01). LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 25, // Die-F. (1y-01). D9XRR.
LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF = 26, // 4266Mbps. Die-F. D9XRR. 10nm-class (1y-01). LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF = 26, // Die-F. (1y-01). D9XRR.
LPDDR4X_AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 27, // 4266Mbps. Die-F. D9XRR. 10nm-class (1y-01). LPDDR4X_AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 27, // Die-F. (1y-01). D9XRR.
LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 28, // Die-A. LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 28, // Die-A. (1y-X03). 2nd gen.
LPDDR4X_UNK0_4GB_HYNIX_1A = 29, // 1a nm. 61% lower power usage. (1a-01). // Old naming scheme: H9HCNNNBKMCLXR-NEE
LPDDR4X_UNK1_4GB_HYNIX_1A = 30, // 1a nm. 61% lower power usage. (1a-01). LPDDR4X_IOWA_4GB_HYNIX_H54G46CYRBX267 = 29, // Die-C. (1a-01). 61% lp.
LPDDR4X_UNK2_4GB_HYNIX_1A = 31, // 1a nm. 61% lower power usage. (1a-01). LPDDR4X_HOAG_4GB_HYNIX_H54G46CYRBX267 = 30, // Die-C. (1a-01). 61% lp.
LPDDR4X_AULA_4GB_HYNIX_H54G46CYRBX267 = 31, // Die-C. (1a-01). 61% lp.
LPDDR4X_UNK0_4GB_MICRON_1A = 32, // 1a nm. 61% lower power usage. (1a-01). LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 32, // Die-B. (1a-01). D8BQM. 61% lp.
LPDDR4X_UNK1_4GB_MICRON_1A = 33, // 1a nm. 61% lower power usage. (1a-01). LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB = 33, // Die-B. (1a-01). D8BQM. 61% lp.
LPDDR4X_UNK2_4GB_MICRON_1A = 34, // 1a nm. 61% lower power usage. (1a-01). LPDDR4X_AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 34, // Die-B. (1a-01). D8BQM. 61% lp.
}; };
enum sdram_codes_mariko enum sdram_codes_mariko
@@ -112,18 +124,18 @@ enum sdram_codes_mariko
LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE = 2, // DRAM IDs: 11, 15. LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE = 2, // DRAM IDs: 11, 15.
LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 3, // DRAM IDs: 17, 19, 24. LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL = 3, // DRAM IDs: 17, 19, 24.
LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 4, // DRAM IDs: 18, 23, 28. LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL = 4, // DRAM IDs: 18, 23, 28.
LPDDR4X_4GB_SAMSUNG_1Z = 5, // DRAM IDs: 20, 21, 22. LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL = 5, // DRAM IDs: 20, 21, 22.
LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF = 6, // DRAM IDs: 25, 26, 27. LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF = 6, // DRAM IDs: 25, 26, 27.
LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 7, // DRAM IDs: 03, 05, 06. LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE = 7, // DRAM IDs: 03, 05, 06.
LPDDR4X_4GB_HYNIX_H54G46CYRBX267 = 8, // DRAM IDs: 29, 30, 31.
LPDDR4X_4GB_HYNIX_1A = 8, // DRAM IDs: 29, 30, 31. LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB = 9, // DRAM IDs: 32, 33, 34.
LPDDR4X_4GB_MICRON_1A = 9, // DRAM IDs: 32, 33, 34.
}; };
void sdram_init(); void sdram_init();
void *sdram_get_params_patched(); void *sdram_get_params_patched();
void *sdram_get_params_t210b01(); void *sdram_get_params_t210b01();
void sdram_lp0_save_params(const void *params); 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); emc_mr_data_t sdram_read_mrx(emc_mr_t mrx);
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2020-2022 CTCaer * Copyright (c) 2020-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -434,9 +434,9 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = {
.emc_dll_cfg0 = 0x1F13412F, .emc_dll_cfg0 = 0x1F13412F,
.emc_dll_cfg1 = 0x00010014, .emc_dll_cfg1 = 0x00010014,
.emc_pmc_scratch1 = 0x4FAFFFFF, .emc_pmc_scratch1 = 0x4FAFFFFF, // APBDEV_PMC_IO_DPD3_REQ.
.emc_pmc_scratch2 = 0x7FFFFFFF, .emc_pmc_scratch2 = 0x7FFFFFFF,
.emc_pmc_scratch3 = 0x4006D70B, .emc_pmc_scratch3 = 0x4006D70B, // APBDEV_PMC_DDR_CNTRL.
.emc_pmacro_pad_cfg_ctrl = 0x00020000, .emc_pmacro_pad_cfg_ctrl = 0x00020000,
.emc_pmacro_vttgen_ctrl0 = 0x00030808, .emc_pmacro_vttgen_ctrl0 = 0x00030808,
@@ -489,8 +489,8 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = {
/* DRAM size information */ /* DRAM size information */
.mc_emem_adr_cfg = 0x00000001, // 2 Ranks. .mc_emem_adr_cfg = 0x00000001, // 2 Ranks.
.mc_emem_adr_cfg_dev0 = 0x00070302, // Rank 0 Density 512MB. .mc_emem_adr_cfg_dev0 = 0x00070302, // Chip 0 Density 512MB.
.mc_emem_adr_cfg_dev1 = 0x00070302, // Rank 1 Density 512MB. .mc_emem_adr_cfg_dev1 = 0x00070302, // Chip 1 Density 512MB.
.mc_emem_adr_cfg_channel_mask = 0xFFFF2400, .mc_emem_adr_cfg_channel_mask = 0xFFFF2400,
.mc_emem_adr_cfg_bank_mask0 = 0x6E574400, .mc_emem_adr_cfg_bank_mask0 = 0x6E574400,
.mc_emem_adr_cfg_bank_mask1 = 0x39722800, .mc_emem_adr_cfg_bank_mask1 = 0x39722800,
@@ -499,7 +499,7 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = {
* Specifies the value for MC_EMEM_CFG which holds the external memory * Specifies the value for MC_EMEM_CFG which holds the external memory
* size (in KBytes) * size (in KBytes)
*/ */
.mc_emem_cfg = 0x00001000, // 4GB total density. .mc_emem_cfg = 0x00001000, // 4GB total density. Max 8GB.
/* MC arbitration configuration */ /* MC arbitration configuration */
.mc_emem_arb_cfg = 0x08000001, .mc_emem_arb_cfg = 0x08000001,
@@ -538,20 +538,36 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = {
.mc_clken_override = 0x00008000, .mc_clken_override = 0x00008000,
.mc_stat_control = 0x00000000, .mc_stat_control = 0x00000000,
/* VPR carveout configuration */
.mc_video_protect_bom = 0xFFF00000, .mc_video_protect_bom = 0xFFF00000,
.mc_video_protect_bom_adr_hi = 0x00000000, .mc_video_protect_bom_adr_hi = 0x00000000,
.mc_video_protect_size_mb = 0x00000000, .mc_video_protect_size_mb = 0x00000000,
// AFI, BPMP, HC, ISP2, CCPLEX, PPCS (AHB), SATA, VI, XUSB_HOST, XUSB_DEV, ADSP, PPCS1 (AHB), DC1, SDMMC1A, SDMMC2A, SDMMC3A. // Disable access:
.mc_video_protect_vpr_override = 0xE4BAC343, // AFI (PCIE), BPMP, HC (HOST1x), ISP2, CCPLEX, PPCS (AHB), SATA, VI, XUSB_HOST, XUSB_DEV, ADSP, PPCS1 (AHB), DC1 (WinT), SDMMC1/2/3. Plus TSEC, NVENC.
// SDMMC4A, ISP2B, PPCS2 (AHB), APE, SE, HC1, SE1, AXIAP, ETR. // Enable access:
.mc_video_protect_vpr_override1 = 0x00001ED3, // DC, DCB, HDA, VIC.
.mc_video_protect_vpr_override = 0xE4FACB43, // Stock/Reset: 0xE4BAC343. HOS new: 0xE4FACB43. + TSEC, NVENC.
// Disable access:
// SDMMC4, ISP2B, PPCS2 (AHB), APE, SE, HC1, SE1, AXIAP, ETR. Plus TSECB, TSEC1, TSECB1.
// Enable access:
// GPU, GPUB, NVDEC, NVJPG, NVDEC1.
.mc_video_protect_vpr_override1 = 0x0000FED3, // Stock/Reset: 0x00001ED3. HOS new: 0x0000FED3. + TSECB, TSEC1, TSECB1.
.mc_video_protect_gpu_override0 = 0x00000000, // VPR CYA. L4T override (set PD, SCC, SKED, L1 as UNTRUSTED).
.mc_video_protect_gpu_override1 = 0x00000000, .mc_video_protect_gpu_override0 = VPR_OVR0_CYA_TRUST_GCC(VPR_TRUST_GRAPHICS) |
VPR_OVR0_CYA_TRUST_RASTER(VPR_TRUST_GRAPHICS) |
VPR_OVR0_CYA_TRUST_PE(VPR_TRUST_GRAPHICS) |
VPR_OVR0_CYA_TRUST_TEX(VPR_TRUST_GRAPHICS) |
VPR_OVR0_CYA_TRUST_OVERRIDE, // Stock: 0. HOS: VPR_OVR0_CYA_TRUST_DEFAULT.
.mc_video_protect_gpu_override1 = VPR_OVR1_CYA_TRUST_PROP(VPR_TRUST_GRAPHICS), // Stock: 0. HOS: 0.
/* TZDRAM carveout configuration */
.mc_sec_carveout_bom = 0xFFF00000, .mc_sec_carveout_bom = 0xFFF00000,
.mc_sec_carveout_adr_hi = 0x00000000, .mc_sec_carveout_adr_hi = 0x00000000,
.mc_sec_carveout_size_mb = 0x00000000, .mc_sec_carveout_size_mb = 0x00000000,
.mc_video_protect_write_access = 0x00000000, .mc_video_protect_write_access = 0x00000000,
.mc_sec_carveout_protect_write_access = 0x00000000, .mc_sec_carveout_protect_write_access = 0x00000000,
@@ -640,59 +656,34 @@ static const sdram_params_t210_t _dram_cfg_0_samsung_4gb = {
/* Specifies data for patched boot rom write */ /* Specifies data for patched boot rom write */
.boot_rom_patch_data = 0x00000000, .boot_rom_patch_data = 0x00000000,
/* CPU FW carveout configuration */
.mc_mts_carveout_bom = 0xFFF00000, .mc_mts_carveout_bom = 0xFFF00000,
.mc_mts_carveout_adr_hi = 0x00000000, .mc_mts_carveout_adr_hi = 0x00000000,
.mc_mts_carveout_size_mb = 0x00000000, .mc_mts_carveout_size_mb = 0x00000000,
.mc_mts_carveout_reg_ctrl = 0x00000000 .mc_mts_carveout_reg_ctrl = 0x00000000
}; };
#define DCFG_OFFSET_OF(m) (OFFSET_OF(sdram_params_t210_t, m) / 4)
static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210[] = { static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210[] = {
// Hynix timing config. // Hynix timing config.
{ 0x0000000D, 0x10C / 4, DRAM_ID(1) }, // emc_r2w. { 0x0000000D, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_r2w) },
{ 0x00000001, 0x16C / 4, DRAM_ID(1) }, // emc_puterm_extra. { 0x00000001, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_puterm_extra) },
{ 0x80000000, 0x170 / 4, DRAM_ID(1) }, // emc_puterm_width. { 0x80000000, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_puterm_width) },
{ 0x00000210, 0x4F4 / 4, DRAM_ID(1) }, // emc_pmacro_data_rx_term_mode. { 0x00000210, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_pmacro_data_rx_term_mode) },
{ 0x00000005, 0x5C0 / 4, DRAM_ID(1) }, // mc_emem_arb_timing_r2w. { 0x00000005, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(mc_emem_arb_timing_r2w) },
// Samsung 6GB density config. // Samsung 6GB density config.
{ 0x000C0302, 0x56C / 4, DRAM_ID(4) }, // mc_emem_adr_cfg_dev0. 768MB Rank 0 density. { 0x000C0302, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH), DCFG_OFFSET_OF(mc_emem_adr_cfg_dev0) }, // 768MB Chip 0 density.
{ 0x000C0302, 0x570 / 4, DRAM_ID(4) }, // mc_emem_adr_cfg_dev1. 768MB Rank 1 density. { 0x000C0302, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH), DCFG_OFFSET_OF(mc_emem_adr_cfg_dev1) }, // 768MB Chip 1 density.
{ 0x00001800, 0x584 / 4, DRAM_ID(4) }, // mc_emem_cfg. 6GB total density. { 0x00001800, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH), DCFG_OFFSET_OF(mc_emem_cfg) }, // 6GB total density. Max 8GB.
#ifdef CONFIG_SDRAM_COPPER_SUPPORT // Samsung 8GB density config.
// Copper prototype Samsung/Hynix/Micron timing configs. { 0x0000003A, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(emc_rfc) },
{ 0x0000003A, 0xEC / 4, DRAM_ID(6) }, // emc_rfc. Auto refresh. { 0x0000001D, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(emc_rfc_pb) },
{ 0x0000001D, 0xF0 / 4, DRAM_ID(6) }, // emc_rfc_pb. Bank Auto refresh. { 0x0000003B, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(emc_txsr) },
{ 0x0000000D, 0x10C / 4, DRAM_ID(5) }, // emc_r2w. { 0x0000003B, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(emc_txsr_dll) },
{ 0x00000001, 0x16C / 4, DRAM_ID(5) }, // emc_puterm_extra. { 0x00080302, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(mc_emem_adr_cfg_dev0) }, // 1024MB Chip 0 density.
{ 0x80000000, 0x170 / 4, DRAM_ID(5) }, // emc_puterm_width. { 0x00080302, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(mc_emem_adr_cfg_dev1) }, // 1024MB Chip 1 density.
{ 0x00000012, 0x1B0 / 4, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_rw2pden. { 0x00002000, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX), DCFG_OFFSET_OF(mc_emem_cfg) }, // 8GB total density. Max 8GB.
{ 0x0000003B, 0x1C0 / 4, DRAM_ID(6) }, // emc_txsr.
{ 0x0000003B, 0x1C4 / 4, DRAM_ID(6) }, // emc_txsr_dll.
{ 0x00000003, 0x1DC / 4, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_tclkstable.
{ 0x00120015, 0x334 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_4.
{ 0x00160012, 0x338 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank0_5.
{ 0x00120015, 0x34C / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_4.
{ 0x00160012, 0x350 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dq_rank1_5.
{ 0x002F0032, 0x354 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_0.
{ 0x00310032, 0x358 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_1.
{ 0x00360034, 0x35C / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_2.
{ 0x0033002F, 0x360 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_3.
{ 0x00000006, 0x364 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank0_4.
{ 0x002F0032, 0x36C / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_0.
{ 0x00310032, 0x370 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_1.
{ 0x00360034, 0x374 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_2.
{ 0x0033002F, 0x378 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_3.
{ 0x00000006, 0x37C / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ob_ddll_long_dqs_rank1_4.
{ 0x00150015, 0x3A4 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_0.
{ 0x00120012, 0x3AC / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_2.
{ 0x00160016, 0x3B0 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_3.
{ 0x00000015, 0x3B4 / 4, DRAM_ID(5) | DRAM_ID(6) }, // emc_pmacro_ddll_long_cmd_4.
{ 0x00000012, 0x49C / 4, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft2.
{ 0x00000012, 0x4A0 / 4, DRAM_ID(3) | DRAM_ID(5) | DRAM_ID(6) }, // emc_cmd_brlshft3.
{ 0x00000210, 0x4F4 / 4, DRAM_ID(5) }, // emc_pmacro_data_rx_term_mode.
{ 0x00000005, 0x5C0 / 4, DRAM_ID(5) }, // mc_emem_arb_timing_r2w.
{ 0x00000007, 0x5C8 / 4, DRAM_ID(6) }, // mc_emem_arb_timing_rfcpb. Bank refresh.
{ 0x72A30504, 0x5D4 / 4, DRAM_ID(6) }, // mc_emem_arb_misc0.
#endif
}; };
#undef DCFG_OFFSET_OF

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020-2022 CTCaer * Copyright (c) 2020-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -542,8 +542,8 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = {
/* DRAM size information */ /* DRAM size information */
.mc_emem_adr_cfg = 0x00000000, // 1 Rank. .mc_emem_adr_cfg = 0x00000000, // 1 Rank.
.mc_emem_adr_cfg_dev0 = 0x00080302, // Rank 0 Density 1024MB. .mc_emem_adr_cfg_dev0 = 0x00080302, // Chip 0 Density 1024MB.
.mc_emem_adr_cfg_dev1 = 0x00080302, // Rank 1 Density 1024MB. .mc_emem_adr_cfg_dev1 = 0x00080302, // Chip 1 Density 1024MB.
.mc_emem_adr_cfg_channel_mask = 0xFFFF2400, .mc_emem_adr_cfg_channel_mask = 0xFFFF2400,
.mc_emem_adr_cfg_bank_mask0 = 0x6E574400, .mc_emem_adr_cfg_bank_mask0 = 0x6E574400,
.mc_emem_adr_cfg_bank_mask1 = 0x39722800, .mc_emem_adr_cfg_bank_mask1 = 0x39722800,
@@ -552,7 +552,7 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = {
* Specifies the value for MC_EMEM_CFG which holds the external memory * Specifies the value for MC_EMEM_CFG which holds the external memory
* size (in KBytes) * size (in KBytes)
*/ */
.mc_emem_cfg = 0x00001000, // 4GB total density. .mc_emem_cfg = 0x00001000, // 4GB total density. Max 8GB.
/* MC arbitration configuration */ /* MC arbitration configuration */
.mc_emem_arb_cfg = 0x08000001, .mc_emem_arb_cfg = 0x08000001,
@@ -595,17 +595,30 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = {
.mc_video_protect_bom_adr_hi = 0x00000000, .mc_video_protect_bom_adr_hi = 0x00000000,
.mc_video_protect_size_mb = 0x00000000, .mc_video_protect_size_mb = 0x00000000,
// AFI, BPMP, HC, ISP2, CCPLEX, PPCS (AHB), SATA, VI, XUSB_HOST, XUSB_DEV, ADSP, PPCS1 (AHB), DC1, SDMMC1A, SDMMC2A, SDMMC3A. // Disable access:
.mc_video_protect_vpr_override = 0xE4BAC343, // AFI (PCIE), BPMP, HC (HOST1x), ISP2, CCPLEX, PPCS (AHB), SATA, VI, XUSB_HOST, XUSB_DEV, ADSP, PPCS1 (AHB), DC1 (WinT), SDMMC1/2/3. Plus TSEC, NVENC.
// SDMMC4A, ISP2B, PPCS2 (AHB), APE, SE, HC1, SE1, AXIAP, ETR. Plus SE2, SE2B. // Enable access:
.mc_video_protect_vpr_override1 = 0x06001ED3, // DC, DCB, HDA, VIC.
.mc_video_protect_vpr_override = 0xE4FACB43, // Stock/Reset: 0xE4BAC343. HOS new: 0xE4FACB43. + TSEC, NVENC.
// Disable access:
// SDMMC4, ISP2B, PPCS2 (AHB), APE, SE, HC1, SE1, AXIAP, ETR, SE2, SE2B. Plus TSECB, TSEC1, TSECB1.
// Enable access:
// GPU, GPUB, NVDEC, NVJPG, NVDEC1.
.mc_video_protect_vpr_override1 = 0x0600FED3, // Reset: 0x06001ED3. HOS new: 0x0600FED3. + TSECB, TSEC1, TSECB1.
.mc_video_protect_gpu_override0 = 0x00000000, // VPR CYA. L4T override (set PD, SCC, SKED, L1 as UNTRUSTED).
.mc_video_protect_gpu_override1 = 0x00000000, .mc_video_protect_gpu_override0 = VPR_OVR0_CYA_TRUST_GCC(VPR_TRUST_GRAPHICS) |
VPR_OVR0_CYA_TRUST_RASTER(VPR_TRUST_GRAPHICS) |
VPR_OVR0_CYA_TRUST_PE(VPR_TRUST_GRAPHICS) |
VPR_OVR0_CYA_TRUST_TEX(VPR_TRUST_GRAPHICS) |
VPR_OVR0_CYA_TRUST_OVERRIDE, // Stock: 0. HOS: VPR_OVR0_CYA_TRUST_DEFAULT.
.mc_video_protect_gpu_override1 = VPR_OVR1_CYA_TRUST_PROP(VPR_TRUST_GRAPHICS), // Stock: 0. HOS: 0.
/* TZDRAM carveout configuration */
.mc_sec_carveout_bom = 0xFFF00000, .mc_sec_carveout_bom = 0xFFF00000,
.mc_sec_carveout_adr_hi = 0x00000000, .mc_sec_carveout_adr_hi = 0x00000000,
.mc_sec_carveout_size_mb = 0x00000000, .mc_sec_carveout_size_mb = 0x00000000,
.mc_video_protect_write_access = 0x00000000, .mc_video_protect_write_access = 0x00000000,
.mc_sec_carveout_protect_write_access = 0x00000000, .mc_sec_carveout_protect_write_access = 0x00000000,
@@ -708,100 +721,104 @@ static const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = {
#define DRAM_CC_LPDDR4X_PMACRO_IB (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ)) #define DRAM_CC_LPDDR4X_PMACRO_IB (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ))
#define DRAM_CC_LPDDR4X_AUTOCAL_VPR (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \ #define DRAM_CC_LPDDR4X_PUPD_VPR (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \
DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE) | \
DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \ DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \
DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \ DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \
DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \
DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \
DRAM_CC(LPDDR4X_4GB_HYNIX_1A) | \ DRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267) | \
DRAM_CC(LPDDR4X_4GB_MICRON_1A) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \
DRAM_CC(LPDDR4X_4GB_SAMSUNG_1Z)) DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL))
#define DRAM_CC_LPDDR4X_DYN_SELF_CTRL (DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE) | \ #define DRAM_CC_LPDDR4X_DSR (DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE) | \
DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \ DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \
DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \
DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \
DRAM_CC(LPDDR4X_4GB_HYNIX_1A) | \ DRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267) | \
DRAM_CC(LPDDR4X_4GB_MICRON_1A) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \
DRAM_CC(LPDDR4X_4GB_SAMSUNG_1Z)) DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL))
#define DRAM_CC_LPDDR4X_QUSE_EINPUT (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \ #define DRAM_CC_LPDDR4X_QUSE (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \
DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \ DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL) | \
DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \ DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \
DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \
DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \
DRAM_CC(LPDDR4X_4GB_HYNIX_1A) | \ DRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267) | \
DRAM_CC(LPDDR4X_4GB_MICRON_1A) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \
DRAM_CC(LPDDR4X_4GB_SAMSUNG_1Z)) DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL))
#define DRAM_CC_LPDDR4X_FAW (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \ #define DRAM_CC_LPDDR4X_FAW (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL) | \
DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \
DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \
DRAM_CC(LPDDR4X_4GB_MICRON_1A)) DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB))
#define DRAM_CC_LPDDR4X_VPR (DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \ #define DRAM_CC_LPDDR4X_VPR (DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE) | \
DRAM_CC(LPDDR4X_4GB_HYNIX_1A) | \ DRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267) | \
DRAM_CC(LPDDR4X_4GB_MICRON_1A) | \ DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \
DRAM_CC(LPDDR4X_4GB_SAMSUNG_1Z)) DRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL))
#define DRAM_CC_LPDDR4X_SAMSUNG_8GB (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \ #define DRAM_CC_LPDDR4X_8GB (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ) | \
DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL)) DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL))
#define DCFG_OFFSET_OF(m) (OFFSET_OF(sdram_params_t210b01_t, m) / 4)
static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = { static const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = {
// Samsung LPDDR4X 8GB K4UBE3D4AM-MGCJ Die-M for SDEV Iowa and Hoag. // Samsung LPDDR4X 8GB K4UBE3D4AM-MGCJ Die-M for SDEV Iowa and Hoag.
{ 0x35353535, 0x350 / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_vref_dq_0. { 0x35353535, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_vref_dq_0) },
{ 0x35353535, 0x354 / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_vref_dq_1. { 0x35353535, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_vref_dq_1) },
{ 0x00100010, 0x3FC / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_ddll_long_dqs_rank0_0. { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_0) },
{ 0x00100010, 0x400 / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_ddll_long_dqs_rank0_1. { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_1) },
{ 0x00100010, 0x404 / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_ddll_long_dqs_rank0_2. { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_2) },
{ 0x00100010, 0x408 / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_ddll_long_dqs_rank0_3. { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_3) },
{ 0x00100010, 0x40C / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_ddll_long_dqs_rank1_0. { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_0) },
{ 0x00100010, 0x410 / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_ddll_long_dqs_rank1_1. { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_1) },
{ 0x00100010, 0x414 / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_ddll_long_dqs_rank1_2. { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_2) },
{ 0x00100010, 0x418 / 4, DRAM_CC_LPDDR4X_PMACRO_IB }, // emc_pmacro_ib_ddll_long_dqs_rank1_3. { 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_3) },
/*! Shared patched between DRAM Codes. */ /*! Shared patched between DRAM Codes. */
{ 0x05500000, 0x0D4 / 4, DRAM_CC_LPDDR4X_AUTOCAL_VPR }, // emc_auto_cal_config2. { 0x05500000, DRAM_CC_LPDDR4X_PUPD_VPR, DCFG_OFFSET_OF(emc_auto_cal_config2) },
{ 0xC9AFBCBC, 0x0F4 / 4, DRAM_CC_LPDDR4X_AUTOCAL_VPR }, // emc_auto_cal_vref_sel0. { 0xC9AFBCBC, DRAM_CC_LPDDR4X_PUPD_VPR, DCFG_OFFSET_OF(emc_auto_cal_vref_sel0) },
{ 0x2A800000, 0x6DC / 4, DRAM_CC_LPDDR4X_AUTOCAL_VPR }, // mc_video_protect_gpu_override0.
{ 0x00000002, 0x6E0 / 4, DRAM_CC_LPDDR4X_AUTOCAL_VPR }, // mc_video_protect_gpu_override1.
//!TODO Find out what mc_video_protect_gpu_override0 and mc_video_protect_gpu_override1 new bits are.
{ 0x88161414, 0x2E0 / 4, DRAM_CC_LPDDR4X_DYN_SELF_CTRL }, // emc_mrw14. // Moved to default config.
{ 0x80000713, 0x32C / 4, DRAM_CC_LPDDR4X_DYN_SELF_CTRL }, // emc_dyn_self_ref_control. // { 0x2A800000, DRAM_CC_LPDDR4X_PUPD_VPR, DCFG_OFFSET_OF(mc_video_protect_gpu_override0) },
// { 0x00000002, DRAM_CC_LPDDR4X_PUPD_VPR, DCFG_OFFSET_OF(mc_video_protect_gpu_override1) },
{ 0x00000006, 0x1CC / 4, DRAM_CC_LPDDR4X_QUSE_EINPUT }, // emc_quse. { 0x88161414, DRAM_CC_LPDDR4X_DSR, DCFG_OFFSET_OF(emc_mrw14) },
{ 0x00000005, 0x1D0 / 4, DRAM_CC_LPDDR4X_QUSE_EINPUT }, // emc_quse_width. { 0x80000713, DRAM_CC_LPDDR4X_DSR, DCFG_OFFSET_OF(emc_dyn_self_ref_control) },
{ 0x00000003, 0x1DC / 4, DRAM_CC_LPDDR4X_QUSE_EINPUT }, // emc_einput.
{ 0x0000000C, 0x1E0 / 4, DRAM_CC_LPDDR4X_QUSE_EINPUT }, // emc_einput_duration.
{ 0x00000008, 0x24C / 4, DRAM_CC_LPDDR4X_FAW }, // emc_tfaw. { 0x00000006, DRAM_CC_LPDDR4X_QUSE, DCFG_OFFSET_OF(emc_quse) },
{ 0x00000001, 0x670 / 4, DRAM_CC_LPDDR4X_FAW }, // mc_emem_arb_timing_faw. { 0x00000005, DRAM_CC_LPDDR4X_QUSE, DCFG_OFFSET_OF(emc_quse_width) },
{ 0x00000003, DRAM_CC_LPDDR4X_QUSE, DCFG_OFFSET_OF(emc_einput) },
{ 0x0000000C, DRAM_CC_LPDDR4X_QUSE, DCFG_OFFSET_OF(emc_einput_duration) },
{ 0xE4FACB43, 0x6D4 / 4, DRAM_CC_LPDDR4X_VPR }, // mc_video_protect_vpr_override. + TSEC, NVENC. { 0x00000008, DRAM_CC_LPDDR4X_FAW, DCFG_OFFSET_OF(emc_tfaw) },
{ 0x0600FED3, 0x6D8 / 4, DRAM_CC_LPDDR4X_VPR }, // mc_video_protect_vpr_override1. + TSECB, TSEC1, TSECB1. { 0x00000001, DRAM_CC_LPDDR4X_FAW, DCFG_OFFSET_OF(mc_emem_arb_timing_faw) },
{ 0x00000001, 0x134 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_adr_cfg. 2 Ranks. // Moved to default config.
{ 0x08010004, 0x2B8 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw1. // { 0xE4FACB43, DRAM_CC_LPDDR4X_VPR, DCFG_OFFSET_OF(mc_video_protect_vpr_override) }, // + TSEC, NVENC.
{ 0x08020000, 0x2BC / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw2. // { 0x0600FED3, DRAM_CC_LPDDR4X_VPR, DCFG_OFFSET_OF(mc_video_protect_vpr_override1) }, // + TSECB, TSEC1, TSECB1.
{ 0x080D0000, 0x2C0 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw3.
{ 0x08033131, 0x2C8 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw6. { 0x00000001, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_adr_cfg) }, // 2 Ranks.
{ 0x080B0000, 0x2CC / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw8. { 0x08010004, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw1) },
{ 0x0C0E5D5D, 0x2D0 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw9. { 0x08020000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw2) },
{ 0x080C5D5D, 0x2D4 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw10. { 0x080D0000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw3) },
{ 0x0C0D0808, 0x2D8 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw12. { 0x08033131, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw6) },
{ 0x0C0D0000, 0x2DC / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw13. { 0x080B0000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw8) },
{ 0x08161414, 0x2E0 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw14. { 0x0C0E5D5D, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw9) },
{ 0x08010004, 0x2E4 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_mrw_extra. { 0x080C5D5D, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw10) },
{ 0x00000000, 0x340 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_dev_select. Both devices. { 0x0C0D0808, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw12) },
{ 0x0051004F, 0x450 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_zcal_mrw_cmd. { 0x0C0D0000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw13) },
{ 0x40000001, 0x45C / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_zcal_init_dev1. { 0x08161414, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw14) },
{ 0x00000000, 0x594 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_pmacro_tx_pwrd4. { 0x08010004, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_mrw_extra) },
{ 0x00001000, 0x598 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // emc_pmacro_tx_pwrd5. { 0x00000000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_dev_select) }, // Both devices.
{ 0x00000001, 0x630 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // mc_emem_adr_cfg. 2 Ranks. { 0x0051004F, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_zcal_mrw_cmd) },
{ 0x00002000, 0x64C / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // mc_emem_cfg. 8GB total density. { 0x40000001, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_zcal_init_dev1) },
{ 0x00000002, 0x680 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // mc_emem_arb_timing_r2r. { 0x00000000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_pmacro_tx_pwrd4) },
{ 0x02020001, 0x694 / 4, DRAM_CC_LPDDR4X_SAMSUNG_8GB }, // mc_emem_arb_da_turns. { 0x00001000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(emc_pmacro_tx_pwrd5) },
{ 0x00000001, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(mc_emem_adr_cfg) }, // 2 Ranks.
{ 0x00002000, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(mc_emem_cfg) }, // 8GB total density. Max 8GB.
{ 0x00000002, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(mc_emem_arb_timing_r2r) },
{ 0x02020001, DRAM_CC_LPDDR4X_8GB, DCFG_OFFSET_OF(mc_emem_arb_da_turns) },
}; };
#undef DCFG_OFFSET_OF

View File

@@ -225,7 +225,6 @@ typedef struct _sdram_params_t210b01_t
u32 emc_r2p; u32 emc_r2p;
/* Specifies the value for EMC_W2P */ /* Specifies the value for EMC_W2P */
u32 emc_w2p; u32 emc_w2p;
/* Specifies the value for EMC_RD_RCD */
u32 emc_tppd; u32 emc_tppd;
u32 emc_trtm; u32 emc_trtm;
@@ -235,6 +234,7 @@ typedef struct _sdram_params_t210b01_t
u32 emc_tr2ref; u32 emc_tr2ref;
u32 emc_ccdmw; u32 emc_ccdmw;
/* Specifies the value for EMC_RD_RCD */
u32 emc_rd_rcd; u32 emc_rd_rcd;
/* Specifies the value for EMC_WR_RCD */ /* Specifies the value for EMC_WR_RCD */
u32 emc_wr_rcd; u32 emc_wr_rcd;

View File

@@ -1,7 +1,7 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011 * Copyright (c) 2018 balika011
* Copyright (c) 2018-2022 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -18,156 +18,254 @@
#include <string.h> #include <string.h>
#include <soc/bpmp.h>
#include <soc/ccplex.h> #include <soc/ccplex.h>
#include <soc/timer.h> #include <soc/timer.h>
#include <soc/t210.h> #include <soc/t210.h>
#include <mem/mc_t210.h> #include <mem/mc_t210.h>
#include <mem/smmu.h> #include <mem/smmu.h>
#include <utils/aarch64_util.h> #include <memory_map.h>
bool smmu_used = false; /*! SMMU register defines */
u8 *_pageheap = (u8 *)SMMU_HEAP_ADDR; #define SMMU_ASID(asid) (((asid) << 24u) | ((asid) << 16u) | ((asid) << 8u) | (asid))
#define SMMU_ENABLE BIT(31)
#define SMMU_TLB_ACTIVE_LINES(l) ((l) << 0u)
#define SMMU_TLB_RR_ARBITRATION BIT(28)
#define SMMU_TLB_HIT_UNDER_MISS BIT(29)
#define SMMU_TLB_STATS_ENABLE BIT(31)
#define SMUU_PTC_INDEX_MAP(m) ((m) << 0u)
#define SMUU_PTC_LINE_MASK(m) ((m) << 8u)
#define SMUU_PTC_REQ_LIMIT(l) ((l) << 24u)
#define SMUU_PTC_CACHE_ENABLE BIT(29)
#define SMUU_PTC_STATS_ENABLE BIT(31)
//Enabling SMMU requires a TZ secure write: MC(MC_SMMU_CONFIG) = 1; /*! Page table defines */
u8 smmu_payload[] __attribute__((aligned(16))) = { #define SMMU_4MB_REGION 0
0x41, 0x01, 0x00, 0x58, // 0x00: LDR X1, =0x70019010 #define SMMU_PAGE_TABLE 1
#define SMMU_PDIR_COUNT 1024
#define SMMU_PTBL_COUNT 1024
#define SMMU_PAGE_SHIFT 12u
#define SMMU_PTN_SHIFT SMMU_PAGE_SHIFT
#define SMMU_PDN_SHIFT 22u
#define SMMU_ADDR_TO_PFN(addr) ((addr) >> SMMU_PAGE_SHIFT)
#define SMMU_ADDR_TO_PTN(addr) ((addr) >> SMMU_PTN_SHIFT)
#define SMMU_ADDR_TO_PDN(addr) ((addr) >> SMMU_PDN_SHIFT)
#define SMMU_PTN_TO_ADDR(ptn) ((ptn) << SMMU_PTN_SHIFT)
#define SMMU_PDN_TO_ADDR(pdn) ((pdn) << SMMU_PDN_SHIFT)
#define SMMU_PTB(page, attr) (((attr) << 29u) | ((page) >> SMMU_PAGE_SHIFT))
#define SMMU_PAYLOAD_EN_SHIFT 4
#define SMMU_PAYLOAD_EN_SET 0x20
#define SMMU_PAYLOAD_EN_UNSET 0x00
// Enabling SMMU requires a TZ (EL3) secure write. MC(MC_SMMU_CONFIG) = 1;
static u8 smmu_enable_payload[] = {
0xC1, 0x00, 0x00, 0x18, // 0x00: LDR W1, =0x70019010
0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1 0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1
0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1] 0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1]
0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS 0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS
0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH 0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH
0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop 0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop
0x00, 0x00, 0x80, 0xD2, // 0x18: MOV X0, #0x0 0x10, 0x90, 0x01, 0x70, // 0x18: MC_SMMU_CONFIG
0x20, 0x00, 0x00, 0xB9, // 0x1C: STR W0, [X1]
0x80, 0x00, 0x00, 0x58, // 0x20: LDR X0, =0x4002B000
0x00, 0x00, 0x1F, 0xD6, // 0x28: BR X0
0x10, 0x90, 0x01, 0x70, // 0x28: MC_SMMU_CONFIG
0x00, 0x00, 0x00, 0x00, // 0x2C:
0x00, 0x00, 0x00, 0x00, // 0x30: secmon address
0x00, 0x00, 0x00, 0x00 // 0x34:
}; };
void *page_alloc(u32 num) static void *smmu_heap = (void *)SMMU_HEAP_ADDR;
static bool smmu_enabled = false;
void *smmu_page_zalloc(u32 num)
{ {
u8 *res = _pageheap; void *page = smmu_heap;
_pageheap += SZ_PAGE * num; memset(page, 0, SZ_PAGE * num);
memset(res, 0, SZ_PAGE * num);
return res; smmu_heap += SZ_PAGE * num;
return page;
} }
u32 *smmu_alloc_pdir() static pde_t *_smmu_pdir_alloc()
{ {
u32 *pdir = (u32 *)page_alloc(1); pde_t *pdir = (pde_t *)smmu_page_zalloc(1);
for (int pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
pdir[pdn] = _PDE_VACANT(pdn); // Initialize pdes with no permissions.
for (u32 pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
pdir[pdn].huge.page = pdn;
return pdir; return pdir;
} }
void smmu_flush_regs() static void _smmu_flush_regs()
{ {
(void)MC(MC_SMMU_PTB_DATA); (void)MC(MC_SMMU_PTB_DATA);
} }
void smmu_flush_all() void smmu_flush_all()
{ {
// Flush the entire page table cache.
MC(MC_SMMU_PTC_FLUSH) = 0; MC(MC_SMMU_PTC_FLUSH) = 0;
smmu_flush_regs(); _smmu_flush_regs();
// Flush the entire table.
MC(MC_SMMU_TLB_FLUSH) = 0; MC(MC_SMMU_TLB_FLUSH) = 0;
smmu_flush_regs(); _smmu_flush_regs();
} }
void smmu_init(u32 secmon_base) void smmu_init()
{ {
MC(MC_SMMU_PTB_ASID) = 0; MC(MC_SMMU_PTB_ASID) = 0;
MC(MC_SMMU_PTB_DATA) = 0; MC(MC_SMMU_PTB_DATA) = 0;
MC(MC_SMMU_TLB_CONFIG) = 0x30000030; MC(MC_SMMU_TLB_CONFIG) = SMMU_TLB_HIT_UNDER_MISS | SMMU_TLB_RR_ARBITRATION | SMMU_TLB_ACTIVE_LINES(48);
MC(MC_SMMU_PTC_CONFIG) = 0x28000F3F; MC(MC_SMMU_PTC_CONFIG) = SMUU_PTC_CACHE_ENABLE | SMUU_PTC_REQ_LIMIT(8) | SMUU_PTC_LINE_MASK(0xF) | SMUU_PTC_INDEX_MAP(0x3F);
MC(MC_SMMU_PTC_FLUSH) = 0; MC(MC_SMMU_PTC_FLUSH) = 0;
MC(MC_SMMU_TLB_FLUSH) = 0; MC(MC_SMMU_TLB_FLUSH) = 0;
// Set the secmon address
*(u32 *)(smmu_payload + 0x30) = secmon_base;
} }
void smmu_enable() void smmu_enable()
{ {
if (smmu_used) if (smmu_enabled)
return; return;
ccplex_boot_cpu0((u32)smmu_payload); // Launch payload on CCPLEX in order to set SMMU enable bit.
smmu_used = true; ccplex_boot_cpu0((u32)smmu_enable_payload, false);
msleep(150); msleep(100);
ccplex_powergate_cpu0();
smmu_flush_all(); smmu_flush_all();
smmu_enabled = true;
} }
bool smmu_is_used() void smmu_disable()
{ {
return smmu_used; if (!smmu_enabled)
return;
// Set payload to disable SMMU.
smmu_enable_payload[SMMU_PAYLOAD_EN_SHIFT] = SMMU_PAYLOAD_EN_UNSET;
smmu_flush_all();
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
// Launch payload on CCPLEX in order to set SMMU enable bit.
ccplex_boot_cpu0((u32)smmu_enable_payload, false);
msleep(100);
ccplex_powergate_cpu0();
smmu_flush_all();
// Restore payload to SMMU enable.
smmu_enable_payload[SMMU_PAYLOAD_EN_SHIFT] = SMMU_PAYLOAD_EN_SET;
smmu_enabled = false;
} }
void smmu_exit() void smmu_reset_heap()
{ {
*(u32 *)(smmu_payload + 0x14) = _NOP(); smmu_heap = (void *)SMMU_HEAP_ADDR;
} }
u32 *smmu_init_domain4(u32 dev_base, u32 asid) void *smmu_init_domain(u32 dev_base, u32 asid)
{ {
u32 *pdir = smmu_alloc_pdir(); void *ptb = _smmu_pdir_alloc();
MC(MC_SMMU_PTB_ASID) = asid; MC(MC_SMMU_PTB_ASID) = asid;
MC(MC_SMMU_PTB_DATA) = SMMU_MK_PDIR((u32)pdir, _PDIR_ATTR); MC(MC_SMMU_PTB_DATA) = SMMU_PTB((u32)ptb, SMMU_ATTR_ALL);
smmu_flush_regs(); _smmu_flush_regs();
MC(dev_base) = 0x80000000 | (asid << 24) | (asid << 16) | (asid << 8) | (asid); // Use the same macro for both quad and single domains. Reserved bits are not set anyway.
smmu_flush_regs(); MC(dev_base) = SMMU_ENABLE | SMMU_ASID(asid);
_smmu_flush_regs();
return pdir; return ptb;
} }
u32 *smmu_get_pte(u32 *pdir, u32 iova) void smmu_deinit_domain(u32 dev_base, u32 asid)
{ {
u32 ptn = SMMU_ADDR_TO_PFN(iova); MC(MC_SMMU_PTB_ASID) = asid;
u32 pdn = SMMU_ADDR_TO_PDN(iova); MC(MC_SMMU_PTB_DATA) = 0;
u32 *ptbl; MC(dev_base) = 0;
_smmu_flush_regs();
}
if (pdir[pdn] != _PDE_VACANT(pdn)) void smmu_domain_bypass(u32 dev_base, bool bypass)
ptbl = (u32 *)((pdir[pdn] & SMMU_PFN_MASK) << SMMU_PDIR_SHIFT); {
if (bypass)
{
smmu_flush_all();
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
MC(dev_base) &= ~SMMU_ENABLE;
}
else else
{ {
ptbl = (u32 *)page_alloc(1); bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
MC(dev_base) |= SMMU_ENABLE;
smmu_flush_all();
}
_smmu_flush_regs();
}
static pte_t *_smmu_get_pte(pde_t *pdir, u32 iova)
{
u32 pdn = SMMU_ADDR_TO_PDN(iova);
pte_t *ptbl;
// Get 4MB page table or initialize one.
if (pdir[pdn].tbl.attr)
ptbl = (pte_t *)(SMMU_PTN_TO_ADDR(pdir[pdn].tbl.table));
else
{
// Allocate page table.
ptbl = (pte_t *)smmu_page_zalloc(1);
// Get address.
u32 addr = SMMU_PDN_TO_ADDR(pdn); u32 addr = SMMU_PDN_TO_ADDR(pdn);
for (int pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SMMU_PAGE_SIZE)
ptbl[pn] = _PTE_VACANT(addr); // Initialize page table with no permissions.
pdir[pdn] = SMMU_MK_PDE((u32)ptbl, _PDE_ATTR | _PDE_NEXT); for (u32 pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SZ_PAGE)
ptbl[pn].page = SMMU_ADDR_TO_PFN(addr);
// Set page table to the page directory.
pdir[pdn].tbl.table = SMMU_ADDR_TO_PTN((u32)ptbl);
pdir[pdn].tbl.next = SMMU_PAGE_TABLE;
pdir[pdn].tbl.attr = SMMU_ATTR_ALL;
smmu_flush_all(); smmu_flush_all();
} }
return &ptbl[ptn % SMMU_PTBL_COUNT]; return &ptbl[SMMU_ADDR_TO_PTN(iova) % SMMU_PTBL_COUNT];
} }
void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr) void smmu_map(void *ptb, u32 iova, u64 iopa, u32 pages, u32 attr)
{ {
for (int i = 0; i < cnt; i++) // Map pages to page table entries. VA/PA should be aligned to 4KB.
for (u32 i = 0; i < pages; i++)
{ {
u32 *pte = smmu_get_pte(pdir, addr); pte_t *pte = _smmu_get_pte((pde_t *)ptb, iova);
*pte = SMMU_ADDR_TO_PFN(page) | attr;
addr += SZ_PAGE; pte->page = SMMU_ADDR_TO_PFN(iopa);
page += SZ_PAGE; pte->attr = attr;
iova += SZ_PAGE;
iopa += SZ_PAGE;
} }
smmu_flush_all(); smmu_flush_all();
} }
u32 *smmu_init_for_tsec() void smmu_map_huge(void *ptb, u32 iova, u64 iopa, u32 regions, u32 attr)
{ {
return smmu_init_domain4(MC_SMMU_TSEC_ASID, 1); pde_t *pdir = (pde_t *)ptb;
}
void smmu_deinit_for_tsec() // Map 4MB regions to page directory entries. VA/PA should be aligned to 4MB.
{ for (u32 i = 0; i < regions; i++)
MC(MC_SMMU_PTB_ASID) = 1; {
MC(MC_SMMU_PTB_DATA) = 0; u32 pdn = SMMU_ADDR_TO_PDN(iova);
MC(MC_SMMU_TSEC_ASID) = 0; pdir[pdn].huge.page = SMMU_ADDR_TO_PDN(iopa);
smmu_flush_regs(); pdir[pdn].huge.next = SMMU_4MB_REGION;
} pdir[pdn].huge.attr = attr;
iova += SZ_4M;
iopa += SZ_4M;
}
smmu_flush_all();
}

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2024 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -14,70 +15,58 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <assert.h>
#include <utils/types.h> #include <utils/types.h>
#define SMMU_HEAP_ADDR 0xA0000000
#define MC_INTSTATUS 0x0
#define MC_INTMASK 0x4
#define MC_ERR_STATUS 0x8
#define MC_ERR_ADR 0xc
#define MC_SMMU_CONFIG 0x10
#define MC_SMMU_TLB_CONFIG 0x14
#define MC_SMMU_PTC_CONFIG 0x18
#define MC_SMMU_PTB_ASID 0x1c
#define MC_SMMU_PTB_DATA 0x20
#define MC_SMMU_TLB_FLUSH 0x30
#define MC_SMMU_PTC_FLUSH 0x34
#define MC_SMMU_ASID_SECURITY 0x38
#define MC_SMMU_AVPC_ASID 0x23C #define MC_SMMU_AVPC_ASID 0x23C
#define MC_SMMU_TSEC_ASID 0x294 #define MC_SMMU_TSEC_ASID 0x294
#define MC_SMMU_TRANSLATION_ENABLE_0 0x228
#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c
#define MC_SMMU_TRANSLATION_ENABLE_2 0x230
#define MC_SMMU_TRANSLATION_ENABLE_3 0x234
#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98
#define SMMU_PDE_NEXT_SHIFT 28 #define SMMU_NS BIT(0)
#define MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT 29 #define SMMU_WRITE BIT(1)
#define MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT 30 #define SMMU_READ BIT(2)
#define MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT 31 #define SMMU_ATTR_ALL (SMMU_READ | SMMU_WRITE | SMMU_NS)
#define SMMU_PAGE_SHIFT 12
#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT)
#define SMMU_PDIR_COUNT 1024
#define SMMU_PDIR_SIZE (sizeof(u32) * SMMU_PDIR_COUNT)
#define SMMU_PTBL_COUNT 1024
#define SMMU_PTBL_SIZE (sizeof(u32) * SMMU_PTBL_COUNT)
#define SMMU_PDIR_SHIFT 12
#define SMMU_PDE_SHIFT 12
#define SMMU_PTE_SHIFT 12
#define SMMU_PFN_MASK 0x000FFFFF
#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12)
#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22)
#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22)
#define _READABLE (1 << MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT)
#define _WRITABLE (1 << MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT)
#define _NONSECURE (1 << MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT)
#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT)
#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR)
#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR)
#define SMMU_MK_PDIR(page, attr) (((page) >> SMMU_PDIR_SHIFT) | (attr))
#define SMMU_MK_PDE(page, attr) (((page) >> SMMU_PDE_SHIFT) | (attr))
void *page_alloc(u32 num); typedef struct _pde_t {
u32 *smmu_alloc_pdir(); union {
void smmu_flush_regs(); union {
void smmu_flush_all(); struct {
void smmu_init(u32 secmon_base); u32 table:22;
void smmu_enable(); u32 rsvd:6;
bool smmu_is_used(); u32 next:1;
void smmu_exit(); u32 attr:3;
u32 *smmu_init_domain4(u32 dev_base, u32 asid); } tbl;
u32 *smmu_get_pte(u32 *pdir, u32 iova);
void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr); struct {
u32 *smmu_init_for_tsec(); u32 rsvd_:10;
void smmu_deinit_for_tsec(); u32 page:12;
u32 rsvd:6;
u32 next:1;
u32 attr:3;
} huge;
};
u32 pde;
};
} pde_t;
typedef struct _pte_t {
u32 page:22;
u32 rsvd:7;
u32 attr:3;
} pte_t;
static_assert(sizeof(pde_t) == sizeof(u32), "pde_t size is wrong!");
static_assert(sizeof(pte_t) == sizeof(u32), "pte_t size is wrong!");
void *smmu_page_zalloc(u32 num);
void smmu_flush_all();
void smmu_init();
void smmu_enable();
void smmu_disable();
void smmu_reset_heap();
void *smmu_init_domain(u32 dev_base, u32 asid);
void smmu_deinit_domain(u32 dev_base, u32 asid);
void smmu_domain_bypass(u32 dev_base, bool bypass);
void smmu_map(void *ptb, u32 iova, u64 iopa, u32 pages, u32 attr);
void smmu_map_huge(void *ptb, u32 iova, u64 iopa, u32 regions, u32 attr);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2021 CTCaer * Copyright (c) 2019-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -29,7 +29,6 @@
#define SECMON_MIN_START 0x4002B000 // Minimum reserved address for secmon. #define SECMON_MIN_START 0x4002B000 // Minimum reserved address for secmon.
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. #define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.
#define CBFS_DRAM_EN_ADDR 0x4003e000 // u32.
/* start.S / exception_handlers.S */ /* start.S / exception_handlers.S */
#define SYS_STACK_TOP_INIT 0x4003FF00 #define SYS_STACK_TOP_INIT 0x4003FF00
@@ -48,27 +47,27 @@
#define NYX_SZ_MAX SZ_16M #define NYX_SZ_MAX SZ_16M
/* --- Gap: 0x82000000 - 0x82FFFFFF --- */ /* --- Gap: 0x82000000 - 0x82FFFFFF --- */
/* Stack theoretical max: 33MB */ // Heap buffer.
#define IPL_STACK_TOP 0x83100000 #define IPL_HEAP_START 0x82000000
#define IPL_HEAP_START 0x84000000 #define IPL_HEAP_SZ (SZ_256M)
#define IPL_HEAP_SZ SZ_512M
/* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */ #define SMMU_HEAP_ADDR 0x92000000
/* --- Gap: 1280MB 0x96000000 - 0xE4FFFFFF --- */
// Virtual disk / Chainloader buffers. // Virtual disk / Chainloader buffers.
#define RAM_DISK_ADDR 0xA4000000 #define RAM_DISK_ADDR 0x95000000
#define RAM_DISK_SZ 0x41000000 // 1040MB. #define RAM_DISK_SZ 0x50000000 // 1280MB.
#define RAM_DISK2_SZ 0x21000000 // 528MB.
// NX BIS driver sector cache.
#define NX_BIS_CACHE_ADDR 0xC5000000
#define NX_BIS_CACHE_SZ 0x10020000 // 256MB.
#define NX_BIS_LOOKUP_ADDR 0xD6000000
#define NX_BIS_LOOKUP_SZ 0xF000000 // 240MB.
// L4T Kernel Panic Storage (PSTORE). // L4T Kernel Panic Storage (PSTORE).
#define PSTORE_ADDR 0xB0000000 #define PSTORE_ADDR 0xB0000000
#define PSTORE_SZ SZ_2M #define PSTORE_SZ SZ_2M
// NX BIS driver sector cache.
#define NX_BIS_CACHE_ADDR 0xC7000000
#define NX_BIS_CACHE_SZ 0x10020000 // 256MB.
#define NX_BIS_LOOKUP_ADDR 0xD8000000
#define NX_BIS_LOOKUP_SZ 0x8000000 // 128MB. 512GB eMMC partition max.
//#define DRAM_LIB_ADDR 0xE0000000 //#define DRAM_LIB_ADDR 0xE0000000
/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. /* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading.
@@ -76,7 +75,7 @@
#define SDMMC_UPPER_BUFFER 0xE5000000 #define SDMMC_UPPER_BUFFER 0xE5000000
#define SDMMC_UP_BUF_SZ SZ_128M #define SDMMC_UP_BUF_SZ SZ_128M
// Nyx buffers. // Nyx buffers. !Do not change!
#define NYX_STORAGE_ADDR 0xED000000 #define NYX_STORAGE_ADDR 0xED000000
#define NYX_RES_ADDR 0xEE000000 #define NYX_RES_ADDR 0xEE000000
#define NYX_RES_SZ SZ_16M #define NYX_RES_SZ SZ_16M
@@ -84,7 +83,6 @@
// SDMMC DMA buffers 2 // SDMMC DMA buffers 2
#define SDXC_BUF_ALIGNED 0xEF000000 #define SDXC_BUF_ALIGNED 0xEF000000
#define MIXD_BUF_ALIGNED 0xF0000000 #define MIXD_BUF_ALIGNED 0xF0000000
#define TITLEKEY_BUF_ADR MIXD_BUF_ALIGNED
#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED #define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
#define SDMMC_DMA_BUF_SZ SZ_16M // 4MB currently used. #define SDMMC_DMA_BUF_SZ SZ_16M // 4MB currently used.
@@ -94,7 +92,7 @@
#define NYX_LV_MEM_ADR 0xF1400000 #define NYX_LV_MEM_ADR 0xF1400000
#define NYX_LV_MEM_SZ 0x6600000 // 70MB. #define NYX_LV_MEM_SZ 0x6600000 // 70MB.
// Framebuffer addresses. // Framebuffer addresses. !Do not change!
#define IPL_FB_ADDRESS 0xF5A00000 #define IPL_FB_ADDRESS 0xF5A00000
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. #define IPL_FB_SZ 0x384000 // 720 x 1280 x 4.
#define LOG_FB_ADDRESS 0xF5E00000 #define LOG_FB_ADDRESS 0xF5E00000
@@ -103,13 +101,6 @@
#define NYX_FB2_ADDRESS 0xF6600000 #define NYX_FB2_ADDRESS 0xF6600000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. #define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
/* OBSOLETE: Very old hwinit based payloads were setting a carveout here. */
#define DRAM_MEM_HOLE_ADR 0xF6A00000
#define NX_BIS_LOOKUP_ADR DRAM_MEM_HOLE_ADR
#define DRAM_MEM_HOLE_SZ 0x8140000
/* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */
#define DRAM_START2 0xFEB40000
// USB buffers. // USB buffers.
#define USBD_ADDR 0xFEF00000 #define USBD_ADDR 0xFEF00000
#define USB_DESCRIPTOR_ADDR 0xFEF40000 #define USB_DESCRIPTOR_ADDR 0xFEF40000

View File

@@ -1,7 +1,7 @@
/* /*
* USB-PD driver for Nintendo Switch's TI BM92T36 * USB-PD driver for Nintendo Switch's TI BM92T36
* *
* Copyright (c) 2020-2023 CTCaer * Copyright (c) 2020-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -54,6 +54,10 @@
#define STATUS1_INSERT BIT(7) // Cable inserted. #define STATUS1_INSERT BIT(7) // Cable inserted.
#define VER_36 0x36
#define MAX_ROHM 0x4B5
#define DEV_BM92T 0x3B0
typedef struct _pd_object_t { typedef struct _pd_object_t {
unsigned int amp:10; unsigned int amp:10;
unsigned int volt:10; unsigned int volt:10;
@@ -63,9 +67,29 @@ typedef struct _pd_object_t {
static int _bm92t36_read_reg(u8 *buf, u32 size, u32 reg) static int _bm92t36_read_reg(u8 *buf, u32 size, u32 reg)
{ {
memset(buf, 0, size);
return i2c_recv_buf_big(buf, size, I2C_1, BM92T36_I2C_ADDR, reg); return i2c_recv_buf_big(buf, size, I2C_1, BM92T36_I2C_ADDR, reg);
} }
int bm92t36_get_version(u32 *value)
{
u8 buf[2];
u16 version, man, dev;
_bm92t36_read_reg(buf, 2, FW_TYPE_REG);
version = (buf[0] << 4) | buf[1];
_bm92t36_read_reg(buf, 2, MAN_ID_REG);
man = (buf[1] << 8) | buf[0];
_bm92t36_read_reg(buf, 2, DEV_ID_REG);
dev = (buf[1] << 8) | buf[0];
if (value)
*value = (dev << 16) | version;
if (version == VER_36 && man == MAX_ROHM && dev == DEV_BM92T)
return 0;
else
return -1;
}
void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd) void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd)
{ {
u8 buf[32]; u8 buf[32];
@@ -73,14 +97,12 @@ void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd)
if (inserted) if (inserted)
{ {
memset(buf, 0, sizeof(buf));
_bm92t36_read_reg(buf, 2, STATUS1_REG); _bm92t36_read_reg(buf, 2, STATUS1_REG);
*inserted = buf[0] & STATUS1_INSERT ? true : false; *inserted = (buf[0] & STATUS1_INSERT) ? true : false;
} }
if (usb_pd) if (usb_pd)
{ {
memset(buf, 0, sizeof(buf));
_bm92t36_read_reg(buf, 29, READ_PDOS_SRC_REG); _bm92t36_read_reg(buf, 29, READ_PDOS_SRC_REG);
memcpy(pdos, &buf[1], 28); memcpy(pdos, &buf[1], 28);

View File

@@ -36,6 +36,7 @@ typedef struct _usb_pd_objects_t
usb_pd_object_t selected_pdo; usb_pd_object_t selected_pdo;
} usb_pd_objects_t; } usb_pd_objects_t;
int bm92t36_get_version(u32 *value);
void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd); void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd);
#endif #endif

View File

@@ -1,7 +1,7 @@
/* /*
* Battery charger driver for Nintendo Switch's TI BQ24193 * Battery charger driver for Nintendo Switch's TI BQ24193
* *
* Copyright (c) 2018 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -25,131 +25,144 @@ static u8 bq24193_get_reg(u8 reg)
return i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, reg); return i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, reg);
} }
int bq24193_get_version(u32 *value)
{
u16 data = bq24193_get_reg(BQ24193_VendorPart);
if (value)
*value = data;
if (data == 0x2F)
return 0;
else
return -1;
}
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value) int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
{ {
u8 data; u8 data;
switch (prop) { switch (prop)
case BQ24193_InputVoltageLimit: // Input voltage limit (mV). {
data = bq24193_get_reg(BQ24193_InputSource); case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3; data = bq24193_get_reg(BQ24193_InputSource);
*value = 0; data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3;
*value += ((data >> 0) & 1) ? 80 : 0; *value = 0;
*value += ((data >> 1) & 1) ? 160 : 0; *value += ((data >> 0) & 1) ? 80 : 0;
*value += ((data >> 2) & 1) ? 320 : 0; *value += ((data >> 1) & 1) ? 160 : 0;
*value += ((data >> 3) & 1) ? 640 : 0; *value += ((data >> 2) & 1) ? 320 : 0;
*value += 3880; *value += ((data >> 3) & 1) ? 640 : 0;
*value += 3880;
break;
case BQ24193_InputCurrentLimit: // Input current limit (mA).
data = bq24193_get_reg(BQ24193_InputSource);
data &= BQ24193_INCONFIG_INLIMIT_MASK;
switch (data)
{
case 0:
*value = 100;
break; break;
case BQ24193_InputCurrentLimit: // Input current limit (mA). case 1:
data = bq24193_get_reg(BQ24193_InputSource); *value = 150;
data &= BQ24193_INCONFIG_INLIMIT_MASK;
switch (data)
{
case 0:
*value = 100;
break;
case 1:
*value = 150;
break;
case 2:
*value = 500;
break;
case 3:
*value = 900;
break;
case 4:
*value = 1200;
break;
case 5:
*value = 1500;
break;
case 6:
*value = 2000;
break;
case 7:
*value = 3000;
break;
}
break; break;
case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV). case 2:
data = bq24193_get_reg(BQ24193_PORConfig); *value = 500;
*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;
*value *= 100;
*value += 3000;
break; break;
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA). case 3:
data = bq24193_get_reg(BQ24193_ChrgCurr); *value = 900;
data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2;
*value = 0;
*value += ((data >> 0) & 1) ? 64 : 0;
*value += ((data >> 1) & 1) ? 128 : 0;
*value += ((data >> 2) & 1) ? 256 : 0;
*value += ((data >> 3) & 1) ? 512 : 0;
*value += ((data >> 4) & 1) ? 1024 : 0;
*value += ((data >> 5) & 1) ? 2048 : 0;
*value += 512;
data = bq24193_get_reg(BQ24193_ChrgCurr);
data &= BQ24193_CHRGCURR_20PCT_MASK;
if (data)
*value = *value * 20 / 100; // Fast charge current limit is 20%.
break; break;
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV). case 4:
data = bq24193_get_reg(BQ24193_ChrgVolt); *value = 1200;
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
*value = 0;
*value += ((data >> 0) & 1) ? 16 : 0;
*value += ((data >> 1) & 1) ? 32 : 0;
*value += ((data >> 2) & 1) ? 64 : 0;
*value += ((data >> 3) & 1) ? 128 : 0;
*value += ((data >> 4) & 1) ? 256 : 0;
*value += ((data >> 5) & 1) ? 512 : 0;
*value += 3504;
break; break;
case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV). case 5:
data = bq24193_get_reg(BQ24193_ChrgVolt); *value = 1500;
data &= BQ24193_IRTHERMAL_THERM_MASK;
if (data)
*value = 300;
else
*value = 100;
break; break;
case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC). case 6:
data = bq24193_get_reg(BQ24193_IRCompThermal); *value = 2000;
data &= BQ24193_IRTHERMAL_THERM_MASK;
switch (data)
{
case 0:
*value = 60;
break;
case 1:
*value = 80;
break;
case 2:
*value = 100;
break;
case 3:
*value = 120;
break;
}
break; break;
case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done case 7:
data = bq24193_get_reg(BQ24193_Status); *value = 3000;
*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;
break; break;
case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot. }
data = bq24193_get_reg(BQ24193_FaultReg); break;
*value = data & BQ24193_FAULT_THERM_MASK; case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV).
data = bq24193_get_reg(BQ24193_PORConfig);
*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;
*value *= 100;
*value += 3000;
break;
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).
data = bq24193_get_reg(BQ24193_ChrgCurr);
data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2;
*value = 0;
*value += ((data >> 0) & 1) ? 64 : 0;
*value += ((data >> 1) & 1) ? 128 : 0;
*value += ((data >> 2) & 1) ? 256 : 0;
*value += ((data >> 3) & 1) ? 512 : 0;
*value += ((data >> 4) & 1) ? 1024 : 0;
*value += ((data >> 5) & 1) ? 2048 : 0;
*value += 512;
data = bq24193_get_reg(BQ24193_ChrgCurr);
data &= BQ24193_CHRGCURR_20PCT_MASK;
if (data)
*value = *value * 20 / 100; // Fast charge current limit is 20%.
break;
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).
data = bq24193_get_reg(BQ24193_ChrgVolt);
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
*value = 0;
*value += ((data >> 0) & 1) ? 16 : 0;
*value += ((data >> 1) & 1) ? 32 : 0;
*value += ((data >> 2) & 1) ? 64 : 0;
*value += ((data >> 3) & 1) ? 128 : 0;
*value += ((data >> 4) & 1) ? 256 : 0;
*value += ((data >> 5) & 1) ? 512 : 0;
*value += 3504;
break;
case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV).
data = bq24193_get_reg(BQ24193_ChrgVolt);
data &= BQ24193_IRTHERMAL_THERM_MASK;
if (data)
*value = 300;
else
*value = 100;
break;
case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC).
data = bq24193_get_reg(BQ24193_IRCompThermal);
data &= BQ24193_IRTHERMAL_THERM_MASK;
switch (data)
{
case 0:
*value = 60;
break; break;
case BQ24193_DevID: // Dev ID. case 1:
data = bq24193_get_reg(BQ24193_VendorPart); *value = 80;
*value = data & BQ24193_VENDORPART_DEV_MASK;
break; break;
case BQ24193_ProductNumber: // Product number. case 2:
data = bq24193_get_reg(BQ24193_VendorPart); *value = 100;
*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;
break; break;
default: case 3:
return -1; *value = 120;
break;
}
break;
case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done
data = bq24193_get_reg(BQ24193_Status);
*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;
break;
case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot.
data = bq24193_get_reg(BQ24193_FaultReg);
*value = data & BQ24193_FAULT_THERM_MASK;
break;
case BQ24193_DevID: // Dev ID.
data = bq24193_get_reg(BQ24193_VendorPart);
*value = data & BQ24193_VENDORPART_DEV_MASK;
break;
case BQ24193_ProductNumber: // Product number.
data = bq24193_get_reg(BQ24193_VendorPart);
*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;
break;
default:
return -1;
} }
return 0; return 0;
} }

View File

@@ -19,6 +19,8 @@
#ifndef __BQ24193_H_ #ifndef __BQ24193_H_
#define __BQ24193_H_ #define __BQ24193_H_
#include <utils/types.h>
#define BQ24193_I2C_ADDR 0x6B #define BQ24193_I2C_ADDR 0x6B
// REG 0 masks. // REG 0 masks.
@@ -114,7 +116,8 @@ enum BQ24193_reg_prop {
BQ24193_ProductNumber, // REG A. BQ24193_ProductNumber, // REG A.
}; };
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value); int bq24193_get_version(u32 *value);
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value);
void bq24193_enable_charger(); void bq24193_enable_charger();
void bq24193_fake_battery_removal(); void bq24193_fake_battery_removal();

View File

@@ -3,7 +3,7 @@
* *
* Copyright (c) 2011 Samsung Electronics * Copyright (c) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com> * MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (c) 2018 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -60,6 +60,18 @@ static u16 max17050_get_reg(u8 reg)
return data; return data;
} }
int max17050_get_version(u32 *value)
{
u16 data = max17050_get_reg(MAX17050_DevName);
if (value)
*value = data;
if (data == 0x00AC)
return 0;
else
return -1;
}
int max17050_get_property(enum MAX17050_reg reg, int *value) int max17050_get_property(enum MAX17050_reg reg, int *value)
{ {
u16 data; u16 data;
@@ -279,3 +291,26 @@ int max17050_fix_configuration()
return 0; return 0;
} }
void max17050_dump_regs(void *buf)
{
u16 *buff = (u16 *)buf;
// Unlock model table.
u16 unlock = 0x59;
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2);
unlock = 0xC4;
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2);
// Dump all battery fuel gauge registers.
for (u32 i = 0; i < 0x100; i++)
{
buff[i] = max17050_get_reg(i);
msleep(1);
}
// Lock model table.
unlock = 0;
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2);
i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2);
}

View File

@@ -130,8 +130,10 @@ enum MAX17050_reg {
MAX17050_VFSOC = 0xFF, MAX17050_VFSOC = 0xFF,
}; };
int max17050_get_property(enum MAX17050_reg reg, int *value); int max17050_get_version(u32 *value);
int max17050_fix_configuration(); int max17050_get_property(enum MAX17050_reg reg, int *value);
u32 max17050_get_cached_batt_volt(); int max17050_fix_configuration();
void max17050_dump_regs(void *buf);
u32 max17050_get_cached_batt_volt();
#endif /* __MAX17050_H_ */ #endif /* __MAX17050_H_ */

View File

@@ -75,7 +75,7 @@ typedef struct _max77620_regulator_t
static const max77620_regulator_t _pmic_regulators[] = { static const max77620_regulator_t _pmic_regulators[] = {
{ "sd0", 12500, 600000, 625000, 1400000, REGULATOR_SD, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, {{ MAX77620_REG_FPS_SD0, 1, 7, 1 }} }, { "sd0", 12500, 600000, 625000, 1400000, REGULATOR_SD, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, {{ MAX77620_REG_FPS_SD0, 1, 7, 1 }} },
{ "sd1", 12500, 600000, 1125000, 1250000, REGULATOR_SD, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, {{ MAX77620_REG_FPS_SD1, 0, 1, 5 }} }, { "sd1", 12500, 600000, 1125000, 1237500, REGULATOR_SD, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, {{ MAX77620_REG_FPS_SD1, 0, 1, 5 }} },
{ "sd2", 12500, 600000, 1325000, 1350000, REGULATOR_SD, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD2, 1, 5, 2 }} }, { "sd2", 12500, 600000, 1325000, 1350000, REGULATOR_SD, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD2, 1, 5, 2 }} },
{ "sd3", 12500, 600000, 1800000, 1800000, REGULATOR_SD, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD3, 0, 3, 3 }} }, { "sd3", 12500, 600000, 1800000, 1800000, REGULATOR_SD, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD3, 0, 3, 3 }} },
{ "ldo0", 25000, 800000, 1200000, 1200000, REGULATOR_LDO, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO0, 3, 7, 0 }} }, { "ldo0", 25000, 800000, 1200000, 1200000, REGULATOR_LDO, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO0, 3, 7, 0 }} },
@@ -103,7 +103,7 @@ static u8 _max77812_get_address()
return max77812_i2c_addr; return max77812_i2c_addr;
max77812_i2c_addr = max77812_i2c_addr =
!(FUSE(FUSE_RESERVED_ODM28_T210B01) & 1) ? MAX77812_PHASE31_CPU_I2C_ADDR : MAX77812_PHASE211_CPU_I2C_ADDR; !(FUSE(FUSE_RESERVED_ODM28_B01) & 1) ? MAX77812_PHASE31_CPU_I2C_ADDR : MAX77812_PHASE211_CPU_I2C_ADDR;
return max77812_i2c_addr; return max77812_i2c_addr;
} }
@@ -123,7 +123,7 @@ static u8 _max7762x_get_i2c_address(u32 id)
case REGULATOR_BC1: case REGULATOR_BC1:
{ {
u8 reg_addr = _max77812_get_address(); u8 reg_addr = _max77812_get_address();
if (id == REGULATOR_RAM1 && reg_addr == MAX77812_PHASE31_CPU_I2C_ADDR) if (id == REGULATOR_RAM0 && reg_addr == MAX77812_PHASE31_CPU_I2C_ADDR)
reg_addr = 0; reg_addr = 0;
return reg_addr; return reg_addr;
} }
@@ -327,7 +327,7 @@ void max77620_config_default()
return; return;
// Set default voltages and enable regulators. // Set default voltages and enable regulators.
for (u32 i = 1; i <= REGULATOR_LDO8; i++) for (u32 i = REGULATOR_SD1; i <= REGULATOR_LDO8; i++)
{ {
max77620_regulator_config_fps(i); max77620_regulator_config_fps(i);
max7762x_regulator_set_voltage(i, _pmic_regulators[i].uv_default); max7762x_regulator_set_voltage(i, _pmic_regulators[i].uv_default);

View File

@@ -47,6 +47,27 @@
* ldo8 | XUSB, DP, MCU | 50000 | 800000 | 1050000 | 2800000 | 1.05V/2.8V (pcv) * ldo8 | XUSB, DP, MCU | 50000 | 800000 | 1050000 | 2800000 | 1.05V/2.8V (pcv)
*/ */
// GPIOs T210: 3: 3.3V, 5: CPU PMIC, 6: GPU PMIC, 7: DSI/VI 1.2V powered by ldo0.
/*
* OTP: T210 - T210B01:
* SD0: 1.0V 1.05V - SoC. EN Based on FPSSRC.
* SD1: 1.15V 1.1V - DRAM for T210. EN Based on FPSSRC.
* SD2: 1.35V 1.35V
* SD3: 1.8V 1.8V
* All powered off?
* LDO0: -- -- - Display
* LDO1: 1.05V 1.05V
* LDO2: -- -- - SD
* LDO3: 3.1V 3.1V - GC ASIC
* LDO4: 1.0V 0.8V - Needed for RTC domain on T210.
* LDO5: 3.1V 3.1V
* LDO6: 2.8V 2.9V - Touch.
* LDO7: 1.05V 1.0V
* LDO8: 1.05V 1.0V
*/
/* /*
* MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode * MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode
* MAX77620_REG_GPIOx: 0x9 sets output and enable * MAX77620_REG_GPIOx: 0x9 sets output and enable
@@ -69,9 +90,9 @@
#define REGULATOR_CPU0 13 // T210 CPU. #define REGULATOR_CPU0 13 // T210 CPU.
#define REGULATOR_GPU0 14 // T210 CPU. #define REGULATOR_GPU0 14 // T210 CPU.
#define REGULATOR_CPU1 15 // T210B01 CPU. #define REGULATOR_CPU1 15 // T210B01 CPU.
#define REGULATOR_RAM1 16 // T210B01 RAM for PHASE211. #define REGULATOR_RAM0 16 // T210B01 RAM for PHASE211.
//#define REGULATOR_GPU1 17 // T210B01 CPU. //#define REGULATOR_GPU1 17 // T210B01 CPU.
#define REGULATOR_MAX REGULATOR_RAM1 #define REGULATOR_MAX REGULATOR_RAM0
#define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_CPU_I2C_ADDR 0x1B
#define MAX77621_GPU_I2C_ADDR 0x1C #define MAX77621_GPU_I2C_ADDR 0x1C

View File

@@ -75,14 +75,14 @@
#define MAX77812_REG_GLB_CFG3 0x35 #define MAX77812_REG_GLB_CFG3 0x35
/*! Protected area and settings only for MAX77812_ES2_VERSION */ /*! Protected area and settings only for MAX77812_ES2_VERSION */
#define MAX77812_REG_GLB_CFG4 0x36 #define MAX77812_REG_GLB_CFG4 0x36 // QS: 0xBB.
#define MAX77812_REG_GLB_CFG5 0x37 // HOS: 0x3E. Unmasked write. #define MAX77812_REG_GLB_CFG5 0x37 // QS: 0x39. ES2: Set to 0x3E.
#define MAX77812_REG_GLB_CFG6 0x38 // HOS: 0x90. Unmasked write. #define MAX77812_REG_GLB_CFG6 0x38 // QS: 0x88. ES2: Set to 0x90.
#define MAX77812_REG_GLB_CFG7 0x39 #define MAX77812_REG_GLB_CFG7 0x39 // QS: 0x04.
#define MAX77812_REG_GLB_CFG8 0x3A // HOS: 0x3A. Unmasked write. #define MAX77812_REG_GLB_CFG8 0x3A // QS: 0x3A. ES2: Set to 0x3A.
#define MAX77812_REG_PROT_ACCESS 0xFD // 0x00: Lock, 0x5A: Unlock. #define MAX77812_REG_PROT_ACCESS 0xFD // 0x00: Lock, 0x5A: Unlock.
#define MAX77812_REG_MAX 0xFD #define MAX77812_REG_UNKNOWN 0xFE
#define MAX77812_REG_EN_CTRL_MASK(n) BIT(n) #define MAX77812_REG_EN_CTRL_MASK(n) BIT(n)
#define MAX77812_START_SLEW_RATE_MASK 0x07 #define MAX77812_START_SLEW_RATE_MASK 0x07

View File

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

View File

@@ -1,7 +1,7 @@
/* /*
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
* *
* Copyright (c) 2018-2022 CTCaer * Copyright (c) 2018-2025 CTCaer
* Copyright (c) 2019 shchmue * Copyright (c) 2019 shchmue
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -23,6 +23,9 @@
#include <soc/timer.h> #include <soc/timer.h>
#include <soc/t210.h> #include <soc/t210.h>
bool auto_dst = false;
int epoch_offset = 0;
void max77620_rtc_prep_read() void max77620_rtc_prep_read()
{ {
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE); i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
@@ -37,20 +40,24 @@ void max77620_rtc_get_time(rtc_time_t *time)
// Get control reg config. // Get control reg config.
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG); val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG);
// TODO: Check for binary format also? // TODO: Make also sure it's binary format?
// Get time. // Get time.
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F; time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG); u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
time->hour = hour & 0x1F; time->hour = hour & 0x1F;
if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK)) if (!(val & MAX77620_RTC_24H))
time->hour = (time->hour & 0xF) + 12; {
time->hour = hour & 0xF;
if (hour & MAX77620_RTC_HOUR_PM_MASK)
time->hour += 12;
}
// Get day of week. 1: Monday to 7: Sunday. // Get day of week. 1: Monday to 7: Sunday.
time->weekday = 0; time->weekday = 0;
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG); val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG) & 0x7F;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
time->weekday++; time->weekday++;
@@ -60,8 +67,9 @@ void max77620_rtc_get_time(rtc_time_t *time)
} }
// Get date. // Get date.
time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DAY_REG) & 0x1F;
time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1; time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;
time->month++; // Normally minus 1, but everything else expects 1 as January.
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000; time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
} }
@@ -124,7 +132,7 @@ void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time)
time->day = day; time->day = day;
// Set weekday. // Set weekday.
time->weekday = 0; //! TODO. time->weekday = (day + 4) % 7;
} }
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time) u32 max77620_rtc_date_to_epoch(const rtc_time_t *time)
@@ -154,6 +162,32 @@ u32 max77620_rtc_date_to_epoch(const rtc_time_t *time)
return epoch; return epoch;
} }
void max77620_rtc_get_time_adjusted(rtc_time_t *time)
{
max77620_rtc_get_time(time);
if (epoch_offset)
{
u32 epoch = (u32)((s64)max77620_rtc_date_to_epoch(time) + epoch_offset);
// Adjust for DST between 28 march and 28 october. Good enough to cover all years as week info is not valid.
u16 md = (time->month << 8) | time->day;
if (auto_dst && md >= 0x31C && md < 0xA1C)
epoch += 3600;
max77620_rtc_epoch_to_date(epoch, time);
}
}
void max77620_rtc_set_auto_dst(bool enable)
{
auto_dst = enable;
}
void max77620_rtc_set_epoch_offset(int offset)
{
epoch_offset = offset;
}
void max77620_rtc_set_reboot_reason(rtc_reboot_reason_t *rr) void max77620_rtc_set_reboot_reason(rtc_reboot_reason_t *rr)
{ {
max77620_rtc_stop_alarm(); max77620_rtc_stop_alarm();

View File

@@ -46,7 +46,7 @@
#define MAX77620_RTC_WEEKDAY_REG 0x0A #define MAX77620_RTC_WEEKDAY_REG 0x0A
#define MAX77620_RTC_MONTH_REG 0x0B #define MAX77620_RTC_MONTH_REG 0x0B
#define MAX77620_RTC_YEAR_REG 0x0C #define MAX77620_RTC_YEAR_REG 0x0C
#define MAX77620_RTC_DATE_REG 0x0D #define MAX77620_RTC_DAY_REG 0x0D
#define MAX77620_ALARM1_SEC_REG 0x0E #define MAX77620_ALARM1_SEC_REG 0x0E
#define MAX77620_ALARM1_MIN_REG 0x0F #define MAX77620_ALARM1_MIN_REG 0x0F
@@ -109,6 +109,9 @@ typedef struct _rtc_reboot_reason_t
void max77620_rtc_prep_read(); void max77620_rtc_prep_read();
void max77620_rtc_get_time(rtc_time_t *time); void max77620_rtc_get_time(rtc_time_t *time);
void max77620_rtc_get_time_adjusted(rtc_time_t *time);
void max77620_rtc_set_epoch_offset(int offset);
void max77620_rtc_set_auto_dst(bool enable);
void max77620_rtc_stop_alarm(); void max77620_rtc_stop_alarm();
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time); void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time);
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time); u32 max77620_rtc_date_to_epoch(const rtc_time_t *time);

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2022 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -19,7 +19,6 @@
#include "se.h" #include "se.h"
#include <memory_map.h> #include <memory_map.h>
#include <mem/heap.h>
#include <soc/bpmp.h> #include <soc/bpmp.h>
#include <soc/hw_init.h> #include <soc/hw_init.h>
#include <soc/pmc.h> #include <soc/pmc.h>
@@ -182,7 +181,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
if (!src || !dst) if (!src || !dst)
return 0; return 0;
u8 *block = (u8 *)calloc(1, SE_AES_BLOCK_SIZE); u32 block[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};
SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1; SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1;
@@ -190,11 +189,10 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
int res = _se_execute_oneshot(op, block, SE_AES_BLOCK_SIZE, block, SE_AES_BLOCK_SIZE); int res = _se_execute_oneshot(op, block, SE_AES_BLOCK_SIZE, block, SE_AES_BLOCK_SIZE);
memcpy(dst, block, dst_size); memcpy(dst, block, dst_size);
free(block);
return res; 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]; u32 data[SE_AES_IV_SIZE / 4];
memcpy(data, ctr, SE_AES_IV_SIZE); memcpy(data, ctr, SE_AES_IV_SIZE);
@@ -226,7 +224,7 @@ u32 se_key_acc_ctrl_get(u32 ks)
return SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + 4 * 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]; u32 data[SE_AES_MAX_KEY_SIZE / 4];
memcpy(data, key, size); memcpy(data, key, size);
@@ -238,7 +236,7 @@ void se_aes_key_set(u32 ks, void *key, u32 size)
} }
} }
void se_aes_iv_set(u32 ks, void *iv) void se_aes_iv_set(u32 ks, const void *iv)
{ {
u32 data[SE_AES_IV_SIZE / 4]; u32 data[SE_AES_IV_SIZE / 4];
memcpy(data, iv, SE_AES_IV_SIZE); memcpy(data, iv, SE_AES_IV_SIZE);
@@ -281,6 +279,14 @@ void se_aes_iv_clear(u32 ks)
} }
} }
void se_aes_iv_updated_clear(u32 ks)
{
for (u32 i = 0; i < (SE_AES_IV_SIZE / 4); i++)
{
SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(UPDATED_IV) | SE_KEYTABLE_PKT(i);
SE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0;
}
}
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input) int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
{ {
@@ -292,6 +298,26 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
return _se_execute_oneshot(SE_OP_START, NULL, 0, input, SE_KEY_128_SIZE); return _se_execute_oneshot(SE_OP_START, NULL, 0, input, SE_KEY_128_SIZE);
} }
int se_aes_crypt_hash(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
{
if (enc)
{
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) |
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP) |
SE_CRYPTO_HASH(HASH_ENABLE);
}
else
{
SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) |
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM) |
SE_CRYPTO_HASH(HASH_ENABLE);
}
SE(SE_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1;
return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size);
}
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size) int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
{ {
if (enc) if (enc)
@@ -361,7 +387,8 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize) int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize)
{ {
int res = 0; int res = 0;
u8 *tweak = (u8 *)malloc(SE_AES_BLOCK_SIZE); u32 tmp[SE_AES_BLOCK_SIZE / sizeof(u32)];
u8 *tweak = (u8 *)tmp;
u8 *pdst = (u8 *)dst; u8 *pdst = (u8 *)dst;
u8 *psrc = (u8 *)src; u8 *psrc = (u8 *)src;
@@ -371,7 +398,7 @@ int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst
tweak[i] = sec & 0xFF; tweak[i] = sec & 0xFF;
sec >>= 8; sec >>= 8;
} }
if (!se_aes_crypt_block_ecb(tweak_ks, CORE_ENCRYPT, tweak, tweak)) if (!se_aes_crypt_block_ecb(tweak_ks, ENCRYPT, tweak, tweak))
goto out; goto out;
// We are assuming a 0x10-aligned sector size in this implementation. // We are assuming a 0x10-aligned sector size in this implementation.
@@ -390,8 +417,7 @@ int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst
res = 1; res = 1;
out:; out:
free(tweak);
return res; return res;
} }
@@ -408,7 +434,7 @@ int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, u8 *tw
tweak[i] = sec & 0xFF; tweak[i] = sec & 0xFF;
sec >>= 8; sec >>= 8;
} }
if (!se_aes_crypt_block_ecb(tweak_ks, CORE_ENCRYPT, tweak, tweak)) if (!se_aes_crypt_block_ecb(tweak_ks, ENCRYPT, tweak, tweak))
return 0; return 0;
} }
@@ -459,59 +485,21 @@ int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, vo
return 1; return 1;
} }
// se_aes_cmac() was derived from Atmosphère's se_compute_aes_cmac static void se_calc_sha256_get_hash(void *hash, u32 *msg_left)
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
{ {
int res = 0; u32 hash32[SE_SHA_256_SIZE / 4];
u8 *key = (u8 *)calloc(0x10, 1);
u8 *last_block = (u8 *)calloc(0x10, 1);
// generate derived key // Backup message left.
if (!se_aes_crypt_block_ecb(ks, 1, key, key)) if (msg_left)
goto out;
_gf256_mul_x(key);
if (src_size & 0xF)
_gf256_mul_x(key);
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_MEMORY) |
SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) |
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
se_aes_iv_clear(ks);
u32 num_blocks = (src_size + 0xf) >> 4;
if (num_blocks > 1)
{ {
SE(SE_CRYPTO_BLOCK_COUNT_REG) = num_blocks - 2; msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG);
if (!_se_execute_oneshot(SE_OP_START, NULL, 0, src, src_size)) msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG);
goto out;
SE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_IV_SEL(IV_UPDATED);
} }
if (src_size & 0xf) // Copy output hash.
{ for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++)
memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf); hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i * 4)));
last_block[src_size & 0xf] = 0x80; memcpy(hash, hash32, SE_SHA_256_SIZE);
}
else if (src_size >= 0x10)
{
memcpy(last_block, src + src_size - 0x10, 0x10);
}
for (u32 i = 0; i < 0x10; i++)
last_block[i] ^= key[i];
SE(SE_CRYPTO_BLOCK_COUNT_REG) = 0;
res = _se_execute_oneshot(SE_OP_START, NULL, 0, last_block, 0x10);
u32 *dst32 = (u32 *)dst;
for (u32 i = 0; i < (dst_size >> 2); i++)
dst32[i] = SE(SE_HASH_RESULT_REG + (i << 2));
out:;
free(key);
free(last_block);
return res;
} }
int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot) int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot)
@@ -523,6 +511,17 @@ int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64
if (src_size > 0xFFFFFF || !hash) // Max 16MB - 1 chunks and aligned x4 hash buffer. if (src_size > 0xFFFFFF || !hash) // Max 16MB - 1 chunks and aligned x4 hash buffer.
return 0; return 0;
// Src size of 0 is not supported, so return null string sha256.
if (!src_size)
{
const u8 null_hash[SE_SHA_256_SIZE] = {
0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55
};
memcpy(hash, null_hash, SE_SHA_256_SIZE);
return 1;
}
// Setup config for SHA256. // Setup config for SHA256.
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_SHA_CONFIG_REG) = sha_cfg; SE(SE_SHA_CONFIG_REG) = sha_cfg;
@@ -561,19 +560,7 @@ int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64
res = _se_execute(SE_OP_START, NULL, 0, src, src_size, is_oneshot); res = _se_execute(SE_OP_START, NULL, 0, src, src_size, is_oneshot);
if (is_oneshot) if (is_oneshot)
{ se_calc_sha256_get_hash(hash, msg_left);
// Backup message left.
if (msg_left)
{
msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG);
msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG);
}
// Copy output hash.
for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++)
hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i * 4)));
memcpy(hash, hash32, SE_SHA_256_SIZE);
}
return res; return res;
} }
@@ -585,65 +572,10 @@ int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size)
int se_calc_sha256_finalize(void *hash, u32 *msg_left) int se_calc_sha256_finalize(void *hash, u32 *msg_left)
{ {
u32 hash32[SE_SHA_256_SIZE / 4];
int res = _se_execute_finalize(); int res = _se_execute_finalize();
// Backup message left. se_calc_sha256_get_hash(hash, msg_left);
if (msg_left)
{
msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG);
msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG);
}
// Copy output hash.
for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++)
hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i * 4)));
memcpy(hash, hash32, SE_SHA_256_SIZE);
return res;
}
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size)
{
int res = 0;
u8 *secret = (u8 *)malloc(0x40);
u8 *ipad = (u8 *)malloc(0x40 + src_size);
u8 *opad = (u8 *)malloc(0x60);
if (key_size > 0x40)
{
if (!se_calc_sha256_oneshot(secret, key, key_size))
goto out;
memset(secret + 0x20, 0, 0x20);
}
else
{
memcpy(secret, key, key_size);
memset(secret + key_size, 0, 0x40 - key_size);
}
u32 *secret32 = (u32 *)secret;
u32 *ipad32 = (u32 *)ipad;
u32 *opad32 = (u32 *)opad;
for (u32 i = 0; i < 0x10; i++)
{
ipad32[i] = secret32[i] ^ 0x36363636;
opad32[i] = secret32[i] ^ 0x5C5C5C5C;
}
memcpy(ipad + 0x40, src, src_size);
if (!se_calc_sha256_oneshot(dst, ipad, 0x40 + src_size))
goto out;
memcpy(opad + 0x40, dst, 0x20);
if (!se_calc_sha256_oneshot(dst, opad, 0x60))
goto out;
res = 1;
out:;
free(secret);
free(ipad);
free(opad);
return res; return res;
} }
@@ -716,6 +648,66 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
// Decrypt context. // Decrypt context.
se_aes_key_clear(3); se_aes_key_clear(3);
se_aes_key_set(3, srk, SE_KEY_128_SIZE); se_aes_key_set(3, srk, SE_KEY_128_SIZE);
se_aes_crypt_cbc(3, CORE_DECRYPT, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize); se_aes_crypt_cbc(3, DECRYPT, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize);
se_aes_key_clear(3); se_aes_key_clear(3);
} }
int se_aes_cmac_128(u32 ks, void *dst, const void *src, u32 src_size)
{
int res = 0;
u32 tmp1[SE_KEY_128_SIZE / sizeof(u32)] = {0};
u32 tmp2[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};
u8 *key = (u8 *)tmp1;
u8 *last_block = (u8 *)tmp2;
se_aes_iv_clear(ks);
se_aes_iv_updated_clear(ks);
// Generate sub key
if (!se_aes_crypt_hash(ks, ENCRYPT, key, SE_KEY_128_SIZE, key, SE_KEY_128_SIZE))
goto out;
_gf256_mul_x(key);
if (src_size & 0xF)
_gf256_mul_x(key);
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_MEMORY) |
SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) |
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
se_aes_iv_clear(ks);
se_aes_iv_updated_clear(ks);
u32 num_blocks = (src_size + 0xf) >> 4;
if (num_blocks > 1)
{
SE(SE_CRYPTO_BLOCK_COUNT_REG) = num_blocks - 2;
if (!_se_execute_oneshot(SE_OP_START, NULL, 0, src, src_size))
goto out;
SE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_IV_SEL(IV_UPDATED);
}
if (src_size & 0xf)
{
memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf);
last_block[src_size & 0xf] = 0x80;
}
else if (src_size >= SE_AES_BLOCK_SIZE)
{
memcpy(last_block, src + src_size - SE_AES_BLOCK_SIZE, SE_AES_BLOCK_SIZE);
}
for (u32 i = 0; i < SE_KEY_128_SIZE; i++)
last_block[i] ^= key[i];
SE(SE_CRYPTO_BLOCK_COUNT_REG) = 0;
res = _se_execute_oneshot(SE_OP_START, NULL, 0, last_block, SE_AES_BLOCK_SIZE);
u32 *dst32 = (u32 *)dst;
for (u32 i = 0; i < (SE_KEY_128_SIZE / 4); i++)
dst32[i] = SE(SE_HASH_RESULT_REG + (i * 4));
out:
return res;
}

View File

@@ -25,12 +25,14 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags);
void se_key_acc_ctrl(u32 ks, u32 flags); void se_key_acc_ctrl(u32 ks, u32 flags);
u32 se_key_acc_ctrl_get(u32 ks); u32 se_key_acc_ctrl_get(u32 ks);
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize); 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_key_set(u32 ks, const void *key, u32 size);
void se_aes_iv_set(u32 ks, void *iv); void se_aes_iv_set(u32 ks, const void *iv);
void se_aes_key_get(u32 ks, void *key, u32 size); void se_aes_key_get(u32 ks, void *key, u32 size);
void se_aes_key_clear(u32 ks); void se_aes_key_clear(u32 ks);
void se_aes_iv_clear(u32 ks); void se_aes_iv_clear(u32 ks);
void se_aes_iv_updated_clear(u32 ks);
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
int se_aes_crypt_hash(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
@@ -38,11 +40,10 @@ int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *ds
int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size); int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size);
int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs); int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs);
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot); int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot);
int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size); int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size);
int se_calc_sha256_finalize(void *hash, u32 *msg_left); int se_calc_sha256_finalize(void *hash, u32 *msg_left);
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size);
int se_gen_prng128(void *dst); int se_gen_prng128(void *dst);
int se_aes_cmac_128(u32 ks, void *dst, const void *src, u32 src_size);
#endif #endif

View File

@@ -50,6 +50,9 @@
#define SE_RSA1536_DIGEST_SIZE 192 #define SE_RSA1536_DIGEST_SIZE 192
#define SE_RSA2048_DIGEST_SIZE 256 #define SE_RSA2048_DIGEST_SIZE 256
#define DECRYPT 0
#define ENCRYPT 1
/* SE register definitions */ /* SE register definitions */
#define SE_SE_SECURITY_REG 0x000 #define SE_SE_SECURITY_REG 0x000
#define SE_HARD_SETTING BIT(0) #define SE_HARD_SETTING BIT(0)

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2021 CTCaer * Copyright (c) 2018-2024 CTCaer
* Copyright (c) 2018 balika011 * Copyright (c) 2018 balika011
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -70,11 +70,12 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
int res = 0; int res = 0;
u8 *fwbuf = NULL; u8 *fwbuf = NULL;
u32 type = tsec_ctxt->type; u32 type = tsec_ctxt->type;
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; u32 *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
u32 *pkg11_magic_off; u32 *pkg11_magic_off;
void *ptb;
bpmp_mmu_disable(); bpmp_mmu_disable();
bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL); bpmp_clk_rate_relaxed(true);
// Enable clocks. // Enable clocks.
clock_enable_tsec(); clock_enable_tsec();
@@ -90,10 +91,10 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
if (type == TSEC_FW_TYPE_NEW) if (type == TSEC_FW_TYPE_NEW)
{ {
// Disable all CCPLEX core rails. // Disable all CCPLEX core rails.
pmc_enable_partition(POWER_RAIL_CE0, DISABLE); pmc_domain_pwrgate_set(POWER_RAIL_CE0, DISABLE);
pmc_enable_partition(POWER_RAIL_CE1, DISABLE); pmc_domain_pwrgate_set(POWER_RAIL_CE1, DISABLE);
pmc_enable_partition(POWER_RAIL_CE2, DISABLE); pmc_domain_pwrgate_set(POWER_RAIL_CE2, DISABLE);
pmc_enable_partition(POWER_RAIL_CE3, DISABLE); pmc_domain_pwrgate_set(POWER_RAIL_CE3, DISABLE);
// Enable AHB aperture and set it to full mmio. // Enable AHB aperture and set it to full mmio.
mc_enable_ahb_redirect(); mc_enable_ahb_redirect();
@@ -145,64 +146,64 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
if (type == TSEC_FW_TYPE_EMU) if (type == TSEC_FW_TYPE_EMU)
{ {
// Init SMMU translation for TSEC. // Init SMMU translation for TSEC.
pdir = smmu_init_for_tsec(); ptb = smmu_init_domain(MC_SMMU_TSEC_ASID, 1);
smmu_init(tsec_ctxt->secmon_base); smmu_init();
// Enable SMMU
if (!smmu_is_used()) // Enable SMMU.
smmu_enable(); smmu_enable();
// Clock reset controller. // Clock reset controller.
car = page_alloc(1); car = smmu_page_zalloc(1);
memcpy(car, (void *)CLOCK_BASE, SZ_PAGE); memcpy(car, (void *)CLOCK_BASE, SZ_PAGE);
car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2; car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = CLK_SRC_DIV(2);
smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE); smmu_map(ptb, CLOCK_BASE, (u32)car, 1, SMMU_WRITE | SMMU_READ | SMMU_NS);
// Fuse driver. // Fuse driver.
fuse = page_alloc(1); fuse = smmu_page_zalloc(1);
memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, SZ_1K); memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, SZ_1K);
fuse[0x82C / 4] = 0; fuse[0x82C / 4] = 0;
fuse[0x9E0 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1; fuse[0x9E0 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1;
fuse[0x9E4 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1; fuse[0x9E4 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1;
smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE); smmu_map(ptb, (FUSE_BASE - 0x800), (u32)fuse, 1, SMMU_READ | SMMU_NS);
// Power management controller. // Power management controller.
pmc = page_alloc(1); pmc = smmu_page_zalloc(1);
smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE); smmu_map(ptb, RTC_BASE, (u32)pmc, 1, SMMU_READ | SMMU_NS);
// Flow control. // Flow control.
flowctrl = page_alloc(1); flowctrl = smmu_page_zalloc(1);
smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE); smmu_map(ptb, FLOW_CTLR_BASE, (u32)flowctrl, 1, SMMU_WRITE | SMMU_NS);
// Security engine. // Security engine.
se = page_alloc(1); se = smmu_page_zalloc(1);
memcpy(se, (void *)SE_BASE, SZ_PAGE); memcpy(se, (void *)SE_BASE, SZ_PAGE);
smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); smmu_map(ptb, SE_BASE, (u32)se, 1, SMMU_READ | SMMU_WRITE | SMMU_NS);
// Memory controller. // Memory controller.
mc = page_alloc(1); mc = smmu_page_zalloc(1);
memcpy(mc, (void *)MC_BASE, SZ_PAGE); memcpy(mc, (void *)MC_BASE, SZ_PAGE);
mc[MC_IRAM_BOM / 4] = 0; mc[MC_IRAM_BOM / 4] = 0;
mc[MC_IRAM_TOM / 4] = DRAM_START; mc[MC_IRAM_TOM / 4] = DRAM_START;
smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE); smmu_map(ptb, MC_BASE, (u32)mc, 1, SMMU_READ | SMMU_NS);
// IRAM // IRAM
iram = page_alloc(0x30); iram = smmu_page_zalloc(0x30);
memcpy(iram, tsec_ctxt->pkg1, 0x30000); memcpy(iram, tsec_ctxt->pkg1, 0x30000);
// PKG1.1 magic offset. // PKG1.1 magic offset.
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4)); pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / sizeof(u32)));
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); smmu_map(ptb, 0x40010000, (u32)iram, 0x30, SMMU_READ | SMMU_WRITE | SMMU_NS);
// Exception vectors // Exception vectors
evec = page_alloc(1); evec = smmu_page_zalloc(1);
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); smmu_map(ptb, EXCP_VEC_BASE, (u32)evec, 1, SMMU_READ | SMMU_WRITE | SMMU_NS);
} }
// Execute firmware. // Execute firmware.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
TSEC(TSEC_STATUS) = 0; TSEC(TSEC_MAILBOX1) = 0;
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. TSEC(TSEC_MAILBOX0) = 1; // Set HOS key version.
TSEC(TSEC_BOOTVEC) = 0; TSEC(TSEC_BOOTVEC) = 0;
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
if (type == TSEC_FW_TYPE_EMU) if (type == TSEC_FW_TYPE_EMU)
{ {
@@ -229,7 +230,7 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
if (kidx != 8) if (kidx != 8)
{ {
res = -6; res = -6;
smmu_deinit_for_tsec(); smmu_deinit_domain(MC_SMMU_TSEC_ASID, 1);
goto out_free; goto out_free;
} }
@@ -240,12 +241,12 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
memcpy(tsec_keys, &key, 0x20); memcpy(tsec_keys, &key, 0x20);
memcpy(tsec_ctxt->pkg1, iram, 0x30000); memcpy(tsec_ctxt->pkg1, iram, 0x30000);
smmu_deinit_for_tsec(); smmu_deinit_domain(MC_SMMU_TSEC_ASID, 1);
// for (int i = 0; i < kidx; i++) // for (int i = 0; i < kidx; i++)
// gfx_printf("key %08X\n", key[i]); // gfx_printf("key %08X\n", key[i]);
// gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS)); // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_MAILBOX1));
// u32 errst = MC(MC_ERR_STATUS); // u32 errst = MC(MC_ERR_STATUS);
// gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR)); // gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
@@ -261,14 +262,18 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
res = -3; res = -3;
goto out_free; goto out_free;
} }
u32 timeout = get_tmr_ms() + 2000; u32 timeout = get_tmr_ms() + 2000;
while (!TSEC(TSEC_STATUS)) while (!TSEC(TSEC_MAILBOX1))
{
if (get_tmr_ms() > timeout) if (get_tmr_ms() > timeout)
{ {
res = -4; res = -4;
goto out_free; goto out_free;
} }
if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) }
if (TSEC(TSEC_MAILBOX1) != 0xB0B0B0B0)
{ {
res = -5; res = -5;
goto out_free; goto out_free;
@@ -277,14 +282,14 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
// Fetch result. // Fetch result.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
u32 buf[4]; u32 buf[4];
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); buf[0] = SOR1(SOR_DP_HDCP_BKSV_LSB);
buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); buf[1] = SOR1(SOR_TMDS_HDCP_BKSV_LSB);
buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB); buf[2] = SOR1(SOR_TMDS_HDCP_CN_MSB);
buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB); buf[3] = SOR1(SOR_TMDS_HDCP_CN_LSB);
SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0; SOR1(SOR_DP_HDCP_BKSV_LSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0; SOR1(SOR_TMDS_HDCP_BKSV_LSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0; SOR1(SOR_TMDS_HDCP_CN_MSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0; SOR1(SOR_TMDS_HDCP_CN_LSB) = 0;
memcpy(tsec_keys, &buf, SE_KEY_128_SIZE); memcpy(tsec_keys, &buf, SE_KEY_128_SIZE);
} }
@@ -300,7 +305,7 @@ out:
clock_disable_sor_safe(); clock_disable_sor_safe();
clock_disable_tsec(); clock_disable_tsec();
bpmp_mmu_enable(); bpmp_mmu_enable();
bpmp_clk_rate_set(prev_fid); bpmp_clk_rate_relaxed(false);
#ifdef BDK_MC_ENABLE_AHB_REDIRECT #ifdef BDK_MC_ENABLE_AHB_REDIRECT
// Re-enable AHB aperture. // Re-enable AHB aperture.

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -20,13 +20,11 @@
#include <utils/types.h> #include <utils/types.h>
#define TSEC_KEY_DATA_OFFSET 0x300
enum tsec_fw_type enum tsec_fw_type
{ {
// Retail Hovi Keygen. // Retail Hovi Keygen.
TSEC_FW_TYPE_OLD = 0, // 1.0.0 - 6.1.0. TSEC_FW_TYPE_OLD = 0, // 1.0.0 - 6.1.0.
TSEC_FW_TYPE_EMU = 1, // 6.2.0 emulated enviroment. TSEC_FW_TYPE_EMU = 1, // 6.2.0 emulated environment.
TSEC_FW_TYPE_NEW = 2, // 7.0.0+. TSEC_FW_TYPE_NEW = 2, // 7.0.0+.
}; };
@@ -37,26 +35,8 @@ typedef struct _tsec_ctxt_t
u32 type; u32 type;
void *pkg1; void *pkg1;
u32 pkg11_off; u32 pkg11_off;
u32 secmon_base;
} tsec_ctxt_t; } tsec_ctxt_t;
typedef struct _tsec_key_data_t
{
u8 debug_key[0x10];
u8 blob0_auth_hash[0x10];
u8 blob1_auth_hash[0x10];
u8 blob2_auth_hash[0x10];
u8 blob2_aes_iv[0x10];
u8 hovi_eks_seed[0x10];
u8 hovi_common_seed[0x10];
u32 blob0_size;
u32 blob1_size;
u32 blob2_size;
u32 blob3_size;
u32 blob4_size;
u8 reserved[0x7C];
} tsec_key_data_t;
int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt); int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt);
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018 CTCaer * Copyright (c) 2018-2023 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -17,8 +17,8 @@
#ifndef _TSEC_T210_H_ #ifndef _TSEC_T210_H_
#define _TSEC_T210_H_ #define _TSEC_T210_H_
#define TSEC_BOOTKEYVER 0x1040 #define TSEC_MAILBOX0 0x1040
#define TSEC_STATUS 0x1044 #define TSEC_MAILBOX1 0x1044
#define TSEC_ITFEN 0x1048 #define TSEC_ITFEN 0x1048
#define TSEC_ITFEN_CTXEN BIT(0) #define TSEC_ITFEN_CTXEN BIT(0)
#define TSEC_ITFEN_MTHDEN BIT(1) #define TSEC_ITFEN_MTHDEN BIT(1)

View File

@@ -76,7 +76,9 @@
#define ACTMON_HISTOGRAM_DATA_BASE 0x380 #define ACTMON_HISTOGRAM_DATA_BASE 0x380
#define ACTMON_HISTOGRAM_DATA_NUM 32 #define ACTMON_HISTOGRAM_DATA_NUM 32
#define ACTMON_FREQ 19200000 #define ACTMON_FREQ 19200000
#define ACTMON_PERIOD_MS 20
#define DEV_COUNT_WEIGHT 5
typedef struct _actmon_dev_reg_t typedef struct _actmon_dev_reg_t
{ {
@@ -91,11 +93,9 @@ typedef struct _actmon_dev_reg_t
vu32 avg_count; vu32 avg_count;
vu32 intr_status; vu32 intr_status;
vu32 ctrl2; vu32 ctrl2;
vu32 unk[5]; vu32 rsvd[5];
} actmon_dev_reg_t; } actmon_dev_reg_t;
u32 sample_period = 0;
void actmon_hist_enable(actmon_hist_src_t src) void actmon_hist_enable(actmon_hist_src_t src)
{ {
ACTMON(ACTMON_HISTOGRAM_CONFIG) = ACTMON_HIST_CFG_SOURCE(src) | ACTMON_HIST_CFG_ACTIVE; ACTMON(ACTMON_HISTOGRAM_CONFIG) = ACTMON_HIST_CFG_SOURCE(src) | ACTMON_HIST_CFG_ACTIVE;
@@ -120,10 +120,10 @@ void actmon_dev_enable(actmon_dev_t dev)
{ {
actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));
regs->init_avg = 0; regs->init_avg = ACTMON_FREQ * ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT / 100;
regs->count_weight = 5; regs->count_weight = DEV_COUNT_WEIGHT;
regs->ctrl = ACTMON_DEV_CTRL_ENB | ACTMON_DEV_CTRL_ENB_PERIODIC; regs->ctrl = ACTMON_DEV_CTRL_ENB | ACTMON_DEV_CTRL_ENB_PERIODIC | ACTMON_DEV_CTRL_K_VAL(7); // 128 samples average.
} }
void actmon_dev_disable(actmon_dev_t dev) void actmon_dev_disable(actmon_dev_t dev)
@@ -138,7 +138,7 @@ u32 actmon_dev_get_load(actmon_dev_t dev)
actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));
// Get load-based sampling. 1 decimal point precision. // Get load-based sampling. 1 decimal point precision.
u32 load = regs->count / (ACTMON_FREQ / 1000); u32 load = regs->count * 100 / (ACTMON_FREQ / (ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT));
return load; return load;
} }
@@ -148,7 +148,7 @@ u32 actmon_dev_get_load_avg(actmon_dev_t dev)
actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));
// Get load-based sampling. 1 decimal point precision. // Get load-based sampling. 1 decimal point precision.
u32 avg_load = regs->avg_count / (ACTMON_FREQ / 1000); u32 avg_load = regs->avg_count * 100 / (ACTMON_FREQ / (ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT));
return avg_load; return avg_load;
} }
@@ -162,9 +162,8 @@ void actmon_init()
{ {
clock_enable_actmon(); clock_enable_actmon();
// Set period to 200ms. // Set period.
ACTMON(ACTMON_GLB_PERIOD_CTRL) &= ~ACTMON_GLB_PERIOD_USEC; ACTMON(ACTMON_GLB_PERIOD_CTRL) = ACTMON_GLB_PERIOD_SAMPLE(ACTMON_PERIOD_MS);
ACTMON(ACTMON_GLB_PERIOD_CTRL) |= ACTMON_GLB_PERIOD_SAMPLE(200);
} }
void actmon_end() void actmon_end()

View File

@@ -1,7 +1,7 @@
/* /*
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -118,7 +118,7 @@
#define MMU_EN_READ BIT(2) #define MMU_EN_READ BIT(2)
#define MMU_EN_WRITE BIT(3) #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 }, { 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 } { 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); 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) if (idx > 31)
return; return;
@@ -200,10 +200,45 @@ void bpmp_mmu_disable()
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0; 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, // APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
// I2C host, DC/DSI/DISP. UART gives extra stress. // I2C host, DC/DSI/DISP. UART gives extra stress.
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less. // 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. 0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB. 85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
88, // BPMP_CLK_HIGH2_BOOST: 563MHz 38% - 141MHz 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. //95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB.
}; };
bpmp_freq_t bpmp_fid_current = BPMP_CLK_NORMAL;
void bpmp_clk_rate_get() void bpmp_clk_rate_get()
{ {
bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3; 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)) if (fid > (BPMP_CLK_MAX - 1))
fid = BPMP_CLK_MAX - 1; fid = BPMP_CLK_MAX - 1;
if (prev_fid == fid) if (bpmp_fid_current == fid)
return prev_fid; return;
bpmp_fid_current = fid;
if (fid) if (fid)
{ {
if (prev_fid) // Use default SCLK / HCLK / PCLK clocks.
{ bpmp_clk_rate_relaxed(true);
// 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.
}
// Configure and enable PLLC. // Configure and enable PLLC.
clock_enable_pllc(pll_divn[fid]); clock_enable_pllc(pll_divn[fid]);
// Set SCLK / HCLK / PCLK. // Set new source and SCLK / HCLK / PCLK dividers.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK. bpmp_clk_rate_relaxed(false);
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle.
} }
else else
{ {
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle. // Use default SCLK / HCLK / PCLK clocks.
msleep(1); // Wait a bit for clock source change. bpmp_clk_rate_relaxed(true);
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
// Disable PLLC to save power. // Disable PLLC to save power.
clock_disable_pllc(); clock_disable_pllc();
} }
bpmp_fid_current = fid; }
// Return old fid in case of temporary swap. // State is reset to RUN on any clock or source set via SW.
return prev_fid; 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. // The following functions halt BPMP to reduce power while sleeping.
@@ -287,10 +317,10 @@ void bpmp_usleep(u32 us)
// Each iteration takes 1us. // Each iteration takes 1us.
while (us) while (us)
{ {
delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us; delay = (us > HALT_MAX_CNT) ? HALT_MAX_CNT : us;
us -= delay; us -= delay;
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay; FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_USEC | delay;
} }
} }
@@ -301,14 +331,14 @@ void bpmp_msleep(u32 ms)
// Iteration time is variable. ~200 - 1000us. // Iteration time is variable. ~200 - 1000us.
while (ms) while (ms)
{ {
delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms; delay = (ms > HALT_MAX_CNT) ? HALT_MAX_CNT : ms;
ms -= delay; ms -= delay;
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay; FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_MSEC | delay;
} }
} }
void bpmp_halt() void bpmp_halt()
{ {
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG; FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_JTAG;
} }

View File

@@ -1,7 +1,7 @@
/* /*
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
* *
* Copyright (c) 2019-2023 CTCaer * Copyright (c) 2019-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -54,16 +54,32 @@ typedef enum
BPMP_CLK_MAX BPMP_CLK_MAX
} bpmp_freq_t; } bpmp_freq_t;
#define BPMP_CLK_LOWEST_BOOST BPMP_CLK_HIGH2_BOOST typedef enum
#define BPMP_CLK_LOWER_BOOST BPMP_CLK_SUPER_BOOST {
#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST 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_BIN0_BOOST BPMP_CLK_HYPER_BOOST
#define BPMP_CLK_BIN1_BOOST BPMP_CLK_SUPER_BOOST
#define BPMP_CLK_BIN2_BOOST BPMP_CLK_HIGH2_BOOST
#define BPMP_CLK_BIN3_BOOST BPMP_CLK_HIGH_BOOST
#define BPMP_CLK_LOWER_BOOST BPMP_CLK_BIN1_BOOST
#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_BIN0_BOOST
void bpmp_mmu_maintenance(u32 op, bool force); 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_enable();
void bpmp_mmu_disable(); void bpmp_mmu_disable();
void bpmp_clk_rate_relaxed(bool enable);
void bpmp_clk_rate_get(); 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_usleep(u32 us);
void bpmp_msleep(u32 ms); void bpmp_msleep(u32 ms);
void bpmp_halt(); void bpmp_halt();

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -27,7 +27,9 @@
#include <power/max77812.h> #include <power/max77812.h>
#include <utils/util.h> #include <utils/util.h>
void _ccplex_enable_power_t210() #define CCPLEX_FLOWCTRL_POWERGATING 0
static void _ccplex_enable_power_t210()
{ {
// Configure GPIO5 and enable output in order to power CPU pmic. // Configure GPIO5 and enable output in order to power CPU pmic.
max77620_config_gpio(5, MAX77620_GPIO_OUTPUT_ENABLE); max77620_config_gpio(5, MAX77620_GPIO_OUTPUT_ENABLE);
@@ -37,19 +39,31 @@ void _ccplex_enable_power_t210()
// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL. // 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.
max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_HOS_CFG); max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_HOS_CFG);
// Set voltage and enable cores power. // Set voltage and enable cluster power.
max7762x_regulator_set_voltage(REGULATOR_CPU0, 950000); max7762x_regulator_set_voltage(REGULATOR_CPU0, 950000);
max7762x_regulator_enable(REGULATOR_CPU0, true); max7762x_regulator_enable(REGULATOR_CPU0, true);
} }
void _ccplex_enable_power_t210b01() static void _ccplex_enable_power_t210b01()
{ {
// Set voltage and enable cores power. // Set voltage and enable cluster power.
max7762x_regulator_set_voltage(REGULATOR_CPU1, 800000); max7762x_regulator_set_voltage(REGULATOR_CPU1, 800000);
max7762x_regulator_enable(REGULATOR_CPU1, true); max7762x_regulator_enable(REGULATOR_CPU1, true);
} }
void ccplex_boot_cpu0(u32 entry) static void _ccplex_disable_power()
{
// Disable cluster power.
if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)
{
max7762x_regulator_enable(REGULATOR_CPU0, false);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 0);
}
else
max7762x_regulator_enable(REGULATOR_CPU1, false);
}
void ccplex_boot_cpu0(u32 entry, bool lock)
{ {
// Set ACTIVE_CLUSER to FAST. // Set ACTIVE_CLUSER to FAST.
FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= ~CLUSTER_CTRL_ACTIVE_SLOW; FLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= ~CLUSTER_CTRL_ACTIVE_SLOW;
@@ -62,12 +76,12 @@ void ccplex_boot_cpu0(u32 entry)
clock_enable_pllx(); clock_enable_pllx();
// Configure MSELECT source and enable clock to 102MHz. // Configure MSELECT source and enable clock to 102MHz.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) & 0x1FFFFF00) | 6; CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (0 << 29) | CLK_SRC_DIV(4);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_MSELECT); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_MSELECT);
// Configure initial CPU clock frequency and enable clock. // Configure initial CPU clock frequency and enable clock.
CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; // PLLX_OUT0_LJ. CLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY) = 0x20008888; // PLLX_OUT0_LJ.
CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = 0x80000000; CLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = BIT(31); // SUPER_CDIV_ENB.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_CPUG); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_CPUG);
clock_enable_coresight(); clock_enable_coresight();
@@ -76,11 +90,11 @@ void ccplex_boot_cpu0(u32 entry)
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
// Enable CPU main rail. // Enable CPU main rail.
pmc_enable_partition(POWER_RAIL_CRAIL, ENABLE); pmc_domain_pwrgate_set(POWER_RAIL_CRAIL, ENABLE);
// Enable cluster 0 non-CPU rail. // Enable cluster 0 non-CPU rail.
pmc_enable_partition(POWER_RAIL_C0NC, ENABLE); pmc_domain_pwrgate_set(POWER_RAIL_C0NC, ENABLE);
// Enable CPU0 rail. // Enable CPU0 rail.
pmc_enable_partition(POWER_RAIL_CE0, ENABLE); pmc_domain_pwrgate_set(POWER_RAIL_CE0, ENABLE);
// Request and wait for RAM repair. Needed for the Fast cluster. // Request and wait for RAM repair. Needed for the Fast cluster.
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = RAM_REPAIR_REQ; FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = RAM_REPAIR_REQ;
@@ -90,21 +104,62 @@ void ccplex_boot_cpu0(u32 entry)
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0; EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
// Set reset vector. // Set reset vector.
SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN; SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN;
SB(SB_AA64_RESET_HIGH) = 0; SB(SB_AA64_RESET_HIGH) = 0;
// Non-secure reset vector write disable. // Non-secure reset vector write disable.
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS; if (lock)
(void)SB(SB_CSR); {
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;
(void)SB(SB_CSR);
}
// Tighten up the security aperture. // Tighten up the security aperture.
// MC(MC_TZ_SECURITY_CTRL) = 1; // MC(MC_TZ_SECURITY_CTRL) = TZ_SEC_CTRL_CPU_STRICT_TZ_APERTURE_CHECK;
// Clear MSELECT reset. // Clear MSELECT reset.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_V_CLR) = BIT(CLK_V_MSELECT); CLOCK(CLK_RST_CONTROLLER_RST_DEV_V_CLR) = BIT(CLK_V_MSELECT);
// Clear NONCPU reset. // Clear NONCPU reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000; CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = BIT(29); // CLR_NONCPURESET.
// Clear CPU0 reset. // Clear CPU0 reset.
// < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset. // < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x41010001; CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = BIT(30) | BIT(24) | BIT(16) | BIT(0);
}
void ccplex_powergate_cpu0()
{
#if CCPLEX_FLOWCTRL_POWERGATING
// Halt CPU0.
FLOW_CTLR(FLOW_CTLR_HALT_CPU0_EVENTS) = HALT_MODE_STOP_UNTIL_IRQ;
// Powergate cluster via flow control without waiting for WFI.
FLOW_CTLR(FLOW_CTLR_CPU0_CSR) = CSR_INTR_FLAG | CSR_EVENT_FLAG | CSR_ENABLE_EXT_CPU_RAIL | CSR_WAIT_WFI_NONE | CSR_ENABLE;
// Wait for the rail power off to finish.
while((FLOW_CTLR(FLOW_CTLR_CPU_PWR_CSR) & CPU_PWR_RAIL_STS_MASK) != CPU_PWR_RAIL_OFF);
// Set CPU0 to waitevent.
FLOW_CTLR(FLOW_CTLR_HALT_CPU0_EVENTS) = HALT_MODE_WAITEVENT;
#endif
// Set CPU0 POR and CORE, CX0, L2, and DBG reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET) = BIT(30) | BIT(24) | BIT(16) | BIT(0);
// Set NONCPU reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET) = BIT(29);
// Set MSELECT reset.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_V_SET) = BIT(CLK_V_MSELECT);
// Disable CE0.
pmc_domain_pwrgate_set(POWER_RAIL_CE0, DISABLE);
// Disable cluster 0 non-CPU.
pmc_domain_pwrgate_set(POWER_RAIL_C0NC, DISABLE);
// Disable CPU rail.
pmc_domain_pwrgate_set(POWER_RAIL_CRAIL, DISABLE);
clock_disable_coresight();
// Clear out MSELECT and CPU clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_CLR) = BIT(CLK_V_MSELECT) | BIT(CLK_V_CPUG);
_ccplex_disable_power();
} }

View File

@@ -19,6 +19,7 @@
#include <utils/types.h> #include <utils/types.h>
void ccplex_boot_cpu0(u32 entry); void ccplex_boot_cpu0(u32 entry, bool lock);
void ccplex_powergate_cpu0();
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2023 CTCaer * Copyright (c) 2018-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <soc/bpmp.h>
#include <soc/clock.h> #include <soc/clock.h>
#include <soc/hw_init.h> #include <soc/hw_init.h>
#include <soc/pmc.h> #include <soc/pmc.h>
@@ -22,6 +23,14 @@
#include <soc/t210.h> #include <soc/t210.h>
#include <storage/sdmmc.h> #include <storage/sdmmc.h>
typedef struct _clk_rst_mgd_t
{
u16 reset;
u16 enable;
u16 source;
u8 index;
} clk_rst_mgd_t;
typedef struct _clock_osc_t typedef struct _clock_osc_t
{ {
u32 freq; u32 freq;
@@ -39,108 +48,117 @@ static const clock_osc_t _clock_osc_cnt[] = {
{ 48000, 2836, 3023 } { 48000, 2836, 3023 }
}; };
/* clock_t: reset, enable, source, index, clk_src, clk_div */ /* clk_rst_mgd_t: reset, enable, source, index */
static const clock_t _clock_uart[] = { static const clk_rst_mgd_t _clock_sdmmc[] = {
{ CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, CLK_L_UARTA, 0, 2 }, { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1, CLK_L_SDMMC1 },
{ CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, CLK_L_UARTB, 0, 2 }, { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2, CLK_L_SDMMC2 },
{ CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, CLK_H_UARTC, 0, 2 }, { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3, CLK_U_SDMMC3 },
{ CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, CLK_U_UARTD, 0, 2 }, { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4, CLK_L_SDMMC4 },
{ CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, CLK_Y_UARTAPE, 0, 2 } };
/* clk_rst_t: reset, enable, source, index, clk_src, clk_div */
static const clk_rst_t _clock_uart[] = {
{ CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, CLK_L_UARTA, 0, CLK_SRC_DIV(2) },
{ CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, CLK_L_UARTB, 0, CLK_SRC_DIV(2) },
{ CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, CLK_H_UARTC, 0, CLK_SRC_DIV(2) },
{ CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, CLK_U_UARTD, 0, CLK_SRC_DIV(2) },
{ CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, CLK_Y_UARTAPE, 0, CLK_SRC_DIV(2) }
}; };
//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26. //I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26.
static const clock_t _clock_i2c[] = { static const clk_rst_t _clock_i2c[] = {
{ CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, CLK_L_I2C1, 0, 19 }, //20.4MHz -> 100KHz { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, CLK_L_I2C1, 0, CLK_SRC_DIV(10.5) }, // 20.4 MHz -> 100 KHz
{ CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, CLK_H_I2C2, 0, 4 }, //81.6MHz -> 400KHz { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, CLK_H_I2C2, 0, CLK_SRC_DIV(3) }, // 81.6 MHz -> 400 KHz
{ CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, CLK_U_I2C3, 0, 4 }, //81.6MHz -> 400KHz { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, CLK_U_I2C3, 0, CLK_SRC_DIV(3) }, // 81.6 MHz -> 400 KHz
{ CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, CLK_V_I2C4, 0, 19 }, //20.4MHz -> 100KHz { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, CLK_V_I2C4, 0, CLK_SRC_DIV(10.5) }, // 20.4 MHz -> 100 KHz
{ CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_H_I2C5, 0, 4 }, //81.6MHz -> 400KHz { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_H_I2C5, 0, CLK_SRC_DIV(3) }, // 81.6 MHz -> 400 KHz
{ CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, CLK_X_I2C6, 0, 19 } //20.4MHz -> 100KHz { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, CLK_X_I2C6, 0, CLK_SRC_DIV(10.5) } // 20.4 MHz -> 100 KHz
}; };
static clock_t _clock_se = { static clk_rst_t _clock_se = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, CLK_V_SE, 0, 0 // 408MHz. Default: 408MHz. Max: 627.2 MHz. CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, CLK_V_SE, 0, CLK_SRC_DIV(1) // 408 MHz. Max: 627.2 MHz.
}; };
static clock_t _clock_tzram = { static clk_rst_t _clock_tzram = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, CLK_V_TZRAM, 0, 0 CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, CLK_V_TZRAM, 0, CLK_SRC_DIV(1)
}; };
static clock_t _clock_host1x = { static clk_rst_t _clock_host1x = { // Has idle divisor.
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, CLK_L_HOST1X, 4, 3 // 163.2MHz. Max: 408MHz. CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, CLK_L_HOST1X, 4, CLK_SRC_DIV(2.5) // 163.2MHz. Max: 408 MHz.
}; };
static clock_t _clock_tsec = { static clk_rst_t _clock_tsec = {
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, CLK_U_TSEC, 0, 2 // 204MHz. Max: 408MHz. CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, CLK_U_TSEC, 0, CLK_SRC_DIV(2) // 204 MHz. Max: 408 MHz.
}; };
static clock_t _clock_nvdec = { static clk_rst_t _clock_nvdec = {
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC, CLK_Y_NVDEC, 4, 0 // 408 MHz. Max: 716.8/979.2MHz. CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC, CLK_Y_NVDEC, 4, CLK_SRC_DIV(1) // 408 MHz. Max: 716.8/979.2 MHz.
}; };
static clock_t _clock_nvjpg = { static clk_rst_t _clock_nvjpg = {
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG, CLK_Y_NVJPG, 4, 0 // 408 MHz. Max: 627.2/652.8MHz. CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG, CLK_Y_NVJPG, 4, CLK_SRC_DIV(1) // 408 MHz. Max: 627.2/652.8 MHz.
}; };
static clock_t _clock_vic = { static clk_rst_t _clock_vic = { // Has idle divisor.
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_VIC, CLK_X_VIC, 2, 0 // 408 MHz. Max: 627.2/652.8MHz. CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_VIC, CLK_X_VIC, 2, CLK_SRC_DIV(1) // 408 MHz. Max: 627.2/652.8 MHz.
}; };
static clock_t _clock_sor_safe = { static clk_rst_t _clock_sor_safe = {
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, CLK_Y_SOR_SAFE, 0, 0 CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, CLK_Y_SOR_SAFE, 0, CLK_SRC_DIV(1) // 24 MHz.
}; };
static clock_t _clock_sor0 = { static clk_rst_t _clock_sor0 = {
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NOT_USED, CLK_X_SOR0, 0, 0 CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NOT_USED, CLK_X_SOR0, 0, CLK_SRC_DIV(1)
}; };
static clock_t _clock_sor1 = { static clk_rst_t _clock_sor1 = {
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, CLK_X_SOR1, 0, 2 // 204MHz. CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, CLK_X_SOR1, 0, CLK_SRC_DIV(2) // 204 MHz.
}; };
static clock_t _clock_kfuse = { static clk_rst_t _clock_kfuse = {
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_KFUSE, 0, 0 CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_KFUSE, 0, CLK_SRC_DIV(1)
}; };
static clock_t _clock_cl_dvfs = { static clk_rst_t _clock_cl_dvfs = {
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, CLK_W_DVFS, 0, 0 CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, CLK_W_DVFS, 0, CLK_SRC_DIV(1)
}; };
static clock_t _clock_coresight = { static clk_rst_t _clock_coresight = {
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, CLK_U_CSITE, 0, 4 // 136MHz. CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, CLK_U_CSITE, 0, CLK_SRC_DIV(3) // 136 MHz.
}; };
static clock_t _clock_pwm = { static clk_rst_t _clock_pwm = {
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, CLK_L_PWM, 6, 4 // Fref: 6.4MHz. HOS: PLLP / 54 = 7.55MHz. CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, CLK_L_PWM, 6, CLK_SRC_DIV(3) // Fref: 6.4MHz. HOS: PLLP / 54 = 7.55MHz.
}; };
static clock_t _clock_sdmmc_legacy_tm = { static clk_rst_t _clock_sdmmc_legacy_tm = {
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, CLK_Y_SDMMC_LEGACY_TM, 4, 66 CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, CLK_Y_SDMMC_LEGACY_TM, 4, CLK_SRC_DIV(34) // 12MHz.
}; };
static clock_t _clock_apbdma = { static clk_rst_t _clock_apbdma = {
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_APBDMA, 0, 0 // Max: 204MHz. CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_APBDMA, 0, CLK_SRC_DIV(1) // Max: 204 MHz.
}; };
static clock_t _clock_ahbdma = { static clk_rst_t _clock_ahbdma = {
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_AHBDMA, 0, 0 CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, CLK_H_AHBDMA, 0, CLK_SRC_DIV(1)
}; };
static clock_t _clock_actmon = { static clk_rst_t _clock_actmon = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON, CLK_V_ACTMON, 6, 0 // 19.2MHz. CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON, CLK_V_ACTMON, 6, CLK_SRC_DIV(1) // 19.2 MHz.
}; };
static clock_t _clock_extperiph1 = { static clk_rst_t _clock_extperiph1 = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1, CLK_V_EXTPERIPH1, 0, 0 CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1, CLK_V_EXTPERIPH1, 0, CLK_SRC_DIV(1)
}; };
static clock_t _clock_extperiph2 = { static clk_rst_t _clock_extperiph2 = {
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2, CLK_V_EXTPERIPH2, 2, 202 // 4.0MHz CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2, CLK_V_EXTPERIPH2, 2, CLK_SRC_DIV(102) // 4.0 MHz
}; };
void clock_enable(const clock_t *clk) void clock_enable(const clk_rst_t *clk)
{ {
// Put clock into reset. // Put clock into reset.
CLOCK(clk->reset) = (CLOCK(clk->reset) & ~BIT(clk->index)) | BIT(clk->index); CLOCK(clk->reset) |= BIT(clk->index);
// Disable. // Disable.
CLOCK(clk->enable) &= ~BIT(clk->index); CLOCK(clk->enable) &= ~BIT(clk->index);
// Configure clock source if required. // Configure clock source if required.
if (clk->source) if (clk->source)
CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); CLOCK(clk->source) = (clk->clk_src << 29u) | clk->clk_div;
// Enable. // Enable.
CLOCK(clk->enable) = (CLOCK(clk->enable) & ~BIT(clk->index)) | BIT(clk->index); CLOCK(clk->enable) |= BIT(clk->index);
usleep(2); usleep(2);
// Take clock off reset. // Take clock off reset.
CLOCK(clk->reset) &= ~BIT(clk->index); CLOCK(clk->reset) &= ~BIT(clk->index);
} }
void clock_disable(const clock_t *clk) void clock_disable(const clk_rst_t *clk)
{ {
// Put clock into reset. // Put clock into reset.
CLOCK(clk->reset) = (CLOCK(clk->reset) & ~BIT(clk->index)) | BIT(clk->index); CLOCK(clk->reset) |= BIT(clk->index);
// Disable. // Disable.
CLOCK(clk->enable) &= ~BIT(clk->index); CLOCK(clk->enable) &= ~BIT(clk->index);
} }
@@ -153,7 +171,13 @@ void clock_enable_fuse(bool enable)
void clock_enable_uart(u32 idx) void clock_enable_uart(u32 idx)
{ {
// Ease the stress to APB.
bpmp_clk_rate_relaxed(true);
clock_enable(&_clock_uart[idx]); clock_enable(&_clock_uart[idx]);
// Restore OC.
bpmp_clk_rate_relaxed(false);
} }
void clock_disable_uart(u32 idx) void clock_disable_uart(u32 idx)
@@ -168,12 +192,12 @@ int clock_uart_use_src_div(u32 idx, u32 baud)
u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000; u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000;
if (baud == 3000000) if (baud == 3000000)
CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 15; CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | CLK_SRC_DIV(8.5);
else if (baud == 1000000) else if (baud == 1000000)
CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 49; CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | CLK_SRC_DIV(25.5);
else else
{ {
CLOCK(_clock_uart[idx].source) = clk_src_div | 2; CLOCK(_clock_uart[idx].source) = clk_src_div | CLK_SRC_DIV(2);
return 1; return 1;
} }
@@ -208,6 +232,9 @@ void clock_enable_tzram()
void clock_enable_host1x() void clock_enable_host1x()
{ {
clock_enable(&_clock_host1x); clock_enable(&_clock_host1x);
// Set idle frequency to 81.6 MHz.
// CLOCK(_clock_host1x.clk_src) |= CLK_SRC_DIV(5) << 8;
} }
void clock_disable_host1x() void clock_disable_host1x()
@@ -247,7 +274,16 @@ void clock_disable_nvjpg()
void clock_enable_vic() void clock_enable_vic()
{ {
// Ease the stress to APB.
bpmp_clk_rate_relaxed(true);
clock_enable(&_clock_vic); clock_enable(&_clock_vic);
// Set idle frequency to 136 MHz.
// CLOCK(_clock_vic.clk_src) |= CLK_SRC_DIV(3) << 8;
// Restore sys clock.
bpmp_clk_rate_relaxed(false);
} }
void clock_disable_vic() void clock_disable_vic()
@@ -323,7 +359,13 @@ void clock_disable_coresight()
void clock_enable_pwm() void clock_enable_pwm()
{ {
// Ease the stress to APB.
bpmp_clk_rate_relaxed(true);
clock_enable(&_clock_pwm); clock_enable(&_clock_pwm);
// Restore OC.
bpmp_clk_rate_relaxed(false);
} }
void clock_disable_pwm() void clock_disable_pwm()
@@ -398,23 +440,27 @@ void clock_enable_plld(u32 divp, u32 divn, bool lowpower, bool tegra_t210)
if (lowpower && tegra_t210) if (lowpower && tegra_t210)
misc = 0x2D0000 | 0x0AAA; // Clock enable and PLLD_SDM_DIN: 2730 -> DIVN + 0.833. misc = 0x2D0000 | 0x0AAA; // Clock enable and PLLD_SDM_DIN: 2730 -> DIVN + 0.833.
// Set DISP1 clock source.
// Set DISP1 clock source and parent clock. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 2 << 29u; // PLLD_OUT0.
if (lowpower)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 0x40000000; // PLLD_OUT0.
// Set dividers and enable PLLD. // Set dividers and enable PLLD.
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | plld_div; CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) = PLL_BASE_ENABLE | PLL_BASE_LOCK | plld_div;
CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = tegra_t210 ? 0x20 : 0; // Keep default PLLD_SETUP. CLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = tegra_t210 ? 0x20 : 0; // Keep default PLLD_SETUP.
// Set PLLD_SDM_DIN and enable PLLD to DSI pads. // Set PLLD_SDM_DIN and enable (T210) PLLD to DSI pads.
CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = misc; CLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = misc;
// Wait for PLL to stabilize.
while (!(CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) & PLL_BASE_LOCK))
;
usleep(10);
} }
void clock_enable_pllx() void clock_enable_pllx()
{ {
// Configure and enable PLLX if disabled. // Configure and enable PLLX if disabled.
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_ENABLE)) // PLLX_ENABLE. if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLL_BASE_ENABLE)) // PLLX_ENABLE.
{ {
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= ~PLLX_MISC3_IDDQ; // Disable IDDQ. CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= ~PLLX_MISC3_IDDQ; // Disable IDDQ.
usleep(2); usleep(2);
@@ -423,18 +469,20 @@ void clock_enable_pllx()
const u32 pllx_div_cfg = (2 << 20) | (156 << 8) | 2; // P div: 2 (3), N div: 156, M div: 2. 998.4 MHz. const u32 pllx_div_cfg = (2 << 20) | (156 << 8) | 2; // P div: 2 (3), N div: 156, M div: 2. 998.4 MHz.
// Bypass dividers. // Bypass dividers.
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_BYPASS | pllx_div_cfg; CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLL_BASE_BYPASS | pllx_div_cfg;
// Disable bypass // Disable bypass
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = pllx_div_cfg; CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = pllx_div_cfg;
// Set PLLX_LOCK_ENABLE. // Set PLLX_LOCK_ENABLE.
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) |= PLLX_MISC_LOCK_EN; CLOCK(CLK_RST_CONTROLLER_PLLX_MISC) |= PLLX_MISC_LOCK_EN;
// Enable PLLX. // Enable PLLX.
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLLX_BASE_ENABLE | pllx_div_cfg; CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLL_BASE_ENABLE | pllx_div_cfg;
} }
// Wait for PLL to stabilize. // Wait for PLL to stabilize.
while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLLX_BASE_LOCK)) while (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLL_BASE_LOCK))
; ;
usleep(10);
} }
void clock_enable_pllc(u32 divn) void clock_enable_pllc(u32 divn)
@@ -442,7 +490,7 @@ void clock_enable_pllc(u32 divn)
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
// Check if already enabled and configured. // Check if already enabled and configured.
if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn)) if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLL_BASE_ENABLE) && (pll_divn_curr == divn))
return; return;
// Take PLLC out of reset and set basic misc parameters. // Take PLLC out of reset and set basic misc parameters.
@@ -451,7 +499,7 @@ void clock_enable_pllc(u32 divn)
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM. CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM.
// Disable PLL and IDDQ in case they are on. // Disable PLL and IDDQ in case they are on.
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLL_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ; CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ;
usleep(10); usleep(10);
@@ -459,15 +507,15 @@ void clock_enable_pllc(u32 divn)
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1. CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1.
// Enable PLLC and wait for Phase and Frequency lock. // Enable PLLC and wait for Phase and Frequency lock.
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLL_BASE_ENABLE;
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK)) while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLL_BASE_LOCK))
; ;
// Disable PLLC_OUT1, enable reset and set div to 1.5. // 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. // 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. msleep(1); // Wait a bit for PLL to stabilize.
} }
@@ -476,7 +524,7 @@ void clock_disable_pllc()
// Disable PLLC and PLLC_OUT1. // Disable PLLC and PLLC_OUT1.
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~PLLC_OUT1_RSTN_CLR; CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~PLLC_OUT1_RSTN_CLR;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = PLLC_MISC_RESET; CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = PLLC_MISC_RESET;
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLL_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ; CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ;
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) &= ~(0xFF << 8); // PLLC_FLL_LD_MEM. CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) &= ~(0xFF << 8); // PLLC_FLL_LD_MEM.
usleep(10); usleep(10);
@@ -498,16 +546,16 @@ static void _clock_enable_pllc4(u32 mask)
//CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; //CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET;
// Disable PLL and IDDQ in case they are on. // Disable PLL and IDDQ in case they are on.
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLC4_BASE_IDDQ; CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLC4_BASE_IDDQ;
usleep(10); usleep(10);
// Set PLLC4 dividers. // Set PLLC4 dividers.
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = (104 << 8) | 4; // DIVM: 4, DIVP: 1. CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = (0 << 19) | (104 << 8) | 4; // DIVP: 1, DIVN: 104, DIVM: 4. 998MHz OUT0, 199MHz OUT2.
// Enable PLLC4 and wait for Phase and Frequency lock. // Enable PLLC4 and wait for Phase and Frequency lock.
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLL_BASE_ENABLE;
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLCX_BASE_LOCK)) while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLL_BASE_LOCK))
; ;
msleep(1); // Wait a bit for PLL to stabilize. msleep(1); // Wait a bit for PLL to stabilize.
@@ -525,7 +573,7 @@ static void _clock_disable_pllc4(u32 mask)
// Disable PLLC4. // Disable PLLC4.
msleep(1); // Wait at least 1ms to prevent glitching. msleep(1); // Wait at least 1ms to prevent glitching.
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE;
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLC4_BASE_IDDQ; CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLC4_BASE_IDDQ;
usleep(10); usleep(10);
@@ -538,11 +586,11 @@ void clock_enable_pllu()
CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) |= BIT(29); // Disable reference clock. CLOCK(CLK_RST_CONTROLLER_PLLU_MISC) |= BIT(29); // Disable reference clock.
u32 pllu_cfg = (CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & 0xFFE00000) | BIT(24) | (1 << 16) | (0x19 << 8) | 2; u32 pllu_cfg = (CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & 0xFFE00000) | BIT(24) | (1 << 16) | (0x19 << 8) | 2;
CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg; CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg;
CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg | PLLCX_BASE_ENABLE; // Enable. CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg | PLL_BASE_ENABLE; // Enable.
// Wait for PLL to stabilize. // Wait for PLL to stabilize.
u32 timeout = get_tmr_us() + 1300; u32 timeout = get_tmr_us() + 1300;
while (!(CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & PLLCX_BASE_LOCK)) // PLL_LOCK. while (!(CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & PLL_BASE_LOCK)) // PLL_LOCK.
if (get_tmr_us() > timeout) if (get_tmr_us() > timeout)
break; break;
usleep(10); usleep(10);
@@ -576,115 +624,50 @@ void clock_enable_utmipll()
static int _clock_sdmmc_is_reset(u32 id) static int _clock_sdmmc_is_reset(u32 id)
{ {
switch (id) const clk_rst_mgd_t *clk = &_clock_sdmmc[id];
{
case SDMMC_1: return CLOCK(clk->reset) & BIT(clk->index);
return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC1);
case SDMMC_2:
return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC2);
case SDMMC_3:
return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_U) & BIT(CLK_U_SDMMC3);
case SDMMC_4:
return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & BIT(CLK_L_SDMMC4);
}
return 0;
} }
static void _clock_sdmmc_set_reset(u32 id) static void _clock_sdmmc_set_reset(u32 id)
{ {
switch (id) const clk_rst_mgd_t *clk = &_clock_sdmmc[id];
{
case SDMMC_1: CLOCK(clk->reset) |= BIT(clk->index);
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC1);
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC2);
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = BIT(CLK_U_SDMMC3);
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_SDMMC4);
break;
}
} }
static void _clock_sdmmc_clear_reset(u32 id) static void _clock_sdmmc_clear_reset(u32 id)
{ {
switch (id) const clk_rst_mgd_t *clk = &_clock_sdmmc[id];
{
case SDMMC_1: CLOCK(clk->reset) &= ~BIT(clk->index);
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC1);
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC2);
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = BIT(CLK_U_SDMMC3);
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_SDMMC4);
break;
}
} }
static int _clock_sdmmc_is_enabled(u32 id) static int _clock_sdmmc_is_enabled(u32 id)
{ {
switch (id) const clk_rst_mgd_t *clk = &_clock_sdmmc[id];
{
case SDMMC_1: return CLOCK(clk->enable) & BIT(clk->index);
return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC1);
case SDMMC_2:
return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC2);
case SDMMC_3:
return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) & BIT(CLK_U_SDMMC3);
case SDMMC_4:
return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_SDMMC4);
}
return 0;
} }
static void _clock_sdmmc_set_enable(u32 id) static void _clock_sdmmc_set_enable(u32 id)
{ {
switch (id) const clk_rst_mgd_t *clk = &_clock_sdmmc[id];
{
case SDMMC_1: CLOCK(clk->enable) |= BIT(clk->index);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC1);
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC2);
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = BIT(CLK_U_SDMMC3);
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_SDMMC4);
break;
}
} }
static void _clock_sdmmc_clear_enable(u32 id) static void _clock_sdmmc_clear_enable(u32 id)
{ {
switch (id) const clk_rst_mgd_t *clk = &_clock_sdmmc[id];
{
case SDMMC_1: CLOCK(clk->enable) &= ~BIT(clk->index);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC1);
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC2);
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = BIT(CLK_U_SDMMC3);
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_SDMMC4);
break;
}
} }
static void _clock_sdmmc_config_legacy_tm() static void _clock_sdmmc_config_legacy_tm()
{ {
clock_t *clk = &_clock_sdmmc_legacy_tm; const clk_rst_t *clk = &_clock_sdmmc_legacy_tm;
if (!(CLOCK(clk->enable) & BIT(clk->index))) if (!(CLOCK(clk->enable) & BIT(clk->index)))
clock_enable(clk); clock_enable(clk);
} }
@@ -692,123 +675,123 @@ static void _clock_sdmmc_config_legacy_tm()
typedef struct _clock_sdmmc_t typedef struct _clock_sdmmc_t
{ {
u32 clock; u32 clock;
u32 real_clock; u32 pclock;
} clock_sdmmc_t; } clock_sdmmc_t;
static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 }; static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 };
#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0 #define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0
#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3 #define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3
#define SDMMC_CLOCK_SRC_PLLC4_OUT0 0x7
#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1 #define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1
static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 clock)
{ {
u32 divisor = 0; u32 divisor = 0;
u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0; u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0;
if (id > SDMMC_4) if (id > SDMMC_4)
return 0; return 0;
// Get IO clock divisor. // Get IO clock divisor.
switch (val) switch (clock)
{ {
case 25000: case 25000:
*pclock = 24728; *pclock = 24728;
divisor = 31; // 16.5 div. divisor = CLK_SRC_DIV(16.5);
break; break;
case 26000: case 26000:
*pclock = 25500; *pclock = 25500;
divisor = 30; // 16 div. divisor = CLK_SRC_DIV(16);
break; break;
case 50000: case 50000:
*pclock = 48000; *pclock = 48000;
divisor = 15; // 8.5 div. divisor = CLK_SRC_DIV(8.5);
break; break;
case 52000: case 52000:
*pclock = 51000; *pclock = 51000;
divisor = 14; // 8 div. divisor = CLK_SRC_DIV(8);
break; break;
case 81600: // Originally MMC_HS50 for GC FPGA at 40800 KHz, div 18 (real 10).
case 82000:
*pclock = 81600; *pclock = 81600;
divisor = 8; // 5 div. divisor = CLK_SRC_DIV(5);
break; break;
case 100000: case 100000:
source = SDMMC_CLOCK_SRC_PLLC4_OUT2; source = SDMMC_CLOCK_SRC_PLLC4_OUT2;
*pclock = 99840; *pclock = 99840;
divisor = 2; // 2 div. divisor = CLK_SRC_DIV(2);
break; break;
case 164000: case 164000:
*pclock = 163200; *pclock = 163200;
divisor = 3; // 2.5 div. divisor = CLK_SRC_DIV(2.5);
break; break;
case 200000: // 240MHz evo+.
case 200000:
switch (id) switch (id)
{ {
case SDMMC_1: case SDMMC_1:
source = SDMMC_CLOCK_SRC_PLLC4_OUT2;
break;
case SDMMC_2:
source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ;
break;
case SDMMC_3: case SDMMC_3:
source = SDMMC_CLOCK_SRC_PLLC4_OUT2; source = SDMMC_CLOCK_SRC_PLLC4_OUT2;
break; break;
case SDMMC_2:
case SDMMC_4: case SDMMC_4:
source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; // CLK RST divisor is ignored.
break; break;
} }
*pclock = 199680; *pclock = 199680;
divisor = 0; // 1 div. divisor = CLK_SRC_DIV(1);
break; break;
default:
*pclock = 24728; #ifdef BDK_SDMMC_UHS_DDR200_SUPPORT
divisor = 31; // 16.5 div. case 400000:
source = SDMMC_CLOCK_SRC_PLLC4_OUT0;
*pclock = 399360;
divisor = CLK_SRC_DIV(2.5);
break;
#endif
} }
_clock_sdmmc_table[id].clock = val; _clock_sdmmc_table[id].clock = clock;
_clock_sdmmc_table[id].real_clock = *pclock; _clock_sdmmc_table[id].pclock = *pclock;
// Enable PLLC4 if in use by any SDMMC. // Enable PLLC4 if in use by any SDMMC.
if (source) if (source != SDMMC_CLOCK_SRC_PLLP_OUT0)
_clock_enable_pllc4(BIT(id)); _clock_enable_pllc4(BIT(id));
// Set SDMMC legacy timeout clock. // Set SDMMC legacy timeout clock.
_clock_sdmmc_config_legacy_tm(); _clock_sdmmc_config_legacy_tm();
// Set SDMMC clock. // Set SDMMC clock.
switch (id) const clk_rst_mgd_t *clk = &_clock_sdmmc[id];
{ CLOCK(clk->source) = (source << 29u) | divisor;
case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor;
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor;
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor;
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | divisor;
break;
}
return 1; return 1;
} }
void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val) void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 clock)
{ {
if (_clock_sdmmc_table[id].clock == val) if (_clock_sdmmc_table[id].clock == clock)
{ {
*pclock = _clock_sdmmc_table[id].real_clock; *pclock = _clock_sdmmc_table[id].pclock;
} }
else else
{ {
int is_enabled = _clock_sdmmc_is_enabled(id); int is_enabled = _clock_sdmmc_is_enabled(id);
if (is_enabled) if (is_enabled)
_clock_sdmmc_clear_enable(id); _clock_sdmmc_clear_enable(id);
_clock_sdmmc_config_clock_host(pclock, id, val);
_clock_sdmmc_config_clock_host(pclock, id, clock);
if (is_enabled) if (is_enabled)
_clock_sdmmc_set_enable(id); _clock_sdmmc_set_enable(id);
// Commit changes.
_clock_sdmmc_is_reset(id); _clock_sdmmc_is_reset(id);
} }
} }
@@ -818,54 +801,71 @@ void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type)
// Get Card clock divisor. // Get Card clock divisor.
switch (type) switch (type)
{ {
case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz. case SDHCI_TIMING_MMC_ID: // Actual card clock: 386.36 KHz.
*pclock = 26000; *pclock = 26000;
*pdivisor = 66; *pdivisor = 66;
break; break;
case SDHCI_TIMING_MMC_LS26: case SDHCI_TIMING_MMC_LS26:
*pclock = 26000; *pclock = 26000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case SDHCI_TIMING_MMC_HS52: case SDHCI_TIMING_MMC_HS52:
*pclock = 52000; *pclock = 52000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case SDHCI_TIMING_MMC_HS200: case SDHCI_TIMING_MMC_HS200:
case SDHCI_TIMING_MMC_HS400: case SDHCI_TIMING_MMC_HS400:
case SDHCI_TIMING_UHS_SDR104: case SDHCI_TIMING_UHS_SDR104:
*pclock = 200000; *pclock = 200000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz.
case SDHCI_TIMING_SD_ID: // Actual card clock: 386.38 KHz.
*pclock = 25000; *pclock = 25000;
*pdivisor = 64; *pdivisor = 64;
break; break;
case SDHCI_TIMING_SD_DS12: case SDHCI_TIMING_SD_DS12:
case SDHCI_TIMING_UHS_SDR12: case SDHCI_TIMING_UHS_SDR12:
*pclock = 25000; *pclock = 25000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case SDHCI_TIMING_SD_HS25: case SDHCI_TIMING_SD_HS25:
case SDHCI_TIMING_UHS_SDR25: case SDHCI_TIMING_UHS_SDR25:
*pclock = 50000; *pclock = 50000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case SDHCI_TIMING_UHS_SDR50: case SDHCI_TIMING_UHS_SDR50:
*pclock = 100000; *pclock = 100000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case SDHCI_TIMING_UHS_SDR82: case SDHCI_TIMING_UHS_SDR82:
*pclock = 164000; *pclock = 164000;
*pdivisor = 1; *pdivisor = 1;
break; break;
case SDHCI_TIMING_UHS_DDR50:
*pclock = 81600; // Originally MMC_HS50 for GC FPGA at 40800 KHz, div 1. case SDHCI_TIMING_UHS_DDR50: // Actual card clock: 40.80 MHz.
*pclock = 82000;
*pdivisor = 2; *pdivisor = 2;
break; break;
case SDHCI_TIMING_MMC_DDR100: // Actual IO Freq: 99.84 MHz.
case SDHCI_TIMING_MMC_HS100: // Actual card clock: 99.84 MHz.
*pclock = 200000; *pclock = 200000;
*pdivisor = 2; *pdivisor = 2;
break; break;
#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT
case SDHCI_TIMING_UHS_DDR200: // Actual card clock: 199.68 KHz.
*pclock = 400000;
*pdivisor = 2;
break;
#endif
} }
} }
@@ -874,17 +874,17 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id)
return !_clock_sdmmc_is_reset(id) && _clock_sdmmc_is_enabled(id); return !_clock_sdmmc_is_reset(id) && _clock_sdmmc_is_enabled(id);
} }
void clock_sdmmc_enable(u32 id, u32 val) void clock_sdmmc_enable(u32 id, u32 clock)
{ {
u32 clock = 0; _clock_sdmmc_clear_enable(id);
if (_clock_sdmmc_is_enabled(id))
_clock_sdmmc_clear_enable(id);
_clock_sdmmc_set_reset(id); _clock_sdmmc_set_reset(id);
_clock_sdmmc_config_clock_host(&clock, id, val); _clock_sdmmc_config_clock_host(&clock, id, clock);
_clock_sdmmc_set_enable(id); _clock_sdmmc_set_enable(id);
// // Commit changes and wait 100 cycles for reset and for clocks to stabilize.
_clock_sdmmc_is_reset(id); _clock_sdmmc_is_reset(id);
usleep((100000 + clock - 1) / clock); usleep((100 * 1000 + clock - 1) / clock);
_clock_sdmmc_clear_reset(id); _clock_sdmmc_clear_reset(id);
_clock_sdmmc_is_reset(id); _clock_sdmmc_is_reset(id);
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -47,6 +47,7 @@
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 #define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C #define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 #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_BASE 0xB0
#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4 #define CLK_RST_CONTROLLER_PLLA_OUT 0xB4
#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8 #define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8
@@ -149,6 +150,7 @@
#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0 #define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 #define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 #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_FS 0x608
#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV 0x60C #define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV 0x60C
#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS 0x610 #define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS 0x610
@@ -170,18 +172,14 @@
#define CLK_NOT_USED 0x0 #define CLK_NOT_USED 0x0
/*! PLL control and status bits */ /*! PLL control and status bits */
#define PLLX_BASE_LOCK BIT(27) #define PLL_BASE_LOCK BIT(27)
#define PLLX_BASE_REF_DIS BIT(29) #define PLL_BASE_REF_DIS BIT(29)
#define PLLX_BASE_ENABLE BIT(30) #define PLL_BASE_ENABLE BIT(30)
#define PLLX_BASE_BYPASS BIT(31) #define PLL_BASE_BYPASS BIT(31)
#define PLLX_MISC_LOCK_EN BIT(18) #define PLLX_MISC_LOCK_EN BIT(18)
#define PLLX_MISC3_IDDQ BIT(3) #define PLLX_MISC3_IDDQ BIT(3)
#define PLLCX_BASE_LOCK BIT(27)
#define PLLCX_BASE_REF_DIS BIT(29)
#define PLLCX_BASE_ENABLE BIT(30)
#define PLLCX_BASE_BYPASS BIT(31)
#define PLLA_OUT0_RSTN_CLR BIT(0) #define PLLA_OUT0_RSTN_CLR BIT(0)
#define PLLA_OUT0_CLKEN BIT(1) #define PLLA_OUT0_CLKEN BIT(1)
#define PLLA_BASE_IDDQ BIT(25) #define PLLA_BASE_IDDQ BIT(25)
@@ -198,6 +196,9 @@
#define UTMIPLL_LOCK BIT(31) #define UTMIPLL_LOCK BIT(31)
/*! Clock source */
#define CLK_SRC_DIV(d) ((d) ? ((u32)(((d) - 1) * 2)) : 0)
/*! PTO_CLK_CNT */ /*! PTO_CLK_CNT */
#define PTO_REF_CLK_WIN_CFG_MASK 0xF #define PTO_REF_CLK_WIN_CFG_MASK 0xF
#define PTO_REF_CLK_WIN_CFG_16P 0xF #define PTO_REF_CLK_WIN_CFG_16P 0xF
@@ -227,138 +228,232 @@
/*! PTO IDs. */ /*! PTO IDs. */
typedef enum _clock_pto_id_t typedef enum _clock_pto_id_t
{ {
CLK_PTO_PCLK_SYS = 0x06, CLK_PTO_PCLK_SYS = 0x06,
CLK_PTO_HCLK_SYS = 0x07, CLK_PTO_HCLK_SYS = 0x07,
CLK_PTO_DMIC1 = 0x08,
CLK_PTO_DMIC2 = 0x09,
CLK_PTO_HDMI_SLOWCLK_DIV2 = 0x0A,
CLK_PTO_JTAG_REG = 0x0B,
CLK_PTO_UTMIP_240_A = 0x0C,
CLK_PTO_UTMIP_240_B = 0x0D,
CLK_PTO_UTMIP_240 = 0x0C, CLK_PTO_CCLK_G = 0x12,
CLK_PTO_CCLK_G_DIV2 = 0x13,
CLK_PTO_MIPIBIF = 0x14,
CLK_PTO_CCLK_G = 0x12, CLK_PTO_SPI1 = 0x17,
CLK_PTO_CCLK_G_DIV2 = 0x13, CLK_PTO_SPI2 = 0x18,
CLK_PTO_SPI3 = 0x19,
CLK_PTO_SPI4 = 0x1A,
CLK_PTO_MAUD = 0x1B,
CLK_PTO_SCLK = 0x1C,
CLK_PTO_SPI1 = 0x17, CLK_PTO_SDMMC1 = 0x20,
CLK_PTO_SPI2 = 0x18, CLK_PTO_SDMMC2 = 0x21,
CLK_PTO_SPI3 = 0x19, CLK_PTO_SDMMC3 = 0x22,
CLK_PTO_SPI4 = 0x1A, CLK_PTO_SDMMC4 = 0x23,
CLK_PTO_MAUD = 0x1B, CLK_PTO_EMC = 0x24,
CLK_PTO_SCLK = 0x1C,
CLK_PTO_SDMMC1 = 0x20, CLK_PTO_DMIC3 = 0x2A,
CLK_PTO_SDMMC2 = 0x21, CLK_PTO_CCLK_LP = 0x2B,
CLK_PTO_SDMMC3 = 0x22, CLK_PTO_CCLK_LP_DIV2 = 0x2C,
CLK_PTO_SDMMC4 = 0x23,
CLK_PTO_EMC = 0x24,
CLK_PTO_CCLK_LP = 0x2B, CLK_PTO_MSELECT = 0x2F,
CLK_PTO_CCLK_LP_DIV2 = 0x2C,
CLK_PTO_MSELECT = 0x2F, CLK_PTO_VI_SENSOR2 = 0x33,
CLK_PTO_VI_SENSOR = 0x34,
CLK_PTO_VIC = 0x35,
CLK_PTO_VIC_SKIP = 0x36,
CLK_PTO_ISP_SKIP = 0x37,
CLK_PTO_ISPB_SE2_SKIP = 0x38,
CLK_PTO_NVDEC_SKIP = 0x39,
CLK_PTO_NVENC_SKIP = 0x3A,
CLK_PTO_NVJPG_SKIP = 0x3B,
CLK_PTO_TSEC_SKIP = 0x3C,
CLK_PTO_TSECB_SKIP = 0x3D,
CLK_PTO_SE_SKIP = 0x3E,
CLK_PTO_VI_SKIP = 0x3F,
CLK_PTO_VIC = 0x36, CLK_PTO_PLLX_OBS = 0x40,
CLK_PTO_PLLC_OBS = 0x41,
CLK_PTO_PLLM_OBS = 0x42,
CLK_PTO_PLLP_OBS = 0x43,
CLK_PTO_PLLA_OBS = 0x44,
CLK_PTO_PLLMB_OBS = 0x45,
CLK_PTO_SATA_OOB = 0x46,
CLK_PTO_NVDEC = 0x39, CLK_PTO_FCPU_DVFS_DIV12_CPU = 0x48,
CLK_PTO_NVENC = 0x3A, CLK_PTO_EQOS_AXI = 0x4C,
CLK_PTO_NVJPG = 0x3B, CLK_PTO_EQOS_PTP_REF = 0x4D,
CLK_PTO_TSEC = 0x3C, CLK_PTO_EQOS_TX = 0x4E,
CLK_PTO_TSECB = 0x3D, CLK_PTO_EQOS_RX = 0x4F,
CLK_PTO_SE = 0x3E,
CLK_PTO_DSIA_LP = 0x62, CLK_PTO_CILAB = 0x52,
CLK_PTO_CILCD = 0x53,
CLK_PTO_ISP = 0x64, CLK_PTO_CILEF = 0x55,
CLK_PTO_MC = 0x6A, CLK_PTO_PLLA1_PTO_OBS = 0x56,
CLK_PTO_PLLC4_PTO_OBS = 0x57,
CLK_PTO_ACTMON = 0x6B, CLK_PTO_PLLC2_PTO_OBS = 0x59,
CLK_PTO_CSITE = 0x6C, CLK_PTO_PLLC3_PTO_OBS = 0x5B,
CLK_PTO_HOST1X = 0x6F, CLK_PTO_DSIA_LP = 0x62,
CLK_PTO_DSIB_LP = 0x63,
CLK_PTO_ISP = 0x64,
CLK_PTO_PEX_PAD = 0x65,
CLK_PTO_SE_2 = 0x74, // Same as CLK_PTO_SE. CLK_PTO_MC = 0x6A,
CLK_PTO_SOC_THERM = 0x75,
CLK_PTO_TSEC_2 = 0x77, // Same as CLK_PTO_TSEC. CLK_PTO_ACTMON = 0x6B,
CLK_PTO_CSITE = 0x6C,
CLK_PTO_VI_I2C = 0x6D,
CLK_PTO_ACLK = 0x7C, CLK_PTO_HOST1X = 0x6F,
CLK_PTO_QSPI = 0x7D,
CLK_PTO_I2S1 = 0x80, CLK_PTO_QSPI_2X = 0x71,
CLK_PTO_I2S2 = 0x81, CLK_PTO_NVDEC = 0x72,
CLK_PTO_I2S3 = 0x82, CLK_PTO_NVJPG = 0x73,
CLK_PTO_I2S4 = 0x83, CLK_PTO_SE = 0x74,
CLK_PTO_I2S5 = 0x84, CLK_PTO_SOC_THERM = 0x75,
CLK_PTO_AHUB = 0x85,
CLK_PTO_APE = 0x86,
CLK_PTO_DVFS_SOC = 0x88, CLK_PTO_TSEC = 0x77,
CLK_PTO_DVFS_REF = 0x89, CLK_PTO_TSECB = 0x78,
CLK_PTO_VI = 0x79,
CLK_PTO_LA = 0x7A,
CLK_PTO_SCLK_SKIP = 0x7B,
CLK_PTO_SPDIF = 0x8F, CLK_PTO_ADSP_SKIP = 0x7C,
CLK_PTO_SPDIF_IN = 0x90, CLK_PTO_QSPI = 0x7D,
CLK_PTO_SDMMC2_SHAPER = 0x7E,
CLK_PTO_SDMMC4_SHAPER = 0x7F,
CLK_PTO_I2S1 = 0x80,
CLK_PTO_I2S2 = 0x81,
CLK_PTO_I2S3 = 0x82,
CLK_PTO_I2S4 = 0x83,
CLK_PTO_I2S5 = 0x84,
CLK_PTO_AHUB = 0x85,
CLK_PTO_APE = 0x86,
CLK_PTO_DVFS_SOC = 0x88,
CLK_PTO_DVFS_REF = 0x89,
CLK_PTO_ADSP_CLK = 0x8A,
CLK_PTO_ADSP_DIV2_CLK = 0x8B,
CLK_PTO_SPDIF_OUT = 0x8F,
CLK_PTO_SPDIF_IN = 0x90,
CLK_PTO_UART_FST_MIPI_CAL = 0x91, CLK_PTO_UART_FST_MIPI_CAL = 0x91,
CLK_PTO_SYS2HSIO_SATA_CLK = 0x92,
CLK_PTO_PWM = 0x93,
CLK_PTO_I2C1 = 0x94,
CLK_PTO_I2C2 = 0x95,
CLK_PTO_I2C3 = 0x96,
CLK_PTO_I2C4 = 0x97,
CLK_PTO_I2C5 = 0x98,
CLK_PTO_I2C6 = 0x99,
CLK_PTO_I2C_SLOW = 0x9A,
CLK_PTO_UARTAPE = 0x9B,
CLK_PTO_PWM = 0x93, CLK_PTO_EXTPERIPH1 = 0x9D,
CLK_PTO_I2C1 = 0x94, CLK_PTO_EXTPERIPH2 = 0x9E,
CLK_PTO_I2C2 = 0x95, CLK_PTO_EXTPERIPH3 = 0x9F,
CLK_PTO_I2C3 = 0x96, CLK_PTO_ENTROPY = 0xA0,
CLK_PTO_I2C4 = 0x97, CLK_PTO_UARTA = 0xA1,
CLK_PTO_I2C5 = 0x98, CLK_PTO_UARTB = 0xA2,
CLK_PTO_I2C6 = 0x99, CLK_PTO_UARTC = 0xA3,
CLK_PTO_I2C_SLOW = 0x9A, CLK_PTO_UARTD = 0xA4,
CLK_PTO_UARTAPE = 0x9B, CLK_PTO_OWR = 0xA5,
CLK_PTO_TSENSOR = 0xA6,
CLK_PTO_HDA2CODEC_2X = 0xA7,
CLK_PTO_HDA = 0xA8,
CLK_PTO_EMC_LATENCY = 0xA9,
CLK_PTO_EMC_DLL = 0xAA,
CLK_PTO_SDMMC_LEGACY_TM = 0xAB,
CLK_PTO_DBGAPB = 0xAC,
CLK_PTO_EXTPERIPH1 = 0x9D, CLK_PTO_SOR0 = 0xC0,
CLK_PTO_EXTPERIPH2 = 0x9E, CLK_PTO_SOR1 = 0xC1,
CLK_PTO_HDMI = 0xC2,
CLK_PTO_ENTROPY = 0xA0, CLK_PTO_DISP2 = 0xC4,
CLK_PTO_UARTA = 0xA1, CLK_PTO_DISP1 = 0xC5,
CLK_PTO_UARTB = 0xA2,
CLK_PTO_UARTC = 0xA3,
CLK_PTO_UARTD = 0xA4,
CLK_PTO_OWR = 0xA5,
CLK_PTO_HDA2CODEC_2X = 0xA7, CLK_PTO_PLLD_OBS = 0xCA,
CLK_PTO_HDA = 0xA8, CLK_PTO_PLLD2_PTO_OBS = 0xCC,
CLK_PTO_PLLDP_OBS = 0xCE,
CLK_PTO_PLLE_OBS = 0x10A,
CLK_PTO_PLLU_OBS = 0x10C,
CLK_PTO_PLLREFE_OBS = 0x10E,
CLK_PTO_SDMMC_LEGACY_TM = 0xAB, CLK_PTO_XUSB_FALCON = 0x110,
CLK_PTO_XUSB_CLK480M_HSIC = 0x111,
CLK_PTO_USB_L0_RX = 0x112,
CLK_PTO_USB_L3_RX = 0x113,
CLK_PTO_USB_RX = 0x114,
CLK_PTO_USB3_L0_TXCLKREF = 0x115,
CLK_PTO_PEX_TXCLKREF_SWITCH_TMS = 0x116,
CLK_PTO_PEX_TXCLKREF_SWITCH_GRP0 = 0x117,
CLK_PTO_PEX_TXCLKREF_SWITCH_GRP1 = 0x118,
CLK_PTO_PEX_TXCLKREF_SWITCH_GRP2 = 0x119,
CLK_PTO_PEX_L4_RX = 0x11A,
CLK_PTO_PEX_TXCLKREF = 0x11B,
CLK_PTO_PEX_TXCLKREF_DIV2 = 0x11C,
CLK_PTO_PEX_TXCLKREF2 = 0x11D,
CLK_PTO_PEX_L0_RX = 0x11E,
CLK_PTO_PEX_L1_RX = 0x11F,
CLK_PTO_PEX_L2_RX = 0x120,
CLK_PTO_PEX_L3_RX = 0x121,
CLK_PTO_SATA_TXCLKREF = 0x122,
CLK_PTO_SATA_TXCLKREF_DIV2 = 0x123,
CLK_PTO_USB_L5_RX = 0x124,
CLK_PTO_SATA_TX = 0x125,
CLK_PTO_SATA_L0_RX = 0x126,
CLK_PTO_SOR0 = 0xC0, CLK_PTO_USB3_L1_TXCLKREF = 0x129,
CLK_PTO_SOR1 = 0xC1, CLK_PTO_USB3_L7_TXCLKREF = 0x12A,
CLK_PTO_USB3_L7_RX = 0x12B,
CLK_PTO_USB3_TX = 0x12C,
CLK_PTO_UTMIP_PLL_PAD = 0x12D,
CLK_PTO_DISP2 = 0xC4, CLK_PTO_XUSB_FS = 0x136,
CLK_PTO_DISP1 = 0xC5, CLK_PTO_XUSB_SS_HOST_DEV = 0x137,
CLK_PTO_XUSB_CORE_HOST = 0x138,
CLK_PTO_XUSB_CORE_DEV = 0x139,
CLK_PTO_XUSB_FALCON = 0x110, CLK_PTO_USB3_L2_TXCLKREF = 0x13C,
CLK_PTO_USB3_L3_TXCLKREF = 0x13D,
CLK_PTO_XUSB_FS = 0x136, CLK_PTO_USB_L4_RX = 0x13E,
CLK_PTO_XUSB_SS_HOST_DEV = 0x137, CLK_PTO_USB_L6_RX = 0x13F,
CLK_PTO_XUSB_CORE_HOST = 0x138,
CLK_PTO_XUSB_CORE_DEV = 0x139,
/* /*
* PLL need PTO enabled in MISC registers. * PLL need PTO enabled in MISC registers.
* Normal div is 2 so result is multiplied with it. * Normal div is 2 so result is multiplied with it.
*/ */
CLK_PTO_PLLC_DIV2 = 0x01, CLK_PTO_PLLC_DIV2 = 0x01,
CLK_PTO_PLLM_DIV2 = 0x02, CLK_PTO_PLLM_DIV2 = 0x02,
CLK_PTO_PLLP_DIV2 = 0x03, CLK_PTO_PLLP_DIV2 = 0x03,
CLK_PTO_PLLA_DIV2 = 0x04, CLK_PTO_PLLA_DIV2 = 0x04,
CLK_PTO_PLLX_DIV2 = 0x05, CLK_PTO_PLLX_DIV2 = 0x05,
CLK_PTO_PLLMB_DIV2 = 0x25, CLK_PTO_PLLMB_DIV2 = 0x25,
CLK_PTO_PLLC4_DIV2 = 0x51, CLK_PTO_PLLC4_DIV2 = 0x51,
CLK_PTO_PLLA1_DIV2 = 0x55, CLK_PTO_PLLA1_DIV2 = 0x55,
CLK_PTO_PLLC2_DIV2 = 0x58, CLK_PTO_PLLC2_DIV2 = 0x58,
CLK_PTO_PLLC3_DIV2 = 0x5A, CLK_PTO_PLLC3_DIV2 = 0x5A,
CLK_PTO_PLLD_DIV2 = 0xCB, CLK_PTO_PLLD_DIV2 = 0xCB,
CLK_PTO_PLLD2_DIV2 = 0xCD, CLK_PTO_PLLD2_DIV2 = 0xCD,
CLK_PTO_PLLDP_DIV2 = 0xCF, CLK_PTO_PLLDP_DIV2 = 0xCF,
CLK_PTO_PLLU_DIV2 = 0x10D, CLK_PTO_PLLE_DIV2 = 0x10B,
CLK_PTO_PLLREFE_DIV2 = 0x10F, CLK_PTO_PLLU_DIV2 = 0x10D,
CLK_PTO_PLLREFE_DIV2 = 0x10F,
} clock_pto_id_t; } clock_pto_id_t;
/* /*
@@ -374,109 +469,85 @@ typedef enum _clock_pto_id_t
enum CLK_L_DEV enum CLK_L_DEV
{ {
CLK_L_CPU = 0, // Only reset. Deprecated. CLK_L_CPU = 0, // Deprecated.
CLK_L_BPMP = 1, // Only reset. CLK_L_BPMP = 1, // Only reset.
CLK_L_SYS = 2, // Only reset. CLK_L_SYS = 2, // Only reset.
CLK_L_ISPB = 3, CLK_L_ISPB = 3,
CLK_L_RTC = 4, CLK_L_RTC = 4, // Only enable.
CLK_L_TMR = 5, CLK_L_TMR = 5,
CLK_L_UARTA = 6, CLK_L_UARTA = 6,
CLK_L_UARTB = 7, CLK_L_UARTB = 7,
CLK_L_GPIO = 8, CLK_L_GPIO = 8,
CLK_L_SDMMC2 = 9, CLK_L_SDMMC2 = 9,
CLK_L_SPDIF = 10, CLK_L_SPDIF = 10, // Only enable.
CLK_L_I2S2 = 11, // I2S1 CLK_L_I2S2 = 11, // Only enable.
CLK_L_I2C1 = 12, CLK_L_I2C1 = 12,
CLK_L_NDFLASH = 13, // HIDDEN. CLK_L_SDMMC1 = 14,
CLK_L_SDMMC1 = 14, CLK_L_SDMMC4 = 15,
CLK_L_SDMMC4 = 15, CLK_L_TWC = 16, // 3-Wire Controller. Deprecated.
CLK_L_TWC = 16, // HIDDEN. CLK_L_PWM = 17,
CLK_L_PWM = 17, CLK_L_I2S3 = 18, // Only enable.
CLK_L_I2S3 = 18, CLK_L_VI = 20,
CLK_L_EPP = 19, // HIDDEN. CLK_L_USBD = 22,
CLK_L_VI = 20, CLK_L_ISP = 23,
CLK_L_2D = 21, // HIDDEN. CLK_L_DISP2 = 26,
CLK_L_USBD = 22, CLK_L_DISP1 = 27,
CLK_L_ISP = 23, CLK_L_HOST1X = 28,
CLK_L_3D = 24, // HIDDEN. CLK_L_I2S1 = 30, // Only enable.
CLK_L_IDE = 25, // RESERVED. CLK_L_BPMP_CACHE_CTRL = 31, // Controller.
CLK_L_DISP2 = 26,
CLK_L_DISP1 = 27,
CLK_L_HOST1X = 28,
CLK_L_VCP = 29, // HIDDEN.
CLK_L_I2S1 = 30, // I2S0
CLK_L_BPMP_CACHE_CTRL = 31, // CONTROLLER
}; };
enum CLK_H_DEV enum CLK_H_DEV
{ {
CLK_H_MEM = 0, // MC. CLK_H_MEM = 0, // MC.
CLK_H_AHBDMA = 1, CLK_H_AHBDMA = 1,
CLK_H_APBDMA = 2, CLK_H_APBDMA = 2,
//CLK_H_ = 3, CLK_H_STAT_MON = 5,
CLK_H_KBC = 4, // HIDDEN. CLK_H_PMC = 6, // Only enable.
CLK_H_STAT_MON = 5, CLK_H_FUSE = 7,
CLK_H_PMC = 6, CLK_H_KFUSE = 8,
CLK_H_FUSE = 7, CLK_H_SPI1 = 9,
CLK_H_KFUSE = 8,
CLK_H_SPI1 = 9,
CLK_H_SNOR = 10, // HIDDEN.
CLK_H_JTAG2TBC = 11,
CLK_H_SPI2 = 12, CLK_H_SPI2 = 12,
CLK_H_XIO = 13, // HIDDEN. CLK_H_XIO = 13, // Misc IO. Deprecated?
CLK_H_SPI3 = 14, CLK_H_SPI3 = 14,
CLK_H_I2C5 = 15, CLK_H_I2C5 = 15,
CLK_H_DSI = 16, CLK_H_DSI = 16,
CLK_H_TVO = 17, // RESERVED.
CLK_H_HSI = 18, // HIDDEN.
CLK_H_HDMI = 19, // HIDDEN.
CLK_H_CSI = 20, CLK_H_CSI = 20,
CLK_H_TVDAC = 21, // RESERVED.
CLK_H_I2C2 = 22, CLK_H_I2C2 = 22,
CLK_H_UARTC = 23, CLK_H_UARTC = 23,
CLK_H_MIPI_CAL = 24, CLK_H_MIPI_CAL = 24,
CLK_H_EMC = 25, CLK_H_EMC = 25,
CLK_H_USB2 = 26, CLK_H_USB2 = 26,
CLK_H_USB3 = 27, // HIDDEN.
CLK_H_MPE = 28, // HIDDEN.
CLK_H_VDE = 29, // HIDDEN.
CLK_H_BSEA = 30, // HIDDEN.
CLK_H_BSEV = 31, CLK_H_BSEV = 31,
}; };
enum CLK_U_DEV enum CLK_U_DEV
{ {
CLK_U_SPEEDO = 0, // RESERVED. //CLK_U_SPEEDO = 0, // RESERVED. Old speedo ring oscillator.
CLK_U_UARTD = 1, CLK_U_UARTD = 1,
CLK_U_UARTE = 2, // HIDDEN. CLK_U_I2C3 = 3,
CLK_U_I2C3 = 3, CLK_U_SPI4 = 4,
CLK_U_SPI4 = 4, CLK_U_SDMMC3 = 5,
CLK_U_SDMMC3 = 5, CLK_U_PCIE = 6,
CLK_U_PCIE = 6, CLK_U_OWR = 7, // 1-Wire Controller. Deprecated.
CLK_U_OWR = 7, // RESERVED. CLK_U_AFI = 8,
CLK_U_AFI = 8, CLK_U_CSITE = 9,
CLK_U_CSITE = 9,
CLK_U_PCIEXCLK = 10, // Only reset. CLK_U_PCIEXCLK = 10, // Only reset.
CLK_U_BPMPUCQ = 11, // HIDDEN. CLK_U_LA = 12, // DFD.
CLK_U_LA = 12,
CLK_U_TRACECLKIN = 13, // HIDDEN.
CLK_U_SOC_THERM = 14, CLK_U_SOC_THERM = 14,
CLK_U_DTV = 15, CLK_U_DTV = 15, // Deprecated.
CLK_U_NAND_SPEED = 16, // HIDDEN.
CLK_U_I2C_SLOW = 17, CLK_U_I2C_SLOW = 17,
CLK_U_DSIB = 18, CLK_U_DSIB = 18,
CLK_U_TSEC = 19, CLK_U_TSEC = 19,
CLK_U_IRAMA = 20, CLK_U_IRAMA = 20, // Only enable.
CLK_U_IRAMB = 21, CLK_U_IRAMB = 21, // Only enable.
CLK_U_IRAMC = 22, CLK_U_IRAMC = 22, // Only enable.
CLK_U_IRAMD = 23, // EMUCIF ON RESET CLK_U_IRAMD = 23, // EMUCIF ON RESET
CLK_U_BPMP_CACHE_RAM = 24, CLK_U_BPMP_CACHE_RAM = 24, // Only enable.
CLK_U_XUSB_HOST = 25, CLK_U_XUSB_HOST = 25,
CLK_U_CLK_M_DOUBLER = 26, CLK_U_SUS_OUT = 28, // Only enable. VI MCLK. Deprecated?
CLK_U_MSENC = 27, // HIDDEN. CLK_U_DEV2_OUT = 29, // Only enable. DAP MCLK. Deprecated?
CLK_U_SUS_OUT = 28, CLK_U_DEV1_OUT = 30, // Only enable. DAP MCLK. Deprecated?
CLK_U_DEV2_OUT = 29,
CLK_U_DEV1_OUT = 30,
CLK_U_XUSB_DEV = 31, CLK_U_XUSB_DEV = 31,
}; };
@@ -484,133 +555,109 @@ enum CLK_V_DEV
{ {
CLK_V_CPUG = 0, CLK_V_CPUG = 0,
CLK_V_CPULP = 1, // Reserved. CLK_V_CPULP = 1, // Reserved.
CLK_V_3D2 = 2, // HIDDEN.
CLK_V_MSELECT = 3, CLK_V_MSELECT = 3,
CLK_V_TSENSOR = 4, CLK_V_TSENSOR = 4, // Only enable.
CLK_V_I2S4 = 5, CLK_V_I2S4 = 5, // Only enable.
CLK_V_I2S5 = 6, CLK_V_I2S5 = 6, // Only enable.
CLK_V_I2C4 = 7, CLK_V_I2C4 = 7,
CLK_V_SPI5 = 8, // HIDDEN. CLK_V_AHUB = 10, // AUDIO. Only enable.
CLK_V_SPI6 = 9, // HIDDEN. CLK_V_APB2APE = 11, // APBIF. Only enable.
CLK_V_AHUB = 10, // AUDIO.
CLK_V_APB2APE = 11, // APBIF.
CLK_V_DAM0 = 12, // HIDDEN.
CLK_V_DAM1 = 13, // HIDDEN.
CLK_V_DAM2 = 14, // HIDDEN.
CLK_V_HDA2CODEC_2X = 15, CLK_V_HDA2CODEC_2X = 15,
CLK_V_ATOMICS = 16, CLK_V_ATOMICS = 16,
//CLK_V_ = 17, CLK_V_SPDIF_DOUBLER = 22, // Only enable.
//CLK_V_ = 18,
//CLK_V_ = 19,
//CLK_V_ = 20,
//CLK_V_ = 21,
CLK_V_SPDIF_DOUBLER = 22,
CLK_V_ACTMON = 23, CLK_V_ACTMON = 23,
CLK_V_EXTPERIPH1 = 24, CLK_V_EXTPERIPH1 = 24,
CLK_V_EXTPERIPH2 = 25, CLK_V_EXTPERIPH2 = 25,
CLK_V_EXTPERIPH3 = 26, CLK_V_EXTPERIPH3 = 26,
CLK_V_SATA_OOB = 27, CLK_V_SATA_OOB = 27, // Only on T210.
CLK_V_SATA = 28, CLK_V_SATA = 28, // Only on T210.
CLK_V_HDA = 29, CLK_V_HDA = 29,
CLK_V_TZRAM = 30, // HIDDEN. CLK_V_TZRAM = 30,
CLK_V_SE = 31, // HIDDEN. CLK_V_SE = 31,
}; };
enum CLK_W_DEV enum CLK_W_DEV
{ {
CLK_W_HDA2HDMICODEC = 0, CLK_W_HDA2HDMICODEC = 0,
CLK_W_RESERVED0 = 1, //satacoldrstn CLK_W_SATACOLD = 1, // Enable reserved. Unused.
CLK_W_PCIERX0 = 2, CLK_W_PCIERX0 = 2, // Reset reserved.
CLK_W_PCIERX1 = 3, CLK_W_PCIERX1 = 3, // Reset reserved.
CLK_W_PCIERX2 = 4, CLK_W_PCIERX2 = 4, // Reset reserved.
CLK_W_PCIERX3 = 5, CLK_W_PCIERX3 = 5, // Reset reserved.
CLK_W_PCIERX4 = 6, CLK_W_PCIERX4 = 6, // Reset reserved.
CLK_W_PCIERX5 = 7, CLK_W_PCIERX5 = 7, // Reset reserved.
CLK_W_CEC = 8, CLK_W_CEC = 8,
CLK_W_PCIE2_IOBIST = 9, CLK_W_PCIE2_IOBIST = 9, // Reset reserved.
CLK_W_EMC_IOBIST = 10, CLK_W_EMC_IOBIST = 10, // Reset reserved.
CLK_W_HDMI_IOBIST = 11, // HIDDEN. CLK_W_SATA_IOBIST = 12, // Reset reserved.
CLK_W_SATA_IOBIST = 12, CLK_W_MIPI_IOBIST = 13, // Reset reserved.
CLK_W_MIPI_IOBIST = 13,
CLK_W_XUSB_PADCTL = 14, // Only reset. CLK_W_XUSB_PADCTL = 14, // Only reset.
CLK_W_XUSB = 15, CLK_W_XUSB = 15, // Only enable.
CLK_W_CILAB = 16, CLK_W_CILAB = 16, // Only enable.
CLK_W_CILCD = 17, CLK_W_CILCD = 17, // Only enable.
CLK_W_CILEF = 18, CLK_W_CILEF = 18, // Only enable.
CLK_W_DSIA_LP = 19, CLK_W_DSIA_LP = 19, // Only enable.
CLK_W_DSIB_LP = 20, CLK_W_DSIB_LP = 20, // Only enable.
CLK_W_ENTROPY = 21, CLK_W_ENTROPY = 21,
CLK_W_DDS = 22, // HIDDEN.
//CLK_W_ = 23,
CLK_W_DP2 = 24, // HIDDEN. CLK_W_DP2 = 24, // HIDDEN.
CLK_W_AMX0 = 25, // HIDDEN.
CLK_W_ADX0 = 26, // HIDDEN.
CLK_W_DVFS = 27, CLK_W_DVFS = 27,
CLK_W_XUSB_SS = 28, CLK_W_XUSB_SS = 28,
CLK_W_EMC_LATENCY = 29, CLK_W_EMC_LATENCY = 29, // Only enable.
CLK_W_MC1 = 30, CLK_W_MC1 = 30, // Only enable.
//CLK_W_ = 31,
}; };
enum CLK_X_DEV enum CLK_X_DEV
{ {
CLK_X_SPARE = 0, CLK_X_SPARE = 0,
CLK_X_DMIC1 = 1, CLK_X_DMIC1 = 1, // Only enable.
CLK_X_DMIC2 = 2, CLK_X_DMIC2 = 2, // Only enable.
CLK_X_ETR = 3, CLK_X_ETR = 3, // DFD.
CLK_X_CAM_MCLK = 4, CLK_X_CAM_MCLK = 4, // Only enable.
CLK_X_CAM_MCLK2 = 5, CLK_X_CAM_MCLK2 = 5, // Only enable.
CLK_X_I2C6 = 6, CLK_X_I2C6 = 6,
CLK_X_MC_CAPA = 7, // MC DAISY CHAIN1 CLK_X_MC_CAPA = 7, // MC Clients daisy chain 1. Only enable.
CLK_X_MC_CBPA = 8, // MC DAISY CHAIN2 CLK_X_MC_CBPA = 8, // MC Clients daisy chain 2. Only enable.
CLK_X_MC_CPU = 9, CLK_X_MC_CPU = 9, // MC CPU. Only enable.
CLK_X_MC_BBC = 10, CLK_X_MC_BBC = 10, // MC Backbone. Only enable.
CLK_X_VIM2_CLK = 11, CLK_X_VIM2_CLK = 11, // Only enable.
//CLK_X_ = 12, CLK_X_MIPIBIF = 13,
CLK_X_MIPIBIF = 13, //RESERVED CLK_X_EMC_DLL = 14, // Only enable.
CLK_X_EMC_DLL = 14, CLK_X_UART_FST_MIPI_CAL = 17, // Only enable.
//CLK_X_ = 15,
CLK_X_HDMI_AUDIO = 16, // HIDDEN.
CLK_X_UART_FST_MIPI_CAL = 17,
CLK_X_VIC = 18, CLK_X_VIC = 18,
//CLK_X_ = 19,
CLK_X_ADX1 = 20, // HIDDEN.
CLK_X_DPAUX = 21, CLK_X_DPAUX = 21,
CLK_X_SOR0 = 22, CLK_X_SOR0 = 22,
CLK_X_SOR1 = 23, CLK_X_SOR1 = 23,
CLK_X_GPU = 24, CLK_X_GPU = 24,
CLK_X_DBGAPB = 25, CLK_X_DBGAPB = 25, // Only enable.
CLK_X_HPLL_ADSP = 26, CLK_X_HPLL_ADSP = 26, // Only enable.
CLK_X_PLLP_ADSP = 27, CLK_X_PLLP_ADSP = 27, // Only enable.
CLK_X_PLLA_ADSP = 28, CLK_X_PLLA_ADSP = 28, // Only enable.
CLK_X_PLLG_REF = 29, CLK_X_PLLG_REF = 29, // Only enable.
//CLK_X_ = 30, CLK_X_EQOS = 30, // T210B01 only.
//CLK_X_ = 31,
}; };
enum CLK_Y_DEV enum CLK_Y_DEV
{ {
CLK_Y_SPARE1 = 0, CLK_Y_SPARE1 = 0,
CLK_Y_SDMMC_LEGACY_TM = 1, CLK_Y_SDMMC_LEGACY_TM = 1, // Only enable.
CLK_Y_NVDEC = 2, CLK_Y_NVDEC = 2,
CLK_Y_NVJPG = 3, CLK_Y_NVJPG = 3,
CLK_Y_AXIAP = 4, CLK_Y_AXIAP = 4, // DFD.
CLK_Y_DMIC3 = 5, CLK_Y_DMIC3 = 5, // Only enable.
CLK_Y_APE = 6, CLK_Y_APE = 6,
CLK_Y_ADSP = 7, CLK_Y_ADSP = 7,
CLK_Y_MC_CDPA = 8, // MC DAISY CHAIN4 CLK_Y_MC_CDPA = 8, // MC Clients daisy chain 4. Only enable.
CLK_Y_MC_CCPA = 9, // MC DAISY CHAIN3 CLK_Y_MC_CCPA = 9, // MC Clients daisy chain 3. Only enable.
CLK_Y_MAUD = 10, CLK_Y_MAUD = 10, // Only enable.
//CLK_Y_ = 11,
CLK_Y_SATA_USB_UPHY = 12, // Only reset. CLK_Y_SATA_USB_UPHY = 12, // Only reset.
CLK_Y_PEX_USB_UPHY = 13, // Only reset. CLK_Y_PEX_USB_UPHY = 13, // Only reset.
CLK_Y_TSECB = 14, CLK_Y_TSECB = 14,
CLK_Y_DPAUX1 = 15, CLK_Y_DPAUX1 = 15,
CLK_Y_VI_I2C = 16, CLK_Y_VI_I2C = 16,
CLK_Y_HSIC_TRK = 17, CLK_Y_HSIC_TRK = 17, // Only enable.
CLK_Y_USB2_TRK = 18, CLK_Y_USB2_TRK = 18, // Only enable.
CLK_Y_QSPI = 19, CLK_Y_QSPI = 19,
CLK_Y_UARTAPE = 20, CLK_Y_UARTAPE = 20, // Only enable.
CLK_Y_ADSPINTF = 21, // Only reset. CLK_Y_ADSPINTF = 21, // Only reset.
CLK_Y_ADSPPERIPH = 22, // Only reset. CLK_Y_ADSPPERIPH = 22, // Only reset.
CLK_Y_ADSPDBG = 23, // Only reset. CLK_Y_ADSPDBG = 23, // Only reset.
@@ -618,14 +665,14 @@ enum CLK_Y_DEV
CLK_Y_ADSPSCU = 25, // Only reset. CLK_Y_ADSPSCU = 25, // Only reset.
CLK_Y_ADSPNEON = 26, CLK_Y_ADSPNEON = 26,
CLK_Y_NVENC = 27, CLK_Y_NVENC = 27,
CLK_Y_IQC2 = 28, CLK_Y_IQC2 = 28, // Only enable. (Audio.)
CLK_Y_IQC1 = 29, CLK_Y_IQC1 = 29, // Only enable. (Audio.)
CLK_Y_SOR_SAFE = 30, CLK_Y_SOR_SAFE = 30, // Only enable.
CLK_Y_PLLP_OUT_CPU = 31, CLK_Y_PLLP_OUT_CPU = 31, // Only enable.
}; };
/*! Generic clock descriptor. */ /*! Generic clock descriptor. */
typedef struct _clock_t typedef struct _clk_rst_t
{ {
u16 reset; u16 reset;
u16 enable; u16 enable;
@@ -633,11 +680,11 @@ typedef struct _clock_t
u8 index; u8 index;
u8 clk_src; u8 clk_src;
u8 clk_div; u8 clk_div;
} clock_t; } clk_rst_t;
/*! Generic clock enable/disable. */ /*! Generic clock enable/disable. */
void clock_enable(const clock_t *clk); void clock_enable(const clk_rst_t *clk);
void clock_disable(const clock_t *clk); void clock_disable(const clk_rst_t *clk);
/*! Clock control for specific hardware portions. */ /*! Clock control for specific hardware portions. */
void clock_enable_fuse(bool enable); void clock_enable_fuse(bool enable);
@@ -691,10 +738,10 @@ void clock_enable_pllu();
void clock_disable_pllu(); void clock_disable_pllu();
void clock_enable_utmipll(); void clock_enable_utmipll();
void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val); void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 clock);
void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type); void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type);
int clock_sdmmc_is_not_reset_and_enabled(u32 id); int clock_sdmmc_is_not_reset_and_enabled(u32 id);
void clock_sdmmc_enable(u32 id, u32 val); void clock_sdmmc_enable(u32 id, u32 clock);
void clock_sdmmc_disable(u32 id); void clock_sdmmc_disable(u32 id);
u32 clock_get_osc_freq(); u32 clock_get_osc_freq();

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 shuffle2 * Copyright (c) 2018 shuffle2
* Copyright (c) 2018 balika011 * Copyright (c) 2018 balika011
* Copyright (c) 2019-2022 CTCaer * Copyright (c) 2019-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -22,9 +22,12 @@
#include <mem/heap.h> #include <mem/heap.h>
#include <sec/se.h> #include <sec/se.h>
#include <sec/se_t210.h> #include <sec/se_t210.h>
#include <soc/clock.h>
#include <soc/fuse.h> #include <soc/fuse.h>
#include <soc/hw_init.h> #include <soc/hw_init.h>
#include <soc/pmc.h>
#include <soc/t210.h> #include <soc/t210.h>
#include <soc/timer.h>
#include <utils/types.h> #include <utils/types.h>
static const u32 evp_thunk_template[] = { static const u32 evp_thunk_template[] = {
@@ -102,7 +105,7 @@ u32 fuse_read_dramid(bool raw_id)
if (tegra_t210) if (tegra_t210)
{ {
if (dramid > 6) if (dramid > 7)
dramid = 0; dramid = 0;
} }
else else
@@ -167,17 +170,34 @@ int fuse_set_sbk()
void fuse_wait_idle() void fuse_wait_idle()
{ {
u32 ctrl; while (((FUSE(FUSE_CTRL) >> 16) & 0x1F) != FUSE_STATUS_IDLE)
do ;
{ }
ctrl = FUSE(FUSE_CTRL);
} while (((ctrl >> 16) & 0x1f) != 4); void fuse_sense()
{
clock_enable_fuse(false);
FUSE(FUSE_CTRL) = (FUSE(FUSE_CTRL) & (~FUSE_CMD_MASK)) | FUSE_SENSE;
usleep(1);
fuse_wait_idle();
FUSE(FUSE_PRIV2INTFC) = FUSE_PRIV2INTFC_SKIP_RECORDS | FUSE_PRIV2INTFC_START_DATA;
usleep(1);
while (!(FUSE(FUSE_CTRL) & BIT(30)) || ((FUSE(FUSE_CTRL) >> 16) & 0x1F) != FUSE_STATUS_IDLE)
;
clock_enable_fuse(true);
} }
u32 fuse_read(u32 addr) u32 fuse_read(u32 addr)
{ {
FUSE(FUSE_ADDR) = addr; FUSE(FUSE_ADDR) = addr;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ; FUSE(FUSE_CTRL) = (FUSE(FUSE_CTRL) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle(); fuse_wait_idle();
return FUSE(FUSE_RDATA); return FUSE(FUSE_RDATA);
@@ -186,13 +206,13 @@ u32 fuse_read(u32 addr)
void fuse_read_array(u32 *words) void fuse_read_array(u32 *words)
{ {
u32 array_size = (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) ? u32 array_size = (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) ?
FUSE_ARRAY_WORDS_NUM_T210B01 : FUSE_ARRAY_WORDS_NUM; FUSE_ARRAY_WORDS_NUM_B01 : FUSE_ARRAY_WORDS_NUM;
for (u32 i = 0; i < array_size; i++) for (u32 i = 0; i < array_size; i++)
words[i] = fuse_read(i); 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]; u32 acc = words[0];
for (u32 i = 1; i < count; i++) for (u32 i = 1; i < count; i++)
@@ -306,7 +326,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
u32 words[80]; u32 words[80];
u32 word_count; u32 word_count;
u32 word_addr; u32 word_addr;
u32 word0 = 0; u32 word0;
u32 total_read = 0; u32 total_read = 0;
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
@@ -325,9 +345,9 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
// Parse extra T210B01 fuses when the difference is reached. // Parse extra T210B01 fuses when the difference is reached.
if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 && if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 &&
word_addr == ((FUSE_ARRAY_WORDS_NUM - 1) - word_addr == ((FUSE_ARRAY_WORDS_NUM - 1) -
(FUSE_ARRAY_WORDS_NUM_T210B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32))) (FUSE_ARRAY_WORDS_NUM_B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32)))
{ {
word_addr = FUSE_ARRAY_WORDS_NUM_T210B01 - 1; word_addr = FUSE_ARRAY_WORDS_NUM_B01 - 1;
} }
} }
@@ -366,7 +386,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
u32 words[80]; u32 words[80];
u32 word_count; u32 word_count;
u32 word_addr; u32 word_addr;
u32 word0 = 0; u32 word0;
u32 total_read = 0; u32 total_read = 0;
int evp_thunk_written = 0; int evp_thunk_written = 0;
void *evp_thunk_dst_addr = 0; void *evp_thunk_dst_addr = 0;
@@ -395,9 +415,9 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
// Parse extra T210B01 fuses when the difference is reached. // Parse extra T210B01 fuses when the difference is reached.
if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 && if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 &&
word_addr == ((FUSE_ARRAY_WORDS_NUM - 1) - word_addr == ((FUSE_ARRAY_WORDS_NUM - 1) -
(FUSE_ARRAY_WORDS_NUM_T210B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32))) (FUSE_ARRAY_WORDS_NUM_B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32)))
{ {
word_addr = FUSE_ARRAY_WORDS_NUM_T210B01 - 1; word_addr = FUSE_ARRAY_WORDS_NUM_B01 - 1;
} }
} }

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 shuffle2 * Copyright (c) 2018 shuffle2
* Copyright (c) 2018 balika011 * Copyright (c) 2018 balika011
* Copyright (c) 2019-2022 CTCaer * Copyright (c) 2019-2025 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -23,67 +23,276 @@
#include <utils/types.h> #include <utils/types.h>
/*! Fuse registers. */ /*! Fuse registers. */
#define FUSE_CTRL 0x0 #define FUSE_CTRL 0x0
#define FUSE_ADDR 0x4 #define FUSE_ADDR 0x4
#define FUSE_RDATA 0x8 #define FUSE_RDATA 0x8
#define FUSE_WDATA 0xC #define FUSE_WDATA 0xC
#define FUSE_TIME_RD1 0x10 #define FUSE_TIME_RD1 0x10
#define FUSE_TIME_RD2 0x14 #define FUSE_TIME_RD2 0x14
#define FUSE_TIME_PGM1 0x18 #define FUSE_TIME_PGM1 0x18
#define FUSE_TIME_PGM2 0x1C #define FUSE_TIME_PGM2 0x1C
#define FUSE_PRIV2INTFC 0x20 #define FUSE_PRIV2INTFC 0x20
#define FUSE_FUSEBYPASS 0x24 #define FUSE_PRIV2INTFC_START_DATA BIT(0)
#define FUSE_PRIVATEKEYDISABLE 0x28 #define FUSE_PRIV2INTFC_SKIP_RECORDS BIT(1)
#define FUSE_DISABLEREGPROGRAM 0x2C #define FUSE_FUSEBYPASS 0x24
#define FUSE_WRITE_ACCESS_SW 0x30 #define FUSE_PRIVATEKEYDISABLE 0x28
#define FUSE_PWR_GOOD_SW 0x34 #define FUSE_PRIVKEY_DISABLE BIT(0)
#define FUSE_PRIVKEY_TZ_STICKY_BIT BIT(4)
#define FUSE_DISABLEREGPROGRAM 0x2C
#define FUSE_WRITE_ACCESS_SW 0x30
#define FUSE_PWR_GOOD_SW 0x34
#define FUSE_PRIV2RESHIFT 0x3C
#define FUSE_FUSETIME_RD0 0x40
#define FUSE_FUSETIME_RD1 0x44
#define FUSE_FUSETIME_RD2 0x48
#define FUSE_FUSETIME_RD3 0x4C
#define FUSE_PRIVATE_KEY0_NONZERO 0x80
#define FUSE_PRIVATE_KEY1_NONZERO 0x84
#define FUSE_PRIVATE_KEY2_NONZERO 0x88
#define FUSE_PRIVATE_KEY3_NONZERO 0x8C
#define FUSE_PRIVATE_KEY4_NONZERO 0x90
/*! Fuse Cached registers */ /*! Fuse Cached registers */
#define FUSE_SKU_INFO 0x110 #define FUSE_RESERVED_ODM8_B01 0x98
#define FUSE_CPU_SPEEDO_0_CALIB 0x114 #define FUSE_RESERVED_ODM9_B01 0x9C
#define FUSE_CPU_IDDQ_CALIB 0x118 #define FUSE_RESERVED_ODM10_B01 0xA0
#define FUSE_OPT_FT_REV 0x128 #define FUSE_RESERVED_ODM11_B01 0xA4
#define FUSE_CPU_SPEEDO_1_CALIB 0x12C #define FUSE_RESERVED_ODM12_B01 0xA8
#define FUSE_CPU_SPEEDO_2_CALIB 0x130 #define FUSE_RESERVED_ODM13_B01 0xAC
#define FUSE_SOC_SPEEDO_0_CALIB 0x134 #define FUSE_RESERVED_ODM14_B01 0xB0
#define FUSE_SOC_SPEEDO_1_CALIB 0x138 #define FUSE_RESERVED_ODM15_B01 0xB4
#define FUSE_SOC_SPEEDO_2_CALIB 0x13C #define FUSE_RESERVED_ODM16_B01 0xB8
#define FUSE_SOC_IDDQ_CALIB 0x140 #define FUSE_RESERVED_ODM17_B01 0xBC
#define FUSE_OPT_CP_REV 0x190 #define FUSE_RESERVED_ODM18_B01 0xC0
#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c #define FUSE_RESERVED_ODM19_B01 0xC4
#define FUSE_PRIVATE_KEY0 0x1A4 #define FUSE_RESERVED_ODM20_B01 0xC8
#define FUSE_PRIVATE_KEY1 0x1A8 #define FUSE_RESERVED_ODM21_B01 0xCC
#define FUSE_PRIVATE_KEY2 0x1AC #define FUSE_KEK00_B01 0xD0
#define FUSE_PRIVATE_KEY3 0x1B0 #define FUSE_KEK01_B01 0xD4
#define FUSE_PRIVATE_KEY4 0x1B4 #define FUSE_KEK02_B01 0xD8
#define FUSE_RESERVED_SW 0x1C0 #define FUSE_KEK03_B01 0xDC
#define FUSE_USB_CALIB 0x1F0 #define FUSE_BEK00_B01 0xE0
#define FUSE_SKU_DIRECT_CONFIG 0x1F4 #define FUSE_BEK01_B01 0xE4
#define FUSE_OPT_VENDOR_CODE 0x200 #define FUSE_BEK02_B01 0xE8
#define FUSE_OPT_FAB_CODE 0x204 #define FUSE_BEK03_B01 0xEC
#define FUSE_OPT_LOT_CODE_0 0x208 #define FUSE_OPT_RAM_RTSEL_TSMCSP_PO4SVT_B01 0xF0
#define FUSE_OPT_LOT_CODE_1 0x20C #define FUSE_OPT_RAM_WTSEL_TSMCSP_PO4SVT_B01 0xF4
#define FUSE_OPT_WAFER_ID 0x210 #define FUSE_OPT_RAM_RTSEL_TSMCPDP_PO4SVT_B01 0xF8
#define FUSE_OPT_X_COORDINATE 0x214 #define FUSE_OPT_RAM_MTSEL_TSMCPDP_PO4SVT_B01 0xFC
#define FUSE_OPT_Y_COORDINATE 0x218
#define FUSE_OPT_OPS_RESERVED 0x220
#define FUSE_GPU_IDDQ_CALIB 0x228
#define FUSE_USB_CALIB_EXT 0x350
#define FUSE_RESERVED_FIELD 0x354
#define FUSE_RESERVED_ODM28_T210B01 0x240 #define FUSE_PRODUCTION_MODE 0x100
#define FUSE_JTAG_SECUREID_VALID 0x104
#define FUSE_ODM_LOCK 0x108
#define FUSE_OPT_OPENGL_EN 0x10C
#define FUSE_SKU_INFO 0x110
#define FUSE_CPU_SPEEDO_0_CALIB 0x114
#define FUSE_CPU_IDDQ_CALIB 0x118
#define FUSE_RESERVED_ODM22_B01 0x11C
#define FUSE_RESERVED_ODM23_B01 0x120
#define FUSE_RESERVED_ODM24_B01 0x124
#define FUSE_OPT_FT_REV 0x128
#define FUSE_CPU_SPEEDO_1_CALIB 0x12C
#define FUSE_CPU_SPEEDO_2_CALIB 0x130
#define FUSE_SOC_SPEEDO_0_CALIB 0x134
#define FUSE_SOC_SPEEDO_1_CALIB 0x138
#define FUSE_SOC_SPEEDO_2_CALIB 0x13C
#define FUSE_SOC_IDDQ_CALIB 0x140
#define FUSE_RESERVED_ODM25_B01 0x144
#define FUSE_FA 0x148
#define FUSE_RESERVED_PRODUCTION 0x14C
#define FUSE_HDMI_LANE0_CALIB 0x150
#define FUSE_HDMI_LANE1_CALIB 0x154
#define FUSE_HDMI_LANE2_CALIB 0x158
#define FUSE_HDMI_LANE3_CALIB 0x15C
#define FUSE_ENCRYPTION_RATE 0x160
#define FUSE_PUBLIC_KEY0 0x164
#define FUSE_PUBLIC_KEY1 0x168
#define FUSE_PUBLIC_KEY2 0x16C
#define FUSE_PUBLIC_KEY3 0x170
#define FUSE_PUBLIC_KEY4 0x174
#define FUSE_PUBLIC_KEY5 0x178
#define FUSE_PUBLIC_KEY6 0x17C
#define FUSE_PUBLIC_KEY7 0x180
#define FUSE_TSENSOR1_CALIB 0x184 // CPU1.
#define FUSE_TSENSOR2_CALIB 0x188 // CPU2.
#define FUSE_OPT_SECURE_SCC_DIS_B01 0x18C
#define FUSE_OPT_CP_REV 0x190 // FUSE style revision - ATE. 0x101 0x100
#define FUSE_OPT_PFG 0x194
#define FUSE_TSENSOR0_CALIB 0x198 // CPU0.
#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19C
#define FUSE_SECURITY_MODE 0x1A0
#define FUSE_PRIVATE_KEY0 0x1A4
#define FUSE_PRIVATE_KEY1 0x1A8
#define FUSE_PRIVATE_KEY2 0x1AC
#define FUSE_PRIVATE_KEY3 0x1B0
#define FUSE_PRIVATE_KEY4 0x1B4
#define FUSE_ARM_JTAG_DIS 0x1B8
#define FUSE_BOOT_DEVICE_INFO 0x1BC
#define FUSE_RESERVED_SW 0x1C0
#define FUSE_OPT_VP9_DISABLE 0x1C4
#define FUSE_RESERVED_ODM0 0x1C8
#define FUSE_RESERVED_ODM1 0x1CC
#define FUSE_RESERVED_ODM2 0x1D0
#define FUSE_RESERVED_ODM3 0x1D4
#define FUSE_RESERVED_ODM4 0x1D8
#define FUSE_RESERVED_ODM5 0x1DC
#define FUSE_RESERVED_ODM6 0x1E0
#define FUSE_RESERVED_ODM7 0x1E4
#define FUSE_OBS_DIS 0x1E8
#define FUSE_OPT_NVJTAG_PROTECTION_ENABLE_B01 0x1EC
#define FUSE_USB_CALIB 0x1F0
#define FUSE_SKU_DIRECT_CONFIG 0x1F4
#define FUSE_KFUSE_PRIVKEY_CTRL 0x1F8
#define FUSE_PACKAGE_INFO 0x1FC
#define FUSE_OPT_VENDOR_CODE 0x200
#define FUSE_OPT_FAB_CODE 0x204
#define FUSE_OPT_LOT_CODE_0 0x208
#define FUSE_OPT_LOT_CODE_1 0x20C
#define FUSE_OPT_WAFER_ID 0x210
#define FUSE_OPT_X_COORDINATE 0x214
#define FUSE_OPT_Y_COORDINATE 0x218
#define FUSE_OPT_SEC_DEBUG_EN 0x21C
#define FUSE_OPT_OPS_RESERVED 0x220
#define FUSE_SATA_CALIB 0x224
#define FUSE_SPARE_REGISTER_ODM_B01 0x224
#define FUSE_GPU_IDDQ_CALIB 0x228
#define FUSE_TSENSOR3_CALIB 0x22C // CPU3.
#define FUSE_CLOCK_BONDOUT0 0x230
#define FUSE_CLOCK_BONDOUT1 0x234
#define FUSE_RESERVED_ODM26_B01 0x238
#define FUSE_RESERVED_ODM27_B01 0x23C
#define FUSE_RESERVED_ODM28_B01 0x240 // MAX77812 phase configuration.
#define FUSE_OPT_SAMPLE_TYPE 0x244
#define FUSE_OPT_SUBREVISION 0x248 // "", "p", "q", "r". e.g: A01p.
#define FUSE_OPT_SW_RESERVED_0 0x24C
#define FUSE_OPT_SW_RESERVED_1 0x250
#define FUSE_TSENSOR4_CALIB 0x254 // GPU.
#define FUSE_TSENSOR5_CALIB 0x258 // MEM0.
#define FUSE_TSENSOR6_CALIB 0x25C // MEM1.
#define FUSE_TSENSOR7_CALIB 0x260 // PLLX.
#define FUSE_OPT_PRIV_SEC_DIS 0x264
#define FUSE_PKC_DISABLE 0x268
#define FUSE_BOOT_SECURITY_INFO_B01 0x268
#define FUSE_OPT_RAM_RTSEL_TSMCSP_PO4HVT_B01 0x26C
#define FUSE_OPT_RAM_WTSEL_TSMCSP_PO4HVT_B01 0x270
#define FUSE_OPT_RAM_RTSEL_TSMCPDP_PO4HVT_B01 0x274
#define FUSE_OPT_RAM_MTSEL_TSMCPDP_PO4HVT_B01 0x278
#define FUSE_FUSE2TSEC_DEBUG_DISABLE 0x27C
#define FUSE_TSENSOR_COMMON 0x280
#define FUSE_OPT_CP_BIN 0x284
#define FUSE_OPT_GPU_DISABLE 0x288
#define FUSE_OPT_FT_BIN 0x28C
#define FUSE_OPT_DONE_MAP 0x290
#define FUSE_RESERVED_ODM29_B01 0x294
#define FUSE_APB2JTAG_DISABLE 0x298
#define FUSE_ODM_INFO 0x29C // Debug features disable.
#define FUSE_ARM_CRYPT_DE_FEATURE 0x2A8
#define FUSE_OPT_RAM_WTSEL_TSMCPDP_PO4SVT_B01 0x2B0
#define FUSE_OPT_RAM_RCT_TSMCDP_PO4SVT_B01 0x2B4
#define FUSE_OPT_RAM_WCT_TSMCDP_PO4SVT_B01 0x2B8
#define FUSE_OPT_RAM_KP_TSMCDP_PO4SVT_B01 0x2BC
#define FUSE_WOA_SKU_FLAG 0x2C0
#define FUSE_ECO_RESERVE_1 0x2C4
#define FUSE_GCPLEX_CONFIG_FUSE 0x2C8
#define FUSE_GPU_VPR_AUTO_FETCH_DIS BIT(0)
#define FUSE_GPU_VPR_ENABLED BIT(1)
#define FUSE_GPU_WPR_ENABLED BIT(2)
#define FUSE_PRODUCTION_MONTH 0x2CC
#define FUSE_RAM_REPAIR_INDICATOR 0x2D0
#define FUSE_TSENSOR9_CALIB 0x2D4 // AOTAG.
#define FUSE_VMIN_CALIBRATION 0x2DC
#define FUSE_AGING_SENSOR_CALIBRATION 0x2E0
#define FUSE_DEBUG_AUTHENTICATION 0x2E4
#define FUSE_SECURE_PROVISION_INDEX 0x2E8
#define FUSE_SECURE_PROVISION_INFO 0x2EC
#define FUSE_OPT_GPU_DISABLE_CP1 0x2F0
#define FUSE_SPARE_ENDIS 0x2F4
#define FUSE_ECO_RESERVE_0 0x2F8 // AID.
#define FUSE_RESERVED_CALIB0 0x304 // GPCPLL ADC Calibration.
#define FUSE_RESERVED_CALIB1 0x308
#define FUSE_OPT_GPU_TPC0_DISABLE 0x30C
#define FUSE_OPT_GPU_TPC0_DISABLE_CP1 0x310
#define FUSE_OPT_CPU_DISABLE 0x314
#define FUSE_OPT_CPU_DISABLE_CP1 0x318
#define FUSE_TSENSOR10_CALIB 0x31C
#define FUSE_TSENSOR10_CALIB_AUX 0x320
#define FUSE_OPT_RAM_SVOP_DP 0x324
#define FUSE_OPT_RAM_SVOP_PDP 0x328
#define FUSE_OPT_RAM_SVOP_REG 0x32C
#define FUSE_OPT_RAM_SVOP_SP 0x330
#define FUSE_OPT_RAM_SVOP_SMPDP 0x334
#define FUSE_OPT_RAM_WTSEL_TSMCPDP_PO4HVT_B01 0x324
#define FUSE_OPT_RAM_RCT_TSMCDP_PO4HVT_B01 0x328
#define FUSE_OPT_RAM_WCT_TSMCDP_PO4HVT_B01 0x32c
#define FUSE_OPT_RAM_KP_TSMCDP_PO4HVT_B01 0x330
#define FUSE_OPT_RAM_SVOP_SP_B01 0x334
#define FUSE_OPT_GPU_TPC0_DISABLE_CP2 0x338
#define FUSE_OPT_GPU_TPC1_DISABLE 0x33C
#define FUSE_OPT_GPU_TPC1_DISABLE_CP1 0x340
#define FUSE_OPT_GPU_TPC1_DISABLE_CP2 0x344
#define FUSE_OPT_CPU_DISABLE_CP2 0x348
#define FUSE_OPT_GPU_DISABLE_CP2 0x34C
#define FUSE_USB_CALIB_EXT 0x350
#define FUSE_RESERVED_FIELD 0x354 // RMA.
#define FUSE_SPARE_REALIGNMENT_REG 0x37C
#define FUSE_SPARE_BIT_0 0x380
//...
#define FUSE_SPARE_BIT_31 0x3FC
/*! Fuse commands. */ /*! Fuse commands. */
#define FUSE_READ 0x1 #define FUSE_IDLE 0x0
#define FUSE_WRITE 0x2 #define FUSE_READ 0x1
#define FUSE_SENSE 0x3 #define FUSE_WRITE 0x2
#define FUSE_SENSE 0x3
#define FUSE_CMD_MASK 0x3 #define FUSE_CMD_MASK 0x3
/*! Fuse status. */
#define FUSE_STATUS_RESET 0
#define FUSE_STATUS_POST_RESET 1
#define FUSE_STATUS_LOAD_ROW0 2
#define FUSE_STATUS_LOAD_ROW1 3
#define FUSE_STATUS_IDLE 4
#define FUSE_STATUS_READ_SETUP 5
#define FUSE_STATUS_READ_STROBE 6
#define FUSE_STATUS_SAMPLE_FUSES 7
#define FUSE_STATUS_READ_HOLD 8
#define FUSE_STATUS_FUSE_SRC_SETUP 9
#define FUSE_STATUS_WRITE_SETUP 10
#define FUSE_STATUS_WRITE_ADDR_SETUP 11
#define FUSE_STATUS_WRITE_PROGRAM 12
#define FUSE_STATUS_WRITE_ADDR_HOLD 13
#define FUSE_STATUS_FUSE_SRC_HOLD 14
#define FUSE_STATUS_LOAD_RIR 15
#define FUSE_STATUS_READ_BEFORE_WRITE_SETUP 16
#define FUSE_STATUS_READ_DEASSERT_PD 17
/*! Fuse cache registers. */ /*! Fuse cache registers. */
#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) #define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x))
#define FUSE_ARRAY_WORDS_NUM 192 #define FUSE_ARRAY_WORDS_NUM 192
#define FUSE_ARRAY_WORDS_NUM_T210B01 256 #define FUSE_ARRAY_WORDS_NUM_B01 256
enum enum
{ {
@@ -107,6 +316,8 @@ u32 fuse_read_hw_state();
u32 fuse_read_hw_type(); u32 fuse_read_hw_type();
int fuse_set_sbk(); int fuse_set_sbk();
void fuse_wait_idle(); void fuse_wait_idle();
void fuse_sense();
u32 fuse_read(u32 addr);
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);
void fuse_read_array(u32 *words); void fuse_read_array(u32 *words);

View File

@@ -18,23 +18,27 @@
#include <soc/gpio.h> #include <soc/gpio.h>
#include <soc/t210.h> #include <soc/t210.h>
#define GPIO_BANK_IDX(port) ((port) >> 2) #define GPIO_BANK_IDX(port) ((port) >> 2)
#define GPIO_PORT_OFFSET(port) ((GPIO_BANK_IDX(port) << 8) + (((port) % 4) << 2))
#define GPIO_CNF_OFFSET(port) (0x00 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_CNF_OFFSET(port) (0x00 + GPIO_PORT_OFFSET(port))
#define GPIO_OE_OFFSET(port) (0x10 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_OE_OFFSET(port) (0x10 + GPIO_PORT_OFFSET(port))
#define GPIO_OUT_OFFSET(port) (0x20 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_OUT_OFFSET(port) (0x20 + GPIO_PORT_OFFSET(port))
#define GPIO_IN_OFFSET(port) (0x30 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_IN_OFFSET(port) (0x30 + GPIO_PORT_OFFSET(port))
#define GPIO_INT_STA_OFFSET(port) (0x40 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_STA_OFFSET(port) (0x40 + GPIO_PORT_OFFSET(port))
#define GPIO_INT_ENB_OFFSET(port) (0x50 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_ENB_OFFSET(port) (0x50 + GPIO_PORT_OFFSET(port))
#define GPIO_INT_LVL_OFFSET(port) (0x60 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_LVL_OFFSET(port) (0x60 + GPIO_PORT_OFFSET(port))
#define GPIO_INT_CLR_OFFSET(port) (0x70 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_CLR_OFFSET(port) (0x70 + GPIO_PORT_OFFSET(port))
#define GPIO_CNF_MASKED_OFFSET(port) (0x80 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_CNF_MASKED_OFFSET(port) (0x80 + GPIO_PORT_OFFSET(port))
#define GPIO_OE_MASKED_OFFSET(port) (0x90 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_OE_MASKED_OFFSET(port) (0x90 + GPIO_PORT_OFFSET(port))
#define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + GPIO_PORT_OFFSET(port))
#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + GPIO_PORT_OFFSET(port))
#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + GPIO_PORT_OFFSET(port))
#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + GPIO_PORT_OFFSET(port))
#define GPIO_DB_CTRL_OFFSET(port) (0xB0 + GPIO_PORT_OFFSET(port))
#define GPIO_DB_CNT_OFFSET(port) (0xF0 + GPIO_PORT_OFFSET(port))
#define GPIO_IRQ_BANK1 32 #define GPIO_IRQ_BANK1 32
#define GPIO_IRQ_BANK2 33 #define GPIO_IRQ_BANK2 33
@@ -52,7 +56,7 @@ static u8 gpio_bank_irq_ids[8] = {
void gpio_config(u32 port, u32 pins, int mode) void gpio_config(u32 port, u32 pins, int mode)
{ {
u32 offset = GPIO_CNF_OFFSET(port); const u32 offset = GPIO_CNF_OFFSET(port);
if (mode) if (mode)
GPIO(offset) |= pins; GPIO(offset) |= pins;
@@ -64,7 +68,7 @@ void gpio_config(u32 port, u32 pins, int mode)
void gpio_output_enable(u32 port, u32 pins, int enable) void gpio_output_enable(u32 port, u32 pins, int enable)
{ {
u32 port_offset = GPIO_OE_OFFSET(port); const u32 port_offset = GPIO_OE_OFFSET(port);
if (enable) if (enable)
GPIO(port_offset) |= pins; GPIO(port_offset) |= pins;
@@ -76,7 +80,7 @@ void gpio_output_enable(u32 port, u32 pins, int enable)
void gpio_write(u32 port, u32 pins, int high) void gpio_write(u32 port, u32 pins, int high)
{ {
u32 port_offset = GPIO_OUT_OFFSET(port); const u32 port_offset = GPIO_OUT_OFFSET(port);
if (high) if (high)
GPIO(port_offset) |= pins; GPIO(port_offset) |= pins;
@@ -88,27 +92,47 @@ void gpio_write(u32 port, u32 pins, int high)
void gpio_direction_input(u32 port, u32 pins) void gpio_direction_input(u32 port, u32 pins)
{ {
gpio_output_enable(port, pins, GPIO_OUTPUT_DISABLE);
gpio_config(port, pins, GPIO_MODE_GPIO); gpio_config(port, pins, GPIO_MODE_GPIO);
gpio_output_enable(port, pins, GPIO_OUTPUT_DISABLE);
} }
void gpio_direction_output(u32 port, u32 pins, int high) void gpio_direction_output(u32 port, u32 pins, int high)
{ {
gpio_output_enable(port, pins, GPIO_OUTPUT_ENABLE);
gpio_config(port, pins, GPIO_MODE_GPIO); gpio_config(port, pins, GPIO_MODE_GPIO);
gpio_write(port, pins, high); gpio_write(port, pins, high);
gpio_output_enable(port, pins, GPIO_OUTPUT_ENABLE);
} }
int gpio_read(u32 port, u32 pins) int gpio_read(u32 port, u32 pins)
{ {
u32 port_offset = GPIO_IN_OFFSET(port); const u32 port_offset = GPIO_IN_OFFSET(port);
return (GPIO(port_offset) & pins) ? 1 : 0; return (GPIO(port_offset) & pins) ? 1 : 0;
} }
void gpio_set_debounce(u32 port, u32 pins, u32 ms)
{
const u32 db_ctrl_offset = GPIO_DB_CTRL_OFFSET(port);
const u32 db_cnt_offset = GPIO_DB_CNT_OFFSET(port);
if (ms)
{
if (ms > 255)
ms = 255;
// Debounce time affects all pins of the same port.
GPIO(db_cnt_offset) = ms;
GPIO(db_ctrl_offset) = (pins << 8) | pins;
}
else
GPIO(db_ctrl_offset) = (pins << 8) | 0;
(void)GPIO(db_ctrl_offset); // Commit the write.
}
static void _gpio_interrupt_clear(u32 port, u32 pins) static void _gpio_interrupt_clear(u32 port, u32 pins)
{ {
u32 port_offset = GPIO_INT_CLR_OFFSET(port); const u32 port_offset = GPIO_INT_CLR_OFFSET(port);
GPIO(port_offset) |= pins; GPIO(port_offset) |= pins;
@@ -117,10 +141,10 @@ static void _gpio_interrupt_clear(u32 port, u32 pins)
int gpio_interrupt_status(u32 port, u32 pins) int gpio_interrupt_status(u32 port, u32 pins)
{ {
u32 port_offset = GPIO_INT_STA_OFFSET(port); const u32 port_offset = GPIO_INT_STA_OFFSET(port);
u32 enabled = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins; const u32 enabled_mask = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins;
int status = ((GPIO(port_offset) & pins) && enabled) ? 1 : 0; int status = ((GPIO(port_offset) & pins) && enabled_mask) ? 1 : 0;
// Clear the interrupt status. // Clear the interrupt status.
if (status) if (status)
@@ -131,7 +155,7 @@ int gpio_interrupt_status(u32 port, u32 pins)
void gpio_interrupt_enable(u32 port, u32 pins, int enable) void gpio_interrupt_enable(u32 port, u32 pins, int enable)
{ {
u32 port_offset = GPIO_INT_ENB_OFFSET(port); const u32 port_offset = GPIO_INT_ENB_OFFSET(port);
// Clear any possible stray interrupt. // Clear any possible stray interrupt.
_gpio_interrupt_clear(port, pins); _gpio_interrupt_clear(port, pins);
@@ -146,7 +170,7 @@ void gpio_interrupt_enable(u32 port, u32 pins, int enable)
void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta) void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta)
{ {
u32 port_offset = GPIO_INT_LVL_OFFSET(port); const u32 port_offset = GPIO_INT_LVL_OFFSET(port);
u32 val = GPIO(port_offset); u32 val = GPIO(port_offset);
@@ -175,7 +199,7 @@ void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta)
u32 gpio_get_bank_irq_id(u32 port) u32 gpio_get_bank_irq_id(u32 port)
{ {
u32 bank_idx = GPIO_BANK_IDX(port); const u32 bank_idx = GPIO_BANK_IDX(port);
return gpio_bank_irq_ids[bank_idx]; return gpio_bank_irq_ids[bank_idx];
} }

View File

@@ -89,6 +89,7 @@ void gpio_direction_input(u32 port, u32 pins);
void gpio_direction_output(u32 port, u32 pins, int high); void gpio_direction_output(u32 port, u32 pins, int high);
void gpio_write(u32 port, u32 pins, int high); void gpio_write(u32 port, u32 pins, int high);
int gpio_read(u32 port, u32 pins); int gpio_read(u32 port, u32 pins);
void gpio_set_debounce(u32 port, u32 pins, u32 ms);
int gpio_interrupt_status(u32 port, u32 pins); int gpio_interrupt_status(u32 port, u32 pins);
void gpio_interrupt_enable(u32 port, u32 pins, int enable); void gpio_interrupt_enable(u32 port, u32 pins, int enable);
void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta); void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta);

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -77,15 +77,15 @@ static void _config_oscillators()
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength. CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength.
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength. PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength.
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER; PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER;
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN; PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN;
PMC(APB_MISC_GP_ASDBGREG) = (PMC(APB_MISC_GP_ASDBGREG) & 0xFCFFFFFF) | (2 << 24); // CFG2TMC_RAM_SVOP_PDP. APB_MISC(APB_MISC_GP_ASDBGREG) = (APB_MISC(APB_MISC_GP_ASDBGREG) & 0xFCFFFFFF) | (2 << 24); // CFG2TMC_RAM_SVOP_PDP.
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1. CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1.
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable. CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable.
PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; // 0x249F = 19200000 * (16 / 32.768 kHz).
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set BPMP/SCLK div to 1. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set BPMP/SCLK div to 1.
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set BPMP/SCLK source to Run and PLLP_OUT2 (204MHz). CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set BPMP/SCLK source to Run and PLLP_OUT2 (204MHz).
@@ -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. 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. // The uart is skipped for Copper, Hoag and Calcio. Used in Icosa, Iowa and Aula.
static void _config_gpios(bool nx_hoag) static void _config_gpios(bool nx_hoag)
{ {
@@ -137,16 +155,34 @@ static void _config_pmc_scratch()
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT; PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT;
} }
static void _mbist_workaround() static void _mbist_workaround_bl()
{ {
// Make sure Audio clocks are enabled before accessing I2S. /*
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); * DFT MBIST HW Errata for T210.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); * RAM Data corruption observed when MBIST_EN from DFT (Tegra X1 Si Errata)
*
* The MBIST_EN signals from the DFT logic can impact the functional logic of
* internal rams after power-on since they are driven by non-resetable flops.
* That can be worked around by enabling and then disabling the related clocks.
*
* The bootrom patches, already handle the LVL2 SLCG war by enabling all clocks
* and all LVL2 CLK overrides (power saving disable).
* The Bootloader then handles the IP block SLCG part and also restores the
* state for the clocks/lvl2 slcg.
* After these, per domain MBIST WAR is needed every time a domain gets
* unpowergated if it was previously powergated.
*
* Affected power domains: all except IRAM and CCPLEX.
*/
// Set mux output to SOR1 clock switch. // Set mux output to SOR1 clock switch (for VI).
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) & ~BIT(14)) | BIT(15);
// Enabled PLLD and set csi to PLLD for test pattern generation. // Enable PLLD and set csi to PLLD for test pattern generation (for VI).
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000; CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= PLL_BASE_ENABLE | BIT(23);
// Make sure Audio clocks are enabled before accessing I2S.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_AHUB);
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_APE);
// Clear per-clock resets for APE/VIC/HOST1X/DISP1. // Clear per-clock resets for APE/VIC/HOST1X/DISP1.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = BIT(CLK_Y_APE); CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = BIT(CLK_Y_APE);
@@ -154,78 +190,73 @@ static void _mbist_workaround()
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1);
usleep(2); usleep(2);
// I2S channels to master and disable SLCG. // Set I2S to master to enable clocks and set SLCG overrides.
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN; for (u32 i2s_idx = 0; i2s_idx < 5; i2s_idx++)
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE; {
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN; I2S(I2S_CTRL + (i2s_idx << 8u)) |= I2S_CTRL_MASTER_EN;
I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE; I2S(I2S_CG + (i2s_idx << 8u)) = I2S_CG_SLCG_DISABLE;
I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN; }
I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE; // Set SLCG overrides for DISPA and VIC.
I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN; DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= BIT(2); // DSC_SLCG_OVERRIDE.
I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE;
// Set SLCG overrides.
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE.
VIC(VIC_THI_SLCG_OVERRIDE_LOW_A) = 0xFFFFFFFF; VIC(VIC_THI_SLCG_OVERRIDE_LOW_A) = 0xFFFFFFFF;
// Wait a bit for MBIST_EN to get unstuck (1 cycle min).
usleep(2); usleep(2);
// Reset SLCG to automatic mode.
// for (u32 i2s_idx = 0; i2s_idx < 5; i2s_idx++)
// I2S(I2S_CG + (i2s_idx << 8u)) = I2S_CG_SLCG_ENABLE;
// DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) &= ~BIT(2); // DSC_SLCG_OVERRIDE.
// VIC(VIC_THI_SLCG_OVERRIDE_LOW_A) = 0;
// Set per-clock reset for APE/VIC/HOST1X/DISP1. // Set per-clock reset for APE/VIC/HOST1X/DISP1.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = BIT(CLK_Y_APE); CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = BIT(CLK_Y_APE);
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1);
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = BIT(CLK_X_VIC); CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = BIT(CLK_X_VIC);
// Enable specific clocks and disable all others. // Disable all unneeded clocks that were enabled in bootrom.
// CLK L Devices. // CLK L Devices.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = BIT(CLK_H_PMC) |
BIT(CLK_H_PMC) | BIT(CLK_H_FUSE);
BIT(CLK_H_FUSE);
// CLK H Devices. // CLK H Devices.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = BIT(CLK_L_RTC) |
BIT(CLK_L_RTC) | BIT(CLK_L_TMR) |
BIT(CLK_L_TMR) | BIT(CLK_L_GPIO) |
BIT(CLK_L_GPIO) | BIT(CLK_L_BPMP_CACHE_CTRL);
BIT(CLK_L_BPMP_CACHE_CTRL);
// CLK U Devices. // CLK U Devices.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = BIT(CLK_U_CSITE) |
BIT(CLK_U_CSITE) | BIT(CLK_U_IRAMA) |
BIT(CLK_U_IRAMA) | BIT(CLK_U_IRAMB) |
BIT(CLK_U_IRAMB) | BIT(CLK_U_IRAMC) |
BIT(CLK_U_IRAMC) | BIT(CLK_U_IRAMD) |
BIT(CLK_U_IRAMD) | BIT(CLK_U_BPMP_CACHE_RAM);
BIT(CLK_U_BPMP_CACHE_RAM);
// CLK V Devices. // CLK V Devices.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = BIT(CLK_V_MSELECT) |
BIT(CLK_V_MSELECT) | BIT(CLK_V_APB2APE) |
BIT(CLK_V_APB2APE) | BIT(CLK_V_SPDIF_DOUBLER) |
BIT(CLK_V_SPDIF_DOUBLER) | BIT(CLK_V_SE);
BIT(CLK_V_SE);
// CLK W Devices. // CLK W Devices.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = BIT(CLK_W_PCIERX0) |
BIT(CLK_W_PCIERX0) | BIT(CLK_W_PCIERX1) |
BIT(CLK_W_PCIERX1) | BIT(CLK_W_PCIERX2) |
BIT(CLK_W_PCIERX2) | BIT(CLK_W_PCIERX3) |
BIT(CLK_W_PCIERX3) | BIT(CLK_W_PCIERX4) |
BIT(CLK_W_PCIERX4) | BIT(CLK_W_PCIERX5) |
BIT(CLK_W_PCIERX5) | BIT(CLK_W_ENTROPY) |
BIT(CLK_W_ENTROPY) | BIT(CLK_W_MC1);
BIT(CLK_W_MC1);
// CLK X Devices. // CLK X Devices.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = BIT(CLK_X_MC_CAPA) |
BIT(CLK_X_MC_CAPA) | BIT(CLK_X_MC_CBPA) |
BIT(CLK_X_MC_CBPA) | BIT(CLK_X_MC_CPU) |
BIT(CLK_X_MC_CPU) | BIT(CLK_X_MC_BBC) |
BIT(CLK_X_MC_BBC) | BIT(CLK_X_GPU) |
BIT(CLK_X_GPU) | BIT(CLK_X_DBGAPB) |
BIT(CLK_X_DBGAPB) | BIT(CLK_X_PLLG_REF);
BIT(CLK_X_PLLG_REF);
// CLK Y Devices. // CLK Y Devices.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = BIT(CLK_Y_MC_CDPA) |
BIT(CLK_Y_MC_CDPA) | BIT(CLK_Y_MC_CCPA);
BIT(CLK_Y_MC_CCPA);
// Disable clock gate overrides. // Reset clock gate overrides to automatic mode.
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0;
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0;
@@ -234,10 +265,10 @@ static void _mbist_workaround()
// Set child clock sources. // Set child clock sources.
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= ~(BIT(15) | BIT(14)); // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT.
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT.
} }
static void _config_se_brom() static void _config_se_brom()
@@ -248,25 +279,30 @@ static void _config_se_brom()
// Try to set SBK from fuses. If patched, skip. // Try to set SBK from fuses. If patched, skip.
fuse_set_sbk(); fuse_set_sbk();
// Make SBK unreadable.
//FUSE(FUSE_PRIVATEKEYDISABLE) = FUSE_PRIVKEY_TZ_STICKY_BIT | FUSE_PRIVKEY_DISABLE;
// Lock SSK (although it's not set and unused anyways). // Lock SSK (although it's not set and unused anyways).
// se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEYREAD_FLAG); // se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEYREAD_FLAG);
// This memset needs to happen here, else TZRAM will behave weirdly later on. // This memset needs to happen here, else TZRAM will behave weirdly later on.
memset((void *)TZRAM_BASE, 0, TZRAM_SIZE); memset((void *)TZRAM_BASE, 0, TZRAM_SIZE);
PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE; PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE;
SE(SE_INT_STATUS_REG) = 0x1F; // Clear all SE interrupts.
// Clear SE interrupts.
SE(SE_INT_STATUS_REG) = SE_INT_OP_DONE | SE_INT_OUT_DONE | SE_INT_OUT_LL_BUF_WR | SE_INT_IN_DONE | SE_INT_IN_LL_BUF_RD;
// Save reset reason. // Save reset reason.
hw_rst_status = PMC(APBDEV_PMC_SCRATCH200); hw_rst_status = PMC(APBDEV_PMC_SCRATCH200);
hw_rst_reason = PMC(APBDEV_PMC_RST_STATUS) & PMC_RST_STATUS_MASK; hw_rst_reason = PMC(APBDEV_PMC_RST_STATUS) & PMC_RST_STATUS_MASK;
// Clear the boot reason to avoid problems later. // Clear the boot reason to avoid problems later.
PMC(APBDEV_PMC_SCRATCH200) = 0x0; PMC(APBDEV_PMC_SCRATCH200) = 0;
PMC(APBDEV_PMC_RST_STATUS) = 0x0; PMC(APBDEV_PMC_RST_STATUS) = PMC_RST_STATUS_POR;
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10); 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. // Set RTC/AO domain to POR voltage.
if (tegra_t210) if (tegra_t210)
@@ -275,22 +311,26 @@ static void _config_regulators(bool tegra_t210)
// Disable low battery shutdown monitor. // Disable low battery shutdown monitor.
max77620_low_battery_monitor_config(false); max77620_low_battery_monitor_config(false);
// Disable SDMMC1 IO power. // Power on all relevant rails in case we came out of warmboot. Only keep MEM/MEM_COMP and SDMMC1 states.
gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW); 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); 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(); sd_power_cycle_time_start = get_tmr_ms();
// Disable LCD DVDD. // Disable backup battery charger.
max7762x_regulator_enable(REGULATOR_LDO0, false);
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_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) if (tegra_t210)
{ {
// Configure all Flexible Power Sequencers for MAX77620. // 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_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)); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
max77620_regulator_config_fps(REGULATOR_LDO4); max77620_regulator_config_fps(REGULATOR_LDO4);
@@ -299,13 +339,13 @@ static void _config_regulators(bool tegra_t210)
max77620_regulator_config_fps(REGULATOR_SD1); max77620_regulator_config_fps(REGULATOR_SD1);
max77620_regulator_config_fps(REGULATOR_SD3); max77620_regulator_config_fps(REGULATOR_SD3);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, // Set GPIO3 to FPS0 for SYS 3V3 EN. Enabled when FPS0 is enabled.
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ 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. // Set vdd_core voltage to 1.125V.
max7762x_regulator_set_voltage(REGULATOR_SD0, 1125000); 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(5, MAX77620_GPIO_OUTPUT_DISABLE);
max77620_config_gpio(6, MAX77620_GPIO_OUTPUT_DISABLE); max77620_config_gpio(6, MAX77620_GPIO_OUTPUT_DISABLE);
@@ -313,8 +353,26 @@ static void _config_regulators(bool tegra_t210)
max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_POR_CFG); max77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_POR_CFG);
max77621_config_default(REGULATOR_GPU0, 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); 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() void hw_init()
@@ -323,15 +381,19 @@ void hw_init()
bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210; bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;
bool nx_hoag = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG; bool nx_hoag = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG;
// Bootrom stuff we skipped by going through rcm. // Bootrom stuff we might skipped by going through rcm.
_config_se_brom(); _config_se_brom();
//FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11;
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN.
PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC;
// Perform Memory Built-In Self Test WAR if T210. // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN.
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F;
PMC(APBDEV_PMC_SCRATCH49) &= 0xFFFFFFFC;
// Perform the bootloader part of the Memory Built-In Self Test WAR if T210.
if (tegra_t210) if (tegra_t210)
_mbist_workaround(); _mbist_workaround_bl();
// Make sure PLLP_OUT3/4 is set to 408 MHz and enabled.
CLOCK(CLK_RST_CONTROLLER_PLLP_OUTB) = 0x30003;
// Enable Security Engine clock. // Enable Security Engine clock.
clock_enable_se(); clock_enable_se();
@@ -351,19 +413,7 @@ void hw_init()
// Initialize pin configuration. // Initialize pin configuration.
_config_gpios(nx_hoag); _config_gpios(nx_hoag);
#ifdef DEBUG_UART_PORT // Enable CL-DVFS clock unconditionally to avoid issues with I2C5 sharing.
#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 Dynamic Voltage and Frequency Scaling device clock.
clock_enable_cl_dvfs(); clock_enable_cl_dvfs();
// Enable clocks to I2C1 and I2CPWR. // Enable clocks to I2C1 and I2CPWR.
@@ -376,32 +426,29 @@ void hw_init()
// Initialize I2C5, mandatory for PMIC. // Initialize I2C5, mandatory for PMIC.
i2c_init(I2C_5); i2c_init(I2C_5);
// Enable LDO8 on HOAG as it also powers I2C1 IO pads. // Initialize various regulators based on Erista/Mariko platform.
if (nx_hoag) _config_regulators(tegra_t210, nx_hoag);
{
max7762x_regulator_set_voltage(REGULATOR_LDO8, 2800000);
max7762x_regulator_enable(REGULATOR_LDO8, true);
}
// Initialize I2C1 for various power related devices. // Initialize I2C1 for various power related devices.
i2c_init(I2C_1); i2c_init(I2C_1);
// Initialize various regulators based on Erista/Mariko platform.
_config_regulators(tegra_t210);
_config_pmc_scratch(); // Missing from 4.x+ _config_pmc_scratch(); // Missing from 4.x+
// Set BPMP/SCLK to PLLP_OUT (408MHz). // Set BPMP/SCLK to PLLP_OUT (408MHz).
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333;
// Power on T210B01 shadow TZRAM and lock the reg. // Disable T210B01 TZRAM power-gating and lock the reg.
if (!tegra_t210) if (!tegra_t210)
{ {
// This is not actually needed since it's done by bootrom. The read locks are extra.
PMC(APBDEV_PMC_TZRAM_PWR_CNTRL) &= ~PMC_TZRAM_PWR_CNTRL_SD; PMC(APBDEV_PMC_TZRAM_PWR_CNTRL) &= ~PMC_TZRAM_PWR_CNTRL_SD;
PMC(APBDEV_PMC_TZRAM_NON_SEC_DISABLE) = PMC_TZRAM_DISABLE_REG_WRITE | PMC_TZRAM_DISABLE_REG_READ; PMC(APBDEV_PMC_TZRAM_NON_SEC_DISABLE) = PMC_TZRAM_DISABLE_REG_WRITE | PMC_TZRAM_DISABLE_REG_READ;
PMC(APBDEV_PMC_TZRAM_SEC_DISABLE) = PMC_TZRAM_DISABLE_REG_WRITE | PMC_TZRAM_DISABLE_REG_READ; 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. // Initialize External memory controller and configure DRAM parameters.
sdram_init(); sdram_init();
@@ -409,9 +456,22 @@ void hw_init()
// Enable HOST1X used by every display module (DC, VIC, NVDEC, NVENC, TSEC, etc). // Enable HOST1X used by every display module (DC, VIC, NVDEC, NVENC, TSEC, etc).
clock_enable_host1x(); 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; bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;
@@ -422,7 +482,7 @@ void hw_reinit_workaround(bool coreboot, u32 bl_magic)
// Disable temperature sensor, touchscreen, 5V regulators, Joy-Con and VIC. // Disable temperature sensor, touchscreen, 5V regulators, Joy-Con and VIC.
vic_end(); vic_end();
tmp451_end(); tmp451_end();
set_fan_duty(0); fan_set_duty(0);
touch_power_off(); touch_power_off();
jc_deinit(); jc_deinit();
regulator_5v_disable(REGULATOR_5V_ALL); regulator_5v_disable(REGULATOR_5V_ALL);
@@ -435,11 +495,14 @@ void hw_reinit_workaround(bool coreboot, u32 bl_magic)
// Flush/disable MMU cache. // Flush/disable MMU cache.
bpmp_mmu_disable(); bpmp_mmu_disable();
// Re-enable clocks to Audio Processing Engine as a workaround to hanging. // Reset arbiter.
hw_config_arbiter(true);
// Re-enable clocks to Audio Processing Engine as a workaround to rerunning mbist war.
if (tegra_t210) if (tegra_t210)
{ {
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_AHUB);
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_APE);
} }
// Do coreboot mitigations. // Do coreboot mitigations.
@@ -454,7 +517,7 @@ void hw_reinit_workaround(bool coreboot, u32 bl_magic)
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
// Reinstate SD controller power. // 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. // Seamless display or display power off.

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * 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; extern u32 hw_rst_reason;
void hw_init(); 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(); u32 hw_get_chip_id();
#endif #endif

View File

@@ -18,6 +18,7 @@
#include <string.h> #include <string.h>
#include <soc/i2c.h> #include <soc/i2c.h>
#include <soc/t210.h>
#include <soc/timer.h> #include <soc/timer.h>
#define I2C_PACKET_PROT_I2C BIT(4) #define I2C_PACKET_PROT_I2C BIT(4)
@@ -81,14 +82,8 @@
#define MSTR_CONFIG_LOAD BIT(0) #define MSTR_CONFIG_LOAD BIT(0)
#define TIMEOUT_CONFIG_LOAD BIT(2) #define TIMEOUT_CONFIG_LOAD BIT(2)
static const u32 i2c_addrs[] = { /* I2C_1, 2, 3, 4, 5 and 6. */
0x7000C000, // I2C_1. static const u16 _i2c_base_offsets[6] = { 0x0, 0x400, 0x500, 0x700, 0x1000, 0x1100 };
0x7000C400, // I2C_2.
0x7000C500, // I2C_3.
0x7000C700, // I2C_4.
0x7000D000, // I2C_5.
0x7000D100 // I2C_6.
};
static void _i2c_load_cfg_wait(vu32 *base) static void _i2c_load_cfg_wait(vu32 *base)
{ {
@@ -101,14 +96,14 @@ 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) if (size > 8)
return 0; return 0;
u32 tmp = 0; u32 tmp = 0;
vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
// Set device address and send mode. // Set device address and send mode.
base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE; base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE;
@@ -154,7 +149,7 @@ static int _i2c_recv_single(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr)
if (size > 8) if (size > 8)
return 0; return 0;
vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
// Set device address and recv mode. // Set device address and recv mode.
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ; base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;
@@ -198,7 +193,7 @@ static int _i2c_send_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr)
int res = 0; int res = 0;
vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
// Enable interrupts. // Enable interrupts.
base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK | base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK |
@@ -270,7 +265,7 @@ static int _i2c_recv_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr, u32 reg)
int res = 0; int res = 0;
vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
// Enable interrupts. // Enable interrupts.
base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK | base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK |
@@ -352,7 +347,7 @@ static int _i2c_recv_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr, u32 reg)
void i2c_init(u32 i2c_idx) void i2c_init(u32 i2c_idx)
{ {
vu32 *base = (vu32 *)i2c_addrs[i2c_idx]; vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
base[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2. base[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2.
base[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE; base[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE;
@@ -389,9 +384,9 @@ 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); 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[4]; u8 tmp[8];
if (size > 7) if (size > 7)
return 0; return 0;

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_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_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_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_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); 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); u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg);

Some files were not shown because too many files have changed in this diff Show More