1
0
Fork 0

ARM: tegra: move fuse code out of arch/arm

This branch moves code related to the Tegra fuses out of arch/arm and
 into a centralized location which could be shared with ARM64. It also
 adds support for reading the fuse data through sysfs.
 
 Included is also some preparatory work that moves Tegra-related header
 files from include/linux to include/soc/tegra as suggested by Arnd.
 
 Furthermore the Tegra chip ID is now retrieved using a function rather
 than a variable so that sanity checks can be done. This is convenient
 in subsequent patches that will move some of the code that's currently
 called from Tegra machine setup into regular initcalls so that it can
 be reused on 64-bit ARM. The sanity checks help with verifying that no
 code tries to obtain the Tegra chip ID before the underlying driver is
 properly initialized.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABAgAGBQJTyR7HAAoJEN0jrNd/PrOhXRoQAKIs/o8Xf6aTb48OOODFt8g0
 3GiKaYfVPk6VzkrhywmulOndmYy9BjLwhX2jnPgPzFbM5h2jk39/PK3RtssD92Wm
 sHbDflbCj+gaLvjETbTWtYbbYmejqp2xhte/F+MMT0QJKl8BjmyO6WOoUL1+QEyW
 p+OUYRgasmyAiq7qov1MeMW+edNqFHhHpmnsva62NUbcOaKTJ6U6antm79PoAA9M
 Da3UScoX9BxqsyuxBteLdcpgSgOHjW/eLz9xHVf5gtG4ZsTjkWFRyP9wwY6rCxij
 +6cMvKs8OT2y+TjQ6qv5/Zu+XbXGbo2yujnK2oFkLsST/LWobGfuGXUp/K7CkkKJ
 0wgZS1t2iT3RXSQn/Fz8zJx9j0q3GJmvMFmdrOAh8Vx6ucP1m8DZ4noms37D0+Wn
 2HSW55sAXIUFALZgOiVRq0GXtw/iA76S9GtjfFWkCkyGV4WLH6C1NSoojvmXWQ3U
 QQWlpGODQFYUTDUhwh6/T3cP7Ip12W9OU2eTNfdgn8D+PU16CPSfdXN6JWxBI13L
 vVUxWMm9JG+QkbSjfw4q2A0dHEu6lssmOSvMjU6pm5v6xCfry6Fn6m3vBBU3OpLx
 mOge6U696hwL3tNMuwfsIVFNQpoHJT+2Saq71jS+XZeGn+5wC3ovejREls0HIzze
 kwHNIuMygB78uVwWyMJr
 =XyRE
 -----END PGP SIGNATURE-----

Merge tag 'tegra-for-3.17-fuse-move' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/cleanup

Merge "ARM: tegra: move fuse code out of arch/arm" from Thierry Reding:

This branch moves code related to the Tegra fuses out of arch/arm and
into a centralized location which could be shared with ARM64. It also
adds support for reading the fuse data through sysfs.

Included is also some preparatory work that moves Tegra-related header
files from include/linux to include/soc/tegra as suggested by Arnd.

Furthermore the Tegra chip ID is now retrieved using a function rather
than a variable so that sanity checks can be done. This is convenient
in subsequent patches that will move some of the code that's currently
called from Tegra machine setup into regular initcalls so that it can
be reused on 64-bit ARM. The sanity checks help with verifying that no
code tries to obtain the Tegra chip ID before the underlying driver is
properly initialized.

* tag 'tegra-for-3.17-fuse-move' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  soc/tegra: fuse: fix dummy functions
  soc/tegra: fuse: move APB DMA into Tegra20 fuse driver
  soc/tegra: Add efuse and apbmisc bindings
  soc/tegra: Add efuse driver for Tegra
  ARM: tegra: move fuse exports to soc/tegra/fuse.h
  ARM: tegra: export apb dma readl/writel
  ARM: tegra: Use a function to get the chip ID
  ARM: tegra: Sort includes alphabetically
  ARM: tegra: Move includes to include/soc/tegra

Signed-off-by: Olof Johansson <olof@lixom.net>
wifi-calibration
Olof Johansson 2014-07-19 12:29:11 -07:00
commit 23e892929e
57 changed files with 1441 additions and 853 deletions

View File

@ -0,0 +1,11 @@
What: /sys/devices/*/<our-device>/fuse
Date: February 2014
Contact: Peter De Schrijver <pdeschrijver@nvidia.com>
Description: read-only access to the efuses on Tegra20, Tegra30, Tegra114
and Tegra124 SoC's from NVIDIA. The efuses contain write once
data programmed at the factory. The data is layed out in 32bit
words in LSB first format. Each bit represents a single value
as decoded from the fuse registers. Bits order/assignment
exactly matches the HW registers, including any unused bits.
Users: any user space application which wants to read the efuses on
Tegra SoC's

View File

@ -0,0 +1,40 @@
NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 fuse block.
Required properties:
- compatible : should be:
"nvidia,tegra20-efuse"
"nvidia,tegra30-efuse"
"nvidia,tegra114-efuse"
"nvidia,tegra124-efuse"
Details:
nvidia,tegra20-efuse: Tegra20 requires using APB DMA to read the fuse data
due to a hardware bug. Tegra20 also lacks certain information which is
available in later generations such as fab code, lot code, wafer id,..
nvidia,tegra30-efuse, nvidia,tegra114-efuse and nvidia,tegra124-efuse:
The differences between these SoCs are the size of the efuse array,
the location of the spare (OEM programmable) bits and the location of
the speedo data.
- reg: Should contain 1 entry: the entry gives the physical address and length
of the fuse registers.
- clocks: Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names: Must include the following entries:
- fuse
- resets: Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names: Must include the following entries:
- fuse
Example:
fuse@7000f800 {
compatible = "nvidia,tegra20-efuse";
reg = <0x7000F800 0x400>,
<0x70000000 0x400>;
clocks = <&tegra_car TEGRA20_CLK_FUSE>;
clock-names = "fuse";
resets = <&tegra_car 39>;
reset-names = "fuse";
};

View File

@ -0,0 +1,13 @@
NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 apbmisc block
Required properties:
- compatible : should be:
"nvidia,tegra20-apbmisc"
"nvidia,tegra30-apbmisc"
"nvidia,tegra114-apbmisc"
"nvidia,tegra124-apbmisc"
- reg: Should contain 2 entries: the first entry gives the physical address
and length of the registers which contain revision and debug features.
The second entry gives the physical address and length of the
registers indicating the strapping options.

View File

@ -220,6 +220,12 @@
interrupt-controller;
};
apbmisc@70000800 {
compatible = "nvidia,tegra114-apbmisc", "nvidia,tegra20-apbmisc";
reg = <0x70000800 0x64 /* Chip revision */
0x70000008 0x04>; /* Strapping options */
};
pinmux: pinmux@70000868 {
compatible = "nvidia,tegra114-pinmux";
reg = <0x70000868 0x148 /* Pad control registers */
@ -485,6 +491,15 @@
clock-names = "pclk", "clk32k_in";
};
fuse@7000f800 {
compatible = "nvidia,tegra114-efuse";
reg = <0x7000f800 0x400>;
clocks = <&tegra_car TEGRA114_CLK_FUSE>;
clock-names = "fuse";
resets = <&tegra_car 39>;
reset-names = "fuse";
};
iommu@70019010 {
compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
reg = <0x70019010 0x02c

View File

@ -179,6 +179,12 @@
#dma-cells = <1>;
};
apbmisc@0,70000800 {
compatible = "nvidia,tegra124-apbmisc", "nvidia,tegra20-apbmisc";
reg = <0x0 0x70000800 0x0 0x64>, /* Chip revision */
<0x0 0x7000E864 0x0 0x04>; /* Strapping options */
};
pinmux: pinmux@0,70000868 {
compatible = "nvidia,tegra124-pinmux";
reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */
@ -449,6 +455,15 @@
clock-names = "pclk", "clk32k_in";
};
fuse@0,7000f800 {
compatible = "nvidia,tegra124-efuse";
reg = <0x0 0x7000f800 0x0 0x400>;
clocks = <&tegra_car TEGRA124_CLK_FUSE>;
clock-names = "fuse";
resets = <&tegra_car 39>;
reset-names = "fuse";
};
sdhci@0,700b0000 {
compatible = "nvidia,tegra124-sdhci";
reg = <0x0 0x700b0000 0x0 0x200>;

View File

@ -236,6 +236,12 @@
interrupt-controller;
};
apbmisc@70000800 {
compatible = "nvidia,tegra20-apbmisc";
reg = <0x70000800 0x64 /* Chip revision */
0x70000008 0x04>; /* Strapping options */
};
pinmux: pinmux@70000014 {
compatible = "nvidia,tegra20-pinmux";
reg = <0x70000014 0x10 /* Tri-state registers */
@ -545,6 +551,15 @@
#size-cells = <0>;
};
fuse@7000f800 {
compatible = "nvidia,tegra20-efuse";
reg = <0x7000F800 0x400>;
clocks = <&tegra_car TEGRA20_CLK_FUSE>;
clock-names = "fuse";
resets = <&tegra_car 39>;
reset-names = "fuse";
};
pcie-controller@80003000 {
compatible = "nvidia,tegra20-pcie";
device_type = "pci";

View File

@ -335,6 +335,12 @@
interrupt-controller;
};
apbmisc@70000800 {
compatible = "nvidia,tegra30-apbmisc", "nvidia,tegra20-apbmisc";
reg = <0x70000800 0x64 /* Chip revision */
0x70000008 0x04>; /* Strapping options */
};
pinmux: pinmux@70000868 {
compatible = "nvidia,tegra30-pinmux";
reg = <0x70000868 0xd4 /* Pad control registers */
@ -631,6 +637,15 @@
nvidia,ahb = <&ahb>;
};
fuse@7000f800 {
compatible = "nvidia,tegra30-efuse";
reg = <0x7000f800 0x400>;
clocks = <&tegra_car TEGRA30_CLK_FUSE>;
clock-names = "fuse";
resets = <&tegra_car 39>;
reset-names = "fuse";
};
ahub@70080000 {
compatible = "nvidia,tegra30-ahub";
reg = <0x70080000 0x200

View File

@ -2,24 +2,20 @@ asflags-y += -march=armv7-a
obj-y += io.o
obj-y += irq.o
obj-y += fuse.o
obj-y += pmc.o
obj-y += flowctrl.o
obj-y += powergate.o
obj-y += apbio.o
obj-y += pm.o
obj-y += reset.o
obj-y += reset-handler.o
obj-y += sleep.o
obj-y += tegra.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o
ifeq ($(CONFIG_CPU_IDLE),y)
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o
endif
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o
ifeq ($(CONFIG_CPU_IDLE),y)
@ -28,7 +24,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)

View File

@ -1,206 +0,0 @@
/*
* Copyright (C) 2010 NVIDIA Corporation.
* Copyright (C) 2010 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include "apbio.h"
#include "iomap.h"
#if defined(CONFIG_TEGRA20_APB_DMA)
static DEFINE_MUTEX(tegra_apb_dma_lock);
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 struct dma_chan *tegra_apb_dma_chan;
static struct dma_slave_config dma_sconfig;
static bool tegra_apb_dma_init(void)
{
dma_cap_mask_t mask;
mutex_lock(&tegra_apb_dma_lock);
/* Check to see if we raced to setup */
if (tegra_apb_dma_chan)
goto skip_init;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
tegra_apb_dma_chan = dma_request_channel(mask, NULL, NULL);
if (!tegra_apb_dma_chan) {
/*
* This is common until the device is probed, so don't
* shout about it.
*/
pr_debug("%s: can not allocate dma channel\n", __func__);
goto err_dma_alloc;
}
tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
&tegra_apb_bb_phys, GFP_KERNEL);
if (!tegra_apb_bb) {
pr_err("%s: can not allocate bounce buffer\n", __func__);
goto err_buff_alloc;
}
dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dma_sconfig.src_maxburst = 1;
dma_sconfig.dst_maxburst = 1;
skip_init:
mutex_unlock(&tegra_apb_dma_lock);
return true;
err_buff_alloc:
dma_release_channel(tegra_apb_dma_chan);
tegra_apb_dma_chan = NULL;
err_dma_alloc:
mutex_unlock(&tegra_apb_dma_lock);
return false;
}
static void apb_dma_complete(void *args)
{
complete(&tegra_apb_wait);
}
static int do_dma_transfer(unsigned long apb_add,
enum dma_transfer_direction dir)
{
struct dma_async_tx_descriptor *dma_desc;
int ret;
if (dir == DMA_DEV_TO_MEM)
dma_sconfig.src_addr = apb_add;
else
dma_sconfig.dst_addr = apb_add;
ret = dmaengine_slave_config(tegra_apb_dma_chan, &dma_sconfig);
if (ret)
return ret;
dma_desc = dmaengine_prep_slave_single(tegra_apb_dma_chan,
tegra_apb_bb_phys, sizeof(u32), dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!dma_desc)
return -EINVAL;
dma_desc->callback = apb_dma_complete;
dma_desc->callback_param = NULL;
reinit_completion(&tegra_apb_wait);
dmaengine_submit(dma_desc);
dma_async_issue_pending(tegra_apb_dma_chan);
ret = wait_for_completion_timeout(&tegra_apb_wait,
msecs_to_jiffies(50));
if (WARN(ret == 0, "apb read dma timed out")) {
dmaengine_terminate_all(tegra_apb_dma_chan);
return -EFAULT;
}
return 0;
}
static u32 tegra_apb_readl_using_dma(unsigned long offset)
{
int ret;
if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
return tegra_apb_readl_direct(offset);
mutex_lock(&tegra_apb_dma_lock);
ret = do_dma_transfer(offset, DMA_DEV_TO_MEM);
if (ret < 0) {
pr_err("error in reading offset 0x%08lx using dma\n", offset);
*(u32 *)tegra_apb_bb = 0;
}
mutex_unlock(&tegra_apb_dma_lock);
return *((u32 *)tegra_apb_bb);
}
static void 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;
}
mutex_lock(&tegra_apb_dma_lock);
*((u32 *)tegra_apb_bb) = value;
ret = do_dma_transfer(offset, DMA_MEM_TO_DEV);
if (ret < 0)
pr_err("error in writing offset 0x%08lx using dma\n", offset);
mutex_unlock(&tegra_apb_dma_lock);
}
#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);
static apbio_read_fptr apbio_read;
static apbio_write_fptr apbio_write;
static u32 tegra_apb_readl_direct(unsigned long offset)
{
return readl(IO_ADDRESS(offset));
}
static void tegra_apb_writel_direct(u32 value, unsigned long offset)
{
writel(value, IO_ADDRESS(offset));
}
void tegra_apb_io_init(void)
{
/* Need to use dma only when it is Tegra20 based platform */
if (of_machine_is_compatible("nvidia,tegra20") ||
!of_have_populated_dt()) {
apbio_read = tegra_apb_readl_using_dma;
apbio_write = tegra_apb_writel_using_dma;
} else {
apbio_read = tegra_apb_readl_direct;
apbio_write = tegra_apb_writel_direct;
}
}
u32 tegra_apb_readl(unsigned long offset)
{
return apbio_read(offset);
}
void tegra_apb_writel(u32 value, unsigned long offset)
{
apbio_write(value, offset);
}

View File

@ -1,22 +0,0 @@
/*
* Copyright (C) 2010 NVIDIA Corporation.
* Copyright (C) 2010 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __MACH_TEGRA_APBIO_H
#define __MACH_TEGRA_APBIO_H
void tegra_apb_io_init(void);
u32 tegra_apb_readl(unsigned long offset);
void tegra_apb_writel(u32 value, unsigned long offset);
#endif

View File

@ -17,9 +17,10 @@
*
*/
#include <linux/platform_device.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/rfkill-gpio.h>
#include "board.h"
static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = {

View File

@ -14,16 +14,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/firmware.h>
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
#include <linux/clockchips.h>
#include <asm/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/cpuidle.h>
#include <asm/suspend.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include "pm.h"
#include "sleep.h"

View File

@ -19,23 +19,23 @@
* more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/clk/tegra.h>
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
#include <linux/clockchips.h>
#include <linux/clk/tegra.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/cpuidle.h>
#include <asm/proc-fns.h>
#include <asm/suspend.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include "pm.h"
#include "sleep.h"
#include "flowctrl.h"
#include "iomap.h"
#include "irq.h"
#include "flowctrl.h"
#include "pm.h"
#include "sleep.h"
#ifdef CONFIG_PM_SLEEP
static bool abort_flag;

View File

@ -19,17 +19,17 @@
* more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/clk/tegra.h>
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
#include <linux/clockchips.h>
#include <linux/clk/tegra.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/cpuidle.h>
#include <asm/proc-fns.h>
#include <asm/suspend.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include "pm.h"
#include "sleep.h"

View File

@ -24,12 +24,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include "fuse.h"
#include <soc/tegra/fuse.h>
#include "cpuidle.h"
void __init tegra_cpuidle_init(void)
{
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
tegra20_cpuidle_init();
@ -49,7 +50,7 @@ void __init tegra_cpuidle_init(void)
void tegra_cpuidle_pcie_irqs_in_use(void)
{
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
tegra20_cpuidle_pcie_irqs_in_use();

View File

@ -18,14 +18,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <soc/tegra/fuse.h>
#include "flowctrl.h"
#include "iomap.h"
#include "fuse.h"
static u8 flowctrl_offset_halt_cpu[] = {
FLOW_CTRL_HALT_CPU0_EVENTS,
@ -76,7 +77,7 @@ void flowctrl_cpu_suspend_enter(unsigned int cpuid)
int i;
reg = flowctrl_read_cpu_csr(cpuid);
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
/* clear wfe bitmap */
reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
@ -117,7 +118,7 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid)
/* Disable powergating via flow controller for CPU0 */
reg = flowctrl_read_cpu_csr(cpuid);
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
/* clear wfe bitmap */
reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;

View File

@ -1,252 +0,0 @@
/*
* arch/arm/mach-tegra/fuse.c
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/export.h>
#include <linux/random.h>
#include <linux/clk.h>
#include <linux/tegra-soc.h>
#include "fuse.h"
#include "iomap.h"
#include "apbio.h"
/* Tegra20 only */
#define FUSE_UID_LOW 0x108
#define FUSE_UID_HIGH 0x10c
/* Tegra30 and later */
#define FUSE_VENDOR_CODE 0x200
#define FUSE_FAB_CODE 0x204
#define FUSE_LOT_CODE_0 0x208
#define FUSE_LOT_CODE_1 0x20c
#define FUSE_WAFER_ID 0x210
#define FUSE_X_COORDINATE 0x214
#define FUSE_Y_COORDINATE 0x218
#define FUSE_SKU_INFO 0x110
#define TEGRA20_FUSE_SPARE_BIT 0x200
#define TEGRA30_FUSE_SPARE_BIT 0x244
int tegra_sku_id;
int tegra_cpu_process_id;
int tegra_core_process_id;
int tegra_chip_id;
int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */
int tegra_soc_speedo_id;
enum tegra_revision tegra_revision;
static struct clk *fuse_clk;
static int tegra_fuse_spare_bit;
static void (*tegra_init_speedo_data)(void);
/* The BCT to use at boot is specified by board straps that can be read
* through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
*/
int tegra_bct_strapping;
#define STRAP_OPT 0x008
#define GMI_AD0 (1 << 4)
#define GMI_AD1 (1 << 5)
#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
#define RAM_CODE_SHIFT 4
static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_UNKNOWN] = "unknown",
[TEGRA_REVISION_A01] = "A01",
[TEGRA_REVISION_A02] = "A02",
[TEGRA_REVISION_A03] = "A03",
[TEGRA_REVISION_A03p] = "A03 prime",
[TEGRA_REVISION_A04] = "A04",
};
static void tegra_fuse_enable_clk(void)
{
if (IS_ERR(fuse_clk))
fuse_clk = clk_get_sys(NULL, "fuse");
if (IS_ERR(fuse_clk))
return;
clk_prepare_enable(fuse_clk);
}
static void tegra_fuse_disable_clk(void)
{
if (IS_ERR(fuse_clk))
return;
clk_disable_unprepare(fuse_clk);
}
u32 tegra_fuse_readl(unsigned long offset)
{
return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
}
bool tegra_spare_fuse(int bit)
{
bool ret;
tegra_fuse_enable_clk();
ret = tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4);
tegra_fuse_disable_clk();
return ret;
}
static enum tegra_revision tegra_get_revision(u32 id)
{
u32 minor_rev = (id >> 16) & 0xf;
switch (minor_rev) {
case 1:
return TEGRA_REVISION_A01;
case 2:
return TEGRA_REVISION_A02;
case 3:
if (tegra_chip_id == TEGRA20 &&
(tegra_spare_fuse(18) || tegra_spare_fuse(19)))
return TEGRA_REVISION_A03p;
else
return TEGRA_REVISION_A03;
case 4:
return TEGRA_REVISION_A04;
default:
return TEGRA_REVISION_UNKNOWN;
}
}
static void tegra_get_process_id(void)
{
u32 reg;
tegra_fuse_enable_clk();
reg = tegra_fuse_readl(tegra_fuse_spare_bit);
tegra_cpu_process_id = (reg >> 6) & 3;
reg = tegra_fuse_readl(tegra_fuse_spare_bit);
tegra_core_process_id = (reg >> 12) & 3;
tegra_fuse_disable_clk();
}
u32 tegra_read_chipid(void)
{
return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
}
static void __init tegra20_fuse_init_randomness(void)
{
u32 randomness[2];
randomness[0] = tegra_fuse_readl(FUSE_UID_LOW);
randomness[1] = tegra_fuse_readl(FUSE_UID_HIGH);
add_device_randomness(randomness, sizeof(randomness));
}
/* Applies to Tegra30 or later */
static void __init tegra30_fuse_init_randomness(void)
{
u32 randomness[7];
randomness[0] = tegra_fuse_readl(FUSE_VENDOR_CODE);
randomness[1] = tegra_fuse_readl(FUSE_FAB_CODE);
randomness[2] = tegra_fuse_readl(FUSE_LOT_CODE_0);
randomness[3] = tegra_fuse_readl(FUSE_LOT_CODE_1);
randomness[4] = tegra_fuse_readl(FUSE_WAFER_ID);
randomness[5] = tegra_fuse_readl(FUSE_X_COORDINATE);
randomness[6] = tegra_fuse_readl(FUSE_Y_COORDINATE);
add_device_randomness(randomness, sizeof(randomness));
}
void __init tegra_init_fuse(void)
{
u32 id;
u32 randomness[5];
u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
reg |= 1 << 28;
writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
/*
* Enable FUSE clock. This needs to be hardcoded because the clock
* subsystem is not active during early boot.
*/
reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14));
reg |= 1 << 7;
writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14));
fuse_clk = ERR_PTR(-EINVAL);
reg = tegra_fuse_readl(FUSE_SKU_INFO);
randomness[0] = reg;
tegra_sku_id = reg & 0xFF;
reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
randomness[1] = reg;
tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
id = tegra_read_chipid();
randomness[2] = id;
tegra_chip_id = (id >> 8) & 0xff;
switch (tegra_chip_id) {
case TEGRA20:
tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
tegra_init_speedo_data = &tegra20_init_speedo_data;
break;
case TEGRA30:
tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
tegra_init_speedo_data = &tegra30_init_speedo_data;
break;
case TEGRA114:
tegra_init_speedo_data = &tegra114_init_speedo_data;
break;
default:
pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id);
tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
tegra_init_speedo_data = &tegra_get_process_id;
}
tegra_revision = tegra_get_revision(id);
tegra_init_speedo_data();
randomness[3] = (tegra_cpu_process_id << 16) | tegra_core_process_id;
randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id;
add_device_randomness(randomness, sizeof(randomness));
switch (tegra_chip_id) {
case TEGRA20:
tegra20_fuse_init_randomness();
break;
case TEGRA30:
case TEGRA114:
default:
tegra30_fuse_init_randomness();
break;
}
pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
tegra_revision_name[tegra_revision],
tegra_sku_id, tegra_cpu_process_id,
tegra_core_process_id);
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __MACH_TEGRA_FUSE_H
#define __MACH_TEGRA_FUSE_H
#define SKU_ID_T20 8
#define SKU_ID_T25SE 20
#define SKU_ID_AP25 23
#define SKU_ID_T25 24
#define SKU_ID_AP25E 27
#define SKU_ID_T25E 28
#define TEGRA20 0x20
#define TEGRA30 0x30
#define TEGRA114 0x35
#define TEGRA124 0x40
#ifndef __ASSEMBLY__
enum tegra_revision {
TEGRA_REVISION_UNKNOWN = 0,
TEGRA_REVISION_A01,
TEGRA_REVISION_A02,
TEGRA_REVISION_A03,
TEGRA_REVISION_A03p,
TEGRA_REVISION_A04,
TEGRA_REVISION_MAX,
};
extern int tegra_sku_id;
extern int tegra_cpu_process_id;
extern int tegra_core_process_id;
extern int tegra_chip_id;
extern int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */
extern int tegra_soc_speedo_id;
extern enum tegra_revision tegra_revision;
extern int tegra_bct_strapping;
unsigned long long tegra_chip_uid(void);
void tegra_init_fuse(void);
bool tegra_spare_fuse(int bit);
u32 tegra_fuse_readl(unsigned long offset);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
void tegra20_init_speedo_data(void);
#else
static inline void tegra20_init_speedo_data(void) {}
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
void tegra30_init_speedo_data(void);
#else
static inline void tegra30_init_speedo_data(void) {}
#endif
#ifdef CONFIG_ARCH_TEGRA_114_SOC
void tegra114_init_speedo_data(void);
#else
static inline void tegra114_init_speedo_data(void) {}
#endif
#endif /* __ASSEMBLY__ */
#endif

View File

@ -7,13 +7,15 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk/tegra.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/clk/tegra.h>
#include <soc/tegra/fuse.h>
#include <asm/smp_plat.h>
#include "fuse.h"
#include "sleep.h"
static void (*tegra_hotplug_shutdown)(void);
@ -51,12 +53,12 @@ void __init tegra_hotplug_init(void)
if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
return;
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20)
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20)
tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30)
tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114)
if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114)
tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124)
if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124)
tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
}

View File

@ -18,14 +18,14 @@
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/page.h>
#include "board.h"
#include "iomap.h"

View File

@ -17,14 +17,14 @@
*
*/
#include <linux/kernel.h>
#include <linux/cpu_pm.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/syscore_ops.h>
#include "board.h"

View File

@ -11,27 +11,28 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/clk/tegra.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <linux/clk/tegra.h>
#include <soc/tegra/fuse.h>
#include <asm/cacheflush.h>
#include <asm/mach-types.h>
#include <asm/smp_scu.h>
#include <asm/smp_plat.h>
#include "fuse.h"
#include "flowctrl.h"
#include "reset.h"
#include "pmc.h"
#include <asm/smp_scu.h>
#include "common.h"
#include "flowctrl.h"
#include "iomap.h"
#include "pmc.h"
#include "reset.h"
static cpumask_t tegra_cpu_init_mask;
@ -170,13 +171,13 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
static int tegra_boot_secondary(unsigned int cpu,
struct task_struct *idle)
{
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20)
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20)
return tegra20_boot_secondary(cpu, idle);
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30)
return tegra30_boot_secondary(cpu, idle);
if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114)
if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114)
return tegra114_boot_secondary(cpu, idle);
if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124)
if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124)
return tegra114_boot_secondary(cpu, idle);
return -EINVAL;

View File

@ -13,6 +13,7 @@
* 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 "pm.h"

View File

@ -13,6 +13,7 @@
* 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 "pm.h"

View File

@ -16,30 +16,31 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/cpu_pm.h>
#include <linux/suspend.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk/tegra.h>
#include <linux/cpumask.h>
#include <linux/cpu_pm.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/suspend.h>
#include <soc/tegra/fuse.h>
#include <asm/smp_plat.h>
#include <asm/cacheflush.h>
#include <asm/suspend.h>
#include <asm/idmap.h>
#include <asm/proc-fns.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include <asm/tlbflush.h>
#include "iomap.h"
#include "reset.h"
#include "flowctrl.h"
#include "fuse.h"
#include "pm.h"
#include "iomap.h"
#include "pmc.h"
#include "pm.h"
#include "reset.h"
#include "sleep.h"
#ifdef CONFIG_PM_SLEEP
@ -53,7 +54,7 @@ static int (*tegra_sleep_func)(unsigned long v2p);
static void tegra_tear_down_cpu_init(void)
{
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
tegra_tear_down_cpu = tegra20_tear_down_cpu;
@ -143,7 +144,7 @@ bool tegra_set_cpu_in_lp2(void)
if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
last_cpu = true;
else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1)
else if (tegra_get_chip_id() == TEGRA20 && phy_cpu_id == 1)
tegra20_cpu_set_resettable_soon();
spin_unlock(&tegra_lp2_lock);
@ -212,7 +213,7 @@ static int tegra_sleep_core(unsigned long v2p)
*/
static bool tegra_lp1_iram_hook(void)
{
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
tegra20_lp1_iram_hook();
@ -242,7 +243,7 @@ static bool tegra_lp1_iram_hook(void)
static bool tegra_sleep_core_init(void)
{
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
tegra20_sleep_core_init();

View File

@ -15,15 +15,16 @@
*
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/tegra-powergate.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/powergate.h>
#include "flowctrl.h"
#include "fuse.h"
#include "pm.h"
#include "pmc.h"
#include "sleep.h"
@ -251,7 +252,7 @@ void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
reg |= TEGRA_POWER_CPU_PWRREQ_OE;
reg &= ~TEGRA_POWER_EFFECT_LP0;
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
case TEGRA30:
break;

View File

@ -17,21 +17,22 @@
*
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clk/tegra.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/reset.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/clk/tegra.h>
#include <linux/tegra-powergate.h>
#include "fuse.h"
#include <soc/tegra/fuse.h>
#include <soc/tegra/powergate.h>
#include "iomap.h"
#define DPD_SAMPLE 0x020
@ -157,7 +158,7 @@ int tegra_powergate_remove_clamping(int id)
* The Tegra124 GPU has a separate register (with different semantics)
* to remove clamps.
*/
if (tegra_chip_id == TEGRA124) {
if (tegra_get_chip_id() == TEGRA124) {
if (id == TEGRA_POWERGATE_3D) {
pmc_write(0, GPU_RG_CNTRL);
return 0;
@ -227,7 +228,7 @@ int tegra_cpu_powergate_id(int cpuid)
int __init tegra_powergate_init(void)
{
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
tegra_num_powerdomains = 7;
break;
@ -368,7 +369,7 @@ int __init tegra_powergate_debugfs_init(void)
{
struct dentry *d;
switch (tegra_chip_id) {
switch (tegra_get_chip_id()) {
case TEGRA20:
powergate_name = powergate_name_t20;
break;

View File

@ -14,14 +14,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/linkage.h>
#include <soc/tegra/fuse.h>
#include <asm/cache.h>
#include <asm/asm-offsets.h>
#include <asm/cache.h>
#include "flowctrl.h"
#include "fuse.h"
#include "iomap.h"
#include "reset.h"
#include "sleep.h"

View File

@ -14,20 +14,21 @@
*
*/
#include <linux/bitops.h>
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/cpumask.h>
#include <linux/bitops.h>
#include <soc/tegra/fuse.h>
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/firmware.h>
#include <asm/hardware/cache-l2x0.h>
#include "iomap.h"
#include "irammap.h"
#include "reset.h"
#include "sleep.h"
#include "fuse.h"
#define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \
TEGRA_IRAM_RESET_HANDLER_OFFSET)
@ -53,7 +54,7 @@ static void __init tegra_cpu_reset_handler_set(const u32 reset_address)
* Prevent further modifications to the physical reset vector.
* NOTE: Has no effect on chips prior to Tegra30.
*/
if (tegra_chip_id != TEGRA20) {
if (tegra_get_chip_id() != TEGRA20) {
reg = readl(sb_ctrl);
reg |= 2;
writel(reg, sb_ctrl);

View File

@ -16,14 +16,15 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <soc/tegra/fuse.h>
#include <asm/asm-offsets.h>
#include <asm/assembler.h>
#include <asm/cache.h>
#include "irammap.h"
#include "fuse.h"
#include "sleep.h"
#include "flowctrl.h"
#include "irammap.h"
#include "sleep.h"
#define EMC_CFG 0xc
#define EMC_ADR_CFG 0x10

View File

@ -16,37 +16,37 @@
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/clk.h>
#include <linux/clk/tegra.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pda_power.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
#include <linux/usb/tegra_usb_phy.h>
#include <linux/clk/tegra.h>
#include <linux/irqchip.h>
#include <soc/tegra/fuse.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
#include <asm/trusted_foundations.h>
#include "apbio.h"
#include "board.h"
#include "common.h"
#include "cpuidle.h"
#include "fuse.h"
#include "iomap.h"
#include "irq.h"
#include "pmc.h"
@ -73,7 +73,6 @@ u32 tegra_uart_config[3] = {
static void __init tegra_init_early(void)
{
of_register_trusted_foundations();
tegra_apb_io_init();
tegra_init_fuse();
tegra_cpu_reset_handler_init();
tegra_powergate_init();
@ -103,8 +102,9 @@ static void __init tegra_dt_init(void)
goto out;
soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra");
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision);
soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id);
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d",
tegra_sku_info.revision);
soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id());
soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) {

View File

@ -25,7 +25,8 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/tegra-ahb.h>
#include <soc/tegra/ahb.h>
#define DRV_NAME "tegra-ahb"

View File

@ -20,7 +20,8 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/tegra-soc.h>
#include <soc/tegra/fuse.h>
#include "clk.h"

View File

@ -22,8 +22,11 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/tegra.h>
#include <linux/tegra-powergate.h>
#include <soc/tegra/powergate.h>
#include <dt-bindings/clock/tegra30-car.h>
#include "clk.h"
#include "clk-id.h"

View File

@ -19,7 +19,8 @@
#include <linux/of.h>
#include <linux/clk/tegra.h>
#include <linux/reset-controller.h>
#include <linux/tegra-soc.h>
#include <soc/tegra/fuse.h>
#include "clk.h"

View File

@ -12,7 +12,8 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/tegra-powergate.h>
#include <soc/tegra/powergate.h>
#include "drm.h"
#include "gem.h"

View File

@ -11,7 +11,8 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/tegra-powergate.h>
#include <soc/tegra/powergate.h>
#include <drm/drm_dp_helper.h>

View File

@ -35,7 +35,8 @@
#include <linux/of_iommu.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/tegra-ahb.h>
#include <soc/tegra/ahb.h>
#include <asm/page.h>
#include <asm/cacheflush.h>

View File

@ -0,0 +1 @@
obj-$(CONFIG_ARCH_TEGRA) += tegra/

View File

@ -41,11 +41,12 @@
#include <linux/reset.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/tegra-cpuidle.h>
#include <linux/tegra-powergate.h>
#include <linux/vmalloc.h>
#include <linux/regulator/consumer.h>
#include <soc/tegra/cpuidle.h>
#include <soc/tegra/powergate.h>
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
#include <asm/mach/pci.h>

View File

@ -3,3 +3,4 @@
#
obj-$(CONFIG_ARCH_QCOM) += qcom/
obj-$(CONFIG_ARCH_TEGRA) += tegra/

View File

@ -0,0 +1 @@
obj-$(CONFIG_ARCH_TEGRA) += fuse/

View File

@ -0,0 +1,8 @@
obj-y += fuse-tegra.o
obj-y += fuse-tegra30.o
obj-y += tegra-apbmisc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += fuse-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += speedo-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += speedo-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += speedo-tegra124.o

View File

@ -0,0 +1,156 @@
/*
* Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/device.h>
#include <linux/kobject.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
static u32 (*fuse_readl)(const unsigned int offset);
static int fuse_size;
struct tegra_sku_info tegra_sku_info;
static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_UNKNOWN] = "unknown",
[TEGRA_REVISION_A01] = "A01",
[TEGRA_REVISION_A02] = "A02",
[TEGRA_REVISION_A03] = "A03",
[TEGRA_REVISION_A03p] = "A03 prime",
[TEGRA_REVISION_A04] = "A04",
};
static u8 fuse_readb(const unsigned int offset)
{
u32 val;
val = fuse_readl(round_down(offset, 4));
val >>= (offset % 4) * 8;
val &= 0xff;
return val;
}
static ssize_t fuse_read(struct file *fd, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t pos, size_t size)
{
int i;
if (pos < 0 || pos >= fuse_size)
return 0;
if (size > fuse_size - pos)
size = fuse_size - pos;
for (i = 0; i < size; i++)
buf[i] = fuse_readb(pos + i);
return i;
}
static struct bin_attribute fuse_bin_attr = {
.attr = { .name = "fuse", .mode = S_IRUGO, },
.read = fuse_read,
};
static const struct of_device_id car_match[] __initconst = {
{ .compatible = "nvidia,tegra20-car", },
{ .compatible = "nvidia,tegra30-car", },
{ .compatible = "nvidia,tegra114-car", },
{ .compatible = "nvidia,tegra124-car", },
{},
};
static void tegra_enable_fuse_clk(void __iomem *base)
{
u32 reg;
reg = readl_relaxed(base + 0x48);
reg |= 1 << 28;
writel(reg, base + 0x48);
/*
* Enable FUSE clock. This needs to be hardcoded because the clock
* subsystem is not active during early boot.
*/
reg = readl(base + 0x14);
reg |= 1 << 7;
writel(reg, base + 0x14);
}
int tegra_fuse_readl(unsigned long offset, u32 *value)
{
if (!fuse_readl)
return -EPROBE_DEFER;
*value = fuse_readl(offset);
return 0;
}
EXPORT_SYMBOL(tegra_fuse_readl);
int tegra_fuse_create_sysfs(struct device *dev, int size,
u32 (*readl)(const unsigned int offset))
{
if (fuse_size)
return -ENODEV;
fuse_bin_attr.size = size;
fuse_bin_attr.read = fuse_read;
fuse_size = size;
fuse_readl = readl;
return device_create_bin_file(dev, &fuse_bin_attr);
}
void __init tegra_init_fuse(void)
{
struct device_node *np;
void __iomem *car_base;
tegra_init_apbmisc();
np = of_find_matching_node(NULL, car_match);
car_base = of_iomap(np, 0);
if (car_base) {
tegra_enable_fuse_clk(car_base);
iounmap(car_base);
} else {
pr_err("Could not enable fuse clk. ioremap tegra car failed.\n");
return;
}
if (tegra_get_chip_id() == TEGRA20)
tegra20_init_fuse_early();
else
tegra30_init_fuse_early();
pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
tegra_revision_name[tegra_sku_info.revision],
tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id,
tegra_sku_info.core_process_id);
pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n",
tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
}

View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Based on drivers/misc/eeprom/sunxi_sid.c
*/
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
#define FUSE_BEGIN 0x100
#define FUSE_SIZE 0x1f8
#define FUSE_UID_LOW 0x08
#define FUSE_UID_HIGH 0x0c
static phys_addr_t fuse_phys;
static struct clk *fuse_clk;
static void __iomem __initdata *fuse_base;
static DEFINE_MUTEX(apb_dma_lock);
static DECLARE_COMPLETION(apb_dma_wait);
static struct dma_chan *apb_dma_chan;
static struct dma_slave_config dma_sconfig;
static u32 *apb_buffer;
static dma_addr_t apb_buffer_phys;
static void apb_dma_complete(void *args)
{
complete(&apb_dma_wait);
}
static u32 tegra20_fuse_readl(const unsigned int offset)
{
int ret;
u32 val = 0;
struct dma_async_tx_descriptor *dma_desc;
mutex_lock(&apb_dma_lock);
dma_sconfig.src_addr = fuse_phys + FUSE_BEGIN + offset;
ret = dmaengine_slave_config(apb_dma_chan, &dma_sconfig);
if (ret)
goto out;
dma_desc = dmaengine_prep_slave_single(apb_dma_chan, apb_buffer_phys,
sizeof(u32), DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!dma_desc)
goto out;
dma_desc->callback = apb_dma_complete;
dma_desc->callback_param = NULL;
reinit_completion(&apb_dma_wait);
clk_prepare_enable(fuse_clk);
dmaengine_submit(dma_desc);
dma_async_issue_pending(apb_dma_chan);
ret = wait_for_completion_timeout(&apb_dma_wait, msecs_to_jiffies(50));
if (WARN(ret == 0, "apb read dma timed out"))
dmaengine_terminate_all(apb_dma_chan);
else
val = *apb_buffer;
clk_disable_unprepare(fuse_clk);
out:
mutex_unlock(&apb_dma_lock);
return val;
}
static const struct of_device_id tegra20_fuse_of_match[] = {
{ .compatible = "nvidia,tegra20-efuse" },
{},
};
static int apb_dma_init(void)
{
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
apb_dma_chan = dma_request_channel(mask, NULL, NULL);
if (!apb_dma_chan)
return -EPROBE_DEFER;
apb_buffer = dma_alloc_coherent(NULL, sizeof(u32), &apb_buffer_phys,
GFP_KERNEL);
if (!apb_buffer) {
dma_release_channel(apb_dma_chan);
return -ENOMEM;
}
dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
dma_sconfig.src_maxburst = 1;
dma_sconfig.dst_maxburst = 1;
return 0;
}
static int tegra20_fuse_probe(struct platform_device *pdev)
{
struct resource *res;
int err;
fuse_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(fuse_clk)) {
dev_err(&pdev->dev, "missing clock");
return PTR_ERR(fuse_clk);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
fuse_phys = res->start;
err = apb_dma_init();
if (err)
return err;
if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl))
return -ENODEV;
dev_dbg(&pdev->dev, "loaded\n");
return 0;
}
static struct platform_driver tegra20_fuse_driver = {
.probe = tegra20_fuse_probe,
.driver = {
.name = "tegra20_fuse",
.owner = THIS_MODULE,
.of_match_table = tegra20_fuse_of_match,
}
};
static int __init tegra20_fuse_init(void)
{
return platform_driver_register(&tegra20_fuse_driver);
}
postcore_initcall(tegra20_fuse_init);
/* Early boot code. This code is called before the devices are created */
u32 __init tegra20_fuse_early(const unsigned int offset)
{
return readl_relaxed(fuse_base + FUSE_BEGIN + offset);
}
bool __init tegra20_spare_fuse_early(int spare_bit)
{
u32 offset = spare_bit * 4;
bool value;
value = tegra20_fuse_early(offset + 0x100);
return value;
}
static void __init tegra20_fuse_add_randomness(void)
{
u32 randomness[7];
randomness[0] = tegra_sku_info.sku_id;
randomness[1] = tegra_read_straps();
randomness[2] = tegra_read_chipid();
randomness[3] = tegra_sku_info.cpu_process_id << 16;
randomness[3] |= tegra_sku_info.core_process_id;
randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
randomness[4] |= tegra_sku_info.soc_speedo_id;
randomness[5] = tegra20_fuse_early(FUSE_UID_LOW);
randomness[6] = tegra20_fuse_early(FUSE_UID_HIGH);
add_device_randomness(randomness, sizeof(randomness));
}
void __init tegra20_init_fuse_early(void)
{
fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE);
tegra_init_revision();
tegra20_init_speedo_data(&tegra_sku_info);
tegra20_fuse_add_randomness();
iounmap(fuse_base);
}

View File

@ -0,0 +1,224 @@
/*
* Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
#define FUSE_BEGIN 0x100
/* Tegra30 and later */
#define FUSE_VENDOR_CODE 0x100
#define FUSE_FAB_CODE 0x104
#define FUSE_LOT_CODE_0 0x108
#define FUSE_LOT_CODE_1 0x10c
#define FUSE_WAFER_ID 0x110
#define FUSE_X_COORDINATE 0x114
#define FUSE_Y_COORDINATE 0x118
#define FUSE_HAS_REVISION_INFO BIT(0)
enum speedo_idx {
SPEEDO_TEGRA30 = 0,
SPEEDO_TEGRA114,
SPEEDO_TEGRA124,
};
struct tegra_fuse_info {
int size;
int spare_bit;
enum speedo_idx speedo_idx;
};
static void __iomem *fuse_base;
static struct clk *fuse_clk;
static struct tegra_fuse_info *fuse_info;
u32 tegra30_fuse_readl(const unsigned int offset)
{
u32 val;
/*
* early in the boot, the fuse clock will be enabled by
* tegra_init_fuse()
*/
if (fuse_clk)
clk_prepare_enable(fuse_clk);
val = readl_relaxed(fuse_base + FUSE_BEGIN + offset);
if (fuse_clk)
clk_disable_unprepare(fuse_clk);
return val;
}
static struct tegra_fuse_info tegra30_info = {
.size = 0x2a4,
.spare_bit = 0x144,
.speedo_idx = SPEEDO_TEGRA30,
};
static struct tegra_fuse_info tegra114_info = {
.size = 0x2a0,
.speedo_idx = SPEEDO_TEGRA114,
};
static struct tegra_fuse_info tegra124_info = {
.size = 0x300,
.speedo_idx = SPEEDO_TEGRA124,
};
static const struct of_device_id tegra30_fuse_of_match[] = {
{ .compatible = "nvidia,tegra30-efuse", .data = &tegra30_info },
{ .compatible = "nvidia,tegra114-efuse", .data = &tegra114_info },
{ .compatible = "nvidia,tegra124-efuse", .data = &tegra124_info },
{},
};
static int tegra30_fuse_probe(struct platform_device *pdev)
{
const struct of_device_id *of_dev_id;
of_dev_id = of_match_device(tegra30_fuse_of_match, &pdev->dev);
if (!of_dev_id)
return -ENODEV;
fuse_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(fuse_clk)) {
dev_err(&pdev->dev, "missing clock");
return PTR_ERR(fuse_clk);
}
platform_set_drvdata(pdev, NULL);
if (tegra_fuse_create_sysfs(&pdev->dev, fuse_info->size,
tegra30_fuse_readl))
return -ENODEV;
dev_dbg(&pdev->dev, "loaded\n");
return 0;
}
static struct platform_driver tegra30_fuse_driver = {
.probe = tegra30_fuse_probe,
.driver = {
.name = "tegra_fuse",
.owner = THIS_MODULE,
.of_match_table = tegra30_fuse_of_match,
}
};
static int __init tegra30_fuse_init(void)
{
return platform_driver_register(&tegra30_fuse_driver);
}
postcore_initcall(tegra30_fuse_init);
/* Early boot code. This code is called before the devices are created */
typedef void (*speedo_f)(struct tegra_sku_info *sku_info);
static speedo_f __initdata speedo_tbl[] = {
[SPEEDO_TEGRA30] = tegra30_init_speedo_data,
[SPEEDO_TEGRA114] = tegra114_init_speedo_data,
[SPEEDO_TEGRA124] = tegra124_init_speedo_data,
};
static void __init tegra30_fuse_add_randomness(void)
{
u32 randomness[12];
randomness[0] = tegra_sku_info.sku_id;
randomness[1] = tegra_read_straps();
randomness[2] = tegra_read_chipid();
randomness[3] = tegra_sku_info.cpu_process_id << 16;
randomness[3] |= tegra_sku_info.core_process_id;
randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
randomness[4] |= tegra_sku_info.soc_speedo_id;
randomness[5] = tegra30_fuse_readl(FUSE_VENDOR_CODE);
randomness[6] = tegra30_fuse_readl(FUSE_FAB_CODE);
randomness[7] = tegra30_fuse_readl(FUSE_LOT_CODE_0);
randomness[8] = tegra30_fuse_readl(FUSE_LOT_CODE_1);
randomness[9] = tegra30_fuse_readl(FUSE_WAFER_ID);
randomness[10] = tegra30_fuse_readl(FUSE_X_COORDINATE);
randomness[11] = tegra30_fuse_readl(FUSE_Y_COORDINATE);
add_device_randomness(randomness, sizeof(randomness));
}
static void __init legacy_fuse_init(void)
{
switch (tegra_get_chip_id()) {
case TEGRA30:
fuse_info = &tegra30_info;
break;
case TEGRA114:
fuse_info = &tegra114_info;
break;
case TEGRA124:
fuse_info = &tegra124_info;
break;
default:
return;
}
fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE);
}
bool __init tegra30_spare_fuse(int spare_bit)
{
u32 offset = fuse_info->spare_bit + spare_bit * 4;
return tegra30_fuse_readl(offset) & 1;
}
void __init tegra30_init_fuse_early(void)
{
struct device_node *np;
const struct of_device_id *of_match;
np = of_find_matching_node_and_match(NULL, tegra30_fuse_of_match,
&of_match);
if (np) {
fuse_base = of_iomap(np, 0);
fuse_info = (struct tegra_fuse_info *)of_match->data;
} else
legacy_fuse_init();
if (!fuse_base) {
pr_warn("fuse DT node missing and unknown chip id: 0x%02x\n",
tegra_get_chip_id());
return;
}
tegra_init_revision();
speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info);
tegra30_fuse_add_randomness();
}

View File

@ -0,0 +1,71 @@
/*
* 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
#define TEGRA_FUSE_BASE 0x7000f800
#define TEGRA_FUSE_SIZE 0x400
int tegra_fuse_create_sysfs(struct device *dev, int size,
u32 (*readl)(const unsigned int offset));
bool tegra30_spare_fuse(int bit);
u32 tegra30_fuse_readl(const unsigned int offset);
void tegra30_init_fuse_early(void);
void tegra_init_revision(void);
void tegra_init_apbmisc(void);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
void tegra20_init_speedo_data(struct tegra_sku_info *sku_info);
bool tegra20_spare_fuse_early(int spare_bit);
void tegra20_init_fuse_early(void);
u32 tegra20_fuse_early(const unsigned int offset);
#else
static inline void tegra20_init_speedo_data(struct tegra_sku_info *sku_info) {}
static inline bool tegra20_spare_fuse_early(int spare_bit)
{
return false;
}
static inline void tegra20_init_fuse_early(void) {}
static inline u32 tegra20_fuse_early(const unsigned int offset)
{
return 0;
}
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
void tegra30_init_speedo_data(struct tegra_sku_info *sku_info);
#else
static inline void tegra30_init_speedo_data(struct tegra_sku_info *sku_info) {}
#endif
#ifdef CONFIG_ARCH_TEGRA_114_SOC
void tegra114_init_speedo_data(struct tegra_sku_info *sku_info);
#else
static inline void tegra114_init_speedo_data(struct tegra_sku_info *sku_info) {}
#endif
#ifdef CONFIG_ARCH_TEGRA_124_SOC
void tegra124_init_speedo_data(struct tegra_sku_info *sku_info);
#else
static inline void tegra124_init_speedo_data(struct tegra_sku_info *sku_info) {}
#endif
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -14,13 +14,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
#define CORE_PROCESS_CORNERS_NUM 2
#define CPU_PROCESS_CORNERS_NUM 2
#define CORE_PROCESS_CORNERS 2
#define CPU_PROCESS_CORNERS 2
enum {
THRESHOLD_INDEX_0,
@ -28,54 +31,57 @@ enum {
THRESHOLD_INDEX_COUNT,
};
static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
{1123, UINT_MAX},
{0, UINT_MAX},
};
static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
{1695, UINT_MAX},
{0, UINT_MAX},
};
static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold)
static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
int *threshold)
{
u32 tmp;
u32 sku = sku_info->sku_id;
enum tegra_revision rev = sku_info->revision;
switch (sku) {
case 0x00:
case 0x10:
case 0x05:
case 0x06:
tegra_cpu_speedo_id = 1;
tegra_soc_speedo_id = 0;
sku_info->cpu_speedo_id = 1;
sku_info->soc_speedo_id = 0;
*threshold = THRESHOLD_INDEX_0;
break;
case 0x03:
case 0x04:
tegra_cpu_speedo_id = 2;
tegra_soc_speedo_id = 1;
sku_info->cpu_speedo_id = 2;
sku_info->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;
pr_err("Tegra Unknown SKU %d\n", sku);
sku_info->cpu_speedo_id = 0;
sku_info->soc_speedo_id = 0;
*threshold = THRESHOLD_INDEX_0;
break;
}
if (rev == TEGRA_REVISION_A01) {
tmp = tegra_fuse_readl(0x270) << 1;
tmp |= tegra_fuse_readl(0x26c);
tmp = tegra30_fuse_readl(0x270) << 1;
tmp |= tegra30_fuse_readl(0x26c);
if (!tmp)
tegra_cpu_speedo_id = 0;
sku_info->cpu_speedo_id = 0;
}
}
void tegra114_init_speedo_data(void)
void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info)
{
u32 cpu_speedo_val;
u32 core_speedo_val;
@ -87,18 +93,18 @@ void tegra114_init_speedo_data(void)
BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
THRESHOLD_INDEX_COUNT);
rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold);
rev_sku_to_speedo_ids(sku_info, &threshold);
cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024;
core_speedo_val = tegra_fuse_readl(0x134);
cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024;
core_speedo_val = tegra30_fuse_readl(0x134);
for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++)
for (i = 0; i < CPU_PROCESS_CORNERS; i++)
if (cpu_speedo_val < cpu_process_speedos[threshold][i])
break;
tegra_cpu_process_id = i;
sku_info->cpu_process_id = i;
for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++)
for (i = 0; i < CORE_PROCESS_CORNERS; i++)
if (core_speedo_val < core_process_speedos[threshold][i])
break;
tegra_core_process_id = i;
sku_info->core_process_id = i;
}

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/bug.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
#define CPU_PROCESS_CORNERS 2
#define GPU_PROCESS_CORNERS 2
#define CORE_PROCESS_CORNERS 2
#define FUSE_CPU_SPEEDO_0 0x14
#define FUSE_CPU_SPEEDO_1 0x2c
#define FUSE_CPU_SPEEDO_2 0x30
#define FUSE_SOC_SPEEDO_0 0x34
#define FUSE_SOC_SPEEDO_1 0x38
#define FUSE_SOC_SPEEDO_2 0x3c
#define FUSE_CPU_IDDQ 0x18
#define FUSE_SOC_IDDQ 0x40
#define FUSE_GPU_IDDQ 0x128
#define FUSE_FT_REV 0x28
enum {
THRESHOLD_INDEX_0,
THRESHOLD_INDEX_1,
THRESHOLD_INDEX_COUNT,
};
static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
{2190, UINT_MAX},
{0, UINT_MAX},
};
static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = {
{1965, UINT_MAX},
{0, UINT_MAX},
};
static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
{2101, UINT_MAX},
{0, UINT_MAX},
};
static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
int *threshold)
{
int sku = sku_info->sku_id;
/* Assign to default */
sku_info->cpu_speedo_id = 0;
sku_info->soc_speedo_id = 0;
sku_info->gpu_speedo_id = 0;
*threshold = THRESHOLD_INDEX_0;
switch (sku) {
case 0x00: /* Eng sku */
case 0x0F:
case 0x23:
/* Using the default */
break;
case 0x83:
sku_info->cpu_speedo_id = 2;
break;
case 0x1F:
case 0x87:
case 0x27:
sku_info->cpu_speedo_id = 2;
sku_info->soc_speedo_id = 0;
sku_info->gpu_speedo_id = 1;
*threshold = THRESHOLD_INDEX_0;
break;
case 0x81:
case 0x21:
case 0x07:
sku_info->cpu_speedo_id = 1;
sku_info->soc_speedo_id = 1;
sku_info->gpu_speedo_id = 1;
*threshold = THRESHOLD_INDEX_1;
break;
case 0x49:
case 0x4A:
case 0x48:
sku_info->cpu_speedo_id = 4;
sku_info->soc_speedo_id = 2;
sku_info->gpu_speedo_id = 3;
*threshold = THRESHOLD_INDEX_1;
break;
default:
pr_err("Tegra Unknown SKU %d\n", sku);
/* Using the default for the error case */
break;
}
}
void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info)
{
int i, threshold, cpu_speedo_0_value, soc_speedo_0_value;
int cpu_iddq_value, gpu_iddq_value, soc_iddq_value;
BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
THRESHOLD_INDEX_COUNT);
BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) !=
THRESHOLD_INDEX_COUNT);
BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
THRESHOLD_INDEX_COUNT);
cpu_speedo_0_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_0);
/* GPU Speedo is stored in CPU_SPEEDO_2 */
sku_info->gpu_speedo_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_2);
soc_speedo_0_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_0);
cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ);
soc_iddq_value = tegra30_fuse_readl(FUSE_SOC_IDDQ);
gpu_iddq_value = tegra30_fuse_readl(FUSE_GPU_IDDQ);
sku_info->cpu_speedo_value = cpu_speedo_0_value;
if (sku_info->cpu_speedo_value == 0) {
pr_warn("Tegra Warning: Speedo value not fused.\n");
WARN_ON(1);
return;
}
rev_sku_to_speedo_ids(sku_info, &threshold);
sku_info->cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ);
for (i = 0; i < GPU_PROCESS_CORNERS; i++)
if (sku_info->gpu_speedo_value <
gpu_process_speedos[threshold][i])
break;
sku_info->gpu_process_id = i;
for (i = 0; i < CPU_PROCESS_CORNERS; i++)
if (sku_info->cpu_speedo_value <
cpu_process_speedos[threshold][i])
break;
sku_info->cpu_process_id = i;
for (i = 0; i < CORE_PROCESS_CORNERS; i++)
if (soc_speedo_0_value <
core_process_speedos[threshold][i])
break;
sku_info->core_process_id = i;
pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n",
sku_info->gpu_speedo_id, sku_info->gpu_speedo_value);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -14,8 +14,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
@ -47,19 +50,19 @@ enum {
SPEEDO_ID_COUNT,
};
static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
static const u32 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
{315, 366, 420, UINT_MAX},
{303, 368, 419, UINT_MAX},
{316, 331, 383, UINT_MAX},
};
static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
static const u32 __initconst core_process_speedos[][PROCESS_CORNERS_NUM] = {
{165, 195, 224, UINT_MAX},
{165, 195, 224, UINT_MAX},
{165, 195, 224, UINT_MAX},
};
void tegra20_init_speedo_data(void)
void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info)
{
u32 reg;
u32 val;
@ -68,42 +71,40 @@ void tegra20_init_speedo_data(void)
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;
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
tegra_soc_speedo_id = SPEEDO_ID_2;
sku_info->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);
reg = tegra20_spare_fuse_early(i) |
tegra20_spare_fuse_early(i + CPU_SPEEDO_REDUND_OFFS);
val = (val << 1) | (reg & 0x1);
}
val = val * SPEEDO_MULT;
pr_debug("%s CPU speedo value %u\n", __func__, val);
pr_debug("Tegra CPU speedo value %u\n", val);
for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
if (val <= cpu_process_speedos[tegra_soc_speedo_id][i])
if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i])
break;
}
tegra_cpu_process_id = i;
sku_info->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);
reg = tegra20_spare_fuse_early(i) |
tegra20_spare_fuse_early(i + CORE_SPEEDO_REDUND_OFFS);
val = (val << 1) | (reg & 0x1);
}
val = val * SPEEDO_MULT;
pr_debug("%s Core speedo value %u\n", __func__, val);
pr_debug("Core speedo value %u\n", val);
for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
if (val <= core_process_speedos[tegra_soc_speedo_id][i])
if (val <= core_process_speedos[sku_info->soc_speedo_id][i])
break;
}
tegra_core_process_id = i;
pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id);
sku_info->core_process_id = i;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -14,17 +14,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
#define CORE_PROCESS_CORNERS_NUM 1
#define CPU_PROCESS_CORNERS_NUM 6
#define CORE_PROCESS_CORNERS 1
#define CPU_PROCESS_CORNERS 6
#define FUSE_SPEEDO_CALIB_0 0x114
#define FUSE_PACKAGE_INFO 0X1FC
#define FUSE_TEST_PROG_VER 0X128
#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
@ -51,7 +54,7 @@ enum {
THRESHOLD_INDEX_COUNT,
};
static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
{180},
{170},
{195},
@ -66,7 +69,7 @@ static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
{180},
};
static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
{306, 338, 360, 376, UINT_MAX},
{295, 336, 358, 375, UINT_MAX},
{325, 325, 358, 375, UINT_MAX},
@ -81,35 +84,34 @@ static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
{295, 336, 358, 375, 391, UINT_MAX},
};
static int threshold_index;
static int package_id;
static int threshold_index __initdata;
static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
static void __init 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);
reg = tegra30_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);
ate_ver = tegra30_fuse_readl(FUSE_TEST_PROG_VER);
pr_debug("Tegra ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10);
if (ate_ver >= 26) {
bit_minus1 = 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);
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 = 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);
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;
@ -117,133 +119,131 @@ static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
}
}
static void rev_sku_to_speedo_ids(int rev, int sku)
static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info)
{
switch (rev) {
int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
switch (sku_info->revision) {
case TEGRA_REVISION_A01:
tegra_cpu_speedo_id = 0;
tegra_soc_speedo_id = 0;
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) {
switch (sku_info->sku_id) {
case 0x87:
case 0x82:
tegra_cpu_speedo_id = 1;
tegra_soc_speedo_id = 1;
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:
tegra_cpu_speedo_id = 2;
tegra_soc_speedo_id = 2;
sku_info->cpu_speedo_id = 2;
sku_info->soc_speedo_id = 2;
threshold_index = THRESHOLD_INDEX_2;
break;
case 2:
tegra_cpu_speedo_id = 4;
tegra_soc_speedo_id = 1;
sku_info->cpu_speedo_id = 4;
sku_info->soc_speedo_id = 1;
threshold_index = THRESHOLD_INDEX_7;
break;
default:
pr_err("Tegra30: Unknown pkg %d\n", package_id);
BUG();
pr_err("Tegra Unknown pkg %d\n", package_id);
break;
}
break;
case 0x80:
switch (package_id) {
case 1:
tegra_cpu_speedo_id = 5;
tegra_soc_speedo_id = 2;
sku_info->cpu_speedo_id = 5;
sku_info->soc_speedo_id = 2;
threshold_index = THRESHOLD_INDEX_8;
break;
case 2:
tegra_cpu_speedo_id = 6;
tegra_soc_speedo_id = 2;
sku_info->cpu_speedo_id = 6;
sku_info->soc_speedo_id = 2;
threshold_index = THRESHOLD_INDEX_9;
break;
default:
pr_err("Tegra30: Unknown pkg %d\n", package_id);
BUG();
pr_err("Tegra Unknown pkg %d\n", package_id);
break;
}
break;
case 0x83:
switch (package_id) {
case 1:
tegra_cpu_speedo_id = 7;
tegra_soc_speedo_id = 1;
sku_info->cpu_speedo_id = 7;
sku_info->soc_speedo_id = 1;
threshold_index = THRESHOLD_INDEX_10;
break;
case 2:
tegra_cpu_speedo_id = 3;
tegra_soc_speedo_id = 2;
sku_info->cpu_speedo_id = 3;
sku_info->soc_speedo_id = 2;
threshold_index = THRESHOLD_INDEX_3;
break;
default:
pr_err("Tegra30: Unknown pkg %d\n", package_id);
BUG();
pr_err("Tegra Unknown pkg %d\n", package_id);
break;
}
break;
case 0x8F:
tegra_cpu_speedo_id = 8;
tegra_soc_speedo_id = 1;
sku_info->cpu_speedo_id = 8;
sku_info->soc_speedo_id = 1;
threshold_index = THRESHOLD_INDEX_11;
break;
case 0x08:
tegra_cpu_speedo_id = 1;
tegra_soc_speedo_id = 1;
sku_info->cpu_speedo_id = 1;
sku_info->soc_speedo_id = 1;
threshold_index = THRESHOLD_INDEX_4;
break;
case 0x02:
tegra_cpu_speedo_id = 2;
tegra_soc_speedo_id = 2;
sku_info->cpu_speedo_id = 2;
sku_info->soc_speedo_id = 2;
threshold_index = THRESHOLD_INDEX_5;
break;
case 0x04:
tegra_cpu_speedo_id = 3;
tegra_soc_speedo_id = 2;
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:
tegra_cpu_speedo_id = 2;
tegra_soc_speedo_id = 2;
sku_info->cpu_speedo_id = 2;
sku_info->soc_speedo_id = 2;
threshold_index = THRESHOLD_INDEX_2;
break;
case 2:
tegra_cpu_speedo_id = 3;
tegra_soc_speedo_id = 2;
sku_info->cpu_speedo_id = 3;
sku_info->soc_speedo_id = 2;
threshold_index = THRESHOLD_INDEX_3;
break;
default:
pr_err("Tegra30: Unknown pkg %d\n", package_id);
BUG();
pr_err("Tegra Unknown pkg %d\n", package_id);
break;
}
break;
default:
pr_warn("Tegra30: Unknown SKU %d\n", sku);
tegra_cpu_speedo_id = 0;
tegra_soc_speedo_id = 0;
pr_warn("Tegra Unknown SKU %d\n", sku_info->sku_id);
sku_info->cpu_speedo_id = 0;
sku_info->soc_speedo_id = 0;
threshold_index = THRESHOLD_INDEX_0;
break;
}
break;
default:
pr_warn("Tegra30: Unknown chip rev %d\n", rev);
tegra_cpu_speedo_id = 0;
tegra_soc_speedo_id = 0;
pr_warn("Tegra Unknown chip rev %d\n", sku_info->revision);
sku_info->cpu_speedo_id = 0;
sku_info->soc_speedo_id = 0;
threshold_index = THRESHOLD_INDEX_0;
break;
}
}
void tegra30_init_speedo_data(void)
void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info)
{
u32 cpu_speedo_val;
u32 core_speedo_val;
@ -254,39 +254,35 @@ void tegra30_init_speedo_data(void)
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);
rev_sku_to_speedo_ids(sku_info);
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);
pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val);
pr_debug("Tegra Core speedo value %u\n", core_speedo_val);
for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
for (i = 0; i < CPU_PROCESS_CORNERS; i++) {
if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
break;
}
tegra_cpu_process_id = i - 1;
sku_info->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;
if (sku_info->cpu_process_id == -1) {
pr_warn("Tegra CPU speedo value %3d out of range",
cpu_speedo_val);
sku_info->cpu_process_id = 0;
sku_info->cpu_speedo_id = 1;
}
for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) {
for (i = 0; i < CORE_PROCESS_CORNERS; i++) {
if (core_speedo_val < core_process_speedos[threshold_index][i])
break;
}
tegra_core_process_id = i - 1;
sku_info->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;
if (sku_info->core_process_id == -1) {
pr_warn("Tegra CORE speedo value %3d out of range",
core_speedo_val);
sku_info->core_process_id = 0;
sku_info->soc_speedo_id = 1;
}
pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d",
tegra_cpu_speedo_id, tegra_soc_speedo_id);
}

View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <soc/tegra/fuse.h>
#include "fuse.h"
#define APBMISC_BASE 0x70000800
#define APBMISC_SIZE 0x64
#define FUSE_SKU_INFO 0x10
static void __iomem *apbmisc_base;
static void __iomem *strapping_base;
u32 tegra_read_chipid(void)
{
return readl_relaxed(apbmisc_base + 4);
}
u8 tegra_get_chip_id(void)
{
u32 id = tegra_read_chipid();
return (id >> 8) & 0xff;
}
u32 tegra_read_straps(void)
{
if (strapping_base)
return readl_relaxed(strapping_base);
else
return 0;
}
static const struct of_device_id apbmisc_match[] __initconst = {
{ .compatible = "nvidia,tegra20-apbmisc", },
{},
};
void __init tegra_init_revision(void)
{
u32 id, chip_id, minor_rev;
int rev;
id = tegra_read_chipid();
chip_id = (id >> 8) & 0xff;
minor_rev = (id >> 16) & 0xf;
switch (minor_rev) {
case 1:
rev = TEGRA_REVISION_A01;
break;
case 2:
rev = TEGRA_REVISION_A02;
break;
case 3:
if (chip_id == TEGRA20 && (tegra20_spare_fuse_early(18) ||
tegra20_spare_fuse_early(19)))
rev = TEGRA_REVISION_A03p;
else
rev = TEGRA_REVISION_A03;
break;
case 4:
rev = TEGRA_REVISION_A04;
break;
default:
rev = TEGRA_REVISION_UNKNOWN;
}
tegra_sku_info.revision = rev;
if (chip_id == TEGRA20)
tegra_sku_info.sku_id = tegra20_fuse_early(FUSE_SKU_INFO);
else
tegra_sku_info.sku_id = tegra30_fuse_readl(FUSE_SKU_INFO);
}
void __init tegra_init_apbmisc(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, apbmisc_match);
apbmisc_base = of_iomap(np, 0);
if (!apbmisc_base) {
pr_warn("ioremap tegra apbmisc failed. using %08x instead\n",
APBMISC_BASE);
apbmisc_base = ioremap(APBMISC_BASE, APBMISC_SIZE);
}
strapping_base = of_iomap(np, 1);
if (!strapping_base)
pr_err("ioremap tegra strapping_base failed\n");
}

View File

@ -1,22 +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/>.
*/
#ifndef __LINUX_TEGRA_SOC_H_
#define __LINUX_TEGRA_SOC_H_
u32 tegra_read_chipid(void);
#endif /* __LINUX_TEGRA_SOC_H_ */

View File

@ -11,9 +11,9 @@
* more details.
*/
#ifndef __LINUX_AHB_H__
#define __LINUX_AHB_H__
#ifndef __SOC_TEGRA_AHB_H__
#define __SOC_TEGRA_AHB_H__
extern int tegra_ahb_enable_smmu(struct device_node *ahb);
#endif /* __LINUX_AHB_H__ */
#endif /* __SOC_TEGRA_AHB_H__ */

View File

@ -11,8 +11,8 @@
* more details.
*/
#ifndef __LINUX_TEGRA_CPUIDLE_H__
#define __LINUX_TEGRA_CPUIDLE_H__
#ifndef __SOC_TEGRA_CPUIDLE_H__
#define __SOC_TEGRA_CPUIDLE_H__
#ifdef CONFIG_CPU_IDLE
void tegra_cpuidle_pcie_irqs_in_use(void);
@ -22,4 +22,4 @@ static inline void tegra_cpuidle_pcie_irqs_in_use(void)
}
#endif
#endif
#endif /* __SOC_TEGRA_CPUIDLE_H__ */

View File

@ -0,0 +1,66 @@
/*
* 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/>.
*/
#ifndef __SOC_TEGRA_FUSE_H__
#define __SOC_TEGRA_FUSE_H__
#define TEGRA20 0x20
#define TEGRA30 0x30
#define TEGRA114 0x35
#define TEGRA124 0x40
#define TEGRA_FUSE_SKU_CALIB_0 0xf0
#define TEGRA30_FUSE_SATA_CALIB 0x124
#ifndef __ASSEMBLY__
u32 tegra_read_chipid(void);
u8 tegra_get_chip_id(void);
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;
};
u32 tegra_read_straps(void);
u32 tegra_read_chipid(void);
void tegra_init_fuse(void);
int tegra_fuse_readl(unsigned long offset, u32 *value);
extern struct tegra_sku_info tegra_sku_info;
#endif /* __ASSEMBLY__ */
#endif /* __SOC_TEGRA_FUSE_H__ */

View File

@ -15,8 +15,8 @@
*
*/
#ifndef _MACH_TEGRA_POWERGATE_H_
#define _MACH_TEGRA_POWERGATE_H_
#ifndef __SOC_TEGRA_POWERGATE_H__
#define __SOC_TEGRA_POWERGATE_H__
struct clk;
struct reset_control;
@ -131,4 +131,4 @@ static inline int tegra_io_rail_power_off(int id)
}
#endif
#endif /* _MACH_TEGRA_POWERGATE_H_ */
#endif /* __SOC_TEGRA_POWERGATE_H__ */