/*
 * ESP HMAC emulation
 *
 * Copyright (c) 2025 Espressif Systems (Shanghai) Co. Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 or
 * (at your option) any later version.
 */

#pragma once

#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/registerfields.h"
#include "hw/nvram/esp_efuse.h"
#include "crypto/hmac256_i.h"

#define TYPE_ESP_HMAC "misc.esp.hmac"
#define ESP_HMAC(obj) OBJECT_CHECK(ESPHmacState, (obj), TYPE_ESP_HMAC)

#define ESP_HMAC_GET_CLASS(obj) OBJECT_GET_CLASS(ESPHmacClass, obj, TYPE_ESP_HMAC)
#define ESP_HMAC_CLASS(klass) OBJECT_CLASS_CHECK(ESPHmacClass, klass, TYPE_ESP_HMAC)

#define ESP_HMAC_REGS_SIZE (0xFF)

#define ESP_HMAC_WR_MESSAGE_REG_CNT 16
#define ESP_HMAC_RD_RESULT_REG_CNT  8

/* HMAC modes */
#define ESP_HMAC_MODE_UPSTREAM 0
#define ESP_HMAC_MODE_DOWNSTREAM 1

typedef enum {
	HMAC_KEY0 = 0,
	HMAC_KEY1,
	HMAC_KEY2,
	HMAC_KEY3,
	HMAC_KEY4,
	HMAC_KEY5,
	HMAC_KEY_MAX
} HmacKeyId;

typedef struct ESPHmacState {
    SysBusDevice parent_obj;
    MemoryRegion iomem;

    struct hmac_sha256_ctx ctx;
    /* User message value */
    uint32_t message[16];
    uint32_t efuse_block_num;
    uint32_t efuse_key_purpose;
    uint32_t message_write_complete;
    uint32_t result[ESP_HMAC_RD_RESULT_REG_CNT];
    ESPEfuseState *efuse;
} ESPHmacState;

typedef struct ESPHmacClass {
    SysBusDeviceClass parent_class;

    /* Target-specific registers */
    /* peripheral version register (date) */
    uint32_t date;

    /* Virtual methods*/
    void (*hmac_update)(ESPHmacState *s, uint32_t *message);
    void (*hmac_finish)(ESPHmacState *s, uint32_t *result);
} ESPHmacClass;


REG32(HMAC_WR_MESSAGE_0_REG, 0x080)
REG32(HMAC_WR_MESSAGE_1_REG, 0x084)
REG32(HMAC_WR_MESSAGE_2_REG, 0x088)
REG32(HMAC_WR_MESSAGE_3_REG, 0x08C)
REG32(HMAC_WR_MESSAGE_4_REG, 0x090)
REG32(HMAC_WR_MESSAGE_5_REG, 0x094)
REG32(HMAC_WR_MESSAGE_6_REG, 0x098)
REG32(HMAC_WR_MESSAGE_7_REG, 0x09C)
REG32(HMAC_WR_MESSAGE_8_REG, 0x0A0)
REG32(HMAC_WR_MESSAGE_9_REG, 0x0A4)
REG32(HMAC_WR_MESSAGE_10_REG, 0x0A8)
REG32(HMAC_WR_MESSAGE_11_REG, 0x0AC)
REG32(HMAC_WR_MESSAGE_12_REG, 0x0B0)
REG32(HMAC_WR_MESSAGE_13_REG, 0x0B4)
REG32(HMAC_WR_MESSAGE_14_REG, 0x0B8)
REG32(HMAC_WR_MESSAGE_15_REG, 0x0BC)

REG32(HMAC_RD_RESULT_0_REG, 0x0C0)
REG32(HMAC_RD_RESULT_1_REG, 0x0C4)
REG32(HMAC_RD_RESULT_2_REG, 0x0C8)
REG32(HMAC_RD_RESULT_3_REG, 0x0CC)
REG32(HMAC_RD_RESULT_4_REG, 0x0D0)
REG32(HMAC_RD_RESULT_5_REG, 0x0D4)
REG32(HMAC_RD_RESULT_6_REG, 0x0D8)
REG32(HMAC_RD_RESULT_7_REG, 0x0DC)


REG32(HMAC_SET_START_REG, 0x040)
    FIELD(HMAC_SET_START_REG, HMAC_SET_START, 0, 1)

REG32(HMAC_SET_PARA_PURPOSE_REG, 0x044)
    FIELD(HMAC_SET_PARA_PURPOSE_REG, HMAC_PURPOSE_SET, 0, 4)

REG32(HMAC_SET_PARA_KEY_REG, 0x048)
    FIELD(HMAC_SET_PARA_KEY_REG, HMAC_KEY_SET, 0, 3)

REG32(HMAC_SET_PARA_FINISH_REG, 0x04C)
    FIELD(HMAC_SET_PARA_FINISH_REG, HMAC_SET_PARA_END, 0, 1)

REG32(HMAC_SET_MESSAGE_ONE_REG, 0x050)
    FIELD(HMAC_SET_MESSAGE_ONE_REG, HMAC_SET_TEXT_ONE, 0, 1)

REG32(HMAC_SET_MESSAGE_ING_REG, 0x054)
    FIELD(HMAC_SET_MESSAGE_ING_REG, HMAC_SET_TEXT_ING, 0, 1)

REG32(HMAC_SET_MESSAGE_END_REG, 0x058)
    FIELD(HMAC_SET_MESSAGE_END_REG, HMAC_SET_TEXT_END, 0, 1)

REG32(HMAC_SET_RESULT_FINISH_REG, 0x05C)
    FIELD(HMAC_SET_RESULT_FINISH_REG, HMAC_SET_RESULT_END, 0, 1)

REG32(HMAC_SET_INVALIDATE_JTAG_REG, 0x060)
    FIELD(HMAC_SET_INVALIDATE_JTAG_REG, HMAC_SET_INVALIDATE_JTAG, 0, 1)

REG32(HMAC_SET_INVALIDATE_DS_REG, 0x064)
    FIELD(HMAC_SET_INVALIDATE_DS_REG, HMAC_SET_INVALIDATE_DS, 0, 1)

REG32(HMAC_QUERY_ERROR_REG, 0x068)
    FIELD(HMAC_QUERY_ERROR_REG, HMAC_QUREY_CHECK, 0, 1)

REG32(HMAC_QUERY_BUSY_REG, 0x06C)
    FIELD(HMAC_QUERY_BUSY_REG, HMAC_BUSY_STATE, 0, 1)

REG32(HMAC_SET_MESSAGE_PAD_REG, 0x0F0)
    FIELD(HMAC_SET_MESSAGE_PAD_REG, HMAC_SET_TEXT_PAD, 0, 1)

REG32(HMAC_ONE_BLOCK_REG, 0x0F4)
    FIELD(HMAC_ONE_BLOCK_REG, HMAC_SET_ONE_BLOCK, 0, 1)

REG32(HMAC_SOFT_JTAG_CTRL_REG, 0x0F8)
    FIELD(HMAC_SOFT_JTAG_CTRL_REG, HMAC_SOFT_JTAG_CTRL, 0, 1)

REG32(HMAC_WR_JTAG_REG, 0x0FC)
    FIELD(HMAC_WR_JTAG_REG, HMAC_WR_TAG, 0, 32)

REG32(HMAC_DATE_REG, 0x1FC)
    FIELD(HMAC_DATE_REG, HMAC_DATE, 0, 30)
