1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
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
11 * IBM Corporation - initial implementation
12 *****************************************************************************/
15 #include "compat/rtas.h"
16 #include "compat/time.h"
19 #include <x86emu/x86emu.h>
22 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
23 #include <device/pci.h>
24 #include <device/pci_ops.h>
25 #include <device/resource.h>
28 #ifdef CONFIG_ARCH_X86
31 // these are not used, only needed for linking, must be overridden using X86emu_setupPioFuncs
32 // with the functions and struct below
34 outb(u8 val, u16 port)
36 printf("WARNING: outb not implemented!\n");
41 outw(u16 val, u16 port)
43 printf("WARNING: outw not implemented!\n");
48 outl(u32 val, u16 port)
50 printf("WARNING: outl not implemented!\n");
57 printf("WARNING: inb not implemented!\n");
65 printf("WARNING: inw not implemented!\n");
73 printf("WARNING: inl not implemented!\n");
79 #if defined(CONFIG_YABEL_DIRECTHW) && (CONFIG_YABEL_DIRECTHW == 1)
80 u8 my_inb(X86EMU_pioAddr addr)
85 DEBUG_PRINTF_IO("inb(0x%04x) = 0x%02x\n", addr, val);
90 u16 my_inw(X86EMU_pioAddr addr)
95 DEBUG_PRINTF_IO("inw(0x%04x) = 0x%04x\n", addr, val);
100 u32 my_inl(X86EMU_pioAddr addr)
105 DEBUG_PRINTF_IO("inl(0x%04x) = 0x%08x\n", addr, val);
110 void my_outb(X86EMU_pioAddr addr, u8 val)
112 DEBUG_PRINTF_IO("outb(0x%02x, 0x%04x)\n", val, addr);
116 void my_outw(X86EMU_pioAddr addr, u16 val)
118 DEBUG_PRINTF_IO("outw(0x%04x, 0x%04x)\n", val, addr);
122 void my_outl(X86EMU_pioAddr addr, u32 val)
124 DEBUG_PRINTF_IO("outl(0x%08x, 0x%04x)\n", val, addr);
131 read_io(void *addr, size_t sz)
134 /* since we are using inb instructions, we need the port number as 16bit value */
135 u16 port = (u16)(u32) addr;
139 asm volatile ("inb %1, %b0" : "=a"(ret) : "d" (port));
142 asm volatile ("inw %1, %w0" : "=a"(ret) : "d" (port));
145 asm volatile ("inl %1, %0" : "=a"(ret) : "d" (port));
155 write_io(void *addr, unsigned int value, size_t sz)
157 u16 port = (u16)(u32) addr;
159 /* since we are using inb instructions, we need the port number as 16bit value */
161 asm volatile ("outb %b0, %1" : : "a"(value), "d" (port));
164 asm volatile ("outw %w0, %1" : : "a"(value), "d" (port));
167 asm volatile ("outl %0, %1" : : "a"(value), "d" (port));
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);
181 my_inb(X86EMU_pioAddr addr)
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__,
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__,
198 //8254 KB Controller / Timer Port
199 // rval = handle_port_61h();
201 //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
208 // PCI Config Mechanism 1 Ports
209 return (u8) pci_cfg_read(addr, 1);
212 CHECK_DBG(DEBUG_INTR) {
215 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
217 // no break, intentional fall-through to default!!
220 ("%s(%04x) reading from bios_device.io_buffer\n",
222 rval = *((u8 *) (bios_device.io_buffer + addr));
223 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
224 __func__, addr, rval);
232 my_inw(X86EMU_pioAddr addr)
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__,
240 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
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);
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));
252 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
259 //PCI Config Mechanism 1
260 return (u16) pci_cfg_read(addr, 2);
264 ("%s(%04x) reading from bios_device.io_buffer\n",
267 in16le((void *) bios_device.io_buffer + addr);
268 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
269 __func__, addr, rval);
277 my_inl(X86EMU_pioAddr addr)
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__,
285 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
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);
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));
299 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
305 //PCI Config Mechanism 1
306 return pci_cfg_read(addr, 4);
310 ("%s(%04x) reading from bios_device.io_buffer\n",
313 in32le((void *) bios_device.io_buffer + addr);
314 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
315 __func__, addr, rval);
323 my_outb(X86EMU_pioAddr addr, u8 val)
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__,
341 // PCI Config Mechanism 1 Ports
342 pci_cfg_write(addr, val, 1);
346 ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
347 __func__, addr, val);
348 *((u8 *) (bios_device.io_buffer + addr)) = val;
355 my_outw(X86EMU_pioAddr addr, u16 val)
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);
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);
376 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
382 // PCI Config Mechanism 1 Ports
383 pci_cfg_write(addr, val, 2);
387 ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
388 __func__, addr, val);
389 out16le((void *) bios_device.io_buffer + addr, val);
396 my_outl(X86EMU_pioAddr addr, u32 val)
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);
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);
421 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
426 // PCI Config Mechanism 1 Ports
427 pci_cfg_write(addr, val, 4);
431 ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
432 __func__, addr, val);
433 out32le((void *) bios_device.io_buffer + addr, val);
440 pci_cfg_read(X86EMU_pioAddr addr, u8 size)
442 u32 rval = 0xFFFFFFFF;
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...
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));
463 // fail accesses to non-existent devices...
465 dev = bios_device.dev;
466 if ((bus != bios_device.bus)
467 || (devfn != bios_device.devfn)) {
468 // fail accesses to any device but ours...
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);
478 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
481 rval = pci_read_config8(dev, offs);
484 rval = pci_read_config16(dev, offs);
487 rval = pci_read_config32(dev, offs);
492 (u32) rtas_pci_config_read(bios_device.
498 ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
499 __func__, addr, offs, size, rval);
507 pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
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...
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...
525 ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
526 bus, devfn >> 3, devfn & 7, offs);
529 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
532 pci_write_config8(bios_device.dev, offs, val);
535 pci_write_config16(bios_device.dev, offs, val);
538 pci_write_config32(bios_device.dev, offs, val);
542 rtas_pci_config_write(bios_device.puid,
543 size, bus, devfn, offs,
547 ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
548 __func__, addr, offs, size, val);
555 handle_port_61h(void)
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;
572 //finally read the value from the io_buffer
573 return *((u8 *) (bios_device.io_buffer + 0x61));