| /* |
| * 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 |
| */ |