6d36e8078fe92e5bd1c1edc9ba3227bf1622b83d
[coreboot.git] / util / x86emu / yabel / io.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
4  * All rights reserved.
5  * This program and the accompanying materials
6  * are made available under the terms of the BSD License
7  * which accompanies this distribution, and is available at
8  * http://www.opensource.org/licenses/bsd-license.php
9  *
10  * Contributors:
11  *     IBM Corporation - initial implementation
12  *****************************************************************************/
13
14 #include <types.h>
15 #include "compat/rtas.h"
16 #include "compat/time.h"
17 #include "device.h"
18 #include "debug.h"
19 #include <x86emu/x86emu.h>
20 #include "io.h"
21
22 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
23 #include <device/pci.h>
24 #include <device/pci_ops.h>
25 #endif
26
27 // those are defined in net-snk/oflib/pci.c
28 extern unsigned int read_io(void *, size_t);
29 extern int write_io(void *, unsigned int, size_t);
30
31 //defined in net-snk/kernel/timer.c
32 extern u64 get_time(void);
33
34 #ifdef CONFIG_ARCH_X86
35 #include <arch/io.h>
36 #else
37 // these are not used, only needed for linking,  must be overridden using X86emu_setupPioFuncs
38 // with the functions and struct below
39 void
40 outb(u8 val, u16 port)
41 {
42         printf("WARNING: outb not implemented!\n");
43         HALT_SYS();
44 }
45
46 void
47 outw(u16 val, u16 port)
48 {
49         printf("WARNING: outw not implemented!\n");
50         HALT_SYS();
51 }
52
53 void
54 outl(u32 val, u16 port)
55 {
56         printf("WARNING: outl not implemented!\n");
57         HALT_SYS();
58 }
59
60 u8
61 inb(u16 port)
62 {
63         printf("WARNING: inb not implemented!\n");
64         HALT_SYS();
65         return 0;
66 }
67
68 u16
69 inw(u16 port)
70 {
71         printf("WARNING: inw not implemented!\n");
72         HALT_SYS();
73         return 0;
74 }
75
76 u32
77 inl(u16 port)
78 {
79         printf("WARNING: inl not implemented!\n");
80         HALT_SYS();
81         return 0;
82 }
83 #endif
84
85 #if defined(CONFIG_YABEL_DIRECTHW) && (CONFIG_YABEL_DIRECTHW == 1)
86 u8 my_inb(X86EMU_pioAddr addr)
87 {
88         u8 val;
89
90         val = inb(addr);
91         DEBUG_PRINTF_IO("inb(0x%04x) = 0x%02x\n", addr, val);
92
93         return val;
94 }
95
96 u16 my_inw(X86EMU_pioAddr addr)
97 {
98         u16 val;
99
100         val = inw(addr);
101         DEBUG_PRINTF_IO("inw(0x%04x) = 0x%04x\n", addr, val);
102
103         return val;
104 }
105
106 u32 my_inl(X86EMU_pioAddr addr)
107 {
108         u32 val;
109
110         val = inl(addr);
111         DEBUG_PRINTF_IO("inl(0x%04x) = 0x%08x\n", addr, val);
112
113         return val;
114 }
115
116 void my_outb(X86EMU_pioAddr addr, u8 val)
117 {
118         DEBUG_PRINTF_IO("outb(0x%02x, 0x%04x)\n", val, addr);
119         outb(val, addr);
120 }
121
122 void my_outw(X86EMU_pioAddr addr, u16 val)
123 {
124         DEBUG_PRINTF_IO("outw(0x%04x, 0x%04x)\n", val, addr);
125         outw(val, addr);
126 }
127
128 void my_outl(X86EMU_pioAddr addr, u32 val)
129 {
130         DEBUG_PRINTF_IO("outl(0x%08x, 0x%04x)\n", val, addr);
131         outl(val, addr);
132 }
133
134 #else
135
136 u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size);
137 void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size);
138 u8 handle_port_61h(void);
139
140 u8
141 my_inb(X86EMU_pioAddr addr)
142 {
143         u8 rval = 0xFF;
144         unsigned long translated_addr = addr;
145         u8 translated = biosemu_dev_translate_address(&translated_addr);
146         if (translated != 0) {
147                 //translation successfull, access Device I/O (BAR or Legacy...)
148                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
149                                 addr);
150                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
151                 rval = read_io((void *)translated_addr, 1);
152                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __func__,
153                                 addr, rval);
154                 return rval;
155         } else {
156                 switch (addr) {
157                 case 0x61:
158                         //8254 KB Controller / Timer Port
159                         // rval = handle_port_61h();
160                         rval = inb(0x61);
161                         //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
162                         return rval;
163                         break;
164                 case 0xCFC:
165                 case 0xCFD:
166                 case 0xCFE:
167                 case 0xCFF:
168                         // PCI Config Mechanism 1 Ports
169                         return (u8) pci_cfg_read(addr, 1);
170                         break;
171                 case 0x0a:
172                         CHECK_DBG(DEBUG_INTR) {
173                                 X86EMU_trace_on();
174                         }
175                         M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
176                         //HALT_SYS();
177                         // no break, intentional fall-through to default!!
178                 default:
179                         DEBUG_PRINTF_IO
180                             ("%s(%04x) reading from bios_device.io_buffer\n",
181                              __func__, addr);
182                         rval = *((u8 *) (bios_device.io_buffer + addr));
183                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
184                                         __func__, addr, rval);
185                         return rval;
186                         break;
187                 }
188         }
189 }
190
191 u16
192 my_inw(X86EMU_pioAddr addr)
193 {
194         unsigned long translated_addr = addr;
195         u8 translated = biosemu_dev_translate_address(&translated_addr);
196         if (translated != 0) {
197                 //translation successfull, access Device I/O (BAR or Legacy...)
198                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
199                                 addr);
200                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
201                 u16 rval;
202                 if ((translated_addr & (u64) 0x1) == 0) {
203                         // 16 bit aligned access...
204                         u16 tempval = read_io((void *)translated_addr, 2);
205                         //little endian conversion
206                         rval = in16le((void *) &tempval);
207                 } else {
208                         // unaligned access, read single bytes, little-endian
209                         rval = (read_io((void *)translated_addr, 1) << 8)
210                                 | (read_io((void *)(translated_addr + 1), 1));
211                 }
212                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
213                                 addr, rval);
214                 return rval;
215         } else {
216                 switch (addr) {
217                 case 0xCFC:
218                 case 0xCFE:
219                         //PCI Config Mechanism 1
220                         return (u16) pci_cfg_read(addr, 2);
221                         break;
222                 default:
223                         DEBUG_PRINTF_IO
224                             ("%s(%04x) reading from bios_device.io_buffer\n",
225                              __func__, addr);
226                         u16 rval =
227                             in16le((void *) bios_device.io_buffer + addr);
228                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
229                                         __func__, addr, rval);
230                         return rval;
231                         break;
232                 }
233         }
234 }
235
236 u32
237 my_inl(X86EMU_pioAddr addr)
238 {
239         unsigned long translated_addr = addr;
240         u8 translated = biosemu_dev_translate_address(&translated_addr);
241         if (translated != 0) {
242                 //translation successfull, access Device I/O (BAR or Legacy...)
243                 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
244                                 addr);
245                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
246                 u32 rval;
247                 if ((translated_addr & (u64) 0x3) == 0) {
248                         // 32 bit aligned access...
249                         u32 tempval = read_io((void *) translated_addr, 4);
250                         //little endian conversion
251                         rval = in32le((void *) &tempval);
252                 } else {
253                         // unaligned access, read single bytes, little-endian
254                         rval = (read_io((void *)(translated_addr), 1) << 24)
255                                 | (read_io((void *)(translated_addr + 1), 1) << 16)
256                                 | (read_io((void *)(translated_addr + 2), 1) << 8)
257                                 | (read_io((void *)(translated_addr + 3), 1));
258                 }
259                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
260                                 addr, rval);
261                 return rval;
262         } else {
263                 switch (addr) {
264                 case 0xCFC:
265                         //PCI Config Mechanism 1
266                         return pci_cfg_read(addr, 4);
267                         break;
268                 default:
269                         DEBUG_PRINTF_IO
270                             ("%s(%04x) reading from bios_device.io_buffer\n",
271                              __func__, addr);
272                         u32 rval =
273                             in32le((void *) bios_device.io_buffer + addr);
274                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
275                                         __func__, addr, rval);
276                         return rval;
277                         break;
278                 }
279         }
280 }
281
282 void
283 my_outb(X86EMU_pioAddr addr, u8 val)
284 {
285         unsigned long translated_addr = addr;
286         u8 translated = biosemu_dev_translate_address(&translated_addr);
287         if (translated != 0) {
288                 //translation successfull, access Device I/O (BAR or Legacy...)
289                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
290                                 __func__, addr, val);
291                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
292                 write_io((void *) translated_addr, val, 1);
293                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__,
294                                 addr, val);
295         } else {
296                 switch (addr) {
297                 case 0xCFC:
298                 case 0xCFD:
299                 case 0xCFE:
300                 case 0xCFF:
301                         // PCI Config Mechanism 1 Ports
302                         pci_cfg_write(addr, val, 1);
303                         break;
304                 default:
305                         DEBUG_PRINTF_IO
306                             ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
307                              __func__, addr, val);
308                         *((u8 *) (bios_device.io_buffer + addr)) = val;
309                         break;
310                 }
311         }
312 }
313
314 void
315 my_outw(X86EMU_pioAddr addr, u16 val)
316 {
317         unsigned long translated_addr = addr;
318         u8 translated = biosemu_dev_translate_address(&translated_addr);
319         if (translated != 0) {
320                 //translation successfull, access Device I/O (BAR or Legacy...)
321                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
322                                 __func__, addr, val);
323                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
324                 if ((translated_addr & (u64) 0x1) == 0) {
325                         // little-endian conversion
326                         u16 tempval = in16le((void *) &val);
327                         // 16 bit aligned access...
328                         write_io((void *) translated_addr, tempval, 2);
329                 } else {
330                         // unaligned access, write single bytes, little-endian
331                         write_io(((void *) (translated_addr + 1)),
332                                 (u8) ((val & 0xFF00) >> 8), 1);
333                         write_io(((void *) translated_addr),
334                                 (u8) (val & 0x00FF), 1);
335                 }
336                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
337                                 addr, val);
338         } else {
339                 switch (addr) {
340                 case 0xCFC:
341                 case 0xCFE:
342                         // PCI Config Mechanism 1 Ports
343                         pci_cfg_write(addr, val, 2);
344                         break;
345                 default:
346                         DEBUG_PRINTF_IO
347                             ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
348                              __func__, addr, val);
349                         out16le((void *) bios_device.io_buffer + addr, val);
350                         break;
351                 }
352         }
353 }
354
355 void
356 my_outl(X86EMU_pioAddr addr, u32 val)
357 {
358         unsigned long translated_addr = addr;
359         u8 translated = biosemu_dev_translate_address(&translated_addr);
360         if (translated != 0) {
361                 //translation successfull, access Device I/O (BAR or Legacy...)
362                 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
363                                 __func__, addr, val);
364                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
365                 if ((translated_addr & (u64) 0x3) == 0) {
366                         // little-endian conversion
367                         u32 tempval = in32le((void *) &val);
368                         // 32 bit aligned access...
369                         write_io((void *) translated_addr,  tempval, 4);
370                 } else {
371                         // unaligned access, write single bytes, little-endian
372                         write_io(((void *) translated_addr + 3),
373                             (u8) ((val & 0xFF000000) >> 24), 1);
374                         write_io(((void *) translated_addr + 2),
375                             (u8) ((val & 0x00FF0000) >> 16), 1);
376                         write_io(((void *) translated_addr + 1),
377                             (u8) ((val & 0x0000FF00) >> 8), 1);
378                         write_io(((void *) translated_addr),
379                             (u8) (val & 0x000000FF), 1);
380                 }
381                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
382                                 addr, val);
383         } else {
384                 switch (addr) {
385                 case 0xCFC:
386                         // PCI Config Mechanism 1 Ports
387                         pci_cfg_write(addr, val, 4);
388                         break;
389                 default:
390                         DEBUG_PRINTF_IO
391                             ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
392                              __func__, addr, val);
393                         out32le((void *) bios_device.io_buffer + addr, val);
394                         break;
395                 }
396         }
397 }
398
399 u32
400 pci_cfg_read(X86EMU_pioAddr addr, u8 size)
401 {
402         u32 rval = 0xFFFFFFFF;
403         struct device * dev;
404         if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
405                 // PCI Configuration Mechanism 1 step 1
406                 // write to 0xCF8, sets bus, device, function and Config Space offset
407                 // later read from 0xCFC-0xCFF returns the value...
408                 u8 bus, devfn, offs;
409                 u32 port_cf8_val = my_inl(0xCF8);
410                 if ((port_cf8_val & 0x80000000) != 0) {
411                         //highest bit enables config space mapping
412                         bus = (port_cf8_val & 0x00FF0000) >> 16;
413                         devfn = (port_cf8_val & 0x0000FF00) >> 8;
414                         offs = (port_cf8_val & 0x000000FF);
415                         offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
416                         DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
417                                 __func__, bus, devfn, offs);
418 #if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
419                         dev = dev_find_slot(bus, devfn);
420                         DEBUG_PRINTF_INTR("%s(): dev_find_slot() returned: %s\n",
421                                 __func__, dev_path(dev));
422                         if (dev == 0) {
423                                 // fail accesses to non-existent devices...
424 #else
425                         dev = bios_device.dev;
426                         if ((bus != bios_device.bus)
427                              || (devfn != bios_device.devfn)) {
428                                 // fail accesses to any device but ours...
429 #endif
430                                 printf
431                                     ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
432                                      __func__, bus, bios_device.bus, devfn,
433                                      bios_device.devfn, offs);
434                                 SET_FLAG(F_CF);
435                                 HALT_SYS();
436                                 return 0;
437                         } else {
438 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
439                                 switch (size) {
440                                         case 1:
441                                                 rval = pci_read_config8(dev, offs);
442                                                 break;
443                                         case 2:
444                                                 rval = pci_read_config16(dev, offs);
445                                                 break;
446                                         case 4:
447                                                 rval = pci_read_config32(dev, offs);
448                                                 break;
449                                 }
450 #else
451                                 rval =
452                                     (u32) rtas_pci_config_read(bios_device.
453                                                                     puid, size,
454                                                                     bus, devfn,
455                                                                     offs);
456 #endif
457                                 DEBUG_PRINTF_IO
458                                     ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
459                                      __func__, addr, offs, size, rval);
460                         }
461                 }
462         }
463         return rval;
464 }
465
466 void
467 pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
468 {
469         if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
470                 // PCI Configuration Mechanism 1 step 1
471                 // write to 0xCF8, sets bus, device, function and Config Space offset
472                 // later write to 0xCFC-0xCFF sets the value...
473                 u8 bus, devfn, offs;
474                 u32 port_cf8_val = my_inl(0xCF8);
475                 if ((port_cf8_val & 0x80000000) != 0) {
476                         //highest bit enables config space mapping
477                         bus = (port_cf8_val & 0x00FF0000) >> 16;
478                         devfn = (port_cf8_val & 0x0000FF00) >> 8;
479                         offs = (port_cf8_val & 0x000000FF);
480                         offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
481                         if ((bus != bios_device.bus)
482                             || (devfn != bios_device.devfn)) {
483                                 // fail accesses to any device but ours...
484                                 printf
485                                     ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
486                                      bus, devfn >> 3, devfn & 7, offs);
487                                 HALT_SYS();
488                         } else {
489 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
490                                 switch (size) {
491                                         case 1:
492                                                 pci_write_config8(bios_device.dev, offs, val);
493                                                 break;
494                                         case 2:
495                                                 pci_write_config16(bios_device.dev, offs, val);
496                                                 break;
497                                         case 4:
498                                                 pci_write_config32(bios_device.dev, offs, val);
499                                                 break;
500                                 }
501 #else
502                                 rtas_pci_config_write(bios_device.puid,
503                                                       size, bus, devfn, offs,
504                                                       val);
505 #endif
506                                 DEBUG_PRINTF_IO
507                                     ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
508                                      __func__, addr, offs, size, val);
509                         }
510                 }
511         }
512 }
513
514 u8
515 handle_port_61h(void)
516 {
517         static u64 last_time = 0;
518         u64 curr_time = get_time();
519         u64 time_diff;  // time since last call
520         u32 period_ticks;       // length of a period in ticks
521         u32 nr_periods; //number of periods passed since last call
522         // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
523         time_diff = curr_time - last_time;
524         // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
525         // TODO: as long as the frequency does not change, we should not calculate this every time
526         period_ticks = (15 * tb_freq) / 1000000;
527         nr_periods = time_diff / period_ticks;
528         // if the number if ticks passed since last call is odd, we toggle bit 4
529         if ((nr_periods % 2) != 0) {
530                 *((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10;
531         }
532         //finally read the value from the io_buffer
533         return *((u8 *) (bios_device.io_buffer + 0x61));
534 }
535 #endif