2014-06-12 18:36:37 +03:00
/*
* 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)
2015-04-29 16:54:04 +02:00
# if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
defined ( CONFIG_ARCH_TEGRA_114_SOC ) | | \
defined ( CONFIG_ARCH_TEGRA_124_SOC ) | | \
2015-04-29 16:55:57 +02:00
defined ( CONFIG_ARCH_TEGRA_132_SOC ) | | \
defined ( CONFIG_ARCH_TEGRA_210_SOC )
2015-04-29 16:54:04 +02:00
static u32 tegra30_fuse_read_early ( struct tegra_fuse * fuse , unsigned int offset )
2014-06-12 18:36:37 +03:00
{
2015-04-29 16:54:04 +02:00
return readl_relaxed ( fuse - > base + FUSE_BEGIN + offset ) ;
2014-06-12 18:36:37 +03:00
}
2015-04-29 16:54:04 +02:00
static u32 tegra30_fuse_read ( struct tegra_fuse * fuse , unsigned int offset )
2014-06-12 18:36:37 +03:00
{
2015-04-29 16:54:04 +02:00
u32 value ;
int err ;
2014-06-12 18:36:37 +03:00
2015-04-29 16:54:04 +02:00
err = clk_prepare_enable ( fuse - > clk ) ;
if ( err < 0 ) {
dev_err ( fuse - > dev , " failed to enable FUSE clock: %d \n " , err ) ;
return 0 ;
2014-06-12 18:36:37 +03:00
}
2015-04-29 16:54:04 +02:00
value = readl_relaxed ( fuse - > base + FUSE_BEGIN + offset ) ;
2014-06-12 18:36:37 +03:00
2015-04-29 16:54:04 +02:00
clk_disable_unprepare ( fuse - > clk ) ;
2014-06-12 18:36:37 +03:00
2015-04-29 16:54:04 +02:00
return value ;
2014-06-12 18:36:37 +03:00
}
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 ;
2015-03-23 14:44:08 +01:00
randomness [ 3 ] | = tegra_sku_info . soc_process_id ;
2014-06-12 18:36:37 +03:00
randomness [ 4 ] = tegra_sku_info . cpu_speedo_id < < 16 ;
randomness [ 4 ] | = tegra_sku_info . soc_speedo_id ;
2015-04-29 16:54:04 +02:00
randomness [ 5 ] = tegra_fuse_read_early ( FUSE_VENDOR_CODE ) ;
randomness [ 6 ] = tegra_fuse_read_early ( FUSE_FAB_CODE ) ;
randomness [ 7 ] = tegra_fuse_read_early ( FUSE_LOT_CODE_0 ) ;
randomness [ 8 ] = tegra_fuse_read_early ( FUSE_LOT_CODE_1 ) ;
randomness [ 9 ] = tegra_fuse_read_early ( FUSE_WAFER_ID ) ;
randomness [ 10 ] = tegra_fuse_read_early ( FUSE_X_COORDINATE ) ;
randomness [ 11 ] = tegra_fuse_read_early ( FUSE_Y_COORDINATE ) ;
2014-06-12 18:36:37 +03:00
add_device_randomness ( randomness , sizeof ( randomness ) ) ;
}
2015-04-29 16:54:04 +02:00
static void __init tegra30_fuse_init ( struct tegra_fuse * fuse )
2014-06-12 18:36:37 +03:00
{
2015-04-29 16:54:04 +02:00
fuse - > read_early = tegra30_fuse_read_early ;
fuse - > read = tegra30_fuse_read ;
2014-06-12 18:36:37 +03:00
2015-04-29 16:54:04 +02:00
tegra_init_revision ( ) ;
fuse - > soc - > speedo_init ( & tegra_sku_info ) ;
tegra30_fuse_add_randomness ( ) ;
2014-06-12 18:36:37 +03:00
}
2015-04-29 16:54:04 +02:00
# endif
2014-06-12 18:36:37 +03:00
2015-04-29 16:54:04 +02:00
# ifdef CONFIG_ARCH_TEGRA_3x_SOC
static const struct tegra_fuse_info tegra30_fuse_info = {
. read = tegra30_fuse_read ,
. size = 0x2a4 ,
. spare = 0x144 ,
} ;
2014-06-12 18:36:37 +03:00
2015-04-29 16:54:04 +02:00
const struct tegra_fuse_soc tegra30_fuse_soc = {
. init = tegra30_fuse_init ,
. speedo_init = tegra30_init_speedo_data ,
. info = & tegra30_fuse_info ,
} ;
# endif
2014-06-12 18:36:37 +03:00
2015-04-29 16:54:04 +02:00
# ifdef CONFIG_ARCH_TEGRA_114_SOC
static const struct tegra_fuse_info tegra114_fuse_info = {
. read = tegra30_fuse_read ,
. size = 0x2a0 ,
2015-05-04 16:38:28 +02:00
. spare = 0x180 ,
2015-04-29 16:54:04 +02:00
} ;
2014-06-12 18:36:37 +03:00
2015-04-29 16:54:04 +02:00
const struct tegra_fuse_soc tegra114_fuse_soc = {
. init = tegra30_fuse_init ,
. speedo_init = tegra114_init_speedo_data ,
. info = & tegra114_fuse_info ,
} ;
# endif
# if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct tegra_fuse_info tegra124_fuse_info = {
. read = tegra30_fuse_read ,
. size = 0x300 ,
2015-05-04 16:44:29 +02:00
. spare = 0x200 ,
2015-04-29 16:54:04 +02:00
} ;
const struct tegra_fuse_soc tegra124_fuse_soc = {
. init = tegra30_fuse_init ,
. speedo_init = tegra124_init_speedo_data ,
. info = & tegra124_fuse_info ,
} ;
# endif
2015-04-29 16:55:57 +02:00
# if defined(CONFIG_ARCH_TEGRA_210_SOC)
static const struct tegra_fuse_info tegra210_fuse_info = {
. read = tegra30_fuse_read ,
. size = 0x300 ,
} ;
const struct tegra_fuse_soc tegra210_fuse_soc = {
. init = tegra30_fuse_init ,
. speedo_init = tegra210_init_speedo_data ,
. info = & tegra210_fuse_info ,
} ;
# endif