From 3681925508c0da88fee6325ea35ead7b112856c6 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Tue, 20 Dec 2011 16:27:54 +0100 Subject: LEON: updated shared drivers to Driver Manger framework Some bugfixes at the same time. After this patch the drivers may be used on RASTA systems having a big-endian PCI layout. Removed not up to date changelogs, rely on git log instead. --- c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c | 355 +++++++++++++++++------------ 1 file changed, 205 insertions(+), 150 deletions(-) (limited to 'c/src/lib/libbsp/sparc/shared/i2c') diff --git a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c index 02710e1b84..f71af0be61 100644 --- a/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c +++ b/c/src/lib/libbsp/sparc/shared/i2c/i2cmst.c @@ -1,7 +1,7 @@ /* * Driver for GRLIB port of OpenCores I2C-master * - * COPYRIGHT (c) 2007 Gaisler Research + * COPYRIGHT (c) 2007 Cobham Gaisler AB * based on the RTEMS MPC83xx I2C driver (c) 2007 Embedded Brains GmbH. * * The license and distribution terms for this file may be @@ -9,27 +9,41 @@ * http://www.rtems.org/license/LICENSE. * * This file contains the driver and initialization code - * - * 2007-09-27: First version of driver (jan@gaisler.com) */ - #include -#include +#include +#include #include -#include #include +#include +#include + +#include /* Enable debug printks? */ -/* #define DEBUG */ +/*#define DEBUG*/ -/* Default to 40 MHz system clock? */ -/* - #ifndef SYS_FREQ_kHZ - #define SYS_FREQ_kHZ 40000 - #endif -*/ +#ifdef DEBUG + #define DBG(args...) printk(args) +#else + #define DBG(args...) +#endif +/* The OC I2C core will perform a write after a start unless the RD bit + in the command register has been set. Since the rtems framework has + a send_start function we buffer that command and use it when the first + data is written. The START is buffered in the sendstart member below */ +typedef struct gr_i2cmst_prv { + rtems_libi2c_bus_t i2clib_desc; + struct drvmgr_dev *dev; + gr_i2cmst_regs_t *reg_ptr; + unsigned int sysfreq; /* System clock frequency in kHz */ + int minor; + unsigned char sendstart; /* START events are buffered here */ + /* rtems_irq_number irq_number; */ + /* rtems_id irq_sema_id; */ +} gr_i2cmst_prv_t; /* Calculates the scaler value for 100 kHz operation */ static int gr_i2cmst_calc_scaler(int sysfreq) @@ -42,12 +56,12 @@ static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts) { uint32_t tout = 0; int current_sts; -#if defined(DEBUG) - printk("(gr_i2cmst_wait called..."); -#endif + + DBG("(gr_i2cmst_wait called..."); do { if (tout++ > 1000000) { + DBG("gr_i2cmst_wait: TIMEOUT\n"); return RTEMS_TIMEOUT; } } while (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP); @@ -57,32 +71,31 @@ static int gr_i2cmst_wait(gr_i2cmst_prv_t *prv_ptr, uint8_t expected_sts) if (current_sts != expected_sts) { #if defined(DEBUG) if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_RXACK) { - printk("Transfer NAKed.."); + DBG("Transfer NAKed.."); } if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_AL) { - printk("arbitration lost.."); + DBG("arbitration lost.."); } if (prv_ptr->reg_ptr->cmdsts & GRI2C_STS_TIP) { - printk("transfer still in progress, huh?.."); + DBG("transfer still in progress, huh?.."); } - printk("exited with IO error..)"); + DBG("exited with IO error..)"); #endif + DBG("gr_i2cmst_wait: IO-ERROR\n"); return RTEMS_IO_ERROR; } -#if defined(DEBUG) - printk("exited...)"); -#endif + DBG("exited...)"); + return RTEMS_SUCCESSFUL; } /* Initialize hardware core */ static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl) { - gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv); -#if defined(DEBUG) - printk("gr_i2cmst_init called..."); -#endif + gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl; + + DBG("gr_i2cmst_init called..."); /* Disable core before changing prescale register */ prv_ptr->reg_ptr->ctrl = 0; @@ -96,54 +109,48 @@ static rtems_status_code gr_i2cmst_init(rtems_libi2c_bus_t *bushdl) /* Clear possible START condition */ prv_ptr->sendstart = 0; -#if defined(DEBUG) - printk("exited\n"); -#endif + DBG("exited\n"); + return RTEMS_SUCCESSFUL; } static rtems_status_code gr_i2cmst_send_start(rtems_libi2c_bus_t *bushdl) { - gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv); -#if defined(DEBUG) - printk("gr_i2cmst_send_start called..."); -#endif + gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl; + + DBG("gr_i2cmst_send_start called..."); /* The OC I2C core does not work with stand alone START events, instead the event is buffered */ prv_ptr->sendstart = GRI2C_CMD_STA; -#if defined(DEBUG) - printk("exited\n"); -#endif + DBG("exited\n"); + return RTEMS_SUCCESSFUL; } static rtems_status_code gr_i2cmst_send_stop(rtems_libi2c_bus_t *bushdl) { - gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv); -#if defined(DEBUG) - printk("gr_i2cmst_send_stop called..."); -#endif + gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl; + + DBG("gr_i2cmst_send_stop called..."); prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_STO; -#if defined(DEBUG) - printk("exited\n"); -#endif + DBG("exited\n"); + return RTEMS_SUCCESSFUL; } static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl, uint32_t addr, int rw) { - gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv); + gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl; uint8_t addr_byte; rtems_status_code rc; -#if defined(DEBUG) - printk("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...", + + DBG("gr_i2cmst_send_addr called, addr = 0x%x, rw = %d...", addr, rw); -#endif /* Check if long address is needed */ if (addr > 0x7f) { @@ -156,9 +163,9 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl, /* Wait for transfer to complete */ rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE); if (rc != RTEMS_SUCCESSFUL) { -#if defined(DEBUG) - printk("exited with error\n"); -#endif + + DBG("exited with error\n"); + return -rc; } } @@ -176,16 +183,12 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl, /* Wait for transfer to complete */ rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE); if (rc != RTEMS_SUCCESSFUL) { -#if defined(DEBUG) - printk("exited with error\n"); -#endif + DBG("exited with error\n"); return -rc; } - } + } -#if defined(DEBUG) - printk("exited\n"); -#endif + DBG("exited\n"); return rc; } @@ -193,13 +196,12 @@ static rtems_status_code gr_i2cmst_send_addr(rtems_libi2c_bus_t *bushdl, static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl, unsigned char *bytes, int nbytes) { - gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv); + gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl; unsigned char *buf = bytes; rtems_status_code rc; unsigned char expected_sts = GRI2C_STATUS_IDLE; -#if defined(DEBUG) - printk("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes); -#endif + + DBG("gr_i2cmst_read_bytes called, nbytes = %d...", nbytes); while (nbytes-- > 0) { if (nbytes == 0) { @@ -214,34 +216,30 @@ static int gr_i2cmst_read_bytes(rtems_libi2c_bus_t *bushdl, /* Wait until end of transfer */ rc = gr_i2cmst_wait(prv_ptr, expected_sts); if (rc != RTEMS_SUCCESSFUL) { + DBG("exited with error\n"); return -rc; -#if defined(DEBUG) - printk("exited with error\n"); -#endif } *buf++ = prv_ptr->reg_ptr->tdrd; } -#if defined(DEBUG) - printk("exited\n"); -#endif + DBG("exited\n"); + return buf - bytes; } static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl, unsigned char *bytes, int nbytes) { - gr_i2cmst_prv_t *prv_ptr = &(((gr_i2cmst_desc_t *)(bushdl))->prv); + gr_i2cmst_prv_t *prv_ptr = (gr_i2cmst_prv_t *)bushdl; unsigned char *buf = bytes; rtems_status_code rc; -#if defined(DEBUG) - printk("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes); -#endif + + DBG("gr_i2cmst_write_bytes called, nbytes = %d...", nbytes); while (nbytes-- > 0) { -#if defined(DEBUG) - printk("writing byte 0x%02X...", *buf); -#endif + + DBG("writing byte 0x%02X...", *buf); + prv_ptr->reg_ptr->tdrd = *buf++; prv_ptr->reg_ptr->cmdsts = GRI2C_CMD_WR | prv_ptr->sendstart; prv_ptr->sendstart = 0; @@ -250,16 +248,13 @@ static int gr_i2cmst_write_bytes(rtems_libi2c_bus_t *bushdl, rc = gr_i2cmst_wait(prv_ptr, GRI2C_STATUS_IDLE); if (rc != RTEMS_SUCCESSFUL) { -#if defined(DEBUG) - printk("exited with error\n"); -#endif + DBG("exited with error\n"); return -rc; } } -#if defined(DEBUG) - printk("exited\n"); -#endif + DBG("exited\n"); + return buf - bytes; } @@ -272,88 +267,148 @@ static rtems_libi2c_bus_ops_t gr_i2cmst_ops = { write_bytes: gr_i2cmst_write_bytes, }; +/* Get Hardware and disable it */ +int i2cmst_device_init(gr_i2cmst_prv_t *priv) +{ + struct amba_dev_info *ambadev; + struct ambapp_core *pnpinfo; -static gr_i2cmst_desc_t gr_i2cmst_desc = { - { /* rtems_libi2c_bus_t */ - ops : &gr_i2cmst_ops, - size : sizeof(gr_i2cmst_ops), - }, - { /* gr_i2cmst_prv_t, private data */ - reg_ptr : NULL, - sysfreq : 40000, - } + /* Get device information from AMBA PnP information */ + ambadev = (struct amba_dev_info *)priv->dev->businfo; + if ( ambadev == NULL ) { + return -1; + } + pnpinfo = &ambadev->info; + priv->reg_ptr = (gr_i2cmst_regs_t *)pnpinfo->apb_slv->start; + + /* Disable core */ + priv->reg_ptr->ctrl = 0; + + priv->i2clib_desc.ops = &gr_i2cmst_ops; + priv->i2clib_desc.size = sizeof(gr_i2cmst_ops); + return 0; +} + + +/******************* Driver Manager Part ***********************/ + +int i2cmst_init2(struct drvmgr_dev *dev); +int i2cmst_init3(struct drvmgr_dev *dev); +struct drvmgr_drv_ops i2cmst_ops = +{ + .init = {NULL, i2cmst_init2, i2cmst_init3, NULL}, + .remove = NULL, + .info = NULL }; -/* Scans for I2CMST core and initalizes i2c library */ -rtems_status_code leon_register_i2c(struct ambapp_bus *abus) +struct amba_dev_id i2cmst_ids[] = { -#if defined(DEBUG) - printk("leon_register_i2c called..."); -#endif + {VENDOR_GAISLER, GAISLER_I2CMST}, + {0, 0} /* Mark end of table */ +}; - int rc; - int device_found = 0; - struct ambapp_apb_info apbi2cmst; +struct amba_drv_info i2cmst_drv_info = +{ + { + DRVMGR_OBJ_DRV, /* Driver */ + NULL, /* Next driver */ + NULL, /* Device list */ + DRIVER_AMBAPP_GAISLER_I2CMST_ID, /* Driver ID */ + "I2CMST_DRV", /* Driver Name */ + DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ + &i2cmst_ops, + NULL, /* Funcs */ + 0, /* No devices yet */ + 0, + }, + &i2cmst_ids[0] +}; - /* Scan AMBA bus for I2CMST core */ - device_found = ambapp_find_apbslv(abus, VENDOR_GAISLER, GAISLER_I2CMST, - &apbi2cmst); +void i2cmst_register_drv (void) +{ + DBG("Registering I2CMST driver\n"); + drvmgr_drv_register(&i2cmst_drv_info.general); +} - if (device_found == 1) { +/* The I2CMST Driver is informed about a new hardware device */ +int i2cmst_init2(struct drvmgr_dev *dev) +{ + gr_i2cmst_prv_t *priv; - /* Initialize i2c library */ - rc = rtems_libi2c_initialize(); - if (rc < 0) { -#if defined(DEBUG) - printk("rtems_libi2x_initialize failed, exiting...\n"); -#endif - return rc; - } + DBG("I2CMST[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); - gr_i2cmst_desc.prv.reg_ptr = (gr_i2cmst_regs_t *)apbi2cmst.start; + priv = dev->priv = malloc(sizeof(gr_i2cmst_prv_t)); + if ( !priv ) + return DRVMGR_NOMEM; + memset(priv, 0, sizeof(*priv)); + priv->dev = dev; - /* Detect system frequency, same as in apbuart_initialize */ -#ifndef SYS_FREQ_kHZ -#if defined(LEON3) - /* LEON3: find timer address via AMBA Plug&Play info */ - { - struct ambapp_apb_info gptimer; - struct gptimer_regs *tregs; - - if (ambapp_find_apbslv(abus, VENDOR_GAISLER, - GAISLER_GPTIMER, &gptimer) == 1 ) { - tregs = (struct gptimer_regs *)gptimer.start; - gr_i2cmst_desc.prv.sysfreq = (tregs->scaler_reload+1)*1000; - } else { - gr_i2cmst_desc.prv.sysfreq = 40000; /* Default to 40MHz */ - } + /* This core will not find other cores, so we wait for init2() */ + + return DRVMGR_OK; +} + +/* Init stage 2 */ +int i2cmst_init3(struct drvmgr_dev *dev) +{ + gr_i2cmst_prv_t *priv; + char prefix[32]; + char devName[32]; + int rc; + + priv = (gr_i2cmst_prv_t *)dev->priv; + + /* Do initialization */ + + /* Initialize i2c library */ + rc = rtems_libi2c_initialize(); + if (rc != 0) { + DBG("I2CMST: rtems_libi2c_initialize failed, exiting...\n"); + free(dev->priv); + dev->priv = NULL; + return DRVMGR_FAIL; } -#elif defined(LEON2) - /* LEON2: use hardcoded address to get to timer */ - { - LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000; - gr_i2cmst_desc.prv.sysfreq = (regs->Scaler_Reload+1)*1000; + + /* I/O system registered and initialized + * Now we take care of device initialization. + */ + + /* Get frequency */ + if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->sysfreq) ) { + return DRVMGR_FAIL; } -#else -#error CPU not supported for I2CMST driver */ -#endif -#else - /* Use hardcoded frequency */ - gr_i2cmst_desc.prv.sysfreq = SYS_FREQ_kHZ; -#endif + priv->sysfreq = priv->sysfreq / 1000; /* Convert to kHz */ - rc = rtems_libi2c_register_bus("/dev/i2c1", &gr_i2cmst_desc.bus_desc); - if (rc < 0) { -#if defined(DEBUG) - printk("rtems_libi2c_register_bus failed, exiting..\n"); -#endif - return -rc; - } - } + if ( i2cmst_device_init(priv) ) { + free(dev->priv); + dev->priv = NULL; + return DRVMGR_FAIL; + } -#if defined(DEBUG) - printk("exited\n"); -#endif - return 0; + /* Get Filesystem name prefix */ + prefix[0] = '\0'; + if ( drvmgr_get_dev_prefix(dev, prefix) ) { + /* Failed to get prefix, make sure of a unique FS name + * by using the driver minor. + */ + sprintf(devName, "/dev/i2c%d", dev->minor_drv+1); + } else { + /* Got special prefix, this means we have a bus prefix + * And we should use our "bus minor" + */ + sprintf(devName, "/dev/%si2c%d", prefix, dev->minor_bus+1); + } + + /* Register Bus for this Device */ + rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc); + if (rc < 0) { + DBG("I2CMST: rtems_libi2c_register_bus(%s) failed, exiting..\n", devName); + free(dev->priv); + dev->priv = NULL; + return DRVMGR_FAIL; + } + priv->minor = rc; + + return DRVMGR_OK; } -- cgit v1.2.3