Commit | Line | Data |
---|---|---|
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 | ||
34 | extern int term_init(FILE *fp,void (*)(void *, char *, int), void *cbData,char **tty_name); | |
35 | extern int term_console (char *pty_dev, char *display); | |
36 | extern serialInterface *systemConsole; | |
37 | extern char * console_display; | |
38 | extern bool pop_window; | |
39 | // one-line help | |
40 | const char * | |
41 | Module::get_help_string() | |
42 | { | |
43 | return "PCI Serial Device"; | |
44 | } | |
45 | ||
46 | // factory function | |
47 | Module * | |
48 | Module::create(const char *_modname, const char *_instance_name) | |
49 | { | |
50 | return new Serial(_modname, _instance_name); | |
51 | } | |
52 | ||
53 | // downstream I/O access | |
54 | pciXactnStatus 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 | |
62 | const char * | |
63 | Serial::get_help() | |
64 | { | |
65 | return Module::get_help_string(); | |
66 | } | |
67 | ||
68 | // constructor | |
69 | Serial::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 | |
90 | Serial::~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 | |
101 | bool | |
102 | Serial::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 | |
129 | bool | |
130 | Serial::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 | |
177 | void | |
178 | Serial::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 | |
210 | void | |
211 | Serial::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 | |
217 | void | |
218 | Serial::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 | |
224 | void | |
225 | Serial::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 | |
235 | void * | |
236 | Serial::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 | ||
247 | void | |
248 | Serial::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 | ||
304 | void handleSerialIp(void * sptr, char * data, int port){ | |
305 | Serial * S = (Serial *)sptr; | |
306 | S->chars_send(data,port); | |
307 | } | |
308 | ||
309 | ||
310 | void 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 | ||
350 | mmi_instance_t Serial::pciDev_getInstance(){ return Module::getInstance();} | |
351 | const char * Serial::pciDev_getName(){ return Module::getName();} | |
352 | void 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 | } |