blob: 32e00d6ea611f6ba2ef9b8c9b8390880bab27848 [file] [log] [blame]
Kyösti Mälkkic5cc9f22014-10-17 22:33:22 +03001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <device/pci_def.h>
21#include <device/device.h>
22
23/* warning: Porting.h includes an open #pragma pack(1) */
24#include "Porting.h"
25#include "AGESA.h"
26#include "amdlib.h"
27
28#include <northbridge/amd/agesa/dimmSpd.h>
29
30/*-----------------------------------------------------------------------------
31 *
32 * readSmbusByteData - read a single SPD byte from any offset
33 */
34
35static int readSmbusByteData (int iobase, int address, char *buffer, int offset)
36{
37 unsigned int status;
38 UINT64 limit;
39
40 address |= 1; // set read bit
41
42 __outbyte (iobase + 0, 0xFF); // clear error status
43 __outbyte (iobase + 1, 0x1F); // clear error status
44 __outbyte (iobase + 3, offset); // offset in eeprom
45 __outbyte (iobase + 4, address); // slave address and read bit
46 __outbyte (iobase + 2, 0x48); // read byte command
47
48 // time limit to avoid hanging for unexpected error status (should never happen)
49 limit = __rdtsc () + 2000000000 / 10;
50 for (;;)
51 {
52 status = __inbyte (iobase);
53 if (__rdtsc () > limit) break;
54 if ((status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
55 if ((status & 1) == 1) continue; // HostBusy set, keep waiting
56 break;
57 }
58
59 buffer [0] = __inbyte (iobase + 5);
60 if (status == 2) status = 0; // check for done with no errors
61 return status;
62}
63
64/*-----------------------------------------------------------------------------
65 *
66 * readSmbusByte - read a single SPD byte from the default offset
67 * this function is faster function readSmbusByteData
68 */
69
70static int readSmbusByte (int iobase, int address, char *buffer)
71{
72 unsigned int status;
73 UINT64 limit;
74
75 __outbyte (iobase + 0, 0xFF); // clear error status
76 __outbyte (iobase + 2, 0x44); // read command
77
78 // time limit to avoid hanging for unexpected error status
79 limit = __rdtsc () + 2000000000 / 10;
80 for (;;)
81 {
82 status = __inbyte (iobase);
83 if (__rdtsc () > limit) break;
84 if ((status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
85 if ((status & 1) == 1) continue; // HostBusy set, keep waiting
86 break;
87 }
88
89 buffer [0] = __inbyte (iobase + 5);
90 if (status == 2) status = 0; // check for done with no errors
91 return status;
92}
93
94/*---------------------------------------------------------------------------
95 *
96 * readspd - Read one or more SPD bytes from a DIMM.
97 * Start with offset zero and read sequentially.
98 * Optimization relies on autoincrement to avoid
99 * sending offset for every byte.
100 * Reads 128 bytes in 7-8 ms at 400 KHz.
101 */
102
103static int readspd (int iobase, int SmbusSlaveAddress, char *buffer, int count)
104{
105 int index, error;
106
107 printk(BIOS_SPEW, "-------------READING SPD-----------\n");
108 printk(BIOS_SPEW, "iobase: 0x%08X, SmbusSlave: 0x%08X, count: %d\n",
109 iobase, SmbusSlaveAddress, count);
110
111 /* read the first byte using offset zero */
112 error = readSmbusByteData (iobase, SmbusSlaveAddress, buffer, 0);
113
114 if (error) {
115 printk(BIOS_ERR, "-------------SPD READ ERROR-----------\n");
116 return error;
117 }
118
119 /* read the remaining bytes using auto-increment for speed */
120 for (index = 1; index < count; index++)
121 {
122 error = readSmbusByte (iobase, SmbusSlaveAddress, &buffer [index]);
123 if (error) {
124 printk(BIOS_ERR, "-------------SPD READ ERROR-----------\n");
125 return error;
126 }
127 }
128 printk(BIOS_SPEW, "\n");
129 printk(BIOS_SPEW, "-------------FINISHED READING SPD-----------\n");
130
131 return 0;
132}
133
134static void writePmReg (int reg, int data)
135{
136 __outbyte (0xCD6, reg);
137 __outbyte (0xCD7, data);
138}
139
140static void setupFch (int ioBase)
141{
142 writePmReg (0x2D, ioBase >> 8);
143 writePmReg (0x2C, ioBase | 1);
144 __outbyte (ioBase + 0x0E, 66000000 / 400000 / 4); // set SMBus clock to 400 KHz
145}
146
147int hudson_readSpd(int spdAddress, char *buf, size_t len)
148{
149 int ioBase = 0xB00;
150 setupFch (ioBase);
151 return readspd (ioBase, spdAddress, buf, len);
152}