tegra: Add tegra_get_chip_type() to detect SKU
We want to know which type of chip we are running on - the Tegra
family has several SKUs. This can be determined by reading a
fuse register, so add this function to ap20.
Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c
index a6dd3e4..150fbfd 100644
--- a/arch/arm/cpu/armv7/tegra2/ap20.c
+++ b/arch/arm/cpu/armv7/tegra2/ap20.c
@@ -26,11 +26,47 @@
#include <asm/arch/ap20.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
+#include <asm/arch/fuse.h>
+#include <asm/arch/gp_padctrl.h>
#include <asm/arch/pmc.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/scu.h>
#include <common.h>
+int tegra_get_chip_type(void)
+{
+ struct apb_misc_gp_ctlr *gp;
+ struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE;
+ uint tegra_sku_id, rev;
+
+ /*
+ * This is undocumented, Chip ID is bits 15:8 of the register
+ * APB_MISC + 0x804, and has value 0x20 for Tegra20, 0x30 for
+ * Tegra30
+ */
+ gp = (struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE;
+ rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT;
+
+ tegra_sku_id = readl(&fuse->sku_info) & 0xff;
+
+ switch (rev) {
+ case CHIPID_TEGRA2:
+ switch (tegra_sku_id) {
+ case SKU_ID_T20:
+ return TEGRA_SOC_T20;
+ case SKU_ID_T25SE:
+ case SKU_ID_AP25:
+ case SKU_ID_T25:
+ case SKU_ID_AP25E:
+ case SKU_ID_T25E:
+ return TEGRA_SOC_T25;
+ }
+ break;
+ }
+ /* unknown sku id */
+ return TEGRA_SOC_UNKNOWN;
+}
+
/* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */
static int ap20_cpu_is_cortexa9(void)
{
diff --git a/arch/arm/include/asm/arch-tegra2/ap20.h b/arch/arm/include/asm/arch-tegra2/ap20.h
index a4b4d73..d222c44 100644
--- a/arch/arm/include/asm/arch-tegra2/ap20.h
+++ b/arch/arm/include/asm/arch-tegra2/ap20.h
@@ -100,3 +100,10 @@
/* This is the main entry into U-Boot, used by the Cortex-A9 */
extern void _start(void);
+
+/**
+ * Works out the SOC type used for clocks settings
+ *
+ * @return SOC type - see TEGRA_SOC...
+ */
+int tegra_get_chip_type(void);
diff --git a/arch/arm/include/asm/arch-tegra2/gp_padctrl.h b/arch/arm/include/asm/arch-tegra2/gp_padctrl.h
index 25bb46d..1755ab2 100644
--- a/arch/arm/include/asm/arch-tegra2/gp_padctrl.h
+++ b/arch/arm/include/asm/arch-tegra2/gp_padctrl.h
@@ -61,4 +61,13 @@
u32 memcomp; /* 0xD4: APB_MISC_GP_MEMCOMPPADCTRL */
};
+/* bit fields definitions for APB_MISC_GP_HIDREV register */
+#define HIDREV_CHIPID_SHIFT 8
+#define HIDREV_CHIPID_MASK (0xff << HIDREV_CHIPID_SHIFT)
+#define HIDREV_MAJORPREV_SHIFT 4
+#define HIDREV_MAJORPREV_MASK (0xf << HIDREV_MAJORPREV_SHIFT)
+
+/* CHIPID field returned from APB_MISC_GP_HIDREV register */
+#define CHIPID_TEGRA2 0x20
+
#endif
diff --git a/arch/arm/include/asm/arch-tegra2/tegra2.h b/arch/arm/include/asm/arch-tegra2/tegra2.h
index 2e152fd..d4ada10 100644
--- a/arch/arm/include/asm/arch-tegra2/tegra2.h
+++ b/arch/arm/include/asm/arch-tegra2/tegra2.h
@@ -33,6 +33,7 @@
#define NV_PA_GPIO_BASE 0x6000D000
#define NV_PA_EVP_BASE 0x6000F000
#define NV_PA_APB_MISC_BASE 0x70000000
+#define TEGRA2_APB_MISC_GP_BASE (NV_PA_APB_MISC_BASE + 0x0800)
#define NV_PA_APB_UARTA_BASE (NV_PA_APB_MISC_BASE + 0x6000)
#define NV_PA_APB_UARTB_BASE (NV_PA_APB_MISC_BASE + 0x6040)
#define NV_PA_APB_UARTC_BASE (NV_PA_APB_MISC_BASE + 0x6200)
@@ -55,6 +56,29 @@
struct timerus {
unsigned int cntr_1us;
};
+
+/* Address at which WB code runs, it must not overlap Bootrom's IRAM usage */
+#define AP20_WB_RUN_ADDRESS 0x40020000
+
+/* These are the available SKUs (product types) for Tegra */
+enum {
+ SKU_ID_T20 = 0x8,
+ SKU_ID_T25SE = 0x14,
+ SKU_ID_AP25 = 0x17,
+ SKU_ID_T25 = 0x18,
+ SKU_ID_AP25E = 0x1b,
+ SKU_ID_T25E = 0x1c,
+};
+
+/* These are the SOC categories that affect clocking */
+enum {
+ TEGRA_SOC_T20,
+ TEGRA_SOC_T25,
+
+ TEGRA_SOC_COUNT,
+ TEGRA_SOC_UNKNOWN = -1,
+};
+
#else /* __ASSEMBLY__ */
#define PRM_RSTCTRL TEGRA2_PMC_BASE
#endif