Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / serial / serial_mod.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: serial_mod.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21/*
22 * Copyright 2004 by Sun Microsystems, Inc.
23 * All rights reserved.
24 *
25 * W% 06/06/15
26 */
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/types.h>
31
32#include "serial_mod.h"
33
34extern int term_init(FILE *fp,void (*)(void *, char *, int), void *cbData,char **tty_name);
35extern int term_console (char *pty_dev, char *display);
36extern serialInterface *systemConsole;
37extern char * console_display;
38extern bool pop_window;
39// one-line help
40const char *
41Module::get_help_string()
42{
43 return "PCI Serial Device";
44}
45
46// factory function
47Module *
48Module::create(const char *_modname, const char *_instance_name)
49{
50 return new Serial(_modname, _instance_name);
51}
52
53// downstream I/O access
54pciXactnStatus Serial::pciTarget_mem32access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){
55 debug_info("%s: %s MEM32: offset %llx size %x\n", HERE, wr?"WRITE":"READ ", offset, size);
56
57 int retval = reg_access((char*)buf, offset - pciMem32_base,wr);
58 return SUCCESS;
59}
60
61// return help string
62const char *
63Serial::get_help()
64{
65 return Module::get_help_string();
66}
67
68// constructor
69Serial::Serial(const char *_modname, const char *_instance_name)
70 : Module(_modname, _instance_name)
71{
72 msp = allocation_obj();
73/*
74 cfg->vendor_id = 0x108e;
75 cfg->pci_device_id = 0x0; //XXX look up from spec
76 cfg->class_code = 0x10000; //XXX verify
77 cfg->header_type = 0x0;
78*/
79 isSystemConsole = false;
80 termAredirect = 0;
81 termBredirect = 0;
82 ttyAname = ttyBname = 0;
83 termAfp = termBfp = 0;
84 if(console_display)
85 display = strdup(console_display);
86 pciMem32_size = 0x2000;
87}
88
89// destructor
90Serial::~Serial()
91{
92 debug_info("%s: destructor\n", HERE);
93
94 SYSTEM_ss_unregister((void*)this);
95 DR_unregister((void*)this);
96 if (msp)
97 free((void*)msp);
98}
99
100// parse an arg
101bool
102Serial::parse_arg(const char *arg)
103{
104
105 if(restore_v4_dump()){
106 if(argval("mem32_base",arg,&pciMem32_base)){
107 debug_more("%s:mem32_base = %llx\n",getName(),pciMem32_base);
108 return true;
109 }else if(argval("mem32_size",arg,&pciMem32_size)){
110 debug_more("%s:mem32_size = %llx\n",getName(),pciMem32_size);
111 return true;
112 }
113 }
114
115 if(!strcmp("sam-console",arg)){
116 isSystemConsole = true;
117 return true;
118 }else if(argval("redirectA",arg,&termAredirect)){
119 debug_more("%s: term A redirected to file %s\n",termAredirect);
120 return true;
121 }else if (argval("redirectB",arg,&termBredirect)){
122 debug_more("%s: term B redirected to file %s\n",termBredirect);
123 return true;
124 }else
125 return dev_parse_arg(arg);
126}
127
128// check args for sanity
129bool
130Serial::check_args()
131{
132 bool ret = dev_check_args();
133
134 if(ret){
135 // all the args are provided correctly. init the console now.
136 // can't do this from init_done because console-send in rc file
137 // can be called before init_done.
138 if(isSystemConsole)
139 systemConsole = (serialInterface*)this; // blaze system has a callback that
140 // uses this to allow prints from
141 // fakeprom. using access_serial_cb()
142 // could be removed if there was a
143 // way to set the name of serial device
144 // as being done by conf. In any case its
145 // better than hard coding the sysconf
146 // supplied name in blaze code.
147 // Hence future cleanup item XXX
148 if(termAredirect != 0)
149 termAfp = fopen(termAredirect,"w");
150 if(termBredirect != 0)
151 termBfp = fopen(termBredirect,"w");
152
153 portHandle[0] = term_init(termAfp, handleSerialIp, (void *) this, &ttyAname);
154 printf("TIP connection for %s port A is %s\n",getName(),ttyAname);
155
156 portHandle[1] = term_init(termBfp, handleSerialIp, (void *) this, &ttyBname);
157 printf("TIP connection for %s port B is %s\n",getName(),ttyBname);
158
159 if(isSystemConsole){
160 systemConsole->portH = portHandle[0];
161 if(!pop_window)
162 return ret;
163 if(display[0] != 0 && termAredirect == 0){
164 if(term_console(ttyAname, display) < 0){
165 debug_err("%s:Unable to popup XTERM for simulated Os\n",getName());
166 exit(1);
167 }
168 }else
169 debug_err("%s: DISPLAY variable not set or using console redirection\n",getName());
170 }
171 }
172
173 return ret;
174}
175
176// called once after blaze has initialized devices and cpu data structs
177void
178Serial::init_done()
179{
180
181 initPci();
182 dev_init_done(debug_level);
183
184#ifdef V5_FAKEPROM
185 // map in the device. these functions would normally be
186 // performed by the boot prom
187
188 // 1. get the lowest available base address on the bus
189 if(!DR_is_restoreOP)
190 pciMem32_base = getBase(PCI_MEM32,pciMem32_size);
191 // Map in the address if this is a v4 restore or a new v5 run
192 if(restore_v4_dump() || !restore_v5_dump()){
193 // 2. set the base address 0 register
194 confSpace->confAccessSize(PCI_CONF_BASE0,true,&pciMem32_base,4);
195 // 3. enable the pci mem32 access by setting the command reg.
196 uint64_t command = 2;
197 confSpace->confAccessSize(PCI_CONF_COMM,true,&command,2);
198 }
199
200 get_dev_props();
201 plist->writeToFakeProm();
202 if(Module::debug_level >= 2)
203 plist->print();
204
205#endif
206
207}
208
209// called each time a new module instance has been created
210void
211Serial::module_added(mmi_instance_t target, const char *target_name)
212{
213 dev_module_added(target_name);
214}
215
216// called each time a new module instance has been unloaded
217void
218Serial::module_deleted(mmi_instance_t target, const char *target_name)
219{
220 dev_module_deleted(target_name);
221}
222
223// print interesting info about this module
224void
225Serial::modinfo()
226{
227 printf("%s: This is a Serial PCI device\n",
228 getName());
229 printf("TIP for port A is %s\n",ttyAname);
230 printf("TIP for port B is %s\n",ttyBname);
231 pciDevInfo();
232}
233
234// return pointer to interface
235void *
236Serial::get_interface(const char *name)
237{
238
239 if (!strcmp(name, PCI_GENERIC_DEV_INTERFACE))
240 return (genericPciDevIf*)this;
241 if (!strcmp(name, "Serial"))
242 return (Serial *)this;
243 return NULL;
244}
245
246
247void
248Serial::get_dev_props()
249{
250 int busnum =0;
251 debug_more("enter serial_mod.cc ::get_dev_props\n");
252
253 pcisimc_props[0].value = new char[strlen(devif_getBusName())+1];
254 strcpy(pcisimc_props[0].value,devif_getBusName());
255 pcisimc_props[0].size = strlen(devif_getBusName()) + 1;
256 sprintf(pcisimc_device,"%d",devif_getDevice());
257 pcisimc_props[1].value = pcisimc_device;
258 pcisimc_props[1].size = strlen(pcisimc_device)+1;
259
260 sprintf(pcisimc_membase,"%d",pciMem32_base);
261 pcisimc_props[2].value = pcisimc_membase;
262 pcisimc_props[2].size = strlen(pcisimc_membase)+1;
263
264 sprintf(pcisimc_memsize,"%d",pciMem32_size);
265 pcisimc_props[3].value = pcisimc_memsize;
266 pcisimc_props[3].size = strlen(pcisimc_memsize)+1;
267
268 if(isSystemConsole)
269 strcpy(pcisimc_isconsole,"1");
270 else
271 strcpy(pcisimc_isconsole,"0");
272
273 pcisimc_props[4].value = pcisimc_isconsole;
274 pcisimc_props[4].size = 2;
275
276 pcisimc_reg[0].pci_phys_hi = 0x00000000 | devif_getDevice() << 11 | devif_getFunction() << 8;
277 pcisimc_reg[0].pci_phys_mid = 0;
278 pcisimc_reg[0].pci_phys_low = 0;
279 pcisimc_reg[0].pci_size_hi = 0;
280 pcisimc_reg[0].pci_size_low = 0;
281
282
283 // pcisimc_reg[1].pci_phys_hi = 0x82000000 | devif_getDevice() << 11;
284 pcisimc_reg[1].pci_phys_hi = 0x02000000 | devif_getDevice() << 11 | devif_getFunction() << 8 | PCI_CONF_BASE0;
285 pcisimc_reg[1].pci_phys_mid = 0;
286 pcisimc_reg[1].pci_phys_low = 0;
287 pcisimc_reg[1].pci_size_hi = 0;
288 pcisimc_reg[1].pci_size_low = pciMem32_size;
289
290 pcisimc_assigned_addr[0].pci_phys_hi = 0x82000000 | devif_getDevice() << 11 | devif_getFunction() << 8 | PCI_CONF_BASE0;
291 pcisimc_assigned_addr[0].pci_phys_mid = 0;
292 pcisimc_assigned_addr[0].pci_phys_low = pciMem32_base;
293 pcisimc_assigned_addr[0].pci_size_hi = 0;
294 pcisimc_assigned_addr[0].pci_size_low = pciMem32_size;
295
296 pcisimc_intr = slot_irl[0];
297
298 plist->add_bunch(pcisimc_props);
299
300 debug_more("leave serial_mod.cc ::get_dev_props plist->count %x\n",plist->count);
301}
302
303
304void handleSerialIp(void * sptr, char * data, int port){
305 Serial * S = (Serial *)sptr;
306 S->chars_send(data,port);
307}
308
309
310void Serial::initPci(){
311
312 char reg_descr[100];
313 snprintf(reg_descr,100,"%s Vendor ID", getName());
314 confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x108e,0x0,0x0),PCI_CONF_VENID);//0x108e, ro
315
316 snprintf(reg_descr,100,"%s Device ID", getName());
317 confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x0,0x0,0x0),PCI_CONF_DEVID); //0x0, ro
318
319 snprintf(reg_descr,100,"%s command reg", getName());
320 confSpace->addConfReg(new pciCommandReg(reg_descr,(genericPciDev*)this,0x2),PCI_CONF_COMM);// write mask = 0x2, only allows mem32 access
321
322 snprintf(reg_descr,100,"%s status reg", getName());
323 confSpace->addConfReg(new pciStatusReg(reg_descr,(genericPciDev*)this,0x0,0x0),PCI_CONF_STAT);//write mask = 0x0, init val 0x0
324
325 snprintf(reg_descr,100,"%s revision id",getName());
326 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0,0x0),PCI_CONF_REVID);// rev id = 0x0, ro
327
328 snprintf(reg_descr,100,"%s prog class",getName());
329 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_PROGCLASS);//0x00, ro
330
331 snprintf(reg_descr,100,"%s sub class",getName());
332 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_SUBCLASS);//0x00, ro
333
334 snprintf(reg_descr,100,"%s base class",getName());
335 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x01,0x0),PCI_CONF_BASCLASS);//0x01, ro
336
337 snprintf(reg_descr,100,"%s Header type",getName());
338 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00,0x0),PCI_CONF_HEADER); //0x00,ro
339
340 snprintf(reg_descr,100,"%s BAR0",getName());
341 confSpace->addConfReg(new baseAddrReg(reg_descr,(genericPciDev*)this,pciMem32_size,PCI_MEM32),PCI_CONF_BASE0);//0x2000 non prefetchable, pci mem32 mapped
342
343 snprintf(reg_descr,100,"%s interrupt line",getName());
344 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xff),PCI_CONF_ILINE);//0x0
345
346 snprintf(reg_descr,100,"%s interrupt pin",getName());
347 confSpace->addConfReg(new pciConfReg(reg_descr,1,0x1,0x00),PCI_CONF_IPIN);//0x1,ro
348}
349
350mmi_instance_t Serial::pciDev_getInstance(){ return Module::getInstance();}
351const char * Serial::pciDev_getName(){ return Module::getName();}
352void Serial::pciDev_confAccessCb(bool_t wr, uint64_t offset, uint8_t size){
353 if(!wr)
354 return;
355
356 if(offset == PCI_CONF_BASE0){
357 assert(size == 4);
358 pciMem32_base = confSpace->readConf(offset) & 0xfffffff0;
359 }
360
361 return;
362}