hc
2025-02-14 bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e
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 <prabu.t@synopsys.com>
 *    Manjunath M B <manjumb@synopsys.com>
 */
 
#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,
};