/* disc_access_sdhc.h - header SDHC*/

/*
 * Copyright (c) 2019 NXP
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef ZEPHYR_INCLUDE_DISK_DRIVER_SDMMC_H_
#define ZEPHYR_INCLUDE_DISK_DRIVER_SDMMC_H_

#include <drivers/spi.h>

#define SDMMC_CLOCK_400KHZ (400000U)
#define SD_CLOCK_25MHZ (25000000U)
#define SD_CLOCK_50MHZ (50000000U)
#define SD_CLOCK_100MHZ (100000000U)
#define SD_CLOCK_208MHZ (208000000U)
#define MMC_CLOCK_26MHZ (26000000U)
#define MMC_CLOCK_52MHZ (52000000U)
#define MMC_CLOCK_DDR52 (52000000U)
#define MMC_CLOCK_HS200 (200000000U)
#define MMC_CLOCK_HS400 (400000000U)

/* Command IDs */
#define SDHC_GO_IDLE_STATE 0
#define SDHC_ALL_SEND_CID 2
#define SDHC_SEND_RELATIVE_ADDR 3
#define SDHC_SWITCH 6
#define SDHC_SELECT_CARD 7
#define SDHC_SEND_IF_COND 8
#define SDHC_SEND_CSD 9
#define SDHC_SEND_CID 10
#define SDHC_VOL_SWITCH 11
#define SDHC_STOP_TRANSMISSION 12
#define SDHC_SEND_STATUS 13
#define SDHC_GO_INACTIVE_STATE 15
#define SDHC_SET_BLOCK_SIZE 16
#define SDHC_READ_SINGLE_BLOCK 17
#define SDHC_READ_MULTIPLE_BLOCK 18
#define SDHC_SEND_TUNING_BLOCK 19
#define SDHC_SET_BLOCK_COUNT 23
#define SDHC_WRITE_BLOCK 24
#define SDHC_WRITE_MULTIPLE_BLOCK 25
#define SDHC_ERASE_BLOCK_START 32
#define SDHC_ERASE_BLOCK_END 33
#define SDHC_ERASE_BLOCK_OPERATION 38
#define SDHC_APP_CMD 55
#define SDHC_READ_OCR 58
#define SDHC_CRC_ON_OFF 59

enum sdhc_app_ext_cmd {
	SDHC_APP_SET_BUS_WIDTH = 6,
	SDHC_APP_SEND_STATUS = 13,
	SDHC_APP_SEND_NUM_WRITTEN_BLK = 22,
	SDHC_APP_SET_WRITE_BLK_ERASE_CNT = 23,
	SDHC_APP_SEND_OP_COND = 41,
	SDHC_APP_CLEAR_CARD_DETECT = 42,
	SDHC_APP_SEND_SCR = 51
};

#define SDHC_SEND_OP_COND SDHC_APP_SEND_OP_COND

/* R1 response status */
#define SDHC_R1_IDLE 0x01
#define SDHC_R1_ERASE_RESET 0x02
#define SDHC_R1_ILLEGAL_COMMAND 0x04
#define SDHC_R1_COM_CRC 0x08
#define SDHC_R1_ERASE_SEQ 0x10
#define SDHC_R1_ADDRESS 0x20
#define SDHC_R1_PARAMETER 0x40

#define SDHC_CMD_SIZE 6
#define SDHC_CMD_BODY_SIZE (SDHC_CMD_SIZE - 1)
#define SDHC_CRC16_SIZE 2

/* Command flags */
#define SDHC_START 0x80
#define SDHC_TX 0x40

/* Fields in various card registers */
#define SDHC_HCS (1 << 30)
#define SDHC_CCS (1 << 30)
#define SDHC_BUSY (1 << 31)
#define SDHC_VHS_MASK (0x0F << 8)
#define SDHC_VHS_3V3 (1 << 8)
#define SDHC_CHECK 0xAA
#define SDHC_CSD_SIZE 16
#define SDHC_CSD_V1 0
#define SDHC_CSD_V2 1

/* Data block tokens */
#define SDHC_TOKEN_SINGLE 0xFE
#define SDHC_TOKEN_MULTI_WRITE 0xFC
#define SDHC_TOKEN_STOP_TRAN 0xFD

/* Data block responses */
#define SDHC_RESPONSE_ACCEPTED 0x05
#define SDHC_RESPONSE_CRC_ERR 0x0B
#define SDHC_RESPONSE_WRITE_ERR 0x0E

#define SDHC_MIN_TRIES 20
#define SDHC_RETRY_DELAY 20
/* Time to wait for the card to initialise */
#define SDHC_INIT_TIMEOUT 5000
/* Time to wait for the card to respond or come ready */
#define SDHC_READY_TIMEOUT 500

enum sdhc_rsp_type {
	SDHC_RSP_TYPE_NONE = 0U,
	SDHC_RSP_TYPE_R1 = 1U,
	SDHC_RSP_TYPE_R1b = 2U,
	SDHC_RSP_TYPE_R2 = 3U,
	SDHC_RSP_TYPE_R3 = 4U,
	SDHC_RSP_TYPE_R4 = 5U,
	SDHC_RSP_TYPE_R5 = 6U,
	SDHC_RSP_TYPE_R5b = 7U,
	SDHC_RSP_TYPE_R6 = 8U,
	SDHC_RSP_TYPE_R7 = 9U,
};

enum sdhc_bus_width {
	SDHC_BUS_WIDTH1BIT = 0U,
	SDHC_BUS_WIDTH4BIT = 1U,
};

enum sdhc_flag {
	SDHC_HIGH_CAPACITY_FLAG = (1U << 1U),
	SDHC_4BITS_WIDTH = (1U << 2U),
	SDHC_SDHC_FLAG = (1U << 3U),
	SDHC_SDXC_FLAG = (1U << 4U),
	SDHC_1800MV_FLAG = (1U << 5U),
	SDHC_CMD23_FLAG = (1U << 6U),
	SDHC_SPEED_CLASS_CONTROL_FLAG = (1U << 7U),
};

enum sdhc_r1_error_flag {
	SDHC_R1OUTOF_RANGE_ERR = (1U << 31U),
	SDHC_R1ADDRESS_ERR = (1U << 30U),
	SDHC_R1BLK_LEN_ERR = (1U << 29U),
	SDHC_R1ERASE_SEQ_ERR = (1U << 28U),
	SDHC_R1ERASE_PARAMETER_ERR = (1U << 27U),
	SDHC_R1WRITE_PROTECTION_ERR = (1U << 26U),
	SDHC_R1CARD_LOCKED_ERR = (1U << 25U),
	SDHC_R1LOCK_UNLOCK_ERR = (1U << 24U),
	SDHC_R1CMD_CRC_ERR = (1U << 23U),
	SDHC_R1ILLEGAL_CMD_ERR = (1U << 22U),
	SDHC_R1ECC_ERR = (1U << 21U),
	SDHC_R1CARD_CONTROL_ERR = (1U << 20U),
	SDHC_R1ERR = (1U << 19U),
	SDHC_R1CID_CSD_OVERWRITE_ERR = (1U << 16U),
	SDHC_R1WRITE_PROTECTION_ERASE_SKIP = (1U << 15U),
	SDHC_R1CARD_ECC_DISABLED = (1U << 14U),
	SDHC_R1ERASE_RESET = (1U << 13U),
	SDHC_R1READY_FOR_DATA = (1U << 8U),
	SDHC_R1SWITCH_ERR = (1U << 7U),
	SDHC_R1APP_CMD = (1U << 5U),
	SDHC_R1AUTH_SEQ_ERR = (1U << 3U),

	SDHC_R1ERR_All_FLAG =
		(SDHC_R1OUTOF_RANGE_ERR |
		SDHC_R1ADDRESS_ERR |
		SDHC_R1BLK_LEN_ERR |
		SDHC_R1ERASE_SEQ_ERR |
		SDHC_R1ERASE_PARAMETER_ERR |
		SDHC_R1WRITE_PROTECTION_ERR |
		SDHC_R1CARD_LOCKED_ERR |
		SDHC_R1LOCK_UNLOCK_ERR |
		SDHC_R1CMD_CRC_ERR |
		SDHC_R1ILLEGAL_CMD_ERR |
		SDHC_R1ECC_ERR |
		SDHC_R1CARD_CONTROL_ERR |
		SDHC_R1ERR |
		SDHC_R1CID_CSD_OVERWRITE_ERR |
		SDHC_R1AUTH_SEQ_ERR),

	SDHC_R1ERR_NONE = 0,
};

#define SD_R1_CURRENT_STATE(x) (((x)&0x00001E00U) >> 9U)

enum sd_r1_current_state {
	SDMMC_R1_IDLE = 0U,
	SDMMC_R1_READY = 1U,
	SDMMC_R1_IDENTIFY = 2U,
	SDMMC_R1_STANDBY = 3U,
	SDMMC_R1_TRANSFER = 4U,
	SDMMC_R1_SEND_DATA = 5U,
	SDMMC_R1_RECIVE_DATA = 6U,
	SDMMC_R1_PROGRAM = 7U,
	SDMMC_R1_DISCONNECT = 8U,
};

enum sd_ocr_flag {
	SD_OCR_PWR_BUSY_FLAG = (1U << 31U),
	/*!< Power up busy status */
	SD_OCR_HOST_CAP_FLAG = (1U << 30U),
	/*!< Card capacity status */
	SD_OCR_CARD_CAP_FLAG = SD_OCR_HOST_CAP_FLAG,
	/*!< Card capacity status */
	SD_OCR_SWITCH_18_REQ_FLAG = (1U << 24U),
	/*!< Switch to 1.8V request */
	SD_OCR_SWITCH_18_ACCEPT_FLAG = SD_OCR_SWITCH_18_REQ_FLAG,
	/*!< Switch to 1.8V accepted */
	SD_OCR_VDD27_28FLAG = (1U << 15U),
	/*!< VDD 2.7-2.8 */
	SD_OCR_VDD28_29FLAG = (1U << 16U),
	/*!< VDD 2.8-2.9 */
	SD_OCR_VDD29_30FLAG = (1U << 17U),
	/*!< VDD 2.9-3.0 */
	SD_OCR_VDD30_31FLAG = (1U << 18U),
	/*!< VDD 2.9-3.0 */
	SD_OCR_VDD31_32FLAG = (1U << 19U),
	/*!< VDD 3.0-3.1 */
	SD_OCR_VDD32_33FLAG = (1U << 20U),
	/*!< VDD 3.1-3.2 */
	SD_OCR_VDD33_34FLAG = (1U << 21U),
	/*!< VDD 3.2-3.3 */
	SD_OCR_VDD34_35FLAG = (1U << 22U),
	/*!< VDD 3.3-3.4 */
	SD_OCR_VDD35_36FLAG = (1U << 23U),
	/*!< VDD 3.4-3.5 */
};

#define SD_PRODUCT_NAME_BYTES (5U)

struct sd_cid {
	uint8_t manufacturer;
	/*!< Manufacturer ID [127:120] */
	uint16_t application;
	/*!< OEM/Application ID [119:104] */
	uint8_t name[SD_PRODUCT_NAME_BYTES];
	/*!< Product name [103:64] */
	uint8_t version;
	/*!< Product revision [63:56] */
	uint32_t ser_num;
	/*!< Product serial number [55:24] */
	uint16_t date;
	/*!< Manufacturing date [19:8] */
};

struct sd_csd {
	uint8_t csd_structure;
	/*!< CSD structure [127:126] */
	uint8_t read_time1;
	/*!< Data read access-time-1 [119:112] */
	uint8_t read_time2;
	/*!< Data read access-time-2 in clock cycles (NSAC*100) [111:104] */
	uint8_t xfer_rate;
	/*!< Maximum data transfer rate [103:96] */
	uint16_t cmd_class;
	/*!< Card command classes [95:84] */
	uint8_t read_blk_len;
	/*!< Maximum read data block length [83:80] */
	uint16_t flags;
	/*!< Flags in _sd_csd_flag */
	uint32_t device_size;
	/*!< Device size [73:62] */
	uint8_t read_current_min;
	/*!< Maximum read current at VDD min [61:59] */
	uint8_t read_current_max;
	/*!< Maximum read current at VDD max [58:56] */
	uint8_t write_current_min;
	/*!< Maximum write current at VDD min [55:53] */
	uint8_t write_current_max;
	/*!< Maximum write current at VDD max [52:50] */
	uint8_t dev_size_mul;
	/*!< Device size multiplier [49:47] */

	uint8_t erase_size;
	/*!< Erase sector size [45:39] */
	uint8_t write_prtect_size;
	/*!< Write protect group size [38:32] */
	uint8_t write_speed_factor;
	/*!< Write speed factor [28:26] */
	uint8_t write_blk_len;
	/*!< Maximum write data block length [25:22] */
	uint8_t file_fmt;
	/*!< File format [11:10] */
};

struct sd_scr {
	uint8_t scr_structure;
	/*!< SCR Structure [63:60] */
	uint8_t sd_spec;
	/*!< SD memory card specification version [59:56] */
	uint16_t flags;
	/*!< SCR flags in _sd_scr_flag */
	uint8_t sd_sec;
	/*!< Security specification supported [54:52] */
	uint8_t sd_width;
	/*!< Data bus widths supported [51:48] */
	uint8_t sd_ext_sec;
	/*!< Extended security support [46:43] */
	uint8_t cmd_support;
	/*!< Command support bits [33:32] 33-support CMD23, 32-support cmd20*/
	uint32_t rsvd;
	/*!< reserved for manufacturer usage [31:0] */
};

enum sd_timing_mode {
	SD_TIMING_SDR12_DFT_MODE = 0U,
	/*!< Identification mode & SDR12 */
	SD_TIMING_SDR25_HIGH_SPEED_MODE = 1U,
	/*!< High speed mode & SDR25 */
	SD_TIMING_SDR50_MODE = 2U,
	/*!< SDR50 mode*/
	SD_TIMING_SDR104_MODE = 3U,
	/*!< SDR104 mode */
	SD_TIMING_DDR50_MODE = 4U,
	/*!< DDR50 mode */
};

/*! @brief SD card current limit */
enum sd_max_current {
	SD_MAX_CURRENT_200MA = 0U,
	/*!< default current limit */
	SD_MAX_CURRENT_400MA = 1U,
	/*!< current limit to 400MA */
	SD_MAX_CURRENT_600MA = 2U,
	/*!< current limit to 600MA */
	SD_MAX_CURRENT_800MA = 3U,
	/*!< current limit to 800MA */
};

enum sd_voltage {
	SD_VOL_NONE = 0U,
	/*!< indicate current voltage setting is not setting bu suser*/
	SD_VOL_3_3_V = 1U,
	/*!< card operation voltage around 3.3v */
	SD_VOL_3_0_V = 2U,
	/*!< card operation voltage around 3.0v */
	SD_VOL_1_8_V = 3U,
	/*!< card operation voltage around 31.8v */
};

#define SDMMC_DEFAULT_BLOCK_SIZE (512U)

struct sd_data_op {
	uint32_t start_block;
	uint32_t block_size;
	uint32_t block_count;
	uint32_t *buf;
};

enum sd_switch_arg {
	SD_SWITCH_CHECK = 0U,
	/*!< SD switch mode 0: check function */
	SD_SWITCH_SET = 1U,
	/*!< SD switch mode 1: set function */
};

enum sd_group_num {
	SD_GRP_TIMING_MODE = 0U,
	/*!< access mode group*/
	SD_GRP_CMD_SYS_MODE = 1U,
	/*!< command system group*/
	SD_GRP_DRIVER_STRENGTH_MODE = 2U,
	/*!< driver strength group*/
	SD_GRP_CURRENT_LIMIT_MODE = 3U,
	/*!< current limit group*/
};

enum sd_driver_strength {
	SD_DRV_STRENGTH_TYPEB = 0U,
	/*!< default driver strength*/
	SD_DRV_STRENGTH_TYPEA = 1U,
	/*!< driver strength TYPE A */
	SD_DRV_STRENGTH_TYPEC = 2U,
	/*!< driver strength TYPE C */
	SD_DRV_STRENGTH_TYPED = 3U,
	/*!< driver strength TYPE D */
};

enum sd_csd_flag {
	SD_CSD_READ_BLK_PARTIAL_FLAG = (1U << 0U),
	/*!< Partial blocks for read allowed [79:79] */
	SD_CSD_WRITE_BLK_MISALIGN_FLAG = (1U << 1U),
	/*!< Write block misalignment [78:78] */
	SD_CSD_READ_BLK_MISALIGN_FLAG = (1U << 2U),
	/*!< Read block misalignment [77:77] */
	SD_CSD_DSR_IMPLEMENTED_FLAG = (1U << 3U),
	/*!< DSR implemented [76:76] */
	SD_CSD_ERASE_BLK_EN_FLAG = (1U << 4U),
	/*!< Erase single block enabled [46:46] */
	SD_CSD_WRITE_PROTECT_GRP_EN_FLAG = (1U << 5U),
	/*!< Write protect group enabled [31:31] */
	SD_CSD_WRITE_BLK_PARTIAL_FLAG = (1U << 6U),
	/*!< Partial blocks for write allowed [21:21] */
	SD_CSD_FILE_FMT_GRP_FLAG = (1U << 7U),
	/*!< File format group [15:15] */
	SD_CSD_COPY_FLAG = (1U << 8U),
	/*!< Copy flag [14:14] */
	SD_CSD_PERMANENT_WRITE_PROTECT_FLAG = (1U << 9U),
	/*!< Permanent write protection [13:13] */
	SD_CSD_TMP_WRITE_PROTECT_FLAG = (1U << 10U),
	/*!< Temporary write protection [12:12] */
};

enum sd_scr_flag {
	SD_SCR_DATA_STATUS_AFTER_ERASE = (1U << 0U),
	/*!< Data status after erases [55:55] */
	SD_SCR_SPEC3 = (1U << 1U),
	/*!< Specification version 3.00 or higher [47:47]*/
};

enum sd_spec_version {
	SD_SPEC_VER1_0 = (1U << 0U),
	/*!< SD card version 1.0-1.01 */
	SD_SPEC_VER1_1 = (1U << 1U),
	/*!< SD card version 1.10 */
	SD_SPEC_VER2_0 = (1U << 2U),
	/*!< SD card version 2.00 */
	SD_SPEC_VER3_0 = (1U << 3U),
	/*!< SD card version 3.0 */
};

enum sd_command_class {
	SD_CMD_CLASS_BASIC = (1U << 0U),
	/*!< Card command class 0 */
	SD_CMD_CLASS_BLOCK_READ = (1U << 2U),
	/*!< Card command class 2 */
	SD_CMD_CLASS_BLOCK_WRITE = (1U << 4U),
	/*!< Card command class 4 */
	SD_CMD_CLASS_ERASE = (1U << 5U),
	/*!< Card command class 5 */
	SD_CMD_CLASS_WRITE_PROTECT = (1U << 6U),
	/*!< Card command class 6 */
	SD_CMD_CLASS_LOCKCARD = (1U << 7U),
	/*!< Card command class 7 */
	SD_CMD_CLASS_APP_SPECIFIC = (1U << 8U),
	/*!< Card command class 8 */
	SD_CMD_CLASS_IO_MODE = (1U << 9U),
	/*!< Card command class 9 */
	SD_CMD_CLASS_SWITCH = (1U << 10U),
	/*!< Card command class 10 */
};

struct sdhc_retry {
	uint32_t end;
	int16_t tries;
	uint16_t sleep;
};

struct sdhc_flag_map {
	uint8_t mask;
	uint8_t err;
};

/* The SD protocol requires sending ones while reading but Zephyr
 * defaults to writing zeros.
 */
static const uint8_t sdhc_ones[] = {
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};

BUILD_ASSERT(sizeof(sdhc_ones) % SDHC_CSD_SIZE == 0);
BUILD_ASSERT(SDMMC_DEFAULT_BLOCK_SIZE % sizeof(sdhc_ones) == 0);

/* Maps R1 response flags to error codes */
static const struct sdhc_flag_map sdhc_r1_flags[] = {
	{SDHC_R1_PARAMETER, EFAULT},	   {SDHC_R1_ADDRESS, EFAULT},
	{SDHC_R1_ILLEGAL_COMMAND, EINVAL}, {SDHC_R1_COM_CRC, EILSEQ},
	{SDHC_R1_ERASE_SEQ, EIO},	  {SDHC_R1_ERASE_RESET, EIO},
	{SDHC_R1_IDLE, ECONNRESET},	{0, 0},
};

/* Maps disk status flags to error codes */
static const struct sdhc_flag_map sdhc_disk_status_flags[] = {
	{DISK_STATUS_UNINIT, ENODEV},
	{DISK_STATUS_NOMEDIA, ENOENT},
	{DISK_STATUS_WR_PROTECT, EROFS},
	{0, 0},
};

/* Maps data block flags to error codes */
static const struct sdhc_flag_map sdhc_data_response_flags[] = {
	{SDHC_RESPONSE_WRITE_ERR, EIO},
	{SDHC_RESPONSE_CRC_ERR, EILSEQ},
	{SDHC_RESPONSE_ACCEPTED, 0},
	/* Unrecognised value */
	{0, EPROTO},
};

/* Returns true if an error code is retryable at the disk layer */
static inline bool sdhc_is_retryable(int err)
{
	switch (err) {
	case 0:
		return false;
	case -EILSEQ:
	case -EIO:
	case -ETIMEDOUT:
		return true;
	default:
		return false;
	}
}

/* Maps a flag based error code into a Zephyr errno */
static inline int sdhc_map_flags(const struct sdhc_flag_map *map, int flags)
{
	if (flags < 0) {
		return flags;
	}

	for (; map->mask != 0U; map++) {
		if ((flags & map->mask) == map->mask) {
			return -map->err;
		}
	}

	return -map->err;
}

/* Converts disk status into an error code */
static inline int sdhc_map_disk_status(int status)
{
	return sdhc_map_flags(sdhc_disk_status_flags, status);
}

/* Converts the R1 response flags into an error code */
static inline int sdhc_map_r1_status(int status)
{
	return sdhc_map_flags(sdhc_r1_flags, status);
}

/* Converts an eary stage idle mode R1 code into an error code */
static inline int sdhc_map_r1_idle_status(int status)
{
	if (status < 0) {
		return status;
	}

	if (status == SDHC_R1_IDLE) {
		return 0;
	}

	return sdhc_map_r1_status(status);
}

/* Converts the data block response flags into an error code */
static inline int sdhc_map_data_status(int status)
{
	return sdhc_map_flags(sdhc_data_response_flags, status);
}

/* Initialises a retry helper */
static inline void sdhc_retry_init(struct sdhc_retry *retry, uint32_t timeout,
			    uint16_t sleep)
{
	retry->end = k_uptime_get_32() + timeout;
	retry->tries = 0;
	retry->sleep = sleep;
}

/* Called at the end of a retry loop.  Returns if the minimum try
 * count and timeout has passed.  Delays/yields on retry.
 */
static inline bool sdhc_retry_ok(struct sdhc_retry *retry)
{
	int32_t remain = retry->end - k_uptime_get_32();

	if (retry->tries < SDHC_MIN_TRIES) {
		retry->tries++;
		if (retry->sleep != 0U) {
			k_msleep(retry->sleep);
		}

		return true;
	}

	if (remain >= 0) {
		if (retry->sleep > 0) {
			k_msleep(retry->sleep);
		} else {
			k_yield();
		}

		return true;
	}

	return false;
}

static inline void sdhc_decode_csd(struct sd_csd *csd,
	uint32_t *raw_csd, uint32_t *blk_cout, uint32_t *blk_size)
{
	uint32_t tmp_blk_cout, tmp_blk_size;

	csd->csd_structure = (uint8_t)((raw_csd[3U] &
		0xC0000000U) >> 30U);
	csd->read_time1 = (uint8_t)((raw_csd[3U] &
		0xFF0000U) >> 16U);
	csd->read_time2 = (uint8_t)((raw_csd[3U] &
		0xFF00U) >> 8U);
	csd->xfer_rate = (uint8_t)(raw_csd[3U] &
		0xFFU);
	csd->cmd_class = (uint16_t)((raw_csd[2U] &
		0xFFF00000U) >> 20U);
	csd->read_blk_len = (uint8_t)((raw_csd[2U] &
		0xF0000U) >> 16U);
	if (raw_csd[2U] & 0x8000U)
		csd->flags |= SD_CSD_READ_BLK_PARTIAL_FLAG;
	if (raw_csd[2U] & 0x4000U)
		csd->flags |= SD_CSD_READ_BLK_PARTIAL_FLAG;
	if (raw_csd[2U] & 0x2000U)
		csd->flags |= SD_CSD_READ_BLK_MISALIGN_FLAG;
	if (raw_csd[2U] & 0x1000U)
		csd->flags |= SD_CSD_DSR_IMPLEMENTED_FLAG;

	switch (csd->csd_structure) {
	case 0:
		csd->device_size = (uint32_t)((raw_csd[2U] &
			0x3FFU) << 2U);
		csd->device_size |= (uint32_t)((raw_csd[1U] &
			0xC0000000U) >> 30U);
		csd->read_current_min = (uint8_t)((raw_csd[1U] &
			0x38000000U) >> 27U);
		csd->read_current_max = (uint8_t)((raw_csd[1U] &
			0x7000000U) >> 24U);
		csd->write_current_min = (uint8_t)((raw_csd[1U] &
			0xE00000U) >> 20U);
		csd->write_current_max = (uint8_t)((raw_csd[1U] &
			0x1C0000U) >> 18U);
		csd->dev_size_mul = (uint8_t)((raw_csd[1U] &
			0x38000U) >> 15U);

		/* Get card total block count and block size. */
		tmp_blk_cout = ((csd->device_size + 1U) <<
			(csd->dev_size_mul + 2U));
		tmp_blk_size = (1U << (csd->read_blk_len));
		if (tmp_blk_size != SDMMC_DEFAULT_BLOCK_SIZE) {
			tmp_blk_cout = (tmp_blk_cout * tmp_blk_size);
			tmp_blk_size = SDMMC_DEFAULT_BLOCK_SIZE;
			tmp_blk_cout = (tmp_blk_cout / tmp_blk_size);
		}
		if (blk_cout)
			*blk_cout = tmp_blk_cout;
		if (blk_size)
			*blk_size = tmp_blk_size;
		break;
	case 1:
		tmp_blk_size = SDMMC_DEFAULT_BLOCK_SIZE;

		csd->device_size = (uint32_t)((raw_csd[2U] &
			0x3FU) << 16U);
		csd->device_size |= (uint32_t)((raw_csd[1U] &
			0xFFFF0000U) >> 16U);

		tmp_blk_cout = ((csd->device_size + 1U) * 1024U);
		if (blk_cout)
			*blk_cout = tmp_blk_cout;
		if (blk_size)
			*blk_size = tmp_blk_size;
		break;
	default:
		break;
	}

	if ((uint8_t)((raw_csd[1U] & 0x4000U) >> 14U))
		csd->flags |= SD_CSD_ERASE_BLK_EN_FLAG;
	csd->erase_size = (uint8_t)((raw_csd[1U] &
		0x3F80U) >> 7U);
	csd->write_prtect_size = (uint8_t)(raw_csd[1U] &
		0x7FU);
	csd->write_speed_factor = (uint8_t)((raw_csd[0U] &
		0x1C000000U) >> 26U);
	csd->write_blk_len = (uint8_t)((raw_csd[0U] &
		0x3C00000U) >> 22U);
	if ((uint8_t)((raw_csd[0U] & 0x200000U) >> 21U))
		csd->flags |= SD_CSD_WRITE_BLK_PARTIAL_FLAG;
	if ((uint8_t)((raw_csd[0U] & 0x8000U) >> 15U))
		csd->flags |= SD_CSD_FILE_FMT_GRP_FLAG;
	if ((uint8_t)((raw_csd[0U] & 0x4000U) >> 14U))
		csd->flags |= SD_CSD_COPY_FLAG;
	if ((uint8_t)((raw_csd[0U] & 0x2000U) >> 13U))
		csd->flags |=
			SD_CSD_PERMANENT_WRITE_PROTECT_FLAG;
	if ((uint8_t)((raw_csd[0U] & 0x1000U) >> 12U))
		csd->flags |=
			SD_CSD_TMP_WRITE_PROTECT_FLAG;
	csd->file_fmt = (uint8_t)((raw_csd[0U] & 0xC00U) >> 10U);
}

static inline void sdhc_decode_scr(struct sd_scr *scr,
	uint32_t *raw_scr, uint32_t *version)
{
	uint32_t tmp_version = 0;

	scr->scr_structure = (uint8_t)((raw_scr[0U] & 0xF0000000U) >> 28U);
	scr->sd_spec = (uint8_t)((raw_scr[0U] & 0xF000000U) >> 24U);
	if ((uint8_t)((raw_scr[0U] & 0x800000U) >> 23U))
		scr->flags |= SD_SCR_DATA_STATUS_AFTER_ERASE;
	scr->sd_sec = (uint8_t)((raw_scr[0U] & 0x700000U) >> 20U);
	scr->sd_width = (uint8_t)((raw_scr[0U] & 0xF0000U) >> 16U);
	if ((uint8_t)((raw_scr[0U] & 0x8000U) >> 15U))
		scr->flags |= SD_SCR_SPEC3;
	scr->sd_ext_sec = (uint8_t)((raw_scr[0U] & 0x7800U) >> 10U);
	scr->cmd_support = (uint8_t)(raw_scr[0U] & 0x3U);
	scr->rsvd = raw_scr[1U];
	/* Get specification version. */
	switch (scr->sd_spec) {
	case 0U:
		tmp_version = SD_SPEC_VER1_0;
		break;
	case 1U:
		tmp_version = SD_SPEC_VER1_1;
		break;
	case 2U:
		tmp_version = SD_SPEC_VER2_0;
		if (scr->flags & SD_SCR_SPEC3) {
			tmp_version = SD_SPEC_VER3_0;
		}
		break;
	default:
		break;
	}

	if (version && tmp_version)
		*version = tmp_version;
}

static inline void sdhc_decode_cid(struct sd_cid *cid,
	uint32_t *raw_cid)
{
	cid->manufacturer = (uint8_t)((raw_cid[3U] & 0xFF000000U) >> 24U);
	cid->application = (uint16_t)((raw_cid[3U] & 0xFFFF00U) >> 8U);

	cid->name[0U] = (uint8_t)((raw_cid[3U] & 0xFFU));
	cid->name[1U] = (uint8_t)((raw_cid[2U] & 0xFF000000U) >> 24U);
	cid->name[2U] = (uint8_t)((raw_cid[2U] & 0xFF0000U) >> 16U);
	cid->name[3U] = (uint8_t)((raw_cid[2U] & 0xFF00U) >> 8U);
	cid->name[4U] = (uint8_t)((raw_cid[2U] & 0xFFU));

	cid->version = (uint8_t)((raw_cid[1U] & 0xFF000000U) >> 24U);

	cid->ser_num = (uint32_t)((raw_cid[1U] & 0xFFFFFFU) << 8U);
	cid->ser_num |= (uint32_t)((raw_cid[0U] & 0xFF000000U) >> 24U);

	cid->date = (uint16_t)((raw_cid[0U] & 0xFFF00U) >> 8U);
}

#endif /*ZEPHYR_INCLUDE_DISK_DRIVER_SDMMC_H_*/
