remove trailing whitespace
[coreboot.git] / src / mainboard / supermicro / h8qgi / dimmSpd.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2011 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 "Porting.h"
21 #include "AGESA.h"
22 #include "amdlib.h"
23 #include <arch/io.h>
24 #include <arch/romcc_io.h>
25 #include <device/pci_ids.h>
26
27 AGESA_STATUS AmdMemoryReadSPD (UINT32 unused1, UINT32 unused2, AGESA_READ_SPD_PARAMS *info);
28 #define DIMENSION(array)(sizeof (array)/ sizeof (array [0]))
29
30 /* SP5100 GPIO 53-56 contoled by SMBUS PCI_Reg 0x52 */
31 #define SP5100_GPIO53_56        0x52
32
33 /**
34  * TODO not support all GPIO yet
35  * @param reg -GPIO Cntrl Register
36  * @param out -GPIO bitmap
37  * @param out -GPIO enable bitmap
38  */
39 static void sp5100_set_gpio(u8 reg, u8 out, u8 enable)
40 {
41         u8 value;
42         device_t sm_dev = PCI_DEV(0, 0x14, 0); //SMBUS
43
44         value = pci_read_config8(sm_dev, reg);
45         value &= ~(enable);
46         value |= out;
47         value &= ~(enable << 4);
48         pci_write_config8(sm_dev, reg, value);
49 }
50
51 /*-----------------------------------------------------------------------------
52  *
53  * SPD address table - porting required
54  */
55 static const UINT8 spdAddressLookup [8] [4] [2] = { // socket, channel, dimm
56         /* socket 0 */
57         {
58                 {0xAE, 0xAC},
59                 {0xAA, 0xA8},
60                 {0xA6, 0xA4},
61                 {0xA2, 0xA0},
62         },
63         /* socket 1 */
64         {
65                 {0xAE, 0xAC},
66                 {0xAA, 0xA8},
67                 {0xA6, 0xA4},
68                 {0xA2, 0xA0},
69         },
70         /* socket 2 */
71         {
72                 {0xAE, 0xAC},
73                 {0xAA, 0xA8},
74                 {0xA6, 0xA4},
75                 {0xA2, 0xA0},
76         },
77         /* socket 3 */
78         {
79                 {0xAE, 0xAC},
80                 {0xAA, 0xA8},
81                 {0xA6, 0xA4},
82                 {0xA2, 0xA0},
83         },
84 };
85
86 /*-----------------------------------------------------------------------------
87  *
88  * readSmbusByteData - read a single SPD byte from any offset
89  */
90
91 static int readSmbusByteData (int iobase, int address, char *buffer, int offset)
92 {
93         unsigned int status;
94         UINT64 limit;
95
96         address |= 1; // set read bit
97
98         outb(0xFF, iobase + 0);                // clear error status
99         outb(0x1F, iobase + 1);                // clear error status
100         outb(offset, iobase + 3);              // offset in eeprom
101         outb(address, iobase + 4);             // slave address and read bit
102         outb(0x48, iobase + 2);                // read byte command
103
104         // time limit to avoid hanging for unexpected error status (should never happen)
105         limit = __rdtsc () + 2000000000 / 10;
106         for (;;)
107         {
108                 status = inb(iobase);
109                 if (__rdtsc () > limit) break;
110                 if ((status & 2) == 0) continue;               // SMBusInterrupt not set, keep waiting
111                 if ((status & 1) == 1) continue;               // HostBusy set, keep waiting
112                 break;
113         }
114
115         buffer [0] = inb(iobase + 5);
116         if (status == 2) status = 0;                      // check for done with no errors
117         return status;
118 }
119
120 /*-----------------------------------------------------------------------------
121  *
122  * readSmbusByte - read a single SPD byte from the default offset
123  *                 this function is faster function readSmbusByteData
124  */
125
126 static int readSmbusByte (int iobase, int address, char *buffer)
127 {
128         unsigned int status;
129         UINT64 limit;
130
131         outb(0xFF, iobase + 0);                // clear error status
132         outb(0x44, iobase + 2);                // read command
133
134         // time limit to avoid hanging for unexpected error status
135         limit = __rdtsc () + 2000000000 / 10;
136         for (;;)
137         {
138                 status = inb(iobase);
139                 if (__rdtsc () > limit) break;
140                 if ((status & 2) == 0) continue;               // SMBusInterrupt not set, keep waiting
141                 if ((status & 1) == 1) continue;               // HostBusy set, keep waiting
142                 break;
143         }
144
145         buffer [0] = inb(iobase + 5);
146         if (status == 2) status = 0;                      // check for done with no errors
147         return status;
148 }
149
150 /*---------------------------------------------------------------------------
151  *
152  * readspd - Read one or more SPD bytes from a DIMM.
153  *           Start with offset zero and read sequentially.
154  *           Optimization relies on autoincrement to avoid
155  *           sending offset for every byte.
156  *          Reads 128 bytes in 7-8 ms at 400 KHz.
157  */
158
159 static int readspd (int iobase, int SmbusSlaveAddress, char *buffer, int count)
160 {
161         int index, error;
162
163         /* read the first byte using offset zero */
164         error = readSmbusByteData (iobase, SmbusSlaveAddress, buffer, 0);
165         if (error) {
166                 return error;
167         }
168
169         /* read the remaining bytes using auto-increment for speed */
170         for (index = 1; index < count; index++)
171         {
172                 error = readSmbusByte (iobase, SmbusSlaveAddress, buffer + index);
173                 if (error)
174                         return error;
175         }
176
177         return 0;
178 }
179
180 static void writePmReg (int reg, int data)
181 {
182         outb(reg, 0xCD6);
183         outb(data, 0xCD7);
184 }
185
186 static void setupFch (int ioBase)
187 {
188         writePmReg (0x2D, ioBase >> 8);
189         writePmReg (0x2C, ioBase | 1);
190         writePmReg (0x29, 0x80);
191         writePmReg (0x28, 0x61);
192         outb(66000000 / 400000 / 4, ioBase + 0x0E); // set SMBus clock to 400 KHz
193 }
194
195 AGESA_STATUS AmdMemoryReadSPD (UINT32 unused1, UINT32 unused2, AGESA_READ_SPD_PARAMS *info)
196 {
197         int spdAddress, ioBase;
198         u8 i2c_channel;
199         device_t sm_dev;
200
201         if (info->SocketId     >= DIMENSION (spdAddressLookup      )) return AGESA_ERROR;
202         if (info->MemChannelId >= DIMENSION (spdAddressLookup[0]   )) return AGESA_ERROR;
203         if (info->DimmId       >= DIMENSION (spdAddressLookup[0][0])) return AGESA_ERROR;
204         i2c_channel = (UINT8) info->SocketId;
205
206         /* set ght i2c channel
207          * GPIO54,53 control the HC4052 S1,S0
208          *  S1 S0 true table
209          *   0  0   channel 1 (Socket1)
210          *   0  1   channel 2 (Socket2)
211          *   1  0   channel 3 (Socket3)
212          *   1  1   channel 4 (Socket4)
213          */
214         sp5100_set_gpio(SP5100_GPIO53_56, i2c_channel, 0x03);
215
216         spdAddress = spdAddressLookup [info->SocketId] [info->MemChannelId] [info->DimmId];
217         if (spdAddress == 0)
218                 return AGESA_ERROR;
219
220         /*
221          * SMBus Base Address was set during southbridge early setup.
222          * e.g. sb700 IO mapped SMBUS_IO_BASE 0x6000
223          */
224         sm_dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SB700_SM), 0);
225         ioBase = pci_read_config32(sm_dev, 0x90) & (0xFFFFFFF0);
226         setupFch(ioBase);
227
228         return readspd(ioBase, spdAddress, (void *)info->Buffer, 256);
229 }