• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_sdmmc_common.h"
9 #include "hpm_sdmmc_card.h"
10 #include <string.h>
11 
sdmmc_go_idle_state(sdmmc_host_t * host,uint32_t argument)12 hpm_stat_t sdmmc_go_idle_state(sdmmc_host_t *host, uint32_t argument)
13 {
14     hpm_stat_t status = status_invalid_argument;
15 
16     do {
17         HPM_BREAK_IF(host == NULL);
18         sdmmchost_cmd_t *host_cmd = &host->cmd;
19         (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
20 
21         host_cmd->cmd_index = sdmmc_cmd_go_idle_state;
22         host_cmd->cmd_argument = argument;
23         host_cmd->resp_type = sdxc_dev_resp_none;
24 
25         status = sdmmchost_send_command(host, host_cmd);
26 
27     } while (false);
28 
29     return status;
30 }
31 
sdmmc_go_inactive_state(sdmmc_host_t * host,uint16_t relative_addr)32 hpm_stat_t sdmmc_go_inactive_state(sdmmc_host_t *host, uint16_t relative_addr)
33 {
34     hpm_stat_t status = status_invalid_argument;
35 
36     do {
37         HPM_BREAK_IF(host == NULL);
38         sdmmchost_cmd_t *host_cmd = &host->cmd;
39         (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
40 
41         host_cmd->cmd_index = sdmmc_cmd_go_inactive_state;
42         host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
43         host_cmd->resp_type = sdxc_dev_resp_none;
44 
45         status = sdmmchost_send_command(host, host_cmd);
46 
47     } while (false);
48 
49     return status;
50 }
51 
sdmmc_select_card(sdmmc_host_t * host,uint16_t relative_addr,bool is_selected)52 hpm_stat_t sdmmc_select_card(sdmmc_host_t *host, uint16_t relative_addr, bool is_selected)
53 {
54     hpm_stat_t status = status_invalid_argument;
55 
56     do {
57         HPM_BREAK_IF(host == NULL);
58         sdmmchost_cmd_t *host_cmd = &host->cmd;
59         (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
60 
61         host_cmd->cmd_index = sdmmc_cmd_select_card;
62         host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
63 
64         if (is_selected) {
65             host_cmd->resp_type = sdxc_dev_resp_r1b;
66         } else {
67             host_cmd->resp_type = sdxc_dev_resp_none;
68         }
69         status = sdmmchost_send_command(host, host_cmd);
70 
71     } while (false);
72 
73     return status;
74 }
75 
sdmmc_send_application_command(sdmmc_host_t * host,uint16_t relative_addr)76 hpm_stat_t sdmmc_send_application_command(sdmmc_host_t *host, uint16_t relative_addr)
77 {
78     hpm_stat_t status = status_invalid_argument;
79 
80     do {
81         HPM_BREAK_IF(host == NULL);
82         sdmmchost_cmd_t *host_cmd = &host->cmd;
83         (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
84 
85         host_cmd->cmd_index = sdmmc_cmd_app_cmd;
86         host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
87 
88         host_cmd->resp_type = sdxc_dev_resp_r1;
89         status = sdmmchost_send_command(host, host_cmd);
90 
91     } while (false);
92 
93     return status;
94 }
95 
sdmmc_set_block_count(sdmmc_host_t * host,uint32_t block_count)96 hpm_stat_t sdmmc_set_block_count(sdmmc_host_t *host, uint32_t block_count)
97 {
98     hpm_stat_t status = status_invalid_argument;
99 
100     do {
101         HPM_BREAK_IF(host == NULL);
102         sdmmchost_cmd_t *host_cmd = &host->cmd;
103         (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
104 
105         host_cmd->cmd_index = sdmmc_cmd_set_block_count;
106         host_cmd->cmd_argument = block_count;
107         host_cmd->resp_type = sdxc_dev_resp_r1;
108 
109         status = sdmmchost_send_command(host, host_cmd);
110 
111     } while (false);
112 
113     return status;
114 }
115 
sdmmc_set_block_size(sdmmc_host_t * host,uint32_t block_size)116 hpm_stat_t sdmmc_set_block_size(sdmmc_host_t *host, uint32_t block_size)
117 {
118     hpm_stat_t status = status_invalid_argument;
119 
120     do {
121         HPM_BREAK_IF(host == NULL);
122         sdmmchost_cmd_t *host_cmd = &host->cmd;
123         (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
124 
125         host_cmd->cmd_index = sdmmc_cmd_set_block_length;
126         host_cmd->cmd_argument = block_size;
127         host_cmd->resp_type = sdxc_dev_resp_r1;
128 
129         status = sdmmchost_send_command(host, host_cmd);
130 
131     } while (false);
132 
133     return status;
134 }
135 
sdmmc_enable_auto_tuning(sdmmc_host_t * host)136 hpm_stat_t sdmmc_enable_auto_tuning(sdmmc_host_t *host)
137 {
138     hpm_stat_t status = status_invalid_argument;
139 
140     do {
141         HPM_BREAK_IF((host == NULL) || (host->host_param.base == NULL));
142 
143         SDXC_Type *base = host->host_param.base;
144 
145         /* Prepare the Auto tuning environment */
146         sdxc_stop_clock_during_phase_code_change(base, true);
147         sdxc_set_post_change_delay(base, 3U);
148         sdxc_select_cardclk_delay_source(base, false);
149         sdxc_enable_power(base, true);
150 
151         /* Start Auto tuning */
152         uint8_t tuning_cmd = (host->dev_type == sdmmc_dev_type_sd) ? 19U : 21U;
153         status = sdxc_perform_auto_tuning(host->host_param.base, tuning_cmd);
154         HPM_BREAK_IF(status != status_success);
155 
156     } while (false);
157 
158     return status;
159 }
160 
extract_csd_field(const uint32_t * raw_csd,uint8_t end_offset,uint8_t start_offset)161 uint32_t extract_csd_field(const uint32_t *raw_csd, uint8_t end_offset, uint8_t start_offset)
162 {
163     uint32_t result = 0;
164 
165     uint32_t start_word_index = start_offset / 32;
166     uint32_t end_word_index = end_offset / 32;
167     uint32_t end_offset_in_word = end_offset % 32;
168     uint32_t start_offset_in_word = start_offset % 32;
169 
170     /* If all bits of the field are in the same raw_csd word */
171     if (start_word_index == end_word_index) {
172         uint32_t field_width = end_offset - start_offset + 1U;
173         uint32_t field_mask = ((1UL << field_width) - 1U) << start_offset;
174         result = (raw_csd[start_word_index] & field_mask) >> start_offset_in_word;
175     } else {
176         /* If the bits of the field crosses two raw_csd words */
177         uint32_t lsb_width = 32U - start_offset_in_word;
178         uint32_t result_lsb = raw_csd[start_word_index] >> start_offset_in_word;
179         uint32_t msb_width = end_offset_in_word + 1UL;
180         uint32_t result_msb = raw_csd[end_word_index] & ((1UL << msb_width) - 1U);
181         result = (result_msb << lsb_width) | result_lsb;
182     }
183 
184     return result;
185 }
186