soc: tegra: pmc: add r2p support
This commit is contained in:
@@ -176,3 +176,25 @@ config SOC_TEGRA_CBB
|
||||
Support for handling error from Tegra Control Backbone(CBB).
|
||||
This driver handles the errors from CBB and prints debug
|
||||
information about the failed transactions.
|
||||
|
||||
config TEGRA_124_R2P
|
||||
bool "Tegra124 Reboot 2 Payload support"
|
||||
depends on ARCH_TEGRA_124_SOC
|
||||
select TEGRA_R2P
|
||||
default n
|
||||
help
|
||||
This enables a special reboot path which allows the board to reboot
|
||||
to a specified bootloader other than the one in boot storage.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config TEGRA_210_R2P
|
||||
bool "Tegra210 Reboot 2 Payload support"
|
||||
depends on ARCH_TEGRA_210_SOC
|
||||
select TEGRA_R2P
|
||||
default n
|
||||
help
|
||||
This enables a special reboot path which allows the board to reboot
|
||||
to a specified bootloader other than the one in boot storage.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
@@ -3,6 +3,7 @@ obj-y += fuse/
|
||||
obj-y += cbb/
|
||||
|
||||
obj-y += common.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_210_SOC) += pmc-r2p.o
|
||||
obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
|
||||
obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
|
||||
obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o
|
||||
|
||||
409
drivers/soc/tegra/pmc-r2p.c
Normal file
409
drivers/soc/tegra/pmc-r2p.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Ezekiel Bethel <zek@9net.org>
|
||||
* Copyright (c) 2021-2022, CTCaer <ctcaer@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <soc/tegra/pmc.h>
|
||||
|
||||
#define TEGRA_SIP_R2P_DO_REBOOT 0xC2FFFE03u
|
||||
#define TEGRA_SIP_R2P_SET_BIN_CFG 0xC2FFFE04u
|
||||
|
||||
#define IRAM_PAYLOAD_BASE 0x40010000u
|
||||
#define IRAM_CHUNK_SIZE 0x4000
|
||||
|
||||
#define RTC_REBOOT_REASON_MAGIC 0x77
|
||||
|
||||
/* hekate/Nyx */
|
||||
#define BOOT_CFG_AUTOBOOT_EN BIT(0)
|
||||
#define BOOT_CFG_FROM_ID BIT(2)
|
||||
|
||||
#define EXTRA_CFG_NYX_UMS BIT(5)
|
||||
#define EXTRA_CFG_NYX_RELOAD BIT(6)
|
||||
|
||||
enum {
|
||||
NYX_UMS_SD_CARD = 0,
|
||||
NYX_UMS_EMMC_BOOT0,
|
||||
NYX_UMS_EMMC_BOOT1,
|
||||
NYX_UMS_EMMC_GPP,
|
||||
NYX_UMS_EMUMMC_BOOT0,
|
||||
NYX_UMS_EMUMMC_BOOT1,
|
||||
NYX_UMS_EMUMMC_GPP
|
||||
};
|
||||
|
||||
enum {
|
||||
REBOOT_REASON_NOP = 0, /* Use [config]. */
|
||||
REBOOT_REASON_SELF = 1, /* Use autoboot_idx/autoboot_list. */
|
||||
REBOOT_REASON_MENU = 2, /* Force menu. */
|
||||
REBOOT_REASON_UMS = 3, /* Force selected UMS partition. */
|
||||
REBOOT_REASON_REC = 4, /* Set PMC_SCRATCH0_MODE_RECOVERY and reboot to self. */
|
||||
REBOOT_REASON_PANIC = 5 /* Inform bootloader that panic occured if T210B01. */
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) hekate_boot_cfg
|
||||
{
|
||||
u8 boot_cfg;
|
||||
u8 autoboot;
|
||||
u8 autoboot_list;
|
||||
u8 extra_cfg;
|
||||
union {
|
||||
struct {
|
||||
char id[8];
|
||||
char emummc_path[0x78];
|
||||
};
|
||||
u8 ums;
|
||||
u8 xt_str[0x80];
|
||||
};
|
||||
};
|
||||
|
||||
struct rtc_rr_dec
|
||||
{
|
||||
u16 reason:4;
|
||||
u16 autoboot_idx:4;
|
||||
u16 autoboot_list:1;
|
||||
u16 ums_idx:3;
|
||||
};
|
||||
|
||||
struct rtc_rr_enc
|
||||
{
|
||||
u16 val1:6; /* 6-bit reg. */
|
||||
u16 val2:6; /* 6-bit reg. */
|
||||
};
|
||||
|
||||
struct rtc_reboot_reason
|
||||
{
|
||||
union {
|
||||
struct rtc_rr_dec dec;
|
||||
struct rtc_rr_enc enc;
|
||||
};
|
||||
};
|
||||
|
||||
struct reboot_driver_state
|
||||
{
|
||||
char action[16];
|
||||
int param1;
|
||||
int param2;
|
||||
char entry_id[8];
|
||||
};
|
||||
|
||||
static int enabled = 0;
|
||||
static int param1 = 0;
|
||||
static int param2 = 0;
|
||||
static char* action = NULL;
|
||||
static char* entry_id = NULL;
|
||||
|
||||
module_param(enabled, int, 0664);
|
||||
module_param(action, charp, 0664);
|
||||
module_param(param1, int, 0664);
|
||||
module_param(param2, int, 0664);
|
||||
module_param(entry_id, charp, 0664);
|
||||
|
||||
MODULE_PARM_DESC(enabled, "Enable Reboot 2 Payload function");
|
||||
MODULE_PARM_DESC(action, "Reboot action to take");
|
||||
MODULE_PARM_DESC(param1, "Autoboot entry or UMS device index");
|
||||
MODULE_PARM_DESC(param2, "Autooboot entry is ini list");
|
||||
MODULE_PARM_DESC(entry_id, "Autoboot entry id");
|
||||
|
||||
struct platform_device *r2p_device = NULL;
|
||||
|
||||
static void tegra_pmc_r2p_set_cfg(struct hekate_boot_cfg *hekate_bcfg)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
u64 hekate_boot_smc_cfg[4];
|
||||
|
||||
memcpy(hekate_boot_smc_cfg, hekate_bcfg, sizeof(hekate_boot_smc_cfg));
|
||||
|
||||
arm_smccc_smc(TEGRA_SIP_R2P_SET_BIN_CFG,
|
||||
hekate_boot_smc_cfg[0],
|
||||
hekate_boot_smc_cfg[1],
|
||||
hekate_boot_smc_cfg[2],
|
||||
hekate_boot_smc_cfg[3],
|
||||
0, 0, 0, &res);
|
||||
|
||||
if (res.a0) {
|
||||
pr_err("%s: SMC failed (ret=%ld)\n", __func__, res.a0);
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
void tegra_pmc_r2p_setup(const char *cmd, bool panic_occurred)
|
||||
{
|
||||
struct rtc_reboot_reason rr = {};
|
||||
struct hekate_boot_cfg hekate_bcfg = {};
|
||||
struct reboot_driver_state *state;
|
||||
|
||||
uint32_t reboot_reason = REBOOT_REASON_NOP;
|
||||
|
||||
if (r2p_device == NULL)
|
||||
return;
|
||||
|
||||
state = dev_get_drvdata(&r2p_device->dev);
|
||||
|
||||
/* Linux reboot reason */
|
||||
if (cmd) {
|
||||
if (!strcmp(cmd, "recovery")) {
|
||||
reboot_reason = REBOOT_REASON_REC;
|
||||
} else if (!strcmp(cmd, "bootloader")) {
|
||||
reboot_reason = REBOOT_REASON_MENU;
|
||||
} else {
|
||||
dev_err(&r2p_device->dev,
|
||||
"Command '%s' not recognized\n", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Missing reboot reason or not matching, use r2p action. */
|
||||
if (reboot_reason == REBOOT_REASON_NOP && strlen(state->action)) {
|
||||
if (!strcmp(state->action, "self") ||
|
||||
!strcmp(state->action, "via-payload")) { /* Deprecated */
|
||||
reboot_reason = REBOOT_REASON_SELF;
|
||||
} else if (!strcmp(state->action, "bootloader")) {
|
||||
reboot_reason = REBOOT_REASON_MENU;
|
||||
} else if (!strcmp(state->action, "ums")) {
|
||||
reboot_reason = REBOOT_REASON_UMS;
|
||||
} else if (!strcmp(state->action, "normal")) {
|
||||
reboot_reason = REBOOT_REASON_NOP;
|
||||
} else {
|
||||
dev_err(&r2p_device->dev,
|
||||
"Action '%s' not recognized\n", state->action);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare boot config data */
|
||||
switch (reboot_reason) {
|
||||
case REBOOT_REASON_NOP:
|
||||
break;
|
||||
case REBOOT_REASON_REC:
|
||||
case REBOOT_REASON_SELF:
|
||||
hekate_bcfg.boot_cfg = BOOT_CFG_AUTOBOOT_EN;
|
||||
if (strlen(state->entry_id) != 0) {
|
||||
hekate_bcfg.boot_cfg |= BOOT_CFG_FROM_ID;
|
||||
strcpy(hekate_bcfg.id, state->entry_id);
|
||||
}
|
||||
hekate_bcfg.autoboot = state->param1;
|
||||
hekate_bcfg.autoboot_list = state->param2;
|
||||
|
||||
rr.dec.reason = reboot_reason;
|
||||
rr.dec.autoboot_idx = state->param1;
|
||||
rr.dec.autoboot_list = state->param2;
|
||||
break;
|
||||
case REBOOT_REASON_MENU:
|
||||
hekate_bcfg.boot_cfg = BOOT_CFG_AUTOBOOT_EN;
|
||||
|
||||
rr.dec.reason = reboot_reason;
|
||||
break;
|
||||
case REBOOT_REASON_UMS:
|
||||
hekate_bcfg.boot_cfg = BOOT_CFG_AUTOBOOT_EN;
|
||||
hekate_bcfg.extra_cfg = EXTRA_CFG_NYX_UMS;
|
||||
hekate_bcfg.ums = state->param1;
|
||||
|
||||
rr.dec.reason = reboot_reason;
|
||||
rr.dec.ums_idx = state->param1;
|
||||
break;
|
||||
case REBOOT_REASON_PANIC:
|
||||
rr.dec.reason = reboot_reason;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Notify TZ to use its preloaded payload */
|
||||
/* Set hekate boot config. */
|
||||
tegra_pmc_r2p_set_cfg(&hekate_bcfg);
|
||||
}
|
||||
|
||||
static ssize_t action_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct reboot_driver_state *state = dev_get_drvdata(&r2p_device->dev);
|
||||
int res;
|
||||
|
||||
if (strlen(state->action))
|
||||
res = sprintf(buf, "%s\n", state->action);
|
||||
else
|
||||
res = sprintf(buf, "Not-set\n");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t action_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct reboot_driver_state *state = dev_get_drvdata(&r2p_device->dev);
|
||||
|
||||
if (count > sizeof(state->action) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(state->action, buf, sizeof(state->action) - 1);
|
||||
state->action[sizeof(state->action) - 1] = 0;
|
||||
|
||||
/* Strip newline if it exists */
|
||||
if (state->action[count - 1] == '\n')
|
||||
state->action[count - 1] = 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t entry_id_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct reboot_driver_state *state = dev_get_drvdata(&r2p_device->dev);
|
||||
int res;
|
||||
|
||||
if (strlen(state->entry_id))
|
||||
res = sprintf(buf, "%s\n", state->entry_id);
|
||||
else
|
||||
res = sprintf(buf, "Not-set\n");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t entry_id_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct reboot_driver_state *state = dev_get_drvdata(&r2p_device->dev);
|
||||
|
||||
if (count > sizeof(state->entry_id) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(state->entry_id, buf, sizeof(state->entry_id) - 1);
|
||||
state->entry_id[sizeof(state->entry_id) - 1] = 0;
|
||||
|
||||
/* Strip newline if it exists */
|
||||
if (state->entry_id[count - 1] == '\n')
|
||||
state->entry_id[count - 1] = 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t param1_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct reboot_driver_state *state = dev_get_drvdata(&r2p_device->dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (int)state->param1);
|
||||
}
|
||||
|
||||
static ssize_t param1_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct reboot_driver_state *state = dev_get_drvdata(&r2p_device->dev);
|
||||
ssize_t res;
|
||||
long value;
|
||||
|
||||
res = kstrtol(buf, 0, &value);
|
||||
if (!res)
|
||||
state->param1 = value;
|
||||
|
||||
return res ? res : count;
|
||||
}
|
||||
|
||||
static ssize_t param2_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct reboot_driver_state *state = dev_get_drvdata(&r2p_device->dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (int)state->param2);
|
||||
}
|
||||
|
||||
static ssize_t param2_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct reboot_driver_state *state = dev_get_drvdata(&r2p_device->dev);
|
||||
ssize_t res;
|
||||
long value;
|
||||
|
||||
res = kstrtol(buf, 0, &value);
|
||||
if (!res)
|
||||
state->param2 = value;
|
||||
|
||||
return res ? res : count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(action);
|
||||
static DEVICE_ATTR_RW(entry_id);
|
||||
static DEVICE_ATTR_RW(param1);
|
||||
static DEVICE_ATTR_RW(param2);
|
||||
|
||||
static struct attribute *r2p_sysfs_attrs[] = {
|
||||
&dev_attr_action.attr,
|
||||
&dev_attr_entry_id.attr,
|
||||
&dev_attr_param1.attr,
|
||||
&dev_attr_param2.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(r2p_sysfs);
|
||||
|
||||
static int tegra_pmc_r2p_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct reboot_driver_state *state;
|
||||
|
||||
if (!enabled)
|
||||
return 0;
|
||||
|
||||
r2p_device = pdev;
|
||||
|
||||
state = devm_kzalloc(&pdev->dev, sizeof(struct reboot_driver_state), GFP_KERNEL);
|
||||
|
||||
/* Copy reboot action if valid */
|
||||
if (action) {
|
||||
strncpy(state->action, action, sizeof(state->action) - 1);
|
||||
state->action[sizeof(state->action) - 1] = 0;
|
||||
}
|
||||
|
||||
/* Copy entry ID if valid */
|
||||
if (entry_id) {
|
||||
strncpy(state->entry_id, entry_id, sizeof(state->entry_id) - 1);
|
||||
state->entry_id[sizeof(state->entry_id) - 1] = 0;
|
||||
}
|
||||
|
||||
/* Set reboot reason parameters. */
|
||||
state->param1 = param1;
|
||||
state->param2 = param2;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, state);
|
||||
|
||||
if (sysfs_create_groups(&pdev->dev.kobj, r2p_sysfs_groups))
|
||||
dev_err(&pdev->dev, "sysfs creation failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id tegra_pmc_r2p_match[] = {
|
||||
{ .compatible = "tegra-r2p", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver tegra_pmc_r2p_driver = {
|
||||
.probe = tegra_pmc_r2p_driver_probe,
|
||||
.driver = {
|
||||
.name = "tegra-r2p",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = tegra_pmc_r2p_match
|
||||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(tegra_pmc_r2p_driver);
|
||||
@@ -94,12 +94,13 @@
|
||||
|
||||
#define PMC_PWR_DET 0x48
|
||||
|
||||
#define PMC_SCRATCH0_MODE_RECOVERY BIT(31)
|
||||
#define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30)
|
||||
#define PMC_SCRATCH0_MODE_RCM BIT(1)
|
||||
#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \
|
||||
PMC_SCRATCH0_MODE_BOOTLOADER | \
|
||||
PMC_SCRATCH0_MODE_RCM)
|
||||
#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31)
|
||||
#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30)
|
||||
#define PMC_SCRATCH0_MODE_PAYLOAD (1 << 29) /* R2P custom mode. Deprecated */
|
||||
#define PMC_SCRATCH0_MODE_RCM (1 << 1)
|
||||
#define PMC_SCRATCH0_MODE_MASK \
|
||||
(PMC_SCRATCH0_MODE_RECOVERY | PMC_SCRATCH0_MODE_BOOTLOADER | \
|
||||
PMC_SCRATCH0_MODE_RCM | PMC_SCRATCH0_MODE_PAYLOAD)
|
||||
|
||||
#define PMC_CPUPWRGOOD_TIMER 0xc8
|
||||
#define PMC_CPUPWROFF_TIMER 0xcc
|
||||
@@ -199,6 +200,8 @@
|
||||
#define TEGRA_SMC_PMC_READ 0xaa
|
||||
#define TEGRA_SMC_PMC_WRITE 0xbb
|
||||
|
||||
#define KERNEL_PANIC_MAGIC 0x4E415054
|
||||
|
||||
struct pmc_clk {
|
||||
struct clk_hw hw;
|
||||
unsigned long offs;
|
||||
@@ -385,6 +388,7 @@ struct tegra_pmc_soc {
|
||||
bool has_usb_sleepwalk;
|
||||
bool supports_core_domain;
|
||||
bool has_single_mmio_aperture;
|
||||
bool supports_r2p;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1102,6 +1106,7 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid)
|
||||
static void tegra_pmc_program_reboot_reason(const char *cmd)
|
||||
{
|
||||
u32 value;
|
||||
u32 panic_code = tegra_pmc_scratch_readl(pmc, PMC_SCRATCH37);
|
||||
|
||||
value = tegra_pmc_scratch_readl(pmc, pmc->soc->regs->scratch0);
|
||||
value &= ~PMC_SCRATCH0_MODE_MASK;
|
||||
@@ -1110,13 +1115,21 @@ static void tegra_pmc_program_reboot_reason(const char *cmd)
|
||||
if (strcmp(cmd, "recovery") == 0)
|
||||
value |= PMC_SCRATCH0_MODE_RECOVERY;
|
||||
|
||||
if (strcmp(cmd, "bootloader") == 0)
|
||||
else if (strcmp(cmd, "bootloader") == 0)
|
||||
value |= PMC_SCRATCH0_MODE_BOOTLOADER;
|
||||
|
||||
if (strcmp(cmd, "forced-recovery") == 0)
|
||||
else if (strcmp(cmd, "forced-recovery") == 0)
|
||||
value |= PMC_SCRATCH0_MODE_RCM;
|
||||
}
|
||||
|
||||
/* Setup R2P for T124/T210/T210B01 */
|
||||
if (pmc->soc->supports_r2p) {
|
||||
tegra_pmc_r2p_setup(cmd, panic_code == KERNEL_PANIC_MAGIC);
|
||||
|
||||
/* Deprecated: Old TZ support. */
|
||||
value |= PMC_SCRATCH0_MODE_PAYLOAD;
|
||||
}
|
||||
|
||||
tegra_pmc_scratch_writel(pmc, value, pmc->soc->regs->scratch0);
|
||||
}
|
||||
|
||||
@@ -3564,6 +3577,9 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
|
||||
.has_blink_output = true,
|
||||
.has_usb_sleepwalk = true,
|
||||
.has_single_mmio_aperture = true,
|
||||
#ifdef CONFIG_TEGRA_124_R2P
|
||||
.supports_r2p = true,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const char * const tegra210_powergates[] = {
|
||||
@@ -3728,6 +3744,10 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
|
||||
.has_blink_output = true,
|
||||
.has_usb_sleepwalk = true,
|
||||
.has_single_mmio_aperture = true,
|
||||
#ifdef CONFIG_TEGRA_210_R2P
|
||||
.supports_r2p = true,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static const struct tegra_io_pad_soc tegra210b01_io_pads[] = {
|
||||
@@ -3844,6 +3864,9 @@ static const struct tegra_pmc_soc tegra210b01_pmc_soc = {
|
||||
.has_blink_output = true,
|
||||
.has_usb_sleepwalk = true,
|
||||
.has_single_mmio_aperture = true,
|
||||
#ifdef CONFIG_TEGRA_210_R2P
|
||||
.supports_r2p = true,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct tegra_io_pad_soc tegra186_io_pads[] = {
|
||||
|
||||
@@ -227,4 +227,6 @@ static inline enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
void tegra_pmc_r2p_setup(const char *cmd, bool panic_occurred);
|
||||
|
||||
#endif /* __SOC_TEGRA_PMC_H__ */
|
||||
|
||||
Reference in New Issue
Block a user