soc/intel/alderlake: Add ADL-P 4+4 with 28W TDP
[coreboot.git] / src / device / oprom / yabel / io.c
blobed8db1a6a0cf30f44e096753ac35562dac8c098b
1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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.
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.
31 * Contributors:
32 * IBM Corporation - initial implementation
33 *****************************************************************************/
35 #include <types.h>
36 #include "compat/rtas.h"
37 #include "compat/time.h"
38 #include "device.h"
39 #include "debug.h"
40 #include <x86emu/x86emu.h>
41 #include <device/oprom/include/io.h>
42 #include "io.h"
44 #include <device/pci.h>
45 #include <device/pci_ops.h>
46 #include <device/resource.h>
48 #include <arch/io.h>
50 #if CONFIG(YABEL_DIRECTHW)
51 u8 my_inb(X86EMU_pioAddr addr)
53 u8 val;
55 val = inb(addr);
56 DEBUG_PRINTF_IO("inb(0x%04x) = 0x%02x\n", addr, val);
58 return val;
61 u16 my_inw(X86EMU_pioAddr addr)
63 u16 val;
65 val = inw(addr);
66 DEBUG_PRINTF_IO("inw(0x%04x) = 0x%04x\n", addr, val);
68 return val;
71 u32 my_inl(X86EMU_pioAddr addr)
73 u32 val;
75 val = inl(addr);
76 DEBUG_PRINTF_IO("inl(0x%04x) = 0x%08x\n", addr, val);
78 return val;
81 void my_outb(X86EMU_pioAddr addr, u8 val)
83 DEBUG_PRINTF_IO("outb(0x%02x, 0x%04x)\n", val, addr);
84 outb(val, addr);
87 void my_outw(X86EMU_pioAddr addr, u16 val)
89 DEBUG_PRINTF_IO("outw(0x%04x, 0x%04x)\n", val, addr);
90 outw(val, addr);
93 void my_outl(X86EMU_pioAddr addr, u32 val)
95 DEBUG_PRINTF_IO("outl(0x%08x, 0x%04x)\n", val, addr);
96 outl(val, addr);
99 #else
101 static unsigned int
102 read_io(void *addr, size_t sz)
104 unsigned int ret;
105 /* since we are using inb instructions, we need the port number as 16bit value */
106 u16 port = (u16)(uintptr_t) addr;
108 switch (sz) {
109 case 1:
110 ret = inb(port);
111 break;
112 case 2:
113 ret = inw(port);
114 break;
115 case 4:
116 ret = inl(port);
117 break;
118 default:
119 ret = 0;
122 return ret;
125 static int
126 write_io(void *addr, unsigned int value, size_t sz)
128 u16 port = (u16)(uintptr_t) addr;
129 switch (sz) {
130 /* since we are using inb instructions, we need the port number as 16bit value */
131 case 1:
132 outb(value, port);
133 break;
134 case 2:
135 outw(value, port);
136 break;
137 case 4:
138 outl(value, port);
139 break;
140 default:
141 return -1;
144 return 0;
147 u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size);
148 void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size);
149 u8 handle_port_61h(void);
152 my_inb(X86EMU_pioAddr addr)
154 u8 rval = 0xFF;
155 unsigned long translated_addr = addr;
156 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
157 if (translated != 0) {
158 //translation successful, access Device I/O (BAR or Legacy...)
159 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
170 // rval = handle_port_61h();
171 rval = inb(0x61);
172 //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();
186 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
187 __fallthrough;
188 default:
189 DEBUG_PRINTF_IO
190 ("%s(%04x) reading from bios_device.io_buffer\n",
191 __func__, addr);
192 rval = *((u8 *) (bios_device.io_buffer + addr));
193 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
194 __func__, addr, rval);
195 return rval;
196 break;
202 my_inw(X86EMU_pioAddr addr)
204 unsigned long translated_addr = addr;
205 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
206 if (translated != 0) {
207 //translation successful, access Device I/O (BAR or Legacy...)
208 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
209 addr);
210 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
211 u16 rval;
212 if ((translated_addr & (u64) 0x1) == 0) {
213 // 16 bit aligned access...
214 u16 tempval = read_io((void *)translated_addr, 2);
215 //little endian conversion
216 rval = in16le((void *) &tempval);
217 } else {
218 // unaligned access, read single bytes, little-endian
219 rval = (read_io((void *)translated_addr, 1) << 8)
220 | (read_io((void *)(translated_addr + 1), 1));
222 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
223 addr, rval);
224 return rval;
225 } else {
226 switch (addr) {
227 case 0xCFC:
228 case 0xCFE:
229 //PCI Config Mechanism 1
230 return (u16) pci_cfg_read(addr, 2);
231 break;
232 default:
233 DEBUG_PRINTF_IO
234 ("%s(%04x) reading from bios_device.io_buffer\n",
235 __func__, addr);
236 u16 rval =
237 in16le((void *) bios_device.io_buffer + addr);
238 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
239 __func__, addr, rval);
240 return rval;
241 break;
247 my_inl(X86EMU_pioAddr addr)
249 unsigned long translated_addr = addr;
250 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
251 if (translated != 0) {
252 //translation successful, access Device I/O (BAR or Legacy...)
253 DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
254 addr);
255 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
256 u32 rval;
257 if ((translated_addr & (u64) 0x3) == 0) {
258 // 32 bit aligned access...
259 u32 tempval = read_io((void *) translated_addr, 4);
260 //little endian conversion
261 rval = in32le((void *) &tempval);
262 } else {
263 // unaligned access, read single bytes, little-endian
264 rval = (read_io((void *)(translated_addr), 1) << 24)
265 | (read_io((void *)(translated_addr + 1), 1) << 16)
266 | (read_io((void *)(translated_addr + 2), 1) << 8)
267 | (read_io((void *)(translated_addr + 3), 1));
269 DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
270 addr, rval);
271 return rval;
272 } else {
273 switch (addr) {
274 case 0xCFC:
275 //PCI Config Mechanism 1
276 return pci_cfg_read(addr, 4);
277 break;
278 default:
279 DEBUG_PRINTF_IO
280 ("%s(%04x) reading from bios_device.io_buffer\n",
281 __func__, addr);
282 u32 rval =
283 in32le((void *) bios_device.io_buffer + addr);
284 DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
285 __func__, addr, rval);
286 return rval;
287 break;
292 void
293 my_outb(X86EMU_pioAddr addr, u8 val)
295 unsigned long translated_addr = addr;
296 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
297 if (translated != 0) {
298 //translation successful, access Device I/O (BAR or Legacy...)
299 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
300 __func__, addr, val);
301 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
302 write_io((void *) translated_addr, val, 1);
303 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__,
304 addr, val);
305 } else {
306 switch (addr) {
307 case 0xCFC:
308 case 0xCFD:
309 case 0xCFE:
310 case 0xCFF:
311 // PCI Config Mechanism 1 Ports
312 pci_cfg_write(addr, val, 1);
313 break;
314 default:
315 DEBUG_PRINTF_IO
316 ("%s(%04x,%02x) writing to bios_device.io_buffer\n",
317 __func__, addr, val);
318 *((u8 *) (bios_device.io_buffer + addr)) = val;
319 break;
324 void
325 my_outw(X86EMU_pioAddr addr, u16 val)
327 unsigned long translated_addr = addr;
328 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
329 if (translated != 0) {
330 //translation successful, access Device I/O (BAR or Legacy...)
331 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
332 __func__, addr, val);
333 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
334 if ((translated_addr & (u64) 0x1) == 0) {
335 // little-endian conversion
336 u16 tempval = in16le((void *) &val);
337 // 16 bit aligned access...
338 write_io((void *) translated_addr, tempval, 2);
339 } else {
340 // unaligned access, write single bytes, little-endian
341 write_io(((void *) (translated_addr + 1)),
342 (u8) ((val & 0xFF00) >> 8), 1);
343 write_io(((void *) translated_addr),
344 (u8) (val & 0x00FF), 1);
346 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
347 addr, val);
348 } else {
349 switch (addr) {
350 case 0xCFC:
351 case 0xCFE:
352 // PCI Config Mechanism 1 Ports
353 pci_cfg_write(addr, val, 2);
354 break;
355 default:
356 DEBUG_PRINTF_IO
357 ("%s(%04x,%04x) writing to bios_device.io_buffer\n",
358 __func__, addr, val);
359 out16le((void *) bios_device.io_buffer + addr, val);
360 break;
365 void
366 my_outl(X86EMU_pioAddr addr, u32 val)
368 unsigned long translated_addr = addr;
369 u8 translated = biosemu_dev_translate_address(IORESOURCE_IO, &translated_addr);
370 if (translated != 0) {
371 //translation successful, access Device I/O (BAR or Legacy...)
372 DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
373 __func__, addr, val);
374 //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
375 if ((translated_addr & (u64) 0x3) == 0) {
376 // little-endian conversion
377 u32 tempval = in32le((void *) &val);
378 // 32 bit aligned access...
379 write_io((void *) translated_addr, tempval, 4);
380 } else {
381 // unaligned access, write single bytes, little-endian
382 write_io(((void *) translated_addr + 3),
383 (u8) ((val & 0xFF000000) >> 24), 1);
384 write_io(((void *) translated_addr + 2),
385 (u8) ((val & 0x00FF0000) >> 16), 1);
386 write_io(((void *) translated_addr + 1),
387 (u8) ((val & 0x0000FF00) >> 8), 1);
388 write_io(((void *) translated_addr),
389 (u8) (val & 0x000000FF), 1);
391 DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
392 addr, val);
393 } else {
394 switch (addr) {
395 case 0xCFC:
396 // PCI Config Mechanism 1 Ports
397 pci_cfg_write(addr, val, 4);
398 break;
399 default:
400 DEBUG_PRINTF_IO
401 ("%s(%04x,%08x) writing to bios_device.io_buffer\n",
402 __func__, addr, val);
403 out32le((void *) bios_device.io_buffer + addr, val);
404 break;
410 pci_cfg_read(X86EMU_pioAddr addr, u8 size)
412 u32 port_cf8_val = 0;
413 u32 rval = 0xFFFFFFFF;
414 struct device *dev = NULL;
415 u8 bus, devfn, offs;
417 // PCI Configuration Mechanism 1 step 1
418 // write to 0xCF8, sets bus, device, function and Config Space offset
419 // later read from 0xCFC-0xCFF returns the value...
420 if ((addr >= 0xCFC) && ((addr + size) <= 0xD00))
421 port_cf8_val = my_inl(0xCF8);
423 if ((port_cf8_val & 0x80000000) == 0)
424 return rval;
426 //highest bit enables config space mapping
427 bus = (port_cf8_val & 0x00FF0000) >> 16;
428 devfn = (port_cf8_val & 0x0000FF00) >> 8;
429 offs = (port_cf8_val & 0x000000FF);
430 offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
431 DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
432 __func__, bus, devfn, offs);
434 if ((bus == bios_device.bus) && (devfn == bios_device.devfn)) {
435 dev = bios_device.dev;
436 } else if (CONFIG(YABEL_PCI_ACCESS_OTHER_DEVICES)) {
437 dev = pcidev_path_on_bus(bus, devfn);
438 DEBUG_PRINTF_INTR("%s(): pcidev_path_on_bus() returned: %s\n",
439 __func__, dev_path(dev));
442 if (dev == NULL) {
443 printf
444 ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
445 __func__, bus, bios_device.bus, devfn,
446 bios_device.devfn, offs);
447 SET_FLAG(F_CF);
448 HALT_SYS();
449 return 0;
452 if (CONFIG(PCI_OPTION_ROM_RUN_YABEL)) {
453 switch (size) {
454 case 1:
455 rval = pci_read_config8(dev, offs);
456 break;
457 case 2:
458 rval = pci_read_config16(dev, offs);
459 break;
460 case 4:
461 rval = pci_read_config32(dev, offs);
462 break;
464 } else {
465 rval = (u32) rtas_pci_config_read(bios_device.puid, size, bus, devfn, offs);
468 DEBUG_PRINTF_IO
469 ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
470 __func__, addr, offs, size, rval);
472 return rval;
475 void
476 pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
478 struct device *dev = NULL;
479 u32 port_cf8_val = 0;
480 u8 bus, devfn, offs;
482 // PCI Configuration Mechanism 1 step 1
483 // write to 0xCF8, sets bus, device, function and Config Space offset
484 // later write to 0xCFC-0xCFF sets the value...
486 if ((addr >= 0xCFC) && ((addr + size) <= 0xD00))
487 port_cf8_val = my_inl(0xCF8);
489 if ((port_cf8_val & 0x80000000) == 0)
490 return;
492 //highest bit enables config space mapping
493 bus = (port_cf8_val & 0x00FF0000) >> 16;
494 devfn = (port_cf8_val & 0x0000FF00) >> 8;
495 offs = (port_cf8_val & 0x000000FF);
496 offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
498 if ((bus == bios_device.bus) && (devfn == bios_device.devfn)) {
499 dev = bios_device.dev;
500 } else {
501 printf
502 ("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
503 bus, devfn >> 3, devfn & 7, offs);
505 if (CONFIG(YABEL_PCI_FAKE_WRITING_OTHER_DEVICES_CONFIG))
506 return;
507 // fail accesses to any device but ours...
508 HALT_SYS();
511 if (CONFIG(PCI_OPTION_ROM_RUN_YABEL)) {
512 switch (size) {
513 case 1:
514 pci_write_config8(dev, offs, val);
515 break;
516 case 2:
517 pci_write_config16(dev, offs, val);
518 break;
519 case 4:
520 pci_write_config32(dev, offs, val);
521 break;
523 } else {
524 rtas_pci_config_write(bios_device.puid, size, bus, devfn, offs, val);
527 DEBUG_PRINTF_IO
528 ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
529 __func__, addr, offs, size, val);
533 handle_port_61h(void)
535 static u64 last_time = 0;
536 u64 curr_time = get_time();
537 u64 time_diff; // time since last call
538 u32 period_ticks; // length of a period in ticks
539 u32 nr_periods; //number of periods passed since last call
540 // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
541 time_diff = curr_time - last_time;
542 // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
543 // TODO: as long as the frequency does not change, we should not calculate this every time
544 period_ticks = (15 * tb_freq) / 1000000;
545 nr_periods = time_diff / period_ticks;
546 // if the number if ticks passed since last call is odd, we toggle bit 4
547 if ((nr_periods % 2) != 0) {
548 *((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10;
550 //finally read the value from the io_buffer
551 return *((u8 *) (bios_device.io_buffer + 0x61));
553 #endif