Implementing PCI & Super I/O Firmware For Linux

From RCSWiki

Jump to: navigation, search

Contents

Early device configuration

Before Linux kernel is uncompressed, onboard PCI devices including Super I/O devices need to be configured correctly:

  1. Implement configuration function ml410_init() :
    • Download ml410.c and ml410.h to directory linux-2.6.10/arch/ppc/boot/simple
  2. Modify linux-2.6.10/arch/ppc/boot/simple/Makefile
    • Add ml410.o right after boot-$(CONFIG_40x) += embed_config.o
   boot-$(CONFIG_40x)              += embed_config.o ml410.o
  1. Call extern function in linux-2.6.10/arch/ppc/boot/simple/misc-embedded.c
    • Declare ml410_init() right after the line extern void embed_config(bd_t **bp);
  extern void embed_config(bd_t **bp);
  /* Early PCI device configuration on ML-410*/
  extern void ml410_init();
    • Call ml410_init() right after the piece of code com_port = serial_init(0, bp); #endif
  #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
        com_port = serial_init(0, bp);
  #endif
  /* Early PCI device configuration on ML-410*/
  #ifdef CONFIG_PCI
        ml410_init();
  #endif

Map PCI I/O, Memory, Configuration Space parameters

Once the kernel is uncompressed to the memory, Linux requires developer to define several names in order to talk to PCI devices.

    • The reader can download virtex-ii_pro.h and just replace the original.
    • Or add definition in linux-2.6.10/arch/ppc/platforms/4xx/virtex-ii_pro.h right after the line #include <asm/ibm405.h>
 #include <asm/ibm405.h>
 #ifdef CONFIG_PCI
 #include "./xparameters/xparameters_ml300.h"
 /* PCI memory space */
 #define PPC405_PCI_MEM_BASE XPAR_PCI_0_MEM_BASEADDR
 #define PPC405_PCI_LOWER_MEM    XPAR_PCI_0_MEM_BASEADDR
 #define PPC405_PCI_UPPER_MEM    XPAR_PCI_0_MEM_HIGHADDR
 #define PPC405_PCI_PHY_MEM_BASE XPAR_PCI_0_MEM_BASEADDR
 
 /* PCI I/O space parameters for io_block_mapping. */
 #define PPC4xx_PCI_IO_PADDR ((uint)XPAR_PCI_0_IO_BASEADDR)
 #define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR
 #define PPC4xx_PCI_IO_SIZE  0x10000 /* Hardcoded size from ppc405_pci.c */
 /* PCI I/O space processor address */
 #define PPC405_PCI_PHY_IO_BASE  XPAR_PCI_0_IO_BASEADDR
 /* PCI I/O space PCI address */
 #define PPC405_PCI_LOWER_IO 0x00000000
 #define PPC405_PCI_UPPER_IO (PPC405_PCI_LOWER_IO + PPC4xx_PCI_IO_SIZE - 1)
   
 /* PCI Configuration space parameters for io_block_mapping. */ 
 #define PPC4xx_PCI_CFG_PADDR    ((uint)XPAR_PCI_0_CONFIG_ADDR)
 #define PPC4xx_PCI_CFG_VADDR    PPC4xx_PCI_CFG_PADDR
 #define PPC4xx_PCI_CFG_SIZE 8u /* size of two registers */
 /* PCI Configuration space address and data registers. */
 #define PPC405_PCI_CONFIG_ADDR  XPAR_PCI_0_CONFIG_ADDR
 #define PPC405_PCI_CONFIG_DATA  XPAR_PCI_0_CONFIG_DATA
 
 /* PCI Local configuration space parameters for io_block_mapping. */
 #define PPC4xx_PCI_LCFG_PADDR   ((uint)XPAR_PCI_0_LCONFIG_ADDR)
 #define PPC4xx_PCI_LCFG_VADDR   PPC4xx_PCI_LCFG_PADDR
 #define PPC4xx_PCI_LCFG_SIZE    256u /* PCI configuration address space size */
 
 #define _IO_BASE            isa_io_base
 #define _ISA_MEM_BASE           isa_mem_base
 #define PCI_DRAM_OFFSET         pci_dram_offset
 #endif /* CONFIG_PCI */


Add OPB2PCI parameters for Linux

In xparameters_ml40x.h automatically generated by EDK8.2i (EDK9.2 or higher has solved this problem), some PCI parameters have to be added manually.

    • In linux-2.6.10/arch/ppc/platforms/xparameters/xparameters_ml300.h (we have overlay it by xparameters_ml40x.h before )
    • Comment the line #define XPAR_PCI_0_CLOCK_FREQ_HZ
  //#define XPAR_PCI_0_CLOCK_FREQ_HZ  
    • Add PCI parameters:
 #define XPAR_XPCI_CLOCK_HZ 33333333
 #define XPAR_PCI32_BRIDGE_CONFIG_ADDR 0x42600000+0x10c
 #define XPAR_PCI32_BRIDGE_CONFIG_DATA 0x42600000+0x110
 #define XPAR_PCI32_BRIDGE_LCONFIG_ADDR 0x42600000
 #define XPAR_PCI32_BRIDGE_MEM_BASEADDR 0x20000000
 #define XPAR_PCI32_BRIDGE_MEM_HIGHADDR 0x3fffffff
 #define XPAR_PCI32_BRIDGE_IO_BASEADDR 0xe8000000
 #define XPAR_PCI32_BRIDGE_IO_HIGHADDR 0xebffffff
 
 /******************************************************************/
 
 #define XPAR_PCI_0_BASEADDR XPAR_PCI32_BRIDGE_BASEADDR
 #define XPAR_PCI_0_HIGHADDR XPAR_PCI32_BRIDGE_HIGHADDR
 #define XPAR_PCI_0_CONFIG_ADDR XPAR_PCI32_BRIDGE_CONFIG_ADDR
 #define XPAR_PCI_0_CONFIG_DATA XPAR_PCI32_BRIDGE_CONFIG_DATA
 #define XPAR_PCI_0_LCONFIG_ADDR XPAR_PCI32_BRIDGE_LCONFIG_ADDR
 #define XPAR_PCI_0_MEM_BASEADDR XPAR_PCI32_BRIDGE_MEM_BASEADDR
 #define XPAR_PCI_0_MEM_HIGHADDR XPAR_PCI32_BRIDGE_MEM_HIGHADDR
 #define XPAR_PCI_0_IO_BASEADDR XPAR_PCI32_BRIDGE_IO_BASEADDR
 #define XPAR_PCI_0_IO_HIGHADDR XPAR_PCI32_BRIDGE_IO_HIGHADDR
 #define XPAR_PCI_0_CLOCK_FREQ_HZ XPAR_XPCI_CLOCK_HZ
 #define XPAR_PCI_0_DEVICE_ID XPAR_PCI32_BRIDGE_DEVICE_ID
 
 #define XPAR_INTC_0_PCI_0_VEC_ID_SBR XPAR_OPB_INTC_0_SYSTEM_FPGA_0_PCI32_BRIDGE_PCI_SBR_INT_INTR


Define PCI device IRQ Lookup Table

Linux also needs to allocate its IRQ resources to PCI devices when probing PCI bus.

    • The reader can download xilinx_ml300.c and just replace the original.
    • Or add IRQ Lookup Table in linux-2.6.10/arch/ppc/platforms/4xx/xilinx_ml300.c right after head files:
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/serialP.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/ocp.h>
 #include <platforms/4xx/virtex-ii_pro.h>        /* for NR_SER_PORTS */
 #ifdef CONFIG_PCI
 #include <asm/pci-bridge.h>
 #define PCI_INTA (XPAR_INTC_0_PCI_0_VEC_ID_A)
 #define PCI_INTB (XPAR_INTC_0_PCI_0_VEC_ID_B)
 #define PCI_INTC (XPAR_INTC_0_PCI_0_VEC_ID_C)
 #define PCI_INTD (XPAR_INTC_0_PCI_0_VEC_ID_D)
 /* changes for ML410 */
 #define PCI_SBR  (XPAR_INTC_0_PCI_0_VEC_ID_SBR)
   
 int __init
 ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
 {
 static signed char pci_irq_table[][32] =
 {
 { PCI_SBR,  -1,       -1,       -1       },    /* ALi Audio        1 */
 { PCI_SBR,  -1,       -1,       -1       },    /* ALi South Bridge 2 */
 { PCI_SBR,  -1,       -1,       -1       },    /* ALi Modem        3 */
 { -1,       -1,       -1,       -1       },    /* Other            4 */
 { PCI_INTB, PCI_INTC, PCI_INTD, PCI_INTA },    /* Pri. slot 5      5 */
 { PCI_INTC, PCI_INTD, PCI_INTA, PCI_INTB },    /* Pri. slot 3      6 */
 { -1,       -1,       -1,       -1       },    /* Other            7 */
 { -1,       -1,       -1,       -1       },    /* Other            8 */
 { PCI_INTB, PCI_INTC, PCI_INTD, PCI_INTA },    /* PCI 2 PCI Bridge 9 */
 { PCI_SBR,  -1,       -1,       -1       },    /* ALi USB #2      10 */
 { PCI_SBR,  -1,       -1,       -1       },    /* ALi IDE         11 */
 { PCI_SBR,  -1,       -1,       -1       },    /* ALi Pwr Mgmt    12 */
 { -1,       -1,       -1,       -1       },    /* Other           13 */
 { -1,       -1,       -1,       -1       },    /* Other           14 */
 { PCI_SBR,  -1,       -1,       -1       },    /* ALi USB #1      15 */
 };
 
     const long min_idsel = 1, max_idsel = 15, irqs_per_slot = 4;
         int res = PCI_IRQ_TABLE_LOOKUP;
     int bus = dev->bus->number;
 
         printk("ppc405_map_irq: bus %d idsel %d pin %d, res = %d\n", bus, idsel, pin, res);
 
         return res;
 };
 #endif


Hook up 8259 and Xilinx interrupt controller in Linux

On Ali 15x3 South Bridge, there is an embedded interrupt controller 8259 which the developer needs to hook up with Xilinx interrupt controller in Linux.

    • In linux-2.6.10/arch/ppc/syslib/, download xilinx_pic.c and replace the original.

Setup PCI bridge memory ranges in Linux

    • In linux-2.6.10/arch/ppc/syslib/, download ppc405_pci.c and replace the original.

Assign IRQ to South bridge

    • In linux-2.6.10/driver/ide/pci , download alim15x3.c and replace the original.

Compile and create Linux image

Clean old Linux image:

  • make ARCH=ppc CROSS_COMPILE=powerpc-405-linux-gnu- clean

Create Linux Image combined with initial ram disk:

  • make ARCH=ppc CROSS_COMPILE=powerpc-405-linux-gnu- zImage.initrd


Continue on with Example: How to mount IDE hard drive on ML410

Personal tools