summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2022-06-23 08:16:21 -0400
committerTom Rini <[email protected]>2022-06-23 08:16:21 -0400
commit9121478ee6f2aee381f8fe49d8997d43527d351a (patch)
tree44ca356e93474a6d909dd4754288bc92cee33e7c /drivers
parent52af0101be55da74a32e9b169864508101f886fe (diff)
parent929e581a620feba40bea659725f88b338d8b65ec (diff)
Merge branch '2022-06-22-platform-updates-and-additions' into next
- Add hpe gxp architecture and platform, Arm corstone1000 platform. - ast2600, devkit8000, NPCM7xx improvements
Diffstat (limited to 'drivers')
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/nuvoton/Kconfig14
-rw-r--r--drivers/crypto/nuvoton/Makefile2
-rw-r--r--drivers/crypto/nuvoton/npcm_aes.c301
-rw-r--r--drivers/crypto/nuvoton/npcm_sha.c897
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/npcm_otp.c512
-rw-r--r--drivers/spi/Kconfig6
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/gxp_spi.c304
-rw-r--r--drivers/timer/Kconfig7
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/gxp-timer.c64
15 files changed, 2122 insertions, 0 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 675081ecd37..12ef84ca05c 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -6,4 +6,6 @@ source drivers/crypto/fsl/Kconfig
source drivers/crypto/aspeed/Kconfig
+source drivers/crypto/nuvoton/Kconfig
+
endmenu
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 6b762565a1f..b9105186097 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -8,3 +8,4 @@ obj-y += rsa_mod_exp/
obj-y += fsl/
obj-y += hash/
obj-y += aspeed/
+obj-y += nuvoton/
diff --git a/drivers/crypto/nuvoton/Kconfig b/drivers/crypto/nuvoton/Kconfig
new file mode 100644
index 00000000000..034fcadfcc8
--- /dev/null
+++ b/drivers/crypto/nuvoton/Kconfig
@@ -0,0 +1,14 @@
+config NPCM_AES
+ bool "Support the NPCM AES algorithm"
+ select NPCM_OTP
+ help
+ This provides a means to encrypt and decrypt data using the NPCM
+ AES (Advanced Encryption Standard). This algorithm uses a symmetric
+ key and is widely used as a streaming cipher. This command only
+ supports AES256-CBC.
+
+config NPCM_SHA
+ bool "Enable NPCM cryptographic HW SHA accelerator"
+ help
+ This option enables support of NPCM cryptographic HW SHA accelerator.
+ It supports SHA1 and SHA256 hashing algorithms.
diff --git a/drivers/crypto/nuvoton/Makefile b/drivers/crypto/nuvoton/Makefile
new file mode 100644
index 00000000000..5a1173dfe73
--- /dev/null
+++ b/drivers/crypto/nuvoton/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_NPCM_AES) += npcm_aes.o
+obj-$(CONFIG_NPCM_SHA) += npcm_sha.o
diff --git a/drivers/crypto/nuvoton/npcm_aes.c b/drivers/crypto/nuvoton/npcm_aes.c
new file mode 100644
index 00000000000..6493ea108ec
--- /dev/null
+++ b/drivers/crypto/nuvoton/npcm_aes.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Nuvoton Technology Corp.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <uboot_aes.h>
+#include <asm/io.h>
+#include <asm/arch/aes.h>
+#include <asm/arch/otp.h>
+#include <malloc.h>
+
+#define ONE_SECOND 0xC00000
+
+struct npcm_aes_priv {
+ struct npcm_aes_regs *regs;
+};
+
+static struct npcm_aes_priv *aes_priv;
+static u8 fkeyind_to_set = 0xff;
+
+static int second_timeout(u32 *addr, u32 bitmask, u32 bitpol)
+{
+ ulong time, i = 0;
+
+ time = get_timer(0);
+
+ /* default 1 second timeout */
+ while (((readl(addr) & bitmask) == bitpol) && i < ONE_SECOND)
+ i++;
+
+ if (i == ONE_SECOND) {
+ printf("%xms timeout: addr = %x, mask = %x\n", (u32)get_timer(time),
+ *addr, bitmask);
+ return -1;
+ }
+
+ return 0;
+}
+
+int npcm_aes_select_key(u8 fkeyind)
+{
+ if (npcm_otp_is_fuse_array_disabled(NPCM_KEY_SA)) {
+ printf("AES key access denied\n");
+ return -EACCES;
+ }
+
+ if (fkeyind < 4)
+ fkeyind_to_set = fkeyind;
+
+ return 0;
+}
+
+static int npcm_aes_init(u8 dec_enc)
+{
+ struct npcm_aes_regs *regs = aes_priv->regs;
+ u32 ctrl, orgctrlval, wrtimeout;
+
+ /* reset hw */
+ writel(readl(&regs->aes_sw_reset) | SW_RESET_BIT, &regs->aes_sw_reset);
+ writel(readl(&regs->aes_fifo_status) | DIN_FIFO_OVERFLOW, &regs->aes_fifo_status);
+ writel(readl(&regs->aes_fifo_status) | DOUT_FIFO_UNDERFLOW, &regs->aes_fifo_status);
+
+ /* Workaround to over come Errata #648 */
+ orgctrlval = readl(&regs->aes_control);
+ ctrl = (0x00002004 | dec_enc); /* AES256(CBC) */
+
+ if (ctrl != orgctrlval) {
+ writel(ctrl, &regs->aes_control);
+
+ if (ctrl != readl(&regs->aes_control)) {
+ u32 read_ctrl;
+ int intwr;
+
+ for (wrtimeout = 0; wrtimeout < 1000; wrtimeout++) {
+ for (intwr = 0 ; intwr < 10; intwr++) {
+ writel(ctrl, &regs->aes_control);
+ writew(ctrl, (u16 *)&regs->aes_control + 1);
+ /* Write configurable info in a single write operation */
+ mb();
+ }
+
+ read_ctrl = readl(&regs->aes_control);
+ if (ctrl == read_ctrl)
+ break;
+ }
+
+ if (wrtimeout == 1000) {
+ printf("\nTIMEOUT expected data=0x%x Actual AES_CONTROL data 0x%x\n\n",
+ ctrl, read_ctrl);
+ return -EAGAIN;
+ }
+
+ printf("Workaround success, wrtimeout = %d\n", wrtimeout);
+ }
+ }
+
+ if (second_timeout(&regs->aes_busy, AES_BUSY_BIT, AES_BUSY_BIT))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static inline void npcm_aes_load_iv(u8 *iv)
+{
+ struct npcm_aes_regs *regs = aes_priv->regs;
+ u32 *p = (u32 *)iv;
+ u32 i;
+
+ /* Initialization Vector is loaded in 32-bit chunks */
+ for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++)
+ writel(p[i], &regs->aes_iv_0 + i);
+}
+
+static inline void npcm_aes_load_key(u8 *key)
+{
+ struct npcm_aes_regs *regs = aes_priv->regs;
+ u32 *p = (u32 *)key;
+ u32 i;
+
+ /* The key can be loaded either via the configuration or by using sideband
+ * key port (aes_select_key).
+ * If aes_select_key has been called ('fkeyind_to_set' was set to desired
+ * key index) and no key is specified (key is NULL), we should use the
+ * key index. Otherwise, we write the given key to the registers.
+ */
+ if (!key && fkeyind_to_set < 4) {
+ npcm_otp_select_key(fkeyind_to_set);
+
+ /* Sample the new key */
+ writel(readl(&regs->aes_sk) | AES_SK_BIT, &regs->aes_sk);
+
+ } else {
+ /* Initialization Vector is loaded in 32-bit chunks */
+ for (i = 0; i < (2 * SIZE_AES_BLOCK / sizeof(u32)); i++)
+ writel(p[i], &regs->aes_key_0 + i);
+
+ fkeyind_to_set = 0xff;
+ }
+}
+
+static inline void npcm_aes_write(u32 *in)
+{
+ struct npcm_aes_regs *regs = aes_priv->regs;
+ u32 i;
+
+ /* 16 Byte AES Block is written in 32-bit chunks */
+ for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++)
+ writel(in[i], &regs->aes_fifo_data);
+}
+
+static inline void npcm_aes_read(u32 *out)
+{
+ struct npcm_aes_regs *regs = aes_priv->regs;
+ u32 i;
+
+ /* Data is read in 32-bit chunks */
+ for (i = 0; i < (SIZE_AES_BLOCK / sizeof(u32)); i++)
+ out[i] = readl(&regs->aes_fifo_data);
+}
+
+static void npcm_aes_feed(u32 num_aes_blocks, u32 *datain, u32 *dataout)
+{
+ struct npcm_aes_regs *regs = aes_priv->regs;
+ u32 aes_datablk;
+ u32 total_blocks = num_aes_blocks;
+ u32 blocks_left = num_aes_blocks;
+
+ /* data mode */
+ writel(readl(&regs->aes_busy) | AES_BUSY_BIT, &regs->aes_busy);
+
+ /* Clear overflow and underflow */
+ writel(readl(&regs->aes_fifo_status) | DIN_FIFO_OVERFLOW, &regs->aes_fifo_status);
+ writel(readl(&regs->aes_fifo_status) | DOUT_FIFO_UNDERFLOW, &regs->aes_fifo_status);
+
+ /* datain/dataout is advanced in 32-bit chunks */
+ aes_datablk = (SIZE_AES_BLOCK / sizeof(u32));
+
+ /* Quit if there is no complete blocks */
+ if (total_blocks == 0)
+ return;
+
+ /* Write the first block */
+ if (total_blocks > 1) {
+ npcm_aes_write(datain);
+ datain += aes_datablk;
+ blocks_left--;
+ }
+
+ /* Write the second block */
+ if (total_blocks > 2) {
+ second_timeout(&regs->aes_fifo_status, DIN_FIFO_EMPTY, 0);
+ npcm_aes_write(datain);
+ datain += aes_datablk;
+ blocks_left--;
+ }
+
+ /* Write & read available blocks */
+ while (blocks_left > 0) {
+ second_timeout(&regs->aes_fifo_status, DIN_FIFO_FULL, DIN_FIFO_FULL);
+
+ /* Write next block */
+ npcm_aes_write(datain);
+ datain += aes_datablk;
+
+ /* Wait till DOUT FIFO is empty */
+ second_timeout(&regs->aes_fifo_status, DOUT_FIFO_EMPTY, DOUT_FIFO_EMPTY);
+
+ /* Read next block */
+ npcm_aes_read(dataout);
+ dataout += aes_datablk;
+
+ blocks_left--;
+ }
+
+ if (total_blocks > 2) {
+ second_timeout(&regs->aes_fifo_status, DOUT_FIFO_FULL, 0);
+
+ /* Read next block */
+ npcm_aes_read(dataout);
+ dataout += aes_datablk;
+
+ second_timeout(&regs->aes_fifo_status, DOUT_FIFO_FULL, 0);
+
+ /* Read next block */
+ npcm_aes_read(dataout);
+ dataout += aes_datablk;
+ } else if (total_blocks > 1) {
+ second_timeout(&regs->aes_fifo_status, DOUT_FIFO_FULL, 0);
+
+ /* Read next block */
+ npcm_aes_read(dataout);
+ dataout += aes_datablk;
+ }
+}
+
+void aes_expand_key(u8 *key, u32 key_size, u8 *expkey)
+{
+ /* npcm hw expands the key automatically, just copy it */
+ memcpy(expkey, key, SIZE_AES_BLOCK * 2);
+}
+
+void aes_cbc_encrypt_blocks(u32 key_size, u8 *key_exp, u8 *iv, u8 *src, u8 *dst,
+ u32 num_aes_blocks)
+{
+ if (npcm_aes_init(AES_OP_ENCRYPT))
+ return;
+
+ npcm_aes_load_iv(iv);
+
+ npcm_aes_load_key(key_exp);
+
+ npcm_aes_feed(num_aes_blocks, (u32 *)src, (u32 *)dst);
+}
+
+void aes_cbc_decrypt_blocks(u32 key_size, u8 *key_exp, u8 *iv, u8 *src, u8 *dst,
+ u32 num_aes_blocks)
+{
+ if (npcm_aes_init(AES_OP_DECRYPT))
+ return;
+
+ npcm_aes_load_iv(iv);
+
+ npcm_aes_load_key(key_exp);
+
+ npcm_aes_feed(num_aes_blocks, (u32 *)src, (u32 *)dst);
+}
+
+static int npcm_aes_bind(struct udevice *dev)
+{
+ aes_priv = calloc(1, sizeof(struct npcm_aes_priv));
+ if (!aes_priv) {
+ printf("%s: %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ aes_priv->regs = dev_read_addr_ptr(dev);
+ if (!aes_priv->regs) {
+ printf("Cannot find aes reg address, binding failed\n");
+ return -EINVAL;
+ }
+
+ printf("AES: NPCM AES module bind OK\n");
+
+ return 0;
+}
+
+static const struct udevice_id npcm_aes_ids[] = {
+ { .compatible = "nuvoton,npcm845-aes" },
+ { .compatible = "nuvoton,npcm750-aes" },
+ { }
+};
+
+U_BOOT_DRIVER(npcm_aes) = {
+ .name = "npcm_aes",
+ .id = UCLASS_MISC,
+ .of_match = npcm_aes_ids,
+ .priv_auto = sizeof(struct npcm_aes_priv),
+ .bind = npcm_aes_bind,
+};
diff --git a/drivers/crypto/nuvoton/npcm_sha.c b/drivers/crypto/nuvoton/npcm_sha.c
new file mode 100644
index 00000000000..7ebdfa16f4f
--- /dev/null
+++ b/drivers/crypto/nuvoton/npcm_sha.c
@@ -0,0 +1,897 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Nuvoton Technology Corp.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <hash.h>
+#include <malloc.h>
+#include <uboot_aes.h>
+#include <asm/io.h>
+
+#define HASH_DIG_H_NUM 8
+
+#define HASH_CTR_STS_SHA_EN BIT(0)
+#define HASH_CTR_STS_SHA_BUSY BIT(1)
+#define HASH_CTR_STS_SHA_RST BIT(2)
+#define HASH_CFG_SHA1_SHA2 BIT(0)
+
+/* SHA type */
+enum npcm_sha_type {
+ npcm_sha_type_sha2 = 0,
+ npcm_sha_type_sha1,
+ npcm_sha_type_num
+};
+
+struct npcm_sha_regs {
+ unsigned int hash_data_in;
+ unsigned char hash_ctr_sts;
+ unsigned char reserved_0[0x03];
+ unsigned char hash_cfg;
+ unsigned char reserved_1[0x03];
+ unsigned char hash_ver;
+ unsigned char reserved_2[0x13];
+ unsigned int hash_dig[HASH_DIG_H_NUM];
+};
+
+struct npcm_sha_priv {
+ struct npcm_sha_regs *regs;
+};
+
+static struct npcm_sha_priv *sha_priv;
+
+#ifdef SHA_DEBUG_MODULE
+#define sha_print(fmt, args...) printf(fmt, ##args)
+#else
+#define sha_print(fmt, args...) (void)0
+#endif
+
+#define SHA_BLOCK_LENGTH (512 / 8)
+#define SHA_2_HASH_LENGTH (256 / 8)
+#define SHA_1_HASH_LENGTH (160 / 8)
+#define SHA_HASH_LENGTH(type) ((type == npcm_sha_type_sha2) ? \
+ (SHA_2_HASH_LENGTH) : (SHA_1_HASH_LENGTH))
+
+#define SHA_SECRUN_BUFF_SIZE 64
+#define SHA_TIMEOUT 100
+#define SHA_DATA_LAST_BYTE 0x80
+
+#define SHA2_NUM_OF_SELF_TESTS 3
+#define SHA1_NUM_OF_SELF_TESTS 4
+
+#define NUVOTON_ALIGNMENT 4
+
+/*-----------------------------------------------------------------------------*/
+/* SHA instance struct handler */
+/*-----------------------------------------------------------------------------*/
+struct SHA_HANDLE_T {
+ u32 hv[SHA_2_HASH_LENGTH / sizeof(u32)];
+ u32 length0;
+ u32 length1;
+ u32 block[SHA_BLOCK_LENGTH / sizeof(u32)];
+ u8 type;
+ bool active;
+};
+
+// The # of bytes currently in the sha block buffer
+#define SHA_BUFF_POS(length) ((length) & (SHA_BLOCK_LENGTH - 1))
+
+// The # of free bytes in the sha block buffer
+#define SHA_BUFF_FREE(length) (SHA_BLOCK_LENGTH - SHA_BUFF_POS(length))
+
+static void SHA_FlushLocalBuffer_l(const u32 *buff);
+static int SHA_BusyWait_l(void);
+static void SHA_GetShaDigest_l(u8 *hashdigest, u8 type);
+static void SHA_SetShaDigest_l(const u32 *hashdigest, u8 type);
+static void SHA_SetBlock_l(const u8 *data, u32 len, u16 position, u32 *block);
+static void SHA_ClearBlock_l(u16 len, u16 position, u32 *block);
+static void SHA_SetLength32_l(struct SHA_HANDLE_T *handleptr, u32 *block);
+
+static int SHA_Init(struct SHA_HANDLE_T *handleptr);
+static int SHA_Start(struct SHA_HANDLE_T *handleptr, u8 type);
+static int SHA_Update(struct SHA_HANDLE_T *handleptr, const u8 *buffer, u32 len);
+static int SHA_Finish(struct SHA_HANDLE_T *handleptr, u8 *hashdigest);
+static int SHA_Reset(void);
+static int SHA_Power(bool on);
+#ifdef SHA_PRINT
+static void SHA_PrintRegs(void);
+static void SHA_PrintVersion(void);
+#endif
+
+static struct SHA_HANDLE_T sha_handle;
+
+/*----------------------------------------------------------------------------*/
+/* Checks if give function returns int error, and returns the error */
+/* immediately after SHA disabling */
+/*----------------------------------------------------------------------------*/
+int npcm_sha_check(int status)
+{
+ if (status != 0) {
+ SHA_Power(false);
+ return status;
+ }
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_sha_calc */
+/* */
+/* Parameters: type - SHA module type */
+/* inBuff - Pointer to a buffer containing the data to */
+/* be hashed */
+/* len - Length of the data to hash */
+/* hashDigest - Pointer to a buffer where the reseulting */
+/* digest will be copied to */
+/* */
+/* Returns: 0 on success or other int error code on error */
+/* Side effects: */
+/* Description: */
+/* This routine performs complete SHA calculation in one */
+/* step */
+/*----------------------------------------------------------------------------*/
+int npcm_sha_calc(u8 type, const u8 *inbuff, u32 len, u8 *hashdigest)
+{
+ int status;
+ struct SHA_HANDLE_T handle;
+
+ SHA_Init(&handle);
+ SHA_Power(true);
+ SHA_Reset();
+ SHA_Start(&handle, type);
+ status = SHA_Update(&handle, inbuff, len);
+ npcm_sha_check(status);
+ status = SHA_Finish(&handle, hashdigest);
+ npcm_sha_check(status);
+ SHA_Power(false);
+
+ return 0;
+}
+
+/*
+ * Computes hash value of input pbuf using h/w acceleration
+ *
+ * @param in_addr A pointer to the input buffer
+ * @param bufleni Byte length of input buffer
+ * @param out_addr A pointer to the output buffer. When complete
+ * 32 bytes are copied to pout[0]...pout[31]. Thus, a user
+ * should allocate at least 32 bytes at pOut in advance.
+ * @param chunk_size chunk size for sha256
+ */
+void hw_sha256(const uchar *in_addr, uint buflen, uchar *out_addr, uint chunk_size)
+{
+ puts("\nhw_sha256 using BMC HW accelerator\t");
+ npcm_sha_calc(npcm_sha_type_sha2, (u8 *)in_addr, buflen, (u8 *)out_addr);
+}
+
+/*
+ * Computes hash value of input pbuf using h/w acceleration
+ *
+ * @param in_addr A pointer to the input buffer
+ * @param bufleni Byte length of input buffer
+ * @param out_addr A pointer to the output buffer. When complete
+ * 32 bytes are copied to pout[0]...pout[31]. Thus, a user
+ * should allocate at least 32 bytes at pOut in advance.
+ * @param chunk_size chunk_size for sha1
+ */
+void hw_sha1(const uchar *in_addr, uint buflen, uchar *out_addr, uint chunk_size)
+{
+ puts("\nhw_sha1 using BMC HW accelerator\t");
+ npcm_sha_calc(npcm_sha_type_sha1, (u8 *)in_addr, buflen, (u8 *)out_addr);
+}
+
+/*
+ * Create the context for sha progressive hashing using h/w acceleration
+ *
+ * @algo: Pointer to the hash_algo struct
+ * @ctxp: Pointer to the pointer of the context for hashing
+ * @return 0 if ok, -ve on error
+ */
+int hw_sha_init(struct hash_algo *algo, void **ctxp)
+{
+ const char *algo_name1 = "sha1";
+ const char *algo_name2 = "sha256";
+
+ SHA_Init(&sha_handle);
+ SHA_Power(true);
+ SHA_Reset();
+ if (!strcmp(algo_name1, algo->name))
+ return SHA_Start(&sha_handle, npcm_sha_type_sha1);
+ else if (!strcmp(algo_name2, algo->name))
+ return SHA_Start(&sha_handle, npcm_sha_type_sha2);
+ else
+ return -EPROTO;
+}
+
+/*
+ * Update buffer for sha progressive hashing using h/w acceleration
+ *
+ * The context is freed by this function if an error occurs.
+ *
+ * @algo: Pointer to the hash_algo struct
+ * @ctx: Pointer to the context for hashing
+ * @buf: Pointer to the buffer being hashed
+ * @size: Size of the buffer being hashed
+ * @is_last: 1 if this is the last update; 0 otherwise
+ * @return 0 if ok, -ve on error
+ */
+int hw_sha_update(struct hash_algo *algo, void *ctx, const void *buf,
+ unsigned int size, int is_last)
+{
+ return SHA_Update(&sha_handle, buf, size);
+}
+
+/*
+ * Copy sha hash result at destination location
+ *
+ * The context is freed after completion of hash operation or after an error.
+ *
+ * @algo: Pointer to the hash_algo struct
+ * @ctx: Pointer to the context for hashing
+ * @dest_buf: Pointer to the destination buffer where hash is to be copied
+ * @size: Size of the buffer being hashed
+ * @return 0 if ok, -ve on error
+ */
+int hw_sha_finish(struct hash_algo *algo, void *ctx, void *dest_buf, int size)
+{
+ int status;
+
+ status = SHA_Finish(&sha_handle, dest_buf);
+ npcm_sha_check(status);
+ return SHA_Power(false);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_Init */
+/* */
+/* Parameters: handlePtr - SHA processing handle pointer */
+/* Returns: 0 on success or other int error code on error. */
+/* Side effects: */
+/* Description: */
+/* This routine initialize the SHA module */
+/*----------------------------------------------------------------------------*/
+static int SHA_Init(struct SHA_HANDLE_T *handleptr)
+{
+ handleptr->active = false;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_Start */
+/* */
+/* Parameters: handlePtr - SHA processing handle pointer */
+/* type - SHA module type */
+/* */
+/* Returns: 0 on success or other int error code on error. */
+/* Side effects: */
+/* Description: */
+/* This routine start a single SHA process */
+/*----------------------------------------------------------------------------*/
+static int SHA_Start(struct SHA_HANDLE_T *handleptr, u8 type)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+
+ // Initialize handle
+ handleptr->length0 = 0;
+ handleptr->length1 = 0;
+ handleptr->type = type;
+ handleptr->active = true;
+
+ // Set SHA type
+ writeb(handleptr->type & HASH_CFG_SHA1_SHA2, &regs->hash_cfg);
+
+ // Reset SHA hardware
+ SHA_Reset();
+
+ /* The handlePtr->hv is initialized with the correct IV as the SHA engine
+ * automatically fill the HASH_DIG_Hn registers according to SHA spec
+ * (following SHA_RST assertion)
+ */
+ SHA_GetShaDigest_l((u8 *)handleptr->hv, type);
+
+ // Init block with zeros
+ memset(handleptr->block, 0, sizeof(handleptr->block));
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_Update */
+/* */
+/* Parameters: handlePtr - SHA processing handle pointer */
+/* buffer - Pointer to the data that will be added to */
+/* the hash calculation */
+/* len - Length of data to add to SHA calculation */
+/* */
+/* */
+/* Returns: 0 on success or other int error code on error */
+/* Side effects: */
+/* Description: */
+/* This routine adds data to previously started SHA */
+/* calculation */
+/*----------------------------------------------------------------------------*/
+static int SHA_Update(struct SHA_HANDLE_T *handleptr, const u8 *buffer, u32 len)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+ u32 localbuffer[SHA_SECRUN_BUFF_SIZE / sizeof(u32)];
+ u32 bufferlen = len;
+ u16 pos = 0;
+ u8 *blockptr;
+ int status;
+
+ // Error check
+ if (!handleptr->active)
+ return -EPROTO;
+
+ // Wait till SHA is not busy
+ status = SHA_BusyWait_l();
+ npcm_sha_check(status);
+
+ // Set SHA type
+ writeb(handleptr->type & HASH_CFG_SHA1_SHA2, &regs->hash_cfg);
+
+ // Write SHA latest digest into SHA module
+ SHA_SetShaDigest_l(handleptr->hv, handleptr->type);
+
+ // Set number of unhashed bytes which remained from last update
+ pos = SHA_BUFF_POS(handleptr->length0);
+
+ // Copy unhashed bytes which remained from last update to secrun buffer
+ SHA_SetBlock_l((u8 *)handleptr->block, pos, 0, localbuffer);
+
+ while (len) {
+ // Wait for the hardware to be available (in case we are hashing)
+ status = SHA_BusyWait_l();
+ npcm_sha_check(status);
+
+ // Move as much bytes as we can into the secrun buffer
+ bufferlen = min(len, SHA_BUFF_FREE(handleptr->length0));
+
+ // Copy current given buffer to the secrun buffer
+ SHA_SetBlock_l((u8 *)buffer, bufferlen, pos, localbuffer);
+
+ // Update size of hashed bytes
+ handleptr->length0 += bufferlen;
+
+ if (handleptr->length0 < bufferlen)
+ handleptr->length1++;
+
+ // Update length of data left to digest
+ len -= bufferlen;
+
+ // Update given buffer pointer
+ buffer += bufferlen;
+
+ // If secrun buffer is full
+ if (SHA_BUFF_POS(handleptr->length0) == 0) {
+ /* We just filled up the buffer perfectly, so let it hash (we'll
+ * unload the hash only when we are done with all hashing)
+ */
+ SHA_FlushLocalBuffer_l(localbuffer);
+
+ pos = 0;
+ bufferlen = 0;
+ }
+ }
+
+ // Wait till SHA is not busy
+ status = SHA_BusyWait_l();
+ npcm_sha_check(status);
+
+ /* Copy unhashed bytes from given buffer to handle block for next update/finish */
+ blockptr = (u8 *)handleptr->block;
+ while (bufferlen)
+ blockptr[--bufferlen + pos] = *(--buffer);
+
+ // Save SHA current digest
+ SHA_GetShaDigest_l((u8 *)handleptr->hv, handleptr->type);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_Finish */
+/* */
+/* Parameters: handlePtr - SHA processing handle pointer */
+/* hashDigest - Pointer to a buffer where the final digest */
+/* will be copied to */
+/* */
+/* Returns: 0 on success or other int error code on error */
+/* Side effects: */
+/* Description: */
+/* This routine finish SHA calculation and get */
+/* the resulting SHA digest */
+/*----------------------------------------------------------------------------*/
+static int SHA_Finish(struct SHA_HANDLE_T *handleptr, u8 *hashdigest)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+ u32 localbuffer[SHA_SECRUN_BUFF_SIZE / sizeof(u32)];
+ const u8 lastbyte = SHA_DATA_LAST_BYTE;
+ u16 pos;
+ int status;
+
+ // Error check
+ if (!handleptr->active)
+ return -EPROTO;
+
+ // Set SHA type
+ writeb(handleptr->type & HASH_CFG_SHA1_SHA2, &regs->hash_cfg);
+
+ // Wait till SHA is not busy
+ status = SHA_BusyWait_l();
+ npcm_sha_check(status);
+
+ // Finish off the current buffer with the SHA spec'ed padding
+ pos = SHA_BUFF_POS(handleptr->length0);
+
+ // Init SHA digest
+ SHA_SetShaDigest_l(handleptr->hv, handleptr->type);
+
+ // Load data into secrun buffer
+ SHA_SetBlock_l((u8 *)handleptr->block, pos, 0, localbuffer);
+
+ // Set data last byte as in SHA algorithm spec
+ SHA_SetBlock_l(&lastbyte, 1, pos++, localbuffer);
+
+ // If the remainder of data is longer then one block
+ if (pos > (SHA_BLOCK_LENGTH - 8)) {
+ /* The length will be in the next block Pad the rest of the last block with 0's */
+ SHA_ClearBlock_l((SHA_BLOCK_LENGTH - pos), pos, localbuffer);
+
+ // Hash the current block
+ SHA_FlushLocalBuffer_l(localbuffer);
+
+ pos = 0;
+
+ // Wait till SHA is not busy
+ status = SHA_BusyWait_l();
+ npcm_sha_check(status);
+ }
+
+ // Pad the rest of the last block with 0's except for the last 8-3 bytes
+ SHA_ClearBlock_l((SHA_BLOCK_LENGTH - (8 - 3)) - pos, pos, localbuffer);
+
+ /* The last 8-3 bytes are set to the bit-length of the message in big-endian form */
+ SHA_SetLength32_l(handleptr, localbuffer);
+
+ // Hash all that, and save the hash for the caller
+ SHA_FlushLocalBuffer_l(localbuffer);
+
+ // Wait till SHA is not busy
+ status = SHA_BusyWait_l();
+ npcm_sha_check(status);
+
+ // Save SHA final digest into given buffer
+ SHA_GetShaDigest_l(hashdigest, handleptr->type);
+
+ // Free handle
+ handleptr->active = false;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_Reset */
+/* */
+/* Parameters: none */
+/* Returns: none */
+/* Side effects: */
+/* Description: */
+/* This routine reset SHA module */
+/*----------------------------------------------------------------------------*/
+static int SHA_Reset(void)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+
+ writel(readl(&regs->hash_ctr_sts) | HASH_CTR_STS_SHA_RST, &regs->hash_ctr_sts);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_Power */
+/* */
+/* Parameters: on - true enable the module, false disable the module */
+/* Returns: none */
+/* Side effects: */
+/* Description: */
+/* This routine set SHA module power on/off */
+/*----------------------------------------------------------------------------*/
+static int SHA_Power(bool on)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+ u8 hash_sts;
+
+ hash_sts = readb(&regs->hash_ctr_sts) & ~HASH_CTR_STS_SHA_EN;
+ writeb(hash_sts | (on & HASH_CTR_STS_SHA_EN), &regs->hash_ctr_sts);
+
+ return 0;
+}
+
+#ifdef SHA_PRINT
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_PrintRegs */
+/* */
+/* Parameters: none */
+/* Returns: none */
+/* Side effects: */
+/* Description: */
+/* This routine prints the module registers */
+/*----------------------------------------------------------------------------*/
+static void SHA_PrintRegs(void)
+{
+#ifdef SHA_DEBUG_MODULE
+ struct npcm_sha_regs *regs = sha_priv->regs;
+#endif
+ unsigned int i;
+
+ sha_print("/*--------------*/\n");
+ sha_print("/* SHA */\n");
+ sha_print("/*--------------*/\n\n");
+
+ sha_print("HASH_CTR_STS = 0x%02X\n", readb(&regs->hash_ctr_sts));
+ sha_print("HASH_CFG = 0x%02X\n", readb(&regs->hash_cfg));
+
+ for (i = 0; i < HASH_DIG_H_NUM; i++)
+ sha_print("HASH_DIG_H%d = 0x%08X\n", i, readl(&regs->hash_dig[i]));
+
+ sha_print("HASH_VER = 0x%08X\n", readb(&regs->hash_ver));
+
+ sha_print("\n");
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_PrintVersion */
+/* */
+/* Parameters: none */
+/* Returns: none */
+/* Side effects: */
+/* Description: */
+/* This routine prints the module version */
+/*----------------------------------------------------------------------------*/
+static void SHA_PrintVersion(void)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+
+ printf("SHA MODULE VER = %d\n", readb(&regs->hash_ver));
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_sha_selftest */
+/* */
+/* Parameters: type - SHA module type */
+/* Returns: 0 on success or other int error code on error */
+/* Side effects: */
+/* Description: */
+/* This routine performs various tests on the SHA HW and SW */
+/*----------------------------------------------------------------------------*/
+int npcm_sha_selftest(u8 type)
+{
+ int status;
+ struct SHA_HANDLE_T handle;
+ u8 hashdigest[max(SHA_1_HASH_LENGTH, SHA_2_HASH_LENGTH)];
+ u16 i, j;
+
+ /*------------------------------------------------------------------------*/
+ /* SHA1 tests info */
+ /*------------------------------------------------------------------------*/
+
+ static const u8 sha1selftestbuff[SHA1_NUM_OF_SELF_TESTS][94] = {
+ {"abc"},
+ {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
+ {"0123456789012345678901234567890123456789012345678901234567890123"},
+ {0x30, 0x5c, 0x30, 0x2c, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x05, 0x2b,
+ 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x30, 0x06, 0x06, 0x04, 0x67, 0x2a,
+ 0x01, 0x0c, 0x04, 0x14, 0xe1, 0xb6, 0x93, 0xfe, 0x33, 0x43, 0xc1, 0x20,
+ 0x5d, 0x4b, 0xaa, 0xb8, 0x63, 0xfb, 0xcf, 0x6c, 0x46, 0x1e, 0x88, 0x04,
+ 0x30, 0x2c, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
+ 0x02, 0x1a, 0x05, 0x00, 0x30, 0x06, 0x06, 0x04, 0x67, 0x2a, 0x01, 0x0c,
+ 0x04, 0x14, 0x13, 0xc1, 0x0c, 0xfc, 0xc8, 0x92, 0xd7, 0xde, 0x07, 0x1c,
+ 0x40, 0xde, 0x4f, 0xcd, 0x07, 0x5b, 0x68, 0x20, 0x5a, 0x6c}
+ };
+
+ static const u8 sha1selftestbufflen[SHA1_NUM_OF_SELF_TESTS] = {
+ 3, 56, 64, 94
+ };
+
+ static const u8 sha1selftestexpres[SHA1_NUM_OF_SELF_TESTS][SHA_1_HASH_LENGTH] = {
+ {0xA9, 0x99, 0x3E, 0x36,
+ 0x47, 0x06, 0x81, 0x6A,
+ 0xBA, 0x3E, 0x25, 0x71,
+ 0x78, 0x50, 0xC2, 0x6C,
+ 0x9C, 0xD0, 0xD8, 0x9D},
+ {0x84, 0x98, 0x3E, 0x44,
+ 0x1C, 0x3B, 0xD2, 0x6E,
+ 0xBA, 0xAE, 0x4A, 0xA1,
+ 0xF9, 0x51, 0x29, 0xE5,
+ 0xE5, 0x46, 0x70, 0xF1},
+ {0xCF, 0x08, 0x00, 0xF7,
+ 0x64, 0x4A, 0xCE, 0x3C,
+ 0xB4, 0xC3, 0xFA, 0x33,
+ 0x38, 0x8D, 0x3B, 0xA0,
+ 0xEA, 0x3C, 0x8B, 0x6E},
+ {0xc9, 0x84, 0x45, 0xc8,
+ 0x64, 0x04, 0xb1, 0xe3,
+ 0x3c, 0x6b, 0x0a, 0x8c,
+ 0x8b, 0x80, 0x94, 0xfc,
+ 0xf3, 0xc9, 0x98, 0xab}
+ };
+
+ /*------------------------------------------------------------------------*/
+ /* SHA2 tests info */
+ /*------------------------------------------------------------------------*/
+
+ static const u8 sha2selftestbuff[SHA2_NUM_OF_SELF_TESTS][100] = {
+ { "abc" },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+ {'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
+ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a'}
+ };
+
+ static const u8 sha2selftestbufflen[SHA2_NUM_OF_SELF_TESTS] = {
+ 3, 56, 100
+ };
+
+ static const u8 sha2selftestexpres[SHA2_NUM_OF_SELF_TESTS][SHA_2_HASH_LENGTH] = {
+ /*
+ * SHA-256 test vectors
+ */
+ { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+ 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+ 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+ 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
+ { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+ 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+ 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+ 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
+ { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
+ 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
+ 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
+ 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 },
+ };
+
+ if (type == npcm_sha_type_sha1) {
+ /*--------------------------------------------------------------------*/
+ /* SHA 1 TESTS */
+ /*--------------------------------------------------------------------*/
+ for (i = 0; i < SHA1_NUM_OF_SELF_TESTS; i++) {
+ if (i != 3) {
+ status = npcm_sha_calc(npcm_sha_type_sha1, sha1selftestbuff[i], sha1selftestbufflen[i], hashdigest);
+ npcm_sha_check(status);
+ } else {
+ SHA_Power(true);
+ SHA_Reset();
+ status = SHA_Start(&handle, npcm_sha_type_sha1);
+ npcm_sha_check(status);
+ status = SHA_Update(&handle, sha1selftestbuff[i], 73);
+ npcm_sha_check(status);
+ status = SHA_Update(&handle, &sha1selftestbuff[i][73], sha1selftestbufflen[i] - 73);
+ npcm_sha_check(status);
+ status = SHA_Finish(&handle, hashdigest);
+ npcm_sha_check(status);
+ SHA_Power(false);
+ }
+
+ if (memcmp(hashdigest, sha1selftestexpres[i], SHA_1_HASH_LENGTH))
+ return -1;
+ }
+
+ } else {
+ /*--------------------------------------------------------------------*/
+ /* SHA 2 TESTS */
+ /*--------------------------------------------------------------------*/
+ for (i = 0; i < SHA2_NUM_OF_SELF_TESTS; i++) {
+ SHA_Power(true);
+ SHA_Reset();
+ status = SHA_Start(&handle, npcm_sha_type_sha2);
+ npcm_sha_check(status);
+ if (i == 2) {
+ for (j = 0; j < 10000; j++) { //not working
+ status = SHA_Update(&handle, sha2selftestbuff[i], sha2selftestbufflen[i]);
+ npcm_sha_check(status);
+ }
+ } else {
+ status = SHA_Update(&handle, sha2selftestbuff[i], sha2selftestbufflen[i]);
+ npcm_sha_check(status);
+ }
+
+ status = SHA_Finish(&handle, hashdigest);
+ npcm_sha_check(status);
+ SHA_Power(false);
+ if (memcmp(hashdigest, sha2selftestexpres[i], SHA_2_HASH_LENGTH))
+ return -1;
+
+ npcm_sha_calc(npcm_sha_type_sha2, sha2selftestbuff[i], sha2selftestbufflen[i], hashdigest);
+ if (memcmp(hashdigest, sha2selftestexpres[i], SHA_2_HASH_LENGTH))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_FlushLocalBuffer_l */
+/* */
+/* Parameters: */
+/* Returns: none */
+/* Side effects: */
+/* Description: This routine flush secrun buffer to SHA module */
+/*----------------------------------------------------------------------------*/
+static void SHA_FlushLocalBuffer_l(const u32 *buff)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+ u32 i;
+
+ for (i = 0; i < (SHA_BLOCK_LENGTH / sizeof(u32)); i++)
+ writel(buff[i], &regs->hash_data_in);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_BusyWait_l */
+/* */
+/* Parameters: */
+/* Returns: 0 if no error was found or DEFS_STATUS_ERROR otherwise */
+/* Side effects: */
+/* Description: This routine wait for SHA unit to no longer be busy */
+/*----------------------------------------------------------------------------*/
+static int SHA_BusyWait_l(void)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+ u32 timeout = SHA_TIMEOUT;
+
+ do {
+ if (timeout-- == 0)
+ return -ETIMEDOUT;
+ } while ((readb(&regs->hash_ctr_sts) & HASH_CTR_STS_SHA_BUSY)
+ == HASH_CTR_STS_SHA_BUSY);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_GetShaDigest_l */
+/* */
+/* Parameters: hashDigest - buffer for the hash output. */
+/* type - SHA module type */
+/* Returns: none */
+/* Side effects: */
+/* Description: This routine copy the hash digest from the hardware */
+/* and into given buffer (in ram) */
+/*----------------------------------------------------------------------------*/
+static void SHA_GetShaDigest_l(u8 *hashdigest, u8 type)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+ u16 j;
+ u8 len = SHA_HASH_LENGTH(type) / sizeof(u32);
+
+ // Copy Bytes from SHA module to given buffer
+ for (j = 0; j < len; j++)
+ ((u32 *)hashdigest)[j] = readl(&regs->hash_dig[j]);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_SetShaDigest_l */
+/* */
+/* Parameters: hashDigest - input buffer to set as hash digest */
+/* type - SHA module type */
+/* Returns: none */
+/* Side effects: */
+/* Description: This routine set the hash digest in the hardware from */
+/* a given buffer (in ram) */
+/*----------------------------------------------------------------------------*/
+static void SHA_SetShaDigest_l(const u32 *hashdigest, u8 type)
+{
+ struct npcm_sha_regs *regs = sha_priv->regs;
+ u16 j;
+ u8 len = SHA_HASH_LENGTH(type) / sizeof(u32);
+
+ // Copy Bytes from given buffer to SHA module
+ for (j = 0; j < len; j++)
+ writel(hashdigest[j], &regs->hash_dig[j]);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_SetBlock_l */
+/* */
+/* Parameters: data - data to copy */
+/* len - size of data */
+/* position - byte offset into the block at which data */
+/* should be placed */
+/* block - block buffer */
+/* Returns: none */
+/* Side effects: */
+/* Description: This routine load bytes into block buffer */
+/*----------------------------------------------------------------------------*/
+static void SHA_SetBlock_l(const u8 *data, u32 len, u16 position, u32 *block)
+{
+ u8 *dest = (u8 *)block;
+
+ memcpy(dest + position, data, len);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_SetBlock_l */
+/* */
+/* Parameters: */
+/* len - size of data */
+/* position - byte offset into the block at which data */
+/* should be placed */
+/* block - block buffer */
+/* Returns: none */
+/* Side effects: */
+/* Description: This routine load zero's into the block buffer */
+/*----------------------------------------------------------------------------*/
+static void SHA_ClearBlock_l(u16 len, u16 position, u32 *block)
+{
+ u8 *dest = (u8 *)block;
+
+ memset(dest + position, 0, len);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: SHA_SetLength32_l */
+/* */
+/* Parameters: */
+/* handlePtr - SHA processing handle pointer */
+/* block - block buffer */
+/* Returns: none */
+/* Side effects: */
+/* Description: This routine set the length of the hash's data */
+/* len is the 32-bit byte length of the message */
+/*lint -efunc(734,SHA_SetLength32_l) Supperess loss of percision lint warning */
+/*----------------------------------------------------------------------------*/
+static void SHA_SetLength32_l(struct SHA_HANDLE_T *handleptr, u32 *block)
+{
+ u16 *secrunbufferswappedptr = (u16 *)(void *)(block);
+
+ secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 1] = (u16)
+ ((handleptr->length0 << 3) << 8) | ((u16)(handleptr->length0 << 3) >> 8);
+ secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 2] = (u16)
+ ((handleptr->length0 >> (16 - 3)) >> 8) | ((u16)(handleptr->length0 >> (16 - 3)) << 8);
+ secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 3] = (u16)
+ ((handleptr->length1 << 3) << 8) | ((u16)(handleptr->length1 << 3) >> 8);
+ secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 4] = (u16)
+ ((handleptr->length1 >> (16 - 3)) >> 8) | ((u16)(handleptr->length1 >> (16 - 3)) << 8);
+}
+
+static int npcm_sha_bind(struct udevice *dev)
+{
+ sha_priv = calloc(1, sizeof(struct npcm_sha_priv));
+ if (!sha_priv)
+ return -ENOMEM;
+
+ sha_priv->regs = dev_remap_addr_index(dev, 0);
+ if (!sha_priv->regs) {
+ printf("Cannot find sha reg address, binding failed\n");
+ return -EINVAL;
+ }
+
+ printf("SHA: NPCM SHA module bind OK\n");
+
+ return 0;
+}
+
+static const struct udevice_id npcm_sha_ids[] = {
+ { .compatible = "nuvoton,npcm845-sha" },
+ { .compatible = "nuvoton,npcm750-sha" },
+ { }
+};
+
+U_BOOT_DRIVER(npcm_sha) = {
+ .name = "npcm_sha",
+ .id = UCLASS_MISC,
+ .of_match = npcm_sha_ids,
+ .priv_auto = sizeof(struct npcm_sha_priv),
+ .bind = npcm_sha_bind,
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7b6c371d1c2..28d5da49ff1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -321,6 +321,15 @@ config SPL_MXC_OCOTP
Programmable memory pages, that are stored on some
Freescale i.MX processors, in SPL.
+config NPCM_OTP
+ bool "Nnvoton NPCM BMC On-Chip OTP Memory Support"
+ depends on (ARM && ARCH_NPCM)
+ default n
+ help
+ Support NPCM BMC OTP memory (fuse).
+ To compile this driver as a module, choose M here: the module
+ will be called npcm_otp.
+
config NUVOTON_NCT6102D
bool "Enable Nuvoton NCT6102D Super I/O driver"
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 0a333640b9f..0bf05ca05ef 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
obj-$(CONFIG_$(SPL_TPL_)LS2_SFP) += ls2_sfp.o
obj-$(CONFIG_$(SPL_)MXC_OCOTP) += mxc_ocotp.o
obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
+obj-$(CONFIG_NPCM_OTP) += npcm_otp.o
obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_P2SB) += p2sb-uclass.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
diff --git a/drivers/misc/npcm_otp.c b/drivers/misc/npcm_otp.c
new file mode 100644
index 00000000000..304910888bb
--- /dev/null
+++ b/drivers/misc/npcm_otp.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Nuvoton Technology Corp.
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fuse.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <asm/arch/otp.h>
+
+struct npcm_otp_priv {
+ struct npcm_otp_regs *regs[2];
+};
+
+static struct npcm_otp_priv *otp_priv;
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_check_inputs */
+/* */
+/* Parameters: arr - fuse array number to check */
+/* word - fuse word (offset) to check */
+/* Returns: int */
+/* Side effects: */
+/* Description: Checks is arr and word are illegal and do not exceed */
+/* their range. Return 0 if they are legal, -1 if not */
+/*----------------------------------------------------------------------------*/
+static int npcm_otp_check_inputs(u32 arr, u32 word)
+{
+ if (arr >= NPCM_NUM_OF_SA) {
+ if (IS_ENABLED(CONFIG_ARCH_NPCM8XX))
+ printf("\nError: npcm8XX otp includs only one bank: 0\n");
+ if (IS_ENABLED(CONFIG_ARCH_NPCM7XX))
+ printf("\nError: npcm7XX otp includs only two banks: 0 and 1\n");
+ return -1;
+ }
+
+ if (word >= NPCM_OTP_ARR_BYTE_SIZE) {
+ printf("\nError: npcm otp array comprises only %d bytes, numbered from 0 to %d\n",
+ NPCM_OTP_ARR_BYTE_SIZE, NPCM_OTP_ARR_BYTE_SIZE - 1);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_wait_for_otp_ready */
+/* */
+/* Parameters: array - fuse array to wait for */
+/* Returns: int */
+/* Side effects: */
+/* Description: Initialize the Fuse HW module. */
+/*----------------------------------------------------------------------------*/
+static int npcm_otp_wait_for_otp_ready(u32 arr, u32 timeout)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[arr];
+ u32 time = timeout;
+
+ /*------------------------------------------------------------------------*/
+ /* check parameters validity */
+ /*------------------------------------------------------------------------*/
+ if (arr > NPCM_FUSE_SA)
+ return -EINVAL;
+
+ while (--time > 1) {
+ if (readl(&regs->fst) & FST_RDY) {
+ /* fuse is ready, clear the status. */
+ writel(readl(&regs->fst) | FST_RDST, &regs->fst);
+ return 0;
+ }
+ }
+
+ /* try to clear the status in case it was set */
+ writel(readl(&regs->fst) | FST_RDST, &regs->fst);
+
+ return -EINVAL;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_read_byte */
+/* */
+/* 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 npcm_otp_read_byte(u32 arr, u32 addr, u8 *data)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[arr];
+
+ /* Wait for the Fuse Box Idle */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Configure the byte address in the fuse array for read operation */
+ writel(FADDR_VAL(addr, 0), &regs->faddr);
+
+ /* Initiate a read cycle */
+ writel(READ_INIT, &regs->fctl);
+
+ /* Wait for read operation completion */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Read the result */
+ *data = readl(&regs->fdata) & FDATA_MASK;
+
+ /* Clean FDATA contents to prevent unauthorized software from reading
+ * sensitive information
+ */
+ writel(FDATA_CLEAN_VALUE, &regs->fdata);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_bit_is_programmed */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byte_offset - Byte offset in array [input]. */
+/* bit_offset - 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 npcm_otp_bit_is_programmed(u32 arr,
+ u32 byte_offset, u8 bit_offset)
+{
+ u32 data = 0;
+
+ /* Read the entire byte you wish to program */
+ npcm_otp_read_byte(arr, byte_offset, (u8 *)&data);
+
+ /* Check whether the bit is already programmed */
+ if (data & (1 << bit_offset))
+ return true;
+
+ return false;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_program_bit */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byte)offset - Byte offset in array [input]. */
+/* bit_offset - Bit offset in byte [input]. */
+/* Returns: int */
+/* Side effects: */
+/* Description: Program (set to 1) a bit in an OTP storage array. */
+/*----------------------------------------------------------------------------*/
+static int npcm_otp_program_bit(u32 arr, u32 byte_offset,
+ u8 bit_offset)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[arr];
+ int count;
+ u8 read_data;
+
+ /* Wait for the Fuse Box Idle */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Make sure the bit is not already programmed */
+ if (npcm_otp_bit_is_programmed(arr, byte_offset, bit_offset))
+ return 0;
+
+ /* Configure the bit address in the fuse array for program operation */
+ writel(FADDR_VAL(byte_offset, bit_offset), &regs->faddr);
+ writel(readl(&regs->faddr) | FADDR_IN_PROG, &regs->faddr);
+
+ // program up to MAX_PROGRAM_PULSES
+ for (count = 1; count <= MAX_PROGRAM_PULSES; count++) {
+ /* Initiate a program cycle */
+ writel(PROGRAM_ARM, &regs->fctl);
+ writel(PROGRAM_INIT, &regs->fctl);
+
+ /* Wait for program operation completion */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ // after MIN_PROGRAM_PULSES start verifying the result
+ if (count >= MIN_PROGRAM_PULSES) {
+ /* Initiate a read cycle */
+ writel(READ_INIT, &regs->fctl);
+
+ /* Wait for read operation completion */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Read the result */
+ read_data = readl(&regs->fdata) & FDATA_MASK;
+
+ /* If the bit is set the sequence ended correctly */
+ if (read_data & (1 << bit_offset))
+ break;
+ }
+ }
+
+ // check if programmking failed
+ if (count > MAX_PROGRAM_PULSES) {
+ printf("program fail\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Clean FDATA contents to prevent unauthorized software from reading
+ * sensitive information
+ */
+ writel(FDATA_CLEAN_VALUE, &regs->fdata);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_program_byte */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byte_offset - 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 npcm_otp_program_byte(u32 arr, u32 byte_offset,
+ u8 value)
+{
+ int status = 0;
+ unsigned int i;
+ u8 data = 0;
+ int rc;
+
+ rc = npcm_otp_check_inputs(arr, byte_offset);
+ if (rc != 0)
+ return rc;
+
+ /* Wait for the Fuse Box Idle */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Read the entire byte you wish to program */
+ npcm_otp_read_byte(arr, byte_offset, &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 (value & (1 << i)) {
+ /* Program (set to 1) the relevant bit */
+ int last_status = npcm_otp_program_bit(arr, byte_offset, (u8)i);
+
+ if (last_status != 0)
+ status = last_status;
+ }
+ }
+ return status;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_is_fuse_array_disabled */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* Returns: bool */
+/* Side effects: */
+/* Description: Return true if access to the first 2048 bits of the */
+/* specified fuse array is disabled, false if not */
+/*----------------------------------------------------------------------------*/
+bool npcm_otp_is_fuse_array_disabled(u32 arr)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[arr];
+
+ return (readl(&regs->fcfg) & FCFG_FDIS) != 0;
+}
+
+int npcm_otp_select_key(u8 key_index)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[NPCM_KEY_SA];
+ u32 idx = 0;
+ u32 time = 0xDAEDBEEF;
+
+ if (key_index >= 4)
+ return -1;
+
+ /* Do not destroy ECCDIS bit */
+ idx = readl(&regs->fustrap_fkeyind);
+
+ /* Configure the key size */
+ idx &= ~FKEYIND_KSIZE_MASK;
+ idx |= FKEYIND_KSIZE_256;
+
+ /* Configure the key index (0 to 3) */
+ idx &= ~FKEYIND_KIND_MASK;
+ idx |= FKEYIND_KIND_KEY(key_index);
+
+ writel(idx, &regs->fustrap_fkeyind);
+
+ /* Wait for selection completetion */
+ while (--time > 1) {
+ if (readl(&regs->fustrap_fkeyind) & FKEYIND_KVAL)
+ return 0;
+ udelay(1);
+ }
+
+ return -1;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_nibble_parity_ecc_encode */
+/* */
+/* Parameters: datain - pointer to decoded data buffer */
+/* dataout - pointer to encoded data buffer (buffer size */
+/* should be 2 x dataout) */
+/* size - size of encoded data (decoded data x 2) */
+/* Returns: none */
+/* Side effects: */
+/* Description: Decodes the data according to nibble parity ECC scheme. */
+/* Size specifies the encoded data size. */
+/* Decodes whole bytes only */
+/*----------------------------------------------------------------------------*/
+void npcm_otp_nibble_parity_ecc_encode(u8 *datain, u8 *dataout, u32 size)
+{
+ u32 i, idx;
+ u8 E0, E1, E2, E3;
+
+ for (i = 0; i < (size / 2); i++) {
+ E0 = (datain[i] >> 0) & 0x01;
+ E1 = (datain[i] >> 1) & 0x01;
+ E2 = (datain[i] >> 2) & 0x01;
+ E3 = (datain[i] >> 3) & 0x01;
+
+ idx = i * 2;
+ dataout[idx] = datain[i] & 0x0f;
+ dataout[idx] |= (E0 ^ E1) << 4;
+ dataout[idx] |= (E2 ^ E3) << 5;
+ dataout[idx] |= (E0 ^ E2) << 6;
+ dataout[idx] |= (E1 ^ E3) << 7;
+
+ E0 = (datain[i] >> 4) & 0x01;
+ E1 = (datain[i] >> 5) & 0x01;
+ E2 = (datain[i] >> 6) & 0x01;
+ E3 = (datain[i] >> 7) & 0x01;
+
+ idx = i * 2 + 1;
+ dataout[idx] = (datain[i] & 0xf0) >> 4;
+ dataout[idx] |= (E0 ^ E1) << 4;
+ dataout[idx] |= (E2 ^ E3) << 5;
+ dataout[idx] |= (E0 ^ E2) << 6;
+ dataout[idx] |= (E1 ^ E3) << 7;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_majority_rule_ecc_encode */
+/* */
+/* Parameters: datain - pointer to decoded data buffer */
+/* dataout - pointer to encoded data buffer (buffer size */
+/* should be 3 x dataout) */
+/* size - size of encoded data (decoded data x 3) */
+/* Returns: none */
+/* Side effects: */
+/* Description: Decodes the data according to Major Rule ECC scheme. */
+/* Size specifies the encoded data size. */
+/* Decodes whole bytes only */
+/*----------------------------------------------------------------------------*/
+void npcm_otp_majority_rule_ecc_encode(u8 *datain, u8 *dataout, u32 size)
+{
+ u32 byte;
+ u32 bit;
+ u8 bit_val;
+ u32 decoded_size = size / 3;
+
+ for (byte = 0; byte < decoded_size; byte++) {
+ for (bit = 0; bit < 8; bit++) {
+ bit_val = (datain[byte] >> bit) & 0x01;
+
+ if (bit_val) {
+ dataout[byte] |= (1 << bit);
+ dataout[decoded_size + byte] |= (1 << bit);
+ dataout[decoded_size * 2 + byte] |= (1 << bit);
+ } else {
+ dataout[byte] &= ~(1 << bit);
+ dataout[decoded_size + byte] &= ~(1 << bit);
+ dataout[decoded_size * 2 + byte] &= ~(1 << bit);
+ }
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: fuse_program_data */
+/* */
+/* Parameters: bank - Storage Array type [input]. */
+/* word - Byte offset in array [input]. */
+/* data - Pointer to data buffer to program. */
+/* size - Number of bytes to program. */
+/* Returns: none */
+/* Side effects: */
+/* Description: Programs the given byte array (size bytes) to the given */
+/* OTP storage array, starting from offset word. */
+/*----------------------------------------------------------------------------*/
+int fuse_program_data(u32 bank, u32 word, u8 *data, u32 size)
+{
+ u32 arr = (u32)bank;
+ u32 byte;
+ int rc;
+
+ rc = npcm_otp_check_inputs(bank, word + size - 1);
+ if (rc != 0)
+ return rc;
+
+ for (byte = 0; byte < size; byte++) {
+ u8 val;
+
+ val = data[byte];
+ if (val == 0) // optimization
+ continue;
+
+ rc = npcm_otp_program_byte(arr, word + byte, data[byte]);
+ if (rc != 0)
+ return rc;
+
+ // verify programming of every '1' bit
+ val = 0;
+ npcm_otp_read_byte((u32)bank, byte, &val);
+ if ((data[byte] & ~val) != 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+int fuse_prog_image(u32 bank, uintptr_t address)
+{
+ return fuse_program_data(bank, 0, (u8 *)address, NPCM_OTP_ARR_BYTE_SIZE);
+}
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ int rc = npcm_otp_check_inputs(bank, word);
+
+ if (rc != 0)
+ return rc;
+
+ *val = 0;
+ npcm_otp_read_byte((u32)bank, word, (u8 *)val);
+
+ return 0;
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ /* We do not support overriding */
+ return -EINVAL;
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ int rc;
+
+ rc = npcm_otp_check_inputs(bank, word);
+ if (rc != 0)
+ return rc;
+
+ return npcm_otp_program_byte(bank, word, (u8)val);
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ /* We do not support overriding */
+ return -EINVAL;
+}
+
+static int npcm_otp_bind(struct udevice *dev)
+{
+ struct npcm_otp_regs *regs;
+
+ otp_priv = calloc(1, sizeof(struct npcm_otp_priv));
+ if (!otp_priv)
+ return -ENOMEM;
+
+ regs = dev_remap_addr_index(dev, 0);
+ if (!regs) {
+ printf("Cannot find reg address (arr #0), binding failed\n");
+ return -EINVAL;
+ }
+ otp_priv->regs[0] = regs;
+
+ if (IS_ENABLED(CONFIG_ARCH_NPCM7xx)) {
+ regs = dev_remap_addr_index(dev, 1);
+ if (!regs) {
+ printf("Cannot find reg address (arr #1), binding failed\n");
+ return -EINVAL;
+ }
+ otp_priv->regs[1] = regs;
+ }
+ printf("OTP: NPCM OTP module bind OK\n");
+
+ return 0;
+}
+
+static const struct udevice_id npcm_otp_ids[] = {
+ { .compatible = "nuvoton,npcm845-otp" },
+ { .compatible = "nuvoton,npcm750-otp" },
+ { }
+};
+
+U_BOOT_DRIVER(npcm_otp) = {
+ .name = "npcm_otp",
+ .id = UCLASS_MISC,
+ .of_match = npcm_otp_ids,
+ .priv_auto = sizeof(struct npcm_otp_priv),
+ .bind = npcm_otp_bind,
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a1e515cb2bc..e48d72d7445 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -186,6 +186,12 @@ config FSL_QSPI_AHB_FULL_MAP
Enable the Freescale QSPI driver to use full AHB memory map space for
flash access.
+config GXP_SPI
+ bool "SPI driver for GXP"
+ imply SPI_FLASH_BAR
+ help
+ Enable support for SPI on GXP.
+
config ICH_SPI
bool "Intel ICH SPI driver"
help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 06e81b465bc..8755408e629 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
obj-$(CONFIG_SYNQUACER_SPI) += spi-synquacer.o
+obj-$(CONFIG_GXP_SPI) += gxp_spi.o
obj-$(CONFIG_ICH_SPI) += ich.o
obj-$(CONFIG_IPROC_QSPI) += iproc_qspi.o
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
diff --git a/drivers/spi/gxp_spi.c b/drivers/spi/gxp_spi.c
new file mode 100644
index 00000000000..70d76ac66ad
--- /dev/null
+++ b/drivers/spi/gxp_spi.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GXP SPI driver
+ *
+ * (C) Copyright 2022 Hewlett Packard Enterprise Development LP.
+ * Author: Nick Hawkins <[email protected]>
+ * Author: Jean-Marie Verdun <[email protected]>
+ */
+
+#include <spi.h>
+#include <asm/io.h>
+#include <dm.h>
+
+#define GXP_SPI0_MAX_CHIPSELECT 2
+
+#define MANUAL_MODE 0
+#define AUTO_MODE 1
+#define OFFSET_SPIMCFG 0x00
+#define OFFSET_SPIMCTRL 0x04
+#define OFFSET_SPICMD 0x05
+#define OFFSET_SPIDCNT 0x06
+#define OFFSET_SPIADDR 0x08
+#define OFFSET_SPILDAT 0x40
+#define GXP_SPILDAT_SIZE 64
+
+#define SPIMCTRL_START 0x01
+#define SPIMCTRL_BUSY 0x02
+
+#define CMD_READ_ARRAY_FAST 0x0b
+
+struct gxp_spi_priv {
+ struct spi_slave slave;
+ void __iomem *base;
+ unsigned int mode;
+
+};
+
+static void spi_set_mode(struct gxp_spi_priv *priv, int mode)
+{
+ unsigned char value;
+
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ if (mode == MANUAL_MODE) {
+ writeb(0x55, priv->base + OFFSET_SPICMD);
+ writeb(0xaa, priv->base + OFFSET_SPICMD);
+ /* clear bit5 and bit4, auto_start and start_mask */
+ value &= ~(0x03 << 4);
+ } else {
+ value |= (0x03 << 4);
+ }
+ writeb(value, priv->base + OFFSET_SPIMCTRL);
+}
+
+static int gxp_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din,
+ unsigned long flags)
+{
+ struct gxp_spi_priv *priv = dev_get_priv(dev->parent);
+ struct spi_slave *slave = dev_get_parent_priv(dev);
+ struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
+
+ unsigned int len = bitlen / 8;
+ unsigned int value;
+ unsigned int addr = 0;
+ unsigned char uchar_out[len];
+ unsigned char *uchar_in = (unsigned char *)din;
+ int read_len;
+ int read_ptr;
+
+ if (dout && din) {
+ /*
+ * error: gxp spi engin cannot send data to dout and read data from din at the same
+ * time
+ */
+ return -1;
+ }
+
+ memset(uchar_out, 0, sizeof(uchar_out));
+ if (dout)
+ memcpy(uchar_out, dout, len);
+
+ if (flags & SPI_XFER_BEGIN) {
+ /* the dout is cmd + addr, cmd=dout[0], add1~3=dout[1~3]. */
+ /* cmd reg */
+ writeb(uchar_out[0], priv->base + OFFSET_SPICMD);
+
+ /* config reg */
+ value = readl(priv->base + OFFSET_SPIMCFG);
+ value &= ~(1 << 24);
+ /* set chipselect */
+ value |= (slave_plat->cs << 24);
+
+ /* addr reg and addr size */
+ if (len >= 4) {
+ addr = uchar_out[1] << 16 | uchar_out[2] << 8 | uchar_out[3];
+ writel(addr, priv->base + OFFSET_SPIADDR);
+ value &= ~(0x07 << 16);
+ /* set the address size to 3 byte */
+ value |= (3 << 16);
+ } else {
+ writel(0, priv->base + OFFSET_SPIADDR);
+ /* set the address size to 0 byte */
+ value &= ~(0x07 << 16);
+ }
+
+ /* dummy */
+ /* clear dummy_cnt to */
+ value &= ~(0x1f << 19);
+ if (uchar_out[0] == CMD_READ_ARRAY_FAST) {
+ /* fast read needs 8 dummy clocks */
+ value |= (8 << 19);
+ }
+
+ writel(value, priv->base + OFFSET_SPIMCFG);
+
+ if (flags & SPI_XFER_END) {
+ /* no data cmd just start it */
+ /* set the data direction bit to 1 */
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ value |= (1 << 3);
+ writeb(value, priv->base + OFFSET_SPIMCTRL);
+
+ /* set the data byte count */
+ writeb(0, priv->base + OFFSET_SPIDCNT);
+
+ /* set the start bit */
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ value |= SPIMCTRL_START;
+ writeb(value, priv->base + OFFSET_SPIMCTRL);
+
+ /* wait busy bit is cleared */
+ do {
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ } while (value & SPIMCTRL_BUSY);
+ return 0;
+ }
+ }
+
+ if (!(flags & SPI_XFER_END) && (flags & SPI_XFER_BEGIN)) {
+ /* first of spi_xfer calls */
+ return 0;
+ }
+
+ /* if dout != null, write data to buf and start transaction */
+ if (dout) {
+ if (len > slave->max_write_size) {
+ printf("SF: write length is too big(>%d)\n", slave->max_write_size);
+ return -1;
+ }
+
+ /* load the data bytes */
+ memcpy((u8 *)priv->base + OFFSET_SPILDAT, dout, len);
+
+ /* write: set the data direction bit to 1 */
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ value |= (1 << 3);
+ writeb(value, priv->base + OFFSET_SPIMCTRL);
+
+ /* set the data byte count */
+ writeb(len, priv->base + OFFSET_SPIDCNT);
+
+ /* set the start bit */
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ value |= SPIMCTRL_START;
+ writeb(value, priv->base + OFFSET_SPIMCTRL);
+
+ /* wait busy bit is cleared */
+ do {
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ } while (value & SPIMCTRL_BUSY);
+
+ return 0;
+ }
+
+ /* if din !=null, start and read data */
+ if (uchar_in) {
+ read_ptr = 0;
+
+ while (read_ptr < len) {
+ read_len = len - read_ptr;
+ if (read_len > GXP_SPILDAT_SIZE)
+ read_len = GXP_SPILDAT_SIZE;
+
+ /* read: set the data direction bit to 0 */
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ value &= ~(1 << 3);
+ writeb(value, priv->base + OFFSET_SPIMCTRL);
+
+ /* set the data byte count */
+ writeb(read_len, priv->base + OFFSET_SPIDCNT);
+
+ /* set the start bit */
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ value |= SPIMCTRL_START;
+ writeb(value, priv->base + OFFSET_SPIMCTRL);
+
+ /* wait busy bit is cleared */
+ do {
+ value = readb(priv->base + OFFSET_SPIMCTRL);
+ } while (value & SPIMCTRL_BUSY);
+
+ /* store the data bytes */
+ memcpy(uchar_in + read_ptr, (u8 *)priv->base + OFFSET_SPILDAT, read_len);
+ /* update read_ptr and addr reg */
+ read_ptr += read_len;
+
+ addr = readl(priv->base + OFFSET_SPIADDR);
+ addr += read_len;
+ writel(addr, priv->base + OFFSET_SPIADDR);
+ }
+
+ return 0;
+ }
+ return -2;
+}
+
+static int gxp_spi_set_speed(struct udevice *dev, unsigned int speed)
+{
+ /* Accept any speed */
+ return 0;
+}
+
+static int gxp_spi_set_mode(struct udevice *dev, unsigned int mode)
+{
+ struct gxp_spi_priv *priv = dev_get_priv(dev->parent);
+
+ priv->mode = mode;
+
+ return 0;
+}
+
+static int gxp_spi_claim_bus(struct udevice *dev)
+{
+ struct gxp_spi_priv *priv = dev_get_priv(dev->parent);
+ unsigned char cmd;
+
+ spi_set_mode(priv, MANUAL_MODE);
+
+ /* exit 4 bytes addr mode, uboot spi_flash only supports 3 byets address mode */
+ cmd = 0xe9;
+ gxp_spi_xfer(dev, 1 * 8, &cmd, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+ return 0;
+}
+
+static int gxp_spi_release_bus(struct udevice *dev)
+{
+ struct gxp_spi_priv *priv = dev_get_priv(dev->parent);
+
+ spi_set_mode(priv, AUTO_MODE);
+
+ return 0;
+}
+
+int gxp_spi_cs_info(struct udevice *bus, unsigned int cs, struct spi_cs_info *info)
+{
+ if (cs < GXP_SPI0_MAX_CHIPSELECT)
+ return 0;
+ else
+ return -ENODEV;
+}
+
+static int gxp_spi_probe(struct udevice *bus)
+{
+ struct gxp_spi_priv *priv = dev_get_priv(bus);
+
+ priv->base = dev_read_addr_ptr(bus);
+ if (!priv->base)
+ return -ENOENT;
+
+ return 0;
+}
+
+static int gxp_spi_child_pre_probe(struct udevice *dev)
+{
+ struct spi_slave *slave = dev_get_parent_priv(dev);
+
+ slave->max_write_size = GXP_SPILDAT_SIZE;
+
+ return 0;
+}
+
+static const struct dm_spi_ops gxp_spi_ops = {
+ .claim_bus = gxp_spi_claim_bus,
+ .release_bus = gxp_spi_release_bus,
+ .xfer = gxp_spi_xfer,
+ .set_speed = gxp_spi_set_speed,
+ .set_mode = gxp_spi_set_mode,
+ .cs_info = gxp_spi_cs_info,
+};
+
+static const struct udevice_id gxp_spi_ids[] = {
+ { .compatible = "hpe,gxp-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(gxp_spi) = {
+ .name = "gxp_spi",
+ .id = UCLASS_SPI,
+ .of_match = gxp_spi_ids,
+ .ops = &gxp_spi_ops,
+ .priv_auto = sizeof(struct gxp_spi_priv),
+ .probe = gxp_spi_probe,
+ .child_pre_probe = gxp_spi_child_pre_probe,
+};
+
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 7b8ab56ed32..d592dba285c 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -139,6 +139,13 @@ config DESIGNWARE_APB_TIMER
Enables support for the Designware APB Timer driver. This timer is
present on Altera SoCFPGA SoCs.
+config GXP_TIMER
+ bool "HPE GXP Timer"
+ depends on TIMER
+ help
+ Enables support for the GXP Timer driver. This timer is
+ present on HPE GXP SoCs.
+
config MPC83XX_TIMER
bool "MPC83xx timer support"
depends on TIMER
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index b2f002d5978..cc2b8516b57 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o
obj-$(CONFIG_$(SPL_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o
obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o
obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o
+obj-$(CONFIG_GXP_TIMER) += gxp-timer.o
obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
obj-$(CONFIG_NOMADIK_MTU_TIMER) += nomadik-mtu-timer.o
obj-$(CONFIG_NPCM_TIMER) += npcm-timer.o
diff --git a/drivers/timer/gxp-timer.c b/drivers/timer/gxp-timer.c
new file mode 100644
index 00000000000..6f316bc8c5c
--- /dev/null
+++ b/drivers/timer/gxp-timer.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GXP timer driver
+ *
+ * (C) Copyright 2022 Hewlett Packard Enterprise Development LP.
+ * Author: Nick Hawkins <[email protected]>
+ * Author: Jean-Marie Verdun <[email protected]>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+
+#define USTIMELO 0x18
+#define USTIMEHI 0x1C
+
+struct gxp_timer_priv {
+ void __iomem *base;
+};
+
+static u64 gxp_timer_get_count(struct udevice *dev)
+{
+ struct gxp_timer_priv *priv = dev_get_priv(dev);
+ u64 val;
+
+ val = readl(priv->base + USTIMEHI);
+ val = (val << 32) | readl(priv->base + USTIMELO);
+
+ return val;
+}
+
+static int gxp_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct gxp_timer_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (!priv->base)
+ return -ENOENT;
+
+ uc_priv->clock_rate = 1000000;
+
+ return 0;
+}
+
+static const struct timer_ops gxp_timer_ops = {
+ .get_count = gxp_timer_get_count,
+};
+
+static const struct udevice_id gxp_timer_ids[] = {
+ { .compatible = "hpe,gxp-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(gxp_timer) = {
+ .name = "gxp-timer",
+ .id = UCLASS_TIMER,
+ .of_match = gxp_timer_ids,
+ .priv_auto = sizeof(struct gxp_timer_priv),
+ .probe = gxp_timer_probe,
+ .ops = &gxp_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};