Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / include / pci_bridge.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: pci_bridge.h
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named 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 work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
#ifndef __PCI_BRIDGE_H__
#define __PCI_BRIDGE_H__
// this file contains register definitions of some
// registers found in type 1 header of pci/pcie bridge.
#include "pci_common.h"
#define swap_hword(value) \
((uint32_t)(((value) & 0xff) << 8 | (value) >> 8))
#define swap_word(value) \
((uint32_t)((Word)swap_hword((HWord)((value) & 0xffff)) << 16 | \
(Word)swap_hword((HWord)((value) >> 16))))
#define swap_lword(value) \
((uint64_t)((((LWord)swap_word(LO_W(value))) << 32) | \
((LWord)swap_word(HI_W(value)))))
// some macros originally defined in pcie-pci bridge code
#define GET_IO_BASE(cfg_space) ( (cfg_space->readConf(PCI_BCNF_IO_BASE_HI) << 16) | \
(cfg_space->readConf(PCI_BCNF_IO_BASE_LOW) >> 4 << 12))
#define GET_IO_LIMIT(cfg_space) ( (cfg_space->readConf(PCI_BCNF_IO_LIMIT_HI) << 16) | \
((cfg_space->readConf(PCI_BCNF_IO_LIMIT_LOW) >> 4 << 12) | 0xfff))
#define GET_PF_MEM_BASE(cfg_space) ((uint64_t)cfg_space->readConf(PCI_BCNF_PF_BASE_HIGH) << 32) | \
(cfg_space->readConf(PCI_BCNF_PF_BASE_LOW) >> 4 << 20)
#define GET_PF_MEM_LIMIT(cfg_space) ((( (uint64_t)cfg_space->readConf(PCI_BCNF_PF_LIMIT_HIGH) << 32) | \
(cfg_space->readConf(PCI_BCNF_PF_LIMIT_LOW) >> 4 << 20)) | 0xfffff)
#define GET_MEM_BASE(cfg_space) cfg_space->readConf(PCI_BCNF_MEM_BASE) >> 4 << 20
#define GET_MEM_LIMIT(cfg_space) ((cfg_space->readConf(PCI_BCNF_MEM_LIMIT) >> 4 << 20) | 0xfffff)
class bridgeCommandReg:public pciConfReg{
private:
enum commandRegBits {IO_SPACE = 0, MEM_SPACE = 1, BUS_MASTER = 2};
enum space_type {IO = 0, MEM = 1, PREFETCH_MEM = 2};
bool io_enabled, mem_enabled;
void enable_io() {io_enabled = true;}
void enable_mem() {mem_enabled = true;}
void disable_io() {io_enabled = false;}
void disable_mem() {mem_enabled = false;}
void check_map(space_type spt, uint64_t base, uint64_t limit, bool isMap) {
if (base >= limit)
return;
if(debug_level >= 2)
fprintf(stderr, "%s: %s %llx %llx\n", isMap ? "Map" : "Unmap",
spt == IO ? "PCIE IO" :
(spt == MEM ? "PCIE MEM" : "PCIE PREFETCHABLE MEM"), base, limit);
if (spt == IO) {
if (isMap)
assert(((genericPcieDev*)data)->mapSpace(PCIE_IO, base, limit - base + 1));
else
assert(((genericPcieDev*)data)->unmapSpace(PCIE_IO, base));
} else {
if (isMap)
assert(((genericPcieDev*)data)->mapSpace(PCIE_MEM, base, limit - base + 1));
else
assert(((genericPcieDev*)data)->unmapSpace(PCIE_MEM, base));
}
if (!isMap) {
base = 0;
limit = 0;
}
}
void mapSpace(pcie_space spc, bool isMap){
uint64_t base, limit, up_base, up_limit;
if (spc == PCIE_IO) {
base = GET_IO_BASE(((genericPcieDev*)data)->confSpace);
limit = GET_IO_LIMIT(((genericPcieDev*)data)->confSpace);
check_map(IO, base, limit, isMap);
} else {
base = GET_PF_MEM_BASE(((genericPcieDev*)data)->confSpace);
limit = GET_PF_MEM_LIMIT(((genericPcieDev*)data)->confSpace);
check_map(PREFETCH_MEM, base, limit, isMap);
base = GET_MEM_BASE(((genericPcieDev*)data)->confSpace);
limit = GET_MEM_LIMIT(((genericPcieDev*)data)->confSpace);
check_map(MEM, base, limit, isMap);
}
}
public:
bridgeCommandReg(const char * name, genericPcieDev * d, uint16_t write_mask,uint16_t val=0):pciConfReg(name,2,val,write_mask & 0x547, (void *)d)
{
if(!d){
printf("Bridge command reg constructor error: must provide genericPcieDev device pointer\n");
exit(-1);
}
io_enabled = mem_enabled = false;
}
bool io_mapped() {return io_enabled;}
bool mem_mapped() {return mem_enabled;}
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write) {
assert(!byte_offset);
uint8_t ret;
if(bytes_to_write <= 2)
ret = bytes_to_write;
else
ret = 2;
buf &= ~((int32_t)-1 << (ret << 3));
uint32_t new_val = val | (mask & buf);
uint32_t changed_bits = new_val ^ val;
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,val,new_val);
val = new_val;
if(changed_bits & 1 << IO_SPACE){ //I/O space map bit has changed
if(val & 1 << IO_SPACE) { //bit set to 1
assert(!io_mapped());
mapSpace(PCIE_IO, true);
enable_io();
} else if (io_mapped()) { //bit set to 0
mapSpace(PCIE_IO, false);
disable_io();
}
}
if(changed_bits & 1 << MEM_SPACE){
if(val & 1 << MEM_SPACE){ //bit set to 1
assert(!mem_mapped());
mapSpace(PCIE_MEM, true);
enable_mem();
}else if (mem_mapped()) {
mapSpace(PCIE_MEM, false);
disable_mem();
}
}
return ret;
}
};
class pciSecondaryStatusReg:public pciConfReg{
public:
enum{
MHZ_CAPABLE_66 = 5,
FAST_BACKTO_BACK = 7,
MASTER_DATA_PARITY_ERR = 8,
DEVSEL_TIMING_LBP = 9,
DEVSEL_TIMING_RBP = 10,
SIGNALED_TARGET_ABORT = 11,
RECVD_TARGET_ABORT = 12,
RECVD_MASTER_ABORT = 13,
RECEIVD_SYSTEM_ERR = 14,
DETECTED_PARITY_ERR = 15
};
enum{
FAST_DEVSEL_TIMING = 0,
MEDIUM_DEVSEL_TIMING = 1,
SLOW_DEVSEL_TIMIMG = 2,
};
pciSecondaryStatusReg(uint16_t por_val = 0x0, uint16_t mask = 0xf900, \
void * d = 0, const char * name = "pciSecStatReg")
:pciConfReg(name, 2, por_val, mask, d){}
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
assert(bytes_to_write == 2);
uint32_t oldval = val;
// if fails, write a more generic function in here.
buf &= mask; // 0 out the ro bits if any in buf
buf = ~buf; // flip the 0's to 1's and vice versa
val &= buf; // and with val so that bits set to 1 are turned off
// bits written to with 0 are unaffected.
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val);
return 2;
}
};
class pciBridgeControlReg:public pciConfReg{
public:
enum{
PARITY_ERROR_RESPONSE_EN = 0,
SERR_EN = 1,
ISA_EN = 2,
VGA_EN = 3,
VGA_16_BIT_DECODE = 4,
MASTER_ABORT = 5,
SEC_BUS_RESET = 6,
FAST_BACK_TO_BACK_EN = 7,
PRIMARY_DISCARD_TIMER = 8,
SECONDARY_DISCARD_TIMER = 9,
DISCARD_TIMER_STATUS = 10, // RW1C bit
DISCARD_TIMER_ERR_EN = 11
};
pciBridgeControlReg(uint16_t por_val = 0x0, uint16_t mask = 0xeff, \
void * d = 0, const char * name = "pciBridgeCtrlReg")
:pciConfReg(name, 2, por_val, mask, d){}
uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){
uint32_t bit10_in_buf = buf & 1 << DISCARD_TIMER_STATUS;
uint32_t bit10_in_val = val & 1 << DISCARD_TIMER_STATUS;
uint32_t oldval = val;
pciConfReg::write(buf,byte_offset,bytes_to_write);
if((bytes_to_write > 1) && bit10_in_buf && bit10_in_val)
val &= ~((uint32_t)1 << DISCARD_TIMER_STATUS);
if(debug_level >= 2)
printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val);
return bytes_to_write;
}
};
#endif// __PCI_BRIDGE_H__