* [PATCH v8 0/6] efuse driver for Tegra
@ 2014-06-12 15:36 Peter De Schrijver
[not found] ` <1402587400-1544-1-git-send-email-pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Peter De Schrijver @ 2014-06-12 15:36 UTC (permalink / raw)
To: Peter De Schrijver
Cc: Mark Rutland, Wolfram Sang, Linus Walleij, Stefan Agner,
Paul Gortmaker, Thierry Reding, Joseph Lo, Russell King,
Pawel Moll, Stephen Warren, Grant Likely, Tomasz Figa,
Sebastian Hesselbarth, devicetree, linux-tegra, Arnd Bergmann,
Ian Campbell, Tejun Heo, Rob Herring, Alexandre Courbot,
Bjorn Helgaas, linux-arm-kernel, Herbert Xu
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
Changes since v5:
* Fix kernel panic when booting on Tegra20 A03 with a missing fuse DT node
* Incorporate review comments
Changes since v6:
* Add the fix when booting on Tegra20 A03 which was supposed to be in v6 but
missing
Changes since v7:
* Initialize speedo info and randomness in early boot
* Expose speedo, sku and revision related info in tegra_sku_info
* Move APB DMA into Tegra20 fuse driver and remove apbio
* Make code more complex to support systems without conforming DT
Peter De Schrijver (6):
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
misc: fuse: move APB DMA into Tegra20 fuse driver
Documentation/ABI/testing/sysfs-driver-tegra-fuse | 11 +
.../bindings/fuse/nvidia,tegra20-fuse.txt | 40 +++
.../bindings/misc/nvidia,tegra20-apbmisc.txt | 13 +
arch/arm/boot/dts/tegra114.dtsi | 15 +
arch/arm/boot/dts/tegra124.dtsi | 15 +
arch/arm/boot/dts/tegra20.dtsi | 15 +
arch/arm/boot/dts/tegra30.dtsi | 15 +
arch/arm/mach-tegra/Makefile | 5 -
arch/arm/mach-tegra/apbio.c | 206 --------------
arch/arm/mach-tegra/apbio.h | 22 --
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 | 7 +-
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 | 1 +
drivers/misc/fuse/Makefile | 1 +
drivers/misc/fuse/tegra/Makefile | 8 +
drivers/misc/fuse/tegra/fuse-tegra.c | 154 ++++++++++
drivers/misc/fuse/tegra/fuse-tegra20.c | 214 ++++++++++++++
drivers/misc/fuse/tegra/fuse-tegra30.c | 223 +++++++++++++++
drivers/misc/fuse/tegra/fuse.h | 71 +++++
drivers/misc/fuse/tegra/speedo-tegra114.c | 109 ++++++++
drivers/misc/fuse/tegra/speedo-tegra124.c | 167 +++++++++++
drivers/misc/fuse/tegra/speedo-tegra20.c | 109 ++++++++
drivers/misc/fuse/tegra/speedo-tegra30.c | 287 +++++++++++++++++++
drivers/misc/fuse/tegra/tegra-apbmisc.c | 110 ++++++++
include/linux/tegra-soc.h | 42 +++
39 files changed, 1633 insertions(+), 1083 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse
create mode 100644 Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
create mode 100644 Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt
delete mode 100644 arch/arm/mach-tegra/apbio.c
delete mode 100644 arch/arm/mach-tegra/apbio.h
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
create mode 100644 drivers/misc/fuse/tegra/tegra-apbmisc.c
--
1.7.7.rc0.72.g4b5ea.dirty
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v8 3/6] misc: fuse: Add efuse driver for Tegra
[not found] ` <1402587400-1544-1-git-send-email-pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-06-12 15:36 ` Peter De Schrijver
2014-06-12 15:36 ` [PATCH v8 4/6] ARM: tegra: Add efuse and apbmisc bindings Peter De Schrijver
1 sibling, 0 replies; 8+ messages in thread
From: Peter De Schrijver @ 2014-06-12 15:36 UTC (permalink / raw)
To: Peter De Schrijver
Cc: Randy Dunlap, Stephen Warren, Thierry Reding, Grant Likely,
Rob Herring, linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124.
Signed-off-by: Peter De Schrijver <pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
Documentation/ABI/testing/sysfs-driver-tegra-fuse | 11 +
drivers/misc/fuse/Makefile | 1 +
drivers/misc/fuse/tegra/Makefile | 8 +
drivers/misc/fuse/tegra/fuse-tegra.c | 144 +++++++++++
drivers/misc/fuse/tegra/fuse-tegra20.c | 141 ++++++++++
drivers/misc/fuse/tegra/fuse-tegra30.c | 223 ++++++++++++++++
drivers/misc/fuse/tegra/fuse.h | 71 +++++
drivers/misc/fuse/tegra/speedo-tegra114.c | 109 ++++++++
drivers/misc/fuse/tegra/speedo-tegra124.c | 167 ++++++++++++
drivers/misc/fuse/tegra/speedo-tegra20.c | 109 ++++++++
drivers/misc/fuse/tegra/speedo-tegra30.c | 287 +++++++++++++++++++++
drivers/misc/fuse/tegra/tegra-apbmisc.c | 110 ++++++++
include/linux/tegra-soc.h | 18 ++
13 files changed, 1399 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
create mode 100644 drivers/misc/fuse/tegra/tegra-apbmisc.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..69f5af6
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-tegra-fuse
@@ -0,0 +1,11 @@
+What: /sys/devices/*/<our-device>/fuse
+Date: February 2014
+Contact: Peter De Schrijver <pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
+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. Each bit represents a single value
+ as decoded from the fuse registers. Bits order/assignment
+ exactly matches the HW registers, including any unused bits.
+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..3af357d
--- /dev/null
+++ b/drivers/misc/fuse/tegra/Makefile
@@ -0,0 +1,8 @@
+obj-y += fuse-tegra.o
+obj-y += fuse-tegra30.o
+obj-y += tegra-apbmisc.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..3fa6f74
--- /dev/null
+++ b/drivers/misc/fuse/tegra/fuse-tegra.c
@@ -0,0 +1,144 @@
+/*
+ * 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"
+
+static u32 (*fuse_readl)(const unsigned int offset);
+static int fuse_size;
+struct tegra_sku_info tegra_sku_info;
+
+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 car_match[] __initconst = {
+ { .compatible = "nvidia,tegra20-car", },
+ { .compatible = "nvidia,tegra30-car", },
+ { .compatible = "nvidia,tegra114-car", },
+ { .compatible = "nvidia,tegra124-car", },
+ {},
+};
+
+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);
+}
+
+int tegra_fuse_create_sysfs(struct device *dev, int size,
+ u32 (*readl)(const unsigned int offset))
+{
+ if (fuse_size)
+ return -ENODEV;
+
+ fuse_bin_attr.size = size;
+ fuse_bin_attr.read = fuse_read;
+
+ fuse_size = size;
+ fuse_readl = readl;
+
+ return device_create_bin_file(dev, &fuse_bin_attr);
+}
+
+void __init tegra_init_fuse(void)
+{
+ struct device_node *np;
+ void __iomem *car_base;
+
+ tegra_init_apbmisc();
+
+ 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");
+ return;
+ }
+
+ if (tegra_chip_id == TEGRA20)
+ tegra20_init_fuse_early();
+ else
+ tegra30_init_fuse_early();
+
+ pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
+ tegra_revision_name[tegra_sku_info.revision],
+ tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id,
+ tegra_sku_info.core_process_id);
+ pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n",
+ tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_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..09f91bf
--- /dev/null
+++ b/drivers/misc/fuse/tegra/fuse-tegra20.c
@@ -0,0 +1,141 @@
+/*
+ * 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_UID_LOW 0x08
+#define FUSE_UID_HIGH 0x0c
+
+static phys_addr_t fuse_phys;
+static struct clk *fuse_clk;
+static void __iomem __initdata *fuse_base;
+
+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 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;
+
+ if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl))
+ 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);
+
+/* Early boot code. This code is called before the devices are created */
+
+u32 __init tegra20_fuse_early(const unsigned int offset)
+{
+ return readl_relaxed(fuse_base + FUSE_BEGIN + offset);
+}
+
+bool __init tegra20_spare_fuse_early(int spare_bit)
+{
+ u32 offset = spare_bit * 4;
+ bool value;
+
+ value = tegra20_fuse_early(offset + 0x100);
+
+ return value;
+}
+
+static void __init tegra20_fuse_add_randomness(void)
+{
+ u32 randomness[7];
+
+ randomness[0] = tegra_sku_info.sku_id;
+ randomness[1] = tegra_read_straps();
+ randomness[2] = tegra_read_chipid();
+ randomness[3] = tegra_sku_info.cpu_process_id << 16;
+ randomness[3] |= tegra_sku_info.core_process_id;
+ randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
+ randomness[4] |= tegra_sku_info.soc_speedo_id;
+ randomness[5] = tegra20_fuse_early(FUSE_UID_LOW);
+ randomness[6] = tegra20_fuse_early(FUSE_UID_HIGH);
+
+ add_device_randomness(randomness, sizeof(randomness));
+}
+
+void __init tegra20_init_fuse_early(void)
+{
+ fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE);
+
+ tegra_init_revision();
+ tegra20_init_speedo_data(&tegra_sku_info);
+ tegra20_fuse_add_randomness();
+
+ iounmap(fuse_base);
+}
diff --git a/drivers/misc/fuse/tegra/fuse-tegra30.c b/drivers/misc/fuse/tegra/fuse-tegra30.c
new file mode 100644
index 0000000..8aef5d0
--- /dev/null
+++ b/drivers/misc/fuse/tegra/fuse-tegra30.c
@@ -0,0 +1,223 @@
+/*
+ * 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/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/tegra-soc.h>
+
+#include "fuse.h"
+
+#define FUSE_BEGIN 0x100
+
+/* 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)
+
+enum speedo_idx {
+ SPEEDO_TEGRA30 = 0,
+ SPEEDO_TEGRA114,
+ SPEEDO_TEGRA124,
+};
+
+struct tegra_fuse_info {
+ int size;
+ int spare_bit;
+ enum speedo_idx speedo_idx;
+};
+
+static void __iomem *fuse_base;
+static struct clk *fuse_clk;
+static struct tegra_fuse_info *fuse_info;
+
+u32 tegra30_fuse_readl(const unsigned int offset)
+{
+ u32 val;
+
+ /*
+ * early in the boot, the fuse clock will be enabled by
+ * tegra_init_fuse()
+ */
+
+ if (fuse_clk)
+ clk_prepare_enable(fuse_clk);
+
+ val = readl_relaxed(fuse_base + FUSE_BEGIN + offset);
+
+ if (fuse_clk)
+ clk_disable_unprepare(fuse_clk);
+
+ return val;
+}
+
+static struct tegra_fuse_info tegra30_info = {
+ .size = 0x2a4,
+ .spare_bit = 0x144,
+ .speedo_idx = SPEEDO_TEGRA30,
+};
+
+static struct tegra_fuse_info tegra114_info = {
+ .size = 0x2a0,
+ .speedo_idx = SPEEDO_TEGRA114,
+};
+
+static struct tegra_fuse_info tegra124_info = {
+ .size = 0x300,
+ .speedo_idx = SPEEDO_TEGRA124,
+};
+
+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;
+
+ of_dev_id = of_match_device(tegra30_fuse_of_match, &pdev->dev);
+ if (!of_dev_id)
+ return -ENODEV;
+
+ fuse_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(fuse_clk)) {
+ dev_err(&pdev->dev, "missing clock");
+ return PTR_ERR(fuse_clk);
+ }
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (tegra_fuse_create_sysfs(&pdev->dev, fuse_info->size,
+ tegra30_fuse_readl))
+ 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);
+
+/* Early boot code. This code is called before the devices are created */
+
+typedef void (*speedo_f)(struct tegra_sku_info *sku_info);
+
+static speedo_f __initdata speedo_tbl[] = {
+ [SPEEDO_TEGRA30] = tegra30_init_speedo_data,
+ [SPEEDO_TEGRA114] = tegra114_init_speedo_data,
+ [SPEEDO_TEGRA124] = tegra124_init_speedo_data,
+};
+
+static void __init tegra30_fuse_add_randomness(void)
+{
+ u32 randomness[12];
+
+ randomness[0] = tegra_sku_info.sku_id;
+ randomness[1] = tegra_read_straps();
+ randomness[2] = tegra_read_chipid();
+ randomness[3] = tegra_sku_info.cpu_process_id << 16;
+ randomness[3] |= tegra_sku_info.core_process_id;
+ randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
+ randomness[4] |= tegra_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 void __init legacy_fuse_init(void)
+{
+ switch (tegra_chip_id) {
+ case TEGRA30:
+ fuse_info = &tegra30_info;
+ break;
+ case TEGRA114:
+ fuse_info = &tegra114_info;
+ break;
+ case TEGRA124:
+ fuse_info = &tegra124_info;
+ break;
+ default:
+ return;
+ }
+
+ fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE);
+}
+
+bool __init tegra30_spare_fuse(int spare_bit)
+{
+ u32 offset = fuse_info->spare_bit + spare_bit * 4;
+
+ return tegra30_fuse_readl(offset) & 1;
+}
+
+void __init tegra30_init_fuse_early(void)
+{
+ struct device_node *np;
+ const struct of_device_id *of_match;
+
+ np = of_find_matching_node_and_match(NULL, tegra30_fuse_of_match,
+ &of_match);
+ if (np) {
+ fuse_base = of_iomap(np, 0);
+ fuse_info = (struct tegra_fuse_info *)of_match->data;
+ } else
+ legacy_fuse_init();
+
+ if (!fuse_base) {
+ pr_warn("fuse DT node missing and unknown chip id: 0x%02x\n",
+ tegra_chip_id);
+ return;
+ }
+
+ tegra_init_revision();
+ speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info);
+ tegra30_fuse_add_randomness();
+}
diff --git a/drivers/misc/fuse/tegra/fuse.h b/drivers/misc/fuse/tegra/fuse.h
new file mode 100644
index 0000000..b344277
--- /dev/null
+++ b/drivers/misc/fuse/tegra/fuse.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author:
+ * Colin Cross <ccross-z5hGa2qSFaRBDgjK7y7TUQ@public.gmane.org>
+ *
+ * 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
+
+#define TEGRA_FUSE_BASE 0x7000f800
+#define TEGRA_FUSE_SIZE 0x400
+
+int tegra_fuse_create_sysfs(struct device *dev, int size,
+ u32 (*readl)(const unsigned int offset));
+
+bool tegra30_spare_fuse(int bit);
+u32 tegra30_fuse_readl(const unsigned int offset);
+void tegra30_init_fuse_early(void);
+void tegra_init_revision(void);
+void tegra_init_apbmisc(void);
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+void tegra20_init_speedo_data(struct tegra_sku_info *sku_info);
+bool tegra20_spare_fuse_early(int spare_bit);
+void tegra20_init_fuse_early(void);
+u32 tegra20_fuse_early(const unsigned int offset);
+#else
+static inline void tegra20_init_speedo_data(struct tegra_sku_info *sku_info) {}
+static inline bool tegra20_spare_fuse_early(int spare_bit, void *fuse_base)
+{
+ return false;
+}
+static inline void tegra20_init_fuse_early(void);
+static inline tegra20_fuse_early(const unsigned int offset);
+{
+ return 0;
+}
+#endif
+
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+void tegra30_init_speedo_data(struct tegra_sku_info *sku_info);
+#else
+static inline void tegra30_init_speedo_data(struct tegra_sku_info *sku_info) {}
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+void tegra114_init_speedo_data(struct tegra_sku_info *sku_info);
+#else
+static inline void tegra114_init_speedo_data(struct tegra_sku_info *sku_info) {}
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_124_SOC
+void tegra124_init_speedo_data(struct tegra_sku_info *sku_info);
+#else
+static inline void tegra124_init_speedo_data(struct tegra_sku_info *sku_info) {}
+#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..98d6cde
--- /dev/null
+++ b/drivers/misc/fuse/tegra/speedo-tegra114.c
@@ -0,0 +1,109 @@
+/*
+ * 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 2
+#define CPU_PROCESS_CORNERS 2
+
+enum {
+ THRESHOLD_INDEX_0,
+ THRESHOLD_INDEX_1,
+ THRESHOLD_INDEX_COUNT,
+};
+
+static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
+ {1123, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
+ {1695, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
+ int *threshold)
+{
+ 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:
+ pr_err("Tegra 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 __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info)
+{
+ 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);
+
+ cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024;
+ core_speedo_val = tegra30_fuse_readl(0x134);
+
+ for (i = 0; i < CPU_PROCESS_CORNERS; i++)
+ if (cpu_speedo_val < cpu_process_speedos[threshold][i])
+ break;
+ sku_info->cpu_process_id = i;
+
+ for (i = 0; i < CORE_PROCESS_CORNERS; 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..a15dd53
--- /dev/null
+++ b/drivers/misc/fuse/tegra/speedo-tegra124.c
@@ -0,0 +1,167 @@
+/*
+ * 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 2
+#define GPU_PROCESS_CORNERS 2
+#define CORE_PROCESS_CORNERS 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 const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
+ {2190, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = {
+ {1965, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
+ {2101, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
+ int *threshold)
+{
+ 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:
+ pr_err("Tegra Unknown SKU %d\n", sku);
+ /* Using the default for the error case */
+ break;
+ }
+}
+
+void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info)
+{
+ int i, threshold, cpu_speedo_0_value, soc_speedo_0_value;
+ int cpu_iddq_value, gpu_iddq_value, soc_iddq_value;
+
+ 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);
+
+ /* 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);
+
+ 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) {
+ pr_warn("Tegra Warning: Speedo value not fused.\n");
+ WARN_ON(1);
+ return;
+ }
+
+ rev_sku_to_speedo_ids(sku_info, &threshold);
+
+ sku_info->cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ);
+
+ for (i = 0; i < GPU_PROCESS_CORNERS; 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; 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; i++)
+ if (soc_speedo_0_value <
+ core_process_speedos[threshold][i])
+ break;
+ sku_info->core_process_id = i;
+
+ pr_debug("Tegra 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..c951fa4
--- /dev/null
+++ b/drivers/misc/fuse/tegra/speedo-tegra20.c
@@ -0,0 +1,109 @@
+/*
+ * 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 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
+ {315, 366, 420, UINT_MAX},
+ {303, 368, 419, UINT_MAX},
+ {316, 331, 383, UINT_MAX},
+};
+
+static const u32 __initconst core_process_speedos[][PROCESS_CORNERS_NUM] = {
+ {165, 195, 224, UINT_MAX},
+ {165, 195, 224, UINT_MAX},
+ {165, 195, 224, UINT_MAX},
+};
+
+void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info)
+{
+ 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_early(i) |
+ tegra20_spare_fuse_early(i + CPU_SPEEDO_REDUND_OFFS);
+ val = (val << 1) | (reg & 0x1);
+ }
+ val = val * SPEEDO_MULT;
+ pr_debug("Tegra 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_early(i) |
+ tegra20_spare_fuse_early(i + CORE_SPEEDO_REDUND_OFFS);
+ val = (val << 1) | (reg & 0x1);
+ }
+ val = val * SPEEDO_MULT;
+ pr_debug("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..1a85ad8
--- /dev/null
+++ b/drivers/misc/fuse/tegra/speedo-tegra30.c
@@ -0,0 +1,287 @@
+/*
+ * 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 1
+#define CPU_PROCESS_CORNERS 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 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
+ {180},
+ {170},
+ {195},
+ {180},
+ {168},
+ {192},
+ {180},
+ {170},
+ {195},
+ {180},
+ {180},
+ {180},
+};
+
+static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
+ {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 __initdata;
+
+static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
+{
+ 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);
+ pr_debug("Tegra 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 __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info)
+{
+ int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
+
+ 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:
+ pr_err("Tegra Unknown pkg %d\n", package_id);
+ 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:
+ pr_err("Tegra Unknown pkg %d\n", package_id);
+ 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:
+ pr_err("Tegra Unknown pkg %d\n", package_id);
+ 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:
+ pr_err("Tegra Unknown pkg %d\n", package_id);
+ break;
+ }
+ break;
+ default:
+ pr_warn("Tegra 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:
+ pr_warn("Tegra 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 __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info)
+{
+ 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);
+
+
+ rev_sku_to_speedo_ids(sku_info);
+ fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
+ pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val);
+ pr_debug("Tegra Core speedo value %u\n", core_speedo_val);
+
+ for (i = 0; i < CPU_PROCESS_CORNERS; 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) {
+ pr_warn("Tegra 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; 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) {
+ pr_warn("Tegra 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/drivers/misc/fuse/tegra/tegra-apbmisc.c b/drivers/misc/fuse/tegra/tegra-apbmisc.c
new file mode 100644
index 0000000..43e5bd5
--- /dev/null
+++ b/drivers/misc/fuse/tegra/tegra-apbmisc.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 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/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
+#define FUSE_SKU_INFO 0x10
+
+int tegra_chip_id;
+
+static void __iomem *apbmisc_base;
+static void __iomem *strapping_base;
+
+u32 tegra_read_chipid(void)
+{
+ return readl_relaxed(apbmisc_base + 4);
+}
+
+u32 tegra_read_straps(void)
+{
+ if (strapping_base)
+ return readl_relaxed(strapping_base);
+ else
+ return 0;
+}
+
+static const struct of_device_id apbmisc_match[] __initconst = {
+ { .compatible = "nvidia,tegra20-apbmisc", },
+ {},
+};
+
+void __init tegra_init_revision(void)
+{
+ u32 id, minor_rev;
+ int rev;
+
+ id = tegra_read_chipid();
+ minor_rev = (id >> 16) & 0xf;
+
+ switch (minor_rev) {
+ case 1:
+ rev = TEGRA_REVISION_A01;
+ break;
+ case 2:
+ rev = TEGRA_REVISION_A02;
+ break;
+ case 3:
+ if (tegra_chip_id == TEGRA20 &&
+ (tegra20_spare_fuse_early(18) ||
+ tegra20_spare_fuse_early(19)))
+ rev = TEGRA_REVISION_A03p;
+ else
+ rev = TEGRA_REVISION_A03;
+ break;
+ case 4:
+ rev = TEGRA_REVISION_A04;
+ break;
+ default:
+ rev = TEGRA_REVISION_UNKNOWN;
+ }
+
+ tegra_sku_info.revision = rev;
+
+ if (tegra_chip_id == TEGRA20)
+ tegra_sku_info.sku_id = tegra20_fuse_early(FUSE_SKU_INFO);
+ else
+ tegra_sku_info.sku_id = tegra30_fuse_readl(FUSE_SKU_INFO);
+}
+
+void __init tegra_init_apbmisc(void)
+{
+ struct device_node *np;
+ u32 id;
+
+ 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, 1);
+ if (!strapping_base)
+ pr_err("ioremap tegra strapping_base failed\n");
+}
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index db93b77..5c33b16 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 {
@@ -34,12 +37,27 @@ enum tegra_revision {
TEGRA_REVISION_MAX,
};
+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;
+};
+
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;
+extern struct tegra_sku_info tegra_sku_info;
#if defined(CONFIG_TEGRA20_APB_DMA)
int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);
--
1.7.7.rc0.72.g4b5ea.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v8 4/6] ARM: tegra: Add efuse and apbmisc bindings
[not found] ` <1402587400-1544-1-git-send-email-pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-06-12 15:36 ` [PATCH v8 3/6] misc: fuse: Add " Peter De Schrijver
@ 2014-06-12 15:36 ` Peter De Schrijver
1 sibling, 0 replies; 8+ messages in thread
From: Peter De Schrijver @ 2014-06-12 15:36 UTC (permalink / raw)
To: Peter De Schrijver
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Add efuse and apbmisc bindings for Tegra20, Tegra30, Tegra114 and Tegra124.
Signed-off-by: Peter De Schrijver <pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
.../bindings/fuse/nvidia,tegra20-fuse.txt | 40 ++++++++++++++++++++
.../bindings/misc/nvidia,tegra20-apbmisc.txt | 13 ++++++
arch/arm/boot/dts/tegra114.dtsi | 15 +++++++
arch/arm/boot/dts/tegra124.dtsi | 15 +++++++
arch/arm/boot/dts/tegra20.dtsi | 15 +++++++
arch/arm/boot/dts/tegra30.dtsi | 15 +++++++
6 files changed, 113 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
create mode 100644 Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt
diff --git a/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt b/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
new file mode 100644
index 0000000..d8c98c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
@@ -0,0 +1,40 @@
+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: Must contain an entry for each entry in clock-names.
+ See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+ - fuse
+- resets: Must contain an entry for each entry in reset-names.
+ See ../reset/reset.txt for details.
+- reset-names: Must include the following entries:
+ - fuse
+
+Example:
+
+ fuse@7000f800 {
+ compatible = "nvidia,tegra20-efuse";
+ reg = <0x7000F800 0x400>,
+ <0x70000000 0x400>;
+ clocks = <&tegra_car TEGRA20_CLK_FUSE>;
+ clock-names = "fuse";
+ resets = <&tegra_car 39>;
+ reset-names = "fuse";
+ };
+
+
diff --git a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt
new file mode 100644
index 0000000..b97b8be
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/nvidia,tegra20-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..335a1d8 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -220,6 +220,12 @@
interrupt-controller;
};
+ apbmisc@70000800 {
+ 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,15 @@
clock-names = "pclk", "clk32k_in";
};
+ fuse@7000f800 {
+ compatible = "nvidia,tegra114-efuse";
+ reg = <0x7000f800 0x400>;
+ clocks = <&tegra_car TEGRA114_CLK_FUSE>;
+ clock-names = "fuse";
+ resets = <&tegra_car 39>;
+ reset-names = "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..9739a13 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -167,6 +167,12 @@
#dma-cells = <1>;
};
+ apbmisc@0,70000800 {
+ 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,15 @@
clock-names = "pclk", "clk32k_in";
};
+ fuse@0,7000f800 {
+ compatible = "nvidia,tegra124-efuse";
+ reg = <0x0 0x7000f800 0x0 0x400>;
+ clocks = <&tegra_car TEGRA124_CLK_FUSE>;
+ clock-names = "fuse";
+ resets = <&tegra_car 39>;
+ reset-names = "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..243d84c 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -236,6 +236,12 @@
interrupt-controller;
};
+ apbmisc@70000800 {
+ 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,15 @@
#size-cells = <0>;
};
+ fuse@7000f800 {
+ compatible = "nvidia,tegra20-efuse";
+ reg = <0x7000F800 0x400>;
+ clocks = <&tegra_car TEGRA20_CLK_FUSE>;
+ clock-names = "fuse";
+ resets = <&tegra_car 39>;
+ reset-names = "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..0b1ede9 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -335,6 +335,12 @@
interrupt-controller;
};
+ apbmisc@70000800 {
+ 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,15 @@
nvidia,ahb = <&ahb>;
};
+ fuse@7000f800 {
+ compatible = "nvidia,tegra30-efuse";
+ reg = <0x7000f800 0x400>;
+ clocks = <&tegra_car TEGRA30_CLK_FUSE>;
+ clock-names = "fuse";
+ resets = <&tegra_car 39>;
+ reset-names = "fuse";
+ };
+
ahub@70080000 {
compatible = "nvidia,tegra30-ahub";
reg = <0x70080000 0x200
--
1.7.7.rc0.72.g4b5ea.dirty
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v8 0/6] efuse driver for Tegra
2014-06-12 15:36 [PATCH v8 0/6] efuse driver for Tegra Peter De Schrijver
[not found] ` <1402587400-1544-1-git-send-email-pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-06-12 22:17 ` Stephen Warren
2014-06-13 7:23 ` Peter De Schrijver
2014-06-16 18:42 ` Stephen Warren
2 siblings, 1 reply; 8+ messages in thread
From: Stephen Warren @ 2014-06-12 22:17 UTC (permalink / raw)
To: Peter De Schrijver
Cc: Mark Rutland, Wolfram Sang, Linus Walleij, Stefan Agner,
Paul Gortmaker, Thierry Reding, Joseph Lo, Russell King,
Pawel Moll, linux-doc, Grant Likely, Tomasz Figa,
Sebastian Hesselbarth, devicetree, linux-tegra, Arnd Bergmann,
Ian Campbell, Tejun Heo, Rob Herring, Alexandre Courbot,
Bjorn Helgaas, linux-arm-kernel, Herbert Xu, Greg Kroah-Hartman
On 06/12/2014 09:36 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).
I think this series looks OK now. However, I noticed one change in
behaviour that I don't think is expected:
The current code/DTB print:
Tegra Revision: A01 SKU: 0 CPU Process: 0 Core Process: 0
However, applying these patches and booting yields:
Tegra Revision: A01 SKU: 0 CPU Process: 1 Core Process: 1
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v8 0/6] efuse driver for Tegra
2014-06-12 22:17 ` [PATCH v8 0/6] efuse driver for Tegra Stephen Warren
@ 2014-06-13 7:23 ` Peter De Schrijver
2014-06-13 8:00 ` Peter De Schrijver
0 siblings, 1 reply; 8+ messages in thread
From: Peter De Schrijver @ 2014-06-13 7:23 UTC (permalink / raw)
To: Stephen Warren
Cc: Mark Rutland, Wolfram Sang, Linus Walleij, Stefan Agner,
Paul Gortmaker, Thierry Reding, Joseph Lo, Russell King,
Pawel Moll, linux-doc@vger.kernel.org, Grant Likely, Tomasz Figa,
Sebastian Hesselbarth, devicetree@vger.kernel.org,
linux-tegra@vger.kernel.org, Arnd Bergmann, Ian Campbell,
Tejun Heo, Rob Herring, Alex Courbot, Bjorn Helgaas,
linux-arm-kernel
On Fri, Jun 13, 2014 at 12:17:02AM +0200, Stephen Warren wrote:
> On 06/12/2014 09:36 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).
>
> I think this series looks OK now. However, I noticed one change in
> behaviour that I don't think is expected:
>
> The current code/DTB print:
> Tegra Revision: A01 SKU: 0 CPU Process: 0 Core Process: 0
>
> However, applying these patches and booting yields:
> Tegra Revision: A01 SKU: 0 CPU Process: 1 Core Process: 1
>
On which board/SoC?
Cheers,
Peter.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v8 0/6] efuse driver for Tegra
2014-06-13 7:23 ` Peter De Schrijver
@ 2014-06-13 8:00 ` Peter De Schrijver
2014-06-13 16:38 ` Stephen Warren
0 siblings, 1 reply; 8+ messages in thread
From: Peter De Schrijver @ 2014-06-13 8:00 UTC (permalink / raw)
To: Stephen Warren
Cc: Mark Rutland, Wolfram Sang, Linus Walleij, Stefan Agner,
Paul Gortmaker, Thierry Reding, Joseph Lo, Russell King,
Pawel Moll, linux-doc@vger.kernel.org, Grant Likely, Tomasz Figa,
Sebastian Hesselbarth, devicetree@vger.kernel.org, Arnd Bergmann,
Ian Campbell, Olof Johansson, Rob Herring, Alex Courbot,
linux-tegra@vger.kernel.org,
"linux-arm-kernel@lists.infradead.org" <linux-arm-kernel>
On Fri, Jun 13, 2014 at 09:23:28AM +0200, Peter De Schrijver wrote:
> On Fri, Jun 13, 2014 at 12:17:02AM +0200, Stephen Warren wrote:
> > On 06/12/2014 09:36 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).
> >
> > I think this series looks OK now. However, I noticed one change in
> > behaviour that I don't think is expected:
> >
> > The current code/DTB print:
> > Tegra Revision: A01 SKU: 0 CPU Process: 0 Core Process: 0
> >
> > However, applying these patches and booting yields:
> > Tegra Revision: A01 SKU: 0 CPU Process: 1 Core Process: 1
> >
>
> On which board/SoC?
>
I'm guessing you're running on Tegra124 because the silicon revision reported
is A01. If this is correct then, the current output is bogus. The current fuse
code does not have any Tegra124 support and will fall back to reading the same
fuse bits as on Tegra20 to determine the process IDs. You should get a warning
message though: 'Tegra: unknown chip id'
Cheers,
Peter.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v8 0/6] efuse driver for Tegra
2014-06-13 8:00 ` Peter De Schrijver
@ 2014-06-13 16:38 ` Stephen Warren
0 siblings, 0 replies; 8+ messages in thread
From: Stephen Warren @ 2014-06-13 16:38 UTC (permalink / raw)
To: Peter De Schrijver
Cc: Mark Rutland, Wolfram Sang, Linus Walleij, Stefan Agner,
Paul Gortmaker, Thierry Reding, Joseph Lo, Russell King,
Pawel Moll, linux-doc@vger.kernel.org, Grant Likely, Tomasz Figa,
Sebastian Hesselbarth, devicetree@vger.kernel.org, Arnd Bergmann,
Ian Campbell, Olof Johansson, Rob Herring, Alex Courbot,
linux-tegra@vger.kernel.org,
"linux-arm-kernel@lists.infradead.org" <linux-arm-kernel>
On 06/13/2014 02:00 AM, Peter De Schrijver wrote:
> On Fri, Jun 13, 2014 at 09:23:28AM +0200, Peter De Schrijver wrote:
>> On Fri, Jun 13, 2014 at 12:17:02AM +0200, Stephen Warren wrote:
>>> On 06/12/2014 09:36 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).
>>>
>>> I think this series looks OK now. However, I noticed one change in
>>> behaviour that I don't think is expected:
>>>
>>> The current code/DTB print:
>>> Tegra Revision: A01 SKU: 0 CPU Process: 0 Core Process: 0
>>>
>>> However, applying these patches and booting yields:
>>> Tegra Revision: A01 SKU: 0 CPU Process: 1 Core Process: 1
>>
>> On which board/SoC?
Oops. Venice2/Tegra124.
> I'm guessing you're running on Tegra124 because the silicon revision reported
> is A01. If this is correct then, the current output is bogus. The current fuse
> code does not have any Tegra124 support and will fall back to reading the same
> fuse bits as on Tegra20 to determine the process IDs. You should get a warning
> message though: 'Tegra: unknown chip id'
Ah yes:
Tegra: unknown chip id 64
OK, so there's nothing wrong with this change in behaviour:-)
If that error message still exists, it might be nice if that value was
printed in hex since that's what the data sheets and code usually
represents it as. That can certainly be a followon patch though; no need
for a respin.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v8 0/6] efuse driver for Tegra
2014-06-12 15:36 [PATCH v8 0/6] efuse driver for Tegra Peter De Schrijver
[not found] ` <1402587400-1544-1-git-send-email-pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-06-12 22:17 ` [PATCH v8 0/6] efuse driver for Tegra Stephen Warren
@ 2014-06-16 18:42 ` Stephen Warren
2 siblings, 0 replies; 8+ messages in thread
From: Stephen Warren @ 2014-06-16 18:42 UTC (permalink / raw)
To: Peter De Schrijver
Cc: Mark Rutland, Wolfram Sang, Linus Walleij, Stefan Agner,
Paul Gortmaker, Thierry Reding, Joseph Lo, Russell King,
Pawel Moll, linux-doc, Grant Likely, Tomasz Figa,
Sebastian Hesselbarth, devicetree, linux-tegra, Arnd Bergmann,
Ian Campbell, Tejun Heo, Rob Herring, Alexandre Courbot,
Bjorn Helgaas, linux-arm-kernel, Herbert Xu, Greg Kroah-Hartman
On 06/12/2014 09:36 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).
I've applied this series to Tegra's for-3.17/fuse-move branch.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2014-06-16 18:42 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-06-12 15:36 [PATCH v8 0/6] efuse driver for Tegra Peter De Schrijver
[not found] ` <1402587400-1544-1-git-send-email-pdeschrijver-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-06-12 15:36 ` [PATCH v8 3/6] misc: fuse: Add " Peter De Schrijver
2014-06-12 15:36 ` [PATCH v8 4/6] ARM: tegra: Add efuse and apbmisc bindings Peter De Schrijver
2014-06-12 22:17 ` [PATCH v8 0/6] efuse driver for Tegra Stephen Warren
2014-06-13 7:23 ` Peter De Schrijver
2014-06-13 8:00 ` Peter De Schrijver
2014-06-13 16:38 ` Stephen Warren
2014-06-16 18:42 ` Stephen Warren
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).