hc
2024-03-25 edb30157bad0c0001c32b854271ace01d3b9a16a
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/** @file
 *
 *  Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *
 *  SPDX-License-Identifier: BSD-2-Clause-Patent
 *
 **/
 
#include "RockchipSdhci.h"
#include <Library/PcdLib.h>
#include <Library/TimerLib.h>
 
#define word32   *(volatile unsigned int *)(long)
#define word16   *(volatile unsigned short *)(long)
 
//#define GRF_BASE            0xFDC60000
#define NS_CRU_BASE         0xFD7C0000
#define CRU_CLKSEL_CON77    0x0434
#define CRU_GPLL_CON1   0x1C4
#define CRU_CPLL_CON1   0x1A4
 
#define EMMC_CLOCK_BASE     (NS_CRU_BASE + CRU_CLKSEL_CON77)
#define EMMC_CLOCK_SEL(a)   (((7 << 12) << 16) | (a << 12))
 
#define EMMC_BASE           PcdGet32 (PcdSdhciDxeBaseAddress)
#define SDHCI_HOST_CTRL2  (EMMC_BASE + 0x3E)
#define SDHCI_HOST_CTRL3  (EMMC_BASE + 0x508)
#define SDHCI_EMMC_CTRL   (EMMC_BASE + 0x52C)
 
#define EMMC_DLL_CTRL       (EMMC_BASE + 0x800)
#define EMMC_DLL_RXCLK      (EMMC_BASE + 0x804)
#define EMMC_DLL_TXCLK      (EMMC_BASE + 0x808)
#define EMMC_DLL_STRBIN     (EMMC_BASE + 0x80C)
#define EMMC_DLL_CMDOUT     (EMMC_BASE + 0x810)
#define EMMC_DLL_STATUS0    (EMMC_BASE + 0x840)
#define EMMC_DLL_STATUS1    (EMMC_BASE + 0x844)
 
EFI_STATUS SdhciSetPHY(
  IN UINTN Clock
  )
{
  UINT32 Ctrl2;
  UINT32 status, timeout, tmp;
 
  word32(SDHCI_EMMC_CTRL) |= (1 << 0); /* Host Controller is an eMMC card */
  if (Clock < 100000000) {
    word32(EMMC_DLL_CTRL) = 0;
    word32(EMMC_DLL_RXCLK) = 0; /* PIO mode need set bit 29*/
    word32(EMMC_DLL_TXCLK) = 0;
    word32(EMMC_DLL_STRBIN) = 0;
    word32(EMMC_DLL_CMDOUT) = 0;
    goto exit;
  }
 
  word32(EMMC_DLL_RXCLK) = 0;
  /*Reset DLL*/
  word32(EMMC_DLL_CTRL) = (0x1 << 1);
  MicroSecondDelay(5);
  word32(EMMC_DLL_CTRL)  = 0;
  /*Init DLL*/
  word32(EMMC_DLL_CTRL) = (5 << 16) | (2 << 8) | 0x1;
 
  /* Wait max 10 ms */
  timeout = 10000;
  while (1) {
    status = word32(EMMC_DLL_STATUS0);
    tmp = (status >> 8) & 0x3;
    if (0x1 == tmp) /*check dll lock*/
      break;
 
    if (timeout-- > 0)
      MicroSecondDelay(1);
    else {
      DEBUG ((DEBUG_ERROR, "%a timeout status:%x\n", __FUNCTION__, status));
      return EFI_TIMEOUT;
    }
  }
 
  Ctrl2 = word16(SDHCI_HOST_CTRL2) & 0x0007; /* Get Bus Speed Mode*/
  if (Clock >= 200000000 && Ctrl2 == 0x7) { /*check is HS400 mode*/
    word32(SDHCI_EMMC_CTRL) |= (1 << 8); /* CMD line is sampled using data strobe for HS400 mode */
    word32(EMMC_DLL_RXCLK) = (1 << 27);
    word32(EMMC_DLL_TXCLK) = (1 << 29) | (1 << 27) | (1 << 24) | 0x8;
    word32(EMMC_DLL_STRBIN) = (1 << 27) | (1 << 24) | 0x4;
  }
  else { /*config for HS200 mode*/
    word32(EMMC_DLL_RXCLK) = (1 << 29) | (1 << 27);
    word32(EMMC_DLL_TXCLK) = (1 << 27) | (1 << 24) | 0x1;
    word32(EMMC_DLL_STRBIN) = 0;      //max is 16
  }
 
exit:
  //DEBUG ((DEBUG_ERROR, "EMMC_DLL_CTRL :0x%x\n", word32(EMMC_DLL_CTRL)));
  //DEBUG ((DEBUG_ERROR, "EMMC_DLL_RXCLK:0x%x\n", word32(EMMC_DLL_RXCLK)));
  //DEBUG ((DEBUG_ERROR, "EMMC_DLL_TXCLK:0x%x\n", word32(EMMC_DLL_TXCLK)));
  //DEBUG ((DEBUG_ERROR, "EMMC_DLL_STRBIN:0x%x\n", word32(EMMC_DLL_STRBIN)));
  return EFI_SUCCESS;
}
 
EFI_STATUS
EFIAPI
SdhciGetClockRate(
  IN UINTN TargetFreq,
  OUT UINTN *BaseFreq
  )
{
  UINT32 CClkEmmcSel, Div;
 
  if (TargetFreq == 0 || BaseFreq == NULL)
    return -1;
 
  //word32(NS_CRU_BASE + CRU_GPLL_CON1) = 0x70002 << 6; //GPLL:600MHz
  //word32(NS_CRU_BASE + CRU_CPLL_CON1) = 0x70002 << 6; //CPLL:750MHZ
 
  /*GPLL:1184MHz, CPLL:750MHZ
  2'b00: clk_gpll_mux
  2'b01: clk_cpll_mux
  2'b10: xin_osc0_func*/
  if (TargetFreq >= 200000000) {
    CClkEmmcSel = 0;
    Div = 6;
  } else if (TargetFreq >= 150000000) {
    CClkEmmcSel = 0;
    Div = 8;
  } else if (TargetFreq >= 100000000) {
    CClkEmmcSel = 0;
    Div = 12;
  } else if (TargetFreq >= 50000000) {
    CClkEmmcSel = 0;
    Div = 24;
  } else if (TargetFreq >= 24000000) {
    CClkEmmcSel = 2;
    Div = 1;
  } else { /* 375KHZ*/
    CClkEmmcSel = 2;
    Div = 64;
  }
 
  DEBUG((DEBUG_ERROR, "+++++SetEmmcClk: %d, %d, %d\n", TargetFreq, CClkEmmcSel, Div));
 
  *BaseFreq = TargetFreq;
  MmioWrite32(EMMC_CLOCK_BASE, ((( 0x3 << 14 )|( 0x3F << 8 )) << 16 ) |
                                ( CClkEmmcSel << 14 ) |
                                (( Div - 1 ) << 8));
 
  //DEBUG ((DEBUG_ERROR, "CRU_0X434: 0x%x\n", word32(NS_CRU_BASE + 0x0434)));
  //DEBUG ((DEBUG_ERROR, "CRU_0X438: 0x%x\n", word32(NS_CRU_BASE + 0x0438))); 
  //DEBUG ((DEBUG_ERROR, "GPLL_CON1: 0x%x\n", word32(NS_CRU_BASE + CRU_GPLL_CON1)));
  //DEBUG ((DEBUG_ERROR, "CPLL_CON1: 0x%x\n", word32(NS_CRU_BASE + CRU_CPLL_CON1)));
  SdhciSetPHY(TargetFreq);
 
  return EFI_SUCCESS;
}