drop COREBOOT_V2 and COREBOOT_V4 define. We're not sharing code with v3
[coreboot.git] / util / x86emu / 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
21 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
22 #include <device/pci.h>
23 #include <device/pci_ops.h>
24 #endif
25
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);
29
30 //defined in net-snk/kernel/timer.c
31 extern u64 get_time(void);
32
33 #ifdef CONFIG_ARCH_X86
34 #include <arch/io.h>
35 #else
36 // these are not used, only needed for linking,  must be overridden using X86emu_setupPioFuncs
37 // with the functions and struct below
38 void
39 outb(u8 val, u16 port)
40 {
41         printf("WARNING: outb not implemented!\n");
42         HALT_SYS();
43 }
44
45 void
46 outw(u16 val, u16 port)
47 {
48         printf("WARNING: outw not implemented!\n");
49         HALT_SYS();
50 }
51
52 void
53 outl(u32 val, u16 port)
54 {
55         printf("WARNING: outl not implemented!\n");
56         HALT_SYS();
57 }
58
59 u8
60 inb(u16 port)
61 {
62         printf("WARNING: inb not implemented!\n");
63         HALT_SYS();
64         return 0;
65 }
66
67 u16
68 inw(u16 port)
69 {
70         printf("WARNING: inw not implemented!\n");
71         HALT_SYS();
72         return 0;
73 }
74
75 u32
76 inl(u16 port)
77 {
78         printf("WARNING: inl not implemented!\n");
79         HALT_SYS();
80         return 0;
81 }
82 #endif
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);
86
87 u8
88 my_inb(X86EMU_pioAddr addr)
89 {
90         u8 rval = 0xFF;
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__,
96                                 addr);
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__,
100                                 addr, rval);
101                 return rval;
102         } else {
103                 switch (addr) {
104                 case 0x61:
105                         //8254 KB Controller / Timer Port
106                         // rval = handle_port_61h();
107                         rval = inb(0x61);
108                         //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
109                         return rval;
110                         break;
111                 case 0xCFC:
112                 case 0xCFD:
113                 case 0xCFE:
114                 case 0xCFF:
115                         // PCI Config Mechanism 1 Ports
116                         return (u8) pci_cfg_read(addr, 1);
117                         break;
118                 case 0x0a:
119                         CHECK_DBG(DEBUG_INTR) {
120                                 X86EMU_trace_on();
121                         }
122                         M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
123                         //HALT_SYS();
124                         // no break, intentional fall-through to default!!
125                 default:
126                         DEBUG_PRINTF_IO
127                             ("%s(%04x) reading from bios_device.io_buffer\n",
128                              __func__, addr);
129                         rval = *((u8 *) (bios_device.io_buffer + addr));
130                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
131                                         __func__, addr, rval);
132                         return rval;
133                         break;
134                 }
135         }
136 }
137
138 u16
139 my_inw(X86EMU_pioAddr addr)
140 {
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__,
146                                 addr);
147                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
148                 u16 rval;
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);
154                 } else {
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));
158                 }
159                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
160                                 addr, rval);
161                 return rval;
162         } else {
163                 switch (addr) {
164                 case 0xCFC:
165                 case 0xCFE:
166                         //PCI Config Mechanism 1
167                         return (u16) pci_cfg_read(addr, 2);
168                         break;
169                 default:
170                         DEBUG_PRINTF_IO
171                             ("%s(%04x) reading from bios_device.io_buffer\n",
172                              __func__, addr);
173                         u16 rval =
174                             in16le((void *) bios_device.io_buffer + addr);
175                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
176                                         __func__, addr, rval);
177                         return rval;
178                         break;
179                 }
180         }
181 }
182
183 u32
184 my_inl(X86EMU_pioAddr addr)
185 {
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__,
191                                 addr);
192                 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
193                 u32 rval;
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);
199                 } else {
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));
205                 }
206                 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
207                                 addr, rval);
208                 return rval;
209         } else {
210                 switch (addr) {
211                 case 0xCFC:
212                         //PCI Config Mechanism 1
213                         return pci_cfg_read(addr, 4);
214                         break;
215                 default:
216                         DEBUG_PRINTF_IO
217                             ("%s(%04x) reading from bios_device.io_buffer\n",
218                              __func__, addr);
219                         u32 rval =
220                             in32le((void *) bios_device.io_buffer + addr);
221                         DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
222                                         __func__, addr, rval);
223                         return rval;
224                         break;
225                 }
226         }
227 }
228
229 void
230 my_outb(X86EMU_pioAddr addr, u8 val)
231 {
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__,
241                                 addr, val);
242         } else {
243                 switch (addr) {
244                 case 0xCFC:
245                 case 0xCFD:
246                 case 0xCFE:
247                 case 0xCFF:
248                         // PCI Config Mechanism 1 Ports
249                         pci_cfg_write(addr, val, 1);
250                         break;
251                 default:
252                         DEBUG_PRINTF_IO
253                             ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
254                              __func__, addr, val);
255                         *((u8 *) (bios_device.io_buffer + addr)) = val;
256                         break;
257                 }
258         }
259 }
260
261 void
262 my_outw(X86EMU_pioAddr addr, u16 val)
263 {
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);
276                 } else {
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);
282                 }
283                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
284                                 addr, val);
285         } else {
286                 switch (addr) {
287                 case 0xCFC:
288                 case 0xCFE:
289                         // PCI Config Mechanism 1 Ports
290                         pci_cfg_write(addr, val, 2);
291                         break;
292                 default:
293                         DEBUG_PRINTF_IO
294                             ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
295                              __func__, addr, val);
296                         out16le((void *) bios_device.io_buffer + addr, val);
297                         break;
298                 }
299         }
300 }
301
302 void
303 my_outl(X86EMU_pioAddr addr, u32 val)
304 {
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);
317                 } else {
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);
327                 }
328                 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
329                                 addr, val);
330         } else {
331                 switch (addr) {
332                 case 0xCFC:
333                         // PCI Config Mechanism 1 Ports
334                         pci_cfg_write(addr, val, 4);
335                         break;
336                 default:
337                         DEBUG_PRINTF_IO
338                             ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
339                              __func__, addr, val);
340                         out32le((void *) bios_device.io_buffer + addr, val);
341                         break;
342                 }
343         }
344 }
345
346 u32
347 pci_cfg_read(X86EMU_pioAddr addr, u8 size)
348 {
349         u32 rval = 0xFFFFFFFF;
350         struct device * dev;
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...
355                 u8 bus, devfn, offs;
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));
369                         if (dev == 0) {
370                                 // fail accesses to non-existent devices...
371 #else
372                         dev = bios_device.dev;
373                         if ((bus != bios_device.bus)
374                              || (devfn != bios_device.devfn)) {
375                                 // fail accesses to any device but ours...
376 #endif
377                                 printf
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);
381                                 SET_FLAG(F_CF);
382                                 HALT_SYS();
383                                 return 0;
384                         } else {
385 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
386                                 switch (size) {
387                                         case 1:
388                                                 rval = pci_read_config8(dev, offs);
389                                                 break;
390                                         case 2:
391                                                 rval = pci_read_config16(dev, offs);
392                                                 break;
393                                         case 4:
394                                                 rval = pci_read_config32(dev, offs);
395                                                 break;
396                                 }
397 #else
398                                 rval =
399                                     (u32) rtas_pci_config_read(bios_device.
400                                                                     puid, size,
401                                                                     bus, devfn,
402                                                                     offs);
403 #endif
404                                 DEBUG_PRINTF_IO
405                                     ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
406                                      __func__, addr, offs, size, rval);
407                         }
408                 }
409         }
410         return rval;
411 }
412
413 void
414 pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
415 {
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...
420                 u8 bus, devfn, offs;
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...
431                                 printf
432                                     ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
433                                      bus, devfn >> 3, devfn & 7, offs);
434                                 HALT_SYS();
435                         } else {
436 #ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
437                                 switch (size) {
438                                         case 1:
439                                                 pci_write_config8(bios_device.dev, offs, val);
440                                                 break;
441                                         case 2:
442                                                 pci_write_config16(bios_device.dev, offs, val);
443                                                 break;
444                                         case 4:
445                                                 pci_write_config32(bios_device.dev, offs, val);
446                                                 break;
447                                 }
448 #else
449                                 rtas_pci_config_write(bios_device.puid,
450                                                       size, bus, devfn, offs,
451                                                       val);
452 #endif
453                                 DEBUG_PRINTF_IO
454                                     ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
455                                      __func__, addr, offs, size, val);
456                         }
457                 }
458         }
459 }
460
461 u8
462 handle_port_61h(void)
463 {
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;
478         }
479         //finally read the value from the io_buffer
480         return *((u8 *) (bios_device.io_buffer + 0x61));
481 }