Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / serial / serial_mod.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: serial_mod.cc
// 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 ============================================
/*
* Copyright 2004 by Sun Microsystems, Inc.
* All rights reserved.
*
* W% 06/06/15
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "serial_mod.h"
extern int term_init(FILE *fp,void (*)(void *, char *, int), void *cbData,char **tty_name);
extern int term_console (char *pty_dev, char *display);
extern serialInterface *systemConsole;
extern char * console_display;
extern bool pop_window;
// one-line help
const char *
Module::get_help_string()
{
return "PCI Serial Device";
}
// factory function
Module *
Module::create(const char *_modname, const char *_instance_name)
{
return new Serial(_modname, _instance_name);
}
// downstream I/O access
pciXactnStatus Serial::pciTarget_mem32access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){
debug_info("%s: %s MEM32: offset %llx size %x\n", HERE, wr?"WRITE":"READ ", offset, size);
int retval = reg_access((char*)buf, offset - pciMem32_base,wr);
return SUCCESS;
}
// return help string
const char *
Serial::get_help()
{
return Module::get_help_string();
}
// constructor
Serial::Serial(const char *_modname, const char *_instance_name)
: Module(_modname, _instance_name)
{
msp = allocation_obj();
/*
cfg->vendor_id = 0x108e;
cfg->pci_device_id = 0x0; //XXX look up from spec
cfg->class_code = 0x10000; //XXX verify
cfg->header_type = 0x0;
*/
isSystemConsole = false;
termAredirect = 0;
termBredirect = 0;
ttyAname = ttyBname = 0;
termAfp = termBfp = 0;
if(console_display)
display = strdup(console_display);
pciMem32_size = 0x2000;
}
// destructor
Serial::~Serial()
{
debug_info("%s: destructor\n", HERE);
SYSTEM_ss_unregister((void*)this);
DR_unregister((void*)this);
if (msp)
free((void*)msp);
}
// parse an arg
bool
Serial::parse_arg(const char *arg)
{
if(restore_v4_dump()){
if(argval("mem32_base",arg,&pciMem32_base)){
debug_more("%s:mem32_base = %llx\n",getName(),pciMem32_base);
return true;
}else if(argval("mem32_size",arg,&pciMem32_size)){
debug_more("%s:mem32_size = %llx\n",getName(),pciMem32_size);
return true;
}
}
if(!strcmp("sam-console",arg)){
isSystemConsole = true;
return true;
}else if(argval("redirectA",arg,&termAredirect)){
debug_more("%s: term A redirected to file %s\n",termAredirect);
return true;
}else if (argval("redirectB",arg,&termBredirect)){
debug_more("%s: term B redirected to file %s\n",termBredirect);
return true;
}else
return dev_parse_arg(arg);
}
// check args for sanity
bool
Serial::check_args()
{
bool ret = dev_check_args();
if(ret){
// all the args are provided correctly. init the console now.
// can't do this from init_done because console-send in rc file
// can be called before init_done.
if(isSystemConsole)
systemConsole = (serialInterface*)this; // blaze system has a callback that
// uses this to allow prints from
// fakeprom. using access_serial_cb()
// could be removed if there was a
// way to set the name of serial device
// as being done by conf. In any case its
// better than hard coding the sysconf
// supplied name in blaze code.
// Hence future cleanup item XXX
if(termAredirect != 0)
termAfp = fopen(termAredirect,"w");
if(termBredirect != 0)
termBfp = fopen(termBredirect,"w");
portHandle[0] = term_init(termAfp, handleSerialIp, (void *) this, &ttyAname);
printf("TIP connection for %s port A is %s\n",getName(),ttyAname);
portHandle[1] = term_init(termBfp, handleSerialIp, (void *) this, &ttyBname);
printf("TIP connection for %s port B is %s\n",getName(),ttyBname);
if(isSystemConsole){
systemConsole->portH = portHandle[0];
if(!pop_window)
return ret;
if(display[0] != 0 && termAredirect == 0){
if(term_console(ttyAname, display) < 0){
debug_err("%s:Unable to popup XTERM for simulated Os\n",getName());
exit(1);
}
}else
debug_err("%s: DISPLAY variable not set or using console redirection\n",getName());
}
}
return ret;
}
// called once after blaze has initialized devices and cpu data structs
void
Serial::init_done()
{
initPci();
dev_init_done(debug_level);
#ifdef V5_FAKEPROM
// map in the device. these functions would normally be
// performed by the boot prom
// 1. get the lowest available base address on the bus
if(!DR_is_restoreOP)
pciMem32_base = getBase(PCI_MEM32,pciMem32_size);
// Map in the address if this is a v4 restore or a new v5 run
if(restore_v4_dump() || !restore_v5_dump()){
// 2. set the base address 0 register
confSpace->confAccessSize(PCI_CONF_BASE0,true,&pciMem32_base,4);
// 3. enable the pci mem32 access by setting the command reg.
uint64_t command = 2;
confSpace->confAccessSize(PCI_CONF_COMM,true,&command,2);
}
get_dev_props();
plist->writeToFakeProm();
if(Module::debug_level >= 2)
plist->print();
#endif
}
// called each time a new module instance has been created
void
Serial::module_added(mmi_instance_t target, const char *target_name)
{
dev_module_added(target_name);
}
// called each time a new module instance has been unloaded
void
Serial::module_deleted(mmi_instance_t target, const char *target_name)
{
dev_module_deleted(target_name);
}
// print interesting info about this module
void
Serial::modinfo()
{
printf("%s: This is a Serial PCI device\n",
getName());
printf("TIP for port A is %s\n",ttyAname);
printf("TIP for port B is %s\n",ttyBname);
pciDevInfo();
}
// return pointer to interface
void *
Serial::get_interface(const char *name)
{
if (!strcmp(name, PCI_GENERIC_DEV_INTERFACE))
return (genericPciDevIf*)this;
if (!strcmp(name, "Serial"))
return (Serial *)this;
return NULL;
}
void
Serial::get_dev_props()
{
int busnum =0;
debug_more("enter serial_mod.cc ::get_dev_props\n");
pcisimc_props[0].value = new char[strlen(devif_getBusName())+1];
strcpy(pcisimc_props[0].value,devif_getBusName());
pcisimc_props[0].size = strlen(devif_getBusName()) + 1;
sprintf(pcisimc_device,"%d",devif_getDevice());
pcisimc_props[1].value = pcisimc_device;
pcisimc_props[1].size = strlen(pcisimc_device)+1;
sprintf(pcisimc_membase,"%d",pciMem32_base);
pcisimc_props[2].value = pcisimc_membase;
pcisimc_props[2].size = strlen(pcisimc_membase)+1;
sprintf(pcisimc_memsize,"%d",pciMem32_size);
pcisimc_props[3].value = pcisimc_memsize;
pcisimc_props[3].size = strlen(pcisimc_memsize)+1;
if(isSystemConsole)
strcpy(pcisimc_isconsole,"1");
else
strcpy(pcisimc_isconsole,"0");
pcisimc_props[4].value = pcisimc_isconsole;
pcisimc_props[4].size = 2;
pcisimc_reg[0].pci_phys_hi = 0x00000000 | devif_getDevice() << 11 | devif_getFunction() << 8;
pcisimc_reg[0].pci_phys_mid = 0;
pcisimc_reg[0].pci_phys_low = 0;
pcisimc_reg[0].pci_size_hi = 0;
pcisimc_reg[0].pci_size_low = 0;
// pcisimc_reg[1].pci_phys_hi = 0x82000000 | devif_getDevice() << 11;
pcisimc_reg[1].pci_phys_hi = 0x02000000 | devif_getDevice() << 11 | devif_getFunction() << 8 | PCI_CONF_BASE0;
pcisimc_reg[1].pci_phys_mid = 0;
pcisimc_reg[1].pci_phys_low = 0;
pcisimc_reg[1].pci_size_hi = 0;
pcisimc_reg[1].pci_size_low = pciMem32_size;
pcisimc_assigned_addr[0].pci_phys_hi = 0x82000000 | devif_getDevice() << 11 | devif_getFunction() << 8 | PCI_CONF_BASE0;
pcisimc_assigned_addr[0].pci_phys_mid = 0;
pcisimc_assigned_addr[0].pci_phys_low = pciMem32_base;
pcisimc_assigned_addr[0].pci_size_hi = 0;
pcisimc_assigned_addr[0].pci_size_low = pciMem32_size;
pcisimc_intr = slot_irl[0];
plist->add_bunch(pcisimc_props);
debug_more("leave serial_mod.cc ::get_dev_props plist->count %x\n",plist->count);
}
void handleSerialIp(void * sptr, char * data, int port){
Serial * S = (Serial *)sptr;
S->chars_send(data,port);
}
void Serial::initPci(){
char reg_descr[100];
snprintf(reg_descr,100,"%s Vendor ID", getName());
confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x108e,0x0,0x0),PCI_CONF_VENID);//0x108e, ro
snprintf(reg_descr,100,"%s Device ID", getName());
confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x0,0x0,0x0),PCI_CONF_DEVID); //0x0, ro
snprintf(reg_descr,100,"%s command reg", getName());
confSpace->addConfReg(new pciCommandReg(reg_descr,(genericPciDev*)this,0x2),PCI_CONF_COMM);// write mask = 0x2, only allows mem32 access
snprintf(reg_descr,100,"%s status reg", getName());
confSpace->addConfReg(new pciStatusReg(reg_descr,(genericPciDev*)this,0x0,0x0),PCI_CONF_STAT);//write mask = 0x0, init val 0x0
snprintf(reg_descr,100,"%s revision id",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0,0x0),PCI_CONF_REVID);// rev id = 0x0, ro
snprintf(reg_descr,100,"%s prog class",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_PROGCLASS);//0x00, ro
snprintf(reg_descr,100,"%s sub class",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_SUBCLASS);//0x00, ro
snprintf(reg_descr,100,"%s base class",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x01,0x0),PCI_CONF_BASCLASS);//0x01, ro
snprintf(reg_descr,100,"%s Header type",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00,0x0),PCI_CONF_HEADER); //0x00,ro
snprintf(reg_descr,100,"%s BAR0",getName());
confSpace->addConfReg(new baseAddrReg(reg_descr,(genericPciDev*)this,pciMem32_size,PCI_MEM32),PCI_CONF_BASE0);//0x2000 non prefetchable, pci mem32 mapped
snprintf(reg_descr,100,"%s interrupt line",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),PCI_CONF_ILINE);//0x0
snprintf(reg_descr,100,"%s interrupt pin",getName());
confSpace->addConfReg(new pciConfReg(reg_descr,1,0x1,0x00),PCI_CONF_IPIN);//0x1,ro
}
mmi_instance_t Serial::pciDev_getInstance(){ return Module::getInstance();}
const char * Serial::pciDev_getName(){ return Module::getName();}
void Serial::pciDev_confAccessCb(bool_t wr, uint64_t offset, uint8_t size){
if(!wr)
return;
if(offset == PCI_CONF_BASE0){
assert(size == 4);
pciMem32_base = confSpace->readConf(offset) & 0xfffffff0;
}
return;
}