263 lines
6.6 KiB
C
263 lines
6.6 KiB
C
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
/*
|
||
|
* Copyright (c) 2019 MediaTek Inc.
|
||
|
*/
|
||
|
|
||
|
#ifndef __MT_MSDC_H__
|
||
|
#define __MT_MSDC_H__
|
||
|
|
||
|
#include <mt-plat/sync_write.h>
|
||
|
#if defined(CONFIG_MACH_MT6768) && defined(CONFIG_MTK_PMQOS)
|
||
|
#include <linux/soc/mediatek/mtk-pm-qos.h>
|
||
|
#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
|