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>
21 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
22 #include <device/pci.h>
23 #include <device/pci_ops.h>
26 // those are defined in net-snk/oflib/pci.c
27 extern unsigned int read_io(void *, size_t);
28 extern int write_io(void *, unsigned int, size_t);
30 //defined in net-snk/kernel/timer.c
31 extern u64 get_time(void);
33 #ifdef CONFIG_ARCH_X86
36 // these are not used, only needed for linking, must be overridden using X86emu_setupPioFuncs
37 // with the functions and struct below
39 outb(u8 val, u16 port)
41 printf("WARNING: outb not implemented!\n");
46 outw(u16 val, u16 port)
48 printf("WARNING: outw not implemented!\n");
53 outl(u32 val, u16 port)
55 printf("WARNING: outl not implemented!\n");
62 printf("WARNING: inb not implemented!\n");
70 printf("WARNING: inw not implemented!\n");
78 printf("WARNING: inl not implemented!\n");
83 u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size);
84 void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size);
85 u8 handle_port_61h(void);
88 my_inb(X86EMU_pioAddr addr)
91 unsigned long translated_addr = addr;
92 u8 translated = biosemu_dev_translate_address(&translated_addr);
93 if (translated != 0) {
94 //translation successfull, access Device I/O (BAR or Legacy...)
95 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
97 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
98 rval = read_io((void *)translated_addr, 1);
99 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __func__,
105 //8254 KB Controller / Timer Port
106 // rval = handle_port_61h();
108 //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
115 // PCI Config Mechanism 1 Ports
116 return (u8) pci_cfg_read(addr, 1);
119 CHECK_DBG(DEBUG_INTR) {
122 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
124 // no break, intentional fall-through to default!!
127 ("%s(%04x) reading from bios_device.io_buffer\n",
129 rval = *((u8 *) (bios_device.io_buffer + addr));
130 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
131 __func__, addr, rval);
139 my_inw(X86EMU_pioAddr addr)
141 unsigned long translated_addr = addr;
142 u8 translated = biosemu_dev_translate_address(&translated_addr);
143 if (translated != 0) {
144 //translation successfull, access Device I/O (BAR or Legacy...)
145 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
147 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
149 if ((translated_addr & (u64) 0x1) == 0) {
150 // 16 bit aligned access...
151 u16 tempval = read_io((void *)translated_addr, 2);
152 //little endian conversion
153 rval = in16le((void *) &tempval);
155 // unaligned access, read single bytes, little-endian
156 rval = (read_io((void *)translated_addr, 1) << 8)
157 | (read_io((void *)(translated_addr + 1), 1));
159 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
166 //PCI Config Mechanism 1
167 return (u16) pci_cfg_read(addr, 2);
171 ("%s(%04x) reading from bios_device.io_buffer\n",
174 in16le((void *) bios_device.io_buffer + addr);
175 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
176 __func__, addr, rval);
184 my_inl(X86EMU_pioAddr addr)
186 unsigned long translated_addr = addr;
187 u8 translated = biosemu_dev_translate_address(&translated_addr);
188 if (translated != 0) {
189 //translation successfull, access Device I/O (BAR or Legacy...)
190 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
192 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
194 if ((translated_addr & (u64) 0x3) == 0) {
195 // 32 bit aligned access...
196 u32 tempval = read_io((void *) translated_addr, 4);
197 //little endian conversion
198 rval = in32le((void *) &tempval);
200 // unaligned access, read single bytes, little-endian
201 rval = (read_io((void *)(translated_addr), 1) << 24)
202 | (read_io((void *)(translated_addr + 1), 1) << 16)
203 | (read_io((void *)(translated_addr + 2), 1) << 8)
204 | (read_io((void *)(translated_addr + 3), 1));
206 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
212 //PCI Config Mechanism 1
213 return pci_cfg_read(addr, 4);
217 ("%s(%04x) reading from bios_device.io_buffer\n",
220 in32le((void *) bios_device.io_buffer + addr);
221 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
222 __func__, addr, rval);
230 my_outb(X86EMU_pioAddr addr, u8 val)
232 unsigned long translated_addr = addr;
233 u8 translated = biosemu_dev_translate_address(&translated_addr);
234 if (translated != 0) {
235 //translation successfull, access Device I/O (BAR or Legacy...)
236 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
237 __func__, addr, val);
238 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
239 write_io((void *) translated_addr, val, 1);
240 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__,
248 // PCI Config Mechanism 1 Ports
249 pci_cfg_write(addr, val, 1);
253 ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
254 __func__, addr, val);
255 *((u8 *) (bios_device.io_buffer + addr)) = val;
262 my_outw(X86EMU_pioAddr addr, u16 val)
264 unsigned long translated_addr = addr;
265 u8 translated = biosemu_dev_translate_address(&translated_addr);
266 if (translated != 0) {
267 //translation successfull, access Device I/O (BAR or Legacy...)
268 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
269 __func__, addr, val);
270 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
271 if ((translated_addr & (u64) 0x1) == 0) {
272 // little-endian conversion
273 u16 tempval = in16le((void *) &val);
274 // 16 bit aligned access...
275 write_io((void *) translated_addr, tempval, 2);
277 // unaligned access, write single bytes, little-endian
278 write_io(((void *) (translated_addr + 1)),
279 (u8) ((val & 0xFF00) >> 8), 1);
280 write_io(((void *) translated_addr),
281 (u8) (val & 0x00FF), 1);
283 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
289 // PCI Config Mechanism 1 Ports
290 pci_cfg_write(addr, val, 2);
294 ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
295 __func__, addr, val);
296 out16le((void *) bios_device.io_buffer + addr, val);
303 my_outl(X86EMU_pioAddr addr, u32 val)
305 unsigned long translated_addr = addr;
306 u8 translated = biosemu_dev_translate_address(&translated_addr);
307 if (translated != 0) {
308 //translation successfull, access Device I/O (BAR or Legacy...)
309 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
310 __func__, addr, val);
311 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
312 if ((translated_addr & (u64) 0x3) == 0) {
313 // little-endian conversion
314 u32 tempval = in32le((void *) &val);
315 // 32 bit aligned access...
316 write_io((void *) translated_addr, tempval, 4);
318 // unaligned access, write single bytes, little-endian
319 write_io(((void *) translated_addr + 3),
320 (u8) ((val & 0xFF000000) >> 24), 1);
321 write_io(((void *) translated_addr + 2),
322 (u8) ((val & 0x00FF0000) >> 16), 1);
323 write_io(((void *) translated_addr + 1),
324 (u8) ((val & 0x0000FF00) >> 8), 1);
325 write_io(((void *) translated_addr),
326 (u8) (val & 0x000000FF), 1);
328 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
333 // PCI Config Mechanism 1 Ports
334 pci_cfg_write(addr, val, 4);
338 ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
339 __func__, addr, val);
340 out32le((void *) bios_device.io_buffer + addr, val);
347 pci_cfg_read(X86EMU_pioAddr addr, u8 size)
349 u32 rval = 0xFFFFFFFF;
351 if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
352 // PCI Configuration Mechanism 1 step 1
353 // write to 0xCF8, sets bus, device, function and Config Space offset
354 // later read from 0xCFC-0xCFF returns the value...
356 u32 port_cf8_val = my_inl(0xCF8);
357 if ((port_cf8_val & 0x80000000) != 0) {
358 //highest bit enables config space mapping
359 bus = (port_cf8_val & 0x00FF0000) >> 16;
360 devfn = (port_cf8_val & 0x0000FF00) >> 8;
361 offs = (port_cf8_val & 0x000000FF);
362 offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
363 DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
364 __func__, bus, devfn, offs);
365 #if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
366 dev = dev_find_slot(bus, devfn);
367 DEBUG_PRINTF_INTR("%s(): dev_find_slot() returned: %s\n",
368 __func__, dev_path(dev));
370 // fail accesses to non-existent devices...
372 dev = bios_device.dev;
373 if ((bus != bios_device.bus)
374 || (devfn != bios_device.devfn)) {
375 // fail accesses to any device but ours...
378 ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
379 __func__, bus, bios_device.bus, devfn,
380 bios_device.devfn, offs);
385 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
388 rval = pci_read_config8(dev, offs);
391 rval = pci_read_config16(dev, offs);
394 rval = pci_read_config32(dev, offs);
399 (u32) rtas_pci_config_read(bios_device.
405 ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
406 __func__, addr, offs, size, rval);
414 pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
416 if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
417 // PCI Configuration Mechanism 1 step 1
418 // write to 0xCF8, sets bus, device, function and Config Space offset
419 // later write to 0xCFC-0xCFF sets the value...
421 u32 port_cf8_val = my_inl(0xCF8);
422 if ((port_cf8_val & 0x80000000) != 0) {
423 //highest bit enables config space mapping
424 bus = (port_cf8_val & 0x00FF0000) >> 16;
425 devfn = (port_cf8_val & 0x0000FF00) >> 8;
426 offs = (port_cf8_val & 0x000000FF);
427 offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
428 if ((bus != bios_device.bus)
429 || (devfn != bios_device.devfn)) {
430 // fail accesses to any device but ours...
432 ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
433 bus, devfn >> 3, devfn & 7, offs);
436 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
439 pci_write_config8(bios_device.dev, offs, val);
442 pci_write_config16(bios_device.dev, offs, val);
445 pci_write_config32(bios_device.dev, offs, val);
449 rtas_pci_config_write(bios_device.puid,
450 size, bus, devfn, offs,
454 ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
455 __func__, addr, offs, size, val);
462 handle_port_61h(void)
464 static u64 last_time = 0;
465 u64 curr_time = get_time();
466 u64 time_diff; // time since last call
467 u32 period_ticks; // length of a period in ticks
468 u32 nr_periods; //number of periods passed since last call
469 // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
470 time_diff = curr_time - last_time;
471 // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
472 // TODO: as long as the frequency does not change, we should not calculate this every time
473 period_ticks = (15 * tb_freq) / 1000000;
474 nr_periods = time_diff / period_ticks;
475 // if the number if ticks passed since last call is odd, we toggle bit 4
476 if ((nr_periods % 2) != 0) {
477 *((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10;
479 //finally read the value from the io_buffer
480 return *((u8 *) (bios_device.io_buffer + 0x61));