/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Efinix SDIO Host Controller Driver Header with DMA Support * * Copyright (C) 2026 Efinix, Inc. * Author: Khor Swee Aun */ #ifndef __EFX_SDIO_H__ #define __EFX_SDIO_H__ #include #include #include #include #include #include /* Compatibility macros */ #ifndef min3 #define min3(x, y, z) min(min(x, y), z) #endif /* ADMA descriptor definitions */ #define EFX_ADMA_DESC_VALID BIT(0) #define EFX_ADMA_DESC_END BIT(1) #define EFX_ADMA_DESC_INT BIT(2) #define EFX_ADMA_DESC_NOP (0 << 4) #define EFX_ADMA_DESC_TRAN (2 << 4) #define EFX_ADMA_DESC_LINK (3 << 4) #define EFX_ADMA_MAX_LEN 65536 #define EFX_ADMA_DESC_ALIGN 8 #define EFX_ADMA_TABLE_SZ (512 * 8) /* Support up to 512 descriptors */ /* DMA boundary sizes */ #define EFX_DMA_BOUNDARY_4K 0 #define EFX_DMA_BOUNDARY_8K 1 #define EFX_DMA_BOUNDARY_16K 2 #define EFX_DMA_BOUNDARY_32K 3 #define EFX_DMA_BOUNDARY_64K 4 #define EFX_DMA_BOUNDARY_128K 5 #define EFX_DMA_BOUNDARY_256K 6 #define EFX_DMA_BOUNDARY_512K 7 /* SDIO IP Register Offsets - Efinix SDIO Controller */ #define EFX_SDIO_VERSION 0x000 #define EFX_SDIO_BASE_REG0 0x004 #define EFX_SDIO_BASE_STATUS_REG0 0x008 #define EFX_SDIO_BASE_REG1 0x00C #define EFX_SDIO_ARG2 0x100 #define EFX_SDIO_BLOCK_SIZE 0x104 #define EFX_SDIO_ARG1 0x108 #define EFX_SDIO_TRANSFER_MODE 0x10C #define EFX_SDIO_RESPONSE0 0x110 #define EFX_SDIO_RESPONSE1 0x114 #define EFX_SDIO_RESPONSE2 0x118 #define EFX_SDIO_RESPONSE3 0x11C #define EFX_SDIO_BUFFER_DATA_PORT 0x120 #define EFX_SDIO_PRESENT_STATE 0x124 #define EFX_SDIO_HOST_CONTROL 0x128 #define EFX_SDIO_INT_STATUS 0x130 #define EFX_SDIO_INT_STATUS_EN 0x134 #define EFX_SDIO_INT_SIGNAL_EN 0x138 #define EFX_SDIO_HOST_CAPABILITIES 0x140 #define EFX_SDIO_HOST_ADJUSTMENT 0x144 #define EFX_SDIO_ADMA_SYS_ADDR_LOW 0x158 #define EFX_SDIO_ADMA_SYS_ADDR_HIGH 0x15C /* System Register Offsets */ #define EFX_SYS_DATE_REG 0x000 #define EFX_SYS_TEST_REG 0x004 #define EFX_SYS_RESET_REG 0x008 /* Base Register 0 (0x004) */ #define EFX_SDIO_BASE_REG0_CLK_EN BIT(16) #define EFX_SDIO_BASE_REG0_CLK_DIV_MASK 0xFFFF /* Base Status Register 0 (0x008) */ #define EFX_SDIO_BASE_STATUS_DAT_BUSY BIT(1) #define EFX_SDIO_BASE_STATUS_CMD_BUSY BIT(0) /* Base Register 1 (0x00C) */ #define EFX_SDIO_BASE_REG1_SAMPLE_CNT_SHIFT 16 #define EFX_SDIO_BASE_REG1_SAMPLE_CNT_MASK (0xFFFF << 16) #define EFX_SDIO_BASE_REG1_PHASE_SHIFT 6 #define EFX_SDIO_BASE_REG1_PHASE_MASK (0x7 << 6) #define EFX_SDIO_BASE_REG1_PHASE_PULSE BIT(0) /* Block Size Register (0x104) */ #define EFX_SDIO_BLOCK_COUNT_SHIFT 16 #define EFX_SDIO_BLOCK_COUNT_MASK (0xFFFF << 16) #define EFX_SDIO_BLOCK_SIZE_MASK 0xFFF #define EFX_SDIO_DMA_BOUNDARY_SHIFT 12 #define EFX_SDIO_DMA_BOUNDARY_MASK (0x7 << 12) /* Transfer Mode Register (0x10C) */ #define EFX_SDIO_CMD_INDEX_SHIFT 24 #define EFX_SDIO_CMD_INDEX_MASK (0x3F << 24) #define EFX_SDIO_DATA_PRESENT BIT(21) #define EFX_SDIO_CMD_INDEX_CHECK_EN BIT(20) #define EFX_SDIO_CMD_CRC_CHECK_EN BIT(19) #define EFX_SDIO_RESP_TYPE_SHIFT 16 #define EFX_SDIO_RESP_TYPE_MASK (0x3 << 16) #define EFX_SDIO_RESP_TYPE_NONE 0 #define EFX_SDIO_RESP_TYPE_136 1 #define EFX_SDIO_RESP_TYPE_48 2 #define EFX_SDIO_RESP_TYPE_48_BUSY 3 #define EFX_SDIO_MULTI_BLOCK_SEL BIT(5) #define EFX_SDIO_DATA_XFER_DIR BIT(4) #define EFX_SDIO_AUTO_CMD_EN_SHIFT 2 #define EFX_SDIO_AUTO_CMD_EN_MASK (0x3 << 2) #define EFX_SDIO_BLOCK_COUNT_EN BIT(1) #define EFX_SDIO_DMA_EN BIT(0) /* Present State Register (0x124) */ #define EFX_SDIO_DAT_0_SIG_LVL BIT(20) #define EFX_SDIO_BUFFER_READ_EN BIT(11) #define EFX_SDIO_BUFFER_WRITE_EN BIT(10) #define EFX_SDIO_READ_XFER_ACTIVE BIT(9) #define EFX_SDIO_WRITE_XFER_ACTIVE BIT(8) #define EFX_SDIO_DAT_LINE_ACTIVE BIT(2) #define EFX_SDIO_CMD_INHIBIT_DAT BIT(1) #define EFX_SDIO_CMD_INHIBIT_CMD BIT(0) /* Host Control Register (0x128) */ #define EFX_SDIO_DATA_SAMPLING_MODE BIT(3) #define EFX_SDIO_DATA_WIDTH_SHIFT 1 #define EFX_SDIO_DATA_WIDTH_MASK (0x3 << 1) #define EFX_SDIO_DATA_WIDTH_1BIT 0 #define EFX_SDIO_DATA_WIDTH_4BIT 1 #define EFX_SDIO_DATA_WIDTH_8BIT 2 /* Interrupt Status Register bits */ #define EFX_SDIO_INT_ADMA_ERROR BIT(25) #define EFX_SDIO_INT_DATA_TIMEOUT_ERR BIT(22) #define EFX_SDIO_INT_DATA_CRC_ERR BIT(21) #define EFX_SDIO_INT_DATA_END_BIT_ERR BIT(20) #define EFX_SDIO_INT_CMD_INDEX_ERR BIT(19) #define EFX_SDIO_INT_CMD_END_BIT_ERR BIT(18) #define EFX_SDIO_INT_CMD_CRC_ERR BIT(17) #define EFX_SDIO_INT_CMD_TIMEOUT_ERR BIT(16) #define EFX_SDIO_INT_CARD BIT(8) #define EFX_SDIO_INT_BUFFER_READ_RDY BIT(5) #define EFX_SDIO_INT_BUFFER_WRITE_RDY BIT(4) #define EFX_SDIO_INT_DMA_INTERRUPT BIT(3) #define EFX_SDIO_INT_BLOCK_GAP_EVENT BIT(2) #define EFX_SDIO_INT_XFER_COMPLETE BIT(1) #define EFX_SDIO_INT_CMD_COMPLETE BIT(0) #define EFX_SDIO_INT_ERROR_MASK (EFX_SDIO_INT_ADMA_ERROR | \ EFX_SDIO_INT_DATA_TIMEOUT_ERR | \ EFX_SDIO_INT_DATA_CRC_ERR | \ EFX_SDIO_INT_DATA_END_BIT_ERR | \ EFX_SDIO_INT_CMD_INDEX_ERR | \ EFX_SDIO_INT_CMD_END_BIT_ERR | \ EFX_SDIO_INT_CMD_CRC_ERR | \ EFX_SDIO_INT_CMD_TIMEOUT_ERR) /* SDIO Ccard interrupt not included in ALL_MASK as it is handled separately * by mmc core during SDIO IO driver initialization */ #define EFX_SDIO_INT_ALL_MASK (EFX_SDIO_INT_ERROR_MASK | \ EFX_SDIO_INT_BUFFER_READ_RDY | \ EFX_SDIO_INT_BUFFER_WRITE_RDY | \ EFX_SDIO_INT_DMA_INTERRUPT | \ EFX_SDIO_INT_BLOCK_GAP_EVENT | \ EFX_SDIO_INT_XFER_COMPLETE | \ EFX_SDIO_INT_CMD_COMPLETE) /* System Reset Register bits */ #define EFX_SYS_RESET_SDIO_DEV BIT(3) #define EFX_SYS_RESET_SDIO_IP BIT(2) /* Host capabilities */ #define EFX_SDIO_BASE_CLK_FREQ_MHZ 200 #define EFX_SDIO_MAX_BLOCK_LENGTH 512 #define EFX_SDIO_TIMEOUT_CLK_FREQ 200000000 #define EFX_SDIO_IO_VOLTAGE_1_8V 0 #define EFX_SDIO_IO_VOLTAGE_3_3V 1 /* Driver constants */ #define EFX_SDIO_MIN_FREQ 400000 /* 400 KHz */ #define EFX_SDIO_MAX_FREQ 200000000 /* 200 MHz */ #define EFX_SDIO_PIO_TIMEOUT_MS 1000 /* Hardware specific constants from documentation */ #define EFX_SDIO_CLOCK_STABILIZE_DELAY 1000 /* 1ms + 74 clock cycles */ #define EFX_SDIO_RESET_PULSE_WIDTH 1 /* 1us minimum */ #define EFX_SDIO_POST_RESET_DELAY 200 /* 200us minimum */ #define EFX_SDIO_CMD_RETRY_COUNT 3 /* Command retry attempts */ /* Tuning algorithm constants */ #define EFX_SDIO_MAX_PLL_SHIFT 8 /* 8 phase positions (45°) */ #define EFX_SDIO_PLL_SETTLING_TIME 50 /* 50ms PLL settling time */ #define EFX_SDIO_TUNING_TIMEOUT_MS 50 /* CMD19 timeout */ #define EFX_SDIO_TUNING_POLL_INTERVAL 200 /* 200us polling interval */ #define EFX_SDIO_TUNING_BLOCK_SIZE_4BIT 64 /* 4-bit bus tuning block */ #define EFX_SDIO_TUNING_BLOCK_SIZE_8BIT 128 /* 8-bit bus tuning block */ #define EFX_SDIO_MIN_TIMING_MARGIN 1 /* Min consecutive valid */ /** * struct efx_adma_desc - ADMA descriptor structure * @attr: Descriptor attributes (valid, end, interrupt, type) * @len: Data length for this descriptor * @addr: 32-bit DMA address * * Hardware ADMA descriptor structure, must be 8-byte aligned */ struct efx_adma_desc { u16 attr; u16 len; u32 addr; } __packed __aligned(8); /** * struct efx_sdio_host - Efinix SDIO host controller instance * @mmc: MMC host structure * @ioaddr: Base address for SDIO registers * @sys_ioaddr: Base address for system registers * @clk: Controller clock * @irq: Interrupt number * @mrq: Current MMC request * @cmd: Current MMC command * @data: Current MMC data transfer * @base_clk: Base clock frequency * @current_clk: Current configured clock frequency * @bytes_to_transfer: Remaining bytes for PIO transfer * @blocks_done: Number of completed blocks * @sg_offset: Current offset in scatter-gather list * @adma_desc: ADMA descriptor table * @adma_desc_dma: DMA address of descriptor table * @adma_desc_sz: Size of descriptor table * @bounce_buffer: Bounce buffer for unaligned transfers * @bounce_dma: DMA address of bounce buffer * @bounce_buffer_size: Size of bounce buffer * @use_dma: Flag indicating DMA mode is active * @dma_64bit: Flag indicating 64-bit DMA support * @clk_div: Current clock divider value * @optimal_sample_count: Optimal sample count from tuning * @optimal_pll_shift: Optimal PLL shift from tuning * @optimal_margin: Timing margin from tuning * @tuning_done: Flag indicating tuning completion * @tuning_in_progress: Flag indicating active tuning * @prev_timing: Previous timing mode * @hs400_retune_pending: Flag indicating HS400 retune needed * @hs400_retune_work: Delayed work for HS400 retuning * @tuned_timing_modes: Bitmap of successfully tuned timing modes * @lock: Spinlock for protecting shared data * @pdev: Platform device */ struct efx_sdio_host { struct mmc_host *mmc; void __iomem *ioaddr; void __iomem *sys_ioaddr; struct clk *clk; int irq; u32 io_voltage; struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; u32 base_clk; u32 current_clk; /* Transfer state tracking */ unsigned int bytes_to_transfer; unsigned int blocks_done; unsigned int sg_offset; /* DMA related fields */ struct efx_adma_desc *adma_desc; dma_addr_t adma_desc_dma; size_t adma_desc_sz; void *bounce_buffer; dma_addr_t bounce_dma; unsigned int bounce_buffer_size; bool use_bounce; bool use_dma; bool dma_64bit; /* Tuning related fields */ u32 clk_div; u32 optimal_sample_count; u32 optimal_pll_shift; u32 optimal_margin; bool tuning_done; bool tuning_in_progress; unsigned int prev_timing; bool hs400_retune_pending; bool tuning_crc_error; struct delayed_work hs400_retune_work; /* Tuning state bitmap - tracks which timing modes have been tuned */ unsigned long tuned_timing_modes; spinlock_t lock; struct platform_device *pdev; }; /* Debug macros */ #define efx_sdio_dbg_irq(host, fmt, ...) \ dev_dbg(&(host)->pdev->dev, fmt, ##__VA_ARGS__) #define efx_sdio_dbg_pio(host, fmt, ...) \ dev_dbg(&(host)->pdev->dev, fmt, ##__VA_ARGS__) #define efx_sdio_dbg_cmd(host, fmt, ...) \ dev_dbg(&(host)->pdev->dev, fmt, ##__VA_ARGS__) /* Platform driver function prototypes */ int efx_sdio_probe(struct platform_device *pdev); int efx_sdio_remove(struct platform_device *pdev); int efx_sdio_init_hw(struct efx_sdio_host *host); void efx_sdio_reset_hw(struct efx_sdio_host *host); void efx_sdio_hs400_retune_work(struct work_struct *work); /* Core MMC host operation prototypes */ void efx_sdio_request(struct mmc_host *mmc, struct mmc_request *mrq); void efx_sdio_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); int efx_sdio_get_cd(struct mmc_host *mmc); int efx_sdio_card_busy_wrapper(struct mmc_host *mmc); int efx_sdio_get_ro(struct mmc_host *mmc); irqreturn_t efx_sdio_irq(int irq, void *dev_id); void efx_sdio_enable_sdio_irq(struct mmc_host *host, int enable); void efx_sdio_ack_sdio_irq(struct mmc_host *host); int efx_sdio_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios); /* Core helper function prototypes */ void efx_sdio_send_command(struct efx_sdio_host *host, struct mmc_command *cmd); void efx_sdio_finish_request(struct efx_sdio_host *host, struct mmc_request *mrq); void efx_sdio_finish_command(struct efx_sdio_host *host); void efx_sdio_finish_data(struct efx_sdio_host *host); void efx_sdio_transfer_pio(struct efx_sdio_host *host); void efx_sdio_set_clock(struct efx_sdio_host *host, unsigned int clock); void efx_sdio_set_bus_width(struct efx_sdio_host *host, int width); void efx_sdio_set_timing(struct efx_sdio_host *host, unsigned int timing); bool efx_sdio_card_busy(struct efx_sdio_host *host); /* DMA function prototypes */ int efx_sdio_adma_table_pre(struct efx_sdio_host *host, struct mmc_data *data); void efx_sdio_adma_table_post(struct efx_sdio_host *host, struct mmc_data *data); void efx_sdio_prepare_dma(struct efx_sdio_host *host, struct mmc_data *data); void efx_sdio_cleanup_dma(struct efx_sdio_host *host, struct mmc_data *data); void efx_sdio_set_adma_addr(struct efx_sdio_host *host, dma_addr_t addr); /* Tuning function prototypes */ int efx_sdio_execute_tuning(struct mmc_host *mmc, u32 opcode); int efx_sdio_execute_tuning_command(struct efx_sdio_host *host, int bus_width); int efx_sdio_execute_custom_tuning_command(struct efx_sdio_host *host, int bus_width); void efx_sdio_set_timing_config(struct efx_sdio_host *host, u32 sample_count, u32 pll_shift); int efx_sdio_find_optimal_timing(struct efx_sdio_host *host, u8 result_map[][EFX_SDIO_MAX_PLL_SHIFT], u32 max_sample_count); /* Register access helpers */ static inline u32 efx_sdio_readl(struct efx_sdio_host *host, u32 reg) { return readl(host->ioaddr + reg); } static inline void efx_sdio_writel(struct efx_sdio_host *host, u32 val, u32 reg) { writel(val, host->ioaddr + reg); } static inline u32 efx_sdio_sys_readl(struct efx_sdio_host *host, u32 reg) { return readl(host->sys_ioaddr + reg); } static inline void efx_sdio_sys_writel(struct efx_sdio_host *host, u32 val, u32 reg) { writel(val, host->sys_ioaddr + reg); } #endif /* __EFX_SDIO_H__ */