/*
 * Copyright (c) 2017 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 */

#ifndef ZEPHYR_DRIVERS_CRYPTO_CRYPTO_ATAES132A_PRIV_H_
#define ZEPHYR_DRIVERS_CRYPTO_CRYPTO_ATAES132A_PRIV_H_

#include <zephyr/drivers/i2c.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>

/* Configuration Read Only Registers */
#define ATAES_SERIALNUM_REG	0xF000
#define ATAES_LOTHISTORY_REG	0xF008
#define ATAES_JEDEC_REG		0xF010
#define ATAES_ALGORITHM_REG	0xF015
#define ATAES_EEPAGESIZE_REG	0xF017
#define ATAES_ENCREADSIZE_REG	0xF018
#define ATAES_ENCWRITESIZE_REG	0xF019
#define ATAES_DEVICENUM_REG	0xF01A
#define ATAES_MANUFACTID_REG	0xF02B
#define ATAES_PERMCONFIG_REG	0xF02D

/* Configuration Pre-Lock Writable Registers */
#define ATAES_I2CADDR_REG	0xF040
#define ATAES_CHIPCONFIG_REG	0xF042
#define ATAES_FREESPACE_ADDR	0xF180

/**
 * Counter Config Memory Map
 * ctrid valid entries are [0x0-0xF]
 */
#define ATAES_CTRCFG_REG(ctrid) (0xF060 + (ctrid < 1))

/**
 * Key Config Memory Map
 * keyid valid entries are [0x0-0xF]
 */
#define ATAES_KEYCFG_REG(keyid) (0xF080 + (keyid < 2))

/**
 * Zone Config Memory Map
 * zoneid valid entries are [0x0-0xF]
 */
#define ATAES_ZONECFG_REG(zoneid) (0xF0C0 + (zoneid < 2))

/**
 * Counter Memory Map
 * crtid valid entries are [0x0-0xF] characters
 */
#define ATAES_COUNTER_REG(ctrid) (0xF100 + (ctrid < 3))

/**
 * Small Zone Memory Address
 * Pre-Small Zone Lock Writable
 */
#define ATAES_SMALLZONE_ADDR	0xF1E0

/**
 * Key Memory Map
 * keynum valid entries are [0-F] characters
 */
#define ATAES_KEYMEMMAP_REG(keyid) (0xF2##keyid##0)

#define ATAES_COMMAND_MEM_ADDR		0xFE00
#define ATAES_COMMAND_ADDRR_RESET	0xFFE0
#define ATAES_STATUS_REG		0xFFF0

#define ATAES_STATUS_WIP BIT(0)
#define ATAES_STATUS_WEN BIT(1)
#define ATAES_STATUS_WAK BIT(2)
#define ATAES_STATUS_CRC BIT(4)
#define ATAES_STATUS_RDY BIT(6)
#define ATAES_STATUS_ERR BIT(7)

#define ATAES_VOLATILE_KEYID 0xFF
#define ATAES_VOLATILE_AUTHOK   BIT(0)
#define ATAES_VOLATILE_ENCOK    (BIT(1) & BIT(2))
#define ATAES_VOLATILE_DECOK    BIT(3)
#define ATAES_VOLATILE_RNDNNC   BIT(4)
#define ATAES_VOLATILE_AUTHCO   BIT(5)
#define ATAES_VOLATILE_LEGACYOK BIT(6)

#define ATAES_KEYCONFIG_EXTERNAL	BIT(0)
#define ATAES_KEYCONFIG_RAND_NONCE	BIT(2)
#define ATAES_KEYCONFIG_LEGACYOK	BIT(3)
#define ATAES_KEYCONFIG_AUTHKEY		BIT(4)

#define ATAES_CHIPCONFIG_LEGACYE	BIT(0)

#define ATAES_NONCE_OP		0x01
#define ATAES_ENCRYPT_OP	0x06
#define ATAES_DECRYPT_OP	0x07
#define ATAES_INFO_OP		0x0C
#define ATAES_LEGACY_OP		0x0F
#define ATAES_BLOCKRD_OP	0x10

#define ATAES_MAC_MODE_COUNTER   BIT(5)
#define ATAES_MAC_MODE_SERIAL    BIT(6)
#define ATAES_MAC_MODE_SMALLZONE BIT(7)

#if defined(CONFIG_CRYPTO_ATAES132A_I2C_SPEED_STANDARD)
#define ATAES132A_BUS_SPEED		I2C_SPEED_STANDARD
#else
#define ATAES132A_BUS_SPEED		I2C_SPEED_FAST
#endif

#define CRC16_POLY 0x8005

void ataes132a_atmel_crc(uint8_t *input, uint8_t length,
			 uint8_t *output)
{
	int i, j;
	uint8_t bit;
	uint16_t crc;
	uint16_t double_carry;
	uint8_t higher_crc_bit;

	for (i = 0, crc = 0U; i < length; i++) {
		for (j = 7; j >=  0; j--) {
			bit = !!(input[i] & BIT(j));
			higher_crc_bit = crc >> 15;
			double_carry = (crc & BIT(8)) << 1;
			crc <<= 1;
			crc |= double_carry;

			if ((bit ^ higher_crc_bit)) {
				crc ^= CRC16_POLY;
			}
		}
	}

	*(uint16_t *)output = crc << 8 | crc >> 8;
}

static inline int burst_write_i2c(const struct i2c_dt_spec *spec,
				  uint16_t start_addr, uint8_t *buf,
				  uint8_t num_bytes)
{
	uint8_t addr_buffer[2];
	struct i2c_msg msg[2];

	addr_buffer[1] = start_addr & 0xFF;
	addr_buffer[0] = start_addr >> 8;
	msg[0].buf = addr_buffer;
	msg[0].len = 2U;
	msg[0].flags = I2C_MSG_WRITE;

	msg[1].buf = buf;
	msg[1].len = num_bytes;
	msg[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;

	return i2c_transfer_dt(spec, msg, 2);
}


static inline int burst_read_i2c(const struct i2c_dt_spec *spec,
				 uint16_t start_addr, uint8_t *buf,
				 uint8_t num_bytes)
{
	uint8_t addr_buffer[2];
	struct i2c_msg msg[2];

	addr_buffer[1] = start_addr & 0xFF;
	addr_buffer[0] = start_addr >> 8;
	msg[0].buf = addr_buffer;
	msg[0].len = 2U;
	msg[0].flags = I2C_MSG_WRITE;

	msg[1].buf = buf;
	msg[1].len = num_bytes;
	msg[1].flags = I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP;

	return i2c_transfer_dt(spec, msg, 2);
}

static inline int read_reg_i2c(const struct i2c_dt_spec *spec,
			       uint16_t reg_addr, uint8_t *value)
{
	return burst_read_i2c(spec, reg_addr, value, 1);
}

static inline int write_reg_i2c(const struct i2c_dt_spec *spec,
				uint16_t reg_addr, uint8_t value)
{
	return burst_write_i2c(spec, reg_addr, &value, 1);
}

struct ataes132a_device_config {
	struct i2c_dt_spec i2c;
};

struct ataes132a_device_data {
	const struct device *i2c;
	uint8_t command_buffer[64];
	struct k_sem device_sem;
};

struct ataes132a_driver_state {
	bool in_use;
	uint8_t key_id;
	uint8_t key_config;
	uint8_t chip_config;
};

/**
 * @brief Data structure that describes the ATAES132A device external items
 * used in the CCM MAC generation and authorization processes.
 */
struct ataes132a_mac_packet {
	/** Key storage id used on CCM encryption */
	uint8_t encryption_key_id;
	/** MAC Count value */
	uint8_t encryption_mac_count;
};

/**
 * @brief Data structure that describes the ATAES132A device internal items
 * used in the CCM MAC generation and authorization processes.
 */
struct ataes132a_mac_mode {
	/** Indicates to include the counter value
	 *  in the MAC calculation
	 */
	bool include_counter;
	/** Indicates to include the device serial
	 *  number in the MAC calculation
	 */
	bool include_serial;
	/** Indicates to include the small zone number
	 *  in the MAC calculation
	 */
	bool include_smallzone;
};

/**
 * @brief ATAES132A device initialize function
 *
 * This function receives a reference to the i2c port
 * where the ATES132A device is attached. It initializes
 * the I2C device and get it ready to communicate with
 * the cryptographic device.
 *
 * @param i2c_dev reference to the I2C device where ATES132A is attached.
 *
 * @return Returns 0 in case of success and an error code otherwise.
 */
int ataes132a_init(const struct device *i2c_dev);

/**
 * @brief ATAES132A CCM decrypt function
 *
 * This function performs a CCM decrypt and authorization operation on the
 * input and MAC buffer. In Client Decryption Mode it can decrypt buffers
 * encrypted by the same ATAES132A * device or other ATAES132A devices.
 * In User Decryption Mode it can decrypt buffers encrypted by the Host.
 * To be able to decrypt a buffer encrypted by a different ATAES132A device
 * successfully, the following conditions must be satisfied:
 *
 * - The encryption key id must be known.
 * - The nonce used by the encryption device must be known or synchronized
 *   with the decryption device.
 * - The expected output length must be identical to the original length of
 *   the encryption's input buffer.
 * - The MAC Count of the encryption device must be known.
 * - The MAC Mode must be identical between encrypt and decrypt calls.
 * - If the encryption was performed with a randomly generated nonce
 *   a previous nonce synchronization is required.
 * - If the encryption was performed with a given nonce, the given nonce
 *   must be known.
 *
 * @param i2c_dev Reference to the I2C device where ATES132A is attached.
 *
 * @param key_id Key ID from the ATAS132A key storage. This will be the used
 *		 to decrypt and authenticate the buffer and MAC.
 *
 * @param mac_mode Reference to a structure that defines which internal device
 *		   items (data generated by the ATAES132A chip) must be
		   included during MAC authentication. The values
 *		   must be identical to the ones used during encryption. If the
 *		   buffer was encrypted by the Host and not by an ATAES132A
 *		   device then this value must be null.
 *
 * @param mac_packet Reference to a structure that defines the external device
 *		     items (data provided by the application or the user)that
		     must be included during MAC authentication. The
 *		     values must be identical to those used during encryption.
 *		     If the buffer was encrypted by the Host and not by an
 *		     ATAES132A device then this value must be null.
 *
 * @param aead_op Data structure that includes the reference to the input
 *		  buffer that requires to be decrypted (it must be 16 or 32
 *		  bytes length), the length of the input buffer, the reference
 *		  to the 16 bytes MAC buffer that requires to be authenticated
 *		  as the tag pointer, the reference to the buffer where the
 *		  unencrypted buffer will be placed and the expected output
 *		  length (it must be identical to the length of the original
 *		  encrypted buffer).
 *
 * @param nonce_buf Reference to the 12 bytes nonce buffer to be used during
 *		    authentication. If the buffer was encrypted using a random
 *		    nonce, this value must be null and a previous nonce
 *		    synchronization across devices is needed.
 *
 * @return Returns 0 in case of success and an error code otherwise.
 */
int ataes132a_aes_ccm_decrypt(const struct device *i2c_dev,
			      uint8_t key_id,
			      struct ataes132a_mac_mode *mac_mode,
			      struct ataes132a_mac_packet *mac_packet,
			      struct cipher_aead_pkt *aead_op,
			      uint8_t *nonce_buf);

 /**
  * @brief ATAES132A CCM encrypt function
  *
  * This function performs a CCM encrypt operation on the input buffer.
  * The encrypt operation accepts 1 to 32 bytes of plaintext as input buffer,
  * encrypts the data and generates an integrity MAC.
  * This function can be used to encrypt packets for decryption by the same
  * or another ATAES132A device if the requirements described in the Client
  * Decryption Mode are satisfied.
  *
  * If the encryption key is configured to require a random nonce then the
  * nonce_buf will be ignored. It preferably must be null.
  *
  * @param i2c_dev Reference to the I2C device where ATES132A is attached.
  *
  * @param key_id Key ID from the ATAS132A key storage. This will be the used
  *               to encrypt and generate the buffer and MAC.
  *
  * @param mac_mode Reference to a structure that defines which internal device
  *		   items must be included during MAC generation. The values
  *		   must be known by the decrypt operation. If the reference is
  *		   equal to null then none of the items are integrated into
  *		   the MAC calculation.
  * @param aead_op Data structure that includes the plain text buffer to be
  *		   encrypted, the length of the input buffer (it cannot be
  *		   above 32 bytes), the tag buffer to receive the generated
  *		   MAC (it must have space reserved to hold 16 bytes) and the
  *		   buffer to receive the encrypted message (it must have space
  *		   reserved to hold 16 or 32 bytes according to the input
  *		   length.
  *
  * @param non_buf 12 bytes nonce buffer. If encryption key requires random
  *		  nonce the parameter will be ignored. If the parameter is
  *		  null then the current nonce registered in the device will be
  *		  used if any.
  *
  * @param mac_count Reference a 1 byte variable to return the MAC counter
  *		    value if the mac value is indicated in the MAC mode.
  *
  * @return Returns 0 in case of success and an error code otherwise.
  */
int ataes132a_aes_ccm_encrypt(const struct device *i2c_dev,
			      uint8_t key_id,
			      struct ataes132a_mac_mode *mac_mode,
			      struct cipher_aead_pkt *aead_op,
			      uint8_t *nonce_buf,
			      uint8_t *mac_count);

/**
 * @brief ATAES132A ECM block function
 *
 * This function performs an ECM encrypt operation on the input buffer.
 * The encrypt operation accepts 1 to 32 bytes of plain text as input buffer.
 * The encryption key must be enabled to perform legacy ECM operation.
 * Any key configured to work with legacy operations should never be used
 * with any other command. The ECM operation can be used to exhaustively
 * attack the key.
 *
 * @param i2c_dev Reference to the I2C device where ATES132A is attached.
 *
 * @param key_id Key ID from the ATAS132A key storage.
 *
 * @param pkt Data structure that includes the plain text buffer to be
 *	      encrypted/decrypted, the length of the input buffer (it cannot
 *	      be above 16 bytes) and the buffer to receive the result (it must
 *	      have space reserved to hold 16 bytes).
 *
 * @return Returns 0 in case of success and an error code otherwise.
 */
int ataes132a_aes_ecb_block(const struct device *i2c_dev,
			    uint8_t key_id,
			    struct cipher_pkt *pkt);

#endif /* ZEPHYR_DRIVERS_CRYPTO_CRYPTO_ATAES132A_PRIV_H_ */
