board: htc: endeavoru: add an early SPL RCM hook

Unlike all other supported Tegra devices and most known Tegra devices, the
HTC One X has no hardware way to enter APX/RCM mode, which may lead to a
dangerous situation when, if BCT is set correctly and the bootloader is
faulty, the device will hang in a permanent brick state. Exiting from this
state can be done only by disassembling the device and shortening the
testpad to the ground.

To prevent this or to minimize the probability of such an accident, it was
proposed to add the RCM rebooting hook as early into SPL as possible since
SPL is much more robust and has minimal changes that can break bootflow.

gpio_early_init_uart() function was chosen as it is the earliest function
exposed for setup by the device. Hook performs a check for volume up button
state and triggers RCM if it is pressed.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
This commit is contained in:
Svyatoslav Ryhel 2024-01-05 17:35:26 +02:00
parent 5c39fbfa13
commit 86e581a560

View File

@ -9,7 +9,12 @@
* Svyatoslav Ryhel <clamor95@gmail.com>
*/
#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/tegra.h>
#include <asm/arch-tegra/board.h>
#include <asm/arch-tegra/pmc.h>
#include <asm/arch-tegra/tegra_i2c.h>
#include <linux/delay.h>
@ -30,6 +35,8 @@
#define TPS80032_SMPS1_CFG_STATE_DATA (0x0100 | TPS80032_SMPS1_CFG_STATE_REG)
#define TPS80032_SMPS2_CFG_STATE_DATA (0x0100 | TPS80032_SMPS2_CFG_STATE_REG)
#define TEGRA_GPIO_PS0 144
void pmic_enable_cpu_vdd(void)
{
/* Set VDD_CORE to 1.200V. */
@ -45,3 +52,52 @@ void pmic_enable_cpu_vdd(void)
tegra_i2c_ll_write(TPS80032_CTL1_I2C_ADDR, TPS80032_SMPS1_CFG_STATE_DATA);
udelay(10 * 1000);
}
/*
* Unlike all other supported Tegra devices and most known Tegra devices, the
* HTC One X has no hardware way to enter APX/RCM mode, which may lead to a
* dangerous situation when, if BCT is set correctly and the bootloader is
* faulty, the device will hang in a permanent brick state. Exiting from this
* state can be done only by disassembling the device and shortening testpad
* to the ground.
*
* To prevent this or to minimize the probability of such an accident, it was
* proposed to add the RCM rebooting hook as early into SPL as possible since
* SPL is much more robust and has minimal changes that can break bootflow.
*
* gpio_early_init_uart() function was chosen as it is the earliest function
* exposed for setup by the device. Hook performs a check for volume up
* button state and triggers RCM if it is pressed.
*/
void gpio_early_init_uart(void)
{
struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(TEGRA_GPIO_PS0)];
u32 value;
/* Configure pinmux */
pinmux_set_func(PMUX_PINGRP_KB_ROW8_PS0, PMUX_FUNC_KBC);
pinmux_set_pullupdown(PMUX_PINGRP_KB_ROW8_PS0, PMUX_PULL_UP);
pinmux_tristate_disable(PMUX_PINGRP_KB_ROW8_PS0);
pinmux_set_io(PMUX_PINGRP_KB_ROW8_PS0, PMUX_PIN_INPUT);
/* Configure GPIO direction as input. */
value = readl(&bank->gpio_dir_out[GPIO_PORT(TEGRA_GPIO_PS0)]);
value &= ~(1 << GPIO_BIT(TEGRA_GPIO_PS0));
writel(value, &bank->gpio_dir_out[GPIO_PORT(TEGRA_GPIO_PS0)]);
/* Enable the pin as a GPIO */
value = readl(&bank->gpio_config[GPIO_PORT(TEGRA_GPIO_PS0)]);
value |= 1 << GPIO_BIT(TEGRA_GPIO_PS0);
writel(value, &bank->gpio_config[GPIO_PORT(TEGRA_GPIO_PS0)]);
/* Get GPIO value */
value = readl(&bank->gpio_in[GPIO_PORT(TEGRA_GPIO_PS0)]);
value = (value >> GPIO_BIT(TEGRA_GPIO_PS0)) & 1;
/* Enter RCM if button is pressed */
if (!value) {
tegra_pmc_writel(2, PMC_SCRATCH0);
tegra_pmc_writel(PMC_CNTRL_MAIN_RST, PMC_CNTRL);
}
}