From 5a4e3dc0a5af631b1723858bc50a9af1545392fb Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 23 Apr 2018 12:50:58 +0200 Subject: bsps: Move PCI drivers to bsps This patch is a part of the BSP source reorganization. Update #3285. --- bsps/i386/shared/pci/pci_io.c | 213 ++++++++++++++++++ bsps/i386/shared/pci/pcibios.c | 479 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 692 insertions(+) create mode 100644 bsps/i386/shared/pci/pci_io.c create mode 100644 bsps/i386/shared/pci/pcibios.c (limited to 'bsps/i386') 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 +#include +#include + +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 +#include +#include + +#include /* 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 +}; -- cgit v1.2.3