diff options
author | Venu Byravarasu <vbyravarasu@nvidia.com> | 2010-05-17 11:30:37 +0530 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-05-17 11:38:48 -0700 |
commit | 7babb616e672128db7ec4a3efa8fbe0c09fed1b5 (patch) | |
tree | f55d88e06805192f334ecc4b93461accd6380e0a | |
parent | b8a0f3f1d92e521fb517219daa5083363a4a57e0 (diff) |
tegra-kernel-fuse: Add fuse burning support from Linux via sysfs
A fuse module is added to support programming and reading back
fuse values.
This module is built as part of kernel.
Bug 657504
Tested on: Whistler
Change-Id: I5663679c8d41834aa4077e9940a0595f6575af64
Reviewed-on: http://git-master/r/1259
Reviewed-by: Andy Carman <acarman@nvidia.com>
Tested-by: Andy Carman <acarman@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
13 files changed, 3635 insertions, 66 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 4dc32e649534..ff1f43f22259 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -8,7 +8,6 @@ ccflags-y += -DNV_DEBUG=0 endif ccflags-y += -Iarch/arm/mach-tegra/nvrm/core/common - # Mandatory components obj-y += clock.o obj-y += io.o @@ -18,6 +17,7 @@ obj-y += pinmux-t2-tables.o obj-y += pinmux.o obj-y += timer.o obj-y += tegra_sysmap.o +obj-y += sysfs-fuse.o # IOVMM support obj-$(CONFIG_TEGRA_IOVMM_GART) += iovmm-gart.o diff --git a/arch/arm/mach-tegra/include/fuse_bitmap.h b/arch/arm/mach-tegra/include/fuse_bitmap.h new file mode 100644 index 000000000000..38b09541862e --- /dev/null +++ b/arch/arm/mach-tegra/include/fuse_bitmap.h @@ -0,0 +1,787 @@ +/* + * Copyright (c) 2010 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +// **************************************************************** +// This file is automatically generated by FUSEGEN. Do NOT modify. +// **************************************************************** +#define FUSE_ENABLE_FUSE_PROGRAM__WIDTH 1 +#define FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0 0x0 +#define FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0_DATA 0:0 +#define FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0_WIDTH 1 +#define FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0 0x1 +#define FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0_DATA 0:0 +#define FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0_WIDTH 1 + +#define FUSE_DISABLE_FUSE_PROGRAM__WIDTH 1 +#define FUSE_DISABLE_FUSE_PROGRAM__PRI_ALIAS_0 0x0 +#define FUSE_DISABLE_FUSE_PROGRAM__PRI_ALIAS_0_DATA 1:1 +#define FUSE_DISABLE_FUSE_PROGRAM__PRI_ALIAS_0_WIDTH 1 +#define FUSE_DISABLE_FUSE_PROGRAM__RED_ALIAS_0 0x1 +#define FUSE_DISABLE_FUSE_PROGRAM__RED_ALIAS_0_DATA 1:1 +#define FUSE_DISABLE_FUSE_PROGRAM__RED_ALIAS_0_WIDTH 1 + +#define FUSE_BYPASS_FUSES__WIDTH 1 +#define FUSE_BYPASS_FUSES__PRI_ALIAS_0 0x0 +#define FUSE_BYPASS_FUSES__PRI_ALIAS_0_DATA 2:2 +#define FUSE_BYPASS_FUSES__PRI_ALIAS_0_WIDTH 1 +#define FUSE_BYPASS_FUSES__RED_ALIAS_0 0x1 +#define FUSE_BYPASS_FUSES__RED_ALIAS_0_DATA 2:2 +#define FUSE_BYPASS_FUSES__RED_ALIAS_0_WIDTH 1 + +#define FUSE_JTAG_DIRECT_ACCESS_DISABLE__WIDTH 1 +#define FUSE_JTAG_DIRECT_ACCESS_DISABLE__PRI_ALIAS_0 0x0 +#define FUSE_JTAG_DIRECT_ACCESS_DISABLE__PRI_ALIAS_0_DATA 3:3 +#define FUSE_JTAG_DIRECT_ACCESS_DISABLE__PRI_ALIAS_0_WIDTH 1 +#define FUSE_JTAG_DIRECT_ACCESS_DISABLE__RED_ALIAS_0 0x1 +#define FUSE_JTAG_DIRECT_ACCESS_DISABLE__RED_ALIAS_0_DATA 3:3 +#define FUSE_JTAG_DIRECT_ACCESS_DISABLE__RED_ALIAS_0_WIDTH 1 + +#define FUSE_RAMREPAIR_CHAIN_1_SIZE__WIDTH 16 +#define FUSE_RAMREPAIR_CHAIN_1_SIZE__PRI_ALIAS_0 0x0 +#define FUSE_RAMREPAIR_CHAIN_1_SIZE__PRI_ALIAS_0_DATA 19:4 +#define FUSE_RAMREPAIR_CHAIN_1_SIZE__PRI_ALIAS_0_WIDTH 16 +#define FUSE_RAMREPAIR_CHAIN_1_SIZE__RED_ALIAS_0 0x1 +#define FUSE_RAMREPAIR_CHAIN_1_SIZE__RED_ALIAS_0_DATA 19:4 +#define FUSE_RAMREPAIR_CHAIN_1_SIZE__RED_ALIAS_0_WIDTH 16 + +#define FUSE_PRODUCTION_MODE__WIDTH 1 +#define FUSE_PRODUCTION_MODE__PRI_ALIAS_0 0x0 +#define FUSE_PRODUCTION_MODE__PRI_ALIAS_0_DATA 20:20 +#define FUSE_PRODUCTION_MODE__PRI_ALIAS_0_WIDTH 1 +#define FUSE_PRODUCTION_MODE__RED_ALIAS_0 0x1 +#define FUSE_PRODUCTION_MODE__RED_ALIAS_0_DATA 20:20 +#define FUSE_PRODUCTION_MODE__RED_ALIAS_0_WIDTH 1 + +#define FUSE_JTAG_SECUREID_VALID__WIDTH 1 +#define FUSE_JTAG_SECUREID_VALID__PRI_ALIAS_0 0x0 +#define FUSE_JTAG_SECUREID_VALID__PRI_ALIAS_0_DATA 21:21 +#define FUSE_JTAG_SECUREID_VALID__PRI_ALIAS_0_WIDTH 1 +#define FUSE_JTAG_SECUREID_VALID__RED_ALIAS_0 0x1 +#define FUSE_JTAG_SECUREID_VALID__RED_ALIAS_0_DATA 21:21 +#define FUSE_JTAG_SECUREID_VALID__RED_ALIAS_0_WIDTH 1 + +#define FUSE_FA__WIDTH 1 +#define FUSE_FA__PRI_ALIAS_0 0x0 +#define FUSE_FA__PRI_ALIAS_0_DATA 22:22 +#define FUSE_FA__PRI_ALIAS_0_WIDTH 1 +#define FUSE_FA__RED_ALIAS_0 0x1 +#define FUSE_FA__RED_ALIAS_0_DATA 22:22 +#define FUSE_FA__RED_ALIAS_0_WIDTH 1 + +#define FUSE_SECURITY_MODE__WIDTH 1 +#define FUSE_SECURITY_MODE__PRI_ALIAS_0 0x0 +#define FUSE_SECURITY_MODE__PRI_ALIAS_0_DATA 23:23 +#define FUSE_SECURITY_MODE__PRI_ALIAS_0_WIDTH 1 +#define FUSE_SECURITY_MODE__RED_ALIAS_0 0x1 +#define FUSE_SECURITY_MODE__RED_ALIAS_0_DATA 23:23 +#define FUSE_SECURITY_MODE__RED_ALIAS_0_WIDTH 1 + +#define FUSE_ARM_DEBUG_DIS__WIDTH 1 +#define FUSE_ARM_DEBUG_DIS__PRI_ALIAS_0 0x0 +#define FUSE_ARM_DEBUG_DIS__PRI_ALIAS_0_DATA 24:24 +#define FUSE_ARM_DEBUG_DIS__PRI_ALIAS_0_WIDTH 1 +#define FUSE_ARM_DEBUG_DIS__RED_ALIAS_0 0x1 +#define FUSE_ARM_DEBUG_DIS__RED_ALIAS_0_DATA 24:24 +#define FUSE_ARM_DEBUG_DIS__RED_ALIAS_0_WIDTH 1 + +#define FUSE_OBS_DIS__WIDTH 1 +#define FUSE_OBS_DIS__PRI_ALIAS_0 0x0 +#define FUSE_OBS_DIS__PRI_ALIAS_0_DATA 25:25 +#define FUSE_OBS_DIS__PRI_ALIAS_0_WIDTH 1 +#define FUSE_OBS_DIS__RED_ALIAS_0 0x1 +#define FUSE_OBS_DIS__RED_ALIAS_0_DATA 25:25 +#define FUSE_OBS_DIS__RED_ALIAS_0_WIDTH 1 + +#define FUSE_JTAG_SECUREID_0__WIDTH 32 +#define FUSE_JTAG_SECUREID_0__PRI_ALIAS_0 0x2 +#define FUSE_JTAG_SECUREID_0__PRI_ALIAS_0_DATA 31:0 +#define FUSE_JTAG_SECUREID_0__PRI_ALIAS_0_WIDTH 32 +#define FUSE_JTAG_SECUREID_0__RED_ALIAS_0 0x3 +#define FUSE_JTAG_SECUREID_0__RED_ALIAS_0_DATA 31:0 +#define FUSE_JTAG_SECUREID_0__RED_ALIAS_0_WIDTH 32 + +#define FUSE_JTAG_SECUREID_1__WIDTH 32 +#define FUSE_JTAG_SECUREID_1__PRI_ALIAS_0 0x4 +#define FUSE_JTAG_SECUREID_1__PRI_ALIAS_0_DATA 31:0 +#define FUSE_JTAG_SECUREID_1__PRI_ALIAS_0_WIDTH 32 +#define FUSE_JTAG_SECUREID_1__RED_ALIAS_0 0x5 +#define FUSE_JTAG_SECUREID_1__RED_ALIAS_0_DATA 31:0 +#define FUSE_JTAG_SECUREID_1__RED_ALIAS_0_WIDTH 32 + +#define FUSE_SKU_INFO__WIDTH 8 +#define FUSE_SKU_INFO__PRI_ALIAS_0 0x6 +#define FUSE_SKU_INFO__PRI_ALIAS_0_DATA 7:0 +#define FUSE_SKU_INFO__PRI_ALIAS_0_WIDTH 8 +#define FUSE_SKU_INFO__RED_ALIAS_0 0x7 +#define FUSE_SKU_INFO__RED_ALIAS_0_DATA 7:0 +#define FUSE_SKU_INFO__RED_ALIAS_0_WIDTH 8 + +#define FUSE_PROCESS_CALIB__WIDTH 2 +#define FUSE_PROCESS_CALIB__PRI_ALIAS_0 0x6 +#define FUSE_PROCESS_CALIB__PRI_ALIAS_0_DATA 9:8 +#define FUSE_PROCESS_CALIB__PRI_ALIAS_0_WIDTH 2 +#define FUSE_PROCESS_CALIB__RED_ALIAS_0 0x7 +#define FUSE_PROCESS_CALIB__RED_ALIAS_0_DATA 9:8 +#define FUSE_PROCESS_CALIB__RED_ALIAS_0_WIDTH 2 + +#define FUSE_IO_CALIB__WIDTH 10 +#define FUSE_IO_CALIB__PRI_ALIAS_0 0x6 +#define FUSE_IO_CALIB__PRI_ALIAS_0_DATA 19:10 +#define FUSE_IO_CALIB__PRI_ALIAS_0_WIDTH 10 +#define FUSE_IO_CALIB__RED_ALIAS_0 0x7 +#define FUSE_IO_CALIB__RED_ALIAS_0_DATA 19:10 +#define FUSE_IO_CALIB__RED_ALIAS_0_WIDTH 10 + +#define FUSE_DAC_CRT_CALIB__WIDTH 8 +#define FUSE_DAC_CRT_CALIB__PRI_ALIAS_0 0x6 +#define FUSE_DAC_CRT_CALIB__PRI_ALIAS_0_DATA 27:20 +#define FUSE_DAC_CRT_CALIB__PRI_ALIAS_0_WIDTH 8 +#define FUSE_DAC_CRT_CALIB__RED_ALIAS_0 0x7 +#define FUSE_DAC_CRT_CALIB__RED_ALIAS_0_DATA 27:20 +#define FUSE_DAC_CRT_CALIB__RED_ALIAS_0_WIDTH 8 + +#define FUSE_DAC_HDTV_CALIB__WIDTH 8 +#define FUSE_DAC_HDTV_CALIB__PRI_ALIAS_0 0x6 +#define FUSE_DAC_HDTV_CALIB__PRI_ALIAS_0_DATA 31:28 +#define FUSE_DAC_HDTV_CALIB__PRI_ALIAS_0_WIDTH 4 +#define FUSE_DAC_HDTV_CALIB__PRI_ALIAS_1 0x8 +#define FUSE_DAC_HDTV_CALIB__PRI_ALIAS_1_DATA 3:0 +#define FUSE_DAC_HDTV_CALIB__PRI_ALIAS_1_WIDTH 4 +#define FUSE_DAC_HDTV_CALIB__RED_ALIAS_0 0x7 +#define FUSE_DAC_HDTV_CALIB__RED_ALIAS_0_DATA 31:28 +#define FUSE_DAC_HDTV_CALIB__RED_ALIAS_0_WIDTH 4 +#define FUSE_DAC_HDTV_CALIB__RED_ALIAS_1 0x9 +#define FUSE_DAC_HDTV_CALIB__RED_ALIAS_1_DATA 3:0 +#define FUSE_DAC_HDTV_CALIB__RED_ALIAS_1_WIDTH 4 + +#define FUSE_DAC_SDTV_CALIB__WIDTH 8 +#define FUSE_DAC_SDTV_CALIB__PRI_ALIAS_0 0x8 +#define FUSE_DAC_SDTV_CALIB__PRI_ALIAS_0_DATA 11:4 +#define FUSE_DAC_SDTV_CALIB__PRI_ALIAS_0_WIDTH 8 +#define FUSE_DAC_SDTV_CALIB__RED_ALIAS_0 0x9 +#define FUSE_DAC_SDTV_CALIB__RED_ALIAS_0_DATA 11:4 +#define FUSE_DAC_SDTV_CALIB__RED_ALIAS_0_WIDTH 8 + +#define FUSE_RESERVED_PRODUCTION__WIDTH 4 +#define FUSE_RESERVED_PRODUCTION__PRI_ALIAS_0 0x8 +#define FUSE_RESERVED_PRODUCTION__PRI_ALIAS_0_DATA 15:12 +#define FUSE_RESERVED_PRODUCTION__PRI_ALIAS_0_WIDTH 4 +#define FUSE_RESERVED_PRODUCTION__RED_ALIAS_0 0x9 +#define FUSE_RESERVED_PRODUCTION__RED_ALIAS_0_DATA 15:12 +#define FUSE_RESERVED_PRODUCTION__RED_ALIAS_0_WIDTH 4 + +#define FUSE_HDMI_LANE0_CALIB__WIDTH 6 +#define FUSE_HDMI_LANE0_CALIB__PRI_ALIAS_0 0x8 +#define FUSE_HDMI_LANE0_CALIB__PRI_ALIAS_0_DATA 21:16 +#define FUSE_HDMI_LANE0_CALIB__PRI_ALIAS_0_WIDTH 6 +#define FUSE_HDMI_LANE0_CALIB__RED_ALIAS_0 0x9 +#define FUSE_HDMI_LANE0_CALIB__RED_ALIAS_0_DATA 21:16 +#define FUSE_HDMI_LANE0_CALIB__RED_ALIAS_0_WIDTH 6 + +#define FUSE_HDMI_LANE1_CALIB__WIDTH 6 +#define FUSE_HDMI_LANE1_CALIB__PRI_ALIAS_0 0x8 +#define FUSE_HDMI_LANE1_CALIB__PRI_ALIAS_0_DATA 27:22 +#define FUSE_HDMI_LANE1_CALIB__PRI_ALIAS_0_WIDTH 6 +#define FUSE_HDMI_LANE1_CALIB__RED_ALIAS_0 0x9 +#define FUSE_HDMI_LANE1_CALIB__RED_ALIAS_0_DATA 27:22 +#define FUSE_HDMI_LANE1_CALIB__RED_ALIAS_0_WIDTH 6 + +#define FUSE_HDMI_LANE2_CALIB__WIDTH 6 +#define FUSE_HDMI_LANE2_CALIB__PRI_ALIAS_0 0x8 +#define FUSE_HDMI_LANE2_CALIB__PRI_ALIAS_0_DATA 31:28 +#define FUSE_HDMI_LANE2_CALIB__PRI_ALIAS_0_WIDTH 4 +#define FUSE_HDMI_LANE2_CALIB__PRI_ALIAS_1 0xa +#define FUSE_HDMI_LANE2_CALIB__PRI_ALIAS_1_DATA 1:0 +#define FUSE_HDMI_LANE2_CALIB__PRI_ALIAS_1_WIDTH 2 +#define FUSE_HDMI_LANE2_CALIB__RED_ALIAS_0 0x9 +#define FUSE_HDMI_LANE2_CALIB__RED_ALIAS_0_DATA 31:28 +#define FUSE_HDMI_LANE2_CALIB__RED_ALIAS_0_WIDTH 4 +#define FUSE_HDMI_LANE2_CALIB__RED_ALIAS_1 0xb +#define FUSE_HDMI_LANE2_CALIB__RED_ALIAS_1_DATA 1:0 +#define FUSE_HDMI_LANE2_CALIB__RED_ALIAS_1_WIDTH 2 + +#define FUSE_HDMI_LANE3_CALIB__WIDTH 6 +#define FUSE_HDMI_LANE3_CALIB__PRI_ALIAS_0 0xa +#define FUSE_HDMI_LANE3_CALIB__PRI_ALIAS_0_DATA 7:2 +#define FUSE_HDMI_LANE3_CALIB__PRI_ALIAS_0_WIDTH 6 +#define FUSE_HDMI_LANE3_CALIB__RED_ALIAS_0 0xb +#define FUSE_HDMI_LANE3_CALIB__RED_ALIAS_0_DATA 7:2 +#define FUSE_HDMI_LANE3_CALIB__RED_ALIAS_0_WIDTH 6 + +#define FUSE_PRIVATE_KEY0__WIDTH 32 +#define FUSE_PRIVATE_KEY0__PRI_ALIAS_0 0xa +#define FUSE_PRIVATE_KEY0__PRI_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY0__PRI_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY0__PRI_ALIAS_1 0xc +#define FUSE_PRIVATE_KEY0__PRI_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY0__PRI_ALIAS_1_WIDTH 8 +#define FUSE_PRIVATE_KEY0__RED_ALIAS_0 0xb +#define FUSE_PRIVATE_KEY0__RED_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY0__RED_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY0__RED_ALIAS_1 0xd +#define FUSE_PRIVATE_KEY0__RED_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY0__RED_ALIAS_1_WIDTH 8 + +#define FUSE_PRIVATE_KEY1__WIDTH 32 +#define FUSE_PRIVATE_KEY1__PRI_ALIAS_0 0xc +#define FUSE_PRIVATE_KEY1__PRI_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY1__PRI_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY1__PRI_ALIAS_1 0xe +#define FUSE_PRIVATE_KEY1__PRI_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY1__PRI_ALIAS_1_WIDTH 8 +#define FUSE_PRIVATE_KEY1__RED_ALIAS_0 0xd +#define FUSE_PRIVATE_KEY1__RED_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY1__RED_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY1__RED_ALIAS_1 0xf +#define FUSE_PRIVATE_KEY1__RED_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY1__RED_ALIAS_1_WIDTH 8 + +#define FUSE_PRIVATE_KEY2__WIDTH 32 +#define FUSE_PRIVATE_KEY2__PRI_ALIAS_0 0xe +#define FUSE_PRIVATE_KEY2__PRI_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY2__PRI_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY2__PRI_ALIAS_1 0x10 +#define FUSE_PRIVATE_KEY2__PRI_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY2__PRI_ALIAS_1_WIDTH 8 +#define FUSE_PRIVATE_KEY2__RED_ALIAS_0 0xf +#define FUSE_PRIVATE_KEY2__RED_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY2__RED_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY2__RED_ALIAS_1 0x11 +#define FUSE_PRIVATE_KEY2__RED_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY2__RED_ALIAS_1_WIDTH 8 + +#define FUSE_PRIVATE_KEY3__WIDTH 32 +#define FUSE_PRIVATE_KEY3__PRI_ALIAS_0 0x10 +#define FUSE_PRIVATE_KEY3__PRI_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY3__PRI_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY3__PRI_ALIAS_1 0x12 +#define FUSE_PRIVATE_KEY3__PRI_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY3__PRI_ALIAS_1_WIDTH 8 +#define FUSE_PRIVATE_KEY3__RED_ALIAS_0 0x11 +#define FUSE_PRIVATE_KEY3__RED_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY3__RED_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY3__RED_ALIAS_1 0x13 +#define FUSE_PRIVATE_KEY3__RED_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY3__RED_ALIAS_1_WIDTH 8 + +#define FUSE_PRIVATE_KEY4__WIDTH 32 +#define FUSE_PRIVATE_KEY4__PRI_ALIAS_0 0x12 +#define FUSE_PRIVATE_KEY4__PRI_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY4__PRI_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY4__PRI_ALIAS_1 0x14 +#define FUSE_PRIVATE_KEY4__PRI_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY4__PRI_ALIAS_1_WIDTH 8 +#define FUSE_PRIVATE_KEY4__RED_ALIAS_0 0x13 +#define FUSE_PRIVATE_KEY4__RED_ALIAS_0_DATA 31:8 +#define FUSE_PRIVATE_KEY4__RED_ALIAS_0_WIDTH 24 +#define FUSE_PRIVATE_KEY4__RED_ALIAS_1 0x15 +#define FUSE_PRIVATE_KEY4__RED_ALIAS_1_DATA 7:0 +#define FUSE_PRIVATE_KEY4__RED_ALIAS_1_WIDTH 8 + +#define FUSE_BOOT_DEVICE_INFO__WIDTH 16 +#define FUSE_BOOT_DEVICE_INFO__PRI_ALIAS_0 0x14 +#define FUSE_BOOT_DEVICE_INFO__PRI_ALIAS_0_DATA 23:8 +#define FUSE_BOOT_DEVICE_INFO__PRI_ALIAS_0_WIDTH 16 +#define FUSE_BOOT_DEVICE_INFO__RED_ALIAS_0 0x15 +#define FUSE_BOOT_DEVICE_INFO__RED_ALIAS_0_DATA 23:8 +#define FUSE_BOOT_DEVICE_INFO__RED_ALIAS_0_WIDTH 16 + +#define FUSE_RESERVED_SW__WIDTH 8 +#define FUSE_RESERVED_SW__PRI_ALIAS_0 0x14 +#define FUSE_RESERVED_SW__PRI_ALIAS_0_DATA 31:24 +#define FUSE_RESERVED_SW__PRI_ALIAS_0_WIDTH 8 +#define FUSE_RESERVED_SW__RED_ALIAS_0 0x15 +#define FUSE_RESERVED_SW__RED_ALIAS_0_DATA 31:24 +#define FUSE_RESERVED_SW__RED_ALIAS_0_WIDTH 8 + +#define FUSE_ARM_DEBUG_CONTROL__WIDTH 4 +#define FUSE_ARM_DEBUG_CONTROL__PRI_ALIAS_0 0x16 +#define FUSE_ARM_DEBUG_CONTROL__PRI_ALIAS_0_DATA 3:0 +#define FUSE_ARM_DEBUG_CONTROL__PRI_ALIAS_0_WIDTH 4 +#define FUSE_ARM_DEBUG_CONTROL__RED_ALIAS_0 0x17 +#define FUSE_ARM_DEBUG_CONTROL__RED_ALIAS_0_DATA 3:0 +#define FUSE_ARM_DEBUG_CONTROL__RED_ALIAS_0_WIDTH 4 + +#define FUSE_RESERVED_ODM0__WIDTH 32 +#define FUSE_RESERVED_ODM0__PRI_ALIAS_0 0x16 +#define FUSE_RESERVED_ODM0__PRI_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM0__PRI_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM0__PRI_ALIAS_1 0x18 +#define FUSE_RESERVED_ODM0__PRI_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM0__PRI_ALIAS_1_WIDTH 4 +#define FUSE_RESERVED_ODM0__RED_ALIAS_0 0x17 +#define FUSE_RESERVED_ODM0__RED_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM0__RED_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM0__RED_ALIAS_1 0x19 +#define FUSE_RESERVED_ODM0__RED_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM0__RED_ALIAS_1_WIDTH 4 + +#define FUSE_RESERVED_ODM1__WIDTH 32 +#define FUSE_RESERVED_ODM1__PRI_ALIAS_0 0x18 +#define FUSE_RESERVED_ODM1__PRI_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM1__PRI_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM1__PRI_ALIAS_1 0x1a +#define FUSE_RESERVED_ODM1__PRI_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM1__PRI_ALIAS_1_WIDTH 4 +#define FUSE_RESERVED_ODM1__RED_ALIAS_0 0x19 +#define FUSE_RESERVED_ODM1__RED_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM1__RED_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM1__RED_ALIAS_1 0x1b +#define FUSE_RESERVED_ODM1__RED_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM1__RED_ALIAS_1_WIDTH 4 + +#define FUSE_RESERVED_ODM2__WIDTH 32 +#define FUSE_RESERVED_ODM2__PRI_ALIAS_0 0x1a +#define FUSE_RESERVED_ODM2__PRI_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM2__PRI_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM2__PRI_ALIAS_1 0x1c +#define FUSE_RESERVED_ODM2__PRI_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM2__PRI_ALIAS_1_WIDTH 4 +#define FUSE_RESERVED_ODM2__RED_ALIAS_0 0x1b +#define FUSE_RESERVED_ODM2__RED_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM2__RED_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM2__RED_ALIAS_1 0x1d +#define FUSE_RESERVED_ODM2__RED_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM2__RED_ALIAS_1_WIDTH 4 + +#define FUSE_RESERVED_ODM3__WIDTH 32 +#define FUSE_RESERVED_ODM3__PRI_ALIAS_0 0x1c +#define FUSE_RESERVED_ODM3__PRI_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM3__PRI_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM3__PRI_ALIAS_1 0x1e +#define FUSE_RESERVED_ODM3__PRI_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM3__PRI_ALIAS_1_WIDTH 4 +#define FUSE_RESERVED_ODM3__RED_ALIAS_0 0x1d +#define FUSE_RESERVED_ODM3__RED_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM3__RED_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM3__RED_ALIAS_1 0x1f +#define FUSE_RESERVED_ODM3__RED_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM3__RED_ALIAS_1_WIDTH 4 + +#define FUSE_RESERVED_ODM4__WIDTH 32 +#define FUSE_RESERVED_ODM4__PRI_ALIAS_0 0x1e +#define FUSE_RESERVED_ODM4__PRI_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM4__PRI_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM4__PRI_ALIAS_1 0x20 +#define FUSE_RESERVED_ODM4__PRI_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM4__PRI_ALIAS_1_WIDTH 4 +#define FUSE_RESERVED_ODM4__RED_ALIAS_0 0x1f +#define FUSE_RESERVED_ODM4__RED_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM4__RED_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM4__RED_ALIAS_1 0x21 +#define FUSE_RESERVED_ODM4__RED_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM4__RED_ALIAS_1_WIDTH 4 + +#define FUSE_RESERVED_ODM5__WIDTH 32 +#define FUSE_RESERVED_ODM5__PRI_ALIAS_0 0x20 +#define FUSE_RESERVED_ODM5__PRI_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM5__PRI_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM5__PRI_ALIAS_1 0x22 +#define FUSE_RESERVED_ODM5__PRI_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM5__PRI_ALIAS_1_WIDTH 4 +#define FUSE_RESERVED_ODM5__RED_ALIAS_0 0x21 +#define FUSE_RESERVED_ODM5__RED_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM5__RED_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM5__RED_ALIAS_1 0x23 +#define FUSE_RESERVED_ODM5__RED_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM5__RED_ALIAS_1_WIDTH 4 + +#define FUSE_RESERVED_ODM6__WIDTH 32 +#define FUSE_RESERVED_ODM6__PRI_ALIAS_0 0x22 +#define FUSE_RESERVED_ODM6__PRI_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM6__PRI_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM6__PRI_ALIAS_1 0x24 +#define FUSE_RESERVED_ODM6__PRI_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM6__PRI_ALIAS_1_WIDTH 4 +#define FUSE_RESERVED_ODM6__RED_ALIAS_0 0x23 +#define FUSE_RESERVED_ODM6__RED_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM6__RED_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM6__RED_ALIAS_1 0x25 +#define FUSE_RESERVED_ODM6__RED_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM6__RED_ALIAS_1_WIDTH 4 + +#define FUSE_RESERVED_ODM7__WIDTH 32 +#define FUSE_RESERVED_ODM7__PRI_ALIAS_0 0x24 +#define FUSE_RESERVED_ODM7__PRI_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM7__PRI_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM7__PRI_ALIAS_1 0x26 +#define FUSE_RESERVED_ODM7__PRI_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM7__PRI_ALIAS_1_WIDTH 4 +#define FUSE_RESERVED_ODM7__RED_ALIAS_0 0x25 +#define FUSE_RESERVED_ODM7__RED_ALIAS_0_DATA 31:4 +#define FUSE_RESERVED_ODM7__RED_ALIAS_0_WIDTH 28 +#define FUSE_RESERVED_ODM7__RED_ALIAS_1 0x27 +#define FUSE_RESERVED_ODM7__RED_ALIAS_1_DATA 3:0 +#define FUSE_RESERVED_ODM7__RED_ALIAS_1_WIDTH 4 + +#define FUSE_NOR_INFO__WIDTH 2 +#define FUSE_NOR_INFO__PRI_ALIAS_0 0x26 +#define FUSE_NOR_INFO__PRI_ALIAS_0_DATA 5:4 +#define FUSE_NOR_INFO__PRI_ALIAS_0_WIDTH 2 +#define FUSE_NOR_INFO__RED_ALIAS_0 0x27 +#define FUSE_NOR_INFO__RED_ALIAS_0_DATA 5:4 +#define FUSE_NOR_INFO__RED_ALIAS_0_WIDTH 2 + +#define FUSE_USB_CALIB__WIDTH 7 +#define FUSE_USB_CALIB__PRI_ALIAS_0 0x26 +#define FUSE_USB_CALIB__PRI_ALIAS_0_DATA 12:6 +#define FUSE_USB_CALIB__PRI_ALIAS_0_WIDTH 7 +#define FUSE_USB_CALIB__RED_ALIAS_0 0x27 +#define FUSE_USB_CALIB__RED_ALIAS_0_DATA 12:6 +#define FUSE_USB_CALIB__RED_ALIAS_0_WIDTH 7 + +#define FUSE_KFUSE_PRIVKEY_CTRL__WIDTH 2 +#define FUSE_KFUSE_PRIVKEY_CTRL__PRI_ALIAS_0 0x26 +#define FUSE_KFUSE_PRIVKEY_CTRL__PRI_ALIAS_0_DATA 14:13 +#define FUSE_KFUSE_PRIVKEY_CTRL__PRI_ALIAS_0_WIDTH 2 +#define FUSE_KFUSE_PRIVKEY_CTRL__RED_ALIAS_0 0x27 +#define FUSE_KFUSE_PRIVKEY_CTRL__RED_ALIAS_0_DATA 14:13 +#define FUSE_KFUSE_PRIVKEY_CTRL__RED_ALIAS_0_WIDTH 2 + +#define FUSE_PACKAGE_INFO__WIDTH 2 +#define FUSE_PACKAGE_INFO__PRI_ALIAS_0 0x26 +#define FUSE_PACKAGE_INFO__PRI_ALIAS_0_DATA 16:15 +#define FUSE_PACKAGE_INFO__PRI_ALIAS_0_WIDTH 2 +#define FUSE_PACKAGE_INFO__RED_ALIAS_0 0x27 +#define FUSE_PACKAGE_INFO__RED_ALIAS_0_DATA 16:15 +#define FUSE_PACKAGE_INFO__RED_ALIAS_0_WIDTH 2 + +#define FUSE_SPARE_BIT_0__WIDTH 1 +#define FUSE_SPARE_BIT_0__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_0__PRI_ALIAS_0_DATA 17:17 +#define FUSE_SPARE_BIT_0__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_1__WIDTH 1 +#define FUSE_SPARE_BIT_1__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_1__PRI_ALIAS_0_DATA 18:18 +#define FUSE_SPARE_BIT_1__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_2__WIDTH 1 +#define FUSE_SPARE_BIT_2__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_2__PRI_ALIAS_0_DATA 19:19 +#define FUSE_SPARE_BIT_2__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_3__WIDTH 1 +#define FUSE_SPARE_BIT_3__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_3__PRI_ALIAS_0_DATA 20:20 +#define FUSE_SPARE_BIT_3__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_4__WIDTH 1 +#define FUSE_SPARE_BIT_4__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_4__PRI_ALIAS_0_DATA 21:21 +#define FUSE_SPARE_BIT_4__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_5__WIDTH 1 +#define FUSE_SPARE_BIT_5__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_5__PRI_ALIAS_0_DATA 22:22 +#define FUSE_SPARE_BIT_5__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_6__WIDTH 1 +#define FUSE_SPARE_BIT_6__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_6__PRI_ALIAS_0_DATA 23:23 +#define FUSE_SPARE_BIT_6__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_7__WIDTH 1 +#define FUSE_SPARE_BIT_7__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_7__PRI_ALIAS_0_DATA 24:24 +#define FUSE_SPARE_BIT_7__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_8__WIDTH 1 +#define FUSE_SPARE_BIT_8__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_8__PRI_ALIAS_0_DATA 25:25 +#define FUSE_SPARE_BIT_8__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_9__WIDTH 1 +#define FUSE_SPARE_BIT_9__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_9__PRI_ALIAS_0_DATA 26:26 +#define FUSE_SPARE_BIT_9__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_10__WIDTH 1 +#define FUSE_SPARE_BIT_10__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_10__PRI_ALIAS_0_DATA 27:27 +#define FUSE_SPARE_BIT_10__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_11__WIDTH 1 +#define FUSE_SPARE_BIT_11__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_11__PRI_ALIAS_0_DATA 28:28 +#define FUSE_SPARE_BIT_11__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_12__WIDTH 1 +#define FUSE_SPARE_BIT_12__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_12__PRI_ALIAS_0_DATA 29:29 +#define FUSE_SPARE_BIT_12__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_13__WIDTH 1 +#define FUSE_SPARE_BIT_13__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_13__PRI_ALIAS_0_DATA 30:30 +#define FUSE_SPARE_BIT_13__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_14__WIDTH 1 +#define FUSE_SPARE_BIT_14__PRI_ALIAS_0 0x26 +#define FUSE_SPARE_BIT_14__PRI_ALIAS_0_DATA 31:31 +#define FUSE_SPARE_BIT_14__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_15__WIDTH 1 +#define FUSE_SPARE_BIT_15__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_15__PRI_ALIAS_0_DATA 17:17 +#define FUSE_SPARE_BIT_15__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_16__WIDTH 1 +#define FUSE_SPARE_BIT_16__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_16__PRI_ALIAS_0_DATA 18:18 +#define FUSE_SPARE_BIT_16__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_17__WIDTH 1 +#define FUSE_SPARE_BIT_17__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_17__PRI_ALIAS_0_DATA 19:19 +#define FUSE_SPARE_BIT_17__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_18__WIDTH 1 +#define FUSE_SPARE_BIT_18__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_18__PRI_ALIAS_0_DATA 20:20 +#define FUSE_SPARE_BIT_18__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_19__WIDTH 1 +#define FUSE_SPARE_BIT_19__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_19__PRI_ALIAS_0_DATA 21:21 +#define FUSE_SPARE_BIT_19__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_20__WIDTH 1 +#define FUSE_SPARE_BIT_20__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_20__PRI_ALIAS_0_DATA 22:22 +#define FUSE_SPARE_BIT_20__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_21__WIDTH 1 +#define FUSE_SPARE_BIT_21__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_21__PRI_ALIAS_0_DATA 23:23 +#define FUSE_SPARE_BIT_21__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_22__WIDTH 1 +#define FUSE_SPARE_BIT_22__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_22__PRI_ALIAS_0_DATA 24:24 +#define FUSE_SPARE_BIT_22__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_23__WIDTH 1 +#define FUSE_SPARE_BIT_23__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_23__PRI_ALIAS_0_DATA 25:25 +#define FUSE_SPARE_BIT_23__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_24__WIDTH 1 +#define FUSE_SPARE_BIT_24__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_24__PRI_ALIAS_0_DATA 26:26 +#define FUSE_SPARE_BIT_24__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_25__WIDTH 1 +#define FUSE_SPARE_BIT_25__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_25__PRI_ALIAS_0_DATA 27:27 +#define FUSE_SPARE_BIT_25__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_26__WIDTH 1 +#define FUSE_SPARE_BIT_26__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_26__PRI_ALIAS_0_DATA 28:28 +#define FUSE_SPARE_BIT_26__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_27__WIDTH 1 +#define FUSE_SPARE_BIT_27__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_27__PRI_ALIAS_0_DATA 29:29 +#define FUSE_SPARE_BIT_27__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_28__WIDTH 1 +#define FUSE_SPARE_BIT_28__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_28__PRI_ALIAS_0_DATA 30:30 +#define FUSE_SPARE_BIT_28__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_29__WIDTH 1 +#define FUSE_SPARE_BIT_29__PRI_ALIAS_0 0x27 +#define FUSE_SPARE_BIT_29__PRI_ALIAS_0_DATA 31:31 +#define FUSE_SPARE_BIT_29__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_30__WIDTH 1 +#define FUSE_SPARE_BIT_30__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_30__PRI_ALIAS_0_DATA 0:0 +#define FUSE_SPARE_BIT_30__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_31__WIDTH 1 +#define FUSE_SPARE_BIT_31__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_31__PRI_ALIAS_0_DATA 1:1 +#define FUSE_SPARE_BIT_31__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_32__WIDTH 1 +#define FUSE_SPARE_BIT_32__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_32__PRI_ALIAS_0_DATA 2:2 +#define FUSE_SPARE_BIT_32__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_33__WIDTH 1 +#define FUSE_SPARE_BIT_33__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_33__PRI_ALIAS_0_DATA 3:3 +#define FUSE_SPARE_BIT_33__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_34__WIDTH 1 +#define FUSE_SPARE_BIT_34__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_34__PRI_ALIAS_0_DATA 4:4 +#define FUSE_SPARE_BIT_34__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_35__WIDTH 1 +#define FUSE_SPARE_BIT_35__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_35__PRI_ALIAS_0_DATA 5:5 +#define FUSE_SPARE_BIT_35__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_36__WIDTH 1 +#define FUSE_SPARE_BIT_36__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_36__PRI_ALIAS_0_DATA 6:6 +#define FUSE_SPARE_BIT_36__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_37__WIDTH 1 +#define FUSE_SPARE_BIT_37__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_37__PRI_ALIAS_0_DATA 7:7 +#define FUSE_SPARE_BIT_37__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_38__WIDTH 1 +#define FUSE_SPARE_BIT_38__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_38__PRI_ALIAS_0_DATA 8:8 +#define FUSE_SPARE_BIT_38__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_39__WIDTH 1 +#define FUSE_SPARE_BIT_39__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_39__PRI_ALIAS_0_DATA 9:9 +#define FUSE_SPARE_BIT_39__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_40__WIDTH 1 +#define FUSE_SPARE_BIT_40__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_40__PRI_ALIAS_0_DATA 10:10 +#define FUSE_SPARE_BIT_40__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_41__WIDTH 1 +#define FUSE_SPARE_BIT_41__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_41__PRI_ALIAS_0_DATA 11:11 +#define FUSE_SPARE_BIT_41__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_42__WIDTH 1 +#define FUSE_SPARE_BIT_42__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_42__PRI_ALIAS_0_DATA 12:12 +#define FUSE_SPARE_BIT_42__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_43__WIDTH 1 +#define FUSE_SPARE_BIT_43__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_43__PRI_ALIAS_0_DATA 13:13 +#define FUSE_SPARE_BIT_43__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_44__WIDTH 1 +#define FUSE_SPARE_BIT_44__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_44__PRI_ALIAS_0_DATA 14:14 +#define FUSE_SPARE_BIT_44__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_45__WIDTH 1 +#define FUSE_SPARE_BIT_45__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_45__PRI_ALIAS_0_DATA 15:15 +#define FUSE_SPARE_BIT_45__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_46__WIDTH 1 +#define FUSE_SPARE_BIT_46__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_46__PRI_ALIAS_0_DATA 16:16 +#define FUSE_SPARE_BIT_46__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_47__WIDTH 1 +#define FUSE_SPARE_BIT_47__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_47__PRI_ALIAS_0_DATA 17:17 +#define FUSE_SPARE_BIT_47__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_48__WIDTH 1 +#define FUSE_SPARE_BIT_48__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_48__PRI_ALIAS_0_DATA 18:18 +#define FUSE_SPARE_BIT_48__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_49__WIDTH 1 +#define FUSE_SPARE_BIT_49__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_49__PRI_ALIAS_0_DATA 19:19 +#define FUSE_SPARE_BIT_49__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_50__WIDTH 1 +#define FUSE_SPARE_BIT_50__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_50__PRI_ALIAS_0_DATA 20:20 +#define FUSE_SPARE_BIT_50__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_51__WIDTH 1 +#define FUSE_SPARE_BIT_51__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_51__PRI_ALIAS_0_DATA 21:21 +#define FUSE_SPARE_BIT_51__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_52__WIDTH 1 +#define FUSE_SPARE_BIT_52__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_52__PRI_ALIAS_0_DATA 22:22 +#define FUSE_SPARE_BIT_52__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_53__WIDTH 1 +#define FUSE_SPARE_BIT_53__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_53__PRI_ALIAS_0_DATA 23:23 +#define FUSE_SPARE_BIT_53__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_54__WIDTH 1 +#define FUSE_SPARE_BIT_54__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_54__PRI_ALIAS_0_DATA 24:24 +#define FUSE_SPARE_BIT_54__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_55__WIDTH 1 +#define FUSE_SPARE_BIT_55__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_55__PRI_ALIAS_0_DATA 25:25 +#define FUSE_SPARE_BIT_55__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_56__WIDTH 1 +#define FUSE_SPARE_BIT_56__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_56__PRI_ALIAS_0_DATA 26:26 +#define FUSE_SPARE_BIT_56__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_57__WIDTH 1 +#define FUSE_SPARE_BIT_57__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_57__PRI_ALIAS_0_DATA 27:27 +#define FUSE_SPARE_BIT_57__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_58__WIDTH 1 +#define FUSE_SPARE_BIT_58__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_58__PRI_ALIAS_0_DATA 28:28 +#define FUSE_SPARE_BIT_58__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_59__WIDTH 1 +#define FUSE_SPARE_BIT_59__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_59__PRI_ALIAS_0_DATA 29:29 +#define FUSE_SPARE_BIT_59__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_60__WIDTH 1 +#define FUSE_SPARE_BIT_60__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_60__PRI_ALIAS_0_DATA 30:30 +#define FUSE_SPARE_BIT_60__PRI_ALIAS_0_WIDTH 1 + +#define FUSE_SPARE_BIT_61__WIDTH 1 +#define FUSE_SPARE_BIT_61__PRI_ALIAS_0 0x28 +#define FUSE_SPARE_BIT_61__PRI_ALIAS_0_DATA 31:31 +#define FUSE_SPARE_BIT_61__PRI_ALIAS_0_WIDTH 1 + diff --git a/arch/arm/mach-tegra/include/nvddk_bootdevices.h b/arch/arm/mach-tegra/include/nvddk_bootdevices.h new file mode 100644 index 000000000000..97f460d9df28 --- /dev/null +++ b/arch/arm/mach-tegra/include/nvddk_bootdevices.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_NVDDK_BOOTDEVICES_H +#define INCLUDED_NVDDK_BOOTDEVICES_H + +/** + * @defgroup nvddk_bootdevices_group Boot Device Types + * + * Provides types of boot devices for NVIDIA Tegra functions. + * + * @ingroup nvddk_group + * @{ + */ + +/** + * Defines the supported secondary boot device types. + */ +typedef enum +{ + // Specifies NAND flash (SLC and MLC). + NvDdkSecBootDeviceType_Nand = 1, + + // Specifies NOR flash. + NvDdkSecBootDeviceType_Nor, + + // Specifies SPI flash. + NvDdkSecBootDeviceType_Spi, + + // Specifies eMMC flash + // @note eSD is only supported on Tegra 2 devices. + NvDdkSecBootDeviceType_eMMC, + + // Specifies 16-bit NAND flash. + NvDdkSecBootDeviceType_Nand_x16, + + // Specifies mobileLBA NAND flash (Tegra 2 only). + NvDdkSecBootDeviceType_MobileLbaNand, + + // Specifies SD flash. + // @note eSD is only supported on Tegra 2 devices. + NvDdkSecBootDeviceType_Sdmmc, + + // Specifies MuxOneNAND flash (Tegra 2 only). + NvDdkSecBootDeviceType_MuxOneNand, + + // Specifies the maximum number of flash device types + // -- Should appear after the last legal item. + NvDdkSecBootDeviceType_Max, + + // Undefined. + NvDdkSecBootDeviceType_Undefined, + + // Ignore -- Forces compilers to make 32-bit enums. + NvDdkSecBootDeviceType_Force32 = 0x7FFFFFFF +} NvDdkSecBootDeviceType; + +/** @} */ + +#endif // INCLUDED_NVDDK_BOOTDEVICES_H + diff --git a/arch/arm/mach-tegra/include/nvddk_fuse.h b/arch/arm/mach-tegra/include/nvddk_fuse.h new file mode 100644 index 000000000000..52796d3c86f8 --- /dev/null +++ b/arch/arm/mach-tegra/include/nvddk_fuse.h @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2010 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_NVDDK_FUSE_H +#define INCLUDED_NVDDK_FUSE_H + +#include "nvrm_module.h" +/** + * @defgroup nvddk_fuse_group Fuse Programming APIs + * + * Enables fuse programming. + * + * @par Library Usage + * + * - Calling the NvDdkDisableFuseProgram() API before exiting the boot loader + * disables further fuse programming until the next system reset. (See the + * example code.) + * - It is advised that you disable the JTAG while using this code in + * the final version. + * - Enabling clock and voltage to program the fuse is out of scope of this + * library. You must ensure that these are enabled prior to using the library + * functions. + * - The library works on physical mapped memory or on virtual mapped with + * one-to-one mapping for the fuse registers. + * + * @par Example Code + * + * The following example shows one way to use Fuse Programming APIs. + * @note You must ensure fuse clock and fuse voltage is enabled prior + * to programming fuses. + * + * @code + * // + * // Fuse Programming Example + * // + * #include "nvddk_fuse.h" + * #include "nvtest.h" + * #include "nvrm_init.h" + * #include "nvrm_pmu.h" + * #include "nvodm_query_discovery.h" + * #include "nvodm_services.h" + * + * #define DISABLE_PROGRMING_TEST 0 + * + * static NvError NvddkFuseProgramTest(NvTestApplicationHandle h ) + * { + * NvError err = NvSuccess; + * err = NvDdkFuseProgram(); + * if(err != NvError_Success) + * { + * NvOsDebugPrintf("NvDdkFuseProgram failed \n"); + * return err; + * } + * // Check fuse sense. + * NvDdkFuseSense(); + * // Verify the fuses and return the result. + * err = NvDdkFuseVerify(); + * if(err != NvError_Success) + * NvOsDebugPrintf("NvDdkFuseVerify failed \n"); + * return err; + * } + * + * static NvError PrepareFuseData(void) + * { + * // Initialize argument sizes to zero to perform initial queries. + * NvU32 BootDevSel_Size = 0; + * NvU32 BootDevConfig_Size = 0; + * NvU32 ResevOdm_size = 0; + * NvU32 size = 0; + * + * // Specify values to be programmed. + * NvU16 BootDevConfig_Data = 0x9; // Set device config value to 0x9. + * NvU8 BootDevSel_Data = 0x1; // Set boot select to 0x1 for NAND. + * NvU8 ResevOdm_Data[32] = {0xEF,0xCD,0xAB,0x89, + * 0x78,0x56,0x34,0x12, + * 0xa,0xb,0xc,0xd, + * 0xAA,0xBB,0xCC,0xDD, + * 0,0,0,0, + * 0,0,0,0, + * 0x78,0x56,0x34,0x12, + * 0x78,0x56,0x34,0x12}; + * + * NvU8 skpDevSelStrap_data = 1; + * NvError e; + * + * // Query the sizes of the fuse values. + * e = NvDdkFuseGet(NvDdkFuseDataType_SecBootDeviceSelect, + * &BootDevSel_Data, &BootDevSel_Size); + * if (e != NvError_Success) return e; + * + * e = NvDdkFuseGet(NvDdkFuseDataType_SecBootDeviceConfig, + * &BootDevConfig_Data, &BootDevConfig_Size); + * if (e != NvError_Success) return e; + * + * #ifdef DISABLE_PROGRMING_TEST + * NvDdkDisableFuseProgram(); + * #endif + * + * e = NvDdkFuseGet(NvDdkFuseDataType_ReservedOdm, + * &ResevOdm_Data, &ResevOdm_size); + * if (e != NvError_Success) return e; + * + * e = NvDdkFuseGet(NvDdkFuseDataType_SkipDevSelStraps, + * &skpDevSelStrap_data, &size); + * if (e != NvError_Success) return e; + * + * + * // Set the fuse values. + * e = NvDdkFuseSet(NvDdkFuseDataType_SecBootDeviceSelect, + * &BootDevSel_Data, &BootDevSel_Size); + * if (e != NvError_Success) return e; + * + * e = NvDdkFuseSet(NvDdkFuseDataType_SecBootDeviceConfig, + * &BootDevConfig_Data, &BootDevConfig_Size); + * if (e != NvError_Success) return e; + * + * e = NvDdkFuseSet(NvDdkFuseDataType_SkipDevSelStraps, + * &skpDevSelStrap_data, &size); + * if (e != NvError_Success) return e; + * + * + * e = NvDdkFuseSet(NvDdkFuseDataType_ReservedOdm, + * &ResevOdm_Data, &ResevOdm_size); + * if (e != NvError_Success) return e; + * + * return e; + * } + * + * + * NvError NvTestMain(int argc, char *argv[]) + * { + * NvTestApplication h; + * NvError err; + * + * NVTEST_INIT( &h ); + * // Enable fuse clock and fuse voltage prior to programming fuses. + * err = PrepareFuseData(); + * if( err != NvSuccess) + * return err; + * + * NvOdmOsWaitUS(10000); + * + * NVTEST_RUN(&h, NvddkFuseProgramTest); + * + * NVTEST_RESULT( &h ); + * } + * @endcode + * + * @ingroup nvddk_modules + * @{ + */ + +#if defined(__cplusplus) +extern "C" +{ +#endif + + +#include "nvcommon.h" +#include "nverror.h" + + +/* ----------- Program/Verify API's -------------- */ + +/** + * Defines types of fuse data to set or query. + */ +typedef enum +{ + /// Specifies a default (unset) value. + NvDdkFuseDataType_None = 0, + + /// Specifies a device key (DK). + NvDdkFuseDataType_DeviceKey, + + /** + * Specifies a JTAG disable flag: + * - NV_TRUE specifies to permanently disable JTAG-based debugging. + * - NV_FALSE indicates that JTAG-based debugging is not permanently + * disabled. + */ + NvDdkFuseDataType_JtagDisable, + + /** + * Specifies a key programmed flag (read-only): + * - NV_TRUE indicates that either the SBK or the DK value is nonzero. + * - NV_FALSE indicates that both the SBK and DK values are zero (0). + * + * @note Once the ODM production fuse is set to NV_TRUE, applications + * can no longer read back the SBK or DK value; however, by using + * this \c KeyProgrammed query it is still possible to determine + * whether or not the SBK or DK has been programmed to a nonzero value. + */ + NvDdkFuseDataType_KeyProgrammed, + + /** + * Specifies an ODM production flag: + * - NV_TRUE specifies the chip is in ODM production mode. + * - NV_FALSE indicates that the chip is not in ODM production mode. + */ + NvDdkFuseDataType_OdmProduction, + + /** + * Specifies a secondary boot device configuration. + * This value is chip-dependent. + * For Tegra APX 2600, use the NVBOOT_FUSE_*_CONFIG_* + * defines from: + * <pre> + * /src/drivers/hwinc/ap15/nvboot_fuse.h + * </pre> + */ + NvDdkFuseDataType_SecBootDeviceConfig, + + /** + * Specifies a secondary boot device selection. + * This value is chip-independent and is described in \c nvddk_bootdevices.h. + * The chip-dependent version of this data is + * ::NvDdkFuseDataType_SecBootDeviceSelectRaw. + * For Tegra APX 2600, the values for \c SecBootDeviceSelect and + * \c SecBootDeviceSelectRaw are identical. + */ + NvDdkFuseDataType_SecBootDeviceSelect, + + /** Specifies a secure boot key (SBK). */ + NvDdkFuseDataType_SecureBootKey, + + /** + * Specifies a stock-keeping unit (read-only). + * This value is chip-dependent. + * See chip-specific documentation for legal values. + */ + NvDdkFuseDataType_Sku, + + /** + * Specifies spare fuse bits (read-only). + * Reserved for future use by NVIDIA. + */ + NvDdkFuseDataType_SpareBits, + + /** + * Specifies software reserved fuse bits (read-only). + * Reserved for future use by NVIDIA. + */ + NvDdkFuseDataType_SwReserved, + + /** + * Specifies skip device select straps (applies to Tegra 200 series only): + * - NV_TRUE specifies to ignore the device selection straps setting + * and that the boot device is specified via the + * \c SecBootDeviceSelect and \c SecBootDeviceConfig fuse settings. + * - NV_FALSE indicates that the boot device is specified via the device + * selection straps setting. + */ + NvDdkFuseDataType_SkipDevSelStraps, + + /** + * Specifies a secondary boot device selection. + * This value is chip-dependent. + * The chip-independent version of this data is + * ::NvDdkFuseDataType_SecBootDeviceSelect. + * For Tegra APX 2600, use the \c NvBootFuseBootDevice enum + * values found at: + * <pre> + * /src/drivers/hwinc/ap15/nvboot_fuse.h + * </pre> + */ + NvDdkFuseDataType_SecBootDeviceSelectRaw, + + /** + * Specifies raw field for reserved the ODM. + * This value is ODM-specific. Reserved for customers. + */ + NvDdkFuseDataType_ReservedOdm, + + /** The following must be last. */ + NvDdkFuseDataType_Num, + /** Ignore -- Forces compilers to make 32-bit enums. */ + NvDdkFuseDataType_Force32 = 0x7FFFFFFF +} NvDdkFuseDataType; + +// Gets the base address for Fuse anc CAR modules. +// Call this function before accessing any other API of Fuse. +NvError NvDdkFuseOpen(NvRmDeviceHandle hRmDevice); + +// to free up all resources +void NvDdkFuseClose(void); +/** + * Gets a value from the fuse registers. + * + *@pre NvDdkFuseOpen should have been called before using this API + * @pre Do not call this function while the programming power is applied! + * + * After programming fuses and removing the programming power, + * NvDdkFuseSense() must be called to read the new values. + * + * By passing a size of 0, the caller is requesting to be told the + * expected size. + * + * Treatment of fuse data depends upon its size: + * - if \a *pSize == 1, treat \a *pData as an NvU8 + * - if \a *pSize == 2, treat \a *pData as an NvU16 + * - if \a *pSize == 4, treat \a *pData as an NvU32 + * - else, treat \a *pData as an array of NvU8 values (i.e., NvU8[]). + */ +NvError NvDdkFuseGet(NvDdkFuseDataType Type, void *pData, NvU32 *pSize); + +/** + * Schedules fuses to be programmed to the specified values when the next + * NvDdkFuseProgram() operation is performed. + * + *@pre NvDdkFuseOpen should have been called before using this API + * + * @note Attempting to program the ODM production fuse at the same + * time as the SBK or DK causes an error, because it is not + * possible to verify that the SBK or DK were programmed correctly. + * After triggering this error, all further attempts to set fuse + * values will fail, as will \c NvDdkFuseProgram, until NvDdkFuseClear() + * has been called. + * + * By passing a size of 0, the caller is requesting to be told the + * expected size. + * + * Treatment of fuse data depends upon its size: + * - if \a *pSize == 1, treat \a *pData as an NvU8 + * - if \a *pSize == 2, treat \a *pData as an NvU16 + * - if \a *pSize == 4, treat \a *pData as an NvU32 + * - else, treat \a *pData as an array of NvU8 values (i.e., NvU8[]). + * + * @retval NvError_BadValue If other than "reserved ODM fuse" is set in ODM + * production mode. + * @retval NvError_AccessDenied If programming to fuse registers is disabled. + */ +NvError NvDdkFuseSet(NvDdkFuseDataType Type, void *pData, NvU32 *pSize); + +/** + * Reads the current fuse data into the fuse registers. + * + *@pre NvDdkFuseOpen should have been called before using this API + * + * \c NvDdkFuseSense must be called at least once, either: + * - After programming fuses and removing the programming power, + * - Prior to calling NvDdkFuseVerify(), or + * - Prior to calling NvDdkFuseGet(). + */ +void NvDdkFuseSense(void); + +/** + * Programs all fuses based on cache data changed via the NvDdkFuseSet() API. + * + *@pre NvDdkFuseOpen should have been called before using this API + * + * @pre Prior to invoking this routine, the caller is responsible for supplying + * valid fuse programming voltage. + * + * @retval NvError_AccessDenied If programming to fuse registers is disabled. + * @return An error if an invalid combination of fuse values was provided. + */ +NvError NvDdkFuseProgram(void); + +/** + * Verify all fuses scheduled via the NvDdkFuseSet() API. + * + *@pre NvDdkFuseOpen should have been called before using this API + * + * @pre Prior to invoking this routine, the caller is responsible for ensuring + * that fuse programming voltage is removed and subsequently calling + * NvDdkFuseSense(). + */ +NvError NvDdkFuseVerify(void); + +/** + * Clears the cache of fuse data, once NvDdkFuseProgram() and NvDdkFuseVerify() + * API are called to clear all buffers. + * + *@pre NvDdkFuseOpen should have been called before using this API + */ +void NvDdkFuseClear(void); + + +/** + * Disables further fuse programming until the next system reset. + * + *@pre NvDdkFuseOpen should have been called before using this API + */ +void NvDdkDisableFuseProgram(void); + + +#if defined(__cplusplus) +} +#endif + +/** @} */ +#endif // INCLUDED_NVDDK_FUSE_H + diff --git a/arch/arm/mach-tegra/include/nvddk_operatingmodes.h b/arch/arm/mach-tegra/include/nvddk_operatingmodes.h new file mode 100644 index 000000000000..5cda2df6891b --- /dev/null +++ b/arch/arm/mach-tegra/include/nvddk_operatingmodes.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_NVDDK_OPERATINGMODES_H +#define INCLUDED_NVDDK_OPERATINGMODES_H + +/** + * @defgroup nvddk_operatingmodes_group Operating Modes + * + * Provides operating mode information for NVIDIA Boot Loader functions. + * + * @ingroup nvddk_group + * @{ + */ + +/** + * Defines the supported operating modes. + */ +typedef enum +{ + // Specifies development mode; boot loader is validated using a fixed key of zeroes. + NvDdkOperatingMode_NvProduction = 3, + + // Specifies production mode; boot loader is decrypted using the Secure Boot Key, + // then validated using the Secure Boot Key. + NvDdkOperatingMode_OdmProductionSecure, + + // Specifies ODM production mode; boot loader is validated using the Secure Boot Key. + NvDdkOperatingMode_OdmProductionOpen, + + // Undefined. + NvDdkOperatingMode_Undefined, + + // Ignore -- Forces compilers to make 32-bit enums. + NvDdkOperatingMode_Force32 = 0x7FFFFFFF +} NvDdkOperatingMode; + +/** @} */ + +#endif // INCLUDED_NVDDK_OPERATINGMODES_H + diff --git a/arch/arm/mach-tegra/include/nvodm_query_discovery.h b/arch/arm/mach-tegra/include/nvodm_query_discovery.h index 1a109fd8381e..74f8777616ee 100644 --- a/arch/arm/mach-tegra/include/nvodm_query_discovery.h +++ b/arch/arm/mach-tegra/include/nvodm_query_discovery.h @@ -55,7 +55,7 @@ * 64-bit value (8-character code) that uniquely identifies each peripheral, * i.e., each peripheral will have exactly one GUID, and each GUID will refer * to exactly one peripheral. - * + * * The implementation of this API is similar to a simple database: tables are * provided by the ODMs that, for every peripheral, define the peripheral's * GUID, and specify the bus, or set of buses, to which the peripheral is @@ -140,6 +140,7 @@ extern "C" #define NV_PMU_TRANSPORT_ODM_ID (NV_ODM_GUID('N','V','P','M','U','T','R','N')) +#define NV_VDD_FUSE_ODM_ID (NV_ODM_GUID('N','V','D','D','F','U','S','E')) /** * Some of the NVIDIA driver libraries enumerate peripherals based on the * logical functionality that the peripheral performs, rather than by the @@ -172,10 +173,10 @@ typedef enum NvOdmPeripheralClass_Force32 = 0x7fffffffUL } NvOdmPeripheralClass; -/** +/** * Defines the unique address on a bus where a peripheral is connected. */ -typedef struct +typedef struct { /// Specifies the type of bus or I/O (I2C, DAP, GPIO) for this connection. NvOdmIoModule Interface; @@ -194,7 +195,7 @@ typedef struct /** * Some buses, such as I2C and SPI, support multiple slave devices on - * a single bus, through the use of peripheral addresses and/or chip + * a single bus, through the use of peripheral addresses and/or chip * select signals. This value specifies the appropriate address or chip * select required to communicate with the peripheral. * @@ -212,7 +213,7 @@ typedef struct * Defines the full bus connectivity for peripherals connected to the * application processor. */ -typedef struct +typedef struct { /// The ODM-defined 64-bit GUID that identifies this peripheral. NvU64 Guid; @@ -232,7 +233,7 @@ typedef struct /// Defines different criteria for searching through the peripheral database. -typedef enum +typedef enum { /// Searches for peripherals that are members of the specified class. NvOdmPeripheralSearch_PeripheralClass, @@ -240,7 +241,7 @@ typedef enum /// Searches for peripherals connected to the specified I/O module. NvOdmPeripheralSearch_IoModule, - /** + /** * Searches for peripherals connected to the specified bus instance. * * @note This value will be compared against all entries in \a addressList. @@ -259,7 +260,7 @@ typedef enum NvOdmPeripheralSearch_Force32 = 0x7fffffffUL } NvOdmPeripheralSearch; -/** +/** * Defines the data structure that describes each sub-assembly of the * development platform. This data is read from EEPROMs on each of the sub- * assemblies, which is saved with the following format: @@ -269,13 +270,13 @@ typedef enum * * Where: * - * - xxxx is the board ID number 0-9999 (2 byte number) - * - yyyy is the SKU number 0-9999 (2 byte number) - * - zz is the FAB number 0-99 (1 byte number) + * - xxxx is the board ID number 0-9999 (2 byte number) + * - yyyy is the SKU number 0-9999 (2 byte number) + * - zz is the FAB number 0-99 (1 byte number) * - X is the major revision, (1 byte ASCII character), e.g., 'A', 'B', etc. * - N is the minor revision, (1 byte number, 0 - 9) */ -typedef struct +typedef struct { /// Specifies the board number. NvU16 BoardID; @@ -327,10 +328,10 @@ NvOdmPeripheralEnumerate( /** * Searches through the database of connected peripherals for the peripheral - * matching the specified GUID and returns that peripheral's connectivity + * matching the specified GUID and returns that peripheral's connectivity * structure. * - * @note If the ODM system supports hot-pluggable peripherals (e.g., an + * @note If the ODM system supports hot-pluggable peripherals (e.g., an * external TV-out display), the connectivity structure should only be returned * when the peripheral is useable by the NVIDIA driver libraries. If hot-plug * detection is not supported, the peripheral's connectivity structure may @@ -348,13 +349,13 @@ NvOdmPeripheralGetGuid(NvU64 searchGuid); /** * Gets the ::NvOdmBoardInfo data structure values for the given board ID. - * + * * @param BoardId Identifies the board for which the BoardInfo data is to be retrieved. * @note The \a BoardId is in Binary Encoded Decimal (BCD) format. For example, * E920 is identified by a \a BoardId of 0x0920 and E9820 would be 0x9820. * @param pBoardInfo A pointer to the location where the requested \a BoardInfo data * shall be saved. - * + * * @return NV_TRUE if successful, or NV_FALSE otherwise. */ NvBool @@ -367,5 +368,4 @@ NvOdmPeripheralGetBoardInfo( #endif /** @} */ - #endif // INCLUDED_NVODM_QUERY_DISCOVERY_H diff --git a/arch/arm/mach-tegra/nvddk/Makefile b/arch/arm/mach-tegra/nvddk/Makefile index f1b5da42d5c8..b839f6e2590e 100644 --- a/arch/arm/mach-tegra/nvddk/Makefile +++ b/arch/arm/mach-tegra/nvddk/Makefile @@ -16,6 +16,8 @@ obj-y += nvddk_usbphy_ap16.o obj-y += nvddk_usbphy_ap20.o endif +obj-y += nvddk_fuse_ap20.o + obj-$(CONFIG_MTD_NAND_TEGRA) += nvddk_nand.o obj-$(CONFIG_TEGRA_SNOR) += nvsnor_controller.o diff --git a/arch/arm/mach-tegra/nvddk/nvddk_fuse_ap20.c b/arch/arm/mach-tegra/nvddk/nvddk_fuse_ap20.c new file mode 100644 index 000000000000..804be01ddf89 --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/nvddk_fuse_ap20.c @@ -0,0 +1,1642 @@ +/* + * Copyright (c) 2010 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "fuse_bitmap.h" +#include "ap20/arclk_rst.h" +#include "ap20/arfuse.h" +#include "nvddk_bootdevices.h" +#include "nvddk_operatingmodes.h" +#include "nvddk_fuse.h" +#include "nvrm_hardware_access.h" +#include "nvassert.h" +#include "nvrm_drf.h" +#include "nvos.h" +#include "nvodm_query_discovery.h" +#include "nvodm_services.h" +#include "nvrm_pmu.h" + +// Set below macro to 0, to disable voltage required for Fuse programming. +#define ENABLE_FUSE_VOLTAGE 1 +// By setting below macro to 1, a dummy interface of fuse is enabled for +// verifying sysfs interface. +#define FUSE_DUMMY_CODE 0 +// Set below macro to 1 to get prints during fuse read/ program operations. +#define ENABLE_DEBUG_PRINTS 0 + +#define FUSE_BOOT_DEVICE_INFO_0_BOOT_DEVICE_CONFIG_RANGE 13:0 +#define FUSE_RESERVED_SW_0_BOOT_DEVICE_SELECT_RANGE 2:0 +#define FUSE_RESERVED_SW_0_SKIP_DEV_SEL_STRAPS_RANGE 3:3 +#define FUSE_RESERVED_SW_0_SW_RESERVED_RANGE 7:4 + +#define FLAGS_PROGRAM_SECURE_BOOT_KEY 0x001 +#define FLAGS_PROGRAM_DEVICE_KEY 0x002 +#define FLAGS_PROGRAM_JTAG_DISABLE 0x004 +#define FLAGS_PROGRAM_BOOT_DEV_SEL 0x008 +#define FLAGS_PROGRAM_BOOT_DEV_CONFIG 0x010 +#define FLAGS_PROGRAM_SW_RESERVED 0x020 +#define FLAGS_PROGRAM_ODM_PRODUCTION 0x040 +#define FLAGS_PROGRAM_SPARE_BITS 0x080 +#define FLAGS_PROGRAM_SKIP_DEV_SEL_STRAPS 0x100 +#define FLAGS_PROGRAM_RESERVED_ODM 0x200 + +#define FLAGS_PROGRAM_ILLEGAL 0x80000000 + +#define NVDDK_DEVICE_KEY_BYTES (4) +#define NVDDK_SECURE_BOOT_KEY_BYTES (16) +#define NVDDK_RESERVED_ODM_BYTES (32) + +#define NVDDK_TPROGRAM_VALUE_CORRECTED 0 + +// Number of words of fuses as defined by the hardware. +#define FUSE_WORDS 64 + +/* + * Representation of the fuse data. + * + */ +typedef struct NvDdkFuseDataRec +{ + // Specifies the Secure Boot Key (SBK). + NvU8 SecureBootKey[NVDDK_SECURE_BOOT_KEY_BYTES]; + + // Specifies the Device Key (DK). + NvU8 DeviceKey[NVDDK_DEVICE_KEY_BYTES]; + + // Specifies the JTAG Disable fuse value. + NvBool JtagDisable; + + // Specifies the device selection value in terms of the API. + NvU32 SecBootDeviceSelect; + + // Specifies the device selection value in the actual fuses. + NvU32 SecBootDeviceSelectRaw; + + // Specifies the device configuration value (right aligned). + NvU32 SecBootDeviceConfig; + + // Specifies the SwReserved value. + NvU32 SwReserved; + + // Specifies the ODM Production fuse value. + NvBool OdmProduction; + + // Specifies the SkipDevSelStraps value. + NvU32 SkipDevSelStraps; + + // Specifies the Reserved Odm value + NvU8 ReservedOdm[NVDDK_RESERVED_ODM_BYTES]; + + // Flags that indicate what to program. + NvU32 ProgramFlags; + + // Flag indicates whether reservedodm fuses are setting or not + NvBool ReservedOdmFlag; +} NvDdkFuseData; + +static NvDdkFuseData s_FuseData = {{0}}; + +typedef enum +{ + FuseBootDev_Sdmmc, + FuseBootDev_SnorFlash, + FuseBootDev_SpiFlash, + FuseBootDev_NandFlash, + FuseBootDev_NandFlash_x8 = FuseBootDev_NandFlash, + FuseBootDev_NandFlash_x16 = FuseBootDev_NandFlash, + FuseBootDev_MobileLbaNand, + FuseBootDev_MuxOneNand, + FuseBootDev_Max, /* Must appear after the last legal item */ + FuseBootDev_Force32 = 0x7fffffff +} FuseBootDev; + +// Holds various params that are needed by Fuse module. +typedef struct NvDdkFuseRec +{ + // Fuse registers physical base address + NvRmPhysAddr pBaseAddress; + // Holds the virtual address for accessing registers. + NvU32 *pVirtualAddress; + // Holds the register map size. + NvU32 BankSize; + + // Fuse registers physical base address + NvRmPhysAddr pCarBaseAddress; + // Holds the virtual address for accessing registers. + NvU32 *pCarVirtualAddress; + // Holds the register map size. + NvU32 CarBankSize; + + // Mutex for fuse + NvOsMutexHandle Mutex; +}NvDdkFuse; + +static NvDdkFuse* s_pFuseRec = NULL; + +// Size of the data items, in bytes +static NvU32 s_DataSize[] = +{ + 0, // FuseDataType_None + sizeof(NvU64), // FuseDataType_DeviceKey + sizeof(NvBool), // FuseDataType_JtagDisable + sizeof(NvBool), // FuseDataType_KeyProgrammed + sizeof(NvBool), // FuseDataType_OdmProductionEnable + sizeof(NvU32), // FuseDataType_SecBootDeviceConfig + sizeof(NvU32), // FuseDataType_SecBootDeviceSelect + NVDDK_SECURE_BOOT_KEY_BYTES, // FuseDataType_SecureBootKey + sizeof(NvU32), // FuseDataType_Sku + sizeof(NvU32), // FuseDataType_SpareBits + sizeof(NvU32), // FuseDataType_SwReserved + sizeof(NvBool), // FuseDataType_SkipDevSelStraps + sizeof(NvU32), // FuseDataType_SecBootDeviceSelectRaw + NVDDK_RESERVED_ODM_BYTES // NvDdkFuseDataType_ReservedOdm fuse +}; + + +// Map NvDdkSecBootDeviceType enum onto AP20 Boot Device Selection values. +static NvU32 NvDdkToFuseBootDeviceSel[] = +{ + FuseBootDev_Sdmmc, // None + FuseBootDev_NandFlash, // NvDdkSecBootDeviceType_Nand + FuseBootDev_SnorFlash, // NvDdkSecBootDeviceType_Nor + FuseBootDev_SpiFlash, // NvDdkSecBootDeviceType_Spi_Flash + FuseBootDev_Sdmmc, // NvDdkSecBootDeviceType_eMMC + FuseBootDev_NandFlash, // NvDdkSecBootDeviceType_Nand_x16 + FuseBootDev_MobileLbaNand, // NvDdkSecBootDeviceType_MobileLbaNand + FuseBootDev_Sdmmc, // NvDdkSecBootDeviceType_eMMC + FuseBootDev_MuxOneNand, // NvDdkSecBootDeviceType_MuxOneNand +}; + +// Map AP20 fuse values onto NvDdkSecBootDeviceType enum values. +static NvU32 FuseToNvDdkBootDeviceSel[] = +{ + NvDdkSecBootDeviceType_Sdmmc, // FuseBootDev_Sdmmc + NvDdkSecBootDeviceType_Nor, // FuseBootDev_SnorFlash + NvDdkSecBootDeviceType_Spi, // FuseBootDev_SpiFlash + NvDdkSecBootDeviceType_Nand, // FuseBootDev_NandFlash + NvDdkSecBootDeviceType_MobileLbaNand, // FuseBootDev_MobileLbaNand + NvDdkSecBootDeviceType_MuxOneNand, // FuseBootDev_MuxOneNand +}; + +// Storage for the array of fuse words & mask words. +static NvU32 s_FuseArray [FUSE_WORDS] = { 0 }; +static NvU32 s_MaskArray [FUSE_WORDS] = { 0 }; +static NvU32 s_TempFuseData[FUSE_WORDS]; + + +#define FUSE_NV_READ32(offset) \ + NV_READ32(s_pFuseRec->pVirtualAddress + (offset >> 2)) + +#define FUSE_NV_WRITE32(offset, val) \ + NV_WRITE32((s_pFuseRec->pVirtualAddress + (offset >> 2)), val) + +#define CLOCK_NV_READ32(offset) \ + NV_READ32(s_pFuseRec->pCarVirtualAddress + (offset >> 2)) + +#define CLOCK_NV_WRITE32(offset, val) \ + NV_WRITE32((s_pFuseRec->pCarVirtualAddress + (offset >> 2)), val) + +// Macro to get the difference between two numbers T1 & T2 and T1 > T2. +#define DIFF(T1, T2) \ + (((T1) > (T2)) ? ((T1) - (T2)) : ((T2) - (T1))) +// For rollover proof, +// (((T1) > (T2)) ? ((T1) - (T2)) : ((T1) + ((NvU64)0xFFFFFFFFFFFFFFFF - (T2)))) + +static void NvFuseUtilWaitUS(NvU32 usec) +{ + NvU64 t0; + NvU64 t1; + + t0 = NvOsGetTimeUS(); + t1 = t0; + // Use the difference for the comparison to be wraparound safe + while (DIFF(t1, t0) < usec) + { + t1 = NvOsGetTimeUS(); + } +} + +static void fusememset(void* Source, NvU8 val, NvU32 size) +{ + NvOsMemset(Source, val, size); +} + +static void fusememcpy(void* Destination, void* Source, NvU32 size) +{ + NvOsMemcpy(Destination, Source, size); +} +/** + * Reports whether any of the SBK fuses are set (burned) + * + * @param none + * + * @return NV_TRUE if the SBK is non-zero + * @return NV_FALSE otherwise + */ +static NvBool NvDdkFuseIsSbkSet(void) +{ + NvU32 AllKeysOred; + AllKeysOred = FUSE_NV_READ32(FUSE_PRIVATE_KEY0_NONZERO_0); + AllKeysOred |= FUSE_NV_READ32(FUSE_PRIVATE_KEY1_NONZERO_0); + AllKeysOred |= FUSE_NV_READ32(FUSE_PRIVATE_KEY2_NONZERO_0); + AllKeysOred |= FUSE_NV_READ32(FUSE_PRIVATE_KEY3_NONZERO_0); + if (AllKeysOred) + return NV_TRUE; + else + return NV_FALSE; +} + +/** + * Reports whether any of the SBK or DK fuses are set (burned) + * + * @param none + * + * @return NV_TRUE if the SBK or the DK is non-zero + * @return NV_FALSE otherwise + */ +static NvBool IsSbkOrDkSet(void) +{ + NvU32 AllKeysOred; + + AllKeysOred = NvDdkFuseIsSbkSet(); + AllKeysOred |= FUSE_NV_READ32(FUSE_PRIVATE_KEY4_NONZERO_0); + + if (AllKeysOred) + return NV_TRUE; + else + return NV_FALSE; +} + + +/** + * Reports whether the ODM Production Mode fuse is set (burned) + * + * Note that this fuse by itself does not determine whether the chip is in + * ODM Production Mode. + * + * @param none + * + * @return NV_TRUE if ODM Production Mode fuse is set (burned); else NV_FALSE + */ +static NvBool NvDdkFuseIsOdmProductionModeFuseSet(void) +{ + NvU32 RegValue; + RegValue = FUSE_NV_READ32(FUSE_SECURITY_MODE_0); + if (RegValue) + { + return NV_TRUE; + } + else + { + return NV_FALSE; + } +} + + +/** + * Reports whether the Disable Register Program register is set. + * + * @param none + * + * @return NV_TRUE if Disable reg program is iset, else NV_FALSE + */ + +static NvBool NvDdkPrivIsDisableRegProgramSet(void) +{ + NvU32 RegValue; + RegValue = FUSE_NV_READ32(FUSE_DISABLEREGPROGRAM_0); + if (RegValue) + { + return NV_TRUE; + } + else + { + return NV_FALSE; + } +} + +static NvBool NvDdkFuseIsOdmProductionMode(void) +{ + if (NvDdkFuseIsOdmProductionModeFuseSet()) + { + return NV_TRUE; + } + return NV_FALSE; +} + +static NvU32 NvDdkFuseGetSecBootDeviceRaw(void) +{ + NvU32 RegData; + + RegData = FUSE_NV_READ32(FUSE_RESERVED_SW_0); + RegData = NV_DRF_VAL(FUSE, RESERVED_SW, BOOT_DEVICE_SELECT, RegData); + if (RegData >= (NvU32) FuseBootDev_Max) + { + RegData = FuseBootDev_Sdmmc; + } + + return RegData; +} + +static NvDdkSecBootDeviceType NvDdkFuseGetSecBootDevice(void) +{ + NvU32 RegData; + NvDdkSecBootDeviceType SecBootDevice; + + RegData = NvDdkFuseGetSecBootDeviceRaw(); + + // Map from AP20 definitions onto NvDdkSecBootDeviceType definitions. + SecBootDevice = FuseToNvDdkBootDeviceSel[RegData]; + + return SecBootDevice; +} + +// p = prefix, c = copy, i = index, d = data + +#define FUSE_BASE(p, c, i) FUSE_##p##__##c##_ALIAS_##i +#define FUSE_DATA(p, c, i) FUSE_##p##__##c##_ALIAS_##i##_DATA +#define FUSE_WIDTH(p, c, i) FUSE_##p##__##c##_ALIAS_##i##_WIDTH + +#define SET_FUSE(p, c, i, d) \ + s_FuseArray[FUSE_BASE(p, c, i)] = \ + (s_FuseArray[FUSE_BASE(p, c, i)] & \ + ~NV_FIELD_SHIFTMASK(FUSE_DATA(p, c, i))) | \ + ((d & (NV_FIELD_MASK(FUSE_DATA(p, c, i)))) << \ + (NV_FIELD_SHIFT(FUSE_DATA(p, c, i)))) + +#define SET_MASK(p, c, i) \ + s_MaskArray[FUSE_BASE(p,c,i)] |= NV_FIELD_SHIFTMASK(FUSE_DATA(p,c,i)) + +#define SET_FUSE_DATA(p, c, i, d) \ + SET_FUSE(p,c,i,d); \ + SET_MASK(p,c,i); + +#define SET_FUSE_PRI(p, i, d) SET_FUSE_DATA(p, PRI, i, d); +#define SET_FUSE_RED(p, i, d) SET_FUSE_DATA(p, RED, i, d); + +#define SET_FUSE_BOTH(p, i, d) \ + SET_FUSE_PRI(p,i,d); \ + SET_FUSE_RED(p,i,d); + +// Update fuses with an explicit mask. +#define SET_FUSE_BOTH_WITH_MASK(p, i, d, md) \ + SET_FUSE(p, PRI, i, d); \ + SET_FUSE(p, RED, i, d); \ + s_MaskArray[FUSE_BASE(p, PRI, i)] |= \ + (md << NV_FIELD_SHIFT(FUSE_DATA(p, PRI, i))); \ + s_MaskArray[FUSE_BASE(p, RED, i)] |= \ + (md << NV_FIELD_SHIFT(FUSE_DATA(p, RED, i))); + +#define UPDATE_DATA(p,i,d) (d >>= FUSE_WIDTH(p,PRI,i)); + +#define SET_SPARE_BIT(n) \ + SET_FUSE_PRI(SPARE_BIT_##n, 0, Data); \ + UPDATE_DATA (SPARE_BIT_##n, 0, Data); + + +static void MapDataToFuseArrays(void) +{ + NvU32 *Src; + NvU32 Data = 0; + NvU32 MaskData; + + // Start by clearing the arrays. + fusememset(s_FuseArray, 0, sizeof(s_FuseArray)); + fusememset(s_MaskArray, 0, sizeof(s_MaskArray)); + // Set ENABLE_FUSE_PROGRAM bit to 1 + SET_FUSE_BOTH(ENABLE_FUSE_PROGRAM, 0, 1); + + // Reserved Odm fuse + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_RESERVED_ODM) + { + Src = (NvU32*)(s_FuseData.ReservedOdm); + Data = Src[0]; + SET_FUSE_BOTH(RESERVED_ODM0, 0, Data); + UPDATE_DATA (RESERVED_ODM0, 0, Data); + SET_FUSE_BOTH(RESERVED_ODM0, 1, Data); + + Data = Src[1]; + SET_FUSE_BOTH(RESERVED_ODM1, 0, Data); + UPDATE_DATA (RESERVED_ODM1, 0, Data); + SET_FUSE_BOTH(RESERVED_ODM1, 1, Data); + + Data = Src[2]; + SET_FUSE_BOTH(RESERVED_ODM2, 0, Data); + UPDATE_DATA (RESERVED_ODM2, 0, Data); + SET_FUSE_BOTH(RESERVED_ODM2, 1, Data); + + Data = Src[3]; + SET_FUSE_BOTH(RESERVED_ODM3, 0, Data); + UPDATE_DATA (RESERVED_ODM3, 0, Data); + SET_FUSE_BOTH(RESERVED_ODM3, 1, Data); + + Data = Src[4]; + SET_FUSE_BOTH(RESERVED_ODM4, 0, Data); + UPDATE_DATA (RESERVED_ODM4, 0, Data); + SET_FUSE_BOTH(RESERVED_ODM4, 1, Data); + + Data = Src[5]; + SET_FUSE_BOTH(RESERVED_ODM5, 0, Data); + UPDATE_DATA (RESERVED_ODM5, 0, Data); + SET_FUSE_BOTH(RESERVED_ODM5, 1, Data); + + Data = Src[6]; + SET_FUSE_BOTH(RESERVED_ODM6, 0, Data); + UPDATE_DATA (RESERVED_ODM6, 0, Data); + SET_FUSE_BOTH(RESERVED_ODM6, 1, Data); + + Data = Src[7]; + SET_FUSE_BOTH(RESERVED_ODM7, 0, Data); + UPDATE_DATA (RESERVED_ODM7, 0, Data); + SET_FUSE_BOTH(RESERVED_ODM7, 1, Data); + } + + // If Secure mode is set, we can not burn any other fuses, so return. + if (NvDdkFuseIsOdmProductionModeFuseSet()) + { + return; + } + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_JTAG_DISABLE) + { + Data = (NvU32)(s_FuseData.JtagDisable); + SET_FUSE_BOTH(ARM_DEBUG_DIS, 0, Data); + } + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_ODM_PRODUCTION) + { + Data = (NvU32)(s_FuseData.OdmProduction); + SET_FUSE_BOTH(SECURITY_MODE, 0, Data); + } + + // SBK & DK + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_SECURE_BOOT_KEY) + { + Src = (NvU32*)(s_FuseData.SecureBootKey); + Data = Src[0]; + SET_FUSE_BOTH(PRIVATE_KEY0, 0, Data); + UPDATE_DATA (PRIVATE_KEY0, 0, Data); + SET_FUSE_BOTH(PRIVATE_KEY0, 1, Data); + + Data = Src[1]; + SET_FUSE_BOTH(PRIVATE_KEY1, 0, Data); + UPDATE_DATA (PRIVATE_KEY1, 0, Data); + SET_FUSE_BOTH(PRIVATE_KEY1, 1, Data); + + Data = Src[2]; + SET_FUSE_BOTH(PRIVATE_KEY2, 0, Data); + UPDATE_DATA (PRIVATE_KEY2, 0, Data); + SET_FUSE_BOTH(PRIVATE_KEY2, 1, Data); + + Data = Src[3]; + SET_FUSE_BOTH(PRIVATE_KEY3, 0, Data); + UPDATE_DATA (PRIVATE_KEY3, 0, Data); + SET_FUSE_BOTH(PRIVATE_KEY3, 1, Data); + } + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_DEVICE_KEY) + { + Src = (NvU32*)(s_FuseData.DeviceKey); + Data = Src[0]; + SET_FUSE_BOTH(PRIVATE_KEY4, 0, Data); + UPDATE_DATA (PRIVATE_KEY4, 0, Data); + SET_FUSE_BOTH(PRIVATE_KEY4, 1, Data); + } + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_BOOT_DEV_CONFIG) + { + // BootDeviceConfig is 14 bits so mask other bits + Data = (s_FuseData.SecBootDeviceConfig & 0x3FFF); + SET_FUSE_BOTH(BOOT_DEVICE_INFO, 0, Data); + } + + // Assemble RESERVED_SW + if ((s_FuseData.ProgramFlags & FLAGS_PROGRAM_BOOT_DEV_SEL ) || + (s_FuseData.ProgramFlags & FLAGS_PROGRAM_SKIP_DEV_SEL_STRAPS) || + (s_FuseData.ProgramFlags & FLAGS_PROGRAM_SW_RESERVED )) + { + Data = 0; + MaskData = 0; + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_BOOT_DEV_SEL) + { + Data |= (s_FuseData.SecBootDeviceSelectRaw & 0x7); + MaskData |= 0x7; + } + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_SKIP_DEV_SEL_STRAPS) + { + Data |= ((s_FuseData.SkipDevSelStraps & 0x1) << 3); + MaskData |= (0x1 << 3); + } + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_SW_RESERVED) + { + Data |= ((s_FuseData.SwReserved & 0xF) << 4); + MaskData |= (0xF << 4); + } + + SET_FUSE_BOTH_WITH_MASK(RESERVED_SW, 0, Data, MaskData); + } +} + + +static void FuseCopyBytes(NvU32 RegAddress, NvU8 *pByte, const NvU32 nBytes) +{ + NvU32 RegData; + NvU32 i; + + NV_ASSERT((pByte != NULL) || (nBytes == 0)); + NV_ASSERT (RegAddress != 0); + + for (i = 0, RegData = 0; i < nBytes; i++) + { + if ((i&3) == 0) + { + RegData = FUSE_NV_READ32(RegAddress); + RegAddress += 4; + } + pByte[i] = RegData & 0xFF; + RegData >>= 8; + } +} + +// Expose (Visibility = 1) or hide (Visibility = 0) the fuse registers. +static void SetFuseRegVisibility(NvU32 Visibility) +{ + NvU32 RegData; + + RegData = CLOCK_NV_READ32(CLK_RST_CONTROLLER_MISC_CLK_ENB_0); + RegData = NV_FLD_SET_DRF_NUM(CLK_RST_CONTROLLER, + MISC_CLK_ENB, + CFG_ALL_VISIBLE, + Visibility, + RegData); + CLOCK_NV_WRITE32(CLK_RST_CONTROLLER_MISC_CLK_ENB_0, RegData); +} + +// Wait for completion (state machine goes idle). +static void WaitForFuseIdle(void) +{ + NvU32 RegData; + + do + { + RegData = FUSE_NV_READ32(FUSE_FUSECTRL_0); + } while (NV_DRF_VAL(FUSE, FUSECTRL, FUSECTRL_STATE, RegData) != + FUSE_FUSECTRL_0_FUSECTRL_STATE_STATE_IDLE); +} + + +// Start the regulator and wait +static void StartRegulator(void) +{ + NvU32 RegData; + RegData = NV_DRF_DEF(FUSE, PWR_GOOD_SW, PWR_GOOD_SW_VAL, PWR_GOOD_OK); + FUSE_NV_WRITE32(FUSE_PWR_GOOD_SW_0, RegData); + /* + * Wait for at least 150ns. In HDEFUSE_64X32_E2F2R2_L1_A.pdf, + * this is found on p.11 as TSUP_PWRGD. + */ + NvFuseUtilWaitUS(1); +} + +// Stop the regulator and wait +static void StopRegulator(void) +{ + NvU32 RegData; + + RegData = NV_DRF_DEF(FUSE, PWR_GOOD_SW, PWR_GOOD_SW_VAL, PWR_GOOD_NOT_OK); + FUSE_NV_WRITE32(FUSE_PWR_GOOD_SW_0, RegData); + + /* + * Wait for at least 150ns. In HDEFUSE_64X32_E2F2R2_L1_A.pdf, + * this is found on p.11 as TSUP_PWRGD + */ + NvFuseUtilWaitUS(1); +} + + /* + * Read a word from the fuses. + * Note: The fuses must already have been sensed, and + * the programming power should be off. + */ +static NvU32 ReadFuseWord(NvU32 Addr) +{ + NvU32 RegData; + + // Prepare the data + FUSE_NV_WRITE32(FUSE_FUSEADDR_0, Addr); + + // Trigger the read + RegData = FUSE_NV_READ32(FUSE_FUSECTRL_0); + RegData = NV_FLD_SET_DRF_DEF(FUSE, FUSECTRL, FUSECTRL_CMD, READ, RegData); + FUSE_NV_WRITE32(FUSE_FUSECTRL_0, RegData); + + // Wait for completion (state machine goes idle). + WaitForFuseIdle(); + + RegData = FUSE_NV_READ32(FUSE_FUSERDATA_0); + + return RegData; +} + +/* + * Write a word to the fuses. + * Note: The programming power should be on, and the only non-zero + * bits should be fuses that have not yet been blown. + */ +static void WriteFuseWord(NvU32 Addr, NvU32 Data) +{ + NvU32 RegData; + + if (Data == 0) return; + + // Prepare the data + FUSE_NV_WRITE32(FUSE_FUSEADDR_0, Addr); + FUSE_NV_WRITE32(FUSE_FUSEWDATA_0, Data); + + // Trigger the write + RegData = FUSE_NV_READ32(FUSE_FUSECTRL_0); + RegData = NV_FLD_SET_DRF_DEF(FUSE, FUSECTRL, FUSECTRL_CMD, WRITE, RegData); + FUSE_NV_WRITE32(FUSE_FUSECTRL_0, RegData); + + // Wait for completion (state machine goes idle). + WaitForFuseIdle(); +} + +// Sense the fuse array & wait until done. +static void SenseFuseArray(void) +{ + NvU32 RegData; + + RegData = FUSE_NV_READ32(FUSE_FUSECTRL_0); + RegData = NV_FLD_SET_DRF_DEF(FUSE, + FUSECTRL, + FUSECTRL_CMD, + SENSE_CTRL, + RegData); + FUSE_NV_WRITE32(FUSE_FUSECTRL_0, RegData); + + // Wait for completion (state machine goes idle). + WaitForFuseIdle(); +} + + +// The following has not appeared in any netlist headers. +#ifndef FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0 +#define FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0 0x0 +#define FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0_DATA 0:0 +#define FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0_WIDTH 1 +#define FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0 0x1 +#define FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0_DATA 0:0 +#define FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0_WIDTH 1 +#endif +#ifndef FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0_SHIFT +#define FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0_SHIFT 0 +#define FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0_SHIFT 0 +#endif + +static void +NvDdkFuseProgramFuseArray( + NvU32 *FuseData, + NvU32 *MaskData, + NvU32 NumWords, + NvU32 TProgramCycles) +{ + NvU32 RegData; + NvU32 i; + NvU32 Addr = 0; + NvU32 *Data = NULL; + NvU32 *Mask = NULL; + NvU32 FuseWord0; // Needed for initially enabling fuse programming. + NvU32 FuseWord1; // Needed for initially enabling fuse programming. + + // Make all registers visible first + SetFuseRegVisibility(1); + // Read the first two fuse words. + SenseFuseArray(); + FuseWord0 = ReadFuseWord(FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0); + FuseWord1 = ReadFuseWord(FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0); + // also indicate power good to start the regulator and wait (again) + StartRegulator(); + /* + *In AP20, the fuse macro is a high density macro, with a completely + * different interface from the procedure used in AP15. Fuses are + * burned using an addressing mechanism, so no need to prepare + * the full list, but more write to control registers are needed, not + * a big deal + * The only bit that can be written at first is bit 0, a special write + * protection bit by assumptions all other bits are at 0 + * Note that the bit definitions are no more part of arfuse.h + * (unfortunately). So we define them here + * + * Modify the fuse programming time. + * + * For AP20, the programming pulse must have a precise width of + * [9000, 11000] ns. + */ + if (TProgramCycles > 0) + { + RegData = NV_DRF_NUM(FUSE, + FUSETIME_PGM2, + FUSETIME_PGM2_TWIDTH_PGM, + TProgramCycles); + FUSE_NV_WRITE32(FUSE_FUSETIME_PGM2_0, RegData); + } + /* FuseWord0 and FuseWord1 should be left with only the Fuse Enable fuse + * set to 1, and then only if this fuse has not yet been burned. + */ + FuseWord0 = (0x1 << FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0_SHIFT) & + ~FuseWord0; + FuseWord1 = (0x1 << FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0_SHIFT) & + ~FuseWord1; + + WriteFuseWord(FUSE_ENABLE_FUSE_PROGRAM__PRI_ALIAS_0, FuseWord0); + WriteFuseWord(FUSE_ENABLE_FUSE_PROGRAM__RED_ALIAS_0, FuseWord1); + // Remove power good as we may toggle fuse_src in the model, wait + StopRegulator(); + /* + * Sense the fuse macro, this will allow programming of other fuses + * and the reading of the existing fuse values + */ + SenseFuseArray(); + /* + * Clear out all bits in FuseData that have already been burned + * or that have been masked out. + */ + + fusememcpy(s_TempFuseData, FuseData, sizeof(NvU32) * 64); + Addr = 0; + Data = s_TempFuseData; + Mask = MaskData; + for (i = 0; i < NumWords; i++, Addr++, Data++, Mask++) + { + RegData = ReadFuseWord(Addr); + *Data = (*Data & ~RegData) & *Mask; + } + + // Enable power good + StartRegulator(); + /* + * Finally loop on all fuses, program the non zero ones + * Words 0 and 1 are written last and they contain control fuses and we + * need a sense after writing to a control word (with the exception of + * the master enable fuse) this is also the reason we write them last + */ + Addr = 2; + Data = s_TempFuseData + Addr; + for (; Addr < NumWords; Addr++, Data++) + { + WriteFuseWord(Addr, *Data); + } + // write the two control words, we need a sense after each write + Addr = 0; + Data = s_TempFuseData; + for (; Addr < NV_MIN(2, NumWords); Addr++, Data++) + { + WriteFuseWord(Addr, *Data); + // Remove power good as we may toggle fuse_src in the model, wait + StopRegulator(); + SenseFuseArray(); + StartRegulator(); + } + // Read all data into the chip options + RegData = NV_DRF_NUM(FUSE, PRIV2INTFC_START, PRIV2INTFC_START_DATA, 0x1); + FUSE_NV_WRITE32(FUSE_PRIV2INTFC_START_0, RegData); + /* + * Not sure if still needs to be set back to 0 + * we wait a little bit, then set it back to 0, then loop on state + */ + + NvFuseUtilWaitUS(1); + + RegData = NV_DRF_NUM(FUSE, PRIV2INTFC_START, PRIV2INTFC_START_DATA, 0x0); + FUSE_NV_WRITE32(FUSE_PRIV2INTFC_START_0, RegData); + /* + * Wait until done (polling) + * this one needs to use fuse_sense done, the FSM follows a periodic + * sequence that includes idle + */ + do { + RegData = FUSE_NV_READ32(FUSE_FUSECTRL_0); + } while (NV_DRF_VAL(FUSE, FUSECTRL, FUSECTRL_FUSE_SENSE_DONE, RegData) != 0x1); +} + +static NvError +NvDdkFuseVerifyFuseArray( + NvU32 *FuseData, + NvU32 *MaskData, + NvU32 NumWords) +{ + NvU32 RegData; + NvU32 i; + NvU32 Addr = 0; + NvU32 *Data = NULL; + NvU32 *Mask = NULL; + NvError e = NvSuccess; + + // Make all registers visible first + SetFuseRegVisibility(1); + + // Sense the fuse array + SenseFuseArray(); + + // Loop over the data, checking fuse registers. + Addr = 0; + Data = FuseData; + Mask = MaskData; + for (i = 0; i < NumWords; i++, Addr++, Data++, Mask++) + { + RegData = (ReadFuseWord(Addr) & (*Mask)); + + /* + * Once Odm production mode fuse word(0th word) is set, it can + * not set any other fuse word in the fuse cell, including the + * redundent fuse word (1st word). + * Hence it makes no sense to verify it. + */ + if ((i == 1) && NvDdkFuseIsOdmProductionMode()) + { + continue; + } + + // Check the results. + if (RegData != ((*Data) & (*Mask))) + { + // Abort with an error on a miscompare + e = NvError_BadValue; + goto fail; + } + } + + // Fallthrough on sucessful completion. + + fail: + // Hide back registers + SetFuseRegVisibility(0); + return e; +} + +/* + ************************************* + * PUBLIC API + ************************************* + */ + +/** + * Clears the cache of fuse data. + */ +void NvDdkFuseClear(void) +{ + if(!s_pFuseRec) + { + // NV_ASSERT(0); + NvOsDebugPrintf("\r\n Plz call NvDdkFuseOpen before using this API"); + return; + } + NvOsMutexLock(s_pFuseRec->Mutex); + fusememset(&s_FuseData, 0, sizeof(NvDdkFuseData)); + NvOsMutexUnlock(s_pFuseRec->Mutex); +} + +/** + * Read the current fuse data into the fuse registers. + */ +void NvDdkFuseSense(void) +{ + if(!s_pFuseRec) + { + // NV_ASSERT(0); + NvOsDebugPrintf("\r\n Plz call NvDdkFuseOpen before using this API"); + return; + } + NvOsMutexLock(s_pFuseRec->Mutex); + SetFuseRegVisibility(1); + SenseFuseArray(); + SetFuseRegVisibility(0); + NvOsMutexUnlock(s_pFuseRec->Mutex); +} + +/** + * Macro's to swap byte order for an NvU32 + */ + +#define EXTRACT_BYTE_NVU32(Data32, ByteNum) \ + (((Data32) >> ((ByteNum)*8)) & 0xFF) + +#define SWAP_BYTES_NVU32(Data32) \ + do { \ + NV_ASSERT(sizeof(Data32)==4); \ + (Data32) = \ + (EXTRACT_BYTE_NVU32(Data32, 0) << 24) | \ + (EXTRACT_BYTE_NVU32(Data32, 1) << 16) | \ + (EXTRACT_BYTE_NVU32(Data32, 2) << 8) | \ + (EXTRACT_BYTE_NVU32(Data32, 3) << 0); \ + } while (0) + +#if FUSE_DUMMY_CODE +// Sizes of different fuses in bytes. +static NvU8 DeviceKey[4]; +static NvU8 JtagDisable[1]; +static NvU8 KeyProgrammed[1]; +static NvU8 OdmProduction[1]; +static NvU8 SecBootDeviceConfig[2]; +static NvU8 SecBootDeviceSelect[1]; +static NvU8 SecureBootKey[16]; +static NvU8 Sku[4]; +static NvU8 SpareBits[4]; +static NvU8 SwReserved[1]; +static NvU8 SkipDevSelStraps[1]; +static NvU8 SecBootDeviceSelectRaw[4]; +static NvU8 ReservedOdm[32]; + +NvError NvDdkFuseGet(NvDdkFuseDataType Type, void *pData, NvU32 *pSize) +{ + switch (Type) + { + case NvDdkFuseDataType_DeviceKey: + fusememcpy(pData, DeviceKey, sizeof(DeviceKey)); + break; + case NvDdkFuseDataType_JtagDisable: + fusememcpy(pData, JtagDisable, sizeof(JtagDisable)); + break; + case NvDdkFuseDataType_KeyProgrammed: + fusememcpy(pData, KeyProgrammed, sizeof(KeyProgrammed)); + break; + case NvDdkFuseDataType_OdmProduction: + fusememcpy(pData, OdmProduction, sizeof(OdmProduction)); + break; + case NvDdkFuseDataType_SecBootDeviceConfig: + fusememcpy(pData, SecBootDeviceConfig, sizeof(SecBootDeviceConfig)); + break; + case NvDdkFuseDataType_SecBootDeviceSelect: + fusememcpy(pData, SecBootDeviceSelect, sizeof(SecBootDeviceSelect)); + break; + case NvDdkFuseDataType_SecureBootKey: + fusememcpy(pData, SecureBootKey, sizeof(SecureBootKey)); + break; + case NvDdkFuseDataType_Sku: + fusememcpy(pData, Sku, sizeof(Sku)); + break; + case NvDdkFuseDataType_SpareBits: + fusememcpy(pData, SpareBits, sizeof(SpareBits)); + break; + case NvDdkFuseDataType_SwReserved: + fusememcpy(pData, SwReserved, sizeof(SwReserved)); + break; + case NvDdkFuseDataType_SkipDevSelStraps: + fusememcpy(pData, SkipDevSelStraps, sizeof(SkipDevSelStraps)); + break; + case NvDdkFuseDataType_SecBootDeviceSelectRaw: + fusememcpy(pData, SecBootDeviceSelectRaw, sizeof(SecBootDeviceSelectRaw)); + break; + case NvDdkFuseDataType_ReservedOdm: + fusememcpy(pData, ReservedOdm, sizeof(ReservedOdm)); + break; + default: + NvOsDebugPrintf("\r\n Invalid fuse type selected"); + break; + } + return NvSuccess; +} +#else +/** + * This gets value from the fuse cache. + * + * To read from the actual fuses, NvDdkFuseSense() must be called first. + * Note that NvDdkFuseSet() follwed by NvDdkFuseGet() for the same data will + * return the set data, not the actual fuse values. + * + * By passing a size of zero, the caller is requesting tfor the + * expected size. + */ +NvError NvDdkFuseGet(NvDdkFuseDataType Type, void *pData, NvU32 *pSize) +{ + NvU32 RegData; + NvU32 Size; + NvU32 DataSizeArrayLen; + + if(!s_pFuseRec) + { + NvOsDebugPrintf("\r\n Plz call NvDdkFuseOpen before using this API"); + return 1; + } + DataSizeArrayLen = ((sizeof(s_DataSize)) / (sizeof(NvU32))); + // Check the arguments + // NvDdkFuseDataType_Num is not ap20 specific as s_DataSize + if (Type == NvDdkFuseDataType_None || + (Type > (NvDdkFuseDataType)DataSizeArrayLen)) + return NvError_BadValue; + if (pSize == NULL) return NvError_BadParameter; + + Size = s_DataSize[(NvU32)Type]; + + if (*pSize == 0) + { + *pSize = Size; + return NvError_Success; + } + +// if (*pSize > Size) return NvError_InsufficientMemory; + if (pData == NULL) return NvError_BadParameter; + + NvOsMutexLock(s_pFuseRec->Mutex); + switch (Type) + { + case NvDdkFuseDataType_DeviceKey: + /* + * Boot ROM expects DK to be stored in big-endian byte order; + * since cpu is little-endian and client treats data as an NvU32, + * perform byte swapping here + */ + RegData = FUSE_NV_READ32(FUSE_PRIVATE_KEY4_0); + SWAP_BYTES_NVU32(RegData); + *((NvU32*)pData) = RegData; + break; + + case NvDdkFuseDataType_JtagDisable: + RegData = FUSE_NV_READ32(FUSE_ARM_DEBUG_DIS_0); + *((NvBool*)pData) = RegData ? NV_TRUE : NV_FALSE; + break; + + case NvDdkFuseDataType_KeyProgrammed: + *((NvBool*)pData) = IsSbkOrDkSet(); + break; + + case NvDdkFuseDataType_OdmProduction: + *((NvBool*)pData) = NvDdkFuseIsOdmProductionModeFuseSet(); + break; + + case NvDdkFuseDataType_SecBootDeviceConfig: + RegData = FUSE_NV_READ32(FUSE_BOOT_DEVICE_INFO_0); + RegData = NV_DRF_VAL(FUSE, + BOOT_DEVICE_INFO, + BOOT_DEVICE_CONFIG, + RegData); + + *((NvU32*)pData) = RegData; + break; + + case NvDdkFuseDataType_SecBootDeviceSelect: + RegData = (NvU32)NvDdkFuseGetSecBootDevice(); + *((NvU32*)pData) = RegData; + break; + + case NvDdkFuseDataType_SecBootDeviceSelectRaw: + RegData = NvDdkFuseGetSecBootDeviceRaw(); + *((NvU32*)pData) = RegData; + break; + + case NvDdkFuseDataType_SecureBootKey: + FuseCopyBytes(FUSE_PRIVATE_KEY0_0, + pData, + NVDDK_SECURE_BOOT_KEY_BYTES); + break; + + case NvDdkFuseDataType_Sku: + *((NvU32*)pData) = FUSE_NV_READ32(FUSE_SKU_INFO_0); + break; + + case NvDdkFuseDataType_SwReserved: + RegData = FUSE_NV_READ32(FUSE_RESERVED_SW_0); + RegData = NV_DRF_VAL(FUSE, RESERVED_SW, SW_RESERVED, RegData); + *((NvU32*)pData) = RegData; + break; + + case NvDdkFuseDataType_SkipDevSelStraps: + RegData = FUSE_NV_READ32(FUSE_RESERVED_SW_0); + RegData = NV_DRF_VAL(FUSE, RESERVED_SW, SKIP_DEV_SEL_STRAPS, RegData); + *((NvU32*)pData) = RegData; + break; + + case NvDdkFuseDataType_ReservedOdm: + FuseCopyBytes(FUSE_RESERVED_ODM0_0, + pData, + NVDDK_RESERVED_ODM_BYTES); + break; + + default: + NvOsMutexUnlock(s_pFuseRec->Mutex); + return(NvError_BadValue); + } + NvOsMutexUnlock(s_pFuseRec->Mutex); + return NvError_Success; +} +#endif + +#if ENABLE_FUSE_VOLTAGE +static NvRmDeviceHandle *ps_hRmDevice = NULL; +#endif +NvError NvDdkFuseOpen(NvRmDeviceHandle hRmDevice) +{ + NvError e; + + // Allocate memory for handle. + s_pFuseRec = NvOsAlloc(sizeof(NvDdkFuse)); + if (s_pFuseRec == NULL) + { + e = NvError_InsufficientMemory; + NvOsDebugPrintf("\r\n NvDdkFuseOpen malloc failed"); + return e; + } + + e = NvOsMutexCreate(&s_pFuseRec->Mutex); + if (e) + { + NvOsDebugPrintf("\r\n NvDdkFuseOpen Mutex creation failed"); + goto fail; + } + +#if ENABLE_FUSE_VOLTAGE + ps_hRmDevice = NvOsAlloc(sizeof(NvRmDeviceHandle)); + if (ps_hRmDevice == NULL) + { + e = NvError_InsufficientMemory; + NvOsDebugPrintf("\r\n NvDdkFuseOpen malloc failed"); + return e; + } + + *ps_hRmDevice = hRmDevice; +#endif + // Get the base address of the Fuse registers + NvRmModuleGetBaseAddress(hRmDevice, + NVRM_MODULE_ID(NvRmModuleID_Fuse, 0), + &(s_pFuseRec->pBaseAddress), &(s_pFuseRec->BankSize)); + NV_CHECK_ERROR_CLEANUP(NvRmPhysicalMemMap(s_pFuseRec->pBaseAddress, + s_pFuseRec->BankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, + (void **)&(s_pFuseRec->pVirtualAddress))); + + // Get the base address of the CAR registers + NvRmModuleGetBaseAddress(hRmDevice, + NVRM_MODULE_ID(NvRmPrivModuleID_ClockAndReset, 0), + &(s_pFuseRec->pCarBaseAddress), &(s_pFuseRec->CarBankSize)); + NV_CHECK_ERROR_CLEANUP(NvRmPhysicalMemMap(s_pFuseRec->pCarBaseAddress, + s_pFuseRec->CarBankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, + (void **)&(s_pFuseRec->pCarVirtualAddress))); + + return NvSuccess; +fail: + NvOsFree(s_pFuseRec); + return e; +} + +void NvDdkFuseClose() +{ + NvOsDebugPrintf("\r\n NvDdkFuseClose "); + NvOsMutexDestroy(s_pFuseRec->Mutex); + NvOsFree(s_pFuseRec); + s_pFuseRec = NULL; +} + +#if FUSE_DUMMY_CODE +NvError NvDdkFuseSet(NvDdkFuseDataType Type, void *pData, NvU32 *pSize) +{ +#if ENABLE_DEBUG_PRINTS + NvU8 i; + NvOsDebugPrintf("\n data to be written:"); + for(i = 0; i < *pSize; i++) + NvOsDebugPrintf("\t 0x%x", *((NvU8 *)pData + i)); +#endif + switch (Type) + { + case NvDdkFuseDataType_DeviceKey: + fusememcpy(DeviceKey, pData, sizeof(DeviceKey)); + break; + case NvDdkFuseDataType_JtagDisable: + fusememcpy(JtagDisable, pData, sizeof(JtagDisable)); + break; + case NvDdkFuseDataType_KeyProgrammed: + fusememcpy(KeyProgrammed, pData, sizeof(KeyProgrammed)); + break; + case NvDdkFuseDataType_OdmProduction: + fusememcpy(OdmProduction, pData, sizeof(OdmProduction)); + break; + case NvDdkFuseDataType_SecBootDeviceConfig: + fusememcpy(SecBootDeviceConfig, pData, sizeof(SecBootDeviceConfig)); + break; + case NvDdkFuseDataType_SecBootDeviceSelect: + fusememcpy(SecBootDeviceSelect, pData, sizeof(SecBootDeviceSelect)); + break; + case NvDdkFuseDataType_SecureBootKey: + fusememcpy(SecureBootKey, pData, sizeof(SecureBootKey)); + break; + case NvDdkFuseDataType_Sku: + fusememcpy(Sku, pData, sizeof(Sku)); + break; + case NvDdkFuseDataType_SpareBits: + fusememcpy(SpareBits, pData, sizeof(SpareBits)); + break; + case NvDdkFuseDataType_SwReserved: + fusememcpy(SwReserved, pData, sizeof(SwReserved)); + break; + case NvDdkFuseDataType_SkipDevSelStraps: + fusememcpy(SkipDevSelStraps, pData, sizeof(SkipDevSelStraps)); + break; + case NvDdkFuseDataType_SecBootDeviceSelectRaw: + fusememcpy(SecBootDeviceSelectRaw, pData, sizeof(SecBootDeviceSelectRaw)); + break; + case NvDdkFuseDataType_ReservedOdm: + fusememcpy(ReservedOdm, pData, sizeof(ReservedOdm)); + break; + default: + NvOsDebugPrintf("\r\n Invalid fuse type selected"); + break; + } + return NvSuccess; +} + +#else + +/** + * Schedule fuses to be programmed to the specified values when the next + * NvDdkFuseProgram() operation is performed + * + * By passing a size of zero, the caller is requesting to be told the + * expected size. + */ +#define FUSE_SET(name, flag) \ + case NvDdkFuseDataType_##name: \ + { \ + NvU8 *p = (NvU8 *)&(p_FuseData.name); \ + NvU32 i; \ + NvError e = NvSuccess; \ + /* read existing fuse value */ \ + e = NvDdkFuseGet(NvDdkFuseDataType_##name, p, &Size); \ + if (e != NvSuccess) \ + {\ + NvOsDebugPrintf("\r\n Err returned from Fuse Get:0x%x in Set",e); \ + return e; \ + }\ + /* check consistency between existing and desired fuse values. */ \ + /* fuses cannot be unburned, so desired value cannot specify */ \ + /* any unburned (0x0) bits where the existing value already */ \ + /* contains burned (0x1) bits. */ \ + for (i=0; i<Size; i++) \ + if ((p[i] | pDataPtr[i]) != pDataPtr[i]) \ + { \ + e = NvError_InvalidState; \ + NvOsDebugPrintf("\n p[%d] = 0x%x, pDataptr[%d] = 0x%x",i, p[i],i,*(NvU32*)pDataPtr); \ + NvOsDebugPrintf("\r\n Consistency check failure in Fuse Set:0x%x",e); \ + return e; \ + } \ + /* consistency check passed; schedule fuses to be burned */ \ + fusememcpy(&(s_FuseData.name), (void *)pDataPtr, Size); \ + s_FuseData.ProgramFlags |= FLAGS_PROGRAM_##flag; \ + } \ + break + +NvError NvDdkFuseSet(NvDdkFuseDataType Type, void *pData, NvU32 *pSize) +{ + NvError e = NvError_Success; + NvU32 Size; + NvU32 DataSizeArrayLen; + NvDdkFuseData p_FuseData; + volatile NvU8* pDataPtr = (volatile NvU8*)pData; + if(!s_pFuseRec) + { + // NV_ASSERT(0); + NvOsDebugPrintf("\r\n Plz call NvDdkFuseOpen before using this API"); + return 1; + } + NvOsMutexLock(s_pFuseRec->Mutex); + DataSizeArrayLen = ((sizeof(s_DataSize)) / (sizeof(NvU32))); + + if (Type == NvDdkFuseDataType_None || + (Type > (NvDdkFuseDataType)DataSizeArrayLen)) + { + e = NvError_BadValue; + NvOsDebugPrintf("\r\n NvDdkFuseDataType is incorrect"); + goto fail; + } + + if (pSize == NULL) + { + e = NvError_BadParameter; + goto fail; + } + + Size = s_DataSize[(NvU32)Type]; + + // Return the required size, if requested. + if (*pSize == 0) + { + *pSize = Size; + e = NvError_Success; + goto fail; + } + + if (*pSize > Size) + { + NvOsDebugPrintf("\n passed size = %d, fuse size = %d", *pSize, Size); + e = NvError_InsufficientMemory; + goto fail; + } + + if (pData == NULL) + { + e = NvError_BadParameter; + goto fail; + } + + /* + * If Disable Reg program is set, chip can not be fused, so return as + * "Access denied". + */ + if (NvDdkPrivIsDisableRegProgramSet()) + { + e = NvError_AccessDenied; + goto fail; + } + + + // Only reserved odm fuses are allowed to burn in secure mode + if (NvDdkFuseIsOdmProductionModeFuseSet() && + (Type != NvDdkFuseDataType_ReservedOdm)) + { + e = NvError_BadValue; + NvOsDebugPrintf("\r\n only reserved odm fuses are allowed to burn \ + in secure mode"); + goto fail; + } + + switch (Type) + { + FUSE_SET(DeviceKey, DEVICE_KEY ); + FUSE_SET(JtagDisable, JTAG_DISABLE ); + FUSE_SET(OdmProduction, ODM_PRODUCTION ); + FUSE_SET(SecBootDeviceConfig, BOOT_DEV_CONFIG ); + + case NvDdkFuseDataType_SecBootDeviceSelect: + case NvDdkFuseDataType_SecBootDeviceSelectRaw: + { + NvU8 *p = (NvU8 *)&(s_FuseData.SecBootDeviceSelectRaw); + NvU32 ApiData; // API symbolic value for device selection + NvU32 FuseData; // Raw fuse data for the device selection + + if (Type == NvDdkFuseDataType_SecBootDeviceSelect) + { + /* Read out the argument. */ + + fusememcpy(&(ApiData), pData, Size); + + if (ApiData == 0 || ApiData >= NvDdkSecBootDeviceType_Max) + { + e = NvError_BadValue; + NvOsDebugPrintf("\r\n ApiData is incorrect"); + goto fail; + } + + /* Map the symbolic value to a fuse value. */ + FuseData = NvDdkToFuseBootDeviceSel[ApiData]; + } + else + { + /* + * Type == NvDdkFuseDataType_SecBootDeviceSelectRaw + * Read out the argument. + */ + fusememcpy(&(FuseData), pData, Size); + if (FuseData >= FuseBootDev_Max) + { + e = NvError_BadValue; + NvOsDebugPrintf("\r\n FuseData is incorrect"); + goto fail; + } + + /* Map the fuse value to a symbolic value */ + ApiData = FuseToNvDdkBootDeviceSel[FuseData]; + } + + /* read existing fuse value */ + NV_CHECK_ERROR(NvDdkFuseGet(NvDdkFuseDataType_SecBootDeviceSelectRaw, + p, &Size)); + + /* + * Check consistency between existing and desired fuse values. + * fuses cannot be unburned, so desired value cannot specify + * any unburned (0x0) bits where the existing value already + * contains burned (0x1) bits. + */ + if ((s_FuseData.SecBootDeviceSelectRaw | FuseData) != FuseData) + { + e = NvError_InvalidState; + goto fail; + } + + + /* Consistency check passed; schedule fuses to be burned */ + s_FuseData.SecBootDeviceSelect = ApiData; + s_FuseData.SecBootDeviceSelectRaw = FuseData; + s_FuseData.ProgramFlags |= FLAGS_PROGRAM_BOOT_DEV_SEL; + } + break; + + FUSE_SET(SecureBootKey, SECURE_BOOT_KEY ); + FUSE_SET(SwReserved, SW_RESERVED ); + FUSE_SET(SkipDevSelStraps, SKIP_DEV_SEL_STRAPS ); + FUSE_SET(ReservedOdm, RESERVED_ODM ); + + default: + { + e = NvError_BadValue; + NvOsDebugPrintf("\r\n Entered default case"); + goto fail; + } + } + // Set the ReservOdm flag if it present + if (Type == NvDdkFuseDataType_ReservedOdm) + { + s_FuseData.ReservedOdmFlag = NV_TRUE; + } + + // Check for invalid state combinations. + if ((s_FuseData.ProgramFlags & FLAGS_PROGRAM_ODM_PRODUCTION) && + (s_FuseData.ProgramFlags & (FLAGS_PROGRAM_SECURE_BOOT_KEY | + FLAGS_PROGRAM_DEVICE_KEY))) + { + s_FuseData.ProgramFlags |= FLAGS_PROGRAM_ILLEGAL; + } + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_ILLEGAL) + { + e = NvError_InvalidState; + goto fail; + } + +fail: + NvOsMutexUnlock(s_pFuseRec->Mutex); + if (e != NvSuccess) + NvOsDebugPrintf("\r\n NvDdkFuseSet exit with err value e = 0x%x",e); + return e; +} +#endif + +#if FUSE_DUMMY_CODE +NvError NvDdkFuseProgram(void) +{ + +} +#else +#if ENABLE_FUSE_VOLTAGE +static void EnableFuseVoltage(void) +{ + const NvOdmPeripheralConnectivity *pConnectivity = NULL; + NvRmPmuVddRailCapabilities RailCaps; + NvU32 i; + + pConnectivity = NvOdmPeripheralGetGuid(NV_VDD_FUSE_ODM_ID); + if (pConnectivity != NULL) + { + for (i = 0; i < pConnectivity->NumAddress; i++) + { + // Search for the vdd rail entry + if (pConnectivity->AddressList[i].Interface == NvOdmIoModule_Vdd) + { + NvRmPmuGetCapabilities((*ps_hRmDevice), + pConnectivity->AddressList[i].Address, &RailCaps); + + NvRmPmuSetVoltage((*ps_hRmDevice), + pConnectivity->AddressList[i].Address, + RailCaps.requestMilliVolts, NULL); + } + } + } +} +#endif +/** + * Program all fuses based on cache data changed via the NvDdkFuseSet() API. + * + * Caller is responsible for supplying valid fuse programming voltage prior to + * invoking this routine. + * + * NOTE: All values that are not intended to be programmed must have + * value 0. There is no need to conditionalize this code based on which + * logical values were actually set through the API. + */ +NvError NvDdkFuseProgram(void) +{ + if(!s_pFuseRec) + { + NvOsDebugPrintf("\r\n Plz call NvDdkFuseOpen before using this API"); + return 1; + } +#if ENABLE_FUSE_VOLTAGE + EnableFuseVoltage(); +#endif + NvOsMutexLock(s_pFuseRec->Mutex); + /* + * Validate the current state. + * If Secure mode is already burned, only reserved odm fuses are allowed to burn + */ + if (NvDdkFuseIsOdmProductionModeFuseSet() && (!s_FuseData.ReservedOdmFlag)) + { + NvOsDebugPrintf("\r\n NvDdkFuseProgram err - InvalidState"); + return NvError_InvalidState; + } + /* + * If Disable Reg program is set, chip can not be fused, so return as + * "Access denied". + */ + if (NvDdkPrivIsDisableRegProgramSet()) + { + NvOsDebugPrintf("\r\n NvDdkFuseProgram err - AccessDenied"); + return NvError_AccessDenied; + } + + if (s_FuseData.ProgramFlags & FLAGS_PROGRAM_ILLEGAL) + { + NvOsDebugPrintf("\r\n NvDdkFuseProgram err - InvalidState"); + return NvError_InvalidState; + } + + // Map data onto a fuse array. + MapDataToFuseArrays(); + NvDdkFuseProgramFuseArray(s_FuseArray, s_MaskArray, FUSE_WORDS, + NVDDK_TPROGRAM_VALUE_CORRECTED); + NvOsMutexUnlock(s_pFuseRec->Mutex); + // Clear reserved odm flag + s_FuseData.ReservedOdmFlag = NV_FALSE; + return NvError_Success; +} +#endif + +#if FUSE_DUMMY_CODE +NvError NvDdkFuseVerify(void) +{} +#else +/** + * Verify all fuses scheduled via the NvDdkFuseSet*() API's + */ + +NvError NvDdkFuseVerify(void) +{ + NvError e = NvError_Success; + if(!s_pFuseRec) + { + NvOsDebugPrintf("\r\n Plz call NvDdkFuseOpen before using this API"); + return 1; + } + NvOsMutexLock(s_pFuseRec->Mutex); + // Map data onto a fuse array. + MapDataToFuseArrays(); + // Check to see if the data matches the real fuses. + e = NvDdkFuseVerifyFuseArray(s_FuseArray, s_MaskArray, FUSE_WORDS); + NvOsMutexUnlock(s_pFuseRec->Mutex); + if (e != NvError_Success) + { + e = NvError_InvalidState; + NvOsDebugPrintf("\r\n NvDdkFuseVerify returning modified err:0x%x",e); + } + return e; +} +#endif +/* + * NvDdkDisableFuseProgram API disables the fuse programming until the next + * next system reset. + */ + +void NvDdkDisableFuseProgram(void) +{ + NvU32 RegData; + if(!s_pFuseRec) + { + // NV_ASSERT(0); + NvOsDebugPrintf("\r\n Plz call NvDdkFuseOpen before using this API"); + return; + } + NvOsMutexLock(s_pFuseRec->Mutex); + RegData = NV_DRF_DEF(FUSE, DISABLEREGPROGRAM, DISABLEREGPROGRAM_VAL, ENABLE); + FUSE_NV_WRITE32(FUSE_DISABLEREGPROGRAM_0, RegData); + NvOsMutexUnlock(s_pFuseRec->Mutex); +} + +/** @} */ diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b.c index 285044034f97..fdd3b3eeffa1 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b.c +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b.c @@ -141,7 +141,7 @@ static const NvU32 VoltageTable_VOUT_02[] = { // Specifies the time between each sequencer event. // Disable temporarily to keep the compiler happy. -//static const NvU32 SequencerPeriod[] = { 20, 40, 80, 160, 320, 640, 1280, 2560 }; +//static const NvU32 SequencerPeriod[] = {20, 40, 80, 160, 320, 640, 1280, 2560}; /*-- Voltage translation functions --*/ @@ -1055,6 +1055,25 @@ const Max8907bPmuSupplyInfo Max8907bSupplyInfoTable[] = AD5258_VMAX, MAX8907B_REQUESTVOLTAGE_LX_V1 }, + }, + + // FUSE Vcc is wired from VBAT. + { + Max8907bPmuSupply_VBAT_FUSE, + TCA6416_CONFIG_PORT_0, + TCA6416_INVALID_PORT, + TCA6416_INVALID_PORT, + TCA6416_PORT_0, + TCA6416_PIN_2, + NULL, + NULL, + { + NV_FALSE, + FAN5355_MIN_OUTPUT_VOLTAGE_x10/10, + FAN5355_OUTPUT_VOLTAGE_INCREMENT_x10/10, + FAN5355_MAX_OUTPUT_VOLTAGE_x10/10, + MAX8907B_REQUESTVOLTAGE_EXT_DCDC_3 + }, } }; @@ -1786,6 +1805,39 @@ Tca6416UsbVbusControl( return NV_TRUE; } +static NvBool +Tca6416FuseControl( + NvOdmPmuDeviceHandle hDevice, + NvU32 vddRail, + NvU32 MilliVolts) +{ + const Max8907bPmuSupplyInfo *pSupplyInfo = &Max8907bSupplyInfoTable[vddRail]; + NvU32 PortNo; + NvU32 PinNo; + + // Get port number and pin number + PortNo = pSupplyInfo->OutputPort; + PinNo = pSupplyInfo->PmuGpio; + + // Configure port pin as output + if (!Tca6416ConfigPortPin(hDevice, PortNo, PinNo, GpioPinMode_Output)) + return NV_FALSE; + + if (MilliVolts == ODM_VOLTAGE_OFF) // to disable FUSE voltage + { + // Set Low on pin + if (!Tca6416WritePortPin(hDevice, PortNo, PinNo, GpioPinState_Low)) + return NV_FALSE; + } + else // to Enable FUSE voltage + { + // Set high on pin + if (!Tca6416WritePortPin(hDevice, PortNo, PinNo, GpioPinState_High)) + return NV_FALSE; + } + return NV_TRUE; +} + NvBool Max8907bSetVoltage( NvOdmPmuDeviceHandle hDevice, @@ -1802,6 +1854,15 @@ Max8907bSetVoltage( return NV_TRUE; } + if (vddRail == Max8907bPmuSupply_VBAT_FUSE) + { + // Enable fuse voltage + if (!Tca6416FuseControl(hDevice, vddRail, MilliVolts)) + return NV_FALSE; + + return NV_TRUE; + } + if ((MilliVolts == ODM_VOLTAGE_ENABLE_EXT_ONOFF) || (MilliVolts == ODM_VOLTAGE_DISABLE_EXT_ONOFF)) { diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_supply_info_table.h b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_supply_info_table.h index 1b362aac43f4..77cf70bc32b5 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_supply_info_table.h +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_supply_info_table.h @@ -29,7 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. * */ - + #ifndef INCLUDED_MAX8907B_SUPPLY_INFO_HEADER #define INCLUDED_MAX8907B_SUPPLY_INFO_HEADER @@ -86,7 +86,7 @@ extern "C" // Defines common for all supplies I2C (s/w) sequencer selection #define MAX8907B_SEQSEL_I2CEN_LXX 7 /* I2CEN (s/w) */ -// Defines sequencer count default values +// Defines sequencer count default values #define MAX8907B_SEQCNT_DEFAULT_LX_V1 0x1C #define MAX8907B_SEQCNT_DEFAULT_LX_V2 0x1C @@ -156,7 +156,7 @@ typedef enum Max8907bPmuSupply_EXT_DCDC_3_USB1, //USB1 VBUS Max8907bPmuSupply_EXT_DCDC_3_USB3, // USB3 VBUS - /** Secondary PMU MIC2826 Rails **/ + /** Secondary PMU MIC2826 Rails **/ MIC2826PmuSupply_BUCK, MIC2826PmuSupply_LDO1, MIC2826PmuSupply_LDO2, @@ -166,6 +166,9 @@ typedef enum // potentiometer (DPM) AD5258 Max8907bLxV1_Ad5258_DPM_EXT_DCDC_7, + //Temp for enabling fuse using p2 of i0 expander + Max8907bPmuSupply_VBAT_FUSE, + Max8907bPmuSupply_Num, Max8907bPmuSupply_Force32 = 0x7FFFFFFF } Max8907bPmuSupply; @@ -192,6 +195,5 @@ typedef struct Max8907bPmuSupplyInfoRec #if defined(__cplusplus) } #endif - #endif //INCLUDED_MAX8907B_SUPPLY_INFO_HEADER diff --git a/arch/arm/mach-tegra/odm_kit/query/whistler/subboards/nvodm_query_discovery_e1116_addresses.h b/arch/arm/mach-tegra/odm_kit/query/whistler/subboards/nvodm_query_discovery_e1116_addresses.h index 2b5ca7f8bacd..7c3d38f7c04d 100644 --- a/arch/arm/mach-tegra/odm_kit/query/whistler/subboards/nvodm_query_discovery_e1116_addresses.h +++ b/arch/arm/mach-tegra/odm_kit/query/whistler/subboards/nvodm_query_discovery_e1116_addresses.h @@ -30,13 +30,12 @@ * */ - /** * @file * <b>NVIDIA APX ODM Kit:: * Implementation of the ODM Peripheral Discovery API</b> * - * @b Description: Specifies the peripheral connectivity + * @b Description: Specifies the peripheral connectivity * database NvOdmIoAddress entries for the E1116 * Power module. */ @@ -44,227 +43,233 @@ #include "pmu/max8907b/max8907b_supply_info_table.h" // Persistent voltage rail (ie, for RTC, Standby, etc...) -static const NvOdmIoAddress s_ffaRtcAddresses[] = +static const NvOdmIoAddress s_ffaRtcAddresses[] = { // On Maxim 8907B, the standby rail automatically follows V2 { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V2 } /* VDD_RTC -> RTC */ }; // Core voltage rail -static const NvOdmIoAddress s_ffaCoreAddresses[] = +static const NvOdmIoAddress s_ffaCoreAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V2 } /* VDD_CORE -> V2 */ }; // PMU CPU voltage rail -static const NvOdmIoAddress s_ffaCpuAddresses[] = +static const NvOdmIoAddress s_ffaCpuAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V1 } /* VDD_CPU_PMU -> V1 */ }; // External CPU DCDC voltage rail -static const NvOdmIoAddress s_ffaCpuExtSupplyAddresses[] = +static const NvOdmIoAddress s_ffaCpuExtSupplyAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bLxV1_Ad5258_DPM_EXT_DCDC_7 } /* VDD_CPU_PMU -> DCDC7 */ }; // PLLA voltage rail -static const NvOdmIoAddress s_ffaPllAAddresses[] = +static const NvOdmIoAddress s_ffaPllAAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO2 } /* AVDD_PLLA_P_C_S -> VOUT2 */ }; // PLLM voltage rail -static const NvOdmIoAddress s_ffaPllMAddresses[] = +static const NvOdmIoAddress s_ffaPllMAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO2 } /* AVDD_PLLM -> VOUT2 */ }; // PLLP voltage rail -static const NvOdmIoAddress s_ffaPllPAddresses[] = +static const NvOdmIoAddress s_ffaPllPAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO2 } /* AVDD_PLLA_P_C_S -> VOUT2 */ }; // PLLC voltage rail -static const NvOdmIoAddress s_ffaPllCAddresses[] = +static const NvOdmIoAddress s_ffaPllCAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO2 } /* AVDD_PLLA_P_C_S -> VOUT2 */ }; // PLLE voltage rail -static const NvOdmIoAddress s_ffaPllEAddresses[] = +static const NvOdmIoAddress s_ffaPllEAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO2 } /* AVDD_PLL_E -> VOUT2 */ }; // PLLU1 voltage rail -static const NvOdmIoAddress s_ffaPllU1Addresses[] = +static const NvOdmIoAddress s_ffaPllU1Addresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO2 } /* AVDD_PLLU -> VOUT2 */ }; // PLLS voltage rail -static const NvOdmIoAddress s_ffaPllSAddresses[] = +static const NvOdmIoAddress s_ffaPllSAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO2 } /* AVDD_PLLA_P_C_S -> VOUT2 */ }; // PLLHD voltage rail -static const NvOdmIoAddress s_ffaPllHdmiAddresses[] = +static const NvOdmIoAddress s_ffaPllHdmiAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO6 } /* AVDD_HDMI_PLL -> VOUT6 */ }; // OSC voltage rail -static const NvOdmIoAddress s_ffaVddOscAddresses[] = +static const NvOdmIoAddress s_ffaVddOscAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V3 } /* AVDD_OSC -> V3 */ }; // PLLX voltage rail -static const NvOdmIoAddress s_ffaPllXAddresses[] = +static const NvOdmIoAddress s_ffaPllXAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO2 } /* AVDD_PLLX -> VOUT2 */ }; // PLL_USB voltage rail -static const NvOdmIoAddress s_ffaPllUsbAddresses[] = +static const NvOdmIoAddress s_ffaPllUsbAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO4 } /* AVDD_USB_PLL -> VOUT4 */ }; // SYS IO voltage rail -static const NvOdmIoAddress s_ffaVddSysAddresses[] = +static const NvOdmIoAddress s_ffaVddSysAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V3 } /* VDDIO_SYS -> V3 */ }; // USB voltage rail -static const NvOdmIoAddress s_ffaVddUsbAddresses[] = +static const NvOdmIoAddress s_ffaVddUsbAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO4 } /* AVDD_USB -> VOUT4 */ }; // HDMI voltage rail -static const NvOdmIoAddress s_ffaVddHdmiAddresses[] = +static const NvOdmIoAddress s_ffaVddHdmiAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO11 } /* AVDD_HDMI -> VOUT11 */ }; // MIPI voltage rail -static const NvOdmIoAddress s_ffaVddMipiAddresses[] = +static const NvOdmIoAddress s_ffaVddMipiAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO17 } /* VDDIO_MIPI -> VOUT17 */ }; // LCD voltage rail -static const NvOdmIoAddress s_ffaVddLcdAddresses[] = +static const NvOdmIoAddress s_ffaVddLcdAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V3 } /* VDDIO_LCD_PMU -> V3 */ }; // Audio voltage rail -static const NvOdmIoAddress s_ffaVddAudAddresses[] = +static const NvOdmIoAddress s_ffaVddAudAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V3 } /* VDDIO_AUDIO -> V3 */ }; // LPDDR2 voltage rail (default) -static const NvOdmIoAddress s_ffaVddDdrAddresses[] = +static const NvOdmIoAddress s_ffaVddDdrAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO20 } /* VDDIO_DDR_1V2 -> VOUT20 */ }; // DDR2 voltage rail (on E1109 board ext 1.8V DCDC is controlled by LDO5) -static const NvOdmIoAddress s_ffaVddDdr2Addresses[] = +static const NvOdmIoAddress s_ffaVddDdr2Addresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO5 } /* VDDIO_DDR_1V8 -> VOUT05 */ }; // DDR_RX voltage rail -static const NvOdmIoAddress s_ffaVddDdrRxAddresses[] = +static const NvOdmIoAddress s_ffaVddDdrRxAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO1 } /* VDDIO_RX_DDR(2.7-3.3) -> VOUT1 */ }; // NAND voltage rail -static const NvOdmIoAddress s_ffaVddNandAddresses[] = +static const NvOdmIoAddress s_ffaVddNandAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V3 } /* VDDIO_NAND_PMU -> V3 */ }; // UART voltage rail -static const NvOdmIoAddress s_ffaVddUartAddresses[] = +static const NvOdmIoAddress s_ffaVddUartAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V3 } /* VDDIO_UART -> V3 */ }; // SDIO voltage rail -static const NvOdmIoAddress s_ffaVddSdioAddresses[] = +static const NvOdmIoAddress s_ffaVddSdioAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO12 } /* VDDIO_SDIO -> VOUT12 */ }; // VDAC voltage rail -static const NvOdmIoAddress s_ffaVddVdacAddresses[] = +static const NvOdmIoAddress s_ffaVddVdacAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO14 } /* AVDD_VDAC -> VOUT14 */ }; // VI voltage rail -static const NvOdmIoAddress s_ffaVddViAddresses[] = +static const NvOdmIoAddress s_ffaVddViAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO18 } /* VDDIO_VI -> VOUT18 */ }; // BB voltage rail -static const NvOdmIoAddress s_ffaVddBbAddresses[] = +static const NvOdmIoAddress s_ffaVddBbAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V3 } /* VDDIO_BB -> V3 */ }; // HSIC voltage rail -static const NvOdmIoAddress s_ffaVddHsicAddresses[] = +static const NvOdmIoAddress s_ffaVddHsicAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO20 } /* VDDIO_HSIC -> VOUT20 */ }; // USB_IC voltage rail -static const NvOdmIoAddress s_ffaVddUsbIcAddresses[] = +static const NvOdmIoAddress s_ffaVddUsbIcAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LX_V3 } /* AVDD_USB_IC -> V3 */ }; // PEX_CLK voltage rail -static const NvOdmIoAddress s_ffaVddPexClkAddresses[] = +static const NvOdmIoAddress s_ffaVddPexClkAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO11 }, /* VDDIO_PEX_CLK -> VOUT11 */ { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_LDO12 }, /* VDDIO_PEX_CLK -> VOUT12 */ - { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_EXT_DCDC_3 } + { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_EXT_DCDC_3 } }; // PMU0 -static const NvOdmIoAddress s_Pmu0Addresses[] = +static const NvOdmIoAddress s_Pmu0Addresses[] = { { NvOdmIoModule_I2c_Pmu, 0x00, 0x78 }, }; // I2C IO Expander -static const NvOdmIoAddress s_I2cioexpanderAddress[] = +static const NvOdmIoAddress s_I2cioexpanderAddress[] = { { NvOdmIoModule_I2c_Pmu, 0x00, 0x40 }, }; // USB1 VBus voltage rail -static const NvOdmIoAddress s_ffaVddUsb1VBusAddresses[] = +static const NvOdmIoAddress s_ffaVddUsb1VBusAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_EXT_DCDC_3_USB1 }, }; // USB3 VBus voltage rail -static const NvOdmIoAddress s_ffaVddUsb3VBusAddresses[] = +static const NvOdmIoAddress s_ffaVddUsb3VBusAddresses[] = { { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_EXT_DCDC_3_USB3 }, }; +// FUSE voltage enablel +static const NvOdmIoAddress s_ffaVddFuseAddresses[] = +{ + { NvOdmIoModule_Vdd, 0x00, Max8907bPmuSupply_VBAT_FUSE }, +}; + diff --git a/arch/arm/mach-tegra/odm_kit/query/whistler/subboards/nvodm_query_discovery_e1116_peripherals.h b/arch/arm/mach-tegra/odm_kit/query/whistler/subboards/nvodm_query_discovery_e1116_peripherals.h index 5145bf5b0711..1fe3f615226b 100644 --- a/arch/arm/mach-tegra/odm_kit/query/whistler/subboards/nvodm_query_discovery_e1116_peripherals.h +++ b/arch/arm/mach-tegra/odm_kit/query/whistler/subboards/nvodm_query_discovery_e1116_peripherals.h @@ -35,7 +35,7 @@ * <b>NVIDIA APX ODM Kit:: * Implementation of the ODM Peripheral Discovery API</b> * - * @b Description: Specifies the peripheral connectivity + * @b Description: Specifies the peripheral connectivity * database Peripheral entries for the E1116 * power module. */ @@ -51,8 +51,7 @@ NV_ARRAY_SIZE(s_ffaPllU1Addresses), NvOdmPeripheralClass_Other }, -// -------- END WHISTLER_AP16_ONLY -------- - +// -------- END WHISTLER_AP16_ONLY -------- // RTC (NV reserved) { @@ -208,6 +207,13 @@ NvOdmPeripheralClass_Other }, +// Fuse +{ + NV_VDD_FUSE_ODM_ID, + s_ffaVddFuseAddresses, + NV_ARRAY_SIZE(s_ffaVddFuseAddresses), + NvOdmPeripheralClass_Other +}, // HDMI VDD (NV reserved) { diff --git a/arch/arm/mach-tegra/sysfs-fuse.c b/arch/arm/mach-tegra/sysfs-fuse.c new file mode 100644 index 000000000000..d32d098972ab --- /dev/null +++ b/arch/arm/mach-tegra/sysfs-fuse.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2010 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sysfs.h> +#include <linux/kobject.h> +#include "nvddk_fuse.h" +#include "mach/nvrm_linux.h" + +#define SYSFS_FUSE_DEBUG_PRINTS 0 + +#if SYSFS_FUSE_DEBUG_PRINTS +#define PRINT_FUSE(x) printk x +#else +#define PRINT_FUSE(x) +#endif + +#define BUF_SIZE 66 // Max_fuse_size(32) * AsciiCharsPerFuseByte(2) + \n\0 (2) + +static struct kobject *nvfuse_kobj; + +typedef enum +{ + TegraFuseSizeInBytes_DeviceKey = 4, + TegraFuseSizeInBytes_JtagDisable = 1, // 1 bit + TegraFuseSizeInBytes_KeyProgrammed = 1, + TegraFuseSizeInBytes_OdmProduction = 1, // 1 bit + TegraFuseSizeInBytes_SecBootDeviceConfig = 2, // 14 bits + TegraFuseSizeInBytes_SecBootDeviceSelect = 1, // 3 bits + TegraFuseSizeInBytes_SecureBootKey = 16, + TegraFuseSizeInBytes_Sku = 4, + TegraFuseSizeInBytes_SpareBits = 4, + TegraFuseSizeInBytes_SwReserved = 1, // 4 bit + TegraFuseSizeInBytes_SkipDevSelStraps = 1, // 1 bit + TegraFuseSizeInBytes_SecBootDeviceSelectRaw = 4, + TegraFuseSizeInBytes_ReservedOdm = 32 +} TegraFuseSizeInBytes; + + +static ssize_t sysfsfuse_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static ssize_t sysfsfuse_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + + +static struct kobj_attribute nvfuse_DeviceKey_attr = + __ATTR(DeviceKey, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_JtagDisable_attr = + __ATTR(JtagDisable, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_KeyProgrammed_attr = + __ATTR(KeyProgrammed, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_OdmProduction_attr = + __ATTR(OdmProduction, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_SecBootDeviceConfig_attr = + __ATTR(SecBootDeviceConfig, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_SecBootDeviceSelect_attr = + __ATTR(SecBootDeviceSelect, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_SecureBootKey_attr = + __ATTR(SecureBootKey, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_sku_attr = + __ATTR(sku, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_SpareBits_attr = + __ATTR(SpareBits, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_SwReserved_attr = + __ATTR(SwReserved, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_SkipDevSelStraps_attr = + __ATTR(SkipDevSelStraps, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_SecBootDeviceSelectRaw_attr = + __ATTR(SecBootDeviceSelectRaw, 0440, sysfsfuse_show, sysfsfuse_store); + +static struct kobj_attribute nvfuse_ReservedOdm_attr = + __ATTR(ReservedOdm, 0440, sysfsfuse_show, sysfsfuse_store); + + + +// return the fuse type based on the fuse name. +NvDdkFuseDataType GetFuseType(const char *str, unsigned int* pSize) +{ + NvDdkFuseDataType type; + + if(!strcmp(str, "DeviceKey")) + { + type = NvDdkFuseDataType_DeviceKey; + *pSize = TegraFuseSizeInBytes_DeviceKey; + } + else if (!strcmp(str, "JtagDisable")) + { + type = NvDdkFuseDataType_JtagDisable; + *pSize = TegraFuseSizeInBytes_JtagDisable; + } + else if (!strcmp(str, "KeyProgrammed")) + { + type = NvDdkFuseDataType_KeyProgrammed; + *pSize = TegraFuseSizeInBytes_KeyProgrammed; + } + else if (!strcmp(str, "OdmProduction")) + { + type = NvDdkFuseDataType_OdmProduction; + *pSize = TegraFuseSizeInBytes_OdmProduction; + } + else if (!strcmp(str, "SecBootDeviceConfig")) + { + type = NvDdkFuseDataType_SecBootDeviceConfig; + *pSize = TegraFuseSizeInBytes_SecBootDeviceConfig; + } + else if (!strcmp(str, "SecBootDeviceSelect")) + { + type = NvDdkFuseDataType_SecBootDeviceSelect; + *pSize = TegraFuseSizeInBytes_SecBootDeviceSelect; + } + else if (!strcmp(str, "SecureBootKey")) + { + type = NvDdkFuseDataType_SecureBootKey; + *pSize = TegraFuseSizeInBytes_SecureBootKey; + } + else if (!strcmp(str, "sku")) + { + type = NvDdkFuseDataType_Sku; + *pSize = TegraFuseSizeInBytes_Sku; + } + else if (!strcmp(str, "SpareBits")) + { + type = NvDdkFuseDataType_SpareBits; + *pSize = TegraFuseSizeInBytes_SpareBits; + } + else if (!strcmp(str, "SwReserved")) + { + type = NvDdkFuseDataType_SwReserved; + *pSize = TegraFuseSizeInBytes_SwReserved; + } + else if (!strcmp(str, "SkipDevSelStraps")) + { + type = NvDdkFuseDataType_SkipDevSelStraps; + *pSize = TegraFuseSizeInBytes_SkipDevSelStraps; + } + else if (!strcmp(str, "SecBootDeviceSelectRaw")) + { + type = NvDdkFuseDataType_SecBootDeviceSelectRaw; + *pSize = TegraFuseSizeInBytes_SecBootDeviceSelectRaw; + } + else if (!strcmp(str, "ReservedOdm")) + { + type = NvDdkFuseDataType_ReservedOdm; + *pSize = TegraFuseSizeInBytes_ReservedOdm; + } + else + { + type = NvDdkFuseDataType_None; + PRINT_FUSE(("\r\n Invalid Fuse type:%s... Find out reason\r",str)); + } + return type; +} + +/* + * return values: + * 0 - ODM production fuse is not blown + * 1 - ODM production fuse is blown + * 2 - Fuse Get API returned error + */ +static char OdmProductionFuseVal(void) +{ + NvU8 FuseVal = 0; + NvError Err; + NvU32 size = 1; + + // check if ODM production fuse is burned already. If so, return here. + Err = NvDdkFuseGet(NvDdkFuseDataType_OdmProduction, &FuseVal, &size); + if (Err != NvSuccess) + { + PRINT_FUSE(("\r\n NvDdkFuseGet failed in sysfsfuse_store\n")); + return 2; + } + if (FuseVal) + { + PRINT_FUSE(("\r\n ODM production fuse is already blown\n")); + return 1; + } + else + return 0; +} + +void IntToStr(char *arr, char *str, unsigned int MaxSize) +{ + int i = 0, j = 0; + char tmp[BUF_SIZE]={0}; + strcpy(tmp,"0"); + + for(i = 0; i < MaxSize; i++) + { + if ((arr[i] == 0) && (j==0)) + continue; + + sprintf(&tmp[j*2],"%02X",arr[i]); + j++; + } + strcat(tmp,"\n"); + + // if first char contains 0, skip it. + if ((*tmp == '0') && (j != 0)) + { + strcpy(str, &tmp[1]); + } + else + strcpy(str, &tmp[0]); + + PRINT_FUSE(("\n string out: %s \n",str)); +} + +static ssize_t sysfsfuse_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ +#if SYSFS_FUSE_DEBUG_PRINTS + unsigned char i = 0; +#endif + unsigned int size = 0; + NvError Err; + NvDdkFuseDataType FuseType; + char ReadFuseBuf[BUF_SIZE]; + char OdmProdFuseVal = 0; + + FuseType = GetFuseType(attr->attr.name, &size); + + // Reading SecureBootKey should be allowed only till ODM production is not blown + if (FuseType == NvDdkFuseDataType_SecureBootKey) + { + OdmProdFuseVal = OdmProductionFuseVal(); + if(OdmProdFuseVal == 1) + { + PRINT_FUSE(("\r\n ODM production fuse is already blown\n")); + return 0; + } + } + + NvDdkFuseSense(); + NvDdkFuseClear(); + Err = NvDdkFuseGet(FuseType, ReadFuseBuf, &size); + if (Err != NvSuccess) + { + PRINT_FUSE(("\r\n NvDdkFuseGet failed in sysfsfuse_show 2\n")); + return 0; + } + IntToStr(ReadFuseBuf, buf, size); +#if SYSFS_FUSE_DEBUG_PRINTS + if (Err == NvSuccess) + PRINT_FUSE(("\n Fuse Get success \n")); + else + PRINT_FUSE(("\n Fuse Get failed Err: 0x%x \n",Err)); + PRINT_FUSE(("\n\n Data read from Fuse:\n")); + for (i = 0; i < size; i++) + PRINT_FUSE((" 0x%x",ReadFuseBuf[i])); +#endif + return (strlen(buf)); +} + +void StrToInt(const char *str, + char *arr, unsigned char NumChars, unsigned int MaxSize) +{ + int i = 0, j = 0; + char tmp[BUF_SIZE]={0}; + unsigned char Iterations = (NumChars + 1)/2; + unsigned int t; + for(j = 0; j < (MaxSize - Iterations); j++) + { + arr[j] = 0; + } + for(i = 0; i < Iterations; i++) + { + if (NumChars & 1) + { + if (!i) + strncpy(tmp, &str[0], 1); + else + strncpy(tmp, &str[i*2 - 1], 2); + } + else + strncpy(tmp, &str[i*2], 2); + sscanf(tmp,"%02X",&t); + arr[j++]=(char)t; + } + + PRINT_FUSE(("\r\n Input string after conversion to int: 0x%x", *arr)); +} + +static ssize_t sysfsfuse_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret; + unsigned int size = 0; + NvDdkFuseDataType FuseType; + NvError Err; + char WriteFuseBuf[BUF_SIZE]; +#if SYSFS_FUSE_DEBUG_PRINTS + unsigned char i = 0; +#endif + unsigned char OdmProdFuseVal = 0; + + OdmProdFuseVal = OdmProductionFuseVal(); + if(OdmProdFuseVal == 1) + { + PRINT_FUSE(("\r\n ODM production fuse is already blown\n")); + return 0; + } + + FuseType = GetFuseType(attr->attr.name, &size); + + // As count includes data bytes followed by 0xA (line feed character) + // and two chars can be stored in a fuse byte + if ((count - 1) > (2 * size)) + { + PRINT_FUSE(("\r\n Requested data size[%d] > fuse size [%d]\n",count/2,size)); + return 0; + } + + if (buf != NULL) + { + StrToInt(buf, WriteFuseBuf, (count - 1), size); + } + else + printk("\r\n buf is NULL"); + + PRINT_FUSE(("\r\n Input string: %s", buf)); + PRINT_FUSE(("\n Fuse data of size [%d] to write\n", size)); +#if SYSFS_FUSE_DEBUG_PRINTS + for (i = 0; i < size; i++) + PRINT_FUSE(("0x%x\n",WriteFuseBuf[i])); +#endif + NvDdkFuseClear(); + Err = NvDdkFuseSet(FuseType, WriteFuseBuf, &size); + if (Err == NvSuccess) + { + NvDdkFuseProgram(); + NvDdkFuseSense(); + NvDdkFuseVerify(); + } + else + { + PRINT_FUSE(("\r\n Fuse programming failed with error 0x%x",Err)); + } + if (Err == NvSuccess) + { + ret = count; + // if ODM production fuse is blown, change file permissions to 0440 + if (FuseType == NvDdkFuseDataType_OdmProduction) + { + sysfs_chmod_file(kobj, &attr->attr, 0440); + + sysfs_chmod_file(kobj, &nvfuse_DeviceKey_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_JtagDisable_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_OdmProduction_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_SecBootDeviceConfig_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_SecBootDeviceSelect_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_SecureBootKey_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_SwReserved_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_SkipDevSelStraps_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_SecBootDeviceSelectRaw_attr.attr, 0440); + sysfs_chmod_file(kobj, &nvfuse_ReservedOdm_attr.attr, 0440); + } + PRINT_FUSE(("\r\n fuse set success \n")); + } + else + { + ret = 0; + PRINT_FUSE(("\r\n fuse set failed Err: 0x%x\n", Err)); + } + + return ret; +} + +#define CHK_ERR(x) \ +{ \ + if(x) \ + { \ + PRINT_FUSE(("Fuse: sysfs_create_file failed!")); \ + return x; \ + } \ +} + +static int __init sysfsfuse_init(void) +{ + nvfuse_kobj = kobject_create_and_add("fuse", firmware_kobj); + PRINT_FUSE(("\n Fuse Init")); + + CHK_ERR(NvDdkFuseOpen(s_hRmGlobal)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_OdmProduction_attr.attr)); + + // change fuse file permissions, if ODM production fuse is not blown + if (OdmProductionFuseVal() == 0) + { + nvfuse_DeviceKey_attr.attr.mode = 0640; + nvfuse_JtagDisable_attr.attr.mode = 0640; + nvfuse_OdmProduction_attr.attr.mode = 0640; + nvfuse_SecBootDeviceConfig_attr.attr.mode = 0640; + nvfuse_SecBootDeviceSelect_attr.attr.mode = 0640; + nvfuse_SecureBootKey_attr.attr.mode = 0640; + nvfuse_SwReserved_attr.attr.mode = 0640; + nvfuse_SkipDevSelStraps_attr.attr.mode = 0640; + nvfuse_SecBootDeviceSelectRaw_attr.attr.mode = 0640; + nvfuse_ReservedOdm_attr.attr.mode = 0640; + sysfs_chmod_file(nvfuse_kobj, &nvfuse_OdmProduction_attr.attr, 0640); + } + + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_DeviceKey_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_JtagDisable_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_KeyProgrammed_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_SecBootDeviceConfig_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_SecBootDeviceSelect_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_SecureBootKey_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_sku_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_SpareBits_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_SwReserved_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_SkipDevSelStraps_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_SecBootDeviceSelectRaw_attr.attr)); + CHK_ERR(sysfs_create_file(nvfuse_kobj, &nvfuse_ReservedOdm_attr.attr)); + PRINT_FUSE(("\n Fuse Init Exiting")); + return 0; +} + +static void __exit sysfsfuse_exit(void) +{ + sysfs_remove_file(nvfuse_kobj, &nvfuse_DeviceKey_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_JtagDisable_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_KeyProgrammed_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_OdmProduction_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_SecBootDeviceConfig_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_SecBootDeviceSelect_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_SecureBootKey_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_sku_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_SpareBits_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_SwReserved_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_SkipDevSelStraps_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_SecBootDeviceSelectRaw_attr.attr); + sysfs_remove_file(nvfuse_kobj, &nvfuse_ReservedOdm_attr.attr); + kobject_del(nvfuse_kobj); + NvDdkFuseClose(); +} + +module_init(sysfsfuse_init); +module_exit(sysfsfuse_exit); +MODULE_LICENSE("GPL"); |