|
| 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 | + * 2024-08-16 zhujiale first version |
| 9 | + */ |
| 10 | + |
| 11 | +#ifndef __DEV_SDHCI_HOST_H__ |
| 12 | +#define __DEV_SDHCI_HOST_H__ |
| 13 | + |
| 14 | +#include <rtthread.h> |
| 15 | + |
| 16 | +#include <drivers/dma.h> |
| 17 | +#include <drivers/mmcsd_cmd.h> |
| 18 | +#include <drivers/mmcsd_host.h> |
| 19 | +#include <drivers/dev_mmcsd_core.h> |
| 20 | + |
| 21 | +#define rt_mmc_dev(x) ((x)->parent) |
| 22 | + |
| 23 | +#define MMC_SEND_TUNING_BLOCK_HS200 SEND_TUNING_BLOCK_HS200 |
| 24 | +#define MMC_SEND_TUNING_BLOCK SEND_TUNING_BLOCK |
| 25 | +#define MMC_STOP_TRANSMISSION STOP_TRANSMISSION |
| 26 | +#define MMC_BUS_TEST_R 14 /* adtc R1 */ |
| 27 | +#define MMC_WRITE_MULTIPLE_BLOCK WRITE_MULTIPLE_BLOCK |
| 28 | +#define MMC_READ_MULTIPLE_BLOCK READ_MULTIPLE_BLOCK |
| 29 | + |
| 30 | +#define MMC_TIMING_UHS_DDR50 MMCSD_TIMING_UHS_DDR50 |
| 31 | +#define MMC_TIMING_UHS_SDR50 MMCSD_TIMING_UHS_SDR50 |
| 32 | +#define MMC_TIMING_MMC_HS200 MMCSD_TIMING_MMC_HS200 |
| 33 | +#define MMC_TIMING_MMC_HS400 MMCSD_TIMING_MMC_HS400 |
| 34 | +#define MMC_TIMING_UHS_SDR104 MMCSD_TIMING_UHS_SDR104 |
| 35 | +#define MMC_TIMING_UHS_SDR25 MMCSD_TIMING_UHS_SDR25 |
| 36 | +#define MMC_TIMING_MMC_DDR52 MMCSD_TIMING_MMC_DDR52 |
| 37 | +#define MMC_TIMING_UHS_SDR12 MMCSD_TIMING_UHS_SDR12 |
| 38 | +#define MMC_TIMING_SD_HS MMCSD_TIMING_SD_HS |
| 39 | +#define MMC_TIMING_MMC_HS MMCSD_TIMING_MMC_HS |
| 40 | + |
| 41 | +#define MMC_POWER_OFF MMCSD_POWER_OFF |
| 42 | +#define MMC_POWER_UP MMCSD_POWER_UP |
| 43 | +#define MMC_POWER_ON MMCSD_POWER_ON |
| 44 | +#define MMC_POWER_UNDEFINED 3 |
| 45 | + |
| 46 | +#define MMC_SET_DRIVER_TYPE_B 0 |
| 47 | +#define MMC_SET_DRIVER_TYPE_A 1 |
| 48 | +#define MMC_SET_DRIVER_TYPE_C 2 |
| 49 | +#define MMC_SET_DRIVER_TYPE_D 3 |
| 50 | + |
| 51 | +#define MMC_SIGNAL_VOLTAGE_330 0 |
| 52 | +#define MMC_SIGNAL_VOLTAGE_180 1 |
| 53 | +#define MMC_SIGNAL_VOLTAGE_120 2 |
| 54 | + |
| 55 | +#define MMC_RSP_PRESENT (1 << 16) |
| 56 | +#define MMC_RSP_136 (1 << 17) /* 136 bit response */ |
| 57 | +#define MMC_RSP_CRC (1 << 18) /* expect valid crc */ |
| 58 | +#define MMC_RSP_BUSY (1 << 19) /* card may send busy */ |
| 59 | +#define MMC_RSP_OPCODE (1 << 20) /* response contains opcode */ |
| 60 | + |
| 61 | +#define MMC_RSP_NONE (0) |
| 62 | +#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) |
| 63 | +#define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) |
| 64 | +#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) |
| 65 | +#define MMC_RSP_R3 (MMC_RSP_PRESENT) |
| 66 | +#define MMC_RSP_R4 (MMC_RSP_PRESENT) |
| 67 | +#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) |
| 68 | +#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) |
| 69 | +#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) |
| 70 | + |
| 71 | +#define MMC_CMD_ADTC CMD_ADTC |
| 72 | + |
| 73 | +#define MMC_BUS_WIDTH_8 MMCSD_BUS_WIDTH_8 |
| 74 | +#define MMC_BUS_WIDTH_4 MMCSD_BUS_WIDTH_4 |
| 75 | +#define MMC_BUS_WIDTH_1 MMCSD_BUS_WIDTH_1 |
| 76 | + |
| 77 | +#define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */ |
| 78 | +#define MMC_PM_WAKE_SDIO_IRQ (1 << 1) /* wake up host system on SDIO IRQ assertion */ |
| 79 | + |
| 80 | +enum mmc_blk_status |
| 81 | +{ |
| 82 | + MMC_BLK_SUCCESS = 0, |
| 83 | + MMC_BLK_PARTIAL, |
| 84 | + MMC_BLK_CMD_ERR, |
| 85 | + MMC_BLK_RETRY, |
| 86 | + MMC_BLK_ABORT, |
| 87 | + MMC_BLK_DATA_ERR, |
| 88 | + MMC_BLK_ECC_ERR, |
| 89 | + MMC_BLK_NOMEDIUM, |
| 90 | + MMC_BLK_NEW_REQUEST, |
| 91 | +}; |
| 92 | + |
| 93 | +#define MMC_NUM_CLK_PHASES (MMC_TIMING_MMC_HS400 + 1) |
| 94 | + |
| 95 | +struct rt_mmc_host; |
| 96 | + |
| 97 | +struct rt_mmc_host_ops |
| 98 | +{ |
| 99 | + void (*request)(struct rt_mmc_host *host, struct rt_mmcsd_req *req); |
| 100 | + void (*set_ios)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios); |
| 101 | + int (*get_ro)(struct rt_mmc_host *host); |
| 102 | + int (*get_cd)(struct rt_mmc_host *host); |
| 103 | + void (*enable_sdio_irq)(struct rt_mmc_host *host, int enable); |
| 104 | + void (*ack_sdio_irq)(struct rt_mmc_host *host); |
| 105 | + int (*start_signal_voltage_switch)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios); |
| 106 | + int (*card_busy)(struct rt_mmc_host *host); |
| 107 | + int (*execute_tuning)(struct rt_mmc_host *host, unsigned opcode); |
| 108 | + int (*prepare_hs400_tuning)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios); |
| 109 | + int (*hs400_prepare_ddr)(struct rt_mmc_host *host); |
| 110 | + void (*hs400_downgrade)(struct rt_mmc_host *host); |
| 111 | + void (*hs400_complete)(struct rt_mmc_host *host); |
| 112 | + void (*hs400_enhanced_strobe)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios); |
| 113 | + void (*hw_reset)(struct rt_mmc_host *host); |
| 114 | + void (*card_event)(struct rt_mmc_host *host); |
| 115 | +}; |
| 116 | + |
| 117 | +/* VDD voltage 3.3 ~ 3.4 */ |
| 118 | +#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ |
| 119 | +#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ |
| 120 | + |
| 121 | +#define MMC_CAP2_HS200_1_8V_SDR MMCSD_SUP_HS200_1V8 |
| 122 | +#define MMC_CAP2_HS200_1_2V_SDR MMCSD_SUP_HS200_1V2 |
| 123 | +#define MMC_CAP_4_BIT_DATA MMCSD_BUSWIDTH_4 |
| 124 | +#define MMC_CAP_8_BIT_DATA MMCSD_BUSWIDTH_8 |
| 125 | +#define MMC_CAP2_HS200 MMCSD_SUP_HS200 |
| 126 | +#define MMC_CAP_MMC_HIGHSPEED MMCSD_SUP_HIGHSPEED |
| 127 | +#define MMC_CAP_SD_HIGHSPEED MMCSD_SUP_HIGHSPEED |
| 128 | +#define MMC_CAP_1_8V_DDR MMCSD_SUP_DDR_1V8 |
| 129 | +#define MMC_CAP_3_3V_DDR MMCSD_SUP_DDR_3V3 |
| 130 | +#define MMC_CAP_1_2V_DDR MMCSD_SUP_DDR_1V2 |
| 131 | +#define MMC_CAP_NONREMOVABLE MMCSD_SUP_NONREMOVABLE |
| 132 | + |
| 133 | +#define MMC_CAP_UHS_DDR50 0 |
| 134 | +#define MMC_CAP2_HS400 0 |
| 135 | +#define MMC_CAP_UHS_SDR50 0 |
| 136 | +#define MMC_CAP_UHS_SDR25 0 |
| 137 | +#define MMC_CAP_UHS_SDR12 0 |
| 138 | +#define MMC_CAP_UHS_SDR104 0 |
| 139 | +#define MMC_CAP_UHS 0 |
| 140 | +#define MMC_CAP2_HSX00_1_8V 0 |
| 141 | +#define MMC_CAP2_HS400_ES 0 |
| 142 | +#define MMC_CAP_NEEDS_POLL 0 |
| 143 | +#define MMC_CAP2_HSX00_1_2V 0 |
| 144 | +#define MMC_CAP2_HS400_1_2V 0 |
| 145 | +#define MMC_CAP2_HS400_1_8V 0 |
| 146 | +#define MMC_CAP_DRIVER_TYPE_D 0 |
| 147 | +#define MMC_CAP_DRIVER_TYPE_C 0 |
| 148 | +#define MMC_SET_DRIVER_TYPE_B 0 |
| 149 | +#define MMC_CAP_DRIVER_TYPE_A 0 |
| 150 | +#define MMC_CAP2_SDIO_IRQ_NOTHREAD 0 |
| 151 | +#define MMC_CAP_CMD23 0 |
| 152 | +#define MMC_CAP_SDIO_IRQ 0 |
| 153 | + |
| 154 | +#define MMC_CAP2_NO_SDIO (1 << 19) |
| 155 | +#define MMC_CAP2_NO_SD (1 << 21) |
| 156 | +#define MMC_CAP2_NO_MMC (1 << 22) |
| 157 | +#define MMC_CAP2_CQE (1 << 23) |
| 158 | + |
| 159 | +#define MMC_VDD_165_195 VDD_165_195 |
| 160 | +#define MMC_VDD_20_21 VDD_20_21 |
| 161 | +#define MMC_VDD_29_30 VDD_29_30 |
| 162 | +#define MMC_VDD_30_31 VDD_30_31 |
| 163 | +#define MMC_VDD_32_33 VDD_32_33 |
| 164 | +#define MMC_VDD_33_34 VDD_33_34 |
| 165 | + |
| 166 | +struct rt_mmc_host |
| 167 | +{ |
| 168 | + struct rt_mmcsd_host rthost; |
| 169 | + struct rt_device *parent; |
| 170 | + int index; |
| 171 | + const struct rt_mmc_host_ops *ops; |
| 172 | + unsigned int f_min; |
| 173 | + unsigned int f_max; |
| 174 | + unsigned int f_init; |
| 175 | + rt_uint32_t ocr_avail; |
| 176 | + rt_uint32_t ocr_avail_sdio; /* SDIO-specific OCR */ |
| 177 | + rt_uint32_t ocr_avail_sd; /* SD-specific OCR */ |
| 178 | + rt_uint32_t ocr_avail_mmc; /* MMC-specific OCR */ |
| 179 | + struct wakeup_source *ws; /* Enable consume of uevents */ |
| 180 | + rt_uint32_t max_current_330; |
| 181 | + rt_uint32_t max_current_300; |
| 182 | + rt_uint32_t max_current_180; |
| 183 | + rt_uint32_t caps; /* Host capabilities */ |
| 184 | + rt_uint32_t caps2; /* More host capabilities */ |
| 185 | + |
| 186 | + |
| 187 | + /* host specific block data */ |
| 188 | + unsigned int max_seg_size; /* see blk_queue_max_segment_size */ |
| 189 | + unsigned short max_segs; /* see blk_queue_max_segments */ |
| 190 | + unsigned short unused; |
| 191 | + unsigned int max_req_size; /* maximum number of bytes in one req */ |
| 192 | + unsigned int max_blk_size; /* maximum size of one mmc block */ |
| 193 | + unsigned int max_blk_count; /* maximum number of blocks in one req */ |
| 194 | + unsigned int max_busy_timeout; /* max busy timeout in ms */ |
| 195 | + struct rt_mmcsd_io_cfg ios; /* current io bus settings */ |
| 196 | + unsigned int retune_period; |
| 197 | + /* group bitfields together to minimize padding */ |
| 198 | + unsigned int use_spi_crc : 1; |
| 199 | + unsigned int claimed : 1; /* host exclusively claimed */ |
| 200 | + unsigned int doing_init_tune : 1; /* initial tuning in progress */ |
| 201 | + unsigned int can_retune : 1; /* re-tuning can be used */ |
| 202 | + unsigned int doing_retune : 1; /* re-tuning in progress */ |
| 203 | + unsigned int retune_now : 1; /* do re-tuning at next req */ |
| 204 | + unsigned int retune_paused : 1; /* re-tuning is temporarily disabled */ |
| 205 | + unsigned int retune_crc_disable : 1; /* don't trigger retune upon crc */ |
| 206 | + unsigned int can_dma_map_merge : 1; /* merging can be used */ |
| 207 | + unsigned int vqmmc_enabled : 1; /* vqmmc regulator is enabled */ |
| 208 | + |
| 209 | + int need_retune; /* re-tuning is needed */ |
| 210 | + int hold_retune; /* hold off re-tuning */ |
| 211 | + rt_bool_t trigger_card_event; /* card_event necessary */ |
| 212 | + unsigned int sdio_irqs; |
| 213 | + rt_bool_t sdio_irq_pending; |
| 214 | + |
| 215 | + /* Ongoing data transfer that allows commands during transfer */ |
| 216 | + struct rt_mmcsd_req *ongoing_mrq; |
| 217 | + |
| 218 | + rt_uint32_t actual_clock; /* Actual HC clock rate */ |
| 219 | + rt_uint32_t pm_caps; |
| 220 | + rt_ubase_t private[]; |
| 221 | +}; |
| 222 | + |
| 223 | +rt_inline int mmc_card_is_removable(struct rt_mmc_host *host) |
| 224 | +{ |
| 225 | + return !(host->caps & MMC_CAP_NONREMOVABLE); |
| 226 | +} |
| 227 | + |
| 228 | +struct rt_mmc_host *rt_mmc_alloc_host(int extra, struct rt_device *); |
| 229 | +rt_err_t rt_mmc_add_host(struct rt_mmc_host *); |
| 230 | +void rt_mmc_remove_host(struct rt_mmc_host *); |
| 231 | +void rt_mmc_free_host(struct rt_mmc_host *); |
| 232 | +rt_err_t rt_mmc_of_parse(struct rt_mmc_host *host); |
| 233 | + |
| 234 | +rt_inline void *rt_mmc_priv(struct rt_mmc_host *host) |
| 235 | +{ |
| 236 | + return (void *)host->private; |
| 237 | +} |
| 238 | + |
| 239 | +#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI) |
| 240 | + |
| 241 | +#define mmc_dev(x) ((x)->parent) |
| 242 | +#define mmc_classdev(x) (&(x)->class_dev) |
| 243 | +#define mmc_hostname(x) (x->parent->parent.name) |
| 244 | + |
| 245 | +void rt_mmc_detect_change(struct rt_mmc_host *host, rt_ubase_t delay); |
| 246 | +void rt_mmc_request_done(struct rt_mmc_host *host, struct rt_mmcsd_req *req); |
| 247 | + |
| 248 | +rt_inline rt_bool_t sdio_irq_claimed(struct rt_mmc_host *host) |
| 249 | +{ |
| 250 | + return host->sdio_irqs > 0; |
| 251 | +} |
| 252 | + |
| 253 | +void mmc_retune_timer_stop(struct rt_mmc_host* host); |
| 254 | + |
| 255 | +enum dma_data_direction |
| 256 | +{ |
| 257 | + DMA_BIDIRECTIONAL = 0, |
| 258 | + DMA_TO_DEVICE = 1, |
| 259 | + DMA_FROM_DEVICE = 2, |
| 260 | + DMA_NONE = 3, |
| 261 | +}; |
| 262 | + |
| 263 | +rt_inline void mmc_retune_needed(struct rt_mmc_host *host) |
| 264 | +{ |
| 265 | + if (host->can_retune) |
| 266 | + { |
| 267 | + host->need_retune = 1; |
| 268 | + } |
| 269 | +} |
| 270 | + |
| 271 | +rt_inline rt_bool_t mmc_can_retune(struct rt_mmc_host *host) |
| 272 | +{ |
| 273 | + return host->can_retune == 1; |
| 274 | +} |
| 275 | + |
| 276 | +rt_inline rt_bool_t mmc_doing_retune(struct rt_mmc_host *host) |
| 277 | +{ |
| 278 | + return host->doing_retune == 1; |
| 279 | +} |
| 280 | + |
| 281 | +rt_inline rt_bool_t mmc_doing_tune(struct rt_mmc_host *host) |
| 282 | +{ |
| 283 | + return host->doing_retune == 1 || host->doing_init_tune == 1; |
| 284 | +} |
| 285 | + |
| 286 | +rt_inline int mmc_get_dma_dir(struct rt_mmcsd_data *data) |
| 287 | +{ |
| 288 | + return data->flags & DATA_DIR_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
| 289 | +} |
| 290 | + |
| 291 | +rt_inline rt_bool_t mmc_op_multi(rt_uint32_t opcode) |
| 292 | +{ |
| 293 | + return opcode == MMC_WRITE_MULTIPLE_BLOCK || |
| 294 | + opcode == MMC_READ_MULTIPLE_BLOCK; |
| 295 | +} |
| 296 | + |
| 297 | +rt_inline rt_bool_t mmc_op_tuning(rt_uint32_t opcode) |
| 298 | +{ |
| 299 | + return opcode == MMC_SEND_TUNING_BLOCK || |
| 300 | + opcode == MMC_SEND_TUNING_BLOCK_HS200; |
| 301 | +} |
| 302 | + |
| 303 | +rt_err_t rt_mmc_gpio_get_cd(struct rt_mmc_host *host); |
| 304 | +void rt_mmc_detect_change(struct rt_mmc_host *host, rt_ubase_t delay); |
| 305 | +rt_bool_t rt_mmc_can_gpio_ro(struct rt_mmc_host *host); |
| 306 | +rt_err_t rt_mmc_gpio_get_ro(struct rt_mmc_host *host); |
| 307 | + |
| 308 | +rt_err_t rt_mmc_send_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode); |
| 309 | + |
| 310 | +#endif /* __DEV_SDHCI_HOST_H__ */ |
0 commit comments