diff options
Diffstat (limited to 'c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c')
-rw-r--r-- | c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c | 447 |
1 files changed, 0 insertions, 447 deletions
diff --git a/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c b/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c deleted file mode 100644 index c602bac5eb..0000000000 --- a/c/src/lib/libbsp/powerpc/beatnik/marvell/gti2c.c +++ /dev/null @@ -1,447 +0,0 @@ -/* $NetBSD: gti2c.c,v 1.2 2005/02/27 00:27:21 perry Exp $ */ - -/* - * Copyright (c) 2005 Brocade Communcations, inc. - * All rights reserved. - * - * Written by Matt Thomas for Brocade Communcations, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Brocade Communications, Inc. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Fixed many things + ported to RTEMS by Till Straumann, 2005 */ - -#include <stdio.h> -#include <rtems.h> -#include <libcpu/io.h> -#include <sys/errno.h> -#include <rtems/bspIo.h> -#include <rtems/score/sysstate.h> -#include <bsp/irq.h> -#include <rtems/libi2c.h> - -#include <sys/cdefs.h> - -#include <bsp/gtintrreg.h> -#include <bsp/gti2creg.h> -#include <bsp/gti2c_busdrv.h> - -#define ENABLE_IRQ_AT_PIC_HACK /* workaround for a bad HW bug */ -#undef DEBUG - -#ifndef BSP_IRQ_MIN_PRIO -#define BSP_IRQ_MIN_PRIO 1 -#endif - -struct gti2c_softc { - uint32_t sc_gt; - uint32_t sc_cntl; - int sc_inited; - rtems_id sc_sync; - int sc_irqs; /* statistics */ -}; - -#ifdef DEBUG -#define STATIC -#else -#define STATIC static -#endif - -typedef struct { - rtems_libi2c_bus_t bus_desc; - struct gti2c_softc pvt; -} gti2c_desc_rec, *gti2c_desc; - -STATIC rtems_status_code -gt_i2c_init(rtems_libi2c_bus_t *bh); -STATIC rtems_status_code -gt_i2c_send_start(rtems_libi2c_bus_t *bh); -STATIC rtems_status_code -gt_i2c_send_stop(rtems_libi2c_bus_t *bh); -STATIC rtems_status_code -gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw); -STATIC int -gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len); -STATIC int -gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len); - -static rtems_libi2c_bus_ops_t myops = { - init: gt_i2c_init, - send_start: gt_i2c_send_start, - send_stop: gt_i2c_send_stop, - send_addr: gt_i2c_send_addr, - read_bytes: gt_i2c_read_bytes, - write_bytes: gt_i2c_write_bytes, -}; - -static gti2c_desc_rec my_bus_tbl = { - { - ops: &myops, - size: sizeof(my_bus_tbl), - },/* public fields */ - { - sc_gt: BSP_MV64x60_BASE, - sc_cntl: I2C_Control_TWSIEn, - sc_inited: 0, - sc_sync: 0 - } /* our private fields */ -}; - - -static inline uint32_t -gt_read(uint32_t base, uint32_t off) -{ - return in_le32((volatile uint32_t*)(base+off)); -} - -static inline void -gt_write(uint32_t base, uint32_t off, uint32_t val) -{ - out_le32((volatile uint32_t*)(base+off), val); -} - - -static inline void -disable_irq(struct gti2c_softc *sc) -{ -uint32_t v = gt_read(sc->sc_gt, I2C_REG_Control); - gt_write(sc->sc_gt, I2C_REG_Control, v & ~I2C_Control_IntEn); -} - - -static rtems_status_code -gt_i2c_wait(struct gti2c_softc *sc, uint32_t control, uint32_t desired_status) -{ - uint32_t status; - rtems_status_code rval; - - control |= I2C_Control_IntEn; - - gt_write(sc->sc_gt, I2C_REG_Control, control | sc->sc_cntl); - - if ( sc->sc_inited ) { - -#ifdef ENABLE_IRQ_AT_PIC_HACK - BSP_enable_irq_at_pic(BSP_IRQ_I2C); -#endif - - rval = rtems_semaphore_obtain(sc->sc_sync, RTEMS_WAIT, 100); - - if ( RTEMS_SUCCESSFUL != rval ) - return rval; - } else { - uint32_t then, now; - - /* run in polling mode - useful during init */ - if ( _System_state_Is_up(_System_state_Get()) ) { - printk("WARNING: gti2c running in polled mode -- should initialize properly!\n"); - } - - asm volatile("mftb %0":"=r"(then)); - - do { - asm volatile("mftb %0":"=r"(now)); - /* poll timebase for .2 seconds assuming a bus clock of 100MHz */ - if ( now - then > (uint32_t)100000000/4/5 ) - return RTEMS_TIMEOUT; - } while ( ! (I2C_Control_IFlg & gt_read(sc->sc_gt, I2C_REG_Control)) ); - } - - status = gt_read(sc->sc_gt, I2C_REG_Status); - - if ( status != desired_status && (status!=I2C_Status_ReStarted || desired_status!=I2C_Status_Started) ) - return RTEMS_IO_ERROR; - - return RTEMS_SUCCESSFUL; -} - -static void -gt_i2c_intr(void *arg) -{ -struct gti2c_softc * const sc = &my_bus_tbl.pvt; - uint32_t v; - - v = gt_read(sc->sc_gt, I2C_REG_Control); - if ((v & I2C_Control_IFlg) == 0) { - printk("gt_i2c_intr: IRQ but IFlg not set??\n"); - return; - } - gt_write(sc->sc_gt, I2C_REG_Control, v & ~(I2C_Control_IntEn)); -#if 0 - gt_read(sc->sc_gt, I2C_REG_Control); - asm volatile("sync"); -/* This is how bad it is: after turning off the IntEn bit, the line - * still remains asserted! (shame on you.) - * - * The test below (on MVME6100; the MVME5500 has the same problem - * but the main cause register address is different; substitute - * 0xf100000c for 0xf1000c68 on a 5500). - * - * The skew was 101 TB ticks or ~3us (bus freq 133MHz) which - * really sucks. - * - * Therefore, we must disable the interrupt at the PIC - */ -{unsigned from,to; - asm volatile("mftb %0":"=r"(from)); - while ( in_le32((volatile uint32_t*)0xf100000c) & 0x20 ) - ; - asm volatile("mftb %0":"=r"(to)); - printk("I2C IRQ remained asserted for %i TB ticks!\n",to-from); -} -#endif -#ifdef ENABLE_IRQ_AT_PIC_HACK - BSP_disable_irq_at_pic(BSP_IRQ_I2C); -#endif - - sc->sc_irqs++; - - rtems_semaphore_release(sc->sc_sync); -} - -STATIC rtems_status_code -gt_i2c_init(rtems_libi2c_bus_t *bh) -{ -struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; -unsigned m,n,N; - - disable_irq(sc); - - /* reset */ - gt_write(sc->sc_gt, I2C_REG_SoftReset, 0); - gt_write(sc->sc_gt, I2C_REG_SlaveAddr, 0); - gt_write(sc->sc_gt, I2C_REG_ExtSlaveAddr, 0); - - /* Set baud rate; I don't know the details - * but have to assume that it has to fit into 7 bits - * (as indicated by some experiment) - */ - n = 0, N=1<<n; - do { - n++, N<<=1; - /* increase 2^n until m becomes small enough */ - m = BSP_bus_frequency / 10 / 62500 / N; - } while ( m > 16 ); - - /* n is at least 1 */ - if ( n > 8 ) { - n = 8; m = 16; /* nothing else we can do */ - } - if ( 0 == m ) - m = 1; /* nothing we can do */ - - gt_write(sc->sc_gt, I2C_REG_BaudRate, I2C_BaudRate(m-1, n-1)); - - if ( !sc->sc_inited ) { - - if ( _System_state_Is_up(_System_state_Get()) ) { - rtems_irq_connect_data ii = { - name: BSP_IRQ_I2C, - hdl: gt_i2c_intr, - on: 0, - off: 0, - isOn: 0 - }; - rtems_status_code err; - /* synchronization semaphore */ - err = rtems_semaphore_create( - rtems_build_name('g','i','2','c'), - 0, - RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_LOCAL, - 0, - &sc->sc_sync); - if ( err ) { - sc->sc_sync = 0; - return err; - } - if ( !BSP_install_rtems_irq_handler(&ii) ) { - fprintf(stderr,"Unable to install interrupt handler\n"); - rtems_semaphore_delete(sc->sc_sync); - return RTEMS_INTERNAL_ERROR; - } - BSP_irq_set_priority(BSP_IRQ_I2C, BSP_IRQ_MIN_PRIO); - sc->sc_inited = 1; - } else { - } - } else { - rtems_semaphore_flush(sc->sc_sync); - } - return RTEMS_SUCCESSFUL; -} - -STATIC rtems_status_code -gt_i2c_send_start(rtems_libi2c_bus_t *bh) -{ -struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; - - return gt_i2c_wait(sc, I2C_Control_Start, I2C_Status_Started); -} - -STATIC rtems_status_code -gt_i2c_send_stop(rtems_libi2c_bus_t *bh) -{ -struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; -uint32_t data; - - data = gt_read(sc->sc_gt, I2C_REG_Status); - if ( I2C_Status_Started == data || I2C_Status_ReStarted == data ) { - /* According to the spec, a void message (start - stop sequence) - * is illegal and indeed, the chip plays bad tricks with us, i.e., - * sometimes it hangs the bus so that it remains idle forever. - * so we have to address someone... - */ - gt_i2c_send_addr(bh, /*just something... */ 8, 1); - data = gt_read(sc->sc_gt, I2C_REG_Status); - } - - if ( I2C_Status_AddrReadAck == data ) { - /* Another thing: spec says that the master generates stop only after - * not acknowledging the last byte. Again, the chip doesn't like - * to be stopped in this condition - hence we just do it the favor - * and read a single byte... - */ - gt_i2c_read_bytes(bh, (unsigned char *)&data, 1); - } - - gt_write(sc->sc_gt, I2C_REG_Control, I2C_Control_Stop | sc->sc_cntl); - - /* should we poll for idle? There seems to be in IRQ when this completes */ - return RTEMS_SUCCESSFUL; -} - -STATIC rtems_status_code -gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw) -{ -struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; -uint32_t data, wanted_status; -uint8_t read_mask = rw ? 1 : 0; -rtems_status_code error; - - if (read_mask) { - wanted_status = I2C_Status_AddrReadAck; - } else { - wanted_status = I2C_Status_AddrWriteAck; - } - /* - * First byte contains whether this xfer is a read or write. - */ - data = read_mask; - if (addr > 0x7f) { - /* - * If this is a 10bit request, the first address byte is - * 0b11110<b9><b8><r/w>. - */ - data |= 0xf0 | ((addr & 0x300) >> 7); - gt_write(sc->sc_gt, I2C_REG_Data, data); - error = gt_i2c_wait(sc, 0, wanted_status); - if (error) - return error; - /* - * The first address byte has been sent, now to send - * the second one. - */ - if (read_mask) { - wanted_status = I2C_Status_2ndAddrReadAck; - } else { - wanted_status = I2C_Status_2ndAddrWriteAck; - } - data = (uint8_t) addr; - } else { - data |= (addr << 1); - } - - gt_write(sc->sc_gt, I2C_REG_Data, data); - return gt_i2c_wait(sc, 0, wanted_status); -} - -STATIC int -gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len) -{ -struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; -rtems_status_code error; -register unsigned char *p=buf; - - while ( len-- > 0 ) { - error = gt_i2c_wait( - sc, - len ? I2C_Control_ACK : 0, - len ? I2C_Status_MasterReadAck : I2C_Status_MasterReadNoAck); - if ( error ) { - return -error; - } - *p++ = gt_read(sc->sc_gt, I2C_REG_Data); - } - - return p-buf; -} - -STATIC int -gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len) -{ -struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt; -int rval = 0; -rtems_status_code error; - - while ( len-- > 0 ) { - gt_write(sc->sc_gt, I2C_REG_Data, buf[rval]); - error = gt_i2c_wait(sc, 0, I2C_Status_MasterWriteAck); - if ( error ) { - return -error; - } - rval++; - } - - return rval; -} - -rtems_libi2c_bus_t *gt64260_i2c_bus_descriptor = &my_bus_tbl.bus_desc; - -#ifdef DEBUG_MODULAR - -void -_cexpModuleInitialize(void *arg) -{ - gt_i2c_init(>64260_i2c_bus_descriptor->bus_desc); -} - -int -_cexpModuleFinalize(void * arg) -{ -struct gti2c_softc * const sc = >64260_i2c_bus_descriptor->pvt; - - rtems_irq_connect_data ii = { - name: BSP_IRQ_I2C, - hdl: gt_i2c_intr, - on: noop, - off: noop, - isOn: inoop - }; - - rtems_semaphore_delete(sc->sc_sync); - - return !BSP_remove_rtems_irq_handler(&ii); -} - -#endif |