[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:
GUI
2025-12-26 21:04:42 +08:00
committed by GitHub
parent 71d802c415
commit c6498b5f65
29 changed files with 7111 additions and 1813 deletions

View File

@@ -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)

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View 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__ */

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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')

View File

@@ -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;

View 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;
}
}

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View 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);
}

View 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__ */

View 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;
}

View 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 */

View 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__ */

View 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"

View 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')

View 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);

View 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);

View 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);

View 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__ */

File diff suppressed because it is too large Load Diff

View 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__ */

View File

@@ -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

View File

@@ -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

View File

@@ -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