File Index
Files and directories
Sign in
FILE

sdhci-of-ma35d1.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mmc/host/sdhci-of-ma35d1.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) 2024 Nuvoton Technology Corp.
  4 *
  5 * Author: Shan-Chun Hung <shanchun1218@gmail.com>
  6 */
  7
  8#include <linux/align.h>
  9#include <linux/array_size.h>
 10#include <linux/bits.h>
 11#include <linux/build_bug.h>
 12#include <linux/clk.h>
 13#include <linux/delay.h>
 14#include <linux/dev_printk.h>
 15#include <linux/device.h>
 16#include <linux/dma-mapping.h>
 17#include <linux/err.h>
 18#include <linux/math.h>
 19#include <linux/mfd/syscon.h>
 20#include <linux/minmax.h>
 21#include <linux/mmc/card.h>
 22#include <linux/mmc/host.h>
 23#include <linux/mod_devicetable.h>
 24#include <linux/module.h>
 25#include <linux/pinctrl/consumer.h>
 26#include <linux/platform_device.h>
 27#include <linux/regmap.h>
 28#include <linux/reset.h>
 29#include <linux/sizes.h>
 30#include <linux/types.h>
 31
 32#include "sdhci-pltfm.h"
 33#include "sdhci.h"
 34
 35#define MA35_SYS_MISCFCR0	0x070
 36#define MA35_SDHCI_MSHCCTL	0x508
 37#define MA35_SDHCI_MBIUCTL	0x510
 38
 39#define MA35_SDHCI_CMD_CONFLICT_CHK	BIT(0)
 40#define MA35_SDHCI_INCR_MSK		GENMASK(3, 0)
 41#define MA35_SDHCI_INCR16		BIT(3)
 42#define MA35_SDHCI_INCR8		BIT(2)
 43
 44struct ma35_priv {
 45	struct reset_control	*rst;
 46	struct pinctrl		*pinctrl;
 47	struct pinctrl_state	*pins_uhs;
 48	struct pinctrl_state	*pins_default;
 49};
 50
 51struct ma35_restore_data {
 52	u32	reg;
 53	u32	width;
 54};
 55
 56static const struct ma35_restore_data restore_data[] = {
 57	{ SDHCI_CLOCK_CONTROL,		sizeof(u32)},
 58	{ SDHCI_BLOCK_SIZE,		sizeof(u32)},
 59	{ SDHCI_INT_ENABLE,		sizeof(u32)},
 60	{ SDHCI_SIGNAL_ENABLE,		sizeof(u32)},
 61	{ SDHCI_AUTO_CMD_STATUS,	sizeof(u32)},
 62	{ SDHCI_HOST_CONTROL,		sizeof(u32)},
 63	{ SDHCI_TIMEOUT_CONTROL,	sizeof(u8) },
 64	{ MA35_SDHCI_MSHCCTL,		sizeof(u16)},
 65	{ MA35_SDHCI_MBIUCTL,		sizeof(u16)},
 66};
 67
 68/*
 69 * If DMA addr spans 128MB boundary, we split the DMA transfer into two
 70 * so that each DMA transfer doesn't exceed the boundary.
 71 */
 72static void ma35_adma_write_desc(struct sdhci_host *host, void **desc, dma_addr_t addr, int len,
 73				 unsigned int cmd)
 74{
 75	int tmplen, offset;
 76
 77	if (likely(!len || (ALIGN(addr, SZ_128M) == ALIGN(addr + len - 1, SZ_128M)))) {
 78		sdhci_adma_write_desc(host, desc, addr, len, cmd);
 79		return;
 80	}
 81
 82	offset = addr & (SZ_128M - 1);
 83	tmplen = SZ_128M - offset;
 84	sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
 85
 86	addr += tmplen;
 87	len -= tmplen;
 88	sdhci_adma_write_desc(host, desc, addr, len, cmd);
 89}
 90
 91static void ma35_set_clock(struct sdhci_host *host, unsigned int clock)
 92{
 93	u32 ctl;
 94
 95	/*
 96	 * If the clock frequency exceeds MMC_HIGH_52_MAX_DTR,
 97	 * disable command conflict check.
 98	 */
 99	ctl = sdhci_readw(host, MA35_SDHCI_MSHCCTL);
100	if (clock > MMC_HIGH_52_MAX_DTR)
101		ctl &= ~MA35_SDHCI_CMD_CONFLICT_CHK;
102	else
103		ctl |= MA35_SDHCI_CMD_CONFLICT_CHK;
104	sdhci_writew(host, ctl, MA35_SDHCI_MSHCCTL);
105
106	sdhci_set_clock(host, clock);
107}
108
109static int ma35_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
110{
111	struct sdhci_host *host = mmc_priv(mmc);
112	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
113	struct ma35_priv *priv = sdhci_pltfm_priv(pltfm_host);
114
115	switch (ios->signal_voltage) {
116	case MMC_SIGNAL_VOLTAGE_180:
117		if (!IS_ERR(priv->pinctrl) && !IS_ERR(priv->pins_uhs))
118			pinctrl_select_state(priv->pinctrl, priv->pins_uhs);
119		break;
120	case MMC_SIGNAL_VOLTAGE_330:
121		if (!IS_ERR(priv->pinctrl) && !IS_ERR(priv->pins_default))
122			pinctrl_select_state(priv->pinctrl, priv->pins_default);
123		break;
124	default:
125		dev_err(mmc_dev(host->mmc), "Unsupported signal voltage!\n");
126		return -EINVAL;
127	}
128
129	return sdhci_start_signal_voltage_switch(mmc, ios);
130}
131
132static void ma35_voltage_switch(struct sdhci_host *host)
133{
134	/* Wait for 5ms after set 1.8V signal enable bit */
135	fsleep(5000);
136}
137
138static int ma35_execute_tuning(struct mmc_host *mmc, u32 opcode)
139{
140	struct sdhci_host *host = mmc_priv(mmc);
141	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
142	struct ma35_priv *priv = sdhci_pltfm_priv(pltfm_host);
143	int idx;
144	u32 regs[ARRAY_SIZE(restore_data)] = {};
145
146	/*
147	 * Limitations require a reset of SD/eMMC before tuning and
148	 * saving the registers before resetting, then restoring
149	 * after the reset.
150	 */
151	for (idx = 0; idx < ARRAY_SIZE(restore_data); idx++) {
152		if (restore_data[idx].width == sizeof(u32))
153			regs[idx] = sdhci_readl(host, restore_data[idx].reg);
154		else if (restore_data[idx].width == sizeof(u16))
155			regs[idx] = sdhci_readw(host, restore_data[idx].reg);
156		else if (restore_data[idx].width == sizeof(u8))
157			regs[idx] = sdhci_readb(host, restore_data[idx].reg);
158	}
159
160	reset_control_assert(priv->rst);
161	reset_control_deassert(priv->rst);
162
163	for (idx = 0; idx < ARRAY_SIZE(restore_data); idx++) {
164		if (restore_data[idx].width == sizeof(u32))
165			sdhci_writel(host, regs[idx], restore_data[idx].reg);
166		else if (restore_data[idx].width == sizeof(u16))
167			sdhci_writew(host, regs[idx], restore_data[idx].reg);
168		else if (restore_data[idx].width == sizeof(u8))
169			sdhci_writeb(host, regs[idx], restore_data[idx].reg);
170	}
171
172	return sdhci_execute_tuning(mmc, opcode);
173}
174
175static const struct sdhci_ops sdhci_ma35_ops = {
176	.set_clock		= ma35_set_clock,
177	.set_bus_width		= sdhci_set_bus_width,
178	.set_uhs_signaling	= sdhci_set_uhs_signaling,
179	.get_max_clock		= sdhci_pltfm_clk_get_max_clock,
180	.reset			= sdhci_reset,
181	.adma_write_desc	= ma35_adma_write_desc,
182	.voltage_switch		= ma35_voltage_switch,
183};
184
185static const struct sdhci_pltfm_data sdhci_ma35_pdata = {
186	.ops = &sdhci_ma35_ops,
187	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
188	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_BROKEN_DDR50 |
189		   SDHCI_QUIRK2_ACMD23_BROKEN,
190};
191
192static int ma35_probe(struct platform_device *pdev)
193{
194	struct device *dev = &pdev->dev;
195	struct sdhci_pltfm_host *pltfm_host;
196	struct sdhci_host *host;
197	struct ma35_priv *priv;
198	int err;
199	u32 extra, ctl;
200
201	host = sdhci_pltfm_init(pdev, &sdhci_ma35_pdata, sizeof(struct ma35_priv));
202	if (IS_ERR(host))
203		return PTR_ERR(host);
204
205	/* Extra adma table cnt for cross 128M boundary handling. */
206	extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M);
207	extra = min(extra, SDHCI_MAX_SEGS);
208
209	host->adma_table_cnt += extra;
210	pltfm_host = sdhci_priv(host);
211	priv = sdhci_pltfm_priv(pltfm_host);
212
213	pltfm_host->clk = devm_clk_get_optional_enabled(dev, NULL);
214	if (IS_ERR(pltfm_host->clk))
215		return dev_err_probe(dev, PTR_ERR(pltfm_host->clk),
216				     "failed to get clk\n");
217
218	err = mmc_of_parse(host->mmc);
219	if (err)
220		return err;
221
222	priv->rst = devm_reset_control_get_exclusive(dev, NULL);
223	if (IS_ERR(priv->rst))
224		return dev_err_probe(dev, PTR_ERR(priv->rst),
225				     "failed to get reset control\n");
226
227	sdhci_get_of_property(pdev);
228
229	priv->pinctrl = devm_pinctrl_get(dev);
230	if (!IS_ERR(priv->pinctrl)) {
231		priv->pins_default = pinctrl_lookup_state(priv->pinctrl, "default");
232		priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl, "state_uhs");
233		pinctrl_select_state(priv->pinctrl, priv->pins_default);
234	}
235
236	if (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)) {
237		struct regmap	*regmap;
238		u32		reg;
239
240		regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev), "nuvoton,sys");
241		if (!IS_ERR(regmap)) {
242			/* Enable SDHCI voltage stable for 1.8V */
243			regmap_read(regmap, MA35_SYS_MISCFCR0, &reg);
244			reg |= BIT(17);
245			regmap_write(regmap, MA35_SYS_MISCFCR0, reg);
246		}
247
248		host->mmc_host_ops.start_signal_voltage_switch =
249					ma35_start_signal_voltage_switch;
250	}
251
252	host->mmc_host_ops.execute_tuning = ma35_execute_tuning;
253
254	err = sdhci_add_host(host);
255	if (err)
256		return err;
257
258	/*
259	 * Split data into chunks of 16 or 8 bytes for transmission.
260	 * Each chunk transfer is guaranteed to be uninterrupted on the bus.
261	 * This likely corresponds to the AHB bus DMA burst size.
262	 */
263	ctl = sdhci_readw(host, MA35_SDHCI_MBIUCTL);
264	ctl &= ~MA35_SDHCI_INCR_MSK;
265	ctl |= MA35_SDHCI_INCR16 | MA35_SDHCI_INCR8;
266	sdhci_writew(host, ctl, MA35_SDHCI_MBIUCTL);
267
268	return 0;
269}
270
271static void ma35_disable_card_clk(struct sdhci_host *host)
272{
273	u16 ctrl;
274
275	ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
276	if (ctrl & SDHCI_CLOCK_CARD_EN) {
277		ctrl &= ~SDHCI_CLOCK_CARD_EN;
278		sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
279	}
280}
281
282static void ma35_remove(struct platform_device *pdev)
283{
284	struct sdhci_host *host = platform_get_drvdata(pdev);
285
286	sdhci_remove_host(host, 0);
287	ma35_disable_card_clk(host);
288}
289
290static const struct of_device_id sdhci_ma35_dt_ids[] = {
291	{ .compatible = "nuvoton,ma35d1-sdhci" },
292	{}
293};
294
295static struct platform_driver sdhci_ma35_driver = {
296	.driver	= {
297		.name	= "sdhci-ma35",
298		.of_match_table = sdhci_ma35_dt_ids,
299	},
300	.probe	= ma35_probe,
301	.remove = ma35_remove,
302};
303module_platform_driver(sdhci_ma35_driver);
304
305MODULE_DESCRIPTION("SDHCI platform driver for Nuvoton MA35");
306MODULE_AUTHOR("Shan-Chun Hung <shanchun1218@gmail.com>");
307MODULE_LICENSE("GPL");
~/ Read-only file preview.