162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. 662306a36Sopenharmony_ci * Copyright (C) 2010 ST-Ericsson SA 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/moduleparam.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/ioport.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <linux/err.h> 1962306a36Sopenharmony_ci#include <linux/highmem.h> 2062306a36Sopenharmony_ci#include <linux/log2.h> 2162306a36Sopenharmony_ci#include <linux/mmc/mmc.h> 2262306a36Sopenharmony_ci#include <linux/mmc/pm.h> 2362306a36Sopenharmony_ci#include <linux/mmc/host.h> 2462306a36Sopenharmony_ci#include <linux/mmc/card.h> 2562306a36Sopenharmony_ci#include <linux/mmc/sd.h> 2662306a36Sopenharmony_ci#include <linux/mmc/slot-gpio.h> 2762306a36Sopenharmony_ci#include <linux/amba/bus.h> 2862306a36Sopenharmony_ci#include <linux/clk.h> 2962306a36Sopenharmony_ci#include <linux/scatterlist.h> 3062306a36Sopenharmony_ci#include <linux/of.h> 3162306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 3262306a36Sopenharmony_ci#include <linux/dmaengine.h> 3362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3462306a36Sopenharmony_ci#include <linux/amba/mmci.h> 3562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3662306a36Sopenharmony_ci#include <linux/types.h> 3762306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 3862306a36Sopenharmony_ci#include <linux/reset.h> 3962306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 4062306a36Sopenharmony_ci#include <linux/workqueue.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include <asm/div64.h> 4362306a36Sopenharmony_ci#include <asm/io.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "mmci.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define DRIVER_NAME "mmci-pl18x" 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void mmci_variant_init(struct mmci_host *host); 5062306a36Sopenharmony_cistatic void ux500_variant_init(struct mmci_host *host); 5162306a36Sopenharmony_cistatic void ux500v2_variant_init(struct mmci_host *host); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic unsigned int fmax = 515633; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic struct variant_data variant_arm = { 5662306a36Sopenharmony_ci .fifosize = 16 * 4, 5762306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 5862306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 5962306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 6062306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 6162306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 6262306a36Sopenharmony_ci .datalength_bits = 16, 6362306a36Sopenharmony_ci .datactrl_blocksz = 11, 6462306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_UP, 6562306a36Sopenharmony_ci .f_max = 100000000, 6662306a36Sopenharmony_ci .reversed_irq_handling = true, 6762306a36Sopenharmony_ci .mmcimask1 = true, 6862306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 6962306a36Sopenharmony_ci .start_err = MCI_STARTBITERR, 7062306a36Sopenharmony_ci .opendrain = MCI_ROD, 7162306a36Sopenharmony_ci .init = mmci_variant_init, 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct variant_data variant_arm_extended_fifo = { 7562306a36Sopenharmony_ci .fifosize = 128 * 4, 7662306a36Sopenharmony_ci .fifohalfsize = 64 * 4, 7762306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 7862306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 7962306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 8062306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 8162306a36Sopenharmony_ci .datalength_bits = 16, 8262306a36Sopenharmony_ci .datactrl_blocksz = 11, 8362306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_UP, 8462306a36Sopenharmony_ci .f_max = 100000000, 8562306a36Sopenharmony_ci .mmcimask1 = true, 8662306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 8762306a36Sopenharmony_ci .start_err = MCI_STARTBITERR, 8862306a36Sopenharmony_ci .opendrain = MCI_ROD, 8962306a36Sopenharmony_ci .init = mmci_variant_init, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic struct variant_data variant_arm_extended_fifo_hwfc = { 9362306a36Sopenharmony_ci .fifosize = 128 * 4, 9462306a36Sopenharmony_ci .fifohalfsize = 64 * 4, 9562306a36Sopenharmony_ci .clkreg_enable = MCI_ARM_HWFCEN, 9662306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 9762306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 9862306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 9962306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 10062306a36Sopenharmony_ci .datalength_bits = 16, 10162306a36Sopenharmony_ci .datactrl_blocksz = 11, 10262306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_UP, 10362306a36Sopenharmony_ci .f_max = 100000000, 10462306a36Sopenharmony_ci .mmcimask1 = true, 10562306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 10662306a36Sopenharmony_ci .start_err = MCI_STARTBITERR, 10762306a36Sopenharmony_ci .opendrain = MCI_ROD, 10862306a36Sopenharmony_ci .init = mmci_variant_init, 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct variant_data variant_u300 = { 11262306a36Sopenharmony_ci .fifosize = 16 * 4, 11362306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 11462306a36Sopenharmony_ci .clkreg_enable = MCI_ST_U300_HWFCEN, 11562306a36Sopenharmony_ci .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, 11662306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 11762306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 11862306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 11962306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 12062306a36Sopenharmony_ci .datalength_bits = 16, 12162306a36Sopenharmony_ci .datactrl_blocksz = 11, 12262306a36Sopenharmony_ci .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, 12362306a36Sopenharmony_ci .st_sdio = true, 12462306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_ON, 12562306a36Sopenharmony_ci .f_max = 100000000, 12662306a36Sopenharmony_ci .signal_direction = true, 12762306a36Sopenharmony_ci .pwrreg_clkgate = true, 12862306a36Sopenharmony_ci .pwrreg_nopower = true, 12962306a36Sopenharmony_ci .mmcimask1 = true, 13062306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 13162306a36Sopenharmony_ci .start_err = MCI_STARTBITERR, 13262306a36Sopenharmony_ci .opendrain = MCI_OD, 13362306a36Sopenharmony_ci .init = mmci_variant_init, 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic struct variant_data variant_nomadik = { 13762306a36Sopenharmony_ci .fifosize = 16 * 4, 13862306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 13962306a36Sopenharmony_ci .clkreg = MCI_CLK_ENABLE, 14062306a36Sopenharmony_ci .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, 14162306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 14262306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 14362306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 14462306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 14562306a36Sopenharmony_ci .datalength_bits = 24, 14662306a36Sopenharmony_ci .datactrl_blocksz = 11, 14762306a36Sopenharmony_ci .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, 14862306a36Sopenharmony_ci .st_sdio = true, 14962306a36Sopenharmony_ci .st_clkdiv = true, 15062306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_ON, 15162306a36Sopenharmony_ci .f_max = 100000000, 15262306a36Sopenharmony_ci .signal_direction = true, 15362306a36Sopenharmony_ci .pwrreg_clkgate = true, 15462306a36Sopenharmony_ci .pwrreg_nopower = true, 15562306a36Sopenharmony_ci .mmcimask1 = true, 15662306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 15762306a36Sopenharmony_ci .start_err = MCI_STARTBITERR, 15862306a36Sopenharmony_ci .opendrain = MCI_OD, 15962306a36Sopenharmony_ci .init = mmci_variant_init, 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic struct variant_data variant_ux500 = { 16362306a36Sopenharmony_ci .fifosize = 30 * 4, 16462306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 16562306a36Sopenharmony_ci .clkreg = MCI_CLK_ENABLE, 16662306a36Sopenharmony_ci .clkreg_enable = MCI_ST_UX500_HWFCEN, 16762306a36Sopenharmony_ci .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, 16862306a36Sopenharmony_ci .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, 16962306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 17062306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 17162306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 17262306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 17362306a36Sopenharmony_ci .datalength_bits = 24, 17462306a36Sopenharmony_ci .datactrl_blocksz = 11, 17562306a36Sopenharmony_ci .datactrl_any_blocksz = true, 17662306a36Sopenharmony_ci .dma_power_of_2 = true, 17762306a36Sopenharmony_ci .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, 17862306a36Sopenharmony_ci .st_sdio = true, 17962306a36Sopenharmony_ci .st_clkdiv = true, 18062306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_ON, 18162306a36Sopenharmony_ci .f_max = 100000000, 18262306a36Sopenharmony_ci .signal_direction = true, 18362306a36Sopenharmony_ci .pwrreg_clkgate = true, 18462306a36Sopenharmony_ci .busy_detect = true, 18562306a36Sopenharmony_ci .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, 18662306a36Sopenharmony_ci .busy_detect_flag = MCI_ST_CARDBUSY, 18762306a36Sopenharmony_ci .busy_detect_mask = MCI_ST_BUSYENDMASK, 18862306a36Sopenharmony_ci .pwrreg_nopower = true, 18962306a36Sopenharmony_ci .mmcimask1 = true, 19062306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 19162306a36Sopenharmony_ci .start_err = MCI_STARTBITERR, 19262306a36Sopenharmony_ci .opendrain = MCI_OD, 19362306a36Sopenharmony_ci .init = ux500_variant_init, 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic struct variant_data variant_ux500v2 = { 19762306a36Sopenharmony_ci .fifosize = 30 * 4, 19862306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 19962306a36Sopenharmony_ci .clkreg = MCI_CLK_ENABLE, 20062306a36Sopenharmony_ci .clkreg_enable = MCI_ST_UX500_HWFCEN, 20162306a36Sopenharmony_ci .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, 20262306a36Sopenharmony_ci .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, 20362306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 20462306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 20562306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 20662306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 20762306a36Sopenharmony_ci .datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE, 20862306a36Sopenharmony_ci .datalength_bits = 24, 20962306a36Sopenharmony_ci .datactrl_blocksz = 11, 21062306a36Sopenharmony_ci .datactrl_any_blocksz = true, 21162306a36Sopenharmony_ci .dma_power_of_2 = true, 21262306a36Sopenharmony_ci .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, 21362306a36Sopenharmony_ci .st_sdio = true, 21462306a36Sopenharmony_ci .st_clkdiv = true, 21562306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_ON, 21662306a36Sopenharmony_ci .f_max = 100000000, 21762306a36Sopenharmony_ci .signal_direction = true, 21862306a36Sopenharmony_ci .pwrreg_clkgate = true, 21962306a36Sopenharmony_ci .busy_detect = true, 22062306a36Sopenharmony_ci .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, 22162306a36Sopenharmony_ci .busy_detect_flag = MCI_ST_CARDBUSY, 22262306a36Sopenharmony_ci .busy_detect_mask = MCI_ST_BUSYENDMASK, 22362306a36Sopenharmony_ci .pwrreg_nopower = true, 22462306a36Sopenharmony_ci .mmcimask1 = true, 22562306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 22662306a36Sopenharmony_ci .start_err = MCI_STARTBITERR, 22762306a36Sopenharmony_ci .opendrain = MCI_OD, 22862306a36Sopenharmony_ci .init = ux500v2_variant_init, 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic struct variant_data variant_stm32 = { 23262306a36Sopenharmony_ci .fifosize = 32 * 4, 23362306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 23462306a36Sopenharmony_ci .clkreg = MCI_CLK_ENABLE, 23562306a36Sopenharmony_ci .clkreg_enable = MCI_ST_UX500_HWFCEN, 23662306a36Sopenharmony_ci .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, 23762306a36Sopenharmony_ci .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, 23862306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 23962306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 24062306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 24162306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 24262306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 24362306a36Sopenharmony_ci .datalength_bits = 24, 24462306a36Sopenharmony_ci .datactrl_blocksz = 11, 24562306a36Sopenharmony_ci .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, 24662306a36Sopenharmony_ci .st_sdio = true, 24762306a36Sopenharmony_ci .st_clkdiv = true, 24862306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_ON, 24962306a36Sopenharmony_ci .f_max = 48000000, 25062306a36Sopenharmony_ci .pwrreg_clkgate = true, 25162306a36Sopenharmony_ci .pwrreg_nopower = true, 25262306a36Sopenharmony_ci .init = mmci_variant_init, 25362306a36Sopenharmony_ci}; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic struct variant_data variant_stm32_sdmmc = { 25662306a36Sopenharmony_ci .fifosize = 16 * 4, 25762306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 25862306a36Sopenharmony_ci .f_max = 208000000, 25962306a36Sopenharmony_ci .stm32_clkdiv = true, 26062306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, 26162306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, 26262306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, 26362306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_STM32_SRSP, 26462306a36Sopenharmony_ci .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, 26562306a36Sopenharmony_ci .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, 26662306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, 26762306a36Sopenharmony_ci .datactrl_first = true, 26862306a36Sopenharmony_ci .datacnt_useless = true, 26962306a36Sopenharmony_ci .datalength_bits = 25, 27062306a36Sopenharmony_ci .datactrl_blocksz = 14, 27162306a36Sopenharmony_ci .datactrl_any_blocksz = true, 27262306a36Sopenharmony_ci .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, 27362306a36Sopenharmony_ci .stm32_idmabsize_mask = GENMASK(12, 5), 27462306a36Sopenharmony_ci .stm32_idmabsize_align = BIT(5), 27562306a36Sopenharmony_ci .busy_timeout = true, 27662306a36Sopenharmony_ci .busy_detect = true, 27762306a36Sopenharmony_ci .busy_detect_flag = MCI_STM32_BUSYD0, 27862306a36Sopenharmony_ci .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, 27962306a36Sopenharmony_ci .init = sdmmc_variant_init, 28062306a36Sopenharmony_ci}; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic struct variant_data variant_stm32_sdmmcv2 = { 28362306a36Sopenharmony_ci .fifosize = 16 * 4, 28462306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 28562306a36Sopenharmony_ci .f_max = 267000000, 28662306a36Sopenharmony_ci .stm32_clkdiv = true, 28762306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, 28862306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, 28962306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, 29062306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_STM32_SRSP, 29162306a36Sopenharmony_ci .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, 29262306a36Sopenharmony_ci .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, 29362306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, 29462306a36Sopenharmony_ci .datactrl_first = true, 29562306a36Sopenharmony_ci .datacnt_useless = true, 29662306a36Sopenharmony_ci .datalength_bits = 25, 29762306a36Sopenharmony_ci .datactrl_blocksz = 14, 29862306a36Sopenharmony_ci .datactrl_any_blocksz = true, 29962306a36Sopenharmony_ci .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, 30062306a36Sopenharmony_ci .stm32_idmabsize_mask = GENMASK(16, 5), 30162306a36Sopenharmony_ci .stm32_idmabsize_align = BIT(5), 30262306a36Sopenharmony_ci .dma_lli = true, 30362306a36Sopenharmony_ci .busy_timeout = true, 30462306a36Sopenharmony_ci .busy_detect = true, 30562306a36Sopenharmony_ci .busy_detect_flag = MCI_STM32_BUSYD0, 30662306a36Sopenharmony_ci .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, 30762306a36Sopenharmony_ci .init = sdmmc_variant_init, 30862306a36Sopenharmony_ci}; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic struct variant_data variant_stm32_sdmmcv3 = { 31162306a36Sopenharmony_ci .fifosize = 256 * 4, 31262306a36Sopenharmony_ci .fifohalfsize = 128 * 4, 31362306a36Sopenharmony_ci .f_max = 267000000, 31462306a36Sopenharmony_ci .stm32_clkdiv = true, 31562306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, 31662306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, 31762306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, 31862306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_STM32_SRSP, 31962306a36Sopenharmony_ci .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, 32062306a36Sopenharmony_ci .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, 32162306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, 32262306a36Sopenharmony_ci .datactrl_first = true, 32362306a36Sopenharmony_ci .datacnt_useless = true, 32462306a36Sopenharmony_ci .datalength_bits = 25, 32562306a36Sopenharmony_ci .datactrl_blocksz = 14, 32662306a36Sopenharmony_ci .datactrl_any_blocksz = true, 32762306a36Sopenharmony_ci .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, 32862306a36Sopenharmony_ci .stm32_idmabsize_mask = GENMASK(16, 6), 32962306a36Sopenharmony_ci .stm32_idmabsize_align = BIT(6), 33062306a36Sopenharmony_ci .dma_lli = true, 33162306a36Sopenharmony_ci .busy_timeout = true, 33262306a36Sopenharmony_ci .busy_detect = true, 33362306a36Sopenharmony_ci .busy_detect_flag = MCI_STM32_BUSYD0, 33462306a36Sopenharmony_ci .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, 33562306a36Sopenharmony_ci .init = sdmmc_variant_init, 33662306a36Sopenharmony_ci}; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic struct variant_data variant_qcom = { 33962306a36Sopenharmony_ci .fifosize = 16 * 4, 34062306a36Sopenharmony_ci .fifohalfsize = 8 * 4, 34162306a36Sopenharmony_ci .clkreg = MCI_CLK_ENABLE, 34262306a36Sopenharmony_ci .clkreg_enable = MCI_QCOM_CLK_FLOWENA | 34362306a36Sopenharmony_ci MCI_QCOM_CLK_SELECT_IN_FBCLK, 34462306a36Sopenharmony_ci .clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8, 34562306a36Sopenharmony_ci .datactrl_mask_ddrmode = MCI_QCOM_CLK_SELECT_IN_DDR_MODE, 34662306a36Sopenharmony_ci .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, 34762306a36Sopenharmony_ci .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, 34862306a36Sopenharmony_ci .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, 34962306a36Sopenharmony_ci .cmdreg_srsp = MCI_CPSM_RESPONSE, 35062306a36Sopenharmony_ci .data_cmd_enable = MCI_CPSM_QCOM_DATCMD, 35162306a36Sopenharmony_ci .datalength_bits = 24, 35262306a36Sopenharmony_ci .datactrl_blocksz = 11, 35362306a36Sopenharmony_ci .datactrl_any_blocksz = true, 35462306a36Sopenharmony_ci .pwrreg_powerup = MCI_PWR_UP, 35562306a36Sopenharmony_ci .f_max = 208000000, 35662306a36Sopenharmony_ci .explicit_mclk_control = true, 35762306a36Sopenharmony_ci .qcom_fifo = true, 35862306a36Sopenharmony_ci .qcom_dml = true, 35962306a36Sopenharmony_ci .mmcimask1 = true, 36062306a36Sopenharmony_ci .irq_pio_mask = MCI_IRQ_PIO_MASK, 36162306a36Sopenharmony_ci .start_err = MCI_STARTBITERR, 36262306a36Sopenharmony_ci .opendrain = MCI_ROD, 36362306a36Sopenharmony_ci .init = qcom_variant_init, 36462306a36Sopenharmony_ci}; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/* Busy detection for the ST Micro variant */ 36762306a36Sopenharmony_cistatic int mmci_card_busy(struct mmc_host *mmc) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 37062306a36Sopenharmony_ci unsigned long flags; 37162306a36Sopenharmony_ci int busy = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 37462306a36Sopenharmony_ci if (readl(host->base + MMCISTATUS) & host->variant->busy_detect_flag) 37562306a36Sopenharmony_ci busy = 1; 37662306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return busy; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic void mmci_reg_delay(struct mmci_host *host) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci /* 38462306a36Sopenharmony_ci * According to the spec, at least three feedback clock cycles 38562306a36Sopenharmony_ci * of max 52 MHz must pass between two writes to the MMCICLOCK reg. 38662306a36Sopenharmony_ci * Three MCLK clock cycles must pass between two MMCIPOWER reg writes. 38762306a36Sopenharmony_ci * Worst delay time during card init is at 100 kHz => 30 us. 38862306a36Sopenharmony_ci * Worst delay time when up and running is at 25 MHz => 120 ns. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci if (host->cclk < 25000000) 39162306a36Sopenharmony_ci udelay(30); 39262306a36Sopenharmony_ci else 39362306a36Sopenharmony_ci ndelay(120); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* 39762306a36Sopenharmony_ci * This must be called with host->lock held 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_civoid mmci_write_clkreg(struct mmci_host *host, u32 clk) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci if (host->clk_reg != clk) { 40262306a36Sopenharmony_ci host->clk_reg = clk; 40362306a36Sopenharmony_ci writel(clk, host->base + MMCICLOCK); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci/* 40862306a36Sopenharmony_ci * This must be called with host->lock held 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_civoid mmci_write_pwrreg(struct mmci_host *host, u32 pwr) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci if (host->pwr_reg != pwr) { 41362306a36Sopenharmony_ci host->pwr_reg = pwr; 41462306a36Sopenharmony_ci writel(pwr, host->base + MMCIPOWER); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/* 41962306a36Sopenharmony_ci * This must be called with host->lock held 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_cistatic void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci /* Keep busy mode in DPSM if enabled */ 42462306a36Sopenharmony_ci datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (host->datactrl_reg != datactrl) { 42762306a36Sopenharmony_ci host->datactrl_reg = datactrl; 42862306a36Sopenharmony_ci writel(datactrl, host->base + MMCIDATACTRL); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci/* 43362306a36Sopenharmony_ci * This must be called with host->lock held 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_cistatic void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct variant_data *variant = host->variant; 43862306a36Sopenharmony_ci u32 clk = variant->clkreg; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Make sure cclk reflects the current calculated clock */ 44162306a36Sopenharmony_ci host->cclk = 0; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (desired) { 44462306a36Sopenharmony_ci if (variant->explicit_mclk_control) { 44562306a36Sopenharmony_ci host->cclk = host->mclk; 44662306a36Sopenharmony_ci } else if (desired >= host->mclk) { 44762306a36Sopenharmony_ci clk = MCI_CLK_BYPASS; 44862306a36Sopenharmony_ci if (variant->st_clkdiv) 44962306a36Sopenharmony_ci clk |= MCI_ST_UX500_NEG_EDGE; 45062306a36Sopenharmony_ci host->cclk = host->mclk; 45162306a36Sopenharmony_ci } else if (variant->st_clkdiv) { 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * DB8500 TRM says f = mclk / (clkdiv + 2) 45462306a36Sopenharmony_ci * => clkdiv = (mclk / f) - 2 45562306a36Sopenharmony_ci * Round the divider up so we don't exceed the max 45662306a36Sopenharmony_ci * frequency 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_ci clk = DIV_ROUND_UP(host->mclk, desired) - 2; 45962306a36Sopenharmony_ci if (clk >= 256) 46062306a36Sopenharmony_ci clk = 255; 46162306a36Sopenharmony_ci host->cclk = host->mclk / (clk + 2); 46262306a36Sopenharmony_ci } else { 46362306a36Sopenharmony_ci /* 46462306a36Sopenharmony_ci * PL180 TRM says f = mclk / (2 * (clkdiv + 1)) 46562306a36Sopenharmony_ci * => clkdiv = mclk / (2 * f) - 1 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ci clk = host->mclk / (2 * desired) - 1; 46862306a36Sopenharmony_ci if (clk >= 256) 46962306a36Sopenharmony_ci clk = 255; 47062306a36Sopenharmony_ci host->cclk = host->mclk / (2 * (clk + 1)); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci clk |= variant->clkreg_enable; 47462306a36Sopenharmony_ci clk |= MCI_CLK_ENABLE; 47562306a36Sopenharmony_ci /* This hasn't proven to be worthwhile */ 47662306a36Sopenharmony_ci /* clk |= MCI_CLK_PWRSAVE; */ 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Set actual clock for debug */ 48062306a36Sopenharmony_ci host->mmc->actual_clock = host->cclk; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) 48362306a36Sopenharmony_ci clk |= MCI_4BIT_BUS; 48462306a36Sopenharmony_ci if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) 48562306a36Sopenharmony_ci clk |= variant->clkreg_8bit_bus_enable; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 || 48862306a36Sopenharmony_ci host->mmc->ios.timing == MMC_TIMING_MMC_DDR52) 48962306a36Sopenharmony_ci clk |= variant->clkreg_neg_edge_enable; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci mmci_write_clkreg(host, clk); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic void mmci_dma_release(struct mmci_host *host) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci if (host->ops && host->ops->dma_release) 49762306a36Sopenharmony_ci host->ops->dma_release(host); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci host->use_dma = false; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void mmci_dma_setup(struct mmci_host *host) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci if (!host->ops || !host->ops->dma_setup) 50562306a36Sopenharmony_ci return; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (host->ops->dma_setup(host)) 50862306a36Sopenharmony_ci return; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* initialize pre request cookie */ 51162306a36Sopenharmony_ci host->next_cookie = 1; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci host->use_dma = true; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci/* 51762306a36Sopenharmony_ci * Validate mmc prerequisites 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_cistatic int mmci_validate_data(struct mmci_host *host, 52062306a36Sopenharmony_ci struct mmc_data *data) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct variant_data *variant = host->variant; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!data) 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci if (!is_power_of_2(data->blksz) && !variant->datactrl_any_blocksz) { 52762306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), 52862306a36Sopenharmony_ci "unsupported block size (%d bytes)\n", data->blksz); 52962306a36Sopenharmony_ci return -EINVAL; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (host->ops && host->ops->validate_data) 53362306a36Sopenharmony_ci return host->ops->validate_data(host, data); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return 0; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int mmci_prep_data(struct mmci_host *host, struct mmc_data *data, bool next) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci int err; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (!host->ops || !host->ops->prep_data) 54362306a36Sopenharmony_ci return 0; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci err = host->ops->prep_data(host, data, next); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (next && !err) 54862306a36Sopenharmony_ci data->host_cookie = ++host->next_cookie < 0 ? 54962306a36Sopenharmony_ci 1 : host->next_cookie; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci return err; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void mmci_unprep_data(struct mmci_host *host, struct mmc_data *data, 55562306a36Sopenharmony_ci int err) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci if (host->ops && host->ops->unprep_data) 55862306a36Sopenharmony_ci host->ops->unprep_data(host, data, err); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci data->host_cookie = 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (host->ops && host->ops->get_next_data) 56862306a36Sopenharmony_ci host->ops->get_next_data(host, data); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int mmci_dma_start(struct mmci_host *host, unsigned int datactrl) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct mmc_data *data = host->data; 57462306a36Sopenharmony_ci int ret; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (!host->use_dma) 57762306a36Sopenharmony_ci return -EINVAL; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ret = mmci_prep_data(host, data, false); 58062306a36Sopenharmony_ci if (ret) 58162306a36Sopenharmony_ci return ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (!host->ops || !host->ops->dma_start) 58462306a36Sopenharmony_ci return -EINVAL; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* Okay, go for it. */ 58762306a36Sopenharmony_ci dev_vdbg(mmc_dev(host->mmc), 58862306a36Sopenharmony_ci "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", 58962306a36Sopenharmony_ci data->sg_len, data->blksz, data->blocks, data->flags); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci ret = host->ops->dma_start(host, &datactrl); 59262306a36Sopenharmony_ci if (ret) 59362306a36Sopenharmony_ci return ret; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* Trigger the DMA transfer */ 59662306a36Sopenharmony_ci mmci_write_datactrlreg(host, datactrl); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* 59962306a36Sopenharmony_ci * Let the MMCI say when the data is ended and it's time 60062306a36Sopenharmony_ci * to fire next DMA request. When that happens, MMCI will 60162306a36Sopenharmony_ci * call mmci_data_end() 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_ci writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, 60462306a36Sopenharmony_ci host->base + MMCIMASK0); 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci if (!host->use_dma) 61162306a36Sopenharmony_ci return; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (host->ops && host->ops->dma_finalize) 61462306a36Sopenharmony_ci host->ops->dma_finalize(host, data); 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic void mmci_dma_error(struct mmci_host *host) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci if (!host->use_dma) 62062306a36Sopenharmony_ci return; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (host->ops && host->ops->dma_error) 62362306a36Sopenharmony_ci host->ops->dma_error(host); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic void 62762306a36Sopenharmony_cimmci_request_end(struct mmci_host *host, struct mmc_request *mrq) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci writel(0, host->base + MMCICOMMAND); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci BUG_ON(host->data); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci host->mrq = NULL; 63462306a36Sopenharmony_ci host->cmd = NULL; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci mmc_request_done(host->mmc, mrq); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic void mmci_set_mask1(struct mmci_host *host, unsigned int mask) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci void __iomem *base = host->base; 64262306a36Sopenharmony_ci struct variant_data *variant = host->variant; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (host->singleirq) { 64562306a36Sopenharmony_ci unsigned int mask0 = readl(base + MMCIMASK0); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci mask0 &= ~variant->irq_pio_mask; 64862306a36Sopenharmony_ci mask0 |= mask; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci writel(mask0, base + MMCIMASK0); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (variant->mmcimask1) 65462306a36Sopenharmony_ci writel(mask, base + MMCIMASK1); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci host->mask1_reg = mask; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic void mmci_stop_data(struct mmci_host *host) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci mmci_write_datactrlreg(host, 0); 66262306a36Sopenharmony_ci mmci_set_mask1(host, 0); 66362306a36Sopenharmony_ci host->data = NULL; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci unsigned int flags = SG_MITER_ATOMIC; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) 67162306a36Sopenharmony_ci flags |= SG_MITER_TO_SG; 67262306a36Sopenharmony_ci else 67362306a36Sopenharmony_ci flags |= SG_MITER_FROM_SG; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic u32 mmci_get_dctrl_cfg(struct mmci_host *host) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci return MCI_DPSM_ENABLE | mmci_dctrl_blksz(host); 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci return MCI_DPSM_ENABLE | (host->data->blksz << 16); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic void ux500_busy_clear_mask_done(struct mmci_host *host) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci void __iomem *base = host->base; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci writel(host->variant->busy_detect_mask, base + MMCICLEAR); 69362306a36Sopenharmony_ci writel(readl(base + MMCIMASK0) & 69462306a36Sopenharmony_ci ~host->variant->busy_detect_mask, base + MMCIMASK0); 69562306a36Sopenharmony_ci host->busy_state = MMCI_BUSY_DONE; 69662306a36Sopenharmony_ci host->busy_status = 0; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci/* 70062306a36Sopenharmony_ci * ux500_busy_complete() - this will wait until the busy status 70162306a36Sopenharmony_ci * goes off, saving any status that occur in the meantime into 70262306a36Sopenharmony_ci * host->busy_status until we know the card is not busy any more. 70362306a36Sopenharmony_ci * The function returns true when the busy detection is ended 70462306a36Sopenharmony_ci * and we should continue processing the command. 70562306a36Sopenharmony_ci * 70662306a36Sopenharmony_ci * The Ux500 typically fires two IRQs over a busy cycle like this: 70762306a36Sopenharmony_ci * 70862306a36Sopenharmony_ci * DAT0 busy +-----------------+ 70962306a36Sopenharmony_ci * | | 71062306a36Sopenharmony_ci * DAT0 not busy ----+ +-------- 71162306a36Sopenharmony_ci * 71262306a36Sopenharmony_ci * ^ ^ 71362306a36Sopenharmony_ci * | | 71462306a36Sopenharmony_ci * IRQ1 IRQ2 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_cistatic bool ux500_busy_complete(struct mmci_host *host, struct mmc_command *cmd, 71762306a36Sopenharmony_ci u32 status, u32 err_msk) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci void __iomem *base = host->base; 72062306a36Sopenharmony_ci int retries = 10; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (status & err_msk) { 72362306a36Sopenharmony_ci /* Stop any ongoing busy detection if an error occurs */ 72462306a36Sopenharmony_ci ux500_busy_clear_mask_done(host); 72562306a36Sopenharmony_ci goto out_ret_state; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* 72962306a36Sopenharmony_ci * The state transitions are encoded in a state machine crossing 73062306a36Sopenharmony_ci * the edges in this switch statement. 73162306a36Sopenharmony_ci */ 73262306a36Sopenharmony_ci switch (host->busy_state) { 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* 73562306a36Sopenharmony_ci * Before unmasking for the busy end IRQ, confirm that the 73662306a36Sopenharmony_ci * command was sent successfully. To keep track of having a 73762306a36Sopenharmony_ci * command in-progress, waiting for busy signaling to end, 73862306a36Sopenharmony_ci * store the status in host->busy_status. 73962306a36Sopenharmony_ci * 74062306a36Sopenharmony_ci * Note that, the card may need a couple of clock cycles before 74162306a36Sopenharmony_ci * it starts signaling busy on DAT0, hence re-read the 74262306a36Sopenharmony_ci * MMCISTATUS register here, to allow the busy bit to be set. 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci case MMCI_BUSY_DONE: 74562306a36Sopenharmony_ci /* 74662306a36Sopenharmony_ci * Save the first status register read to be sure to catch 74762306a36Sopenharmony_ci * all bits that may be lost will retrying. If the command 74862306a36Sopenharmony_ci * is still busy this will result in assigning 0 to 74962306a36Sopenharmony_ci * host->busy_status, which is what it should be in IDLE. 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_ci host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND); 75262306a36Sopenharmony_ci while (retries) { 75362306a36Sopenharmony_ci status = readl(base + MMCISTATUS); 75462306a36Sopenharmony_ci /* Keep accumulating status bits */ 75562306a36Sopenharmony_ci host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND); 75662306a36Sopenharmony_ci if (status & host->variant->busy_detect_flag) { 75762306a36Sopenharmony_ci writel(readl(base + MMCIMASK0) | 75862306a36Sopenharmony_ci host->variant->busy_detect_mask, 75962306a36Sopenharmony_ci base + MMCIMASK0); 76062306a36Sopenharmony_ci host->busy_state = MMCI_BUSY_WAITING_FOR_START_IRQ; 76162306a36Sopenharmony_ci schedule_delayed_work(&host->ux500_busy_timeout_work, 76262306a36Sopenharmony_ci msecs_to_jiffies(cmd->busy_timeout)); 76362306a36Sopenharmony_ci goto out_ret_state; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci retries--; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), 76862306a36Sopenharmony_ci "no busy signalling in time CMD%02x\n", cmd->opcode); 76962306a36Sopenharmony_ci ux500_busy_clear_mask_done(host); 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* 77362306a36Sopenharmony_ci * If there is a command in-progress that has been successfully 77462306a36Sopenharmony_ci * sent, then bail out if busy status is set and wait for the 77562306a36Sopenharmony_ci * busy end IRQ. 77662306a36Sopenharmony_ci * 77762306a36Sopenharmony_ci * Note that, the HW triggers an IRQ on both edges while 77862306a36Sopenharmony_ci * monitoring DAT0 for busy completion, but there is only one 77962306a36Sopenharmony_ci * status bit in MMCISTATUS for the busy state. Therefore 78062306a36Sopenharmony_ci * both the start and the end interrupts needs to be cleared, 78162306a36Sopenharmony_ci * one after the other. So, clear the busy start IRQ here. 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_ci case MMCI_BUSY_WAITING_FOR_START_IRQ: 78462306a36Sopenharmony_ci if (status & host->variant->busy_detect_flag) { 78562306a36Sopenharmony_ci host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND); 78662306a36Sopenharmony_ci writel(host->variant->busy_detect_mask, base + MMCICLEAR); 78762306a36Sopenharmony_ci host->busy_state = MMCI_BUSY_WAITING_FOR_END_IRQ; 78862306a36Sopenharmony_ci } else { 78962306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), 79062306a36Sopenharmony_ci "lost busy status when waiting for busy start IRQ CMD%02x\n", 79162306a36Sopenharmony_ci cmd->opcode); 79262306a36Sopenharmony_ci cancel_delayed_work(&host->ux500_busy_timeout_work); 79362306a36Sopenharmony_ci ux500_busy_clear_mask_done(host); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci case MMCI_BUSY_WAITING_FOR_END_IRQ: 79862306a36Sopenharmony_ci if (!(status & host->variant->busy_detect_flag)) { 79962306a36Sopenharmony_ci host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND); 80062306a36Sopenharmony_ci writel(host->variant->busy_detect_mask, base + MMCICLEAR); 80162306a36Sopenharmony_ci cancel_delayed_work(&host->ux500_busy_timeout_work); 80262306a36Sopenharmony_ci ux500_busy_clear_mask_done(host); 80362306a36Sopenharmony_ci } else { 80462306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), 80562306a36Sopenharmony_ci "busy status still asserted when handling busy end IRQ - will keep waiting CMD%02x\n", 80662306a36Sopenharmony_ci cmd->opcode); 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci default: 81162306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), "fell through on state %d, CMD%02x\n", 81262306a36Sopenharmony_ci host->busy_state, cmd->opcode); 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ciout_ret_state: 81762306a36Sopenharmony_ci return (host->busy_state == MMCI_BUSY_DONE); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci/* 82162306a36Sopenharmony_ci * All the DMA operation mode stuff goes inside this ifdef. 82262306a36Sopenharmony_ci * This assumes that you have a generic DMA device interface, 82362306a36Sopenharmony_ci * no custom DMA interfaces are supported. 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci#ifdef CONFIG_DMA_ENGINE 82662306a36Sopenharmony_cistruct mmci_dmae_next { 82762306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc; 82862306a36Sopenharmony_ci struct dma_chan *chan; 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistruct mmci_dmae_priv { 83262306a36Sopenharmony_ci struct dma_chan *cur; 83362306a36Sopenharmony_ci struct dma_chan *rx_channel; 83462306a36Sopenharmony_ci struct dma_chan *tx_channel; 83562306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc_current; 83662306a36Sopenharmony_ci struct mmci_dmae_next next_data; 83762306a36Sopenharmony_ci}; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ciint mmci_dmae_setup(struct mmci_host *host) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci const char *rxname, *txname; 84262306a36Sopenharmony_ci struct mmci_dmae_priv *dmae; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL); 84562306a36Sopenharmony_ci if (!dmae) 84662306a36Sopenharmony_ci return -ENOMEM; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci host->dma_priv = dmae; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci dmae->rx_channel = dma_request_chan(mmc_dev(host->mmc), "rx"); 85162306a36Sopenharmony_ci if (IS_ERR(dmae->rx_channel)) { 85262306a36Sopenharmony_ci int ret = PTR_ERR(dmae->rx_channel); 85362306a36Sopenharmony_ci dmae->rx_channel = NULL; 85462306a36Sopenharmony_ci return ret; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci dmae->tx_channel = dma_request_chan(mmc_dev(host->mmc), "tx"); 85862306a36Sopenharmony_ci if (IS_ERR(dmae->tx_channel)) { 85962306a36Sopenharmony_ci if (PTR_ERR(dmae->tx_channel) == -EPROBE_DEFER) 86062306a36Sopenharmony_ci dev_warn(mmc_dev(host->mmc), 86162306a36Sopenharmony_ci "Deferred probe for TX channel ignored\n"); 86262306a36Sopenharmony_ci dmae->tx_channel = NULL; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci /* 86662306a36Sopenharmony_ci * If only an RX channel is specified, the driver will 86762306a36Sopenharmony_ci * attempt to use it bidirectionally, however if it 86862306a36Sopenharmony_ci * is specified but cannot be located, DMA will be disabled. 86962306a36Sopenharmony_ci */ 87062306a36Sopenharmony_ci if (dmae->rx_channel && !dmae->tx_channel) 87162306a36Sopenharmony_ci dmae->tx_channel = dmae->rx_channel; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (dmae->rx_channel) 87462306a36Sopenharmony_ci rxname = dma_chan_name(dmae->rx_channel); 87562306a36Sopenharmony_ci else 87662306a36Sopenharmony_ci rxname = "none"; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (dmae->tx_channel) 87962306a36Sopenharmony_ci txname = dma_chan_name(dmae->tx_channel); 88062306a36Sopenharmony_ci else 88162306a36Sopenharmony_ci txname = "none"; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n", 88462306a36Sopenharmony_ci rxname, txname); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* 88762306a36Sopenharmony_ci * Limit the maximum segment size in any SG entry according to 88862306a36Sopenharmony_ci * the parameters of the DMA engine device. 88962306a36Sopenharmony_ci */ 89062306a36Sopenharmony_ci if (dmae->tx_channel) { 89162306a36Sopenharmony_ci struct device *dev = dmae->tx_channel->device->dev; 89262306a36Sopenharmony_ci unsigned int max_seg_size = dma_get_max_seg_size(dev); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci if (max_seg_size < host->mmc->max_seg_size) 89562306a36Sopenharmony_ci host->mmc->max_seg_size = max_seg_size; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci if (dmae->rx_channel) { 89862306a36Sopenharmony_ci struct device *dev = dmae->rx_channel->device->dev; 89962306a36Sopenharmony_ci unsigned int max_seg_size = dma_get_max_seg_size(dev); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (max_seg_size < host->mmc->max_seg_size) 90262306a36Sopenharmony_ci host->mmc->max_seg_size = max_seg_size; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (!dmae->tx_channel || !dmae->rx_channel) { 90662306a36Sopenharmony_ci mmci_dmae_release(host); 90762306a36Sopenharmony_ci return -EINVAL; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci return 0; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci/* 91462306a36Sopenharmony_ci * This is used in or so inline it 91562306a36Sopenharmony_ci * so it can be discarded. 91662306a36Sopenharmony_ci */ 91762306a36Sopenharmony_civoid mmci_dmae_release(struct mmci_host *host) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (dmae->rx_channel) 92262306a36Sopenharmony_ci dma_release_channel(dmae->rx_channel); 92362306a36Sopenharmony_ci if (dmae->tx_channel) 92462306a36Sopenharmony_ci dma_release_channel(dmae->tx_channel); 92562306a36Sopenharmony_ci dmae->rx_channel = dmae->tx_channel = NULL; 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cistatic void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 93162306a36Sopenharmony_ci struct dma_chan *chan; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) 93462306a36Sopenharmony_ci chan = dmae->rx_channel; 93562306a36Sopenharmony_ci else 93662306a36Sopenharmony_ci chan = dmae->tx_channel; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, 93962306a36Sopenharmony_ci mmc_get_dma_dir(data)); 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_civoid mmci_dmae_error(struct mmci_host *host) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (!dma_inprogress(host)) 94762306a36Sopenharmony_ci return; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); 95062306a36Sopenharmony_ci dmaengine_terminate_all(dmae->cur); 95162306a36Sopenharmony_ci host->dma_in_progress = false; 95262306a36Sopenharmony_ci dmae->cur = NULL; 95362306a36Sopenharmony_ci dmae->desc_current = NULL; 95462306a36Sopenharmony_ci host->data->host_cookie = 0; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci mmci_dma_unmap(host, host->data); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_civoid mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 96262306a36Sopenharmony_ci u32 status; 96362306a36Sopenharmony_ci int i; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (!dma_inprogress(host)) 96662306a36Sopenharmony_ci return; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* Wait up to 1ms for the DMA to complete */ 96962306a36Sopenharmony_ci for (i = 0; ; i++) { 97062306a36Sopenharmony_ci status = readl(host->base + MMCISTATUS); 97162306a36Sopenharmony_ci if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100) 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci udelay(10); 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* 97762306a36Sopenharmony_ci * Check to see whether we still have some data left in the FIFO - 97862306a36Sopenharmony_ci * this catches DMA controllers which are unable to monitor the 97962306a36Sopenharmony_ci * DMALBREQ and DMALSREQ signals while allowing us to DMA to non- 98062306a36Sopenharmony_ci * contiguous buffers. On TX, we'll get a FIFO underrun error. 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci if (status & MCI_RXDATAAVLBLMASK) { 98362306a36Sopenharmony_ci mmci_dma_error(host); 98462306a36Sopenharmony_ci if (!data->error) 98562306a36Sopenharmony_ci data->error = -EIO; 98662306a36Sopenharmony_ci } else if (!data->host_cookie) { 98762306a36Sopenharmony_ci mmci_dma_unmap(host, data); 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* 99162306a36Sopenharmony_ci * Use of DMA with scatter-gather is impossible. 99262306a36Sopenharmony_ci * Give up with DMA and switch back to PIO mode. 99362306a36Sopenharmony_ci */ 99462306a36Sopenharmony_ci if (status & MCI_RXDATAAVLBLMASK) { 99562306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n"); 99662306a36Sopenharmony_ci mmci_dma_release(host); 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci host->dma_in_progress = false; 100062306a36Sopenharmony_ci dmae->cur = NULL; 100162306a36Sopenharmony_ci dmae->desc_current = NULL; 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci/* prepares DMA channel and DMA descriptor, returns non-zero on failure */ 100562306a36Sopenharmony_cistatic int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, 100662306a36Sopenharmony_ci struct dma_chan **dma_chan, 100762306a36Sopenharmony_ci struct dma_async_tx_descriptor **dma_desc) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 101062306a36Sopenharmony_ci struct variant_data *variant = host->variant; 101162306a36Sopenharmony_ci struct dma_slave_config conf = { 101262306a36Sopenharmony_ci .src_addr = host->phybase + MMCIFIFO, 101362306a36Sopenharmony_ci .dst_addr = host->phybase + MMCIFIFO, 101462306a36Sopenharmony_ci .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 101562306a36Sopenharmony_ci .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 101662306a36Sopenharmony_ci .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ 101762306a36Sopenharmony_ci .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ 101862306a36Sopenharmony_ci .device_fc = false, 101962306a36Sopenharmony_ci }; 102062306a36Sopenharmony_ci struct dma_chan *chan; 102162306a36Sopenharmony_ci struct dma_device *device; 102262306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc; 102362306a36Sopenharmony_ci int nr_sg; 102462306a36Sopenharmony_ci unsigned long flags = DMA_CTRL_ACK; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) { 102762306a36Sopenharmony_ci conf.direction = DMA_DEV_TO_MEM; 102862306a36Sopenharmony_ci chan = dmae->rx_channel; 102962306a36Sopenharmony_ci } else { 103062306a36Sopenharmony_ci conf.direction = DMA_MEM_TO_DEV; 103162306a36Sopenharmony_ci chan = dmae->tx_channel; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* If there's no DMA channel, fall back to PIO */ 103562306a36Sopenharmony_ci if (!chan) 103662306a36Sopenharmony_ci return -EINVAL; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci /* If less than or equal to the fifo size, don't bother with DMA */ 103962306a36Sopenharmony_ci if (data->blksz * data->blocks <= variant->fifosize) 104062306a36Sopenharmony_ci return -EINVAL; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* 104362306a36Sopenharmony_ci * This is necessary to get SDIO working on the Ux500. We do not yet 104462306a36Sopenharmony_ci * know if this is a bug in: 104562306a36Sopenharmony_ci * - The Ux500 DMA controller (DMA40) 104662306a36Sopenharmony_ci * - The MMCI DMA interface on the Ux500 104762306a36Sopenharmony_ci * some power of two blocks (such as 64 bytes) are sent regularly 104862306a36Sopenharmony_ci * during SDIO traffic and those work fine so for these we enable DMA 104962306a36Sopenharmony_ci * transfers. 105062306a36Sopenharmony_ci */ 105162306a36Sopenharmony_ci if (host->variant->dma_power_of_2 && !is_power_of_2(data->blksz)) 105262306a36Sopenharmony_ci return -EINVAL; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci device = chan->device; 105562306a36Sopenharmony_ci nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, 105662306a36Sopenharmony_ci mmc_get_dma_dir(data)); 105762306a36Sopenharmony_ci if (nr_sg == 0) 105862306a36Sopenharmony_ci return -EINVAL; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (host->variant->qcom_dml) 106162306a36Sopenharmony_ci flags |= DMA_PREP_INTERRUPT; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci dmaengine_slave_config(chan, &conf); 106462306a36Sopenharmony_ci desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg, 106562306a36Sopenharmony_ci conf.direction, flags); 106662306a36Sopenharmony_ci if (!desc) 106762306a36Sopenharmony_ci goto unmap_exit; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci *dma_chan = chan; 107062306a36Sopenharmony_ci *dma_desc = desc; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci return 0; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci unmap_exit: 107562306a36Sopenharmony_ci dma_unmap_sg(device->dev, data->sg, data->sg_len, 107662306a36Sopenharmony_ci mmc_get_dma_dir(data)); 107762306a36Sopenharmony_ci return -ENOMEM; 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ciint mmci_dmae_prep_data(struct mmci_host *host, 108162306a36Sopenharmony_ci struct mmc_data *data, 108262306a36Sopenharmony_ci bool next) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 108562306a36Sopenharmony_ci struct mmci_dmae_next *nd = &dmae->next_data; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (!host->use_dma) 108862306a36Sopenharmony_ci return -EINVAL; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (next) 109162306a36Sopenharmony_ci return _mmci_dmae_prep_data(host, data, &nd->chan, &nd->desc); 109262306a36Sopenharmony_ci /* Check if next job is already prepared. */ 109362306a36Sopenharmony_ci if (dmae->cur && dmae->desc_current) 109462306a36Sopenharmony_ci return 0; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* No job were prepared thus do it now. */ 109762306a36Sopenharmony_ci return _mmci_dmae_prep_data(host, data, &dmae->cur, 109862306a36Sopenharmony_ci &dmae->desc_current); 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ciint mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 110462306a36Sopenharmony_ci int ret; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci host->dma_in_progress = true; 110762306a36Sopenharmony_ci ret = dma_submit_error(dmaengine_submit(dmae->desc_current)); 110862306a36Sopenharmony_ci if (ret < 0) { 110962306a36Sopenharmony_ci host->dma_in_progress = false; 111062306a36Sopenharmony_ci return ret; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci dma_async_issue_pending(dmae->cur); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci *datactrl |= MCI_DPSM_DMAENABLE; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci return 0; 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_civoid mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 112262306a36Sopenharmony_ci struct mmci_dmae_next *next = &dmae->next_data; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (!host->use_dma) 112562306a36Sopenharmony_ci return; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci WARN_ON(!data->host_cookie && (next->desc || next->chan)); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci dmae->desc_current = next->desc; 113062306a36Sopenharmony_ci dmae->cur = next->chan; 113162306a36Sopenharmony_ci next->desc = NULL; 113262306a36Sopenharmony_ci next->chan = NULL; 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_civoid mmci_dmae_unprep_data(struct mmci_host *host, 113662306a36Sopenharmony_ci struct mmc_data *data, int err) 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci struct mmci_dmae_priv *dmae = host->dma_priv; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (!host->use_dma) 114262306a36Sopenharmony_ci return; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci mmci_dma_unmap(host, data); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (err) { 114762306a36Sopenharmony_ci struct mmci_dmae_next *next = &dmae->next_data; 114862306a36Sopenharmony_ci struct dma_chan *chan; 114962306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) 115062306a36Sopenharmony_ci chan = dmae->rx_channel; 115162306a36Sopenharmony_ci else 115262306a36Sopenharmony_ci chan = dmae->tx_channel; 115362306a36Sopenharmony_ci dmaengine_terminate_all(chan); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (dmae->desc_current == next->desc) 115662306a36Sopenharmony_ci dmae->desc_current = NULL; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (dmae->cur == next->chan) { 115962306a36Sopenharmony_ci host->dma_in_progress = false; 116062306a36Sopenharmony_ci dmae->cur = NULL; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci next->desc = NULL; 116462306a36Sopenharmony_ci next->chan = NULL; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_cistatic struct mmci_host_ops mmci_variant_ops = { 116962306a36Sopenharmony_ci .prep_data = mmci_dmae_prep_data, 117062306a36Sopenharmony_ci .unprep_data = mmci_dmae_unprep_data, 117162306a36Sopenharmony_ci .get_datactrl_cfg = mmci_get_dctrl_cfg, 117262306a36Sopenharmony_ci .get_next_data = mmci_dmae_get_next_data, 117362306a36Sopenharmony_ci .dma_setup = mmci_dmae_setup, 117462306a36Sopenharmony_ci .dma_release = mmci_dmae_release, 117562306a36Sopenharmony_ci .dma_start = mmci_dmae_start, 117662306a36Sopenharmony_ci .dma_finalize = mmci_dmae_finalize, 117762306a36Sopenharmony_ci .dma_error = mmci_dmae_error, 117862306a36Sopenharmony_ci}; 117962306a36Sopenharmony_ci#else 118062306a36Sopenharmony_cistatic struct mmci_host_ops mmci_variant_ops = { 118162306a36Sopenharmony_ci .get_datactrl_cfg = mmci_get_dctrl_cfg, 118262306a36Sopenharmony_ci}; 118362306a36Sopenharmony_ci#endif 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic void mmci_variant_init(struct mmci_host *host) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci host->ops = &mmci_variant_ops; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic void ux500_variant_init(struct mmci_host *host) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci host->ops = &mmci_variant_ops; 119362306a36Sopenharmony_ci host->ops->busy_complete = ux500_busy_complete; 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic void ux500v2_variant_init(struct mmci_host *host) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci host->ops = &mmci_variant_ops; 119962306a36Sopenharmony_ci host->ops->busy_complete = ux500_busy_complete; 120062306a36Sopenharmony_ci host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 120662306a36Sopenharmony_ci struct mmc_data *data = mrq->data; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (!data) 120962306a36Sopenharmony_ci return; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci WARN_ON(data->host_cookie); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (mmci_validate_data(host, data)) 121462306a36Sopenharmony_ci return; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci mmci_prep_data(host, data, true); 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, 122062306a36Sopenharmony_ci int err) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 122362306a36Sopenharmony_ci struct mmc_data *data = mrq->data; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (!data || !data->host_cookie) 122662306a36Sopenharmony_ci return; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci mmci_unprep_data(host, data, err); 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic void mmci_start_data(struct mmci_host *host, struct mmc_data *data) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci struct variant_data *variant = host->variant; 123462306a36Sopenharmony_ci unsigned int datactrl, timeout, irqmask; 123562306a36Sopenharmony_ci unsigned long long clks; 123662306a36Sopenharmony_ci void __iomem *base; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n", 123962306a36Sopenharmony_ci data->blksz, data->blocks, data->flags); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci host->data = data; 124262306a36Sopenharmony_ci host->size = data->blksz * data->blocks; 124362306a36Sopenharmony_ci data->bytes_xfered = 0; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci clks = (unsigned long long)data->timeout_ns * host->cclk; 124662306a36Sopenharmony_ci do_div(clks, NSEC_PER_SEC); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci timeout = data->timeout_clks + (unsigned int)clks; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci base = host->base; 125162306a36Sopenharmony_ci writel(timeout, base + MMCIDATATIMER); 125262306a36Sopenharmony_ci writel(host->size, base + MMCIDATALENGTH); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci datactrl = host->ops->get_datactrl_cfg(host); 125562306a36Sopenharmony_ci datactrl |= host->data->flags & MMC_DATA_READ ? MCI_DPSM_DIRECTION : 0; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (host->mmc->card && mmc_card_sdio(host->mmc->card)) { 125862306a36Sopenharmony_ci u32 clk; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci datactrl |= variant->datactrl_mask_sdio; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* 126362306a36Sopenharmony_ci * The ST Micro variant for SDIO small write transfers 126462306a36Sopenharmony_ci * needs to have clock H/W flow control disabled, 126562306a36Sopenharmony_ci * otherwise the transfer will not start. The threshold 126662306a36Sopenharmony_ci * depends on the rate of MCLK. 126762306a36Sopenharmony_ci */ 126862306a36Sopenharmony_ci if (variant->st_sdio && data->flags & MMC_DATA_WRITE && 126962306a36Sopenharmony_ci (host->size < 8 || 127062306a36Sopenharmony_ci (host->size <= 8 && host->mclk > 50000000))) 127162306a36Sopenharmony_ci clk = host->clk_reg & ~variant->clkreg_enable; 127262306a36Sopenharmony_ci else 127362306a36Sopenharmony_ci clk = host->clk_reg | variant->clkreg_enable; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci mmci_write_clkreg(host, clk); 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 || 127962306a36Sopenharmony_ci host->mmc->ios.timing == MMC_TIMING_MMC_DDR52) 128062306a36Sopenharmony_ci datactrl |= variant->datactrl_mask_ddrmode; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci /* 128362306a36Sopenharmony_ci * Attempt to use DMA operation mode, if this 128462306a36Sopenharmony_ci * should fail, fall back to PIO mode 128562306a36Sopenharmony_ci */ 128662306a36Sopenharmony_ci if (!mmci_dma_start(host, datactrl)) 128762306a36Sopenharmony_ci return; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* IRQ mode, map the SG list for CPU reading/writing */ 129062306a36Sopenharmony_ci mmci_init_sg(host, data); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) { 129362306a36Sopenharmony_ci irqmask = MCI_RXFIFOHALFFULLMASK; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* 129662306a36Sopenharmony_ci * If we have less than the fifo 'half-full' threshold to 129762306a36Sopenharmony_ci * transfer, trigger a PIO interrupt as soon as any data 129862306a36Sopenharmony_ci * is available. 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_ci if (host->size < variant->fifohalfsize) 130162306a36Sopenharmony_ci irqmask |= MCI_RXDATAAVLBLMASK; 130262306a36Sopenharmony_ci } else { 130362306a36Sopenharmony_ci /* 130462306a36Sopenharmony_ci * We don't actually need to include "FIFO empty" here 130562306a36Sopenharmony_ci * since its implicit in "FIFO half empty". 130662306a36Sopenharmony_ci */ 130762306a36Sopenharmony_ci irqmask = MCI_TXFIFOHALFEMPTYMASK; 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci mmci_write_datactrlreg(host, datactrl); 131162306a36Sopenharmony_ci writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); 131262306a36Sopenharmony_ci mmci_set_mask1(host, irqmask); 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_cistatic void 131662306a36Sopenharmony_cimmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci void __iomem *base = host->base; 131962306a36Sopenharmony_ci bool busy_resp = cmd->flags & MMC_RSP_BUSY; 132062306a36Sopenharmony_ci unsigned long long clks; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", 132362306a36Sopenharmony_ci cmd->opcode, cmd->arg, cmd->flags); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci if (readl(base + MMCICOMMAND) & host->variant->cmdreg_cpsm_enable) { 132662306a36Sopenharmony_ci writel(0, base + MMCICOMMAND); 132762306a36Sopenharmony_ci mmci_reg_delay(host); 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci if (host->variant->cmdreg_stop && 133162306a36Sopenharmony_ci cmd->opcode == MMC_STOP_TRANSMISSION) 133262306a36Sopenharmony_ci c |= host->variant->cmdreg_stop; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci c |= cmd->opcode | host->variant->cmdreg_cpsm_enable; 133562306a36Sopenharmony_ci if (cmd->flags & MMC_RSP_PRESENT) { 133662306a36Sopenharmony_ci if (cmd->flags & MMC_RSP_136) 133762306a36Sopenharmony_ci c |= host->variant->cmdreg_lrsp_crc; 133862306a36Sopenharmony_ci else if (cmd->flags & MMC_RSP_CRC) 133962306a36Sopenharmony_ci c |= host->variant->cmdreg_srsp_crc; 134062306a36Sopenharmony_ci else 134162306a36Sopenharmony_ci c |= host->variant->cmdreg_srsp; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci host->busy_status = 0; 134562306a36Sopenharmony_ci host->busy_state = MMCI_BUSY_DONE; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci /* Assign a default timeout if the core does not provide one */ 134862306a36Sopenharmony_ci if (busy_resp && !cmd->busy_timeout) 134962306a36Sopenharmony_ci cmd->busy_timeout = 10 * MSEC_PER_SEC; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci if (busy_resp && host->variant->busy_timeout) { 135262306a36Sopenharmony_ci if (cmd->busy_timeout > host->mmc->max_busy_timeout) 135362306a36Sopenharmony_ci clks = (unsigned long long)host->mmc->max_busy_timeout * host->cclk; 135462306a36Sopenharmony_ci else 135562306a36Sopenharmony_ci clks = (unsigned long long)cmd->busy_timeout * host->cclk; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci do_div(clks, MSEC_PER_SEC); 135862306a36Sopenharmony_ci writel_relaxed(clks, host->base + MMCIDATATIMER); 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (host->ops->pre_sig_volt_switch && cmd->opcode == SD_SWITCH_VOLTAGE) 136262306a36Sopenharmony_ci host->ops->pre_sig_volt_switch(host); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci if (/*interrupt*/0) 136562306a36Sopenharmony_ci c |= MCI_CPSM_INTERRUPT; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) 136862306a36Sopenharmony_ci c |= host->variant->data_cmd_enable; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci host->cmd = cmd; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci writel(cmd->arg, base + MMCIARGUMENT); 137362306a36Sopenharmony_ci writel(c, base + MMCICOMMAND); 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic void mmci_stop_command(struct mmci_host *host) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci host->stop_abort.error = 0; 137962306a36Sopenharmony_ci mmci_start_command(host, &host->stop_abort, 0); 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_cistatic void 138362306a36Sopenharmony_cimmci_data_irq(struct mmci_host *host, struct mmc_data *data, 138462306a36Sopenharmony_ci unsigned int status) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci unsigned int status_err; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* Make sure we have data to handle */ 138962306a36Sopenharmony_ci if (!data) 139062306a36Sopenharmony_ci return; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci /* First check for errors */ 139362306a36Sopenharmony_ci status_err = status & (host->variant->start_err | 139462306a36Sopenharmony_ci MCI_DATACRCFAIL | MCI_DATATIMEOUT | 139562306a36Sopenharmony_ci MCI_TXUNDERRUN | MCI_RXOVERRUN); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (status_err) { 139862306a36Sopenharmony_ci u32 remain, success; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* Terminate the DMA transfer */ 140162306a36Sopenharmony_ci mmci_dma_error(host); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* 140462306a36Sopenharmony_ci * Calculate how far we are into the transfer. Note that 140562306a36Sopenharmony_ci * the data counter gives the number of bytes transferred 140662306a36Sopenharmony_ci * on the MMC bus, not on the host side. On reads, this 140762306a36Sopenharmony_ci * can be as much as a FIFO-worth of data ahead. This 140862306a36Sopenharmony_ci * matters for FIFO overruns only. 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_ci if (!host->variant->datacnt_useless) { 141162306a36Sopenharmony_ci remain = readl(host->base + MMCIDATACNT); 141262306a36Sopenharmony_ci success = data->blksz * data->blocks - remain; 141362306a36Sopenharmony_ci } else { 141462306a36Sopenharmony_ci success = 0; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n", 141862306a36Sopenharmony_ci status_err, success); 141962306a36Sopenharmony_ci if (status_err & MCI_DATACRCFAIL) { 142062306a36Sopenharmony_ci /* Last block was not successful */ 142162306a36Sopenharmony_ci success -= 1; 142262306a36Sopenharmony_ci data->error = -EILSEQ; 142362306a36Sopenharmony_ci } else if (status_err & MCI_DATATIMEOUT) { 142462306a36Sopenharmony_ci data->error = -ETIMEDOUT; 142562306a36Sopenharmony_ci } else if (status_err & MCI_STARTBITERR) { 142662306a36Sopenharmony_ci data->error = -ECOMM; 142762306a36Sopenharmony_ci } else if (status_err & MCI_TXUNDERRUN) { 142862306a36Sopenharmony_ci data->error = -EIO; 142962306a36Sopenharmony_ci } else if (status_err & MCI_RXOVERRUN) { 143062306a36Sopenharmony_ci if (success > host->variant->fifosize) 143162306a36Sopenharmony_ci success -= host->variant->fifosize; 143262306a36Sopenharmony_ci else 143362306a36Sopenharmony_ci success = 0; 143462306a36Sopenharmony_ci data->error = -EIO; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci data->bytes_xfered = round_down(success, data->blksz); 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (status & MCI_DATABLOCKEND) 144062306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (status & MCI_DATAEND || data->error) { 144362306a36Sopenharmony_ci mmci_dma_finalize(host, data); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci mmci_stop_data(host); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (!data->error) 144862306a36Sopenharmony_ci /* The error clause is handled above, success! */ 144962306a36Sopenharmony_ci data->bytes_xfered = data->blksz * data->blocks; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (!data->stop) { 145262306a36Sopenharmony_ci if (host->variant->cmdreg_stop && data->error) 145362306a36Sopenharmony_ci mmci_stop_command(host); 145462306a36Sopenharmony_ci else 145562306a36Sopenharmony_ci mmci_request_end(host, data->mrq); 145662306a36Sopenharmony_ci } else if (host->mrq->sbc && !data->error) { 145762306a36Sopenharmony_ci mmci_request_end(host, data->mrq); 145862306a36Sopenharmony_ci } else { 145962306a36Sopenharmony_ci mmci_start_command(host, data->stop, 0); 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci} 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_cistatic void 146562306a36Sopenharmony_cimmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, 146662306a36Sopenharmony_ci unsigned int status) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci u32 err_msk = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT; 146962306a36Sopenharmony_ci void __iomem *base = host->base; 147062306a36Sopenharmony_ci bool sbc, busy_resp; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (!cmd) 147362306a36Sopenharmony_ci return; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci sbc = (cmd == host->mrq->sbc); 147662306a36Sopenharmony_ci busy_resp = !!(cmd->flags & MMC_RSP_BUSY); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci /* 147962306a36Sopenharmony_ci * We need to be one of these interrupts to be considered worth 148062306a36Sopenharmony_ci * handling. Note that we tag on any latent IRQs postponed 148162306a36Sopenharmony_ci * due to waiting for busy status. 148262306a36Sopenharmony_ci */ 148362306a36Sopenharmony_ci if (host->variant->busy_timeout && busy_resp) 148462306a36Sopenharmony_ci err_msk |= MCI_DATATIMEOUT; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci if (!((status | host->busy_status) & 148762306a36Sopenharmony_ci (err_msk | MCI_CMDSENT | MCI_CMDRESPEND))) 148862306a36Sopenharmony_ci return; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci /* Handle busy detection on DAT0 if the variant supports it. */ 149162306a36Sopenharmony_ci if (busy_resp && host->variant->busy_detect) 149262306a36Sopenharmony_ci if (!host->ops->busy_complete(host, cmd, status, err_msk)) 149362306a36Sopenharmony_ci return; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci host->cmd = NULL; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci if (status & MCI_CMDTIMEOUT) { 149862306a36Sopenharmony_ci cmd->error = -ETIMEDOUT; 149962306a36Sopenharmony_ci } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { 150062306a36Sopenharmony_ci cmd->error = -EILSEQ; 150162306a36Sopenharmony_ci } else if (host->variant->busy_timeout && busy_resp && 150262306a36Sopenharmony_ci status & MCI_DATATIMEOUT) { 150362306a36Sopenharmony_ci cmd->error = -ETIMEDOUT; 150462306a36Sopenharmony_ci /* 150562306a36Sopenharmony_ci * This will wake up mmci_irq_thread() which will issue 150662306a36Sopenharmony_ci * a hardware reset of the MMCI block. 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_ci host->irq_action = IRQ_WAKE_THREAD; 150962306a36Sopenharmony_ci } else { 151062306a36Sopenharmony_ci cmd->resp[0] = readl(base + MMCIRESPONSE0); 151162306a36Sopenharmony_ci cmd->resp[1] = readl(base + MMCIRESPONSE1); 151262306a36Sopenharmony_ci cmd->resp[2] = readl(base + MMCIRESPONSE2); 151362306a36Sopenharmony_ci cmd->resp[3] = readl(base + MMCIRESPONSE3); 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci if ((!sbc && !cmd->data) || cmd->error) { 151762306a36Sopenharmony_ci if (host->data) { 151862306a36Sopenharmony_ci /* Terminate the DMA transfer */ 151962306a36Sopenharmony_ci mmci_dma_error(host); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci mmci_stop_data(host); 152262306a36Sopenharmony_ci if (host->variant->cmdreg_stop && cmd->error) { 152362306a36Sopenharmony_ci mmci_stop_command(host); 152462306a36Sopenharmony_ci return; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci if (host->irq_action != IRQ_WAKE_THREAD) 152962306a36Sopenharmony_ci mmci_request_end(host, host->mrq); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci } else if (sbc) { 153262306a36Sopenharmony_ci mmci_start_command(host, host->mrq->cmd, 0); 153362306a36Sopenharmony_ci } else if (!host->variant->datactrl_first && 153462306a36Sopenharmony_ci !(cmd->data->flags & MMC_DATA_READ)) { 153562306a36Sopenharmony_ci mmci_start_data(host, cmd->data); 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci} 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_cistatic char *ux500_state_str(struct mmci_host *host) 154062306a36Sopenharmony_ci{ 154162306a36Sopenharmony_ci switch (host->busy_state) { 154262306a36Sopenharmony_ci case MMCI_BUSY_WAITING_FOR_START_IRQ: 154362306a36Sopenharmony_ci return "waiting for start IRQ"; 154462306a36Sopenharmony_ci case MMCI_BUSY_WAITING_FOR_END_IRQ: 154562306a36Sopenharmony_ci return "waiting for end IRQ"; 154662306a36Sopenharmony_ci case MMCI_BUSY_DONE: 154762306a36Sopenharmony_ci return "not waiting for IRQs"; 154862306a36Sopenharmony_ci default: 154962306a36Sopenharmony_ci return "unknown"; 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci} 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci/* 155462306a36Sopenharmony_ci * This busy timeout worker is used to "kick" the command IRQ if a 155562306a36Sopenharmony_ci * busy detect IRQ fails to appear in reasonable time. Only used on 155662306a36Sopenharmony_ci * variants with busy detection IRQ delivery. 155762306a36Sopenharmony_ci */ 155862306a36Sopenharmony_cistatic void ux500_busy_timeout_work(struct work_struct *work) 155962306a36Sopenharmony_ci{ 156062306a36Sopenharmony_ci struct mmci_host *host = container_of(work, struct mmci_host, 156162306a36Sopenharmony_ci ux500_busy_timeout_work.work); 156262306a36Sopenharmony_ci unsigned long flags; 156362306a36Sopenharmony_ci u32 status; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (host->cmd) { 156862306a36Sopenharmony_ci /* If we are still busy let's tag on a cmd-timeout error. */ 156962306a36Sopenharmony_ci status = readl(host->base + MMCISTATUS); 157062306a36Sopenharmony_ci if (status & host->variant->busy_detect_flag) { 157162306a36Sopenharmony_ci status |= MCI_CMDTIMEOUT; 157262306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), 157362306a36Sopenharmony_ci "timeout in state %s still busy with CMD%02x\n", 157462306a36Sopenharmony_ci ux500_state_str(host), host->cmd->opcode); 157562306a36Sopenharmony_ci } else { 157662306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), 157762306a36Sopenharmony_ci "timeout in state %s waiting for busy CMD%02x\n", 157862306a36Sopenharmony_ci ux500_state_str(host), host->cmd->opcode); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci mmci_cmd_irq(host, host->cmd, status); 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_cistatic int mmci_get_rx_fifocnt(struct mmci_host *host, u32 status, int remain) 158862306a36Sopenharmony_ci{ 158962306a36Sopenharmony_ci return remain - (readl(host->base + MMCIFIFOCNT) << 2); 159062306a36Sopenharmony_ci} 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_cistatic int mmci_qcom_get_rx_fifocnt(struct mmci_host *host, u32 status, int r) 159362306a36Sopenharmony_ci{ 159462306a36Sopenharmony_ci /* 159562306a36Sopenharmony_ci * on qcom SDCC4 only 8 words are used in each burst so only 8 addresses 159662306a36Sopenharmony_ci * from the fifo range should be used 159762306a36Sopenharmony_ci */ 159862306a36Sopenharmony_ci if (status & MCI_RXFIFOHALFFULL) 159962306a36Sopenharmony_ci return host->variant->fifohalfsize; 160062306a36Sopenharmony_ci else if (status & MCI_RXDATAAVLBL) 160162306a36Sopenharmony_ci return 4; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci return 0; 160462306a36Sopenharmony_ci} 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_cistatic int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) 160762306a36Sopenharmony_ci{ 160862306a36Sopenharmony_ci void __iomem *base = host->base; 160962306a36Sopenharmony_ci char *ptr = buffer; 161062306a36Sopenharmony_ci u32 status = readl(host->base + MMCISTATUS); 161162306a36Sopenharmony_ci int host_remain = host->size; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci do { 161462306a36Sopenharmony_ci int count = host->get_rx_fifocnt(host, status, host_remain); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci if (count > remain) 161762306a36Sopenharmony_ci count = remain; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci if (count <= 0) 162062306a36Sopenharmony_ci break; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci /* 162362306a36Sopenharmony_ci * SDIO especially may want to send something that is 162462306a36Sopenharmony_ci * not divisible by 4 (as opposed to card sectors 162562306a36Sopenharmony_ci * etc). Therefore make sure to always read the last bytes 162662306a36Sopenharmony_ci * while only doing full 32-bit reads towards the FIFO. 162762306a36Sopenharmony_ci */ 162862306a36Sopenharmony_ci if (unlikely(count & 0x3)) { 162962306a36Sopenharmony_ci if (count < 4) { 163062306a36Sopenharmony_ci unsigned char buf[4]; 163162306a36Sopenharmony_ci ioread32_rep(base + MMCIFIFO, buf, 1); 163262306a36Sopenharmony_ci memcpy(ptr, buf, count); 163362306a36Sopenharmony_ci } else { 163462306a36Sopenharmony_ci ioread32_rep(base + MMCIFIFO, ptr, count >> 2); 163562306a36Sopenharmony_ci count &= ~0x3; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci } else { 163862306a36Sopenharmony_ci ioread32_rep(base + MMCIFIFO, ptr, count >> 2); 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci ptr += count; 164262306a36Sopenharmony_ci remain -= count; 164362306a36Sopenharmony_ci host_remain -= count; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci if (remain == 0) 164662306a36Sopenharmony_ci break; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci status = readl(base + MMCISTATUS); 164962306a36Sopenharmony_ci } while (status & MCI_RXDATAAVLBL); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci return ptr - buffer; 165262306a36Sopenharmony_ci} 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_cistatic int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci struct variant_data *variant = host->variant; 165762306a36Sopenharmony_ci void __iomem *base = host->base; 165862306a36Sopenharmony_ci char *ptr = buffer; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci do { 166162306a36Sopenharmony_ci unsigned int count, maxcnt; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci maxcnt = status & MCI_TXFIFOEMPTY ? 166462306a36Sopenharmony_ci variant->fifosize : variant->fifohalfsize; 166562306a36Sopenharmony_ci count = min(remain, maxcnt); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci /* 166862306a36Sopenharmony_ci * SDIO especially may want to send something that is 166962306a36Sopenharmony_ci * not divisible by 4 (as opposed to card sectors 167062306a36Sopenharmony_ci * etc), and the FIFO only accept full 32-bit writes. 167162306a36Sopenharmony_ci * So compensate by adding +3 on the count, a single 167262306a36Sopenharmony_ci * byte become a 32bit write, 7 bytes will be two 167362306a36Sopenharmony_ci * 32bit writes etc. 167462306a36Sopenharmony_ci */ 167562306a36Sopenharmony_ci iowrite32_rep(base + MMCIFIFO, ptr, (count + 3) >> 2); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci ptr += count; 167862306a36Sopenharmony_ci remain -= count; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci if (remain == 0) 168162306a36Sopenharmony_ci break; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci status = readl(base + MMCISTATUS); 168462306a36Sopenharmony_ci } while (status & MCI_TXFIFOHALFEMPTY); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci return ptr - buffer; 168762306a36Sopenharmony_ci} 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci/* 169062306a36Sopenharmony_ci * PIO data transfer IRQ handler. 169162306a36Sopenharmony_ci */ 169262306a36Sopenharmony_cistatic irqreturn_t mmci_pio_irq(int irq, void *dev_id) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci struct mmci_host *host = dev_id; 169562306a36Sopenharmony_ci struct sg_mapping_iter *sg_miter = &host->sg_miter; 169662306a36Sopenharmony_ci struct variant_data *variant = host->variant; 169762306a36Sopenharmony_ci void __iomem *base = host->base; 169862306a36Sopenharmony_ci u32 status; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci status = readl(base + MMCISTATUS); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci do { 170562306a36Sopenharmony_ci unsigned int remain, len; 170662306a36Sopenharmony_ci char *buffer; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci /* 170962306a36Sopenharmony_ci * For write, we only need to test the half-empty flag 171062306a36Sopenharmony_ci * here - if the FIFO is completely empty, then by 171162306a36Sopenharmony_ci * definition it is more than half empty. 171262306a36Sopenharmony_ci * 171362306a36Sopenharmony_ci * For read, check for data available. 171462306a36Sopenharmony_ci */ 171562306a36Sopenharmony_ci if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) 171662306a36Sopenharmony_ci break; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci if (!sg_miter_next(sg_miter)) 171962306a36Sopenharmony_ci break; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci buffer = sg_miter->addr; 172262306a36Sopenharmony_ci remain = sg_miter->length; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci len = 0; 172562306a36Sopenharmony_ci if (status & MCI_RXACTIVE) 172662306a36Sopenharmony_ci len = mmci_pio_read(host, buffer, remain); 172762306a36Sopenharmony_ci if (status & MCI_TXACTIVE) 172862306a36Sopenharmony_ci len = mmci_pio_write(host, buffer, remain, status); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci sg_miter->consumed = len; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci host->size -= len; 173362306a36Sopenharmony_ci remain -= len; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci if (remain) 173662306a36Sopenharmony_ci break; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci status = readl(base + MMCISTATUS); 173962306a36Sopenharmony_ci } while (1); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci sg_miter_stop(sg_miter); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci /* 174462306a36Sopenharmony_ci * If we have less than the fifo 'half-full' threshold to transfer, 174562306a36Sopenharmony_ci * trigger a PIO interrupt as soon as any data is available. 174662306a36Sopenharmony_ci */ 174762306a36Sopenharmony_ci if (status & MCI_RXACTIVE && host->size < variant->fifohalfsize) 174862306a36Sopenharmony_ci mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci /* 175162306a36Sopenharmony_ci * If we run out of data, disable the data IRQs; this 175262306a36Sopenharmony_ci * prevents a race where the FIFO becomes empty before 175362306a36Sopenharmony_ci * the chip itself has disabled the data path, and 175462306a36Sopenharmony_ci * stops us racing with our data end IRQ. 175562306a36Sopenharmony_ci */ 175662306a36Sopenharmony_ci if (host->size == 0) { 175762306a36Sopenharmony_ci mmci_set_mask1(host, 0); 175862306a36Sopenharmony_ci writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci return IRQ_HANDLED; 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci/* 176562306a36Sopenharmony_ci * Handle completion of command and data transfers. 176662306a36Sopenharmony_ci */ 176762306a36Sopenharmony_cistatic irqreturn_t mmci_irq(int irq, void *dev_id) 176862306a36Sopenharmony_ci{ 176962306a36Sopenharmony_ci struct mmci_host *host = dev_id; 177062306a36Sopenharmony_ci u32 status; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci spin_lock(&host->lock); 177362306a36Sopenharmony_ci host->irq_action = IRQ_HANDLED; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci do { 177662306a36Sopenharmony_ci status = readl(host->base + MMCISTATUS); 177762306a36Sopenharmony_ci if (!status) 177862306a36Sopenharmony_ci break; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci if (host->singleirq) { 178162306a36Sopenharmony_ci if (status & host->mask1_reg) 178262306a36Sopenharmony_ci mmci_pio_irq(irq, dev_id); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci status &= ~host->variant->irq_pio_mask; 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci /* 178862306a36Sopenharmony_ci * Busy detection is managed by mmci_cmd_irq(), including to 178962306a36Sopenharmony_ci * clear the corresponding IRQ. 179062306a36Sopenharmony_ci */ 179162306a36Sopenharmony_ci status &= readl(host->base + MMCIMASK0); 179262306a36Sopenharmony_ci if (host->variant->busy_detect) 179362306a36Sopenharmony_ci writel(status & ~host->variant->busy_detect_mask, 179462306a36Sopenharmony_ci host->base + MMCICLEAR); 179562306a36Sopenharmony_ci else 179662306a36Sopenharmony_ci writel(status, host->base + MMCICLEAR); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci if (host->variant->reversed_irq_handling) { 180162306a36Sopenharmony_ci mmci_data_irq(host, host->data, status); 180262306a36Sopenharmony_ci mmci_cmd_irq(host, host->cmd, status); 180362306a36Sopenharmony_ci } else { 180462306a36Sopenharmony_ci mmci_cmd_irq(host, host->cmd, status); 180562306a36Sopenharmony_ci mmci_data_irq(host, host->data, status); 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci /* 180962306a36Sopenharmony_ci * Busy detection has been handled by mmci_cmd_irq() above. 181062306a36Sopenharmony_ci * Clear the status bit to prevent polling in IRQ context. 181162306a36Sopenharmony_ci */ 181262306a36Sopenharmony_ci if (host->variant->busy_detect_flag) 181362306a36Sopenharmony_ci status &= ~host->variant->busy_detect_flag; 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci } while (status); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci spin_unlock(&host->lock); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci return host->irq_action; 182062306a36Sopenharmony_ci} 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci/* 182362306a36Sopenharmony_ci * mmci_irq_thread() - A threaded IRQ handler that manages a reset of the HW. 182462306a36Sopenharmony_ci * 182562306a36Sopenharmony_ci * A reset is needed for some variants, where a datatimeout for a R1B request 182662306a36Sopenharmony_ci * causes the DPSM to stay busy (non-functional). 182762306a36Sopenharmony_ci */ 182862306a36Sopenharmony_cistatic irqreturn_t mmci_irq_thread(int irq, void *dev_id) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci struct mmci_host *host = dev_id; 183162306a36Sopenharmony_ci unsigned long flags; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci if (host->rst) { 183462306a36Sopenharmony_ci reset_control_assert(host->rst); 183562306a36Sopenharmony_ci udelay(2); 183662306a36Sopenharmony_ci reset_control_deassert(host->rst); 183762306a36Sopenharmony_ci } 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 184062306a36Sopenharmony_ci writel(host->clk_reg, host->base + MMCICLOCK); 184162306a36Sopenharmony_ci writel(host->pwr_reg, host->base + MMCIPOWER); 184262306a36Sopenharmony_ci writel(MCI_IRQENABLE | host->variant->start_err, 184362306a36Sopenharmony_ci host->base + MMCIMASK0); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci host->irq_action = IRQ_HANDLED; 184662306a36Sopenharmony_ci mmci_request_end(host, host->mrq); 184762306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci return host->irq_action; 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) 185362306a36Sopenharmony_ci{ 185462306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 185562306a36Sopenharmony_ci unsigned long flags; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci WARN_ON(host->mrq != NULL); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci mrq->cmd->error = mmci_validate_data(host, mrq->data); 186062306a36Sopenharmony_ci if (mrq->cmd->error) { 186162306a36Sopenharmony_ci mmc_request_done(mmc, mrq); 186262306a36Sopenharmony_ci return; 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci host->mrq = mrq; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (mrq->data) 187062306a36Sopenharmony_ci mmci_get_next_data(host, mrq->data); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci if (mrq->data && 187362306a36Sopenharmony_ci (host->variant->datactrl_first || mrq->data->flags & MMC_DATA_READ)) 187462306a36Sopenharmony_ci mmci_start_data(host, mrq->data); 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci if (mrq->sbc) 187762306a36Sopenharmony_ci mmci_start_command(host, mrq->sbc, 0); 187862306a36Sopenharmony_ci else 187962306a36Sopenharmony_ci mmci_start_command(host, mrq->cmd, 0); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 188262306a36Sopenharmony_ci} 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_cistatic void mmci_set_max_busy_timeout(struct mmc_host *mmc) 188562306a36Sopenharmony_ci{ 188662306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 188762306a36Sopenharmony_ci u32 max_busy_timeout = 0; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci if (!host->variant->busy_detect) 189062306a36Sopenharmony_ci return; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (host->variant->busy_timeout && mmc->actual_clock) 189362306a36Sopenharmony_ci max_busy_timeout = U32_MAX / DIV_ROUND_UP(mmc->actual_clock, 189462306a36Sopenharmony_ci MSEC_PER_SEC); 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci mmc->max_busy_timeout = max_busy_timeout; 189762306a36Sopenharmony_ci} 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_cistatic void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 190062306a36Sopenharmony_ci{ 190162306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 190262306a36Sopenharmony_ci struct variant_data *variant = host->variant; 190362306a36Sopenharmony_ci u32 pwr = 0; 190462306a36Sopenharmony_ci unsigned long flags; 190562306a36Sopenharmony_ci int ret; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci switch (ios->power_mode) { 190862306a36Sopenharmony_ci case MMC_POWER_OFF: 190962306a36Sopenharmony_ci if (!IS_ERR(mmc->supply.vmmc)) 191062306a36Sopenharmony_ci mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) { 191362306a36Sopenharmony_ci regulator_disable(mmc->supply.vqmmc); 191462306a36Sopenharmony_ci host->vqmmc_enabled = false; 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci break; 191862306a36Sopenharmony_ci case MMC_POWER_UP: 191962306a36Sopenharmony_ci if (!IS_ERR(mmc->supply.vmmc)) 192062306a36Sopenharmony_ci mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci /* 192362306a36Sopenharmony_ci * The ST Micro variant doesn't have the PL180s MCI_PWR_UP 192462306a36Sopenharmony_ci * and instead uses MCI_PWR_ON so apply whatever value is 192562306a36Sopenharmony_ci * configured in the variant data. 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ci pwr |= variant->pwrreg_powerup; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci break; 193062306a36Sopenharmony_ci case MMC_POWER_ON: 193162306a36Sopenharmony_ci if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) { 193262306a36Sopenharmony_ci ret = regulator_enable(mmc->supply.vqmmc); 193362306a36Sopenharmony_ci if (ret < 0) 193462306a36Sopenharmony_ci dev_err(mmc_dev(mmc), 193562306a36Sopenharmony_ci "failed to enable vqmmc regulator\n"); 193662306a36Sopenharmony_ci else 193762306a36Sopenharmony_ci host->vqmmc_enabled = true; 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci pwr |= MCI_PWR_ON; 194162306a36Sopenharmony_ci break; 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) { 194562306a36Sopenharmony_ci /* 194662306a36Sopenharmony_ci * The ST Micro variant has some additional bits 194762306a36Sopenharmony_ci * indicating signal direction for the signals in 194862306a36Sopenharmony_ci * the SD/MMC bus and feedback-clock usage. 194962306a36Sopenharmony_ci */ 195062306a36Sopenharmony_ci pwr |= host->pwr_reg_add; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci if (ios->bus_width == MMC_BUS_WIDTH_4) 195362306a36Sopenharmony_ci pwr &= ~MCI_ST_DATA74DIREN; 195462306a36Sopenharmony_ci else if (ios->bus_width == MMC_BUS_WIDTH_1) 195562306a36Sopenharmony_ci pwr &= (~MCI_ST_DATA74DIREN & 195662306a36Sopenharmony_ci ~MCI_ST_DATA31DIREN & 195762306a36Sopenharmony_ci ~MCI_ST_DATA2DIREN); 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci if (variant->opendrain) { 196162306a36Sopenharmony_ci if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) 196262306a36Sopenharmony_ci pwr |= variant->opendrain; 196362306a36Sopenharmony_ci } else { 196462306a36Sopenharmony_ci /* 196562306a36Sopenharmony_ci * If the variant cannot configure the pads by its own, then we 196662306a36Sopenharmony_ci * expect the pinctrl to be able to do that for us 196762306a36Sopenharmony_ci */ 196862306a36Sopenharmony_ci if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) 196962306a36Sopenharmony_ci pinctrl_select_state(host->pinctrl, host->pins_opendrain); 197062306a36Sopenharmony_ci else 197162306a36Sopenharmony_ci pinctrl_select_default_state(mmc_dev(mmc)); 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci /* 197562306a36Sopenharmony_ci * If clock = 0 and the variant requires the MMCIPOWER to be used for 197662306a36Sopenharmony_ci * gating the clock, the MCI_PWR_ON bit is cleared. 197762306a36Sopenharmony_ci */ 197862306a36Sopenharmony_ci if (!ios->clock && variant->pwrreg_clkgate) 197962306a36Sopenharmony_ci pwr &= ~MCI_PWR_ON; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci if (host->variant->explicit_mclk_control && 198262306a36Sopenharmony_ci ios->clock != host->clock_cache) { 198362306a36Sopenharmony_ci ret = clk_set_rate(host->clk, ios->clock); 198462306a36Sopenharmony_ci if (ret < 0) 198562306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), 198662306a36Sopenharmony_ci "Error setting clock rate (%d)\n", ret); 198762306a36Sopenharmony_ci else 198862306a36Sopenharmony_ci host->mclk = clk_get_rate(host->clk); 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci host->clock_cache = ios->clock; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci if (host->ops && host->ops->set_clkreg) 199562306a36Sopenharmony_ci host->ops->set_clkreg(host, ios->clock); 199662306a36Sopenharmony_ci else 199762306a36Sopenharmony_ci mmci_set_clkreg(host, ios->clock); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci mmci_set_max_busy_timeout(mmc); 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci if (host->ops && host->ops->set_pwrreg) 200262306a36Sopenharmony_ci host->ops->set_pwrreg(host, pwr); 200362306a36Sopenharmony_ci else 200462306a36Sopenharmony_ci mmci_write_pwrreg(host, pwr); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci mmci_reg_delay(host); 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 200962306a36Sopenharmony_ci} 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_cistatic int mmci_get_cd(struct mmc_host *mmc) 201262306a36Sopenharmony_ci{ 201362306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 201462306a36Sopenharmony_ci struct mmci_platform_data *plat = host->plat; 201562306a36Sopenharmony_ci unsigned int status = mmc_gpio_get_cd(mmc); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci if (status == -ENOSYS) { 201862306a36Sopenharmony_ci if (!plat->status) 201962306a36Sopenharmony_ci return 1; /* Assume always present */ 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci status = plat->status(mmc_dev(host->mmc)); 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci return status; 202462306a36Sopenharmony_ci} 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_cistatic int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) 202762306a36Sopenharmony_ci{ 202862306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 202962306a36Sopenharmony_ci int ret; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci ret = mmc_regulator_set_vqmmc(mmc, ios); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci if (!ret && host->ops && host->ops->post_sig_volt_switch) 203462306a36Sopenharmony_ci ret = host->ops->post_sig_volt_switch(host, ios); 203562306a36Sopenharmony_ci else if (ret) 203662306a36Sopenharmony_ci ret = 0; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci if (ret < 0) 203962306a36Sopenharmony_ci dev_warn(mmc_dev(mmc), "Voltage switch failed\n"); 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci return ret; 204262306a36Sopenharmony_ci} 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_cistatic struct mmc_host_ops mmci_ops = { 204562306a36Sopenharmony_ci .request = mmci_request, 204662306a36Sopenharmony_ci .pre_req = mmci_pre_request, 204762306a36Sopenharmony_ci .post_req = mmci_post_request, 204862306a36Sopenharmony_ci .set_ios = mmci_set_ios, 204962306a36Sopenharmony_ci .get_ro = mmc_gpio_get_ro, 205062306a36Sopenharmony_ci .get_cd = mmci_get_cd, 205162306a36Sopenharmony_ci .start_signal_voltage_switch = mmci_sig_volt_switch, 205262306a36Sopenharmony_ci}; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_cistatic void mmci_probe_level_translator(struct mmc_host *mmc) 205562306a36Sopenharmony_ci{ 205662306a36Sopenharmony_ci struct device *dev = mmc_dev(mmc); 205762306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 205862306a36Sopenharmony_ci struct gpio_desc *cmd_gpio; 205962306a36Sopenharmony_ci struct gpio_desc *ck_gpio; 206062306a36Sopenharmony_ci struct gpio_desc *ckin_gpio; 206162306a36Sopenharmony_ci int clk_hi, clk_lo; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci /* 206462306a36Sopenharmony_ci * Assume the level translator is present if st,use-ckin is set. 206562306a36Sopenharmony_ci * This is to cater for DTs which do not implement this test. 206662306a36Sopenharmony_ci */ 206762306a36Sopenharmony_ci host->clk_reg_add |= MCI_STM32_CLK_SELCKIN; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci cmd_gpio = gpiod_get(dev, "st,cmd", GPIOD_OUT_HIGH); 207062306a36Sopenharmony_ci if (IS_ERR(cmd_gpio)) 207162306a36Sopenharmony_ci goto exit_cmd; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci ck_gpio = gpiod_get(dev, "st,ck", GPIOD_OUT_HIGH); 207462306a36Sopenharmony_ci if (IS_ERR(ck_gpio)) 207562306a36Sopenharmony_ci goto exit_ck; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci ckin_gpio = gpiod_get(dev, "st,ckin", GPIOD_IN); 207862306a36Sopenharmony_ci if (IS_ERR(ckin_gpio)) 207962306a36Sopenharmony_ci goto exit_ckin; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci /* All GPIOs are valid, test whether level translator works */ 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci /* Sample CKIN */ 208462306a36Sopenharmony_ci clk_hi = !!gpiod_get_value(ckin_gpio); 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci /* Set CK low */ 208762306a36Sopenharmony_ci gpiod_set_value(ck_gpio, 0); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci /* Sample CKIN */ 209062306a36Sopenharmony_ci clk_lo = !!gpiod_get_value(ckin_gpio); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci /* Tristate all */ 209362306a36Sopenharmony_ci gpiod_direction_input(cmd_gpio); 209462306a36Sopenharmony_ci gpiod_direction_input(ck_gpio); 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci /* Level translator is present if CK signal is propagated to CKIN */ 209762306a36Sopenharmony_ci if (!clk_hi || clk_lo) { 209862306a36Sopenharmony_ci host->clk_reg_add &= ~MCI_STM32_CLK_SELCKIN; 209962306a36Sopenharmony_ci dev_warn(dev, 210062306a36Sopenharmony_ci "Level translator inoperable, CK signal not detected on CKIN, disabling.\n"); 210162306a36Sopenharmony_ci } 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci gpiod_put(ckin_gpio); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ciexit_ckin: 210662306a36Sopenharmony_ci gpiod_put(ck_gpio); 210762306a36Sopenharmony_ciexit_ck: 210862306a36Sopenharmony_ci gpiod_put(cmd_gpio); 210962306a36Sopenharmony_ciexit_cmd: 211062306a36Sopenharmony_ci pinctrl_select_default_state(dev); 211162306a36Sopenharmony_ci} 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_cistatic int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) 211462306a36Sopenharmony_ci{ 211562306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 211662306a36Sopenharmony_ci int ret = mmc_of_parse(mmc); 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci if (ret) 211962306a36Sopenharmony_ci return ret; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci if (of_property_read_bool(np, "st,sig-dir-dat0")) 212262306a36Sopenharmony_ci host->pwr_reg_add |= MCI_ST_DATA0DIREN; 212362306a36Sopenharmony_ci if (of_property_read_bool(np, "st,sig-dir-dat2")) 212462306a36Sopenharmony_ci host->pwr_reg_add |= MCI_ST_DATA2DIREN; 212562306a36Sopenharmony_ci if (of_property_read_bool(np, "st,sig-dir-dat31")) 212662306a36Sopenharmony_ci host->pwr_reg_add |= MCI_ST_DATA31DIREN; 212762306a36Sopenharmony_ci if (of_property_read_bool(np, "st,sig-dir-dat74")) 212862306a36Sopenharmony_ci host->pwr_reg_add |= MCI_ST_DATA74DIREN; 212962306a36Sopenharmony_ci if (of_property_read_bool(np, "st,sig-dir-cmd")) 213062306a36Sopenharmony_ci host->pwr_reg_add |= MCI_ST_CMDDIREN; 213162306a36Sopenharmony_ci if (of_property_read_bool(np, "st,sig-pin-fbclk")) 213262306a36Sopenharmony_ci host->pwr_reg_add |= MCI_ST_FBCLKEN; 213362306a36Sopenharmony_ci if (of_property_read_bool(np, "st,sig-dir")) 213462306a36Sopenharmony_ci host->pwr_reg_add |= MCI_STM32_DIRPOL; 213562306a36Sopenharmony_ci if (of_property_read_bool(np, "st,neg-edge")) 213662306a36Sopenharmony_ci host->clk_reg_add |= MCI_STM32_CLK_NEGEDGE; 213762306a36Sopenharmony_ci if (of_property_read_bool(np, "st,use-ckin")) 213862306a36Sopenharmony_ci mmci_probe_level_translator(mmc); 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci if (of_property_read_bool(np, "mmc-cap-mmc-highspeed")) 214162306a36Sopenharmony_ci mmc->caps |= MMC_CAP_MMC_HIGHSPEED; 214262306a36Sopenharmony_ci if (of_property_read_bool(np, "mmc-cap-sd-highspeed")) 214362306a36Sopenharmony_ci mmc->caps |= MMC_CAP_SD_HIGHSPEED; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci return 0; 214662306a36Sopenharmony_ci} 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_cistatic int mmci_probe(struct amba_device *dev, 214962306a36Sopenharmony_ci const struct amba_id *id) 215062306a36Sopenharmony_ci{ 215162306a36Sopenharmony_ci struct mmci_platform_data *plat = dev->dev.platform_data; 215262306a36Sopenharmony_ci struct device_node *np = dev->dev.of_node; 215362306a36Sopenharmony_ci struct variant_data *variant = id->data; 215462306a36Sopenharmony_ci struct mmci_host *host; 215562306a36Sopenharmony_ci struct mmc_host *mmc; 215662306a36Sopenharmony_ci int ret; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci /* Must have platform data or Device Tree. */ 215962306a36Sopenharmony_ci if (!plat && !np) { 216062306a36Sopenharmony_ci dev_err(&dev->dev, "No plat data or DT found\n"); 216162306a36Sopenharmony_ci return -EINVAL; 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci if (!plat) { 216562306a36Sopenharmony_ci plat = devm_kzalloc(&dev->dev, sizeof(*plat), GFP_KERNEL); 216662306a36Sopenharmony_ci if (!plat) 216762306a36Sopenharmony_ci return -ENOMEM; 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); 217162306a36Sopenharmony_ci if (!mmc) 217262306a36Sopenharmony_ci return -ENOMEM; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci host = mmc_priv(mmc); 217562306a36Sopenharmony_ci host->mmc = mmc; 217662306a36Sopenharmony_ci host->mmc_ops = &mmci_ops; 217762306a36Sopenharmony_ci mmc->ops = &mmci_ops; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci ret = mmci_of_parse(np, mmc); 218062306a36Sopenharmony_ci if (ret) 218162306a36Sopenharmony_ci goto host_free; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci /* 218462306a36Sopenharmony_ci * Some variant (STM32) doesn't have opendrain bit, nevertheless 218562306a36Sopenharmony_ci * pins can be set accordingly using pinctrl 218662306a36Sopenharmony_ci */ 218762306a36Sopenharmony_ci if (!variant->opendrain) { 218862306a36Sopenharmony_ci host->pinctrl = devm_pinctrl_get(&dev->dev); 218962306a36Sopenharmony_ci if (IS_ERR(host->pinctrl)) { 219062306a36Sopenharmony_ci dev_err(&dev->dev, "failed to get pinctrl"); 219162306a36Sopenharmony_ci ret = PTR_ERR(host->pinctrl); 219262306a36Sopenharmony_ci goto host_free; 219362306a36Sopenharmony_ci } 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci host->pins_opendrain = pinctrl_lookup_state(host->pinctrl, 219662306a36Sopenharmony_ci MMCI_PINCTRL_STATE_OPENDRAIN); 219762306a36Sopenharmony_ci if (IS_ERR(host->pins_opendrain)) { 219862306a36Sopenharmony_ci dev_err(mmc_dev(mmc), "Can't select opendrain pins\n"); 219962306a36Sopenharmony_ci ret = PTR_ERR(host->pins_opendrain); 220062306a36Sopenharmony_ci goto host_free; 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci } 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci host->hw_designer = amba_manf(dev); 220562306a36Sopenharmony_ci host->hw_revision = amba_rev(dev); 220662306a36Sopenharmony_ci dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer); 220762306a36Sopenharmony_ci dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision); 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci host->clk = devm_clk_get(&dev->dev, NULL); 221062306a36Sopenharmony_ci if (IS_ERR(host->clk)) { 221162306a36Sopenharmony_ci ret = PTR_ERR(host->clk); 221262306a36Sopenharmony_ci goto host_free; 221362306a36Sopenharmony_ci } 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci ret = clk_prepare_enable(host->clk); 221662306a36Sopenharmony_ci if (ret) 221762306a36Sopenharmony_ci goto host_free; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci if (variant->qcom_fifo) 222062306a36Sopenharmony_ci host->get_rx_fifocnt = mmci_qcom_get_rx_fifocnt; 222162306a36Sopenharmony_ci else 222262306a36Sopenharmony_ci host->get_rx_fifocnt = mmci_get_rx_fifocnt; 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci host->plat = plat; 222562306a36Sopenharmony_ci host->variant = variant; 222662306a36Sopenharmony_ci host->mclk = clk_get_rate(host->clk); 222762306a36Sopenharmony_ci /* 222862306a36Sopenharmony_ci * According to the spec, mclk is max 100 MHz, 222962306a36Sopenharmony_ci * so we try to adjust the clock down to this, 223062306a36Sopenharmony_ci * (if possible). 223162306a36Sopenharmony_ci */ 223262306a36Sopenharmony_ci if (host->mclk > variant->f_max) { 223362306a36Sopenharmony_ci ret = clk_set_rate(host->clk, variant->f_max); 223462306a36Sopenharmony_ci if (ret < 0) 223562306a36Sopenharmony_ci goto clk_disable; 223662306a36Sopenharmony_ci host->mclk = clk_get_rate(host->clk); 223762306a36Sopenharmony_ci dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n", 223862306a36Sopenharmony_ci host->mclk); 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci host->phybase = dev->res.start; 224262306a36Sopenharmony_ci host->base = devm_ioremap_resource(&dev->dev, &dev->res); 224362306a36Sopenharmony_ci if (IS_ERR(host->base)) { 224462306a36Sopenharmony_ci ret = PTR_ERR(host->base); 224562306a36Sopenharmony_ci goto clk_disable; 224662306a36Sopenharmony_ci } 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci if (variant->init) 224962306a36Sopenharmony_ci variant->init(host); 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci /* 225262306a36Sopenharmony_ci * The ARM and ST versions of the block have slightly different 225362306a36Sopenharmony_ci * clock divider equations which means that the minimum divider 225462306a36Sopenharmony_ci * differs too. 225562306a36Sopenharmony_ci * on Qualcomm like controllers get the nearest minimum clock to 100Khz 225662306a36Sopenharmony_ci */ 225762306a36Sopenharmony_ci if (variant->st_clkdiv) 225862306a36Sopenharmony_ci mmc->f_min = DIV_ROUND_UP(host->mclk, 257); 225962306a36Sopenharmony_ci else if (variant->stm32_clkdiv) 226062306a36Sopenharmony_ci mmc->f_min = DIV_ROUND_UP(host->mclk, 2046); 226162306a36Sopenharmony_ci else if (variant->explicit_mclk_control) 226262306a36Sopenharmony_ci mmc->f_min = clk_round_rate(host->clk, 100000); 226362306a36Sopenharmony_ci else 226462306a36Sopenharmony_ci mmc->f_min = DIV_ROUND_UP(host->mclk, 512); 226562306a36Sopenharmony_ci /* 226662306a36Sopenharmony_ci * If no maximum operating frequency is supplied, fall back to use 226762306a36Sopenharmony_ci * the module parameter, which has a (low) default value in case it 226862306a36Sopenharmony_ci * is not specified. Either value must not exceed the clock rate into 226962306a36Sopenharmony_ci * the block, of course. 227062306a36Sopenharmony_ci */ 227162306a36Sopenharmony_ci if (mmc->f_max) 227262306a36Sopenharmony_ci mmc->f_max = variant->explicit_mclk_control ? 227362306a36Sopenharmony_ci min(variant->f_max, mmc->f_max) : 227462306a36Sopenharmony_ci min(host->mclk, mmc->f_max); 227562306a36Sopenharmony_ci else 227662306a36Sopenharmony_ci mmc->f_max = variant->explicit_mclk_control ? 227762306a36Sopenharmony_ci fmax : min(host->mclk, fmax); 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci host->rst = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); 228362306a36Sopenharmony_ci if (IS_ERR(host->rst)) { 228462306a36Sopenharmony_ci ret = PTR_ERR(host->rst); 228562306a36Sopenharmony_ci goto clk_disable; 228662306a36Sopenharmony_ci } 228762306a36Sopenharmony_ci ret = reset_control_deassert(host->rst); 228862306a36Sopenharmony_ci if (ret) 228962306a36Sopenharmony_ci dev_err(mmc_dev(mmc), "failed to de-assert reset\n"); 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* Get regulators and the supported OCR mask */ 229262306a36Sopenharmony_ci ret = mmc_regulator_get_supply(mmc); 229362306a36Sopenharmony_ci if (ret) 229462306a36Sopenharmony_ci goto clk_disable; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci if (!mmc->ocr_avail) 229762306a36Sopenharmony_ci mmc->ocr_avail = plat->ocr_mask; 229862306a36Sopenharmony_ci else if (plat->ocr_mask) 229962306a36Sopenharmony_ci dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci /* We support these capabilities. */ 230262306a36Sopenharmony_ci mmc->caps |= MMC_CAP_CMD23; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci /* 230562306a36Sopenharmony_ci * Enable busy detection. 230662306a36Sopenharmony_ci */ 230762306a36Sopenharmony_ci if (variant->busy_detect) { 230862306a36Sopenharmony_ci mmci_ops.card_busy = mmci_card_busy; 230962306a36Sopenharmony_ci /* 231062306a36Sopenharmony_ci * Not all variants have a flag to enable busy detection 231162306a36Sopenharmony_ci * in the DPSM, but if they do, set it here. 231262306a36Sopenharmony_ci */ 231362306a36Sopenharmony_ci if (variant->busy_dpsm_flag) 231462306a36Sopenharmony_ci mmci_write_datactrlreg(host, 231562306a36Sopenharmony_ci host->variant->busy_dpsm_flag); 231662306a36Sopenharmony_ci mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; 231762306a36Sopenharmony_ci } 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci /* Variants with mandatory busy timeout in HW needs R1B responses. */ 232062306a36Sopenharmony_ci if (variant->busy_timeout) 232162306a36Sopenharmony_ci mmc->caps |= MMC_CAP_NEED_RSP_BUSY; 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci /* Prepare a CMD12 - needed to clear the DPSM on some variants. */ 232462306a36Sopenharmony_ci host->stop_abort.opcode = MMC_STOP_TRANSMISSION; 232562306a36Sopenharmony_ci host->stop_abort.arg = 0; 232662306a36Sopenharmony_ci host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci /* We support these PM capabilities. */ 232962306a36Sopenharmony_ci mmc->pm_caps |= MMC_PM_KEEP_POWER; 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci /* 233262306a36Sopenharmony_ci * We can do SGIO 233362306a36Sopenharmony_ci */ 233462306a36Sopenharmony_ci mmc->max_segs = NR_SG; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci /* 233762306a36Sopenharmony_ci * Since only a certain number of bits are valid in the data length 233862306a36Sopenharmony_ci * register, we must ensure that we don't exceed 2^num-1 bytes in a 233962306a36Sopenharmony_ci * single request. 234062306a36Sopenharmony_ci */ 234162306a36Sopenharmony_ci mmc->max_req_size = (1 << variant->datalength_bits) - 1; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci /* 234462306a36Sopenharmony_ci * Set the maximum segment size. Since we aren't doing DMA 234562306a36Sopenharmony_ci * (yet) we are only limited by the data length register. 234662306a36Sopenharmony_ci */ 234762306a36Sopenharmony_ci mmc->max_seg_size = mmc->max_req_size; 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci /* 235062306a36Sopenharmony_ci * Block size can be up to 2048 bytes, but must be a power of two. 235162306a36Sopenharmony_ci */ 235262306a36Sopenharmony_ci mmc->max_blk_size = 1 << variant->datactrl_blocksz; 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci /* 235562306a36Sopenharmony_ci * Limit the number of blocks transferred so that we don't overflow 235662306a36Sopenharmony_ci * the maximum request size. 235762306a36Sopenharmony_ci */ 235862306a36Sopenharmony_ci mmc->max_blk_count = mmc->max_req_size >> variant->datactrl_blocksz; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci spin_lock_init(&host->lock); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci writel(0, host->base + MMCIMASK0); 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci if (variant->mmcimask1) 236562306a36Sopenharmony_ci writel(0, host->base + MMCIMASK1); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci writel(0xfff, host->base + MMCICLEAR); 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci /* 237062306a36Sopenharmony_ci * If: 237162306a36Sopenharmony_ci * - not using DT but using a descriptor table, or 237262306a36Sopenharmony_ci * - using a table of descriptors ALONGSIDE DT, or 237362306a36Sopenharmony_ci * look up these descriptors named "cd" and "wp" right here, fail 237462306a36Sopenharmony_ci * silently of these do not exist 237562306a36Sopenharmony_ci */ 237662306a36Sopenharmony_ci if (!np) { 237762306a36Sopenharmony_ci ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0); 237862306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 237962306a36Sopenharmony_ci goto clk_disable; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0); 238262306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 238362306a36Sopenharmony_ci goto clk_disable; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci ret = devm_request_threaded_irq(&dev->dev, dev->irq[0], mmci_irq, 238762306a36Sopenharmony_ci mmci_irq_thread, IRQF_SHARED, 238862306a36Sopenharmony_ci DRIVER_NAME " (cmd)", host); 238962306a36Sopenharmony_ci if (ret) 239062306a36Sopenharmony_ci goto clk_disable; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci if (!dev->irq[1]) 239362306a36Sopenharmony_ci host->singleirq = true; 239462306a36Sopenharmony_ci else { 239562306a36Sopenharmony_ci ret = devm_request_irq(&dev->dev, dev->irq[1], mmci_pio_irq, 239662306a36Sopenharmony_ci IRQF_SHARED, DRIVER_NAME " (pio)", host); 239762306a36Sopenharmony_ci if (ret) 239862306a36Sopenharmony_ci goto clk_disable; 239962306a36Sopenharmony_ci } 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci if (host->variant->busy_detect) 240262306a36Sopenharmony_ci INIT_DELAYED_WORK(&host->ux500_busy_timeout_work, 240362306a36Sopenharmony_ci ux500_busy_timeout_work); 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci writel(MCI_IRQENABLE | variant->start_err, host->base + MMCIMASK0); 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci amba_set_drvdata(dev, mmc); 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n", 241062306a36Sopenharmony_ci mmc_hostname(mmc), amba_part(dev), amba_manf(dev), 241162306a36Sopenharmony_ci amba_rev(dev), (unsigned long long)dev->res.start, 241262306a36Sopenharmony_ci dev->irq[0], dev->irq[1]); 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci mmci_dma_setup(host); 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(&dev->dev, 50); 241762306a36Sopenharmony_ci pm_runtime_use_autosuspend(&dev->dev); 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci ret = mmc_add_host(mmc); 242062306a36Sopenharmony_ci if (ret) 242162306a36Sopenharmony_ci goto clk_disable; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci pm_runtime_put(&dev->dev); 242462306a36Sopenharmony_ci return 0; 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci clk_disable: 242762306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 242862306a36Sopenharmony_ci host_free: 242962306a36Sopenharmony_ci mmc_free_host(mmc); 243062306a36Sopenharmony_ci return ret; 243162306a36Sopenharmony_ci} 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_cistatic void mmci_remove(struct amba_device *dev) 243462306a36Sopenharmony_ci{ 243562306a36Sopenharmony_ci struct mmc_host *mmc = amba_get_drvdata(dev); 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci if (mmc) { 243862306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 243962306a36Sopenharmony_ci struct variant_data *variant = host->variant; 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci /* 244262306a36Sopenharmony_ci * Undo pm_runtime_put() in probe. We use the _sync 244362306a36Sopenharmony_ci * version here so that we can access the primecell. 244462306a36Sopenharmony_ci */ 244562306a36Sopenharmony_ci pm_runtime_get_sync(&dev->dev); 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci mmc_remove_host(mmc); 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci writel(0, host->base + MMCIMASK0); 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci if (variant->mmcimask1) 245262306a36Sopenharmony_ci writel(0, host->base + MMCIMASK1); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci writel(0, host->base + MMCICOMMAND); 245562306a36Sopenharmony_ci writel(0, host->base + MMCIDATACTRL); 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci mmci_dma_release(host); 245862306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 245962306a36Sopenharmony_ci mmc_free_host(mmc); 246062306a36Sopenharmony_ci } 246162306a36Sopenharmony_ci} 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci#ifdef CONFIG_PM 246462306a36Sopenharmony_cistatic void mmci_save(struct mmci_host *host) 246562306a36Sopenharmony_ci{ 246662306a36Sopenharmony_ci unsigned long flags; 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci writel(0, host->base + MMCIMASK0); 247162306a36Sopenharmony_ci if (host->variant->pwrreg_nopower) { 247262306a36Sopenharmony_ci writel(0, host->base + MMCIDATACTRL); 247362306a36Sopenharmony_ci writel(0, host->base + MMCIPOWER); 247462306a36Sopenharmony_ci writel(0, host->base + MMCICLOCK); 247562306a36Sopenharmony_ci } 247662306a36Sopenharmony_ci mmci_reg_delay(host); 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 247962306a36Sopenharmony_ci} 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_cistatic void mmci_restore(struct mmci_host *host) 248262306a36Sopenharmony_ci{ 248362306a36Sopenharmony_ci unsigned long flags; 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci if (host->variant->pwrreg_nopower) { 248862306a36Sopenharmony_ci writel(host->clk_reg, host->base + MMCICLOCK); 248962306a36Sopenharmony_ci writel(host->datactrl_reg, host->base + MMCIDATACTRL); 249062306a36Sopenharmony_ci writel(host->pwr_reg, host->base + MMCIPOWER); 249162306a36Sopenharmony_ci } 249262306a36Sopenharmony_ci writel(MCI_IRQENABLE | host->variant->start_err, 249362306a36Sopenharmony_ci host->base + MMCIMASK0); 249462306a36Sopenharmony_ci mmci_reg_delay(host); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 249762306a36Sopenharmony_ci} 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_cistatic int mmci_runtime_suspend(struct device *dev) 250062306a36Sopenharmony_ci{ 250162306a36Sopenharmony_ci struct amba_device *adev = to_amba_device(dev); 250262306a36Sopenharmony_ci struct mmc_host *mmc = amba_get_drvdata(adev); 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci if (mmc) { 250562306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 250662306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 250762306a36Sopenharmony_ci mmci_save(host); 250862306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 250962306a36Sopenharmony_ci } 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci return 0; 251262306a36Sopenharmony_ci} 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_cistatic int mmci_runtime_resume(struct device *dev) 251562306a36Sopenharmony_ci{ 251662306a36Sopenharmony_ci struct amba_device *adev = to_amba_device(dev); 251762306a36Sopenharmony_ci struct mmc_host *mmc = amba_get_drvdata(adev); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci if (mmc) { 252062306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 252162306a36Sopenharmony_ci clk_prepare_enable(host->clk); 252262306a36Sopenharmony_ci mmci_restore(host); 252362306a36Sopenharmony_ci pinctrl_select_default_state(dev); 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci return 0; 252762306a36Sopenharmony_ci} 252862306a36Sopenharmony_ci#endif 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_cistatic const struct dev_pm_ops mmci_dev_pm_ops = { 253162306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 253262306a36Sopenharmony_ci pm_runtime_force_resume) 253362306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) 253462306a36Sopenharmony_ci}; 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_cistatic const struct amba_id mmci_ids[] = { 253762306a36Sopenharmony_ci { 253862306a36Sopenharmony_ci .id = 0x00041180, 253962306a36Sopenharmony_ci .mask = 0xff0fffff, 254062306a36Sopenharmony_ci .data = &variant_arm, 254162306a36Sopenharmony_ci }, 254262306a36Sopenharmony_ci { 254362306a36Sopenharmony_ci .id = 0x01041180, 254462306a36Sopenharmony_ci .mask = 0xff0fffff, 254562306a36Sopenharmony_ci .data = &variant_arm_extended_fifo, 254662306a36Sopenharmony_ci }, 254762306a36Sopenharmony_ci { 254862306a36Sopenharmony_ci .id = 0x02041180, 254962306a36Sopenharmony_ci .mask = 0xff0fffff, 255062306a36Sopenharmony_ci .data = &variant_arm_extended_fifo_hwfc, 255162306a36Sopenharmony_ci }, 255262306a36Sopenharmony_ci { 255362306a36Sopenharmony_ci .id = 0x00041181, 255462306a36Sopenharmony_ci .mask = 0x000fffff, 255562306a36Sopenharmony_ci .data = &variant_arm, 255662306a36Sopenharmony_ci }, 255762306a36Sopenharmony_ci /* ST Micro variants */ 255862306a36Sopenharmony_ci { 255962306a36Sopenharmony_ci .id = 0x00180180, 256062306a36Sopenharmony_ci .mask = 0x00ffffff, 256162306a36Sopenharmony_ci .data = &variant_u300, 256262306a36Sopenharmony_ci }, 256362306a36Sopenharmony_ci { 256462306a36Sopenharmony_ci .id = 0x10180180, 256562306a36Sopenharmony_ci .mask = 0xf0ffffff, 256662306a36Sopenharmony_ci .data = &variant_nomadik, 256762306a36Sopenharmony_ci }, 256862306a36Sopenharmony_ci { 256962306a36Sopenharmony_ci .id = 0x00280180, 257062306a36Sopenharmony_ci .mask = 0x00ffffff, 257162306a36Sopenharmony_ci .data = &variant_nomadik, 257262306a36Sopenharmony_ci }, 257362306a36Sopenharmony_ci { 257462306a36Sopenharmony_ci .id = 0x00480180, 257562306a36Sopenharmony_ci .mask = 0xf0ffffff, 257662306a36Sopenharmony_ci .data = &variant_ux500, 257762306a36Sopenharmony_ci }, 257862306a36Sopenharmony_ci { 257962306a36Sopenharmony_ci .id = 0x10480180, 258062306a36Sopenharmony_ci .mask = 0xf0ffffff, 258162306a36Sopenharmony_ci .data = &variant_ux500v2, 258262306a36Sopenharmony_ci }, 258362306a36Sopenharmony_ci { 258462306a36Sopenharmony_ci .id = 0x00880180, 258562306a36Sopenharmony_ci .mask = 0x00ffffff, 258662306a36Sopenharmony_ci .data = &variant_stm32, 258762306a36Sopenharmony_ci }, 258862306a36Sopenharmony_ci { 258962306a36Sopenharmony_ci .id = 0x10153180, 259062306a36Sopenharmony_ci .mask = 0xf0ffffff, 259162306a36Sopenharmony_ci .data = &variant_stm32_sdmmc, 259262306a36Sopenharmony_ci }, 259362306a36Sopenharmony_ci { 259462306a36Sopenharmony_ci .id = 0x00253180, 259562306a36Sopenharmony_ci .mask = 0xf0ffffff, 259662306a36Sopenharmony_ci .data = &variant_stm32_sdmmcv2, 259762306a36Sopenharmony_ci }, 259862306a36Sopenharmony_ci { 259962306a36Sopenharmony_ci .id = 0x20253180, 260062306a36Sopenharmony_ci .mask = 0xf0ffffff, 260162306a36Sopenharmony_ci .data = &variant_stm32_sdmmcv2, 260262306a36Sopenharmony_ci }, 260362306a36Sopenharmony_ci { 260462306a36Sopenharmony_ci .id = 0x00353180, 260562306a36Sopenharmony_ci .mask = 0xf0ffffff, 260662306a36Sopenharmony_ci .data = &variant_stm32_sdmmcv3, 260762306a36Sopenharmony_ci }, 260862306a36Sopenharmony_ci /* Qualcomm variants */ 260962306a36Sopenharmony_ci { 261062306a36Sopenharmony_ci .id = 0x00051180, 261162306a36Sopenharmony_ci .mask = 0x000fffff, 261262306a36Sopenharmony_ci .data = &variant_qcom, 261362306a36Sopenharmony_ci }, 261462306a36Sopenharmony_ci { 0, 0 }, 261562306a36Sopenharmony_ci}; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(amba, mmci_ids); 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_cistatic struct amba_driver mmci_driver = { 262062306a36Sopenharmony_ci .drv = { 262162306a36Sopenharmony_ci .name = DRIVER_NAME, 262262306a36Sopenharmony_ci .pm = &mmci_dev_pm_ops, 262362306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 262462306a36Sopenharmony_ci }, 262562306a36Sopenharmony_ci .probe = mmci_probe, 262662306a36Sopenharmony_ci .remove = mmci_remove, 262762306a36Sopenharmony_ci .id_table = mmci_ids, 262862306a36Sopenharmony_ci}; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_cimodule_amba_driver(mmci_driver); 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_cimodule_param(fmax, uint, 0444); 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ciMODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); 263562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2636