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