Files
efinix-linux/drivers/mmc/host/efx_sdio.h
Swee Aun Khor 334eb3ba15 Add a new SDIO controller driver for Efinix devices
The driver supports UHS-I bus speed modes: SDR25, DDR50, and SDR104.
By default, the controller operates in SDR25 mode. Higher-speed modes
can be enabled via the Device Tree by adding the following properties
to the SDIO node:

  - sd-uhs-ddr50
  - sd-uhs-sdr104

When these properties are present, the driver negotiates the highest
supported UHS mode with the card and host.

Signed-off-by: Swee Aun Khor <sakhor@efinixinc.com>
2026-08-09 22:44:47 -07:00

386 lines
14 KiB
C

/* 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 <sakhor@efinixinc.com>
*/
#ifndef __EFX_SDIO_H__
#define __EFX_SDIO_H__
#include <linux/types.h>
#include <linux/mmc/host.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
/* 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__ */