Rename almost all occurences of LinuxBIOS to coreboot.
[coreboot.git] / src / northbridge / amd / amdht / comlib.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2007 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 #undef FILECODE
21 #define FILECODE 0xCCCC
22 #include "comlib.h"
23
24 /*
25  *---------------------------------------------------------------------------
26  * EXPORTED FUNCTIONS
27  *
28  *---------------------------------------------------------------------------
29  */
30
31 void CALLCONV AmdPCIReadBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
32 {
33         ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0);
34
35         AmdPCIRead(loc, pValue);
36         *pValue = *pValue >> lowbit;  /* Shift */
37
38         /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
39         if ((highbit-lowbit) != 31)
40                 *pValue &= (((u32)1 << (highbit-lowbit+1))-1);
41 }
42
43
44 void CALLCONV AmdPCIWriteBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
45 {
46         u32 temp, mask;
47
48         ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0);
49
50         /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
51         if ((highbit-lowbit) != 31)
52                 mask = (((u32)1 << (highbit-lowbit+1))-1);
53         else
54                 mask = (u32)0xFFFFFFFF;
55
56         AmdPCIRead(loc, &temp);
57         temp &= ~(mask << lowbit);
58         temp |= (*pValue & mask) << lowbit;
59         AmdPCIWrite(loc, &temp);
60 }
61
62
63 /*
64  *  Given a SBDFO this routine will find the next PCI capabilities list entry.
65  *   If the end of the list of reached, or if a problem is detected, then
66  *   ILLEGAL_SBDFO is returned.
67  *
68  *   To start a new search from the beginning of head of the list, specify a
69  *   SBDFO with a offset of zero.
70  */
71 void CALLCONV AmdPCIFindNextCap(SBDFO *pCurrent)
72 {
73         SBDFO base;
74         u32 offset;
75         u32 temp;
76
77         if (*pCurrent == ILLEGAL_SBDFO)
78                 return;
79
80         offset = SBDFO_OFF(*pCurrent);
81         base = *pCurrent - offset;
82         *pCurrent = ILLEGAL_SBDFO;
83
84         /* Verify that the SBDFO points to a valid PCI device SANITY CHECK */
85         AmdPCIRead(base, &temp);
86         if (temp == 0xFFFFFFFF)
87                 return; /* There is no device at this address */
88
89         /* Verify that the device supports a capability list */
90         AmdPCIReadBits(base + 0x04, 20, 20, &temp);
91         if (temp == 0)
92                 return; /* This PCI device does not support capability lists */
93
94         if (offset != 0)
95         {
96                 /* If we are continuing on an existing list */
97                 AmdPCIReadBits(base + offset, 15, 8, &temp);
98         }
99         else
100         {
101                 /* We are starting on a new list */
102                 AmdPCIReadBits(base + 0x34, 7, 0, &temp);
103         }
104
105         if (temp == 0)
106                 return; /* We have reached the end of the capabilties list */
107
108         /* Error detection and recovery- The statement below protects against
109                 PCI devices with broken PCI capabilities lists.  Detect a pointer
110                 that is not u32 aligned, points into the first 64 reserved DWORDs
111                 or points back to itself.
112         */
113         if (((temp & 3) != 0) || (temp == offset) || (temp < 0x40))
114                 return;
115
116         *pCurrent = base + temp;
117         return;
118 }
119
120
121 void CALLCONV Amdmemcpy(void *pDst, const void *pSrc, u32 length)
122 {
123         ASSERT(length <= 32768);
124         ASSERT(pDst != NULL);
125         ASSERT(pSrc != NULL);
126
127         while (length--){
128         //      *(((u8*)pDst)++) = *(((u8*)pSrc)++);
129                 *((u8*)pDst) = *((u8*)pSrc);
130                 pDst++;
131                 pSrc++;
132         }
133 }
134
135
136 void CALLCONV Amdmemset(void *pBuf, u8 val, u32 length)
137 {
138         ASSERT(length <= 32768);
139         ASSERT(pBuf != NULL);
140
141         while (length--){
142                 //*(((u8*)pBuf)++) = val;
143                 *(((u8*)pBuf)) = val;
144                 pBuf++;
145         }
146 }
147
148
149 u8 CALLCONV AmdBitScanReverse(u32 value)
150 {
151         u8 i;
152
153         for (i = 31; i != 0xFF; i--)
154         {
155                 if (value & ((u32)1 << i))
156                         break;
157         }
158
159         return i;
160 }
161
162
163 u32 CALLCONV AmdRotateRight(u32 value, u8 size, u32 count)
164 {
165         u32 msb, mask;
166         ASSERT(size > 0 && size <= 32);
167
168         msb = (u32)1 << (size-1);
169         mask = ((msb-1) << 1) + 1;
170
171         value = value & mask;
172
173         while (count--)
174         {
175                 if (value & 1)
176                         value = (value >> 1) | msb;
177                 else
178                         value = value >> 1;
179         }
180
181         return value;
182 }
183
184
185 u32 CALLCONV AmdRotateLeft(u32 value, u8 size, u32 count)
186 {
187         u32 msb, mask;
188         ASSERT(size > 0 && size <= 32);
189
190         msb = (u32)1 << (size-1);
191         mask = ((msb-1) << 1) + 1;
192
193         value = value & mask;
194
195         while (count--)
196         {
197                 if (value & msb)
198                         value = ((value << 1) & mask) | (u32)1;
199                 else
200                         value = ((value << 1) & mask);
201         }
202
203         return value;
204 }
205
206
207 void CALLCONV AmdPCIRead(SBDFO loc, u32 *Value)
208 {
209         /* Use coreboot PCI functions */
210         *Value = pci_read_config32((loc & 0xFFFFF000), SBDFO_OFF(loc));
211 }
212
213
214 void CALLCONV AmdPCIWrite(SBDFO loc, u32 *Value)
215 {
216         /* Use coreboot PCI functions */
217         pci_write_config32((loc & 0xFFFFF000), SBDFO_OFF(loc), *Value);
218 }
219
220
221 void CALLCONV AmdMSRRead(uint32 Address, uint64 *Value)
222 {
223         msr_t msr;
224
225         msr = rdmsr(Address);
226         Value->lo = msr.lo;
227         Value->hi = msr.hi;
228 }
229
230
231 void CALLCONV AmdMSRWrite(uint32 Address, uint64 *Value)
232 {
233         msr_t msr;
234
235         msr.lo = Value->lo;
236         msr.hi = Value->hi;
237         wrmsr(Address, msr);
238 }
239
240
241 void ErrorStop(u32 value)
242 {
243         printk_debug("Error: %08x ", value);
244
245 }
246
247 /*;----------------------------------------------------------------------------
248 ; void __pascal ErrorStop(DWORD Value);
249 ;
250 ; This implementation provides a rotating display of the error code on the
251 ; a port 80h POST display card.  The rotation is used to make it easier to
252 ; view the error on both a 16-bit as well as a 32-bit display card.
253 ;
254 ; For use with SimNow the unrotated error code is also written to port 84h
255 ErrorStop   PROC FAR PASCAL PUBLIC Value:DWORD
256         pushad
257         mov     eax, Value
258         mov     bx, 0DEADh
259         out     84h, eax
260
261 ErrorStopTop:
262         out     80h, eax
263
264         mov     cx, 4           ; Rotate the display by one nibble
265 @@:
266         bt      bx, 15
267         rcl     eax, 1
268         rcl     bx, 1
269         loop    @B
270
271
272         push    eax             ; Delay a few hundred milliseconds
273         push    ebx
274         mov     ecx, 10h        ; TSC
275         db      00Fh, 032h      ; RDMSR
276         mov     ebx, eax
277 @@:
278         db      00Fh, 032h      ; RDMSR
279         sub     eax, ebx
280         cmp     eax, 500000000
281         jb      @B
282         pop     ebx
283         pop     eax
284
285         jmp     ErrorStopTop
286
287         popad
288         ret
289 ErrorStop   ENDP
290 */