1 /********************************************************************************
2 Copyright (C) 2016 Marvell International Ltd.
3
4 Marvell BSD License Option
5
6 If you received this File from Marvell, you may opt to use, redistribute and/or
7 modify this File under the following licensing terms.
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
10
11 * Redistributions of source code must retain the above copyright notice,
12 this list of conditions and the following disclaimer.
13
14 * Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17
18 * Neither the name of Marvell nor the names of its contributors may be
19 used to endorse or promote products derived from this software without
20 specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 *******************************************************************************/
34
35 #include <Protocol/DriverBinding.h>
36 #include <Protocol/Mdio.h>
37
38 #include <Library/BaseLib.h>
39 #include <Library/BaseMemoryLib.h>
40 #include <Library/DebugLib.h>
41 #include <Library/IoLib.h>
42 #include <Library/MemoryAllocationLib.h>
43 #include <Library/PcdLib.h>
44 #include <Library/UefiBootServicesTableLib.h>
45 #include <Library/UefiLib.h>
46
47 #include "MvMdioDxe.h"
48
49 UINT64 MdioBase = 0;
50
51 STATIC
52 EFI_STATUS
MdioCheckParam(INTN PhyAddr,INTN RegOff)53 MdioCheckParam (
54 INTN PhyAddr,
55 INTN RegOff
56 )
57 {
58 if (PhyAddr > MVEBU_PHY_ADDR_MASK) {
59 DEBUG((DEBUG_ERROR, "Invalid PHY address %d\n", PhyAddr));
60 return EFI_INVALID_PARAMETER;
61 }
62
63 if (RegOff > MVEBU_PHY_REG_MASK) {
64 DEBUG((DEBUG_ERROR, "Invalid register offset %d\n", RegOff));
65 return EFI_INVALID_PARAMETER;
66 }
67 return EFI_SUCCESS;
68 }
69
70 STATIC
71 EFI_STATUS
MdioWaitReady(VOID)72 MdioWaitReady (
73 VOID
74 )
75 {
76 UINT32 Timeout = MVEBU_SMI_TIMEOUT;
77 UINT32 MdioReg;
78
79 /* wait till the SMI is not busy */
80 do {
81 /* read smi register */
82 MdioReg = MmioRead32(MdioBase);
83 if (Timeout-- == 0) {
84 DEBUG((DEBUG_ERROR, "SMI busy Timeout\n"));
85 return EFI_TIMEOUT;
86 }
87 } while (MdioReg & MVEBU_SMI_BUSY);
88
89 return EFI_SUCCESS;
90 }
91
92 STATIC
93 EFI_STATUS
MdioWaitValid(VOID)94 MdioWaitValid (
95 VOID
96 )
97 {
98 UINT32 Timeout = MVEBU_SMI_TIMEOUT;
99 UINT32 MdioReg;
100
101 /* wait till read value is ready */
102 do {
103 /* read smi register */
104 MdioReg = MmioRead32 (MdioBase);
105 if (Timeout-- == 0) {
106 DEBUG((DEBUG_ERROR, "SMI read ready time-out\n"));
107 return EFI_TIMEOUT;
108 }
109 } while (!(MdioReg & MVEBU_SMI_READ_VALID));
110
111 return EFI_SUCCESS;
112 }
113
114 STATIC
115 EFI_STATUS
MdioOperation(IN CONST MARVELL_MDIO_PROTOCOL * This,IN UINT32 PhyAddr,IN UINT32 RegOff,IN BOOLEAN Write,IN OUT UINT32 * Data)116 MdioOperation (
117 IN CONST MARVELL_MDIO_PROTOCOL *This,
118 IN UINT32 PhyAddr,
119 IN UINT32 RegOff,
120 IN BOOLEAN Write,
121 IN OUT UINT32 *Data
122 )
123 {
124 UINT32 MdioReg;
125 EFI_STATUS Status;
126
127 Status = MdioCheckParam (PhyAddr, RegOff);
128 if (EFI_ERROR(Status)) {
129 DEBUG((DEBUG_ERROR, "MdioDxe: wrong parameters\n"));
130 return Status;
131 }
132
133 /* wait till the SMI is not busy */
134 Status = MdioWaitReady ();
135 if (EFI_ERROR(Status)) {
136 DEBUG((DEBUG_ERROR, "MdioDxe: MdioWaitReady error\n"));
137 return Status;
138 }
139
140 /* fill the phy addr and reg offset and write opcode and data */
141 MdioReg = (PhyAddr << MVEBU_SMI_DEV_ADDR_OFFS)
142 | (RegOff << MVEBU_SMI_REG_ADDR_OFFS);
143 if (Write) {
144 MdioReg &= ~MVEBU_SMI_OPCODE_READ;
145 MdioReg |= (*Data << MVEBU_SMI_DATA_OFFS);
146 } else {
147 MdioReg |= MVEBU_SMI_OPCODE_READ;
148 }
149
150 /* write the smi register */
151 MdioRegWrite32 (MdioReg, MdioBase);
152
153 /* make sure that the write transaction is over */
154 Status = Write ? MdioWaitReady () : MdioWaitValid ();
155 if (EFI_ERROR(Status)) {
156 DEBUG((DEBUG_ERROR, "MdioDxe: MdioWaitReady error\n"));
157 return Status;
158 }
159
160 if (!Write) {
161 *Data = MmioRead32 (MdioBase) & MVEBU_SMI_DATA_MASK;
162 }
163
164 return EFI_SUCCESS;
165 }
166
167 STATIC
168 EFI_STATUS
MvMdioRead(IN CONST MARVELL_MDIO_PROTOCOL * This,IN UINT32 PhyAddr,IN UINT32 RegOff,IN UINT32 * Data)169 MvMdioRead (
170 IN CONST MARVELL_MDIO_PROTOCOL *This,
171 IN UINT32 PhyAddr,
172 IN UINT32 RegOff,
173 IN UINT32 *Data
174 )
175 {
176 EFI_STATUS Status;
177
178 Status = MdioOperation (
179 This,
180 PhyAddr,
181 RegOff,
182 FALSE,
183 Data
184 );
185
186 return Status;
187 }
188
189 EFI_STATUS
MvMdioWrite(IN CONST MARVELL_MDIO_PROTOCOL * This,IN UINT32 PhyAddr,IN UINT32 RegOff,IN UINT32 Data)190 MvMdioWrite (
191 IN CONST MARVELL_MDIO_PROTOCOL *This,
192 IN UINT32 PhyAddr,
193 IN UINT32 RegOff,
194 IN UINT32 Data
195 )
196 {
197 return MdioOperation (
198 This,
199 PhyAddr,
200 RegOff,
201 TRUE,
202 &Data
203 );
204 }
205
206 EFI_STATUS
207 EFIAPI
MvMdioDxeInitialise(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)208 MvMdioDxeInitialise (
209 IN EFI_HANDLE ImageHandle,
210 IN EFI_SYSTEM_TABLE *SystemTable
211 )
212 {
213 MARVELL_MDIO_PROTOCOL *Mdio;
214 EFI_STATUS Status;
215 EFI_HANDLE Handle = NULL;
216
217 Mdio = AllocateZeroPool (sizeof (MARVELL_MDIO_PROTOCOL));
218 Mdio->Read = MvMdioRead;
219 Mdio->Write = MvMdioWrite;
220 MdioBase = PcdGet64 (PcdMdioBaseAddress);
221 if (MdioBase == 0) {
222 DEBUG((DEBUG_ERROR, "MdioDxe: PcdMdioBaseAddress not set\n"));
223 return EFI_INVALID_PARAMETER;
224 }
225 Status = gBS->InstallMultipleProtocolInterfaces (
226 &Handle,
227 &gMarvellMdioProtocolGuid, Mdio,
228 NULL
229 );
230
231 if (EFI_ERROR(Status)) {
232 DEBUG((DEBUG_ERROR, "Failed to install interfaces\n"));
233 return Status;
234 }
235
236 return EFI_SUCCESS;
237 }
238