diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mainboard/emulation/qemu-i440fx/fw_cfg.c | 46 | ||||
-rw-r--r-- | src/mainboard/emulation/qemu-i440fx/fw_cfg_if.h | 33 |
2 files changed, 75 insertions, 4 deletions
diff --git a/src/mainboard/emulation/qemu-i440fx/fw_cfg.c b/src/mainboard/emulation/qemu-i440fx/fw_cfg.c index 3acb11e5f5..580e09ad45 100644 --- a/src/mainboard/emulation/qemu-i440fx/fw_cfg.c +++ b/src/mainboard/emulation/qemu-i440fx/fw_cfg.c @@ -24,20 +24,29 @@ #define FW_CFG_PORT_CTL 0x0510 #define FW_CFG_PORT_DATA 0x0511 +#define FW_CFG_DMA_ADDR_HIGH 0x0514 +#define FW_CFG_DMA_ADDR_LOW 0x0518 static int fw_cfg_detected; +static uint8_t fw_ver; + +static void fw_cfg_dma(int control, void *buf, int len); static int fw_cfg_present(void) { static const char qsig[] = "QEMU"; - unsigned char sig[4]; + unsigned char sig[FW_CFG_SIG_SIZE]; int detected = 0; if (fw_cfg_detected == 0) { fw_cfg_get(FW_CFG_SIGNATURE, sig, sizeof(sig)); - detected = memcmp(sig, qsig, 4) == 0; + detected = memcmp(sig, qsig, FW_CFG_SIG_SIZE) == 0; printk(BIOS_INFO, "QEMU: firmware config interface %s\n", detected ? "detected" : "not found"); + if (detected) { + fw_cfg_get(FW_CFG_ID, &fw_ver, sizeof(fw_ver)); + printk(BIOS_INFO, "Firmware config version id: %d\n", fw_ver); + } fw_cfg_detected = detected + 1; } return fw_cfg_detected - 1; @@ -50,7 +59,10 @@ static void fw_cfg_select(uint16_t entry) static void fw_cfg_read(void *dst, int dstlen) { - insb(FW_CFG_PORT_DATA, dst, dstlen); + if (fw_ver & FW_CFG_VERSION_DMA) + fw_cfg_dma(FW_CFG_DMA_CTL_READ, dst, dstlen); + else + insb(FW_CFG_PORT_DATA, dst, dstlen); } void fw_cfg_get(uint16_t entry, void *dst, int dstlen) @@ -500,3 +512,31 @@ void smbios_system_set_uuid(u8 *uuid) fw_cfg_smbios_init(); memcpy(uuid, type1_uuid, 16); } + +/* + * Configure DMA setup + */ + +static void fw_cfg_dma(int control, void *buf, int len) +{ + volatile FwCfgDmaAccess dma; + uintptr_t dma_desc_addr; + uint32_t dma_desc_addr_hi, dma_desc_addr_lo; + + dma.control = be32_to_cpu(control); + dma.length = be32_to_cpu(len); + dma.address = be64_to_cpu((uintptr_t)buf); + + dma_desc_addr = (uintptr_t)&dma; + dma_desc_addr_lo = (uint32_t)(dma_desc_addr & 0xFFFFFFFFU); + dma_desc_addr_hi = sizeof(uintptr_t) > sizeof(uint32_t) + ? (uint32_t)(dma_desc_addr >> 32) : 0; + + // Skip writing high half if unnecessary. + if (dma_desc_addr_hi) + outl(be32_to_cpu(dma_desc_addr_hi), FW_CFG_DMA_ADDR_HIGH); + outl(be32_to_cpu(dma_desc_addr_lo), FW_CFG_DMA_ADDR_LOW); + + while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_CTL_ERROR) + ; +} diff --git a/src/mainboard/emulation/qemu-i440fx/fw_cfg_if.h b/src/mainboard/emulation/qemu-i440fx/fw_cfg_if.h index de67f021ea..dad6ca9e7f 100644 --- a/src/mainboard/emulation/qemu-i440fx/fw_cfg_if.h +++ b/src/mainboard/emulation/qemu-i440fx/fw_cfg_if.h @@ -67,11 +67,20 @@ enum fw_cfg_enum { #define FW_CFG_INVALID 0xffff +/* width in bytes of fw_cfg control register */ +#define FW_CFG_CTL_SIZE 0x02 + +/* fw_cfg "file name" is up to 56 characters (including terminating nul) */ +#define FW_CFG_MAX_FILE_PATH 56 + +/* size in bytes of fw_cfg signature */ +#define FW_CFG_SIG_SIZE 4 + typedef struct FWCfgFile { uint32_t size; /* file size */ uint16_t select; /* write this to 0x510 to read it */ uint16_t reserved; - char name[56]; + char name[FW_CFG_MAX_FILE_PATH]; } FWCfgFile; typedef struct FWCfgFiles { @@ -96,4 +105,26 @@ typedef struct FwCfgSmbios { uint16_t fieldoffset; } FwCfgSmbios; +/* FW_CFG_ID bits */ +#define FW_CFG_VERSION 0x01 +#define FW_CFG_VERSION_DMA 0x02 + +/* FW_CFG_DMA_CONTROL bits */ +#define FW_CFG_DMA_CTL_ERROR 0x01 +#define FW_CFG_DMA_CTL_READ 0x02 +#define FW_CFG_DMA_CTL_SKIP 0x04 +#define FW_CFG_DMA_CTL_SELECT 0x08 +#define FW_CFG_DMA_CTL_WRITE 0x10 + +#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */ + +/* Control as first field allows for different structures selected by this + * field, which might be useful in the future + */ +typedef struct FwCfgDmaAccess { + uint32_t control; + uint32_t length; + uint64_t address; +} FwCfgDmaAccess; + #endif /* FW_CFG_IF_H */ |