blob: ef5f0b05f29150b02eb2abf3906a6de4afebaae0 [file] [log] [blame]
From 85b332eccf4ac93f47eb86e9917f50ffa0750fa7 Mon Sep 17 00:00:00 2001
From: David Wang <davidwang@quantatw.com>
Date: Mon, 6 Nov 2023 12:02:52 +0800
Subject: [PATCH 12/16] drivers: char: sync npcm otp
---
drivers/char/Kconfig | 21 +
drivers/char/Makefile | 1 +
drivers/char/npcm750_otp.c | 1618 ++++++++++++++++++++++++++++++++++++
drivers/char/npcm750_otp.h | 208 +++++
4 files changed, 1848 insertions(+)
create mode 100644 drivers/char/npcm750_otp.c
create mode 100644 drivers/char/npcm750_otp.h
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7216ba81ccc4..f550781a61f2 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -30,6 +30,27 @@ config TTY_PRINTK_LEVEL
help
Printk log level to use for ttyprintk messages.
+config NPCM750_OTP
+ tristate "BMC NPCM750 On-Chip OTP Memory Support"
+ depends on ARCH_NPCM
+ default n
+ help
+ Support NPCM750 BMC OTP memory (fuse).
+ To compile this driver as a module, choose M here: the module
+ will be called npcm750_otp.
+
+
+config NPCM750_OTP_WRITE_ENABLE
+ bool "BMC NPCM750 On-Chip OTP : Enable writing support of OTP pages"
+ depends on NPCM750_OTP
+ default n
+ help
+ If you say Y here, you will enable support for writing of the
+ OTP pages. This is dangerous by nature as you can only program
+ the pages once, so only enable this option when you actually
+ need it so as to not inadvertently clobber data.
+ If unsure, say N.
+
config PRINTER
tristate "Parallel printer support"
depends on PARPORT
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 264eb398fdd4..0f7206059691 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_HW_RANDOM) += hw_random/
obj-$(CONFIG_PPDEV) += ppdev.o
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
+obj-$(CONFIG_NPCM750_OTP) += npcm750_otp.o
obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
diff --git a/drivers/char/npcm750_otp.c b/drivers/char/npcm750_otp.c
new file mode 100644
index 000000000000..9318f7a1e905
--- /dev/null
+++ b/drivers/char/npcm750_otp.c
@@ -0,0 +1,1618 @@
+/*
+ * NPCMP750 BMC On-Chip OTP (FUSE) Memory Interface
+ *
+ * Copyright 2016 Nuvoton Technologies
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ * based on blackfin OTP.
+ *
+ */
+
+#ifdef CONFIG_NPCM750_OTP
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <mtd/mtd-abi.h>
+#include <asm/uaccess.h>
+#include <linux/uaccess.h>
+#include <linux/of_irq.h>
+
+//#include <mach/map.h>
+//#include <mach/hal.h>
+//#include <defs.h>
+#include "npcm750_otp.h"
+
+#ifdef REG_READ
+#undef REG_READ
+#endif
+static inline u32 REG_READ(unsigned int __iomem *mem ) {
+ return ioread32(mem);
+}
+
+#ifdef REG_WRITE
+#undef REG_WRITE
+#endif
+static inline void REG_WRITE(unsigned int __iomem *mem, u32 val ) {
+ iowrite32(val, mem);
+}
+
+#ifdef SET_REG_FIELD
+#undef SET_REG_FIELD
+#endif
+/*---------------------------------------------------------------------------------------------------------*/
+/* Set field of a register / variable according to the field offset and size */
+/*---------------------------------------------------------------------------------------------------------*/
+static inline void SET_REG_FIELD(unsigned int __iomem *mem, bit_field_t bit_field, u32 val) {
+ u32 tmp = ioread32(mem);
+ tmp &= ~(((1 << bit_field.size) - 1) << bit_field.offset); // mask the field size
+ tmp |= val << bit_field.offset; // or with the requested value
+ iowrite32(tmp, mem);
+}
+
+#ifdef SET_VAR_FIELD
+#undef SET_VAR_FIELD
+#endif
+// bit_field should be of bit_field_t type
+#define SET_VAR_FIELD(var, bit_field, value) { \
+ typeof(var) tmp = var; \
+ tmp &= ~(((1 << bit_field.size) - 1) << bit_field.offset); /* mask the field size */ \
+ tmp |= value << bit_field.offset; /* or with the requested value */ \
+ var = tmp; \
+}
+
+#ifdef READ_REG_FIELD
+#undef READ_REG_FIELD
+#endif
+/*---------------------------------------------------------------------------------------------------------*/
+/* Get field of a register / variable according to the field offset and size */
+/*---------------------------------------------------------------------------------------------------------*/
+static inline u8 READ_REG_FIELD(unsigned int __iomem *mem, bit_field_t bit_field) {
+ u8 tmp = ioread32(mem);
+ tmp = tmp >> bit_field.offset; // shift right the offset
+ tmp &= (1 << bit_field.size) - 1; // mask the size
+ return tmp;
+}
+
+#ifdef READ_VAR_FIELD
+#undef READ_VAR_FIELD
+#endif
+// bit_field should be of bit_field_t type
+#define READ_VAR_FIELD(var, bit_field) ({ \
+ typeof(var) tmp = var; \
+ tmp = tmp >> bit_field.offset; /* shift right the offset */ \
+ tmp &= (1 << bit_field.size) - 1; /* mask the size */ \
+ tmp; \
+})
+
+#ifdef MASK_FIELD
+#undef MASK_FIELD
+#endif
+/*---------------------------------------------------------------------------------------------------------*/
+/* Build a mask of a register / variable field */
+/*---------------------------------------------------------------------------------------------------------*/
+// bit_field should be of bit_field_t type
+#define MASK_FIELD(bit_field) \
+ (((1 << bit_field.size) - 1) << bit_field.offset) /* mask the field size */
+
+#ifdef BUILD_FIELD_VAL
+#undef BUILD_FIELD_VAL
+#endif
+/*---------------------------------------------------------------------------------------------------------*/
+/* Expand the value of the given field into its correct position */
+/*---------------------------------------------------------------------------------------------------------*/
+// bit_field should be of bit_field_t type
+#define BUILD_FIELD_VAL(bit_field, value) \
+ ((((1 << bit_field.size) - 1) & (value)) << bit_field.offset)
+
+
+#ifdef SET_REG_MASK
+#undef SET_REG_MASK
+#endif
+/*---------------------------------------------------------------------------------------------------------*/
+/* Set field of a register / variable according to the field offset and size */
+/*---------------------------------------------------------------------------------------------------------*/
+static inline void SET_REG_MASK(unsigned int __iomem *mem, u32 val) {
+ iowrite32(ioread32(mem) | val, mem);
+}
+
+#ifdef READ_VAR_BIT
+#undef READ_VAR_BIT
+#endif
+#define READ_VAR_BIT(var, nb) (((var) >> (nb)) & 0x1)
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+#define ASSERT(cond)
+
+#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
+
+#define DRIVER_NAME "npcm750_otp"
+
+static DEFINE_MUTEX(npcm750_otp_lock);
+
+
+/* OTP MODULE registers */
+static void __iomem *otp_base[2];
+static struct platform_device *otp_dev;
+
+static struct clk* otp_clk;
+
+
+//#define CONFIG_npcm750_otp_EMULATE
+#ifdef CONFIG_NPCM750_OTP_EMULATE
+ u8 *fuse_array_mem = (u8 *)0x2000000;
+ #define npcm750_otp_ARR_SIZE 1024
+#endif
+
+// #define OTP_DEBUG_MODULE 1
+#ifdef OTP_DEBUG_MODULE
+#define printk_dbg(x...) printk(x)
+#else
+#define printk_dbg(x...) (void)0
+#endif
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Fuse module constant definitions */
+/*---------------------------------------------------------------------------------------------------------*/
+
+
+// Read cycle initiation value:
+#define READ_INIT 0x02
+
+// Program cycle initiation values (a sequence of two adjacent writes is required):
+#define PROGRAM_ARM 0x1
+#define PROGRAM_INIT 0xBF79E5D0
+
+// Value to clean FDATA contents:
+#define FDATA_CLEAN_VALUE 0x01
+
+// Default APB Clock Rate (in MHz):
+#define DEFAULT_APB_RATE 0x30
+
+#define MIN_PROGRAM_PULSES 4
+#define MAX_PROGRAM_PULSES 20
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Fuse module local macro definitions */
+/*---------------------------------------------------------------------------------------------------------*/
+// #define STORAGE_ARRAY_READY(sa) READ_REG_FIELD(FST(sa), FST_RDY)
+#define KEY_IS_VALID() READ_REG_FIELD(FKEYIND, FKEYIND_KVAL)
+#define DISABLE_KEY_ACCESS() SET_REG_FIELD(FCFG(NPCM750_KEY_SA), FCFG_FDIS, 1) /* Lock OTP module access */
+
+static bool npcm750_otp_IsInitialized = false;
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Internal functions for this module */
+/*---------------------------------------------------------------------------------------------------------*/
+
+/* HAL functions */
+static int NPCM750_OTP_WaitForOTPReadyWithTimeout(NPCM750_OTP_STORAGE_ARRAY_T array, u32 timeout);
+static int NPCM750_OTP_Init (void);
+static void NPCM750_OTP_Read (NPCM750_OTP_STORAGE_ARRAY_T arr, u32 addr, u8 *data);
+static int NPCM750_OTP_ProgramBit (NPCM750_OTP_STORAGE_ARRAY_T arr, u32 byteNum, u8 bitNum);
+static int NPCM750_OTP_ProgramByte (NPCM750_OTP_STORAGE_ARRAY_T arr, u32 byteNum, u8 value);
+static bool NPCM750_OTP_BitIsProgrammed (NPCM750_OTP_STORAGE_ARRAY_T arr, u32 byteNum, u8 bitNum);
+#if (defined RSA_MODULE_TYPE) || (defined AES_MODULE_TYPE)
+static void NPCM750_OTP_UploadKey (AES_KEY_SIZE_T keySize, u8 keyIndex);
+static int NPCM750_OTP_ReadKey (NPCM750_OTP_KEY_TYPE_T keyType, u8 keyIndex, u8 *output);
+static int NPCM750_OTP_SelectKey (u8 keyIndex);
+#endif
+static void NPCM750_OTP_DisableKeyAccess (void);
+#ifdef ROM_CODE_ONLY
+static int NPCM750_OTP_LockAccess (NPCM750_OTP_STORAGE_ARRAY_T array, u8 lockForRead, u8 lockForWrite, bool lockRegister);
+#endif
+#ifdef _CODE_THAT_SHOULD_BE_IN_USER_
+static int NPCM750_OTP_NibParEccDecode (u8 *datain, u8 *dataout, u32 encoded_size);
+static int NPCM750_OTP_NibParEccEncode (u8 *datain, u8 *dataout, u32 encoded_size);
+static int NPCM750_OTP_MajRulEccDecode (u8 *datain, u8 *dataout, u32 encoded_size);
+static int NPCM750_OTP_MajRulEccEncode (u8 *datain, u8 *dataout, u32 encoded_size);
+static unsigned int NPCM750_OTP_Fustrap_Get (NPCM750_OTP_FUSTRAP_FIELDS_T oFuse); // TODO: is this needed for Linux?
+#endif // _CODE_THAT_SHOULD_BE_IN_USER_
+static void NPCM750_PrintRegs (void);
+static void NPCM750_PrintModuleRegs (NPCM750_OTP_STORAGE_ARRAY_T array);
+
+/* Linux IF */
+static ssize_t npcm750_otp_read (struct file *file, char __user *buff, size_t count, loff_t *pos);
+static ssize_t npcm750_otp_write (struct file *filp, const char __user *buff, size_t count, loff_t *pos);
+ long npcm750_otp_ioctl (struct file *filp, unsigned cmd, unsigned long arg);
+static int npcm750_otp_probe (struct platform_device *pdev);
+static int __exit npcmx50_otp_remove (struct platform_device *pdev);
+static int __init npcm750_otp_init (void);
+static void __exit npcm750_otp_exit (void);
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_OTP_WaitForOTPReadyWithTimeout */
+/* */
+/* Parameters: array - fuse array to wait for */
+/* Returns: int */
+/* Side effects: */
+/* Description: Initialize the Fuse HW module. */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_WaitForOTPReadyWithTimeout(NPCM750_OTP_STORAGE_ARRAY_T array, u32 timeout)
+{
+ volatile u32 time = timeout;
+
+ /*-----------------------------------------------------------------------------------------------------*/
+ /* check parameters validity */
+ /*-----------------------------------------------------------------------------------------------------*/
+ if (array > NPCM750_FUSE_SA)
+ {
+ return -EINVAL;
+ }
+
+ while (--time > 1)
+ {
+ if (READ_REG_FIELD(FST(array), FST_RDY))
+ {
+ /* fuse is ready, clear the status. */
+ SET_REG_FIELD(FST(array), FST_RDST, 1);
+
+ return 0;
+ }
+ }
+ /* try to clear the status in case it was set */
+ SET_REG_FIELD(FST(array), FST_RDST, 1);
+
+ return -EINVAL;
+}
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_OTP_Init */
+/* */
+/* Parameters: APBclock - APB clock rate in MHz */
+/* Returns: int */
+/* Side effects: */
+/* Description: Initialize the Fuse HW module. */
+/*---------------------------------------------------------------------------------------------------------*/
+// TaliP: notice: this entire function is realy not needed. ROM code does it for us. Thanks, ROM.
+static int NPCM750_OTP_Init (void)
+{
+
+ // APBRT (APB Clock Rate). Informs the fuse array state machine on the APB clock rate in MHz. The
+ // software must update this field before writing the OTP, and before APB4 actual clock rate change. The
+ // state machine contains an internal copy of this field, sampled at the beginning of every read or program
+ // operation. Software should not write this field with 0. The reset value of this field is 1Fh (31 MHz). The
+ // accuracy of the setting should be 10%.
+ // Note: The minimum APB allowed frequency for accessing the fuse arrays is 10 MHz.
+
+ u8 APBclock = clk_get_rate(otp_clk)/1000000 + 1;
+
+ /* Configure the Key Storage Array APB Clock Rate */
+ SET_REG_FIELD(FCFG(NPCM750_KEY_SA), FCFG_APBRT, APBclock & 0x3F);
+
+ /* Configure the Fuse Storage Array APB Clock Rate */
+ SET_REG_FIELD(FCFG(NPCM750_FUSE_SA), FCFG_APBRT, APBclock & 0x3F);
+
+ npcm750_otp_IsInitialized = true;
+
+ return 0;
+
+
+}
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_OTP_Read */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* addr - Byte-address to read from [input]. */
+/* data - Pointer to result [output]. */
+/* Returns: none */
+/* Side effects: */
+/* Description: Read 8-bit data from an OTP storage array. */
+/*---------------------------------------------------------------------------------------------------------*/
+static void NPCM750_OTP_Read (NPCM750_OTP_STORAGE_ARRAY_T arr,
+ u32 addr,
+ u8 *data
+)
+{
+ //if (!npcm750_otp_IsInitialized)
+ //{
+ // NPCM750_OTP_Init();
+ //}
+
+#ifdef CONFIG_npcm750_otp_EMULATE
+ *data = fuse_array_mem[(arr*npcm750_otp_ARR_SIZE)+addr];
+#else
+ /* Wait for the Fuse Box Idle */
+ NPCM750_OTP_WaitForOTPReadyWithTimeout(arr, 0xDEADBEEF ); // TODO: decide proper timeout
+
+ /* Configure the byte address in the fuse array for read operation */
+ SET_REG_FIELD(FADDR(arr), FADDR_BYTEADDR, addr);
+
+ /* Initiate a read cycle from the byte in the fuse array, pointed by FADDR */
+ REG_WRITE(FCTL(arr), READ_INIT);
+
+ /* Wait for read operation completion */
+ NPCM750_OTP_WaitForOTPReadyWithTimeout(arr, 0xDEADBEEF ); // TODO: decide proper timeout
+
+ /* Read the result */
+ *data = READ_REG_FIELD(FDATA(arr), FDATA_FDATA);
+
+ /* Clean FDATA contents to prevent unauthorized software from reading sensitive information */
+ SET_REG_FIELD(FDATA(arr), FDATA_FDATA, FDATA_CLEAN_VALUE);
+#endif
+}
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_OTP_BitIsProgrammed */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byteNum - Byte offset in array [input]. */
+/* bitNum - Bit offset in byte [input]. */
+/* Returns: Nonzero if bit is programmed, zero otherwise. */
+/* Side effects: */
+/* Description: Check if a bit is programmed in an OTP storage array. */
+/*---------------------------------------------------------------------------------------------------------*/
+static bool NPCM750_OTP_BitIsProgrammed (
+ NPCM750_OTP_STORAGE_ARRAY_T arr,
+ u32 byteNum,
+ u8 bitNum
+)
+{
+ u8 data;
+
+ if (!npcm750_otp_IsInitialized)
+ {
+ NPCM750_OTP_Init();
+ }
+
+ /* Read the entire byte you wish to program */
+ NPCM750_OTP_Read(arr, byteNum, &data);
+
+ /* Check whether the bit is already programmed */
+ if (READ_VAR_BIT(data, bitNum))
+ {
+ return true;
+ }
+ return false;
+}
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_OTP_ProgramBit */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byteNum - Byte offset in array [input]. */
+/* bitNum - Bit offset in byte [input]. */
+/* Returns: int */
+/* Side effects: */
+/* Description: Program (set to 1) a bit in an OTP storage array. */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_ProgramBit (
+ NPCM750_OTP_STORAGE_ARRAY_T arr,
+ u32 byteNum,
+ u8 bitNum
+)
+{
+ int status = 0;
+
+ if (!npcm750_otp_IsInitialized)
+ {
+ NPCM750_OTP_Init();
+ }
+
+ /* Wait for the Fuse Box Idle */
+ NPCM750_OTP_WaitForOTPReadyWithTimeout(arr, 0xDEADBEEF ); // TODO: decide proper timeout
+
+ /* Make sure the bit is not already programmed */
+ if (! NPCM750_OTP_BitIsProgrammed(arr, byteNum, bitNum))
+ {
+
+#ifdef CONFIG_npcm750_otp_EMULATE
+ fuse_array_mem[(arr* NPCM750_OTP_ARR_SIZE)+byteNum] |= 1<<bitNum;
+#else
+ u8 read_data;
+ int count;
+
+ /* Configure the bit address in the fuse array for program operation */
+ SET_REG_FIELD(FADDR(arr), FADDR_BYTEADDR, byteNum);
+
+ SET_REG_FIELD(FADDR(arr), FADDR_BITPOS, bitNum);
+
+ // program up to MAX_PROGRAM_PULSES
+ for (count=1; count<=MAX_PROGRAM_PULSES; count++)
+ {
+ /* Arm the program operation */
+ REG_WRITE(FCTL(arr), PROGRAM_ARM);
+
+ /* Initiate a program cycle to the bit in the fuse array, pointed by FADDR */
+ REG_WRITE(FCTL(arr), PROGRAM_INIT);
+
+ /* Wait for program operation completion */
+ NPCM750_OTP_WaitForOTPReadyWithTimeout(arr, 0xDEADBEEF ); // TODO: decide proper timeout
+
+ // after MIN_PROGRAM_PULSES start verifying the result
+ if (count >= MIN_PROGRAM_PULSES)
+ {
+ /* Initiate a read cycle from the byte in the fuse array, pointed by FADDR */
+ REG_WRITE(FCTL(arr), READ_INIT);
+
+ /* Wait for read operation completion */
+ NPCM750_OTP_WaitForOTPReadyWithTimeout(arr, 0xDEADBEEF ); // TODO: decide proper timeout
+
+ /* Read the result */
+ read_data = READ_REG_FIELD(FDATA(arr), FDATA_FDATA);
+
+ /* If the bit is set the sequence ended correctly */
+ if (read_data & (1 << bitNum))
+ break;
+ }
+ }
+
+ // check if programmking failed
+ if (count > MAX_PROGRAM_PULSES)
+ {
+ status = -EINVAL;
+ }
+
+ /* Clean FDATA contents to prevent unauthorized software from reading sensitive information */
+ SET_REG_FIELD(FDATA(arr), FDATA_FDATA, FDATA_CLEAN_VALUE);
+#endif
+ }
+
+ return status;
+}
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_OTP_ProgramByte */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byteNum - Byte offset in array [input]. */
+/* value - Byte to program [input]. */
+/* Returns: int */
+/* Side effects: */
+/* Description: Program (set to 1) a given byte's relevant bits in an OTP */
+/* storage array. */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_ProgramByte (
+ NPCM750_OTP_STORAGE_ARRAY_T arr,
+ u32 byteNum,
+ u8 value
+)
+{
+ unsigned int i;
+
+ u8 data;
+ int status = 0;
+
+ if (!npcm750_otp_IsInitialized)
+ {
+ NPCM750_OTP_Init();
+ }
+
+ if (byteNum > NPCM750_OTP_ARR_BYTE_SIZE)
+ return -1;
+
+ if(arr > NPCM750_FUSE_SA)
+ return -1;
+
+ /* Wait for the Fuse Box Idle */
+ NPCM750_OTP_WaitForOTPReadyWithTimeout(arr, 0xDEADBEEF ); // TODO: decide proper timeout
+
+ /* Read the entire byte you wish to program */
+ NPCM750_OTP_Read(arr, byteNum, &data);
+
+ /* In case all relevant bits are already programmed - nothing to do */
+ if ((~data & value) == 0)
+ return status;
+
+ /* Program unprogrammed bits. */
+ for (i = 0; i < 8; i++)
+ {
+ if (READ_VAR_BIT(value, i) == 1)
+ {
+ /* Program (set to 1) the relevant bit */
+ int last_status = NPCM750_OTP_ProgramBit(arr, byteNum, (u8)i);
+ if (last_status != 0)
+ {
+ status = last_status;
+ }
+ }
+ }
+
+ return status;
+}
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_OTP_SelectKey */
+/* */
+/* Parameters: */
+/* keyIndex - AES key index in the key array (in 128-bit steps) [input]. */
+/* Returns: 0 on successful read completion, int_ERROR* otherwise. */
+/* Side effects: */
+/* Description: Select a key from the key storage array. */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_SelectKey (
+ u8 keyIndex )
+{
+
+ u32 fKeyInd = 0;
+ volatile u32 time = 2000;
+
+ /* check if access disabled to the first 2048 bits of the fuse array */
+ if (READ_REG_FIELD(FCFG(NPCM750_KEY_SA), FCFG_FDIS) == 1)
+ {
+ return -EACCES;
+ }
+
+ if (!npcm750_otp_IsInitialized)
+ {
+ NPCM750_OTP_Init();
+ }
+
+ if (keyIndex >= 4 )
+ {
+ return -EINVAL;
+ }
+
+ printk_dbg(KERN_DEBUG "\tnpcm750_otp: select key = %d\n", keyIndex);
+
+ /* Do not destroy ECCDIS bit */
+ fKeyInd = REG_READ(FKEYIND);
+
+ /* Configure the key size */
+ SET_VAR_FIELD(fKeyInd, FKEYIND_KSIZE, FKEYIND_KSIZE_VALUE_256);
+
+ /* Configure the key index (0 to 3) */
+ SET_VAR_FIELD(fKeyInd, FKEYIND_KIND, keyIndex);
+
+ REG_WRITE(FKEYIND, fKeyInd);
+
+ /*-----------------------------------------------------------------------------------------------------*/
+ /* Wait for selection completetion */
+ /*-----------------------------------------------------------------------------------------------------*/
+ while (--time > 1)
+ {
+ if (READ_REG_FIELD(FKEYIND, FKEYIND_KVAL))
+ return 0;
+
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: npcm750_otp_DisableKeyAccess */
+/* */
+/* Parameters: none */
+/* Returns: none */
+/* Side effects: */
+/* Description: */
+/* This routine disables read and write accees to key array */
+/*---------------------------------------------------------------------------------------------------------*/
+static void NPCM750_OTP_DisableKeyAccess ()
+{
+ if (!npcm750_otp_IsInitialized)
+ {
+ NPCM750_OTP_Init();
+ }
+ printk_dbg("\tnpcm750_otp: disable key\n");
+ DISABLE_KEY_ACCESS();
+}
+
+// TaliP: will the Linux lock access to fuses? need ioctl for this?
+#ifdef ROM_CODE_ONLY
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: npcm750_otp_LockAccess */
+/* */
+/* Parameters: lockForRead: bitwise, which block to lock for reading */
+/* Parameters: lockForWrite: bitwise, which block to lock for program */
+/* Returns: int */
+/* Side effects: */
+/* Description: */
+/* This routine lock the otp blocks */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_LockAccess (NPCM750_OTP_STORAGE_ARRAY_T array, u8 lockForRead, u8 lockForWrite, bool lockRegister)
+{
+ u32 FCFG_VAR = 0;
+
+ if (!npcm750_otp_IsInitialized)
+ {
+ NPCM750_OTP_Init();
+ }
+
+ /*-----------------------------------------------------------------------------------------------------*/
+ /* check parameters validity */
+ /*-----------------------------------------------------------------------------------------------------*/
+ if (array > NPCM750_FUSE_SA)
+ {
+ return HAL_ERROR_BAD_PARAM;
+ }
+
+ /*-----------------------------------------------------------------------------------------------------*/
+ /* Read reg for modify all fields apart APBRT */
+ /*-----------------------------------------------------------------------------------------------------*/
+ FCFG_VAR = REG_READ(FCFG(array));
+
+
+ SET_VAR_FIELD(FCFG_VAR, FCFG_FRDLK, lockForRead & 0x00FF);
+
+ SET_VAR_FIELD(FCFG_VAR, FCFG_FPRGLK, lockForWrite & 0x00FF);
+
+ /*-----------------------------------------------------------------------------------------------------*/
+ /* Lock any access to this register (until next POR) */
+ /*-----------------------------------------------------------------------------------------------------*/
+ if ( lockRegister == true)
+ {
+ SET_VAR_FIELD(FCFG_VAR, FCFG_FCFGLK, (lockForWrite | lockForRead) & 0x00FF);
+ }
+
+ /*----------------------------------------------------------------------------------------------------*/
+ /* Lock the side band in case it's a key array, and read is locked */
+ /*----------------------------------------------------------------------------------------------------*/
+ if ( array == NPCM750_KEY_SA)
+ {
+ /* Set FDIS bit if oKAP bit 7 is set, to disable the side-band key loading. */
+ if ( (lockForRead & 0x80) > 0 )
+ {
+ SET_VAR_FIELD(FCFG_VAR, FCFG_FDIS, 1); // 1: Access to the first 2048 bits of the fuse array is disabled.
+ }
+ }
+
+ /*-----------------------------------------------------------------------------------------------------*/
+ /* Return the moified value */
+ /*-----------------------------------------------------------------------------------------------------*/
+ REG_WRITE(FCFG(array), FCFG_VAR);
+
+ return 0;
+}
+#endif
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Logical level functions */
+/*---------------------------------------------------------------------------------------------------------*/
+
+#ifdef _CODE_THAT_SHOULD_BE_IN_USER_
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: npcm750_otp_NibParEccDecode */
+/* */
+/* Parameters: */
+/* datain - pointer to encoded data buffer (buffer size should be 2 x dataout) */
+/* dataout - pointer to decoded data buffer */
+/* encoded_size - size of encoded data (decoded data x 2) */
+/* */
+/* Returns: int */
+/* Side effects: */
+/* Description: */
+/* Decodes the data according to nibble parity ECC scheme. */
+/* Size specifies the encoded data size. */
+/* Decodes whole bytes only */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_NibParEccDecode (
+ u8 *datain,
+ u8 *dataout,
+ u32 encoded_size
+)
+{
+ u32 i;
+ u8 BER;
+ u8 src_re_calc;
+ u8 dst;
+ u8 E0;
+ u8 E1;
+ u8 E2;
+ u8 E3;
+ u8 E4;
+ u8 E5;
+ u8 E6;
+ u8 E7;
+ int status = 0;
+
+//Define the Bit Field macros in order to use the SET_VAR_FIELD macro:
+#define BITF0 0, 1
+#define BITF1 1, 1
+#define BITF2 2, 1
+#define BITF3 3, 1
+#define BITF4 4, 1
+#define BITF5 5, 1
+#define BITF6 6, 1
+#define BITF7 7, 1
+
+#define LSNF 0, 4
+#define MSNF 4, 4
+
+ for (i = 0; i < encoded_size; i++)
+ {
+ E0 = READ_VAR_FIELD(datain[i], BITF0);
+ E1 = READ_VAR_FIELD(datain[i], BITF1);
+ E2 = READ_VAR_FIELD(datain[i], BITF2);
+ E3 = READ_VAR_FIELD(datain[i], BITF3);
+ E4 = READ_VAR_FIELD(datain[i], BITF4);
+ E5 = READ_VAR_FIELD(datain[i], BITF5);
+ E6 = READ_VAR_FIELD(datain[i], BITF6);
+ E7 = READ_VAR_FIELD(datain[i], BITF7);
+
+ if (i % 2)
+ {//Decode higher nibble
+ SET_VAR_FIELD(dataout[i/2], BITF4, ((E0 & (E1 ^ E4)) | (E0 & (E2 ^ E6)) | ((E1 ^ E4) & (E2 ^ E6))));
+ SET_VAR_FIELD(dataout[i/2], BITF5, ((E1 & (E0 ^ E4)) | (E1 & (E3 ^ E7)) | ((E0 ^ E4) & (E3 ^ E7))));
+ SET_VAR_FIELD(dataout[i/2], BITF6, ((E2 & (E0 ^ E6)) | (E2 & (E3 ^ E5)) | ((E0 ^ E6) & (E3 ^ E5))));
+ SET_VAR_FIELD(dataout[i/2], BITF7, ((E3 & (E2 ^ E5)) | (E3 & (E1 ^ E7)) | ((E2 ^ E5) & (E1 ^ E7))));
+
+ dst = MSN( dataout[i/2] );
+ }
+ else
+ {//Decode lower nibble
+ SET_VAR_FIELD(dataout[i/2], BITF0, ((E0 & (E1 ^ E4)) | (E0 & (E2 ^ E6)) | ((E1 ^ E4) & (E2 ^ E6))));
+ SET_VAR_FIELD(dataout[i/2], BITF1, ((E1 & (E0 ^ E4)) | (E1 & (E3 ^ E7)) | ((E0 ^ E4) & (E3 ^ E7))));
+ SET_VAR_FIELD(dataout[i/2], BITF2, ((E2 & (E0 ^ E6)) | (E2 & (E3 ^ E5)) | ((E0 ^ E6) & (E3 ^ E5))));
+ SET_VAR_FIELD(dataout[i/2], BITF3, ((E3 & (E2 ^ E5)) | (E3 & (E1 ^ E7)) | ((E2 ^ E5) & (E1 ^ E7))));
+
+ dst = LSN( dataout[i/2] );
+ }
+
+
+ /*-------------------------------------------------------------------------------------------------*/
+ /* calculate the encoded value back from the decoded value and compare the original value for */
+ /* comparison */
+ /*-------------------------------------------------------------------------------------------------*/
+ /* Take decode byte*/
+ src_re_calc = dst;
+
+ /* calc its' parity */
+ E0 = READ_VAR_FIELD(dst, BITF0);
+ E1 = READ_VAR_FIELD(dst, BITF1);
+ E2 = READ_VAR_FIELD(dst, BITF2);
+ E3 = READ_VAR_FIELD(dst, BITF3);
+
+ SET_VAR_FIELD(src_re_calc, BITF4, E0 ^ E1);
+ SET_VAR_FIELD(src_re_calc, BITF5, E2 ^ E3);
+ SET_VAR_FIELD(src_re_calc, BITF6, E0 ^ E2);
+ SET_VAR_FIELD(src_re_calc, BITF7, E1 ^ E3);
+
+ /*-----------------------------------------------------------------------------------------------------*/
+ /* Check that only one bit is corrected per byte */
+ /*-----------------------------------------------------------------------------------------------------*/
+ BER = src_re_calc ^ datain[i];
+
+ BER = READ_VAR_FIELD(BER, BITF0)
+ + READ_VAR_FIELD(BER, BITF1)
+ + READ_VAR_FIELD(BER, BITF2)
+ + READ_VAR_FIELD(BER, BITF3)
+ + READ_VAR_FIELD(BER, BITF4)
+ + READ_VAR_FIELD(BER, BITF5)
+ + READ_VAR_FIELD(BER, BITF6)
+ + READ_VAR_FIELD(BER, BITF7);
+
+ /*-------------------------------------------------------------------------------------------------*/
+ /* Bit Error Rate can be 0x00 (no change) or 0x01 0x02 0x04 0x08 -> one bit change only */
+ /*-------------------------------------------------------------------------------------------------*/
+ if ( BER > 1 )
+ {
+ /*---------------------------------------------------------------------------------------------*/
+ /* Use original nible : */
+ /*---------------------------------------------------------------------------------------------*/
+ if (i % 2)
+ { // copy lower nibble to higher nibble
+ SET_VAR_FIELD(dataout[i/2], MSNF, LSN( datain[i] ));
+
+ }
+ else
+ { // copy lower nibble to lower nibble
+ SET_VAR_FIELD(dataout[i/2], LSNF, LSN( datain[i] ) );
+ }
+
+ status = HAL_ERROR_BAD_PARITY;
+ }
+
+
+ }
+
+ return status;
+
+
+
+}
+
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: npcm750_otp_NibParEccEncode */
+/* */
+/* Parameters: */
+/* datain - pointer to decoded data buffer (buffer size should be 2 x dataout) */
+/* dataout - pointer to encoded data buffer */
+/* encoded_size - size of encoded data (decoded data x 2) */
+/* */
+/* Returns: int */
+/* Side effects: */
+/* Description: */
+/* Decodes the data according to nibble parity ECC scheme. */
+/* Size specifies the encoded data size. */
+/* Decodes whole bytes only */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_NibParEccEncode (
+ u8 *datain,
+ u8 *dataout,
+ u32 encoded_size
+)
+{
+ u32 i;
+ u8 E0;
+ u8 E1;
+ u8 E2;
+ u8 E3;
+ int status = 0;
+ u32 decoded_size = encoded_size/2;
+
+//Define the Bit Field macros in order to use the SET_VAR_FIELD macro:
+#define BITF0 0, 1
+#define BITF1 1, 1
+#define BITF2 2, 1
+#define BITF3 3, 1
+#define BITF4 4, 1
+#define BITF5 5, 1
+#define BITF6 6, 1
+#define BITF7 7, 1
+
+#define LSNF 0, 4
+#define MSNF 4, 4
+
+ for (i = 0; i < decoded_size; i++)
+ {
+ dataout[i*2] = LSN(datain[i]);
+ E0 = READ_VAR_FIELD(datain[i], BITF0);
+ E1 = READ_VAR_FIELD(datain[i], BITF1);
+ E2 = READ_VAR_FIELD(datain[i], BITF2);
+ E3 = READ_VAR_FIELD(datain[i], BITF3);
+
+ SET_VAR_FIELD(dataout[i*2], BITF4, E0 ^ E1);
+ SET_VAR_FIELD(dataout[i*2], BITF5, E2 ^ E3);
+ SET_VAR_FIELD(dataout[i*2], BITF6, E0 ^ E2);
+ SET_VAR_FIELD(dataout[i*2], BITF7, E1 ^ E3);
+
+ dataout[i*2+1] = MSN(datain[i]);
+ E0 = READ_VAR_FIELD(datain[i], BITF4);
+ E1 = READ_VAR_FIELD(datain[i], BITF5);
+ E2 = READ_VAR_FIELD(datain[i], BITF6);
+ E3 = READ_VAR_FIELD(datain[i], BITF7);
+
+ SET_VAR_FIELD(dataout[i*2+1], BITF4, E0 ^ E1);
+ SET_VAR_FIELD(dataout[i*2+1], BITF5, E2 ^ E3);
+ SET_VAR_FIELD(dataout[i*2+1], BITF6, E0 ^ E2);
+ SET_VAR_FIELD(dataout[i*2+1], BITF7, E1 ^ E3);
+ }
+
+ return status;
+}
+
+
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: npcm750_otp_MajRulEccDecode */
+/* */
+/* Parameters: */
+/* datain - pointer to encoded data buffer (buffer size should be 3 x dataout) */
+/* dataout - pointer to decoded data buffer */
+/* encoded_size - size of encoded data (decoded data x 3) */
+/* */
+/* Returns: int */
+/* Side effects: */
+/* Description: */
+/* Decodes the data according to Major Rule ECC scheme. */
+/* Size specifies the encoded data size. */
+/* Decodes whole bytes only */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_MajRulEccDecode (
+ u8 *datain,
+ u8 *dataout,
+ u32 encoded_size
+)
+{
+ unsigned int byte;
+ unsigned int bit;
+ u8 E1, E2, E3;
+ u32 decoded_size;
+
+ if (encoded_size % 3)
+ // return DEFS_STATUS_INVALID_PARAMETER;
+ encoded_size -= encoded_size % 3;
+
+ decoded_size = encoded_size/3;
+
+ for (byte = 0; byte < decoded_size; byte++)
+ {
+ for (bit = 0; bit < 8; bit++)
+ {
+ E1 = READ_VAR_BIT(datain[decoded_size*0+byte], bit);
+ E2 = READ_VAR_BIT(datain[decoded_size*1+byte], bit);
+ E3 = READ_VAR_BIT(datain[decoded_size*2+byte], bit);
+ if ((E1+E2+E3) >= 2)
+ {
+ SET_VAR_BIT(dataout[byte], bit); //Majority is 1
+ }
+ else
+ {
+ CLEAR_VAR_BIT(dataout[byte], bit); //Majority is 0
+ }
+ }//Inner for (bit)
+ }//Outer for (byte)
+
+ return 0;
+
+}
+
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: npcm750_otp_MajRulEccEncode */
+/* */
+/* Parameters: */
+/* datain - pointer to decoded data buffer (buffer size should be 3 x dataout) */
+/* dataout - pointer to encoded data buffer */
+/* encoded_size - size of encoded data (decoded data x 3) */
+/* */
+/* Returns: int */
+/* Side effects: */
+/* Description: */
+/* Decodes the data according to Major Rule ECC scheme. */
+/* Size specifies the encoded data size. */
+/* Decodes whole bytes only */
+/*---------------------------------------------------------------------------------------------------------*/
+static int NPCM750_OTP_MajRulEccEncode (
+ u8 *datain,
+ u8 *dataout,
+ u32 encoded_size
+)
+{
+ unsigned int byte;
+ unsigned int bit;
+ u8 bit_val;
+ u32 decoded_size;
+
+ if (encoded_size % 3)
+ // return DEFS_STATUS_INVALID_PARAMETER;
+ encoded_size -= encoded_size % 3;
+
+ decoded_size = encoded_size/3;
+
+ for (byte = 0; byte < decoded_size; byte++)
+ {
+ for (bit = 0; bit < 8; bit++)
+ {
+ bit_val = READ_VAR_BIT(datain[byte], bit);
+
+ if (bit_val == 1)
+ {
+ SET_VAR_BIT(dataout[decoded_size*0+byte], bit);
+ SET_VAR_BIT(dataout[decoded_size*1+byte], bit);
+ SET_VAR_BIT(dataout[decoded_size*2+byte], bit);
+
+ }
+ else
+ {
+ CLEAR_VAR_BIT(dataout[decoded_size*0+byte], bit);
+ CLEAR_VAR_BIT(dataout[decoded_size*1+byte], bit);
+ CLEAR_VAR_BIT(dataout[decoded_size*2+byte], bit);
+ }
+ } // Inner for (bit)
+ }// Outer for (byte)
+
+ return 0;
+
+}
+#endif // _CODE_THAT_SHOULD_BE_IN_USER_
+
+
+#ifdef CHECK_FUSE_IS_LOCKED_FOR_ACCESS
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_OTP_ProgramByteFustrap */
+/* */
+/* Parameters: */
+/* oFuse - fuse value to read */
+/* */
+/* Returns: retVal */
+/* Side effects: */
+/* Description: */
+/* This is a getter for fustrap */
+/*---------------------------------------------------------------------------------------------------------*/
+static unsigned int NPCM750_OTP_Fustrap_Get (NPCM750_OTP_FUSTRAP_FIELDS_T oFuse)
+{
+ unsigned int retVal = 0;
+ switch (oFuse)
+ {
+ case NPCM750_OTP_FUSTRAP_DIS_FAST_BOOT:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_DIS_FAST_BOOT);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oWDEN:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oWDEN);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oHLTOF:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oHLTOF);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oAESKEYACCLK:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oAESKEYACCLK);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oJDIS:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oJDIS);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oSECBOOT:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oSECBOOT);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_USEFUSTRAP:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_USEFUSTRAP);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oPKInvalid2_0:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oPKInvalid2_0);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oAltImgLoc:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oAltImgLoc);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_Bit_28:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_BIT_28);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oSecBootDisable:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oSecBootDisable);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oCPU1STOP2:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oCPU1STOP2);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oCPU1STOP1:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oCPU1STOP1);
+ break;
+
+ case NPCM750_OTP_FUSTRAP_oHINDDIS:
+ retVal = READ_REG_FIELD(FUSTRAP, FUSTRAP_oHINDDIS);
+ break;
+
+
+ default:
+ ASSERT(false);
+ break;
+ }
+
+ return retVal;
+}
+#endif // CHECK_FUSE_IS_LOCKED_FOR_ACCESS
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_PrintRegs */
+/* */
+/* Parameters: none */
+/* Returns: none */
+/* Side effects: */
+/* Description: */
+/* This routine prints the module registers */
+/*---------------------------------------------------------------------------------------------------------*/
+static void NPCM750_PrintRegs (void)
+{
+ unsigned int i;
+
+ printk_dbg("/*--------------*/\n");
+ printk_dbg("/* FUSE */\n");
+ printk_dbg("/*--------------*/\n\n");
+
+ for (i = 0; i <= NPCM750_FUSE_SA; i++)
+ {
+ NPCM750_PrintModuleRegs((NPCM750_OTP_STORAGE_ARRAY_T)i);
+ }
+}
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Function: NPCM750_PrintModuleRegs */
+/* */
+/* Parameters: */
+/* array - The Storage Array type module to be printed. */
+/* */
+/* Returns: none */
+/* Side effects: */
+/* Description: */
+/* This routine prints the module instance registers */
+/*lint -e{715} Supress 'array' not referenced */
+/*---------------------------------------------------------------------------------------------------------*/
+static void NPCM750_PrintModuleRegs (NPCM750_OTP_STORAGE_ARRAY_T array)
+{
+ ASSERT(array <= NPCM750_FUSE_SA);
+
+ printk_dbg("FUSE%1X:\n", (array+1));
+ printk_dbg("------\n");
+ printk_dbg("FST%d = 0x%08X\n", (array+1), REG_READ(FST(array)));
+ printk_dbg("FADDR%d = 0x%08X\n", (array+1), REG_READ(FADDR(array)));
+ printk_dbg("FDATA%d = 0x%08X\n", (array+1), REG_READ(FDATA(array)));
+ printk_dbg("FCFG%d = 0x%08X\n", (array+1), REG_READ(FCFG(array)));
+
+ if (array == NPCM750_KEY_SA)
+ {
+ printk_dbg("FKEYIND = 0x%08X\n", REG_READ(FKEYIND));
+ }
+ else
+ {
+ printk_dbg("FUSTRAP = 0x%08X\n", REG_READ(FUSTRAP));
+ }
+
+ printk_dbg("\n");
+}
+
+
+
+/**
+ * npcm750_otp_seek - Seek on the OTP, size is fixed to 2KB.
+ */
+ static loff_t npcm750_otp_seek(struct file *file, loff_t off, int whence)
+{
+ printk_dbg("\t otp: seek off=%lld, whence = %d\n", off, whence);
+ if(off >= 2*NPCM750_OTP_ARR_BYTE_SIZE)
+ return -EINVAL;
+ return fixed_size_llseek(file, off, whence, 2*NPCM750_OTP_ARR_BYTE_SIZE);
+}
+
+
+/**
+ * npcm750_otp_read - Read OTP pages
+ */
+static ssize_t npcm750_otp_read(struct file *file, char __user *buff, size_t count, loff_t *pos)
+{
+ ssize_t bytes_read = 0;
+ u8 *read_buf;
+ u32 addr;
+ NPCM750_OTP_STORAGE_ARRAY_T array;
+
+ if(*pos >= 2*NPCM750_OTP_ARR_BYTE_SIZE)
+ return -EINVAL;
+
+ array = NPCM750_KEY_SA;
+ addr = (u32)(*pos % NPCM750_OTP_ARR_BYTE_SIZE);
+
+ if ( (*pos % (2*NPCM750_OTP_ARR_BYTE_SIZE))>= NPCM750_OTP_ARR_BYTE_SIZE)
+ array = NPCM750_FUSE_SA;
+
+ printk_dbg("\n\t otp: read %d bytes from address 0x%x, array%d, *pos=%lld\n", count, addr, (int)array, *pos);
+
+ if (((int)array*NPCM750_OTP_ARR_BYTE_SIZE + addr + count) > 2*NPCM750_OTP_ARR_BYTE_SIZE)
+ count = 2*NPCM750_OTP_ARR_BYTE_SIZE - addr - (int)array*NPCM750_OTP_ARR_BYTE_SIZE; // can only read up to 2KB
+
+ mutex_lock(&npcm750_otp_lock);
+
+
+ read_buf = kmalloc(count, GFP_KERNEL);
+ if (!read_buf) {
+ printk("\totp: kmalloc fail\n");
+ return -ENOMEM;
+ }
+
+
+ while ( bytes_read < count)
+ {
+ NPCM750_OTP_Read(array, addr, &read_buf[bytes_read]);
+ printk_dbg("\t otp: read array%d addr %d 0x%02x \t(%d/%d), pos=%lld \n", array, addr, read_buf[bytes_read], bytes_read, count, *pos);
+ bytes_read++;
+ *pos += 1;
+ addr++;
+
+ // check if we crossed to the next array:
+ if (addr >= NPCM750_OTP_ARR_BYTE_SIZE)
+ {
+ addr = 0;
+ if (array == NPCM750_KEY_SA)
+ array = NPCM750_FUSE_SA;
+ else /* OTP is 2KB only */
+ break;
+ }
+ }
+
+ if (copy_to_user(buff, read_buf, bytes_read)) {
+ printk("\t otp: copy_to_user failed\n");
+ bytes_read = -EFAULT;
+ }
+
+ mutex_unlock(&npcm750_otp_lock);
+
+ kfree(read_buf);
+
+ return bytes_read;
+}
+
+#ifdef CONFIG_NPCM750_OTP_WRITE_ENABLE
+
+
+/**
+ * npcm750_otp_write - write OTP pages
+ *
+ * All writes must be in half page chunks (half page == 64 bits).
+ */
+static ssize_t npcm750_otp_write(struct file *filp, const char __user *buff, size_t count, loff_t *pos)
+{
+
+ ssize_t bytes_prog = 0;
+ u8 *prog_buf;
+ u32 addr;
+ NPCM750_OTP_STORAGE_ARRAY_T array;
+
+ if(*pos >= 2*NPCM750_OTP_ARR_BYTE_SIZE)
+ return -EINVAL;
+
+ array = NPCM750_KEY_SA;
+ addr = (u32)(*pos % NPCM750_OTP_ARR_BYTE_SIZE);
+
+ if ( (*pos % (2*NPCM750_OTP_ARR_BYTE_SIZE))>= NPCM750_OTP_ARR_BYTE_SIZE)
+ array = NPCM750_FUSE_SA;
+
+ printk_dbg("\t otp: prog %d bytes from address 0x%x, array%d, pos=%lld\n", count, addr, (int)array, *pos);
+
+ if (((int)array*NPCM750_OTP_ARR_BYTE_SIZE + addr + count) > 2*NPCM750_OTP_ARR_BYTE_SIZE)
+ count = 2*NPCM750_OTP_ARR_BYTE_SIZE - addr - (int)array*NPCM750_OTP_ARR_BYTE_SIZE; // can only read up to 2KB
+
+ mutex_lock(&npcm750_otp_lock);
+
+ prog_buf = kmalloc(count, GFP_KERNEL);
+ if (!prog_buf) {
+ printk("otp: kmalloc fail\n");
+ return -ENOMEM;
+ }
+
+
+ if (copy_from_user(prog_buf, buff, count)) {
+ printk("otp: copy_from_user failed\n");
+ bytes_prog = -EFAULT;
+ }
+
+ while ( bytes_prog < count)
+ {
+ NPCM750_OTP_ProgramByte(array, addr, prog_buf[bytes_prog]);
+ printk_dbg("\t otp: prog array%d, addr=%d 0x%02x (%d/%d), pos=%lld, \n", array, addr, prog_buf[bytes_prog], bytes_prog, count, *pos );
+ *pos += 1;
+ addr++;
+ bytes_prog++;
+
+ // check if we crossed to the next array:
+ if (addr >= NPCM750_OTP_ARR_BYTE_SIZE)
+ {
+ addr = 0;
+ if (array == NPCM750_KEY_SA)
+ array = NPCM750_FUSE_SA;
+ else /* OTP is 2KB only */
+ break;
+ }
+ }
+
+ mutex_unlock(&npcm750_otp_lock);
+
+ kfree(prog_buf);
+
+ return bytes_prog;
+
+}
+
+#else
+# define npcm750_otp_write NULL
+#endif
+
+
+long npcm750_otp_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
+{
+
+ int ret = -ENOKEY;
+#ifdef CHECK_AES_KEY_IS_FUSED_TO_NONE_ZERO_KEY
+ int ii = 0;
+ u8 data;
+#endif
+
+ printk_dbg("\tnpcm750_otp: ioctl %d, arg= %ld\n",cmd, arg);
+
+ if ( arg > NPCM750_MAX_KEYS)
+ {
+ pr_err("\tnpcm750_otp: ioctl %d, arg= %ld. arg invalid\n",cmd, arg);
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case IOCTL_SELECT_AES_KEY: {
+
+ // TODO: finalyze with Eugene key verification!
+#ifdef CHECK_FUSE_IS_LOCKED_FOR_ACCESS
+ if (NPCM750_OTP_Fustrap_Get(NPCM750_OTP_FUSTRAP_oAESKEYACCLK) == 0 )
+ {
+ pr_err("\tERROR: npcm750_otp: keys are not locked, oAESKEYACCLK not fused\n");
+ return -ENOKEY;
+ }
+#endif // CHECK_FUSE_IS_LOCKED_FOR_ACCESS
+ if (mutex_lock_interruptible(&npcm750_otp_lock))
+ return -ERESTARTSYS;
+
+ /*--------------------------------------------------------------------*/
+ /* check that the keys fused and locked before using */
+ /*--------------------------------------------------------------------*/
+#ifdef CHECK_AES_KEY_IS_FUSED_TO_NONE_ZERO_KEY
+ /* Read the key and make sure it's not all zeros : */
+ for ( ii = 0 ; ii < 64; ii++)
+ {
+ NPCM750_OTP_Read(NPCM750_KEY_SA, arg*64+ii, &data);
+ if ( data != 0)
+ {
+ break;
+ }
+
+ }
+ if (ii == 64)
+ {
+ mutex_unlock(&npcm750_otp_lock);
+ pr_err("\tERROR: npcm750_otp: ioctl %d, arg= %ld. Key is not fused. Key is all zeros.\n",cmd, arg);
+ return -ENOKEY;
+ }
+#endif // CHECK_AES_KEY_IS_FUSED_TO_NONE_ZERO_KEY
+
+ ret = NPCM750_OTP_SelectKey(arg);
+
+ mutex_unlock(&npcm750_otp_lock);
+
+ return ret;
+ }
+
+ case IOCTL_GET_AES_KEY_NUM: {
+ return READ_REG_FIELD(FKEYIND, FKEYIND_KIND);
+ break;
+ }
+
+ case IOCTL_DISABLE_KEY_ACCESS: {
+ if (mutex_lock_interruptible(&npcm750_otp_lock))
+ return -ERESTARTSYS;
+
+ NPCM750_OTP_DisableKeyAccess();
+
+ mutex_unlock(&npcm750_otp_lock);
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(npcm750_otp_ioctl);
+
+////////////////////// driver init /////////////////////////////////////
+
+static const struct file_operations npcm750_otp_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = npcm750_otp_ioctl,
+ .read = npcm750_otp_read,
+#if CONFIG_NPCM750_OTP_WRITE_ENABLE
+ .write = npcm750_otp_write,
+#endif
+ .llseek = npcm750_otp_seek,
+ // .open = npcm750_otp_open,
+};
+
+static struct miscdevice npcm750_otp_misc_device = {
+ .minor = NVRAM_MINOR, // MISC_DYNAMIC_MINOR,
+ .name = DRIVER_NAME,
+ .fops = &npcm750_otp_fops,
+};
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:npcm750_otp");
+
+static const struct of_device_id otp_dt_id[] = {
+ { .compatible = "nuvoton,npcm750-otp", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, otp_dt_id);
+
+static struct platform_driver npcm750_otp_driver = {
+ .probe = npcm750_otp_probe,
+ .remove = npcmx50_otp_remove,
+ .shutdown = NULL,
+ .suspend = NULL,
+ .resume = NULL,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(otp_dt_id),
+ }
+};
+
+
+static int npcm750_otp_probe(struct platform_device *pdev)
+{
+ struct resource *res[2] = {NULL, NULL};
+ int ret;
+ int resource_count = 0;
+
+ printk_dbg(KERN_INFO "\t\t\t* OTP probe start\n");
+ /*
+ * A bit ugly, and it will never actually happen but there can
+ * be only one RNG and this catches any bork
+ */
+ if (otp_dev)
+ {
+ pr_err("\t\t\t* OTP probe failed: can't instantiate more then one device.\n");
+ return -EBUSY;
+ }
+
+#ifdef CONFIG_OF
+ otp_clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (IS_ERR(otp_clk))
+ {
+ pr_err(" OTP probe failed: can't read clk.\n");
+ ret = -EPROBE_DEFER; // this error will cause the probing to run again after clk is ready.
+ goto err_ioremap;
+ }
+
+ //clk_prepare_enable(otp_clk);
+
+ printk_dbg("\tOTP clock is %ld\n" , clk_get_rate(otp_clk));
+#endif // CONFIG_OF
+
+
+ for (resource_count = 0; resource_count < 2 ; resource_count++)
+ {
+ res[resource_count] = platform_get_resource(pdev, IORESOURCE_MEM, resource_count);
+ if (!res[resource_count]) {
+ pr_err(" OTP probe failed: can't read resource %d.\n", resource_count);
+ ret = -ENOENT;
+ goto err_ioremap;
+ }
+
+ if (!request_mem_region(res[resource_count]->start, resource_size(res[resource_count]), pdev->name)) {
+ pr_err(" OTP probe failed: can't request_mem_region for resource %d.\n", resource_count);
+ ret = -EBUSY;
+ goto err_ioremap;
+ }
+
+ dev_set_drvdata(&pdev->dev, res[resource_count]);
+ otp_base[resource_count] = ioremap(res[resource_count]->start, resource_size(res[resource_count]));
+ printk(KERN_INFO "\t\t\t* OTP%d (FUZE) base is 0x%08X, size 0x%08X, phys 0x%08X \n",
+ resource_count, (u32)otp_base[resource_count], resource_size(res[resource_count]), res[resource_count]->start);
+ if (!otp_base[resource_count]) {
+ pr_err(" OTP probe failed: can't read otp base address for resource %d.\n", resource_count);
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+ }
+
+ otp_dev = pdev;
+
+ NPCM750_PrintRegs();
+
+ printk(KERN_INFO "NPCMx50: OTP module probe OK\n");
+
+ return 0;
+
+err_ioremap:
+ if (otp_base[0] != NULL)
+ {
+ iounmap(otp_base[0]);
+ otp_base[0] = NULL;
+ }
+ if (otp_base[1] != NULL)
+ {
+ iounmap(otp_base[1]);
+ otp_base[1] = NULL;
+ }
+ otp_dev = NULL;
+ // release resources already allocated.
+ for (;resource_count > 0 ; resource_count--)
+ {
+ release_mem_region(res[resource_count]->start, resource_size(res[resource_count]));
+ }
+//err_region:
+ printk(KERN_INFO "NPCMx50: OTP module load fail . Error %d\n", ret);
+
+ return ret;
+}
+
+static int __exit npcmx50_otp_remove(struct platform_device *pdev)
+{
+ struct resource *res = dev_get_drvdata(&pdev->dev);
+
+ printk(KERN_NOTICE "\t\t\t*npcmX50-OTP: remove: stop using Nuvoton npcmx50 OTP.\n");
+
+ if (otp_base[0] != NULL)
+ {
+ iounmap(otp_base[0]);
+ otp_base[0] = NULL;
+ }
+ if (otp_base[1] != NULL)
+ {
+ iounmap(otp_base[1]);
+ otp_base[1] = NULL;
+ }
+ otp_dev = NULL;
+
+ release_mem_region(res->start, resource_size(res));
+ return 0;
+}
+
+
+
+//static dev_t npcm750_otp_dev; // (major,minor) value
+
+/**
+ * npcm750_otp_init - Initialize module
+ *
+ * Registers the device and notifier handler. Actual device
+ * initialization is handled by npcm750_otp_open().
+ */
+static int __init npcm750_otp_init(void)
+{
+ int ret;
+
+ /*
+ * A bit ugly, and it will never actually happen but there can
+ * be only one FUSE and this catches any bork
+ */
+ //if (otp_dev)
+ // return -EBUSY;
+
+ ret = platform_driver_register(&npcm750_otp_driver);
+ if (ret) {
+ printk("otp: unable to register a platform driver\n");
+ goto err_region;
+ }
+ ret = misc_register(&npcm750_otp_misc_device);
+ if (ret) {
+ printk("otp: unable to register a misc device\n");
+ goto err_region;
+ }
+
+ printk("NPCMx50: OTP (FUZE) module is ready\n");
+
+ return 0;
+
+
+err_region:
+ printk(KERN_INFO "NPCMx50: OTP module load fail . Error %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * npcm750_otp_exit - Deinitialize module
+ *
+ * Unregisters the device and notifier handler. Actual device
+ * deinitialization is handled by npcm750_otp_close().
+ */
+static void __exit npcm750_otp_exit(void)
+{
+ otp_dev = NULL;
+ otp_base[0] = 0;
+ otp_base[1] = 0;
+ misc_deregister(&npcm750_otp_misc_device);
+ platform_driver_unregister(&npcm750_otp_driver);
+}
+
+module_init(npcm750_otp_init);
+module_exit(npcm750_otp_exit);
+
+
+MODULE_AUTHOR("Tali Perry <tali.perry@nuvoton.com>");
+MODULE_DESCRIPTION("NPCM750 OTP Memory Interface");
+MODULE_LICENSE("GPL");
+
+
+#endif// CONFIG_NPCM750_OTP
+
diff --git a/drivers/char/npcm750_otp.h b/drivers/char/npcm750_otp.h
new file mode 100644
index 000000000000..554eee79fcd8
--- /dev/null
+++ b/drivers/char/npcm750_otp.h
@@ -0,0 +1,208 @@
+/*
+ * NPCMP750 BMC On-Chip OTP (FUSE) Memory Interface
+ *
+ * Copyright 2016 Nuvoton Technologies
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ *
+ */
+
+#ifndef NPCM750_NPCM750_OTP_H
+#define NPCM750_NPCM750_OTP_H
+
+typedef struct bit_field {
+ u8 offset;
+ u8 size;
+} bit_field_t;
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* OTP IOCTLs */
+/*---------------------------------------------------------------------------------------------------------*/
+#define NPCM750_OTP_IOC_MAGIC '2' /* used for all IOCTLs to npcm750_otp. AES Key handling */
+
+#define IOCTL_SELECT_AES_KEY _IO(NPCM750_OTP_IOC_MAGIC, 0)/* To Configure the Bus topology based on I2CTopology.config file*/
+#define IOCTL_DISABLE_KEY_ACCESS _IO(NPCM750_OTP_IOC_MAGIC, 1)/* To send request header and perform I2C operation */
+#define IOCTL_GET_AES_KEY_NUM _IO(NPCM750_OTP_IOC_MAGIC, 2)/* To Configure the Bus topology based on I2CTopology.config file*/
+
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Fuse module definitions */
+/*---------------------------------------------------------------------------------------------------------*/
+#define NPCM750_OTP_ARR_BYTE_SIZE (1024)
+#define NPCM750_KEYS_ARR_BYTE_SIZE (128)
+
+#define NPCM750_RSA_KEY_BYTE_SIZE (256)
+
+// 4 aes keys, 3 rsa keys:
+#define NPCM750_MAX_KEYS (4)
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Fuse ECC type */
+/*---------------------------------------------------------------------------------------------------------*/
+typedef enum NPCM750_OTP_ECC_TYPE_tag
+{
+ NPCM750_OTP_ECC_MAJORITY = 0,
+ NPCM750_OTP_ECC_NIBBLE_PARITY = 1,
+ NPCM750_OTP_ECC_NONE = 2
+} NPCM750_OTP_ECC_TYPE_T;
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Fuse key Type */
+/*---------------------------------------------------------------------------------------------------------*/
+typedef enum NPCM750_OTP_KEY_TYPE_tag
+{
+ NPCM750_OTP_KEY_AES = 0,
+ NPCM750_OTP_KEY_RSA = 1
+} NPCM750_OTP_KEY_TYPE_T;
+
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Fuse module enumerations */
+/*---------------------------------------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Storage Array Type: */
+/*---------------------------------------------------------------------------------------------------------*/
+typedef enum
+{
+ NPCM750_KEY_SA = 0,
+ NPCM750_FUSE_SA = 1
+} NPCM750_OTP_STORAGE_ARRAY_T;
+
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* AES Key Size */
+/* Do no change order, hardware dependent */
+/*---------------------------------------------------------------------------------------------------------*/
+typedef enum
+{
+ AES_KEY_SIZE_128 = 0, /* = 128 */
+ AES_KEY_SIZE_192 = 1, /* = 192 */
+ AES_KEY_SIZE_256 = 2, /* = 256 */
+} AES_KEY_SIZE_T;
+
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* FUSTRAP fields definition */
+/*---------------------------------------------------------------------------------------------------------*/
+typedef enum NPCM750_OTP_FUSTRAP_FIELDS_T_tag
+{
+ NPCM750_OTP_FUSTRAP_DIS_FAST_BOOT = 29, // (Disable Fast Boot).
+ NPCM750_OTP_FUSTRAP_Bit_28 = 28, // unknown register field !
+ NPCM750_OTP_FUSTRAP_oWDEN = 27, // (Watchdog Enable).
+ NPCM750_OTP_FUSTRAP_oHLTOF = 26, // (Halt on Failure). I
+ NPCM750_OTP_FUSTRAP_oAESKEYACCLK = 25, // (AES Key Access Lock).
+ NPCM750_OTP_FUSTRAP_oJDIS = 24, // (JTAG Disable).
+ NPCM750_OTP_FUSTRAP_oSECBOOT = 23, // (Secure Boot).
+ NPCM750_OTP_FUSTRAP_USEFUSTRAP = 22, //
+ NPCM750_OTP_FUSTRAP_oPKInvalid2_0 = 19, //
+ NPCM750_OTP_FUSTRAP_oAltImgLoc = 18, // Alternate image location definition.
+
+ /*-----------------------------------------------------------------------------------------------------*/
+ /* Added on Z2 */
+ /*-----------------------------------------------------------------------------------------------------*/
+ NPCM750_OTP_FUSTRAP_oHINDDIS = 14, // oHINDDIS: disable eSPI independent mode
+ NPCM750_OTP_FUSTRAP_oSecBootDisable = 15, // {oSecBootDisable} - when set, disables capability enter Secure Mode. Used for Derivatives.
+ NPCM750_OTP_FUSTRAP_oCPU1STOP2 = 16, // {oCPU1STOP2} - when set, stops CPU core 1 clock.
+ NPCM750_OTP_FUSTRAP_oCPU1STOP1 = 17 // {oCPU1STOP1} - when set, CPU core 1 stops and cannot be woken.
+
+
+} NPCM750_OTP_FUSTRAP_FIELDS_T;
+
+
+
+
+
+/**************************************************************************************************************************/
+/* Fuse Array Control Register (FCTL1,2) */
+/**************************************************************************************************************************/
+#define FCTL(n) (otp_base[n] + 0x14) /* Location: BASE+14h */
+static const bit_field_t FCTL_FCTL = { 0 , 32 };
+/* 31-0 FCTL. A sequence of two adjacent writes to this register, first with a
+value of 0000_0001h and the second with */
+
+/**************************************************************************************************************************/
+/* Fuse Array Status Register (FST1,2) */
+/**************************************************************************************************************************/
+#define FST(n) (otp_base[n] + 0x00) /* Location: BASE+00h */
+static const bit_field_t FST_RIEN = { 2 , 1 }; /* 2 RIEN (Ready Interrupt Enable). Enables an interrupt when RDST bit is set. (Bit added in Poleg) */
+static const bit_field_t FST_RDST = { 1 , 1 }; /* 1 RDST (Ready Status). This bit is set by hardware when a read or program operation is competed and */
+static const bit_field_t FST_RDY = { 0 , 1 }; /* 0 RDY (Ready). If cleared to 0, indicates that the fuse array interface is busy processing a read or */
+
+/**************************************************************************************************************************/
+/* Fuse Array Address Register (FADDR1,2) */
+/**************************************************************************************************************************/
+#define FADDR(n) (otp_base[n] + 0x04) /* Location: BASE+04h */
+static const bit_field_t FADDR_BITPOS = { 10 , 3 }; /* (n)-10 BITPOS (Bit Position). For write operations, designates the position of the bit (to be programmed) in the byte */
+static const bit_field_t FADDR_BYTEADDR = { 0 , 10 }; /* 9-0 BYTEADDR (Fuse Read Address). Designates the byte address in the fuse array for read and program */
+
+/**************************************************************************************************************************/
+/* Fuse Array Data Register (FDATA1,2) */
+/**************************************************************************************************************************/
+#define FDATA(n) (otp_base[n] + 0x08) /* Location: BASE+08h */
+static const bit_field_t FDATA_FDATA = { 0 , 8 };
+/* 7-0 FDATA. On read, returns the data from the read operation. The register
+contents are valid only if RDY bit in */
+
+/**************************************************************************************************************************/
+/* Fuse Array Configuration Register (FCFG1,2) */
+/**************************************************************************************************************************/
+#define FCFG(n) (otp_base[n] + 0x0C) /* Location: BASE+0Ch */
+static const bit_field_t FCFG_FDIS = { 31 , 1 }; /* 31 FDIS (Fuse Array Disable). This sticky bit disables access to the first 2048 bits of the fuse array, either */
+static const bit_field_t FCFG_APBRT = { 24 , 6 }; /* 29-24 APBRT (APB Clock Rate). Informs the fuse array state machine on the APB clock rate in MHz. The */
+static const bit_field_t FCFG_FCFGLK = { 16 , 8 }; /* 23-16 FCFGLK (FCFG Lock). Bit FCFGLKn locks the corresponding FPRGLKn and FRDLKn bits. These bits */
+static const bit_field_t FCFG_FPRGLK = { 8 , 8 }; /* FPRGLK (Fuse Program Lock). Controls program access to the fuse array. FPRGLKn bit protects the */
+static const bit_field_t FCFG_FRDLK = { 0 , 8 }; /* FRDLK (Fuse Read Lock). Controls APB read access to the fuse array. Bit FRDLKn protects the nth */
+
+/**************************************************************************************************************************/
+/* Fuse Key Index Register (FKEYIND) */
+/**************************************************************************************************************************/
+#define FKEYIND (otp_base[0] + 0x10) /* Location: BASE+10h */
+static const bit_field_t FKEYIND_KIND = { 18 , 2 }; /* 19-18 KIND (Key Index). Indicates the address of the key in the fuse array, in 5(n)-bit steps. (Changed in */
+static const bit_field_t FKEYIND_FUSERR = { 8 , 1 }; /* 8 FUSERR (Fuse Error). Indicates that the ECC decoding mechanism detected an error while reading */
+static const bit_field_t FKEYIND_KSIZE = { 4 , 3 }; /* 6-4 KSIZE (Key Size). Indicates the size of the cryptographic key to upload on the sideband key port. */
+static const bit_field_t FKEYIND_KVAL = { 0 , 1 }; /* 0 KVAL (Key Valid). Indicates whether the sideband key port contents are valid. This bit is cleared to 0 */
+
+/**************************************************************************************************************************/
+/* Fuse Strap Register (FUSTRAP) */
+/**************************************************************************************************************************/
+#define FUSTRAP (otp_base[1] + 0x10) /* Location: BASE+10h */
+static const bit_field_t FUSTRAP_DIS_FAST_BOOT = { 29 , 1 }; /* 29 DIS_FAST_BOOT (Disable Fast Boot). (Z2) Disables the option to jump to SPI flash before MDLR is written. */
+static const bit_field_t FUSTRAP_BIT_28 = { 28 , 1 }; /* Apears on ROM flow. Name unknown ! */
+static const bit_field_t FUSTRAP_oWDEN = { 27 , 1 }; /* 27 oWDEN (Watchdog Enable). If set, tells the ROM Code to enable a 22 seconds watchdog before jumping to */
+static const bit_field_t FUSTRAP_oHLTOF = { 26 , 1 }; /* 26 oHLTOF (Halt on Failure). If set, tells the ROM Code to halt execution on a signature verification failure. */
+static const bit_field_t FUSTRAP_oAESKEYACCLK = { 25 , 1 }; /* 25 oAESKEYACCLK (AES Key Access Lock). If set, prevents any access to the first 2048 bits of the Key Storage */
+static const bit_field_t FUSTRAP_oJDIS = { 24 , 1 }; /* 24 oJDIS (JTAG Disable). If set, locks (disables) the BMC CPU JTAG port. It can be reopened via JTAGDIS bit in */
+static const bit_field_t FUSTRAP_oSECBOOT = { 23 , 1 }; /* 23 oSECBOOT (Secure Boot). If set, indicates that the ROM code will perform an integrity check on power-up, */
+static const bit_field_t FUSTRAP_USEFUSTRAP = { 22 , 1 }; /* 22 USEFUSTRAP. When set, indicates the configuration in this register must be used instead of the configuration */
+static const bit_field_t FUSTRAP_oPKInvalid2_0 = { 19 , 3 }; /* 21-19 oPKInvalid2-0. A 3 bit field that may invalidate a Public Key (oPK2-0) stored in OTP. Bit 21 is for oPK2, Bit 20*/
+static const bit_field_t FUSTRAP_oAltImgLoc = { 18 , 1 }; /* 18 oAltImgLoc. Alternate image location definition. */
+static const bit_field_t FUSTRAP_FUSTRAP_SFAB = { 11 , 1 }; /* 11 FUSTRAP(n). System Flash Attached to BMC (SFAB). */
+static const bit_field_t FUSTRAP_FUSTRAP3_1 = { 0 , 3 }; /* 2-0 FUSTRAP3-1. CPU core clock and DDR4 memory frequency (CKFRQ). See Power-On Setting Register */
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* Added on Z2: */
+/*---------------------------------------------------------------------------------------------------------*/
+static const bit_field_t FUSTRAP_oHINDDIS = { 14 , 1 }; /* oHINDDIS (Host Independence Disable). Disables initialization of a few registers in step 1 of the ROM code */
+static const bit_field_t FUSTRAP_oSecBootDisable = { 15 , 1 }; /* {oSecBootDisable} - when set, disables capability enter Secure Mode. Used for Derivatives.*/
+static const bit_field_t FUSTRAP_oCPU1STOP2 = { 16 , 1 }; /* {oCPU1STOP2} - when set, stops CPU core 1 clock. */
+static const bit_field_t FUSTRAP_oCPU1STOP1 = { 17 , 1 }; /* {oCPU1STOP1} - when set, CPU core 1 stops and cannot be woken.*/
+
+
+
+
+/*---------------------------------------------------------------------------------------------------------*/
+/* FKEYIND field values */
+/*---------------------------------------------------------------------------------------------------------*/
+#define FKEYIND_KSIZE_VALUE_128 0x4
+#define FKEYIND_KSIZE_VALUE_192 0x5
+#define FKEYIND_KSIZE_VALUE_256 0x6
+
+
+#endif /* NPCM750_NPCM750_OTP_H */
--
2.25.1