POD Drivers

From ArmadeusWiki
Revision as of 13:40, 7 February 2013 by FabienM (Talk | contribs) (Source code modification)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Driver generation mechanism

POD is able to generate the drivers corresponding to the components present in the project and this for a given operating system. The source code of a driver and for a dedicated operating system is located in the drivers/ directory of the component

Note Note: Operating System represent a complete system like a distribution, not only the kernel. We can have several linux drivers but in different OS-distribution. For embedded operating systems we also talk about BSP (Board Support Package)


The driver generation mechanism is a three step process:

  • selection of the template source code depending on the targeted operating system. The template located in the drivers/ directory of a component is copied in the drivers/ directory of the project
  • modification of the copied sources (done by POD)
  • integration of the resulting code to the software tree (where the compilation will take place)

Source code selection

Once the project built, POD creates a drivers/ directory in the project directory. The driver files for the targeted OS are then copied to this directory.

figure 1 - source code selection

Source code modification

The template source code has several special tags embeded in the comments. These tags help POD to specify and to modify the sources.

These tags are represented as following :

 /*$tag$*/

If the tag foreach:list_of_somethings is written at the beginning of a line, POD will write one line for each element of the list.

  • foreach:instance : written before a code bloc, must be ended by foreach:instance:end. Tags used with foreach:instance are:
    • instance_name : name of the instance.
    • instance_num : number of the instance
    • registers_base_address:interface_name : Base address of the register in the interface connected to the processor bus.
    • interrupt_number : indicates the number of interruptions connected to the irq manager.
    • generic:<generic_name> : writes the value of a generic, generic_name must be replaced with the name of the generic.
    • register:interfacename:registername:attribute : writes the attribute value of one register
  • number_of_instances : gives the number of instances of the same component in project.
  • main_clock : gives the frequency of the main clock connected to the FPGA (in kHz).

All values are written in upper case.

For example, to generate a Linux UART driver with 2 UART instances, named UART1 and UART2, the code to be generated will looks like :

#define UART1_INPUT_CLOCK 96000000
#define UART2_INPUT_CLOCK 96000000
#define UART1_BASE       0x10
#define UART2_BASE       0x20
#define UART1_IRQ        IRQ_FPGA(0)
#define UART2_IRQ        IRQ_FPGA(1)


static struct plat_serial8250_port ocore_16550_data[] = {
    PORT( APF9328_FPGA_VIRT+UART1_BASE, APF9328_FPGA_PHYS+UART1_BASE, UART1_INPUT_CLOCK, UART1_IRQ ),
    PORT( APF9328_FPGA_VIRT+UART2_BASE, APF9328_FPGA_PHYS+UART2_BASE, UART2_INPUT_CLOCK, UART2_IRQ ),
    { },
};

static struct platform_device ocore_16550_device = {
    .name = "serial8250", /* we use generic 8250/16550 Linux layer */
    .id   = PLAT8250_DEV_PLATFORM1,
    .dev  = {
        .platform_data = ocore_16550_data,
    },
};

Thus the following template has to be written :

/*$foreach:instance$*/
#define /*$instance_name$*/_INPUT_CLOCK /*$generic:clock_speed$*/
#define /*$instance_name$*/_BASE   /*$registers_base_address:swb16$*/
#define /*$instance_name$*/_IRQ        IRQ_FPGA(/*$interrupt_number$*/)
/*$foreach:instance:end$*/

static struct plat_serial8250_port ocore_16550_data[] = {
/*$foreach:instance$*/  
    PORT( APF9328_FPGA_VIRT+/*$instance_name$*/_BASE, 
          APF9328_FPGA_PHYS+/*$instance_name$*/_BASE, 
          /*$instance_name$*/_INPUT_CLOCK, 
          /*$instance_name$*/_IRQ ),
/*$foreach:instance:end$*/
    { },
};  

static struct platform_device ocore_16550_device = {
    .name = "serial8250", /* we use generic 8250/16550 Linux layer */
    .id   = PLAT8250_DEV_PLATFORM1,
    .dev  = {
        .platform_data = ocore_16550_data,
    },
};

Driver integration

Once the source codes filled in, they can be copied in the software development tree. The destination for an Armadeus tree is the special directory POD/.

figure 2 - drivers generation principle


Some links

Linux driver model