forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sdhci-pci-dwc-mshc.c
84 lines (71 loc) · 2.2 KB
/
sdhci-pci-dwc-mshc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// SPDX-License-Identifier: GPL-2.0
/*
* SDHCI driver for Synopsys DWC_MSHC controller
*
* Copyright (C) 2018 Synopsys, Inc. (www.synopsys.com)
*
* Authors:
* Prabu Thangamuthu <[email protected]>
* Manjunath M B <[email protected]>
*/
#include "sdhci.h"
#include "sdhci-pci.h"
#define SDHCI_VENDOR_PTR_R 0xE8
/* Synopsys vendor specific registers */
#define SDHC_GPIO_OUT 0x34
#define SDHC_AT_CTRL_R 0x40
#define SDHC_SW_TUNE_EN 0x00000010
/* MMCM DRP */
#define SDHC_MMCM_DIV_REG 0x1020
#define DIV_REG_100_MHZ 0x1145
#define DIV_REG_200_MHZ 0x1083
#define SDHC_MMCM_CLKFBOUT 0x1024
#define CLKFBOUT_100_MHZ 0x0000
#define CLKFBOUT_200_MHZ 0x0080
#define SDHC_CCLK_MMCM_RST 0x00000001
static void sdhci_snps_set_clock(struct sdhci_host *host, unsigned int clock)
{
u16 clk;
u32 reg, vendor_ptr;
vendor_ptr = sdhci_readw(host, SDHCI_VENDOR_PTR_R);
/* Disable software managed rx tuning */
reg = sdhci_readl(host, (SDHC_AT_CTRL_R + vendor_ptr));
reg &= ~SDHC_SW_TUNE_EN;
sdhci_writel(host, reg, (SDHC_AT_CTRL_R + vendor_ptr));
if (clock <= 52000000) {
sdhci_set_clock(host, clock);
} else {
/* Assert reset to MMCM */
reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr));
reg |= SDHC_CCLK_MMCM_RST;
sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr));
/* Configure MMCM */
if (clock == 100000000) {
sdhci_writel(host, DIV_REG_100_MHZ, SDHC_MMCM_DIV_REG);
sdhci_writel(host, CLKFBOUT_100_MHZ,
SDHC_MMCM_CLKFBOUT);
} else {
sdhci_writel(host, DIV_REG_200_MHZ, SDHC_MMCM_DIV_REG);
sdhci_writel(host, CLKFBOUT_200_MHZ,
SDHC_MMCM_CLKFBOUT);
}
/* De-assert reset to MMCM */
reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr));
reg &= ~SDHC_CCLK_MMCM_RST;
sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr));
/* Enable clock */
clk = SDHCI_PROG_CLOCK_MODE | SDHCI_CLOCK_INT_EN |
SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
}
static const struct sdhci_ops sdhci_snps_ops = {
.set_clock = sdhci_snps_set_clock,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
const struct sdhci_pci_fixes sdhci_snps = {
.ops = &sdhci_snps_ops,
};