/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #ifndef __MT_MSDC_H__ #define __MT_MSDC_H__ #include #if defined(CONFIG_MACH_MT6768) && defined(CONFIG_MTK_PMQOS) #include #endif #define HOST_MAX_NUM (2) #define TUNE_NONE (0) /* No need tune */ #define TUNE_CMD_CRC (0x1 << 0) /* transfer cmd crc */ #define TUNE_DATA_WRITE (0x1 << 1) /* transfer data crc */ #define TUNE_DATA_READ (0x1 << 2) /* transfer data crc */ #define TUNE_CMD_TMO (0x1 << 3) /* transfer cmd tmo */ #define TUNE_AUTOK_PASS (0x1 << 4) /* autok pass flag */ enum { MODE_PIO = 0, MODE_DMA = 1, MODE_SIZE_DEP = 2, MODE_NONE = 3, }; static inline unsigned int uffs(unsigned int x) { unsigned int r = 1; if (!x) return 0; if (!(x & 0xffff)) { x >>= 16; r += 16; } if (!(x & 0xff)) { x >>= 8; r += 8; } if (!(x & 0xf)) { x >>= 4; r += 4; } if (!(x & 3)) { x >>= 2; r += 2; } if (!(x & 1)) { x >>= 1; r += 1; } return r; } #define MSDC_READ8(reg) __raw_readb(reg) #define MSDC_READ16(reg) __raw_readw(reg) #define MSDC_READ32(reg) __raw_readl(reg) #define MSDC_WRITE8(reg, val) mt_reg_sync_writeb(val, reg) #define MSDC_WRITE16(reg, val) mt_reg_sync_writew(val, reg) #define MSDC_WRITE32(reg, val) mt_reg_sync_writel(val, reg) #define UNSTUFF_BITS(resp, start, size) \ ({ \ const int __size = size; \ const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ const int __off = 3 - ((start) / 32); \ const int __shft = (start) & 31; \ u32 __res; \ __res = resp[__off] >> __shft; \ if (__size + __shft > 32) \ __res |= resp[__off-1] << ((32 - __shft) % 32); \ __res & __mask; \ }) #define MSDC_SET_BIT32(reg, bs) \ do { \ unsigned int tv = MSDC_READ32(reg);\ tv |= (u32)(bs); \ MSDC_WRITE32(reg, tv); \ } while (0) #define MSDC_CLR_BIT32(reg, bs) \ do { \ unsigned int tv = MSDC_READ32(reg);\ tv &= ~((u32)(bs)); \ MSDC_WRITE32(reg, tv); \ } while (0) #define MSDC_SET_FIELD(reg, field, val) \ do { \ unsigned int tv = MSDC_READ32(reg); \ tv &= ~(field); \ tv |= ((val) << (uffs((unsigned int)field) - 1)); \ MSDC_WRITE32(reg, tv); \ } while (0) #define MSDC_GET_FIELD(reg, field, val) \ do { \ unsigned int tv = MSDC_READ32(reg); \ val = ((tv & (field)) >> (uffs((unsigned int)field) - 1)); \ } while (0) #define GET_FIELD(reg, field_shift, field_mask, val) \ (val = (reg >> field_shift) & field_mask) struct mt_gpdma_desc { u32 gpd_info; #define GPDMA_DESC_HWO (0x1 << 0) #define GPDMA_DESC_BDP (0x1 << 1) #define GPDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ #define GPDMA_DESC_INT (0x1 << 16) #define GPDMA_DESC_NEXT_H4 (0xf << 24) #define GPDMA_DESC_PTR_H4 (0xf << 28) u32 next; u32 ptr; u32 gpd_data_len; #define GPDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */ #define GPDMA_DESC_EXTLEN (0xff << 16) /* bit16 ~ bit23 */ u32 arg; u32 blknum; u32 cmd; }; struct mt_bdma_desc { u32 bd_info; #define BDMA_DESC_EOL (0x1 << 0) #define BDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ #define BDMA_DESC_BLKPAD (0x1 << 17) #define BDMA_DESC_DWPAD (0x1 << 18) #define BDMA_DESC_NEXT_H4 (0xf << 24) #define BDMA_DESC_PTR_H4 (0xf << 28) u32 next; u32 ptr; u32 bd_data_len; #define BDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */ #define BDMA_DESC_BUFLEN_EXT (0xffffff) /* bit0 ~ bit23 */ }; struct msdc_dma { struct scatterlist *sg; /* I/O scatter list */ struct mt_gpdma_desc *gpd; /* pointer to gpd array */ struct mt_bdma_desc *bd; /* pointer to bd array */ dma_addr_t gpd_addr; /* the physical address of gpd array */ dma_addr_t bd_addr; /* the physical address of bd array */ }; struct msdc_save_para { u32 msdc_cfg; u32 iocon; u32 sdc_cfg; u32 pad_tune; u32 patch_bit0; u32 patch_bit1; u32 patch_bit2; u32 pad_ds_tune; u32 pad_cmd_tune; u32 emmc50_cfg0; u32 emmc50_cfg3; u32 sdc_fifo_cfg; u32 emmc_top_control; u32 emmc_top_cmd; u32 emmc50_pad_ds_tune; }; struct msdc_tune_para { u32 iocon; u32 pad_tune; u32 pad_cmd_tune; u32 emmc_top_control; u32 emmc_top_cmd; }; struct msdc_host { struct device *dev; const struct mtk_mmc_compatible *dev_comp; struct mmc_host *mmc; /* mmc structure */ int cmd_rsp; spinlock_t lock; struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; int error; void __iomem *base; /* host base address */ void __iomem *top_base; /* host top register base address */ struct msdc_dma dma; /* dma channel */ u64 dma_mask; u32 timeout_ns; /* data timeout ns */ u32 timeout_clks; /* data timeout clks */ struct pinctrl *pinctrl; struct pinctrl_state *pins_default; struct pinctrl_state *pins_uhs; struct pinctrl_state *pins_pull_down; struct delayed_work req_timeout; int irq; /* host interrupt */ struct clk *src_clk; /* msdc source clock */ struct clk *h_clk; /* msdc h_clk */ struct clk *bus_clk; /* bus clock which used to access register */ struct clk *src_clk_cg; /* msdc source clock control gate */ struct clk *crypto_clk; /* msdc crypto clock */ void __iomem *crypto_clk_base; /*dbg use: for dump aes clk cg*/ u32 mclk; /* mmc subsystem clock frequency */ u32 src_clk_freq; /* source clock frequency */ #ifdef CONFIG_MACH_MT8173 u32 sclk; /* SD/MS bus clock frequency */ #endif unsigned char timing; bool vqmmc_enabled; #ifdef CONFIG_MACH_MT8173 u32 host_id; #endif u32 latch_ck; u32 hs400_ds_delay; u32 hs400_ds_dly3; u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */ u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */ #ifdef CONFIG_MACH_MT8173 u32 hs200_cmd_resp_sel; /* cmd response sample selection */ /* valid after tune response && final delay != 0xffffffff */ bool tune_response_valid; u8 tune_response_delay; /* saved tune response value */ #endif bool hs400_cmd_resp_sel_rising; /* cmd response sample selection for HS400 */ bool hs400_mode; /* current eMMC will run at hs400 mode */ bool hs400_tuning; /* hs400 mode online tuning */ bool cqhci; /* support eMMC hw cmdq */ bool is_autok_done; bool internal_cd; /* Use internal card-detect logic */ bool block_bad_card; u8 card_inserted; /* the status of card inserted */ int retune_times; u32 need_tune; int power_cycle_cnt; u32 data_timeout_cont; /* data continuous timeout */ struct msdc_save_para save_para; /* used when gate HCLK */ struct msdc_tune_para def_tune_para; /* default tune setting */ struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ struct cqhci_host *cq_host; #if defined(CONFIG_MACH_MT6768) && defined(CONFIG_MTK_PMQOS) struct mtk_pm_qos_request pm_qos; #endif }; #endif