1 /*******************************************************************************
2  * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * PolarFire SoC MSS eMMC SD Interface Level Driver.
7  *
8  * This eMMC/SD Interface driver provides functions for transferring
9  * configuration and programming commands to the eMMC/SD device. Functions
10  * contained within the eMMC/SD interface driver are accessed through the
11  * mss_mmc_if.h header file.
12  *
13  */
14 #include "mss_mmc_if.h"
15 #include "mss_mmc_regs.h"
16 #include "mss_mmc_types.h"
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 #define MMC_CLEAR                       0u
23 #define MMC_SET                         1u
24 #define SHIFT_16BIT                     16u
25 #define DELAY_COUNT                     0xFFFFu
26 
27 /***************************************************************************//**
28  * Local Function Prototypes
29  */
30 static cif_response_t response_1_parser(void);
31 static uint32_t process_request_checkresptype(uint8_t responsetype);
32 static cif_response_t cq_execute_task(uint8_t task_id);
33 /***************************************************************************//**
34  * cif_send_cmd()
35  * See ".h" for details of how to use this function.
36  */
cif_send_cmd(uint32_t cmd_arg,uint32_t cmd_type,uint8_t resp_type)37 cif_response_t cif_send_cmd
38 (
39     uint32_t cmd_arg,
40     uint32_t cmd_type,
41     uint8_t resp_type
42 )
43 {
44     uint32_t trans_status_isr;
45     cif_response_t ret_status = TRANSFER_IF_FAIL;
46 
47    /* clear all status interrupts except:
48     * current limit error, card interrupt, card removal, card insertion */
49     MMC->SRS12 = ~(SRS12_CURRENT_LIMIT_ERROR
50                             | SRS12_CARD_INTERRUPT
51                             | SRS12_CARD_REMOVAL
52                             | SRS12_CARD_INSERTION);
53 
54     /* Transfer the Command to the MMC device */
55     send_mmc_cmd(cmd_arg, cmd_type, resp_type, CHECK_IF_CMD_SENT_POLL);
56 
57     /* No responses for CMD 0,4,15 */
58     if ((MMC_CMD_0_GO_IDLE_STATE != cmd_type) && (MMC_CMD_4_SET_DSR != cmd_type)
59                                 && (MMC_CMD_15_GOTO_INACTIVE_STATE != cmd_type))
60     {
61         trans_status_isr = MMC->SRS12;
62 
63         if (SRS12_COMMAND_COMPLETE == (trans_status_isr & SRS12_COMMAND_COMPLETE))
64         {
65             /* If the response is an R1/B response */
66             if ((MSS_MMC_RESPONSE_R1 == resp_type) || (MSS_MMC_RESPONSE_R1B == resp_type))
67             {
68                 ret_status = response_1_parser();
69             }
70             else
71             {
72                 ret_status = TRANSFER_IF_SUCCESS;
73             }
74         }
75         else if (SRS12_ERROR_INTERRUPT == (SRS12_ERROR_INTERRUPT & trans_status_isr))
76         {
77             ret_status = TRANSFER_IF_FAIL;
78         }
79         else
80         {
81             ret_status = TRANSFER_IF_FAIL;
82         }
83     }
84     else
85     {
86         ret_status = TRANSFER_IF_SUCCESS;
87     }
88     /* clear flags for the next time */
89     MMC->SRS12 = ~(SRS12_CURRENT_LIMIT_ERROR
90                             | SRS12_CARD_INTERRUPT
91                             | SRS12_CARD_REMOVAL
92                             | SRS12_CARD_INSERTION);
93 
94     return(ret_status);
95 }
96 
97 /***************************************************************************//**
98  * The send_mmc_cmd() function transfers the eMMC/SD command and argument to the
99  * eMMC/SD device and waits until the core indicates that the command has been
100  * transferred successfully.
101  */
send_mmc_cmd(uint32_t cmd_arg,uint32_t cmd_type,uint8_t resp_type,cmd_response_check_options cmd_option)102 void send_mmc_cmd
103 (
104     uint32_t cmd_arg,
105     uint32_t cmd_type,
106     uint8_t resp_type,
107     cmd_response_check_options cmd_option
108 )
109 {
110     uint32_t command_information;
111     uint32_t srs9, trans_status_isr;
112 
113     /* check if command line is not busy */
114     do
115     {
116         srs9 = MMC->SRS09;
117     }while ((srs9 & SRS9_CMD_INHIBIT_CMD) != NO_CMD_INHIBIT);
118 
119     command_information = process_request_checkresptype(resp_type);
120 
121     MMC->SRS02 = cmd_arg;
122     MMC->SRS03 = (uint32_t)((cmd_type << CMD_SHIFT) | command_information);
123 
124     switch (cmd_option)
125     {
126         /* only need to wait around if expecting no response */
127         case CHECK_IF_CMD_SENT_POLL:
128             do
129             {
130                 trans_status_isr = MMC->SRS12;
131             }while (((SRS12_COMMAND_COMPLETE | SRS12_ERROR_INTERRUPT) & trans_status_isr) == MMC_CLEAR);
132             break;
133         case CHECK_IF_CMD_SENT_INT:
134             break;
135         case CHECK_IF_CMD_SENT_NO:    /* use when expecting a response */
136             /* No check- will be checked when response received */
137             break;
138         default:
139         /* nothing */
140             break;
141     }
142 }
143 
144 /***************************************************************************//**
145  * The response_1_parser() returns the contents of the Card Status Register.
146  * This function checks that none of the error fields are set within the CSR
147  * and the status of the READY_FOR_DATA flag (Bit 8).
148  */
response_1_parser(void)149 static cif_response_t response_1_parser(void)
150 {
151     cif_response_t ret_status = TRANSFER_IF_FAIL;
152     uint32_t response;
153 
154     response = MMC->SRS04;
155     if (MMC_CLEAR == (CARD_STATUS_ALL_ERRORS_MASK & response)) /* no error */
156     {
157         if ((CARD_STATUS_READY_FOR_DATA & response) != MMC_CLEAR)
158         {
159             ret_status = TRANSFER_IF_SUCCESS;
160         }
161         else
162         {
163             ret_status = DEVICE_BUSY;
164         }
165     }
166     return(ret_status);
167 }
168 
169 /*****************************************************************************/
process_request_checkresptype(uint8_t responsetype)170 static uint32_t process_request_checkresptype(uint8_t responsetype)
171 {
172     uint32_t command_information;
173 
174     /* check response type */
175     switch (responsetype) {
176     default:
177     case MSS_MMC_RESPONSE_NO_RESP:
178         command_information = (uint32_t)SRS3_NO_RESPONSE;
179         break;
180     case MSS_MMC_RESPONSE_R2:
181         command_information = (uint32_t)(SRS3_RESP_LENGTH_136
182                                          | SRS3_CRC_CHECK_EN);
183         break;
184     case MSS_MMC_RESPONSE_R3:
185     case MSS_MMC_RESPONSE_R4:
186         command_information = (uint32_t)SRS3_RESP_LENGTH_48;
187         break;
188     case MSS_MMC_RESPONSE_R1:
189     case MSS_MMC_RESPONSE_R5:
190     case MSS_MMC_RESPONSE_R6:
191     case MSS_MMC_RESPONSE_R7:
192         command_information = (uint32_t)(SRS3_RESP_LENGTH_48
193                                          | SRS3_CRC_CHECK_EN
194                                          | SRS3_INDEX_CHECK_EN);
195         break;
196     case MSS_MMC_RESPONSE_R1B:
197     case MSS_MMC_RESPONSE_R5B:
198         command_information = (uint32_t)(SRS3_RESP_LENGTH_48B
199                                          | SRS3_CRC_CHECK_EN
200                                          | SRS3_INDEX_CHECK_EN);
201 
202         break;
203     }
204 
205     return (command_information);
206 }
207 
208 /******************************************************************************/
cif_send_cq_direct_command(uint8_t * desc_base_addr,uint32_t cmd_arg,uint32_t cmd_type,uint8_t resp_type,uint8_t task_id)209 cif_response_t cif_send_cq_direct_command
210 (
211     uint8_t *desc_base_addr,
212     uint32_t cmd_arg,
213     uint32_t cmd_type,
214     uint8_t resp_type,
215     uint8_t task_id
216 )
217 {
218 
219     uint32_t *dcmdTaskDesc;
220     uint32_t flags;
221     uint32_t desc_offset;
222     uint32_t reg;
223     uint32_t cmd_response;
224     cif_response_t ret_status = TRANSFER_IF_FAIL;
225 
226     /* Enable direct command */
227     reg = MMC->CQRS02;
228     reg |= (uint32_t)CQRS02_DIRECT_CMD_ENABLE;
229     MMC->CQRS02 = reg;
230 
231     desc_offset = CQ_HOST_NUMBER_OF_TASKS * task_id;
232 
233     dcmdTaskDesc = (uint32_t *)(desc_base_addr + desc_offset);
234 
235     /* first prepare general task flags */
236     flags = (uint32_t)(CQ_DESC_VALID |  CQ_DESC_END | CQ_DESC_ACT_TASK | CQ_DESC_INT);
237 
238     /* now prepare direct command specific flags */
239     flags |= ((cmd_type & 0x3FU) << SHIFT_16BIT);
240 
241     switch (resp_type)
242     {
243     case MSS_MMC_RESPONSE_NO_RESP:
244         flags |= (uint32_t)CQ_DESC_DCMD_RESP_TYPE_NO_RESP;
245         break;
246     case MSS_MMC_RESPONSE_R1:
247     case MSS_MMC_RESPONSE_R4:
248     case MSS_MMC_RESPONSE_R5:
249         flags |= (uint32_t)CQ_DESC_DCMD_RESP_TYPE_R1_R4_R5;
250         break;
251     case MSS_MMC_RESPONSE_R1B:
252         flags |= (uint32_t)CQ_DESC_DCMD_RESP_TYPE_R1B;
253         break;
254     default:
255         /* nothing */
256         break;
257     }
258 
259     flags |= (uint32_t)CQ_DESC_DCMD_CMD_TIMING;
260 
261     dcmdTaskDesc[0] = flags;
262     dcmdTaskDesc[1] = cmd_arg << SHIFT_16BIT;
263     dcmdTaskDesc[2] = MMC_CLEAR;
264     dcmdTaskDesc[3] = MMC_CLEAR;
265 
266     dcmdTaskDesc[4] = (uint32_t)(CQ_DESC_VALID |  CQ_DESC_END | CQ_DESC_ACT_NOP);
267     dcmdTaskDesc[5] = MMC_CLEAR;
268     dcmdTaskDesc[6] = MMC_CLEAR;
269     dcmdTaskDesc[7] = MMC_CLEAR;
270 
271     ret_status = cq_execute_task(task_id);
272 
273     cmd_response = MMC->CQRS18;
274 
275     reg = MMC->CQRS02;
276     reg &= ~(uint32_t)CQRS02_DIRECT_CMD_ENABLE;
277     MMC->CQRS02 = reg;
278 
279     if (TRANSFER_IF_SUCCESS == ret_status)
280     {
281         if ((CARD_STATUS_ALL_ERRORS_MASK & cmd_response) == MMC_CLEAR) /* no error */
282         {
283             if ((CARD_STATUS_READY_FOR_DATA & cmd_response) != MMC_CLEAR)
284             {
285                 ret_status = TRANSFER_IF_SUCCESS;
286             }
287             else
288             {
289                 ret_status = DEVICE_BUSY;
290             }
291         }
292     }
293     return ret_status;
294 }
295 
296 /******************************************************************************/
cq_execute_task(uint8_t task_id)297 static cif_response_t cq_execute_task(uint8_t task_id)
298 {
299 
300     cif_response_t ret_status = TRANSFER_IF_FAIL;
301     uint32_t reg;
302     uint32_t trans_status_isr;
303     uint32_t cmd_response;
304     uint32_t value = DELAY_COUNT;
305 
306     /* Set doorbell to start processing descriptors by controller */
307     reg = MMC_SET << task_id;
308     MMC->CQRS10 = reg;
309 
310     while (value--);
311 
312     do
313     {
314         trans_status_isr = MMC->SRS12;
315     }while (((SRS12_ERROR_INTERRUPT | SRS12_CMD_QUEUING_INT) & trans_status_isr) == MMC_CLEAR);
316 
317     if ((trans_status_isr & (SRS12_ERROR_INTERRUPT | SRS12_CMD_QUEUING_INT)) != MMC_CLEAR)
318     {
319         trans_status_isr = MMC->SRS12;
320         MMC->SRS12 = trans_status_isr;
321 
322         if ((trans_status_isr & SRS12_ERROR_INTERRUPT) != MMC_CLEAR)
323         {
324             ret_status = TRANSFER_IF_FAIL;
325         }
326         if ((trans_status_isr & SRS12_CMD_QUEUING_INT) != MMC_CLEAR)
327         {
328             reg = MMC->CQRS04;
329             MMC->CQRS04 = reg;
330 
331             if ((reg & CQRS04_RESP_ERR_INT) != MMC_CLEAR)
332             {
333                 ret_status = TRANSFER_IF_FAIL;
334             }
335 
336             if ((reg & CQRS04_TASK_COMPLETE_INT) != MMC_CLEAR)
337             {
338                 reg = MMC->CQRS11;
339                 /* clear all caught notifications */
340                 MMC->CQRS11 = reg;
341                 if (task_id == CQ_DCMD_TASK_ID)
342                 {
343                     if ((reg & (MMC_SET << task_id)) != MMC_CLEAR)
344                     {
345                         cmd_response = MMC->CQRS18;
346                         ret_status = TRANSFER_IF_SUCCESS;
347                     }
348                 }
349                 else
350                 {
351                     ret_status = TRANSFER_IF_SUCCESS;
352                 }
353             }
354         }
355     }
356     else
357     {
358         ret_status = TRANSFER_IF_FAIL;
359     }
360     return ret_status;
361 }
362 /******************************************************************************/
363 #ifdef __cplusplus
364 }
365 #endif
366