File Index
Files and directories
Sign in
FILE

sdhci-brcmstb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mmc/host/sdhci-brcmstb.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * sdhci-brcmstb.c Support for SDHCI on Broadcom BRCMSTB SoC's
  4 *
  5 * Copyright (C) 2015 Broadcom Corporation
  6 */
  7
  8#include <linux/io.h>
  9#include <linux/iopoll.h>
 10#include <linux/mmc/host.h>
 11#include <linux/module.h>
 12#include <linux/of.h>
 13#include <linux/bitops.h>
 14#include <linux/delay.h>
 15
 16#include "sdhci-cqhci.h"
 17#include "sdhci-pltfm.h"
 18#include "cqhci.h"
 19
 20#define SDHCI_VENDOR 0x78
 21#define  SDHCI_VENDOR_ENHANCED_STRB 0x1
 22#define  SDHCI_VENDOR_GATE_SDCLK_EN 0x2
 23
 24#define BRCMSTB_MATCH_FLAGS_NO_64BIT		BIT(0)
 25#define BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT	BIT(1)
 26#define BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE	BIT(2)
 27#define BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY	BIT(4)
 28
 29#define BRCMSTB_PRIV_FLAGS_HAS_CQE		BIT(0)
 30#define BRCMSTB_PRIV_FLAGS_GATE_CLOCK		BIT(1)
 31
 32#define SDHCI_ARASAN_CQE_BASE_ADDR		0x200
 33
 34#define SDIO_CFG_CTRL				0x0
 35#define SDIO_CFG_CTRL_SDCD_N_TEST_EN		BIT(31)
 36#define SDIO_CFG_CTRL_SDCD_N_TEST_LEV		BIT(30)
 37#define SDIO_CFG_OP_DLY				0x34
 38#define SDIO_CFG_OP_DLY_DEFAULT			0x80000003
 39#define SDIO_CFG_CQ_CAPABILITY			0x4c
 40#define SDIO_CFG_CQ_CAPABILITY_FMUL		GENMASK(13, 12)
 41#define SDIO_CFG_SD_PIN_SEL			0x44
 42#define SDIO_CFG_V1_SD_PIN_SEL			0x54
 43#define SDIO_CFG_PHY_SW_MODE_0_RX_CTRL		0x7C
 44#define SDIO_CFG_MAX_50MHZ_MODE			0x1ac
 45#define SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE	BIT(31)
 46#define SDIO_CFG_MAX_50MHZ_MODE_ENABLE		BIT(0)
 47
 48#define SDIO_BOOT_MAIN_CTL			0x0
 49
 50#define MMC_CAP_HSE_MASK	(MMC_CAP2_HSX00_1_2V | MMC_CAP2_HSX00_1_8V)
 51/* Select all SD UHS type I SDR speed above 50MB/s */
 52#define MMC_CAP_UHS_I_SDR_MASK	(MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104)
 53
 54enum cfg_core_ver {
 55	SDIO_CFG_CORE_V1 = 1,
 56	SDIO_CFG_CORE_V2,
 57};
 58
 59struct sdhci_brcmstb_saved_regs {
 60	u32 sd_pin_sel;
 61	u32 phy_sw_mode0_rxctrl;
 62	u32 max_50mhz_mode;
 63	u32 boot_main_ctl;
 64};
 65
 66struct brcmstb_match_priv {
 67	void (*cfginit)(struct sdhci_host *host);
 68	void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios);
 69	void (*save_restore_regs)(struct mmc_host *mmc, int save);
 70	struct sdhci_ops *ops;
 71	const unsigned int flags;
 72};
 73
 74struct sdhci_brcmstb_priv {
 75	void __iomem *cfg_regs;
 76	void __iomem *boot_regs;
 77	struct sdhci_brcmstb_saved_regs saved_regs;
 78	unsigned int flags;
 79	struct clk *base_clk;
 80	u32 base_freq_hz;
 81	const struct brcmstb_match_priv *match_priv;
 82};
 83
 84static void sdhci_brcmstb_save_regs(struct mmc_host *mmc, enum cfg_core_ver ver)
 85{
 86	struct sdhci_host *host = mmc_priv(mmc);
 87	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 88	struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
 89	struct sdhci_brcmstb_saved_regs *sr = &priv->saved_regs;
 90	void __iomem *cr = priv->cfg_regs;
 91	bool is_emmc = mmc->caps & MMC_CAP_NONREMOVABLE;
 92
 93	if (is_emmc && priv->boot_regs)
 94		sr->boot_main_ctl = readl(priv->boot_regs + SDIO_BOOT_MAIN_CTL);
 95
 96	if (ver == SDIO_CFG_CORE_V1) {
 97		sr->sd_pin_sel = readl(cr + SDIO_CFG_V1_SD_PIN_SEL);
 98		return;
 99	}
100
101	sr->sd_pin_sel = readl(cr + SDIO_CFG_SD_PIN_SEL);
102	sr->phy_sw_mode0_rxctrl = readl(cr + SDIO_CFG_PHY_SW_MODE_0_RX_CTRL);
103	sr->max_50mhz_mode = readl(cr + SDIO_CFG_MAX_50MHZ_MODE);
104}
105
106static void sdhci_brcmstb_restore_regs(struct mmc_host *mmc, enum cfg_core_ver ver)
107{
108	struct sdhci_host *host = mmc_priv(mmc);
109	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
110	struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
111	struct sdhci_brcmstb_saved_regs *sr = &priv->saved_regs;
112	void __iomem *cr = priv->cfg_regs;
113	bool is_emmc = mmc->caps & MMC_CAP_NONREMOVABLE;
114
115	if (is_emmc && priv->boot_regs)
116		writel(sr->boot_main_ctl, priv->boot_regs + SDIO_BOOT_MAIN_CTL);
117
118	if (ver == SDIO_CFG_CORE_V1) {
119		writel(sr->sd_pin_sel, cr + SDIO_CFG_V1_SD_PIN_SEL);
120		return;
121	}
122
123	writel(sr->sd_pin_sel, cr + SDIO_CFG_SD_PIN_SEL);
124	writel(sr->phy_sw_mode0_rxctrl, cr + SDIO_CFG_PHY_SW_MODE_0_RX_CTRL);
125	writel(sr->max_50mhz_mode, cr + SDIO_CFG_MAX_50MHZ_MODE);
126}
127
128static void sdhci_brcmstb_save_restore_regs_v1(struct mmc_host *mmc, int save)
129{
130	if (save)
131		sdhci_brcmstb_save_regs(mmc, SDIO_CFG_CORE_V1);
132	else
133		sdhci_brcmstb_restore_regs(mmc, SDIO_CFG_CORE_V1);
134}
135
136static void sdhci_brcmstb_save_restore_regs_v2(struct mmc_host *mmc, int save)
137{
138	if (save)
139		sdhci_brcmstb_save_regs(mmc, SDIO_CFG_CORE_V2);
140	else
141		sdhci_brcmstb_restore_regs(mmc, SDIO_CFG_CORE_V2);
142}
143
144static inline void enable_clock_gating(struct sdhci_host *host)
145{
146	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
147	struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
148	u32 reg;
149
150	if (!(priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK))
151		return;
152
153	reg = sdhci_readl(host, SDHCI_VENDOR);
154	reg |= SDHCI_VENDOR_GATE_SDCLK_EN;
155	sdhci_writel(host, reg, SDHCI_VENDOR);
156}
157
158static void brcmstb_reset(struct sdhci_host *host, u8 mask)
159{
160	sdhci_and_cqhci_reset(host, mask);
161
162	/* Reset will clear this, so re-enable it */
163	enable_clock_gating(host);
164}
165
166static void brcmstb_sdhci_reset_cmd_data(struct sdhci_host *host, u8 mask)
167{
168	u32 new_mask = (mask &  (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) << 24;
169	int ret;
170	u32 reg;
171
172	/*
173	 * SDHCI_CLOCK_CONTROL register CARD_EN and CLOCK_INT_EN bits shall
174	 * be set along with SOFTWARE_RESET register RESET_CMD or RESET_DATA
175	 * bits, hence access SDHCI_CLOCK_CONTROL register as 32-bit register
176	 */
177	new_mask |= SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN;
178	reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
179	sdhci_writel(host, reg | new_mask, SDHCI_CLOCK_CONTROL);
180
181	reg = sdhci_readb(host, SDHCI_SOFTWARE_RESET);
182
183	ret = read_poll_timeout_atomic(sdhci_readb, reg, !(reg & mask),
184				       10, 10000, false,
185				       host, SDHCI_SOFTWARE_RESET);
186
187	if (ret) {
188		pr_err("%s: Reset 0x%x never completed.\n",
189		       mmc_hostname(host->mmc), (int)mask);
190		sdhci_err_stats_inc(host, CTRL_TIMEOUT);
191		sdhci_dumpregs(host);
192	}
193}
194
195static void brcmstb_reset_74165b0(struct sdhci_host *host, u8 mask)
196{
197	/* take care of RESET_ALL as usual */
198	if (mask & SDHCI_RESET_ALL)
199		sdhci_and_cqhci_reset(host, SDHCI_RESET_ALL);
200
201	/* cmd and/or data treated differently on this core */
202	if (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA))
203		brcmstb_sdhci_reset_cmd_data(host, mask);
204
205	/* Reset will clear this, so re-enable it */
206	enable_clock_gating(host);
207}
208
209static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
210{
211	struct sdhci_host *host = mmc_priv(mmc);
212
213	u32 reg;
214
215	dev_dbg(mmc_dev(mmc), "%s(): Setting HS400-Enhanced-Strobe mode\n",
216		__func__);
217	reg = readl(host->ioaddr + SDHCI_VENDOR);
218	if (ios->enhanced_strobe)
219		reg |= SDHCI_VENDOR_ENHANCED_STRB;
220	else
221		reg &= ~SDHCI_VENDOR_ENHANCED_STRB;
222	writel(reg, host->ioaddr + SDHCI_VENDOR);
223}
224
225static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock)
226{
227	u16 clk;
228
229	host->mmc->actual_clock = 0;
230
231	clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
232	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
233
234	if (clock == 0)
235		return;
236
237	sdhci_enable_clk(host, clk);
238}
239
240static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
241					    unsigned int timing)
242{
243	u16 ctrl_2;
244
245	dev_dbg(mmc_dev(host->mmc), "%s: Setting UHS signaling for %d timing\n",
246		__func__, timing);
247	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
248	/* Select Bus Speed Mode for host */
249	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
250	if ((timing == MMC_TIMING_MMC_HS200) ||
251	    (timing == MMC_TIMING_UHS_SDR104))
252		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
253	else if (timing == MMC_TIMING_UHS_SDR12)
254		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
255	else if (timing == MMC_TIMING_SD_HS ||
256		 timing == MMC_TIMING_MMC_HS ||
257		 timing == MMC_TIMING_UHS_SDR25)
258		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
259	else if (timing == MMC_TIMING_UHS_SDR50)
260		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
261	else if ((timing == MMC_TIMING_UHS_DDR50) ||
262		 (timing == MMC_TIMING_MMC_DDR52))
263		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
264	else if (timing == MMC_TIMING_MMC_HS400)
265		ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
266	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
267}
268
269static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host)
270{
271	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
272	struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
273	u32 reg;
274
275	/*
276	 * If we support a speed that requires tuning,
277	 * then select the delay line PHY as the clock source.
278	 */
279	if ((host->mmc->caps & MMC_CAP_UHS_I_SDR_MASK) || (host->mmc->caps2 & MMC_CAP_HSE_MASK)) {
280		reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE);
281		reg &= ~SDIO_CFG_MAX_50MHZ_MODE_ENABLE;
282		reg |= SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE;
283		writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE);
284	}
285
286	if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
287	    (host->mmc->caps & MMC_CAP_NEEDS_POLL)) {
288		/* Force presence */
289		reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_CTRL);
290		reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV;
291		reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN;
292		writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CTRL);
293	}
294}
295
296static void sdhci_brcmstb_set_72116_uhs_signaling(struct sdhci_host *host, unsigned int timing)
297{
298	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
299	struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
300	u32 reg;
301
302	/* no change to SDIO_CFG_OP_DLY_DEFAULT when using preset clk rate */
303	if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
304		return;
305
306	reg = (timing == MMC_TIMING_MMC_HS200) ? 0 : SDIO_CFG_OP_DLY_DEFAULT;
307	writel(reg, priv->cfg_regs + SDIO_CFG_OP_DLY);
308	sdhci_set_uhs_signaling(host, timing);
309}
310
311static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
312{
313	sdhci_dumpregs(mmc_priv(mmc));
314}
315
316static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc)
317{
318	struct sdhci_host *host = mmc_priv(mmc);
319	u32 reg;
320
321	reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
322	while (reg & SDHCI_DATA_AVAILABLE) {
323		sdhci_readl(host, SDHCI_BUFFER);
324		reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
325	}
326
327	sdhci_cqe_enable(mmc);
328}
329
330static const struct cqhci_host_ops sdhci_brcmstb_cqhci_ops = {
331	.enable         = sdhci_brcmstb_cqe_enable,
332	.disable        = sdhci_cqe_disable,
333	.dumpregs       = sdhci_brcmstb_dumpregs,
334};
335
336static struct sdhci_ops sdhci_brcmstb_ops = {
337	.set_clock = sdhci_set_clock,
338	.set_bus_width = sdhci_set_bus_width,
339	.reset = sdhci_reset,
340	.set_uhs_signaling = sdhci_set_uhs_signaling,
341};
342
343static struct sdhci_ops sdhci_brcmstb_ops_2712 = {
344	.set_clock = sdhci_set_clock,
345	.set_power = sdhci_set_power_and_bus_voltage,
346	.set_bus_width = sdhci_set_bus_width,
347	.reset = sdhci_reset,
348	.set_uhs_signaling = sdhci_set_uhs_signaling,
349};
350
351static struct sdhci_ops sdhci_brcmstb_ops_72116 = {
352	.set_clock = sdhci_set_clock,
353	.set_bus_width = sdhci_set_bus_width,
354	.reset = sdhci_reset,
355	.set_uhs_signaling = sdhci_brcmstb_set_72116_uhs_signaling,
356};
357
358static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
359	.set_clock = sdhci_brcmstb_set_clock,
360	.set_bus_width = sdhci_set_bus_width,
361	.reset = brcmstb_reset,
362	.set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
363};
364
365static struct sdhci_ops sdhci_brcmstb_ops_74165b0 = {
366	.set_clock = sdhci_brcmstb_set_clock,
367	.set_bus_width = sdhci_set_bus_width,
368	.reset = brcmstb_reset_74165b0,
369	.set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
370};
371
372static const struct brcmstb_match_priv match_priv_2712 = {
373	.cfginit = sdhci_brcmstb_cfginit_2712,
374	.ops = &sdhci_brcmstb_ops_2712,
375};
376
377static struct brcmstb_match_priv match_priv_7425 = {
378	.flags = BRCMSTB_MATCH_FLAGS_NO_64BIT |
379	BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
380	.ops = &sdhci_brcmstb_ops,
381};
382
383static struct brcmstb_match_priv match_priv_74371 = {
384	.flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
385	.ops = &sdhci_brcmstb_ops,
386};
387
388static struct brcmstb_match_priv match_priv_7445 = {
389	.flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
390	.save_restore_regs = sdhci_brcmstb_save_restore_regs_v1,
391	.ops = &sdhci_brcmstb_ops,
392};
393
394static struct brcmstb_match_priv match_priv_72116 = {
395	.flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
396	.save_restore_regs = sdhci_brcmstb_save_restore_regs_v1,
397	.ops = &sdhci_brcmstb_ops_72116,
398};
399
400static const struct brcmstb_match_priv match_priv_7216 = {
401	.flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE,
402	.save_restore_regs = sdhci_brcmstb_save_restore_regs_v2,
403	.hs400es = sdhci_brcmstb_hs400es,
404	.ops = &sdhci_brcmstb_ops_7216,
405};
406
407static struct brcmstb_match_priv match_priv_74165b0 = {
408	.flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE,
409	.save_restore_regs = sdhci_brcmstb_save_restore_regs_v2,
410	.hs400es = sdhci_brcmstb_hs400es,
411	.ops = &sdhci_brcmstb_ops_74165b0,
412};
413
414static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = {
415	{ .compatible = "brcm,bcm2712-sdhci", .data = &match_priv_2712 },
416	{ .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
417	{ .compatible = "brcm,bcm74371-sdhci", .data = &match_priv_74371 },
418	{ .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
419	{ .compatible = "brcm,bcm72116-sdhci", .data = &match_priv_72116 },
420	{ .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
421	{ .compatible = "brcm,bcm74165b0-sdhci", .data = &match_priv_74165b0 },
422	{},
423};
424
425static u32 sdhci_brcmstb_cqhci_irq(struct sdhci_host *host, u32 intmask)
426{
427	int cmd_error = 0;
428	int data_error = 0;
429
430	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
431		return intmask;
432
433	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
434
435	return 0;
436}
437
438static int sdhci_brcmstb_add_host(struct sdhci_host *host,
439				  struct sdhci_brcmstb_priv *priv)
440{
441	struct cqhci_host *cq_host;
442	bool dma64;
443	int ret;
444
445	if ((priv->flags & BRCMSTB_PRIV_FLAGS_HAS_CQE) == 0)
446		return sdhci_add_host(host);
447
448	dev_dbg(mmc_dev(host->mmc), "CQE is enabled\n");
449	host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
450	ret = sdhci_setup_host(host);
451	if (ret)
452		return ret;
453
454	cq_host = devm_kzalloc(mmc_dev(host->mmc),
455			       sizeof(*cq_host), GFP_KERNEL);
456	if (!cq_host) {
457		ret = -ENOMEM;
458		goto cleanup;
459	}
460
461	cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR;
462	cq_host->ops = &sdhci_brcmstb_cqhci_ops;
463
464	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
465	if (dma64) {
466		dev_dbg(mmc_dev(host->mmc), "Using 64 bit DMA\n");
467		cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
468	}
469
470	ret = cqhci_init(cq_host, host->mmc, dma64);
471	if (ret)
472		goto cleanup;
473
474	ret = __sdhci_add_host(host);
475	if (ret)
476		goto cleanup;
477
478	return 0;
479
480cleanup:
481	sdhci_cleanup_host(host);
482	return ret;
483}
484
485static int sdhci_brcmstb_probe(struct platform_device *pdev)
486{
487	const struct brcmstb_match_priv *match_priv;
488	struct sdhci_pltfm_data brcmstb_pdata;
489	struct sdhci_pltfm_host *pltfm_host;
490	const struct of_device_id *match;
491	struct sdhci_brcmstb_priv *priv;
492	u32 actual_clock_mhz;
493	struct sdhci_host *host;
494	struct clk *clk;
495	struct clk *base_clk = NULL;
496	int res;
497
498	match = of_match_node(sdhci_brcm_of_match, pdev->dev.of_node);
499	match_priv = match->data;
500
501	dev_dbg(&pdev->dev, "Probe found match for %s\n",  match->compatible);
502
503	clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
504	if (IS_ERR(clk))
505		return dev_err_probe(&pdev->dev, PTR_ERR(clk),
506				     "Failed to get and enable clock from Device Tree\n");
507
508	memset(&brcmstb_pdata, 0, sizeof(brcmstb_pdata));
509	brcmstb_pdata.ops = match_priv->ops;
510	host = sdhci_pltfm_init(pdev, &brcmstb_pdata,
511				sizeof(struct sdhci_brcmstb_priv));
512	if (IS_ERR(host))
513		return PTR_ERR(host);
514
515	pltfm_host = sdhci_priv(host);
516	priv = sdhci_pltfm_priv(pltfm_host);
517	priv->match_priv = match->data;
518	if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
519		priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE;
520		match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
521	}
522
523	/* Map in the non-standard CFG registers */
524	priv->cfg_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
525	if (IS_ERR(priv->cfg_regs)) {
526		res = PTR_ERR(priv->cfg_regs);
527		goto err;
528	}
529
530	sdhci_get_of_property(pdev);
531	res = mmc_of_parse(host->mmc);
532	if (res)
533		goto err;
534
535	/* map non-standard BOOT registers if present */
536	if (host->mmc->caps & MMC_CAP_NONREMOVABLE) {
537		priv->boot_regs = devm_platform_get_and_ioremap_resource(pdev, 2, NULL);
538		if (IS_ERR(priv->boot_regs))
539			priv->boot_regs = NULL;
540	}
541
542	/*
543	 * Automatic clock gating does not work for SD cards that may
544	 * voltage switch so only enable it for non-removable devices.
545	 */
546	if ((match_priv->flags & BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE) &&
547	    (host->mmc->caps & MMC_CAP_NONREMOVABLE))
548		priv->flags |= BRCMSTB_PRIV_FLAGS_GATE_CLOCK;
549
550	/*
551	 * If the chip has enhanced strobe and it's enabled, add
552	 * callback
553	 */
554	if (match_priv->hs400es &&
555	    (host->mmc->caps2 & MMC_CAP2_HS400_ES))
556		host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es;
557
558	if (match_priv->cfginit)
559		match_priv->cfginit(host);
560
561	/*
562	 * Supply the existing CAPS, but clear the UHS modes. This
563	 * will allow these modes to be specified by device tree
564	 * properties through mmc_of_parse().
565	 */
566	sdhci_read_caps(host);
567	if (match_priv->flags & BRCMSTB_MATCH_FLAGS_NO_64BIT)
568		host->caps &= ~SDHCI_CAN_64BIT;
569	host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
570			 SDHCI_SUPPORT_DDR50);
571
572	if (match_priv->flags & BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT)
573		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
574
575	if (!(match_priv->flags & BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY))
576		host->mmc_host_ops.card_busy = NULL;
577
578	/* Change the base clock frequency if the DT property exists */
579	if (device_property_read_u32(&pdev->dev, "clock-frequency",
580				     &priv->base_freq_hz) != 0)
581		goto add_host;
582
583	base_clk = devm_clk_get_optional(&pdev->dev, "sdio_freq");
584	if (IS_ERR(base_clk)) {
585		dev_warn(&pdev->dev, "Clock for \"sdio_freq\" not found\n");
586		goto add_host;
587	}
588
589	res = clk_prepare_enable(base_clk);
590	if (res)
591		goto err;
592
593	/* set improved clock rate */
594	clk_set_rate(base_clk, priv->base_freq_hz);
595	actual_clock_mhz = clk_get_rate(base_clk) / 1000000;
596
597	host->caps &= ~SDHCI_CLOCK_V3_BASE_MASK;
598	host->caps |= (actual_clock_mhz << SDHCI_CLOCK_BASE_SHIFT);
599	/* Disable presets because they are now incorrect */
600	host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
601
602	dev_dbg(&pdev->dev, "Base Clock Frequency changed to %dMHz\n",
603		actual_clock_mhz);
604	priv->base_clk = base_clk;
605
606add_host:
607	res = sdhci_brcmstb_add_host(host, priv);
608	if (res)
609		goto err;
610
611	pltfm_host->clk = clk;
612	return res;
613
614err:
615	clk_disable_unprepare(base_clk);
616	return res;
617}
618
619static void sdhci_brcmstb_shutdown(struct platform_device *pdev)
620{
621	sdhci_pltfm_suspend(&pdev->dev);
622}
623
624MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
625
626static int sdhci_brcmstb_suspend(struct device *dev)
627{
628	struct sdhci_host *host = dev_get_drvdata(dev);
629	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
630	struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
631	const struct brcmstb_match_priv *match_priv = priv->match_priv;
632
633	int ret;
634
635	if (match_priv->save_restore_regs)
636		match_priv->save_restore_regs(host->mmc, 1);
637
638	clk_disable_unprepare(priv->base_clk);
639	if (host->mmc->caps2 & MMC_CAP2_CQE) {
640		ret = cqhci_suspend(host->mmc);
641		if (ret)
642			return ret;
643	}
644
645	return sdhci_pltfm_suspend(dev);
646}
647
648static int sdhci_brcmstb_resume(struct device *dev)
649{
650	struct sdhci_host *host = dev_get_drvdata(dev);
651	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
652	struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
653	const struct brcmstb_match_priv *match_priv = priv->match_priv;
654	int ret;
655
656	ret = sdhci_pltfm_resume(dev);
657	if (!ret && priv->base_freq_hz) {
658		ret = clk_prepare_enable(priv->base_clk);
659		/*
660		 * Note: using clk_get_rate() below as clk_get_rate()
661		 * honors CLK_GET_RATE_NOCACHE attribute, but clk_set_rate()
662		 * may do implicit get_rate() calls that do not honor
663		 * CLK_GET_RATE_NOCACHE.
664		 */
665		if (!ret &&
666		    (clk_get_rate(priv->base_clk) != priv->base_freq_hz))
667			ret = clk_set_rate(priv->base_clk, priv->base_freq_hz);
668	}
669
670	if (match_priv->save_restore_regs)
671		match_priv->save_restore_regs(host->mmc, 0);
672
673	if (host->mmc->caps2 & MMC_CAP2_CQE)
674		ret = cqhci_resume(host->mmc);
675
676	return ret;
677}
678
679static DEFINE_SIMPLE_DEV_PM_OPS(sdhci_brcmstb_pmops, sdhci_brcmstb_suspend, sdhci_brcmstb_resume);
680
681static struct platform_driver sdhci_brcmstb_driver = {
682	.driver		= {
683		.name	= "sdhci-brcmstb",
684		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
685		.pm	= pm_sleep_ptr(&sdhci_brcmstb_pmops),
686		.of_match_table = of_match_ptr(sdhci_brcm_of_match),
687	},
688	.probe		= sdhci_brcmstb_probe,
689	.remove		= sdhci_pltfm_remove,
690	.shutdown	= sdhci_brcmstb_shutdown,
691};
692
693module_platform_driver(sdhci_brcmstb_driver);
694
695MODULE_DESCRIPTION("SDHCI driver for Broadcom BRCMSTB SoCs");
696MODULE_AUTHOR("Broadcom");
697MODULE_LICENSE("GPL v2");
~/ Read-only file preview.