diff options
Diffstat (limited to 'drivers/mci/sdhci.h')
-rw-r--r-- | drivers/mci/sdhci.h | 369 |
1 files changed, 284 insertions, 85 deletions
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h index 90595e6433..5de85239b1 100644 --- a/drivers/mci/sdhci.h +++ b/drivers/mci/sdhci.h @@ -1,6 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef __MCI_SDHCI_H #define __MCI_SDHCI_H +#include <pbl.h> +#include <dma.h> +#include <linux/iopoll.h> +#include <linux/sizes.h> + #define SDHCI_DMA_ADDRESS 0x00 #define SDHCI_BLOCK_SIZE__BLOCK_COUNT 0x04 #define SDHCI_BLOCK_SIZE 0x04 @@ -13,6 +19,8 @@ #define SDHCI_DMA_BOUNDARY_8K SDHCI_DMA_BOUNDARY(1) #define SDHCI_DMA_BOUNDARY_4K SDHCI_DMA_BOUNDARY(0) #define SDHCI_DMA_BOUNDARY(x) (((x) & 0x7) << 12) +#define SDHCI_DEFAULT_BOUNDARY_SIZE SZ_512K +#define SDHCI_DEFAULT_BOUNDARY_ARG SDHCI_DMA_BOUNDARY_512K #define SDHCI_TRANSFER_BLOCK_SIZE(x) ((x) & 0xfff) #define SDHCI_BLOCK_COUNT 0x06 #define SDHCI_ARGUMENT 0x08 @@ -20,10 +28,15 @@ #define SDHCI_TRANSFER_MODE 0x0c #define SDHCI_MULTIPLE_BLOCKS BIT(5) #define SDHCI_DATA_TO_HOST BIT(4) +#define SDHCI_TRNS_AUTO_CMD12 BIT(3) #define SDHCI_BLOCK_COUNT_EN BIT(1) #define SDHCI_DMA_EN BIT(0) #define SDHCI_COMMAND 0x0e +#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) #define SDHCI_CMD_INDEX(c) (((c) & 0x3f) << 8) +#define SDHCI_COMMAND_CMDTYP_SUSPEND (1 << 6) +#define SDHCI_COMMAND_CMDTYP_RESUME (2 << 6) +#define SDHCI_COMMAND_CMDTYP_ABORT (3 << 6) #define SDHCI_DATA_PRESENT BIT(5) #define SDHCI_CMD_INDEX_CHECK_EN BIT(4) #define SDHCI_CMD_CRC_CHECK_EN BIT(3) @@ -37,116 +50,302 @@ #define SDHCI_RESPONSE_3 0x1c #define SDHCI_BUFFER 0x20 #define SDHCI_PRESENT_STATE 0x24 +#define SDHCI_WRITE_PROTECT BIT(19) +#define SDHCI_CARD_DETECT BIT(18) +#define SDHCI_CARD_PRESENT BIT(16) +#define SDHCI_BUFFER_READ_ENABLE BIT(11) +#define SDHCI_BUFFER_WRITE_ENABLE BIT(10) +#define SDHCI_DATA_LINE_ACTIVE BIT(2) #define SDHCI_CMD_INHIBIT_DATA BIT(1) #define SDHCI_CMD_INHIBIT_CMD BIT(0) #define SDHCI_PRESENT_STATE1 0x26 #define SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL 0x28 #define SDHCI_HOST_CONTROL 0x28 -#define SDHCI_DATA_WIDTH_8BIT BIT(5) -#define SDHCI_HIGHSPEED_EN BIT(2) -#define SDHCI_DATA_WIDTH_4BIT BIT(1) +#define SDHCI_CTRL_LED BIT(0) +#define SDHCI_CTRL_4BITBUS BIT(1) +#define SDHCI_CTRL_HISPD BIT(2) +#define SDHCI_CTRL_DMA_MASK 0x18 +#define SDHCI_CTRL_SDMA 0x00 +#define SDHCI_CTRL_ADMA1 0x08 +#define SDHCI_CTRL_ADMA32 0x10 +#define SDHCI_CTRL_ADMA64 0x18 +#define SDHCI_CTRL_ADMA3 0x18 +#define SDHCI_CTRL_8BITBUS BIT(5) +#define SDHCI_CTRL_CDTEST_INS BIT(6) +#define SDHCI_CTRL_CDTEST_EN BIT(7) #define SDHCI_POWER_CONTROL 0x29 +#define SDHCI_POWER_ON 0x01 +#define SDHCI_POWER_180 0x0A +#define SDHCI_POWER_300 0x0C +#define SDHCI_POWER_330 0x0E #define SDHCI_BUS_VOLTAGE_330 SDHCI_BUS_VOLTAGE(7) #define SDHCI_BUS_VOLTAGE(v) ((v) << 1) #define SDHCI_BUS_POWER_EN BIT(0) #define SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET 0x2c -#define SDHCI_CLOCK_CONTROL 0x2c -#define SDHCI_FREQ_SEL(x) (((x) & 0xff) << 8) -#define SDHCI_SDCLOCK_EN BIT(2) -#define SDHCI_INTCLOCK_STABLE BIT(1) -#define SDHCI_INTCLOCK_EN BIT(0) +#define SDHCI_CLOCK_CONTROL 0x2C +#define SDHCI_DIVIDER_SHIFT 8 +#define SDHCI_DIVIDER_HI_SHIFT 6 +#define SDHCI_DIV_MASK 0xFF +#define SDHCI_DIV_HI_MASK 0x300 +#define SDHCI_DIV_MASK_LEN 8 +#define SDHCI_FREQ_SEL(x) (((x) & 0xff) << 8) +#define SDHCI_DIV_HI_MASK 0x300 +#define SDHCI_PROG_CLOCK_MODE BIT(5) +#define SDHCI_CLOCK_CARD_EN BIT(2) +#define SDHCI_CLOCK_PLL_EN BIT(3) +#define SDHCI_CLOCK_INT_STABLE BIT(1) +#define SDHCI_CLOCK_INT_EN BIT(0) #define SDHCI_TIMEOUT_CONTROL 0x2e #define SDHCI_SOFTWARE_RESET 0x2f #define SDHCI_RESET_ALL BIT(0) +#define SDHCI_RESET_CMD BIT(1) +#define SDHCI_RESET_DATA BIT(2) #define SDHCI_INT_STATUS 0x30 #define SDHCI_INT_NORMAL_STATUS 0x30 +#define SDHCI_INT_DATA_END_BIT BIT(22) +#define SDHCI_INT_DATA_CRC BIT(21) +#define SDHCI_INT_DATA_TIMEOUT BIT(20) +#define SDHCI_INT_INDEX BIT(19) +#define SDHCI_INT_END_BIT BIT(18) +#define SDHCI_INT_CRC BIT(17) +#define SDHCI_INT_TIMEOUT BIT(16) #define SDHCI_INT_ERROR BIT(15) +#define SDHCI_INT_CARD_INT BIT(8) +#define SDHCI_INT_CARD_INSERT BIT(6) +#define SDHCI_INT_DATA_AVAIL BIT(5) +#define SDHCI_INT_SPACE_AVAIL BIT(4) #define SDHCI_INT_DMA BIT(3) #define SDHCI_INT_XFER_COMPLETE BIT(1) #define SDHCI_INT_CMD_COMPLETE BIT(0) #define SDHCI_INT_ERROR_STATUS 0x32 #define SDHCI_INT_ENABLE 0x34 +#define SDHCI_INT_ERROR_ENABLE 0x36 #define SDHCI_SIGNAL_ENABLE 0x38 #define SDHCI_ACMD12_ERR__HOST_CONTROL2 0x3C +#define SDHCI_HOST_CONTROL2 0x3E +#define SDHCI_CTRL_UHS_MASK GENMASK(3, 0) +#define SDHCI_CTRL_UHS_SDR12 0x0 +#define SDHCI_CTRL_UHS_SDR25 0x1 +#define SDHCI_CTRL_UHS_SDR50 0x2 +#define SDHCI_CTRL_UHS_SDR104 0x3 +#define SDHCI_CTRL_UHS_DDR50 0x4 +#define SDHCI_CTRL_HS400 0x5 /* Non-standard */ +#define SDHCI_CTRL_EXEC_TUNING BIT(6) +#define SDHCI_CTRL_TUNED_CLK BIT(7) +#define SDHCI_CTRL_64BIT_ADDR BIT(13) +#define SDHCI_CTRL_V4_MODE BIT(12) #define SDHCI_CAPABILITIES 0x40 -#define SDHCI_CAPABILITIES_1 0x42 -#define SDHCI_HOSTCAP_VOLTAGE_180 BIT(10) -#define SDHCI_HOSTCAP_VOLTAGE_300 BIT(9) -#define SDHCI_HOSTCAP_VOLTAGE_330 BIT(8) -#define SDHCI_HOSTCAP_HIGHSPEED BIT(5) -#define SDHCI_HOSTCAP_8BIT BIT(2) - -#define SDHCI_SPEC_200_MAX_CLK_DIVIDER 256 +#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0) +#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 +#define SDHCI_CLOCK_BASE_MASK GENMASK(13, 8) +#define SDHCI_CLOCK_V3_BASE_MASK GENMASK(15, 8) +#define SDHCI_MAX_BLOCK_MASK 0x00030000 +#define SDHCI_MAX_BLOCK_SHIFT 16 +#define SDHCI_CAN_DO_8BIT 0x00040000 +#define SDHCI_CAN_DO_ADMA2 0x00080000 +#define SDHCI_CAN_DO_ADMA1 0x00100000 +#define SDHCI_CAN_DO_HISPD 0x00200000 +#define SDHCI_CAN_DO_SDMA 0x00400000 +#define SDHCI_CAN_DO_SUSPEND 0x00800000 +#define SDHCI_CAN_VDD_330 0x01000000 +#define SDHCI_CAN_VDD_300 0x02000000 +#define SDHCI_CAN_VDD_180 0x04000000 +#define SDHCI_CAN_64BIT_V4 0x08000000 +#define SDHCI_CAN_64BIT 0x10000000 + +#define SDHCI_CAPABILITIES_1 0x44 +#define SDHCI_SUPPORT_SDR50 0x00000001 +#define SDHCI_SUPPORT_SDR104 0x00000002 +#define SDHCI_SUPPORT_DDR50 0x00000004 +#define SDHCI_DRIVER_TYPE_A 0x00000010 +#define SDHCI_DRIVER_TYPE_C 0x00000020 +#define SDHCI_DRIVER_TYPE_D 0x00000040 +#define SDHCI_RETUNING_TIMER_COUNT_MASK GENMASK(11, 8) +#define SDHCI_USE_SDR50_TUNING 0x00002000 +#define SDHCI_RETUNING_MODE_MASK GENMASK(15, 14) +#define SDHCI_CLOCK_MUL_MASK GENMASK(23, 16) +#define SDHCI_CAN_DO_ADMA3 0x08000000 +#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ + +#define SDHCI_PRESET_FOR_SDR12 0x66 +#define SDHCI_PRESET_FOR_SDR25 0x68 +#define SDHCI_PRESET_FOR_SDR50 0x6A +#define SDHCI_PRESET_FOR_SDR104 0x6C +#define SDHCI_PRESET_FOR_DDR50 0x6E +#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */ +#define SDHCI_PRESET_CLKGEN_SEL BIT(10) +#define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0) + +#define SDHCI_P_VENDOR_SPEC_AREA 0xE8 +#define SDHCI_P_VENDOR_SPEC_AREA_MASK GENMASK(11, 0) +#define SDHCI_HOST_VERSION 0xFE +#define SDHCI_VENDOR_VER_MASK 0xFF00 +#define SDHCI_VENDOR_VER_SHIFT 8 +#define SDHCI_SPEC_VER_MASK 0x00FF +#define SDHCI_SPEC_VER_SHIFT 0 +#define SDHCI_SPEC_100 0 +#define SDHCI_SPEC_200 1 +#define SDHCI_SPEC_300 2 +#define SDHCI_SPEC_400 3 +#define SDHCI_SPEC_410 4 +#define SDHCI_SPEC_420 5 + +#define SDHCI_CLOCK_MUL_SHIFT 16 + +#define SDHCI_ADMA_ADDRESS 0x58 +#define SDHCI_ADMA_ADDRESS_HI 0x5c + #define SDHCI_MMC_BOOT 0xC4 -#define COMMAND_CMD(x) ((x & 0x3f) << 24) -#define COMMAND_CMDTYP_NORMAL 0x0 -#define COMMAND_CMDTYP_SUSPEND 0x00400000 -#define COMMAND_CMDTYP_RESUME 0x00800000 -#define COMMAND_CMDTYP_ABORT 0x00c00000 -#define COMMAND_DPSEL 0x00200000 -#define COMMAND_CICEN 0x00100000 -#define COMMAND_CCCEN 0x00080000 -#define COMMAND_RSPTYP_NONE 0 -#define COMMAND_RSPTYP_136 0x00010000 -#define COMMAND_RSPTYP_48 0x00020000 -#define COMMAND_RSPTYP_48_BUSY 0x00030000 -#define TRANSFER_MODE_MSBSEL 0x00000020 -#define TRANSFER_MODE_DTDSEL 0x00000010 -#define TRANSFER_MODE_AC12EN 0x00000004 -#define TRANSFER_MODE_BCEN 0x00000002 -#define TRANSFER_MODE_DMAEN 0x00000001 - -#define IRQSTAT_TE 0x04000000 -#define IRQSTAT_DMAE 0x02000000 -#define IRQSTAT_AC12E 0x01000000 -#define IRQSTAT_CLE 0x00800000 -#define IRQSTAT_DEBE 0x00400000 -#define IRQSTAT_DCE 0x00200000 -#define IRQSTAT_DTOE 0x00100000 -#define IRQSTAT_CIE 0x00080000 -#define IRQSTAT_CEBE 0x00040000 -#define IRQSTAT_CCE 0x00020000 -#define IRQSTAT_CTOE 0x00010000 -#define IRQSTAT_CINT 0x00000100 -#define IRQSTAT_CRM 0x00000080 -#define IRQSTAT_CINS 0x00000040 -#define IRQSTAT_BRR 0x00000020 -#define IRQSTAT_BWR 0x00000010 -#define IRQSTAT_DINT 0x00000008 -#define IRQSTAT_BGE 0x00000004 -#define IRQSTAT_TC 0x00000002 -#define IRQSTAT_CC 0x00000001 - -#define IRQSTATEN_DMAE 0x10000000 -#define IRQSTATEN_AC12E 0x01000000 -#define IRQSTATEN_DEBE 0x00400000 -#define IRQSTATEN_DCE 0x00200000 -#define IRQSTATEN_DTOE 0x00100000 -#define IRQSTATEN_CIE 0x00080000 -#define IRQSTATEN_CEBE 0x00040000 -#define IRQSTATEN_CCE 0x00020000 -#define IRQSTATEN_CTOE 0x00010000 -#define IRQSTATEN_CINT 0x00000100 -#define IRQSTATEN_CRM 0x00000080 -#define IRQSTATEN_CINS 0x00000040 -#define IRQSTATEN_BRR 0x00000020 -#define IRQSTATEN_BWR 0x00000010 -#define IRQSTATEN_DINT 0x00000008 -#define IRQSTATEN_BGE 0x00000004 -#define IRQSTATEN_TC 0x00000002 -#define IRQSTATEN_CC 0x00000001 - -#define PRSSTAT_DAT0 0x01000000 -#define PRSSTAT_CLSL 0x00800000 -#define PRSSTAT_WPSPL 0x00080000 -#define PRSSTAT_CDPL 0x00040000 -#define PRSSTAT_CINS 0x00010000 -#define PRSSTAT_BREN 0x00000800 -#define PRSSTAT_BWEN 0x00000400 -#define PRSSTAT_SDSTB 0x00000008 -#define PRSSTAT_DLA 0x00000004 -#define PRSSTAT_CIDHB 0x00000002 -#define PRSSTAT_CICHB 0x00000001 +#define SDHCI_MAX_DIV_SPEC_200 256 +#define SDHCI_MAX_DIV_SPEC_300 2046 + +struct sdhci { + u32 (*read32)(struct sdhci *host, int reg); + u16 (*read16)(struct sdhci *host, int reg); + u8 (*read8)(struct sdhci *host, int reg); + void (*write32)(struct sdhci *host, int reg, u32 val); + void (*write16)(struct sdhci *host, int reg, u16 val); + void (*write8)(struct sdhci *host, int reg, u8 val); + + void __iomem *base; + + int max_clk; /* Max possible freq (Hz) */ + int clk_mul; /* Clock Muliplier value */ + + int flags; /* Host attributes */ +#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */ +#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ +#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ +#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ +#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */ +#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ +#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ +#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ +#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ +#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ +#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */ +#define SDHCI_SIGNALING_180 (1<<15) /* Host is capable of 1.8V signaling */ +#define SDHCI_SIGNALING_120 (1<<16) /* Host is capable of 1.2V signaling */ + + unsigned int version; /* SDHCI spec. version */ + + enum mci_timing timing; + bool preset_enabled; /* Preset is enabled */ + bool v4_mode; /* Host Version 4 Enable */ + + unsigned int quirks; +#define SDHCI_QUIRK_MISSING_CAPS BIT(27) + unsigned int quirks2; +#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN BIT(15) +#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER BIT(19) + u32 caps; /* CAPABILITY_0 */ + u32 caps1; /* CAPABILITY_1 */ + bool read_caps; /* Capability flags have been read */ + u32 sdma_boundary; + + unsigned int tuning_count; /* Timer count for re-tuning */ + unsigned int tuning_mode; /* Re-tuning mode supported by host */ + unsigned int tuning_err; /* Error code for re-tuning */ +#define SDHCI_TUNING_MODE_1 0 +#define SDHCI_TUNING_MODE_2 1 +#define SDHCI_TUNING_MODE_3 2 + /* Delay (ms) between tuning commands */ + int tuning_delay; + int tuning_loop_count; + int tuning_old_ier; + int tuning_old_sig; + + struct mci_host *mci; + + int (*platform_execute_tuning)(struct mci_host *host, u32 opcode); +}; + +static inline u32 sdhci_read32(struct sdhci *host, int reg) +{ + if (host->read32) + return host->read32(host, reg); + else + return readl(host->base + reg); +} + +static inline u32 sdhci_read16(struct sdhci *host, int reg) +{ + if (host->read16) + return host->read16(host, reg); + else + return readw(host->base + reg); +} + +static inline u32 sdhci_read8(struct sdhci *host, int reg) +{ + if (host->read8) + return host->read8(host, reg); + else + return readb(host->base + reg); +} + +static inline void sdhci_write32(struct sdhci *host, int reg, u32 val) +{ + if (host->write32) + host->write32(host, reg, val); + else + writel(val, host->base + reg); +} + +static inline void sdhci_write16(struct sdhci *host, int reg, u32 val) +{ + if (host->write16) + host->write16(host, reg, val); + else + writew(val, host->base + reg); +} + +static inline void sdhci_write8(struct sdhci *host, int reg, u32 val) +{ + if (host->write8) + host->write8(host, reg, val); + else + writeb(val, host->base + reg); +} + +#define SDHCI_NO_DMA DMA_ERROR_CODE +int sdhci_execute_tuning(struct sdhci *sdhci, u32 opcode); +int sdhci_wait_idle_data(struct sdhci *host, struct mci_cmd *cmd); +int sdhci_wait_idle(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *data); +int sdhci_wait_for_done(struct sdhci *host, u32 mask); +void sdhci_read_response(struct sdhci *host, struct mci_cmd *cmd); +void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd, + struct mci_data *data, bool dma, u32 *command, + u32 *xfer); +void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data); +void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data, dma_addr_t *dma); +int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma); +int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data); +int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data, + dma_addr_t dma); +int sdhci_reset(struct sdhci *sdhci, u8 mask); +u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock, + unsigned int *actual_clock, unsigned int input_clock); +void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock); +void sdhci_enable_clk(struct sdhci *host, u16 clk); +void sdhci_enable_v4_mode(struct sdhci *host); +int sdhci_setup_host(struct sdhci *host); +void __sdhci_read_caps(struct sdhci *host, const u16 *ver, + const u32 *caps, const u32 *caps1); +static inline void sdhci_read_caps(struct sdhci *host) +{ + __sdhci_read_caps(host, NULL, NULL, NULL); +} +void sdhci_set_bus_width(struct sdhci *host, int width); + +#define sdhci_read8_poll_timeout(sdhci, reg, val, cond, timeout_us) \ + read_poll_timeout(sdhci_read8, val, cond, timeout_us, sdhci, reg) + +#define sdhci_read16_poll_timeout(sdhci, reg, val, cond, timeout_us) \ + read_poll_timeout(sdhci_read16, val, cond, timeout_us, sdhci, reg) + +#define sdhci_read32_poll_timeout(sdhci, reg, val, cond, timeout_us) \ + read_poll_timeout(sdhci_read32, val, cond, timeout_us, sdhci, reg) #endif /* __MCI_SDHCI_H */ |