mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-06 09:02:20 +08:00
[sdio][dm] update for DM (#11078)
* [sdio][dm] import Kconfig for DM Signed-off-by: GuEe-GUI <2991707448@qq.com> * [sdio] fixup IRQ and mmcsd threads' stack size default Signed-off-by: GuEe-GUI <2991707448@qq.com> * [sdio][dm] Support DM mode 1. Support features read by DM. 2. Support regulator API in drivers. 3. Support send tuning option CMD. 4. Replace `switch_uhs_voltage` by `signal_voltage_switch`. Signed-off-by: GuEe-GUI <2991707448@qq.com> * [dm][sdhci] Cleanup the SDHCI Signed-off-by: GuEe-GUI <2991707448@qq.com> * [sdio][dm] add new SDIO/SDHCI drivers 1. SDHCI support on PCI bus 2. Synopsys DesignWare MMC Family(MMIO/PCI) Signed-off-by: GuEe-GUI <2991707448@qq.com> --------- Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
@@ -97,7 +97,7 @@ static hpm_stat_t hpm_sdmmc_transfer_polling(struct hpm_mmcsd *mmcsd, sdxc_adma_
|
||||
static hpm_stat_t hpm_sdmmc_transfer_interrupt_driven(struct hpm_mmcsd *mmcsd, sdxc_adma_config_t *dma_config, sdxc_xfer_t *xfer);
|
||||
static hpm_stat_t hpm_sdmmc_transfer(struct hpm_mmcsd *mmcsd, sdxc_adma_config_t *dma_config, sdxc_xfer_t *xfer);
|
||||
static rt_int32_t hpm_sdmmc_execute_tuning(struct rt_mmcsd_host *host, rt_int32_t opcode);
|
||||
static rt_int32_t hpm_sdmmc_switch_uhs_voltage(struct rt_mmcsd_host *host);
|
||||
static rt_err_t hpm_sdmmc_signal_voltage_switch(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
|
||||
|
||||
static void hpm_sdmmc_power_on_via_pin(struct hpm_mmcsd *mmcsd);
|
||||
static void hpm_sdmmc_power_off_via_pin(struct hpm_mmcsd *mmcsd);
|
||||
@@ -152,7 +152,7 @@ static void hpm_sdmmc_switch_to_1v8_via_pin(struct hpm_mmcsd *mmcsd)
|
||||
}
|
||||
|
||||
|
||||
static rt_int32_t hpm_sdmmc_switch_uhs_voltage(struct rt_mmcsd_host *host)
|
||||
static rt_err_t hpm_sdmmc_signal_voltage_switch(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
|
||||
{
|
||||
struct hpm_mmcsd *mmcsd = (struct hpm_mmcsd *) host->private_data;
|
||||
SDXC_Type *base = mmcsd->sdxc_base;
|
||||
@@ -174,9 +174,17 @@ static rt_int32_t hpm_sdmmc_switch_uhs_voltage(struct rt_mmcsd_host *host)
|
||||
return -RT_ETIMEOUT;
|
||||
}
|
||||
|
||||
/* 3. Switch to 1.8V */
|
||||
hpm_sdmmc_switch_to_1v8_via_pin(mmcsd);
|
||||
sdxc_select_voltage(mmcsd->sdxc_base, sdxc_bus_voltage_sd_1v8);
|
||||
/* 3. Switch to 1.8V/3.3V */
|
||||
if (ios->signal_voltage == MMCSD_SIGNAL_VOLTAGE_330)
|
||||
{
|
||||
hpm_sdmmc_switch_to_3v3_via_pin(mmcsd);
|
||||
sdxc_select_voltage(mmcsd->sdxc_base, sdxc_bus_voltage_sd_3v3);
|
||||
}
|
||||
else
|
||||
{
|
||||
hpm_sdmmc_switch_to_1v8_via_pin(mmcsd);
|
||||
sdxc_select_voltage(mmcsd->sdxc_base, sdxc_bus_voltage_sd_1v8);
|
||||
}
|
||||
|
||||
/* 4. spec:host delay 5ms, host: give more delay time here */
|
||||
rt_thread_mdelay(10);
|
||||
@@ -213,7 +221,7 @@ static const struct rt_mmcsd_host_ops hpm_mmcsd_host_ops =
|
||||
.get_card_status = NULL,
|
||||
.enable_sdio_irq = hpm_sdmmc_enable_sdio_irq,
|
||||
.execute_tuning = hpm_sdmmc_execute_tuning,
|
||||
.switch_uhs_voltage = hpm_sdmmc_switch_uhs_voltage,
|
||||
.signal_voltage_switch = hpm_sdmmc_signal_voltage_switch,
|
||||
};
|
||||
|
||||
void hpm_sdmmc_isr(struct hpm_mmcsd *mmcsd)
|
||||
|
||||
@@ -242,6 +242,12 @@ void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width);
|
||||
void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing);
|
||||
void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card);
|
||||
rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr);
|
||||
rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage);
|
||||
void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host);
|
||||
rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host);
|
||||
rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr);
|
||||
rt_err_t mmcsd_send_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode, rt_err_t *cmd_error);
|
||||
rt_err_t mmcsd_send_abort_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode);
|
||||
void mmcsd_change(struct rt_mmcsd_host *host);
|
||||
void mmcsd_detect(void *param);
|
||||
void mmcsd_host_init(struct rt_mmcsd_host *host);
|
||||
|
||||
668
components/drivers/include/drivers/dev_sdhci.h
Executable file
668
components/drivers/include/drivers/dev_sdhci.h
Executable file
File diff suppressed because it is too large
Load Diff
310
components/drivers/include/drivers/dev_sdhci_host.h
Executable file
310
components/drivers/include/drivers/dev_sdhci_host.h
Executable file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-16 zhujiale first version
|
||||
*/
|
||||
|
||||
#ifndef __DEV_SDHCI_HOST_H__
|
||||
#define __DEV_SDHCI_HOST_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <drivers/dma.h>
|
||||
#include <drivers/mmcsd_cmd.h>
|
||||
#include <drivers/mmcsd_host.h>
|
||||
#include <drivers/dev_mmcsd_core.h>
|
||||
|
||||
#define rt_mmc_dev(x) ((x)->parent)
|
||||
|
||||
#define MMC_SEND_TUNING_BLOCK_HS200 SEND_TUNING_BLOCK_HS200
|
||||
#define MMC_SEND_TUNING_BLOCK SEND_TUNING_BLOCK
|
||||
#define MMC_STOP_TRANSMISSION STOP_TRANSMISSION
|
||||
#define MMC_BUS_TEST_R 14 /* adtc R1 */
|
||||
#define MMC_WRITE_MULTIPLE_BLOCK WRITE_MULTIPLE_BLOCK
|
||||
#define MMC_READ_MULTIPLE_BLOCK READ_MULTIPLE_BLOCK
|
||||
|
||||
#define MMC_TIMING_UHS_DDR50 MMCSD_TIMING_UHS_DDR50
|
||||
#define MMC_TIMING_UHS_SDR50 MMCSD_TIMING_UHS_SDR50
|
||||
#define MMC_TIMING_MMC_HS200 MMCSD_TIMING_MMC_HS200
|
||||
#define MMC_TIMING_MMC_HS400 MMCSD_TIMING_MMC_HS400
|
||||
#define MMC_TIMING_UHS_SDR104 MMCSD_TIMING_UHS_SDR104
|
||||
#define MMC_TIMING_UHS_SDR25 MMCSD_TIMING_UHS_SDR25
|
||||
#define MMC_TIMING_MMC_DDR52 MMCSD_TIMING_MMC_DDR52
|
||||
#define MMC_TIMING_UHS_SDR12 MMCSD_TIMING_UHS_SDR12
|
||||
#define MMC_TIMING_SD_HS MMCSD_TIMING_SD_HS
|
||||
#define MMC_TIMING_MMC_HS MMCSD_TIMING_MMC_HS
|
||||
|
||||
#define MMC_POWER_OFF MMCSD_POWER_OFF
|
||||
#define MMC_POWER_UP MMCSD_POWER_UP
|
||||
#define MMC_POWER_ON MMCSD_POWER_ON
|
||||
#define MMC_POWER_UNDEFINED 3
|
||||
|
||||
#define MMC_SET_DRIVER_TYPE_B 0
|
||||
#define MMC_SET_DRIVER_TYPE_A 1
|
||||
#define MMC_SET_DRIVER_TYPE_C 2
|
||||
#define MMC_SET_DRIVER_TYPE_D 3
|
||||
|
||||
#define MMC_SIGNAL_VOLTAGE_330 0
|
||||
#define MMC_SIGNAL_VOLTAGE_180 1
|
||||
#define MMC_SIGNAL_VOLTAGE_120 2
|
||||
|
||||
#define MMC_RSP_PRESENT (1 << 16)
|
||||
#define MMC_RSP_136 (1 << 17) /* 136 bit response */
|
||||
#define MMC_RSP_CRC (1 << 18) /* expect valid crc */
|
||||
#define MMC_RSP_BUSY (1 << 19) /* card may send busy */
|
||||
#define MMC_RSP_OPCODE (1 << 20) /* response contains opcode */
|
||||
|
||||
#define MMC_RSP_NONE (0)
|
||||
#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
|
||||
#define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
|
||||
#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
|
||||
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
|
||||
#define MMC_RSP_R4 (MMC_RSP_PRESENT)
|
||||
#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
|
||||
#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
|
||||
#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
|
||||
|
||||
#define MMC_CMD_ADTC CMD_ADTC
|
||||
|
||||
#define MMC_BUS_WIDTH_8 MMCSD_BUS_WIDTH_8
|
||||
#define MMC_BUS_WIDTH_4 MMCSD_BUS_WIDTH_4
|
||||
#define MMC_BUS_WIDTH_1 MMCSD_BUS_WIDTH_1
|
||||
|
||||
#define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */
|
||||
#define MMC_PM_WAKE_SDIO_IRQ (1 << 1) /* wake up host system on SDIO IRQ assertion */
|
||||
|
||||
enum mmc_blk_status
|
||||
{
|
||||
MMC_BLK_SUCCESS = 0,
|
||||
MMC_BLK_PARTIAL,
|
||||
MMC_BLK_CMD_ERR,
|
||||
MMC_BLK_RETRY,
|
||||
MMC_BLK_ABORT,
|
||||
MMC_BLK_DATA_ERR,
|
||||
MMC_BLK_ECC_ERR,
|
||||
MMC_BLK_NOMEDIUM,
|
||||
MMC_BLK_NEW_REQUEST,
|
||||
};
|
||||
|
||||
#define MMC_NUM_CLK_PHASES (MMC_TIMING_MMC_HS400 + 1)
|
||||
|
||||
struct rt_mmc_host;
|
||||
|
||||
struct rt_mmc_host_ops
|
||||
{
|
||||
void (*request)(struct rt_mmc_host *host, struct rt_mmcsd_req *req);
|
||||
void (*set_ios)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios);
|
||||
int (*get_ro)(struct rt_mmc_host *host);
|
||||
int (*get_cd)(struct rt_mmc_host *host);
|
||||
void (*enable_sdio_irq)(struct rt_mmc_host *host, int enable);
|
||||
void (*ack_sdio_irq)(struct rt_mmc_host *host);
|
||||
int (*start_signal_voltage_switch)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios);
|
||||
int (*card_busy)(struct rt_mmc_host *host);
|
||||
int (*execute_tuning)(struct rt_mmc_host *host, unsigned opcode);
|
||||
int (*prepare_hs400_tuning)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios);
|
||||
int (*hs400_prepare_ddr)(struct rt_mmc_host *host);
|
||||
void (*hs400_downgrade)(struct rt_mmc_host *host);
|
||||
void (*hs400_complete)(struct rt_mmc_host *host);
|
||||
void (*hs400_enhanced_strobe)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios);
|
||||
void (*hw_reset)(struct rt_mmc_host *host);
|
||||
void (*card_event)(struct rt_mmc_host *host);
|
||||
};
|
||||
|
||||
/* VDD voltage 3.3 ~ 3.4 */
|
||||
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
|
||||
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
|
||||
|
||||
#define MMC_CAP2_HS200_1_8V_SDR MMCSD_SUP_HS200_1V8
|
||||
#define MMC_CAP2_HS200_1_2V_SDR MMCSD_SUP_HS200_1V2
|
||||
#define MMC_CAP_4_BIT_DATA MMCSD_BUSWIDTH_4
|
||||
#define MMC_CAP_8_BIT_DATA MMCSD_BUSWIDTH_8
|
||||
#define MMC_CAP2_HS200 MMCSD_SUP_HS200
|
||||
#define MMC_CAP_MMC_HIGHSPEED MMCSD_SUP_HIGHSPEED
|
||||
#define MMC_CAP_SD_HIGHSPEED MMCSD_SUP_HIGHSPEED
|
||||
#define MMC_CAP_1_8V_DDR MMCSD_SUP_DDR_1V8
|
||||
#define MMC_CAP_3_3V_DDR MMCSD_SUP_DDR_3V3
|
||||
#define MMC_CAP_1_2V_DDR MMCSD_SUP_DDR_1V2
|
||||
#define MMC_CAP_NONREMOVABLE MMCSD_SUP_NONREMOVABLE
|
||||
|
||||
#define MMC_CAP_UHS_DDR50 0
|
||||
#define MMC_CAP2_HS400 0
|
||||
#define MMC_CAP_UHS_SDR50 0
|
||||
#define MMC_CAP_UHS_SDR25 0
|
||||
#define MMC_CAP_UHS_SDR12 0
|
||||
#define MMC_CAP_UHS_SDR104 0
|
||||
#define MMC_CAP_UHS 0
|
||||
#define MMC_CAP2_HSX00_1_8V 0
|
||||
#define MMC_CAP2_HS400_ES 0
|
||||
#define MMC_CAP_NEEDS_POLL 0
|
||||
#define MMC_CAP2_HSX00_1_2V 0
|
||||
#define MMC_CAP2_HS400_1_2V 0
|
||||
#define MMC_CAP2_HS400_1_8V 0
|
||||
#define MMC_CAP_DRIVER_TYPE_D 0
|
||||
#define MMC_CAP_DRIVER_TYPE_C 0
|
||||
#define MMC_SET_DRIVER_TYPE_B 0
|
||||
#define MMC_CAP_DRIVER_TYPE_A 0
|
||||
#define MMC_CAP2_SDIO_IRQ_NOTHREAD 0
|
||||
#define MMC_CAP_CMD23 0
|
||||
#define MMC_CAP_SDIO_IRQ 0
|
||||
|
||||
#define MMC_CAP2_NO_SDIO (1 << 19)
|
||||
#define MMC_CAP2_NO_SD (1 << 21)
|
||||
#define MMC_CAP2_NO_MMC (1 << 22)
|
||||
#define MMC_CAP2_CQE (1 << 23)
|
||||
|
||||
#define MMC_VDD_165_195 VDD_165_195
|
||||
#define MMC_VDD_20_21 VDD_20_21
|
||||
#define MMC_VDD_29_30 VDD_29_30
|
||||
#define MMC_VDD_30_31 VDD_30_31
|
||||
#define MMC_VDD_32_33 VDD_32_33
|
||||
#define MMC_VDD_33_34 VDD_33_34
|
||||
|
||||
struct rt_mmc_host
|
||||
{
|
||||
struct rt_mmcsd_host rthost;
|
||||
struct rt_device *parent;
|
||||
int index;
|
||||
const struct rt_mmc_host_ops *ops;
|
||||
unsigned int f_min;
|
||||
unsigned int f_max;
|
||||
unsigned int f_init;
|
||||
rt_uint32_t ocr_avail;
|
||||
rt_uint32_t ocr_avail_sdio; /* SDIO-specific OCR */
|
||||
rt_uint32_t ocr_avail_sd; /* SD-specific OCR */
|
||||
rt_uint32_t ocr_avail_mmc; /* MMC-specific OCR */
|
||||
struct wakeup_source *ws; /* Enable consume of uevents */
|
||||
rt_uint32_t max_current_330;
|
||||
rt_uint32_t max_current_300;
|
||||
rt_uint32_t max_current_180;
|
||||
rt_uint32_t caps; /* Host capabilities */
|
||||
rt_uint32_t caps2; /* More host capabilities */
|
||||
|
||||
|
||||
/* host specific block data */
|
||||
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
|
||||
unsigned short max_segs; /* see blk_queue_max_segments */
|
||||
unsigned short unused;
|
||||
unsigned int max_req_size; /* maximum number of bytes in one req */
|
||||
unsigned int max_blk_size; /* maximum size of one mmc block */
|
||||
unsigned int max_blk_count; /* maximum number of blocks in one req */
|
||||
unsigned int max_busy_timeout; /* max busy timeout in ms */
|
||||
struct rt_mmcsd_io_cfg ios; /* current io bus settings */
|
||||
unsigned int retune_period;
|
||||
/* group bitfields together to minimize padding */
|
||||
unsigned int use_spi_crc : 1;
|
||||
unsigned int claimed : 1; /* host exclusively claimed */
|
||||
unsigned int doing_init_tune : 1; /* initial tuning in progress */
|
||||
unsigned int can_retune : 1; /* re-tuning can be used */
|
||||
unsigned int doing_retune : 1; /* re-tuning in progress */
|
||||
unsigned int retune_now : 1; /* do re-tuning at next req */
|
||||
unsigned int retune_paused : 1; /* re-tuning is temporarily disabled */
|
||||
unsigned int retune_crc_disable : 1; /* don't trigger retune upon crc */
|
||||
unsigned int can_dma_map_merge : 1; /* merging can be used */
|
||||
unsigned int vqmmc_enabled : 1; /* vqmmc regulator is enabled */
|
||||
|
||||
int need_retune; /* re-tuning is needed */
|
||||
int hold_retune; /* hold off re-tuning */
|
||||
rt_bool_t trigger_card_event; /* card_event necessary */
|
||||
unsigned int sdio_irqs;
|
||||
rt_bool_t sdio_irq_pending;
|
||||
|
||||
/* Ongoing data transfer that allows commands during transfer */
|
||||
struct rt_mmcsd_req *ongoing_mrq;
|
||||
|
||||
rt_uint32_t actual_clock; /* Actual HC clock rate */
|
||||
rt_uint32_t pm_caps;
|
||||
rt_ubase_t private[];
|
||||
};
|
||||
|
||||
rt_inline int mmc_card_is_removable(struct rt_mmc_host *host)
|
||||
{
|
||||
return !(host->caps & MMC_CAP_NONREMOVABLE);
|
||||
}
|
||||
|
||||
struct rt_mmc_host *rt_mmc_alloc_host(int extra, struct rt_device *);
|
||||
rt_err_t rt_mmc_add_host(struct rt_mmc_host *);
|
||||
void rt_mmc_remove_host(struct rt_mmc_host *);
|
||||
void rt_mmc_free_host(struct rt_mmc_host *);
|
||||
rt_err_t rt_mmc_of_parse(struct rt_mmc_host *host);
|
||||
|
||||
rt_inline void *rt_mmc_priv(struct rt_mmc_host *host)
|
||||
{
|
||||
return (void *)host->private;
|
||||
}
|
||||
|
||||
#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI)
|
||||
|
||||
#define mmc_dev(x) ((x)->parent)
|
||||
#define mmc_classdev(x) (&(x)->class_dev)
|
||||
#define mmc_hostname(x) (x->parent->parent.name)
|
||||
|
||||
void rt_mmc_detect_change(struct rt_mmc_host *host, rt_ubase_t delay);
|
||||
void rt_mmc_request_done(struct rt_mmc_host *host, struct rt_mmcsd_req *req);
|
||||
|
||||
rt_inline rt_bool_t sdio_irq_claimed(struct rt_mmc_host *host)
|
||||
{
|
||||
return host->sdio_irqs > 0;
|
||||
}
|
||||
|
||||
void mmc_retune_timer_stop(struct rt_mmc_host* host);
|
||||
|
||||
enum dma_data_direction
|
||||
{
|
||||
DMA_BIDIRECTIONAL = 0,
|
||||
DMA_TO_DEVICE = 1,
|
||||
DMA_FROM_DEVICE = 2,
|
||||
DMA_NONE = 3,
|
||||
};
|
||||
|
||||
rt_inline void mmc_retune_needed(struct rt_mmc_host *host)
|
||||
{
|
||||
if (host->can_retune)
|
||||
{
|
||||
host->need_retune = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline rt_bool_t mmc_can_retune(struct rt_mmc_host *host)
|
||||
{
|
||||
return host->can_retune == 1;
|
||||
}
|
||||
|
||||
rt_inline rt_bool_t mmc_doing_retune(struct rt_mmc_host *host)
|
||||
{
|
||||
return host->doing_retune == 1;
|
||||
}
|
||||
|
||||
rt_inline rt_bool_t mmc_doing_tune(struct rt_mmc_host *host)
|
||||
{
|
||||
return host->doing_retune == 1 || host->doing_init_tune == 1;
|
||||
}
|
||||
|
||||
rt_inline int mmc_get_dma_dir(struct rt_mmcsd_data *data)
|
||||
{
|
||||
return data->flags & DATA_DIR_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
}
|
||||
|
||||
rt_inline rt_bool_t mmc_op_multi(rt_uint32_t opcode)
|
||||
{
|
||||
return opcode == MMC_WRITE_MULTIPLE_BLOCK ||
|
||||
opcode == MMC_READ_MULTIPLE_BLOCK;
|
||||
}
|
||||
|
||||
rt_inline rt_bool_t mmc_op_tuning(rt_uint32_t opcode)
|
||||
{
|
||||
return opcode == MMC_SEND_TUNING_BLOCK ||
|
||||
opcode == MMC_SEND_TUNING_BLOCK_HS200;
|
||||
}
|
||||
|
||||
rt_err_t rt_mmc_gpio_get_cd(struct rt_mmc_host *host);
|
||||
void rt_mmc_detect_change(struct rt_mmc_host *host, rt_ubase_t delay);
|
||||
rt_bool_t rt_mmc_can_gpio_ro(struct rt_mmc_host *host);
|
||||
rt_err_t rt_mmc_gpio_get_ro(struct rt_mmc_host *host);
|
||||
|
||||
rt_err_t rt_mmc_send_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode);
|
||||
|
||||
#endif /* __DEV_SDHCI_HOST_H__ */
|
||||
@@ -76,6 +76,8 @@ struct rt_mmcsd_io_cfg
|
||||
#define MMCSD_SIGNAL_VOLTAGE_330 0
|
||||
#define MMCSD_SIGNAL_VOLTAGE_180 1
|
||||
#define MMCSD_SIGNAL_VOLTAGE_120 2
|
||||
|
||||
rt_bool_t enhanced_strobe;
|
||||
};
|
||||
|
||||
struct rt_mmcsd_host;
|
||||
@@ -88,9 +90,23 @@ struct rt_mmcsd_host_ops
|
||||
rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
|
||||
void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
|
||||
rt_int32_t (*execute_tuning)(struct rt_mmcsd_host *host, rt_int32_t opcode);
|
||||
rt_int32_t (*switch_uhs_voltage)(struct rt_mmcsd_host *host);
|
||||
rt_bool_t (*card_busy)(struct rt_mmcsd_host *host);
|
||||
rt_err_t (*signal_voltage_switch)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
|
||||
};
|
||||
|
||||
#ifdef RT_USING_REGULATOR
|
||||
struct rt_regulator;
|
||||
|
||||
struct rt_mmcsd_supply
|
||||
{
|
||||
rt_bool_t vqmmc_enabled;
|
||||
rt_bool_t regulator_enabled;
|
||||
|
||||
struct rt_regulator *vmmc; /* Card power supply */
|
||||
struct rt_regulator *vqmmc; /* Optional Vccq supply */
|
||||
};
|
||||
#endif /* RT_USING_REGULATOR */
|
||||
|
||||
struct rt_mmcsd_host
|
||||
{
|
||||
char name[RT_NAME_MAX];
|
||||
@@ -158,6 +174,13 @@ struct rt_mmcsd_host
|
||||
struct rt_semaphore *sdio_irq_sem;
|
||||
struct rt_thread *sdio_irq_thread;
|
||||
|
||||
#ifdef RT_USING_REGULATOR
|
||||
struct rt_mmcsd_supply supply;
|
||||
#endif
|
||||
#ifdef RT_USING_OFW
|
||||
void *ofw_node;
|
||||
#endif
|
||||
|
||||
void *private_data;
|
||||
};
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -215,6 +215,10 @@ extern "C" {
|
||||
#include "drivers/dev_mmcsd_core.h"
|
||||
#include "drivers/dev_sd.h"
|
||||
#include "drivers/dev_sdio.h"
|
||||
#if defined(RT_USING_DM) && defined(RT_USING_SDHCI)
|
||||
#include "drivers/dev_sdhci.h"
|
||||
#include "drivers/dev_sdhci_host.h"
|
||||
#endif /* RT_USING_DM && RT_USING_SDHCI */
|
||||
#endif /* RT_USING_SDIO */
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
config RT_USING_SDIO
|
||||
menuconfig RT_USING_SDIO
|
||||
bool "Using SD/MMC device drivers"
|
||||
select RT_USING_BLK
|
||||
default n
|
||||
@@ -6,7 +6,7 @@ config RT_USING_SDIO
|
||||
if RT_USING_SDIO
|
||||
config RT_SDIO_STACK_SIZE
|
||||
int "The stack size for sdio irq thread"
|
||||
default 512
|
||||
default IDLE_THREAD_STACK_SIZE
|
||||
|
||||
config RT_SDIO_THREAD_PRIORITY
|
||||
int "The priority level value of sdio irq thread"
|
||||
@@ -14,7 +14,7 @@ config RT_USING_SDIO
|
||||
|
||||
config RT_MMCSD_STACK_SIZE
|
||||
int "The stack size for mmcsd thread"
|
||||
default 1024
|
||||
default IDLE_THREAD_STACK_SIZE
|
||||
|
||||
config RT_MMCSD_THREAD_PRIORITY
|
||||
int "The priority level value of mmcsd thread"
|
||||
@@ -30,3 +30,7 @@ config RT_USING_SDIO
|
||||
bool "Using sdhci for sd/mmc drivers"
|
||||
default n
|
||||
endif
|
||||
|
||||
if RT_USING_DM && RT_USING_SDIO
|
||||
rsource "host/Kconfig"
|
||||
endif
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
group = []
|
||||
objs = []
|
||||
|
||||
if not GetDepend(['RT_USING_SDIO']):
|
||||
Return('group')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split("""
|
||||
dev_block.c
|
||||
dev_mmcsd_core.c
|
||||
dev_sd.c
|
||||
dev_sdio.c
|
||||
dev_mmc.c
|
||||
""")
|
||||
list = os.listdir(cwd)
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
path = [cwd + '/../include' , cwd + '/sdhci/include']
|
||||
src = ['dev_block.c', 'dev_mmcsd_core.c', 'dev_sd.c', 'dev_sdio.c', 'dev_mmc.c']
|
||||
|
||||
if GetDepend('RT_USING_SDHCI'):
|
||||
src += [os.path.join('sdhci', 'sdhci.c')]
|
||||
src += [os.path.join('sdhci', 'fit-mmc.c')]
|
||||
src += [os.path.join('sdhci', 'sdhci-platform.c')]
|
||||
if GetDepend(['RT_USING_DM']):
|
||||
src += ['dev_sdio_dm.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SDIO'], CPPPATH = path)
|
||||
if GetDepend('RT_USING_SDHCI'):
|
||||
src += ['dev_sdhci.c', 'dev_sdhci_dm.c', 'dev_sdhci_host.c']
|
||||
|
||||
Return('group')
|
||||
if GetDepend(['RT_USING_REGULATOR']):
|
||||
src += ['dev_regulator.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
objs = objs + group
|
||||
|
||||
Return('objs')
|
||||
|
||||
@@ -549,6 +549,281 @@ rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr)
|
||||
return ocr;
|
||||
}
|
||||
|
||||
rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
unsigned char old_signal_voltage = host->io_cfg.signal_voltage;
|
||||
|
||||
host->io_cfg.signal_voltage = signal_voltage;
|
||||
if (host->ops->signal_voltage_switch)
|
||||
{
|
||||
err = host->ops->signal_voltage_switch(host, &host->io_cfg);
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
host->io_cfg.signal_voltage = old_signal_voltage;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host)
|
||||
{
|
||||
/* 3.3V -> 1.8v -> 1.2v */
|
||||
if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_330))
|
||||
{
|
||||
LOG_D("Initial signal voltage of %sv", "3.3");
|
||||
}
|
||||
else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180))
|
||||
{
|
||||
LOG_D("Initial signal voltage of %sv", "1.8");
|
||||
}
|
||||
else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_120))
|
||||
{
|
||||
LOG_D("Initial signal voltage of %sv", "1.2");
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host)
|
||||
{
|
||||
rt_uint32_t old_clock = host->io_cfg.clock;
|
||||
|
||||
host->io_cfg.clock = 0;
|
||||
mmcsd_set_iocfg(host);
|
||||
|
||||
if (mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180))
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
host->io_cfg.clock = old_clock;
|
||||
mmcsd_set_iocfg(host);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr);
|
||||
|
||||
rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct rt_mmcsd_cmd cmd;
|
||||
|
||||
if (!host->ops->signal_voltage_switch)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (!host->ops->card_busy)
|
||||
{
|
||||
LOG_W("%s: Cannot verify signal voltage switch", host->name);
|
||||
}
|
||||
|
||||
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
|
||||
cmd.cmd_code = VOLTAGE_SWITCH;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = RESP_R1 | CMD_AC;
|
||||
|
||||
err = mmcsd_send_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
{
|
||||
goto power_cycle;
|
||||
}
|
||||
|
||||
if (!controller_is_spi(host) && (cmd.resp[0] & R1_ERROR))
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* The card should drive cmd and dat[0:3] low immediately
|
||||
* after the response of cmd11, but wait 1 ms to be sure
|
||||
*/
|
||||
rt_thread_mdelay(1);
|
||||
if (host->ops->card_busy && !host->ops->card_busy(host))
|
||||
{
|
||||
err = -RT_ERROR;
|
||||
goto power_cycle;
|
||||
}
|
||||
|
||||
if (mmcsd_host_set_uhs_voltage(host))
|
||||
{
|
||||
/*
|
||||
* Voltages may not have been switched, but we've already
|
||||
* sent CMD11, so a power cycle is required anyway
|
||||
*/
|
||||
err = -RT_ERROR;
|
||||
goto power_cycle;
|
||||
}
|
||||
|
||||
/* Wait for at least 1 ms according to spec */
|
||||
rt_thread_mdelay(1);
|
||||
|
||||
/*
|
||||
* Failure to switch is indicated by the card holding
|
||||
* dat[0:3] low
|
||||
*/
|
||||
if (host->ops->card_busy && host->ops->card_busy(host))
|
||||
{
|
||||
err = -RT_ERROR;
|
||||
}
|
||||
|
||||
power_cycle:
|
||||
if (err)
|
||||
{
|
||||
LOG_D("%s: Signal voltage switch failed, power cycling card", host->name);
|
||||
mmcsd_power_cycle(host, ocr);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const rt_uint8_t tuning_blk_pattern_4bit[] =
|
||||
{
|
||||
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
|
||||
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
|
||||
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
|
||||
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
|
||||
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
|
||||
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
|
||||
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
|
||||
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
|
||||
};
|
||||
|
||||
static const rt_uint8_t tuning_blk_pattern_8bit[] =
|
||||
{
|
||||
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
|
||||
0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
|
||||
0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
|
||||
0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
|
||||
0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
|
||||
0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
|
||||
0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
|
||||
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
|
||||
0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
|
||||
0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
|
||||
0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
|
||||
0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
|
||||
0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
|
||||
0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
|
||||
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
|
||||
};
|
||||
|
||||
rt_err_t mmcsd_send_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode, rt_err_t *cmd_error)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
int size;
|
||||
rt_uint8_t *data_buf;
|
||||
const rt_uint8_t *tuning_block_pattern;
|
||||
struct rt_mmcsd_req req = {};
|
||||
struct rt_mmcsd_cmd cmd = {};
|
||||
struct rt_mmcsd_data data = {};
|
||||
struct rt_mmcsd_io_cfg *io_cfg = &host->io_cfg;
|
||||
|
||||
if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
|
||||
{
|
||||
tuning_block_pattern = tuning_blk_pattern_8bit;
|
||||
size = sizeof(tuning_blk_pattern_8bit);
|
||||
}
|
||||
else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
|
||||
{
|
||||
tuning_block_pattern = tuning_blk_pattern_4bit;
|
||||
size = sizeof(tuning_blk_pattern_4bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
data_buf = rt_malloc(size);
|
||||
if (!data_buf)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
rt_memset(data_buf, 0, size);
|
||||
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
|
||||
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
|
||||
|
||||
req.cmd = &cmd;
|
||||
req.data = &data;
|
||||
|
||||
cmd.cmd_code = opcode;
|
||||
cmd.flags = RESP_R1 | CMD_ADTC;
|
||||
|
||||
data.blksize = size;
|
||||
data.blks = 1;
|
||||
data.flags = DATA_DIR_READ;
|
||||
|
||||
/*
|
||||
* According to the tuning specs, Tuning process
|
||||
* is normally shorter 40 executions of CMD19,
|
||||
* and timeout value should be shorter than 150 ms
|
||||
*/
|
||||
data.timeout_ns = 150 * 1000000;
|
||||
|
||||
mmcsd_send_request(host, &req);
|
||||
|
||||
if (cmd_error)
|
||||
{
|
||||
*cmd_error = cmd.err;
|
||||
}
|
||||
|
||||
if (cmd.err)
|
||||
{
|
||||
err = cmd.err;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (data.err)
|
||||
{
|
||||
err = data.err;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (rt_memcmp(data_buf, tuning_block_pattern, size))
|
||||
{
|
||||
err = -RT_EIO;
|
||||
}
|
||||
|
||||
out_free:
|
||||
rt_free(data_buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t mmcsd_send_abort_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode)
|
||||
{
|
||||
struct rt_mmcsd_cmd cmd = {};
|
||||
|
||||
/*
|
||||
* eMMC specification specifies that CMD12 can be used to stop a tuning
|
||||
* command, but SD specification does not, so do nothing unless it is eMMC.
|
||||
*/
|
||||
if (opcode != SEND_TUNING_BLOCK_HS200)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd.cmd_code = STOP_TRANSMISSION;
|
||||
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
|
||||
|
||||
/*
|
||||
* For drivers that override R1 to R1b, set an arbitrary timeout based
|
||||
* on the tuning timeout i.e. 150ms.
|
||||
*/
|
||||
cmd.busy_timeout = 150;
|
||||
|
||||
return mmcsd_send_cmd(host, &cmd, 0);
|
||||
}
|
||||
|
||||
static void mmcsd_power_up(struct rt_mmcsd_host *host)
|
||||
{
|
||||
int bit = __rt_fls(host->valid_ocr) - 1;
|
||||
@@ -568,6 +843,8 @@ static void mmcsd_power_up(struct rt_mmcsd_host *host)
|
||||
host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1;
|
||||
mmcsd_set_iocfg(host);
|
||||
|
||||
mmcsd_set_initial_signal_voltage(host);
|
||||
|
||||
/*
|
||||
* This delay should be sufficient to allow the power supply
|
||||
* to reach the minimum voltage.
|
||||
@@ -599,6 +876,17 @@ static void mmcsd_power_off(struct rt_mmcsd_host *host)
|
||||
mmcsd_set_iocfg(host);
|
||||
}
|
||||
|
||||
static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr)
|
||||
{
|
||||
mmcsd_power_off(host);
|
||||
|
||||
/* Wait at least 1 ms according to SD spec */
|
||||
rt_thread_mdelay(1);
|
||||
|
||||
mmcsd_power_up(host);
|
||||
mmcsd_select_voltage(host, ocr);
|
||||
}
|
||||
|
||||
int mmcsd_wait_cd_changed(rt_int32_t timeout)
|
||||
{
|
||||
struct rt_mmcsd_host *host;
|
||||
|
||||
262
components/drivers/sdio/dev_regulator.c
Executable file
262
components/drivers/sdio/dev_regulator.c
Executable file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "dev_sdio_dm.h"
|
||||
|
||||
#define DBG_TAG "SDIO"
|
||||
#ifdef RT_SDIO_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_SDIO_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
static rt_err_t ocrbitnum_to_vdd(int vdd_bit, int *min_uvolt, int *max_uvolt)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
if (!vdd_bit)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
tmp = vdd_bit - rt_ilog2(VDD_165_195);
|
||||
|
||||
if (tmp == 0)
|
||||
{
|
||||
*min_uvolt = 1650 * 1000;
|
||||
*max_uvolt = 1950 * 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
*min_uvolt = 1900 * 1000 + tmp * 100 * 1000;
|
||||
*max_uvolt = *min_uvolt + 100 * 1000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host,
|
||||
struct rt_regulator *supply, rt_uint16_t vdd_bit)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
if (!host)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (rt_is_err_or_null(supply))
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
if (vdd_bit)
|
||||
{
|
||||
int min_uvolt, max_uvolt;
|
||||
|
||||
ocrbitnum_to_vdd(vdd_bit, &min_uvolt, &max_uvolt);
|
||||
|
||||
err = rt_regulator_set_voltage(supply, min_uvolt, max_uvolt);
|
||||
|
||||
if (!err && host->supply.regulator_enabled)
|
||||
{
|
||||
err = rt_regulator_enable(supply);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
host->supply.regulator_enabled = RT_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (host->supply.regulator_enabled)
|
||||
{
|
||||
err = rt_regulator_disable(supply);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
host->supply.regulator_enabled = RT_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
LOG_E("Set regulator OCR %d error = %s", vdd_bit, rt_strerror(err));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int regulator_set_voltage_if_supported(struct rt_regulator *regulator,
|
||||
int min_uvolt, int target_uvolt, int max_uvolt)
|
||||
{
|
||||
if (!rt_regulator_is_supported_voltage(regulator, min_uvolt, max_uvolt))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (rt_regulator_get_voltage(regulator) == target_uvolt)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
return rt_regulator_set_voltage_triplet(regulator, min_uvolt, target_uvolt,
|
||||
max_uvolt);
|
||||
}
|
||||
|
||||
rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host,
|
||||
struct rt_mmcsd_io_cfg *ios)
|
||||
{
|
||||
rt_err_t err;
|
||||
int uvolt, min_uvolt, max_uvolt;
|
||||
|
||||
if (rt_is_err_or_null(host->supply.vqmmc))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
switch (ios->signal_voltage)
|
||||
{
|
||||
case MMCSD_SIGNAL_VOLTAGE_120:
|
||||
return regulator_set_voltage_if_supported(host->supply.vqmmc,
|
||||
1100000, 1200000, 1300000);
|
||||
|
||||
case MMCSD_SIGNAL_VOLTAGE_180:
|
||||
return regulator_set_voltage_if_supported(host->supply.vqmmc,
|
||||
1700000, 1800000, 1950000);
|
||||
|
||||
case MMCSD_SIGNAL_VOLTAGE_330:
|
||||
err = ocrbitnum_to_vdd(host->io_cfg.vdd, &uvolt, &max_uvolt);
|
||||
|
||||
if (err)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
min_uvolt = rt_max(uvolt - 300000, 2700000);
|
||||
max_uvolt = rt_min(max_uvolt + 200000, 3600000);
|
||||
|
||||
err = regulator_set_voltage_if_supported(host->supply.vqmmc,
|
||||
min_uvolt, uvolt, max_uvolt);
|
||||
if (err >= 0)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
return regulator_set_voltage_if_supported(host->supply.vqmmc,
|
||||
2700000, uvolt, 3600000);
|
||||
|
||||
default:
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t sdio_regulator_get_supply(struct rt_device *dev, struct rt_mmcsd_host *host)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
if (!dev || !host)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
host->supply.vmmc = rt_regulator_get(dev, "vmmc");
|
||||
host->supply.vqmmc = rt_regulator_get(dev, "vqmmc");
|
||||
|
||||
if (!rt_is_err(host->supply.vmmc))
|
||||
{
|
||||
if (!host->supply.vmmc)
|
||||
{
|
||||
LOG_D("%s: No %s regulator found", rt_dm_dev_get_name(dev), "vmmc");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = rt_ptr_err(host->supply.vmmc);
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if (!rt_is_err(host->supply.vqmmc))
|
||||
{
|
||||
if (!host->supply.vqmmc)
|
||||
{
|
||||
LOG_D("%s: No %s regulator found", rt_dm_dev_get_name(dev), "vqmmc");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = rt_ptr_err(host->supply.vqmmc);
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
if (!rt_is_err_or_null(host->supply.vmmc))
|
||||
{
|
||||
rt_regulator_put(host->supply.vmmc);
|
||||
host->supply.vmmc = RT_NULL;
|
||||
}
|
||||
|
||||
if (!rt_is_err_or_null(host->supply.vqmmc))
|
||||
{
|
||||
rt_regulator_put(host->supply.vqmmc);
|
||||
host->supply.vqmmc = RT_NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t sdio_regulator_enable_vqmmc(struct rt_mmcsd_host *host)
|
||||
{
|
||||
struct rt_mmcsd_supply *supply;
|
||||
|
||||
if (!host)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
supply = &host->supply;
|
||||
|
||||
if (!rt_is_err_or_null(supply->vqmmc) && !supply->vqmmc_enabled)
|
||||
{
|
||||
rt_err_t err = rt_regulator_enable(supply->vqmmc);
|
||||
|
||||
if (err)
|
||||
{
|
||||
LOG_E("Enabling vqmmc regulator failed error = %s", rt_strerror(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
supply->vqmmc_enabled = RT_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void sdio_regulator_disable_vqmmc(struct rt_mmcsd_host *host)
|
||||
{
|
||||
struct rt_mmcsd_supply *supply;
|
||||
|
||||
if (!host)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
supply = &host->supply;
|
||||
|
||||
if (!rt_is_err_or_null(supply->vqmmc) && supply->vqmmc_enabled)
|
||||
{
|
||||
rt_regulator_disable(supply->vqmmc);
|
||||
|
||||
supply->vqmmc_enabled = RT_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ rt_inline rt_uint32_t GET_BITS(rt_uint32_t *resp,
|
||||
rt_uint32_t size)
|
||||
{
|
||||
const rt_int32_t __size = size;
|
||||
const rt_uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;
|
||||
const rt_uint32_t __mask = (__size < 32 ? 1U << __size : 0) - 1;
|
||||
const rt_int32_t __off = 3 - ((start) / 32);
|
||||
const rt_int32_t __shft = (start) & 31;
|
||||
rt_uint32_t __res;
|
||||
@@ -274,7 +274,7 @@ static rt_int32_t mmcsd_switch(struct rt_mmcsd_card *card)
|
||||
card->max_data_rate = 50000000;
|
||||
if (switch_func_timing == SD_SWITCH_FUNC_TIMING_SDR104)
|
||||
{
|
||||
LOG_I("sd: switch to SDR104 mode\n");
|
||||
LOG_I("SD card switch to %s mode", "SDR104");
|
||||
mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_SDR104);
|
||||
mmcsd_set_clock(card->host, 208000000);
|
||||
err = mmcsd_excute_tuning(card);
|
||||
@@ -282,7 +282,7 @@ static rt_int32_t mmcsd_switch(struct rt_mmcsd_card *card)
|
||||
}
|
||||
else if (switch_func_timing == SD_SWITCH_FUNC_TIMING_SDR50)
|
||||
{
|
||||
LOG_I("sd: switch to SDR50 mode\n");
|
||||
LOG_I("SD card switch to %s mode", "SDR50");
|
||||
mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_SDR50);
|
||||
mmcsd_set_clock(card->host, 100000000);
|
||||
err = mmcsd_excute_tuning(card);
|
||||
@@ -290,13 +290,13 @@ static rt_int32_t mmcsd_switch(struct rt_mmcsd_card *card)
|
||||
}
|
||||
else if (switch_func_timing == SD_SWITCH_FUNC_TIMING_DDR50)
|
||||
{
|
||||
LOG_I("sd: switch to DDR50 mode\n");
|
||||
LOG_I("SD card switch to %s mode", "DDR50");
|
||||
mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_DDR50);
|
||||
mmcsd_set_clock(card->host, 50000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("sd: switch to High Speed / SDR25 mode \n");
|
||||
LOG_I("SD card switch to %s mode", "High Speed / SDR25");
|
||||
mmcsd_set_timing(card->host, MMCSD_TIMING_SD_HS);
|
||||
mmcsd_set_clock(card->host, 50000000);
|
||||
}
|
||||
@@ -629,31 +629,6 @@ static rt_err_t mmcsd_read_sd_status(struct rt_mmcsd_card *card, rt_uint32_t *sd
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t sd_switch_voltage(struct rt_mmcsd_host *host)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_mmcsd_cmd cmd = { 0 };
|
||||
|
||||
cmd.cmd_code = VOLTAGE_SWITCH;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = RESP_R1 | CMD_AC;
|
||||
|
||||
err = mmcsd_send_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t sd_switch_uhs_voltage(struct rt_mmcsd_host *host)
|
||||
{
|
||||
if (host->ops->switch_uhs_voltage != RT_NULL)
|
||||
{
|
||||
return host->ops->switch_uhs_voltage(host);
|
||||
}
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
|
||||
rt_uint32_t ocr)
|
||||
{
|
||||
@@ -675,7 +650,7 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
|
||||
ocr |= 1 << 30;
|
||||
|
||||
/* Switch to UHS voltage if both Host and the Card support this feature */
|
||||
if (((host->valid_ocr & VDD_165_195) != 0) && (host->ops->switch_uhs_voltage != RT_NULL))
|
||||
if (((host->valid_ocr & VDD_165_195) != 0) && (host->ops->signal_voltage_switch != RT_NULL))
|
||||
{
|
||||
ocr |= OCR_S18R;
|
||||
}
|
||||
@@ -687,10 +662,7 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
|
||||
if (ocr & OCR_S18R)
|
||||
{
|
||||
ocr = VDD_165_195;
|
||||
err = sd_switch_voltage(host);
|
||||
if (err)
|
||||
goto err2;
|
||||
err = sd_switch_uhs_voltage(host);
|
||||
err = mmcsd_set_uhs_voltage(host, ocr);
|
||||
if (err)
|
||||
goto err2;
|
||||
}
|
||||
|
||||
1541
components/drivers/sdio/sdhci/sdhci.c → components/drivers/sdio/dev_sdhci.c
Normal file → Executable file
1541
components/drivers/sdio/sdhci/sdhci.c → components/drivers/sdio/dev_sdhci.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
82
components/drivers/sdio/sdhci/sdhci-platform.c → components/drivers/sdio/dev_sdhci_dm.c
Normal file → Executable file
82
components/drivers/sdio/sdhci/sdhci-platform.c → components/drivers/sdio/dev_sdhci_dm.c
Normal file → Executable file
@@ -7,9 +7,11 @@
|
||||
* Date Author Notes
|
||||
* 2024-08-16 zhujiale first version
|
||||
*/
|
||||
#include "sdhci-platform.h"
|
||||
|
||||
static const struct rt_sdhci_ops sdhci_pltfm_ops = {
|
||||
#include "dev_sdhci_dm.h"
|
||||
|
||||
static const struct rt_sdhci_ops sdhci_pltfm_ops =
|
||||
{
|
||||
.set_clock = rt_sdhci_set_clock,
|
||||
.set_bus_width = rt_sdhci_set_bus_width,
|
||||
.reset = rt_sdhci_reset,
|
||||
@@ -18,40 +20,54 @@ static const struct rt_sdhci_ops sdhci_pltfm_ops = {
|
||||
|
||||
void rt_sdhci_get_property(struct rt_platform_device *pdev)
|
||||
{
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct rt_sdhci_host *host = pdev->priv;
|
||||
struct rt_sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
rt_uint32_t bus_width;
|
||||
rt_uint32_t bus_width;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct rt_sdhci_host *host = pdev->priv;
|
||||
struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host);
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "sdhci,auto-cmd12"))
|
||||
{
|
||||
host->quirks |= RT_SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "sdhci,1-bit-only") || (rt_dm_dev_prop_read_u32(dev, "bus-width", &bus_width) == 0 && bus_width == 1))
|
||||
if (rt_dm_dev_prop_read_bool(dev, "sdhci,1-bit-only") ||
|
||||
(!rt_dm_dev_prop_read_u32(dev, "bus-width", &bus_width) && bus_width == 1))
|
||||
{
|
||||
host->quirks |= RT_SDHCI_QUIRK_FORCE_1_BIT_DATA;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "broken-cd"))
|
||||
{
|
||||
host->quirks |= RT_SDHCI_QUIRK_BROKEN_CARD_DETECTION;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "no-1-8-v"))
|
||||
{
|
||||
host->quirks2 |= RT_SDHCI_QUIRK2_NO_1_8_V;
|
||||
}
|
||||
|
||||
rt_dm_dev_prop_read_u32(dev, "clock-frequency", &pltfm_host->clock);
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "keep-power-in-suspend"))
|
||||
{
|
||||
host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "wakeup-source") || rt_dm_dev_prop_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
|
||||
if (rt_dm_dev_prop_read_bool(dev, "wakeup-source") ||
|
||||
rt_dm_dev_prop_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
|
||||
{
|
||||
host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
|
||||
}
|
||||
}
|
||||
|
||||
struct rt_sdhci_host *rt_sdhci_pltfm_init(struct rt_platform_device *pdev,
|
||||
const struct rt_sdhci_pltfm_data *pdata,
|
||||
size_t priv_size)
|
||||
struct rt_sdhci_host *rt_sdhci_pltfm_init(struct rt_platform_device *pdev,
|
||||
const struct rt_sdhci_pltfm_data *pdata,
|
||||
rt_size_t priv_size)
|
||||
{
|
||||
struct rt_sdhci_host *host;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
void *ioaddr;
|
||||
int irq;
|
||||
int irq;
|
||||
void *ioaddr;
|
||||
struct rt_sdhci_host *host;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
|
||||
ioaddr = rt_dm_dev_iomap(dev, 0);
|
||||
if (!ioaddr)
|
||||
@@ -64,19 +80,26 @@ struct rt_sdhci_host *rt_sdhci_pltfm_init(struct rt_platform_device *pdev,
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
host = rt_sdhci_alloc_host(dev,sizeof(struct rt_sdhci_pltfm_host) + priv_size);
|
||||
|
||||
host = rt_sdhci_alloc_host(dev, sizeof(struct rt_sdhci_pltfm_host) + priv_size);
|
||||
if (!host)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
host->irq = irq;
|
||||
host->ioaddr = ioaddr;
|
||||
host->hw_name = rt_dm_dev_get_name(dev);
|
||||
|
||||
if (pdata && pdata->ops)
|
||||
{
|
||||
host->ops = pdata->ops;
|
||||
}
|
||||
else
|
||||
{
|
||||
host->ops = &sdhci_pltfm_ops;
|
||||
}
|
||||
|
||||
if (pdata)
|
||||
{
|
||||
host->quirks = pdata->quirks;
|
||||
@@ -88,22 +111,26 @@ struct rt_sdhci_host *rt_sdhci_pltfm_init(struct rt_platform_device *pdev,
|
||||
return host;
|
||||
}
|
||||
|
||||
int rt_sdhci_pltfm_init_and_add_host(struct rt_platform_device *pdev,
|
||||
const struct rt_sdhci_pltfm_data *pdata,
|
||||
size_t priv_size)
|
||||
rt_err_t rt_sdhci_pltfm_init_and_add_host(struct rt_platform_device *pdev,
|
||||
const struct rt_sdhci_pltfm_data *pdata,
|
||||
rt_size_t priv_size)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct rt_sdhci_host *host;
|
||||
int ret = 0;
|
||||
|
||||
host = rt_sdhci_pltfm_init(pdev, pdata, priv_size);
|
||||
if (!host)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_sdhci_get_property(pdev);
|
||||
|
||||
ret = rt_sdhci_init_host(host);
|
||||
if (ret)
|
||||
{
|
||||
rt_sdhci_pltfm_free(pdev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -115,11 +142,22 @@ void rt_sdhci_pltfm_free(struct rt_platform_device *pdev)
|
||||
rt_sdhci_free_host(host);
|
||||
}
|
||||
|
||||
void rt_sdhci_pltfm_remove(struct rt_platform_device *pdev)
|
||||
rt_err_t rt_sdhci_pltfm_remove(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_bool_t dead;
|
||||
struct rt_sdhci_host *host = pdev->priv;
|
||||
int dead = (readl(host->ioaddr + RT_SDHCI_INT_STATUS) == 0xffffffff);
|
||||
|
||||
dead = (HWREG32(host->ioaddr + RT_SDHCI_INT_STATUS) == 0xffffffff);
|
||||
|
||||
rt_sdhci_uninit_host(host, dead);
|
||||
rt_sdhci_pltfm_free(pdev);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_uint32_t rt_sdhci_pltfm_clk_get_max_clock(struct rt_sdhci_host *host)
|
||||
{
|
||||
struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host);
|
||||
|
||||
return rt_clk_get_rate(pltfm_host->clk);
|
||||
}
|
||||
68
components/drivers/sdio/dev_sdhci_dm.h
Executable file
68
components/drivers/sdio/dev_sdhci_dm.h
Executable file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-16 zhujiale first version
|
||||
*/
|
||||
|
||||
#ifndef __DEV_SDHCI_DM_H__
|
||||
#define __DEV_SDHCI_DM_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
struct rt_sdhci_pltfm_data
|
||||
{
|
||||
const struct rt_sdhci_ops *ops;
|
||||
rt_uint32_t quirks;
|
||||
rt_uint32_t quirks2;
|
||||
};
|
||||
|
||||
struct rt_sdhci_pltfm_host
|
||||
{
|
||||
struct rt_clk *clk;
|
||||
rt_uint32_t clock;
|
||||
rt_uint16_t xfer_mode_shadow;
|
||||
|
||||
rt_ubase_t private[];
|
||||
};
|
||||
|
||||
void rt_sdhci_get_property(struct rt_platform_device *pdev);
|
||||
|
||||
rt_inline void rt_sdhci_get_of_property(struct rt_platform_device *pdev)
|
||||
{
|
||||
return rt_sdhci_get_property(pdev);
|
||||
}
|
||||
|
||||
extern struct rt_sdhci_host *rt_sdhci_pltfm_init(struct rt_platform_device *pdev,
|
||||
const struct rt_sdhci_pltfm_data *pdata,
|
||||
rt_size_t priv_size);
|
||||
extern void rt_sdhci_pltfm_free(struct rt_platform_device *pdev);
|
||||
|
||||
extern rt_err_t rt_sdhci_pltfm_init_and_add_host(struct rt_platform_device *pdev,
|
||||
const struct rt_sdhci_pltfm_data *pdata,
|
||||
rt_size_t priv_size);
|
||||
|
||||
extern rt_err_t rt_sdhci_pltfm_remove(struct rt_platform_device *pdev);
|
||||
|
||||
extern rt_uint32_t rt_sdhci_pltfm_clk_get_max_clock(struct rt_sdhci_host *host);
|
||||
|
||||
rt_inline void *rt_sdhci_pltfm_priv(struct rt_sdhci_pltfm_host *host)
|
||||
{
|
||||
return host->private;
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_sdhci_pltfm_suspend(struct rt_device *dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_sdhci_pltfm_resume(struct rt_device *dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#endif /* __DEV_SDHCI_DM_H__ */
|
||||
188
components/drivers/sdio/sdhci/fit-mmc.c → components/drivers/sdio/dev_sdhci_host.c
Normal file → Executable file
188
components/drivers/sdio/sdhci/fit-mmc.c → components/drivers/sdio/dev_sdhci_host.c
Normal file → Executable file
@@ -7,17 +7,25 @@
|
||||
* Date Author Notes
|
||||
* 2024-08-16 zhujiale first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include "sdhci.h"
|
||||
#include <rtdbg.h>
|
||||
#include <mmu.h>
|
||||
#include <drivers/core/dm.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "SDHCI"
|
||||
#ifdef RT_SDIO_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_SDIO_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "dev_sdio_dm.h"
|
||||
#include "dev_sdhci_dm.h"
|
||||
|
||||
static void rt_plat_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
|
||||
{
|
||||
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
||||
rt_uint32_t flags = req->cmd->flags;
|
||||
rt_uint32_t flags = req->cmd->flags;
|
||||
struct rt_mmc_host *mmc = rt_container_of(host, struct rt_mmc_host, rthost);
|
||||
|
||||
switch (flags & RESP_MASK)
|
||||
{
|
||||
@@ -49,12 +57,13 @@ static void rt_plat_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req
|
||||
flags |= MMC_RSP_R7;
|
||||
break;
|
||||
}
|
||||
|
||||
if (req->data)
|
||||
{
|
||||
if ((rt_uint64_t)rt_kmem_v2p(req->data->buf) > 0xffffffff)
|
||||
{
|
||||
void *req_buf = RT_NULL;
|
||||
void *dma_buffer = rt_malloc(req->data->blks * req->data->blksize);
|
||||
void *req_buf = NULL;
|
||||
|
||||
if (req->data->flags & DATA_DIR_WRITE)
|
||||
{
|
||||
@@ -76,7 +85,9 @@ static void rt_plat_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req
|
||||
{
|
||||
rt_memcpy(req_buf, dma_buffer, req->data->blksize * req->data->blks);
|
||||
req->data->buf = req_buf;
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
req->data->buf = req_buf;
|
||||
}
|
||||
|
||||
@@ -98,9 +109,9 @@ static void rt_plat_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req
|
||||
|
||||
static void rt_plat_set_ioconfig(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *iocfg)
|
||||
{
|
||||
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
||||
struct rt_mmc_host *mmc = rt_container_of(host, struct rt_mmc_host, rthost);
|
||||
|
||||
LOG_D("clock:%d,width:%d,power:%d,vdd:%d,timing:%d\n",
|
||||
LOG_D("clock: %u, width: %u, power: %u, vdd: %u, timing: %u",
|
||||
iocfg->clock, iocfg->bus_width,
|
||||
iocfg->power_mode, iocfg->vdd, iocfg->timing);
|
||||
|
||||
@@ -109,66 +120,80 @@ static void rt_plat_set_ioconfig(struct rt_mmcsd_host *host, struct rt_mmcsd_io_
|
||||
|
||||
static rt_int32_t rt_plat_get_card_status(struct rt_mmcsd_host *host)
|
||||
{
|
||||
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
||||
struct rt_mmc_host *mmc = rt_container_of(host, struct rt_mmc_host, rthost);
|
||||
|
||||
return mmc->ops->get_cd(mmc);
|
||||
}
|
||||
|
||||
static rt_int32_t rt_plat_execute_tuning(struct rt_mmcsd_host *host, rt_int32_t opcode)
|
||||
{
|
||||
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
||||
struct rt_mmc_host *mmc = rt_container_of(host, struct rt_mmc_host, rthost);
|
||||
|
||||
return mmc->ops->execute_tuning(mmc, opcode);
|
||||
}
|
||||
|
||||
static void rt_plat_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t en)
|
||||
{
|
||||
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
||||
struct rt_mmc_host *mmc = rt_container_of(host, struct rt_mmc_host, rthost);
|
||||
|
||||
return mmc->ops->enable_sdio_irq(mmc, en);
|
||||
}
|
||||
|
||||
static rt_bool_t rt_plat_card_busy(struct rt_mmcsd_host *host)
|
||||
{
|
||||
struct rt_mmc_host *mmc = rt_container_of(host, struct rt_mmc_host, rthost);
|
||||
|
||||
static const struct rt_mmcsd_host_ops rt_mmcsd_ops = {
|
||||
.request = rt_plat_request,
|
||||
.set_iocfg = rt_plat_set_ioconfig,
|
||||
.get_card_status = rt_plat_get_card_status,
|
||||
.enable_sdio_irq = rt_plat_enable_sdio_irq,
|
||||
.execute_tuning = rt_plat_execute_tuning,
|
||||
return mmc->ops->card_busy(mmc);
|
||||
}
|
||||
|
||||
static rt_err_t rt_plat_signal_voltage_switch(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
|
||||
{
|
||||
struct rt_mmc_host *mmc = rt_container_of(host, struct rt_mmc_host, rthost);
|
||||
|
||||
return mmc->ops->start_signal_voltage_switch(mmc, io_cfg);
|
||||
}
|
||||
|
||||
static const struct rt_mmcsd_host_ops rt_mmcsd_ops =
|
||||
{
|
||||
.request = rt_plat_request,
|
||||
.set_iocfg = rt_plat_set_ioconfig,
|
||||
.get_card_status = rt_plat_get_card_status,
|
||||
.enable_sdio_irq = rt_plat_enable_sdio_irq,
|
||||
.execute_tuning = rt_plat_execute_tuning,
|
||||
.card_busy = rt_plat_card_busy,
|
||||
.signal_voltage_switch = rt_plat_signal_voltage_switch,
|
||||
};
|
||||
|
||||
|
||||
void rt_mmc_request_done(struct rt_mmc_host *host, struct rt_mmcsd_req *mrq)
|
||||
{
|
||||
mmcsd_req_complete(&host->rthost);
|
||||
}
|
||||
|
||||
/*add host in rtt while sdhci complete*/
|
||||
int rt_mmc_add_host(struct rt_mmc_host *mmc)
|
||||
/* Add host in rtt while sdhci complete */
|
||||
rt_err_t rt_mmc_add_host(struct rt_mmc_host *mmc)
|
||||
{
|
||||
mmc->rthost.ops = &rt_mmcsd_ops;
|
||||
mmc->rthost.flags = mmc->caps;
|
||||
mmc->rthost.freq_max = mmc->f_max;
|
||||
mmc->rthost.freq_min = 400000;
|
||||
mmc->rthost.freq_min = mmc->f_min;
|
||||
mmc->rthost.max_dma_segs = mmc->max_segs;
|
||||
mmc->rthost.max_seg_size = mmc->max_seg_size;
|
||||
mmc->rthost.max_blk_size = mmc->max_blk_size;
|
||||
mmc->rthost.max_blk_count = mmc->max_blk_count;
|
||||
mmc->rthost.valid_ocr = VDD_165_195|VDD_20_21|VDD_21_22|VDD_22_23|VDD_24_25|VDD_25_26|VDD_26_27|VDD_27_28|VDD_28_29|VDD_29_30|VDD_30_31|VDD_32_33|VDD_33_34|VDD_34_35|VDD_35_36;
|
||||
|
||||
mmc->rthost.valid_ocr = mmc->ocr_avail;
|
||||
|
||||
mmcsd_change(&mmc->rthost);
|
||||
return 0;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
struct rt_mmc_host *rt_mmc_alloc_host(int extra, struct rt_device *dev)
|
||||
{
|
||||
struct rt_mmc_host *mmc;
|
||||
|
||||
mmc = rt_malloc(sizeof(*mmc) + extra);
|
||||
mmc = rt_calloc(1, sizeof(*mmc) + extra);
|
||||
if (mmc)
|
||||
{
|
||||
rt_memset(mmc, 0, sizeof(*mmc) + extra);
|
||||
mmc->parent = dev;
|
||||
mmcsd_host_init(&mmc->rthost);
|
||||
}
|
||||
@@ -181,86 +206,52 @@ void rt_mmc_remove_host(struct rt_mmc_host *host)
|
||||
rt_free(host);
|
||||
}
|
||||
|
||||
int rt_mmc_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode)
|
||||
rt_err_t rt_mmc_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode)
|
||||
{
|
||||
return 0;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
||||
int rt_mmc_gpio_get_cd(struct rt_mmc_host *host)
|
||||
rt_err_t rt_mmc_gpio_get_cd(struct rt_mmc_host *host)
|
||||
{
|
||||
return -ENOSYS;
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
void rt_mmc_detect_change(struct rt_mmc_host *host, unsigned long delay)
|
||||
void rt_mmc_detect_change(struct rt_mmc_host *host, rt_ubase_t delay)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int rt_mmc_regulator_set_vqmmc(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_bool_t rt_mmc_can_gpio_ro(struct rt_mmc_host *host)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
int rt_mmc_gpio_get_ro(struct rt_mmc_host *host)
|
||||
rt_err_t rt_mmc_gpio_get_ro(struct rt_mmc_host *host)
|
||||
{
|
||||
return 0;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int rt_mmc_send_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode)
|
||||
rt_err_t rt_mmc_send_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode)
|
||||
{
|
||||
return 0;
|
||||
return RT_EOK;
|
||||
}
|
||||
int rt_mmc_of_parse(struct rt_mmc_host *host)
|
||||
|
||||
rt_err_t rt_mmc_of_parse(struct rt_mmc_host *host)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_device *dev = host->parent;
|
||||
rt_uint32_t bus_width;
|
||||
|
||||
if (!dev || !dev->ofw_node)
|
||||
return 0;
|
||||
|
||||
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
|
||||
if (rt_dm_dev_prop_read_u32(dev, "bus-width", &bus_width) < 0)
|
||||
{
|
||||
bus_width = 1;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
switch (bus_width)
|
||||
err = sdio_ofw_parse(dev->ofw_node, &host->rthost);
|
||||
if (err)
|
||||
{
|
||||
case 8:
|
||||
host->caps |= MMC_CAP_8_BIT_DATA;
|
||||
break; /* Hosts capable of 8-bit can also do 4 bits */
|
||||
case 4:
|
||||
host->caps |= MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* f_max is obtained from the optional "max-frequency" property */
|
||||
rt_dm_dev_prop_read_u32(dev, "max-frequency", &host->f_max);
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "cap-mmc-highspeed"))
|
||||
{
|
||||
host->caps |= MMC_CAP_MMC_HIGHSPEED;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "mmc-hs200-1_8v"))
|
||||
{
|
||||
host->caps |= MMC_CAP2_HS200_1_8V_SDR;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "non-removable"))
|
||||
{
|
||||
host->caps |= MMC_CAP_NONREMOVABLE;
|
||||
}
|
||||
host->caps |= host->rthost.flags;
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "no-sdio"))
|
||||
{
|
||||
@@ -272,25 +263,9 @@ int rt_mmc_of_parse(struct rt_mmc_host *host)
|
||||
host->caps2 |= MMC_CAP2_NO_SD;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-3_3v"))
|
||||
{
|
||||
host->caps |= MMC_CAP_3_3V_DDR;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-1_8v"))
|
||||
{
|
||||
host->caps |= MMC_CAP_1_8V_DDR;
|
||||
}
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-1_2v"))
|
||||
{
|
||||
host->caps |= MMC_CAP_1_2V_DDR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
||||
void rt_mmc_free_host(struct rt_mmc_host *host)
|
||||
{
|
||||
}
|
||||
@@ -299,22 +274,3 @@ rt_bool_t rt_mmc_can_gpio_cd(struct rt_mmc_host *host)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
int mmc_regulator_get_supply(struct rt_mmc_host *mmc)
|
||||
{
|
||||
mmc->supply.vmmc = -RT_NULL;
|
||||
mmc->supply.vqmmc = -RT_NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
int regulator_get_current_limit(struct regulator *regulator)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int regulator_is_supported_voltage(struct regulator *regulator,
|
||||
|
||||
int min_uV, int max_uV)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
157
components/drivers/sdio/dev_sdio_dm.c
Executable file
157
components/drivers/sdio/dev_sdio_dm.c
Executable file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include <rtatomic.h>
|
||||
#include "dev_sdio_dm.h"
|
||||
|
||||
#define DBG_TAG "SDIO"
|
||||
#ifdef RT_SDIO_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_SDIO_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
int sdio_host_set_name(struct rt_mmcsd_host *host, char *out_devname)
|
||||
{
|
||||
int id = -1, res;
|
||||
static int uid_min = -1;
|
||||
static volatile rt_atomic_t uid = 0;
|
||||
|
||||
RT_ASSERT(host != RT_NULL);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (host->ofw_node)
|
||||
{
|
||||
id = rt_ofw_get_alias_id(host->ofw_node, "mmc");
|
||||
|
||||
if (uid_min < 0)
|
||||
{
|
||||
uid_min = rt_ofw_get_alias_last_id("mmc");
|
||||
uid_min = uid_min < 0 ? 0 : (uid_min + 1);
|
||||
|
||||
rt_atomic_store(&uid, uid_min);
|
||||
}
|
||||
}
|
||||
#endif /* RT_USING_OFW */
|
||||
|
||||
if (id < 0)
|
||||
{
|
||||
id = (int)rt_atomic_add(&uid, 1);
|
||||
}
|
||||
|
||||
res = rt_snprintf(host->name, RT_NAME_MAX, "sd%u", id);
|
||||
|
||||
if (out_devname)
|
||||
{
|
||||
rt_strncpy(out_devname, host->name, RT_NAME_MAX);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host)
|
||||
{
|
||||
rt_uint32_t bus_width = 1;
|
||||
|
||||
if (!dev_np)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
host->ofw_node = host->ofw_node ? : dev_np;
|
||||
|
||||
host->flags = MMCSD_MUTBLKWRITE;
|
||||
rt_ofw_prop_read_u32(dev_np, "bus-width", &bus_width);
|
||||
|
||||
switch (bus_width)
|
||||
{
|
||||
case 0x8:
|
||||
host->flags |= MMCSD_BUSWIDTH_8;
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
host->flags |= MMCSD_BUSWIDTH_4;
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E("Invalid \"bus-width\" value %d", bus_width);
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
rt_ofw_prop_read_u32(dev_np, "max-frequency", &host->freq_max);
|
||||
|
||||
if (rt_ofw_prop_read_bool(dev_np, "non-removable"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_NONREMOVABLE;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_bool(dev_np, "cap-sdio-irq"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_SDIO_IRQ;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_bool(dev_np, "cap-sd-highspeed") ||
|
||||
rt_ofw_prop_read_bool(dev_np, "cap-mmc-highspeed"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_HIGHSPEED;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-3_3v"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_DDR_3V3;
|
||||
}
|
||||
if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-1_8v"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_DDR_1V8;
|
||||
}
|
||||
if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-1_2v"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_DDR_1V2;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_bool(dev_np, "mmc-hs200-1_2v"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_HS200_1V2;
|
||||
}
|
||||
if (rt_ofw_prop_read_bool(dev_np, "mmc-hs200-1_8v"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_HS200_1V8;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_bool(dev_np, "mmc-hs400-1_8v"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_HS400_1V8;
|
||||
}
|
||||
if (rt_ofw_prop_read_bool(dev_np, "mmc-hs400-1_2v"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_HS400_1V2;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_bool(dev_np, "sd-uhs-sdr50"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_SDR50;
|
||||
}
|
||||
if (rt_ofw_prop_read_bool(dev_np, "sd-uhs-sdr104"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_SDR104;
|
||||
}
|
||||
if (rt_ofw_prop_read_bool(dev_np, "sd-uhs-ddr50"))
|
||||
{
|
||||
host->flags |= MMCSD_SUP_DDR50;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
#endif /* RT_USING_OFW */
|
||||
39
components/drivers/sdio/dev_sdio_dm.h
Executable file
39
components/drivers/sdio/dev_sdio_dm.h
Executable file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __DEV_SDIO_DM_H__
|
||||
#define __DEV_SDIO_DM_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
int sdio_host_set_name(struct rt_mmcsd_host *host, char *out_devname);
|
||||
|
||||
#ifdef RT_USING_REGULATOR
|
||||
rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host,
|
||||
struct rt_regulator *supply, rt_uint16_t vdd_bit);
|
||||
rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host,
|
||||
struct rt_mmcsd_io_cfg *ios);
|
||||
rt_err_t sdio_regulator_get_supply(struct rt_device *dev, struct rt_mmcsd_host *host);
|
||||
rt_err_t sdio_regulator_enable_vqmmc(struct rt_mmcsd_host *host);
|
||||
void sdio_regulator_disable_vqmmc(struct rt_mmcsd_host *host);
|
||||
#endif /* RT_USING_REGULATOR */
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host);
|
||||
#else
|
||||
rt_inline rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
#endif /* RT_USING_OFW */
|
||||
|
||||
#endif /* __DEV_SDIO_DM_H__ */
|
||||
22
components/drivers/sdio/host/Kconfig
Executable file
22
components/drivers/sdio/host/Kconfig
Executable file
@@ -0,0 +1,22 @@
|
||||
config RT_SDIO_SDHCI_PCI
|
||||
bool "SDHCI support on PCI bus"
|
||||
depends on RT_USING_PCI
|
||||
select RT_USING_SDHCI
|
||||
default n
|
||||
|
||||
config RT_SDIO_DW_MMC
|
||||
bool "Synopsys DesignWare MMC Family"
|
||||
depends on RT_USING_PINCTRL
|
||||
depends on RT_USING_RESET
|
||||
depends on RT_USING_REGULATOR
|
||||
select RT_USING_DEVICE_IPC
|
||||
select RT_USING_SYSTEM_WORKQUEUE
|
||||
default n
|
||||
|
||||
config RT_SDIO_DW_MMC_PCI
|
||||
bool "Synopsys Designware MCI support on PCI bus"
|
||||
depends on RT_SDIO_DW_MMC
|
||||
depends on RT_USING_PCI
|
||||
default n
|
||||
|
||||
osource "$(SOC_DM_SDIO_DIR)/Kconfig"
|
||||
24
components/drivers/sdio/host/SConscript
Executable file
24
components/drivers/sdio/host/SConscript
Executable file
@@ -0,0 +1,24 @@
|
||||
from building import *
|
||||
|
||||
group = []
|
||||
|
||||
if not GetDepend(['RT_USING_SDIO']) and not GetDepend(['RT_USING_DM']):
|
||||
Return('group')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + '/../../include']
|
||||
|
||||
src = []
|
||||
|
||||
if GetDepend(['RT_SDIO_SDHCI_PCI']):
|
||||
src += ['sdhci-pci.c']
|
||||
|
||||
if GetDepend(['RT_SDIO_DW_MMC']):
|
||||
src += ['sdio-dw.c', 'sdio-dw-platform.c']
|
||||
|
||||
if GetDepend(['RT_SDIO_DW_MMC_PCI']):
|
||||
src += ['sdio-dw-pci.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
113
components/drivers/sdio/host/sdhci-pci.c
Executable file
113
components/drivers/sdio/host/sdhci-pci.c
Executable file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#define SDHCI_REG_BAR 0
|
||||
|
||||
#include "../dev_sdio_dm.h"
|
||||
|
||||
struct pci_sdhci_host
|
||||
{
|
||||
struct rt_sdhci_host parent;
|
||||
};
|
||||
|
||||
static const struct rt_sdhci_ops pci_sdhci_ops =
|
||||
{
|
||||
.set_clock = rt_sdhci_set_clock,
|
||||
.set_bus_width = rt_sdhci_set_bus_width,
|
||||
.reset = rt_sdhci_reset,
|
||||
};
|
||||
|
||||
static rt_err_t pci_sdhci_probe(struct rt_pci_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_sdhci_host *host;
|
||||
struct pci_sdhci_host *pci_host;
|
||||
|
||||
host = rt_sdhci_alloc_host(&pdev->parent, sizeof(struct pci_sdhci_host));
|
||||
|
||||
if (!host)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
pci_host = rt_container_of(host, struct pci_sdhci_host, parent);
|
||||
|
||||
host->ioaddr = rt_pci_iomap(pdev, SDHCI_REG_BAR);
|
||||
|
||||
if (!host->ioaddr)
|
||||
{
|
||||
err = -RT_EIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
host->irq = pdev->irq;
|
||||
host->ops = &pci_sdhci_ops;
|
||||
|
||||
rt_pci_irq_unmask(pdev);
|
||||
rt_pci_set_master(pdev);
|
||||
|
||||
if ((err = rt_sdhci_set_and_add_host(host)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
pdev->parent.user_data = pci_host;
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
if (host->ioaddr)
|
||||
{
|
||||
rt_iounmap(host->ioaddr);
|
||||
}
|
||||
|
||||
rt_sdhci_free_host(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t pci_sdhci_remove(struct rt_pci_device *pdev)
|
||||
{
|
||||
rt_bool_t dead;
|
||||
struct rt_sdhci_host *host;
|
||||
struct pci_sdhci_host *pci_host = pdev->parent.user_data;
|
||||
|
||||
host = &pci_host->parent;
|
||||
|
||||
/* INTx is shared, don't mask all */
|
||||
rt_hw_interrupt_umask(pdev->irq);
|
||||
rt_pci_irq_mask(pdev);
|
||||
rt_pci_clear_master(pdev);
|
||||
|
||||
dead = (HWREG32(host->ioaddr + RT_SDHCI_INT_STATUS) == 0xffffffff);
|
||||
|
||||
rt_sdhci_uninit_host(host, dead);
|
||||
|
||||
rt_iounmap(host->ioaddr);
|
||||
rt_sdhci_free_host(host);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_pci_device_id pci_sdhci_pci_ids[] =
|
||||
{
|
||||
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0007), },
|
||||
{ RT_PCI_DEVICE_CLASS(PCIS_SYSTEM_SDHCI, ~0) },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_pci_driver pci_sdhci_driver =
|
||||
{
|
||||
.name = "sdhci-pci",
|
||||
|
||||
.ids = pci_sdhci_pci_ids,
|
||||
.probe = pci_sdhci_probe,
|
||||
.remove = pci_sdhci_remove,
|
||||
};
|
||||
RT_PCI_DRIVER_EXPORT(pci_sdhci_driver);
|
||||
100
components/drivers/sdio/host/sdio-dw-pci.c
Executable file
100
components/drivers/sdio/host/sdio-dw-pci.c
Executable file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "dev_sdio_dw.h"
|
||||
|
||||
#include <mmu.h>
|
||||
|
||||
#define SYNOPSYS_DW_MCI_VENDOR_ID 0x0700
|
||||
#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107
|
||||
|
||||
#define MCI_REG_NO 2
|
||||
|
||||
static const struct sdio_dw_drv_data sdio_dw_pci_drv_data =
|
||||
{
|
||||
};
|
||||
|
||||
static rt_err_t sdio_dw_pci_probe(struct rt_pci_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct sdio_dw *sd = rt_calloc(1, sizeof(*sd));
|
||||
|
||||
if (!sd)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
sd->bus_dev = &pdev->parent;
|
||||
sd->base = rt_pci_iomap(pdev, MCI_REG_NO);
|
||||
|
||||
if (!sd->base)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
sd->irq = pdev->irq;
|
||||
rt_pci_irq_unmask(pdev);
|
||||
|
||||
sd->base_phy = (rt_ubase_t)rt_kmem_v2p(sd->base);
|
||||
sd->drv_data = &sdio_dw_pci_drv_data;
|
||||
|
||||
/* board data */
|
||||
sd->bus_hz = 33 * 1000 * 1000;
|
||||
sd->detect_delay_ms = 200;
|
||||
sd->fifo_depth = 32;
|
||||
|
||||
pdev->parent.user_data = sd;
|
||||
|
||||
if ((err = sdio_dw_probe(sd)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
if (sd->base)
|
||||
{
|
||||
rt_iounmap(sd->base);
|
||||
}
|
||||
|
||||
rt_free(sd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t sdio_dw_pci_remove(struct rt_pci_device *pdev)
|
||||
{
|
||||
struct sdio_dw *sd = pdev->parent.user_data;
|
||||
|
||||
sdio_dw_remove(sd);
|
||||
|
||||
rt_iounmap(sd->base);
|
||||
|
||||
rt_free(sd);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_pci_device_id sdio_dw_pci_pci_ids[] =
|
||||
{
|
||||
{ RT_PCI_DEVICE_ID(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_pci_driver sdio_dw_pci_driver =
|
||||
{
|
||||
.name = "dw-mmc-pci",
|
||||
|
||||
.ids = sdio_dw_pci_pci_ids,
|
||||
.probe = sdio_dw_pci_probe,
|
||||
.remove = sdio_dw_pci_remove,
|
||||
};
|
||||
RT_PCI_DRIVER_EXPORT(sdio_dw_pci_driver);
|
||||
110
components/drivers/sdio/host/sdio-dw-platform.c
Executable file
110
components/drivers/sdio/host/sdio-dw-platform.c
Executable file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "sdio-dw-platform.h"
|
||||
|
||||
#include <mmu.h>
|
||||
|
||||
rt_err_t sdio_dw_platform_register(struct rt_platform_device *pdev,
|
||||
const struct sdio_dw_drv_data *drv_data)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct sdio_dw *sd = rt_calloc(1, sizeof(*sd));
|
||||
|
||||
if (!sd)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
sd->bus_dev = &pdev->parent;
|
||||
sd->base = rt_dm_dev_iomap(dev, 0);
|
||||
|
||||
if (!sd->base)
|
||||
{
|
||||
err = -RT_EIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
sd->irq = rt_dm_dev_get_irq(dev, 0);
|
||||
|
||||
if (sd->irq < 0)
|
||||
{
|
||||
err = sd->irq;
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
sd->parent.ofw_node = dev->ofw_node;
|
||||
|
||||
sd->base_phy = (rt_ubase_t)rt_kmem_v2p(sd->base);
|
||||
sd->drv_data = drv_data;
|
||||
|
||||
pdev->parent.user_data = sd;
|
||||
|
||||
if ((err = sdio_dw_probe(sd)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
if (sd->base)
|
||||
{
|
||||
rt_iounmap(sd->base);
|
||||
}
|
||||
|
||||
rt_free(sd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t sdio_dw_platform_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
const struct sdio_dw_drv_data *drv_data = RT_NULL;
|
||||
|
||||
if (pdev->parent.ofw_node)
|
||||
{
|
||||
drv_data = pdev->id->data;
|
||||
}
|
||||
|
||||
return sdio_dw_platform_register(pdev, drv_data);
|
||||
}
|
||||
|
||||
static rt_err_t sdio_dw_platform_remove(struct rt_platform_device *pdev)
|
||||
{
|
||||
struct sdio_dw *sd = pdev->parent.user_data;
|
||||
|
||||
sdio_dw_remove(sd);
|
||||
|
||||
rt_iounmap(sd->base);
|
||||
|
||||
rt_free(sd);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id sdio_dw_platform_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "snps,dw-mshc", },
|
||||
{ .compatible = "img,pistachio-dw-mshc", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver sdio_dw_platform_driver =
|
||||
{
|
||||
.name = "dw-mmc",
|
||||
.ids = sdio_dw_platform_ofw_ids,
|
||||
|
||||
.probe = sdio_dw_platform_probe,
|
||||
.remove = sdio_dw_platform_remove,
|
||||
};
|
||||
RT_PLATFORM_DRIVER_EXPORT(sdio_dw_platform_driver);
|
||||
19
components/drivers/sdio/host/sdio-dw-platform.h
Executable file
19
components/drivers/sdio/host/sdio-dw-platform.h
Executable file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __SDIO_DW_PLATFORM_H__
|
||||
#define __SDIO_DW_PLATFORM_H__
|
||||
|
||||
#include "sdio-dw.h"
|
||||
|
||||
rt_err_t sdio_dw_platform_register(struct rt_platform_device *pdev,
|
||||
const struct sdio_dw_drv_data *drv_data);
|
||||
|
||||
#endif /* __SDIO_DW_PLATFORM_H__ */
|
||||
3265
components/drivers/sdio/host/sdio-dw.c
Executable file
3265
components/drivers/sdio/host/sdio-dw.c
Executable file
File diff suppressed because it is too large
Load Diff
362
components/drivers/sdio/host/sdio-dw.h
Executable file
362
components/drivers/sdio/host/sdio-dw.h
Executable file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-06 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __SDIO_DW_H__
|
||||
#define __SDIO_DW_H__
|
||||
|
||||
#include "../dev_sdio_dm.h"
|
||||
|
||||
#define SDIO_DW_CTRL 0x000
|
||||
#define SDIO_DW_PWREN 0x004
|
||||
#define SDIO_DW_CLKDIV 0x008
|
||||
#define SDIO_DW_CLKSRC 0x00c
|
||||
#define SDIO_DW_CLKENA 0x010
|
||||
#define SDIO_DW_TMOUT 0x014
|
||||
#define SDIO_DW_CTYPE 0x018
|
||||
#define SDIO_DW_BLKSIZ 0x01c
|
||||
#define SDIO_DW_BYTCNT 0x020
|
||||
#define SDIO_DW_INTMASK 0x024
|
||||
#define SDIO_DW_CMDARG 0x028
|
||||
#define SDIO_DW_CMD 0x02c
|
||||
#define SDIO_DW_RESP0 0x030
|
||||
#define SDIO_DW_RESP1 0x034
|
||||
#define SDIO_DW_RESP2 0x038
|
||||
#define SDIO_DW_RESP3 0x03c
|
||||
#define SDIO_DW_MINTSTS 0x040
|
||||
#define SDIO_DW_RINTSTS 0x044
|
||||
#define SDIO_DW_STATUS 0x048
|
||||
#define SDIO_DW_FIFOTH 0x04c
|
||||
#define SDIO_DW_CDETECT 0x050
|
||||
#define SDIO_DW_WRTPRT 0x054
|
||||
#define SDIO_DW_GPIO 0x058
|
||||
#define SDIO_DW_TCBCNT 0x05c
|
||||
#define SDIO_DW_TBBCNT 0x060
|
||||
#define SDIO_DW_DEBNCE 0x064
|
||||
#define SDIO_DW_USRID 0x068
|
||||
#define SDIO_DW_VERID 0x06c
|
||||
#define SDIO_DW_HCON 0x070
|
||||
#define SDIO_DW_UHS_REG 0x074
|
||||
#define SDIO_DW_RST_N 0x078
|
||||
#define SDIO_DW_BMOD 0x080
|
||||
#define SDIO_DW_PLDMND 0x084
|
||||
#define SDIO_DW_DBADDR 0x088
|
||||
#define SDIO_DW_IDSTS 0x08c
|
||||
#define SDIO_DW_IDINTEN 0x090
|
||||
#define SDIO_DW_DSCADDR 0x094
|
||||
#define SDIO_DW_BUFADDR 0x098
|
||||
#define SDIO_DW_CDTHRCTL 0x100
|
||||
#define SDIO_DW_UHS_REG_EXT 0x108
|
||||
#define SDIO_DW_DDR_REG 0x10c
|
||||
#define SDIO_DW_ENABLE_SHIFT 0x110
|
||||
#define SDIO_DW_DATA(x) (x)
|
||||
/*
|
||||
* Registers to support idmac 64-bit address mode
|
||||
*/
|
||||
#define SDIO_DW_DBADDRL 0x088
|
||||
#define SDIO_DW_DBADDRU 0x08c
|
||||
#define SDIO_DW_IDSTS64 0x090
|
||||
#define SDIO_DW_IDINTEN64 0x094
|
||||
#define SDIO_DW_DSCADDRL 0x098
|
||||
#define SDIO_DW_DSCADDRU 0x09c
|
||||
#define SDIO_DW_BUFADDRL 0x0a0
|
||||
#define SDIO_DW_BUFADDRU 0x0a4
|
||||
|
||||
/* Support for longer data read timeout */
|
||||
#define SDIO_DW_QUIRK_EXTENDED_TMOUT RT_BIT(0)
|
||||
|
||||
#define SDIO_DW_240A 0x240a
|
||||
#define SDIO_DW_280A 0x280a
|
||||
|
||||
/*
|
||||
* Data offset is difference according to Version
|
||||
* Lower than 2.40a : data register offest is 0x100
|
||||
*/
|
||||
#define DATA_OFFSET 0x100
|
||||
#define DATA_240A_OFFSET 0x200
|
||||
|
||||
/* Control register defines */
|
||||
#define SDIO_DW_CTRL_USE_IDMAC RT_BIT(25)
|
||||
#define SDIO_DW_CTRL_CEATA_INT_EN RT_BIT(11)
|
||||
#define SDIO_DW_CTRL_SEND_AS_CCSD RT_BIT(10)
|
||||
#define SDIO_DW_CTRL_SEND_CCSD RT_BIT(9)
|
||||
#define SDIO_DW_CTRL_ABRT_READ_DATA RT_BIT(8)
|
||||
#define SDIO_DW_CTRL_SEND_IRQ_RESP RT_BIT(7)
|
||||
#define SDIO_DW_CTRL_READ_WAIT RT_BIT(6)
|
||||
#define SDIO_DW_CTRL_DMA_ENABLE RT_BIT(5)
|
||||
#define SDIO_DW_CTRL_INT_ENABLE RT_BIT(4)
|
||||
#define SDIO_DW_CTRL_DMA_RESET RT_BIT(2)
|
||||
#define SDIO_DW_CTRL_FIFO_RESET RT_BIT(1)
|
||||
#define SDIO_DW_CTRL_RESET RT_BIT(0)
|
||||
/* Clock Enable register defines */
|
||||
#define SDIO_DW_CLKEN_LOW_PWR RT_BIT(16)
|
||||
#define SDIO_DW_CLKEN_ENABLE RT_BIT(0)
|
||||
/* Time-out register defines */
|
||||
#define SDIO_DW_TMOUT_DATA(n) ((n) << 8)
|
||||
#define SDIO_DW_TMOUT_DATA_MSK 0xffffff00
|
||||
#define SDIO_DW_TMOUT_RESP(n) ((n) & 0xff)
|
||||
#define SDIO_DW_TMOUT_RESP_MSK 0xff
|
||||
/* Card-type register defines */
|
||||
#define SDIO_DW_CTYPE_8BIT RT_BIT(16)
|
||||
#define SDIO_DW_CTYPE_4BIT RT_BIT(0)
|
||||
#define SDIO_DW_CTYPE_1BIT 0
|
||||
/* Interrupt status & mask register defines */
|
||||
#define SDIO_DW_INT_SDIO(n) RT_BIT(16 + (n))
|
||||
#define SDIO_DW_INT_RAW_SDIO RT_BIT(24)
|
||||
#define SDIO_DW_INT_EBE RT_BIT(15)
|
||||
#define SDIO_DW_INT_ACD RT_BIT(14)
|
||||
#define SDIO_DW_INT_SBE RT_BIT(13)
|
||||
#define SDIO_DW_INT_HLE RT_BIT(12)
|
||||
#define SDIO_DW_INT_FRUN RT_BIT(11)
|
||||
#define SDIO_DW_INT_HTO RT_BIT(10)
|
||||
#define SDIO_DW_INT_VOLT_SWITCH RT_BIT(10)
|
||||
#define SDIO_DW_INT_DRTO RT_BIT(9)
|
||||
#define SDIO_DW_INT_RTO RT_BIT(8)
|
||||
#define SDIO_DW_INT_DCRC RT_BIT(7)
|
||||
#define SDIO_DW_INT_RCRC RT_BIT(6)
|
||||
#define SDIO_DW_INT_RXDR RT_BIT(5)
|
||||
#define SDIO_DW_INT_TXDR RT_BIT(4)
|
||||
#define SDIO_DW_INT_DATA_OVER RT_BIT(3)
|
||||
#define SDIO_DW_INT_CMD_DONE RT_BIT(2)
|
||||
#define SDIO_DW_INT_RESP_ERR RT_BIT(1)
|
||||
#define SDIO_DW_INT_CD RT_BIT(0)
|
||||
#define SDIO_DW_INT_ERROR 0xbfc2
|
||||
/* Command register defines */
|
||||
#define SDIO_DW_CMD_START RT_BIT(31)
|
||||
#define SDIO_DW_CMD_USE_HOLD_REG RT_BIT(29)
|
||||
#define SDIO_DW_CMD_VOLT_SWITCH RT_BIT(28)
|
||||
#define SDIO_DW_CMD_CCS_EXP RT_BIT(23)
|
||||
#define SDIO_DW_CMD_CEATA_RD RT_BIT(22)
|
||||
#define SDIO_DW_CMD_UPD_CLK RT_BIT(21)
|
||||
#define SDIO_DW_CMD_INIT RT_BIT(15)
|
||||
#define SDIO_DW_CMD_STOP RT_BIT(14)
|
||||
#define SDIO_DW_CMD_PRV_DAT_WAIT RT_BIT(13)
|
||||
#define SDIO_DW_CMD_SEND_STOP RT_BIT(12)
|
||||
#define SDIO_DW_CMD_STRM_MODE RT_BIT(11)
|
||||
#define SDIO_DW_CMD_DAT_WR RT_BIT(10)
|
||||
#define SDIO_DW_CMD_DAT_EXP RT_BIT(9)
|
||||
#define SDIO_DW_CMD_RESP_CRC RT_BIT(8)
|
||||
#define SDIO_DW_CMD_RESP_LONG RT_BIT(7)
|
||||
#define SDIO_DW_CMD_RESP_EXP RT_BIT(6)
|
||||
#define SDIO_DW_CMD_INDX(n) ((n) & 0x1f)
|
||||
/* Status register defines */
|
||||
#define SDIO_DW_GET_FCNT(x) (((x) >> 17) & 0x1fff)
|
||||
#define SDIO_DW_STATUS_DMA_REQ RT_BIT(31)
|
||||
#define SDIO_DW_STATUS_BUSY RT_BIT(9)
|
||||
/* FIFOTH register defines */
|
||||
#define SDIO_DW_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | ((r) & 0xfff) << 16 | ((t) & 0xfff))
|
||||
/* HCON register defines */
|
||||
#define DMA_INTERFACE_IDMA (0x0)
|
||||
#define DMA_INTERFACE_DWDMA (0x1)
|
||||
#define DMA_INTERFACE_GDMA (0x2)
|
||||
#define DMA_INTERFACE_NODMA (0x3)
|
||||
#define SDIO_DW_GET_TRANS_MODE(x) (((x) >> 16) & 0x3)
|
||||
#define SDIO_DW_GET_SLOT_NUM(x) ((((x) >> 1) & 0x1f) + 1)
|
||||
#define SDIO_DW_GET_HDATA_WIDTH(x) (((x) >> 7) & 0x7)
|
||||
#define SDIO_DW_GET_ADDR_CONFIG(x) (((x) >> 27) & 0x1)
|
||||
/* Internal DMAC interrupt defines */
|
||||
#define SDIO_DW_IDMAC_INT_AI RT_BIT(9)
|
||||
#define SDIO_DW_IDMAC_INT_NI RT_BIT(8)
|
||||
#define SDIO_DW_IDMAC_INT_CES RT_BIT(5)
|
||||
#define SDIO_DW_IDMAC_INT_DU RT_BIT(4)
|
||||
#define SDIO_DW_IDMAC_INT_FBE RT_BIT(2)
|
||||
#define SDIO_DW_IDMAC_INT_RI RT_BIT(1)
|
||||
#define SDIO_DW_IDMAC_INT_TI RT_BIT(0)
|
||||
/* Internal DMAC bus mode bits */
|
||||
#define SDIO_DW_IDMAC_ENABLE RT_BIT(7)
|
||||
#define SDIO_DW_IDMAC_FB RT_BIT(1)
|
||||
#define SDIO_DW_IDMAC_SWRESET RT_BIT(0)
|
||||
/* H/W reset */
|
||||
#define SDIO_DW_RST_HWACTIVE 0x1
|
||||
/* Version ID register define */
|
||||
#define SDIO_DW_GET_VERID(x) ((x) & 0xffff)
|
||||
/* Card read threshold */
|
||||
#define SDIO_DW_SET_THLD(v, x) (((v) & 0xfff) << 16 | (x))
|
||||
#define SDIO_DW_CARD_WR_THR_EN RT_BIT(2)
|
||||
#define SDIO_DW_CARD_RD_THR_EN RT_BIT(0)
|
||||
/* UHS-1 register defines */
|
||||
#define SDIO_DW_UHS_DDR RT_BIT(16)
|
||||
#define SDIO_DW_UHS_18V RT_BIT(0)
|
||||
/* DDR register defines */
|
||||
#define SDIO_DW_DDR_HS400 RT_BIT(31)
|
||||
/* Enable shift register defines */
|
||||
#define SDIO_DW_ENABLE_PHASE RT_BIT(0)
|
||||
/* All ctrl reset bits */
|
||||
#define SDIO_DW_CTRL_ALL_RESET_FLAGS (SDIO_DW_CTRL_RESET | SDIO_DW_CTRL_FIFO_RESET | SDIO_DW_CTRL_DMA_RESET)
|
||||
|
||||
struct rt_dma_chan;
|
||||
|
||||
struct sdio_dw
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct rt_device *bus_dev;
|
||||
|
||||
struct rt_workqueue *state_wq;
|
||||
struct rt_work state_work;
|
||||
|
||||
void *base;
|
||||
void *fifo_base;
|
||||
rt_ubase_t base_phy;
|
||||
rt_uint32_t data_addr_override;
|
||||
rt_bool_t wm_aligned;
|
||||
|
||||
int irq;
|
||||
int sdio_id0;
|
||||
rt_uint32_t verid;
|
||||
rt_uint32_t quirks;
|
||||
rt_uint32_t bus_hz;
|
||||
rt_bool_t fifo_mode;
|
||||
rt_uint32_t fifo_depth;
|
||||
rt_uint32_t fifoth_val;
|
||||
rt_uint32_t detect_delay_ms;
|
||||
rt_uint32_t current_speed;
|
||||
rt_uint32_t minimum_speed;
|
||||
void *priv;
|
||||
|
||||
rt_uint32_t vqmmc_enabled;
|
||||
rt_uint32_t cmd_status;
|
||||
rt_uint32_t data_status;
|
||||
rt_uint32_t stop_cmdr;
|
||||
rt_uint32_t dir_status;
|
||||
#define STATE_IDLE 0
|
||||
#define STATE_SENDING_CMD 1
|
||||
#define STATE_SENDING_DATA 2
|
||||
#define STATE_DATA_BUSY 3
|
||||
#define STATE_SENDING_STOP 4
|
||||
#define STATE_DATA_ERROR 5
|
||||
#define STATE_SENDING_CMD11 6
|
||||
#define STATE_WAITING_CMD11_DONE 7
|
||||
rt_uint32_t state;
|
||||
#define EVENT_CMD_COMPLETE 0
|
||||
#define EVENT_XFER_COMPLETE 1
|
||||
#define EVENT_DATA_COMPLETE 2
|
||||
#define EVENT_DATA_ERROR 3
|
||||
rt_bitmap_t pending_events;
|
||||
|
||||
struct rt_mmcsd_req *req;
|
||||
struct rt_mmcsd_data *data;
|
||||
struct rt_mmcsd_cmd *cmd;
|
||||
struct rt_mmcsd_cmd stop_abort;
|
||||
rt_uint32_t prev_blksz;
|
||||
rt_uint8_t timing;
|
||||
|
||||
struct rt_clk *biu_clk;
|
||||
struct rt_clk *ciu_clk;
|
||||
|
||||
void *last_buf;
|
||||
rt_uint32_t last_remain;
|
||||
|
||||
int data_shift;
|
||||
rt_uint8_t part_buf_start;
|
||||
rt_uint8_t part_buf_count;
|
||||
union
|
||||
{
|
||||
rt_uint64_t part_buf;
|
||||
rt_uint16_t part_buf16;
|
||||
rt_uint32_t part_buf32;
|
||||
rt_uint64_t part_buf64;
|
||||
};
|
||||
void (*push_data)(struct sdio_dw *sd, void *buf, int cnt);
|
||||
void (*pull_data)(struct sdio_dw *sd, void *buf, int cnt);
|
||||
|
||||
/* DMA interface members */
|
||||
#define TRANS_MODE_PIO 0
|
||||
#define TRANS_MODE_IDMAC 1
|
||||
#define TRANS_MODE_EDMAC 2
|
||||
rt_bool_t use_dma;
|
||||
rt_bool_t using_dma;
|
||||
rt_bool_t dma_64bit_address;
|
||||
rt_size_t ring_size;
|
||||
void *dma_buf;
|
||||
rt_ubase_t dma_buf_phy;
|
||||
struct rt_dma_chan *edma_chan;
|
||||
const struct sdio_dw_dma_ops *dma_ops;
|
||||
|
||||
struct rt_timer cmd11_timer;
|
||||
struct rt_timer cto_timer;
|
||||
struct rt_timer dto_timer;
|
||||
|
||||
struct rt_reset_control *rstc;
|
||||
|
||||
struct sdio_dw_slot *slot;
|
||||
const struct sdio_dw_drv_data *drv_data;
|
||||
|
||||
struct rt_spinlock lock, irq_lock;
|
||||
};
|
||||
|
||||
/* DMA ops for Internal/External DMAC interface */
|
||||
struct sdio_dw_dma_ops
|
||||
{
|
||||
rt_err_t (*init)(struct sdio_dw *sd);
|
||||
rt_err_t (*start)(struct sdio_dw *sd);
|
||||
rt_err_t (*complete)(struct sdio_dw *sd);
|
||||
rt_err_t (*stop)(struct sdio_dw *sd);
|
||||
rt_err_t (*cleanup)(struct sdio_dw *sd);
|
||||
rt_err_t (*exit)(struct sdio_dw *sd);
|
||||
};
|
||||
|
||||
struct sdio_dw_slot
|
||||
{
|
||||
struct rt_mmcsd_host *host;
|
||||
struct sdio_dw *sd;
|
||||
|
||||
rt_uint32_t ctype;
|
||||
|
||||
struct rt_mmcsd_req *req;
|
||||
|
||||
rt_uint32_t clock;
|
||||
rt_uint32_t clk_old;
|
||||
|
||||
#define DW_MMC_CARD_PRESENT 0
|
||||
#define DW_MMC_CARD_NEED_INIT 1
|
||||
#define DW_MMC_CARD_NO_LOW_PWR 2
|
||||
#define DW_MMC_CARD_NO_USE_HOLD 3
|
||||
#define DW_MMC_CARD_NEEDS_POLL 4
|
||||
rt_bitmap_t flags;
|
||||
|
||||
int id;
|
||||
int sdio_id;
|
||||
};
|
||||
|
||||
struct sdio_dw_drv_data
|
||||
{
|
||||
rt_ubase_t *caps;
|
||||
rt_uint32_t num_caps;
|
||||
rt_uint32_t common_caps;
|
||||
|
||||
rt_err_t (*init)(struct sdio_dw *sd);
|
||||
rt_err_t (*set_iocfg)(struct sdio_dw *sd, struct rt_mmcsd_io_cfg *ios);
|
||||
rt_err_t (*parse_ofw)(struct sdio_dw *sd);
|
||||
rt_err_t (*execute_tuning)(struct sdio_dw_slot *slot, rt_uint32_t opcode);
|
||||
rt_err_t (*prepare_hs400_tuning)(struct sdio_dw *sd, struct rt_mmcsd_io_cfg *ios);
|
||||
rt_err_t (*switch_voltage)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *ios);
|
||||
rt_err_t (*set_data_timeout)(struct sdio_dw *sd, rt_uint32_t timeout_ns);
|
||||
rt_uint32_t (*get_drto_clks)(struct sdio_dw *sd);
|
||||
};
|
||||
|
||||
#define sdio_dw_writel(sd, reg, val) HWREG32((sd)->base + SDIO_DW_##reg) = (val)
|
||||
#define sdio_dw_writew(sd, reg, val) HWREG16((sd)->base + SDIO_DW_##reg) = (val)
|
||||
#define sdio_dw_writeb(sd, reg, val) HWREG8((sd)->base + SDIO_DW_##reg) = (val)
|
||||
|
||||
#define sdio_dw_readl(sd, reg) HWREG32((sd)->base + SDIO_DW_##reg)
|
||||
#define sdio_dw_readw(sd, reg) HWREG16((sd)->base + SDIO_DW_##reg)
|
||||
#define sdio_dw_readb(sd, reg) HWREG8((sd)->base + SDIO_DW_##reg)
|
||||
|
||||
#define sdio_dw_fifo_writew(sd, val) HWREG16((sd)->fifo_base) = (val)
|
||||
#define sdio_dw_fifo_writel(sd, val) HWREG32((sd)->fifo_base) = (val)
|
||||
#define sdio_dw_fifo_writeq(sd, val) HWREG64((sd)->fifo_base) = (val)
|
||||
|
||||
#define sdio_dw_fifo_readw(sd) HWREG16((sd)->fifo_base)
|
||||
#define sdio_dw_fifo_readl(sd) HWREG32((sd)->fifo_base)
|
||||
#define sdio_dw_fifo_readq(sd) HWREG64((sd)->fifo_base)
|
||||
|
||||
rt_err_t sdio_dw_probe(struct sdio_dw *sd);
|
||||
rt_err_t sdio_dw_remove(struct sdio_dw *sd);
|
||||
|
||||
#endif /* __SDIO_DW_H__ */
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-16 zhujiale first version
|
||||
*/
|
||||
|
||||
#ifndef _DRIVERS_MMC_RT_SDHCI_PLTFM_H
|
||||
#define _DRIVERS_MMC_RT_SDHCI_PLTFM_H
|
||||
#include <rtthread.h>
|
||||
#include <drivers/core/dm.h>
|
||||
#include <drivers/ofw.h>
|
||||
#include <drivers/platform.h>
|
||||
#include <drivers/clk.h>
|
||||
#include "sdhci.h"
|
||||
|
||||
struct rt_sdhci_pltfm_data
|
||||
{
|
||||
const struct rt_sdhci_ops *ops;
|
||||
unsigned int quirks;
|
||||
unsigned int quirks2;
|
||||
};
|
||||
|
||||
struct rt_sdhci_pltfm_host
|
||||
{
|
||||
struct rt_clk *clk;
|
||||
unsigned int clock;
|
||||
rt_uint64_t xfer_mode_shadow;
|
||||
|
||||
unsigned long private[];
|
||||
};
|
||||
void rt_sdhci_get_property(struct rt_platform_device *pdev);
|
||||
|
||||
static inline void sdhci_get_of_property(struct rt_platform_device *pdev)
|
||||
{
|
||||
return rt_sdhci_get_property(pdev);
|
||||
}
|
||||
extern struct rt_sdhci_host *rt_sdhci_pltfm_init(struct rt_platform_device *pdev,
|
||||
const struct rt_sdhci_pltfm_data *pdata,
|
||||
size_t priv_size);
|
||||
extern void rt_sdhci_pltfm_free(struct rt_platform_device *pdev);
|
||||
|
||||
extern int rt_sdhci_pltfm_init_and_add_host(struct rt_platform_device *pdev,
|
||||
const struct rt_sdhci_pltfm_data *pdata,
|
||||
size_t priv_size);
|
||||
extern void rt_sdhci_pltfm_remove(struct rt_platform_device *pdev);
|
||||
|
||||
extern unsigned int rt_sdhci_pltfm_clk_get_max_clock(struct rt_sdhci_host *host);
|
||||
|
||||
static inline void *sdhci_pltfm_priv(struct rt_sdhci_pltfm_host *host)
|
||||
{
|
||||
return host->private;
|
||||
}
|
||||
|
||||
static inline int sdhci_pltfm_suspend(struct rt_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int sdhci_pltfm_resume(struct rt_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-16 zhujiale first version
|
||||
*/
|
||||
#ifndef __RT_SDHCI_MMC_H__
|
||||
#define __RT_SDHCI_MMC_H__
|
||||
|
||||
#include <drivers/dev_mmcsd_core.h>
|
||||
#include <rtthread.h>
|
||||
#include <drivers/mmcsd_cmd.h>
|
||||
#include <drivers/dev_mmcsd_core.h>
|
||||
#include <drivers/mmcsd_host.h>
|
||||
#define mmc_dev(x) ((x)->parent)
|
||||
|
||||
#define MMC_SEND_TUNING_BLOCK_HS200 SEND_TUNING_BLOCK_HS200
|
||||
#define MMC_SEND_TUNING_BLOCK SEND_TUNING_BLOCK
|
||||
#define MMC_STOP_TRANSMISSION STOP_TRANSMISSION
|
||||
#define MMC_BUS_TEST_R 14 /* adtc R1 */
|
||||
#define MMC_WRITE_MULTIPLE_BLOCK WRITE_MULTIPLE_BLOCK
|
||||
#define MMC_READ_MULTIPLE_BLOCK READ_MULTIPLE_BLOCK
|
||||
|
||||
#define MMC_TIMING_UHS_DDR50 MMCSD_TIMING_UHS_DDR50
|
||||
#define MMC_TIMING_UHS_SDR50 MMCSD_TIMING_UHS_SDR50
|
||||
#define MMC_TIMING_MMC_HS200 MMCSD_TIMING_MMC_HS200
|
||||
#define MMC_TIMING_MMC_HS400 MMCSD_TIMING_MMC_HS400
|
||||
#define MMC_TIMING_UHS_SDR104 MMCSD_TIMING_UHS_SDR104
|
||||
#define MMC_TIMING_UHS_SDR25 MMCSD_TIMING_UHS_SDR25
|
||||
#define MMC_TIMING_MMC_DDR52 MMCSD_TIMING_MMC_DDR52
|
||||
#define MMC_TIMING_UHS_SDR12 MMCSD_TIMING_UHS_SDR12
|
||||
#define MMC_TIMING_SD_HS MMCSD_TIMING_SD_HS
|
||||
#define MMC_TIMING_MMC_HS MMCSD_TIMING_MMC_HS
|
||||
|
||||
#define MMC_POWER_OFF MMCSD_POWER_OFF
|
||||
#define MMC_POWER_UP MMCSD_POWER_UP
|
||||
#define MMC_POWER_ON MMCSD_POWER_ON
|
||||
#define MMC_POWER_UNDEFINED 3
|
||||
|
||||
#define MMC_SET_DRIVER_TYPE_B 0
|
||||
#define MMC_SET_DRIVER_TYPE_A 1
|
||||
#define MMC_SET_DRIVER_TYPE_C 2
|
||||
#define MMC_SET_DRIVER_TYPE_D 3
|
||||
|
||||
#define MMC_SIGNAL_VOLTAGE_330 0
|
||||
#define MMC_SIGNAL_VOLTAGE_180 1
|
||||
#define MMC_SIGNAL_VOLTAGE_120 2
|
||||
|
||||
#define MMC_RSP_PRESENT (1 << 16)
|
||||
#define MMC_RSP_136 (1 << 17) /* 136 bit response */
|
||||
#define MMC_RSP_CRC (1 << 18) /* expect valid crc */
|
||||
#define MMC_RSP_BUSY (1 << 19) /* card may send busy */
|
||||
#define MMC_RSP_OPCODE (1 << 20) /* response contains opcode */
|
||||
|
||||
#define MMC_RSP_NONE (0)
|
||||
#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
|
||||
#define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
|
||||
#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
|
||||
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
|
||||
#define MMC_RSP_R4 (MMC_RSP_PRESENT)
|
||||
#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
|
||||
#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
|
||||
#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
|
||||
|
||||
#define MMC_CMD_ADTC CMD_ADTC
|
||||
|
||||
#define MMC_BUS_WIDTH_8 MMCSD_BUS_WIDTH_8
|
||||
#define MMC_BUS_WIDTH_4 MMCSD_BUS_WIDTH_4
|
||||
#define MMC_BUS_WIDTH_1 MMCSD_BUS_WIDTH_1
|
||||
|
||||
#define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */
|
||||
#define MMC_PM_WAKE_SDIO_IRQ (1 << 1) /* wake up host system on SDIO IRQ assertion */
|
||||
enum mmc_blk_status
|
||||
{
|
||||
MMC_BLK_SUCCESS = 0,
|
||||
MMC_BLK_PARTIAL,
|
||||
MMC_BLK_CMD_ERR,
|
||||
MMC_BLK_RETRY,
|
||||
MMC_BLK_ABORT,
|
||||
MMC_BLK_DATA_ERR,
|
||||
MMC_BLK_ECC_ERR,
|
||||
MMC_BLK_NOMEDIUM,
|
||||
MMC_BLK_NEW_REQUEST,
|
||||
};
|
||||
|
||||
#define MMC_NUM_CLK_PHASES (MMC_TIMING_MMC_HS400 + 1)
|
||||
|
||||
struct rt_mmc_host ;
|
||||
|
||||
struct mmc_host_ops
|
||||
{
|
||||
void (*request)(struct rt_mmc_host *host, struct rt_mmcsd_req *req);
|
||||
void (*set_ios)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios);
|
||||
int (*get_ro)(struct rt_mmc_host *host);
|
||||
int (*get_cd)(struct rt_mmc_host *host);
|
||||
void (*enable_sdio_irq)(struct rt_mmc_host *host, int enable);
|
||||
void (*ack_sdio_irq)(struct rt_mmc_host *host);
|
||||
int (*start_signal_voltage_switch)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios);
|
||||
int (*card_busy)(struct rt_mmc_host *host);
|
||||
int (*execute_tuning)(struct rt_mmc_host *host, unsigned opcode);
|
||||
int (*prepare_hs400_tuning)(struct rt_mmc_host *host, struct rt_mmcsd_io_cfg *ios);
|
||||
int (*hs400_prepare_ddr)(struct rt_mmc_host *host);
|
||||
void (*hs400_downgrade)(struct rt_mmc_host *host);
|
||||
void (*hs400_complete)(struct rt_mmc_host *host);
|
||||
void (*hs400_enhanced_strobe)(struct rt_mmc_host *host,
|
||||
struct rt_mmcsd_io_cfg* ios);
|
||||
void (*hw_reset)(struct rt_mmc_host* host);
|
||||
void (*card_event)(struct rt_mmc_host* host);
|
||||
};
|
||||
|
||||
struct regulator;
|
||||
struct mmc_pwrseq;
|
||||
|
||||
struct mmc_supply
|
||||
{
|
||||
struct regulator *vmmc; /* Card power supply */
|
||||
struct regulator *vqmmc; /* Optional Vccq supply */
|
||||
};
|
||||
|
||||
struct mmc_ctx
|
||||
{
|
||||
struct task_struct *task;
|
||||
};
|
||||
|
||||
/* VDD voltage 3.3 ~ 3.4 */
|
||||
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
|
||||
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
|
||||
|
||||
#define MMC_CAP2_HS200_1_8V_SDR MMCSD_SUP_HS200_1V8
|
||||
#define MMC_CAP_4_BIT_DATA MMCSD_BUSWIDTH_4
|
||||
#define MMC_CAP_8_BIT_DATA MMCSD_BUSWIDTH_8
|
||||
#define MMC_CAP2_HS200 MMCSD_SUP_HS200
|
||||
#define MMC_CAP_MMC_HIGHSPEED MMCSD_SUP_HIGHSPEED
|
||||
#define MMC_CAP_SD_HIGHSPEED MMCSD_SUP_HIGHSPEED
|
||||
#define MMC_CAP_1_8V_DDR MMCSD_SUP_DDR_1V8
|
||||
#define MMC_CAP_3_3V_DDR MMCSD_SUP_DDR_3V3
|
||||
#define MMC_CAP_1_2V_DDR MMCSD_SUP_DDR_1V2
|
||||
#define MMC_CAP_NONREMOVABLE MMCSD_SUP_NONREMOVABLE
|
||||
|
||||
|
||||
#define MMC_CAP_UHS_DDR50 0
|
||||
#define MMC_CAP2_HS400 0
|
||||
#define MMC_CAP_UHS_SDR50 0
|
||||
#define MMC_CAP_UHS_SDR25 0
|
||||
#define MMC_CAP_UHS_SDR12 0
|
||||
#define MMC_CAP_UHS_SDR104 0
|
||||
#define MMC_CAP_UHS 0
|
||||
#define MMC_CAP2_HSX00_1_8V 0
|
||||
#define MMC_CAP2_HS400_ES 0
|
||||
#define MMC_CAP_NEEDS_POLL 0
|
||||
#define MMC_CAP2_HSX00_1_2V 0
|
||||
#define MMC_CAP2_HS400_1_8V 0
|
||||
#define MMC_CAP_DRIVER_TYPE_D 0
|
||||
#define MMC_CAP_DRIVER_TYPE_C 0
|
||||
#define MMC_SET_DRIVER_TYPE_B 0
|
||||
#define MMC_CAP_DRIVER_TYPE_A 0
|
||||
#define MMC_CAP2_SDIO_IRQ_NOTHREAD 0
|
||||
#define MMC_CAP_CMD23 0
|
||||
#define MMC_CAP_SDIO_IRQ 0
|
||||
|
||||
#define MMC_CAP2_NO_SDIO (1 << 19)
|
||||
#define MMC_CAP2_NO_SD (1 << 21)
|
||||
#define MMC_CAP2_NO_MMC (1 << 22)
|
||||
#define MMC_CAP2_CQE (1 << 23)
|
||||
|
||||
#define MMC_VDD_165_195 VDD_165_195
|
||||
#define MMC_VDD_20_21 VDD_20_21
|
||||
#define MMC_VDD_29_30 VDD_29_30
|
||||
#define MMC_VDD_30_31 VDD_30_31
|
||||
#define MMC_VDD_32_33 VDD_32_33
|
||||
#define MMC_VDD_33_34 VDD_33_34
|
||||
|
||||
|
||||
struct rt_mmc_host
|
||||
{
|
||||
struct rt_mmcsd_host rthost;
|
||||
struct rt_device *parent;
|
||||
int index;
|
||||
const struct mmc_host_ops *ops;
|
||||
unsigned int f_min;
|
||||
unsigned int f_max;
|
||||
unsigned int f_init;
|
||||
rt_uint32_t ocr_avail;
|
||||
rt_uint32_t ocr_avail_sdio; /* SDIO-specific OCR */
|
||||
rt_uint32_t ocr_avail_sd; /* SD-specific OCR */
|
||||
rt_uint32_t ocr_avail_mmc; /* MMC-specific OCR */
|
||||
struct wakeup_source *ws; /* Enable consume of uevents */
|
||||
rt_uint32_t max_current_330;
|
||||
rt_uint32_t max_current_300;
|
||||
rt_uint32_t max_current_180;
|
||||
rt_uint32_t caps; /* Host capabilities */
|
||||
|
||||
rt_uint32_t caps2; /* More host capabilities */
|
||||
|
||||
|
||||
/* host specific block data */
|
||||
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
|
||||
unsigned short max_segs; /* see blk_queue_max_segments */
|
||||
unsigned short unused;
|
||||
unsigned int max_req_size; /* maximum number of bytes in one req */
|
||||
unsigned int max_blk_size; /* maximum size of one mmc block */
|
||||
unsigned int max_blk_count; /* maximum number of blocks in one req */
|
||||
unsigned int max_busy_timeout; /* max busy timeout in ms */
|
||||
struct rt_mmcsd_io_cfg ios; /* current io bus settings */
|
||||
unsigned int retune_period;
|
||||
/* group bitfields together to minimize padding */
|
||||
unsigned int use_spi_crc : 1;
|
||||
unsigned int claimed : 1; /* host exclusively claimed */
|
||||
unsigned int doing_init_tune : 1; /* initial tuning in progress */
|
||||
unsigned int can_retune : 1; /* re-tuning can be used */
|
||||
unsigned int doing_retune : 1; /* re-tuning in progress */
|
||||
unsigned int retune_now : 1; /* do re-tuning at next req */
|
||||
unsigned int retune_paused : 1; /* re-tuning is temporarily disabled */
|
||||
unsigned int retune_crc_disable : 1; /* don't trigger retune upon crc */
|
||||
unsigned int can_dma_map_merge : 1; /* merging can be used */
|
||||
unsigned int vqmmc_enabled : 1; /* vqmmc regulator is enabled */
|
||||
|
||||
int need_retune; /* re-tuning is needed */
|
||||
int hold_retune; /* hold off re-tuning */
|
||||
rt_bool_t trigger_card_event; /* card_event necessary */
|
||||
unsigned int sdio_irqs;
|
||||
rt_bool_t sdio_irq_pending;
|
||||
|
||||
struct led_trigger *led; /* activity led */
|
||||
|
||||
struct mmc_supply supply;
|
||||
|
||||
|
||||
/* Ongoing data transfer that allows commands during transfer */
|
||||
struct rt_mmcsd_req *ongoing_mrq;
|
||||
|
||||
|
||||
unsigned int actual_clock; /* Actual HC clock rate */
|
||||
rt_uint32_t pm_caps;
|
||||
unsigned long private[];
|
||||
};
|
||||
|
||||
|
||||
static inline int mmc_card_is_removable(struct rt_mmc_host *host)
|
||||
{
|
||||
return !(host->caps & MMC_CAP_NONREMOVABLE);
|
||||
}
|
||||
|
||||
struct device_node;
|
||||
struct rt_mmc_host *rt_mmc_alloc_host(int extra, struct rt_device *);
|
||||
int rt_mmc_add_host(struct rt_mmc_host *);
|
||||
void rt_mmc_remove_host(struct rt_mmc_host *);
|
||||
void rt_mmc_free_host(struct rt_mmc_host *);
|
||||
int rt_mmc_of_parse(struct rt_mmc_host *host);
|
||||
int rt_mmc_of_parse_voltage(struct rt_mmc_host *host, rt_uint32_t *mask);
|
||||
|
||||
static inline void *mmc_priv(struct rt_mmc_host *host)
|
||||
{
|
||||
return (void *)host->private;
|
||||
}
|
||||
|
||||
|
||||
#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI)
|
||||
|
||||
#define mmc_dev(x) ((x)->parent)
|
||||
#define mmc_classdev(x) (&(x)->class_dev)
|
||||
#define mmc_hostname(x) (x->parent->parent.name)
|
||||
|
||||
void rt_mmc_detect_change(struct rt_mmc_host *, unsigned long delay);
|
||||
void rt_mmc_request_done(struct rt_mmc_host *, struct rt_mmcsd_req *);
|
||||
void mmc_command_done(struct rt_mmc_host *host, struct rt_mmcsd_req *mrq);
|
||||
|
||||
void mmc_cqe_request_done(struct rt_mmc_host *host, struct rt_mmcsd_req *mrq);
|
||||
|
||||
static inline rt_bool_t sdio_irq_claimed(struct rt_mmc_host *host)
|
||||
{
|
||||
return host->sdio_irqs > 0;
|
||||
}
|
||||
|
||||
static inline int mmc_regulator_set_ocr(struct rt_mmc_host *mmc,
|
||||
struct regulator *supply,
|
||||
unsigned short vdd_bit)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_regulator_get_supply(struct rt_mmc_host *mmc);
|
||||
int mmc_regulator_enable_vqmmc(struct rt_mmc_host *mmc);
|
||||
void mmc_regulator_disable_vqmmc(struct rt_mmc_host *mmc);
|
||||
|
||||
void mmc_retune_timer_stop(struct rt_mmc_host* host);
|
||||
|
||||
enum dma_data_direction
|
||||
{
|
||||
DMA_BIDIRECTIONAL = 0,
|
||||
DMA_TO_DEVICE = 1,
|
||||
DMA_FROM_DEVICE = 2,
|
||||
DMA_NONE = 3,
|
||||
};
|
||||
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL << (n)) - 1))
|
||||
static inline void mmc_retune_needed(struct rt_mmc_host *host)
|
||||
{
|
||||
if (host->can_retune)
|
||||
host->need_retune = 1;
|
||||
}
|
||||
|
||||
static inline rt_bool_t mmc_can_retune(struct rt_mmc_host *host)
|
||||
{
|
||||
return host->can_retune == 1;
|
||||
}
|
||||
|
||||
static inline rt_bool_t mmc_doing_retune(struct rt_mmc_host *host)
|
||||
{
|
||||
return host->doing_retune == 1;
|
||||
}
|
||||
|
||||
static inline rt_bool_t mmc_doing_tune(struct rt_mmc_host *host)
|
||||
{
|
||||
return host->doing_retune == 1 || host->doing_init_tune == 1;
|
||||
}
|
||||
|
||||
static inline int mmc_get_dma_dir(struct rt_mmcsd_data *data)
|
||||
{
|
||||
return data->flags & DATA_DIR_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
}
|
||||
|
||||
static inline rt_bool_t mmc_op_multi(rt_uint32_t opcode)
|
||||
{
|
||||
return opcode == MMC_WRITE_MULTIPLE_BLOCK || opcode == MMC_READ_MULTIPLE_BLOCK;
|
||||
}
|
||||
|
||||
static inline rt_bool_t mmc_op_tuning(rt_uint32_t opcode)
|
||||
{
|
||||
return opcode == MMC_SEND_TUNING_BLOCK || opcode == MMC_SEND_TUNING_BLOCK_HS200;
|
||||
}
|
||||
|
||||
int rt_mmc_gpio_get_cd(struct rt_mmc_host *host);
|
||||
void rt_mmc_detect_change(struct rt_mmc_host *host, unsigned long delay);
|
||||
int rt_mmc_regulator_set_vqmmc(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios);
|
||||
rt_bool_t rt_mmc_can_gpio_ro(struct rt_mmc_host *host);
|
||||
int rt_mmc_gpio_get_ro(struct rt_mmc_host *host);
|
||||
|
||||
int rt_mmc_send_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode);
|
||||
int rt_mmc_of_parse(struct rt_mmc_host *host);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-16 zhujiale first version
|
||||
*/
|
||||
#ifndef __RT_SDHCI_MISC_H__
|
||||
#define __RT_SDHCI_MISC_H__
|
||||
|
||||
|
||||
#define __BF_FIELD_CHECK(...)
|
||||
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
|
||||
#define FIELD_GET(_mask, _reg) \
|
||||
({ \
|
||||
__BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \
|
||||
(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
|
||||
})
|
||||
|
||||
#define FIELD_PREP(_mask, _val) \
|
||||
({ \
|
||||
__BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \
|
||||
((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
|
||||
})
|
||||
|
||||
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||
|
||||
#define min_t(type, x, y) (((type)x < (type)y) ? x : y)
|
||||
#define max_t(type, x, y) (((type)x > (type)y) ? x : y)
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
#define from_timer(var, callback_timer, timer_fieldname) \
|
||||
container_of(callback_timer, typeof(*var), timer_fieldname)
|
||||
|
||||
|
||||
#define le32_to_cpu(x) (x)
|
||||
#define le16_to_cpu(x) (x)
|
||||
#define cpu_to_le16(x) (x)
|
||||
#define cpu_to_le32(x) (x)
|
||||
#define lower_32_bits(n) ((rt_uint32_t)((n) & 0xffffffff))
|
||||
#define upper_32_bits(n) ((rt_uint32_t)(((n) >> 16) >> 16))
|
||||
|
||||
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||
|
||||
#define do_div(n, base) ({ \
|
||||
uint32_t __base = (base); \
|
||||
uint32_t __rem; \
|
||||
__rem = ((uint64_t)(n)) % __base; \
|
||||
(n) = ((uint64_t)(n)) / __base; \
|
||||
__rem; \
|
||||
})
|
||||
|
||||
#define fallthrough \
|
||||
do { \
|
||||
} while (0)
|
||||
|
||||
int regulator_is_supported_voltage(struct regulator *regulator,
|
||||
int min_uV, int max_uV);
|
||||
rt_bool_t rt_mmc_can_gpio_cd(struct rt_mmc_host *host);
|
||||
|
||||
struct regulator
|
||||
{
|
||||
const char *supply_name;
|
||||
};
|
||||
|
||||
int regulator_get_current_limit(struct regulator *regulator);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user