Leroy P Leahy (leroy.p.leahy@intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13440
-gerrit
commit 806905f5665e834dc82e054a96b3aad29bbc424d Author: Lee Leahy leroy.p.leahy@intel.com Date: Thu Jan 28 05:46:50 2016 -0800
soc/intel/quark: Enable ESRAM
The Quark SoC uses ESRAM instead of cache-as-RAM. This code requires that utils/xcompile/xcompile change the machine architecture from i686 to i586 to ensure that the Quark does not attempt to execute unsupported instructions:
* Adjust Makefile.inc to add the RMU to the coreboot image * Place the RMU file into 3rdparty/blobs/mainboard/intel/galileo/rmu.bin * Add code to enable the ESRAM * Testing is successful if the SD LED is on
TEST=Build and run on Galileo
Change-Id: I91d919da144bb72a5d4c4a8050ffab256632a395 Signed-off-by: Lee Leahy leroy.p.leahy@intel.com --- src/soc/intel/quark/Kconfig | 32 ++ src/soc/intel/quark/Makefile.inc | 8 + src/soc/intel/quark/romstage/Makefile.inc | 16 + src/soc/intel/quark/romstage/esram_init.inc | 564 ++++++++++++++++++++++++++++ 4 files changed, 620 insertions(+)
diff --git a/src/soc/intel/quark/Kconfig b/src/soc/intel/quark/Kconfig index 4bc3ebc..2509e06 100644 --- a/src/soc/intel/quark/Kconfig +++ b/src/soc/intel/quark/Kconfig @@ -27,4 +27,36 @@ config CPU_SPECIFIC_OPTIONS select ARCH_ROMSTAGE_X86_32 select ARCH_VERSTAGE_X86_32
+config CBFS_SIZE + hex + default 0x200000 + help + On Quark systems the firmware image has to store a lot more + than just coreboot, including: + - A firmware descriptor (RMU) file containing the LAN address at 0xfff00000 + - Intel Trusted Execution Engine firmware + This option specifies the maximum size of the CBFS portion in the + firmware image. + +config HAVE_RMU_FILE + bool + default n + help + The RMU file is required to get the chip out of reset. + +config RMU_FILE + string + default "3rdparty/blobs/mainboard/$(MAINBOARDDIR)/rmu.bin" + depends on HAVE_RMU_FILE + help + The path and filename of the Intel Quark RMU binary. + +config RMU_LOC + hex + default 0xfff00000 + depends on HAVE_RMU_FILE + help + The location in CBFS that the RMU is located. It must match the + strap-determined base address. + endif # SOC_INTEL_QUARK diff --git a/src/soc/intel/quark/Makefile.inc b/src/soc/intel/quark/Makefile.inc index 39d45fa..5c22d34 100644 --- a/src/soc/intel/quark/Makefile.inc +++ b/src/soc/intel/quark/Makefile.inc @@ -15,6 +15,7 @@
ifeq ($(CONFIG_SOC_INTEL_QUARK),y)
+subdirs-y += romstage subdirs-y += ../../../cpu/x86/tsc
romstage-y += memmap.c @@ -28,4 +29,11 @@ CPPFLAGS_common += -I3rdparty/blobs/mainboard/$(CONFIG_MAINBOARD_DIR)
ROMCCFLAGS := -mcpu=p4 -fno-simplify-phi -O2
+ifeq ($(CONFIG_HAVE_RMU_FILE),y) +cbfs-files-y += rmu.bin +rmu.bin-file := $(call strip_quotes,$(CONFIG_RMU_FILE)) +rmu.bin-position := $(CONFIG_RMU_LOC) +rmu.bin-type := raw +endif # CONFIG_HAVE_RMU_FILE + endif # CONFIG_SOC_INTEL_QUARK diff --git a/src/soc/intel/quark/romstage/Makefile.inc b/src/soc/intel/quark/romstage/Makefile.inc new file mode 100644 index 0000000..a0be5d5 --- /dev/null +++ b/src/soc/intel/quark/romstage/Makefile.inc @@ -0,0 +1,16 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2015-2016 Intel Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +cpu_incs-y += $(src)/soc/intel/quark/romstage/esram_init.inc diff --git a/src/soc/intel/quark/romstage/esram_init.inc b/src/soc/intel/quark/romstage/esram_init.inc new file mode 100644 index 0000000..065dd2d --- /dev/null +++ b/src/soc/intel/quark/romstage/esram_init.inc @@ -0,0 +1,564 @@ +/** @file + * + * Copyright (C) 2015-2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * +**/ + +# +# CR0 cache control bit definition +# +.equ CR0_CACHE_DISABLE, 0x040000000 +.equ CR0_NO_WRITE, 0x020000000 + +.macro RET32 + jmp *%esp +.endm + +# +# ROM/SPI/MEMORY Definitions +# +.equ QUARK_DDR3_MEM_BASE_ADDRESS, (0x000000000) # Memory Base Address = 0 +.equ QUARK_MAX_DDR3_MEM_SIZE_BYTES, (0x80000000) # DDR3 Memory Size = 2GB +.equ QUARK_ESRAM_MEM_BASE_ADDRESS, (QUARK_DDR3_MEM_BASE_ADDRESS + QUARK_MAX_DDR3_MEM_SIZE_BYTES) # eSRAM Memory above DDR3 +.equ QUARK_ESRAM_MEM_SIZE_BYTES, (0x00080000) # eSRAM Memory Size = 512K +.equ QUARK_STACK_SIZE_BYTES, (0x008000) # Quark stack size = 32K +.equ QUARK_STACK_BASE_ADDRESS, (QUARK_ESRAM_MEM_BASE_ADDRESS + QUARK_ESRAM_MEM_SIZE_BYTES) - QUARK_STACK_SIZE_BYTES # Top of eSRAM - stack size +.equ QUARK_CMH_SIZE_BYTES, (0x0400) # Quark Module Header size = 1024bytes +.equ QUARK_ESRAM_STAGE1_BASE_ADDRESS, (QUARK_ESRAM_MEM_BASE_ADDRESS + QUARK_CMH_SIZE_BYTES) # Start of Stage1 code in eSRAM + +# +# RTC/CMOS definitions +# +.equ RTC_INDEX, (0x70) +.equ NMI_DISABLE, (0x80) # Bit7=1 disables NMI +.equ NMI_ENABLE, (0x00) # Bit7=0 disables NMI +.equ RTC_DATA, (0x71) + +# +# PCI Configuration definitions +# +.equ PCI_CFG, (0x80000000) # PCI configuration access mechanism +.equ PCI_ADDRESS_PORT, (0xCF8) +.equ PCI_DATA_PORT, (0xCFC) + +# +# Quark PCI devices +# +.equ HOST_BRIDGE_PFA, (0x0000) # B0:D0:F0 (Host Bridge) +.equ ILB_PFA, (0x00F8) # B0:D31:F0 (Legacy Block) + +# +# ILB PCI Config Registers +# +.equ BDE, (0x0D4) # BIOS Decode Enable register +.equ DECODE_ALL_REGIONS_ENABLE, (0xFF000000) # Decode all BIOS decode ranges + +# +# iLB Reset Register +# +.equ ILB_RESET_REG, (0x0CF9) +.equ CF9_WARM_RESET, (0x02) +.equ CF9_COLD_RESET, (0x08) + +# +# Host Bridge PCI Config Registers +# +.equ MESSAGE_BUS_CONTROL_REG, (0xD0) # Message Bus Control Register +.equ SB_OPCODE_FIELD, (0x18) # Bit location of Opcode field +.equ OPCODE_SIDEBAND_REG_READ, (0x10) # Read opcode +.equ OPCODE_SIDEBAND_REG_WRITE, (0x11) # Write opcode +.equ OPCODE_SIDEBAND_ALT_REG_READ, (0x06) # Alternate Read opcode +.equ OPCODE_SIDEBAND_ALT_REG_WRITE, (0x07) # Alternate Write opcode +.equ OPCODE_WARM_RESET_REQUEST, (0xF4) # Reset Warm +.equ OPCODE_COLD_RESET_REQUEST, (0xF5) # Reset Cold +.equ SB_PORT_FIELD, (0x10) # Bit location of Port ID field +.equ MEMORY_ARBITER_PORT_ID, (0x00) +.equ HOST_BRIDGE_PORT_ID, (0x03) +.equ RMU_PORT_ID, (0x04) +.equ MEMORY_MANAGER_PORT_ID, (0x05) +.equ SOC_UNIT_PORT_ID, (0x31) +.equ SB_ADDR_FIELD, (0x08) # Bit location of Register field +.equ SB_BE_FIELD, (0x04) # Bit location of Byte Enables field +.equ ALL_BYTE_EN, (0x0F) # All Byte Enables +.equ MESSAGE_DATA_REG, (0xD4) # Message Data Register + +# +# Memory Arbiter Config Registers +# +.equ AEC_CTRL_OFFSET, (0x00) + +# +# Host Bridge Config Registers +# +.equ HMISC2_OFFSET, (0x03) # PCI configuration access mechanism +.equ OR_PM_FIELD, (0x10) +.equ SMI_EN, (0x00080000) + +.equ HMBOUND_OFFSET, (0x08) +.equ HMBOUND_ADDRESS, (QUARK_DDR3_MEM_BASE_ADDRESS + QUARK_MAX_DDR3_MEM_SIZE_BYTES + QUARK_ESRAM_MEM_SIZE_BYTES) +.equ HMBOUND_LOCK, (0x01) +.equ HECREG_OFFSET, (0x09) +.equ EC_BASE, (0xE0000000) +.equ EC_ENABLE, (0x01) + +# +# Memory Manager Config Registers +# +.equ ESRAMPGCTRL_BLOCK_OFFSET, (0x82) +.equ BLOCK_ENABLE_PG, (0x10000000) +.equ ESRAM_ADDRESS_2G, (0x10000080) +.equ BIMRVCTL_OFFSET, (0x19) +.equ ENABLE_IMR_INTERRUPT, (0x80000000) + +# +# SOC UNIT Debug Registers +# +.equ CFGSTICKY_W1_OFFSET, (0x50) +.equ FORCE_COLD_RESET, (0x00000001) +.equ CFGSTICKY_RW_OFFSET, (0x51) +.equ RESET_FOR_ESRAM_LOCK, (0x00000020) +.equ RESET_FOR_HMBOUND_LOCK, (0x00000040) +.equ CFGNONSTICKY_W1_OFFSET, (0x52) +.equ FORCE_WARM_RESET, (0x00000001) + +verify_bist: + cmp $0, %eax + je setup_sram + mov $0xa0, %eax + jmp .Lhlt + +setup_sram: + # + # Ensure cache is disabled. + # + movl %cr0, %eax + orl $(CR0_CACHE_DISABLE + CR0_NO_WRITE), %eax + invd + movl %eax, %cr0 + + # + # Disable NMI operation + # Good convention suggests you should read back RTC data port after + # accessing the RTC index port. + # + movb $(NMI_DISABLE), %al + movw $(RTC_INDEX), %dx + outb %al, %dx + movw $(RTC_DATA), %dx + inb %dx, %al + + # + # Disable SMI (Disables SMI wire, not SMI messages) + # + movl $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMISC2_OFFSET << SB_ADDR_FIELD)), %ecx + leal L1, %esp + jmp stackless_SideBand_Read +L1: + andl $(~SMI_EN), %eax + movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMISC2_OFFSET << SB_ADDR_FIELD)), %ecx + leal L2, %esp + jmp stackless_SideBand_Write +L2: + + # + # Before we get going, check SOC Unit Registers to see if we are required to issue a warm/cold reset + # + movl $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGNONSTICKY_W1_OFFSET << SB_ADDR_FIELD)), %ecx + leal L3, %esp + jmp stackless_SideBand_Read +L3: + andl $(FORCE_WARM_RESET), %eax + jz TestForceColdReset # Zero means bit clear, we're not requested to warm reset so continue as normal + jmp IssueWarmReset + +TestForceColdReset: + movl $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGNONSTICKY_W1_OFFSET << SB_ADDR_FIELD)), %ecx + leal L4, %esp + jmp stackless_SideBand_Read +L4: + andl $(FORCE_COLD_RESET), %eax + jz TestHmboundLock # Zero means bit clear, we're not requested to cold reset so continue as normal + jmp IssueColdReset + + # + # Before setting HMBOUND, check it's not locked + # +TestHmboundLock: + movl $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMBOUND_OFFSET << SB_ADDR_FIELD)), %ecx + leal L5, %esp + jmp stackless_SideBand_Read +L5: + andl $(HMBOUND_LOCK), %eax + jz ConfigHmbound # Zero means bit clear, we have the config we want so continue as normal + # + # Failed to config - store sticky bit debug + # + movl $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx + leal L6, %esp + jmp stackless_SideBand_Read +L6: + orl $(RESET_FOR_HMBOUND_LOCK), %eax + movl $((OPCODE_SIDEBAND_ALT_REG_WRITE << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx + leal L7, %esp + jmp stackless_SideBand_Write +L7: + jmp IssueWarmReset + + # + # Set up the HMBOUND register + # +ConfigHmbound: + movl $(HMBOUND_ADDRESS), %eax # Data (Set HMBOUND location) + movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMBOUND_OFFSET << SB_ADDR_FIELD)), %ecx + leal L8, %esp + jmp stackless_SideBand_Write +L8: + + # + # Enable interrupts to Remote Management Unit when a IMR/SMM/HMBOUND violation occurs. + # + movl $(ENABLE_IMR_INTERRUPT), %eax # Data (Set interrupt enable mask) + movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (BIMRVCTL_OFFSET << SB_ADDR_FIELD)), %ecx + leal L9, %esp + jmp stackless_SideBand_Write +L9: + + # + # Move eSRAM memory to 2GB + # + movl $(ESRAM_ADDRESS_2G), %eax # Data (Set eSRAM location) + movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (ESRAMPGCTRL_BLOCK_OFFSET << SB_ADDR_FIELD)), %ecx + leal L10, %esp + jmp stackless_SideBand_Write +L10: + + # + # Check that we're not blocked from setting the config that we want. + # + movl $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (ESRAMPGCTRL_BLOCK_OFFSET << SB_ADDR_FIELD)), %ecx + leal L11, %esp + jmp stackless_SideBand_Read +L11: + andl $(BLOCK_ENABLE_PG), %eax + jnz ConfigPci # Non-zero means bit set, we have the config we want so continue as normal + # + # Failed to config - store sticky bit debug + # + movl $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx + leal L12, %esp + jmp stackless_SideBand_Read +L12: + orl $(RESET_FOR_ESRAM_LOCK), %eax # Set the bit we're interested in + movl $((OPCODE_SIDEBAND_ALT_REG_WRITE << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx + leal L13, %esp + jmp stackless_SideBand_Write +L13: + jmp IssueWarmReset + + # + # Enable PCIEXBAR + # +ConfigPci: + movl $(EC_BASE + EC_ENABLE), %eax # Data + movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_ARBITER_PORT_ID << SB_PORT_FIELD) | (AEC_CTRL_OFFSET << SB_ADDR_FIELD)), %ecx + leal L14, %esp + jmp stackless_SideBand_Write +L14: + + movl $(EC_BASE + EC_ENABLE), %eax # Data + movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HECREG_OFFSET << SB_ADDR_FIELD)), %ecx + leal L15, %esp + jmp stackless_SideBand_Write +L15: + + # + # Open up full 8MB SPI decode + # + movl $(PCI_CFG | (ILB_PFA << 8) | BDE), %ebx # PCI Configuration address + movl $(DECODE_ALL_REGIONS_ENABLE), %eax + leal L16, %esp + jmp stackless_PCIConfig_Write +L16: + + jmp esram_init_done + +IssueWarmReset: + # + # Issue Warm Reset request to Remote Management Unit via iLB + # + movw $(CF9_WARM_RESET), %ax + movw $(ILB_RESET_REG), %dx + outw %ax, %dx + jmp . # Stay here until we are reset. + +IssueColdReset: + # + # Issue Cold Reset request to Remote Management Unit via iLB + # + movw $(CF9_COLD_RESET), %ax + movw $(ILB_RESET_REG), %dx + outw %ax, %dx + jmp . # Stay here until we are reset. + +#---------------------------------------------------------------------------- +# +# Procedure: stackless_SideBand_Read +# +# Input: esp - return address +# ecx[15:8] - Register offset +# ecx[23:16] - Port ID +# ecx[31:24] - Opcode +# +# Output: eax - Data read +# +# Destroys: eax +# ebx +# cl +# esi +# +# Description: +# Perform requested sideband read +# +#---------------------------------------------------------------------------- +stackless_SideBand_Read: + + movl %esp, %esi # Save the return address + + # + # Load the SideBand Packet Register to generate the transaction + # + movl $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_BUS_CONTROL_REG)), %ebx # PCI Configuration address + movb $(ALL_BYTE_EN << SB_BE_FIELD), %cl # Set all Byte Enable bits + xchgl %ecx, %eax + leal L17, %esp + jmp stackless_PCIConfig_Write +L17: + xchgl %ecx, %eax + + # + # Read the SideBand Data Register + # + movl $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_DATA_REG)), %ebx # PCI Configuration address + leal L18, %esp + jmp stackless_PCIConfig_Read +L18: + + movl %esi, %esp # Restore the return address + RET32 + +#---------------------------------------------------------------------------- +# +# Procedure: stackless_SideBand_Write +# +# Input: esp - return address +# eax - Data +# ecx[15:8] - Register offset +# ecx[23:16] - Port ID +# ecx[31:24] - Opcode +# +# Output: None +# +# Destroys: ebx +# cl +# esi +# +# Description: +# Perform requested sideband write +# +#---------------------------------------------------------------------------- +stackless_SideBand_Write: + + movl %esp, %esi # Save the return address + + # + # Load the SideBand Data Register with the data + # + movl $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_DATA_REG)), %ebx # PCI Configuration address + leal L19, %esp + jmp stackless_PCIConfig_Write +L19: + + # + # Load the SideBand Packet Register to generate the transaction + # + movl $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_BUS_CONTROL_REG)), %ebx # PCI Configuration address + movb $(ALL_BYTE_EN << SB_BE_FIELD), %cl # Set all Byte Enable bits + xchgl %ecx, %eax + leal L20, %esp + jmp stackless_PCIConfig_Write +L20: + xchgl %ecx, %eax + + movl %esi, %esp # Restore the return address + RET32 + +#---------------------------------------------------------------------------- +# +# Procedure: stackless_PCIConfig_Write +# +# Input: esp - return address +# eax - Data to write +# ebx - PCI Config Address +# +# Output: None +# +# Destroys: dx +# +# Description: +# Perform a DWORD PCI Configuration write +# +#---------------------------------------------------------------------------- +stackless_PCIConfig_Write: + + # + # Write the PCI Config Address to the address port + # + xchgl %ebx, %eax + movw $(PCI_ADDRESS_PORT), %dx + outl %eax, %dx + xchgl %ebx, %eax + + # + # Write the PCI DWORD Data to the data port + # + movw $(PCI_DATA_PORT), %dx + outl %eax, %dx + + RET32 + +#---------------------------------------------------------------------------- +# +# Procedure: stackless_PCIConfig_Read +# +# Input: esp - return address +# ebx - PCI Config Address +# +# Output: eax - Data read +# +# Destroys: eax +# dx +# +# Description: +# Perform a DWORD PCI Configuration read +# +#---------------------------------------------------------------------------- +stackless_PCIConfig_Read: + + # + # Write the PCI Config Address to the address port + # + xchgl %ebx, %eax + movw $(PCI_ADDRESS_PORT), %dx + outl %eax, %dx + xchgl %ebx, %eax + + # + # Read the PCI DWORD Data from the data port + # + movw $(PCI_DATA_PORT), %dx + inl %dx, %eax + + RET32 + +#---------------------------------------------------------------------------- +# +# Procedure: .Lhlt +# +# Input: ah - Upper 8-bits of POST code +# al - Lower 8-bits of POST code +# +# Description: +# Infinite loop displaying alternating POST code values +# +#---------------------------------------------------------------------------- + +#define LHLT_DELAY 0x50000 /* I/O delay between post codes on failure */ + +.Lhlt: + xchg %al, %ah +#if IS_ENABLED(CONFIG_POST_IO) + outb %al, $CONFIG_POST_IO_PORT +#else + post_code(POST_DEAD_CODE) +#endif + movl $LHLT_DELAY, %ecx +.Lhlt_Delay: + outb %al, $0xED + loop .Lhlt_Delay + jmp .Lhlt + +#---------------------------------------------------------------------------- + +esram_init_done: + +.equ SD_PFA, (0x14 << 11) # B0:D20:F0 - SDIO controller +.equ SD_CFG_BASE, (PCI_CFG | SD_PFA) # SD controller base in PCI config space +.equ SD_CFG_CMD, (SD_CFG_BASE+0x04) # Command register in PCI config space +.equ SD_CFG_ADDR, (SD_CFG_BASE+0x10) # Base address in PCI config space +.equ SD_BASE_ADDR, (0xA0018000) # SD controller's base address +.equ SD_HOST_CTRL, (SD_BASE_ADDR+0x28) # HOST_CTRL register + + # + # Set the SDIO controller's base address + # + movl $(SD_BASE_ADDR), %eax + movl $(SD_CFG_ADDR), %ebx + leal L40, %esp + jmp stackless_PCIConfig_Write + +L40: + movl $(SD_CFG_ADDR), %ebx + leal L41, %esp + jmp stackless_PCIConfig_Read + +L41: + # + # Enable the SDIO controller + # + movl $(SD_CFG_CMD), %ebx + leal L42, %esp + jmp stackless_PCIConfig_Read + +L42: + orl $2, %eax + movl $(SD_CFG_CMD), %ebx + leal L43, %esp + jmp stackless_PCIConfig_Write + +L43: + movl $(SD_CFG_CMD), %ebx + leal L44, %esp + jmp stackless_PCIConfig_Read + +L44: + movl $SD_HOST_CTRL, %ebx + movb 0(%ebx), %al + orb $1, %al + movb %al, 0(%ebx) + + movl $0, %eax + jmp .Lhlt