29 Commits

Author SHA1 Message Date
c6b6b42eda Use parallel build in CI workflow
All checks were successful
Build / Build (push) Successful in 16s
Add -j4 to make for faster compilation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 21:35:43 +01:00
9cd8953f78 Move theme removal to AMS error codes section
All checks were successful
Build / Build (push) Successful in 34s
Relocated "Delete Themes" entry from the boot problem section into
the Atmosphere error codes section as "Fix 0100000000001000
(Installiertes Theme)" to better reflect that it fixes an AMS
title ID conflict.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 21:34:22 +01:00
45c659f1ea Updated workflow
All checks were successful
Build / Build (push) Successful in 34s
2026-02-13 21:24:35 +01:00
f82ee15f52 Updated workflow
Some checks failed
Build / Build (push) Failing after 34s
2026-02-13 21:23:32 +01:00
2987a3c88e Updated Readme
Some checks failed
Build / Build (push) Failing after 2s
2026-02-13 21:22:20 +01:00
e6676315c7 Updated workflow
Some checks failed
Build / Build (push) Failing after 3s
2026-02-13 21:21:52 +01:00
ef9c1eaf7a Fix data abort crash in Mac special files removal (listdir)
The listdir function had three memory corruption bugs causing a
data abort (Err:19) on the Switch:

1. Heap buffer overflow: CpyStr("sd:/") allocated only 5 bytes but
   listdir appends full subdirectory paths in-place via memcpy.
   Fixed by using a 1024-byte stack buffer instead.

2. Use-after-free: _DeleteFileSimple(path) freed the shared traversal
   buffer, but the loop continued using it. Fixed by inlining f_unlink
   without freeing.

3. Recursive free + missing else: free(path) at the end of listdir
   freed the buffer shared across all recursive frames, and a missing
   else caused recursion into directories that were just deleted.
   Removed the free and added an else guard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 21:16:58 +01:00
763cb43983 Added AMS section and fixed inconsistencies 2026-02-07 23:00:29 +01:00
59f7dde33a Updated gitignore 2026-02-06 21:04:13 +01:00
bc086126e5 Updated Readme 2026-02-06 21:03:23 +01:00
5702202ea9 Updated Readme 2026-02-06 21:02:47 +01:00
36a08cf42f Updated Readme 2026-02-06 21:01:27 +01:00
1a7b0a1667 Added german translation and bugfixes 2026-02-06 21:00:36 +01:00
6ee7d5f892 Updated Workflow 2026-02-06 19:22:32 +01:00
6239b65472 Updated Workflow 2026-02-06 19:20:47 +01:00
29d63ffbf7 Updated Workflow 2026-02-06 19:19:03 +01:00
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
172 changed files with 10019 additions and 4456 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

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

@@ -0,0 +1,30 @@
name: Build
on:
push:
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
container: devkitpro/devkita64:latest
steps:
- name: Install dependencies
run: apt-get update && apt-get install -y nodejs
- name: Checkout latest code
uses: actions/checkout@v5
with:
clean: true
submodules: recursive
- name: Build
run: |
export DEVKITPRO=/opt/devkitpro
make -j4 all
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: AllgemeinerProblemLoeser.bin
path: output/AllgemeinerProblemLoeser.bin

13
.gitignore vendored
View File

@@ -2,3 +2,16 @@
build build
output output
research research
# macOS
.DS_Store
.AppleDouble
.LSOverride
._*
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.apDisk

View File

@@ -9,13 +9,13 @@ include $(DEVKITARM)/base_rules
################################################################################ ################################################################################
IPL_LOAD_ADDR := 0x40008000 IPL_LOAD_ADDR := 0x40008000
LPVERSION_MAJOR := 0 APLVERSION_MAJOR := 0
LPVERSION_MINOR := 3 APLVERSION_MINOR := 3
LPVERSION_BUGFX := 4 APLVERSION_BUGFX := 4
################################################################################ ################################################################################
TARGET := CommonProblemResolver TARGET := AllgemeinerProblemLoeser
BUILDDIR := build BUILDDIR := build
OUTPUTDIR := output OUTPUTDIR := output
SOURCEDIR = source SOURCEDIR = source
@@ -37,7 +37,7 @@ FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"'
################################################################################ ################################################################################
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) CUSTOMDEFINES += -DAPL_VER_MJ=$(APLVERSION_MAJOR) -DAPL_VER_MN=$(APLVERSION_MINOR) -DAPL_VER_BF=$(APLVERSION_BUGFX)
CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)
# 0: UART_A, 1: UART_B. # 0: UART_A, 1: UART_B.

View File

@@ -1,34 +1,41 @@
# CommonProblemResolver (CPR) # AllgemeinerProblemLoeser (APL)
Rescue your switch without a pc! Rette deine Switch ohne PC!
## Usage **Original-Projekt:** [Common Problem Resolver](https://github.com/Team-Neptune/CommonProblemResolver) von [Team Neptune](https://github.com/Team-Neptune).
1. Get your favorite payload injector
2. Inject CPR as a payload
Navigate around the menus using the joycons. ## Nutzung
- A: Select
- B: Back
- Left Joystick up/down (Dpad or joystick): navigate menus up/down
- Right Joystick up/down: fast menu navigation up/down
- Capture (Minerva only): Take a screenshot
- L3/R3 (Press joysticks in): Recalibrate centerpoint
If you do not have your joycons connected: 1. Besorge dir einen Payload-Injector deiner Wahl
2. Lade APL als Payload
Navigation in den Menues mit den Joy-Cons:
- A: Auswaehlen
- B: Zurueck
- Linker Stick hoch/runter (D-Pad oder Stick): Menue hoch/runter
- Rechter Stick hoch/runter: Schnelle Menue-Navigation
- Capture (nur Minerva): Screenshot
- L3/R3 (Sticks eindruecken): Mittelpunkt neu kalibrieren
Ohne verbundene Joy-Cons:
- Power -> A - Power -> A
- Vol+ -> Left Joystick up - Vol+ -> Linker Stick hoch
- Vol- -> Left Joystick down - Vol- -> Linker Stick runter
## Functions ## Funktionen
- Disables all sysmodules on your switch (might fix booting issues after update)
- Delete installed themes (will fix booting issues after update) - Deaktiviert automatischen Sysmodule-Start (kann Startprobleme nach Updates beheben)
- Reverts changes made by clingwrap - Loescht installierte Themes (kann Startprobleme nach Updates beheben)
- Behebt Archiv-Bit (SD-Karte)
- Entfernt Mac-Sonderordner
## Support ## Support
Join [our discord](https://discord.gg/VkaRjYN) for help. Fuer Hilfe: [unser Discord](https://discord.gg/VkaRjYN)
## Credits ## Danksagungen
This is heavily based on [TegraExplorer](https://github.com/suchmememanyskill/TegraExplorer) by suchmememanyskill, - **Deutsche Übersetzung:** [Switch Bros.](https://github.com/Switch-Bros/AllgemeinerProblemLoeser)
which itself is based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus also based on [Hekate](https://github.com/CTCaer/hekate) - Dieses Projekt basiert stark auf dem [Original Common Problem Resolver](https://github.com/Team-Neptune/CommonProblemResolver) von [Team Neptune](https://github.com/Team-Neptune),
sowie auf [TegraExplorer](https://github.com/suchmememanyskill/TegraExplorer) von suchmememanyskill,
[Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM) und [Hekate](https://github.com/CTCaer/hekate).

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,6 +72,8 @@
#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>

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,6 +90,16 @@ 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();

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

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.

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