soc/intel/alderlake: Add ADL-P 4+4 with 28W TDP
[coreboot.git] / src / device / oprom / yabel / mem.c
blobfa6959e0e41f17db976730c73790c1ec4e2dd1fb
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 "debug.h"
37 #include "device.h"
38 #include "x86emu/x86emu.h"
39 #include "biosemu.h"
40 #include "mem.h"
41 #include "compat/time.h"
42 #include <device/resource.h>
44 #if !CONFIG(YABEL_DIRECTHW) || !CONFIG(YABEL_DIRECTHW)
46 // define a check for access to certain (virtual) memory regions (interrupt handlers, BIOS Data Area, ...)
47 #if CONFIG(X86EMU_DEBUG)
48 static u8 in_check = 0; // to avoid recursion...
50 static inline void DEBUG_CHECK_VMEM_READ(u32 _addr, u32 _rval)
52 u16 ebda_segment;
53 u32 ebda_size;
54 if (!((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)))
55 return;
56 in_check = 1;
57 /* determine ebda_segment and size
58 * since we are using my_rdx calls, make sure, this is after setting in_check! */
59 /* offset 03 in BDA is EBDA segment */
60 ebda_segment = my_rdw(0x40e);
61 /* first value in ebda is size in KB */
62 ebda_size = my_rdb(ebda_segment << 4) * 1024;
63 /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */
64 if (_addr < 0x400) {
65 DEBUG_PRINTF_CS_IP("%s: read from Interrupt Vector %x --> %x\n",
66 __func__, _addr / 4, _rval);
68 /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/
69 else if ((_addr >= 0x400) && (_addr < 0x500)) {
70 DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Area: addr: %x --> %x\n",
71 __func__, _addr, _rval);
72 /* dump registers */
73 /* x86emu_dump_xregs(); */
75 /* access to first 64k of memory... */
76 else if (_addr < 0x10000) {
77 DEBUG_PRINTF_CS_IP("%s: read from segment 0000h: addr: %x --> %x\n",
78 __func__, _addr, _rval);
79 /* dump registers */
80 /* x86emu_dump_xregs(); */
82 /* read from PMM_CONV_SEGMENT */
83 else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) {
84 DEBUG_PRINTF_CS_IP("%s: read from PMM Segment %04xh: addr: %x --> %x\n",
85 __func__, PMM_CONV_SEGMENT, _addr, _rval);
86 /* HALT_SYS(); */
87 /* dump registers */
88 /* x86emu_dump_xregs(); */
90 /* read from PNP_DATA_SEGMENT */
91 else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) {
92 DEBUG_PRINTF_CS_IP("%s: read from PnP Data Segment %04xh: addr: %x --> %x\n",
93 __func__, PNP_DATA_SEGMENT, _addr, _rval);
94 /* HALT_SYS(); */
95 /* dump registers */
96 /* x86emu_dump_xregs(); */
98 /* read from EBDA Segment */
99 else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) {
100 DEBUG_PRINTF_CS_IP("%s: read from Extended BIOS Data Area %04xh, size: %04x: addr: %x --> %x\n",
101 __func__, ebda_segment, ebda_size, _addr, _rval);
103 /* read from BIOS_DATA_SEGMENT */
104 else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) {
105 DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Segment %04xh: addr: %x --> %x\n",
106 __func__, BIOS_DATA_SEGMENT, _addr, _rval);
107 /* for PMM debugging */
108 /*if (_addr == BIOS_DATA_SEGMENT << 4) {
109 X86EMU_trace_on();
110 M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
112 /* dump registers */
113 /* x86emu_dump_xregs(); */
115 in_check = 0;
118 static inline void DEBUG_CHECK_VMEM_WRITE(u32 _addr, u32 _val)
120 u16 ebda_segment;
121 u32 ebda_size;
122 if (!((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)))
123 return;
124 in_check = 1;
125 /* determine ebda_segment and size
126 * since we are using my_rdx calls, make sure that this is after
127 * setting in_check! */
128 /* offset 03 in BDA is EBDA segment */
129 ebda_segment = my_rdw(0x40e);
130 /* first value in ebda is size in KB */
131 ebda_size = my_rdb(ebda_segment << 4) * 1024;
132 /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */
133 if (_addr < 0x400) {
134 DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n",
135 __func__, _addr / 4, _val);
137 /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/
138 else if ((_addr >= 0x400) && (_addr < 0x500)) {
139 DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Area: addr: %x <-- %x\n",
140 __func__, _addr, _val);
141 /* dump registers */
142 /* x86emu_dump_xregs(); */
144 /* access to first 64k of memory...*/
145 else if (_addr < 0x10000) {
146 DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n",
147 __func__, _addr, _val);
148 /* dump registers */
149 /* x86emu_dump_xregs(); */
151 /* write to PMM_CONV_SEGMENT... */
152 else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) {
153 DEBUG_PRINTF_CS_IP("%s: write to PMM Segment %04xh: addr: %x <-- %x\n",
154 __func__, PMM_CONV_SEGMENT, _addr, _val);
155 /* dump registers */
156 /* x86emu_dump_xregs(); */
158 /* write to PNP_DATA_SEGMENT... */
159 else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) {
160 DEBUG_PRINTF_CS_IP("%s: write to PnP Data Segment %04xh: addr: %x <-- %x\n",
161 __func__, PNP_DATA_SEGMENT, _addr, _val);
162 /* dump registers */
163 /* x86emu_dump_xregs(); */
165 /* write to EBDA Segment... */
166 else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) {
167 DEBUG_PRINTF_CS_IP("%s: write to Extended BIOS Data Area %04xh, size: %04x: addr: %x <-- %x\n",
168 __func__, ebda_segment, ebda_size, _addr, _val);
170 /* write to BIOS_DATA_SEGMENT... */
171 else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) {
172 DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Segment %04xh: addr: %x <-- %x\n",
173 __func__, BIOS_DATA_SEGMENT, _addr, _val);
174 /* dump registers */
175 /* x86emu_dump_xregs(); */
177 /* write to current CS segment... */
178 else if ((_addr < ((M.x86.R_CS << 4) | 0xffff)) && (_addr > (M.x86.R_CS << 4))) {
179 DEBUG_PRINTF_CS_IP("%s: write to CS segment %04xh: addr: %x <-- %x\n",
180 __func__, M.x86.R_CS, _addr, _val);
181 /* dump registers */
182 /* x86emu_dump_xregs(); */
184 in_check = 0;
186 #else
187 static inline void DEBUG_CHECK_VMEM_READ(u32 _addr, u32 _rval) {};
188 static inline void DEBUG_CHECK_VMEM_WRITE(u32 _addr, u32 _val) {};
189 #endif
191 //update time in BIOS Data Area
192 //DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz
193 //byte at 0x70 is timer overflow (set if midnight passed since last call to interrupt 1a function 00
194 //cur_val is the current value, of offset 6c...
195 static void
196 update_time(u32 cur_val)
198 //for convenience, we let the start of timebase be at midnight, we currently don't support
199 //real daytime anyway...
200 u64 ticks_per_day = tb_freq * 60 * 24;
201 // at 18Hz a period is ~55ms, converted to ticks (tb_freq is ticks/second)
202 u32 period_ticks = (55 * tb_freq) / 1000;
203 u64 curr_time = get_time();
204 u64 ticks_since_midnight = curr_time % ticks_per_day;
205 u32 periods_since_midnight = ticks_since_midnight / period_ticks;
206 // if periods since midnight is smaller than last value, set overflow
207 // at BDA Offset 0x70
208 if (periods_since_midnight < cur_val) {
209 my_wrb(0x470, 1);
211 // store periods since midnight at BDA offset 0x6c
212 my_wrl(0x46c, periods_since_midnight);
215 // read byte from memory
217 my_rdb(u32 addr)
219 unsigned long translated_addr = addr;
220 u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
221 u8 rval;
222 if (translated != 0) {
223 //translation successful, access VGA Memory (BAR or Legacy...)
224 DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
225 __func__, addr);
226 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
227 set_ci();
228 rval = *((u8 *) translated_addr);
229 clr_ci();
230 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __func__, addr,
231 rval);
232 return rval;
233 } else if (addr > M.mem_size) {
234 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
235 __func__, addr);
236 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
237 HALT_SYS();
238 } else {
239 /* read from virtual memory */
240 rval = *((u8 *) (M.mem_base + addr));
241 DEBUG_CHECK_VMEM_READ(addr, rval);
242 return rval;
244 return -1;
247 //read word from memory
249 my_rdw(u32 addr)
251 unsigned long translated_addr = addr;
252 u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
253 u16 rval;
254 if (translated != 0) {
255 //translation successful, access VGA Memory (BAR or Legacy...)
256 DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
257 __func__, addr);
258 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
259 // check for legacy memory, because of the remapping to BARs, the reads must
260 // be byte reads...
261 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
262 //read bytes a using my_rdb, because of the remapping to BARs
263 //words may not be contiguous in memory, so we need to translate
264 //every address...
265 rval = ((u8) my_rdb(addr)) |
266 (((u8) my_rdb(addr + 1)) << 8);
267 } else {
268 if ((translated_addr & (u64) 0x1) == 0) {
269 // 16 bit aligned access...
270 set_ci();
271 rval = in16le((void *) translated_addr);
272 clr_ci();
273 } else {
274 // unaligned access, read single bytes
275 set_ci();
276 rval = (*((u8 *) translated_addr)) |
277 (*((u8 *) translated_addr + 1) << 8);
278 clr_ci();
281 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %04x\n", __func__, addr,
282 rval);
283 return rval;
284 } else if (addr > M.mem_size) {
285 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
286 __func__, addr);
287 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
288 HALT_SYS();
289 } else {
290 /* read from virtual memory */
291 rval = in16le((void *) (M.mem_base + addr));
292 DEBUG_CHECK_VMEM_READ(addr, rval);
293 return rval;
295 return -1;
298 //read long from memory
300 my_rdl(u32 addr)
302 unsigned long translated_addr = addr;
303 u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
304 u32 rval;
305 if (translated != 0) {
306 //translation successful, access VGA Memory (BAR or Legacy...)
307 DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n",
308 __func__, addr);
309 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
310 // check for legacy memory, because of the remapping to BARs, the reads must
311 // be byte reads...
312 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
313 //read bytes a using my_rdb, because of the remapping to BARs
314 //dwords may not be contiguous in memory, so we need to translate
315 //every address...
316 rval = ((u8) my_rdb(addr)) |
317 (((u8) my_rdb(addr + 1)) << 8) |
318 (((u8) my_rdb(addr + 2)) << 16) |
319 (((u8) my_rdb(addr + 3)) << 24);
320 } else {
321 if ((translated_addr & (u64) 0x3) == 0) {
322 // 32 bit aligned access...
323 set_ci();
324 rval = in32le((void *) translated_addr);
325 clr_ci();
326 } else {
327 // unaligned access, read single bytes
328 set_ci();
329 rval = (*((u8 *) translated_addr)) |
330 (*((u8 *) translated_addr + 1) << 8) |
331 (*((u8 *) translated_addr + 2) << 16) |
332 (*((u8 *) translated_addr + 3) << 24);
333 clr_ci();
336 DEBUG_PRINTF_MEM("%s(%08x) VGA --> %08x\n", __func__, addr,
337 rval);
338 //HALT_SYS();
339 return rval;
340 } else if (addr > M.mem_size) {
341 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
342 __func__, addr);
343 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
344 HALT_SYS();
345 } else {
346 /* read from virtual memory */
347 rval = in32le((void *) (M.mem_base + addr));
348 switch (addr) {
349 case 0x46c:
350 //BDA Time Data, update it, before reading
351 update_time(rval);
352 rval = in32le((void *) (M.mem_base + addr));
353 break;
355 DEBUG_CHECK_VMEM_READ(addr, rval);
356 return rval;
358 return -1;
361 //write byte to memory
362 void
363 my_wrb(u32 addr, u8 val)
365 unsigned long translated_addr = addr;
366 u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
367 if (translated != 0) {
368 //translation successful, access VGA Memory (BAR or Legacy...)
369 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
370 __func__, addr, val);
371 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
372 set_ci();
373 *((u8 *) translated_addr) = val;
374 clr_ci();
375 } else if (addr > M.mem_size) {
376 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
377 __func__, addr);
378 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
379 HALT_SYS();
380 } else {
381 /* write to virtual memory */
382 DEBUG_CHECK_VMEM_WRITE(addr, val);
383 *((u8 *) (M.mem_base + addr)) = val;
387 void
388 my_wrw(u32 addr, u16 val)
390 unsigned long translated_addr = addr;
391 u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
392 if (translated != 0) {
393 //translation successful, access VGA Memory (BAR or Legacy...)
394 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
395 __func__, addr, val);
396 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
397 // check for legacy memory, because of the remapping to BARs, the reads must
398 // be byte reads...
399 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
400 //read bytes a using my_rdb, because of the remapping to BARs
401 //words may not be contiguous in memory, so we need to translate
402 //every address...
403 my_wrb(addr, (u8) (val & 0x00FF));
404 my_wrb(addr + 1, (u8) ((val & 0xFF00) >> 8));
405 } else {
406 if ((translated_addr & (u64) 0x1) == 0) {
407 // 16 bit aligned access...
408 set_ci();
409 out16le((void *) translated_addr, val);
410 clr_ci();
411 } else {
412 // unaligned access, write single bytes
413 set_ci();
414 *((u8 *) translated_addr) =
415 (u8) (val & 0x00FF);
416 *((u8 *) translated_addr + 1) =
417 (u8) ((val & 0xFF00) >> 8);
418 clr_ci();
421 } else if (addr > M.mem_size) {
422 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
423 __func__, addr);
424 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
425 HALT_SYS();
426 } else {
427 /* write to virtual memory */
428 DEBUG_CHECK_VMEM_WRITE(addr, val);
429 out16le((void *) (M.mem_base + addr), val);
432 void
433 my_wrl(u32 addr, u32 val)
435 unsigned long translated_addr = addr;
436 u8 translated = biosemu_dev_translate_address(IORESOURCE_MEM, &translated_addr);
437 if (translated != 0) {
438 //translation successful, access VGA Memory (BAR or Legacy...)
439 DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
440 __func__, addr, val);
441 //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
442 // check for legacy memory, because of the remapping to BARs, the reads must
443 // be byte reads...
444 if ((addr >= 0xa0000) && (addr < 0xc0000)) {
445 //read bytes a using my_rdb, because of the remapping to BARs
446 //words may not be contiguous in memory, so we need to translate
447 //every address...
448 my_wrb(addr, (u8) (val & 0x000000FF));
449 my_wrb(addr + 1, (u8) ((val & 0x0000FF00) >> 8));
450 my_wrb(addr + 2, (u8) ((val & 0x00FF0000) >> 16));
451 my_wrb(addr + 3, (u8) ((val & 0xFF000000) >> 24));
452 } else {
453 if ((translated_addr & (u64) 0x3) == 0) {
454 // 32 bit aligned access...
455 set_ci();
456 out32le((void *) translated_addr, val);
457 clr_ci();
458 } else {
459 // unaligned access, write single bytes
460 set_ci();
461 *((u8 *) translated_addr) =
462 (u8) (val & 0x000000FF);
463 *((u8 *) translated_addr + 1) =
464 (u8) ((val & 0x0000FF00) >> 8);
465 *((u8 *) translated_addr + 2) =
466 (u8) ((val & 0x00FF0000) >> 16);
467 *((u8 *) translated_addr + 3) =
468 (u8) ((val & 0xFF000000) >> 24);
469 clr_ci();
472 } else if (addr > M.mem_size) {
473 DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
474 __func__, addr);
475 //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
476 HALT_SYS();
477 } else {
478 /* write to virtual memory */
479 DEBUG_CHECK_VMEM_WRITE(addr, val);
480 out32le((void *) (M.mem_base + addr), val);
483 #else
485 my_rdb(u32 addr)
487 return rdb(addr);
491 my_rdw(u32 addr)
493 return rdw(addr);
497 my_rdl(u32 addr)
499 return rdl(addr);
502 void
503 my_wrb(u32 addr, u8 val)
505 wrb(addr, val);
508 void
509 my_wrw(u32 addr, u16 val)
511 wrw(addr, val);
514 void
515 my_wrl(u32 addr, u32 val)
517 wrl(addr, val);
519 #endif