summaryrefslogtreecommitdiff
path: root/bsp/phytium/libraries/standalone/drivers/mmc/fsdio/fsdio_pio.c
blob: dfe4f1b5a90848945eff82a938b15690bd6e945f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*
 * Copyright : (C) 2022 Phytium Information Technology, Inc.
 * All Rights Reserved.
 *
 * This program is OPEN SOURCE software: you can redistribute it and/or modify it
 * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
 * either version 1.0 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the Phytium Public License for more details.
 *
 *
 * FilePath: fsdio_pio.c
 * Date: 2022-06-01 14:21:47
 * LastEditTime: 2022-06-01 14:21:47
 * Description:  This files is for PIO transfer related function implementation
 *
 * Modify History:
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 * 1.1   zhugengyu  2022/6/6     modify according to tech manual.
 */
/***************************** Include Files *********************************/

#include "fio.h"
#include "fdebug.h"
#include "fassert.h"
#include "ftypes.h"

#include "fcache.h"

#include "fsdio_hw.h"
#include "fsdio.h"

/************************** Constant Definitions *****************************/

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/
#define FSDIO_DEBUG_TAG "FSDIO-PIO"
#define FSDIO_ERROR(format, ...)   FT_DEBUG_PRINT_E(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDIO_WARN(format, ...)    FT_DEBUG_PRINT_W(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDIO_INFO(format, ...)    FT_DEBUG_PRINT_I(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDIO_DEBUG(format, ...)   FT_DEBUG_PRINT_D(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)

/************************** Function Prototypes ******************************/
extern FError FSdioTransferCmd(FSdio *const instance_p, FSdioCmdData *const cmd_data_p);

/*****************************************************************************/
/**
 * @name: FSdioPIOWriteData
 * @msg: Write data to fifo
 * @return {FError} FSDIO_SUCCESS if write success
 * @param {FSdio} *instance_p, SDIO controller instance
 * @param {FSdioData} *data_p, contents of transfer data
 */
static FError FSdioPIOWriteData(FSdio *const instance_p, FSdioData *data_p)
{
    FASSERT(data_p);
    FError ret = FSDIO_SUCCESS;
    u32 loop;
    uintptr base_addr = instance_p->config.base_addr;
    const u32 wr_times = data_p->datalen / sizeof(u32); /* u8 --> u32 */
    u32 *wr_buf = (u32 *)data_p->buf;

    /* while in PIO mode, max data transferred is 0x800 */
    if (data_p->datalen > FSDIO_MAX_FIFO_CNT)
    {
        FSDIO_ERROR("Fifo do not support write more than 0x%x", FSDIO_MAX_FIFO_CNT);
        return FSDIO_ERR_NOT_SUPPORT;
    }

    /* write fifo data */
    FSDIO_WRITE_REG(base_addr, FSDIO_CMD_OFFSET, FSDIO_CMD_DAT_WRITE);
    for (loop = 0; loop < wr_times; loop++)
    {
        FSDIO_WRITE_REG(base_addr, FSDIO_DATA_OFFSET, wr_buf[loop]);
    }

    return ret;
}

/**
 * @name: FSdioPIOReadData
 * @msg: Read data from fifo
 * @return {FError} FSDIO_SUCCESS if read success
 * @param {FSdio} *instance_p, SDIO controller instance
 * @param {FSdioData} *data_p, contents of transfer data
 */
FError FSdioPIOReadData(FSdio *const instance_p, FSdioData *data_p)
{
    FASSERT(data_p);
    FError ret = FSDIO_SUCCESS;
    u32 loop;
    uintptr base_addr = instance_p->config.base_addr;
    const u32 rd_times = data_p->datalen / sizeof(u32); /* u8 --> u32 */
    u32 *rd_buf = (u32 *)data_p->buf;

    /* while in PIO mode, max data transferred is 0x800 */
    if (data_p->datalen > FSDIO_MAX_FIFO_CNT)
    {
        FSDIO_ERROR("Fifo do not support write more than 0x%x", FSDIO_MAX_FIFO_CNT);
        return FSDIO_ERR_NOT_SUPPORT;
    }

    /* read data from fifo */
    for (loop = 0; loop < rd_times; loop++)
    {
        rd_buf[loop] = FSDIO_READ_REG(base_addr, FSDIO_DATA_OFFSET);
    }

    return ret;
}

/**
 * @name: FSdioPIOTransfer
 * @msg: Start command and data transfer in PIO mode
 * @return {FError} FSDIO_SUCCESS if transfer success, otherwise failed
 * @param {FSdio} *instance_p, SDIO controller instance
 * @param {FSdioCmdData} *cmd_data_p, contents of transfer command and data
 */
FError FSdioPIOTransfer(FSdio *const instance_p, FSdioCmdData *const cmd_data_p)
{
    FASSERT(instance_p);
    FASSERT(cmd_data_p);
    FError ret = FSDIO_SUCCESS;
    const boolean read = cmd_data_p->flag & FSDIO_CMD_FLAG_READ_DATA;
    uintptr base_addr = instance_p->config.base_addr;

    cmd_data_p->success = FALSE; /* reset cmd transfer status */

    if (FT_COMPONENT_IS_READY != instance_p->is_ready)
    {
        FSDIO_ERROR("device is not yet initialized!!!");
        return FSDIO_ERR_NOT_INIT;
    }

    if (FSDIO_PIO_TRANS_MODE != instance_p->config.trans_mode)
    {
        FSDIO_ERROR("device is not configure in PIO transfer mode");
        return FSDIO_ERR_INVALID_STATE;
    }

    /* for removable media, check if card exists */
    if ((FALSE == instance_p->config.non_removable) &&
            (FALSE == FSdioCheckIfCardExists(base_addr)))
    {
        FSDIO_ERROR("card not detected !!!");
        return FSDIO_ERR_NO_CARD;
    }

    /* reset fifo and not use DMA */
    FSDIO_CLR_BIT(base_addr, FSDIO_CNTRL_OFFSET, FSDIO_CNTRL_USE_INTERNAL_DMAC);
    ret = FSdioResetCtrl(base_addr, FSDIO_CNTRL_FIFO_RESET);
    if (FSDIO_SUCCESS != ret)
        return ret;
    FSDIO_CLR_BIT(base_addr, FSDIO_BUS_MODE_OFFSET, FSDIO_BUS_MODE_DE);

    if (NULL != cmd_data_p->data_p)
    {
        /* set transfer data length and block size */
        FSdioSetTransBytes(base_addr, cmd_data_p->data_p->datalen);
        FSdioSetBlockSize(base_addr, cmd_data_p->data_p->blksz);

        if (FALSE == read) /* if need to write, write to fifo before send command */
        {
            /* invalide buffer for data to write */
            FCacheDCacheInvalidateRange((uintptr)cmd_data_p->data_p->buf,
                                        cmd_data_p->data_p->datalen);

            ret = FSdioPIOWriteData(instance_p, cmd_data_p->data_p);
        }
    }

    if (FSDIO_SUCCESS == ret) /* send command */
    {
        ret = FSdioTransferCmd(instance_p, cmd_data_p);
    }

    return ret;
}

/**
 * @name: FSdioPollWaitPIOEnd
 * @msg: Wait PIO transfer finished by poll
 * @return {FError} FSDIO_SUCCESS if wait success, otherwise wait failed
 * @param {FSdio} *instance_p, SDIO controller instance
 * @param {FSdioCmdData} *cmd_data_p, contents of transfer command and data
 * @param {FSdioRelaxHandler} relax, handler of relax when wait busy
 */
FError FSdioPollWaitPIOEnd(FSdio *const instance_p, FSdioCmdData *const cmd_data_p, FSdioRelaxHandler relax)
{
    FASSERT(instance_p);
    FASSERT(cmd_data_p);
    FError ret = FSDIO_SUCCESS;
    u32 loop;
    u32 reg_val;
    int delay;
    const boolean read = cmd_data_p->flag & FSDIO_CMD_FLAG_READ_DATA;
    uintptr base_addr = instance_p->config.base_addr;

    if (FT_COMPONENT_IS_READY != instance_p->is_ready)
    {
        FSDIO_ERROR("device is not yet initialized!!!");
        return FSDIO_ERR_NOT_INIT;
    }

    if (FSDIO_PIO_TRANS_MODE != instance_p->config.trans_mode)
    {
        FSDIO_ERROR("device is not configure in PIO transfer mode");
        return FSDIO_ERR_INVALID_STATE;
    }

    FSDIO_INFO("wait for PIO cmd to finish ...");
    delay = FSDIO_TIMEOUT;
    do
    {
        reg_val = FSdioGetRawStatus(base_addr);
        if (relax)
            relax();
    }
    while (!(FSDIO_INT_CMD_BIT & reg_val) && (--delay > 0));

    if (!(FSDIO_INT_CMD_BIT & reg_val) && (delay <= 0))
    {
        FSDIO_ERROR("wait cmd done timeout, raw ints: 0x%x", reg_val);
        return FSDIO_ERR_CMD_TIMEOUT;
    }

    /* if need to read data, read fifo after send command */
    if ((NULL != cmd_data_p->data_p) && (read))
    {
        FSDIO_INFO("wait for PIO data to read ...");
        delay = FSDIO_TIMEOUT;
        do
        {
            reg_val = FSdioGetRawStatus(base_addr);
            if (relax)
                relax();
        }
        while (!(FSDIO_INT_DTO_BIT & reg_val) && (--delay > 0));

        /* clear status to ack */
        FSdioClearRawStatus(base_addr);
        FSDIO_INFO("card cnt: 0x%x, fifo cnt: 0x%x",
                   FSDIO_READ_REG(base_addr, FSDIO_TRAN_CARD_CNT_OFFSET),
                   FSDIO_READ_REG(base_addr, FSDIO_TRAN_FIFO_CNT_OFFSET));

        if (!(FSDIO_INT_DTO_BIT & reg_val) && (delay <= 0))
        {
            FSDIO_ERROR("wait PIO transfer timeout, raw ints: 0x%x", reg_val);
            return FSDIO_ERR_TRANS_TIMEOUT;
        }
    }

    /* clear status to ack cmd done */
    FSdioClearRawStatus(base_addr);

    if (FSDIO_SUCCESS == ret)
    {
        ret = FSdioGetCmdResponse(instance_p, cmd_data_p);
    }

    return ret;
}