]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseSmbusLib/SmbusLib.c
Initial import.
[mirror_edk2.git] / MdePkg / Library / BaseSmbusLib / SmbusLib.c
1 /** @file
2 Base SMBUS library implementation built upon I/O library.
3
4 Copyright (c) 2006, Intel Corporation<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 Module Name: SmbusLib.h
14
15 **/
16
17 RETURN_STATUS
18 EFIAPI
19 BaseSmBusLibConstructor (
20 IN VOID *Param1,
21 IN VOID *Param2
22 )
23 {
24 return RETURN_SUCCESS;
25 }
26
27 //
28 // BUGBUG: use PCD to retrieve BUS, DEV, FUNC & OFFSET for SMBUS host BAR
29 //
30 #define SMBUS_HOST_BUS 0
31 #define SMBUS_HOST_DEV 31
32 #define SMBUS_HOST_FUNC 3
33 #define SMBUS_HOST_SMB_BASE 0x20
34
35 //
36 // Offsets of registers for SMBUS controller
37 //
38 #define R_HST_STS 0
39 #define R_HST_CNT 2
40 #define R_HST_CMD 3
41 #define R_XMIT_SLVA 4
42 #define R_HST_D0 5
43 #define R_HST_D1 6
44 #define R_HOST_BLOCK_DB 7
45 #define R_PEC 8
46 #define R_RCV_SLVA 9
47 #define R_SLV_DATA 0x0a
48 #define R_AUX_STS 0x0c
49 #define R_AUX_CTL 0x0d
50 #define R_SMLINK_PIN_CTL 0x0e
51 #define R_SMBUS_PIN_CTL 0x0f
52 #define R_SLV_STS 0x10
53 #define R_SLV_CMD 0x11
54 #define R_NOTIFY_DADDR 0x14
55 #define R_NOTIFY_DLOW 0x16
56 #define R_NOTIFY_DHIGH 0x17
57
58 //
59 // Bits in HST_STS
60 //
61 #define B_HST_STS_DS 0x80
62 #define B_HST_STS_INUSE 0x40
63 #define B_HST_STS_SMBALERT 0x20
64 #define B_HST_STS_FAILED 0x10
65 #define B_HST_STS_BUS_ERR 0x08
66 #define B_HST_STS_DEV_ERR 0x04
67 #define B_HST_STS_INTR 0x02
68 #define B_HST_STS_BUSY 0x01
69 #define B_HST_STS_ERR ( B_HST_STS_BUS_ERR | \
70 B_HST_STS_DEV_ERR | \
71 B_HST_STS_FAILED )
72 #define B_HST_STS_ALL ( B_HST_STS_DS | \
73 B_HST_STS_INUSE | \
74 B_HST_STS_SMBALERT | \
75 B_HST_STS_ERR | \
76 B_HST_STS_INTR )
77
78 //
79 // Bits in HST_CNT
80 //
81 #define B_HST_CNT_PEC 0x80
82 #define B_HST_CNT_START 0x40
83 #define B_HST_CNT_LAST_BYTE 0x20
84 #define B_HST_CNT_SMB_CMD 0x1c
85 #define B_HST_CNT_KILL 0x02
86 #define B_HST_CNT_INTREN 0x01
87
88 //
89 // SMBUS Protocols
90 //
91 #define B_SMB_CMD_QUICK 0
92 #define B_SMB_CMD_BYTE 1
93 #define B_SMB_CMD_BYTE_DATA 2
94 #define B_SMB_CMD_WORD_DATA 3
95 #define B_SMB_CMD_PROCESS_CALL 4
96 #define B_SMB_CMD_BLOCK 5
97 #define B_SMB_CMD_I2C 6
98 #define B_SMB_CMD_BLOCK_PROCESS 7
99
100 //
101 // Bits in AUX_CTL
102 //
103 #define B_AUX_CTL_E32B 0x02
104 #define B_AUX_CTL_AAC 0x01
105
106 //
107 // SMBUS Rd/Wr control
108 //
109 #define B_SMBUS_READ 1
110 #define B_SMBUS_WRITE 0
111
112 static
113 UINT16
114 EFIAPI
115 GetSmBusIOBaseAddress (
116 VOID
117 )
118 {
119 UINT32 SmbusBar;
120
121 SmbusBar = PciRead32 (
122 PCI_LIB_ADDRESS (
123 SMBUS_HOST_BUS,
124 SMBUS_HOST_DEV,
125 SMBUS_HOST_FUNC,
126 SMBUS_HOST_SMB_BASE
127 )
128 );
129 ASSERT ((SmbusBar & 0xffff001f) == 1);
130 return (UINT16)(SmbusBar & ~1);
131 }
132
133 static
134 BOOLEAN
135 EFIAPI
136 SmBusAcquire (
137 IN UINT16 SmBusBase
138 )
139 {
140 UINT8 HstSts;
141
142 HstSts = IoRead8 (SmBusBase + R_HST_STS);
143 if (HstSts & B_HST_STS_INUSE) {
144 return FALSE;
145 }
146
147 //
148 // BUGBUG: Dead loop may occur here
149 //
150 while (HstSts & B_HST_STS_BUSY) {
151 ASSERT (HstSts & B_HST_STS_INUSE);
152 HstSts = IoRead8 (SmBusBase + R_HST_STS);
153 }
154 return TRUE;
155 }
156
157 static
158 VOID
159 EFIAPI
160 SmBusStart (
161 IN UINT16 SmBusBase,
162 IN UINT8 SmBusProtocol,
163 IN UINT8 SlaveAddress
164 )
165 {
166 IoWrite8 (SmBusBase + R_XMIT_SLVA, SlaveAddress);
167 IoWrite8 (
168 SmBusBase + R_HST_CNT,
169 IoBitFieldWrite8 (SmBusBase + R_HST_CNT, 2, 4, SmBusProtocol) |
170 B_HST_CNT_START
171 );
172 }
173
174 static
175 UINT8
176 EFIAPI
177 SmBusWait (
178 IN UINT16 SmBusBase
179 )
180 {
181 UINT8 HstSts;
182
183 while (((HstSts = IoRead8 (SmBusBase + R_HST_STS)) & B_HST_STS_INTR) == 0);
184 return HstSts;
185 }
186
187 static
188 VOID
189 EFIAPI
190 SmBusCleanup (
191 IN UINT16 SmBusBase
192 )
193 {
194 IoWrite8 (SmBusBase + R_HST_STS, B_HST_STS_ALL);
195 }
196
197 static
198 RETURN_STATUS
199 EFIAPI
200 SmBusQuick (
201 IN UINT8 SmBusAddress
202 )
203 {
204 RETURN_STATUS Status;
205 UINT16 SmBusBase;
206
207 SmBusBase = GetSmBusIOBaseAddress ();
208 if (!SmBusAcquire (SmBusBase)) {
209 return RETURN_TIMEOUT;
210 }
211
212 SmBusStart (SmBusAddress, B_SMB_CMD_QUICK, SmBusAddress);
213 if (SmBusWait (SmBusAddress) & B_HST_STS_ERR) {
214 Status = RETURN_DEVICE_ERROR;
215 } else {
216 Status = RETURN_SUCCESS;
217 }
218
219 SmBusCleanup (SmBusAddress);
220 return Status;
221 }
222
223 VOID
224 EFIAPI
225 SmBusQuickRead (
226 IN UINTN SmBusAddress,
227 OUT RETURN_STATUS *Status
228 )
229 {
230 RETURN_STATUS RetStatus;
231
232 ASSERT ((SmBusAddress & ~0xfe) == 0);
233 RetStatus = SmBusQuick ((UINT8)SmBusAddress | B_SMBUS_READ);
234 if (Status) {
235 *Status = RetStatus;
236 }
237 }
238
239 BOOLEAN
240 EFIAPI
241 SmBusQuickWrite (
242 IN UINTN SmBusAddress,
243 OUT RETURN_STATUS *Status
244 )
245 {
246 RETURN_STATUS RetStatus;
247
248 ASSERT ((SmBusAddress & ~0xfe) == 0);
249 RetStatus = SmBusQuick ((UINT8)SmBusAddress | B_SMBUS_WRITE);
250 if (Status) {
251 *Status = RetStatus;
252 }
253 return (BOOLEAN)!RETURN_ERROR (RetStatus);
254 }
255
256 static
257 UINT16
258 EFIAPI
259 SmBusByteWord (
260 IN UINTN SmBusAddress,
261 IN UINT16 Value,
262 IN UINT8 SmBusProtocol,
263 OUT RETURN_STATUS *Status
264 )
265 {
266 RETURN_STATUS RetStatus;
267 UINT16 SmBusBase;
268
269 if (Status == NULL) {
270 Status = &RetStatus;
271 }
272
273 SmBusBase = GetSmBusIOBaseAddress ();
274 if (!SmBusAcquire (SmBusBase)) {
275 *Status = RETURN_TIMEOUT;
276 return Value;
277 }
278
279 IoWrite8 (SmBusBase + R_HST_CMD, (UINT8)(SmBusAddress >> 8));
280 IoWrite8 (SmBusBase + R_HST_D0, (UINT8)Value);
281 IoWrite8 (SmBusBase + R_HST_D1, (UINT8)(Value >> 8));
282 if ((INTN)SmBusAddress < 0) {
283 IoOr8 (SmBusBase + R_HST_CNT, B_HST_CNT_PEC);
284 IoOr8 (SmBusBase + R_AUX_CTL, B_AUX_CTL_AAC);
285 } else {
286 IoAnd8 (SmBusBase + R_HST_CNT, (UINT8)~B_HST_CNT_PEC);
287 IoAnd8 (SmBusBase + R_AUX_CTL, (UINT8)~B_AUX_CTL_AAC);
288 }
289
290 SmBusStart (SmBusBase, SmBusProtocol, (UINT8)SmBusAddress);
291
292 if (SmBusWait (SmBusBase) & B_HST_STS_ERR) {
293 *Status = RETURN_DEVICE_ERROR;
294 } else {
295 *Status = RETURN_SUCCESS;
296 Value = IoRead8 (SmBusBase + R_HST_D0);
297 Value |= (UINT16)IoRead8 (SmBusBase + R_HST_D1) << 8;
298 }
299
300 SmBusCleanup (SmBusBase);
301 return Value;
302 }
303
304 UINT8
305 EFIAPI
306 SmBusReceiveByte (
307 IN UINTN SmBusAddress,
308 OUT RETURN_STATUS *Status
309 )
310 {
311 ASSERT ((SmBusAddress & ~(0xfe | MAX_BIT)) == 0);
312 return (UINT8)SmBusByteWord (
313 SmBusAddress | B_SMBUS_READ,
314 0,
315 B_SMB_CMD_BYTE,
316 Status
317 );
318 }
319
320 UINT8
321 EFIAPI
322 SmBusSendByte (
323 IN UINTN SmBusAddress,
324 IN UINT8 Value,
325 OUT RETURN_STATUS *Status
326 )
327 {
328 ASSERT ((SmBusAddress & ~(0xfe | MAX_BIT)) == 0);
329 return (UINT8)SmBusByteWord (
330 SmBusAddress | B_SMBUS_WRITE,
331 Value,
332 B_SMB_CMD_BYTE,
333 Status
334 );
335 }
336
337 UINT8
338 EFIAPI
339 SmBusReadDataByte (
340 IN UINTN SmBusAddress,
341 OUT RETURN_STATUS *Status
342 )
343 {
344 ASSERT ((SmBusAddress & ~(0xfffe | MAX_BIT)) == 0);
345 return (UINT8)SmBusByteWord (
346 SmBusAddress | B_SMBUS_READ,
347 0,
348 B_SMB_CMD_BYTE_DATA,
349 Status
350 );
351 }
352
353 UINT8
354 EFIAPI
355 SmBusWriteDataByte (
356 IN UINTN SmBusAddress,
357 IN UINT8 Value,
358 OUT RETURN_STATUS *Status
359 )
360 {
361 ASSERT (((UINT32)SmBusAddress & ~(0xfffe | MAX_BIT)) == 0);
362 return (UINT8)SmBusByteWord (
363 SmBusAddress | B_SMBUS_WRITE,
364 Value,
365 B_SMB_CMD_BYTE_DATA,
366 Status
367 );
368 }
369
370 UINT16
371 EFIAPI
372 SmBusReadDataWord (
373 IN UINTN SmBusAddress,
374 OUT RETURN_STATUS *Status
375 )
376 {
377 ASSERT ((SmBusAddress & ~(0xfffe | MAX_BIT)) == 0);
378 return SmBusByteWord (
379 SmBusAddress | B_SMBUS_READ,
380 0,
381 B_SMB_CMD_WORD_DATA,
382 Status
383 );
384 }
385
386 UINT16
387 EFIAPI
388 SmBusWriteDataWord (
389 IN UINTN SmBusAddress,
390 IN UINT16 Value,
391 OUT RETURN_STATUS *Status
392 )
393 {
394 ASSERT ((SmBusAddress & ~(0xfffe | MAX_BIT)) == 0);
395 return SmBusByteWord (
396 SmBusAddress | B_SMBUS_WRITE,
397 Value,
398 B_SMB_CMD_WORD_DATA,
399 Status
400 );
401 }
402
403 UINT16
404 EFIAPI
405 SmBusProcessCall (
406 IN UINTN SmBusAddress,
407 IN UINT16 Value,
408 OUT RETURN_STATUS *Status
409 )
410 {
411 ASSERT ((SmBusAddress & ~(0xfffe | MAX_BIT)) == 0);
412 return SmBusByteWord (
413 SmBusAddress | B_SMBUS_WRITE,
414 Value,
415 B_SMB_CMD_PROCESS_CALL,
416 Status
417 );
418 }
419
420 static
421 UINTN
422 EFIAPI
423 SmBusBlock (
424 IN UINTN SmBusAddress,
425 IN UINT8 SmBusProtocol,
426 IN VOID *InBuffer,
427 OUT VOID *OutBuffer,
428 OUT RETURN_STATUS *Status
429 )
430 {
431 RETURN_STATUS RetStatus;
432 UINT16 SmBusBase;
433 UINTN Index;
434 UINTN BytesCount;
435
436 BytesCount = (UINT8)(SmBusAddress >> 16);
437 ASSERT (BytesCount <= 32);
438
439 if (Status == NULL) {
440 Status = &RetStatus;
441 }
442
443 SmBusBase = GetSmBusIOBaseAddress ();
444 if (!SmBusAcquire (SmBusBase)) {
445 *Status = RETURN_TIMEOUT;
446 return 0;
447 }
448
449 IoWrite8 (SmBusBase + R_HST_CMD, (UINT8)(SmBusAddress >> 8));
450 IoWrite8 (SmBusBase + R_HST_D0, (UINT8)BytesCount);
451 if ((INTN)SmBusAddress < 0) {
452 IoOr8 (SmBusBase + R_HST_CNT, B_HST_CNT_PEC);
453 IoOr8 (SmBusBase + R_AUX_CTL, B_AUX_CTL_AAC);
454 } else {
455 IoAnd8 (SmBusBase + R_HST_CNT, (UINT8)~B_HST_CNT_PEC);
456 IoAnd8 (SmBusBase + R_AUX_CTL, (UINT8)~B_AUX_CTL_AAC);
457 }
458
459 //
460 // BUGBUG: E32B bit does not exist in ICH3 or earlier
461 //
462 IoOr8 (SmBusBase + R_AUX_CTL, B_AUX_CTL_E32B);
463 ASSERT (IoRead8 (SmBusBase + R_AUX_CTL) & B_AUX_CTL_E32B);
464 for (Index = 0; InBuffer != NULL && Index < BytesCount; Index++) {
465 IoWrite8 (SmBusBase + R_HOST_BLOCK_DB, ((UINT8*)InBuffer)[Index]);
466 }
467
468 SmBusStart (SmBusBase, SmBusProtocol, (UINT8)SmBusAddress);
469
470 if (SmBusWait (SmBusBase) & B_HST_STS_ERR) {
471 *Status = RETURN_DEVICE_ERROR;
472 } else {
473 *Status = RETURN_SUCCESS;
474 BytesCount = IoRead8 (SmBusBase + R_HST_D0);
475 for (Index = 0; OutBuffer != NULL && Index < BytesCount; Index++) {
476 ((UINT8*)OutBuffer)[Index] = IoRead8 (SmBusBase + R_HOST_BLOCK_DB);
477 }
478 }
479
480 SmBusCleanup (SmBusBase);
481 return BytesCount;
482 }
483
484 UINTN
485 EFIAPI
486 SmBusReadBlock (
487 IN UINTN SmBusAddress,
488 OUT VOID *Buffer,
489 OUT RETURN_STATUS *Status
490 )
491 {
492 ASSERT ((SmBusAddress & ~(0xfffffe | MAX_BIT)) == 0);
493 return SmBusBlock (
494 SmBusAddress | B_SMBUS_READ,
495 B_SMB_CMD_BLOCK,
496 NULL,
497 Buffer,
498 Status
499 );
500 }
501
502 UINTN
503 EFIAPI
504 SmBusWriteBlock (
505 IN UINTN SmBusAddress,
506 OUT VOID *Buffer,
507 OUT RETURN_STATUS *Status
508 )
509 {
510 ASSERT ((SmBusAddress & ~(0xfffffe | MAX_BIT)) == 0);
511 return SmBusBlock (
512 SmBusAddress | B_SMBUS_WRITE,
513 B_SMB_CMD_BLOCK,
514 Buffer,
515 NULL,
516 Status
517 );
518 }
519
520 UINTN
521 EFIAPI
522 SmBusBlockProcessCall (
523 IN UINTN SmBusAddress,
524 IN VOID *OutBuffer,
525 OUT VOID *InBuffer,
526 OUT RETURN_STATUS *Status
527 )
528 {
529 ASSERT ((SmBusAddress & ~(0xfffffe | MAX_BIT)) == 0);
530 return SmBusBlock (
531 SmBusAddress | B_SMBUS_WRITE,
532 B_SMB_CMD_BLOCK_PROCESS,
533 OutBuffer,
534 InBuffer,
535 Status
536 );
537 }
538
539 RETURN_STATUS
540 EFIAPI
541 SmBusArpAll (
542 IN UINTN SmBusAddress
543 );
544
545 RETURN_STATUS
546 EFIAPI
547 SmBusArpDevice (
548 IN UINTN SmBusAddress,
549 IN CONST GUID *Uuid
550 );
551
552 RETURN_STATUS
553 EFIAPI
554 SmBusGetUuid (
555 IN UINTN SmBusAddress,
556 OUT GUID *Uuid
557 );