* [PATCH v2 0/6] efuse driver for Tegra
@ 2013-12-24 13:32 Peter De Schrijver
2013-12-24 13:32 ` [PATCH v2 1/6] ARM: tegra: export apb dma readl/writel Peter De Schrijver
` (5 more replies)
0 siblings, 6 replies; 24+ messages in thread
From: Peter De Schrijver @ 2013-12-24 13:32 UTC (permalink / raw)
To: linux-arm-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) and Tegra114 (dalmore).
Changes since v1:
* Add documentation for sysfs interface
* Cleanup messages
TODO:
* test on Tegra124 (venice2)
Peter De Schrijver (6):
ARM: tegra: export apb dma readl/writel
misc: fuse: Add efuse driver for Tegra
ARM: tegra: Add efuse bindings
ARM: tegra: rework fuse.c
ARM: Tegra: remove speedo files
misc: enable fuse drivers
Documentation/ABI/testing/sysfs-driver-tegra-fuse | 8 +
arch/arm/boot/dts/tegra114.dtsi | 6 +
arch/arm/boot/dts/tegra124.dtsi | 6 +
arch/arm/boot/dts/tegra20.dtsi | 6 +
arch/arm/boot/dts/tegra30.dtsi | 6 +
arch/arm/mach-tegra/Makefile | 3 -
arch/arm/mach-tegra/apbio.c | 51 +++--
arch/arm/mach-tegra/fuse.c | 147 +----------
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/Kconfig | 1 +
drivers/misc/Makefile | 1 +
drivers/misc/fuse/Kconfig | 12 +
drivers/misc/fuse/Makefile | 1 +
drivers/misc/fuse/tegra/Makefile | 7 +
drivers/misc/fuse/tegra/fuse-tegra.c | 97 +++++++
drivers/misc/fuse/tegra/fuse-tegra20.c | 154 +++++++++++
drivers/misc/fuse/tegra/fuse-tegra30.c | 196 ++++++++++++++
drivers/misc/fuse/tegra/fuse.h | 87 ++++++
drivers/misc/fuse/tegra/tegra114_speedo.c | 109 ++++++++
drivers/misc/fuse/tegra/tegra124_speedo.c | 164 ++++++++++++
drivers/misc/fuse/tegra/tegra20_speedo.c | 109 ++++++++
drivers/misc/fuse/tegra/tegra30_speedo.c | 293 +++++++++++++++++++++
include/linux/tegra-soc.h | 17 ++
25 files changed, 1317 insertions(+), 669 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse
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/Kconfig
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/tegra114_speedo.c
create mode 100644 drivers/misc/fuse/tegra/tegra124_speedo.c
create mode 100644 drivers/misc/fuse/tegra/tegra20_speedo.c
create mode 100644 drivers/misc/fuse/tegra/tegra30_speedo.c
--
1.7.7.rc0.72.g4b5ea.dirty
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH v2 1/6] ARM: tegra: export apb dma readl/writel 2013-12-24 13:32 [PATCH v2 0/6] efuse driver for Tegra Peter De Schrijver @ 2013-12-24 13:32 ` Peter De Schrijver 2014-01-06 20:07 ` Stephen Warren 2013-12-24 13:32 ` [PATCH v2 2/6] misc: fuse: Add efuse driver for Tegra Peter De Schrijver ` (4 subsequent siblings) 5 siblings, 1 reply; 24+ messages in thread From: Peter De Schrijver @ 2013-12-24 13:32 UTC (permalink / raw) To: linux-arm-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. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> --- arch/arm/mach-tegra/apbio.c | 51 ++++++++++++++++++++++++++---------------- include/linux/tegra-soc.h | 16 +++++++++++++ 2 files changed, 47 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..f53fe9c 100644 --- a/include/linux/tegra-soc.h +++ b/include/linux/tegra-soc.h @@ -19,4 +19,20 @@ u32 tegra_read_chipid(void); + +#if defined(CONFIG_TEGRA20_APB_DMA) +void tegra_apb_io_init(void); +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 void tegra_apb_io_init(void) {} +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] 24+ messages in thread
* [PATCH v2 1/6] ARM: tegra: export apb dma readl/writel 2013-12-24 13:32 ` [PATCH v2 1/6] ARM: tegra: export apb dma readl/writel Peter De Schrijver @ 2014-01-06 20:07 ` Stephen Warren 2014-01-07 12:54 ` Peter De Schrijver 0 siblings, 1 reply; 24+ messages in thread From: Stephen Warren @ 2014-01-06 20:07 UTC (permalink / raw) To: linux-arm-kernel On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > 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. This does a lot more than just export the functions; it also changes the prototypes. I'm not sure why the prototype change was required/useful. This needs to be mentioned in the commit description/subject, and the reasoning explained too. > diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h > +#if defined(CONFIG_TEGRA20_APB_DMA) > +void tegra_apb_io_init(void); This seems to be an internal function; why is this one publicly prototyped and/or stubbed? ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 1/6] ARM: tegra: export apb dma readl/writel 2014-01-06 20:07 ` Stephen Warren @ 2014-01-07 12:54 ` Peter De Schrijver 0 siblings, 0 replies; 24+ messages in thread From: Peter De Schrijver @ 2014-01-07 12:54 UTC (permalink / raw) To: linux-arm-kernel On Mon, Jan 06, 2014 at 09:07:26PM +0100, Stephen Warren wrote: > On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > > 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. > > This does a lot more than just export the functions; it also changes the > prototypes. I'm not sure why the prototype change was required/useful. > This needs to be mentioned in the commit description/subject, and the > reasoning explained too. > > > diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h > > > +#if defined(CONFIG_TEGRA20_APB_DMA) > > +void tegra_apb_io_init(void); > > This seems to be an internal function; why is this one publicly > prototyped and/or stubbed? > Ah. this might be a leftover from a previous iteration... Need to check. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 2/6] misc: fuse: Add efuse driver for Tegra 2013-12-24 13:32 [PATCH v2 0/6] efuse driver for Tegra Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 1/6] ARM: tegra: export apb dma readl/writel Peter De Schrijver @ 2013-12-24 13:32 ` Peter De Schrijver 2014-01-06 20:32 ` Stephen Warren 2013-12-24 13:32 ` [PATCH v2 3/6] ARM: tegra: Add efuse bindings Peter De Schrijver ` (3 subsequent siblings) 5 siblings, 1 reply; 24+ messages in thread From: Peter De Schrijver @ 2013-12-24 13:32 UTC (permalink / raw) To: linux-arm-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 | 8 + drivers/misc/fuse/Kconfig | 12 + drivers/misc/fuse/Makefile | 1 + drivers/misc/fuse/tegra/Makefile | 7 + drivers/misc/fuse/tegra/fuse-tegra.c | 97 +++++++ drivers/misc/fuse/tegra/fuse-tegra20.c | 154 +++++++++++ drivers/misc/fuse/tegra/fuse-tegra30.c | 196 ++++++++++++++ drivers/misc/fuse/tegra/fuse.h | 87 ++++++ drivers/misc/fuse/tegra/tegra114_speedo.c | 109 ++++++++ drivers/misc/fuse/tegra/tegra124_speedo.c | 164 ++++++++++++ drivers/misc/fuse/tegra/tegra20_speedo.c | 109 ++++++++ drivers/misc/fuse/tegra/tegra30_speedo.c | 293 +++++++++++++++++++++ 12 files changed, 1237 insertions(+), 0 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse create mode 100644 drivers/misc/fuse/Kconfig 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/tegra114_speedo.c create mode 100644 drivers/misc/fuse/tegra/tegra124_speedo.c create mode 100644 drivers/misc/fuse/tegra/tegra20_speedo.c create mode 100644 drivers/misc/fuse/tegra/tegra30_speedo.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..3b5e1ea --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-tegra-fuse @@ -0,0 +1,8 @@ +What: /sys/devices/*/<our-device>/fuse +Date: December 2013 +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. +Users: any user space application which wants to read the efuses on + Tegra SoC's diff --git a/drivers/misc/fuse/Kconfig b/drivers/misc/fuse/Kconfig new file mode 100644 index 0000000..fb66758 --- /dev/null +++ b/drivers/misc/fuse/Kconfig @@ -0,0 +1,12 @@ +menu "fuse support" + +config FUSE_TEGRA + tristate "Tegra fuse supprt" + depends on ARCH_TEGRA && SYSFS + help + This drivers provides read-only to the e-fuses in Tegra chips. + Parsing of the data is left to userspace. + + This driver can also be built as a module. If so, the module + will be called tegra_efuse. +endmenu diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile new file mode 100644 index 0000000..022c354 --- /dev/null +++ b/drivers/misc/fuse/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FUSE_TEGRA) += tegra/ diff --git a/drivers/misc/fuse/tegra/Makefile b/drivers/misc/fuse/tegra/Makefile new file mode 100644 index 0000000..42829b3 --- /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) += tegra20_speedo.o +obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o +obj-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124_speedo.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..b66b922 --- /dev/null +++ b/drivers/misc/fuse/tegra/fuse-tegra.c @@ -0,0 +1,97 @@ +/* + * 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/device.h> +#include <linux/kobject.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include "fuse.h" + +static u32 (*fuse_readl)(const unsigned int offset); +static int fuse_size; + +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, +}; + +int tegra_fuse_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; +} diff --git a/drivers/misc/fuse/tegra/fuse-tegra20.c b/drivers/misc/fuse/tegra/fuse-tegra20.c new file mode 100644 index 0000000..e6d4ae5 --- /dev/null +++ b/drivers/misc/fuse/tegra/fuse-tegra20.c @@ -0,0 +1,154 @@ +/* + * 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/>. + * + * 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/module.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 int fuse_size; +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 enum tegra_revision get_revision(void) +{ + u32 minor_rev; + + minor_rev = (tegra_read_chipid() >> 16) & 0xf; + switch (minor_rev) { + case 1: + return TEGRA_REVISION_A01; + case 2: + return TEGRA_REVISION_A02; + case 3: + if ((tegra20_spare_fuse(18) || tegra20_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 fuse_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; +} + +static const struct of_device_id tegra20_fuse_of_match[] = { + { .compatible = "nvidia,tegra20-efuse" }, +} + +MODULE_DEVICE_TABLE(of, tegra20_fuse_of_match); + +static int tegra_fuse_probe(struct platform_device *pdev) +{ + struct resource *res; + + if (fuse_size) + 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); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fuse_phys = res->start; + + sku_info.revision = get_revision(); + tegra20_init_speedo_data(&sku_info, &pdev->dev); + dev_dbg(&pdev->dev, "Soc Speedo ID %d", sku_info.soc_speedo_id); + + fuse_randomness(); + + platform_set_drvdata(pdev, NULL); + + if (tegra_fuse_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 = tegra_fuse_probe, + .driver = { + .name = "tegra20_fuse", + .owner = THIS_MODULE, + .of_match_table = tegra20_fuse_of_match, + } +}; +module_platform_driver(tegra20_fuse_driver); + +MODULE_AUTHOR("Peter De Schrijver"); +MODULE_DESCRIPTION("Tegra20 fuse driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/misc/fuse/tegra/fuse-tegra30.c b/drivers/misc/fuse/tegra/fuse-tegra30.c new file mode 100644 index 0000000..cd8240c --- /dev/null +++ b/drivers/misc/fuse/tegra/fuse-tegra30.c @@ -0,0 +1,196 @@ +/* + * 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/device.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.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 enum tegra_revision tegra_get_revision(void) +{ + u32 minor_rev; + + minor_rev = (tegra_read_chipid() >> 16) & 0xf; + switch (minor_rev) { + case 1: + return TEGRA_REVISION_A01; + case 2: + return TEGRA_REVISION_A02; + case 3: + return TEGRA_REVISION_A03; + case 4: + return TEGRA_REVISION_A04; + default: + return TEGRA_REVISION_UNKNOWN; + } +} + +static void fuse_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 tegra_fuse_of_match[] = { + { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_info }, + { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_info }, + { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_info }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_fuse_of_match); + +static int tegra_fuse_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_dev_id; + struct resource *res; + + of_dev_id = of_match_device(tegra_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_get_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); + + fuse_randomness(); + + platform_set_drvdata(pdev, NULL); + + if (tegra_fuse_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 tegra_fuse_driver = { + .probe = tegra_fuse_probe, + .driver = { + .name = "tegra_fuse", + .owner = THIS_MODULE, + .of_match_table = tegra_fuse_of_match, + } +}; +module_platform_driver(tegra_fuse_driver); + +MODULE_AUTHOR("Peter De Schrijver"); +MODULE_DESCRIPTION("Tegra fuse driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/misc/fuse/tegra/fuse.h b/drivers/misc/fuse/tegra/fuse.h new file mode 100644 index 0000000..88913cc --- /dev/null +++ b/drivers/misc/fuse/tegra/fuse.h @@ -0,0 +1,87 @@ +/* + * 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 + +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, +}; + +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_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); +#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) {} +#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/tegra114_speedo.c b/drivers/misc/fuse/tegra/tegra114_speedo.c new file mode 100644 index 0000000..aee9001 --- /dev/null +++ b/drivers/misc/fuse/tegra/tegra114_speedo.c @@ -0,0 +1,109 @@ +/* + * 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/device.h> +#include <linux/kernel.h> +#include <linux/bug.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/tegra124_speedo.c b/drivers/misc/fuse/tegra/tegra124_speedo.c new file mode 100644 index 0000000..927b191 --- /dev/null +++ b/drivers/misc/fuse/tegra/tegra124_speedo.c @@ -0,0 +1,164 @@ +/* + * 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/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: + /* Using the default */ + break; + + case 0x81: + case 0x83: + sku_info->cpu_speedo_id = 2; + break; + + 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; + + 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/tegra20_speedo.c b/drivers/misc/fuse/tegra/tegra20_speedo.c new file mode 100644 index 0000000..fe9a995 --- /dev/null +++ b/drivers/misc/fuse/tegra/tegra20_speedo.c @@ -0,0 +1,109 @@ +/* + * 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/device.h> +#include <linux/bug.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/tegra30_speedo.c b/drivers/misc/fuse/tegra/tegra30_speedo.c new file mode 100644 index 0000000..f72832e --- /dev/null +++ b/drivers/misc/fuse/tegra/tegra30_speedo.c @@ -0,0 +1,293 @@ +/* + * 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/device.h> +#include <linux/kernel.h> +#include <linux/bug.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; + } +} -- 1.7.7.rc0.72.g4b5ea.dirty ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 2/6] misc: fuse: Add efuse driver for Tegra 2013-12-24 13:32 ` [PATCH v2 2/6] misc: fuse: Add efuse driver for Tegra Peter De Schrijver @ 2014-01-06 20:32 ` Stephen Warren 2014-01-07 14:05 ` Peter De Schrijver 0 siblings, 1 reply; 24+ messages in thread From: Stephen Warren @ 2014-01-06 20:32 UTC (permalink / raw) To: linux-arm-kernel On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124. > diff --git a/drivers/misc/fuse/Kconfig b/drivers/misc/fuse/Kconfig > +config FUSE_TEGRA > + tristate "Tegra fuse supprt" > + depends on ARCH_TEGRA && SYSFS Since (I think) the Tegra-specific APIs this uses are stubbed if they can't build, perhaps this should depend on "|| COMPILE_TEST" too? > + help > + This drivers provides read-only to the e-fuses in Tegra chips. > + Parsing of the data is left to userspace. > + > + This driver can also be built as a module. If so, the module > + will be called tegra_efuse. > +endmenu I'd expect a blank line before "endmenu" since there's one at the start of the menu contents. > diff --git a/drivers/misc/fuse/tegra/Makefile b/drivers/misc/fuse/tegra/Makefile > +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) += tegra20_speedo.o > +obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o > +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o > +obj-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124_speedo.o > diff --git a/drivers/misc/fuse/tegra/fuse-tegra20.c b/drivers/misc/fuse/tegra/fuse-tegra20.c > +static int fuse_size; I don't think that's used. > +static u32 tegra20_fuse_readl(const unsigned int offset) ... > + ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val); Shouldn't this use the generic tegra_apb_readl(), so that it works irrespective of whether the Tegra20 APB DMA driver is available? > +static const struct of_device_id tegra20_fuse_of_match[] = { > + { .compatible = "nvidia,tegra20-efuse" }, > +} > + > +MODULE_DEVICE_TABLE(of, tegra20_fuse_of_match); You'd typically omit that blank line. > +static int tegra_fuse_probe(struct platform_device *pdev) > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + fuse_phys = res->start; Don't you need to error-check res here? > + fuse_randomness(); If this is a driver, and particularly if this could be in a module, is there any guarantee at all that fuse_randomness() gets called early enough to be useful?> > + platform_set_drvdata(pdev, NULL); That seems pointless; if the drvdata isn't used, there's no need to set it to anything in particular at all. > + if (tegra_fuse_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl, > + &sku_info)) Here (and also for fuse_randomness()), there's no verb in the function name. Perhaps use tegra_fuse_create_sysfs() and fuse_add_randomness(). It wouldn't hurt to be consistent and use a tegra20_ prefix on all the function names too. > diff --git a/drivers/misc/fuse/tegra/fuse-tegra30.c b/drivers/misc/fuse/tegra/fuse-tegra30.c > +u32 tegra30_fuse_readl(const unsigned int offset) > + val = readl_relaxed(fuse_base + FUSE_BEGIN + offset); If you aren't going to call tegra_apb_readl() here, I wonder if you shouldn't rename tegra_apb_readl() as tegra20_apb_readl() to make it obvious that the workaround isn't needed on all chips? > + clk_disable_unprepare(fuse_clk); Doesn't the use of readl_**relaxed**() above mean that the clk_disable_unprepare() could turn off the clock before the fuse read had completed, and hence hang the system? > +static int tegra_fuse_probe(struct platform_device *pdev) > + fuse_randomness(); Here, the same function name is used as in fuse-tegra20.c, which might make debugging a bit more annoying. > +MODULE_LICENSE("GPLv2"); s/GPLv2/GPL v2/ Perhaps the same in other files? > diff --git a/drivers/misc/fuse/tegra/fuse.h b/drivers/misc/fuse/tegra/fuse.h > +#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); > +#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) {} > +#endif I suppose it doesn't hurt, but the Tegra20 functions don't need stubs since they're only called from files that are only compiled for Tegra20. But, I suppose it's fine to be consistent within this file and provide stubs anyway. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 2/6] misc: fuse: Add efuse driver for Tegra 2014-01-06 20:32 ` Stephen Warren @ 2014-01-07 14:05 ` Peter De Schrijver 2014-01-07 20:41 ` Stephen Warren 0 siblings, 1 reply; 24+ messages in thread From: Peter De Schrijver @ 2014-01-07 14:05 UTC (permalink / raw) To: linux-arm-kernel On Mon, Jan 06, 2014 at 09:32:24PM +0100, Stephen Warren wrote: > On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > > Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124. > > > diff --git a/drivers/misc/fuse/Kconfig b/drivers/misc/fuse/Kconfig > > > +config FUSE_TEGRA > > + tristate "Tegra fuse supprt" > > + depends on ARCH_TEGRA && SYSFS > > Since (I think) the Tegra-specific APIs this uses are stubbed if they > can't build, perhaps this should depend on "|| COMPILE_TEST" too? > > > + help > > + This drivers provides read-only to the e-fuses in Tegra chips. > > + Parsing of the data is left to userspace. > > + > > + This driver can also be built as a module. If so, the module > > + will be called tegra_efuse. > > +endmenu > > I'd expect a blank line before "endmenu" since there's one at the start > of the menu contents. > > > diff --git a/drivers/misc/fuse/tegra/Makefile b/drivers/misc/fuse/tegra/Makefile > > > +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) += tegra20_speedo.o > > +obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o > > +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o > > +obj-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124_speedo.o > > > diff --git a/drivers/misc/fuse/tegra/fuse-tegra20.c b/drivers/misc/fuse/tegra/fuse-tegra20.c > > > +static int fuse_size; > > I don't think that's used. > > > +static u32 tegra20_fuse_readl(const unsigned int offset) > ... > > + ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val); > > Shouldn't this use the generic tegra_apb_readl(), so that it works > irrespective of whether the Tegra20 APB DMA driver is available? > tegra_apb_readl() doesn't work reliably on Tegra20 for reading the fuses. So if the Tegra20 APB DMA, this driver should also be unavailable. > > +static const struct of_device_id tegra20_fuse_of_match[] = { > > + { .compatible = "nvidia,tegra20-efuse" }, > > +} > > + > > +MODULE_DEVICE_TABLE(of, tegra20_fuse_of_match); > > You'd typically omit that blank line. > > > +static int tegra_fuse_probe(struct platform_device *pdev) > > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + fuse_phys = res->start; > > Don't you need to error-check res here? > > > + fuse_randomness(); > > If this is a driver, and particularly if this could be in a module, is > there any guarantee at all that fuse_randomness() gets called early > enough to be useful?> > For a module this might be true yes... Should we disallow this making a module? > > + platform_set_drvdata(pdev, NULL); > > That seems pointless; if the drvdata isn't used, there's no need to set > it to anything in particular at all. > > > + if (tegra_fuse_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl, > > + &sku_info)) > > Here (and also for fuse_randomness()), there's no verb in the function > name. Perhaps use tegra_fuse_create_sysfs() and fuse_add_randomness(). > It wouldn't hurt to be consistent and use a tegra20_ prefix on all the > function names too. > > > diff --git a/drivers/misc/fuse/tegra/fuse-tegra30.c b/drivers/misc/fuse/tegra/fuse-tegra30.c > > > +u32 tegra30_fuse_readl(const unsigned int offset) > > > + val = readl_relaxed(fuse_base + FUSE_BEGIN + offset); > > If you aren't going to call tegra_apb_readl() here, I wonder if you > shouldn't rename tegra_apb_readl() as tegra20_apb_readl() to make it > obvious that the workaround isn't needed on all chips? > > > + clk_disable_unprepare(fuse_clk); > > Doesn't the use of readl_**relaxed**() above mean that the > clk_disable_unprepare() could turn off the clock before the fuse read > had completed, and hence hang the system? > Our clk_disable() has a barrier which should cover for this. > > +static int tegra_fuse_probe(struct platform_device *pdev) > > > + fuse_randomness(); > > Here, the same function name is used as in fuse-tegra20.c, which might > make debugging a bit more annoying. > > > +MODULE_LICENSE("GPLv2"); > > s/GPLv2/GPL v2/ Perhaps the same in other files? > > > diff --git a/drivers/misc/fuse/tegra/fuse.h b/drivers/misc/fuse/tegra/fuse.h > > > +#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); > > +#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) {} > > +#endif > > I suppose it doesn't hurt, but the Tegra20 functions don't need stubs > since they're only called from files that are only compiled for Tegra20. > But, I suppose it's fine to be consistent within this file and provide > stubs anyway. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 2/6] misc: fuse: Add efuse driver for Tegra 2014-01-07 14:05 ` Peter De Schrijver @ 2014-01-07 20:41 ` Stephen Warren 0 siblings, 0 replies; 24+ messages in thread From: Stephen Warren @ 2014-01-07 20:41 UTC (permalink / raw) To: linux-arm-kernel On 01/07/2014 07:05 AM, Peter De Schrijver wrote: > On Mon, Jan 06, 2014 at 09:32:24PM +0100, Stephen Warren wrote: >> On 12/24/2013 06:32 AM, Peter De Schrijver wrote: >>> Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124. >>> diff --git a/drivers/misc/fuse/tegra/fuse-tegra20.c b/drivers/misc/fuse/tegra/fuse-tegra20.c >> >>> +static int fuse_size; >> >> I don't think that's used. >> >>> +static u32 tegra20_fuse_readl(const unsigned int offset) >> ... >>> + ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val); >> >> Shouldn't this use the generic tegra_apb_readl(), so that it works >> irrespective of whether the Tegra20 APB DMA driver is available? > > tegra_apb_readl() doesn't work reliably on Tegra20 for reading the fuses. > So if the Tegra20 APB DMA, this driver should also be unavailable. There's no "depends TEGRA20_APB_DMA" in the Kconfig. Perhaps ARCH_TEGRA_2x_SOC or FUSE_TEGRA should "select TEGRA20_APB_DMA"? >>> +static int tegra_fuse_probe(struct platform_device *pdev) >> ... >>> + fuse_randomness(); >> >> If this is a driver, and particularly if this could be in a module, is >> there any guarantee at all that fuse_randomness() gets called early >> enough to be useful? > > For a module this might be true yes... Should we disallow this making a > module? That would simplify things, I expect... ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 3/6] ARM: tegra: Add efuse bindings 2013-12-24 13:32 [PATCH v2 0/6] efuse driver for Tegra Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 1/6] ARM: tegra: export apb dma readl/writel Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 2/6] misc: fuse: Add efuse driver for Tegra Peter De Schrijver @ 2013-12-24 13:32 ` Peter De Schrijver 2014-01-06 20:40 ` Stephen Warren 2013-12-24 13:32 ` [PATCH v2 4/6] ARM: tegra: rework fuse.c Peter De Schrijver ` (2 subsequent siblings) 5 siblings, 1 reply; 24+ messages in thread From: Peter De Schrijver @ 2013-12-24 13:32 UTC (permalink / raw) To: linux-arm-kernel Add efuse bindings for Tegra20, Tegra30, Tegra114 and Tegra124. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> --- arch/arm/boot/dts/tegra114.dtsi | 6 ++++++ arch/arm/boot/dts/tegra124.dtsi | 6 ++++++ arch/arm/boot/dts/tegra20.dtsi | 6 ++++++ arch/arm/boot/dts/tegra30.dtsi | 6 ++++++ 4 files changed, 24 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 389e987..68c616e 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -481,6 +481,12 @@ clock-names = "pclk", "clk32k_in"; }; + efuse at 7000f800 { + compatible = "nvidia,tegra114-efuse"; + reg = <0x7000f800 0x400>; + clocks = <&tegra_car TEGRA114_CLK_FUSE>; + }; + iommu at 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 ec0698a..97bd8e0 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -524,6 +524,12 @@ }; }; + efuse@7000f800 { + compatible = "nvidia,tegra124-efuse"; + reg = <0x7000f800 0x400>; + clocks = <&tegra_car TEGRA124_CLK_FUSE>; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 480ecda..f647aaa 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -541,6 +541,12 @@ #size-cells = <0>; }; + efuse at 7000F800 { + compatible = "nvidia,tegra20-efuse"; + reg = <0x7000F800 0x400>; + clocks = <&tegra_car TEGRA20_CLK_FUSE>; + }; + pcie-controller at 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 ed8e770..828465e 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -623,6 +623,12 @@ nvidia,ahb = <&ahb>; }; + efuse at 7000f800 { + compatible = "nvidia,tegra30-efuse"; + reg = <0x7000f800 0x400>; + clocks = <&tegra_car TEGRA30_CLK_FUSE>; + }; + ahub at 70080000 { compatible = "nvidia,tegra30-ahub"; reg = <0x70080000 0x200 -- 1.7.7.rc0.72.g4b5ea.dirty ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 3/6] ARM: tegra: Add efuse bindings 2013-12-24 13:32 ` [PATCH v2 3/6] ARM: tegra: Add efuse bindings Peter De Schrijver @ 2014-01-06 20:40 ` Stephen Warren 2014-01-08 13:39 ` Thierry Reding 0 siblings, 1 reply; 24+ messages in thread From: Stephen Warren @ 2014-01-06 20:40 UTC (permalink / raw) To: linux-arm-kernel On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > Add efuse bindings for Tegra20, Tegra30, Tegra114 and Tegra124. This patch doesn't add bindings, it adds nodes to device trees. Bindings are the schemas that dictate how the nodes are to be constructed, not the nodes themselves. On that topic, this series needs to create Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt etc. > diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi > + efuse at 7000f800 { ... > + }; > + > cpus { This node isn't sorted correctly. It should be between sdhci at 700b0600 and ahub at 70300000, not after the ahub. > diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi > + efuse at 7000F800 { "fuse" might be a better node name; "efuse" is presumably the name of the instance, not the type of object. Please use lower-case for hex constants; both here and in the reg property. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 3/6] ARM: tegra: Add efuse bindings 2014-01-06 20:40 ` Stephen Warren @ 2014-01-08 13:39 ` Thierry Reding 2014-01-08 18:50 ` Stephen Warren 0 siblings, 1 reply; 24+ messages in thread From: Thierry Reding @ 2014-01-08 13:39 UTC (permalink / raw) To: linux-arm-kernel On Mon, Jan 06, 2014 at 01:40:51PM -0700, Stephen Warren wrote: > On 12/24/2013 06:32 AM, Peter De Schrijver wrote: [...] > > diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi > > > + efuse at 7000F800 { > > "fuse" might be a better node name; "efuse" is presumably the name of > the instance, not the type of object. There's another occurrence I noticed recently where we haven't followed that rule. The PMIC node on Venice2 for instance is called as3722. Perhaps that should also be renamed. Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140108/22986e05/attachment.sig> ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 3/6] ARM: tegra: Add efuse bindings 2014-01-08 13:39 ` Thierry Reding @ 2014-01-08 18:50 ` Stephen Warren 2014-01-08 20:05 ` Thierry Reding 2014-01-08 20:09 ` Thierry Reding 0 siblings, 2 replies; 24+ messages in thread From: Stephen Warren @ 2014-01-08 18:50 UTC (permalink / raw) To: linux-arm-kernel On 01/08/2014 06:39 AM, Thierry Reding wrote: > On Mon, Jan 06, 2014 at 01:40:51PM -0700, Stephen Warren wrote: >> On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > [...] >>> diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi >> >>> + efuse at 7000F800 { >> >> "fuse" might be a better node name; "efuse" is presumably the name of >> the instance, not the type of object. > > There's another occurrence I noticed recently where we haven't followed > that rule. The PMIC node on Venice2 for instance is called as3722. > Perhaps that should also be renamed. Yes, we should fix that. Care to send a patch? ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 3/6] ARM: tegra: Add efuse bindings 2014-01-08 18:50 ` Stephen Warren @ 2014-01-08 20:05 ` Thierry Reding 2014-01-08 20:09 ` Thierry Reding 1 sibling, 0 replies; 24+ messages in thread From: Thierry Reding @ 2014-01-08 20:05 UTC (permalink / raw) To: linux-arm-kernel On Wed, Jan 08, 2014 at 11:50:35AM -0700, Stephen Warren wrote: > On 01/08/2014 06:39 AM, Thierry Reding wrote: > > On Mon, Jan 06, 2014 at 01:40:51PM -0700, Stephen Warren wrote: > >> On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > > [...] > >>> diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi > >> > >>> + efuse at 7000F800 { > >> > >> "fuse" might be a better node name; "efuse" is presumably the name of > >> the instance, not the type of object. > > > > There's another occurrence I noticed recently where we haven't followed > > that rule. The PMIC node on Venice2 for instance is called as3722. > > Perhaps that should also be renamed. > > Yes, we should fix that. Care to send a patch? Will do. Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140108/876abd9e/attachment.sig> ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 3/6] ARM: tegra: Add efuse bindings 2014-01-08 18:50 ` Stephen Warren 2014-01-08 20:05 ` Thierry Reding @ 2014-01-08 20:09 ` Thierry Reding 2014-01-08 22:41 ` Stephen Warren 1 sibling, 1 reply; 24+ messages in thread From: Thierry Reding @ 2014-01-08 20:09 UTC (permalink / raw) To: linux-arm-kernel On Wed, Jan 08, 2014 at 11:50:35AM -0700, Stephen Warren wrote: > On 01/08/2014 06:39 AM, Thierry Reding wrote: > > On Mon, Jan 06, 2014 at 01:40:51PM -0700, Stephen Warren wrote: > >> On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > > [...] > >>> diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi > >> > >>> + efuse at 7000F800 { > >> > >> "fuse" might be a better node name; "efuse" is presumably the name of > >> the instance, not the type of object. > > > > There's another occurrence I noticed recently where we haven't followed > > that rule. The PMIC node on Venice2 for instance is called as3722. > > Perhaps that should also be renamed. > > Yes, we should fix that. Care to send a patch? Ugh... I've just been going through some of the other DTS files and see that quite a lot of other places aren't following this rule either. The Beaver DTS has things like: rt5640: rt5640 at 1c { ... }; which I guess "should have been" rt5640: codec at 1c { /* or even audio-codec at 1c */ ... }; and pmic: tps65911 at 2d { ... }; > which would be another candidate for pmic at 2d. Perhaps it isn't worth fixing them all up after all? Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140108/a8bf636c/attachment.sig> ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 3/6] ARM: tegra: Add efuse bindings 2014-01-08 20:09 ` Thierry Reding @ 2014-01-08 22:41 ` Stephen Warren 2014-01-09 12:40 ` Thierry Reding 0 siblings, 1 reply; 24+ messages in thread From: Stephen Warren @ 2014-01-08 22:41 UTC (permalink / raw) To: linux-arm-kernel On 01/08/2014 01:09 PM, Thierry Reding wrote: > On Wed, Jan 08, 2014 at 11:50:35AM -0700, Stephen Warren wrote: >> On 01/08/2014 06:39 AM, Thierry Reding wrote: >>> On Mon, Jan 06, 2014 at 01:40:51PM -0700, Stephen Warren wrote: >>>> On 12/24/2013 06:32 AM, Peter De Schrijver wrote: >>> [...] >>>>> diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi >>>> >>>>> + efuse at 7000F800 { >>>> >>>> "fuse" might be a better node name; "efuse" is presumably the name of >>>> the instance, not the type of object. >>> >>> There's another occurrence I noticed recently where we haven't followed >>> that rule. The PMIC node on Venice2 for instance is called as3722. >>> Perhaps that should also be renamed. >> >> Yes, we should fix that. Care to send a patch? > > Ugh... I've just been going through some of the other DTS files and see > that quite a lot of other places aren't following this rule either. The ... > Perhaps it isn't worth fixing them all up after all? I guess that just means the patch will be a little bigger; it doesn't seem like that's a good reason not to fix the issue. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 3/6] ARM: tegra: Add efuse bindings 2014-01-08 22:41 ` Stephen Warren @ 2014-01-09 12:40 ` Thierry Reding 0 siblings, 0 replies; 24+ messages in thread From: Thierry Reding @ 2014-01-09 12:40 UTC (permalink / raw) To: linux-arm-kernel On Wed, Jan 08, 2014 at 03:41:52PM -0700, Stephen Warren wrote: > On 01/08/2014 01:09 PM, Thierry Reding wrote: > > On Wed, Jan 08, 2014 at 11:50:35AM -0700, Stephen Warren wrote: > >> On 01/08/2014 06:39 AM, Thierry Reding wrote: > >>> On Mon, Jan 06, 2014 at 01:40:51PM -0700, Stephen Warren wrote: > >>>> On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > >>> [...] > >>>>> diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi > >>>> > >>>>> + efuse at 7000F800 { > >>>> > >>>> "fuse" might be a better node name; "efuse" is presumably the name of > >>>> the instance, not the type of object. > >>> > >>> There's another occurrence I noticed recently where we haven't followed > >>> that rule. The PMIC node on Venice2 for instance is called as3722. > >>> Perhaps that should also be renamed. > >> > >> Yes, we should fix that. Care to send a patch? > > > > Ugh... I've just been going through some of the other DTS files and see > > that quite a lot of other places aren't following this rule either. The > ... > > Perhaps it isn't worth fixing them all up after all? > > I guess that just means the patch will be a little bigger; it doesn't > seem like that's a good reason not to fix the issue. Alright, I'll make a pass over all the DTS files that we have and try to restore some consistency. Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140109/8b8b37d4/attachment-0001.sig> ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 4/6] ARM: tegra: rework fuse.c 2013-12-24 13:32 [PATCH v2 0/6] efuse driver for Tegra Peter De Schrijver ` (2 preceding siblings ...) 2013-12-24 13:32 ` [PATCH v2 3/6] ARM: tegra: Add efuse bindings Peter De Schrijver @ 2013-12-24 13:32 ` Peter De Schrijver 2014-01-03 11:19 ` Alexandre Courbot 2014-01-06 20:50 ` Stephen Warren 2013-12-24 13:32 ` [PATCH v2 5/6] ARM: Tegra: remove speedo files Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 6/6] misc: enable fuse drivers Peter De Schrijver 5 siblings, 2 replies; 24+ messages in thread From: Peter De Schrijver @ 2013-12-24 13:32 UTC (permalink / raw) To: linux-arm-kernel Reduce fuse.c to the minimum functionality required for the early bootstages. Also export tegra_read_straps() for use by the fuse driver. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> --- arch/arm/mach-tegra/fuse.c | 147 ++------------------------------------------ include/linux/tegra-soc.h | 1 + 2 files changed, 7 insertions(+), 141 deletions(-) diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index c9ac23b..bad46e5 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -29,36 +29,14 @@ #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. */ @@ -70,31 +48,6 @@ int tegra_bct_strapping; #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); @@ -102,15 +55,7 @@ u32 tegra_fuse_readl(unsigned long 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; + return tegra_fuse_readl(TEGRA20_FUSE_SPARE_BIT + bit * 4); } static enum tegra_revision tegra_get_revision(u32 id) @@ -135,18 +80,9 @@ static enum tegra_revision tegra_get_revision(u32 id) } } -static void tegra_get_process_id(void) +u32 tegra_read_straps(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(); + return tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); } u32 tegra_read_chipid(void) @@ -154,38 +90,12 @@ 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; - u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); + reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); reg |= 1 << 28; writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); @@ -196,57 +106,12 @@ void __init tegra_init_fuse(void) 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; + reg = tegra_read_straps(); 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/include/linux/tegra-soc.h b/include/linux/tegra-soc.h index f53fe9c..8805f3f 100644 --- a/include/linux/tegra-soc.h +++ b/include/linux/tegra-soc.h @@ -17,6 +17,7 @@ #ifndef __LINUX_TEGRA_SOC_H_ #define __LINUX_TEGRA_SOC_H_ +u32 tegra_read_straps(void); u32 tegra_read_chipid(void); -- 1.7.7.rc0.72.g4b5ea.dirty ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 4/6] ARM: tegra: rework fuse.c 2013-12-24 13:32 ` [PATCH v2 4/6] ARM: tegra: rework fuse.c Peter De Schrijver @ 2014-01-03 11:19 ` Alexandre Courbot 2014-01-06 20:50 ` Stephen Warren 1 sibling, 0 replies; 24+ messages in thread From: Alexandre Courbot @ 2014-01-03 11:19 UTC (permalink / raw) To: linux-arm-kernel On Tue, Dec 24, 2013 at 10:32 PM, Peter De Schrijver <pdeschrijver@nvidia.com> wrote: > Reduce fuse.c to the minimum functionality required for the early bootstages. > Also export tegra_read_straps() for use by the fuse driver. > > Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Fine with this since the fuse clock is still explicitly enabled during init. Acked-by: Alexandre Courbot <acourbot@nvidia.com> ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 4/6] ARM: tegra: rework fuse.c 2013-12-24 13:32 ` [PATCH v2 4/6] ARM: tegra: rework fuse.c Peter De Schrijver 2014-01-03 11:19 ` Alexandre Courbot @ 2014-01-06 20:50 ` Stephen Warren 2014-01-07 14:10 ` Peter De Schrijver 1 sibling, 1 reply; 24+ messages in thread From: Stephen Warren @ 2014-01-06 20:50 UTC (permalink / raw) To: linux-arm-kernel On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > Reduce fuse.c to the minimum functionality required for the early bootstages. > > Also export tegra_read_straps() for use by the fuse driver. Since the fuse driver is tristate, it could be a module. Doesn't it literally need to be EXPORT_SYMBOL'd, not simply not static? I'm rather worried that this series isn't bisectable, since this patch removes a bunch of code that's replaced by code in the fuse driver which can't be built/linked at this point in the series. I'm also worried about initialization ordering, since a lot of the fuse code could be a module... > diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c > -/* Tegra20 only */ > #define FUSE_UID_LOW 0x108 > #define FUSE_UID_HIGH 0x10c Why remove that comment but leave the two defines it applies to? > #define TEGRA20_FUSE_SPARE_BIT 0x200 That define, and tegra_spare_fuse() which uses it, are no longer used after patch 5/6, but aren't removed in patch 5/6. Perhaps it'd be better to squash or re-order the two patches, so this dead code can be removed? > -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; It's a bit odd to remove most of this, but leave a few parts hanging around. Wouldn't it be better to the drivers/misc/fuse code to export this, so that /all/ the fuse logic was there, rather than part of it being left over in arch/arm/? We'll need to fix that up anyway when we start using these globals on ARMv8, so may as well get it right now. Also, I rather think that the new drivers/misc/fuse code shouldn't be a module or driver, so that we can guarantee it's always there to provide the globals and that they are initialized early enough... ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 4/6] ARM: tegra: rework fuse.c 2014-01-06 20:50 ` Stephen Warren @ 2014-01-07 14:10 ` Peter De Schrijver 2014-01-07 20:47 ` Stephen Warren 0 siblings, 1 reply; 24+ messages in thread From: Peter De Schrijver @ 2014-01-07 14:10 UTC (permalink / raw) To: linux-arm-kernel On Mon, Jan 06, 2014 at 09:50:42PM +0100, Stephen Warren wrote: > On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > > Reduce fuse.c to the minimum functionality required for the early bootstages. > > > > Also export tegra_read_straps() for use by the fuse driver. > > Since the fuse driver is tristate, it could be a module. Doesn't it > literally need to be EXPORT_SYMBOL'd, not simply not static? > Good point. > I'm rather worried that this series isn't bisectable, since this patch > removes a bunch of code that's replaced by code in the fuse driver which > can't be built/linked at this point in the series. I'm also worried > about initialization ordering, since a lot of the fuse code could be a > module... > Maybe it should indeed never be a module... > > diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c > > > -/* Tegra20 only */ > > #define FUSE_UID_LOW 0x108 > > #define FUSE_UID_HIGH 0x10c > > Why remove that comment but leave the two defines it applies to? > > > #define TEGRA20_FUSE_SPARE_BIT 0x200 > > That define, and tegra_spare_fuse() which uses it, are no longer used > after patch 5/6, but aren't removed in patch 5/6. Perhaps it'd be better > to squash or re-order the two patches, so this dead code can be removed? > > > -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; > > It's a bit odd to remove most of this, but leave a few parts hanging > around. Wouldn't it be better to the drivers/misc/fuse code to export > this, so that /all/ the fuse logic was there, rather than part of it > being left over in arch/arm/? We'll need to fix that up anyway when we > start using these globals on ARMv8, so may as well get it right now. > Also, I rather think that the new drivers/misc/fuse code shouldn't be a > module or driver, so that we can guarantee it's always there to provide > the globals and that they are initialized early enough... tegra_revision is used in tegra_dt_init() to initialize soc_dev_attr->revision Hence this needs to be available before the fuse driver is initialized. Cheers, Peter. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 4/6] ARM: tegra: rework fuse.c 2014-01-07 14:10 ` Peter De Schrijver @ 2014-01-07 20:47 ` Stephen Warren 2014-01-08 8:31 ` Peter De Schrijver 0 siblings, 1 reply; 24+ messages in thread From: Stephen Warren @ 2014-01-07 20:47 UTC (permalink / raw) To: linux-arm-kernel On 01/07/2014 07:10 AM, Peter De Schrijver wrote: > On Mon, Jan 06, 2014 at 09:50:42PM +0100, Stephen Warren wrote: >> On 12/24/2013 06:32 AM, Peter De Schrijver wrote: >>> Reduce fuse.c to the minimum functionality required for the early bootstages. >>> >>> Also export tegra_read_straps() for use by the fuse driver. >>> diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c >>> -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; >> >> It's a bit odd to remove most of this, but leave a few parts hanging >> around. Wouldn't it be better to the drivers/misc/fuse code to export >> this, so that /all/ the fuse logic was there, rather than part of it >> being left over in arch/arm/? We'll need to fix that up anyway when we >> start using these globals on ARMv8, so may as well get it right now. >> Also, I rather think that the new drivers/misc/fuse code shouldn't be a >> module or driver, so that we can guarantee it's always there to provide >> the globals and that they are initialized early enough... > > tegra_revision is used in tegra_dt_init() to initialize soc_dev_attr->revision > Hence this needs to be available before the fuse driver is initialized. Yes, the same for tegra_chip_id too. My point is: Why not move all the globals into the fuse driver, and make an early call to that fuse driver to initialize all these globals. Basically, rework this patch series to simply move the code to drivers/misc/fuse/, and keep initializing it by function call rather than as a driver probe(). The code can still scan DT to get the required reg/clock/... resources, in a similar fashion to e.g. the Tegra timer or cpufreq drivers IIRC. Perhaps the sysfs exports could be associated with a driver still though - just initialize the globals early? ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 4/6] ARM: tegra: rework fuse.c 2014-01-07 20:47 ` Stephen Warren @ 2014-01-08 8:31 ` Peter De Schrijver 0 siblings, 0 replies; 24+ messages in thread From: Peter De Schrijver @ 2014-01-08 8:31 UTC (permalink / raw) To: linux-arm-kernel On Tue, Jan 07, 2014 at 09:47:05PM +0100, Stephen Warren wrote: > On 01/07/2014 07:10 AM, Peter De Schrijver wrote: > > On Mon, Jan 06, 2014 at 09:50:42PM +0100, Stephen Warren wrote: > >> On 12/24/2013 06:32 AM, Peter De Schrijver wrote: > >>> Reduce fuse.c to the minimum functionality required for the early bootstages. > >>> > >>> Also export tegra_read_straps() for use by the fuse driver. > > >>> diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c > > >>> -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; > >> > >> It's a bit odd to remove most of this, but leave a few parts hanging > >> around. Wouldn't it be better to the drivers/misc/fuse code to export > >> this, so that /all/ the fuse logic was there, rather than part of it > >> being left over in arch/arm/? We'll need to fix that up anyway when we > >> start using these globals on ARMv8, so may as well get it right now. > >> Also, I rather think that the new drivers/misc/fuse code shouldn't be a > >> module or driver, so that we can guarantee it's always there to provide > >> the globals and that they are initialized early enough... > > > > tegra_revision is used in tegra_dt_init() to initialize soc_dev_attr->revision > > Hence this needs to be available before the fuse driver is initialized. > > Yes, the same for tegra_chip_id too. > > My point is: Why not move all the globals into the fuse driver, and make > an early call to that fuse driver to initialize all these globals. > Basically, rework this patch series to simply move the code to > drivers/misc/fuse/, and keep initializing it by function call rather > than as a driver probe(). The code can still scan DT to get the required > reg/clock/... resources, in a similar fashion to e.g. the Tegra timer or > cpufreq drivers IIRC. Perhaps the sysfs exports could be associated with > a driver still though - just initialize the globals early? That's probably better indeed... Will look into that. Cheers, Peter. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v2 5/6] ARM: Tegra: remove speedo files 2013-12-24 13:32 [PATCH v2 0/6] efuse driver for Tegra Peter De Schrijver ` (3 preceding siblings ...) 2013-12-24 13:32 ` [PATCH v2 4/6] ARM: tegra: rework fuse.c Peter De Schrijver @ 2013-12-24 13:32 ` Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 6/6] misc: enable fuse drivers Peter De Schrijver 5 siblings, 0 replies; 24+ messages in thread From: Peter De Schrijver @ 2013-12-24 13:32 UTC (permalink / raw) To: linux-arm-kernel Speedo data is now handled by the fuse driver. Hence these files can be removed. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> --- arch/arm/mach-tegra/Makefile | 3 - arch/arm/mach-tegra/tegra114_speedo.c | 104 ------------ arch/arm/mach-tegra/tegra20_speedo.c | 109 ------------ arch/arm/mach-tegra/tegra30_speedo.c | 292 --------------------------------- 4 files changed, 0 insertions(+), 508 deletions(-) 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 019bb17..40cf28b 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -13,14 +13,12 @@ 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) += tegra2_emc.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) @@ -29,7 +27,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/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c deleted file mode 100644 index 5218d48..0000000 --- a/arch/arm/mach-tegra/tegra114_speedo.c +++ /dev/null @@ -1,104 +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 "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 fa6eb57..0000000 --- a/arch/arm/mach-tegra/tegra20_speedo.c +++ /dev/null @@ -1,109 +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 "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 125cb16..0000000 --- a/arch/arm/mach-tegra/tegra30_speedo.c +++ /dev/null @@ -1,292 +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 "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); -} -- 1.7.7.rc0.72.g4b5ea.dirty ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v2 6/6] misc: enable fuse drivers 2013-12-24 13:32 [PATCH v2 0/6] efuse driver for Tegra Peter De Schrijver ` (4 preceding siblings ...) 2013-12-24 13:32 ` [PATCH v2 5/6] ARM: Tegra: remove speedo files Peter De Schrijver @ 2013-12-24 13:32 ` Peter De Schrijver 5 siblings, 0 replies; 24+ messages in thread From: Peter De Schrijver @ 2013-12-24 13:32 UTC (permalink / raw) To: linux-arm-kernel Enable building the fuse drivers. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> --- drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6cb388e..45560dc 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -526,4 +526,5 @@ source "drivers/misc/mei/Kconfig" source "drivers/misc/vmw_vmci/Kconfig" source "drivers/misc/mic/Kconfig" source "drivers/misc/genwqe/Kconfig" +source "drivers/misc/fuse/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 99b9424..e243a8b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -54,3 +54,4 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o obj-y += mic/ obj-$(CONFIG_GENWQE) += genwqe/ +obj-y += fuse/ -- 1.7.7.rc0.72.g4b5ea.dirty ^ permalink raw reply related [flat|nested] 24+ messages in thread
end of thread, other threads:[~2014-01-09 12:40 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-12-24 13:32 [PATCH v2 0/6] efuse driver for Tegra Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 1/6] ARM: tegra: export apb dma readl/writel Peter De Schrijver 2014-01-06 20:07 ` Stephen Warren 2014-01-07 12:54 ` Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 2/6] misc: fuse: Add efuse driver for Tegra Peter De Schrijver 2014-01-06 20:32 ` Stephen Warren 2014-01-07 14:05 ` Peter De Schrijver 2014-01-07 20:41 ` Stephen Warren 2013-12-24 13:32 ` [PATCH v2 3/6] ARM: tegra: Add efuse bindings Peter De Schrijver 2014-01-06 20:40 ` Stephen Warren 2014-01-08 13:39 ` Thierry Reding 2014-01-08 18:50 ` Stephen Warren 2014-01-08 20:05 ` Thierry Reding 2014-01-08 20:09 ` Thierry Reding 2014-01-08 22:41 ` Stephen Warren 2014-01-09 12:40 ` Thierry Reding 2013-12-24 13:32 ` [PATCH v2 4/6] ARM: tegra: rework fuse.c Peter De Schrijver 2014-01-03 11:19 ` Alexandre Courbot 2014-01-06 20:50 ` Stephen Warren 2014-01-07 14:10 ` Peter De Schrijver 2014-01-07 20:47 ` Stephen Warren 2014-01-08 8:31 ` Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 5/6] ARM: Tegra: remove speedo files Peter De Schrijver 2013-12-24 13:32 ` [PATCH v2 6/6] misc: enable fuse drivers 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).