dw_mmc: add an option to force 32-bit accesses to 64-bit device registers
Subsystems (2)
PATCH 2/2 dw_mmc: add an option to force 32-bit accesses to 64-bit device registers
--- drivers/mmc/host/dw_mmc.c | 125 +++++++++++++++++++++++++++++++++++++- drivers/mmc/host/dw_mmc.h | 2 + 2 files changed, 125 insertions(+), 2 deletions(-)
drivers/mmc/host/dw_mmc.c +123 -2
@@ -2575,6 +2575,119 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) } } +/* +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. + +XXX: Is this issue specific to Exynos7? +*/ + +static inline uint64_t mci_fifo_readq_32 (void __iomem *addr) +{ +uint64_t ans; +uint32_t 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_writeq_32 (void __iomem *addr,uint64_t value) +{ +uint32_t proxy[2 ]; + +memcpy (proxy, &value,8 ); +mci_fifo_writel (addr, proxy[0 ]); +mci_fifo_writel (addr+4 , proxy[1 ]); +} + +static void dw_mci_push_data64_32 (struct dw_mci *host,void *buf,int cnt) +{ +struct mmc_data *data = host->data; +int init_cnt = cnt; + +/* try and push anything in the part_buf */ +if (unlikely (host->part_buf_count)) { +int len =dw_mci_push_part_bytes (host, buf, cnt); + + buf += len; + cnt -= len; + +if (host->part_buf_count ==8 ) { +mci_fifo_writeq_32 (host->fifo_reg, host->part_buf); + host->part_buf_count =0 ; + } + } +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +if (unlikely ((unsigned long )buf &0x7 )) { +while (cnt >=8 ) { +u64 aligned_buf[16 ]; +int len =min (cnt &-8 , (int )sizeof (aligned_buf)); +int items = len >>3 ; +int i; +/* memcpy from input buffer into aligned buffer */ +memcpy (aligned_buf, buf, len); + buf += len; + cnt -= len; +/* push data from aligned buffer into fifo */ +for (i =0 ; i < items; ++i) +mci_fifo_writeq_32 (host->fifo_reg, aligned_buf[i]); + } + } else +#endif + { +u64 *pdata = buf; + +for (; cnt >=8 ; cnt -=8 ) +mci_fifo_writeq_32 (host->fifo_reg, *pdata++); + buf = pdata; + } +/* put anything remaining in the part_buf */ +if (cnt) { +dw_mci_set_part_bytes (host, buf, cnt); +/* Push data if we have reached the expected data length */ +if ((data->bytes_xfered + init_cnt) == + (data->blksz * data->blocks)) +mci_fifo_writeq_32 (host->fifo_reg, host->part_buf); + } +} + +static void dw_mci_pull_data64_32 (struct dw_mci *host,void *buf,int cnt) +{ +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +if (unlikely ((unsigned long )buf &0x7 )) { +while (cnt >=8 ) { +/* pull data from fifo into aligned buffer */ +u64 aligned_buf[16 ]; +int len =min (cnt &-8 , (int )sizeof (aligned_buf)); +int items = len >>3 ; +int i; + +for (i =0 ; i < items; ++i) + aligned_buf[i] =mci_fifo_readq_32 (host->fifo_reg); + +/* memcpy from aligned buffer into output buffer */ +memcpy (buf, aligned_buf, len); + buf += len; + cnt -= len; + } + } else +#endif + { +u64 *pdata = buf; + +for (; cnt >=8 ; cnt -=8 ) + *pdata++ =mci_fifo_readq_32 (host->fifo_reg); + buf = pdata; + } +if (cnt) { + host->part_buf =mci_fifo_readq_32 (host->fifo_reg); +dw_mci_pull_final_bytes (host, buf, cnt); + } +} +static void dw_mci_pull_data (struct dw_mci *host,void *buf,int cnt) {int len;
@@ -3239,6 +3352,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)if (device_property_present (dev,"fifo-watermark-aligned" )) host->wm_aligned = true; +if (device_property_present (dev,"fifo-access-32bit" )) + host->quirks |=DW_MMC_QUIRK_FIFO64_32 ; +if (!device_property_read_u32 (dev,"clock-frequency" , &clock_frequency)) pdata->bus_hz = clock_frequency;
@@ -3367,8 +3483,13 @@ int dw_mci_probe(struct dw_mci *host) width =16 ; host->data_shift =1 ; }else if (i ==2 ) { - host->push_data = dw_mci_push_data64; - host->pull_data = dw_mci_pull_data64; +if ((host->quirks &DW_MMC_QUIRK_FIFO64_32 )) { + host->push_data = dw_mci_push_data64_32; + host->pull_data = dw_mci_pull_data64_32; + }else { + host->push_data = dw_mci_push_data64; + host->pull_data = dw_mci_pull_data64; + } width =64 ; host->data_shift =3 ; }else {
drivers/mmc/host/dw_mmc.h +2 -0
@@ -280,6 +280,8 @@ struct dw_mci_board {/* 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
Signature · 1 line
2.38.3