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>
28 read_io(void *addr, size_t sz)
31 /* since we are using inb instructions, we need the port number as 16bit value */
32 u16 port = (u16)(u32) addr;
36 asm volatile ("inb %1, %b0" : "=a"(ret) : "d" (port));
39 asm volatile ("inw %1, %w0" : "=a"(ret) : "d" (port));
42 asm volatile ("inl %1, %0" : "=a"(ret) : "d" (port));
52 write_io(void *addr, unsigned int value, size_t sz)
54 u16 port = (u16)(u32) addr;
56 /* since we are using inb instructions, we need the port number as 16bit value */
58 asm volatile ("outb %b0, %1" : : "a"(value), "d" (port));
61 asm volatile ("outw %w0, %1" : : "a"(value), "d" (port));
64 asm volatile ("outl %0, %1" : : "a"(value), "d" (port));
73 #ifdef CONFIG_ARCH_X86
76 // these are not used, only needed for linking, must be overridden using X86emu_setupPioFuncs
77 // with the functions and struct below
79 outb(u8 val, u16 port)
81 printf("WARNING: outb not implemented!\n");
86 outw(u16 val, u16 port)
88 printf("WARNING: outw not implemented!\n");
93 outl(u32 val, u16 port)
95 printf("WARNING: outl not implemented!\n");
102 printf("WARNING: inb not implemented!\n");
110 printf("WARNING: inw not implemented!\n");
118 printf("WARNING: inl not implemented!\n");
124 #if defined(CONFIG_YABEL_DIRECTHW) && (CONFIG_YABEL_DIRECTHW == 1)
125 u8 my_inb(X86EMU_pioAddr addr)
130 DEBUG_PRINTF_IO("inb(0x%04x) = 0x%02x\n", addr, val);
135 u16 my_inw(X86EMU_pioAddr addr)
140 DEBUG_PRINTF_IO("inw(0x%04x) = 0x%04x\n", addr, val);
145 u32 my_inl(X86EMU_pioAddr addr)
150 DEBUG_PRINTF_IO("inl(0x%04x) = 0x%08x\n", addr, val);
155 void my_outb(X86EMU_pioAddr addr, u8 val)
157 DEBUG_PRINTF_IO("outb(0x%02x, 0x%04x)\n", val, addr);
161 void my_outw(X86EMU_pioAddr addr, u16 val)
163 DEBUG_PRINTF_IO("outw(0x%04x, 0x%04x)\n", val, addr);
167 void my_outl(X86EMU_pioAddr addr, u32 val)
169 DEBUG_PRINTF_IO("outl(0x%08x, 0x%04x)\n", val, addr);
175 u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size);
176 void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size);
177 u8 handle_port_61h(void);
180 my_inb(X86EMU_pioAddr addr)
183 unsigned long translated_addr = addr;
184 u8 translated = biosemu_dev_translate_address(&translated_addr);
185 if (translated != 0) {
186 //translation successfull, access Device I/O (BAR or Legacy...)
187 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
189 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
190 rval = read_io((void *)translated_addr, 1);
191 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __func__,
197 //8254 KB Controller / Timer Port
198 // rval = handle_port_61h();
200 //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
207 // PCI Config Mechanism 1 Ports
208 return (u8) pci_cfg_read(addr, 1);
211 CHECK_DBG(DEBUG_INTR) {
214 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
216 // no break, intentional fall-through to default!!
219 ("%s(%04x) reading from bios_device.io_buffer\n",
221 rval = *((u8 *) (bios_device.io_buffer + addr));
222 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
223 __func__, addr, rval);
231 my_inw(X86EMU_pioAddr addr)
233 unsigned long translated_addr = addr;
234 u8 translated = biosemu_dev_translate_address(&translated_addr);
235 if (translated != 0) {
236 //translation successfull, access Device I/O (BAR or Legacy...)
237 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
239 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
241 if ((translated_addr & (u64) 0x1) == 0) {
242 // 16 bit aligned access...
243 u16 tempval = read_io((void *)translated_addr, 2);
244 //little endian conversion
245 rval = in16le((void *) &tempval);
247 // unaligned access, read single bytes, little-endian
248 rval = (read_io((void *)translated_addr, 1) << 8)
249 | (read_io((void *)(translated_addr + 1), 1));
251 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
258 //PCI Config Mechanism 1
259 return (u16) pci_cfg_read(addr, 2);
263 ("%s(%04x) reading from bios_device.io_buffer\n",
266 in16le((void *) bios_device.io_buffer + addr);
267 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
268 __func__, addr, rval);
276 my_inl(X86EMU_pioAddr addr)
278 unsigned long translated_addr = addr;
279 u8 translated = biosemu_dev_translate_address(&translated_addr);
280 if (translated != 0) {
281 //translation successfull, access Device I/O (BAR or Legacy...)
282 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
284 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
286 if ((translated_addr & (u64) 0x3) == 0) {
287 // 32 bit aligned access...
288 u32 tempval = read_io((void *) translated_addr, 4);
289 //little endian conversion
290 rval = in32le((void *) &tempval);
292 // unaligned access, read single bytes, little-endian
293 rval = (read_io((void *)(translated_addr), 1) << 24)
294 | (read_io((void *)(translated_addr + 1), 1) << 16)
295 | (read_io((void *)(translated_addr + 2), 1) << 8)
296 | (read_io((void *)(translated_addr + 3), 1));
298 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
304 //PCI Config Mechanism 1
305 return pci_cfg_read(addr, 4);
309 ("%s(%04x) reading from bios_device.io_buffer\n",
312 in32le((void *) bios_device.io_buffer + addr);
313 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
314 __func__, addr, rval);
322 my_outb(X86EMU_pioAddr addr, u8 val)
324 unsigned long translated_addr = addr;
325 u8 translated = biosemu_dev_translate_address(&translated_addr);
326 if (translated != 0) {
327 //translation successfull, access Device I/O (BAR or Legacy...)
328 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
329 __func__, addr, val);
330 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
331 write_io((void *) translated_addr, val, 1);
332 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__,
340 // PCI Config Mechanism 1 Ports
341 pci_cfg_write(addr, val, 1);
345 ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
346 __func__, addr, val);
347 *((u8 *) (bios_device.io_buffer + addr)) = val;
354 my_outw(X86EMU_pioAddr addr, u16 val)
356 unsigned long translated_addr = addr;
357 u8 translated = biosemu_dev_translate_address(&translated_addr);
358 if (translated != 0) {
359 //translation successfull, access Device I/O (BAR or Legacy...)
360 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
361 __func__, addr, val);
362 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
363 if ((translated_addr & (u64) 0x1) == 0) {
364 // little-endian conversion
365 u16 tempval = in16le((void *) &val);
366 // 16 bit aligned access...
367 write_io((void *) translated_addr, tempval, 2);
369 // unaligned access, write single bytes, little-endian
370 write_io(((void *) (translated_addr + 1)),
371 (u8) ((val & 0xFF00) >> 8), 1);
372 write_io(((void *) translated_addr),
373 (u8) (val & 0x00FF), 1);
375 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
381 // PCI Config Mechanism 1 Ports
382 pci_cfg_write(addr, val, 2);
386 ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
387 __func__, addr, val);
388 out16le((void *) bios_device.io_buffer + addr, val);
395 my_outl(X86EMU_pioAddr addr, u32 val)
397 unsigned long translated_addr = addr;
398 u8 translated = biosemu_dev_translate_address(&translated_addr);
399 if (translated != 0) {
400 //translation successfull, access Device I/O (BAR or Legacy...)
401 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
402 __func__, addr, val);
403 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
404 if ((translated_addr & (u64) 0x3) == 0) {
405 // little-endian conversion
406 u32 tempval = in32le((void *) &val);
407 // 32 bit aligned access...
408 write_io((void *) translated_addr, tempval, 4);
410 // unaligned access, write single bytes, little-endian
411 write_io(((void *) translated_addr + 3),
412 (u8) ((val & 0xFF000000) >> 24), 1);
413 write_io(((void *) translated_addr + 2),
414 (u8) ((val & 0x00FF0000) >> 16), 1);
415 write_io(((void *) translated_addr + 1),
416 (u8) ((val & 0x0000FF00) >> 8), 1);
417 write_io(((void *) translated_addr),
418 (u8) (val & 0x000000FF), 1);
420 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
425 // PCI Config Mechanism 1 Ports
426 pci_cfg_write(addr, val, 4);
430 ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
431 __func__, addr, val);
432 out32le((void *) bios_device.io_buffer + addr, val);
439 pci_cfg_read(X86EMU_pioAddr addr, u8 size)
441 u32 rval = 0xFFFFFFFF;
443 if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
444 // PCI Configuration Mechanism 1 step 1
445 // write to 0xCF8, sets bus, device, function and Config Space offset
446 // later read from 0xCFC-0xCFF returns the value...
448 u32 port_cf8_val = my_inl(0xCF8);
449 if ((port_cf8_val & 0x80000000) != 0) {
450 //highest bit enables config space mapping
451 bus = (port_cf8_val & 0x00FF0000) >> 16;
452 devfn = (port_cf8_val & 0x0000FF00) >> 8;
453 offs = (port_cf8_val & 0x000000FF);
454 offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
455 DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
456 __func__, bus, devfn, offs);
457 #if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
458 dev = dev_find_slot(bus, devfn);
459 DEBUG_PRINTF_INTR("%s(): dev_find_slot() returned: %s\n",
460 __func__, dev_path(dev));
462 // fail accesses to non-existent devices...
464 dev = bios_device.dev;
465 if ((bus != bios_device.bus)
466 || (devfn != bios_device.devfn)) {
467 // fail accesses to any device but ours...
470 ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
471 __func__, bus, bios_device.bus, devfn,
472 bios_device.devfn, offs);
477 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
480 rval = pci_read_config8(dev, offs);
483 rval = pci_read_config16(dev, offs);
486 rval = pci_read_config32(dev, offs);
491 (u32) rtas_pci_config_read(bios_device.
497 ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
498 __func__, addr, offs, size, rval);
506 pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
508 if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
509 // PCI Configuration Mechanism 1 step 1
510 // write to 0xCF8, sets bus, device, function and Config Space offset
511 // later write to 0xCFC-0xCFF sets the value...
513 u32 port_cf8_val = my_inl(0xCF8);
514 if ((port_cf8_val & 0x80000000) != 0) {
515 //highest bit enables config space mapping
516 bus = (port_cf8_val & 0x00FF0000) >> 16;
517 devfn = (port_cf8_val & 0x0000FF00) >> 8;
518 offs = (port_cf8_val & 0x000000FF);
519 offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
520 if ((bus != bios_device.bus)
521 || (devfn != bios_device.devfn)) {
522 // fail accesses to any device but ours...
524 ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
525 bus, devfn >> 3, devfn & 7, offs);
528 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
531 pci_write_config8(bios_device.dev, offs, val);
534 pci_write_config16(bios_device.dev, offs, val);
537 pci_write_config32(bios_device.dev, offs, val);
541 rtas_pci_config_write(bios_device.puid,
542 size, bus, devfn, offs,
546 ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
547 __func__, addr, offs, size, val);
554 handle_port_61h(void)
556 static u64 last_time = 0;
557 u64 curr_time = get_time();
558 u64 time_diff; // time since last call
559 u32 period_ticks; // length of a period in ticks
560 u32 nr_periods; //number of periods passed since last call
561 // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
562 time_diff = curr_time - last_time;
563 // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
564 // TODO: as long as the frequency does not change, we should not calculate this every time
565 period_ticks = (15 * tb_freq) / 1000000;
566 nr_periods = time_diff / period_ticks;
567 // if the number if ticks passed since last call is odd, we toggle bit 4
568 if ((nr_periods % 2) != 0) {
569 *((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10;
571 //finally read the value from the io_buffer
572 return *((u8 *) (bios_device.io_buffer + 0x61));