1 /*
2  * Copyright (c) 2006-2024 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-05-05     vandoul      first
9  */
10 
11 #include <rtthread.h>
12 #include "cy_gpio.h"
13 #include "cyhal_gpio.h"
14 #include "cyhal_sdhc.h"
15 
16 #ifdef BSP_USING_SDCARD
17 
18 /*#define DRV_DEBUG*/
19 #define LOG_TAG             "drv.sdio"
20 #include <drv_log.h>
21 
22 #define SDIO_BLOCK_SIZE                         (512)
23 
24 #if BSP_USING_SDCARD_LED_CTRL_ENANBLE
25 #define SDCARD_LED_CTRL_ENABLE           true
26 #else
27 #define SDCARD_LED_CTRL_ENABLE           false
28 #endif
29 #if BSP_USING_SDCARD_EMMC_ENANBLE
30 #define SDCARD_EMMC_ENABLE           true
31 #else
32 #define SDCARD_EMMC_ENABLE           false
33 #endif
34 
35 struct _cy_sdio_pin_and_name_config
36 {
37     const char *name;
38     cyhal_gpio_t cmd;               /**< The pin connected to the command signal. */
39     cyhal_gpio_t clk;               /**< The pin connected to the clock signal. */
40     cyhal_gpio_t data0;             /**< The pin connected to the data0 signal. */
41     cyhal_gpio_t data1;             /**< The pin connected to the data1 signal. */
42     cyhal_gpio_t data2;             /**< The pin connected to the data2 signal. */
43     cyhal_gpio_t data3;             /**< The pin connected to the data3 signal. */
44     cyhal_gpio_t data4;             /**< The pin connected to the data4 signal; pass NC when unused. */
45     cyhal_gpio_t data5;             /**< The pin connected to the data5 signal; pass NC when unused. */
46     cyhal_gpio_t data6;             /**< The pin connected to the data6 signal; pass NC when unused. */
47     cyhal_gpio_t data7;             /**< The pin connected to the data7 signal; pass NC when unused. */
48     cyhal_gpio_t card_detect;       /**< The pin connected to the card detect signal. */
49     cyhal_gpio_t io_volt_sel;       /**< The pin connected to the voltage select signal. */
50     cyhal_gpio_t card_if_pwr_en;    /**< The pin connected to the card interface power enable signal. */
51     cyhal_gpio_t card_mech_write_prot; /**< The pin connected to the write protect signal. */
52     cyhal_gpio_t led_ctrl;          /**< The pin connected to the LED control signal. */
53     cyhal_gpio_t card_emmc_reset;   /**< The pin connected to the eMMC card reset signal. */
54 };
55 
56 static const struct _cy_sdio_pin_and_name_config _sdcard_config =
57 {
58     .name = "sd0",
59     .cmd                  = BSP_USING_SDCARD_CMD_PIN,
60     .clk                  = BSP_USING_SDCARD_CLK_PIN,
61     .data0                = BSP_USING_SDCARD_DAT0_PIN,
62     .data1                = BSP_USING_SDCARD_DAT1_PIN,
63     .data2                = BSP_USING_SDCARD_DAT2_PIN,
64     .data3                = BSP_USING_SDCARD_DAT3_PIN,
65     .data4                = BSP_USING_SDCARD_DAT4_PIN,
66     .data5                = BSP_USING_SDCARD_DAT5_PIN,
67     .data6                = BSP_USING_SDCARD_DAT6_PIN,
68     .data7                = BSP_USING_SDCARD_DAT7_PIN,
69     .card_detect          = BSP_USING_SDCARD_DETECT_PIN,
70     .io_volt_sel          = BSP_USING_SDCARD_IO_VOLT_SEL_PIN,
71     .card_if_pwr_en       = BSP_USING_SDCARD_CARD_IF_PWR_EN_PIN,
72     .card_mech_write_prot = BSP_USING_SDCARD_CARD_MECH_WRITE_PROT_PIN,
73     #if BSP_USING_SDCARD_LED_CTRL_PIN
74     .led_ctrl             = BSP_USING_SDCARD_LED_CTRL_PIN,
75     #else
76     .led_ctrl             = -1,
77     #endif
78     .card_emmc_reset      = BSP_USING_SDCARD_CARD_EMMC_RESET_PIN,
79 };
80 
81 #include <dfs_fs.h>
82 #include <drivers/dev_mmcsd_core.h>
83 #include <drivers/dev_gpt.h>
84 struct rthw_sdio
85 {
86     struct rt_device parent;
87     cyhal_sdhc_t sdhc_obj; /**< Object for use with the SDHC HAL driver. */
88     cyhal_sdhc_config_t sdhc_config; /**< Card configuration structure to be passed to the HAL driver. */
89     const struct _cy_sdio_pin_config *pins_cfg;
90     struct dfs_partition part;
91     struct rt_device_blk_geometry geometry;
92 };
rt_mmcsd_init(rt_device_t dev)93 static rt_err_t rt_mmcsd_init(rt_device_t dev)
94 {
95     return RT_EOK;
96 }
97 
rt_mmcsd_open(rt_device_t dev,rt_uint16_t oflag)98 static rt_err_t rt_mmcsd_open(rt_device_t dev, rt_uint16_t oflag)
99 {
100     return RT_EOK;
101 }
102 
rt_mmcsd_close(rt_device_t dev)103 static rt_err_t rt_mmcsd_close(rt_device_t dev)
104 {
105     return RT_EOK;
106 }
107 
rt_mmcsd_control(rt_device_t dev,int cmd,void * args)108 static rt_err_t rt_mmcsd_control(rt_device_t dev, int cmd, void *args)
109 {
110     struct rthw_sdio *sdio = (struct rthw_sdio *)dev;
111     struct dfs_partition *part = &sdio->part;
112     struct rt_device_blk_geometry *geometry = &sdio->geometry;
113     struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
114     switch (cmd)
115     {
116     case RT_DEVICE_CTRL_BLK_GETGEOME:
117         rt_memcpy(args, geometry, sizeof(struct rt_device_blk_geometry));
118         break;
119     case RT_DEVICE_CTRL_BLK_PARTITION:
120         rt_memcpy(args, part, sizeof(struct dfs_partition));
121     default:
122         break;
123     }
124     return RT_EOK;
125 }
126 
rt_mmcsd_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)127 static rt_ssize_t rt_mmcsd_read(rt_device_t dev,
128                                rt_off_t    pos,
129                                void       *buffer,
130                                rt_size_t   size)
131 {
132     rt_err_t err = 0;
133     void *rd_ptr = (void *)buffer;
134     struct rthw_sdio *sdio = (struct rthw_sdio *)dev;
135     cyhal_sdhc_t *hw_sdio = &sdio->sdhc_obj;
136     off_t offset = sdio->part.offset;
137 
138     LOG_D("mmc read: off:%d pos:%d size:%d", offset, pos, size);
139     if (dev == RT_NULL)
140     {
141         rt_set_errno(-RT_EINVAL);
142         return 0;
143     }
144 
145     rt_sem_take(sdio->part.lock, RT_WAITING_FOREVER);
146     do {
147         size_t block_count =  size;
148         uint32_t addr = (offset + pos);
149         cy_rslt_t result = cyhal_sdhc_read_async(hw_sdio, addr, buffer, &block_count);
150         if(CY_RSLT_SUCCESS != result)
151         {
152             err = -RT_ERROR;
153             break;
154         }
155         /* Waits on a semaphore until the transfer completes, when RTOS_AWARE component is defined. */
156         result = cyhal_sdhc_wait_transfer_complete(hw_sdio);
157         if(CY_RSLT_SUCCESS != result)
158         {
159             err = -RT_ERROR;
160             break;
161         }
162     }while(0);
163     rt_sem_release(sdio->part.lock);
164 
165     /* the length of reading must align to SECTOR SIZE */
166     if (err)
167     {
168         rt_set_errno(-RT_EIO);
169         return 0;
170     }
171     return size;
172 }
173 
rt_mmcsd_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)174 static rt_ssize_t rt_mmcsd_write(rt_device_t dev,
175                                 rt_off_t    pos,
176                                 const void *buffer,
177                                 rt_size_t   size)
178 {
179     rt_err_t err = 0;
180     void *rd_ptr = (void *)buffer;
181     struct rthw_sdio *sdio = (struct rthw_sdio *)dev;
182     cyhal_sdhc_t *hw_sdio = &sdio->sdhc_obj;
183     off_t offset = sdio->part.offset;
184 
185     LOG_D("mmc write: off:%d pos:%d size:%d", offset, pos, size);
186     if (dev == RT_NULL)
187     {
188         rt_set_errno(-RT_EINVAL);
189         return 0;
190     }
191 
192     rt_sem_take(sdio->part.lock, RT_WAITING_FOREVER);
193     do {
194         size_t block_count =  size ;
195         uint32_t addr = (offset + pos);
196         cy_rslt_t result = cyhal_sdhc_write_async(hw_sdio, addr, buffer, &block_count);
197         if(CY_RSLT_SUCCESS != result)
198         {
199             err = -RT_ERROR;
200             break;
201         }
202         /* Waits on a semaphore until the transfer completes, when RTOS_AWARE component is defined. */
203         result = cyhal_sdhc_wait_transfer_complete(hw_sdio);
204         if(CY_RSLT_SUCCESS != result)
205         {
206             err = -RT_ERROR;
207             break;
208         }
209     }while(0);
210     rt_sem_release(sdio->part.lock);
211 
212     /* the length of reading must align to SECTOR SIZE */
213     if (err)
214     {
215         rt_set_errno(-RT_EIO);
216         return 0;
217     }
218     return size;
219 }
220 #ifdef RT_USING_DEVICE_OPS
221 const static struct rt_device_ops mmcsd_blk_ops =
222 {
223     rt_mmcsd_init,
224     rt_mmcsd_open,
225     rt_mmcsd_close,
226     rt_mmcsd_read,
227     rt_mmcsd_write,
228     rt_mmcsd_control
229 };
230 #endif
rt_hw_sdio_init(void)231 int rt_hw_sdio_init(void)
232 {
233     struct rthw_sdio *sdio = RT_NULL;
234     struct _cy_sdio_pin_config *pins_cfg;
235     char sname[16];
236 
237     sdio = rt_malloc(sizeof(struct rthw_sdio));
238     if (sdio == RT_NULL)
239     {
240         LOG_E("malloc rthw_sdio fail");
241         return RT_NULL;
242     }
243     rt_memset(sdio, 0, sizeof(struct rthw_sdio));
244 
245     LOG_D("sdio pins: cmd=%d,clk=%d,d0=%d,d1=%d,d2=%d,d3=%d,d4=%d,d5=%d,d6=%d,d7=%d",
246         _sdio1_pins_and_name.cmd,   _sdio1_pins_and_name.clk,
247         _sdio1_pins_and_name.data0, _sdio1_pins_and_name.data1, _sdio1_pins_and_name.data2, _sdio1_pins_and_name.data3,
248         _sdio1_pins_and_name.data4, _sdio1_pins_and_name.data5, _sdio1_pins_and_name.data6, _sdio1_pins_and_name.data7
249     );
250     LOG_D("\tdetect=%d,volt_sel=%d,pwr_en=%d,write_prot=%d,led_ctrl=%d,emmc_reset=%d",
251         _sdio1_pins_and_name.card_detect,          _sdio1_pins_and_name.io_volt_sel, _sdio1_pins_and_name.card_if_pwr_en,
252         _sdio1_pins_and_name.card_mech_write_prot, _sdio1_pins_and_name.led_ctrl,    _sdio1_pins_and_name.card_emmc_reset
253     );
254     /* register mmcsd device */
255     sdio->parent.type  = RT_Device_Class_Block;
256 #ifdef RT_USING_DEVICE_OPS
257     sdio->parent.ops  = &mmcsd_blk_ops;
258 #else
259     sdio->parent.init = rt_mmcsd_init;
260     sdio->parent.open = rt_mmcsd_open;
261     sdio->parent.close = rt_mmcsd_close;
262     sdio->parent.read = rt_mmcsd_read;
263     sdio->parent.write = rt_mmcsd_write;
264     sdio->parent.control = rt_mmcsd_control;
265 #endif
266 
267     do {
268         sdio->sdhc_config.enableLedControl = SDCARD_LED_CTRL_ENABLE;
269         sdio->sdhc_config.isEmmc = SDCARD_EMMC_ENABLE;
270         sdio->sdhc_config.lowVoltageSignaling = false;
271         sdio->sdhc_config.busWidth = BSP_USING_SDCARD_BUS_WIDTH;
272         /* Initialize the SD Card interface. */
273         int rslt = cyhal_sdhc_init_hw(&sdio->sdhc_obj, &sdio->sdhc_config, _sdcard_config.cmd,   _sdcard_config.clk,
274                                  _sdcard_config.data0,  _sdcard_config.data1, _sdcard_config.data2, _sdcard_config.data3,
275                                  _sdcard_config.data4,  _sdcard_config.data5, _sdcard_config.data6, _sdcard_config.data7,
276                                  _sdcard_config.card_detect, _sdcard_config.io_volt_sel, _sdcard_config.card_if_pwr_en,
277                                  _sdcard_config.card_mech_write_prot, _sdcard_config.led_ctrl, _sdcard_config.card_emmc_reset, RT_NULL);
278         if(rslt != CY_RSLT_SUCCESS)
279         {
280             LOG_E("sdhc hw init fail: (0x%x)", rslt);
281             break;
282         }
283 
284         rslt = cyhal_sdhc_init_card(&sdio->sdhc_obj);
285         if(rslt != CY_RSLT_SUCCESS)
286         {
287             LOG_E("sdhc init fail: (0x%x)", rslt);
288             break;
289         }
290 
291         rt_uint32_t block_count;
292         rslt = cyhal_sdhc_get_block_count(&sdio->sdhc_obj, &block_count);
293         if(rslt != CY_RSLT_SUCCESS)
294         {
295             LOG_E("get block count fail: (0x%x)", rslt);
296             break;
297         }
298         LOG_D("block count:%d(0x%x)", block_count, block_count);
299 
300         sdio->geometry.bytes_per_sector = 512;
301         sdio->geometry.block_size = 512;
302         sdio->geometry.sector_count = block_count;
303 
304         rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", _sdcard_config.name, 0);
305         sdio->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
306         if(sdio->part.lock == RT_NULL)
307         {
308             LOG_E("create part.lock fail");
309             break;
310         }
311 
312         rt_uint8_t *sector = rt_malloc(512);
313         if(sector == RT_NULL)
314         {
315             LOG_E("malloc sector fail");
316             break;
317         }
318         if(rt_mmcsd_read(&sdio->parent, 0, sector, 1) < 0)
319         {
320             LOG_E("rt_mmcsd_read fail");
321             rt_free(sector);
322             break;
323         }
324         rslt = dfs_filesystem_get_partition(&sdio->part, sector, 0);
325         rt_free(sector);
326         if(rslt != RT_EOK)
327         {
328             LOG_E("partition not found!");
329             break;
330         }
331 
332         rslt = rt_device_register(&(sdio->parent), _sdcard_config.name,
333                        RT_DEVICE_FLAG_RDWR);
334 
335         if(rslt != RT_EOK)
336         {
337             LOG_E("register device fail!");
338             break;
339         }
340 
341         return RT_EOK;
342 
343     }while(0);
344 
345     if(sdio)
346     {
347         cyhal_sdhc_free(&sdio->sdhc_obj);
348         if(sdio->part.lock)
349         {
350             rt_sem_delete(sdio->part.lock);
351         }
352         rt_free(sdio);
353     }
354 
355     return -RT_ERROR;
356 }
357 INIT_DEVICE_EXPORT(rt_hw_sdio_init);
358 
359 #endif
360 
361