rv1126-uboot/include/dwmmc.h

321 lines
8.9 KiB
C
Raw Normal View History

/*
* (C) Copyright 2012 SAMSUNG Electronics
* Jaehoon Chung <jh80.chung@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __DWMMC_HW_H
#define __DWMMC_HW_H
#include <asm/io.h>
#include <mmc.h>
#define DWMCI_CTRL 0x000
#define DWMCI_PWREN 0x004
#define DWMCI_CLKDIV 0x008
#define DWMCI_CLKSRC 0x00C
#define DWMCI_CLKENA 0x010
#define DWMCI_TMOUT 0x014
#define DWMCI_CTYPE 0x018
#define DWMCI_BLKSIZ 0x01C
#define DWMCI_BYTCNT 0x020
#define DWMCI_INTMASK 0x024
#define DWMCI_CMDARG 0x028
#define DWMCI_CMD 0x02C
#define DWMCI_RESP0 0x030
#define DWMCI_RESP1 0x034
#define DWMCI_RESP2 0x038
#define DWMCI_RESP3 0x03C
#define DWMCI_MINTSTS 0x040
#define DWMCI_RINTSTS 0x044
#define DWMCI_STATUS 0x048
#define DWMCI_FIFOTH 0x04C
#define DWMCI_CDETECT 0x050
#define DWMCI_WRTPRT 0x054
#define DWMCI_GPIO 0x058
#define DWMCI_TCMCNT 0x05C
#define DWMCI_TBBCNT 0x060
#define DWMCI_DEBNCE 0x064
#define DWMCI_USRID 0x068
#define DWMCI_VERID 0x06C
#define DWMCI_HCON 0x070
#define DWMCI_UHS_REG 0x074
#define DWMCI_BMOD 0x080
#define DWMCI_PLDMND 0x084
#define DWMCI_DBADDR 0x088
#define DWMCI_IDSTS 0x08C
#define DWMCI_IDINTEN 0x090
#define DWMCI_DSCADDR 0x094
#define DWMCI_BUFADDR 0x098
#define DWMCI_CARDTHRCTL 0x100
#define DWMCI_DATA 0x200
/* Interrupt Mask register */
#define DWMCI_INTMSK_ALL 0xffffffff
#define DWMCI_INTMSK_RE (1 << 1)
#define DWMCI_INTMSK_CDONE (1 << 2)
#define DWMCI_INTMSK_DTO (1 << 3)
#define DWMCI_INTMSK_TXDR (1 << 4)
#define DWMCI_INTMSK_RXDR (1 << 5)
#define DWMCI_INTMSK_DCRC (1 << 7)
#define DWMCI_INTMSK_RTO (1 << 8)
#define DWMCI_INTMSK_DRTO (1 << 9)
#define DWMCI_INTMSK_HTO (1 << 10)
#define DWMCI_INTMSK_FRUN (1 << 11)
#define DWMCI_INTMSK_HLE (1 << 12)
#define DWMCI_INTMSK_SBE (1 << 13)
#define DWMCI_INTMSK_ACD (1 << 14)
#define DWMCI_INTMSK_EBE (1 << 15)
/* Raw interrupt Regsiter */
#define DWMCI_DATA_ERR (DWMCI_INTMSK_EBE | DWMCI_INTMSK_SBE | DWMCI_INTMSK_HLE |\
DWMCI_INTMSK_FRUN | DWMCI_INTMSK_EBE | DWMCI_INTMSK_DCRC)
#define DWMCI_DATA_TOUT (DWMCI_INTMSK_HTO | DWMCI_INTMSK_DRTO)
/* CTRL register */
#define DWMCI_CTRL_RESET (1 << 0)
#define DWMCI_CTRL_FIFO_RESET (1 << 1)
#define DWMCI_CTRL_DMA_RESET (1 << 2)
#define DWMCI_DMA_EN (1 << 5)
#define DWMCI_CTRL_SEND_AS_CCSD (1 << 10)
#define DWMCI_IDMAC_EN (1 << 25)
#define DWMCI_RESET_ALL (DWMCI_CTRL_RESET | DWMCI_CTRL_FIFO_RESET |\
DWMCI_CTRL_DMA_RESET)
/* CMD register */
#define DWMCI_CMD_RESP_EXP (1 << 6)
#define DWMCI_CMD_RESP_LENGTH (1 << 7)
#define DWMCI_CMD_CHECK_CRC (1 << 8)
#define DWMCI_CMD_DATA_EXP (1 << 9)
#define DWMCI_CMD_RW (1 << 10)
#define DWMCI_CMD_SEND_STOP (1 << 12)
#define DWMCI_CMD_ABORT_STOP (1 << 14)
#define DWMCI_CMD_PRV_DAT_WAIT (1 << 13)
#define DWMCI_CMD_UPD_CLK (1 << 21)
#define DWMCI_CMD_USE_HOLD_REG (1 << 29)
#define DWMCI_CMD_START (1 << 31)
/* CLKENA register */
#define DWMCI_CLKEN_ENABLE (1 << 0)
#define DWMCI_CLKEN_LOW_PWR (1 << 16)
/* Card-type registe */
#define DWMCI_CTYPE_1BIT 0
#define DWMCI_CTYPE_4BIT (1 << 0)
#define DWMCI_CTYPE_8BIT (1 << 16)
/* Status Register */
#define DWMCI_BUSY (1 << 9)
#define DWMCI_FIFO_MASK 0x1fff
#define DWMCI_FIFO_SHIFT 17
/* FIFOTH Register */
#define MSIZE(x) ((x) << 28)
#define RX_WMARK(x) ((x) << 16)
#define TX_WMARK(x) (x)
#define RX_WMARK_SHIFT 16
#define RX_WMARK_MASK (0xfff << RX_WMARK_SHIFT)
/* HCON Register */
#define DMA_INTERFACE_IDMA (0x0)
#define SDMMC_GET_TRANS_MODE(x) (((x)>>16) & 0x3)
#define DWMCI_IDMAC_OWN (1 << 31)
#define DWMCI_IDMAC_CH (1 << 4)
#define DWMCI_IDMAC_FS (1 << 3)
#define DWMCI_IDMAC_LD (1 << 2)
/* Bus Mode Register */
#define DWMCI_BMOD_IDMAC_RESET (1 << 0)
#define DWMCI_BMOD_IDMAC_FB (1 << 1)
#define DWMCI_BMOD_IDMAC_EN (1 << 7)
/* UHS register */
#define DWMCI_DDR_MODE (1 << 16)
/* quirks */
#define DWMCI_QUIRK_DISABLE_SMU (1 << 0)
/*
* DWMCI_MSIZE is uses to set burst size of multiple transaction.
* The burst size is set to 128 if DWMCI_MSIZE is set to 0x6.
*/
#define DWMCI_MSIZE 0x6
/* The DW MMC Controller Version */
#define DW_MMC_240A 0x240a
/* sdmmc cardthrctl set */
#define DWMCI_CDTHRCTRL_CONFIG (1 + (0x200 << 16))
/**
* struct dwmci_host - Information about a designware MMC host
*
* @name: Device name
* @ioaddr: Base I/O address of controller
* @quirks: Quick flags - see DWMCI_QUIRK_...
* @caps: Capabilities - see MMC_MODE_...
* @bus_hz: Bus speed in Hz, if @get_mmc_clk() is NULL
* @div: Arbitrary clock divider value for use by controller
* @dev_index: Arbitrary device index for use by controller
* @dev_id: Arbitrary device ID for use by controller
* @buswidth: Bus width in bits (8 or 4)
* @fifoth_val: Value for FIFOTH register (or 0 to leave unset)
* @mmc: Pointer to generic MMC structure for this device
* @priv: Private pointer for use by controller
mmc: dwmmc: Add stride PIO for better burst mode support This patch enables stride PIO for better burst mode support on some rockchip platforms, for instance rk3128, etc. It uses ldm and stm to make multiple accessing from CPU under some ARM architecture. Design Note: 1) Carefully test it beyond the armv7(m) core since I don't test them! If you disassemble the code, dwmci_memcpy_fromio may be changed to use ldmia.w and stmia.w, as well as some other optimization for push/pop stack operation, but they are all fine! 2) Do *NOT* remove noinline and __volatile attributes as you could fall into trouble by the optimization of GCC. And please invent new attributes if you use *OTHER* compilers which have their own keywords claiming the function to be a "plase don't inline the function and please don't reorder the groups". 3) If you want to use this feature for other rockchip platforms, you could append new config in rockchip_dw_mmc.c. But now we only have CONFIG_ROCKCHIP_RK3128 which means we just enable it for rk312x platforms. 4) Stride PIO is determined by both of host->stride_pio and the data payload. The intention of it is to make the block accessing faster. So now only enable it for who's data payload is larger(or equal to)than 512 Bytes. 5) MAX_STRIDE means we support burst MAX_STRIDE * 4 Bytes per stride. Of course you could change that, but please read the comment before it in the code and do it carefully. How to test? 1) Prepare a memory, for instance, 0x70000000 on RK3126c. => mw 0x70000000 0x55aa55aa 0x200 2) Check it to see if 0x70000000 ~ 0x700000200 are all 0x55aa55aa => md 0x70000000 0x200 70000000: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000010: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000020: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000030: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U .... 3) Fetch data of 0x70000000 ~ 0x700000200 and wrrite them to eMMC, for instance, LBA 0x10000, and blk count is 1 as one blk means 0x200 bytes. => mmc write 0x70000000 0x10000 1 MMC write: dev # 0, block # 65536, count 1 ... 1 blocks written: OK 4) Clean the merory buffer and double check it => mw 0x70000000 0x0 0x200 => md 0x70000000 0x200 70000000: 00000000 00000000 00000000 00000000 ................ 70000010: 00000000 00000000 00000000 00000000 ................ 70000020: 00000000 00000000 00000000 00000000 ................ .... 5) Well, now let's read back the data from eMMC from the LBA we wrote before. => mmc read 0x70000000 0x10000 1 MMC read: dev # 0, block # 65536, count 1 ... 1 blocks read: OK 6) We expect the 0x70000000 ~ 0x700000200 should be 0x55aa55aa instead of 0x0 which is cleared by step 4). => md 0x70000000 0x200 70000000: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000010: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000020: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000030: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U .... Great, we see that the write and read eMMC are finished well and the data payload is correct as expected! Change-Id: I9b68c335449550b95f1a8f5841d46821346e45af Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
2017-10-09 09:51:29 +00:00
* @stride_pio: Provide the ability of accessing fifo with burst mode
*/
struct dwmci_host {
const char *name;
void *ioaddr;
unsigned int quirks;
unsigned int caps;
unsigned int version;
unsigned int clock;
unsigned int bus_hz;
unsigned int div;
int dev_index;
int dev_id;
int buswidth;
u32 fifoth_val;
struct mmc *mmc;
void *priv;
mmc: dwmmc: Add stride PIO for better burst mode support This patch enables stride PIO for better burst mode support on some rockchip platforms, for instance rk3128, etc. It uses ldm and stm to make multiple accessing from CPU under some ARM architecture. Design Note: 1) Carefully test it beyond the armv7(m) core since I don't test them! If you disassemble the code, dwmci_memcpy_fromio may be changed to use ldmia.w and stmia.w, as well as some other optimization for push/pop stack operation, but they are all fine! 2) Do *NOT* remove noinline and __volatile attributes as you could fall into trouble by the optimization of GCC. And please invent new attributes if you use *OTHER* compilers which have their own keywords claiming the function to be a "plase don't inline the function and please don't reorder the groups". 3) If you want to use this feature for other rockchip platforms, you could append new config in rockchip_dw_mmc.c. But now we only have CONFIG_ROCKCHIP_RK3128 which means we just enable it for rk312x platforms. 4) Stride PIO is determined by both of host->stride_pio and the data payload. The intention of it is to make the block accessing faster. So now only enable it for who's data payload is larger(or equal to)than 512 Bytes. 5) MAX_STRIDE means we support burst MAX_STRIDE * 4 Bytes per stride. Of course you could change that, but please read the comment before it in the code and do it carefully. How to test? 1) Prepare a memory, for instance, 0x70000000 on RK3126c. => mw 0x70000000 0x55aa55aa 0x200 2) Check it to see if 0x70000000 ~ 0x700000200 are all 0x55aa55aa => md 0x70000000 0x200 70000000: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000010: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000020: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000030: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U .... 3) Fetch data of 0x70000000 ~ 0x700000200 and wrrite them to eMMC, for instance, LBA 0x10000, and blk count is 1 as one blk means 0x200 bytes. => mmc write 0x70000000 0x10000 1 MMC write: dev # 0, block # 65536, count 1 ... 1 blocks written: OK 4) Clean the merory buffer and double check it => mw 0x70000000 0x0 0x200 => md 0x70000000 0x200 70000000: 00000000 00000000 00000000 00000000 ................ 70000010: 00000000 00000000 00000000 00000000 ................ 70000020: 00000000 00000000 00000000 00000000 ................ .... 5) Well, now let's read back the data from eMMC from the LBA we wrote before. => mmc read 0x70000000 0x10000 1 MMC read: dev # 0, block # 65536, count 1 ... 1 blocks read: OK 6) We expect the 0x70000000 ~ 0x700000200 should be 0x55aa55aa instead of 0x0 which is cleared by step 4). => md 0x70000000 0x200 70000000: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000010: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000020: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U 70000030: 55aa55aa 55aa55aa 55aa55aa 55aa55aa .U.U.U.U.U.U.U.U .... Great, we see that the write and read eMMC are finished well and the data payload is correct as expected! Change-Id: I9b68c335449550b95f1a8f5841d46821346e45af Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
2017-10-09 09:51:29 +00:00
bool stride_pio;
void (*clksel)(struct dwmci_host *host);
void (*board_init)(struct dwmci_host *host);
/**
* Get / set a particular MMC clock frequency
*
* This is used to request the current clock frequency of the clock
* that drives the DWMMC peripheral. The caller will then use this
* information to work out the divider it needs to achieve the
* required MMC bus clock frequency. If you want to handle the
* clock external to DWMMC, use @freq to select the frequency and
* return that value too. Then DWMMC will put itself in bypass mode.
*
* @host: DWMMC host
* @freq: Frequency the host is trying to achieve
*/
unsigned int (*get_mmc_clk)(struct dwmci_host *host, uint freq);
int (*execute_tuning)(struct dwmci_host *host, u32 opcode);
#ifndef CONFIG_BLK
struct mmc_config cfg;
#endif
/* use fifo mode to read and write data */
bool fifo_mode;
};
struct dwmci_idmac {
u32 flags;
u32 cnt;
u32 addr;
u32 next_addr;
} __aligned(ARCH_DMA_MINALIGN);
static inline void dwmci_writel(struct dwmci_host *host, int reg, u32 val)
{
writel(val, host->ioaddr + reg);
}
static inline void dwmci_writew(struct dwmci_host *host, int reg, u16 val)
{
writew(val, host->ioaddr + reg);
}
static inline void dwmci_writeb(struct dwmci_host *host, int reg, u8 val)
{
writeb(val, host->ioaddr + reg);
}
static inline u32 dwmci_readl(struct dwmci_host *host, int reg)
{
return readl(host->ioaddr + reg);
}
static inline u16 dwmci_readw(struct dwmci_host *host, int reg)
{
return readw(host->ioaddr + reg);
}
static inline u8 dwmci_readb(struct dwmci_host *host, int reg)
{
return readb(host->ioaddr + reg);
}
#ifdef CONFIG_BLK
/**
* dwmci_setup_cfg() - Set up the configuration for DWMMC
*
* This is used to set up a DWMMC device when you are using CONFIG_BLK.
*
* This should be called from your MMC driver's probe() method once you have
* the information required.
*
* Generally your driver will have a platform data structure which holds both
* the configuration (struct mmc_config) and the MMC device info (struct mmc).
* For example:
*
* struct rockchip_mmc_plat {
* struct mmc_config cfg;
* struct mmc mmc;
* };
*
* ...
*
* Inside U_BOOT_DRIVER():
* .platdata_auto_alloc_size = sizeof(struct rockchip_mmc_plat),
*
* To access platform data:
* struct rockchip_mmc_plat *plat = dev_get_platdata(dev);
*
* See rockchip_dw_mmc.c for an example.
*
* @cfg: Configuration structure to fill in (generally &plat->mmc)
* @host: DWMMC host
* @max_clk: Maximum supported clock speed in HZ (e.g. 150000000)
* @min_clk: Minimum supported clock speed in HZ (e.g. 400000)
*/
void dwmci_setup_cfg(struct mmc_config *cfg, struct dwmci_host *host,
u32 max_clk, u32 min_clk);
/**
* dwmci_bind() - Set up a new MMC block device
*
* This is used to set up a DWMMC block device when you are using CONFIG_BLK.
* It should be called from your driver's bind() method.
*
* See rockchip_dw_mmc.c for an example.
*
* @dev: Device to set up
* @mmc: Pointer to mmc structure (normally &plat->mmc)
* @cfg: Empty configuration structure (generally &plat->cfg). This is
* normally all zeroes at this point. The only purpose of passing
* this in is to set mmc->cfg to it.
* @return 0 if OK, -ve if the block device could not be created
*/
int dwmci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg);
#else
/**
* add_dwmci() - Add a new DWMMC interface
*
* This is used when you are not using CONFIG_BLK. Convert your driver over!
*
* @host: DWMMC host structure
* @max_clk: Maximum supported clock speed in HZ (e.g. 150000000)
* @min_clk: Minimum supported clock speed in HZ (e.g. 400000)
* @return 0 if OK, -ve on error
*/
int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk);
#endif /* !CONFIG_BLK */
#ifdef CONFIG_DM_MMC
/* Export the operations to drivers */
int dwmci_probe(struct udevice *dev);
extern const struct dm_mmc_ops dm_dwmci_ops;
#endif
#endif /* __DWMMC_HW_H */