blob: 6edb9e1a59c574329cdd5db3875848d079aad4c5 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001/* SPDX-License-Identifier: GPL-2.0+ */
Jaehoon Chung7cf73072012-10-15 19:10:29 +00002/*
3 * (C) Copyright 2012 SAMSUNG Electronics
4 * Jaehoon Chung <jh80.chung@samsung.com>
Jaehoon Chung7cf73072012-10-15 19:10:29 +00005 */
6
7#ifndef __DWMMC_HW_H
8#define __DWMMC_HW_H
9
Simon Glass274e0b02020-05-10 11:39:56 -060010#include <asm/cache.h>
Jaehoon Chung7cf73072012-10-15 19:10:29 +000011#include <asm/io.h>
12#include <mmc.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060013#include <linux/bitops.h>
Jaehoon Chung7cf73072012-10-15 19:10:29 +000014
15#define DWMCI_CTRL 0x000
16#define DWMCI_PWREN 0x004
17#define DWMCI_CLKDIV 0x008
Sam Protsenko286892e2024-08-07 22:14:19 -050018#define DWMCI_CLKSRC 0x00c
Jaehoon Chung7cf73072012-10-15 19:10:29 +000019#define DWMCI_CLKENA 0x010
20#define DWMCI_TMOUT 0x014
21#define DWMCI_CTYPE 0x018
Sam Protsenko286892e2024-08-07 22:14:19 -050022#define DWMCI_BLKSIZ 0x01c
Jaehoon Chung7cf73072012-10-15 19:10:29 +000023#define DWMCI_BYTCNT 0x020
24#define DWMCI_INTMASK 0x024
25#define DWMCI_CMDARG 0x028
Sam Protsenko286892e2024-08-07 22:14:19 -050026#define DWMCI_CMD 0x02c
Jaehoon Chung7cf73072012-10-15 19:10:29 +000027#define DWMCI_RESP0 0x030
28#define DWMCI_RESP1 0x034
29#define DWMCI_RESP2 0x038
Sam Protsenko286892e2024-08-07 22:14:19 -050030#define DWMCI_RESP3 0x03c
Jaehoon Chung7cf73072012-10-15 19:10:29 +000031#define DWMCI_MINTSTS 0x040
32#define DWMCI_RINTSTS 0x044
33#define DWMCI_STATUS 0x048
Sam Protsenko286892e2024-08-07 22:14:19 -050034#define DWMCI_FIFOTH 0x04c
Jaehoon Chung7cf73072012-10-15 19:10:29 +000035#define DWMCI_CDETECT 0x050
36#define DWMCI_WRTPRT 0x054
37#define DWMCI_GPIO 0x058
Sam Protsenko286892e2024-08-07 22:14:19 -050038#define DWMCI_TCMCNT 0x05c
Jaehoon Chung7cf73072012-10-15 19:10:29 +000039#define DWMCI_TBBCNT 0x060
40#define DWMCI_DEBNCE 0x064
41#define DWMCI_USRID 0x068
Sam Protsenko286892e2024-08-07 22:14:19 -050042#define DWMCI_VERID 0x06c
Jaehoon Chung7cf73072012-10-15 19:10:29 +000043#define DWMCI_HCON 0x070
44#define DWMCI_UHS_REG 0x074
45#define DWMCI_BMOD 0x080
46#define DWMCI_PLDMND 0x084
Sam Protsenko7c991612024-08-07 22:14:16 -050047#define DWMCI_DATA 0x200
48/* Registers to support IDMAC 32-bit address mode */
Jaehoon Chung7cf73072012-10-15 19:10:29 +000049#define DWMCI_DBADDR 0x088
Sam Protsenko286892e2024-08-07 22:14:19 -050050#define DWMCI_IDSTS 0x08c
Jaehoon Chung7cf73072012-10-15 19:10:29 +000051#define DWMCI_IDINTEN 0x090
52#define DWMCI_DSCADDR 0x094
53#define DWMCI_BUFADDR 0x098
Sam Protsenko7c991612024-08-07 22:14:16 -050054/* Registers to support IDMAC 64-bit address mode */
55#define DWMCI_DBADDRL 0x088
56#define DWMCI_DBADDRU 0x08c
57#define DWMCI_IDSTS64 0x090
58#define DWMCI_IDINTEN64 0x094
59#define DWMCI_DSCADDRL 0x098
60#define DWMCI_DSCADDRU 0x09c
61#define DWMCI_BUFADDRL 0x0a0
62#define DWMCI_BUFADDRU 0x0a4
Jaehoon Chung7cf73072012-10-15 19:10:29 +000063
64/* Interrupt Mask register */
65#define DWMCI_INTMSK_ALL 0xffffffff
Sam Protsenko286892e2024-08-07 22:14:19 -050066#define DWMCI_INTMSK_RE BIT(1)
67#define DWMCI_INTMSK_CDONE BIT(2)
68#define DWMCI_INTMSK_DTO BIT(3)
69#define DWMCI_INTMSK_TXDR BIT(4)
70#define DWMCI_INTMSK_RXDR BIT(5)
71#define DWMCI_INTMSK_RCRC BIT(6)
72#define DWMCI_INTMSK_DCRC BIT(7)
73#define DWMCI_INTMSK_RTO BIT(8)
74#define DWMCI_INTMSK_DRTO BIT(9)
75#define DWMCI_INTMSK_HTO BIT(10)
76#define DWMCI_INTMSK_FRUN BIT(11)
77#define DWMCI_INTMSK_HLE BIT(12)
78#define DWMCI_INTMSK_SBE BIT(13)
79#define DWMCI_INTMSK_ACD BIT(14)
80#define DWMCI_INTMSK_EBE BIT(15)
Jaehoon Chung7cf73072012-10-15 19:10:29 +000081
Sam Protsenko286892e2024-08-07 22:14:19 -050082/* Raw interrupt register */
83#define DWMCI_DATA_ERR (DWMCI_INTMSK_EBE | DWMCI_INTMSK_SBE | \
84 DWMCI_INTMSK_HLE | DWMCI_INTMSK_FRUN | \
85 DWMCI_INTMSK_EBE | DWMCI_INTMSK_DCRC)
86#define DWMCI_DATA_TOUT (DWMCI_INTMSK_HTO | DWMCI_INTMSK_DRTO)
87
Jaehoon Chung7cf73072012-10-15 19:10:29 +000088/* CTRL register */
Sam Protsenko286892e2024-08-07 22:14:19 -050089#define DWMCI_CTRL_RESET BIT(0)
90#define DWMCI_CTRL_FIFO_RESET BIT(1)
91#define DWMCI_CTRL_DMA_RESET BIT(2)
92#define DWMCI_DMA_EN BIT(5)
93#define DWMCI_CTRL_SEND_AS_CCSD BIT(10)
94#define DWMCI_IDMAC_EN BIT(25)
Jaehoon Chung7cf73072012-10-15 19:10:29 +000095#define DWMCI_RESET_ALL (DWMCI_CTRL_RESET | DWMCI_CTRL_FIFO_RESET |\
96 DWMCI_CTRL_DMA_RESET)
97
98/* CMD register */
Sam Protsenko286892e2024-08-07 22:14:19 -050099#define DWMCI_CMD_RESP_EXP BIT(6)
100#define DWMCI_CMD_RESP_LENGTH BIT(7)
101#define DWMCI_CMD_CHECK_CRC BIT(8)
102#define DWMCI_CMD_DATA_EXP BIT(9)
103#define DWMCI_CMD_RW BIT(10)
104#define DWMCI_CMD_SEND_STOP BIT(12)
105#define DWMCI_CMD_ABORT_STOP BIT(14)
106#define DWMCI_CMD_PRV_DAT_WAIT BIT(13)
107#define DWMCI_CMD_UPD_CLK BIT(21)
108#define DWMCI_CMD_USE_HOLD_REG BIT(29)
109#define DWMCI_CMD_START BIT(31)
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000110
111/* CLKENA register */
Sam Protsenko286892e2024-08-07 22:14:19 -0500112#define DWMCI_CLKEN_ENABLE BIT(0)
113#define DWMCI_CLKEN_LOW_PWR BIT(16)
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000114
Sam Protsenko286892e2024-08-07 22:14:19 -0500115/* Card type register */
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000116#define DWMCI_CTYPE_1BIT 0
Sam Protsenko286892e2024-08-07 22:14:19 -0500117#define DWMCI_CTYPE_4BIT BIT(0)
118#define DWMCI_CTYPE_8BIT BIT(16)
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000119
Sam Protsenko286892e2024-08-07 22:14:19 -0500120/* Status register */
121#define DWMCI_FIFO_EMPTY BIT(2)
122#define DWMCI_FIFO_FULL BIT(3)
123#define DWMCI_BUSY BIT(9)
Jaehoon Chung6463b372016-07-28 14:26:24 +0900124#define DWMCI_FIFO_MASK 0x1fff
huang lin50b73752015-11-17 14:20:22 +0800125#define DWMCI_FIFO_SHIFT 17
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000126
Sam Protsenko286892e2024-08-07 22:14:19 -0500127/* FIFOTH register */
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000128#define MSIZE(x) ((x) << 28)
129#define RX_WMARK(x) ((x) << 16)
130#define TX_WMARK(x) (x)
Amard8501212013-04-27 11:42:55 +0530131#define RX_WMARK_SHIFT 16
132#define RX_WMARK_MASK (0xfff << RX_WMARK_SHIFT)
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000133
Sam Protsenko286892e2024-08-07 22:14:19 -0500134#define DWMCI_IDMAC_OWN BIT(31)
135#define DWMCI_IDMAC_CH BIT(4)
136#define DWMCI_IDMAC_FS BIT(3)
137#define DWMCI_IDMAC_LD BIT(2)
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000138
Sam Protsenko286892e2024-08-07 22:14:19 -0500139/* Bus Mode register */
140#define DWMCI_BMOD_IDMAC_RESET BIT(0)
141#define DWMCI_BMOD_IDMAC_FB BIT(1)
142#define DWMCI_BMOD_IDMAC_EN BIT(7)
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000143
Jaehoon Chunge8672942014-05-16 13:59:55 +0900144/* UHS register */
Sam Protsenko286892e2024-08-07 22:14:19 -0500145#define DWMCI_DDR_MODE BIT(16)
Jaehoon Chunge8672942014-05-16 13:59:55 +0900146
Ley Foon Tanb98e8922018-12-20 17:55:41 +0800147/* Internal IDMAC interrupt defines */
Sam Protsenko286892e2024-08-07 22:14:19 -0500148#define DWMCI_IDINTEN_RI BIT(1)
149#define DWMCI_IDINTEN_TI BIT(0)
150#define DWMCI_IDINTEN_MASK (DWMCI_IDINTEN_TI | DWMCI_IDINTEN_RI)
Ley Foon Tanb98e8922018-12-20 17:55:41 +0800151
Simon Glassc3588812015-06-23 15:38:52 -0600152/**
Sam Protsenko7c991612024-08-07 22:14:16 -0500153 * struct dwmci_idmac_regs - Offsets of IDMAC registers
154 *
155 * @dbaddrl: Descriptor base address, lower 32 bits
156 * @dbaddru: Descriptor base address, upper 32 bits
157 * @idsts: Internal DMA status
158 * @idinten: Internal DMA interrupt enable
159 * @dscaddrl: IDMAC descriptor address, lower 32 bits
160 * @dscaddru: IDMAC descriptor address, upper 32 bits
161 * @bufaddrl: Current data buffer address, lower 32 bits
162 * @bufaddru: Current data buffer address, upper 32 bits
163 */
164struct dwmci_idmac_regs {
165 u32 dbaddrl;
166 u32 dbaddru;
167 u32 idsts;
168 u32 idinten;
169 u32 dscaddrl;
170 u32 dscaddru;
171 u32 bufaddrl;
172 u32 bufaddru;
173};
174
175/**
Simon Glassc3588812015-06-23 15:38:52 -0600176 * struct dwmci_host - Information about a designware MMC host
177 *
178 * @name: Device name
179 * @ioaddr: Base I/O address of controller
Simon Glassc3588812015-06-23 15:38:52 -0600180 * @caps: Capabilities - see MMC_MODE_...
Sam Protsenkof1f9c4f2024-08-07 22:14:18 -0500181 * @clock: Current clock frequency (after internal divider), Hz
Simon Glassc3588812015-06-23 15:38:52 -0600182 * @bus_hz: Bus speed in Hz, if @get_mmc_clk() is NULL
Simon Glassc3588812015-06-23 15:38:52 -0600183 * @dev_index: Arbitrary device index for use by controller
184 * @dev_id: Arbitrary device ID for use by controller
185 * @buswidth: Bus width in bits (8 or 4)
Sam Protsenko751fdf12024-08-07 22:14:17 -0500186 * @fifo_depth: Depth of FIFO, bytes (or 0 for automatic detection)
Simon Glassc3588812015-06-23 15:38:52 -0600187 * @mmc: Pointer to generic MMC structure for this device
188 * @priv: Private pointer for use by controller
Sam Protsenkof1f9c4f2024-08-07 22:14:18 -0500189 * @clksel: (Optional) Platform function to run when speed/width is changed
190 * @board_init: (Optional) Platform function to run on init
191 * @cfg: Internal MMC configuration, for !CONFIG_BLK cases
192 * @fifo_mode: Use FIFO mode (not DMA) to read and write data
Sam Protsenko7c991612024-08-07 22:14:16 -0500193 * @dma_64bit_address: Whether DMA supports 64-bit address mode or not
194 * @regs: Registers that can vary for different DW MMC block versions
Simon Glassc3588812015-06-23 15:38:52 -0600195 */
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000196struct dwmci_host {
Simon Glassc3588812015-06-23 15:38:52 -0600197 const char *name;
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000198 void *ioaddr;
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000199 unsigned int caps;
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000200 unsigned int clock;
201 unsigned int bus_hz;
202 int dev_index;
Jaehoon Chung62811102014-05-16 13:59:52 +0900203 int dev_id;
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000204 int buswidth;
Sam Protsenko751fdf12024-08-07 22:14:17 -0500205 u32 fifo_depth;
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000206 struct mmc *mmc;
Jaehoon Chungbcb03eab2015-02-04 15:48:40 +0900207 void *priv;
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000208
Siew Chin Limc51e7e12020-12-24 18:21:03 +0800209 int (*clksel)(struct dwmci_host *host);
Jaehoon Chung42f81a82013-11-29 20:08:57 +0900210 void (*board_init)(struct dwmci_host *host);
Simon Glasseff76682015-08-30 16:55:15 -0600211 /**
Sam Protsenkof1f9c4f2024-08-07 22:14:18 -0500212 * @get_mmc_clk: (Optional) Platform function to get/set a particular
213 * MMC clock frequency
214 *
215 * @host: DWMMC host
216 * @freq: Frequency the host is trying to achieve
Simon Glasseff76682015-08-30 16:55:15 -0600217 *
218 * This is used to request the current clock frequency of the clock
219 * that drives the DWMMC peripheral. The caller will then use this
220 * information to work out the divider it needs to achieve the
221 * required MMC bus clock frequency. If you want to handle the
222 * clock external to DWMMC, use @freq to select the frequency and
223 * return that value too. Then DWMMC will put itself in bypass mode.
Simon Glasseff76682015-08-30 16:55:15 -0600224 */
225 unsigned int (*get_mmc_clk)(struct dwmci_host *host, uint freq);
Sam Protsenko286892e2024-08-07 22:14:19 -0500226
Simon Glass82682542016-05-14 14:03:07 -0600227#ifndef CONFIG_BLK
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200228 struct mmc_config cfg;
Simon Glass82682542016-05-14 14:03:07 -0600229#endif
huang lin50b73752015-11-17 14:20:22 +0800230
huang lin50b73752015-11-17 14:20:22 +0800231 bool fifo_mode;
Sam Protsenko7c991612024-08-07 22:14:16 -0500232 bool dma_64bit_address;
233 const struct dwmci_idmac_regs *regs;
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000234};
235
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000236static inline void dwmci_writel(struct dwmci_host *host, int reg, u32 val)
237{
238 writel(val, host->ioaddr + reg);
239}
240
241static inline void dwmci_writew(struct dwmci_host *host, int reg, u16 val)
242{
243 writew(val, host->ioaddr + reg);
244}
245
246static inline void dwmci_writeb(struct dwmci_host *host, int reg, u8 val)
247{
248 writeb(val, host->ioaddr + reg);
249}
Sam Protsenko286892e2024-08-07 22:14:19 -0500250
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000251static inline u32 dwmci_readl(struct dwmci_host *host, int reg)
252{
253 return readl(host->ioaddr + reg);
254}
255
256static inline u16 dwmci_readw(struct dwmci_host *host, int reg)
257{
258 return readw(host->ioaddr + reg);
259}
260
261static inline u8 dwmci_readb(struct dwmci_host *host, int reg)
262{
263 return readb(host->ioaddr + reg);
264}
265
Simon Glass558f94a2016-06-12 23:30:13 -0600266#ifdef CONFIG_BLK
Sam Protsenko286892e2024-08-07 22:14:19 -0500267
Simon Glass558f94a2016-06-12 23:30:13 -0600268/**
269 * dwmci_setup_cfg() - Set up the configuration for DWMMC
Sam Protsenkof1f9c4f2024-08-07 22:14:18 -0500270 * @cfg: Configuration structure to fill in (generally &plat->mmc)
271 * @host: DWMMC host
272 * @max_clk: Maximum supported clock speed in Hz (e.g. 150000000)
273 * @min_clk: Minimum supported clock speed in Hz (e.g. 400000)
Simon Glass558f94a2016-06-12 23:30:13 -0600274 *
275 * This is used to set up a DWMMC device when you are using CONFIG_BLK.
276 *
277 * This should be called from your MMC driver's probe() method once you have
278 * the information required.
279 *
280 * Generally your driver will have a platform data structure which holds both
281 * the configuration (struct mmc_config) and the MMC device info (struct mmc).
282 * For example:
283 *
284 * struct rockchip_mmc_plat {
285 * struct mmc_config cfg;
286 * struct mmc mmc;
287 * };
288 *
289 * ...
290 *
291 * Inside U_BOOT_DRIVER():
Simon Glass71fa5b42020-12-03 16:55:18 -0700292 * .plat_auto = sizeof(struct rockchip_mmc_plat),
Simon Glass558f94a2016-06-12 23:30:13 -0600293 *
294 * To access platform data:
Simon Glassfa20e932020-12-03 16:55:20 -0700295 * struct rockchip_mmc_plat *plat = dev_get_plat(dev);
Simon Glass558f94a2016-06-12 23:30:13 -0600296 *
297 * See rockchip_dw_mmc.c for an example.
Simon Glass558f94a2016-06-12 23:30:13 -0600298 */
Jaehoon Chungbf819d02016-09-23 19:13:16 +0900299void dwmci_setup_cfg(struct mmc_config *cfg, struct dwmci_host *host,
Sam Protsenko286892e2024-08-07 22:14:19 -0500300 u32 max_clk, u32 min_clk);
Simon Glass558f94a2016-06-12 23:30:13 -0600301
302/**
303 * dwmci_bind() - Set up a new MMC block device
Sam Protsenkof1f9c4f2024-08-07 22:14:18 -0500304 * @dev: Device to set up
305 * @mmc: Pointer to mmc structure (normally &plat->mmc)
306 * @cfg: Empty configuration structure (generally &plat->cfg). This is
307 * normally all zeroes at this point. The only purpose of passing
308 * this in is to set mmc->cfg to it.
Simon Glass558f94a2016-06-12 23:30:13 -0600309 *
310 * This is used to set up a DWMMC block device when you are using CONFIG_BLK.
311 * It should be called from your driver's bind() method.
312 *
313 * See rockchip_dw_mmc.c for an example.
314 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100315 * Return: 0 if OK, -ve if the block device could not be created
Simon Glass558f94a2016-06-12 23:30:13 -0600316 */
Simon Glass82682542016-05-14 14:03:07 -0600317int dwmci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg);
318
Simon Glass558f94a2016-06-12 23:30:13 -0600319#else
Sam Protsenko286892e2024-08-07 22:14:19 -0500320
Simon Glass558f94a2016-06-12 23:30:13 -0600321/**
322 * add_dwmci() - Add a new DWMMC interface
Sam Protsenkof1f9c4f2024-08-07 22:14:18 -0500323 * @host: DWMMC host structure
324 * @max_clk: Maximum supported clock speed in Hz (e.g. 150000000)
325 * @min_clk: Minimum supported clock speed in Hz (e.g. 400000)
Simon Glass558f94a2016-06-12 23:30:13 -0600326 *
327 * This is used when you are not using CONFIG_BLK. Convert your driver over!
328 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100329 * Return: 0 if OK, -ve on error
Simon Glass558f94a2016-06-12 23:30:13 -0600330 */
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000331int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk);
Sam Protsenko286892e2024-08-07 22:14:19 -0500332
Simon Glass558f94a2016-06-12 23:30:13 -0600333#endif /* !CONFIG_BLK */
334
Simon Glasseba48f92017-07-29 11:35:31 -0600335#ifdef CONFIG_DM_MMC
Simon Glassff5c1b72016-06-12 23:30:23 -0600336/* Export the operations to drivers */
Simon Glassff5c1b72016-06-12 23:30:23 -0600337int dwmci_probe(struct udevice *dev);
338extern const struct dm_mmc_ops dm_dwmci_ops;
339#endif
340
Jaehoon Chung7cf73072012-10-15 19:10:29 +0000341#endif /* __DWMMC_HW_H */