blob: c5a27a2dc02dc0cfe76c69cfbe30c2eb55f3faac [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#undef FILECODE
#define FILECODE 0xCCCC
#include "comlib.h"
/*
*---------------------------------------------------------------------------
* EXPORTED FUNCTIONS
*
*---------------------------------------------------------------------------
*/
void CALLCONV AmdPCIReadBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
{
ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0);
AmdPCIRead(loc, pValue);
*pValue = *pValue >> lowbit; /* Shift */
/* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
if ((highbit-lowbit) != 31)
*pValue &= (((u32)1 << (highbit-lowbit+1))-1);
}
void CALLCONV AmdPCIWriteBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
{
u32 temp, mask;
ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0);
/* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
if ((highbit-lowbit) != 31)
mask = (((u32)1 << (highbit-lowbit+1))-1);
else
mask = (u32)0xFFFFFFFF;
AmdPCIRead(loc, &temp);
temp &= ~(mask << lowbit);
temp |= (*pValue & mask) << lowbit;
AmdPCIWrite(loc, &temp);
}
/*
* Given a SBDFO this routine will find the next PCI capabilities list entry.
* If the end of the list of reached, or if a problem is detected, then
* ILLEGAL_SBDFO is returned.
*
* To start a new search from the beginning of head of the list, specify a
* SBDFO with a offset of zero.
*/
void CALLCONV AmdPCIFindNextCap(SBDFO *pCurrent)
{
SBDFO base;
u32 offset;
u32 temp;
if (*pCurrent == ILLEGAL_SBDFO)
return;
offset = SBDFO_OFF(*pCurrent);
base = *pCurrent - offset;
*pCurrent = ILLEGAL_SBDFO;
/* Verify that the SBDFO points to a valid PCI device SANITY CHECK */
AmdPCIRead(base, &temp);
if (temp == 0xFFFFFFFF)
return; /* There is no device at this address */
/* Verify that the device supports a capability list */
AmdPCIReadBits(base + 0x04, 20, 20, &temp);
if (temp == 0)
return; /* This PCI device does not support capability lists */
if (offset != 0)
{
/* If we are continuing on an existing list */
AmdPCIReadBits(base + offset, 15, 8, &temp);
}
else
{
/* We are starting on a new list */
AmdPCIReadBits(base + 0x34, 7, 0, &temp);
}
if (temp == 0)
return; /* We have reached the end of the capabilties list */
/* Error detection and recovery- The statement below protects against
PCI devices with broken PCI capabilities lists. Detect a pointer
that is not u32 aligned, points into the first 64 reserved DWORDs
or points back to itself.
*/
if (((temp & 3) != 0) || (temp == offset) || (temp < 0x40))
return;
*pCurrent = base + temp;
return;
}
void CALLCONV Amdmemcpy(void *pDst, const void *pSrc, u32 length)
{
ASSERT(length <= 32768);
ASSERT(pDst != NULL);
ASSERT(pSrc != NULL);
while (length--){
// *(((u8*)pDst)++) = *(((u8*)pSrc)++);
*((u8*)pDst) = *((u8*)pSrc);
pDst++;
pSrc++;
}
}
void CALLCONV Amdmemset(void *pBuf, u8 val, u32 length)
{
ASSERT(length <= 32768);
ASSERT(pBuf != NULL);
while (length--){
//*(((u8*)pBuf)++) = val;
*(((u8*)pBuf)) = val;
pBuf++;
}
}
u8 CALLCONV AmdBitScanReverse(u32 value)
{
u8 i;
for (i = 31; i != 0xFF; i--)
{
if (value & ((u32)1 << i))
break;
}
return i;
}
u32 CALLCONV AmdRotateRight(u32 value, u8 size, u32 count)
{
u32 msb, mask;
ASSERT(size > 0 && size <= 32);
msb = (u32)1 << (size-1);
mask = ((msb-1) << 1) + 1;
value = value & mask;
while (count--)
{
if (value & 1)
value = (value >> 1) | msb;
else
value = value >> 1;
}
return value;
}
u32 CALLCONV AmdRotateLeft(u32 value, u8 size, u32 count)
{
u32 msb, mask;
ASSERT(size > 0 && size <= 32);
msb = (u32)1 << (size-1);
mask = ((msb-1) << 1) + 1;
value = value & mask;
while (count--)
{
if (value & msb)
value = ((value << 1) & mask) | (u32)1;
else
value = ((value << 1) & mask);
}
return value;
}
void CALLCONV AmdPCIRead(SBDFO loc, u32 *Value)
{
/* Use coreboot PCI functions */
*Value = pci_read_config32((loc & 0xFFFFF000), SBDFO_OFF(loc));
}
void CALLCONV AmdPCIWrite(SBDFO loc, u32 *Value)
{
/* Use coreboot PCI functions */
pci_write_config32((loc & 0xFFFFF000), SBDFO_OFF(loc), *Value);
}
void CALLCONV AmdMSRRead(uint32 Address, uint64 *Value)
{
msr_t msr;
msr = rdmsr(Address);
Value->lo = msr.lo;
Value->hi = msr.hi;
}
void CALLCONV AmdMSRWrite(uint32 Address, uint64 *Value)
{
msr_t msr;
msr.lo = Value->lo;
msr.hi = Value->hi;
wrmsr(Address, msr);
}
void ErrorStop(u32 value)
{
printk(BIOS_DEBUG, "Error: %08x ", value);
}
/*;----------------------------------------------------------------------------
; void __pascal ErrorStop(DWORD Value);
;
; This implementation provides a rotating display of the error code on the
; a port 80h POST display card. The rotation is used to make it easier to
; view the error on both a 16-bit as well as a 32-bit display card.
;
; For use with SimNow the unrotated error code is also written to port 84h
ErrorStop PROC FAR PASCAL PUBLIC Value:DWORD
pushad
mov eax, Value
mov bx, 0DEADh
out 84h, eax
ErrorStopTop:
out 80h, eax
mov cx, 4 ; Rotate the display by one nibble
@@:
bt bx, 15
rcl eax, 1
rcl bx, 1
loop @B
push eax ; Delay a few hundred milliseconds
push ebx
mov ecx, 10h ; TSC
db 00Fh, 032h ; RDMSR
mov ebx, eax
@@:
db 00Fh, 032h ; RDMSR
sub eax, ebx
cmp eax, 500000000
jb @B
pop ebx
pop eax
jmp ErrorStopTop
popad
ret
ErrorStop ENDP
*/