| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002 |
- /*
- * Copyright (c) 2024 HPMicro
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
- #include "hpm_sdmmc_common.h"
- #include "hpm_sdmmc_sdio.h"
- #include "hpm_l1c_drv.h"
- static hpm_stat_t sdio_send_if_cond(sdio_card_t *card);
- static hpm_stat_t sdio_io_send_op_if_cond(sdio_card_t *card, uint32_t arg);
- static hpm_stat_t sdio_send_rca(sdio_card_t *card);
- static hpm_stat_t sdio_probe_sdio_card(sdio_card_t *card);
- static hpm_stat_t sdio_read_cccr(sdio_card_t *card);
- static hpm_stat_t sdio_set_timing(sdio_card_t *card);
- static hpm_stat_t sdio_set_bus_width(sdio_card_t *card);
- static void sdio_switch_to_1v8(sdio_card_t *card);
- static hpm_stat_t sdio_send_command(sdio_card_t *card, sdmmchost_cmd_t *cmd);
- static hpm_stat_t sdio_transfer(sdio_card_t *card, sdmmchost_xfer_t *xfer);
- static hpm_stat_t sdio_error_recovery(sdio_card_t *card);
- static hpm_stat_t sdio_error_recovery(sdio_card_t *card)
- {
- uint32_t cmd_arg = card->host->cmd.cmd_argument;
- uint32_t cmd_index = card->host->cmd.cmd_index;
- sdxc_command_t *cmd;
- if (cmd_index == sdio_cmd_io_rw_direct) {
- /* Abort function transfer */
- const sdio_cmd52_arg_t *cmd52_arg = (const sdio_cmd52_arg_t *) &cmd_arg;
- cmd = &card->host->cmd;
- cmd->cmd_index = sdio_cmd_io_rw_direct;
- sdio_cmd52_arg_t *abort_arg = (sdio_cmd52_arg_t *) &cmd->cmd_argument;
- abort_arg->func_num = 0;
- abort_arg->reg_addr = 6;
- abort_arg->wr_data = cmd52_arg->func_num;
- abort_arg->write = 1;
- cmd->cmd_type = sdxc_cmd_type_abort_cmd;
- } else if (cmd_index == sdio_cmd_io_rw_extend) {
- /* Abort function transfer */
- const sdio_cmd53_arg_t *cmd53_arg = (const sdio_cmd53_arg_t *) &cmd_arg;
- cmd = &card->host->cmd;
- cmd->cmd_index = sdio_cmd_io_rw_direct;
- sdio_cmd52_arg_t *abort_arg = (sdio_cmd52_arg_t *) &cmd->cmd_argument;
- abort_arg->func_num = 0;
- abort_arg->reg_addr = 6;
- abort_arg->wr_data = cmd53_arg->func_num;
- abort_arg->write = 1;
- cmd->cmd_type = sdxc_cmd_type_abort_cmd;
- } else {
- cmd = NULL;
- }
- return sdmmchost_error_recovery(card->host, cmd);
- }
- static hpm_stat_t sdio_send_command(sdio_card_t *card, sdmmchost_cmd_t *cmd)
- {
- hpm_stat_t status = sdmmchost_send_command(card->host, cmd);
- if (status != status_success) {
- hpm_stat_t recover_status = sdio_error_recovery(card);
- if (recover_status != status_success) {
- status = recover_status;
- }
- }
- return status;
- }
- static hpm_stat_t sdio_transfer(sdio_card_t *card, sdmmchost_xfer_t *xfer)
- {
- hpm_stat_t status = sdmmchost_transfer(card->host, xfer);
- if (status != status_success) {
- hpm_stat_t recover_status = sdio_error_recovery(card);
- if (recover_status != status_success) {
- status = recover_status;
- }
- }
- return status;
- }
- static hpm_stat_t sdio_send_if_cond(sdio_card_t *card)
- {
- sdmmc_host_t *host = card->host;
- sdmmchost_cmd_t *cmd = &host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = sd_cmd_send_if_cond;
- cmd->cmd_argument = 0x1aa;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r7;
- hpm_stat_t status = sdio_send_command(card, cmd);
- if (status != status_success) {
- return status;
- }
- if ((cmd->response[0] & 0xFFU) != 0xAAU) {
- return status_sdmmc_card_not_support;
- }
- return status_success;
- }
- static hpm_stat_t sdio_io_send_op_if_cond(sdio_card_t *card, uint32_t arg)
- {
- sdmmc_host_t *host = card->host;
- sdmmchost_cmd_t *cmd = &host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- /* Probe the presence of SDIO */
- cmd->cmd_index = sdio_cmd_io_send_op_cond;
- cmd->cmd_argument = arg;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r4;
- hpm_stat_t status = sdio_send_command(card, cmd);
- if (status != status_success) {
- return status;
- }
- return status_success;
- }
- static hpm_stat_t sdio_send_rca(sdio_card_t *card)
- {
- sdmmc_host_t *host = card->host;
- sdmmchost_cmd_t *cmd = &host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- cmd->cmd_index = sd_cmd_send_relative_addr;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r6;
- hpm_stat_t status = sdio_send_command(card, cmd);
- if (status != status_success) {
- return status;
- }
- card->relative_addr = cmd->response[0] >> 16;
- return status;
- }
- static void sdio_switch_to_1v8(sdio_card_t *card)
- {
- sdmmc_host_t *host = card->host;
- /* 1. Stop providing clock to the card */
- sdxc_enable_inverse_clock(host->host_param.base, false);
- sdxc_enable_sd_clock(host->host_param.base, false);
- /* 2. Switch signaling to 1.8v */
- sdmmchost_vsel_pin_control(host, hpm_sdmmc_io_voltage_1v8);
- sdmmchost_select_voltage(host, hpm_sdmmc_io_voltage_1v8);
- /* 3. Provide SD clock the card again */
- sdxc_enable_inverse_clock(host->host_param.base, true);
- sdxc_enable_sd_clock(host->host_param.base, true);
- /* 4. wait 1ms */
- sdmmchost_delay_ms(host, 1);
- }
- static hpm_stat_t sdio_probe_sdio_card(sdio_card_t *card)
- {
- sdmmc_host_t *host = card->host;
- sdmmchost_cmd_t *cmd = &card->host->cmd;
- hpm_stat_t status = sdmmc_go_idle_state(card->host, 0);
- if (status != status_success) {
- return status;
- }
- /* Probe with CMD8 first */
- status = sdio_send_if_cond(card);
- if ((status != status_sdxc_cmd_timeout_error) && (status != status_sdxc_non_recoverable_error) && (
- status != status_success)) {
- return status;
- }
- /* Probe with CMD */
- sdio_cmd5_resp_t cmd5_resp;
- status = sdio_io_send_op_if_cond(card, 0);
- if (status != status_success) {
- return status;
- }
- cmd5_resp.value = cmd->response[0];
- uint32_t cmd5_arg = (0x3FUL << 18); /* Voltage 3.0 - 3.6 */
- bool switch_voltage = false;
- if (sdmmchost_is_voltage_switch_supported(host) && card->operation_voltage == sdmmc_operation_voltage_3v3) {
- cmd5_arg |= (1UL << 24); /* S18R */
- switch_voltage = true;
- }
- do {
- sdmmchost_delay_ms(host, 1);
- status = sdio_io_send_op_if_cond(card, cmd5_arg);
- if (status != status_success) {
- return status;
- }
- cmd5_resp.value = cmd->response[0];
- } while (!cmd5_resp.ready);
- card->num_of_functions = cmd5_resp.num_func;
- if (switch_voltage && (cmd5_resp.s18r == 1)) {
- sdio_switch_to_1v8(card);
- card->operation_voltage = sdmmc_operation_voltage_1v8;
- }
- return status;
- }
- static hpm_stat_t sdio_read_cccr(sdio_card_t *card)
- {
- hpm_stat_t status;
- sdmmc_host_t *host = card->host;
- sdmmchost_cmd_t *cmd = &host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- uint8_t *pdata = (uint8_t *) &card->cccr;
- for (uint32_t reg = SDIO_REG_CCCR_START; reg <= SDIO_REG_CCCR_END; reg++) {
- status = sdio_io_read_byte(card, 0, reg, pdata);
- if (status != status_success) {
- break;
- }
- ++pdata;
- }
- return status;
- }
- hpm_stat_t sdio_read_cis(sdio_card_t *card, uint32_t cis_ptr, sdio_cis_t *cis, bool keep_tpl_raw_data)
- {
- hpm_stat_t status = status_invalid_argument;
- uint8_t tpl_code;
- uint8_t tpl_link;
- struct sdio_tpl_block *tpl_blk = NULL;
- struct sdio_tpl_block *current_tpl = NULL;
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL) || (cis == NULL));
- do {
- uint8_t tmp_buf[256] = { 0 };
- status = sdio_io_read_byte(card, 0, cis_ptr++, &tpl_code);
- HPM_BREAK_IF(status != status_success);
- status = sdio_io_read_byte(card, 0, cis_ptr++, &tpl_link);
- HPM_BREAK_IF(status != status_success);
- if ((tpl_code == CISTPL_END) || (tpl_link == 0xFF)) {
- if (keep_tpl_raw_data && (tpl_blk != NULL)) {
- tpl_blk->next = NULL;
- }
- break;
- }
- if (tpl_code == CISTPL_NULL) {
- continue;
- }
- uint8_t *pdata = tmp_buf;
- for (uint32_t i = 0; i < tpl_link; i++) {
- status = sdio_io_read_byte(card, 0, cis_ptr++, pdata++);
- if (status != status_success) {
- return status;
- }
- }
- if (keep_tpl_raw_data) {
- tpl_blk = (struct sdio_tpl_block *) HPM_SDMMC_MALLOC(sizeof(struct sdio_tpl_block));
- if (tpl_blk == NULL) {
- status = status_fail;
- break;
- }
- tpl_blk->tpl_code = tpl_code;
- tpl_blk->tpl_size = tpl_link;
- if (tpl_link > 0) {
- tpl_blk->tpl_data = (uint8_t *) HPM_SDMMC_MALLOC(tpl_link);
- if (tpl_blk->tpl_data == NULL) {
- HPM_SDMMC_FREE(tpl_blk);
- status = status_fail;
- break;
- }
- (void) memcpy(tpl_blk->tpl_data, tmp_buf, tpl_link);
- }
- if (current_tpl == NULL) {
- cis->tpl_link = tpl_blk;
- current_tpl = cis->tpl_link;
- } else {
- current_tpl->next = tpl_blk;
- current_tpl = current_tpl->next;
- }
- }
- const uint8_t *tpl_data_buf = tmp_buf;
- sdio_cis_t *p_cis = cis;
- switch (tpl_code) {
- case CISTPL_MANFID:
- if (tpl_link < 4) {
- return status_invalid_argument;
- }
- p_cis->manufacturer = (((uint16_t) tpl_data_buf[1]) << 8) | tpl_data_buf[0];
- p_cis->product = (((uint16_t) tpl_data_buf[3]) << 8) | tpl_data_buf[2];
- break;
- case CISTPL_FUNCE:
- if (tpl_data_buf[0] == 0x00) {
- p_cis->func0_blk_size = (((uint16_t) tpl_data_buf[2]) << 8) | tpl_data_buf[1];
- p_cis->max_tran_speed = tpl_data_buf[3];
- } else if (tpl_data_buf[0] == 0x01) {
- sdio_func_funce_t *pfunce = (sdio_func_funce_t *) &tpl_data_buf[1];
- p_cis->std_io_rev = pfunce->std_io_rev;
- p_cis->support_wakeup = pfunce->support_wakeup;
- p_cis->max_blk_size = pfunce->max_blk_size;
- p_cis->csa_size = pfunce->csa_size;
- p_cis->serial_num = pfunce->psn;
- p_cis->timeout_val_in_10ms = pfunce->enable_timeout_val;
- p_cis->csa_wp = pfunce->csa_wp;
- p_cis->csa_nf = pfunce->csa_nf;
- p_cis->ocr = pfunce->ocr;
- } else {
- /* Skip data */
- }
- break;
- case CISTPL_FUNCID:
- /* Skip */
- break;
- case CISTPL_SDIO_STD:
- p_cis->std_id = tpl_data_buf[0];
- p_cis->std_type = tpl_data_buf[1];
- break;
- case CISTPL_SDIO_EXT:
- /* Skip */
- break;
- default:
- /* Skip */
- break;
- }
- } while (tpl_code != CISTPL_END);
- } while (false);
- return status;
- }
- hpm_stat_t sdio_read_fbr(sdio_card_t *card, uint32_t func_idx, sdio_fbr_t *fbr)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL) || (fbr == NULL));
- uint32_t reg_addr = SDIO_FBR_REG_BASE(func_idx);
- uint8_t *pdata = (uint8_t *) fbr;
- for (uint32_t i = 0; i < sizeof(sdio_fbr_t); i++) {
- status = sdio_io_read_byte(card, 0, reg_addr++, pdata++);
- if (status != status_success) {
- return status;
- }
- }
- } while (false);
- return status;
- }
- hpm_stat_t sdio_io_rw_direct(sdio_card_t *card,
- bool write,
- uint32_t func_idx,
- uint32_t reg_addr,
- uint8_t *pdata,
- bool read_after_write)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(card == NULL);
- sdmmc_host_t *host = card->host;
- sdmmchost_cmd_t *cmd = &host->cmd;
- (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
- sdio_cmd52_arg_t cmd52_arg = { .value = 0 };
- cmd52_arg.write = write ? 1UL : 0U;
- cmd52_arg.read_afer_write = read_after_write ? 1UL : 0U;
- cmd52_arg.func_num = func_idx;
- cmd52_arg.reg_addr = reg_addr;
- if (write) {
- cmd52_arg.wr_data = *pdata;
- }
- cmd->cmd_index = sdio_cmd_io_rw_direct;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r5;
- cmd->cmd_argument = cmd52_arg.value;
- status = sdio_send_command(card, cmd);
- if (status != status_success) {
- break;
- }
- sdio_resp_r5_t cmd52_resp;
- cmd52_resp.value = cmd->response[0];
- if (!write || read_after_write) {
- *pdata = (uint8_t) cmd52_resp.rw_data;
- }
- } while (false);
- return status;
- }
- hpm_stat_t sdio_set_block_size(sdio_card_t *card, uint32_t func_idx, uint32_t block_size)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- if (card == NULL) {
- break;
- }
- if (block_size == 0) {
- block_size = MIN(SDMMC_BLOCK_SIZE_DEFAULT, block_size);
- }
- status = sdio_io_write_byte(card,
- 0,
- SDIO_FBR_REG_BASE(func_idx) + SDIO_REG_CCCR_FN0_BLK_SIZE,
- block_size & 0xFF);
- if (status != status_success) {
- break;
- }
- status = sdio_io_write_byte(card,
- 0,
- SDIO_FBR_REG_BASE(func_idx) + SDIO_REG_CCCR_FN0_BLK_SIZE + 1,
- (block_size >> 8) & 0xFF);
- if (status != status_success) {
- break;
- }
- card->sdio_func[func_idx]->current_block_size = block_size;
- } while (false);
- return status;
- }
- hpm_stat_t sdio_io_read_byte(sdio_card_t *card, uint32_t func_num, uint32_t reg, uint8_t *pdata)
- {
- return sdio_io_rw_direct(card, false, func_num, reg, pdata, false);
- }
- hpm_stat_t sdio_io_write_byte(sdio_card_t *card, uint32_t func_num, uint32_t reg, uint8_t byte_data)
- {
- return sdio_io_rw_direct(card, true, func_num, reg, &byte_data, false);
- }
- hpm_stat_t sdio_io_rw_extend(sdio_card_t *card,
- bool write,
- uint32_t func_idx,
- uint32_t reg_addr,
- uint32_t op_code,
- uint8_t *pbuf,
- uint32_t blocks,
- uint32_t block_size)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL));
- if (!card->host->card_init_done) {
- status = status_sdmmc_device_init_required;
- break;
- }
- sdmmc_host_t *host = card->host;
- sdmmchost_cmd_t *cmd = &host->cmd;
- sdmmchost_data_t *data = &host->data;
- sdmmchost_xfer_t *content = &host->xfer;
- memset(cmd, 0, sizeof(*cmd));
- memset(data, 0, sizeof(*data));
- memset(content, 0, sizeof(*content));
- sdio_cmd53_arg_t cmd53_arg = { .value = 0 };
- cmd53_arg.rw_flag = write ? 1UL : 0;
- cmd53_arg.func_num = func_idx;
- cmd53_arg.reg_addr = reg_addr;
- cmd53_arg.block_mode = 0;
- cmd53_arg.op_code = op_code;
- if ((blocks == 1) && (block_size <= 512)) {
- cmd53_arg.count = (block_size == 512) ? 0 : block_size;
- } else {
- cmd53_arg.count = blocks;
- cmd53_arg.block_mode = 1;
- }
- cmd->cmd_index = sdio_cmd_io_rw_extend;
- cmd->cmd_argument = cmd53_arg.value;
- cmd->cmd_timeout_ms = SDIO_CMD_TIMEOUT_MS;
- cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r5;
- data->block_size = block_size;
- data->block_cnt = blocks;
- if (write) {
- data->tx_data = (uint32_t *) sdmmc_get_sys_addr(host, (uint32_t)pbuf);
- } else {
- data->rx_data = (uint32_t *) sdmmc_get_sys_addr(host, (uint32_t)pbuf);
- }
- content->data = data;
- content->command = cmd;
- #if !defined(HPM_SDMMC_ENABLE_CACHE_MAINTENANCE) || (HPM_SDMMC_ENABLE_CACHE_MAINTENANCE == 1)
- uint32_t buf_start = write ? (uint32_t) data->tx_data : (uint32_t) data->rx_data;
- uint32_t buf_size = blocks * block_size;
- uint32_t end_addr = buf_start + buf_size;
- uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN(buf_start);
- uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP(end_addr);
- uint32_t aligned_size = aligned_end - aligned_start;
- if (write) {
- l1c_dc_writeback(aligned_start, aligned_size);
- } else {
- /* FLUSH un-cacheline aligned memory region */
- if ((buf_start % HPM_L1C_CACHELINE_SIZE) != 0) {
- l1c_dc_writeback(aligned_start, HPM_L1C_CACHELINE_SIZE);
- }
- if ((end_addr % HPM_L1C_CACHELINE_SIZE) != 0) {
- uint32_t aligned_tail = HPM_L1C_CACHELINE_ALIGN_DOWN(end_addr);
- l1c_dc_writeback(aligned_tail, HPM_L1C_CACHELINE_SIZE);
- }
- }
- #endif
- status = sdio_transfer(card, content);
- HPM_BREAK_IF(status != status_success);
- #if !defined(HPM_SDMMC_ENABLE_CACHE_MAINTENANCE) || (HPM_SDMMC_ENABLE_CACHE_MAINTENANCE == 1)
- if (!write) {
- l1c_dc_invalidate(aligned_start, aligned_size);
- }
- #endif
- } while (false);
- return status;
- }
- hpm_stat_t sdio_io_write_multi_bytes_to_fifo(sdio_card_t *card,
- uint32_t func_idx,
- uint32_t reg_addr,
- uint8_t *pbuf,
- uint32_t length)
- {
- if ((card == NULL) || (card->host == NULL) || (length < 1U)) {
- return status_invalid_argument;
- }
- uint32_t block_size = MIN(card->sdio_func[func_idx]->current_block_size, length);
- uint32_t num_blocks = (length + block_size - 1U) / block_size;
- return sdio_io_rw_extend(card,
- true,
- func_idx,
- reg_addr,
- SDIO_CMD53_OP_MODE_FIXED_ADDR,
- pbuf,
- num_blocks,
- block_size);
- }
- hpm_stat_t sdio_io_read_multi_bytes_from_fifo(sdio_card_t *card,
- uint32_t func_idx,
- uint32_t reg_addr,
- uint8_t *pbuf,
- uint32_t length)
- {
- if ((card == NULL) || (card->host == NULL) || (length < 1U)) {
- return status_invalid_argument;
- }
- uint32_t block_size = MIN(card->sdio_func[func_idx]->current_block_size, length);
- uint32_t num_blocks = (length + block_size - 1U) / block_size;
- return sdio_io_rw_extend(card,
- false,
- func_idx,
- reg_addr,
- SDIO_CMD53_OP_MODE_FIXED_ADDR,
- pbuf,
- num_blocks,
- block_size);
- }
- hpm_stat_t sdio_io_write_incr_multi_bytes(sdio_card_t *card,
- uint32_t func_idx,
- uint32_t reg_addr,
- uint8_t *pbuf,
- uint32_t length)
- {
- if ((card == NULL) || (card->host == NULL)) {
- return status_invalid_argument;
- }
- uint32_t block_size = MIN(card->sdio_func[func_idx]->current_block_size, length);
- uint32_t num_blocks = (length + block_size - 1U) / block_size;
- return sdio_io_rw_extend(card,
- true,
- func_idx,
- reg_addr,
- SDIO_CMD53_OP_MODE_INCR_ADDR,
- pbuf,
- num_blocks,
- block_size);
- }
- hpm_stat_t sdio_io_read_incr_multi_bytes(sdio_card_t *card,
- uint32_t func_idx,
- uint32_t reg_addr,
- uint8_t *pbuf,
- uint32_t length)
- {
- if ((card == NULL) || (card->host == NULL)) {
- return status_invalid_argument;
- }
- uint32_t block_size = MIN(card->sdio_func[func_idx]->current_block_size, length);
- uint32_t num_blocks = (length + block_size - 1U) / block_size;
- return sdio_io_rw_extend(card,
- false,
- func_idx,
- reg_addr,
- SDIO_CMD53_OP_MODE_INCR_ADDR,
- pbuf,
- num_blocks,
- block_size);
- }
- hpm_stat_t sdio_init(sdio_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF(card == NULL);
- status = sdio_host_init(card);
- HPM_BREAK_IF(status != status_success);
- card->host->card_init_done = false;
- card->relative_addr = 0;
- card->current_timing = sdmmc_sd_speed_normal;
- card->host->card_inserted = true;
- sdmmchost_delay_ms(card->host, 100); /* Wait a while in case the card connection is still not stable */
- status = sdio_card_init(card);
- } while (false);
- return status;
- }
- void sdio_deinit(sdio_card_t *card)
- {
- if ((card != NULL) && (card->host != NULL) && (card->host->card_init_done)) {
- card->host->card_init_done = false;
- sdmmchost_deinit(card->host);
- }
- }
- static hpm_stat_t sdio_set_bus_width(sdio_card_t *card)
- {
- hpm_stat_t status = status_success;
- do {
- /* If the card is a full-speed card, it shall support both 1-bit and 4-bit bus widths */
- bool support_4bit = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_4BIT);
- if ((card->cccr.low_speed_card == 0) && support_4bit) {
- uint8_t cccr_bus_if_ctrl = 0;
- status = sdio_io_read_byte(card, 0, SDIO_REG_CCCR_BUS_IF_CTRL, &cccr_bus_if_ctrl);
- HPM_BREAK_IF(status != status_success);
- cccr_bus_if_ctrl |= SDIO_CCCR_BUS_WIDTH_4BIT;
- status = sdio_io_write_byte(card, 0, SDIO_REG_CCCR_BUS_IF_CTRL, cccr_bus_if_ctrl);
- HPM_BREAK_IF(status != status_success);
- sdmmchost_set_card_bus_width(card->host, sdmmc_bus_width_4bit);
- }
- } while (false);
- return status;
- }
- static hpm_stat_t sdio_set_timing(sdio_card_t *card)
- {
- hpm_stat_t status = status_success;
- do {
- /* Change Speed */
- if (card->cccr.support_highspeed) {
- uint8_t bus_speed_sel = 0;
- bool need_reverse = true;
- uint32_t clock_option = SD_CLOCK_25MHZ;
- status = sdio_io_read_byte(card, 0, SDIO_REG_CCCR_BUS_SPEED_SEL, &bus_speed_sel);
- HPM_BREAK_IF(status != status_success);
- bool support_ddr = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_DDR);
- bool support_sdr104 = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_SDR104);
- bool support_sdr50 = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_SDR50);
- sdmmc_speed_mode_t speed_mode;
- if (card->cccr.support_sdr104 && support_sdr104) {
- speed_mode = sdmmc_sd_speed_sdr104;
- clock_option = SD_CLOCK_208MHZ;
- bus_speed_sel = SDIO_CCCR_BUS_SPEED_SUPPORT_HIGHSPEED | SDIO_CCCR_BUS_SPEED_SDR104;
- } else if ((card->cccr.support_sdr50 || (card->max_tran_speed_in_kbps > 25000)) && support_sdr50) {
- speed_mode = sdmmc_sd_speed_sdr50;
- clock_option = SD_CLOCK_100MHZ;
- bus_speed_sel = SDIO_CCCR_BUS_SPEED_SUPPORT_HIGHSPEED | SDIO_CCCR_BUS_SPEED_SDR50;
- } else if (card->cccr.support_ddr50 && support_ddr) {
- speed_mode = sdmmc_sd_speed_ddr50;
- clock_option = SD_CLOCK_50MHZ;
- need_reverse = false;
- bus_speed_sel = SDIO_CCCR_BUS_SPEED_SUPPORT_HIGHSPEED | SDIO_CCCR_BUS_SPEED_DDR50;
- } else {
- speed_mode = sdmmc_sd_speed_high;
- bus_speed_sel = SDIO_CCCR_BUS_SPEED_SUPPORT_HIGHSPEED | SDIO_CCCR_BUS_SPEED_HIGH;
- clock_option = SD_CLOCK_50MHZ;
- }
- status = sdio_io_write_byte(card, 0, SDIO_REG_CCCR_BUS_SPEED_SEL, bus_speed_sel);
- HPM_BREAK_IF(status != status_success);
- sdmmchost_set_speed_mode(card->host, speed_mode);
- card->host->clock_freq = sdmmchost_set_card_clock(card->host, clock_option, need_reverse);
- }
- } while (false);
- return status;
- }
- hpm_stat_t sdio_card_init(sdio_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL));
- sdmmchost_set_card_bus_width(card->host, sdmmc_bus_width_1bit);
- sdmmchost_set_card_clock(card->host, SDMMC_CLOCK_400KHZ, true);
- status = sdio_probe_sdio_card(card);
- card->host->operation_mode = hpm_sdmmc_operation_mode_identification;
- sdmmchost_init_io(card->host, card->host->operation_mode);
- HPM_BREAK_IF(status != status_success);
- card->host->dev_type = sdmmc_dev_type_sdio;
- /* Send CMD3 */
- status = sdio_send_rca(card);
- HPM_BREAK_IF(status != status_success);
- /* Send CMD7 */
- status = sdmmc_select_card(card->host, card->relative_addr, true);
- HPM_BREAK_IF(status != status_success);
- sdmmchost_set_card_clock(card->host, SD_CLOCK_25MHZ, true);
- card->host->operation_mode = hpm_sdmmc_operation_mode_transfer;
- sdmmchost_init_io(card->host, card->host->operation_mode);
- status = sdio_read_cccr(card);
- HPM_BREAK_IF(status != status_success);
- uint32_t common_cis_ptr = sdio_cis_csr_addr(card->cccr.common_cis_pointer);
- status = sdio_read_cis(card, common_cis_ptr, &card->common_cis, false);
- HPM_BREAK_IF(status != status_success);
- /* Change Bus Speed */
- status = sdio_set_timing(card);
- HPM_BREAK_IF(status != status_success);
- /* Change Bus width */
- status = sdio_set_bus_width(card);
- HPM_BREAK_IF(status != status_success);
- sdmmchost_init_io(card->host, card->host->operation_mode);
- sdio_get_max_transfer_speed(card);
- /* Update CCCR */
- status = sdio_read_cccr(card);
- } while (false);
- if (status == status_success) {
- card->host->card_init_done = true;
- }
- return status;
- }
- hpm_stat_t sdio_card_deinit(sdio_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL));
- if (!card->host->card_init_done) {
- status = status_sdmmc_device_init_required;
- break;
- }
- /* De-initialize functions */
- status = sdio_deinit_funcs(card);
- } while (false);
- if (status == status_success) {
- card->host->card_init_done = false;
- }
- return status;
- }
- hpm_stat_t sdio_get_max_transfer_speed(sdio_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL));
- uint32_t speed_units[8] = { 100UL, 1000UL, 10UL * 1000UL, 100UL * 1000UL, 0, 0, 0, 0 };
- uint32_t factor_mul10[16] = { 0, 10, 12, 13, 14, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
- uint32_t speed_unit_idx = card->common_cis.max_tran_speed & 0x7;
- uint32_t fact_idx = (card->common_cis.max_tran_speed >> 3) & 0xF;
- card->max_tran_speed_in_kbps = speed_units[speed_unit_idx] * factor_mul10[fact_idx] / 10;
- status = status_success;
- } while (false);
- return status;
- }
- hpm_stat_t sdio_init_funcs(sdio_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL));
- for (uint32_t i = 0; i <= card->num_of_functions; i++) {
- sdio_func_t *sdio_func = (sdio_func_t *) HPM_SDMMC_MALLOC(sizeof(sdio_func_t));
- if (sdio_func == NULL) {
- return status_fail;
- }
- card->sdio_func[i] = sdio_func;
- }
- for (uint32_t i = 1; i <= card->num_of_functions; i++) {
- sdio_func_t *sdio_func = card->sdio_func[i];
- status = sdio_read_fbr(card, i, &sdio_func->fbr);
- HPM_BREAK_IF(status != status_success);
- uint32_t cis_ptr = sdio_cis_csr_addr(sdio_func->fbr.cis_ptr);
- status = sdio_read_cis(card, cis_ptr, &sdio_func->cis, true);
- HPM_BREAK_IF(status != status_success);
- sdio_func->func_idx = i;
- sdio_func->max_block_size = sdio_func->cis.max_blk_size;
- sdio_func->current_block_size = sdio_func->cis.max_blk_size;
- }
- if (status != status_success) {
- for (uint32_t i = 0; i <= card->num_of_functions; i++) {
- HPM_SDMMC_FREE(card->sdio_func[i]);
- card->sdio_func[i] = NULL;
- }
- }
- } while (false);
- return status;
- }
- hpm_stat_t sdio_deinit_funcs(sdio_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- HPM_BREAK_IF((card == NULL) || (card->host == NULL));
- /* Free all buffers */
- for (uint32_t i = 0; i <= card->num_of_functions; i++) {
- if (card->sdio_func[i] == NULL) {
- continue;
- }
- /* Free TPL data if necessary */
- if (card->sdio_func[i]->cis.tpl_link != NULL) {
- sdio_tpl_blk_t current_tpl = card->sdio_func[i]->cis.tpl_link;
- while (current_tpl != NULL) {
- sdio_tpl_blk_t tmp_tpl = current_tpl->next;
- HPM_SDMMC_FREE(current_tpl);
- current_tpl = tmp_tpl;
- }
- }
- HPM_SDMMC_FREE(card->sdio_func[i]);
- card->sdio_func[i] = NULL;
- }
- status = status_success;
- } while (false);
- return status;
- }
- hpm_stat_t sdio_host_init(sdio_card_t *card)
- {
- hpm_stat_t status = status_success;
- assert(card != NULL);
- status = sdmmchost_init(card->host);
- if (status == status_success) {
- card->is_host_ready = true;
- if (IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_3V3)) {
- card->operation_voltage = sdmmc_operation_voltage_3v3;
- } else {
- card->operation_voltage = sdmmc_operation_voltage_1v8;
- }
- }
- return status_success;
- }
- hpm_stat_t sdio_host_deinit(sdio_card_t *card)
- {
- (void) card;
- return status_success;
- }
- const char *sdio_get_func_if_code_str(uint8_t std_func_if_code)
- {
- const char *code_str;
- switch (std_func_if_code) {
- case STD_SDIO_FUNC_IF_CODE_NON_STD:
- code_str = "No Standard SDIO interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_UART:
- code_str = "SDIO Standard UART";
- break;
- case STD_SDIO_FUNC_IF_CODE_BT_TYPEA:
- code_str = "SDIO Bluetooth Type-A standard interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_BT_TYPEB:
- code_str = "SDIO Bluetooth Type-B standard interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_GPS:
- code_str = "SDIO GPS standard interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_CAMERA:
- code_str = "SDIO Camera standard interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_PHS:
- code_str = "SDIO PHS standard interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_WLAN:
- code_str = "SDIO WLAN interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_ATA:
- code_str = "Embedded SDIO-ATA standard interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_BT_TYPEA_AMP:
- code_str = "SDIO Bluetooth Type-A AMP standard interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_ISDIO:
- code_str = "iSDIO standard interface";
- break;
- case STD_SDIO_FUNC_IF_CODE_EXT_STD:
- code_str = "Extended SDIO Function Interface";
- break;
- default:
- code_str = "UnKnown Interface Code";
- break;
- }
- return code_str;
- }
- hpm_stat_t sdio_enable_interrupt(sdio_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- if ((card == NULL) || (card->host == NULL)) {
- break;
- }
- sdmmchost_enable_sdio_interrupt(card->host, true);
- status = status_success;
- } while (false);
- return status;
- }
- hpm_stat_t sdio_disable_interrupt(sdio_card_t *card)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- if ((card == NULL) || (card->host == NULL)) {
- break;
- }
- sdmmchost_enable_sdio_interrupt(card->host, false);
- status = status_success;
- } while (false);
- return status;
- }
- hpm_stat_t sdio_register_irq_callback(sdio_card_t *card, void (*sdio_irq_callback)(void *param), void *sdio_irq_param)
- {
- hpm_stat_t status = status_invalid_argument;
- do {
- if ((card == NULL) || (card->host == NULL)) {
- break;
- }
- sdmmchost_register_sdio_callback(card->host, sdio_irq_callback, sdio_irq_param);
- status = status_success;
- } while (false);
- return status;
- }
|