summaryrefslogtreecommitdiffstats
path: root/bsps/i386/shared/pci/pcibios.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/i386/shared/pci/pcibios.c')
-rw-r--r--bsps/i386/shared/pci/pcibios.c479
1 files changed, 479 insertions, 0 deletions
diff --git a/bsps/i386/shared/pci/pcibios.c b/bsps/i386/shared/pci/pcibios.c
new file mode 100644
index 0000000000..173c89f3f8
--- /dev/null
+++ b/bsps/i386/shared/pci/pcibios.c
@@ -0,0 +1,479 @@
+/**
+ * @file
+ *
+ * PCI Support when Configuration Space is accessed via BIOS
+ */
+
+/*
+ * This software is Copyright (C) 1998 by T.sqware - all rights limited
+ * It is provided in to the public domain "as is", can be freely modified
+ * as far as this copyight notice is kept unchanged, but does not imply
+ * an endorsement by T.sqware of the product in which it is included.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/pci.h>
+
+#include <string.h> /* memcpy */
+
+/*
+ * This is simpliest possible PCI BIOS, it assumes that addressing
+ * is flat and that stack is big enough
+ */
+static int pcibInitialized = 0;
+static unsigned int pcibEntry;
+
+/*
+ * Array to pass data between c and __asm__ parts, at the time of
+ * writing I am not yet that familiar with extended __asm__ feature
+ * of gcc. This code is not on performance path, so we can care
+ * relatively little about performance here
+ */
+static volatile unsigned int pcibExchg[5];
+
+static int pcib_convert_err(int err);
+
+/** @brief
+ * Make device signature from bus number, device numebr and function
+ * number
+ */
+#define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
+
+/** @brief
+ * Extract valrous part from device signature
+ */
+#define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
+#define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
+#define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
+
+/*
+ * Forward reference. Initialized at bottom.
+ */
+static const pci_config_access_functions pci_bios_indirect_functions;
+
+/* prototype before defining */
+const pci_config_access_functions *pci_bios_initialize(void);
+
+/*
+ * Detects presense of PCI BIOS, returns pointer to accessor methods.
+ */
+const pci_config_access_functions *pci_bios_initialize(void)
+{
+ unsigned char *ucp;
+ unsigned char sum;
+ int i;
+
+ pcibInitialized = 0;
+
+ /* First, we have to look for BIOS-32 */
+ for (ucp = (unsigned char *)0xE0000;
+ ucp < (unsigned char *)0xFFFFF;
+ ucp += 0x10) {
+ if (memcmp(ucp, "_32_", 4) != 0) {
+ continue;
+ }
+
+ /* Got signature, check length */
+ if (*(ucp + 9) != 1) {
+ continue;
+ }
+
+ /* Verify checksum */
+ sum = 0;
+ for (i=0; i<16; i++) {
+ sum += *(ucp+i);
+ }
+
+ if (sum == 0) {
+ /* found */
+ break;
+ }
+ }
+
+ if (ucp >= (unsigned char *)0xFFFFF) {
+ /* BIOS-32 not found */
+ return NULL;
+ }
+
+ /* BIOS-32 found, let us find PCI BIOS */
+ ucp += 4;
+
+ pcibExchg[0] = *(unsigned int *)ucp;
+
+ __asm__ (" pusha"); /* Push all registers */
+ __asm__ (" movl pcibExchg, %edi"); /* Move entry point to esi */
+ __asm__ (" movl $0x49435024, %eax"); /* Move signature to eax */
+ __asm__ (" xorl %ebx, %ebx"); /* Zero ebx */
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%edi"); /* Call entry */
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ebx, pcibExchg+4");
+ __asm__ (" movl %ecx, pcibExchg+8");
+ __asm__ (" movl %edx, pcibExchg+12");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff) != 0) {
+ /* Not found */
+ return NULL;
+ }
+
+ /* Found PCI entry point */
+ pcibEntry = pcibExchg[1] + pcibExchg[3];
+
+ /* Let us check whether PCI bios is present */
+ pcibExchg[0] = pcibEntry;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %edi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x01, %al");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%edi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ebx, pcibExchg+4");
+ __asm__ (" movl %ecx, pcibExchg+8");
+ __asm__ (" movl %edx, pcibExchg+12");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff00) != 0) {
+ /* Not found */
+ return NULL;
+ }
+
+ if (pcibExchg[3] != 0x20494350) {
+ /* Signature does not match */
+ return NULL;
+ }
+
+ /* Success */
+ pcibInitialized = 1;
+
+ return &pci_bios_indirect_functions;
+}
+
+/*
+ * Read byte from config space
+ */
+static int
+pcib_conf_read8(int sig, int off, uint8_t *data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x08, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ecx, pcibExchg+4");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff00) != 0) {
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+ }
+
+ *data = (unsigned char)pcibExchg[1] & 0xff;
+
+ return PCIB_ERR_SUCCESS;
+}
+
+
+/*
+ * Read word from config space
+ */
+static int
+pcib_conf_read16(int sig, int off, uint16_t *data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x09, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ecx, pcibExchg+4");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff00) != 0) {
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+ }
+
+ *data = (unsigned short)pcibExchg[1] & 0xffff;
+
+ return PCIB_ERR_SUCCESS;
+}
+
+
+/*
+ * Read dword from config space
+ */
+static int
+pcib_conf_read32(int sig, int off, uint32_t *data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x0a, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ecx, pcibExchg+4");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff00) != 0) {
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+ }
+
+ *data = (unsigned int)pcibExchg[1];
+
+ return PCIB_ERR_SUCCESS;
+}
+
+
+/*
+ * Write byte into config space
+ */
+static int
+pcib_conf_write8(int sig, int off, uint8_t data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+ pcibExchg[3] = data & 0xff;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x0b, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" movl pcibExchg+12, %ecx");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" popa");
+
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+}
+
+/*
+ * Write word into config space
+ */
+static int
+pcib_conf_write16(int sig, int off, uint16_t data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+ pcibExchg[3] = data & 0xffff;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x0c, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" movl pcibExchg+12, %ecx");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" popa");
+
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+}
+
+
+
+/*
+ * Write dword into config space
+ */
+static int
+pcib_conf_write32(int sig, int off, uint32_t data)
+{
+ if (!pcibInitialized){
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+ pcibExchg[3] = data;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x0d, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" movl pcibExchg+12, %ecx");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" popa");
+
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+}
+
+
+static int
+pcib_convert_err(int err)
+{
+ switch(err & 0xff){
+ case 0:
+ return PCIB_ERR_SUCCESS;
+ case 0x81:
+ return PCIB_ERR_NOFUNC;
+ case 0x83:
+ return PCIB_ERR_BADVENDOR;
+ case 0x86:
+ return PCIB_ERR_DEVNOTFOUND;
+ case 0x87:
+ return PCIB_ERR_BADREG;
+ default:
+ break;
+ }
+ return PCIB_ERR_NOFUNC;
+}
+
+static int
+BSP_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ unsigned char *val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_read8(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ unsigned short *val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_read16(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ uint32_t *val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_read32(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ unsigned char val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_write8(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ unsigned short val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_write16(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ uint32_t val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_write32(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static const pci_config_access_functions pci_bios_indirect_functions = {
+ BSP_pci_read_config_byte,
+ BSP_pci_read_config_word,
+ BSP_pci_read_config_dword,
+ BSP_pci_write_config_byte,
+ BSP_pci_write_config_word,
+ BSP_pci_write_config_dword
+};