162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for sunxi SD/MMC host controllers
462306a36Sopenharmony_ci * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
562306a36Sopenharmony_ci * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com>
662306a36Sopenharmony_ci * (C) Copyright 2013-2014 O2S GmbH <www.o2s.ch>
762306a36Sopenharmony_ci * (C) Copyright 2013-2014 David Lanzendörfer <david.lanzendoerfer@o2s.ch>
862306a36Sopenharmony_ci * (C) Copyright 2013-2014 Hans de Goede <hdegoede@redhat.com>
962306a36Sopenharmony_ci * (C) Copyright 2017 Sootech SA
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/clk.h>
1362306a36Sopenharmony_ci#include <linux/clk/sunxi-ng.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/device.h>
1662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1762306a36Sopenharmony_ci#include <linux/err.h>
1862306a36Sopenharmony_ci#include <linux/interrupt.h>
1962306a36Sopenharmony_ci#include <linux/io.h>
2062306a36Sopenharmony_ci#include <linux/kernel.h>
2162306a36Sopenharmony_ci#include <linux/mmc/card.h>
2262306a36Sopenharmony_ci#include <linux/mmc/core.h>
2362306a36Sopenharmony_ci#include <linux/mmc/host.h>
2462306a36Sopenharmony_ci#include <linux/mmc/mmc.h>
2562306a36Sopenharmony_ci#include <linux/mmc/sd.h>
2662306a36Sopenharmony_ci#include <linux/mmc/sdio.h>
2762306a36Sopenharmony_ci#include <linux/mmc/slot-gpio.h>
2862306a36Sopenharmony_ci#include <linux/module.h>
2962306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
3062306a36Sopenharmony_ci#include <linux/of_address.h>
3162306a36Sopenharmony_ci#include <linux/of_platform.h>
3262306a36Sopenharmony_ci#include <linux/platform_device.h>
3362306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
3562306a36Sopenharmony_ci#include <linux/reset.h>
3662306a36Sopenharmony_ci#include <linux/scatterlist.h>
3762306a36Sopenharmony_ci#include <linux/slab.h>
3862306a36Sopenharmony_ci#include <linux/spinlock.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* register offset definitions */
4162306a36Sopenharmony_ci#define SDXC_REG_GCTRL	(0x00) /* SMC Global Control Register */
4262306a36Sopenharmony_ci#define SDXC_REG_CLKCR	(0x04) /* SMC Clock Control Register */
4362306a36Sopenharmony_ci#define SDXC_REG_TMOUT	(0x08) /* SMC Time Out Register */
4462306a36Sopenharmony_ci#define SDXC_REG_WIDTH	(0x0C) /* SMC Bus Width Register */
4562306a36Sopenharmony_ci#define SDXC_REG_BLKSZ	(0x10) /* SMC Block Size Register */
4662306a36Sopenharmony_ci#define SDXC_REG_BCNTR	(0x14) /* SMC Byte Count Register */
4762306a36Sopenharmony_ci#define SDXC_REG_CMDR	(0x18) /* SMC Command Register */
4862306a36Sopenharmony_ci#define SDXC_REG_CARG	(0x1C) /* SMC Argument Register */
4962306a36Sopenharmony_ci#define SDXC_REG_RESP0	(0x20) /* SMC Response Register 0 */
5062306a36Sopenharmony_ci#define SDXC_REG_RESP1	(0x24) /* SMC Response Register 1 */
5162306a36Sopenharmony_ci#define SDXC_REG_RESP2	(0x28) /* SMC Response Register 2 */
5262306a36Sopenharmony_ci#define SDXC_REG_RESP3	(0x2C) /* SMC Response Register 3 */
5362306a36Sopenharmony_ci#define SDXC_REG_IMASK	(0x30) /* SMC Interrupt Mask Register */
5462306a36Sopenharmony_ci#define SDXC_REG_MISTA	(0x34) /* SMC Masked Interrupt Status Register */
5562306a36Sopenharmony_ci#define SDXC_REG_RINTR	(0x38) /* SMC Raw Interrupt Status Register */
5662306a36Sopenharmony_ci#define SDXC_REG_STAS	(0x3C) /* SMC Status Register */
5762306a36Sopenharmony_ci#define SDXC_REG_FTRGL	(0x40) /* SMC FIFO Threshold Watermark Registe */
5862306a36Sopenharmony_ci#define SDXC_REG_FUNS	(0x44) /* SMC Function Select Register */
5962306a36Sopenharmony_ci#define SDXC_REG_CBCR	(0x48) /* SMC CIU Byte Count Register */
6062306a36Sopenharmony_ci#define SDXC_REG_BBCR	(0x4C) /* SMC BIU Byte Count Register */
6162306a36Sopenharmony_ci#define SDXC_REG_DBGC	(0x50) /* SMC Debug Enable Register */
6262306a36Sopenharmony_ci#define SDXC_REG_HWRST	(0x78) /* SMC Card Hardware Reset for Register */
6362306a36Sopenharmony_ci#define SDXC_REG_DMAC	(0x80) /* SMC IDMAC Control Register */
6462306a36Sopenharmony_ci#define SDXC_REG_DLBA	(0x84) /* SMC IDMAC Descriptor List Base Addre */
6562306a36Sopenharmony_ci#define SDXC_REG_IDST	(0x88) /* SMC IDMAC Status Register */
6662306a36Sopenharmony_ci#define SDXC_REG_IDIE	(0x8C) /* SMC IDMAC Interrupt Enable Register */
6762306a36Sopenharmony_ci#define SDXC_REG_CHDA	(0x90)
6862306a36Sopenharmony_ci#define SDXC_REG_CBDA	(0x94)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* New registers introduced in A64 */
7162306a36Sopenharmony_ci#define SDXC_REG_A12A		0x058 /* SMC Auto Command 12 Register */
7262306a36Sopenharmony_ci#define SDXC_REG_SD_NTSR	0x05C /* SMC New Timing Set Register */
7362306a36Sopenharmony_ci#define SDXC_REG_DRV_DL		0x140 /* Drive Delay Control Register */
7462306a36Sopenharmony_ci#define SDXC_REG_SAMP_DL_REG	0x144 /* SMC sample delay control */
7562306a36Sopenharmony_ci#define SDXC_REG_DS_DL_REG	0x148 /* SMC data strobe delay control */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define mmc_readl(host, reg) \
7862306a36Sopenharmony_ci	readl((host)->reg_base + SDXC_##reg)
7962306a36Sopenharmony_ci#define mmc_writel(host, reg, value) \
8062306a36Sopenharmony_ci	writel((value), (host)->reg_base + SDXC_##reg)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* global control register bits */
8362306a36Sopenharmony_ci#define SDXC_SOFT_RESET			BIT(0)
8462306a36Sopenharmony_ci#define SDXC_FIFO_RESET			BIT(1)
8562306a36Sopenharmony_ci#define SDXC_DMA_RESET			BIT(2)
8662306a36Sopenharmony_ci#define SDXC_INTERRUPT_ENABLE_BIT	BIT(4)
8762306a36Sopenharmony_ci#define SDXC_DMA_ENABLE_BIT		BIT(5)
8862306a36Sopenharmony_ci#define SDXC_DEBOUNCE_ENABLE_BIT	BIT(8)
8962306a36Sopenharmony_ci#define SDXC_POSEDGE_LATCH_DATA		BIT(9)
9062306a36Sopenharmony_ci#define SDXC_DDR_MODE			BIT(10)
9162306a36Sopenharmony_ci#define SDXC_MEMORY_ACCESS_DONE		BIT(29)
9262306a36Sopenharmony_ci#define SDXC_ACCESS_DONE_DIRECT		BIT(30)
9362306a36Sopenharmony_ci#define SDXC_ACCESS_BY_AHB		BIT(31)
9462306a36Sopenharmony_ci#define SDXC_ACCESS_BY_DMA		(0 << 31)
9562306a36Sopenharmony_ci#define SDXC_HARDWARE_RESET \
9662306a36Sopenharmony_ci	(SDXC_SOFT_RESET | SDXC_FIFO_RESET | SDXC_DMA_RESET)
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/* clock control bits */
9962306a36Sopenharmony_ci#define SDXC_MASK_DATA0			BIT(31)
10062306a36Sopenharmony_ci#define SDXC_CARD_CLOCK_ON		BIT(16)
10162306a36Sopenharmony_ci#define SDXC_LOW_POWER_ON		BIT(17)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* bus width */
10462306a36Sopenharmony_ci#define SDXC_WIDTH1			0
10562306a36Sopenharmony_ci#define SDXC_WIDTH4			1
10662306a36Sopenharmony_ci#define SDXC_WIDTH8			2
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/* smc command bits */
10962306a36Sopenharmony_ci#define SDXC_RESP_EXPIRE		BIT(6)
11062306a36Sopenharmony_ci#define SDXC_LONG_RESPONSE		BIT(7)
11162306a36Sopenharmony_ci#define SDXC_CHECK_RESPONSE_CRC		BIT(8)
11262306a36Sopenharmony_ci#define SDXC_DATA_EXPIRE		BIT(9)
11362306a36Sopenharmony_ci#define SDXC_WRITE			BIT(10)
11462306a36Sopenharmony_ci#define SDXC_SEQUENCE_MODE		BIT(11)
11562306a36Sopenharmony_ci#define SDXC_SEND_AUTO_STOP		BIT(12)
11662306a36Sopenharmony_ci#define SDXC_WAIT_PRE_OVER		BIT(13)
11762306a36Sopenharmony_ci#define SDXC_STOP_ABORT_CMD		BIT(14)
11862306a36Sopenharmony_ci#define SDXC_SEND_INIT_SEQUENCE		BIT(15)
11962306a36Sopenharmony_ci#define SDXC_UPCLK_ONLY			BIT(21)
12062306a36Sopenharmony_ci#define SDXC_READ_CEATA_DEV		BIT(22)
12162306a36Sopenharmony_ci#define SDXC_CCS_EXPIRE			BIT(23)
12262306a36Sopenharmony_ci#define SDXC_ENABLE_BIT_BOOT		BIT(24)
12362306a36Sopenharmony_ci#define SDXC_ALT_BOOT_OPTIONS		BIT(25)
12462306a36Sopenharmony_ci#define SDXC_BOOT_ACK_EXPIRE		BIT(26)
12562306a36Sopenharmony_ci#define SDXC_BOOT_ABORT			BIT(27)
12662306a36Sopenharmony_ci#define SDXC_VOLTAGE_SWITCH	        BIT(28)
12762306a36Sopenharmony_ci#define SDXC_USE_HOLD_REGISTER	        BIT(29)
12862306a36Sopenharmony_ci#define SDXC_START			BIT(31)
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* interrupt bits */
13162306a36Sopenharmony_ci#define SDXC_RESP_ERROR			BIT(1)
13262306a36Sopenharmony_ci#define SDXC_COMMAND_DONE		BIT(2)
13362306a36Sopenharmony_ci#define SDXC_DATA_OVER			BIT(3)
13462306a36Sopenharmony_ci#define SDXC_TX_DATA_REQUEST		BIT(4)
13562306a36Sopenharmony_ci#define SDXC_RX_DATA_REQUEST		BIT(5)
13662306a36Sopenharmony_ci#define SDXC_RESP_CRC_ERROR		BIT(6)
13762306a36Sopenharmony_ci#define SDXC_DATA_CRC_ERROR		BIT(7)
13862306a36Sopenharmony_ci#define SDXC_RESP_TIMEOUT		BIT(8)
13962306a36Sopenharmony_ci#define SDXC_DATA_TIMEOUT		BIT(9)
14062306a36Sopenharmony_ci#define SDXC_VOLTAGE_CHANGE_DONE	BIT(10)
14162306a36Sopenharmony_ci#define SDXC_FIFO_RUN_ERROR		BIT(11)
14262306a36Sopenharmony_ci#define SDXC_HARD_WARE_LOCKED		BIT(12)
14362306a36Sopenharmony_ci#define SDXC_START_BIT_ERROR		BIT(13)
14462306a36Sopenharmony_ci#define SDXC_AUTO_COMMAND_DONE		BIT(14)
14562306a36Sopenharmony_ci#define SDXC_END_BIT_ERROR		BIT(15)
14662306a36Sopenharmony_ci#define SDXC_SDIO_INTERRUPT		BIT(16)
14762306a36Sopenharmony_ci#define SDXC_CARD_INSERT		BIT(30)
14862306a36Sopenharmony_ci#define SDXC_CARD_REMOVE		BIT(31)
14962306a36Sopenharmony_ci#define SDXC_INTERRUPT_ERROR_BIT \
15062306a36Sopenharmony_ci	(SDXC_RESP_ERROR | SDXC_RESP_CRC_ERROR | SDXC_DATA_CRC_ERROR | \
15162306a36Sopenharmony_ci	 SDXC_RESP_TIMEOUT | SDXC_DATA_TIMEOUT | SDXC_FIFO_RUN_ERROR | \
15262306a36Sopenharmony_ci	 SDXC_HARD_WARE_LOCKED | SDXC_START_BIT_ERROR | SDXC_END_BIT_ERROR)
15362306a36Sopenharmony_ci#define SDXC_INTERRUPT_DONE_BIT \
15462306a36Sopenharmony_ci	(SDXC_AUTO_COMMAND_DONE | SDXC_DATA_OVER | \
15562306a36Sopenharmony_ci	 SDXC_COMMAND_DONE | SDXC_VOLTAGE_CHANGE_DONE)
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/* status */
15862306a36Sopenharmony_ci#define SDXC_RXWL_FLAG			BIT(0)
15962306a36Sopenharmony_ci#define SDXC_TXWL_FLAG			BIT(1)
16062306a36Sopenharmony_ci#define SDXC_FIFO_EMPTY			BIT(2)
16162306a36Sopenharmony_ci#define SDXC_FIFO_FULL			BIT(3)
16262306a36Sopenharmony_ci#define SDXC_CARD_PRESENT		BIT(8)
16362306a36Sopenharmony_ci#define SDXC_CARD_DATA_BUSY		BIT(9)
16462306a36Sopenharmony_ci#define SDXC_DATA_FSM_BUSY		BIT(10)
16562306a36Sopenharmony_ci#define SDXC_DMA_REQUEST		BIT(31)
16662306a36Sopenharmony_ci#define SDXC_FIFO_SIZE			16
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/* Function select */
16962306a36Sopenharmony_ci#define SDXC_CEATA_ON			(0xceaa << 16)
17062306a36Sopenharmony_ci#define SDXC_SEND_IRQ_RESPONSE		BIT(0)
17162306a36Sopenharmony_ci#define SDXC_SDIO_READ_WAIT		BIT(1)
17262306a36Sopenharmony_ci#define SDXC_ABORT_READ_DATA		BIT(2)
17362306a36Sopenharmony_ci#define SDXC_SEND_CCSD			BIT(8)
17462306a36Sopenharmony_ci#define SDXC_SEND_AUTO_STOPCCSD		BIT(9)
17562306a36Sopenharmony_ci#define SDXC_CEATA_DEV_IRQ_ENABLE	BIT(10)
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/* IDMA controller bus mod bit field */
17862306a36Sopenharmony_ci#define SDXC_IDMAC_SOFT_RESET		BIT(0)
17962306a36Sopenharmony_ci#define SDXC_IDMAC_FIX_BURST		BIT(1)
18062306a36Sopenharmony_ci#define SDXC_IDMAC_IDMA_ON		BIT(7)
18162306a36Sopenharmony_ci#define SDXC_IDMAC_REFETCH_DES		BIT(31)
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/* IDMA status bit field */
18462306a36Sopenharmony_ci#define SDXC_IDMAC_TRANSMIT_INTERRUPT		BIT(0)
18562306a36Sopenharmony_ci#define SDXC_IDMAC_RECEIVE_INTERRUPT		BIT(1)
18662306a36Sopenharmony_ci#define SDXC_IDMAC_FATAL_BUS_ERROR		BIT(2)
18762306a36Sopenharmony_ci#define SDXC_IDMAC_DESTINATION_INVALID		BIT(4)
18862306a36Sopenharmony_ci#define SDXC_IDMAC_CARD_ERROR_SUM		BIT(5)
18962306a36Sopenharmony_ci#define SDXC_IDMAC_NORMAL_INTERRUPT_SUM		BIT(8)
19062306a36Sopenharmony_ci#define SDXC_IDMAC_ABNORMAL_INTERRUPT_SUM	BIT(9)
19162306a36Sopenharmony_ci#define SDXC_IDMAC_HOST_ABORT_INTERRUPT		BIT(10)
19262306a36Sopenharmony_ci#define SDXC_IDMAC_IDLE				(0 << 13)
19362306a36Sopenharmony_ci#define SDXC_IDMAC_SUSPEND			(1 << 13)
19462306a36Sopenharmony_ci#define SDXC_IDMAC_DESC_READ			(2 << 13)
19562306a36Sopenharmony_ci#define SDXC_IDMAC_DESC_CHECK			(3 << 13)
19662306a36Sopenharmony_ci#define SDXC_IDMAC_READ_REQUEST_WAIT		(4 << 13)
19762306a36Sopenharmony_ci#define SDXC_IDMAC_WRITE_REQUEST_WAIT		(5 << 13)
19862306a36Sopenharmony_ci#define SDXC_IDMAC_READ				(6 << 13)
19962306a36Sopenharmony_ci#define SDXC_IDMAC_WRITE			(7 << 13)
20062306a36Sopenharmony_ci#define SDXC_IDMAC_DESC_CLOSE			(8 << 13)
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/*
20362306a36Sopenharmony_ci* If the idma-des-size-bits of property is ie 13, bufsize bits are:
20462306a36Sopenharmony_ci*  Bits  0-12: buf1 size
20562306a36Sopenharmony_ci*  Bits 13-25: buf2 size
20662306a36Sopenharmony_ci*  Bits 26-31: not used
20762306a36Sopenharmony_ci* Since we only ever set buf1 size, we can simply store it directly.
20862306a36Sopenharmony_ci*/
20962306a36Sopenharmony_ci#define SDXC_IDMAC_DES0_DIC	BIT(1)  /* disable interrupt on completion */
21062306a36Sopenharmony_ci#define SDXC_IDMAC_DES0_LD	BIT(2)  /* last descriptor */
21162306a36Sopenharmony_ci#define SDXC_IDMAC_DES0_FD	BIT(3)  /* first descriptor */
21262306a36Sopenharmony_ci#define SDXC_IDMAC_DES0_CH	BIT(4)  /* chain mode */
21362306a36Sopenharmony_ci#define SDXC_IDMAC_DES0_ER	BIT(5)  /* end of ring */
21462306a36Sopenharmony_ci#define SDXC_IDMAC_DES0_CES	BIT(30) /* card error summary */
21562306a36Sopenharmony_ci#define SDXC_IDMAC_DES0_OWN	BIT(31) /* 1-idma owns it, 0-host owns it */
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci#define SDXC_CLK_400K		0
21862306a36Sopenharmony_ci#define SDXC_CLK_25M		1
21962306a36Sopenharmony_ci#define SDXC_CLK_50M		2
22062306a36Sopenharmony_ci#define SDXC_CLK_50M_DDR	3
22162306a36Sopenharmony_ci#define SDXC_CLK_50M_DDR_8BIT	4
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci#define SDXC_2X_TIMING_MODE	BIT(31)
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci#define SDXC_CAL_START		BIT(15)
22662306a36Sopenharmony_ci#define SDXC_CAL_DONE		BIT(14)
22762306a36Sopenharmony_ci#define SDXC_CAL_DL_SHIFT	8
22862306a36Sopenharmony_ci#define SDXC_CAL_DL_SW_EN	BIT(7)
22962306a36Sopenharmony_ci#define SDXC_CAL_DL_SW_SHIFT	0
23062306a36Sopenharmony_ci#define SDXC_CAL_DL_MASK	0x3f
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci#define SDXC_CAL_TIMEOUT	3	/* in seconds, 3s is enough*/
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistruct sunxi_mmc_clk_delay {
23562306a36Sopenharmony_ci	u32 output;
23662306a36Sopenharmony_ci	u32 sample;
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistruct sunxi_idma_des {
24062306a36Sopenharmony_ci	__le32 config;
24162306a36Sopenharmony_ci	__le32 buf_size;
24262306a36Sopenharmony_ci	__le32 buf_addr_ptr1;
24362306a36Sopenharmony_ci	__le32 buf_addr_ptr2;
24462306a36Sopenharmony_ci};
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistruct sunxi_mmc_cfg {
24762306a36Sopenharmony_ci	u32 idma_des_size_bits;
24862306a36Sopenharmony_ci	u32 idma_des_shift;
24962306a36Sopenharmony_ci	const struct sunxi_mmc_clk_delay *clk_delays;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* does the IP block support autocalibration? */
25262306a36Sopenharmony_ci	bool can_calibrate;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* Does DATA0 needs to be masked while the clock is updated */
25562306a36Sopenharmony_ci	bool mask_data0;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/*
25862306a36Sopenharmony_ci	 * hardware only supports new timing mode, either due to lack of
25962306a36Sopenharmony_ci	 * a mode switch in the clock controller, or the mmc controller
26062306a36Sopenharmony_ci	 * is permanently configured in the new timing mode, without the
26162306a36Sopenharmony_ci	 * NTSR mode switch.
26262306a36Sopenharmony_ci	 */
26362306a36Sopenharmony_ci	bool needs_new_timings;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* clock hardware can switch between old and new timing modes */
26662306a36Sopenharmony_ci	bool ccu_has_timings_switch;
26762306a36Sopenharmony_ci};
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistruct sunxi_mmc_host {
27062306a36Sopenharmony_ci	struct device *dev;
27162306a36Sopenharmony_ci	struct mmc_host	*mmc;
27262306a36Sopenharmony_ci	struct reset_control *reset;
27362306a36Sopenharmony_ci	const struct sunxi_mmc_cfg *cfg;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* IO mapping base */
27662306a36Sopenharmony_ci	void __iomem	*reg_base;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* clock management */
27962306a36Sopenharmony_ci	struct clk	*clk_ahb;
28062306a36Sopenharmony_ci	struct clk	*clk_mmc;
28162306a36Sopenharmony_ci	struct clk	*clk_sample;
28262306a36Sopenharmony_ci	struct clk	*clk_output;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* irq */
28562306a36Sopenharmony_ci	spinlock_t	lock;
28662306a36Sopenharmony_ci	int		irq;
28762306a36Sopenharmony_ci	u32		int_sum;
28862306a36Sopenharmony_ci	u32		sdio_imask;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* dma */
29162306a36Sopenharmony_ci	dma_addr_t	sg_dma;
29262306a36Sopenharmony_ci	void		*sg_cpu;
29362306a36Sopenharmony_ci	bool		wait_dma;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	struct mmc_request *mrq;
29662306a36Sopenharmony_ci	struct mmc_request *manual_stop_mrq;
29762306a36Sopenharmony_ci	int		ferror;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* vqmmc */
30062306a36Sopenharmony_ci	bool		vqmmc_enabled;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	/* timings */
30362306a36Sopenharmony_ci	bool		use_new_timings;
30462306a36Sopenharmony_ci};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	unsigned long expire = jiffies + msecs_to_jiffies(250);
30962306a36Sopenharmony_ci	u32 rval;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	mmc_writel(host, REG_GCTRL, SDXC_HARDWARE_RESET);
31262306a36Sopenharmony_ci	do {
31362306a36Sopenharmony_ci		rval = mmc_readl(host, REG_GCTRL);
31462306a36Sopenharmony_ci	} while (time_before(jiffies, expire) && (rval & SDXC_HARDWARE_RESET));
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (rval & SDXC_HARDWARE_RESET) {
31762306a36Sopenharmony_ci		dev_err(mmc_dev(host->mmc), "fatal err reset timeout\n");
31862306a36Sopenharmony_ci		return -EIO;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return 0;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int sunxi_mmc_init_host(struct sunxi_mmc_host *host)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	u32 rval;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (sunxi_mmc_reset_host(host))
32962306a36Sopenharmony_ci		return -EIO;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/*
33262306a36Sopenharmony_ci	 * Burst 8 transfers, RX trigger level: 7, TX trigger level: 8
33362306a36Sopenharmony_ci	 *
33462306a36Sopenharmony_ci	 * TODO: sun9i has a larger FIFO and supports higher trigger values
33562306a36Sopenharmony_ci	 */
33662306a36Sopenharmony_ci	mmc_writel(host, REG_FTRGL, 0x20070008);
33762306a36Sopenharmony_ci	/* Maximum timeout value */
33862306a36Sopenharmony_ci	mmc_writel(host, REG_TMOUT, 0xffffffff);
33962306a36Sopenharmony_ci	/* Unmask SDIO interrupt if needed */
34062306a36Sopenharmony_ci	mmc_writel(host, REG_IMASK, host->sdio_imask);
34162306a36Sopenharmony_ci	/* Clear all pending interrupts */
34262306a36Sopenharmony_ci	mmc_writel(host, REG_RINTR, 0xffffffff);
34362306a36Sopenharmony_ci	/* Debug register? undocumented */
34462306a36Sopenharmony_ci	mmc_writel(host, REG_DBGC, 0xdeb);
34562306a36Sopenharmony_ci	/* Enable CEATA support */
34662306a36Sopenharmony_ci	mmc_writel(host, REG_FUNS, SDXC_CEATA_ON);
34762306a36Sopenharmony_ci	/* Set DMA descriptor list base address */
34862306a36Sopenharmony_ci	mmc_writel(host, REG_DLBA, host->sg_dma >> host->cfg->idma_des_shift);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	rval = mmc_readl(host, REG_GCTRL);
35162306a36Sopenharmony_ci	rval |= SDXC_INTERRUPT_ENABLE_BIT;
35262306a36Sopenharmony_ci	/* Undocumented, but found in Allwinner code */
35362306a36Sopenharmony_ci	rval &= ~SDXC_ACCESS_DONE_DIRECT;
35462306a36Sopenharmony_ci	mmc_writel(host, REG_GCTRL, rval);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return 0;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
36062306a36Sopenharmony_ci				    struct mmc_data *data)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
36362306a36Sopenharmony_ci	dma_addr_t next_desc = host->sg_dma;
36462306a36Sopenharmony_ci	int i, max_len = (1 << host->cfg->idma_des_size_bits);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	for (i = 0; i < data->sg_len; i++) {
36762306a36Sopenharmony_ci		pdes[i].config = cpu_to_le32(SDXC_IDMAC_DES0_CH |
36862306a36Sopenharmony_ci					     SDXC_IDMAC_DES0_OWN |
36962306a36Sopenharmony_ci					     SDXC_IDMAC_DES0_DIC);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		if (data->sg[i].length == max_len)
37262306a36Sopenharmony_ci			pdes[i].buf_size = 0; /* 0 == max_len */
37362306a36Sopenharmony_ci		else
37462306a36Sopenharmony_ci			pdes[i].buf_size = cpu_to_le32(data->sg[i].length);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		next_desc += sizeof(struct sunxi_idma_des);
37762306a36Sopenharmony_ci		pdes[i].buf_addr_ptr1 =
37862306a36Sopenharmony_ci			cpu_to_le32(sg_dma_address(&data->sg[i]) >>
37962306a36Sopenharmony_ci				    host->cfg->idma_des_shift);
38062306a36Sopenharmony_ci		pdes[i].buf_addr_ptr2 =
38162306a36Sopenharmony_ci			cpu_to_le32(next_desc >>
38262306a36Sopenharmony_ci				    host->cfg->idma_des_shift);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	pdes[0].config |= cpu_to_le32(SDXC_IDMAC_DES0_FD);
38662306a36Sopenharmony_ci	pdes[i - 1].config |= cpu_to_le32(SDXC_IDMAC_DES0_LD |
38762306a36Sopenharmony_ci					  SDXC_IDMAC_DES0_ER);
38862306a36Sopenharmony_ci	pdes[i - 1].config &= cpu_to_le32(~SDXC_IDMAC_DES0_DIC);
38962306a36Sopenharmony_ci	pdes[i - 1].buf_addr_ptr2 = 0;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/*
39262306a36Sopenharmony_ci	 * Avoid the io-store starting the idmac hitting io-mem before the
39362306a36Sopenharmony_ci	 * descriptors hit the main-mem.
39462306a36Sopenharmony_ci	 */
39562306a36Sopenharmony_ci	wmb();
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int sunxi_mmc_map_dma(struct sunxi_mmc_host *host,
39962306a36Sopenharmony_ci			     struct mmc_data *data)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	u32 i, dma_len;
40262306a36Sopenharmony_ci	struct scatterlist *sg;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
40562306a36Sopenharmony_ci			     mmc_get_dma_dir(data));
40662306a36Sopenharmony_ci	if (dma_len == 0) {
40762306a36Sopenharmony_ci		dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n");
40862306a36Sopenharmony_ci		return -ENOMEM;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	for_each_sg(data->sg, sg, data->sg_len, i) {
41262306a36Sopenharmony_ci		if (sg->offset & 3 || sg->length & 3) {
41362306a36Sopenharmony_ci			dev_err(mmc_dev(host->mmc),
41462306a36Sopenharmony_ci				"unaligned scatterlist: os %x length %d\n",
41562306a36Sopenharmony_ci				sg->offset, sg->length);
41662306a36Sopenharmony_ci			return -EINVAL;
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return 0;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void sunxi_mmc_start_dma(struct sunxi_mmc_host *host,
42462306a36Sopenharmony_ci				struct mmc_data *data)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	u32 rval;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	sunxi_mmc_init_idma_des(host, data);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	rval = mmc_readl(host, REG_GCTRL);
43162306a36Sopenharmony_ci	rval |= SDXC_DMA_ENABLE_BIT;
43262306a36Sopenharmony_ci	mmc_writel(host, REG_GCTRL, rval);
43362306a36Sopenharmony_ci	rval |= SDXC_DMA_RESET;
43462306a36Sopenharmony_ci	mmc_writel(host, REG_GCTRL, rval);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	mmc_writel(host, REG_DMAC, SDXC_IDMAC_SOFT_RESET);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (!(data->flags & MMC_DATA_WRITE))
43962306a36Sopenharmony_ci		mmc_writel(host, REG_IDIE, SDXC_IDMAC_RECEIVE_INTERRUPT);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	mmc_writel(host, REG_DMAC,
44262306a36Sopenharmony_ci		   SDXC_IDMAC_FIX_BURST | SDXC_IDMAC_IDMA_ON);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void sunxi_mmc_send_manual_stop(struct sunxi_mmc_host *host,
44662306a36Sopenharmony_ci				       struct mmc_request *req)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	u32 arg, cmd_val, ri;
44962306a36Sopenharmony_ci	unsigned long expire = jiffies + msecs_to_jiffies(1000);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	cmd_val = SDXC_START | SDXC_RESP_EXPIRE |
45262306a36Sopenharmony_ci		  SDXC_STOP_ABORT_CMD | SDXC_CHECK_RESPONSE_CRC;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (req->cmd->opcode == SD_IO_RW_EXTENDED) {
45562306a36Sopenharmony_ci		cmd_val |= SD_IO_RW_DIRECT;
45662306a36Sopenharmony_ci		arg = (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
45762306a36Sopenharmony_ci		      ((req->cmd->arg >> 28) & 0x7);
45862306a36Sopenharmony_ci	} else {
45962306a36Sopenharmony_ci		cmd_val |= MMC_STOP_TRANSMISSION;
46062306a36Sopenharmony_ci		arg = 0;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	mmc_writel(host, REG_CARG, arg);
46462306a36Sopenharmony_ci	mmc_writel(host, REG_CMDR, cmd_val);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	do {
46762306a36Sopenharmony_ci		ri = mmc_readl(host, REG_RINTR);
46862306a36Sopenharmony_ci	} while (!(ri & (SDXC_COMMAND_DONE | SDXC_INTERRUPT_ERROR_BIT)) &&
46962306a36Sopenharmony_ci		 time_before(jiffies, expire));
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (!(ri & SDXC_COMMAND_DONE) || (ri & SDXC_INTERRUPT_ERROR_BIT)) {
47262306a36Sopenharmony_ci		dev_err(mmc_dev(host->mmc), "send stop command failed\n");
47362306a36Sopenharmony_ci		if (req->stop)
47462306a36Sopenharmony_ci			req->stop->resp[0] = -ETIMEDOUT;
47562306a36Sopenharmony_ci	} else {
47662306a36Sopenharmony_ci		if (req->stop)
47762306a36Sopenharmony_ci			req->stop->resp[0] = mmc_readl(host, REG_RESP0);
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	mmc_writel(host, REG_RINTR, 0xffff);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *host)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct mmc_command *cmd = host->mrq->cmd;
48662306a36Sopenharmony_ci	struct mmc_data *data = host->mrq->data;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* For some cmds timeout is normal with sd/mmc cards */
48962306a36Sopenharmony_ci	if ((host->int_sum & SDXC_INTERRUPT_ERROR_BIT) ==
49062306a36Sopenharmony_ci		SDXC_RESP_TIMEOUT && (cmd->opcode == SD_IO_SEND_OP_COND ||
49162306a36Sopenharmony_ci				      cmd->opcode == SD_IO_RW_DIRECT))
49262306a36Sopenharmony_ci		return;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	dev_dbg(mmc_dev(host->mmc),
49562306a36Sopenharmony_ci		"smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
49662306a36Sopenharmony_ci		host->mmc->index, cmd->opcode,
49762306a36Sopenharmony_ci		data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
49862306a36Sopenharmony_ci		host->int_sum & SDXC_RESP_ERROR     ? " RE"     : "",
49962306a36Sopenharmony_ci		host->int_sum & SDXC_RESP_CRC_ERROR  ? " RCE"    : "",
50062306a36Sopenharmony_ci		host->int_sum & SDXC_DATA_CRC_ERROR  ? " DCE"    : "",
50162306a36Sopenharmony_ci		host->int_sum & SDXC_RESP_TIMEOUT ? " RTO"    : "",
50262306a36Sopenharmony_ci		host->int_sum & SDXC_DATA_TIMEOUT ? " DTO"    : "",
50362306a36Sopenharmony_ci		host->int_sum & SDXC_FIFO_RUN_ERROR  ? " FE"     : "",
50462306a36Sopenharmony_ci		host->int_sum & SDXC_HARD_WARE_LOCKED ? " HL"     : "",
50562306a36Sopenharmony_ci		host->int_sum & SDXC_START_BIT_ERROR ? " SBE"    : "",
50662306a36Sopenharmony_ci		host->int_sum & SDXC_END_BIT_ERROR   ? " EBE"    : ""
50762306a36Sopenharmony_ci		);
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci/* Called in interrupt context! */
51162306a36Sopenharmony_cistatic irqreturn_t sunxi_mmc_finalize_request(struct sunxi_mmc_host *host)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct mmc_request *mrq = host->mrq;
51462306a36Sopenharmony_ci	struct mmc_data *data = mrq->data;
51562306a36Sopenharmony_ci	u32 rval;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	mmc_writel(host, REG_IMASK, host->sdio_imask);
51862306a36Sopenharmony_ci	mmc_writel(host, REG_IDIE, 0);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (host->int_sum & SDXC_INTERRUPT_ERROR_BIT) {
52162306a36Sopenharmony_ci		sunxi_mmc_dump_errinfo(host);
52262306a36Sopenharmony_ci		mrq->cmd->error = -ETIMEDOUT;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		if (data) {
52562306a36Sopenharmony_ci			data->error = -ETIMEDOUT;
52662306a36Sopenharmony_ci			host->manual_stop_mrq = mrq;
52762306a36Sopenharmony_ci		}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		if (mrq->stop)
53062306a36Sopenharmony_ci			mrq->stop->error = -ETIMEDOUT;
53162306a36Sopenharmony_ci	} else {
53262306a36Sopenharmony_ci		if (mrq->cmd->flags & MMC_RSP_136) {
53362306a36Sopenharmony_ci			mrq->cmd->resp[0] = mmc_readl(host, REG_RESP3);
53462306a36Sopenharmony_ci			mrq->cmd->resp[1] = mmc_readl(host, REG_RESP2);
53562306a36Sopenharmony_ci			mrq->cmd->resp[2] = mmc_readl(host, REG_RESP1);
53662306a36Sopenharmony_ci			mrq->cmd->resp[3] = mmc_readl(host, REG_RESP0);
53762306a36Sopenharmony_ci		} else {
53862306a36Sopenharmony_ci			mrq->cmd->resp[0] = mmc_readl(host, REG_RESP0);
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci		if (data)
54262306a36Sopenharmony_ci			data->bytes_xfered = data->blocks * data->blksz;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (data) {
54662306a36Sopenharmony_ci		mmc_writel(host, REG_IDST, 0x337);
54762306a36Sopenharmony_ci		mmc_writel(host, REG_DMAC, 0);
54862306a36Sopenharmony_ci		rval = mmc_readl(host, REG_GCTRL);
54962306a36Sopenharmony_ci		rval |= SDXC_DMA_RESET;
55062306a36Sopenharmony_ci		mmc_writel(host, REG_GCTRL, rval);
55162306a36Sopenharmony_ci		rval &= ~SDXC_DMA_ENABLE_BIT;
55262306a36Sopenharmony_ci		mmc_writel(host, REG_GCTRL, rval);
55362306a36Sopenharmony_ci		rval |= SDXC_FIFO_RESET;
55462306a36Sopenharmony_ci		mmc_writel(host, REG_GCTRL, rval);
55562306a36Sopenharmony_ci		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
55662306a36Sopenharmony_ci			     mmc_get_dma_dir(data));
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	mmc_writel(host, REG_RINTR, 0xffff);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	host->mrq = NULL;
56262306a36Sopenharmony_ci	host->int_sum = 0;
56362306a36Sopenharmony_ci	host->wait_dma = false;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	return host->manual_stop_mrq ? IRQ_WAKE_THREAD : IRQ_HANDLED;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic irqreturn_t sunxi_mmc_irq(int irq, void *dev_id)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct sunxi_mmc_host *host = dev_id;
57162306a36Sopenharmony_ci	struct mmc_request *mrq;
57262306a36Sopenharmony_ci	u32 msk_int, idma_int;
57362306a36Sopenharmony_ci	bool finalize = false;
57462306a36Sopenharmony_ci	bool sdio_int = false;
57562306a36Sopenharmony_ci	irqreturn_t ret = IRQ_HANDLED;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	spin_lock(&host->lock);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	idma_int  = mmc_readl(host, REG_IDST);
58062306a36Sopenharmony_ci	msk_int   = mmc_readl(host, REG_MISTA);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	dev_dbg(mmc_dev(host->mmc), "irq: rq %p mi %08x idi %08x\n",
58362306a36Sopenharmony_ci		host->mrq, msk_int, idma_int);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	mrq = host->mrq;
58662306a36Sopenharmony_ci	if (mrq) {
58762306a36Sopenharmony_ci		if (idma_int & SDXC_IDMAC_RECEIVE_INTERRUPT)
58862306a36Sopenharmony_ci			host->wait_dma = false;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		host->int_sum |= msk_int;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		/* Wait for COMMAND_DONE on RESPONSE_TIMEOUT before finalize */
59362306a36Sopenharmony_ci		if ((host->int_sum & SDXC_RESP_TIMEOUT) &&
59462306a36Sopenharmony_ci				!(host->int_sum & SDXC_COMMAND_DONE))
59562306a36Sopenharmony_ci			mmc_writel(host, REG_IMASK,
59662306a36Sopenharmony_ci				   host->sdio_imask | SDXC_COMMAND_DONE);
59762306a36Sopenharmony_ci		/* Don't wait for dma on error */
59862306a36Sopenharmony_ci		else if (host->int_sum & SDXC_INTERRUPT_ERROR_BIT)
59962306a36Sopenharmony_ci			finalize = true;
60062306a36Sopenharmony_ci		else if ((host->int_sum & SDXC_INTERRUPT_DONE_BIT) &&
60162306a36Sopenharmony_ci				!host->wait_dma)
60262306a36Sopenharmony_ci			finalize = true;
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (msk_int & SDXC_SDIO_INTERRUPT)
60662306a36Sopenharmony_ci		sdio_int = true;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	mmc_writel(host, REG_RINTR, msk_int);
60962306a36Sopenharmony_ci	mmc_writel(host, REG_IDST, idma_int);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (finalize)
61262306a36Sopenharmony_ci		ret = sunxi_mmc_finalize_request(host);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	spin_unlock(&host->lock);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (finalize && ret == IRQ_HANDLED)
61762306a36Sopenharmony_ci		mmc_request_done(host->mmc, mrq);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (sdio_int)
62062306a36Sopenharmony_ci		mmc_signal_sdio_irq(host->mmc);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return ret;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	struct sunxi_mmc_host *host = dev_id;
62862306a36Sopenharmony_ci	struct mmc_request *mrq;
62962306a36Sopenharmony_ci	unsigned long iflags;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	spin_lock_irqsave(&host->lock, iflags);
63262306a36Sopenharmony_ci	mrq = host->manual_stop_mrq;
63362306a36Sopenharmony_ci	spin_unlock_irqrestore(&host->lock, iflags);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (!mrq) {
63662306a36Sopenharmony_ci		dev_err(mmc_dev(host->mmc), "no request for manual stop\n");
63762306a36Sopenharmony_ci		return IRQ_HANDLED;
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	dev_err(mmc_dev(host->mmc), "data error, sending stop command\n");
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	/*
64362306a36Sopenharmony_ci	 * We will never have more than one outstanding request,
64462306a36Sopenharmony_ci	 * and we do not complete the request until after
64562306a36Sopenharmony_ci	 * we've cleared host->manual_stop_mrq so we do not need to
64662306a36Sopenharmony_ci	 * spin lock this function.
64762306a36Sopenharmony_ci	 * Additionally we have wait states within this function
64862306a36Sopenharmony_ci	 * so having it in a lock is a very bad idea.
64962306a36Sopenharmony_ci	 */
65062306a36Sopenharmony_ci	sunxi_mmc_send_manual_stop(host, mrq);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	spin_lock_irqsave(&host->lock, iflags);
65362306a36Sopenharmony_ci	host->manual_stop_mrq = NULL;
65462306a36Sopenharmony_ci	spin_unlock_irqrestore(&host->lock, iflags);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	mmc_request_done(host->mmc, mrq);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return IRQ_HANDLED;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	unsigned long expire = jiffies + msecs_to_jiffies(750);
66462306a36Sopenharmony_ci	u32 rval;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	dev_dbg(mmc_dev(host->mmc), "%sabling the clock\n",
66762306a36Sopenharmony_ci		oclk_en ? "en" : "dis");
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	rval = mmc_readl(host, REG_CLKCR);
67062306a36Sopenharmony_ci	rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	if (oclk_en)
67362306a36Sopenharmony_ci		rval |= SDXC_CARD_CLOCK_ON;
67462306a36Sopenharmony_ci	if (host->cfg->mask_data0)
67562306a36Sopenharmony_ci		rval |= SDXC_MASK_DATA0;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	mmc_writel(host, REG_CLKCR, rval);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	rval = SDXC_START | SDXC_UPCLK_ONLY | SDXC_WAIT_PRE_OVER;
68062306a36Sopenharmony_ci	mmc_writel(host, REG_CMDR, rval);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	do {
68362306a36Sopenharmony_ci		rval = mmc_readl(host, REG_CMDR);
68462306a36Sopenharmony_ci	} while (time_before(jiffies, expire) && (rval & SDXC_START));
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	/* clear irq status bits set by the command */
68762306a36Sopenharmony_ci	mmc_writel(host, REG_RINTR,
68862306a36Sopenharmony_ci		   mmc_readl(host, REG_RINTR) & ~SDXC_SDIO_INTERRUPT);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (rval & SDXC_START) {
69162306a36Sopenharmony_ci		dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n");
69262306a36Sopenharmony_ci		return -EIO;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (host->cfg->mask_data0) {
69662306a36Sopenharmony_ci		rval = mmc_readl(host, REG_CLKCR);
69762306a36Sopenharmony_ci		mmc_writel(host, REG_CLKCR, rval & ~SDXC_MASK_DATA0);
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	return 0;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	if (!host->cfg->can_calibrate)
70662306a36Sopenharmony_ci		return 0;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/*
70962306a36Sopenharmony_ci	 * FIXME:
71062306a36Sopenharmony_ci	 * This is not clear how the calibration is supposed to work
71162306a36Sopenharmony_ci	 * yet. The best rate have been obtained by simply setting the
71262306a36Sopenharmony_ci	 * delay to 0, as Allwinner does in its BSP.
71362306a36Sopenharmony_ci	 *
71462306a36Sopenharmony_ci	 * The only mode that doesn't have such a delay is HS400, that
71562306a36Sopenharmony_ci	 * is in itself a TODO.
71662306a36Sopenharmony_ci	 */
71762306a36Sopenharmony_ci	writel(SDXC_CAL_DL_SW_EN, host->reg_base + reg_off);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	return 0;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic int sunxi_mmc_clk_set_phase(struct sunxi_mmc_host *host,
72362306a36Sopenharmony_ci				   struct mmc_ios *ios, u32 rate)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	int index;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* clk controller delays not used under new timings mode */
72862306a36Sopenharmony_ci	if (host->use_new_timings)
72962306a36Sopenharmony_ci		return 0;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* some old controllers don't support delays */
73262306a36Sopenharmony_ci	if (!host->cfg->clk_delays)
73362306a36Sopenharmony_ci		return 0;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/* determine delays */
73662306a36Sopenharmony_ci	if (rate <= 400000) {
73762306a36Sopenharmony_ci		index = SDXC_CLK_400K;
73862306a36Sopenharmony_ci	} else if (rate <= 25000000) {
73962306a36Sopenharmony_ci		index = SDXC_CLK_25M;
74062306a36Sopenharmony_ci	} else if (rate <= 52000000) {
74162306a36Sopenharmony_ci		if (ios->timing != MMC_TIMING_UHS_DDR50 &&
74262306a36Sopenharmony_ci		    ios->timing != MMC_TIMING_MMC_DDR52) {
74362306a36Sopenharmony_ci			index = SDXC_CLK_50M;
74462306a36Sopenharmony_ci		} else if (ios->bus_width == MMC_BUS_WIDTH_8) {
74562306a36Sopenharmony_ci			index = SDXC_CLK_50M_DDR_8BIT;
74662306a36Sopenharmony_ci		} else {
74762306a36Sopenharmony_ci			index = SDXC_CLK_50M_DDR;
74862306a36Sopenharmony_ci		}
74962306a36Sopenharmony_ci	} else {
75062306a36Sopenharmony_ci		dev_dbg(mmc_dev(host->mmc), "Invalid clock... returning\n");
75162306a36Sopenharmony_ci		return -EINVAL;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	clk_set_phase(host->clk_sample, host->cfg->clk_delays[index].sample);
75562306a36Sopenharmony_ci	clk_set_phase(host->clk_output, host->cfg->clk_delays[index].output);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	return 0;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
76162306a36Sopenharmony_ci				  struct mmc_ios *ios)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
76462306a36Sopenharmony_ci	long rate;
76562306a36Sopenharmony_ci	u32 rval, clock = ios->clock, div = 1;
76662306a36Sopenharmony_ci	int ret;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	ret = sunxi_mmc_oclk_onoff(host, 0);
76962306a36Sopenharmony_ci	if (ret)
77062306a36Sopenharmony_ci		return ret;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/* Our clock is gated now */
77362306a36Sopenharmony_ci	mmc->actual_clock = 0;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (!ios->clock)
77662306a36Sopenharmony_ci		return 0;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	/*
77962306a36Sopenharmony_ci	 * Under the old timing mode, 8 bit DDR requires the module
78062306a36Sopenharmony_ci	 * clock to be double the card clock. Under the new timing
78162306a36Sopenharmony_ci	 * mode, all DDR modes require a doubled module clock.
78262306a36Sopenharmony_ci	 *
78362306a36Sopenharmony_ci	 * We currently only support the standard MMC DDR52 mode.
78462306a36Sopenharmony_ci	 * This block should be updated once support for other DDR
78562306a36Sopenharmony_ci	 * modes is added.
78662306a36Sopenharmony_ci	 */
78762306a36Sopenharmony_ci	if (ios->timing == MMC_TIMING_MMC_DDR52 &&
78862306a36Sopenharmony_ci	    (host->use_new_timings ||
78962306a36Sopenharmony_ci	     ios->bus_width == MMC_BUS_WIDTH_8)) {
79062306a36Sopenharmony_ci		div = 2;
79162306a36Sopenharmony_ci		clock <<= 1;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if (host->use_new_timings && host->cfg->ccu_has_timings_switch) {
79562306a36Sopenharmony_ci		ret = sunxi_ccu_set_mmc_timing_mode(host->clk_mmc, true);
79662306a36Sopenharmony_ci		if (ret) {
79762306a36Sopenharmony_ci			dev_err(mmc_dev(mmc),
79862306a36Sopenharmony_ci				"error setting new timing mode\n");
79962306a36Sopenharmony_ci			return ret;
80062306a36Sopenharmony_ci		}
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	rate = clk_round_rate(host->clk_mmc, clock);
80462306a36Sopenharmony_ci	if (rate < 0) {
80562306a36Sopenharmony_ci		dev_err(mmc_dev(mmc), "error rounding clk to %d: %ld\n",
80662306a36Sopenharmony_ci			clock, rate);
80762306a36Sopenharmony_ci		return rate;
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci	dev_dbg(mmc_dev(mmc), "setting clk to %d, rounded %ld\n",
81062306a36Sopenharmony_ci		clock, rate);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* setting clock rate */
81362306a36Sopenharmony_ci	ret = clk_set_rate(host->clk_mmc, rate);
81462306a36Sopenharmony_ci	if (ret) {
81562306a36Sopenharmony_ci		dev_err(mmc_dev(mmc), "error setting clk to %ld: %d\n",
81662306a36Sopenharmony_ci			rate, ret);
81762306a36Sopenharmony_ci		return ret;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* set internal divider */
82162306a36Sopenharmony_ci	rval = mmc_readl(host, REG_CLKCR);
82262306a36Sopenharmony_ci	rval &= ~0xff;
82362306a36Sopenharmony_ci	rval |= div - 1;
82462306a36Sopenharmony_ci	mmc_writel(host, REG_CLKCR, rval);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	/* update card clock rate to account for internal divider */
82762306a36Sopenharmony_ci	rate /= div;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/*
83062306a36Sopenharmony_ci	 * Configure the controller to use the new timing mode if needed.
83162306a36Sopenharmony_ci	 * On controllers that only support the new timing mode, such as
83262306a36Sopenharmony_ci	 * the eMMC controller on the A64, this register does not exist,
83362306a36Sopenharmony_ci	 * and any writes to it are ignored.
83462306a36Sopenharmony_ci	 */
83562306a36Sopenharmony_ci	if (host->use_new_timings) {
83662306a36Sopenharmony_ci		/* Don't touch the delay bits */
83762306a36Sopenharmony_ci		rval = mmc_readl(host, REG_SD_NTSR);
83862306a36Sopenharmony_ci		rval |= SDXC_2X_TIMING_MODE;
83962306a36Sopenharmony_ci		mmc_writel(host, REG_SD_NTSR, rval);
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/* sunxi_mmc_clk_set_phase expects the actual card clock rate */
84362306a36Sopenharmony_ci	ret = sunxi_mmc_clk_set_phase(host, ios, rate);
84462306a36Sopenharmony_ci	if (ret)
84562306a36Sopenharmony_ci		return ret;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	ret = sunxi_mmc_calibrate(host, SDXC_REG_SAMP_DL_REG);
84862306a36Sopenharmony_ci	if (ret)
84962306a36Sopenharmony_ci		return ret;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/*
85262306a36Sopenharmony_ci	 * FIXME:
85362306a36Sopenharmony_ci	 *
85462306a36Sopenharmony_ci	 * In HS400 we'll also need to calibrate the data strobe
85562306a36Sopenharmony_ci	 * signal. This should only happen on the MMC2 controller (at
85662306a36Sopenharmony_ci	 * least on the A64).
85762306a36Sopenharmony_ci	 */
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	ret = sunxi_mmc_oclk_onoff(host, 1);
86062306a36Sopenharmony_ci	if (ret)
86162306a36Sopenharmony_ci		return ret;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* And we just enabled our clock back */
86462306a36Sopenharmony_ci	mmc->actual_clock = rate;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	return 0;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic void sunxi_mmc_set_bus_width(struct sunxi_mmc_host *host,
87062306a36Sopenharmony_ci				   unsigned char width)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	switch (width) {
87362306a36Sopenharmony_ci	case MMC_BUS_WIDTH_1:
87462306a36Sopenharmony_ci		mmc_writel(host, REG_WIDTH, SDXC_WIDTH1);
87562306a36Sopenharmony_ci		break;
87662306a36Sopenharmony_ci	case MMC_BUS_WIDTH_4:
87762306a36Sopenharmony_ci		mmc_writel(host, REG_WIDTH, SDXC_WIDTH4);
87862306a36Sopenharmony_ci		break;
87962306a36Sopenharmony_ci	case MMC_BUS_WIDTH_8:
88062306a36Sopenharmony_ci		mmc_writel(host, REG_WIDTH, SDXC_WIDTH8);
88162306a36Sopenharmony_ci		break;
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic void sunxi_mmc_set_clk(struct sunxi_mmc_host *host, struct mmc_ios *ios)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	u32 rval;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/* set ddr mode */
89062306a36Sopenharmony_ci	rval = mmc_readl(host, REG_GCTRL);
89162306a36Sopenharmony_ci	if (ios->timing == MMC_TIMING_UHS_DDR50 ||
89262306a36Sopenharmony_ci	    ios->timing == MMC_TIMING_MMC_DDR52)
89362306a36Sopenharmony_ci		rval |= SDXC_DDR_MODE;
89462306a36Sopenharmony_ci	else
89562306a36Sopenharmony_ci		rval &= ~SDXC_DDR_MODE;
89662306a36Sopenharmony_ci	mmc_writel(host, REG_GCTRL, rval);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	host->ferror = sunxi_mmc_clk_set_rate(host, ios);
89962306a36Sopenharmony_ci	/* Android code had a usleep_range(50000, 55000); here */
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_cistatic void sunxi_mmc_card_power(struct sunxi_mmc_host *host,
90362306a36Sopenharmony_ci				 struct mmc_ios *ios)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	struct mmc_host *mmc = host->mmc;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	switch (ios->power_mode) {
90862306a36Sopenharmony_ci	case MMC_POWER_UP:
90962306a36Sopenharmony_ci		dev_dbg(mmc_dev(mmc), "Powering card up\n");
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci		if (!IS_ERR(mmc->supply.vmmc)) {
91262306a36Sopenharmony_ci			host->ferror = mmc_regulator_set_ocr(mmc,
91362306a36Sopenharmony_ci							     mmc->supply.vmmc,
91462306a36Sopenharmony_ci							     ios->vdd);
91562306a36Sopenharmony_ci			if (host->ferror)
91662306a36Sopenharmony_ci				return;
91762306a36Sopenharmony_ci		}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		if (!IS_ERR(mmc->supply.vqmmc)) {
92062306a36Sopenharmony_ci			host->ferror = regulator_enable(mmc->supply.vqmmc);
92162306a36Sopenharmony_ci			if (host->ferror) {
92262306a36Sopenharmony_ci				dev_err(mmc_dev(mmc),
92362306a36Sopenharmony_ci					"failed to enable vqmmc\n");
92462306a36Sopenharmony_ci				return;
92562306a36Sopenharmony_ci			}
92662306a36Sopenharmony_ci			host->vqmmc_enabled = true;
92762306a36Sopenharmony_ci		}
92862306a36Sopenharmony_ci		break;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	case MMC_POWER_OFF:
93162306a36Sopenharmony_ci		dev_dbg(mmc_dev(mmc), "Powering card off\n");
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		if (!IS_ERR(mmc->supply.vmmc))
93462306a36Sopenharmony_ci			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled)
93762306a36Sopenharmony_ci			regulator_disable(mmc->supply.vqmmc);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		host->vqmmc_enabled = false;
94062306a36Sopenharmony_ci		break;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	default:
94362306a36Sopenharmony_ci		dev_dbg(mmc_dev(mmc), "Ignoring unknown card power state\n");
94462306a36Sopenharmony_ci		break;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cistatic void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct sunxi_mmc_host *host = mmc_priv(mmc);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	sunxi_mmc_card_power(host, ios);
95362306a36Sopenharmony_ci	sunxi_mmc_set_bus_width(host, ios->bus_width);
95462306a36Sopenharmony_ci	sunxi_mmc_set_clk(host, ios);
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic int sunxi_mmc_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	int ret;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	/* vqmmc regulator is available */
96262306a36Sopenharmony_ci	if (!IS_ERR(mmc->supply.vqmmc)) {
96362306a36Sopenharmony_ci		ret = mmc_regulator_set_vqmmc(mmc, ios);
96462306a36Sopenharmony_ci		return ret < 0 ? ret : 0;
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	/* no vqmmc regulator, assume fixed regulator at 3/3.3V */
96862306a36Sopenharmony_ci	if (mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330)
96962306a36Sopenharmony_ci		return 0;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	return -EINVAL;
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_cistatic void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	struct sunxi_mmc_host *host = mmc_priv(mmc);
97762306a36Sopenharmony_ci	unsigned long flags;
97862306a36Sopenharmony_ci	u32 imask;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if (enable)
98162306a36Sopenharmony_ci		pm_runtime_get_noresume(host->dev);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	spin_lock_irqsave(&host->lock, flags);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	imask = mmc_readl(host, REG_IMASK);
98662306a36Sopenharmony_ci	if (enable) {
98762306a36Sopenharmony_ci		host->sdio_imask = SDXC_SDIO_INTERRUPT;
98862306a36Sopenharmony_ci		imask |= SDXC_SDIO_INTERRUPT;
98962306a36Sopenharmony_ci	} else {
99062306a36Sopenharmony_ci		host->sdio_imask = 0;
99162306a36Sopenharmony_ci		imask &= ~SDXC_SDIO_INTERRUPT;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci	mmc_writel(host, REG_IMASK, imask);
99462306a36Sopenharmony_ci	spin_unlock_irqrestore(&host->lock, flags);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (!enable)
99762306a36Sopenharmony_ci		pm_runtime_put_noidle(host->mmc->parent);
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_cistatic void sunxi_mmc_hw_reset(struct mmc_host *mmc)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	struct sunxi_mmc_host *host = mmc_priv(mmc);
100362306a36Sopenharmony_ci	mmc_writel(host, REG_HWRST, 0);
100462306a36Sopenharmony_ci	udelay(10);
100562306a36Sopenharmony_ci	mmc_writel(host, REG_HWRST, 1);
100662306a36Sopenharmony_ci	udelay(300);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct sunxi_mmc_host *host = mmc_priv(mmc);
101262306a36Sopenharmony_ci	struct mmc_command *cmd = mrq->cmd;
101362306a36Sopenharmony_ci	struct mmc_data *data = mrq->data;
101462306a36Sopenharmony_ci	unsigned long iflags;
101562306a36Sopenharmony_ci	u32 imask = SDXC_INTERRUPT_ERROR_BIT;
101662306a36Sopenharmony_ci	u32 cmd_val = SDXC_START | (cmd->opcode & 0x3f);
101762306a36Sopenharmony_ci	bool wait_dma = host->wait_dma;
101862306a36Sopenharmony_ci	int ret;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	/* Check for set_ios errors (should never happen) */
102162306a36Sopenharmony_ci	if (host->ferror) {
102262306a36Sopenharmony_ci		mrq->cmd->error = host->ferror;
102362306a36Sopenharmony_ci		mmc_request_done(mmc, mrq);
102462306a36Sopenharmony_ci		return;
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (data) {
102862306a36Sopenharmony_ci		ret = sunxi_mmc_map_dma(host, data);
102962306a36Sopenharmony_ci		if (ret < 0) {
103062306a36Sopenharmony_ci			dev_err(mmc_dev(mmc), "map DMA failed\n");
103162306a36Sopenharmony_ci			cmd->error = ret;
103262306a36Sopenharmony_ci			data->error = ret;
103362306a36Sopenharmony_ci			mmc_request_done(mmc, mrq);
103462306a36Sopenharmony_ci			return;
103562306a36Sopenharmony_ci		}
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (cmd->opcode == MMC_GO_IDLE_STATE) {
103962306a36Sopenharmony_ci		cmd_val |= SDXC_SEND_INIT_SEQUENCE;
104062306a36Sopenharmony_ci		imask |= SDXC_COMMAND_DONE;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (cmd->flags & MMC_RSP_PRESENT) {
104462306a36Sopenharmony_ci		cmd_val |= SDXC_RESP_EXPIRE;
104562306a36Sopenharmony_ci		if (cmd->flags & MMC_RSP_136)
104662306a36Sopenharmony_ci			cmd_val |= SDXC_LONG_RESPONSE;
104762306a36Sopenharmony_ci		if (cmd->flags & MMC_RSP_CRC)
104862306a36Sopenharmony_ci			cmd_val |= SDXC_CHECK_RESPONSE_CRC;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci		if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) {
105162306a36Sopenharmony_ci			cmd_val |= SDXC_DATA_EXPIRE | SDXC_WAIT_PRE_OVER;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci			if (cmd->data->stop) {
105462306a36Sopenharmony_ci				imask |= SDXC_AUTO_COMMAND_DONE;
105562306a36Sopenharmony_ci				cmd_val |= SDXC_SEND_AUTO_STOP;
105662306a36Sopenharmony_ci			} else {
105762306a36Sopenharmony_ci				imask |= SDXC_DATA_OVER;
105862306a36Sopenharmony_ci			}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci			if (cmd->data->flags & MMC_DATA_WRITE)
106162306a36Sopenharmony_ci				cmd_val |= SDXC_WRITE;
106262306a36Sopenharmony_ci			else
106362306a36Sopenharmony_ci				wait_dma = true;
106462306a36Sopenharmony_ci		} else {
106562306a36Sopenharmony_ci			imask |= SDXC_COMMAND_DONE;
106662306a36Sopenharmony_ci		}
106762306a36Sopenharmony_ci	} else {
106862306a36Sopenharmony_ci		imask |= SDXC_COMMAND_DONE;
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	dev_dbg(mmc_dev(mmc), "cmd %d(%08x) arg %x ie 0x%08x len %d\n",
107262306a36Sopenharmony_ci		cmd_val & 0x3f, cmd_val, cmd->arg, imask,
107362306a36Sopenharmony_ci		mrq->data ? mrq->data->blksz * mrq->data->blocks : 0);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	spin_lock_irqsave(&host->lock, iflags);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	if (host->mrq || host->manual_stop_mrq) {
107862306a36Sopenharmony_ci		spin_unlock_irqrestore(&host->lock, iflags);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci		if (data)
108162306a36Sopenharmony_ci			dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len,
108262306a36Sopenharmony_ci				     mmc_get_dma_dir(data));
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci		dev_err(mmc_dev(mmc), "request already pending\n");
108562306a36Sopenharmony_ci		mrq->cmd->error = -EBUSY;
108662306a36Sopenharmony_ci		mmc_request_done(mmc, mrq);
108762306a36Sopenharmony_ci		return;
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (data) {
109162306a36Sopenharmony_ci		mmc_writel(host, REG_BLKSZ, data->blksz);
109262306a36Sopenharmony_ci		mmc_writel(host, REG_BCNTR, data->blksz * data->blocks);
109362306a36Sopenharmony_ci		sunxi_mmc_start_dma(host, data);
109462306a36Sopenharmony_ci	}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	host->mrq = mrq;
109762306a36Sopenharmony_ci	host->wait_dma = wait_dma;
109862306a36Sopenharmony_ci	mmc_writel(host, REG_IMASK, host->sdio_imask | imask);
109962306a36Sopenharmony_ci	mmc_writel(host, REG_CARG, cmd->arg);
110062306a36Sopenharmony_ci	mmc_writel(host, REG_CMDR, cmd_val);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	spin_unlock_irqrestore(&host->lock, iflags);
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic int sunxi_mmc_card_busy(struct mmc_host *mmc)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci	struct sunxi_mmc_host *host = mmc_priv(mmc);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	return !!(mmc_readl(host, REG_STAS) & SDXC_CARD_DATA_BUSY);
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic const struct mmc_host_ops sunxi_mmc_ops = {
111362306a36Sopenharmony_ci	.request	 = sunxi_mmc_request,
111462306a36Sopenharmony_ci	.set_ios	 = sunxi_mmc_set_ios,
111562306a36Sopenharmony_ci	.get_ro		 = mmc_gpio_get_ro,
111662306a36Sopenharmony_ci	.get_cd		 = mmc_gpio_get_cd,
111762306a36Sopenharmony_ci	.enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
111862306a36Sopenharmony_ci	.start_signal_voltage_switch = sunxi_mmc_volt_switch,
111962306a36Sopenharmony_ci	.card_hw_reset	 = sunxi_mmc_hw_reset,
112062306a36Sopenharmony_ci	.card_busy	 = sunxi_mmc_card_busy,
112162306a36Sopenharmony_ci};
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_cistatic const struct sunxi_mmc_clk_delay sunxi_mmc_clk_delays[] = {
112462306a36Sopenharmony_ci	[SDXC_CLK_400K]		= { .output = 180, .sample = 180 },
112562306a36Sopenharmony_ci	[SDXC_CLK_25M]		= { .output = 180, .sample =  75 },
112662306a36Sopenharmony_ci	[SDXC_CLK_50M]		= { .output =  90, .sample = 120 },
112762306a36Sopenharmony_ci	[SDXC_CLK_50M_DDR]	= { .output =  60, .sample = 120 },
112862306a36Sopenharmony_ci	/* Value from A83T "new timing mode". Works but might not be right. */
112962306a36Sopenharmony_ci	[SDXC_CLK_50M_DDR_8BIT]	= { .output =  90, .sample = 180 },
113062306a36Sopenharmony_ci};
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = {
113362306a36Sopenharmony_ci	[SDXC_CLK_400K]		= { .output = 180, .sample = 180 },
113462306a36Sopenharmony_ci	[SDXC_CLK_25M]		= { .output = 180, .sample =  75 },
113562306a36Sopenharmony_ci	[SDXC_CLK_50M]		= { .output = 150, .sample = 120 },
113662306a36Sopenharmony_ci	[SDXC_CLK_50M_DDR]	= { .output =  54, .sample =  36 },
113762306a36Sopenharmony_ci	[SDXC_CLK_50M_DDR_8BIT]	= { .output =  72, .sample =  72 },
113862306a36Sopenharmony_ci};
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun4i_a10_cfg = {
114162306a36Sopenharmony_ci	.idma_des_size_bits = 13,
114262306a36Sopenharmony_ci	.clk_delays = NULL,
114362306a36Sopenharmony_ci	.can_calibrate = false,
114462306a36Sopenharmony_ci};
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun5i_a13_cfg = {
114762306a36Sopenharmony_ci	.idma_des_size_bits = 16,
114862306a36Sopenharmony_ci	.clk_delays = NULL,
114962306a36Sopenharmony_ci	.can_calibrate = false,
115062306a36Sopenharmony_ci};
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun7i_a20_cfg = {
115362306a36Sopenharmony_ci	.idma_des_size_bits = 16,
115462306a36Sopenharmony_ci	.clk_delays = sunxi_mmc_clk_delays,
115562306a36Sopenharmony_ci	.can_calibrate = false,
115662306a36Sopenharmony_ci};
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun8i_a83t_emmc_cfg = {
115962306a36Sopenharmony_ci	.idma_des_size_bits = 16,
116062306a36Sopenharmony_ci	.clk_delays = sunxi_mmc_clk_delays,
116162306a36Sopenharmony_ci	.can_calibrate = false,
116262306a36Sopenharmony_ci	.ccu_has_timings_switch = true,
116362306a36Sopenharmony_ci};
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun9i_a80_cfg = {
116662306a36Sopenharmony_ci	.idma_des_size_bits = 16,
116762306a36Sopenharmony_ci	.clk_delays = sun9i_mmc_clk_delays,
116862306a36Sopenharmony_ci	.can_calibrate = false,
116962306a36Sopenharmony_ci};
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun20i_d1_cfg = {
117262306a36Sopenharmony_ci	.idma_des_size_bits = 13,
117362306a36Sopenharmony_ci	.idma_des_shift = 2,
117462306a36Sopenharmony_ci	.can_calibrate = true,
117562306a36Sopenharmony_ci	.mask_data0 = true,
117662306a36Sopenharmony_ci	.needs_new_timings = true,
117762306a36Sopenharmony_ci};
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun50i_a64_cfg = {
118062306a36Sopenharmony_ci	.idma_des_size_bits = 16,
118162306a36Sopenharmony_ci	.clk_delays = NULL,
118262306a36Sopenharmony_ci	.can_calibrate = true,
118362306a36Sopenharmony_ci	.mask_data0 = true,
118462306a36Sopenharmony_ci	.needs_new_timings = true,
118562306a36Sopenharmony_ci};
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = {
118862306a36Sopenharmony_ci	.idma_des_size_bits = 13,
118962306a36Sopenharmony_ci	.clk_delays = NULL,
119062306a36Sopenharmony_ci	.can_calibrate = true,
119162306a36Sopenharmony_ci	.needs_new_timings = true,
119262306a36Sopenharmony_ci};
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun50i_a100_cfg = {
119562306a36Sopenharmony_ci	.idma_des_size_bits = 16,
119662306a36Sopenharmony_ci	.idma_des_shift = 2,
119762306a36Sopenharmony_ci	.clk_delays = NULL,
119862306a36Sopenharmony_ci	.can_calibrate = true,
119962306a36Sopenharmony_ci	.mask_data0 = true,
120062306a36Sopenharmony_ci	.needs_new_timings = true,
120162306a36Sopenharmony_ci};
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cistatic const struct sunxi_mmc_cfg sun50i_a100_emmc_cfg = {
120462306a36Sopenharmony_ci	.idma_des_size_bits = 13,
120562306a36Sopenharmony_ci	.idma_des_shift = 2,
120662306a36Sopenharmony_ci	.clk_delays = NULL,
120762306a36Sopenharmony_ci	.can_calibrate = true,
120862306a36Sopenharmony_ci	.needs_new_timings = true,
120962306a36Sopenharmony_ci};
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cistatic const struct of_device_id sunxi_mmc_of_match[] = {
121262306a36Sopenharmony_ci	{ .compatible = "allwinner,sun4i-a10-mmc", .data = &sun4i_a10_cfg },
121362306a36Sopenharmony_ci	{ .compatible = "allwinner,sun5i-a13-mmc", .data = &sun5i_a13_cfg },
121462306a36Sopenharmony_ci	{ .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg },
121562306a36Sopenharmony_ci	{ .compatible = "allwinner,sun8i-a83t-emmc", .data = &sun8i_a83t_emmc_cfg },
121662306a36Sopenharmony_ci	{ .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg },
121762306a36Sopenharmony_ci	{ .compatible = "allwinner,sun20i-d1-mmc", .data = &sun20i_d1_cfg },
121862306a36Sopenharmony_ci	{ .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg },
121962306a36Sopenharmony_ci	{ .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg },
122062306a36Sopenharmony_ci	{ .compatible = "allwinner,sun50i-a100-mmc", .data = &sun50i_a100_cfg },
122162306a36Sopenharmony_ci	{ .compatible = "allwinner,sun50i-a100-emmc", .data = &sun50i_a100_emmc_cfg },
122262306a36Sopenharmony_ci	{ /* sentinel */ }
122362306a36Sopenharmony_ci};
122462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_cistatic int sunxi_mmc_enable(struct sunxi_mmc_host *host)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	int ret;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	if (!IS_ERR(host->reset)) {
123162306a36Sopenharmony_ci		ret = reset_control_reset(host->reset);
123262306a36Sopenharmony_ci		if (ret) {
123362306a36Sopenharmony_ci			dev_err(host->dev, "Couldn't reset the MMC controller (%d)\n",
123462306a36Sopenharmony_ci				ret);
123562306a36Sopenharmony_ci			return ret;
123662306a36Sopenharmony_ci		}
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	ret = clk_prepare_enable(host->clk_ahb);
124062306a36Sopenharmony_ci	if (ret) {
124162306a36Sopenharmony_ci		dev_err(host->dev, "Couldn't enable the bus clocks (%d)\n", ret);
124262306a36Sopenharmony_ci		goto error_assert_reset;
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	ret = clk_prepare_enable(host->clk_mmc);
124662306a36Sopenharmony_ci	if (ret) {
124762306a36Sopenharmony_ci		dev_err(host->dev, "Enable mmc clk err %d\n", ret);
124862306a36Sopenharmony_ci		goto error_disable_clk_ahb;
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	ret = clk_prepare_enable(host->clk_output);
125262306a36Sopenharmony_ci	if (ret) {
125362306a36Sopenharmony_ci		dev_err(host->dev, "Enable output clk err %d\n", ret);
125462306a36Sopenharmony_ci		goto error_disable_clk_mmc;
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	ret = clk_prepare_enable(host->clk_sample);
125862306a36Sopenharmony_ci	if (ret) {
125962306a36Sopenharmony_ci		dev_err(host->dev, "Enable sample clk err %d\n", ret);
126062306a36Sopenharmony_ci		goto error_disable_clk_output;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	/*
126462306a36Sopenharmony_ci	 * Sometimes the controller asserts the irq on boot for some reason,
126562306a36Sopenharmony_ci	 * make sure the controller is in a sane state before enabling irqs.
126662306a36Sopenharmony_ci	 */
126762306a36Sopenharmony_ci	ret = sunxi_mmc_reset_host(host);
126862306a36Sopenharmony_ci	if (ret)
126962306a36Sopenharmony_ci		goto error_disable_clk_sample;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	return 0;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_cierror_disable_clk_sample:
127462306a36Sopenharmony_ci	clk_disable_unprepare(host->clk_sample);
127562306a36Sopenharmony_cierror_disable_clk_output:
127662306a36Sopenharmony_ci	clk_disable_unprepare(host->clk_output);
127762306a36Sopenharmony_cierror_disable_clk_mmc:
127862306a36Sopenharmony_ci	clk_disable_unprepare(host->clk_mmc);
127962306a36Sopenharmony_cierror_disable_clk_ahb:
128062306a36Sopenharmony_ci	clk_disable_unprepare(host->clk_ahb);
128162306a36Sopenharmony_cierror_assert_reset:
128262306a36Sopenharmony_ci	if (!IS_ERR(host->reset))
128362306a36Sopenharmony_ci		reset_control_assert(host->reset);
128462306a36Sopenharmony_ci	return ret;
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_cistatic void sunxi_mmc_disable(struct sunxi_mmc_host *host)
128862306a36Sopenharmony_ci{
128962306a36Sopenharmony_ci	sunxi_mmc_reset_host(host);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	clk_disable_unprepare(host->clk_sample);
129262306a36Sopenharmony_ci	clk_disable_unprepare(host->clk_output);
129362306a36Sopenharmony_ci	clk_disable_unprepare(host->clk_mmc);
129462306a36Sopenharmony_ci	clk_disable_unprepare(host->clk_ahb);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	if (!IS_ERR(host->reset))
129762306a36Sopenharmony_ci		reset_control_assert(host->reset);
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
130162306a36Sopenharmony_ci				      struct platform_device *pdev)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	int ret;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	host->cfg = of_device_get_match_data(&pdev->dev);
130662306a36Sopenharmony_ci	if (!host->cfg)
130762306a36Sopenharmony_ci		return -EINVAL;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	ret = mmc_regulator_get_supply(host->mmc);
131062306a36Sopenharmony_ci	if (ret)
131162306a36Sopenharmony_ci		return ret;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	host->reg_base = devm_platform_ioremap_resource(pdev, 0);
131462306a36Sopenharmony_ci	if (IS_ERR(host->reg_base))
131562306a36Sopenharmony_ci		return PTR_ERR(host->reg_base);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	host->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
131862306a36Sopenharmony_ci	if (IS_ERR(host->clk_ahb)) {
131962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not get ahb clock\n");
132062306a36Sopenharmony_ci		return PTR_ERR(host->clk_ahb);
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	host->clk_mmc = devm_clk_get(&pdev->dev, "mmc");
132462306a36Sopenharmony_ci	if (IS_ERR(host->clk_mmc)) {
132562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not get mmc clock\n");
132662306a36Sopenharmony_ci		return PTR_ERR(host->clk_mmc);
132762306a36Sopenharmony_ci	}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	if (host->cfg->clk_delays) {
133062306a36Sopenharmony_ci		host->clk_output = devm_clk_get(&pdev->dev, "output");
133162306a36Sopenharmony_ci		if (IS_ERR(host->clk_output)) {
133262306a36Sopenharmony_ci			dev_err(&pdev->dev, "Could not get output clock\n");
133362306a36Sopenharmony_ci			return PTR_ERR(host->clk_output);
133462306a36Sopenharmony_ci		}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci		host->clk_sample = devm_clk_get(&pdev->dev, "sample");
133762306a36Sopenharmony_ci		if (IS_ERR(host->clk_sample)) {
133862306a36Sopenharmony_ci			dev_err(&pdev->dev, "Could not get sample clock\n");
133962306a36Sopenharmony_ci			return PTR_ERR(host->clk_sample);
134062306a36Sopenharmony_ci		}
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
134462306a36Sopenharmony_ci								"ahb");
134562306a36Sopenharmony_ci	if (PTR_ERR(host->reset) == -EPROBE_DEFER)
134662306a36Sopenharmony_ci		return PTR_ERR(host->reset);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	ret = sunxi_mmc_enable(host);
134962306a36Sopenharmony_ci	if (ret)
135062306a36Sopenharmony_ci		return ret;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	host->irq = platform_get_irq(pdev, 0);
135362306a36Sopenharmony_ci	if (host->irq < 0) {
135462306a36Sopenharmony_ci		ret = host->irq;
135562306a36Sopenharmony_ci		goto error_disable_mmc;
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	return devm_request_threaded_irq(&pdev->dev, host->irq, sunxi_mmc_irq,
135962306a36Sopenharmony_ci			sunxi_mmc_handle_manual_stop, 0, "sunxi-mmc", host);
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_cierror_disable_mmc:
136262306a36Sopenharmony_ci	sunxi_mmc_disable(host);
136362306a36Sopenharmony_ci	return ret;
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_cistatic int sunxi_mmc_probe(struct platform_device *pdev)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	struct sunxi_mmc_host *host;
136962306a36Sopenharmony_ci	struct mmc_host *mmc;
137062306a36Sopenharmony_ci	int ret;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);
137362306a36Sopenharmony_ci	if (!mmc) {
137462306a36Sopenharmony_ci		dev_err(&pdev->dev, "mmc alloc host failed\n");
137562306a36Sopenharmony_ci		return -ENOMEM;
137662306a36Sopenharmony_ci	}
137762306a36Sopenharmony_ci	platform_set_drvdata(pdev, mmc);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	host = mmc_priv(mmc);
138062306a36Sopenharmony_ci	host->dev = &pdev->dev;
138162306a36Sopenharmony_ci	host->mmc = mmc;
138262306a36Sopenharmony_ci	spin_lock_init(&host->lock);
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	ret = sunxi_mmc_resource_request(host, pdev);
138562306a36Sopenharmony_ci	if (ret)
138662306a36Sopenharmony_ci		goto error_free_host;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
138962306a36Sopenharmony_ci					  &host->sg_dma, GFP_KERNEL);
139062306a36Sopenharmony_ci	if (!host->sg_cpu) {
139162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n");
139262306a36Sopenharmony_ci		ret = -ENOMEM;
139362306a36Sopenharmony_ci		goto error_free_host;
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (host->cfg->ccu_has_timings_switch) {
139762306a36Sopenharmony_ci		/*
139862306a36Sopenharmony_ci		 * Supports both old and new timing modes.
139962306a36Sopenharmony_ci		 * Try setting the clk to new timing mode.
140062306a36Sopenharmony_ci		 */
140162306a36Sopenharmony_ci		sunxi_ccu_set_mmc_timing_mode(host->clk_mmc, true);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci		/* And check the result */
140462306a36Sopenharmony_ci		ret = sunxi_ccu_get_mmc_timing_mode(host->clk_mmc);
140562306a36Sopenharmony_ci		if (ret < 0) {
140662306a36Sopenharmony_ci			/*
140762306a36Sopenharmony_ci			 * For whatever reason we were not able to get
140862306a36Sopenharmony_ci			 * the current active mode. Default to old mode.
140962306a36Sopenharmony_ci			 */
141062306a36Sopenharmony_ci			dev_warn(&pdev->dev, "MMC clk timing mode unknown\n");
141162306a36Sopenharmony_ci			host->use_new_timings = false;
141262306a36Sopenharmony_ci		} else {
141362306a36Sopenharmony_ci			host->use_new_timings = !!ret;
141462306a36Sopenharmony_ci		}
141562306a36Sopenharmony_ci	} else if (host->cfg->needs_new_timings) {
141662306a36Sopenharmony_ci		/* Supports new timing mode only */
141762306a36Sopenharmony_ci		host->use_new_timings = true;
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	mmc->ops		= &sunxi_mmc_ops;
142162306a36Sopenharmony_ci	mmc->max_blk_count	= 8192;
142262306a36Sopenharmony_ci	mmc->max_blk_size	= 4096;
142362306a36Sopenharmony_ci	mmc->max_segs		= PAGE_SIZE / sizeof(struct sunxi_idma_des);
142462306a36Sopenharmony_ci	mmc->max_seg_size	= (1 << host->cfg->idma_des_size_bits);
142562306a36Sopenharmony_ci	mmc->max_req_size	= mmc->max_seg_size * mmc->max_segs;
142662306a36Sopenharmony_ci	/* 400kHz ~ 52MHz */
142762306a36Sopenharmony_ci	mmc->f_min		=   400000;
142862306a36Sopenharmony_ci	mmc->f_max		= 52000000;
142962306a36Sopenharmony_ci	mmc->caps	       |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
143062306a36Sopenharmony_ci				  MMC_CAP_SDIO_IRQ;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	/*
143362306a36Sopenharmony_ci	 * Some H5 devices do not have signal traces precise enough to
143462306a36Sopenharmony_ci	 * use HS DDR mode for their eMMC chips.
143562306a36Sopenharmony_ci	 *
143662306a36Sopenharmony_ci	 * We still enable HS DDR modes for all the other controller
143762306a36Sopenharmony_ci	 * variants that support them.
143862306a36Sopenharmony_ci	 */
143962306a36Sopenharmony_ci	if ((host->cfg->clk_delays || host->use_new_timings) &&
144062306a36Sopenharmony_ci	    !of_device_is_compatible(pdev->dev.of_node,
144162306a36Sopenharmony_ci				     "allwinner,sun50i-h5-emmc"))
144262306a36Sopenharmony_ci		mmc->caps      |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	ret = mmc_of_parse(mmc);
144562306a36Sopenharmony_ci	if (ret)
144662306a36Sopenharmony_ci		goto error_free_dma;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	/*
144962306a36Sopenharmony_ci	 * If we don't support delay chains in the SoC, we can't use any
145062306a36Sopenharmony_ci	 * of the higher speed modes. Mask them out in case the device
145162306a36Sopenharmony_ci	 * tree specifies the properties for them, which gets added to
145262306a36Sopenharmony_ci	 * the caps by mmc_of_parse() above.
145362306a36Sopenharmony_ci	 */
145462306a36Sopenharmony_ci	if (!(host->cfg->clk_delays || host->use_new_timings)) {
145562306a36Sopenharmony_ci		mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR |
145662306a36Sopenharmony_ci			       MMC_CAP_1_2V_DDR | MMC_CAP_UHS);
145762306a36Sopenharmony_ci		mmc->caps2 &= ~MMC_CAP2_HS200;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/* TODO: This driver doesn't support HS400 mode yet */
146162306a36Sopenharmony_ci	mmc->caps2 &= ~MMC_CAP2_HS400;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	ret = sunxi_mmc_init_host(host);
146462306a36Sopenharmony_ci	if (ret)
146562306a36Sopenharmony_ci		goto error_free_dma;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
146862306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
146962306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
147062306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	ret = mmc_add_host(mmc);
147362306a36Sopenharmony_ci	if (ret)
147462306a36Sopenharmony_ci		goto error_free_dma;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	dev_info(&pdev->dev, "initialized, max. request size: %u KB%s\n",
147762306a36Sopenharmony_ci		 mmc->max_req_size >> 10,
147862306a36Sopenharmony_ci		 host->use_new_timings ? ", uses new timings mode" : "");
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	return 0;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cierror_free_dma:
148362306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
148462306a36Sopenharmony_cierror_free_host:
148562306a36Sopenharmony_ci	mmc_free_host(mmc);
148662306a36Sopenharmony_ci	return ret;
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_cistatic void sunxi_mmc_remove(struct platform_device *pdev)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	struct mmc_host	*mmc = platform_get_drvdata(pdev);
149262306a36Sopenharmony_ci	struct sunxi_mmc_host *host = mmc_priv(mmc);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	mmc_remove_host(mmc);
149562306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
149662306a36Sopenharmony_ci	if (!pm_runtime_status_suspended(&pdev->dev)) {
149762306a36Sopenharmony_ci		disable_irq(host->irq);
149862306a36Sopenharmony_ci		sunxi_mmc_disable(host);
149962306a36Sopenharmony_ci	}
150062306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
150162306a36Sopenharmony_ci	mmc_free_host(mmc);
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci#ifdef CONFIG_PM
150562306a36Sopenharmony_cistatic int sunxi_mmc_runtime_resume(struct device *dev)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	struct mmc_host	*mmc = dev_get_drvdata(dev);
150862306a36Sopenharmony_ci	struct sunxi_mmc_host *host = mmc_priv(mmc);
150962306a36Sopenharmony_ci	int ret;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	ret = sunxi_mmc_enable(host);
151262306a36Sopenharmony_ci	if (ret)
151362306a36Sopenharmony_ci		return ret;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	sunxi_mmc_init_host(host);
151662306a36Sopenharmony_ci	sunxi_mmc_set_bus_width(host, mmc->ios.bus_width);
151762306a36Sopenharmony_ci	sunxi_mmc_set_clk(host, &mmc->ios);
151862306a36Sopenharmony_ci	enable_irq(host->irq);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	return 0;
152162306a36Sopenharmony_ci}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_cistatic int sunxi_mmc_runtime_suspend(struct device *dev)
152462306a36Sopenharmony_ci{
152562306a36Sopenharmony_ci	struct mmc_host	*mmc = dev_get_drvdata(dev);
152662306a36Sopenharmony_ci	struct sunxi_mmc_host *host = mmc_priv(mmc);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	/*
152962306a36Sopenharmony_ci	 * When clocks are off, it's possible receiving
153062306a36Sopenharmony_ci	 * fake interrupts, which will stall the system.
153162306a36Sopenharmony_ci	 * Disabling the irq  will prevent this.
153262306a36Sopenharmony_ci	 */
153362306a36Sopenharmony_ci	disable_irq(host->irq);
153462306a36Sopenharmony_ci	sunxi_mmc_reset_host(host);
153562306a36Sopenharmony_ci	sunxi_mmc_disable(host);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	return 0;
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci#endif
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_cistatic const struct dev_pm_ops sunxi_mmc_pm_ops = {
154262306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
154362306a36Sopenharmony_ci				pm_runtime_force_resume)
154462306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend,
154562306a36Sopenharmony_ci			   sunxi_mmc_runtime_resume,
154662306a36Sopenharmony_ci			   NULL)
154762306a36Sopenharmony_ci};
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_cistatic struct platform_driver sunxi_mmc_driver = {
155062306a36Sopenharmony_ci	.driver = {
155162306a36Sopenharmony_ci		.name	= "sunxi-mmc",
155262306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
155362306a36Sopenharmony_ci		.of_match_table = sunxi_mmc_of_match,
155462306a36Sopenharmony_ci		.pm = &sunxi_mmc_pm_ops,
155562306a36Sopenharmony_ci	},
155662306a36Sopenharmony_ci	.probe		= sunxi_mmc_probe,
155762306a36Sopenharmony_ci	.remove_new	= sunxi_mmc_remove,
155862306a36Sopenharmony_ci};
155962306a36Sopenharmony_cimodule_platform_driver(sunxi_mmc_driver);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ciMODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver");
156262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
156362306a36Sopenharmony_ciMODULE_AUTHOR("David Lanzendörfer <david.lanzendoerfer@o2s.ch>");
156462306a36Sopenharmony_ciMODULE_ALIAS("platform:sunxi-mmc");
1565