diff options
Diffstat (limited to 'drivers/mmc/host/dw_mmc.h')
| -rw-r--r-- | drivers/mmc/host/dw_mmc.h | 105 |
1 files changed, 83 insertions, 22 deletions
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 75da3756955d..648b4a5641bf 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Synopsys DesignWare Multimedia Card Interface driver * (Based on NXP driver for lpc 31xx) * * Copyright (C) 2009 NXP Semiconductors * Copyright (C) 2009, 2010 Imagination Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #ifndef _DW_MMC_H_ @@ -18,7 +14,10 @@ #include <linux/mmc/core.h> #include <linux/dmaengine.h> #include <linux/reset.h> +#include <linux/fault-inject.h> +#include <linux/hrtimer.h> #include <linux/interrupt.h> +#include <linux/workqueue.h> enum dw_mci_state { STATE_IDLE = 0, @@ -65,8 +64,7 @@ struct dw_mci_dma_slave { * @fifo_reg: Pointer to MMIO registers for data FIFO * @sg: Scatterlist entry currently being processed by PIO code, if any. * @sg_miter: PIO mapping scatterlist iterator. - * @cur_slot: The slot which is currently using the controller. - * @mrq: The request currently being processed on @cur_slot, + * @mrq: The request currently being processed on @slot, * or NULL if the controller is idle. * @cmd: The command currently being sent to the card, or NULL. * @data: The data currently being transferred, or NULL if no data @@ -74,7 +72,8 @@ struct dw_mci_dma_slave { * @stop_abort: The command currently prepared for stoping transfer. * @prev_blksz: The former transfer blksz record. * @timing: Record of current ios timing. - * @use_dma: Whether DMA channel is initialized or not. + * @use_dma: Which DMA channel is in use for the current transfer, zero + * denotes PIO mode. * @using_dma: Whether DMA is in use for the current transfer. * @dma_64bit_address: Whether DMA supports 64-bit address mode or not. * @sg_dma: Bus address of DMA buffer. @@ -91,17 +90,17 @@ struct dw_mci_dma_slave { * @stop_cmdr: Value to be loaded into CMDR when the stop command is * to be sent. * @dir_status: Direction of current transfer. - * @tasklet: Tasklet running the request state machine. + * @bh_work: Work running the request state machine. * @pending_events: Bitmask of events flagged by the interrupt handler - * to be processed by the tasklet. + * to be processed by bh work. * @completed_events: Bitmask of events which the state machine has * processed. - * @state: Tasklet state. + * @state: BH work state. * @queue: List of slots waiting for access to the controller. * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus * rate and timeout calculations. * @current_speed: Configured rate of the controller. - * @num_slots: Number of slots available. + * @minimum_speed: Stored minimum rate of the controller. * @fifoth_val: The value of FIFOTH register. * @verid: Denote Version ID. * @dev: Device associated with the MMC controller. @@ -121,28 +120,30 @@ struct dw_mci_dma_slave { * @part_buf: Simple buffer for partial fifo reads/writes. * @push_data: Pointer to FIFO push function. * @pull_data: Pointer to FIFO pull function. + * @quirks: Set of quirks that apply to specific versions of the IP. * @vqmmc_enabled: Status of vqmmc, should be true or false. * @irq_flags: The flags to be passed to request_irq. * @irq: The irq value to be passed to request_irq. * @sdio_id0: Number of slot0 in the SDIO interrupt registers. * @cmd11_timer: Timer for SD3.0 voltage switch over scheme. + * @cto_timer: Timer for broken command transfer over scheme. * @dto_timer: Timer for broken data transfer over scheme. * * Locking * ======= * * @lock is a softirq-safe spinlock protecting @queue as well as + * @slot, @mrq and @state. These must always be updated * at the same time while holding @lock. + * The @mrq field of struct dw_mci_slot is also protected by @lock, + * and must always be written at the same time as the slot is added to + * @queue. * * @irq_lock is an irq-safe spinlock protecting the INTMASK register * to allow the interrupt handler to modify it directly. Held for only long * enough to read-modify-write INTMASK and no other locks are grabbed when * holding this one. * - * The @mrq field of struct dw_mci_slot is also protected by @lock, - * and must always be written at the same time as the slot is added to - * @queue. - * * @pending_events and @completed_events are accessed using atomic bit * operations, so they don't need any locking. * @@ -194,7 +195,7 @@ struct dw_mci { u32 data_status; u32 stop_cmdr; u32 dir_status; - struct tasklet_struct tasklet; + struct work_struct bh_work; unsigned long pending_events; unsigned long completed_events; enum dw_mci_state state; @@ -202,6 +203,7 @@ struct dw_mci { u32 bus_hz; u32 current_speed; + u32 minimum_speed; u32 fifoth_val; u16 verid; struct device *dev; @@ -225,6 +227,7 @@ struct dw_mci { void (*push_data)(struct dw_mci *host, void *buf, int cnt); void (*pull_data)(struct dw_mci *host, void *buf, int cnt); + u32 quirks; bool vqmmc_enabled; unsigned long irq_flags; /* IRQ flags */ int irq; @@ -232,7 +235,13 @@ struct dw_mci { int sdio_id0; struct timer_list cmd11_timer; + struct timer_list cto_timer; struct timer_list dto_timer; + +#ifdef CONFIG_FAULT_INJECTION + struct fault_attr fail_data_crc; + struct hrtimer fault_timer; +#endif }; /* DMA ops for Internal/External DMAC interface */ @@ -250,8 +259,6 @@ struct dma_pdata; /* Board platform data */ struct dw_mci_board { - u32 num_slots; - unsigned int bus_hz; /* Clock speed at the cclk_in pad */ u32 caps; /* Capabilities */ @@ -272,6 +279,11 @@ struct dw_mci_board { struct dma_pdata *data; }; +/* Support for longer data read timeout */ +#define DW_MMC_QUIRK_EXTENDED_TMOUT BIT(0) +/* Force 32-bit access to the FIFO */ +#define DW_MMC_QUIRK_FIFO64_32 BIT(1) + #define DW_MMC_240A 0x240a #define DW_MMC_280A 0x280a @@ -314,10 +326,13 @@ struct dw_mci_board { #define SDMMC_DSCADDR 0x094 #define SDMMC_BUFADDR 0x098 #define SDMMC_CDTHRCTL 0x100 +#define SDMMC_UHS_REG_EXT 0x108 +#define SDMMC_DDR_REG 0x10c +#define SDMMC_ENABLE_SHIFT 0x110 #define SDMMC_DATA(x) (x) /* -* Registers to support idmac 64-bit address mode -*/ + * Registers to support idmac 64-bit address mode + */ #define SDMMC_DBADDRL 0x088 #define SDMMC_DBADDRU 0x08c #define SDMMC_IDSTS64 0x090 @@ -438,13 +453,19 @@ struct dw_mci_board { #define SDMMC_CARD_WR_THR_EN BIT(2) #define SDMMC_CARD_RD_THR_EN BIT(0) /* UHS-1 register defines */ +#define SDMMC_UHS_DDR BIT(16) #define SDMMC_UHS_18V BIT(0) +/* DDR register defines */ +#define SDMMC_DDR_HS400 BIT(31) +/* Enable shift register defines */ +#define SDMMC_ENABLE_PHASE BIT(0) /* All ctrl reset bits */ #define SDMMC_CTRL_ALL_RESET_FLAGS \ (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) /* FIFO register access macros. These should not change the data endian-ness - * as they are written to memory to be dealt with by the upper layers */ + * as they are written to memory to be dealt with by the upper layers + */ #define mci_fifo_readw(__reg) __raw_readw(__reg) #define mci_fifo_readl(__reg) __raw_readl(__reg) #define mci_fifo_readq(__reg) __raw_readq(__reg) @@ -453,6 +474,31 @@ struct dw_mci_board { #define mci_fifo_writel(__value, __reg) __raw_writel(__reg, __value) #define mci_fifo_writeq(__value, __reg) __raw_writeq(__reg, __value) +/* + * Some dw_mmc devices have 64-bit FIFOs, but expect them to be + * accessed using two 32-bit accesses. If such controller is used + * with a 64-bit kernel, this has to be done explicitly. + */ +static inline u64 mci_fifo_l_readq(void __iomem *addr) +{ + u64 ans; + u32 proxy[2]; + + proxy[0] = mci_fifo_readl(addr); + proxy[1] = mci_fifo_readl(addr + 4); + memcpy(&ans, proxy, 8); + return ans; +} + +static inline void mci_fifo_l_writeq(void __iomem *addr, u64 value) +{ + u32 proxy[2]; + + memcpy(proxy, &value, 8); + mci_fifo_writel(addr, proxy[0]); + mci_fifo_writel(addr + 4, proxy[1]); +} + /* Register access macros */ #define mci_readl(dev, reg) \ readl_relaxed((dev)->regs + SDMMC_##reg) @@ -495,6 +541,9 @@ extern void dw_mci_remove(struct dw_mci *host); #ifdef CONFIG_PM extern int dw_mci_runtime_suspend(struct device *device); extern int dw_mci_runtime_resume(struct device *device); +#else +static inline int dw_mci_runtime_suspend(struct device *device) { return -EOPNOTSUPP; } +static inline int dw_mci_runtime_resume(struct device *device) { return -EOPNOTSUPP; } #endif /** @@ -538,10 +587,16 @@ struct dw_mci_slot { /** * dw_mci driver data - dw-mshc implementation specific driver data. * @caps: mmc subsystem specified capabilities of the controller(s). + * @num_caps: number of capabilities specified by @caps. + * @common_caps: mmc subsystem specified capabilities applicable to all of + * the controllers * @init: early implementation specific initialization. * @set_ios: handle bus specific extensions. * @parse_dt: parse implementation specific device tree properties. * @execute_tuning: implementation specific tuning procedure. + * @set_data_timeout: implementation specific timeout. + * @get_drto_clks: implementation specific cycle count for data read timeout. + * @hw_reset: implementation specific HW reset. * * Provide controller implementation specific extensions. The usage of this * data structure is fully optional and usage of each member in this structure @@ -549,6 +604,8 @@ struct dw_mci_slot { */ struct dw_mci_drv_data { unsigned long *caps; + u32 num_caps; + u32 common_caps; int (*init)(struct dw_mci *host); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); int (*parse_dt)(struct dw_mci *host); @@ -557,5 +614,9 @@ struct dw_mci_drv_data { struct mmc_ios *ios); int (*switch_voltage)(struct mmc_host *mmc, struct mmc_ios *ios); + void (*set_data_timeout)(struct dw_mci *host, + unsigned int timeout_ns); + u32 (*get_drto_clks)(struct dw_mci *host); + void (*hw_reset)(struct dw_mci *host); }; #endif /* _DW_MMC_H_ */ |
