linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/5] efuse driver for Tegra
@ 2014-05-28 12:54 Peter De Schrijver
  2014-05-28 12:54 ` [PATCH v5 1/5] ARM: tegra: export apb dma readl/writel Peter De Schrijver
                   ` (6 more replies)
  0 siblings, 7 replies; 18+ messages in thread
From: Peter De Schrijver @ 2014-05-28 12:54 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Stephen Warren, Thierry Reding, Andrew Morton,
	Linus Walleij, Wolfram Sang, linux-arm-kernel, linux-tegra,
	linux-kernel

This driver allows userspace to read the raw efuse data. Its userspace
interface is modelled after the sunxi_sid driver which provides similar
functionality for some Allwinner SoCs. It has been tested on
Tegra20 (ventana), Tegra30 (beaverboard), Tegra114 (dalmore) and
Tegra124 (jetson TK1).

Changes since v1:

* Add documentation for sysfs interface
* Cleanup messages

Changes since v2:

* Incorporate early fuse code
* Remove module support
* Make driver always build when Tegra platform is selected
* Add DT binding document
* Address comments on v2

Changes since v3:

* Document sysfs file format
* Added apbmisc DT node for access to the apbmisc registers
* Address comments on v3

Changes since v4:

* Provide fallback to hardcoded 0x70000800 in case the apbmisc DT node is
  missing. This is exactly what the current code does and prevents a system
  crash in that case due to an invalid memory access by tegra_read_chipid()
* Added tegra_fuse_readl() function for drivers to read calibration data

Peter De Schrijver (5):
  ARM: tegra: export apb dma readl/writel
  ARM: tegra: move fuse exports to tegra-soc.h
  misc: fuse: Add efuse driver for Tegra
  ARM: tegra: Add efuse and apbmisc bindings
  ARM: tegra: build new fuse driver in drivers/misc

 Documentation/ABI/testing/sysfs-driver-tegra-fuse  |  201 +++++++++++++
 .../devicetree/bindings/fuse/fuse-tegra.txt        |   30 ++
 .../devicetree/bindings/misc/nvidia,apbmisc.txt    |   13 +
 arch/arm/boot/dts/tegra114.dtsi                    |   12 +
 arch/arm/boot/dts/tegra124.dtsi                    |   12 +
 arch/arm/boot/dts/tegra20.dtsi                     |   12 +
 arch/arm/boot/dts/tegra30.dtsi                     |   12 +
 arch/arm/mach-tegra/Makefile                       |    4 -
 arch/arm/mach-tegra/apbio.c                        |   51 ++--
 arch/arm/mach-tegra/cpuidle.c                      |    2 +-
 arch/arm/mach-tegra/flowctrl.c                     |    2 +-
 arch/arm/mach-tegra/fuse.c                         |  252 -----------------
 arch/arm/mach-tegra/fuse.h                         |   79 ------
 arch/arm/mach-tegra/hotplug.c                      |    2 +-
 arch/arm/mach-tegra/platsmp.c                      |    2 +-
 arch/arm/mach-tegra/pm.c                           |    2 +-
 arch/arm/mach-tegra/pmc.c                          |    2 +-
 arch/arm/mach-tegra/powergate.c                    |    2 +-
 arch/arm/mach-tegra/reset-handler.S                |    2 +-
 arch/arm/mach-tegra/reset.c                        |    2 +-
 arch/arm/mach-tegra/sleep-tegra30.S                |    2 +-
 arch/arm/mach-tegra/tegra.c                        |    2 +-
 arch/arm/mach-tegra/tegra114_speedo.c              |  104 -------
 arch/arm/mach-tegra/tegra20_speedo.c               |  109 --------
 arch/arm/mach-tegra/tegra30_speedo.c               |  292 -------------------
 drivers/misc/Makefile                              |    2 +
 drivers/misc/fuse/Makefile                         |    1 +
 drivers/misc/fuse/tegra/Makefile                   |    7 +
 drivers/misc/fuse/tegra/fuse-tegra.c               |  250 +++++++++++++++++
 drivers/misc/fuse/tegra/fuse-tegra20.c             |  134 +++++++++
 drivers/misc/fuse/tegra/fuse-tegra30.c             |  177 ++++++++++++
 drivers/misc/fuse/tegra/fuse.h                     |   82 ++++++
 drivers/misc/fuse/tegra/speedo-tegra114.c          |  110 ++++++++
 drivers/misc/fuse/tegra/speedo-tegra124.c          |  180 ++++++++++++
 drivers/misc/fuse/tegra/speedo-tegra20.c           |  110 ++++++++
 drivers/misc/fuse/tegra/speedo-tegra30.c           |  294 ++++++++++++++++++++
 include/linux/tegra-soc.h                          |   43 +++
 37 files changed, 1724 insertions(+), 871 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse
 create mode 100644 Documentation/devicetree/bindings/fuse/fuse-tegra.txt
 create mode 100644 Documentation/devicetree/bindings/misc/nvidia,apbmisc.txt
 delete mode 100644 arch/arm/mach-tegra/fuse.c
 delete mode 100644 arch/arm/mach-tegra/fuse.h
 delete mode 100644 arch/arm/mach-tegra/tegra114_speedo.c
 delete mode 100644 arch/arm/mach-tegra/tegra20_speedo.c
 delete mode 100644 arch/arm/mach-tegra/tegra30_speedo.c
 create mode 100644 drivers/misc/fuse/Makefile
 create mode 100644 drivers/misc/fuse/tegra/Makefile
 create mode 100644 drivers/misc/fuse/tegra/fuse-tegra.c
 create mode 100644 drivers/misc/fuse/tegra/fuse-tegra20.c
 create mode 100644 drivers/misc/fuse/tegra/fuse-tegra30.c
 create mode 100644 drivers/misc/fuse/tegra/fuse.h
 create mode 100644 drivers/misc/fuse/tegra/speedo-tegra114.c
 create mode 100644 drivers/misc/fuse/tegra/speedo-tegra124.c
 create mode 100644 drivers/misc/fuse/tegra/speedo-tegra20.c
 create mode 100644 drivers/misc/fuse/tegra/speedo-tegra30.c

-- 
1.7.7.rc0.72.g4b5ea.dirty


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v5 1/5] ARM: tegra: export apb dma readl/writel
  2014-05-28 12:54 [PATCH v5 0/5] efuse driver for Tegra Peter De Schrijver
@ 2014-05-28 12:54 ` Peter De Schrijver
  2014-05-28 12:54 ` [PATCH v5 2/5] ARM: tegra: move fuse exports to tegra-soc.h Peter De Schrijver
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 18+ messages in thread
From: Peter De Schrijver @ 2014-05-28 12:54 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Stephen Warren, Thierry Reding, Andrew Morton,
	Linus Walleij, Wolfram Sang, linux-arm-kernel, linux-tegra,
	linux-kernel

Export APB DMA readl and writel. These are needed because we can't access
the fuses directly on Tegra20 without potentially causing a system hang.
Also have the APB DMA readl and writel return an error in case of a read
failure instead of just returning zero or ignore write failures.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 arch/arm/mach-tegra/apbio.c |   51 ++++++++++++++++++++++++++----------------
 include/linux/tegra-soc.h   |   14 +++++++++++
 2 files changed, 45 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index bc47197..e0bf49d 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -32,8 +32,8 @@ static u32 *tegra_apb_bb;
 static dma_addr_t tegra_apb_bb_phys;
 static DECLARE_COMPLETION(tegra_apb_wait);
 
-static u32 tegra_apb_readl_direct(unsigned long offset);
-static void tegra_apb_writel_direct(u32 value, unsigned long offset);
+static int tegra_apb_readl_direct(unsigned long offset, u32 *value);
+static int tegra_apb_writel_direct(u32 value, unsigned long offset);
 
 static struct dma_chan *tegra_apb_dma_chan;
 static struct dma_slave_config dma_sconfig;
@@ -128,58 +128,64 @@ static int do_dma_transfer(unsigned long apb_add,
 	return 0;
 }
 
-static u32 tegra_apb_readl_using_dma(unsigned long offset)
+int tegra_apb_readl_using_dma(unsigned long offset, u32 *value)
 {
 	int ret;
 
 	if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
-		return tegra_apb_readl_direct(offset);
+		return tegra_apb_readl_direct(offset, value);
 
 	mutex_lock(&tegra_apb_dma_lock);
 	ret = do_dma_transfer(offset, DMA_DEV_TO_MEM);
-	if (ret < 0) {
+	if (ret < 0)
 		pr_err("error in reading offset 0x%08lx using dma\n", offset);
-		*(u32 *)tegra_apb_bb = 0;
-	}
+	else
+		*value = *tegra_apb_bb;
+
 	mutex_unlock(&tegra_apb_dma_lock);
-	return *((u32 *)tegra_apb_bb);
+
+	return ret;
 }
 
-static void tegra_apb_writel_using_dma(u32 value, unsigned long offset)
+int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
 {
 	int ret;
 
-	if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) {
-		tegra_apb_writel_direct(value, offset);
-		return;
-	}
+	if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
+		return tegra_apb_writel_direct(value, offset);
 
 	mutex_lock(&tegra_apb_dma_lock);
 	*((u32 *)tegra_apb_bb) = value;
 	ret = do_dma_transfer(offset, DMA_MEM_TO_DEV);
+	mutex_unlock(&tegra_apb_dma_lock);
 	if (ret < 0)
 		pr_err("error in writing offset 0x%08lx using dma\n", offset);
-	mutex_unlock(&tegra_apb_dma_lock);
+
+	return ret;
 }
 #else
 #define tegra_apb_readl_using_dma tegra_apb_readl_direct
 #define tegra_apb_writel_using_dma tegra_apb_writel_direct
 #endif
 
-typedef u32 (*apbio_read_fptr)(unsigned long offset);
-typedef void (*apbio_write_fptr)(u32 value, unsigned long offset);
+typedef int (*apbio_read_fptr)(unsigned long offset, u32 *value);
+typedef int (*apbio_write_fptr)(u32 value, unsigned long offset);
 
 static apbio_read_fptr apbio_read;
 static apbio_write_fptr apbio_write;
 
-static u32 tegra_apb_readl_direct(unsigned long offset)
+static int tegra_apb_readl_direct(unsigned long offset, u32 *value)
 {
-	return readl(IO_ADDRESS(offset));
+	*value = readl(IO_ADDRESS(offset));
+
+	return 0;
 }
 
-static void tegra_apb_writel_direct(u32 value, unsigned long offset)
+static int tegra_apb_writel_direct(u32 value, unsigned long offset)
 {
 	writel(value, IO_ADDRESS(offset));
+
+	return 0;
 }
 
 void tegra_apb_io_init(void)
@@ -197,7 +203,12 @@ void tegra_apb_io_init(void)
 
 u32 tegra_apb_readl(unsigned long offset)
 {
-	return apbio_read(offset);
+	u32 val;
+
+	if (apbio_read(offset, &val) < 0)
+		return 0;
+	else
+		return val;
 }
 
 void tegra_apb_writel(u32 value, unsigned long offset)
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 95f611d..b02d73b 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -19,4 +19,18 @@
 
 u32 tegra_read_chipid(void);
 
+
+#if defined(CONFIG_TEGRA20_APB_DMA)
+int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);
+int tegra_apb_writel_using_dma(u32 value, unsigned long offset);
+#else
+static inline int tegra_apb_readl_using_dma(unsigned long offset, u32 *value)
+{
+	return -EINVAL;
+}
+static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
+{
+	return -EINVAL;
+}
+#endif
 #endif /* __LINUX_TEGRA_SOC_H_ */
-- 
1.7.7.rc0.72.g4b5ea.dirty


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v5 2/5] ARM: tegra: move fuse exports to tegra-soc.h
  2014-05-28 12:54 [PATCH v5 0/5] efuse driver for Tegra Peter De Schrijver
  2014-05-28 12:54 ` [PATCH v5 1/5] ARM: tegra: export apb dma readl/writel Peter De Schrijver
@ 2014-05-28 12:54 ` Peter De Schrijver
  2014-05-29 19:01   ` Stephen Warren
  2014-05-28 12:54 ` [PATCH v5 3/5] misc: fuse: Add efuse driver for Tegra Peter De Schrijver
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Peter De Schrijver @ 2014-05-28 12:54 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Stephen Warren, Thierry Reding, Andrew Morton,
	Linus Walleij, Wolfram Sang, linux-arm-kernel, linux-tegra,
	linux-kernel

All fuse related functionality will move to a driver in the following patches.
To prepare for this, export all the required functionality in a global header
file and move all users of fuse.h to tegra-soc.h. While we're at it, remove
tegra_bct_strapping, as its only user was removed in Commit a7cbe92cef27
("ARM: tegra: remove tegra EMC scaling driver").

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 arch/arm/mach-tegra/cpuidle.c         |    2 +-
 arch/arm/mach-tegra/flowctrl.c        |    2 +-
 arch/arm/mach-tegra/fuse.h            |   18 ------------------
 arch/arm/mach-tegra/hotplug.c         |    2 +-
 arch/arm/mach-tegra/platsmp.c         |    2 +-
 arch/arm/mach-tegra/pm.c              |    2 +-
 arch/arm/mach-tegra/pmc.c             |    2 +-
 arch/arm/mach-tegra/powergate.c       |    2 +-
 arch/arm/mach-tegra/reset-handler.S   |    2 +-
 arch/arm/mach-tegra/reset.c           |    2 +-
 arch/arm/mach-tegra/sleep-tegra30.S   |    2 +-
 arch/arm/mach-tegra/tegra.c           |    2 +-
 arch/arm/mach-tegra/tegra114_speedo.c |    1 +
 arch/arm/mach-tegra/tegra20_speedo.c  |    1 +
 arch/arm/mach-tegra/tegra30_speedo.c  |    1 +
 include/linux/tegra-soc.h             |   25 +++++++++++++++++++++++++
 16 files changed, 39 insertions(+), 29 deletions(-)

diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
index 7bc5d8d..ff0a10b 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -23,8 +23,8 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/tegra-soc.h>
 
-#include "fuse.h"
 #include "cpuidle.h"
 
 void __init tegra_cpuidle_init(void)
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c
index ce8ab8a..4b31091 100644
--- a/arch/arm/mach-tegra/flowctrl.c
+++ b/arch/arm/mach-tegra/flowctrl.c
@@ -22,10 +22,10 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/cpumask.h>
+#include <linux/tegra-soc.h>
 
 #include "flowctrl.h"
 #include "iomap.h"
-#include "fuse.h"
 
 static u8 flowctrl_offset_halt_cpu[] = {
 	FLOW_CTRL_HALT_CPU0_EVENTS,
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index c01d047..b17c4ba 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -26,21 +26,7 @@
 #define SKU_ID_AP25E	27
 #define SKU_ID_T25E	28
 
-#define TEGRA20		0x20
-#define TEGRA30		0x30
-#define TEGRA114	0x35
-#define TEGRA124	0x40
-
 #ifndef __ASSEMBLY__
-enum tegra_revision {
-	TEGRA_REVISION_UNKNOWN = 0,
-	TEGRA_REVISION_A01,
-	TEGRA_REVISION_A02,
-	TEGRA_REVISION_A03,
-	TEGRA_REVISION_A03p,
-	TEGRA_REVISION_A04,
-	TEGRA_REVISION_MAX,
-};
 
 extern int tegra_sku_id;
 extern int tegra_cpu_process_id;
@@ -48,12 +34,8 @@ extern int tegra_core_process_id;
 extern int tegra_chip_id;
 extern int tegra_cpu_speedo_id;		/* only exist in Tegra30 and later */
 extern int tegra_soc_speedo_id;
-extern enum tegra_revision tegra_revision;
-
-extern int tegra_bct_strapping;
 
 unsigned long long tegra_chip_uid(void);
-void tegra_init_fuse(void);
 bool tegra_spare_fuse(int bit);
 u32 tegra_fuse_readl(unsigned long offset);
 
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index ff26af2..38c5170 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -10,10 +10,10 @@
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/clk/tegra.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/smp_plat.h>
 
-#include "fuse.h"
 #include "sleep.h"
 
 static void (*tegra_hotplug_shutdown)(void);
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 929d104..d9878ac 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -19,13 +19,13 @@
 #include <linux/smp.h>
 #include <linux/io.h>
 #include <linux/clk/tegra.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/cacheflush.h>
 #include <asm/mach-types.h>
 #include <asm/smp_scu.h>
 #include <asm/smp_plat.h>
 
-#include "fuse.h"
 #include "flowctrl.h"
 #include "reset.h"
 #include "pmc.h"
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index f55b05a..d7e6370 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -26,6 +26,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/clk/tegra.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/smp_plat.h>
 #include <asm/cacheflush.h>
@@ -37,7 +38,6 @@
 #include "iomap.h"
 #include "reset.h"
 #include "flowctrl.h"
-#include "fuse.h"
 #include "pm.h"
 #include "pmc.h"
 #include "sleep.h"
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
index fb79202..d8fe587 100644
--- a/arch/arm/mach-tegra/pmc.c
+++ b/arch/arm/mach-tegra/pmc.c
@@ -21,9 +21,9 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/tegra-powergate.h>
+#include <linux/tegra-soc.h>
 
 #include "flowctrl.h"
-#include "fuse.h"
 #include "pm.h"
 #include "pmc.h"
 #include "sleep.h"
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 4cefc5c..50a9af4 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -30,8 +30,8 @@
 #include <linux/spinlock.h>
 #include <linux/clk/tegra.h>
 #include <linux/tegra-powergate.h>
+#include <linux/tegra-soc.h>
 
-#include "fuse.h"
 #include "iomap.h"
 
 #define DPD_SAMPLE		0x020
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
index 8c1ba4f..0c480d69 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -20,9 +20,9 @@
 #include <asm/cache.h>
 #include <asm/asm-offsets.h>
 #include <asm/hardware/cache-l2x0.h>
+#include <linux/tegra-soc.h>
 
 #include "flowctrl.h"
-#include "fuse.h"
 #include "iomap.h"
 #include "reset.h"
 #include "sleep.h"
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
index 146fe8e..203bac5 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -22,12 +22,12 @@
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/firmware.h>
+#include <linux/tegra-soc.h>
 
 #include "iomap.h"
 #include "irammap.h"
 #include "reset.h"
 #include "sleep.h"
-#include "fuse.h"
 
 #define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \
 				TEGRA_IRAM_RESET_HANDLER_OFFSET)
diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S
index b16d4a57..f808c2c 100644
--- a/arch/arm/mach-tegra/sleep-tegra30.S
+++ b/arch/arm/mach-tegra/sleep-tegra30.S
@@ -15,13 +15,13 @@
  */
 
 #include <linux/linkage.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
 #include <asm/cache.h>
 
 #include "irammap.h"
-#include "fuse.h"
 #include "sleep.h"
 #include "flowctrl.h"
 
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 6191603..e48b271 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -34,6 +34,7 @@
 #include <linux/usb/tegra_usb_phy.h>
 #include <linux/clk/tegra.h>
 #include <linux/irqchip.h>
+#include <linux/tegra-soc.h>
 
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach-types.h>
@@ -46,7 +47,6 @@
 #include "board.h"
 #include "common.h"
 #include "cpuidle.h"
-#include "fuse.h"
 #include "iomap.h"
 #include "irq.h"
 #include "pmc.h"
diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c
index 5218d48..7c73716 100644
--- a/arch/arm/mach-tegra/tegra114_speedo.c
+++ b/arch/arm/mach-tegra/tegra114_speedo.c
@@ -16,6 +16,7 @@
 
 #include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/tegra-soc.h>
 
 #include "fuse.h"
 
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c
index fa6eb57..3b1bb53 100644
--- a/arch/arm/mach-tegra/tegra20_speedo.c
+++ b/arch/arm/mach-tegra/tegra20_speedo.c
@@ -16,6 +16,7 @@
 
 #include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/tegra-soc.h>
 
 #include "fuse.h"
 
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c
index 125cb16..81a958d 100644
--- a/arch/arm/mach-tegra/tegra30_speedo.c
+++ b/arch/arm/mach-tegra/tegra30_speedo.c
@@ -16,6 +16,7 @@
 
 #include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/tegra-soc.h>
 
 #include "fuse.h"
 
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index b02d73b..60e6ac8 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -17,8 +17,29 @@
 #ifndef __LINUX_TEGRA_SOC_H_
 #define __LINUX_TEGRA_SOC_H_
 
+#define TEGRA20		0x20
+#define TEGRA30		0x30
+#define TEGRA114	0x35
+#define TEGRA124	0x40
+
+#ifndef __ASSEMBLY__
+
+enum tegra_revision {
+	TEGRA_REVISION_UNKNOWN = 0,
+	TEGRA_REVISION_A01,
+	TEGRA_REVISION_A02,
+	TEGRA_REVISION_A03,
+	TEGRA_REVISION_A03p,
+	TEGRA_REVISION_A04,
+	TEGRA_REVISION_MAX,
+};
+
+u32 tegra_read_straps(void);
 u32 tegra_read_chipid(void);
+void tegra_init_fuse(void);
 
+extern int tegra_chip_id;
+extern enum tegra_revision tegra_revision;
 
 #if defined(CONFIG_TEGRA20_APB_DMA)
 int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);
@@ -33,4 +54,8 @@ static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
 	return -EINVAL;
 }
 #endif
+
+#endif /* __ASSEMBLY__ */
+
+
 #endif /* __LINUX_TEGRA_SOC_H_ */
-- 
1.7.7.rc0.72.g4b5ea.dirty


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v5 3/5] misc: fuse: Add efuse driver for Tegra
  2014-05-28 12:54 [PATCH v5 0/5] efuse driver for Tegra Peter De Schrijver
  2014-05-28 12:54 ` [PATCH v5 1/5] ARM: tegra: export apb dma readl/writel Peter De Schrijver
  2014-05-28 12:54 ` [PATCH v5 2/5] ARM: tegra: move fuse exports to tegra-soc.h Peter De Schrijver
@ 2014-05-28 12:54 ` Peter De Schrijver
  2014-05-29 19:04   ` Stephen Warren
  2014-05-28 12:54 ` [PATCH v5 4/5] ARM: tegra: Add efuse and apbmisc bindings Peter De Schrijver
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Peter De Schrijver @ 2014-05-28 12:54 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Stephen Warren, Thierry Reding, Andrew Morton,
	Linus Walleij, Wolfram Sang, linux-arm-kernel, linux-tegra,
	linux-kernel

Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 Documentation/ABI/testing/sysfs-driver-tegra-fuse |  201 ++++++++++++++
 drivers/misc/fuse/Makefile                        |    1 +
 drivers/misc/fuse/tegra/Makefile                  |    7 +
 drivers/misc/fuse/tegra/fuse-tegra.c              |  250 +++++++++++++++++
 drivers/misc/fuse/tegra/fuse-tegra20.c            |  134 ++++++++++
 drivers/misc/fuse/tegra/fuse-tegra30.c            |  177 +++++++++++++
 drivers/misc/fuse/tegra/fuse.h                    |   82 ++++++
 drivers/misc/fuse/tegra/speedo-tegra114.c         |  110 ++++++++
 drivers/misc/fuse/tegra/speedo-tegra124.c         |  180 +++++++++++++
 drivers/misc/fuse/tegra/speedo-tegra20.c          |  110 ++++++++
 drivers/misc/fuse/tegra/speedo-tegra30.c          |  294 +++++++++++++++++++++
 include/linux/tegra-soc.h                         |    4 +
 12 files changed, 1550 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse
 create mode 100644 drivers/misc/fuse/Makefile
 create mode 100644 drivers/misc/fuse/tegra/Makefile
 create mode 100644 drivers/misc/fuse/tegra/fuse-tegra.c
 create mode 100644 drivers/misc/fuse/tegra/fuse-tegra20.c
 create mode 100644 drivers/misc/fuse/tegra/fuse-tegra30.c
 create mode 100644 drivers/misc/fuse/tegra/fuse.h
 create mode 100644 drivers/misc/fuse/tegra/speedo-tegra114.c
 create mode 100644 drivers/misc/fuse/tegra/speedo-tegra124.c
 create mode 100644 drivers/misc/fuse/tegra/speedo-tegra20.c
 create mode 100644 drivers/misc/fuse/tegra/speedo-tegra30.c

diff --git a/Documentation/ABI/testing/sysfs-driver-tegra-fuse b/Documentation/ABI/testing/sysfs-driver-tegra-fuse
new file mode 100644
index 0000000..9d558d1
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-tegra-fuse
@@ -0,0 +1,201 @@
+What:		/sys/devices/*/<our-device>/fuse
+Date:		February 2014
+Contact:	Peter De Schrijver <pdeschrijver@nvidia.com>
+Description:	read-only access to the efuses on Tegra20, Tegra30, Tegra114
+		and Tegra124 SoC's from NVIDIA. The efuses contain write once
+		data programmed at the factory. The data is layed out in 32bit
+		words in LSB first formnat. The number of valid bits depends
+		on the word and the SoC. The mapping is as follows:
+
+		For Tegra20:
+		Word 0 - 1    : bit 0
+		Word 2        : unused
+		Word 3        : bits 0 - 31
+		Word 4        : bits 0 - 7
+		Word 5        : bits 0 - 1
+		Word 6        : bits 0 - 9
+		Word 7 - 9    : bits 0 - 7
+		Word 10 - 17  : unused
+		Word 18       : bit 0
+		Word 19       : bits 0 - 3
+		Word 20 - 23  : bits 0 - 5
+		Word 24 - 39  : unused
+		Word 40       : bit 0
+		Word 41 - 45  : bits 0 - 31
+		Word 46       : bit 0
+		Word 47       : bits 0 - 15
+		Word 48       : bits 0 - 7
+		Word 49       : bits 0 - 3
+		Word 50 - 57  : bits 0 - 31
+		Word 58       : bit 0
+		Word 59       : bits 0 - 1
+		Word 60       : bits 0 - 6
+		Word 61       : unused
+		Word 62 - 63  : bits 0 - 1
+		Word 64 - 125 : bit 0
+
+		For Tegra30:
+		Word 0 - 1    :	bit 0
+		Word 2 - 3    :	unused
+		Word 4        :	bits 0 - 7
+		Word 5        :	bits 0 - 31
+		Word 6        :	bits 0 - 15
+		Word 7 - 9    :	bits 0 - 7
+		Word 10       :	bits 0 - 6
+		Word 11 - 16  : unused
+		Word 17       : bits 0 - 1
+		Word 18       : bit 0
+		Word 19 - 23  :	bits 0 - 5
+		Word 24       : bits 0 - 3
+		Word 25 - 34  : unused
+		Word 35       : bits 0 - 31
+		Word 36       : bits 0 - 6
+		Word 37       : bits 0 - 13
+		Word 38       : bits 0 - 31
+		Word 39       : bits 0 - 6
+		Word 40       : bit 0
+		Word 41 - 45  : bits 0 - 31
+		Word 46       : bit 0
+		Word 47       : bits 0 - 15
+		Word 48       : bits 0 - 7
+		Word 49 - 57  : bits 0 - 31
+		Word 58       : bit 0
+		Word 59       : bits 0 - 1
+		Word 60       : bits 0 - 31
+		Word 61       : bits 0 - 7
+		Word 62       : bits 0 - 1
+		Word 63 - 64  : bits 0 - 3
+		Word 65       : bits 0 - 5
+		Word 66       : bits 0 - 31
+		Word 67       : bits 0 - 27
+		Word 68       : bits 0 - 5
+		Word 69 - 70  : bits 0 - 8
+		Word 71	      : unused
+		Word 72       : bits 0 - 5
+		Word 73       : bits 0 - 1
+		Word 74 - 75  : unused
+		Word 76 - 80  : bits 0 - 31
+	        Word 81 - 168 : bit 0
+
+		For Tegra114:
+		Word 0 - 1    :	bit 0
+		Word 2        : bits 0 - 3
+		Word 3        : unused
+		Word 4        :	bits 0 - 7
+		Word 5        :	bits 0 - 10
+		Word 6        :	bits 0 - 12
+		Word 7 - 9    : unused
+		Word 10 - 16  :	bits 0 - 11
+		Word 17       : unused
+		Word 18       : bit 0
+		Word 19       : bits 0 - 3
+		Word 20 - 23  : bits 0 - 7
+		Word 24       : bits 0 - 3
+		Word 25 - 32  : bits 0 - 31
+		Word 33 - 34  : bits 0 - 25
+		Word 35       : bits 0 - 31
+		Word 36       : bits 0 - 10
+		Word 37       : bits 0 - 13
+		Word 38       : bits 0 - 25
+		Word 39       : bits 0 - 6
+		Word 40       : bit 0
+		Word 41 - 45  : bits 0 - 31
+		Word 46       : bit 0
+		Word 47       : bits 0 - 15
+		Word 48       : bits 0 - 8
+		Word 49       : bit 0
+		Word 50 - 57  : bits 0 - 31
+		Word 58       : bit 0
+		Word 59       : bits 0 - 1
+		Word 60       : bits 0 - 31
+		Word 61       : bits 0 - 7
+		Word 62       : bits 0 - 1
+		Word 63 - 64  : bits 0 - 3
+		Word 65       : bits 0 - 5
+		Word 66       : bits 0 - 31
+		Word 67       : bits 0 - 27
+		Word 68       : bits 0 - 5
+		Word 69 - 70  : bits 0 - 8
+		Word 71       : unused
+		Word 72       : bits 0 - 5
+		Word 75       : bits 0 - 25
+		Word 76 - 80  : bits 0 - 31
+		Word 81 - 84  : unused
+		Word 85 - 88  : bits 0 - 25
+		Word 89       : unused
+		Word 90 - 103 : bit 0
+
+		For Tegra124:
+		Word 0 - 1    :	bit 0
+		Word 2        : bits 0 - 3
+		Word 3        : bit 0
+		Word 4        :	bits 0 - 7
+		Word 5        :	bits 0 - 11
+		Word 6        :	bits 0 - 12
+		Word 7 - 9    : unused
+		Word 10       :	bits 0 - 10
+		Word 11 - 16  :	bits 0 - 11
+		Word 17       : unused
+		Word 18       : bit 0
+		Word 19       : bits 0 - 3
+		Word 20 - 23  : bits 0 - 7
+		Word 24       : bits 0 - 3
+		Word 25 - 32  : bits 0 - 31
+		Word 33 - 34  : bits 0 - 25
+		Word 35       : unused
+		Word 36       : bits 0 - 10
+		Word 37       : bits 0 - 13
+		Word 38       : bits 0 - 25
+		Word 39       : bits 0 - 6
+		Word 40       : bit 0
+		Word 41 - 45  : bits 0 - 31
+		Word 46       : bit 0
+		Word 47       : bits 0 - 15
+		Word 48       : bits 0 - 8
+		Word 49       : bit 0
+		Word 50 - 57  : bits 0 - 31
+		Word 58       : bit 0
+		Word 59       : unused
+		Word 60       : bits 0 - 31
+		Word 61       : bits 0 - 7
+		Word 62       : bits 0 - 1
+		Word 63 - 64  : bits 0 - 3
+		Word 65       : bits 0 - 5
+		Word 66       : bits 0 - 31
+		Word 67       : bits 0 - 27
+		Word 68       : bits 0 - 5
+		Word 69 - 70  : bits 0 - 8
+		Word 71       : bit 0
+		Word 72       : bits 0 - 5
+		Word 73       : bits 0 - 1
+		Word 74       : bits 0 - 11
+		Word 75       : bits 0 - 25
+		Word 76 - 80  : bits 0 - 31
+		Word 81       : bit 0
+		Word 82       : unused
+		Word 83 - 84  : bits 0 - 1
+		Word 85 - 88  : bits 0 - 25
+		Word 89 - 90  : bit 0
+		Word 91 - 94  : unused
+		Word 95       : bit 0
+		Word 96       : bits 0 - 25
+		Word 97       : bits 0 - 1
+		Word 98       : bit 0
+		Word 99       : bits 0 - 9
+		Word 100      : unused
+		Word 101      : bits 0 - 31
+		Word 102      : bit 0
+		Word 103      : unused
+		Word 104 - 105: bits 0 - 4
+		Word 106      : bit 0
+		Word 107      : bits 0 - 9
+		Word 108      : bits 0 - 3
+		Word 109      : bits 0 - 15
+		Word 110 - 112: bit 0
+		Word 113      : bits 0 - 7
+		Word 114      : bits 0 - 2
+		Word 115 - 191: unused
+		Word 192 - 255: bit 0
+
+Users:		any user space application which wants to read the efuses on
+		Tegra SoC's
diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile
new file mode 100644
index 0000000..0679c4f
--- /dev/null
+++ b/drivers/misc/fuse/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
diff --git a/drivers/misc/fuse/tegra/Makefile b/drivers/misc/fuse/tegra/Makefile
new file mode 100644
index 0000000..3a5b37f
--- /dev/null
+++ b/drivers/misc/fuse/tegra/Makefile
@@ -0,0 +1,7 @@
+obj-y					+= fuse-tegra.o
+obj-y					+= fuse-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= fuse-tegra20.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= speedo-tegra20.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= speedo-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= speedo-tegra114.o
+obj-$(CONFIG_ARCH_TEGRA_124_SOC)	+= speedo-tegra124.o
diff --git a/drivers/misc/fuse/tegra/fuse-tegra.c b/drivers/misc/fuse/tegra/fuse-tegra.c
new file mode 100644
index 0000000..ba32871
--- /dev/null
+++ b/drivers/misc/fuse/tegra/fuse-tegra.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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/device.h>
+#include <linux/kobject.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/tegra-soc.h>
+
+#include "fuse.h"
+
+#define APBMISC_BASE	0x70000800
+#define APBMISC_SIZE	0x64
+
+int tegra_chip_id;
+enum tegra_revision tegra_revision;
+
+/*
+ * The BCT to use at boot is specified by board straps that can be read
+ * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
+ */
+
+#define TEGRA_RAM_ID_SHIFT	4
+#define TEGRA_RAM_ID_MASK	3
+
+static u32 (*fuse_readl)(const unsigned int offset);
+static int fuse_size;
+static void __iomem *fuse_base;
+static void __iomem *apbmisc_base;
+static void __iomem *strapping_base;
+
+static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
+	[TEGRA_REVISION_UNKNOWN] = "unknown",
+	[TEGRA_REVISION_A01]     = "A01",
+	[TEGRA_REVISION_A02]     = "A02",
+	[TEGRA_REVISION_A03]     = "A03",
+	[TEGRA_REVISION_A03p]    = "A03 prime",
+	[TEGRA_REVISION_A04]     = "A04",
+};
+
+static u8 fuse_readb(const unsigned int offset)
+{
+	u32 val;
+
+	val = fuse_readl(round_down(offset, 4));
+	val >>= (offset % 4) * 8;
+	val &= 0xff;
+
+	return val;
+}
+
+static ssize_t fuse_read(struct file *fd, struct kobject *kobj,
+			struct bin_attribute *attr, char *buf,
+			loff_t pos, size_t size)
+{
+	int i;
+
+	if (pos < 0 || pos >= fuse_size)
+		return 0;
+
+	if (size > fuse_size - pos)
+		size = fuse_size - pos;
+
+	for (i = 0; i < size; i++)
+		buf[i] = fuse_readb(pos + i);
+
+	return i;
+}
+
+static struct bin_attribute fuse_bin_attr = {
+	.attr = { .name = "fuse", .mode = S_IRUGO, },
+	.read = fuse_read,
+};
+
+static const struct of_device_id tegra_fuse_match[] __initconst = {
+	{ .compatible = "nvidia,tegra20-efuse", },
+	{ .compatible = "nvidia,tegra30-efuse", },
+	{ .compatible = "nvidia,tegra114-efuse", },
+	{ .compatible = "nvidia,tegra124-efuse", },
+	{},
+};
+
+static const struct of_device_id car_match[] __initconst = {
+	{ .compatible = "nvidia,tegra20-car", },
+	{ .compatible = "nvidia,tegra30-car", },
+	{ .compatible = "nvidia,tegra114-car", },
+	{ .compatible = "nvidia,tegra124-car", },
+	{},
+};
+
+static const struct of_device_id apbmisc_match[] __initconst = {
+	{ .compatible = "nvidia,tegra20-apbmisc", },
+	{},
+};
+
+static void tegra_get_revision(u32 id)
+{
+	u32 minor_rev = (id >> 16) & 0xf;
+
+	switch (minor_rev) {
+	case 1:
+		tegra_revision = TEGRA_REVISION_A01;
+		break;
+	case 2:
+		tegra_revision = TEGRA_REVISION_A02;
+		break;
+	case 3:
+		if (tegra_chip_id == TEGRA20 &&
+			(tegra20_spare_fuse_early(18, fuse_base) ||
+			 tegra20_spare_fuse_early(19, fuse_base)))
+			tegra_revision = TEGRA_REVISION_A03p;
+		else
+			tegra_revision = TEGRA_REVISION_A03;
+		break;
+	case 4:
+		tegra_revision = TEGRA_REVISION_A04;
+		break;
+	default:
+		tegra_revision = TEGRA_REVISION_UNKNOWN;
+	}
+}
+
+static void tegra_enable_fuse_clk(void __iomem *base)
+{
+	u32 reg;
+
+	reg = readl_relaxed(base + 0x48);
+	reg |= 1 << 28;
+	writel(reg, base + 0x48);
+
+	/*
+	 * Enable FUSE clock. This needs to be hardcoded because the clock
+	 * subsystem is not active during early boot.
+	 */
+	reg = readl(base + 0x14);
+	reg |= 1 << 7;
+	writel(reg, base + 0x14);
+}
+
+u32 tegra_read_straps(void)
+{
+	if (strapping_base)
+		return readl(strapping_base);
+	else
+		return 0;
+}
+
+u32 tegra_read_chipid(void)
+{
+	return readl_relaxed(apbmisc_base + 4);
+}
+
+int tegra_fuse_readl(u32 offset, u32 *val)
+{
+	if (!fuse_readl)
+		return -ENXIO;
+
+	*val = fuse_readl(offset);
+
+	return 0;
+}
+
+int tegra_fuse_create_sysfs(struct device *dev, int size,
+		     u32 (*readl)(const unsigned int offset),
+		     struct tegra_sku_info *sku_info)
+{
+	int err;
+
+	if (fuse_size)
+		return -ENODEV;
+
+	fuse_bin_attr.size = size;
+	fuse_bin_attr.read = fuse_read;
+
+	fuse_size = size;
+	fuse_readl = readl;
+
+	err = device_create_bin_file(dev, &fuse_bin_attr);
+	if (err)
+		return err;
+
+	dev_info(dev,
+		"Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
+		tegra_revision_name[sku_info->revision],
+		sku_info->sku_id, sku_info->cpu_process_id,
+		sku_info->core_process_id);
+
+	return 0;
+}
+
+void __init tegra_init_fuse(void)
+{
+	struct device_node *np;
+	u32 id;
+	void __iomem *car_base;
+
+	np = of_find_matching_node(NULL, apbmisc_match);
+	apbmisc_base = of_iomap(np, 0);
+	if (!apbmisc_base) {
+		pr_warn("ioremap tegra apbmisc failed. using %08x instead\n",
+			APBMISC_BASE);
+		apbmisc_base = ioremap(APBMISC_BASE, APBMISC_SIZE);
+	}
+
+	id = tegra_read_chipid();
+	tegra_chip_id = (id >> 8) & 0xff;
+
+	strapping_base = of_iomap(np, 0);
+	if (!strapping_base) {
+		pr_err("ioremap tegra strapping_base failed\n");
+		return;
+	}
+
+	np = of_find_matching_node(NULL, tegra_fuse_match);
+	fuse_base = of_iomap(np, 0);
+	if (!fuse_base) {
+		pr_err("ioremap tegra fuse failed\n");
+		return;
+	}
+
+	np = of_find_matching_node(NULL, car_match);
+	car_base = of_iomap(np, 0);
+	if (car_base) {
+		tegra_enable_fuse_clk(car_base);
+		iounmap(car_base);
+	} else {
+		pr_err("Could not enable fuse clk. ioremap tegra car failed.\n");
+		iounmap(fuse_base);
+		return;
+	}
+
+	tegra_get_revision(id);
+}
diff --git a/drivers/misc/fuse/tegra/fuse-tegra20.c b/drivers/misc/fuse/tegra/fuse-tegra20.c
new file mode 100644
index 0000000..852da92
--- /dev/null
+++ b/drivers/misc/fuse/tegra/fuse-tegra20.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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/>.
+ *
+ * Based on drivers/misc/eeprom/sunxi_sid.c
+ */
+
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/tegra-soc.h>
+
+#include "fuse.h"
+
+#define FUSE_BEGIN	0x100
+#define FUSE_SIZE	0x1f8
+#define FUSE_SKU_INFO	0x10
+#define FUSE_UID_LOW	0x08
+#define FUSE_UID_HIGH	0x0c
+
+static phys_addr_t fuse_phys;
+static struct clk *fuse_clk;
+static struct tegra_sku_info sku_info;
+
+static u32 tegra20_fuse_readl(const unsigned int offset)
+{
+	int ret;
+	u32 val;
+
+	clk_prepare_enable(fuse_clk);
+
+	ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val);
+
+	clk_disable_unprepare(fuse_clk);
+
+	return (ret < 0) ? 0 : val;
+}
+
+static void tegra20_fuse_add_randomness(void)
+{
+	u32 randomness[7];
+
+	randomness[0] = tegra20_fuse_readl(FUSE_SKU_INFO);
+	randomness[1] = tegra_read_straps();
+	randomness[2] = tegra_read_chipid();
+	randomness[3] = sku_info.cpu_process_id << 16;
+	randomness[3] |= sku_info.core_process_id;
+	randomness[4] = sku_info.cpu_speedo_id << 16 | sku_info.soc_speedo_id;
+	randomness[5] = tegra20_fuse_readl(FUSE_UID_LOW);
+	randomness[6] = tegra20_fuse_readl(FUSE_UID_HIGH);
+
+	add_device_randomness(randomness, sizeof(randomness));
+}
+
+bool tegra20_spare_fuse(int spare_bit)
+{
+	u32 offset = spare_bit * 4 + 0x100;
+
+	return tegra20_fuse_readl(offset) & 1;
+}
+
+bool tegra20_spare_fuse_early(int spare_bit, void *fuse_base)
+{
+	u32 offset = spare_bit * 4 + 0x100;
+
+	return readl_relaxed(fuse_base + FUSE_BEGIN + offset);
+}
+
+static const struct of_device_id tegra20_fuse_of_match[] = {
+	{ .compatible = "nvidia,tegra20-efuse" },
+	{},
+};
+
+static int tegra20_fuse_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	fuse_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(fuse_clk)) {
+		dev_err(&pdev->dev, "missing clock");
+		return PTR_ERR(fuse_clk);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+	fuse_phys = res->start;
+
+	sku_info.revision = tegra_revision;
+	tegra20_init_speedo_data(&sku_info, &pdev->dev);
+	dev_dbg(&pdev->dev, "Soc Speedo ID %d", sku_info.soc_speedo_id);
+
+	tegra20_fuse_add_randomness();
+
+	if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl,
+			     &sku_info))
+		return -ENODEV;
+
+	dev_dbg(&pdev->dev, "loaded\n");
+
+	return 0;
+}
+
+static struct platform_driver tegra20_fuse_driver = {
+	.probe = tegra20_fuse_probe,
+	.driver = {
+		.name = "tegra20_fuse",
+		.owner = THIS_MODULE,
+		.of_match_table = tegra20_fuse_of_match,
+	}
+};
+
+static int __init tegra20_fuse_init(void)
+{
+	return platform_driver_register(&tegra20_fuse_driver);
+}
+postcore_initcall(tegra20_fuse_init);
diff --git a/drivers/misc/fuse/tegra/fuse-tegra30.c b/drivers/misc/fuse/tegra/fuse-tegra30.c
new file mode 100644
index 0000000..4aa6490
--- /dev/null
+++ b/drivers/misc/fuse/tegra/fuse-tegra30.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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/device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/tegra-soc.h>
+
+#include "fuse.h"
+
+#define FUSE_BEGIN	0x100
+
+#define FUSE_SKU_INFO		0x10
+
+/* Tegra30 and later */
+#define FUSE_VENDOR_CODE	0x100
+#define FUSE_FAB_CODE		0x104
+#define FUSE_LOT_CODE_0		0x108
+#define FUSE_LOT_CODE_1		0x10c
+#define FUSE_WAFER_ID		0x110
+#define FUSE_X_COORDINATE	0x114
+#define FUSE_Y_COORDINATE	0x118
+
+#define FUSE_HAS_REVISION_INFO	BIT(0)
+
+struct tegra_fuse_info {
+	int	size;
+	int	spare_bit;
+	void	(*init_speedo_data)(struct tegra_sku_info *sku_info,
+				    struct device *dev);
+};
+
+static void __iomem *fuse_base;
+static struct clk *fuse_clk;
+static struct tegra_fuse_info *fuse_info;
+static struct tegra_sku_info sku_info;
+
+u32 tegra30_fuse_readl(const unsigned int offset)
+{
+	u32 val;
+
+	clk_prepare_enable(fuse_clk);
+
+	val = readl_relaxed(fuse_base + FUSE_BEGIN + offset);
+
+	clk_disable_unprepare(fuse_clk);
+
+	return val;
+}
+
+bool tegra30_spare_fuse(int spare_bit)
+{
+	u32 offset = fuse_info->spare_bit + spare_bit * 4;
+
+	return tegra30_fuse_readl(offset) & 1;
+}
+
+static void tegra30_fuse_add_randomness(void)
+{
+	u32 randomness[12];
+
+	randomness[0] = tegra30_fuse_readl(FUSE_SKU_INFO);
+	randomness[1] = tegra_read_straps();
+	randomness[2] = tegra_read_chipid();
+	randomness[3] = sku_info.cpu_process_id << 16;
+	randomness[3] |= sku_info.core_process_id;
+	randomness[4] = sku_info.cpu_speedo_id << 16;
+	randomness[4] |= sku_info.soc_speedo_id;
+	randomness[5] = tegra30_fuse_readl(FUSE_VENDOR_CODE);
+	randomness[6] = tegra30_fuse_readl(FUSE_FAB_CODE);
+	randomness[7] = tegra30_fuse_readl(FUSE_LOT_CODE_0);
+	randomness[8] = tegra30_fuse_readl(FUSE_LOT_CODE_1);
+	randomness[9] = tegra30_fuse_readl(FUSE_WAFER_ID);
+	randomness[10] = tegra30_fuse_readl(FUSE_X_COORDINATE);
+	randomness[11] = tegra30_fuse_readl(FUSE_Y_COORDINATE);
+
+	add_device_randomness(randomness, sizeof(randomness));
+}
+
+static struct tegra_fuse_info tegra30_info = {
+	.size			= 0x2a4,
+	.spare_bit		= 0x144,
+	.init_speedo_data	= tegra30_init_speedo_data,
+};
+
+static struct tegra_fuse_info tegra114_info = {
+	.size			= 0x2a0,
+	.init_speedo_data	= tegra114_init_speedo_data,
+};
+
+static struct tegra_fuse_info tegra124_info = {
+	.size			= 0x300,
+	.init_speedo_data	= tegra124_init_speedo_data,
+};
+
+static const struct of_device_id tegra30_fuse_of_match[] = {
+	{ .compatible = "nvidia,tegra30-efuse", .data = &tegra30_info },
+	{ .compatible = "nvidia,tegra114-efuse", .data = &tegra114_info },
+	{ .compatible = "nvidia,tegra124-efuse", .data = &tegra124_info },
+	{},
+};
+
+static int tegra30_fuse_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_dev_id;
+	struct resource *res;
+
+	of_dev_id = of_match_device(tegra30_fuse_of_match, &pdev->dev);
+	if (!of_dev_id)
+		return -ENODEV;
+	fuse_info = (struct tegra_fuse_info *)of_dev_id->data;
+
+	fuse_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(fuse_clk)) {
+		dev_err(&pdev->dev, "missing clock");
+		return PTR_ERR(fuse_clk);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	fuse_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(fuse_base)) {
+		dev_err(&pdev->dev, "unable to map base address");
+		return PTR_ERR(fuse_base);
+	}
+
+	sku_info.revision = tegra_revision;
+	fuse_info->init_speedo_data(&sku_info, &pdev->dev);
+	dev_dbg(&pdev->dev, "CPU Speedo ID %d, Soc Speedo ID %d",
+		sku_info.cpu_speedo_id, sku_info.soc_speedo_id);
+
+	tegra30_fuse_add_randomness();
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (tegra_fuse_create_sysfs(&pdev->dev, fuse_info->size,
+				    tegra30_fuse_readl, &sku_info))
+		return -ENODEV;
+
+	dev_dbg(&pdev->dev, "loaded\n");
+
+	return 0;
+}
+
+static struct platform_driver tegra30_fuse_driver = {
+	.probe = tegra30_fuse_probe,
+	.driver = {
+		.name = "tegra_fuse",
+		.owner = THIS_MODULE,
+		.of_match_table = tegra30_fuse_of_match,
+	}
+};
+
+static int __init tegra30_fuse_init(void)
+{
+	return platform_driver_register(&tegra30_fuse_driver);
+}
+postcore_initcall(tegra30_fuse_init);
+
diff --git a/drivers/misc/fuse/tegra/fuse.h b/drivers/misc/fuse/tegra/fuse.h
new file mode 100644
index 0000000..0baf82b
--- /dev/null
+++ b/drivers/misc/fuse/tegra/fuse.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Author:
+ *	Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ */
+
+#ifndef __DRIVERS_MISC_TEGRA_FUSE_H
+#define __DRIVERS_MISC_TEGRA_FUSE_H
+
+struct tegra_sku_info {
+	int sku_id;
+	int cpu_process_id;
+	int cpu_speedo_id;
+	int cpu_speedo_value;
+	int cpu_iddq_value;
+	int core_process_id;
+	int soc_speedo_id;
+	int gpu_speedo_id;
+	int gpu_process_id;
+	int gpu_speedo_value;
+	enum tegra_revision revision;
+};
+
+int tegra_fuse_create_sysfs(struct device *dev, int size,
+		     u32 (*readl)(const unsigned int offset),
+		     struct tegra_sku_info *sku_info);
+
+bool tegra30_spare_fuse(int bit);
+u32 tegra30_fuse_readl(const unsigned int offset);
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+void tegra20_init_speedo_data(struct tegra_sku_info *sku_info,
+			      struct device *dev);
+bool tegra20_spare_fuse(int bit);
+bool tegra20_spare_fuse_early(int spare_bit, void *fuse_base);
+#else
+static inline void tegra20_init_speedo_data(struct tegra_sku_info *sku_info,
+					    struct device *dev) {}
+static inline bool tegra20_spare_fuse(int bit) { return false; }
+static inline bool tegra20_spare_fuse_early(int spare_bit, void *fuse_base)
+{
+			return false;
+}
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+void tegra30_init_speedo_data(struct tegra_sku_info *sku_info,
+			      struct device *dev);
+#else
+static inline void tegra30_init_speedo_data(struct tegra_sku_info *sku_info,
+					    struct device *dev) {}
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+void tegra114_init_speedo_data(struct tegra_sku_info *sku_info,
+			       struct device *dev);
+#else
+static inline void tegra114_init_speedo_data(struct tegra_sku_info *sku_info,
+					     struct device *dev) {}
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_124_SOC
+void tegra124_init_speedo_data(struct tegra_sku_info *sku_info,
+			       struct device *dev);
+#else
+static inline void tegra124_init_speedo_data(struct tegra_sku_info *sku_info,
+					     struct device *dev) {}
+#endif
+
+#endif
diff --git a/drivers/misc/fuse/tegra/speedo-tegra114.c b/drivers/misc/fuse/tegra/speedo-tegra114.c
new file mode 100644
index 0000000..7be8ba5
--- /dev/null
+++ b/drivers/misc/fuse/tegra/speedo-tegra114.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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/device.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/tegra-soc.h>
+
+#include "fuse.h"
+
+#define CORE_PROCESS_CORNERS_NUM	2
+#define CPU_PROCESS_CORNERS_NUM		2
+
+enum {
+	THRESHOLD_INDEX_0,
+	THRESHOLD_INDEX_1,
+	THRESHOLD_INDEX_COUNT,
+};
+
+static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
+	{1123,     UINT_MAX},
+	{0,        UINT_MAX},
+};
+
+static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
+	{1695,     UINT_MAX},
+	{0,        UINT_MAX},
+};
+
+static void rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
+				  int *threshold, struct device *dev)
+{
+	u32 tmp;
+	u32 sku = sku_info->sku_id;
+	enum tegra_revision rev = sku_info->revision;
+
+	switch (sku) {
+	case 0x00:
+	case 0x10:
+	case 0x05:
+	case 0x06:
+		sku_info->cpu_speedo_id = 1;
+		sku_info->soc_speedo_id = 0;
+		*threshold = THRESHOLD_INDEX_0;
+		break;
+
+	case 0x03:
+	case 0x04:
+		sku_info->cpu_speedo_id = 2;
+		sku_info->soc_speedo_id = 1;
+		*threshold = THRESHOLD_INDEX_1;
+		break;
+
+	default:
+		dev_err(dev, "Unknown SKU %d\n", sku);
+		sku_info->cpu_speedo_id = 0;
+		sku_info->soc_speedo_id = 0;
+		*threshold = THRESHOLD_INDEX_0;
+		break;
+	}
+
+	if (rev == TEGRA_REVISION_A01) {
+		tmp = tegra30_fuse_readl(0x270) << 1;
+		tmp |= tegra30_fuse_readl(0x26c);
+		if (!tmp)
+			sku_info->cpu_speedo_id = 0;
+	}
+}
+
+void tegra114_init_speedo_data(struct tegra_sku_info *sku_info,
+			       struct device *dev)
+{
+	u32 cpu_speedo_val;
+	u32 core_speedo_val;
+	int threshold;
+	int i;
+
+	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
+			THRESHOLD_INDEX_COUNT);
+	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
+			THRESHOLD_INDEX_COUNT);
+
+	rev_sku_to_speedo_ids(sku_info, &threshold, dev);
+
+	cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024;
+	core_speedo_val = tegra30_fuse_readl(0x134);
+
+	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++)
+		if (cpu_speedo_val < cpu_process_speedos[threshold][i])
+			break;
+	sku_info->cpu_process_id = i;
+
+	for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++)
+		if (core_speedo_val < core_process_speedos[threshold][i])
+			break;
+	sku_info->core_process_id = i;
+}
diff --git a/drivers/misc/fuse/tegra/speedo-tegra124.c b/drivers/misc/fuse/tegra/speedo-tegra124.c
new file mode 100644
index 0000000..97bc6b6
--- /dev/null
+++ b/drivers/misc/fuse/tegra/speedo-tegra124.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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/device.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/tegra-soc.h>
+
+#include "fuse.h"
+
+#define CPU_PROCESS_CORNERS_NUM	2
+#define GPU_PROCESS_CORNERS_NUM	2
+#define CORE_PROCESS_CORNERS_NUM	2
+
+#define FUSE_CPU_SPEEDO_0	0x14
+#define FUSE_CPU_SPEEDO_1	0x2c
+#define FUSE_CPU_SPEEDO_2	0x30
+#define FUSE_SOC_SPEEDO_0	0x34
+#define FUSE_SOC_SPEEDO_1	0x38
+#define FUSE_SOC_SPEEDO_2	0x3c
+#define FUSE_CPU_IDDQ		0x18
+#define FUSE_SOC_IDDQ		0x40
+#define FUSE_GPU_IDDQ		0x128
+#define FUSE_FT_REV		0x28
+
+enum {
+	THRESHOLD_INDEX_0,
+	THRESHOLD_INDEX_1,
+	THRESHOLD_INDEX_COUNT,
+};
+
+static int cpu_speedo_0_value;
+static int cpu_speedo_1_value;
+static int soc_speedo_0_value;
+static int soc_speedo_1_value;
+static int soc_speedo_2_value;
+static int cpu_iddq_value;
+static int gpu_iddq_value;
+static int soc_iddq_value;
+
+static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
+	{2190,	UINT_MAX},
+	{0,	UINT_MAX},
+};
+
+static const u32 gpu_process_speedos[][GPU_PROCESS_CORNERS_NUM] = {
+	{1965,	UINT_MAX},
+	{0,	UINT_MAX},
+};
+
+static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
+	{2101,	UINT_MAX},
+	{0,	UINT_MAX},
+};
+
+static void rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
+				  int *threshold, struct device *dev)
+{
+	int sku = sku_info->sku_id;
+
+	/* Assign to default */
+	sku_info->cpu_speedo_id = 0;
+	sku_info->soc_speedo_id = 0;
+	sku_info->gpu_speedo_id = 0;
+	*threshold = THRESHOLD_INDEX_0;
+
+	switch (sku) {
+	case 0x00: /* Eng sku */
+	case 0x0F:
+	case 0x23:
+		/* Using the default */
+		break;
+	case 0x83:
+		sku_info->cpu_speedo_id = 2;
+		break;
+
+	case 0x1F:
+	case 0x87:
+	case 0x27:
+		sku_info->cpu_speedo_id = 2;
+		sku_info->soc_speedo_id = 0;
+		sku_info->gpu_speedo_id = 1;
+		*threshold = THRESHOLD_INDEX_0;
+		break;
+	case 0x81:
+	case 0x21:
+	case 0x07:
+		sku_info->cpu_speedo_id = 1;
+		sku_info->soc_speedo_id = 1;
+		sku_info->gpu_speedo_id = 1;
+		*threshold = THRESHOLD_INDEX_1;
+		break;
+	case 0x49:
+	case 0x4A:
+	case 0x48:
+		sku_info->cpu_speedo_id = 4;
+		sku_info->soc_speedo_id = 2;
+		sku_info->gpu_speedo_id = 3;
+		*threshold = THRESHOLD_INDEX_1;
+		break;
+	default:
+		dev_err(dev, "Unknown SKU %d\n", sku);
+		/* Using the default for the error case */
+		break;
+	}
+}
+
+void tegra124_init_speedo_data(struct tegra_sku_info *sku_info,
+			       struct device *dev)
+{
+	int i;
+	int threshold;
+
+	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
+			THRESHOLD_INDEX_COUNT);
+	BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) !=
+			THRESHOLD_INDEX_COUNT);
+	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
+			THRESHOLD_INDEX_COUNT);
+
+	cpu_speedo_0_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_0);
+	cpu_speedo_1_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_1);
+
+	/* GPU Speedo is stored in CPU_SPEEDO_2 */
+	sku_info->gpu_speedo_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_2);
+
+	soc_speedo_0_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_0);
+	soc_speedo_1_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_1);
+	soc_speedo_2_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_2);
+
+	cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ);
+	soc_iddq_value = tegra30_fuse_readl(FUSE_SOC_IDDQ);
+	gpu_iddq_value = tegra30_fuse_readl(FUSE_GPU_IDDQ);
+
+	sku_info->cpu_speedo_value = cpu_speedo_0_value;
+
+	if (sku_info->cpu_speedo_value == 0) {
+		dev_warn(dev, "Warning: Speedo value not fused.\n");
+		WARN_ON(1);
+		return;
+	}
+
+	rev_sku_to_speedo_ids(sku_info, &threshold, dev);
+
+	sku_info->cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ);
+
+	for (i = 0; i < GPU_PROCESS_CORNERS_NUM; i++)
+		if (sku_info->gpu_speedo_value <
+			gpu_process_speedos[threshold][i])
+			break;
+	sku_info->gpu_process_id = i;
+
+	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++)
+		if (sku_info->cpu_speedo_value <
+			cpu_process_speedos[threshold][i])
+				break;
+	sku_info->cpu_process_id = i;
+
+	for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++)
+		if (soc_speedo_0_value <
+			core_process_speedos[threshold][i])
+			break;
+	sku_info->core_process_id = i;
+
+	dev_dbg(dev, "GPU Speedo ID=%d, Speedo Value=%d\n",
+			sku_info->gpu_speedo_id, sku_info->gpu_speedo_value);
+}
diff --git a/drivers/misc/fuse/tegra/speedo-tegra20.c b/drivers/misc/fuse/tegra/speedo-tegra20.c
new file mode 100644
index 0000000..af8e86a
--- /dev/null
+++ b/drivers/misc/fuse/tegra/speedo-tegra20.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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/kernel.h>
+#include <linux/device.h>
+#include <linux/bug.h>
+#include <linux/tegra-soc.h>
+
+#include "fuse.h"
+
+#define CPU_SPEEDO_LSBIT		20
+#define CPU_SPEEDO_MSBIT		29
+#define CPU_SPEEDO_REDUND_LSBIT		30
+#define CPU_SPEEDO_REDUND_MSBIT		39
+#define CPU_SPEEDO_REDUND_OFFS	(CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT)
+
+#define CORE_SPEEDO_LSBIT		40
+#define CORE_SPEEDO_MSBIT		47
+#define CORE_SPEEDO_REDUND_LSBIT	48
+#define CORE_SPEEDO_REDUND_MSBIT	55
+#define CORE_SPEEDO_REDUND_OFFS	(CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT)
+
+#define SPEEDO_MULT			4
+
+#define PROCESS_CORNERS_NUM		4
+
+#define SPEEDO_ID_SELECT_0(rev)		((rev) <= 2)
+#define SPEEDO_ID_SELECT_1(sku)		\
+	(((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \
+	 ((sku) != 27) && ((sku) != 28))
+
+enum {
+	SPEEDO_ID_0,
+	SPEEDO_ID_1,
+	SPEEDO_ID_2,
+	SPEEDO_ID_COUNT,
+};
+
+static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
+	{315, 366, 420, UINT_MAX},
+	{303, 368, 419, UINT_MAX},
+	{316, 331, 383, UINT_MAX},
+};
+
+static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
+	{165, 195, 224, UINT_MAX},
+	{165, 195, 224, UINT_MAX},
+	{165, 195, 224, UINT_MAX},
+};
+
+void tegra20_init_speedo_data(struct tegra_sku_info *sku_info,
+			      struct device *dev)
+{
+	u32 reg;
+	u32 val;
+	int i;
+
+	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT);
+	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT);
+
+	if (SPEEDO_ID_SELECT_0(sku_info->revision))
+		sku_info->soc_speedo_id = SPEEDO_ID_0;
+	else if (SPEEDO_ID_SELECT_1(sku_info->sku_id))
+		sku_info->soc_speedo_id = SPEEDO_ID_1;
+	else
+		sku_info->soc_speedo_id = SPEEDO_ID_2;
+
+	val = 0;
+	for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
+		reg = tegra20_spare_fuse(i) |
+			tegra20_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS);
+		val = (val << 1) | (reg & 0x1);
+	}
+	val = val * SPEEDO_MULT;
+	dev_dbg(dev, "CPU speedo value %u\n", val);
+
+	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
+		if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i])
+			break;
+	}
+	sku_info->cpu_process_id = i;
+
+	val = 0;
+	for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) {
+		reg = tegra20_spare_fuse(i) |
+			tegra20_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS);
+		val = (val << 1) | (reg & 0x1);
+	}
+	val = val * SPEEDO_MULT;
+	dev_dbg(dev, "Core speedo value %u\n", val);
+
+	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
+		if (val <= core_process_speedos[sku_info->soc_speedo_id][i])
+			break;
+	}
+	sku_info->core_process_id = i;
+}
diff --git a/drivers/misc/fuse/tegra/speedo-tegra30.c b/drivers/misc/fuse/tegra/speedo-tegra30.c
new file mode 100644
index 0000000..11cf0cd
--- /dev/null
+++ b/drivers/misc/fuse/tegra/speedo-tegra30.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2012-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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/device.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/tegra-soc.h>
+
+#include "fuse.h"
+
+#define CORE_PROCESS_CORNERS_NUM	1
+#define CPU_PROCESS_CORNERS_NUM		6
+
+#define FUSE_SPEEDO_CALIB_0	0x14
+#define FUSE_PACKAGE_INFO	0XFC
+#define FUSE_TEST_PROG_VER	0X28
+
+#define G_SPEEDO_BIT_MINUS1	58
+#define G_SPEEDO_BIT_MINUS1_R	59
+#define G_SPEEDO_BIT_MINUS2	60
+#define G_SPEEDO_BIT_MINUS2_R	61
+#define LP_SPEEDO_BIT_MINUS1	62
+#define LP_SPEEDO_BIT_MINUS1_R	63
+#define LP_SPEEDO_BIT_MINUS2	64
+#define LP_SPEEDO_BIT_MINUS2_R	65
+
+enum {
+	THRESHOLD_INDEX_0,
+	THRESHOLD_INDEX_1,
+	THRESHOLD_INDEX_2,
+	THRESHOLD_INDEX_3,
+	THRESHOLD_INDEX_4,
+	THRESHOLD_INDEX_5,
+	THRESHOLD_INDEX_6,
+	THRESHOLD_INDEX_7,
+	THRESHOLD_INDEX_8,
+	THRESHOLD_INDEX_9,
+	THRESHOLD_INDEX_10,
+	THRESHOLD_INDEX_11,
+	THRESHOLD_INDEX_COUNT,
+};
+
+static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
+	{180},
+	{170},
+	{195},
+	{180},
+	{168},
+	{192},
+	{180},
+	{170},
+	{195},
+	{180},
+	{180},
+	{180},
+};
+
+static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
+	{306, 338, 360, 376, UINT_MAX},
+	{295, 336, 358, 375, UINT_MAX},
+	{325, 325, 358, 375, UINT_MAX},
+	{325, 325, 358, 375, UINT_MAX},
+	{292, 324, 348, 364, UINT_MAX},
+	{324, 324, 348, 364, UINT_MAX},
+	{324, 324, 348, 364, UINT_MAX},
+	{295, 336, 358, 375, UINT_MAX},
+	{358, 358, 358, 358, 397, UINT_MAX},
+	{364, 364, 364, 364, 397, UINT_MAX},
+	{295, 336, 358, 375, 391, UINT_MAX},
+	{295, 336, 358, 375, 391, UINT_MAX},
+};
+
+static int threshold_index;
+static int package_id;
+
+static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp,
+			      struct device *dev)
+{
+	u32 reg;
+	int ate_ver;
+	int bit_minus1;
+	int bit_minus2;
+
+	reg = tegra30_fuse_readl(FUSE_SPEEDO_CALIB_0);
+
+	*speedo_lp = (reg & 0xFFFF) * 4;
+	*speedo_g = ((reg >> 16) & 0xFFFF) * 4;
+
+	ate_ver = tegra30_fuse_readl(FUSE_TEST_PROG_VER);
+	dev_dbg(dev, "ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10);
+
+	if (ate_ver >= 26) {
+		bit_minus1 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1);
+		bit_minus1 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1_R);
+		bit_minus2 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2);
+		bit_minus2 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2_R);
+		*speedo_lp |= (bit_minus1 << 1) | bit_minus2;
+
+		bit_minus1 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1);
+		bit_minus1 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1_R);
+		bit_minus2 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2);
+		bit_minus2 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2_R);
+		*speedo_g |= (bit_minus1 << 1) | bit_minus2;
+	} else {
+		*speedo_lp |= 0x3;
+		*speedo_g |= 0x3;
+	}
+}
+
+static void rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
+				  struct device *dev)
+{
+	switch (sku_info->revision) {
+	case TEGRA_REVISION_A01:
+		sku_info->cpu_speedo_id = 0;
+		sku_info->soc_speedo_id = 0;
+		threshold_index = THRESHOLD_INDEX_0;
+		break;
+	case TEGRA_REVISION_A02:
+	case TEGRA_REVISION_A03:
+		switch (sku_info->sku_id) {
+		case 0x87:
+		case 0x82:
+			sku_info->cpu_speedo_id = 1;
+			sku_info->soc_speedo_id = 1;
+			threshold_index = THRESHOLD_INDEX_1;
+			break;
+		case 0x81:
+			switch (package_id) {
+			case 1:
+				sku_info->cpu_speedo_id = 2;
+				sku_info->soc_speedo_id = 2;
+				threshold_index = THRESHOLD_INDEX_2;
+				break;
+			case 2:
+				sku_info->cpu_speedo_id = 4;
+				sku_info->soc_speedo_id = 1;
+				threshold_index = THRESHOLD_INDEX_7;
+				break;
+			default:
+				dev_err(dev, "Unknown pkg %d\n", package_id);
+				BUG();
+				break;
+			}
+			break;
+		case 0x80:
+			switch (package_id) {
+			case 1:
+				sku_info->cpu_speedo_id = 5;
+				sku_info->soc_speedo_id = 2;
+				threshold_index = THRESHOLD_INDEX_8;
+				break;
+			case 2:
+				sku_info->cpu_speedo_id = 6;
+				sku_info->soc_speedo_id = 2;
+				threshold_index = THRESHOLD_INDEX_9;
+				break;
+			default:
+				dev_err(dev, "Unknown pkg %d\n", package_id);
+				BUG();
+				break;
+			}
+			break;
+		case 0x83:
+			switch (package_id) {
+			case 1:
+				sku_info->cpu_speedo_id = 7;
+				sku_info->soc_speedo_id = 1;
+				threshold_index = THRESHOLD_INDEX_10;
+				break;
+			case 2:
+				sku_info->cpu_speedo_id = 3;
+				sku_info->soc_speedo_id = 2;
+				threshold_index = THRESHOLD_INDEX_3;
+				break;
+			default:
+				dev_err(dev, "Unknown pkg %d\n", package_id);
+				BUG();
+				break;
+			}
+			break;
+		case 0x8F:
+			sku_info->cpu_speedo_id = 8;
+			sku_info->soc_speedo_id = 1;
+			threshold_index = THRESHOLD_INDEX_11;
+			break;
+		case 0x08:
+			sku_info->cpu_speedo_id = 1;
+			sku_info->soc_speedo_id = 1;
+			threshold_index = THRESHOLD_INDEX_4;
+			break;
+		case 0x02:
+			sku_info->cpu_speedo_id = 2;
+			sku_info->soc_speedo_id = 2;
+			threshold_index = THRESHOLD_INDEX_5;
+			break;
+		case 0x04:
+			sku_info->cpu_speedo_id = 3;
+			sku_info->soc_speedo_id = 2;
+			threshold_index = THRESHOLD_INDEX_6;
+			break;
+		case 0:
+			switch (package_id) {
+			case 1:
+				sku_info->cpu_speedo_id = 2;
+				sku_info->soc_speedo_id = 2;
+				threshold_index = THRESHOLD_INDEX_2;
+				break;
+			case 2:
+				sku_info->cpu_speedo_id = 3;
+				sku_info->soc_speedo_id = 2;
+				threshold_index = THRESHOLD_INDEX_3;
+				break;
+			default:
+				dev_err(dev, "Unknown pkg %d\n", package_id);
+				BUG();
+				break;
+			}
+			break;
+		default:
+			dev_warn(dev, "Unknown SKU %d\n", sku_info->sku_id);
+			sku_info->cpu_speedo_id = 0;
+			sku_info->soc_speedo_id = 0;
+			threshold_index = THRESHOLD_INDEX_0;
+			break;
+		}
+		break;
+	default:
+		dev_warn(dev, "Unknown chip rev %d\n", sku_info->revision);
+		sku_info->cpu_speedo_id = 0;
+		sku_info->soc_speedo_id = 0;
+		threshold_index = THRESHOLD_INDEX_0;
+		break;
+	}
+}
+
+void tegra30_init_speedo_data(struct tegra_sku_info *sku_info,
+			      struct device *dev)
+{
+	u32 cpu_speedo_val;
+	u32 core_speedo_val;
+	int i;
+
+	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
+			THRESHOLD_INDEX_COUNT);
+	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
+			THRESHOLD_INDEX_COUNT);
+
+	package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
+
+	rev_sku_to_speedo_ids(sku_info, dev);
+	fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val, dev);
+	dev_dbg(dev, "CPU speedo value %u\n", cpu_speedo_val);
+	dev_dbg(dev, "Core speedo value %u\n", core_speedo_val);
+
+	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
+		if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
+			break;
+	}
+	sku_info->cpu_process_id = i - 1;
+
+	if (sku_info->cpu_process_id == -1) {
+		dev_warn(dev, "CPU speedo value %3d out of range",
+		       cpu_speedo_val);
+		sku_info->cpu_process_id = 0;
+		sku_info->cpu_speedo_id = 1;
+	}
+
+	for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) {
+		if (core_speedo_val < core_process_speedos[threshold_index][i])
+			break;
+	}
+	sku_info->core_process_id = i - 1;
+
+	if (sku_info->core_process_id == -1) {
+		dev_warn(dev, "CORE speedo value %3d out of range",
+		       core_speedo_val);
+		sku_info->core_process_id = 0;
+		sku_info->soc_speedo_id = 1;
+	}
+}
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 60e6ac8..a22c55d 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -22,6 +22,9 @@
 #define TEGRA114	0x35
 #define TEGRA124	0x40
 
+#define TEGRA_FUSE_SKU_CALIB_0	0xf0
+#define TEGRA30_FUSE_SATA_CALIB	0x124
+
 #ifndef __ASSEMBLY__
 
 enum tegra_revision {
@@ -37,6 +40,7 @@ enum tegra_revision {
 u32 tegra_read_straps(void);
 u32 tegra_read_chipid(void);
 void tegra_init_fuse(void);
+int tegra_fuse_readl(u32 offset, u32 *val);
 
 extern int tegra_chip_id;
 extern enum tegra_revision tegra_revision;
-- 
1.7.7.rc0.72.g4b5ea.dirty


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v5 4/5] ARM: tegra: Add efuse and apbmisc bindings
  2014-05-28 12:54 [PATCH v5 0/5] efuse driver for Tegra Peter De Schrijver
                   ` (2 preceding siblings ...)
  2014-05-28 12:54 ` [PATCH v5 3/5] misc: fuse: Add efuse driver for Tegra Peter De Schrijver
@ 2014-05-28 12:54 ` Peter De Schrijver
  2014-05-29 19:13   ` Stephen Warren
  2014-05-28 12:54 ` [PATCH v5 5/5] ARM: tegra: build new fuse driver in drivers/misc Peter De Schrijver
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Peter De Schrijver @ 2014-05-28 12:54 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Stephen Warren, Thierry Reding, Andrew Morton,
	Linus Walleij, Wolfram Sang, linux-arm-kernel, linux-tegra,
	linux-kernel

Add efuse and apbmisc bindings for Tegra20, Tegra30, Tegra114 and Tegra124.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 .../devicetree/bindings/fuse/fuse-tegra.txt        |   30 ++++++++++++++++++++
 .../devicetree/bindings/misc/nvidia,apbmisc.txt    |   13 ++++++++
 arch/arm/boot/dts/tegra114.dtsi                    |   12 ++++++++
 arch/arm/boot/dts/tegra124.dtsi                    |   12 ++++++++
 arch/arm/boot/dts/tegra20.dtsi                     |   12 ++++++++
 arch/arm/boot/dts/tegra30.dtsi                     |   12 ++++++++
 6 files changed, 91 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/fuse/fuse-tegra.txt
 create mode 100644 Documentation/devicetree/bindings/misc/nvidia,apbmisc.txt

diff --git a/Documentation/devicetree/bindings/fuse/fuse-tegra.txt b/Documentation/devicetree/bindings/fuse/fuse-tegra.txt
new file mode 100644
index 0000000..831ce50
--- /dev/null
+++ b/Documentation/devicetree/bindings/fuse/fuse-tegra.txt
@@ -0,0 +1,30 @@
+NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 fuse block.
+
+Required properties:
+- compatible : should be:
+	"nvidia,tegra20-efuse"
+	"nvidia,tegra30-efuse"
+	"nvidia,tegra114-efuse"
+	"nvidia,tegra124-efuse"
+  Details:
+  nvidia,tegra20-efuse: Tegra20 requires using APB DMA to read the fuse data
+	due to a hardware bug. Tegra20 also lacks certain information which is
+	available in later generations such as fab code, lot code, wafer id,..
+  nvidia,tegra30-efuse, nvidia,tegra114-efuse and nvidia,tegra124-efuse:
+	The differences between these SoCs are the size of the efuse array,
+	the location of the spare (OEM programmable) bits and the location of
+	the speedo data.
+- reg: Should contain 1 entry: the entry gives the physical address and length
+       of the fuse registers.
+- clocks: Should contain a pointer to the fuse clock.
+
+Example:
+
+        fuse@7000f800 {
+                compatible = "nvidia,tegra20-efuse";
+                reg = <0x7000F800 0x400>,
+                      <0x70000000 0x400>;
+                clocks = <&tegra_car TEGRA20_CLK_FUSE>;
+        };
+
+
diff --git a/Documentation/devicetree/bindings/misc/nvidia,apbmisc.txt b/Documentation/devicetree/bindings/misc/nvidia,apbmisc.txt
new file mode 100644
index 0000000..b97b8be
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/nvidia,apbmisc.txt
@@ -0,0 +1,13 @@
+NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 apbmisc block
+
+Required properties:
+- compatible : should be:
+       "nvidia,tegra20-apbmisc"
+       "nvidia,tegra30-apbmisc"
+       "nvidia,tegra114-apbmisc"
+       "nvidia,tegra124-apbmisc"
+- reg: Should contain 2 entries: the first entry gives the physical address
+       and length of the registers which contain revision and debug features.
+       The second entry gives the physical address and length of the
+       registers indicating the strapping options.
+
diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index fdc559a..d91a601 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -220,6 +220,12 @@
 		interrupt-controller;
 	};
 
+        apbmisc@0x70000800 {
+		compatible = "nvidia,tegra114-apbmisc", "nvidia,tegra20-apbmisc";
+		reg = <0x70000800 0x64   /* Chip revision */
+		       0x70000008 0x04>; /* Strapping options */
+	};
+
 	pinmux: pinmux@70000868 {
 		compatible = "nvidia,tegra114-pinmux";
 		reg = <0x70000868 0x148		/* Pad control registers */
@@ -485,6 +491,12 @@
 		clock-names = "pclk", "clk32k_in";
 	};
 
+	fuse@7000f800 {
+		compatible = "nvidia,tegra114-efuse";
+		reg = <0x7000f800 0x400>;
+		clocks = <&tegra_car TEGRA114_CLK_FUSE>;
+	};
+
 	iommu@70019010 {
 		compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
 		reg = <0x70019010 0x02c
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 6d540a0..e5bd036 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -167,6 +167,12 @@
 		#dma-cells = <1>;
 	};
 
+	apbmisc@0x70000800 {
+		compatible = "nvidia,tegra124-apbmisc", "nvidia,tegra20-apbmisc";
+		reg = <0x0 0x70000800 0x0 0x64>,   /* Chip revision */
+		      <0x0 0x7000E864 0x0 0x04>;   /* Strapping options */
+	};
+
 	pinmux: pinmux@0,70000868 {
 		compatible = "nvidia,tegra124-pinmux";
 		reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */
@@ -437,6 +443,12 @@
 		clock-names = "pclk", "clk32k_in";
 	};
 
+	fuse@7000f800 {
+		compatible = "nvidia,tegra124-efuse";
+		reg = <0x0 0x7000f800 0x0 0x400>;
+		clocks = <&tegra_car TEGRA124_CLK_FUSE>;
+	};
+
 	sdhci@0,700b0000 {
 		compatible = "nvidia,tegra124-sdhci";
 		reg = <0x0 0x700b0000 0x0 0x200>;
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index a7ddf70..b5d1fe1 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -236,6 +236,12 @@
 		interrupt-controller;
 	};
 
+        apbmisc@0x70000800 {
+		compatible = "nvidia,tegra20-apbmisc";
+		reg = <0x70000800 0x64   /* Chip revision */
+		       0x70000008 0x04>; /* Strapping options */
+	};
+
 	pinmux: pinmux@70000014 {
 		compatible = "nvidia,tegra20-pinmux";
 		reg = <0x70000014 0x10   /* Tri-state registers */
@@ -545,6 +551,12 @@
 		#size-cells = <0>;
 	};
 
+	fuse@7000f800 {
+		compatible = "nvidia,tegra20-efuse";
+		reg = <0x7000F800 0x400>;
+		clocks = <&tegra_car TEGRA20_CLK_FUSE>;
+	};
+
 	pcie-controller@80003000 {
 		compatible = "nvidia,tegra20-pcie";
 		device_type = "pci";
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index dec4fc8..bd4969d 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -335,6 +335,12 @@
 		interrupt-controller;
 	};
 
+        apbmisc@0x70000800 {
+		compatible = "nvidia,tegra30-apbmisc", "nvidia,tegra20-apbmisc";
+		reg = <0x70000800 0x64   /* Chip revision */
+		       0x70000008 0x04>; /* Strapping options */
+	};
+
 	pinmux: pinmux@70000868 {
 		compatible = "nvidia,tegra30-pinmux";
 		reg = <0x70000868 0xd4    /* Pad control registers */
@@ -631,6 +637,12 @@
 		nvidia,ahb = <&ahb>;
 	};
 
+	fuse@7000f800 {
+		compatible = "nvidia,tegra30-efuse";
+		reg = <0x7000f800 0x400>;
+		clocks = <&tegra_car TEGRA30_CLK_FUSE>;
+	};
+
 	ahub@70080000 {
 		compatible = "nvidia,tegra30-ahub";
 		reg = <0x70080000 0x200
-- 
1.7.7.rc0.72.g4b5ea.dirty


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v5 5/5] ARM: tegra: build new fuse driver in drivers/misc
  2014-05-28 12:54 [PATCH v5 0/5] efuse driver for Tegra Peter De Schrijver
                   ` (3 preceding siblings ...)
  2014-05-28 12:54 ` [PATCH v5 4/5] ARM: tegra: Add efuse and apbmisc bindings Peter De Schrijver
@ 2014-05-28 12:54 ` Peter De Schrijver
  2014-05-29 19:14   ` Stephen Warren
  2014-05-28 13:16 ` [PATCH v5 0/5] efuse driver for Tegra Andrew Morton
  2014-05-29 19:01 ` Stephen Warren
  6 siblings, 1 reply; 18+ messages in thread
From: Peter De Schrijver @ 2014-05-28 12:54 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Stephen Warren, Thierry Reding, Andrew Morton,
	Linus Walleij, Wolfram Sang, linux-arm-kernel, linux-tegra,
	linux-kernel

The Tegra fuse code has moved to drivers/misc/fuse/tegra. Enable the
building of that code, and disable the building of the old fuse code in
arch/arm/mach-tegra/.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 arch/arm/mach-tegra/Makefile          |    4 -
 arch/arm/mach-tegra/fuse.c            |  252 ----------------------------
 arch/arm/mach-tegra/fuse.h            |   61 -------
 arch/arm/mach-tegra/tegra114_speedo.c |  105 ------------
 arch/arm/mach-tegra/tegra20_speedo.c  |  110 ------------
 arch/arm/mach-tegra/tegra30_speedo.c  |  293 ---------------------------------
 drivers/misc/Makefile                 |    2 +
 7 files changed, 2 insertions(+), 825 deletions(-)
 delete mode 100644 arch/arm/mach-tegra/fuse.c
 delete mode 100644 arch/arm/mach-tegra/fuse.h
 delete mode 100644 arch/arm/mach-tegra/tegra114_speedo.c
 delete mode 100644 arch/arm/mach-tegra/tegra20_speedo.c
 delete mode 100644 arch/arm/mach-tegra/tegra30_speedo.c

diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 6fbfbb7..e8601bb 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -2,7 +2,6 @@ asflags-y				+= -march=armv7-a
 
 obj-y                                   += io.o
 obj-y                                   += irq.o
-obj-y					+= fuse.o
 obj-y					+= pmc.o
 obj-y					+= flowctrl.o
 obj-y					+= powergate.o
@@ -13,13 +12,11 @@ obj-y					+= reset-handler.o
 obj-y					+= sleep.o
 obj-y					+= tegra.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra20_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pm-tegra20.o
 ifeq ($(CONFIG_CPU_IDLE),y)
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= cpuidle-tegra20.o
 endif
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pm-tegra30.o
 ifeq ($(CONFIG_CPU_IDLE),y)
@@ -28,7 +25,6 @@ endif
 obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
 
-obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= tegra114_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= sleep-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= pm-tegra30.o
 ifeq ($(CONFIG_CPU_IDLE),y)
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
deleted file mode 100644
index c9ac23b..0000000
--- a/arch/arm/mach-tegra/fuse.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * arch/arm/mach-tegra/fuse.c
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
- *
- * Author:
- *	Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that 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.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/export.h>
-#include <linux/random.h>
-#include <linux/clk.h>
-#include <linux/tegra-soc.h>
-
-#include "fuse.h"
-#include "iomap.h"
-#include "apbio.h"
-
-/* Tegra20 only */
-#define FUSE_UID_LOW		0x108
-#define FUSE_UID_HIGH		0x10c
-
-/* Tegra30 and later */
-#define FUSE_VENDOR_CODE	0x200
-#define FUSE_FAB_CODE		0x204
-#define FUSE_LOT_CODE_0		0x208
-#define FUSE_LOT_CODE_1		0x20c
-#define FUSE_WAFER_ID		0x210
-#define FUSE_X_COORDINATE	0x214
-#define FUSE_Y_COORDINATE	0x218
-
-#define FUSE_SKU_INFO		0x110
-
-#define TEGRA20_FUSE_SPARE_BIT		0x200
-#define TEGRA30_FUSE_SPARE_BIT		0x244
-
-int tegra_sku_id;
-int tegra_cpu_process_id;
-int tegra_core_process_id;
-int tegra_chip_id;
-int tegra_cpu_speedo_id;		/* only exist in Tegra30 and later */
-int tegra_soc_speedo_id;
-enum tegra_revision tegra_revision;
-
-static struct clk *fuse_clk;
-static int tegra_fuse_spare_bit;
-static void (*tegra_init_speedo_data)(void);
-
-/* The BCT to use at boot is specified by board straps that can be read
- * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
- */
-int tegra_bct_strapping;
-
-#define STRAP_OPT 0x008
-#define GMI_AD0 (1 << 4)
-#define GMI_AD1 (1 << 5)
-#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
-#define RAM_CODE_SHIFT 4
-
-static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
-	[TEGRA_REVISION_UNKNOWN] = "unknown",
-	[TEGRA_REVISION_A01]     = "A01",
-	[TEGRA_REVISION_A02]     = "A02",
-	[TEGRA_REVISION_A03]     = "A03",
-	[TEGRA_REVISION_A03p]    = "A03 prime",
-	[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)
-{
-	return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
-}
-
-bool tegra_spare_fuse(int bit)
-{
-	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)
-{
-	u32 minor_rev = (id >> 16) & 0xf;
-
-	switch (minor_rev) {
-	case 1:
-		return TEGRA_REVISION_A01;
-	case 2:
-		return TEGRA_REVISION_A02;
-	case 3:
-		if (tegra_chip_id == TEGRA20 &&
-			(tegra_spare_fuse(18) || tegra_spare_fuse(19)))
-			return TEGRA_REVISION_A03p;
-		else
-			return TEGRA_REVISION_A03;
-	case 4:
-		return TEGRA_REVISION_A04;
-	default:
-		return TEGRA_REVISION_UNKNOWN;
-	}
-}
-
-static void tegra_get_process_id(void)
-{
-	u32 reg;
-
-	tegra_fuse_enable_clk();
-
-	reg = tegra_fuse_readl(tegra_fuse_spare_bit);
-	tegra_cpu_process_id = (reg >> 6) & 3;
-	reg = tegra_fuse_readl(tegra_fuse_spare_bit);
-	tegra_core_process_id = (reg >> 12) & 3;
-
-	tegra_fuse_disable_clk();
-}
-
-u32 tegra_read_chipid(void)
-{
-	return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
-}
-
-static void __init tegra20_fuse_init_randomness(void)
-{
-	u32 randomness[2];
-
-	randomness[0] = tegra_fuse_readl(FUSE_UID_LOW);
-	randomness[1] = tegra_fuse_readl(FUSE_UID_HIGH);
-
-	add_device_randomness(randomness, sizeof(randomness));
-}
-
-/* Applies to Tegra30 or later */
-static void __init tegra30_fuse_init_randomness(void)
-{
-	u32 randomness[7];
-
-	randomness[0] = tegra_fuse_readl(FUSE_VENDOR_CODE);
-	randomness[1] = tegra_fuse_readl(FUSE_FAB_CODE);
-	randomness[2] = tegra_fuse_readl(FUSE_LOT_CODE_0);
-	randomness[3] = tegra_fuse_readl(FUSE_LOT_CODE_1);
-	randomness[4] = tegra_fuse_readl(FUSE_WAFER_ID);
-	randomness[5] = tegra_fuse_readl(FUSE_X_COORDINATE);
-	randomness[6] = tegra_fuse_readl(FUSE_Y_COORDINATE);
-
-	add_device_randomness(randomness, sizeof(randomness));
-}
-
-void __init tegra_init_fuse(void)
-{
-	u32 id;
-	u32 randomness[5];
-
-	u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
-	reg |= 1 << 28;
-	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);
-	randomness[0] = reg;
-	tegra_sku_id = reg & 0xFF;
-
-	reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
-	randomness[1] = reg;
-	tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
-
-	id = tegra_read_chipid();
-	randomness[2] = id;
-	tegra_chip_id = (id >> 8) & 0xff;
-
-	switch (tegra_chip_id) {
-	case TEGRA20:
-		tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
-		tegra_init_speedo_data = &tegra20_init_speedo_data;
-		break;
-	case TEGRA30:
-		tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
-		tegra_init_speedo_data = &tegra30_init_speedo_data;
-		break;
-	case TEGRA114:
-		tegra_init_speedo_data = &tegra114_init_speedo_data;
-		break;
-	default:
-		pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id);
-		tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
-		tegra_init_speedo_data = &tegra_get_process_id;
-	}
-
-	tegra_revision = tegra_get_revision(id);
-	tegra_init_speedo_data();
-	randomness[3] = (tegra_cpu_process_id << 16) | tegra_core_process_id;
-	randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id;
-
-	add_device_randomness(randomness, sizeof(randomness));
-	switch (tegra_chip_id) {
-	case TEGRA20:
-		tegra20_fuse_init_randomness();
-		break;
-	case TEGRA30:
-	case TEGRA114:
-	default:
-		tegra30_fuse_init_randomness();
-		break;
-	}
-
-	pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
-		tegra_revision_name[tegra_revision],
-		tegra_sku_id, tegra_cpu_process_id,
-		tegra_core_process_id);
-}
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
deleted file mode 100644
index b17c4ba..0000000
--- a/arch/arm/mach-tegra/fuse.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc.
- * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
- *
- * Author:
- *	Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that 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.
- *
- */
-
-#ifndef __MACH_TEGRA_FUSE_H
-#define __MACH_TEGRA_FUSE_H
-
-#define SKU_ID_T20	8
-#define SKU_ID_T25SE	20
-#define SKU_ID_AP25	23
-#define SKU_ID_T25	24
-#define SKU_ID_AP25E	27
-#define SKU_ID_T25E	28
-
-#ifndef __ASSEMBLY__
-
-extern int tegra_sku_id;
-extern int tegra_cpu_process_id;
-extern int tegra_core_process_id;
-extern int tegra_chip_id;
-extern int tegra_cpu_speedo_id;		/* only exist in Tegra30 and later */
-extern int tegra_soc_speedo_id;
-
-unsigned long long tegra_chip_uid(void);
-bool tegra_spare_fuse(int bit);
-u32 tegra_fuse_readl(unsigned long offset);
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-void tegra20_init_speedo_data(void);
-#else
-static inline void tegra20_init_speedo_data(void) {}
-#endif
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-void tegra30_init_speedo_data(void);
-#else
-static inline void tegra30_init_speedo_data(void) {}
-#endif
-
-#ifdef CONFIG_ARCH_TEGRA_114_SOC
-void tegra114_init_speedo_data(void);
-#else
-static inline void tegra114_init_speedo_data(void) {}
-#endif
-#endif /* __ASSEMBLY__ */
-
-#endif
diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c
deleted file mode 100644
index 7c73716..0000000
--- a/arch/arm/mach-tegra/tegra114_speedo.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
- *
- * 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/kernel.h>
-#include <linux/bug.h>
-#include <linux/tegra-soc.h>
-
-#include "fuse.h"
-
-#define CORE_PROCESS_CORNERS_NUM	2
-#define CPU_PROCESS_CORNERS_NUM		2
-
-enum {
-	THRESHOLD_INDEX_0,
-	THRESHOLD_INDEX_1,
-	THRESHOLD_INDEX_COUNT,
-};
-
-static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
-	{1123,     UINT_MAX},
-	{0,        UINT_MAX},
-};
-
-static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
-	{1695,     UINT_MAX},
-	{0,        UINT_MAX},
-};
-
-static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold)
-{
-	u32 tmp;
-
-	switch (sku) {
-	case 0x00:
-	case 0x10:
-	case 0x05:
-	case 0x06:
-		tegra_cpu_speedo_id = 1;
-		tegra_soc_speedo_id = 0;
-		*threshold = THRESHOLD_INDEX_0;
-		break;
-
-	case 0x03:
-	case 0x04:
-		tegra_cpu_speedo_id = 2;
-		tegra_soc_speedo_id = 1;
-		*threshold = THRESHOLD_INDEX_1;
-		break;
-
-	default:
-		pr_err("Tegra114 Unknown SKU %d\n", sku);
-		tegra_cpu_speedo_id = 0;
-		tegra_soc_speedo_id = 0;
-		*threshold = THRESHOLD_INDEX_0;
-		break;
-	}
-
-	if (rev == TEGRA_REVISION_A01) {
-		tmp = tegra_fuse_readl(0x270) << 1;
-		tmp |= tegra_fuse_readl(0x26c);
-		if (!tmp)
-			tegra_cpu_speedo_id = 0;
-	}
-}
-
-void tegra114_init_speedo_data(void)
-{
-	u32 cpu_speedo_val;
-	u32 core_speedo_val;
-	int threshold;
-	int i;
-
-	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
-			THRESHOLD_INDEX_COUNT);
-	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
-			THRESHOLD_INDEX_COUNT);
-
-	rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold);
-
-	cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024;
-	core_speedo_val = tegra_fuse_readl(0x134);
-
-	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++)
-		if (cpu_speedo_val < cpu_process_speedos[threshold][i])
-			break;
-	tegra_cpu_process_id = i;
-
-	for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++)
-		if (core_speedo_val < core_process_speedos[threshold][i])
-			break;
-	tegra_core_process_id = i;
-}
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c
deleted file mode 100644
index 3b1bb53..0000000
--- a/arch/arm/mach-tegra/tegra20_speedo.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
- *
- * 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/kernel.h>
-#include <linux/bug.h>
-#include <linux/tegra-soc.h>
-
-#include "fuse.h"
-
-#define CPU_SPEEDO_LSBIT		20
-#define CPU_SPEEDO_MSBIT		29
-#define CPU_SPEEDO_REDUND_LSBIT		30
-#define CPU_SPEEDO_REDUND_MSBIT		39
-#define CPU_SPEEDO_REDUND_OFFS	(CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT)
-
-#define CORE_SPEEDO_LSBIT		40
-#define CORE_SPEEDO_MSBIT		47
-#define CORE_SPEEDO_REDUND_LSBIT	48
-#define CORE_SPEEDO_REDUND_MSBIT	55
-#define CORE_SPEEDO_REDUND_OFFS	(CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT)
-
-#define SPEEDO_MULT			4
-
-#define PROCESS_CORNERS_NUM		4
-
-#define SPEEDO_ID_SELECT_0(rev)		((rev) <= 2)
-#define SPEEDO_ID_SELECT_1(sku)		\
-	(((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \
-	 ((sku) != 27) && ((sku) != 28))
-
-enum {
-	SPEEDO_ID_0,
-	SPEEDO_ID_1,
-	SPEEDO_ID_2,
-	SPEEDO_ID_COUNT,
-};
-
-static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
-	{315, 366, 420, UINT_MAX},
-	{303, 368, 419, UINT_MAX},
-	{316, 331, 383, UINT_MAX},
-};
-
-static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
-	{165, 195, 224, UINT_MAX},
-	{165, 195, 224, UINT_MAX},
-	{165, 195, 224, UINT_MAX},
-};
-
-void tegra20_init_speedo_data(void)
-{
-	u32 reg;
-	u32 val;
-	int i;
-
-	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT);
-	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT);
-
-	if (SPEEDO_ID_SELECT_0(tegra_revision))
-		tegra_soc_speedo_id = SPEEDO_ID_0;
-	else if (SPEEDO_ID_SELECT_1(tegra_sku_id))
-		tegra_soc_speedo_id = SPEEDO_ID_1;
-	else
-		tegra_soc_speedo_id = SPEEDO_ID_2;
-
-	val = 0;
-	for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
-		reg = tegra_spare_fuse(i) |
-			tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS);
-		val = (val << 1) | (reg & 0x1);
-	}
-	val = val * SPEEDO_MULT;
-	pr_debug("%s CPU speedo value %u\n", __func__, val);
-
-	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
-		if (val <= cpu_process_speedos[tegra_soc_speedo_id][i])
-			break;
-	}
-	tegra_cpu_process_id = i;
-
-	val = 0;
-	for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) {
-		reg = tegra_spare_fuse(i) |
-			tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS);
-		val = (val << 1) | (reg & 0x1);
-	}
-	val = val * SPEEDO_MULT;
-	pr_debug("%s Core speedo value %u\n", __func__, val);
-
-	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
-		if (val <= core_process_speedos[tegra_soc_speedo_id][i])
-			break;
-	}
-	tegra_core_process_id = i;
-
-	pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id);
-}
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c
deleted file mode 100644
index 81a958d..0000000
--- a/arch/arm/mach-tegra/tegra30_speedo.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
- *
- * 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/kernel.h>
-#include <linux/bug.h>
-#include <linux/tegra-soc.h>
-
-#include "fuse.h"
-
-#define CORE_PROCESS_CORNERS_NUM	1
-#define CPU_PROCESS_CORNERS_NUM		6
-
-#define FUSE_SPEEDO_CALIB_0	0x114
-#define FUSE_PACKAGE_INFO	0X1FC
-#define FUSE_TEST_PROG_VER	0X128
-
-#define G_SPEEDO_BIT_MINUS1	58
-#define G_SPEEDO_BIT_MINUS1_R	59
-#define G_SPEEDO_BIT_MINUS2	60
-#define G_SPEEDO_BIT_MINUS2_R	61
-#define LP_SPEEDO_BIT_MINUS1	62
-#define LP_SPEEDO_BIT_MINUS1_R	63
-#define LP_SPEEDO_BIT_MINUS2	64
-#define LP_SPEEDO_BIT_MINUS2_R	65
-
-enum {
-	THRESHOLD_INDEX_0,
-	THRESHOLD_INDEX_1,
-	THRESHOLD_INDEX_2,
-	THRESHOLD_INDEX_3,
-	THRESHOLD_INDEX_4,
-	THRESHOLD_INDEX_5,
-	THRESHOLD_INDEX_6,
-	THRESHOLD_INDEX_7,
-	THRESHOLD_INDEX_8,
-	THRESHOLD_INDEX_9,
-	THRESHOLD_INDEX_10,
-	THRESHOLD_INDEX_11,
-	THRESHOLD_INDEX_COUNT,
-};
-
-static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
-	{180},
-	{170},
-	{195},
-	{180},
-	{168},
-	{192},
-	{180},
-	{170},
-	{195},
-	{180},
-	{180},
-	{180},
-};
-
-static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
-	{306, 338, 360, 376, UINT_MAX},
-	{295, 336, 358, 375, UINT_MAX},
-	{325, 325, 358, 375, UINT_MAX},
-	{325, 325, 358, 375, UINT_MAX},
-	{292, 324, 348, 364, UINT_MAX},
-	{324, 324, 348, 364, UINT_MAX},
-	{324, 324, 348, 364, UINT_MAX},
-	{295, 336, 358, 375, UINT_MAX},
-	{358, 358, 358, 358, 397, UINT_MAX},
-	{364, 364, 364, 364, 397, UINT_MAX},
-	{295, 336, 358, 375, 391, UINT_MAX},
-	{295, 336, 358, 375, 391, UINT_MAX},
-};
-
-static int threshold_index;
-static int package_id;
-
-static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
-{
-	u32 reg;
-	int ate_ver;
-	int bit_minus1;
-	int bit_minus2;
-
-	reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
-
-	*speedo_lp = (reg & 0xFFFF) * 4;
-	*speedo_g = ((reg >> 16) & 0xFFFF) * 4;
-
-	ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER);
-	pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10);
-
-	if (ate_ver >= 26) {
-		bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1);
-		bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R);
-		bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2);
-		bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R);
-		*speedo_lp |= (bit_minus1 << 1) | bit_minus2;
-
-		bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1);
-		bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R);
-		bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2);
-		bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R);
-		*speedo_g |= (bit_minus1 << 1) | bit_minus2;
-	} else {
-		*speedo_lp |= 0x3;
-		*speedo_g |= 0x3;
-	}
-}
-
-static void rev_sku_to_speedo_ids(int rev, int sku)
-{
-	switch (rev) {
-	case TEGRA_REVISION_A01:
-		tegra_cpu_speedo_id = 0;
-		tegra_soc_speedo_id = 0;
-		threshold_index = THRESHOLD_INDEX_0;
-		break;
-	case TEGRA_REVISION_A02:
-	case TEGRA_REVISION_A03:
-		switch (sku) {
-		case 0x87:
-		case 0x82:
-			tegra_cpu_speedo_id = 1;
-			tegra_soc_speedo_id = 1;
-			threshold_index = THRESHOLD_INDEX_1;
-			break;
-		case 0x81:
-			switch (package_id) {
-			case 1:
-				tegra_cpu_speedo_id = 2;
-				tegra_soc_speedo_id = 2;
-				threshold_index = THRESHOLD_INDEX_2;
-				break;
-			case 2:
-				tegra_cpu_speedo_id = 4;
-				tegra_soc_speedo_id = 1;
-				threshold_index = THRESHOLD_INDEX_7;
-				break;
-			default:
-				pr_err("Tegra30: Unknown pkg %d\n", package_id);
-				BUG();
-				break;
-			}
-			break;
-		case 0x80:
-			switch (package_id) {
-			case 1:
-				tegra_cpu_speedo_id = 5;
-				tegra_soc_speedo_id = 2;
-				threshold_index = THRESHOLD_INDEX_8;
-				break;
-			case 2:
-				tegra_cpu_speedo_id = 6;
-				tegra_soc_speedo_id = 2;
-				threshold_index = THRESHOLD_INDEX_9;
-				break;
-			default:
-				pr_err("Tegra30: Unknown pkg %d\n", package_id);
-				BUG();
-				break;
-			}
-			break;
-		case 0x83:
-			switch (package_id) {
-			case 1:
-				tegra_cpu_speedo_id = 7;
-				tegra_soc_speedo_id = 1;
-				threshold_index = THRESHOLD_INDEX_10;
-				break;
-			case 2:
-				tegra_cpu_speedo_id = 3;
-				tegra_soc_speedo_id = 2;
-				threshold_index = THRESHOLD_INDEX_3;
-				break;
-			default:
-				pr_err("Tegra30: Unknown pkg %d\n", package_id);
-				BUG();
-				break;
-			}
-			break;
-		case 0x8F:
-			tegra_cpu_speedo_id = 8;
-			tegra_soc_speedo_id = 1;
-			threshold_index = THRESHOLD_INDEX_11;
-			break;
-		case 0x08:
-			tegra_cpu_speedo_id = 1;
-			tegra_soc_speedo_id = 1;
-			threshold_index = THRESHOLD_INDEX_4;
-			break;
-		case 0x02:
-			tegra_cpu_speedo_id = 2;
-			tegra_soc_speedo_id = 2;
-			threshold_index = THRESHOLD_INDEX_5;
-			break;
-		case 0x04:
-			tegra_cpu_speedo_id = 3;
-			tegra_soc_speedo_id = 2;
-			threshold_index = THRESHOLD_INDEX_6;
-			break;
-		case 0:
-			switch (package_id) {
-			case 1:
-				tegra_cpu_speedo_id = 2;
-				tegra_soc_speedo_id = 2;
-				threshold_index = THRESHOLD_INDEX_2;
-				break;
-			case 2:
-				tegra_cpu_speedo_id = 3;
-				tegra_soc_speedo_id = 2;
-				threshold_index = THRESHOLD_INDEX_3;
-				break;
-			default:
-				pr_err("Tegra30: Unknown pkg %d\n", package_id);
-				BUG();
-				break;
-			}
-			break;
-		default:
-			pr_warn("Tegra30: Unknown SKU %d\n", sku);
-			tegra_cpu_speedo_id = 0;
-			tegra_soc_speedo_id = 0;
-			threshold_index = THRESHOLD_INDEX_0;
-			break;
-		}
-		break;
-	default:
-		pr_warn("Tegra30: Unknown chip rev %d\n", rev);
-		tegra_cpu_speedo_id = 0;
-		tegra_soc_speedo_id = 0;
-		threshold_index = THRESHOLD_INDEX_0;
-		break;
-	}
-}
-
-void tegra30_init_speedo_data(void)
-{
-	u32 cpu_speedo_val;
-	u32 core_speedo_val;
-	int i;
-
-	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
-			THRESHOLD_INDEX_COUNT);
-	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
-			THRESHOLD_INDEX_COUNT);
-
-	package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
-
-	rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id);
-	fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
-	pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
-	pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
-
-	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
-		if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
-			break;
-	}
-	tegra_cpu_process_id = i - 1;
-
-	if (tegra_cpu_process_id == -1) {
-		pr_warn("Tegra30: CPU speedo value %3d out of range",
-		       cpu_speedo_val);
-		tegra_cpu_process_id = 0;
-		tegra_cpu_speedo_id = 1;
-	}
-
-	for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) {
-		if (core_speedo_val < core_process_speedos[threshold_index][i])
-			break;
-	}
-	tegra_core_process_id = i - 1;
-
-	if (tegra_core_process_id == -1) {
-		pr_warn("Tegra30: CORE speedo value %3d out of range",
-		       core_speedo_val);
-		tegra_core_process_id = 0;
-		tegra_soc_speedo_id = 1;
-	}
-
-	pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d",
-		tegra_cpu_speedo_id, tegra_soc_speedo_id);
-}
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7eb4b69..994d02d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,5 @@ obj-$(CONFIG_SRAM)		+= sram.o
 obj-y				+= mic/
 obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
+obj-y				+= fuse/
+
-- 
1.7.7.rc0.72.g4b5ea.dirty


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 0/5] efuse driver for Tegra
  2014-05-28 12:54 [PATCH v5 0/5] efuse driver for Tegra Peter De Schrijver
                   ` (4 preceding siblings ...)
  2014-05-28 12:54 ` [PATCH v5 5/5] ARM: tegra: build new fuse driver in drivers/misc Peter De Schrijver
@ 2014-05-28 13:16 ` Andrew Morton
  2014-05-29 19:22   ` Stephen Warren
  2014-05-29 19:01 ` Stephen Warren
  6 siblings, 1 reply; 18+ messages in thread
From: Andrew Morton @ 2014-05-28 13:16 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Stephen Warren, Thierry Reding, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On Wed, 28 May 2014 15:54:32 +0300 Peter De Schrijver <pdeschrijver@nvidia.com> wrote:

> This driver allows userspace to read the raw efuse data.

The patchset uses an inexplicable mixture of "fuse" and "efuse".
Given that the kernel already has a "fuse", it would be nice if
this code could use "efuse" everywhere.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 2/5] ARM: tegra: move fuse exports to tegra-soc.h
  2014-05-28 12:54 ` [PATCH v5 2/5] ARM: tegra: move fuse exports to tegra-soc.h Peter De Schrijver
@ 2014-05-29 19:01   ` Stephen Warren
  0 siblings, 0 replies; 18+ messages in thread
From: Stephen Warren @ 2014-05-29 19:01 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
> All fuse related functionality will move to a driver in the following patches.
> To prepare for this, export all the required functionality in a global header
> file and move all users of fuse.h to tegra-soc.h. While we're at it, remove
> tegra_bct_strapping, as its only user was removed in Commit a7cbe92cef27
> ("ARM: tegra: remove tegra EMC scaling driver").

> diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h

> @@ -33,4 +54,8 @@ static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
>  	return -EINVAL;
>  }
>  #endif
> +
> +#endif /* __ASSEMBLY__ */
> +
> +
>  #endif /* __LINUX_TEGRA_SOC_H_ */

Nit: 2 blank lines there. I'll try and remember to fix that up when I
apply this, if nothing requires a repost.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 0/5] efuse driver for Tegra
  2014-05-28 12:54 [PATCH v5 0/5] efuse driver for Tegra Peter De Schrijver
                   ` (5 preceding siblings ...)
  2014-05-28 13:16 ` [PATCH v5 0/5] efuse driver for Tegra Andrew Morton
@ 2014-05-29 19:01 ` Stephen Warren
  2014-05-30  8:23   ` Peter De Schrijver
  6 siblings, 1 reply; 18+ messages in thread
From: Stephen Warren @ 2014-05-29 19:01 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
> This driver allows userspace to read the raw efuse data. Its userspace
> interface is modelled after the sunxi_sid driver which provides similar
> functionality for some Allwinner SoCs. It has been tested on
> Tegra20 (ventana), Tegra30 (beaverboard), Tegra114 (dalmore) and
> Tegra124 (jetson TK1).

> Changes since v4:
> 
> * Provide fallback to hardcoded 0x70000800 in case the apbmisc DT node is
>   missing. This is exactly what the current code does and prevents a system
>   crash in that case due to an invalid memory access by tegra_read_chipid()

Wouldn't it be better to simply return an error?

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 3/5] misc: fuse: Add efuse driver for Tegra
  2014-05-28 12:54 ` [PATCH v5 3/5] misc: fuse: Add efuse driver for Tegra Peter De Schrijver
@ 2014-05-29 19:04   ` Stephen Warren
  2014-05-30 11:36     ` Peter De Schrijver
  0 siblings, 1 reply; 18+ messages in thread
From: Stephen Warren @ 2014-05-29 19:04 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
> Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124.

> diff --git a/Documentation/ABI/testing/sysfs-driver-tegra-fuse b/Documentation/ABI/testing/sysfs-driver-tegra-fuse

> +Description:	read-only access to the efuses on Tegra20, Tegra30, Tegra114
> +		and Tegra124 SoC's from NVIDIA. The efuses contain write once
> +		data programmed at the factory. The data is layed out in 32bit
> +		words in LSB first formnat. The number of valid bits depends

s/formnat/format/

> +		on the word and the SoC. The mapping is as follows:
> +
> +		For Tegra20:
> +		Word 0 - 1    : bit 0
> +		Word 2        : unused
> +		Word 3        : bits 0 - 31
> +		Word 4        : bits 0 - 7

Do we really need these long tables that indicate which bits are used?
As I mentioned before, when I asked for documentation of the format of
these files, all I wanted was a brief not indicating that the data was
binary, and that each bit potentially represents a fuse... Either we
should leave it at that, or actually document what each bit represents,
which would hopefully be a pointless duplication of the TRM.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 4/5] ARM: tegra: Add efuse and apbmisc bindings
  2014-05-28 12:54 ` [PATCH v5 4/5] ARM: tegra: Add efuse and apbmisc bindings Peter De Schrijver
@ 2014-05-29 19:13   ` Stephen Warren
  0 siblings, 0 replies; 18+ messages in thread
From: Stephen Warren @ 2014-05-29 19:13 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
> Add efuse and apbmisc bindings for Tegra20, Tegra30, Tegra114 and Tegra124.
> 
> Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
> ---
>  .../devicetree/bindings/fuse/fuse-tegra.txt        |   30 ++++++++++++++++++++
>  .../devicetree/bindings/misc/nvidia,apbmisc.txt    |   13 ++++++++

Please name these files according to the compatible value, like all the
other Tegra bindings. So, nvidia,tegra20-efuse.txt and
nvidia,tegra20-apbmisc.txt.

>  arch/arm/boot/dts/tegra114.dtsi                    |   12 ++++++++
>  arch/arm/boot/dts/tegra124.dtsi                    |   12 ++++++++
>  arch/arm/boot/dts/tegra20.dtsi                     |   12 ++++++++
>  arch/arm/boot/dts/tegra30.dtsi                     |   12 ++++++++

It's a bit odd to mix in the .dtsi changes in the same patch as the
binding doc.

> diff --git a/Documentation/devicetree/bindings/fuse/fuse-tegra.txt b/Documentation/devicetree/bindings/fuse/fuse-tegra.txt

> +- compatible : should be:
> +	"nvidia,tegra20-efuse"
> +	"nvidia,tegra30-efuse"
> +	"nvidia,tegra114-efuse"
> +	"nvidia,tegra124-efuse"
> +  Details:
> +  nvidia,tegra20-efuse: Tegra20 requires using APB DMA to read the fuse data
> +	due to a hardware bug. Tegra20 also lacks certain information which is
> +	available in later generations such as fab code, lot code, wafer id,..
> +  nvidia,tegra30-efuse, nvidia,tegra114-efuse and nvidia,tegra124-efuse:
> +	The differences between these SoCs are the size of the efuse array,
> +	the location of the spare (OEM programmable) bits and the location of
> +	the speedo data.

I suppose it doesn't hurt, but I don't think we need any of the
"Details" section here.

> +- clocks: Should contain a pointer to the fuse clock.

Please require clock-names so we don't need a mix of index-/name-based
lookups in the future. Please follow the same wording as existing Tegra
binding docs that use clocks. For example:

- clocks : Must contain an entry for each entry in clock-names.
  See ../clocks/clock-bindings.txt for details.
- clock-names : Must include the following entries:
  - d_audio
  - apbif

Are there no PMC reset signals fed into the fuse block?

> diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi

> +        apbmisc@0x70000800 {

The unit address in the DT nod name should not contain "0x". Same for
other .dtsi files.

> diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi

> +	apbmisc@0x70000800 {

Tegra124 uses #address-cells=<2>, so the unit address in the node name
needs to follow that. Hence, apbmisc@0,70000800.

> diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi

> @@ -236,6 +236,12 @@
>  		interrupt-controller;
>  	};
>  
> +        apbmisc@0x70000800 {
> +		compatible = "nvidia,tegra20-apbmisc";

Indentation looks odd here. Mix of TABs/spaces perhaps?


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 5/5] ARM: tegra: build new fuse driver in drivers/misc
  2014-05-28 12:54 ` [PATCH v5 5/5] ARM: tegra: build new fuse driver in drivers/misc Peter De Schrijver
@ 2014-05-29 19:14   ` Stephen Warren
  0 siblings, 0 replies; 18+ messages in thread
From: Stephen Warren @ 2014-05-29 19:14 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
> The Tegra fuse code has moved to drivers/misc/fuse/tegra. Enable the
> building of that code, and disable the building of the old fuse code in
> arch/arm/mach-tegra/.

> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 7eb4b69..994d02d 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -55,3 +55,5 @@ obj-$(CONFIG_SRAM)		+= sram.o
>  obj-y				+= mic/
>  obj-$(CONFIG_GENWQE)		+= genwqe/
>  obj-$(CONFIG_ECHO)		+= echo/
> +obj-y				+= fuse/
> +

This adds an empty blank line to the end of the file.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 0/5] efuse driver for Tegra
  2014-05-28 13:16 ` [PATCH v5 0/5] efuse driver for Tegra Andrew Morton
@ 2014-05-29 19:22   ` Stephen Warren
  0 siblings, 0 replies; 18+ messages in thread
From: Stephen Warren @ 2014-05-29 19:22 UTC (permalink / raw)
  To: Andrew Morton, Peter De Schrijver
  Cc: Russell King, Thierry Reding, Linus Walleij, Wolfram Sang,
	linux-arm-kernel, linux-tegra, linux-kernel

On 05/28/2014 07:16 AM, Andrew Morton wrote:
> On Wed, 28 May 2014 15:54:32 +0300 Peter De Schrijver <pdeschrijver@nvidia.com> wrote:
> 
>> This driver allows userspace to read the raw efuse data.
> 
> The patchset uses an inexplicable mixture of "fuse" and "efuse".
> Given that the kernel already has a "fuse", it would be nice if
> this code could use "efuse" everywhere.

I didn't check every instance, but a mix of those two terms seems
reasonable. "fuse" is the type of HW object; it's a generic HW term that
exists outside the scope of this patch. While the conflict with Linux's
filesystem is unfortunate, it's a name collision that I think we'll
simply have to live with; it's not created by this patch. "efuse" is the
name of the Tegra module that hosts Tegra's fuses.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 0/5] efuse driver for Tegra
  2014-05-29 19:01 ` Stephen Warren
@ 2014-05-30  8:23   ` Peter De Schrijver
  2014-05-30 16:17     ` Stephen Warren
  0 siblings, 1 reply; 18+ messages in thread
From: Peter De Schrijver @ 2014-05-30  8:23 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On Thu, May 29, 2014 at 09:01:27PM +0200, Stephen Warren wrote:
> On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
> > This driver allows userspace to read the raw efuse data. Its userspace
> > interface is modelled after the sunxi_sid driver which provides similar
> > functionality for some Allwinner SoCs. It has been tested on
> > Tegra20 (ventana), Tegra30 (beaverboard), Tegra114 (dalmore) and
> > Tegra124 (jetson TK1).
> 
> > Changes since v4:
> > 
> > * Provide fallback to hardcoded 0x70000800 in case the apbmisc DT node is
> >   missing. This is exactly what the current code does and prevents a system
> >   crash in that case due to an invalid memory access by tegra_read_chipid()
> 
> Wouldn't it be better to simply return an error?

This would mean you can't boot a system with these patches applied unless you
also update the device tree. The system would crash during boot because CCF
relies on tegra_read_chipid() as an APB barrier. Also tegra_boot_secondary()
relies on the chipid to select the correct method for booting secondary cores.

Cheers,

Peter.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 3/5] misc: fuse: Add efuse driver for Tegra
  2014-05-29 19:04   ` Stephen Warren
@ 2014-05-30 11:36     ` Peter De Schrijver
  2014-05-30 16:12       ` Stephen Warren
  0 siblings, 1 reply; 18+ messages in thread
From: Peter De Schrijver @ 2014-05-30 11:36 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On Thu, May 29, 2014 at 09:04:33PM +0200, Stephen Warren wrote:
> On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
> > Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124.
> 
> > diff --git a/Documentation/ABI/testing/sysfs-driver-tegra-fuse b/Documentation/ABI/testing/sysfs-driver-tegra-fuse
> 
> > +Description:	read-only access to the efuses on Tegra20, Tegra30, Tegra114
> > +		and Tegra124 SoC's from NVIDIA. The efuses contain write once
> > +		data programmed at the factory. The data is layed out in 32bit
> > +		words in LSB first formnat. The number of valid bits depends
> 
> s/formnat/format/
> 
> > +		on the word and the SoC. The mapping is as follows:
> > +
> > +		For Tegra20:
> > +		Word 0 - 1    : bit 0
> > +		Word 2        : unused
> > +		Word 3        : bits 0 - 31
> > +		Word 4        : bits 0 - 7
> 
> Do we really need these long tables that indicate which bits are used?
> As I mentioned before, when I asked for documentation of the format of
> these files, all I wanted was a brief not indicating that the data was
> binary, and that each bit potentially represents a fuse... Either we
> should leave it at that, or actually document what each bit represents,
> which would hopefully be a pointless duplication of the TRM.

Some fuses are OEM defined, so there is no way to document all fuses there.
Would you be ok with just dropping the tables then? So, the description would
become:

Description:    read-only access to the efuses on Tegra20, Tegra30, Tegra114
                and Tegra124 SoC's from NVIDIA. The efuses contain write once
                data programmed at the factory. The data is layed out in 32bit
                words in LSB first format. The number of valid bits depends
                on the word and the SoC.

Cheers,

Peter.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 3/5] misc: fuse: Add efuse driver for Tegra
  2014-05-30 11:36     ` Peter De Schrijver
@ 2014-05-30 16:12       ` Stephen Warren
  0 siblings, 0 replies; 18+ messages in thread
From: Stephen Warren @ 2014-05-30 16:12 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On 05/30/2014 05:36 AM, Peter De Schrijver wrote:
> On Thu, May 29, 2014 at 09:04:33PM +0200, Stephen Warren wrote:
>> On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
>>> Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124.
>>
>>> diff --git a/Documentation/ABI/testing/sysfs-driver-tegra-fuse b/Documentation/ABI/testing/sysfs-driver-tegra-fuse
>>
>>> +Description:	read-only access to the efuses on Tegra20, Tegra30, Tegra114
>>> +		and Tegra124 SoC's from NVIDIA. The efuses contain write once
>>> +		data programmed at the factory. The data is layed out in 32bit
>>> +		words in LSB first formnat. The number of valid bits depends
>>
>> s/formnat/format/
>>
>>> +		on the word and the SoC. The mapping is as follows:
>>> +
>>> +		For Tegra20:
>>> +		Word 0 - 1    : bit 0
>>> +		Word 2        : unused
>>> +		Word 3        : bits 0 - 31
>>> +		Word 4        : bits 0 - 7
>>
>> Do we really need these long tables that indicate which bits are used?
>> As I mentioned before, when I asked for documentation of the format of
>> these files, all I wanted was a brief not indicating that the data was
>> binary, and that each bit potentially represents a fuse... Either we
>> should leave it at that, or actually document what each bit represents,
>> which would hopefully be a pointless duplication of the TRM.
> 
> Some fuses are OEM defined, so there is no way to document all fuses there.
> Would you be ok with just dropping the tables then?

Yes.

> So, the description would become:
> 
> Description:    read-only access to the efuses on Tegra20, Tegra30, Tegra114
>                 and Tegra124 SoC's from NVIDIA. The efuses contain write once
>                 data programmed at the factory. The data is layed out in 32bit
>                 words in LSB first format. The number of valid bits depends
>                 on the word and the SoC.

Almost. That's still missing the key information that the data format is
one bit per fuse, and the ordering. Perhaps change from:

The data is layed out in 32bit words in LSB first format.

to:

The data is laid out in 32bit words in LSB first format. Each bit
represents a single fuse value. Bits order/assignment exactly matches
the HW registers, including any unused bits.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 0/5] efuse driver for Tegra
  2014-05-30  8:23   ` Peter De Schrijver
@ 2014-05-30 16:17     ` Stephen Warren
  2014-06-02  8:27       ` Peter De Schrijver
  0 siblings, 1 reply; 18+ messages in thread
From: Stephen Warren @ 2014-05-30 16:17 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On 05/30/2014 02:23 AM, Peter De Schrijver wrote:
> On Thu, May 29, 2014 at 09:01:27PM +0200, Stephen Warren wrote:
>> On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
>>> This driver allows userspace to read the raw efuse data. Its userspace
>>> interface is modelled after the sunxi_sid driver which provides similar
>>> functionality for some Allwinner SoCs. It has been tested on
>>> Tegra20 (ventana), Tegra30 (beaverboard), Tegra114 (dalmore) and
>>> Tegra124 (jetson TK1).
>>
>>> Changes since v4:
>>>
>>> * Provide fallback to hardcoded 0x70000800 in case the apbmisc DT node is
>>>   missing. This is exactly what the current code does and prevents a system
>>>   crash in that case due to an invalid memory access by tegra_read_chipid()
>>
>> Wouldn't it be better to simply return an error?
> 
> This would mean you can't boot a system with these patches applied unless you
> also update the device tree. The system would crash during boot because CCF
> relies on tegra_read_chipid() as an APB barrier. Also tegra_boot_secondary()
> relies on the chipid to select the correct method for booting secondary cores.

Is this series really backwards-compatible anyway? tegra_init_fuse()
contains a whole bunch of places where resources are pulled out of DT,
and only one of those has a fallback to use APBMISC_BASE if the DT entry
isn't present.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v5 0/5] efuse driver for Tegra
  2014-05-30 16:17     ` Stephen Warren
@ 2014-06-02  8:27       ` Peter De Schrijver
  0 siblings, 0 replies; 18+ messages in thread
From: Peter De Schrijver @ 2014-06-02  8:27 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Russell King, Thierry Reding, Andrew Morton, Linus Walleij,
	Wolfram Sang, linux-arm-kernel, linux-tegra, linux-kernel

On Fri, May 30, 2014 at 06:17:49PM +0200, Stephen Warren wrote:
> On 05/30/2014 02:23 AM, Peter De Schrijver wrote:
> > On Thu, May 29, 2014 at 09:01:27PM +0200, Stephen Warren wrote:
> >> On 05/28/2014 06:54 AM, Peter De Schrijver wrote:
> >>> This driver allows userspace to read the raw efuse data. Its userspace
> >>> interface is modelled after the sunxi_sid driver which provides similar
> >>> functionality for some Allwinner SoCs. It has been tested on
> >>> Tegra20 (ventana), Tegra30 (beaverboard), Tegra114 (dalmore) and
> >>> Tegra124 (jetson TK1).
> >>
> >>> Changes since v4:
> >>>
> >>> * Provide fallback to hardcoded 0x70000800 in case the apbmisc DT node is
> >>>   missing. This is exactly what the current code does and prevents a system
> >>>   crash in that case due to an invalid memory access by tegra_read_chipid()
> >>
> >> Wouldn't it be better to simply return an error?
> > 
> > This would mean you can't boot a system with these patches applied unless you
> > also update the device tree. The system would crash during boot because CCF
> > relies on tegra_read_chipid() as an APB barrier. Also tegra_boot_secondary()
> > relies on the chipid to select the correct method for booting secondary cores.
> 
> Is this series really backwards-compatible anyway? tegra_init_fuse()
> contains a whole bunch of places where resources are pulled out of DT,
> and only one of those has a fallback to use APBMISC_BASE if the DT entry
> isn't present.

Apart from the randomness initialization, there are no users of
tegra_read_straps(). tegra_fuse_readl() is a new API, so that doesn't pose
any backwards-compatibility problems. The only bug I noticed when rereading
the code is that tegra_get_revision() reads the fuses on an A03 Tegra20 to
findout if it's A03 or A03p. This would obviously crash if the DT entries
are missing. I think this can be worked around by claiming it's an A03
in case the DT entries are missing. I don't think that will cause any problems?

Cheers,

Peter.

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2014-06-02  8:27 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-28 12:54 [PATCH v5 0/5] efuse driver for Tegra Peter De Schrijver
2014-05-28 12:54 ` [PATCH v5 1/5] ARM: tegra: export apb dma readl/writel Peter De Schrijver
2014-05-28 12:54 ` [PATCH v5 2/5] ARM: tegra: move fuse exports to tegra-soc.h Peter De Schrijver
2014-05-29 19:01   ` Stephen Warren
2014-05-28 12:54 ` [PATCH v5 3/5] misc: fuse: Add efuse driver for Tegra Peter De Schrijver
2014-05-29 19:04   ` Stephen Warren
2014-05-30 11:36     ` Peter De Schrijver
2014-05-30 16:12       ` Stephen Warren
2014-05-28 12:54 ` [PATCH v5 4/5] ARM: tegra: Add efuse and apbmisc bindings Peter De Schrijver
2014-05-29 19:13   ` Stephen Warren
2014-05-28 12:54 ` [PATCH v5 5/5] ARM: tegra: build new fuse driver in drivers/misc Peter De Schrijver
2014-05-29 19:14   ` Stephen Warren
2014-05-28 13:16 ` [PATCH v5 0/5] efuse driver for Tegra Andrew Morton
2014-05-29 19:22   ` Stephen Warren
2014-05-29 19:01 ` Stephen Warren
2014-05-30  8:23   ` Peter De Schrijver
2014-05-30 16:17     ` Stephen Warren
2014-06-02  8:27       ` Peter De Schrijver

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).