diff options
| author | Tom Rini <[email protected]> | 2022-06-23 08:16:21 -0400 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2022-06-23 08:16:21 -0400 |
| commit | 9121478ee6f2aee381f8fe49d8997d43527d351a (patch) | |
| tree | 44ca356e93474a6d909dd4754288bc92cee33e7c /drivers | |
| parent | 52af0101be55da74a32e9b169864508101f886fe (diff) | |
| parent | 929e581a620feba40bea659725f88b338d8b65ec (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/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/crypto/Makefile | 1 | ||||
| -rw-r--r-- | drivers/crypto/nuvoton/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/crypto/nuvoton/Makefile | 2 | ||||
| -rw-r--r-- | drivers/crypto/nuvoton/npcm_aes.c | 301 | ||||
| -rw-r--r-- | drivers/crypto/nuvoton/npcm_sha.c | 897 | ||||
| -rw-r--r-- | drivers/misc/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/misc/npcm_otp.c | 512 | ||||
| -rw-r--r-- | drivers/spi/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/spi/Makefile | 1 | ||||
| -rw-r--r-- | drivers/spi/gxp_spi.c | 304 | ||||
| -rw-r--r-- | drivers/timer/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/timer/Makefile | 1 | ||||
| -rw-r--r-- | drivers/timer/gxp-timer.c | 64 |
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(®s->aes_sw_reset) | SW_RESET_BIT, ®s->aes_sw_reset); + writel(readl(®s->aes_fifo_status) | DIN_FIFO_OVERFLOW, ®s->aes_fifo_status); + writel(readl(®s->aes_fifo_status) | DOUT_FIFO_UNDERFLOW, ®s->aes_fifo_status); + + /* Workaround to over come Errata #648 */ + orgctrlval = readl(®s->aes_control); + ctrl = (0x00002004 | dec_enc); /* AES256(CBC) */ + + if (ctrl != orgctrlval) { + writel(ctrl, ®s->aes_control); + + if (ctrl != readl(®s->aes_control)) { + u32 read_ctrl; + int intwr; + + for (wrtimeout = 0; wrtimeout < 1000; wrtimeout++) { + for (intwr = 0 ; intwr < 10; intwr++) { + writel(ctrl, ®s->aes_control); + writew(ctrl, (u16 *)®s->aes_control + 1); + /* Write configurable info in a single write operation */ + mb(); + } + + read_ctrl = readl(®s->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(®s->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], ®s->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(®s->aes_sk) | AES_SK_BIT, ®s->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], ®s->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], ®s->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(®s->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(®s->aes_busy) | AES_BUSY_BIT, ®s->aes_busy); + + /* Clear overflow and underflow */ + writel(readl(®s->aes_fifo_status) | DIN_FIFO_OVERFLOW, ®s->aes_fifo_status); + writel(readl(®s->aes_fifo_status) | DOUT_FIFO_UNDERFLOW, ®s->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(®s->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(®s->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(®s->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(®s->aes_fifo_status, DOUT_FIFO_FULL, 0); + + /* Read next block */ + npcm_aes_read(dataout); + dataout += aes_datablk; + + second_timeout(®s->aes_fifo_status, DOUT_FIFO_FULL, 0); + + /* Read next block */ + npcm_aes_read(dataout); + dataout += aes_datablk; + } else if (total_blocks > 1) { + second_timeout(®s->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, ®s->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, ®s->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, ®s->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(®s->hash_ctr_sts) | HASH_CTR_STS_SHA_RST, ®s->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(®s->hash_ctr_sts) & ~HASH_CTR_STS_SHA_EN; + writeb(hash_sts | (on & HASH_CTR_STS_SHA_EN), ®s->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(®s->hash_ctr_sts)); + sha_print("HASH_CFG = 0x%02X\n", readb(®s->hash_cfg)); + + for (i = 0; i < HASH_DIG_H_NUM; i++) + sha_print("HASH_DIG_H%d = 0x%08X\n", i, readl(®s->hash_dig[i])); + + sha_print("HASH_VER = 0x%08X\n", readb(®s->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(®s->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], ®s->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(®s->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(®s->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], ®s->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(®s->fst) & FST_RDY) { + /* fuse is ready, clear the status. */ + writel(readl(®s->fst) | FST_RDST, ®s->fst); + return 0; + } + } + + /* try to clear the status in case it was set */ + writel(readl(®s->fst) | FST_RDST, ®s->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), ®s->faddr); + + /* Initiate a read cycle */ + writel(READ_INIT, ®s->fctl); + + /* Wait for read operation completion */ + npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF); + + /* Read the result */ + *data = readl(®s->fdata) & FDATA_MASK; + + /* Clean FDATA contents to prevent unauthorized software from reading + * sensitive information + */ + writel(FDATA_CLEAN_VALUE, ®s->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), ®s->faddr); + writel(readl(®s->faddr) | FADDR_IN_PROG, ®s->faddr); + + // program up to MAX_PROGRAM_PULSES + for (count = 1; count <= MAX_PROGRAM_PULSES; count++) { + /* Initiate a program cycle */ + writel(PROGRAM_ARM, ®s->fctl); + writel(PROGRAM_INIT, ®s->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, ®s->fctl); + + /* Wait for read operation completion */ + npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF); + + /* Read the result */ + read_data = readl(®s->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, ®s->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(®s->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(®s->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, ®s->fustrap_fkeyind); + + /* Wait for selection completetion */ + while (--time > 1) { + if (readl(®s->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, +}; |
