summaryrefslogtreecommitdiffstats
path: root/bsps/i386
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 12:50:58 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 15:18:45 +0200
commit5a4e3dc0a5af631b1723858bc50a9af1545392fb (patch)
treef2825a86e99fbf1982fc484278483a03728ccc3a /bsps/i386
parentbsps/sh: Move console.c to bsps (diff)
downloadrtems-5a4e3dc0a5af631b1723858bc50a9af1545392fb.tar.bz2
bsps: Move PCI drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/i386')
-rw-r--r--bsps/i386/shared/pci/pci_io.c213
-rw-r--r--bsps/i386/shared/pci/pcibios.c479
2 files changed, 692 insertions, 0 deletions
diff --git a/bsps/i386/shared/pci/pci_io.c b/bsps/i386/shared/pci/pci_io.c
new file mode 100644
index 0000000000..b6cd1005f0
--- /dev/null
+++ b/bsps/i386/shared/pci/pci_io.c
@@ -0,0 +1,213 @@
+/**
+ * @file
+ *
+ * PCI Support when Configuration Space is in I/O
+ */
+
+/*
+ * COPYRIGHT (c) 2016.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <bsp/bspimpl.h>
+
+static int pci_io_initialized = 0;
+
+/*
+ * Forward reference. Initialized at bottom.
+ */
+static const pci_config_access_functions pci_io_indirect_functions;
+
+/*
+ * Detects presense of PCI Configuration is in I/O space. If so, return
+ * pointer to accessor methods.
+ *
+ * NOTE: TBD to determine if (a) PCI Bus exists and (b) this is the
+ * access method.
+ */
+const pci_config_access_functions *pci_io_initialize(void)
+{
+ pci_io_initialized = 1;
+
+ printk( "PCI I/O Support Initialized\n" );
+
+ return &pci_io_indirect_functions;
+}
+
+/*
+ * Build PCI Address
+ */
+static inline uint32_t pci_io_build_address(
+ uint16_t bus,
+ uint16_t slot,
+ uint16_t function,
+ uint16_t offset
+)
+{
+ uint32_t bus_u32 = (uint32_t)bus;
+ uint32_t slot_u32 = (uint32_t)slot;
+ uint32_t function_u32 = (uint32_t)function;
+ uint32_t address;
+
+ /*
+ * create configuration address as per figure at
+ * http://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231
+ */
+ address = (uint32_t) 0x80000000; /* Bit 31 - Enable Bit */
+ /* Bits 30-24 - Reserved */
+ address |= bus_u32 << 16; /* Bits 23-16 - Bus Number */
+ address |= slot_u32 << 11; /* Bits 15-11 - Device/Slot Number */
+ address |= function_u32 << 8; /* Bits 10-8 - Function Number */
+ address |= offset & 0xfc; /* Bits 7-2 - Offset/Register Number */
+ /* Bits 1-0 - Reserved 0 */
+ return address;
+}
+
+static int BSP_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned char *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ /* (offset & 3) * 8) = 0 will choose the first byte of the 32 bits register */
+ *value = (uint16_t)(tmp >> ((offset & 3) * 8)) & 0xff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned short *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ /* (offset & 2) * 8) = 0 will choose the first word of the 32 bits register */
+ *value = (uint16_t)(tmp >> ((offset & 2) * 8)) & 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ *value = tmp;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned char value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_byte(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned short value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_word(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_long(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static const pci_config_access_functions pci_io_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
+};
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
+};