Commit a3f0fe6d authored by Benoit Rat's avatar Benoit Rat

libswitchhw: improve the io (pin) compatibility for previous & next version

parent 9d3d6a0a
......@@ -48,7 +48,6 @@ typedef struct pio_pin
extern volatile uint8_t *_sys_base;
extern volatile uint8_t *_pio_base[4][NUM_PIO_BANKS+1];
int shw_pio_init();
void shw_pio_configure(const pio_pin_t *pin);
void shw_pio_configure_pins(const pio_pin_t *pins);
......@@ -58,6 +57,10 @@ volatile uint8_t *shw_pio_get_port_base(int port);
void shw_set_fp_led(int led, int state);
int shw_pio_mmap_init();
void shw_pio_toggle_pin(pio_pin_t* pin, uint32_t udelay);
void shw_pio_configure_all();
void shw_pio_configure(const pio_pin_t *pin);
static inline void shw_pio_set(const pio_pin_t *pin, int state)
{
......@@ -93,11 +96,5 @@ static inline int shw_pio_setdir(const pio_pin_t *pin, int dir)
return 0;
}
#include "pio_pins.h"
int shw_pio_mmap_init();
void shw_pio_toggle_pin(pio_pin_t* pin, uint32_t udelay);
void shw_pio_configure_all();
void shw_pio_configure(const pio_pin_t *pin);
#endif //PIO_H
\ No newline at end of file
#endif //PIO_H
#ifndef __PIO_PINS_H
#define __PIO_PINS_H
extern const pio_pin_t * _all_cpu_gpio_pins[];
extern const pio_pin_t * _all_fpga_gpio_pins[];
#endif
/*
* shw_io.h
*
* Generic definition of IO available for the CPU & the FPGA.
*
* Created on: Jan 20, 2013
* Authors:
* - Benoit RAT
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License...
*/
#ifndef _SHW_IO_H_
#define _SHW_IO_H_
#include <stdint.h>
#include "pio.h"
#define assert_init(proc) { int ret; if((ret = proc) < 0) return ret; }
/**
* List of type of IO.
*/
typedef enum {
SHW_UNDEF=0, //undefined type
SHW_CPU_PIO,
SHW_I2C,
SHW_WB_PIO,
SHW_WB_SYSM
} shw_io_type_t;
/**
* List of ID for the various IO.
*/
typedef enum {
shw_io_reset_n=1, //start at 1 (0 <=> undef)
shw_io_box_fan_en, //(< v3.3)
shw_io_box_fan_tacho, //(< v3.3)
shw_io_fpga_fan_en, //(< v3.3)
shw_io_led_cpu1,
shw_io_led_cpu2,
shw_io_arm_boot_sel, //(>= v3.2)
shw_io_led_state_g, //(>= v3.3)
shw_io_led_state_o, //(>= v3.3)
shw_io_arm_gen_but, //(>= v3.3)
NUM_SHW_IO_ID
} shw_io_id_t;
/**
* Structure to setup name and ID
*/
typedef struct
{
uint8_t ID;
uint8_t type;
const char *name;
void *ptr;
} shw_io_t;
/*
* Parameters to a chip
*/
typedef struct
{
void *bus;
uint32_t addr;
uint32_t config;
uint32_t type;
} shw_chip_t;
/*
* Structure to fake an I/O using on a bus
*/
typedef struct
{
const shw_chip_t *chip;
uint8_t mask; //Mask of the interesting bit
uint8_t shift; //Shift masking bit
} shw_io_bus_t;
/**
* Exported structure to use them (Same size as enum)
*/
extern const shw_io_t _all_shw_io[];
//Functions
int shw_io_init();
int shw_io_configure_all();
const shw_io_t* get_shw_io(shw_io_id_t id);
const pio_pin_t* get_pio_pin(shw_io_id_t id);
uint32_t shw_io_read(shw_io_id_t id);
int shw_io_write(shw_io_id_t, uint32_t value);
const char* get_shw_info(const char cmd);
#endif /* _SHW_IO_H_ */
......@@ -2,7 +2,7 @@ CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
CFLAGS = -I. -O2 -I../include -DDEBUG -g
OBJS = trace.o init.o fpga_io.o util.o pps_gen.o i2c.o pio_pins.o i2c_bitbang.o i2c_fpga_reg.o pio.o libshw_i2c.o i2c_sfp.o fan.o
OBJS = trace.o init.o fpga_io.o util.o pps_gen.o i2c.o shw_io.o i2c_bitbang.o i2c_fpga_reg.o pio.o libshw_i2c.o i2c_sfp.o fan.o i2c_io.o
SCAN_OBJS = i2cscan.o
LIB = libswitchhw.a
......
/*
* i2c_cpu.c
*
* Access to the PCA9554PW chip to retrieve scb version and status LED.
*
* Created on: 20 Jan 2013
* Authors:
* - Benoit RAT
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License...
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pio.h>
#include <trace.h>
#include "i2c.h"
#include "i2c_io.h"
#include "i2c_bitbang.h"
#include "libshw_i2c.h"
#define ARRAY_SIZE(a) \
(sizeof(a) / sizeof(*(a)))
#define I2C_SCB_VER_ADDR 0x20
//Connected to miniBP to PB6>PB4>PB24
pio_pin_t wr_i2c_io_sda = {
.port = PIOB,
.pin = 24,
.mode = PIO_MODE_PULLUP | PIO_MODE_GPIO,
.dir = PIO_OUT_0,
};
//Connected to miniBP to PB7>PB0>PB20
pio_pin_t wr_i2c_io_scl = {
.port = PIOB,
.pin = 20,
.mode = PIO_MODE_PULLUP | PIO_MODE_GPIO,
.dir = PIO_OUT_0,
};
struct i2c_bitbang wr_i2c_io_reg = {
.scl = &wr_i2c_io_scl,
.sda = &wr_i2c_io_sda,
};
struct i2c_bus i2c_io_bus = {
.name = "wr_scb_ver",
.type = I2C_TYPE_BITBANG,
.type_specific = &wr_i2c_io_reg,
.err = I2C_NULL_PARAM,
};
int shw_i2c_io_init(void)
{
int i;
TRACE(TRACE_INFO, "Initializing IO I2C bus...%s",__TIME__);
if (i2c_init_bus(&i2c_io_bus) < 0) {
TRACE(TRACE_ERROR,"init failed: %s", i2c_io_bus.name);
return -1;
}
TRACE(TRACE_INFO,"init: success: %s", i2c_io_bus.name);
return 0;
}
int shw_i2c_io_scan(uint8_t *dev_map)
{
int i;
int detect;
if (i2c_io_bus.err)
return -1;
detect = i2c_scan(&i2c_io_bus, dev_map);
printf("\ni2c_bus: %s: %d devices\n", i2c_io_bus.name, detect);
for (i = 0; i < 128; i++)
if (dev_map[i/8] & (1 << (i%8)))
printf("device at: 0x%02X\n", i);
return detect;
}
float shw_get_hw_ver()
{
uint8_t ret;
struct i2c_bus *bus= &i2c_io_bus;
//Check if i2c module exists (>=3.3)
if(bus && bus->scan(bus,I2C_SCB_VER_ADDR))
{
//The 0b00001110 bits are used for SCB HW version
ret= wrswhw_pca9554_get_input(bus,I2C_SCB_VER_ADDR);
switch((ret >> 1) & 0x7)
{
case 0: return 3.3;
case 1: return 3.4; //version is not available
case 2: return 3.41;
default:
TRACE(TRACE_FATAL,"Unknown HW version (0x%x), check the DIP switch under the SCB",(ret >> 1) & 0x7);
return -1;
}
}
else
{
return 3.2;
}
}
uint8_t shw_get_fpga_type()
{
struct i2c_bus *bus= &i2c_io_bus;
if(bus && bus->scan(bus,I2C_SCB_VER_ADDR))
{
//The 0b00001110 bits are used for SCB HW version
if(wrswhw_pca9554_get_input(bus,I2C_SCB_VER_ADDR) & 0x1)
return SHW_FPGA_LX240T;
}
return SHW_FPGA_LX130T;
}
struct i2c_bus* shw_i2c_io_get_bus()
{
return &i2c_io_bus;
}
#ifndef I2C_SFP_H
#define I2C_SFP_H
#include "i2c.h"
//address from AT24C01 datasheet (1k, all address lines shorted to the ground)
#define I2C_SFP_ADDRESS 0x50
#define SHW_FPGA_LX240T 240
#define SHW_FPGA_LX130T 130
/**
* Initializes all the buses related to SFP control. These include:
* - FPGA buses x 2
* - Bitbanged bus to muxes
* - Bitbanged buses to SFP link0 and link1
* @return: 0 on success, -1 on error
*/
extern struct i2c_bus i2c_io_bus;
int shw_i2c_io_init(void);
int shw_i2c_io_scan(uint8_t *dev_map);
uint8_t shw_i2c_read(const *i2c_bus, uint8_t addr);
uint8_t shw_i2c_write(const *i2c_bus, uint8_t addr, uint8_t value, uint8_t mask);
float shw_get_hw_ver();
uint8_t shw_get_fpga_type();
#endif //I2C_SFP_H
......@@ -10,8 +10,9 @@
#include <at91/at91_pmc.h>
#include <at91/at91_pio.h>
#include <pio.h>
#include <trace.h>
#include "pio.h"
#include "trace.h"
#include "shw_io.h"
volatile uint8_t *_pio_base[4][NUM_PIO_BANKS+1];
volatile uint8_t *_sys_base;
......@@ -99,9 +100,13 @@ void shw_pio_toggle_pin(pio_pin_t* pin, uint32_t udelay)
void shw_pio_configure_all()
{
int i = 0;
while (_all_cpu_gpio_pins[i] != NULL)
shw_pio_configure(_all_cpu_gpio_pins[i++]);
int i;
const shw_io_t* all_io=(shw_io_t*)_all_shw_io;
for(i=0;i<NUM_SHW_IO_ID;i++)
{
if(all_io[i].type==SHW_CPU_PIO)
shw_pio_configure(all_io[i].ptr);
}
}
void shw_pio_configure(const pio_pin_t *pin)
......
/* GPIO pin definitions */
#include <pio.h>
#define LED_OFF 0
#define LED_RED 1
#define LED_GREEN 2
#define LED_YELLOW 3
// definitions of commonly used pins
// reset signal for main FPGA
//const pio_pin_t PIN_main_fpga_nrst[] = {{ PIOA, 5, PIO_MODE_GPIO, PIO_OUT }, {0}};
const pio_pin_t PIN_mbl_reset_n[] = {{PIOE, 1, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_mbl_box_fan_en[] = {{PIOB, 20, PIO_MODE_GPIO, PIO_OUT_0}, {0}};
const pio_pin_t PIN_mbl_box_fan_tacho[] = {{PIOE, 7, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t * _all_cpu_gpio_pins[] =
{
PIN_mbl_reset_n,
PIN_mbl_box_fan_en,
PIN_mbl_box_fan_tacho,
0
};
/*
* pio_pins.c
*
* Define the PIO pin available for the CPU & the FPGA.
*
* Created on: Oct 30, 2012
* Authors:
* - Benoit RAT
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License...
*/
#include <pio.h>
#include <trace.h>
#include <string.h>
#include "shw_io.h"
#include "i2c_io.h"
#include "libshw_i2c.h"
//Help to setup the structure.
#define IOARR_SET_IO(_name,_type,_ptr) { \
all_shw_io[_name].ID=_name; \
all_shw_io[_name].type=_type; \
all_shw_io[_name].name=#_name; \
all_shw_io[_name].ptr=(void*)_ptr; }
#define IOARR_SET_GPIO(_name) { \
all_shw_io[_name].ID=_name; \
all_shw_io[_name].type=SHW_CPU_PIO; \
all_shw_io[_name].name=#_name; \
all_shw_io[_name].ptr=(void*)PIN_##_name; }
// definitions of commonly IO pins used with through all the versions (static memory)
// reset signal for main FPGA
//const pio_pin_t PIN_main_fpga_nrst[] = {{ PIOA, 5, PIO_MODE_GPIO, PIO_OUT }, {0}};
const pio_pin_t PIN_shw_io_reset_n[] = {{PIOE, 1, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_shw_io_box_fan_en[] = {{PIOB, 20, PIO_MODE_GPIO, PIO_OUT_0}, {0}}; //<3.3 (then used for i2c io)
const pio_pin_t PIN_shw_io_box_fan_tacho[] = {{PIOE, 7, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_shw_io_fpga_fan_en[] = {{PIOB, 24, PIO_MODE_GPIO, PIO_OUT}, {0}};
const pio_pin_t PIN_shw_io_led_cpu1[] = {{PIOA, 0, PIO_MODE_GPIO, PIO_OUT}, {0}};
const pio_pin_t PIN_shw_io_led_cpu2[] = {{PIOA, 1, PIO_MODE_GPIO, PIO_OUT}, {0}};
const pio_pin_t PIN_shw_io_arm_boot_sel[] = {{PIOC, 7, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_shw_io_arm_gen_but[] = {{PIOE, 9, PIO_MODE_GPIO, PIO_IN}, {0}};
const shw_chip_t I2C_pca9554_ver = {(void*)&i2c_io_bus, 0x20, 0x0F, I2C_CHIP_PCA9554};
const shw_io_bus_t I2C_shw_io_led_state_g[] = { {&I2C_pca9554_ver, (1<<4),4}, {0}};
const shw_io_bus_t I2C_shw_io_led_state_o[] = { {&I2C_pca9554_ver, (1<<5),5}, {0}};
//Declaration of the array
const shw_io_t _all_shw_io[NUM_SHW_IO_ID];
int shw_io_init()
{
float ver;
int ret;
//Remove const for writing
shw_io_t* all_shw_io=(shw_io_t*)_all_shw_io;
//Map CPU's pin into memory space
assert_init(shw_pio_mmap_init());
//then init the i2c (if it was not done)
if(i2c_io_bus.err==I2C_NULL_PARAM)
assert_init(shw_i2c_io_init());
//then obtain the serial number
ver=shw_get_hw_ver();
//Finally assigned the input/ouput according to version number.
if(ver<3.3)
{
IOARR_SET_GPIO(shw_io_reset_n);
IOARR_SET_GPIO(shw_io_box_fan_en);
IOARR_SET_GPIO(shw_io_box_fan_tacho);
IOARR_SET_GPIO(shw_io_fpga_fan_en);
IOARR_SET_GPIO(shw_io_led_cpu1);
IOARR_SET_GPIO(shw_io_led_cpu2);
IOARR_SET_GPIO(shw_io_arm_boot_sel);
IOARR_SET_GPIO(shw_io_arm_gen_but);
}
else
{
IOARR_SET_GPIO(shw_io_reset_n);
IOARR_SET_GPIO(shw_io_led_cpu1);
IOARR_SET_GPIO(shw_io_led_cpu2);
IOARR_SET_GPIO(shw_io_arm_boot_sel);
IOARR_SET_IO(shw_io_led_state_g,SHW_I2C,I2C_shw_io_led_state_g);
IOARR_SET_IO(shw_io_led_state_o,SHW_I2C,I2C_shw_io_led_state_o);
//Finally setup the orange led state before initiate anything else
shw_io_write(shw_io_led_state_o,1);
}
TRACE(TRACE_INFO, "version=%g",ver);
return 0;
}
int shw_io_configure_all()
{
int i;
const shw_io_bus_t *iobus;
const shw_io_t* all_io=(shw_io_t*)_all_shw_io;
for(i=0;i<NUM_SHW_IO_ID;i++)
{
const shw_io_t* io=(const shw_io_t*)&_all_shw_io[i];
switch(io->type)
{
case SHW_CPU_PIO:
shw_pio_configure(all_io[i].ptr);
break;
case SHW_I2C:
iobus = (const shw_io_bus_t *)io->ptr;
if(iobus->chip && iobus->chip->type==I2C_CHIP_PCA9554)
wrswhw_pca9554_configure(iobus->chip->bus,iobus->chip->addr,iobus->chip->config);
break;
case SHW_UNDEF:
//Do nothing for undefined type
break;
default:
TRACE(TRACE_INFO,"Config not implemented for type %d for io #%d",io->type,i); break;
}
}
return 0;
}
const pio_pin_t* get_pio_pin(shw_io_id_t id)
{
const shw_io_t *wrpin=get_shw_io(id);
if(wrpin && wrpin->type==SHW_CPU_PIO)
return (wrpin)?(const pio_pin_t*)wrpin->ptr:0;
}
const shw_io_t* get_shw_io(shw_io_id_t id)
{
if(0< id && id < NUM_SHW_IO_ID)
{
if(_all_shw_io[id].ID==id) return &(_all_shw_io[id]);
else TRACE(TRACE_ERROR,"IO %d does not correspond to its ID %s",id,_all_shw_io[id].name);
}
else TRACE(TRACE_ERROR,"IO %d does not exist",id);
return 0;
}
uint32_t shw_io_read(shw_io_id_t id)
{
uint32_t ret;
int32_t i32data;
uint8_t u8data[2];
const shw_io_t* io=&_all_shw_io[id];
const shw_io_bus_t *iobus;
if(0< id && id < NUM_SHW_IO_ID && io->ID==id && io->ptr)
{
switch(io->type)
{
case SHW_CPU_PIO:
return shw_pio_get((const pio_pin_t*)io->ptr);
case SHW_I2C:
iobus = (const shw_io_bus_t *)io->ptr;
if(iobus->chip && iobus->chip->type==I2C_CHIP_PCA9554)
{
i32data = wrswhw_pca9554_get_input(iobus->chip->bus,iobus->chip->addr);
return ((i32data & iobus->mask) >> iobus->shift);
}
case SHW_UNDEF:
TRACE(TRACE_ERROR,"IO #%d is undef",id); break;
default:
TRACE(TRACE_ERROR,"Unknow type %d for io #%d",io->type,id); break;
}
}
return ret;
}
int shw_io_write(shw_io_id_t id, uint32_t value)
{
int ret=-1;
int32_t i32data;
uint8_t u8data[2];
const shw_io_t* io=&_all_shw_io[id];
const shw_io_bus_t *iobus;
if(0< id && id < NUM_SHW_IO_ID && io->ID==id && io->ptr)
{
switch(io->type)
{
case SHW_CPU_PIO:
shw_pio_set((const pio_pin_t*)io->ptr,value);
return 0;
case SHW_I2C:
iobus = (const shw_io_bus_t *)io->ptr;
if(iobus->chip && iobus->chip->type==I2C_CHIP_PCA9554)
{
i32data = wrswhw_pca9554_get_input(iobus->chip->bus,iobus->chip->addr);
i32data &= ~iobus->mask;
value <<= iobus->shift;
value &= iobus->mask;
return wrswhw_pca9554_set_output_reg(iobus->chip->bus,iobus->chip->addr,value | i32data);
}
case SHW_UNDEF:
TRACE(TRACE_ERROR,"Pin #%d is undef",id); break;
default:
TRACE(TRACE_ERROR,"Unknow type %d for io #%d",io->type,id); break;
}
}
return -1;
}
const char *get_shw_info(const char cmd)
{
static char str_hwver[10];
switch(cmd)
{
case 'p':
snprintf(str_hwver,10,"%g",shw_get_hw_ver()); //generate a non harmful warning with our compiler
return str_hwver;
case 'f':
return (shw_get_fpga_type()==SHW_FPGA_LX240T)?"LX240T":"LX130T";
}
return "";
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment