source: rtems/bsps/powerpc/beatnik/marvell/gti2c.c

Last change on this file was 8266fb53, checked in by Sebastian Huber <sebastian.huber@…>, on 04/25/18 at 08:25:00

bsp/beatnik: Move source files to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 11.3 KB
Line 
1/*      $NetBSD: gti2c.c,v 1.2 2005/02/27 00:27:21 perry Exp $  */
2
3/*
4 * Copyright (c) 2005 Brocade Communcations, inc.
5 * All rights reserved.
6 *
7 * Written by Matt Thomas for Brocade Communcations, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of Brocade Communications, Inc. may not be used to endorse
18 *    or promote products derived from this software without specific prior
19 *    written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY BROCADE COMMUNICATIONS, INC. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL EITHER BROCADE COMMUNICATIONS, INC. BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/* Fixed many things + ported to RTEMS by Till Straumann, 2005 */
35
36#include <stdio.h>
37#include <rtems.h>
38#include <libcpu/io.h>
39#include <sys/errno.h>
40#include <rtems/bspIo.h>
41#include <rtems/score/sysstate.h>
42#include <bsp/irq.h>
43#include <rtems/libi2c.h>
44
45#include <sys/cdefs.h>
46
47#include <bsp/gtintrreg.h>
48#include <bsp/gti2creg.h>
49#include <bsp/gti2c_busdrv.h>
50
51#define ENABLE_IRQ_AT_PIC_HACK  /* workaround for a bad HW bug */
52#undef  DEBUG
53
54#ifndef BSP_IRQ_MIN_PRIO
55#define BSP_IRQ_MIN_PRIO 1
56#endif
57
58struct gti2c_softc {
59        uint32_t        sc_gt;
60        uint32_t        sc_cntl;
61        int                     sc_inited;
62        rtems_id        sc_sync;
63        int                     sc_irqs; /* statistics */
64};
65
66#ifdef DEBUG
67#define STATIC
68#else
69#define STATIC static
70#endif
71
72typedef struct {
73        rtems_libi2c_bus_t      bus_desc;       
74        struct gti2c_softc      pvt;
75} gti2c_desc_rec, *gti2c_desc;
76
77STATIC rtems_status_code
78gt_i2c_init(rtems_libi2c_bus_t *bh);
79STATIC rtems_status_code
80gt_i2c_send_start(rtems_libi2c_bus_t *bh);
81STATIC rtems_status_code
82gt_i2c_send_stop(rtems_libi2c_bus_t *bh);
83STATIC rtems_status_code
84gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw);
85STATIC int
86gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len);
87STATIC int
88gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len);
89
90static rtems_libi2c_bus_ops_t myops = {
91        init:                   gt_i2c_init,
92        send_start:             gt_i2c_send_start,
93        send_stop:              gt_i2c_send_stop,
94        send_addr:              gt_i2c_send_addr,
95        read_bytes:             gt_i2c_read_bytes,
96        write_bytes:    gt_i2c_write_bytes,
97};
98
99static gti2c_desc_rec my_bus_tbl = {
100        {
101                ops:    &myops,
102                size:   sizeof(my_bus_tbl),
103        },/* public fields */
104        {
105                sc_gt:          BSP_MV64x60_BASE,
106                sc_cntl:        I2C_Control_TWSIEn,
107                sc_inited:      0,
108                sc_sync:        0
109        } /* our private fields */
110};
111
112
113static inline uint32_t
114gt_read(uint32_t base, uint32_t off)
115{
116        return in_le32((volatile uint32_t*)(base+off));
117}
118
119static inline void
120gt_write(uint32_t base, uint32_t off, uint32_t val)
121{
122        out_le32((volatile uint32_t*)(base+off), val);
123}
124
125
126static inline void
127disable_irq(struct gti2c_softc *sc)
128{
129uint32_t v = gt_read(sc->sc_gt, I2C_REG_Control);
130        gt_write(sc->sc_gt, I2C_REG_Control, v & ~I2C_Control_IntEn);
131}
132
133
134static rtems_status_code
135gt_i2c_wait(struct gti2c_softc *sc, uint32_t control, uint32_t desired_status)
136{
137        uint32_t status;
138        rtems_status_code rval;
139
140        control |= I2C_Control_IntEn;
141
142        gt_write(sc->sc_gt, I2C_REG_Control, control | sc->sc_cntl);
143
144        if ( sc->sc_inited ) {
145
146#ifdef ENABLE_IRQ_AT_PIC_HACK
147                BSP_enable_irq_at_pic(BSP_IRQ_I2C);
148#endif
149
150                rval = rtems_semaphore_obtain(sc->sc_sync, RTEMS_WAIT, 100);
151
152                if ( RTEMS_SUCCESSFUL != rval )
153                        return rval;
154        } else {
155                uint32_t then, now;
156
157                /* run in polling mode - useful during init */
158                if ( _System_state_Is_up(_System_state_Get()) ) {
159                        printk("WARNING: gti2c running in polled mode -- should initialize properly!\n");
160                }
161
162                asm volatile("mftb %0":"=r"(then));
163
164                do {
165                        asm volatile("mftb %0":"=r"(now));
166                        /* poll timebase for .2 seconds assuming a bus clock of 100MHz */
167                        if ( now - then > (uint32_t)100000000/4/5 )
168                                return RTEMS_TIMEOUT;
169                } while ( ! (I2C_Control_IFlg & gt_read(sc->sc_gt, I2C_REG_Control)) );
170        }
171
172        status = gt_read(sc->sc_gt, I2C_REG_Status);
173
174        if ( status != desired_status && (status!=I2C_Status_ReStarted || desired_status!=I2C_Status_Started) )
175                return RTEMS_IO_ERROR;
176
177        return RTEMS_SUCCESSFUL;
178}
179
180static void
181gt_i2c_intr(void *arg)
182{
183struct gti2c_softc * const sc = &my_bus_tbl.pvt;
184        uint32_t v;
185
186        v = gt_read(sc->sc_gt, I2C_REG_Control);
187        if ((v & I2C_Control_IFlg) == 0) {
188                printk("gt_i2c_intr: IRQ but IFlg not set??\n");
189                return;
190        }
191        gt_write(sc->sc_gt, I2C_REG_Control, v & ~(I2C_Control_IntEn));
192#if 0
193        gt_read(sc->sc_gt, I2C_REG_Control);
194        asm volatile("sync");
195/* This is how bad it is: after turning off the IntEn bit, the line
196 * still remains asserted! (shame on you.)
197 *
198 * The test below (on MVME6100; the MVME5500 has the same problem
199 * but the main cause register address is different; substitute
200 * 0xf100000c for 0xf1000c68 on a 5500).
201 *
202 * The skew was 101 TB ticks or ~3us (bus freq 133MHz) which
203 * really sucks.
204 *
205 * Therefore, we must disable the interrupt at the PIC
206 */
207{unsigned from,to;
208        asm volatile("mftb %0":"=r"(from));
209        while ( in_le32((volatile uint32_t*)0xf100000c) & 0x20 )
210                ;
211        asm volatile("mftb %0":"=r"(to));
212        printk("I2C IRQ remained asserted for %i TB ticks!\n",to-from);
213}
214#endif
215#ifdef ENABLE_IRQ_AT_PIC_HACK
216        BSP_disable_irq_at_pic(BSP_IRQ_I2C);
217#endif
218
219        sc->sc_irqs++;
220
221        rtems_semaphore_release(sc->sc_sync);
222}
223
224STATIC rtems_status_code
225gt_i2c_init(rtems_libi2c_bus_t *bh)
226{
227struct gti2c_softc * const      sc = &((gti2c_desc)bh)->pvt;
228unsigned                                        m,n,N;
229
230        disable_irq(sc);
231
232        /* reset */
233        gt_write(sc->sc_gt, I2C_REG_SoftReset, 0);
234        gt_write(sc->sc_gt, I2C_REG_SlaveAddr, 0);
235        gt_write(sc->sc_gt, I2C_REG_ExtSlaveAddr, 0);
236
237        /* Set baud rate; I don't know the details
238         * but have to assume that it has to fit into 7 bits
239         * (as indicated by some experiment)
240         */
241        n = 0, N=1<<n;
242        do {
243                n++, N<<=1;
244                /* increase 2^n until m becomes small enough */
245                m = BSP_bus_frequency / 10 / 62500 / N;
246        } while ( m > 16 );
247
248        /* n is at least 1 */
249        if ( n > 8 ) {
250                n = 8; m = 16;  /* nothing else we can do */
251        }
252        if ( 0 == m )
253                m = 1; /* nothing we can do */
254
255        gt_write(sc->sc_gt, I2C_REG_BaudRate, I2C_BaudRate(m-1, n-1));
256
257        if ( !sc->sc_inited ) {
258
259                if ( _System_state_Is_up(_System_state_Get()) ) {
260                        rtems_irq_connect_data ii = {
261                                name:   BSP_IRQ_I2C,
262                                hdl:    gt_i2c_intr,
263                                on:             0,
264                                off:    0,
265                                isOn:   0
266                        };
267                        rtems_status_code err;
268                        /* synchronization semaphore */
269                        err = rtems_semaphore_create(
270                                        rtems_build_name('g','i','2','c'),
271                                        0,
272                                        RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_LOCAL,
273                                        0,
274                                        &sc->sc_sync);
275                        if ( err ) {
276                                sc->sc_sync = 0;
277                                return err;
278                        }
279                        if ( !BSP_install_rtems_irq_handler(&ii) ) {
280                                fprintf(stderr,"Unable to install interrupt handler\n");
281                                rtems_semaphore_delete(sc->sc_sync);
282                                return RTEMS_INTERNAL_ERROR;
283                        }
284                        BSP_irq_set_priority(BSP_IRQ_I2C, BSP_IRQ_MIN_PRIO);
285                        sc->sc_inited = 1;
286                } else {
287                }
288        } else {
289                rtems_semaphore_flush(sc->sc_sync);
290        }
291        return RTEMS_SUCCESSFUL;
292}
293
294STATIC rtems_status_code
295gt_i2c_send_start(rtems_libi2c_bus_t *bh)
296{
297struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
298
299        return gt_i2c_wait(sc, I2C_Control_Start, I2C_Status_Started);
300}
301
302STATIC rtems_status_code
303gt_i2c_send_stop(rtems_libi2c_bus_t *bh)
304{
305struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
306uint32_t        data;
307
308        data = gt_read(sc->sc_gt, I2C_REG_Status);
309        if ( I2C_Status_Started == data || I2C_Status_ReStarted == data ) {
310                /* According to the spec, a void message (start - stop sequence)
311                 * is illegal and indeed, the chip plays bad tricks with us, i.e.,
312                 * sometimes it hangs the bus so that it remains idle forever.
313                 * so we have to address someone...
314                 */
315                gt_i2c_send_addr(bh, /*just something... */ 8, 1);
316                data = gt_read(sc->sc_gt, I2C_REG_Status);
317        }
318
319        if ( I2C_Status_AddrReadAck == data ) {
320                /* Another thing: spec says that the master generates stop only after
321                 * not acknowledging the last byte. Again, the chip doesn't like
322                 * to be stopped in this condition - hence we just do it the favor
323                 * and read a single byte...
324                 */
325                gt_i2c_read_bytes(bh, (unsigned char *)&data, 1);
326        }
327
328        gt_write(sc->sc_gt, I2C_REG_Control, I2C_Control_Stop | sc->sc_cntl);
329
330        /* should we poll for idle? There seems to be in IRQ when this completes */
331        return RTEMS_SUCCESSFUL;
332}
333
334STATIC rtems_status_code
335gt_i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw)
336{
337struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
338uint32_t data, wanted_status;
339uint8_t read_mask = rw ? 1 : 0;
340rtems_status_code error;
341
342        if (read_mask) {
343                wanted_status = I2C_Status_AddrReadAck;
344        } else {
345                wanted_status = I2C_Status_AddrWriteAck;
346        }
347        /*
348         * First byte contains whether this xfer is a read or write.
349         */
350        data = read_mask;
351        if (addr > 0x7f) {
352                /*
353                 * If this is a 10bit request, the first address byte is
354                 * 0b11110<b9><b8><r/w>.
355                 */
356                data |= 0xf0 | ((addr & 0x300) >> 7);
357                gt_write(sc->sc_gt, I2C_REG_Data, data);
358                error = gt_i2c_wait(sc, 0, wanted_status);
359                if (error)
360                        return error;
361                /*
362                 * The first address byte has been sent, now to send
363                 * the second one.
364                 */
365                if (read_mask) {
366                        wanted_status = I2C_Status_2ndAddrReadAck;
367                } else {
368                        wanted_status = I2C_Status_2ndAddrWriteAck;
369                }
370                data = (uint8_t) addr;
371        } else {
372                data |= (addr << 1);
373        }
374
375        gt_write(sc->sc_gt, I2C_REG_Data, data);
376        return gt_i2c_wait(sc, 0, wanted_status);
377}
378
379STATIC int
380gt_i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len)
381{
382struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
383rtems_status_code error;
384register unsigned char *p=buf;
385
386        while ( len-- > 0 ) {
387                error = gt_i2c_wait(
388                                        sc,
389                                        len ? I2C_Control_ACK : 0,
390                                        len ? I2C_Status_MasterReadAck : I2C_Status_MasterReadNoAck);
391                if ( error ) {
392                        return -error;
393                }
394                *p++ = gt_read(sc->sc_gt, I2C_REG_Data);
395        }
396
397        return p-buf;
398}
399
400STATIC int
401gt_i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len)
402{
403struct gti2c_softc * const sc = &((gti2c_desc)bh)->pvt;
404int rval = 0;
405rtems_status_code error;
406
407        while ( len-- > 0 ) {
408                gt_write(sc->sc_gt, I2C_REG_Data, buf[rval]);
409                error = gt_i2c_wait(sc, 0, I2C_Status_MasterWriteAck);
410                if ( error ) {
411                        return -error;
412                }
413                rval++;
414        }
415
416        return rval;
417}
418
419rtems_libi2c_bus_t *gt64260_i2c_bus_descriptor = &my_bus_tbl.bus_desc;
420
421#ifdef DEBUG_MODULAR
422
423void
424_cexpModuleInitialize(void *arg)
425{
426        gt_i2c_init(&gt64260_i2c_bus_descriptor->bus_desc);
427}
428
429int
430_cexpModuleFinalize(void * arg)
431{
432struct gti2c_softc * const sc = &gt64260_i2c_bus_descriptor->pvt;
433
434        rtems_irq_connect_data ii = {
435                        name:   BSP_IRQ_I2C,
436                        hdl:    gt_i2c_intr,
437                        on:             noop,
438                        off:    noop,
439                        isOn:   inoop
440        };
441
442        rtems_semaphore_delete(sc->sc_sync);
443
444        return !BSP_remove_rtems_irq_handler(&ii);
445}
446
447#endif
Note: See TracBrowser for help on using the repository browser.