提交 cdcb5a07 编写于 作者: A Alexandre Courbot 提交者: Stephen Warren

ARM: tegra: switch FUSE clock on before usage

FUSE clock is enabled by most bootloaders, but we cannot expect it to be
on in all contexts (e.g. kexec).

Ensure the FUSE clock is enabled before any of its registers is touched.
Since FUSE is touched very early during system boot (before the clock
devices are registered), directly manipulate the clock register bit in
case the clock device cannot be acquired.
Signed-off-by: NAlexandre Courbot <acourbot@nvidia.com>
Signed-off-by: NStephen Warren <swarren@nvidia.com>
上级 6ce4eac1
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/clk.h>
#include <linux/tegra-soc.h> #include <linux/tegra-soc.h>
#include "fuse.h" #include "fuse.h"
...@@ -54,6 +55,7 @@ int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ ...@@ -54,6 +55,7 @@ int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */
int tegra_soc_speedo_id; int tegra_soc_speedo_id;
enum tegra_revision tegra_revision; enum tegra_revision tegra_revision;
static struct clk *fuse_clk;
static int tegra_fuse_spare_bit; static int tegra_fuse_spare_bit;
static void (*tegra_init_speedo_data)(void); static void (*tegra_init_speedo_data)(void);
...@@ -77,6 +79,22 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { ...@@ -77,6 +79,22 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_A04] = "A04", [TEGRA_REVISION_A04] = "A04",
}; };
static void tegra_fuse_enable_clk(void)
{
if (IS_ERR(fuse_clk))
fuse_clk = clk_get_sys(NULL, "fuse");
if (IS_ERR(fuse_clk))
return;
clk_prepare_enable(fuse_clk);
}
static void tegra_fuse_disable_clk(void)
{
if (IS_ERR(fuse_clk))
return;
clk_disable_unprepare(fuse_clk);
}
u32 tegra_fuse_readl(unsigned long offset) u32 tegra_fuse_readl(unsigned long offset)
{ {
return tegra_apb_readl(TEGRA_FUSE_BASE + offset); return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
...@@ -84,7 +102,15 @@ u32 tegra_fuse_readl(unsigned long offset) ...@@ -84,7 +102,15 @@ u32 tegra_fuse_readl(unsigned long offset)
bool tegra_spare_fuse(int bit) bool tegra_spare_fuse(int bit)
{ {
return tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4); bool ret;
tegra_fuse_enable_clk();
ret = tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4);
tegra_fuse_disable_clk();
return ret;
} }
static enum tegra_revision tegra_get_revision(u32 id) static enum tegra_revision tegra_get_revision(u32 id)
...@@ -113,10 +139,14 @@ static void tegra_get_process_id(void) ...@@ -113,10 +139,14 @@ static void tegra_get_process_id(void)
{ {
u32 reg; u32 reg;
tegra_fuse_enable_clk();
reg = tegra_fuse_readl(tegra_fuse_spare_bit); reg = tegra_fuse_readl(tegra_fuse_spare_bit);
tegra_cpu_process_id = (reg >> 6) & 3; tegra_cpu_process_id = (reg >> 6) & 3;
reg = tegra_fuse_readl(tegra_fuse_spare_bit); reg = tegra_fuse_readl(tegra_fuse_spare_bit);
tegra_core_process_id = (reg >> 12) & 3; tegra_core_process_id = (reg >> 12) & 3;
tegra_fuse_disable_clk();
} }
u32 tegra_read_chipid(void) u32 tegra_read_chipid(void)
...@@ -159,6 +189,15 @@ void __init tegra_init_fuse(void) ...@@ -159,6 +189,15 @@ void __init tegra_init_fuse(void)
reg |= 1 << 28; reg |= 1 << 28;
writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
/*
* Enable FUSE clock. This needs to be hardcoded because the clock
* subsystem is not active during early boot.
*/
reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14));
reg |= 1 << 7;
writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14));
fuse_clk = ERR_PTR(-EINVAL);
reg = tegra_fuse_readl(FUSE_SKU_INFO); reg = tegra_fuse_readl(FUSE_SKU_INFO);
randomness[0] = reg; randomness[0] = reg;
tegra_sku_id = reg & 0xFF; tegra_sku_id = reg & 0xFF;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册