blob: 14bec8c3ab137c53b92117e653bc705a1cabbbe2 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Kyösti Mälkkic5cc9f22014-10-17 22:33:22 +03003
Michał Żygowski287ce5f2019-12-01 17:41:23 +01004#include <amdblocks/acpimmio.h>
Kyösti Mälkkic5cc9f22014-10-17 22:33:22 +03005#include <device/pci_def.h>
6#include <device/device.h>
Elyes HAOUAS20eaef02019-03-29 17:45:28 +01007#include <console/console.h>
Kyösti Mälkkic5cc9f22014-10-17 22:33:22 +03008/* warning: Porting.h includes an open #pragma pack(1) */
Elyes HAOUAS19f5ba82018-10-14 14:52:06 +02009#include <Porting.h>
10#include <AGESA.h>
11#include <amdlib.h>
Kyösti Mälkkic5cc9f22014-10-17 22:33:22 +030012#include <northbridge/amd/agesa/dimmSpd.h>
13
14/*-----------------------------------------------------------------------------
15 *
16 * readSmbusByteData - read a single SPD byte from any offset
17 */
18
19static int readSmbusByteData (int iobase, int address, char *buffer, int offset)
20{
21 unsigned int status;
22 UINT64 limit;
23
24 address |= 1; // set read bit
25
26 __outbyte (iobase + 0, 0xFF); // clear error status
27 __outbyte (iobase + 1, 0x1F); // clear error status
28 __outbyte (iobase + 3, offset); // offset in eeprom
29 __outbyte (iobase + 4, address); // slave address and read bit
30 __outbyte (iobase + 2, 0x48); // read byte command
31
32 // time limit to avoid hanging for unexpected error status (should never happen)
33 limit = __rdtsc () + 2000000000 / 10;
34 for (;;)
35 {
36 status = __inbyte (iobase);
37 if (__rdtsc () > limit) break;
38 if ((status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
39 if ((status & 1) == 1) continue; // HostBusy set, keep waiting
40 break;
41 }
42
43 buffer [0] = __inbyte (iobase + 5);
44 if (status == 2) status = 0; // check for done with no errors
45 return status;
46}
47
48/*-----------------------------------------------------------------------------
49 *
50 * readSmbusByte - read a single SPD byte from the default offset
51 * this function is faster function readSmbusByteData
52 */
53
54static int readSmbusByte (int iobase, int address, char *buffer)
55{
56 unsigned int status;
57 UINT64 limit;
58
59 __outbyte (iobase + 0, 0xFF); // clear error status
60 __outbyte (iobase + 2, 0x44); // read command
61
62 // time limit to avoid hanging for unexpected error status
63 limit = __rdtsc () + 2000000000 / 10;
64 for (;;)
65 {
66 status = __inbyte (iobase);
67 if (__rdtsc () > limit) break;
68 if ((status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
69 if ((status & 1) == 1) continue; // HostBusy set, keep waiting
70 break;
71 }
72
73 buffer [0] = __inbyte (iobase + 5);
74 if (status == 2) status = 0; // check for done with no errors
75 return status;
76}
77
78/*---------------------------------------------------------------------------
79 *
80 * readspd - Read one or more SPD bytes from a DIMM.
81 * Start with offset zero and read sequentially.
82 * Optimization relies on autoincrement to avoid
83 * sending offset for every byte.
84 * Reads 128 bytes in 7-8 ms at 400 KHz.
85 */
86
87static int readspd (int iobase, int SmbusSlaveAddress, char *buffer, int count)
88{
89 int index, error;
90
91 printk(BIOS_SPEW, "-------------READING SPD-----------\n");
92 printk(BIOS_SPEW, "iobase: 0x%08X, SmbusSlave: 0x%08X, count: %d\n",
93 iobase, SmbusSlaveAddress, count);
94
95 /* read the first byte using offset zero */
96 error = readSmbusByteData (iobase, SmbusSlaveAddress, buffer, 0);
97
98 if (error) {
99 printk(BIOS_ERR, "-------------SPD READ ERROR-----------\n");
100 return error;
101 }
102
103 /* read the remaining bytes using auto-increment for speed */
104 for (index = 1; index < count; index++)
105 {
106 error = readSmbusByte (iobase, SmbusSlaveAddress, &buffer [index]);
107 if (error) {
108 printk(BIOS_ERR, "-------------SPD READ ERROR-----------\n");
109 return error;
110 }
111 }
112 printk(BIOS_SPEW, "\n");
113 printk(BIOS_SPEW, "-------------FINISHED READING SPD-----------\n");
114
115 return 0;
116}
117
Kyösti Mälkkic5cc9f22014-10-17 22:33:22 +0300118static void setupFch (int ioBase)
119{
Michał Żygowski287ce5f2019-12-01 17:41:23 +0100120 pm_write16(0x2c, ioBase | 1);
Kyösti Mälkkic5cc9f22014-10-17 22:33:22 +0300121 __outbyte (ioBase + 0x0E, 66000000 / 400000 / 4); // set SMBus clock to 400 KHz
122}
123
124int hudson_readSpd(int spdAddress, char *buf, size_t len)
125{
126 int ioBase = 0xB00;
127 setupFch (ioBase);
128 return readspd (ioBase, spdAddress, buf, len);
129}