blob: f173f5c10b1d9fd59391eb5c833bccdd1e05c14a [file] [log] [blame]
Lee Leahy9fd08952016-02-02 07:17:06 -08001/** @file
2 *
3 * Copyright (C) 2015-2016, Intel Corporation
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors may
14 * be used to endorse or promote products derived from this software without
15 * specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 *
29**/
30
31#include <cpu/x86/cr.h>
Lee Leahyce9e21a2016-06-05 18:48:31 -070032#include <cpu/x86/post_code.h>
Lee Leahy9fd08952016-02-02 07:17:06 -080033#include <soc/QuarkNcSocId.h>
Lee Leahyce9e21a2016-06-05 18:48:31 -070034#include <soc/sd.h>
Lee Leahy9fd08952016-02-02 07:17:06 -080035
36.macro RET32
37 jmp *%esp
38.endm
39
40/* ROM/SPI/MEMORY Definitions */
41.equ QUARK_DDR3_MEM_BASE_ADDRESS, (0x000000000) /* Memory Base Address = 0 */
42.equ QUARK_MAX_DDR3_MEM_SIZE_BYTES, (0x80000000) /* DDR3 Memory Size = 2GB */
43.equ QUARK_ESRAM_MEM_BASE_ADDRESS, (QUARK_DDR3_MEM_BASE_ADDRESS \
44 + QUARK_MAX_DDR3_MEM_SIZE_BYTES) /* eSRAM Memory above DDR3 */
45.equ QUARK_ESRAM_MEM_SIZE_BYTES, (0x00080000) /* eSRAM Memory Size = 512K */
46.equ QUARK_STACK_SIZE_BYTES, (0x008000) /* Quark stack size = 32K */
47.equ QUARK_STACK_BASE_ADDRESS, (QUARK_ESRAM_MEM_BASE_ADDRESS \
48 + QUARK_ESRAM_MEM_SIZE_BYTES \
49 - QUARK_STACK_SIZE_BYTES) /* Top of eSRAM - stack size */
50.equ QUARK_CMH_SIZE_BYTES, (0x0400) /* Quark Module Header size */
51.equ QUARK_ESRAM_STAGE1_BASE_ADDRESS, (QUARK_ESRAM_MEM_BASE_ADDRESS \
52 + QUARK_CMH_SIZE_BYTES) /* Start of Stage1 code in eSRAM */
53
54/* RTC/CMOS definitions */
55.equ RTC_INDEX, (0x70)
56.equ NMI_DISABLE, (0x80) /* Bit7=1 disables NMI */
57.equ RTC_DATA, (0x71)
58
59/* PCI Configuration definitions (Datasheet 5.5.1) */
60.equ PCI_CFG, (0x80000000) /* PCI configuration access mechanism */
61.equ PCI_ADDRESS_PORT, (0xCF8)
62.equ PCI_DATA_PORT, (0xCFC)
63
64/* Quark PCI devices */
65.equ HOST_BRIDGE_PFA, (0 << 11) /* B0:D0:F0 (Host Bridge) */
66.equ ILB_PFA, (0x1F << 11) /* B0:D31:F0 (Legacy Block) */
67
68/* ILB PCI Config Registers */
69.equ BDE, (0x0D4) /* BIOS Decode Enable register */
70.equ DECODE_ALL_REGIONS_ENABLE, (0xFF000000) /* Decode all BIOS ranges */
71
72/* iLB Reset Register */
73.equ ILB_RESET_REG, (0x0CF9)
74.equ CF9_WARM_RESET, (0x02)
75.equ CF9_COLD_RESET, (0x08)
76
77/* Memory Arbiter Config Registers */
78.equ AEC_CTRL_OFFSET, (0x00)
79
80/* Host Bridge Config Registers */
81.equ HMBOUND_OFFSET, (0x08)
82.equ HMBOUND_ADDRESS, (QUARK_DDR3_MEM_BASE_ADDRESS \
83 + QUARK_MAX_DDR3_MEM_SIZE_BYTES + QUARK_ESRAM_MEM_SIZE_BYTES)
84.equ HECREG_OFFSET, (0x09)
85.equ EC_BASE, (0xE0000000)
86.equ EC_ENABLE, (0x01)
87
88/* Memory Manager Config Registers */
89.equ ESRAM_ADDRESS_2G, (0x10000080)
90.equ BIMRVCTL_OFFSET, (0x19)
91.equ ENABLE_IMR_INTERRUPT, (0x80000000)
92
93/* SOC UNIT Debug Registers */
94.equ CFGSTICKY_W1_OFFSET, (0x50)
95.equ FORCE_COLD_RESET, (0x00000001)
96.equ CFGSTICKY_RW_OFFSET, (0x51)
97.equ RESET_FOR_ESRAM_LOCK, (0x00000020)
98.equ RESET_FOR_HMBOUND_LOCK, (0x00000040)
99.equ CFGNONSTICKY_W1_OFFSET, (0x52)
100.equ FORCE_WARM_RESET, (0x00000001)
101
Lee Leahyce9e21a2016-06-05 18:48:31 -0700102 .global bootblock_save_bist_and_timestamp
103
104bootblock_save_bist_and_timestamp:
105
106 /* eax: Low 32-bits of timestamp
107 * ebx: BIST result
108 * ebp: return address
109 * edx: High 32-bits of timestamp
110 */
111
112 /* No values to save since Quark does not generate a BIST value
113 * and the timestamp is not saved since future expansion in
114 * bootblock_crt0.S could use ebp and edi. This code prevents
115 * the use of the MMx registers by the default implementation.
116 */
117 jmp *%ebp
118
119 .global bootblock_pre_c_entry
120
121bootblock_pre_c_entry:
122
123 /* Get the timestamp since value from bootblock_crt0.S was discarded */
124 rdtsc
125 movl %eax, %ebp
126 movl %edx, %edi
127
128 /* Registers:
129 * ebp: Low 32-bits of timestamp
130 * edi: High 32-bits of timestamp
131 */
Lee Leahy9fd08952016-02-02 07:17:06 -0800132
133setup_esram:
134 /* Ensure cache is disabled. */
135 movl %cr0, %eax
136 orl $(CR0_CD | CR0_NW), %eax
137 invd
138 movl %eax, %cr0
139
140 /*
141 * Disable NMI operation
142 * Good convention suggests you should read back RTC data port after
143 * accessing the RTC index port.
144 */
145 movb $(NMI_DISABLE), %al
146 movw $(RTC_INDEX), %dx
147 outb %al, %dx
148 movw $(RTC_DATA), %dx
149 inb %dx, %al
150
151 /* Disable SMI (Disables SMI wire, not SMI messages) */
152 movl $((QUARK_OPCODE_READ << QNC_MCR_OP_OFFSET) \
153 | (QUARK_NC_HOST_BRIDGE_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
154 | (QNC_MSG_FSBIC_REG_HMISC << QNC_MCR_REG_OFFSET)), %ecx
155 leal L1, %esp
156 jmp stackless_SideBand_Read
157L1:
158 andl $(~SMI_EN), %eax
159 movl $((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) \
160 | (QUARK_NC_HOST_BRIDGE_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
161 | (QNC_MSG_FSBIC_REG_HMISC << QNC_MCR_REG_OFFSET)), %ecx
162 leal L2, %esp
163 jmp stackless_SideBand_Write
164L2:
165
166 /*
167 * Before we get going, check SOC Unit Registers to see if we are
168 * required to issue a warm/cold reset
169 */
170 movl $((QUARK_ALT_OPCODE_READ << QNC_MCR_OP_OFFSET) \
171 | (QUARK_SCSS_SOC_UNIT_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
172 | (CFGNONSTICKY_W1_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
173 leal L3, %esp
174 jmp stackless_SideBand_Read
175L3:
176 andl $(FORCE_WARM_RESET), %eax
177 jz TestForceColdReset /* No warm reset - branch */
178 jmp IssueWarmReset
179
180TestForceColdReset:
181 movl $((QUARK_ALT_OPCODE_READ << QNC_MCR_OP_OFFSET) \
182 | (QUARK_SCSS_SOC_UNIT_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
183 | (CFGNONSTICKY_W1_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
184 leal L4, %esp
185 jmp stackless_SideBand_Read
186L4:
187 andl $(FORCE_COLD_RESET), %eax
188 jz TestHmboundLock /* No cold reset - branch */
189 jmp IssueColdReset
190
191 /* Before setting HMBOUND, check it's not locked */
192TestHmboundLock:
193 movl $((QUARK_OPCODE_READ << QNC_MCR_OP_OFFSET) \
194 | (QUARK_NC_HOST_BRIDGE_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
195 | (HMBOUND_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
196 leal L5, %esp
197 jmp stackless_SideBand_Read
198L5:
199 andl $(HMBOUND_LOCK), %eax
200 jz ConfigHmbound /* Good configuration - branch */
201
202 /* Failed to config - store sticky bit debug */
203 movl $((QUARK_ALT_OPCODE_READ << QNC_MCR_OP_OFFSET) \
204 | (QUARK_SCSS_SOC_UNIT_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
205 | (CFGSTICKY_RW_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
206 leal L6, %esp
207 jmp stackless_SideBand_Read
208L6:
209 orl $(RESET_FOR_HMBOUND_LOCK), %eax
210 movl $((QUARK_ALT_OPCODE_WRITE << QNC_MCR_OP_OFFSET) \
211 | (QUARK_SCSS_SOC_UNIT_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
212 | (CFGSTICKY_RW_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
213 leal L7, %esp
214 jmp stackless_SideBand_Write
215L7:
216 jmp IssueWarmReset
217
218 /* Set up the HMBOUND register */
219ConfigHmbound:
220 movl $(HMBOUND_ADDRESS), %eax /* Data (Set HMBOUND location) */
221 movl $((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) \
222 | (QUARK_NC_HOST_BRIDGE_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
223 | (HMBOUND_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
224 leal L8, %esp
225 jmp stackless_SideBand_Write
226L8:
227
228 /*
229 * Enable interrupts to Remote Management Unit when a IMR/SMM/HMBOUND
230 * violation occurs.
231 */
232 movl $(ENABLE_IMR_INTERRUPT), %eax /* Set interrupt enable mask */
233 movl $((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) \
234 | (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
235 | (BIMRVCTL_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
236 leal L9, %esp
237 jmp stackless_SideBand_Write
238L9:
239
240 /* Move eSRAM memory to 2GB */
241 movl $(ESRAM_ADDRESS_2G), %eax /* Data (Set eSRAM location) */
242 movl $((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) \
243 | (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
244 | (QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK \
245 << QNC_MCR_REG_OFFSET)), %ecx
246 leal L10, %esp
247 jmp stackless_SideBand_Write
248L10:
249
250 /* Check that we're not blocked from setting the config that we want. */
251 movl $((QUARK_OPCODE_READ << QNC_MCR_OP_OFFSET) \
252 | (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
253 | (QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK \
254 << QNC_MCR_REG_OFFSET)), %ecx
255 leal L11, %esp
256 jmp stackless_SideBand_Read
257L11:
258 andl $(BLOCK_ENABLE_PG), %eax
259 jnz ConfigPci /* Good configuration - branch */
260
261 /* Failed to config - store sticky bit debug */
262 movl $((QUARK_ALT_OPCODE_READ << QNC_MCR_OP_OFFSET) \
263 | (QUARK_SCSS_SOC_UNIT_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
264 | (CFGSTICKY_RW_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
265 leal L12, %esp
266 jmp stackless_SideBand_Read
267L12:
268 orl $(RESET_FOR_ESRAM_LOCK), %eax
269 movl $((QUARK_ALT_OPCODE_WRITE << QNC_MCR_OP_OFFSET) \
270 | (QUARK_SCSS_SOC_UNIT_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
271 | (CFGSTICKY_RW_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
272 leal L13, %esp
273 jmp stackless_SideBand_Write
274L13:
275 jmp IssueWarmReset
276
277 /* Enable PCIEXBAR */
278ConfigPci:
279 movl $(EC_BASE + EC_ENABLE), %eax /* Data */
280 movl $((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) \
281 | (QUARK_NC_MEMORY_ARBITER_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
282 | (AEC_CTRL_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
283 leal L14, %esp
284 jmp stackless_SideBand_Write
285L14:
286
287 movl $(EC_BASE + EC_ENABLE), %eax /* Data */
288 movl $((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) \
289 | (QUARK_NC_HOST_BRIDGE_SB_PORT_ID << QNC_MCR_PORT_OFFSET) \
290 | (HECREG_OFFSET << QNC_MCR_REG_OFFSET)), %ecx
291 leal L15, %esp
292 jmp stackless_SideBand_Write
293L15:
294
295 /* Open up full 8MB SPI decode */
296 movl $(PCI_CFG | ILB_PFA | BDE), %ebx /* PCI config address */
297 movl $(DECODE_ALL_REGIONS_ENABLE), %eax
298 leal L16, %esp
299 jmp stackless_PCIConfig_Write
300L16:
301
302 jmp esram_init_done
303
304IssueWarmReset:
305 /* Issue Warm Reset request to Remote Management Unit via iLB */
306 movw $(CF9_WARM_RESET), %ax
307 movw $(ILB_RESET_REG), %dx
308 outw %ax, %dx
309 jmp . /* Stay here until we are reset. */
310
311IssueColdReset:
312 /* Issue Cold Reset request to Remote Management Unit via iLB */
313 movw $(CF9_COLD_RESET), %ax
314 movw $(ILB_RESET_REG), %dx
315 outw %ax, %dx
316 jmp . /* Stay here until we are reset. */
317
318/*
319 *----------------------------------------------------------------------------
320 *
321 * Procedure: stackless_SideBand_Read
322 *
323 * Input: esp - return address
324 * ecx[15:8] - Register offset
325 * ecx[23:16] - Port ID
326 * ecx[31:24] - Opcode
327 *
328 * Output: eax - Data read
329 *
330 * Destroys: eax
331 * ebx
332 * cl
333 * esi
334 *
335 * Description:
336 * Perform requested sideband read
337 *----------------------------------------------------------------------------
338 */
339
340stackless_SideBand_Read:
341
342 movl %esp, %esi /* Save the return address */
343
344 /* Load the SideBand Packet Register to generate the transaction */
345 movl $(PCI_CFG | HOST_BRIDGE_PFA | QNC_ACCESS_PORT_MCR), %ebx
346 movb $QNC_MCR_BYTE_ENABLES, %cl /* Set all Byte Enable bits */
347 xchgl %ecx, %eax
348 leal L17, %esp
349 jmp stackless_PCIConfig_Write
350L17:
351 xchgl %ecx, %eax
352
353 /* Read the SideBand Data Register */
354 movl $(PCI_CFG | HOST_BRIDGE_PFA | (QNC_ACCESS_PORT_MDR)), %ebx
355 leal L18, %esp
356 jmp stackless_PCIConfig_Read
357L18:
358
359 movl %esi, %esp /* Restore the return address */
360 RET32
361
362/*
363 *----------------------------------------------------------------------------
364 *
365 * Procedure: stackless_SideBand_Write
366 *
367 * Input: esp - return address
368 * eax - Data
369 * ecx[15:8] - Register offset
370 * ecx[23:16] - Port ID
371 * ecx[31:24] - Opcode
372 *
373 * Output: None
374 *
375 * Destroys: ebx
376 * cl
377 * esi
378 *
379 * Description:
380 * Perform requested sideband write
381 *
382 *----------------------------------------------------------------------------
383 */
384
385stackless_SideBand_Write:
386
387 movl %esp, %esi /* Save the return address */
388
389 /* Load the SideBand Data Register with the data */
390 movl $(PCI_CFG | HOST_BRIDGE_PFA | QNC_ACCESS_PORT_MDR), %ebx
391 leal L19, %esp
392 jmp stackless_PCIConfig_Write
393L19:
394
395 /* Load the SideBand Packet Register to generate the transaction */
396 movl $(PCI_CFG | HOST_BRIDGE_PFA | QNC_ACCESS_PORT_MCR), %ebx
397 movb $QNC_MCR_BYTE_ENABLES, %cl /* Set all Byte Enable bits */
398 xchgl %ecx, %eax
399 leal L20, %esp
400 jmp stackless_PCIConfig_Write
401L20:
402 xchgl %ecx, %eax
403
404 movl %esi, %esp /* Restore the return address */
405 RET32
406
407/*
408 *----------------------------------------------------------------------------
409 *
410 * Procedure: stackless_PCIConfig_Write
411 *
412 * Input: esp - return address
413 * eax - Data to write
414 * ebx - PCI Config Address
415 *
416 * Output: None
417 *
418 * Destroys: dx
419 *
420 * Description:
421 * Perform a DWORD PCI Configuration write
422 *
423 *----------------------------------------------------------------------------
424 */
425
426stackless_PCIConfig_Write:
427
428 /* Write the PCI Config Address to the address port */
429 xchgl %ebx, %eax
430 movw $(PCI_ADDRESS_PORT), %dx
431 outl %eax, %dx
432 xchgl %ebx, %eax
433
434 /* Write the PCI DWORD Data to the data port */
435 movw $(PCI_DATA_PORT), %dx
436 outl %eax, %dx
437
438 RET32
439
440/*
441 *----------------------------------------------------------------------------
442 *
443 * Procedure: stackless_PCIConfig_Read
444 *
445 * Input: esp - return address
446 * ebx - PCI Config Address
447 *
448 * Output: eax - Data read
449 *
450 * Destroys: eax
451 * dx
452 *
453 * Description:
454 * Perform a DWORD PCI Configuration read
455 *
456 *----------------------------------------------------------------------------
457 */
458
459stackless_PCIConfig_Read:
460
461 /* Write the PCI Config Address to the address port */
462 xchgl %ebx, %eax
463 movw $(PCI_ADDRESS_PORT), %dx
464 outl %eax, %dx
465 xchgl %ebx, %eax
466
467 /* Read the PCI DWORD Data from the data port */
468 movw $(PCI_DATA_PORT), %dx
469 inl %dx, %eax
470
471 RET32
472
473/*----------------------------------------------------------------------------*/
474
475esram_init_done:
476
Lee Leahya7ba56e2016-02-07 10:42:14 -0800477#if IS_ENABLED(CONFIG_ENABLE_DEBUG_LED)
478sd_led:
479
Lee Leahy9fd08952016-02-02 07:17:06 -0800480 /* Set the SDIO controller's base address */
481 movl $(SD_BASE_ADDR), %eax
482 movl $(SD_CFG_ADDR), %ebx
483 leal L40, %esp
484 jmp stackless_PCIConfig_Write
485
486L40:
487 movl $(SD_CFG_ADDR), %ebx
488 leal L41, %esp
489 jmp stackless_PCIConfig_Read
490
491L41:
492 /* Enable the SDIO controller */
493 movl $(SD_CFG_CMD), %ebx
494 leal L42, %esp
495 jmp stackless_PCIConfig_Read
496
497L42:
498 orl $2, %eax
499 movl $(SD_CFG_CMD), %ebx
500 leal L43, %esp
501 jmp stackless_PCIConfig_Write
502
503L43:
504 movl $(SD_CFG_CMD), %ebx
505 leal L44, %esp
506 jmp stackless_PCIConfig_Read
507
508L44:
Lee Leahya7ba56e2016-02-07 10:42:14 -0800509#if IS_ENABLED(CONFIG_ENABLE_DEBUG_LED_ESRAM)
Lee Leahya7650902016-12-28 11:43:10 -0800510 jmp light_sd_led
Lee Leahya7ba56e2016-02-07 10:42:14 -0800511#endif /* CONFIG_ENABLE_DEBUG_LED_ESRAM */
512#endif /* CONFIG_ENABLE_DEBUG_LED */
Lee Leahyce9e21a2016-06-05 18:48:31 -0700513
514 /* Registers:
515 * ebp: Low 32-bits of timestamp
516 * edi: High 32-bits of timestamp
517 */
518
519 /* Setup bootblock stack */
520 movl $_car_stack_end, %esp
521
522before_carstage:
523 post_code(0x2b)
524
525 /* Get the timestamp passed in bootblock_crt0.S */
526 push %edi
527 push %ebp
528
529 /* We can call into C functions now */
Lee Leahy3de7d4a2016-08-02 17:35:22 -0700530 call bootblock_c_entry
Lee Leahyce9e21a2016-06-05 18:48:31 -0700531
532 /* Never reached */
Lee Leahya7650902016-12-28 11:43:10 -0800533
534 .global light_sd_led
535
536light_sd_led:
537 /* Turn on SD LED to indicate ESRAM successfully initialized */
538 movl $SD_HOST_CTRL, %ebx
539 movb 0(%ebx), %al
540 orb $1, %al
541 movb %al, 0(%ebx)
542
543 /* Loop forever */
544die:
545 hlt
546 jmp die