blob: b50a2f1cf8b6d95c1121deeea691423d828bd11f [file] [log] [blame]
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001/******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
Martin Rotha9e1a222016-01-14 14:15:24 -07004 *
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00005 * All rights reserved.
Martin Rotha9e1a222016-01-14 14:15:24 -07006 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000030 *
31 * Contributors:
32 * IBM Corporation - initial implementation
33 *****************************************************************************/
34
35#include <types.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000036#include "compat/rtas.h"
37#include "compat/time.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000038#include "device.h"
39#include "debug.h"
40#include <x86emu/x86emu.h>
Stefan Reinauer91f14232012-12-07 16:55:12 -080041#include <device/oprom/include/io.h>
Uwe Hermann01ce6012010-03-05 10:03:50 +000042#include "io.h"
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000043
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000044#include <device/pci.h>
45#include <device/pci_ops.h>
Patrick Georgi91443042011-01-13 11:38:46 +000046#include <device/resource.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000047
Stefan Reinauer074356e2009-10-25 19:50:47 +000048#include <arch/io.h>
Edward O'Callaghana173a622014-06-17 17:05:36 +100049
Martin Rothebade5d2017-06-24 13:58:52 -060050#if IS_ENABLED(CONFIG_YABEL_DIRECTHW)
Stefan Reinauerd650e992010-02-22 04:33:13 +000051u8 my_inb(X86EMU_pioAddr addr)
52{
53 u8 val;
54
55 val = inb(addr);
Uwe Hermann01ce6012010-03-05 10:03:50 +000056 DEBUG_PRINTF_IO("inb(0x%04x) = 0x%02x\n", addr, val);
Stefan Reinauerd650e992010-02-22 04:33:13 +000057
58 return val;
59}
60
61u16 my_inw(X86EMU_pioAddr addr)
62{
63 u16 val;
64
65 val = inw(addr);
Uwe Hermann01ce6012010-03-05 10:03:50 +000066 DEBUG_PRINTF_IO("inw(0x%04x) = 0x%04x\n", addr, val);
Stefan Reinauerd650e992010-02-22 04:33:13 +000067
Stefan Reinauerd650e992010-02-22 04:33:13 +000068 return val;
69}
70
71u32 my_inl(X86EMU_pioAddr addr)
72{
73 u32 val;
74
75 val = inl(addr);
Uwe Hermann01ce6012010-03-05 10:03:50 +000076 DEBUG_PRINTF_IO("inl(0x%04x) = 0x%08x\n", addr, val);
Stefan Reinauerd650e992010-02-22 04:33:13 +000077
Stefan Reinauerd650e992010-02-22 04:33:13 +000078 return val;
79}
80
81void my_outb(X86EMU_pioAddr addr, u8 val)
82{
Uwe Hermann01ce6012010-03-05 10:03:50 +000083 DEBUG_PRINTF_IO("outb(0x%02x, 0x%04x)\n", val, addr);
Stefan Reinauerd650e992010-02-22 04:33:13 +000084 outb(val, addr);
85}
86
87void my_outw(X86EMU_pioAddr addr, u16 val)
88{
Uwe Hermann01ce6012010-03-05 10:03:50 +000089 DEBUG_PRINTF_IO("outw(0x%04x, 0x%04x)\n", val, addr);
Stefan Reinauerd650e992010-02-22 04:33:13 +000090 outw(val, addr);
91}
92
93void my_outl(X86EMU_pioAddr addr, u32 val)
94{
Uwe Hermann01ce6012010-03-05 10:03:50 +000095 DEBUG_PRINTF_IO("outl(0x%08x, 0x%04x)\n", val, addr);
Stefan Reinauerd650e992010-02-22 04:33:13 +000096 outl(val, addr);
97}
98
99#else
100
Stefan Reinauer5ae1db02010-04-13 21:29:43 +0000101static unsigned int
102read_io(void *addr, size_t sz)
103{
Martin Roth7f35d3a2017-07-23 16:22:25 -0600104 unsigned int ret;
Stefan Reinauer5ae1db02010-04-13 21:29:43 +0000105 /* since we are using inb instructions, we need the port number as 16bit value */
106 u16 port = (u16)(u32) addr;
107
Martin Roth7f35d3a2017-07-23 16:22:25 -0600108 switch (sz) {
109 case 1:
Stefan Reinauer91f14232012-12-07 16:55:12 -0800110 ret = inb(port);
Martin Roth7f35d3a2017-07-23 16:22:25 -0600111 break;
112 case 2:
Stefan Reinauer91f14232012-12-07 16:55:12 -0800113 ret = inw(port);
Martin Roth7f35d3a2017-07-23 16:22:25 -0600114 break;
115 case 4:
Stefan Reinauer91f14232012-12-07 16:55:12 -0800116 ret = inl(port);
Martin Roth7f35d3a2017-07-23 16:22:25 -0600117 break;
118 default:
119 ret = 0;
120 }
Stefan Reinauer5ae1db02010-04-13 21:29:43 +0000121
Martin Roth7f35d3a2017-07-23 16:22:25 -0600122 return ret;
Stefan Reinauer5ae1db02010-04-13 21:29:43 +0000123}
124
125static int
126write_io(void *addr, unsigned int value, size_t sz)
127{
128 u16 port = (u16)(u32) addr;
Martin Roth7f35d3a2017-07-23 16:22:25 -0600129 switch (sz) {
Stefan Reinauer5ae1db02010-04-13 21:29:43 +0000130 /* since we are using inb instructions, we need the port number as 16bit value */
Martin Roth7f35d3a2017-07-23 16:22:25 -0600131 case 1:
Stefan Reinauer91f14232012-12-07 16:55:12 -0800132 outb(value, port);
Martin Roth7f35d3a2017-07-23 16:22:25 -0600133 break;
134 case 2:
Stefan Reinauer91f14232012-12-07 16:55:12 -0800135 outw(value, port);
Martin Roth7f35d3a2017-07-23 16:22:25 -0600136 break;
137 case 4:
Stefan Reinauer91f14232012-12-07 16:55:12 -0800138 outl(value, port);
Martin Roth7f35d3a2017-07-23 16:22:25 -0600139 break;
140 default:
141 return -1;
142 }
Stefan Reinauer5ae1db02010-04-13 21:29:43 +0000143
Martin Roth7f35d3a2017-07-23 16:22:25 -0600144 return 0;
Stefan Reinauer5ae1db02010-04-13 21:29:43 +0000145}
146
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000147u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size);
148void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size);
149u8 handle_port_61h(void);
150
151u8
152my_inb(X86EMU_pioAddr addr)
153{
154 u8 rval = 0xFF;
155 unsigned long translated_addr = addr;
Patrick Georgi91443042011-01-13 11:38:46 +0000156 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000157 if (translated != 0) {
Martin Roth63373ed2013-07-08 16:24:19 -0600158 //translation successful, access Device I/O (BAR or Legacy...)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000159 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
160 addr);
161 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
162 rval = read_io((void *)translated_addr, 1);
163 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __func__,
164 addr, rval);
165 return rval;
166 } else {
167 switch (addr) {
168 case 0x61:
169 //8254 KB Controller / Timer Port
Stefan Reinauer074356e2009-10-25 19:50:47 +0000170 // rval = handle_port_61h();
171 rval = inb(0x61);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000172 //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
173 return rval;
174 break;
175 case 0xCFC:
176 case 0xCFD:
177 case 0xCFE:
178 case 0xCFF:
179 // PCI Config Mechanism 1 Ports
180 return (u8) pci_cfg_read(addr, 1);
181 break;
182 case 0x0a:
183 CHECK_DBG(DEBUG_INTR) {
184 X86EMU_trace_on();
185 }
186 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
187 //HALT_SYS();
188 // no break, intentional fall-through to default!!
189 default:
190 DEBUG_PRINTF_IO
191 ("%s(%04x) reading from bios_device.io_buffer\n",
192 __func__, addr);
193 rval = *((u8 *) (bios_device.io_buffer + addr));
194 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
195 __func__, addr, rval);
196 return rval;
197 break;
198 }
199 }
200}
201
202u16
203my_inw(X86EMU_pioAddr addr)
204{
205 unsigned long translated_addr = addr;
Patrick Georgi91443042011-01-13 11:38:46 +0000206 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000207 if (translated != 0) {
Martin Roth63373ed2013-07-08 16:24:19 -0600208 //translation successful, access Device I/O (BAR or Legacy...)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000209 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
210 addr);
211 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
212 u16 rval;
213 if ((translated_addr & (u64) 0x1) == 0) {
214 // 16 bit aligned access...
215 u16 tempval = read_io((void *)translated_addr, 2);
216 //little endian conversion
217 rval = in16le((void *) &tempval);
218 } else {
219 // unaligned access, read single bytes, little-endian
220 rval = (read_io((void *)translated_addr, 1) << 8)
221 | (read_io((void *)(translated_addr + 1), 1));
222 }
223 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
224 addr, rval);
225 return rval;
226 } else {
227 switch (addr) {
228 case 0xCFC:
229 case 0xCFE:
230 //PCI Config Mechanism 1
231 return (u16) pci_cfg_read(addr, 2);
232 break;
233 default:
234 DEBUG_PRINTF_IO
235 ("%s(%04x) reading from bios_device.io_buffer\n",
236 __func__, addr);
237 u16 rval =
238 in16le((void *) bios_device.io_buffer + addr);
239 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
240 __func__, addr, rval);
241 return rval;
242 break;
243 }
244 }
245}
246
247u32
248my_inl(X86EMU_pioAddr addr)
249{
250 unsigned long translated_addr = addr;
Patrick Georgi91443042011-01-13 11:38:46 +0000251 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000252 if (translated != 0) {
Martin Roth63373ed2013-07-08 16:24:19 -0600253 //translation successful, access Device I/O (BAR or Legacy...)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000254 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
255 addr);
256 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
257 u32 rval;
258 if ((translated_addr & (u64) 0x3) == 0) {
259 // 32 bit aligned access...
260 u32 tempval = read_io((void *) translated_addr, 4);
261 //little endian conversion
262 rval = in32le((void *) &tempval);
263 } else {
264 // unaligned access, read single bytes, little-endian
265 rval = (read_io((void *)(translated_addr), 1) << 24)
266 | (read_io((void *)(translated_addr + 1), 1) << 16)
267 | (read_io((void *)(translated_addr + 2), 1) << 8)
268 | (read_io((void *)(translated_addr + 3), 1));
269 }
270 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
271 addr, rval);
272 return rval;
273 } else {
274 switch (addr) {
275 case 0xCFC:
276 //PCI Config Mechanism 1
277 return pci_cfg_read(addr, 4);
278 break;
279 default:
280 DEBUG_PRINTF_IO
281 ("%s(%04x) reading from bios_device.io_buffer\n",
282 __func__, addr);
283 u32 rval =
284 in32le((void *) bios_device.io_buffer + addr);
285 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
286 __func__, addr, rval);
287 return rval;
288 break;
289 }
290 }
291}
292
293void
294my_outb(X86EMU_pioAddr addr, u8 val)
295{
296 unsigned long translated_addr = addr;
Patrick Georgi91443042011-01-13 11:38:46 +0000297 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000298 if (translated != 0) {
Martin Roth63373ed2013-07-08 16:24:19 -0600299 //translation successful, access Device I/O (BAR or Legacy...)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000300 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
301 __func__, addr, val);
302 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
303 write_io((void *) translated_addr, val, 1);
304 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__,
305 addr, val);
306 } else {
307 switch (addr) {
308 case 0xCFC:
309 case 0xCFD:
310 case 0xCFE:
311 case 0xCFF:
312 // PCI Config Mechanism 1 Ports
313 pci_cfg_write(addr, val, 1);
314 break;
315 default:
316 DEBUG_PRINTF_IO
317 ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
318 __func__, addr, val);
319 *((u8 *) (bios_device.io_buffer + addr)) = val;
320 break;
321 }
322 }
323}
324
325void
326my_outw(X86EMU_pioAddr addr, u16 val)
327{
328 unsigned long translated_addr = addr;
Patrick Georgi91443042011-01-13 11:38:46 +0000329 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000330 if (translated != 0) {
Martin Roth63373ed2013-07-08 16:24:19 -0600331 //translation successful, access Device I/O (BAR or Legacy...)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000332 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
333 __func__, addr, val);
334 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
335 if ((translated_addr & (u64) 0x1) == 0) {
336 // little-endian conversion
337 u16 tempval = in16le((void *) &val);
338 // 16 bit aligned access...
339 write_io((void *) translated_addr, tempval, 2);
340 } else {
341 // unaligned access, write single bytes, little-endian
342 write_io(((void *) (translated_addr + 1)),
343 (u8) ((val & 0xFF00) >> 8), 1);
344 write_io(((void *) translated_addr),
345 (u8) (val & 0x00FF), 1);
346 }
347 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
348 addr, val);
349 } else {
350 switch (addr) {
351 case 0xCFC:
352 case 0xCFE:
353 // PCI Config Mechanism 1 Ports
354 pci_cfg_write(addr, val, 2);
355 break;
356 default:
357 DEBUG_PRINTF_IO
358 ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
359 __func__, addr, val);
360 out16le((void *) bios_device.io_buffer + addr, val);
361 break;
362 }
363 }
364}
365
366void
367my_outl(X86EMU_pioAddr addr, u32 val)
368{
369 unsigned long translated_addr = addr;
Patrick Georgi91443042011-01-13 11:38:46 +0000370 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000371 if (translated != 0) {
Martin Roth63373ed2013-07-08 16:24:19 -0600372 //translation successful, access Device I/O (BAR or Legacy...)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000373 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
374 __func__, addr, val);
375 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
376 if ((translated_addr & (u64) 0x3) == 0) {
377 // little-endian conversion
378 u32 tempval = in32le((void *) &val);
379 // 32 bit aligned access...
380 write_io((void *) translated_addr, tempval, 4);
381 } else {
382 // unaligned access, write single bytes, little-endian
383 write_io(((void *) translated_addr + 3),
384 (u8) ((val & 0xFF000000) >> 24), 1);
385 write_io(((void *) translated_addr + 2),
386 (u8) ((val & 0x00FF0000) >> 16), 1);
387 write_io(((void *) translated_addr + 1),
388 (u8) ((val & 0x0000FF00) >> 8), 1);
389 write_io(((void *) translated_addr),
390 (u8) (val & 0x000000FF), 1);
391 }
392 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
393 addr, val);
394 } else {
395 switch (addr) {
396 case 0xCFC:
397 // PCI Config Mechanism 1 Ports
398 pci_cfg_write(addr, val, 4);
399 break;
400 default:
401 DEBUG_PRINTF_IO
402 ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
403 __func__, addr, val);
404 out32le((void *) bios_device.io_buffer + addr, val);
405 break;
406 }
407 }
408}
409
410u32
411pci_cfg_read(X86EMU_pioAddr addr, u8 size)
412{
413 u32 rval = 0xFFFFFFFF;
414 struct device * dev;
415 if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
416 // PCI Configuration Mechanism 1 step 1
417 // write to 0xCF8, sets bus, device, function and Config Space offset
418 // later read from 0xCFC-0xCFF returns the value...
419 u8 bus, devfn, offs;
420 u32 port_cf8_val = my_inl(0xCF8);
421 if ((port_cf8_val & 0x80000000) != 0) {
422 //highest bit enables config space mapping
423 bus = (port_cf8_val & 0x00FF0000) >> 16;
424 devfn = (port_cf8_val & 0x0000FF00) >> 8;
425 offs = (port_cf8_val & 0x000000FF);
426 offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
427 DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
428 __func__, bus, devfn, offs);
Martin Rothebade5d2017-06-24 13:58:52 -0600429#if IS_ENABLED(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000430 dev = dev_find_slot(bus, devfn);
431 DEBUG_PRINTF_INTR("%s(): dev_find_slot() returned: %s\n",
432 __func__, dev_path(dev));
433 if (dev == 0) {
434 // fail accesses to non-existent devices...
435#else
436 dev = bios_device.dev;
437 if ((bus != bios_device.bus)
438 || (devfn != bios_device.devfn)) {
439 // fail accesses to any device but ours...
440#endif
441 printf
442 ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
443 __func__, bus, bios_device.bus, devfn,
444 bios_device.devfn, offs);
445 SET_FLAG(F_CF);
446 HALT_SYS();
447 return 0;
448 } else {
Martin Rothebade5d2017-06-24 13:58:52 -0600449#if IS_ENABLED(CONFIG_PCI_OPTION_ROM_RUN_YABEL)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000450 switch (size) {
451 case 1:
452 rval = pci_read_config8(dev, offs);
453 break;
454 case 2:
455 rval = pci_read_config16(dev, offs);
456 break;
457 case 4:
458 rval = pci_read_config32(dev, offs);
459 break;
460 }
461#else
462 rval =
463 (u32) rtas_pci_config_read(bios_device.
464 puid, size,
465 bus, devfn,
466 offs);
467#endif
468 DEBUG_PRINTF_IO
469 ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
470 __func__, addr, offs, size, rval);
471 }
472 }
473 }
474 return rval;
475}
476
477void
478pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
479{
480 if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
481 // PCI Configuration Mechanism 1 step 1
482 // write to 0xCF8, sets bus, device, function and Config Space offset
483 // later write to 0xCFC-0xCFF sets the value...
484 u8 bus, devfn, offs;
485 u32 port_cf8_val = my_inl(0xCF8);
486 if ((port_cf8_val & 0x80000000) != 0) {
487 //highest bit enables config space mapping
488 bus = (port_cf8_val & 0x00FF0000) >> 16;
489 devfn = (port_cf8_val & 0x0000FF00) >> 8;
490 offs = (port_cf8_val & 0x000000FF);
491 offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
492 if ((bus != bios_device.bus)
493 || (devfn != bios_device.devfn)) {
494 // fail accesses to any device but ours...
495 printf
496 ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
497 bus, devfn >> 3, devfn & 7, offs);
Martin Rothebade5d2017-06-24 13:58:52 -0600498#if !IS_ENABLED(CONFIG_YABEL_PCI_FAKE_WRITING_OTHER_DEVICES_CONFIG)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000499 HALT_SYS();
Patrick Georgic4b2a1b2012-07-20 13:44:50 +0200500#endif
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000501 } else {
Martin Rothebade5d2017-06-24 13:58:52 -0600502#if IS_ENABLED(CONFIG_PCI_OPTION_ROM_RUN_YABEL)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000503 switch (size) {
504 case 1:
505 pci_write_config8(bios_device.dev, offs, val);
506 break;
507 case 2:
508 pci_write_config16(bios_device.dev, offs, val);
509 break;
510 case 4:
511 pci_write_config32(bios_device.dev, offs, val);
512 break;
513 }
514#else
515 rtas_pci_config_write(bios_device.puid,
516 size, bus, devfn, offs,
517 val);
518#endif
519 DEBUG_PRINTF_IO
520 ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
521 __func__, addr, offs, size, val);
522 }
523 }
524 }
525}
526
527u8
528handle_port_61h(void)
529{
530 static u64 last_time = 0;
531 u64 curr_time = get_time();
532 u64 time_diff; // time since last call
533 u32 period_ticks; // length of a period in ticks
534 u32 nr_periods; //number of periods passed since last call
535 // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
536 time_diff = curr_time - last_time;
537 // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
538 // TODO: as long as the frequency does not change, we should not calculate this every time
539 period_ticks = (15 * tb_freq) / 1000000;
540 nr_periods = time_diff / period_ticks;
541 // if the number if ticks passed since last call is odd, we toggle bit 4
542 if ((nr_periods % 2) != 0) {
543 *((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10;
544 }
545 //finally read the value from the io_buffer
546 return *((u8 *) (bios_device.io_buffer + 0x61));
547}
Stefan Reinauerd650e992010-02-22 04:33:13 +0000548#endif