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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
/** @file
SynQuacer DXE platform driver - eMMC support
Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available
under the terms and conditions of the BSD License which accompanies this
distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PlatformDxe.h"
// F_SDH30 extended Controller registers
#define F_SDH30_AHB_CONFIG 0x100
#define F_SDH30_AHB_BIGED BIT6
#define F_SDH30_BUSLOCK_DMA BIT5
#define F_SDH30_BUSLOCK_EN BIT4
#define F_SDH30_SIN BIT3
#define F_SDH30_AHB_INCR_16 BIT2
#define F_SDH30_AHB_INCR_8 BIT1
#define F_SDH30_AHB_INCR_4 BIT0
#define F_SDH30_TUNING_SETTING 0x108
#define F_SDH30_CMD_CHK_DIS BIT16
#define F_SDH30_IO_CONTROL2 0x114
#define F_SDH30_MSEL_O_1_8 BIT18
#define F_SDH30_CRES_O_DN BIT19
#define F_SDH30_ESD_CONTROL 0x124
#define F_SDH30_EMMC_RST BIT1
#define F_SDH30_EMMC_HS200 BIT24
#define F_SDH30_CMD_DAT_DELAY BIT9
#define F_SDH30_TUNING_SETTING 0x108
#define F_SDH30_CMD_CHK_DIS BIT16
#define F_SDH30_IO_CONTROL2 0x114
#define F_SDH30_MSEL_O_1_8 BIT18
#define F_SDH30_CRES_O_DN BIT19
#define F_SDH30_ESD_CONTROL 0x124
#define F_SDH30_EMMC_RST BIT1
#define F_SDH30_EMMC_HS200 BIT24
#define F_SDH30_CMD_DAT_DELAY BIT9
#define SD_HC_CLOCK_CTRL 0x2C
#define SYNQUACER_CLOCK_CTRL_VAL 0xBC01
#define SD_HC_CAP_SDR104 BIT33
#define ESD_CONTROL_RESET_DELAY (20 * 1000)
#define IO_CONTROL2_SETTLE_US 3000
STATIC EFI_HANDLE mSdMmcControllerHandle;
/**
Override function for SDHCI capability bits
@param[in] PassThru A pointer to the
EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
@param[in] ControllerHandle The EFI_HANDLE of the controller.
@param[in] Slot The 0 based slot index.
@param[in,out] SdMmcHcSlotCapability The SDHCI capability structure.
@retval EFI_SUCCESS The override function completed successfully.
@retval EFI_NOT_FOUND The specified controller or slot does not exist.
@retval EFI_INVALID_PARAMETER SdMmcHcSlotCapability is NULL
**/
STATIC
EFI_STATUS
EFIAPI
SynQuacerSdMmcCapability (
IN EFI_HANDLE ControllerHandle,
IN UINT8 Slot,
IN OUT VOID *SdMmcHcSlotCapability
)
{
UINT64 Capability;
if (ControllerHandle != mSdMmcControllerHandle) {
return EFI_SUCCESS;
}
ASSERT (Slot == 0);
//
// Clear the SDR104 capability bit. This avoids the need for a HS200 tuning
// quirk that is difficult to support using the generic driver.
//
Capability = ReadUnaligned64 (SdMmcHcSlotCapability);
Capability &= ~(UINT64)SD_HC_CAP_SDR104;
WriteUnaligned64 (SdMmcHcSlotCapability, Capability);
return EFI_SUCCESS;
}
/**
Override function for SDHCI controller operations
@param[in] ControllerHandle The EFI_HANDLE of the controller.
@param[in] Slot The 0 based slot index.
@param[in] PhaseType The type of operation and whether the
hook is invoked right before (pre) or
right after (post)
@retval EFI_SUCCESS The override function completed successfully.
@retval EFI_NOT_FOUND The specified controller or slot does not exist.
@retval EFI_INVALID_PARAMETER PhaseType is invalid
**/
STATIC
EFI_STATUS
EFIAPI
SynQuacerSdMmcNotifyPhase (
IN EFI_HANDLE ControllerHandle,
IN UINT8 Slot,
IN EDKII_SD_MMC_PHASE_TYPE PhaseType
)
{
if (ControllerHandle != mSdMmcControllerHandle) {
return EFI_SUCCESS;
}
ASSERT (Slot == 0);
switch (PhaseType) {
case EdkiiSdMmcResetPre:
// Soft reset does not complete unless the clock is already enabled.
MmioWrite16 (SYNQUACER_EMMC_BASE + SD_HC_CLOCK_CTRL,
SYNQUACER_CLOCK_CTRL_VAL);
break;
case EdkiiSdMmcInitHostPre:
// init vendor specific regs
MmioAnd16 (SYNQUACER_EMMC_BASE + F_SDH30_AHB_CONFIG,
~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN));
MmioOr16 (SYNQUACER_EMMC_BASE + F_SDH30_AHB_CONFIG,
F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 |
F_SDH30_AHB_INCR_4);
MmioAnd32 (SYNQUACER_EMMC_BASE + F_SDH30_ESD_CONTROL, ~F_SDH30_EMMC_RST);
MemoryFence ();
gBS->Stall (ESD_CONTROL_RESET_DELAY);
MmioOr32 (SYNQUACER_EMMC_BASE + F_SDH30_ESD_CONTROL,
F_SDH30_EMMC_RST | F_SDH30_CMD_DAT_DELAY | F_SDH30_EMMC_HS200);
gBS->Stall (IO_CONTROL2_SETTLE_US);
MmioOr32 (SYNQUACER_EMMC_BASE + F_SDH30_IO_CONTROL2, F_SDH30_CRES_O_DN);
MemoryFence ();
MmioOr32 (SYNQUACER_EMMC_BASE + F_SDH30_IO_CONTROL2, F_SDH30_MSEL_O_1_8);
MemoryFence ();
MmioAnd32 (SYNQUACER_EMMC_BASE + F_SDH30_IO_CONTROL2, ~F_SDH30_CRES_O_DN);
MemoryFence ();
gBS->Stall (IO_CONTROL2_SETTLE_US);
MmioOr32 (SYNQUACER_EMMC_BASE + F_SDH30_TUNING_SETTING,
F_SDH30_CMD_CHK_DIS);
break;
default:
break;
}
return EFI_SUCCESS;
}
STATIC EDKII_SD_MMC_OVERRIDE mSdMmcOverride = {
EDKII_SD_MMC_OVERRIDE_PROTOCOL_VERSION,
SynQuacerSdMmcCapability,
SynQuacerSdMmcNotifyPhase,
};
EFI_STATUS
EFIAPI
RegisterEmmc (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
Status = RegisterNonDiscoverableMmioDevice (
NonDiscoverableDeviceTypeSdhci,
NonDiscoverableDeviceDmaTypeCoherent,
NULL,
&mSdMmcControllerHandle,
1,
SYNQUACER_EMMC_BASE, SYNQUACER_EMMC_BASE_SZ);
ASSERT_EFI_ERROR (Status);
Handle = NULL;
Status = gBS->InstallProtocolInterface (&Handle,
&gEdkiiSdMmcOverrideProtocolGuid,
EFI_NATIVE_INTERFACE, (VOID **)&mSdMmcOverride);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
|