source: rtems/cpukit/dev/i2c/xilinx-axi-i2c.c @ dc158ad

5
Last change on this file since dc158ad was 05015dc1, checked in by Chris Johns <chrisj@…>, on 01/23/18 at 02:23:55

Xilinx AXI I2C driver IP race condition causes clock glitch.

Setting the PIRQ to 0 before reading the data produces a short clock pulse.
Moving the write to after reading the data fixes the issue.

Close #3173

  • Property mode set to 100644
File size: 25.7 KB
Line 
1/*
2 * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>  All rights reserved.
3 *
4 * The license and distribution terms for this file may be
5 * found in the file LICENSE in this distribution or at
6 * http://www.rtems.org/license/LICENSE.
7 */
8
9/*
10 * Xilinx AXI IIC Interface v2.0. See PG090.pdf.
11 *
12 * Note, only master support is provided and no dynamic mode by design.
13 */
14
15#include <stdarg.h>
16
17#include <rtems.h>
18#include <rtems/bspIo.h>
19#include <rtems/irq-extension.h>
20#include <rtems/score/assert.h>
21
22#include <dev/i2c/i2c.h>
23#include <dev/i2c/xilinx-axi-i2c.h>
24
25/*
26 * Register map.
27 */
28#define REG_GIE                    0x01c
29#define REG_ISR                    0x020
30#define REG_IER                    0x028
31#define REG_SOFTR                  0x040
32#define REG_CR                     0x100
33#define REG_SR                     0x104
34#define REG_TX_FIFO                0x108
35#define REG_RX_FIFO                0x10c
36#define REG_ADR                    0x110
37#define REG_TX_FIFO_OCY            0x114
38#define REG_RX_FIFO_OCY            0x118
39#define REG_TEN_ADR                0x11c
40#define REG_RX_FIFO_PIRQ           0x120
41#define REG_GPO                    0x124
42#define REG_TSUSTA                 0x128
43#define REG_TSUSTO                 0x12c
44#define REG_THDSTA                 0x130
45#define REG_TSUDAT                 0x134
46#define REG_TBUF                   0x138
47#define REG_THIGH                  0x13c
48#define REG_TLOW                   0x140
49#define REG_THDDAT                 0x144
50
51/*
52 * Interrupts.
53 */
54#define INT_ARB_LOST               (1 << 0)
55#define INT_TX_ERROR               (1 << 1)
56#define INT_TX_FIFO_EMPTY          (1 << 2)
57#define INT_RX_FIFO_FULL           (1 << 3)
58#define INT_BUS_NOT_BUSY           (1 << 4)
59#define INT_ADDRESSED_AS_SLAVE     (1 << 5)
60#define INT_NOT_ADDRESSED_AS_SLAVE (1 << 6)
61#define INT_TX_FIFO_HALF_FULL      (1 << 7)
62#define INT_ALL                    (0xff)
63
64/*
65 * Command register.
66 */
67#define CR_EN                      (1 << 0)
68#define CR_TX_FIFO_RESET           (1 << 1)
69#define CR_MSMS                    (1 << 2)
70#define CR_TX                      (1 << 3)
71#define CR_TXAK                    (1 << 4)
72#define CR_RSTA                    (1 << 5)
73#define CR_GC_EN                   (1 << 6)
74
75/*
76 * Status register.
77 */
78#define SR_ABGC                    (1 << 0)
79#define SR_AAS                     (1 << 1)
80#define SR_BB                      (1 << 2)
81#define SR_SRW                     (1 << 3)
82#define SR_TX_FIFO_FULL            (1 << 4)
83#define SR_RX_FIFO_FULL            (1 << 5)
84#define SR_RX_FIFO_EMPTY           (1 << 6)
85#define SR_TX_FIFO_EMPTY           (1 << 7)
86
87/*
88 * FIFO Sizes.
89 */
90#define TX_FIFO_SIZE      16
91#define TX_FIFO_HALF_SIZE (TX_FIFO_SIZE / 2)
92#define RX_FIFO_SIZE      16
93
94/*
95 * Address flags.
96 */
97#define ADDR_TEN  (1 << 31)
98#define ADDR_GPO  (1 << 30)
99
100typedef struct {
101  i2c_bus               base;
102  uintptr_t             regs;
103  i2c_msg*              msgs;
104  uint32_t              msgs_remaining;
105  i2c_msg*              current_msg;
106  uint32_t              current_msg_todo;
107  uint8_t*              current_msg_byte;
108  uint32_t              current_todo;
109  uint32_t              irqstatus;
110  bool                  read;
111  uint32_t              addr;
112  rtems_id              task_id;
113  bool                  gpo_address;
114  xilinx_aix_i2c_timing timing;
115  rtems_vector_number   irq;
116} xilinx_axi_i2c_bus;
117
118xilinx_axi_i2c_bus* axi_i2c_bus;
119
120/*
121 * Real-time trace buffering with a small overhead. The data can be dumped from
122 * gdb with:
123 *
124 * define axi-i2c
125 *  set $i = 0
126 *  while $i < axi_trace_in
127 *    printf "%4d %08x %08x %08x : ", \
128 *     $i, axi_trace[$i].vars[0], axi_trace[$i].vars[1], axi_trace[$i].vars[2]
129 *    output axi_trace[$i].state
130 *    printf "\n"
131 *    set $i = $i + 1
132 *  end
133 * end
134 */
135
136typedef enum
137{
138  AXI_I2C_NOP,
139  AXI_I2C_BEGIN,
140  AXI_I2C_END,
141  AXI_I2C_TRANSFER,
142  AXI_I2C_ADDRESS,
143  AXI_I2C_START_TRANSFER,
144  AXI_I2C_WRITE,
145  AXI_I2C_READ,
146  AXI_I2C_TX_FIFO,
147  AXI_I2C_RX_FIFO,
148  AXI_I2C_RX_FIFO_LEVEL,
149  AXI_I2C_INT,
150  AXI_I2C_INT_DONE,
151  AXI_I2C_INT_ERROR,
152  AXI_I2C_BUS_NOT_BUSY,
153  AXI_I2C_REG_WRITE,
154  AXI_I2C_REG_READ,
155  AXI_I2C_TIMEOUT,
156  AXI_I2C_WAKE
157} axi_i2c_state;
158
159#define RTEMS_AXI_I2C_TRACE 0
160#if RTEMS_AXI_I2C_TRACE
161
162#define DRIVER_REG_TRACE 1
163
164typedef struct
165{
166  axi_i2c_state state;
167  uint32_t      vars[3];
168} axi_i2c_trace;
169
170#define AXI_I2C_TRACE 5000
171axi_i2c_trace axi_trace[AXI_I2C_TRACE];
172int axi_trace_in;
173
174static inline void axi_trace_reset(void)
175{
176  axi_trace_in = 0;
177}
178
179static inline void axi_trace_append(axi_i2c_state state,
180                                    uint32_t      v1,
181                                    uint32_t      v2,
182                                    uint32_t      v3)
183{
184  if (axi_trace_in < AXI_I2C_TRACE) {
185    axi_i2c_trace rec = { state, { v1, v2, v3 } };
186    axi_trace[axi_trace_in++] = rec;
187  }
188}
189#else
190#define axi_trace_reset()
191#define axi_trace_append(s, v1, v2, v3)
192#endif
193
194#define DRIVER_DEBUG 0
195#define DRIVER_DEBUG_DEFAULT true
196#if DRIVER_DEBUG
197#ifndef RTEMS_PRINTFLIKE
198#define RTEMS_PRINTFLIKE( _format_pos, _ap_pos ) \
199__attribute__((__format__(__printf__, _format_pos, _ap_pos)))
200#endif
201static bool drv_printk_enable = DRIVER_DEBUG_DEFAULT;
202static void drv_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
203static void
204drv_printk(const char* format, ...)
205{
206  va_list ap;
207  va_start(ap, format);
208  if (drv_printk_enable)
209    vprintk(format, ap);
210  va_end(ap);
211}
212#else
213#define drv_printk(_fmt, ...)
214#endif
215
216static inline void
217xilinx_axi_i2c_reg_write(const xilinx_axi_i2c_bus* bus, uint32_t reg, uint32_t value)
218{
219  #if DRIVER_REG_TRACE
220    axi_trace_append(AXI_I2C_REG_WRITE, reg, value, 0);
221  #endif
222  *((volatile uint32_t*) (bus->regs + reg))= value;
223}
224
225static inline uint32_t
226xilinx_axi_i2c_reg_read(const xilinx_axi_i2c_bus* bus, uint32_t reg)
227{
228  uint32_t value = *((volatile uint32_t*) (bus->regs + reg));
229  #if DRIVER_REG_TRACE
230    axi_trace_append(AXI_I2C_REG_READ, reg, value, 0);
231  #endif
232  return value;
233}
234
235static uint32_t
236xilinx_axi_i2c_read_irq_status(const xilinx_axi_i2c_bus* bus)
237{
238  return xilinx_axi_i2c_reg_read(bus, REG_ISR);
239}
240
241static uint32_t
242xilinx_axi_i2c_read_irq_enabled(const xilinx_axi_i2c_bus* bus)
243{
244  return xilinx_axi_i2c_reg_read(bus, REG_IER);
245}
246
247static void
248xilinx_axi_i2c_clear_irq(const xilinx_axi_i2c_bus* bus, uint32_t mask)
249{
250  /*
251   * The ISR bits can be toggled so only write a 1 if set.
252   */
253  xilinx_axi_i2c_reg_write(bus, REG_ISR,
254                           xilinx_axi_i2c_reg_read(bus, REG_ISR) & mask);
255}
256
257static inline void
258xilinx_axi_i2c_enable_irq(const xilinx_axi_i2c_bus* bus, uint32_t mask)
259{
260  xilinx_axi_i2c_reg_write(bus, REG_IER,
261                           xilinx_axi_i2c_reg_read(bus, REG_IER) | mask);
262}
263
264static inline void
265xilinx_axi_i2c_disable_irq(const xilinx_axi_i2c_bus* bus, uint32_t mask)
266{
267  xilinx_axi_i2c_reg_write(bus, REG_IER,
268                           xilinx_axi_i2c_reg_read(bus, REG_IER) & ~mask);
269}
270
271static void
272xilinx_axi_i2c_clear_enable_irq(const xilinx_axi_i2c_bus* bus, uint32_t mask)
273{
274  xilinx_axi_i2c_clear_irq(bus, mask);
275  xilinx_axi_i2c_enable_irq(bus, mask);
276}
277
278static void
279xilinx_axi_i2c_disable_clear_irq(const xilinx_axi_i2c_bus* bus, uint32_t mask)
280{
281  xilinx_axi_i2c_disable_irq(bus, mask);
282  xilinx_axi_i2c_clear_irq(bus, mask);
283}
284
285static inline void
286xilinx_axi_i2c_disable_all_irq(const xilinx_axi_i2c_bus* bus)
287{
288  xilinx_axi_i2c_reg_write(bus, REG_GIE, 0);
289}
290
291static void
292xilinx_axi_i2c_enable_interrupts(const xilinx_axi_i2c_bus* bus)
293{
294  xilinx_axi_i2c_reg_write(bus, REG_GIE, 1 << 31);
295}
296
297static void
298xilinx_axi_i2c_disable_interrupts(const xilinx_axi_i2c_bus* bus)
299{
300  xilinx_axi_i2c_reg_write(bus, REG_GIE, 0);
301  xilinx_axi_i2c_reg_write(bus, REG_IER, 0);
302}
303
304static inline void
305xilinx_axi_i2c_write_cr(const xilinx_axi_i2c_bus* bus, uint32_t value)
306{
307  xilinx_axi_i2c_reg_write(bus, REG_CR, value);
308}
309
310static inline uint32_t
311xilinx_axi_i2c_read_cr(const xilinx_axi_i2c_bus* bus)
312{
313  return xilinx_axi_i2c_reg_read(bus, REG_CR);
314}
315
316static inline void
317xilinx_axi_i2c_set_cr(const xilinx_axi_i2c_bus* bus, uint32_t mask)
318{
319  xilinx_axi_i2c_reg_write(bus, REG_CR,
320                           xilinx_axi_i2c_reg_read(bus, REG_CR) | mask);
321}
322
323static inline void
324xilinx_axi_i2c_clear_cr(const xilinx_axi_i2c_bus* bus, uint32_t mask)
325{
326  xilinx_axi_i2c_write_cr(bus, xilinx_axi_i2c_read_cr(bus) & ~mask);
327}
328
329static inline uint32_t
330xilinx_axi_i2c_read_sr(const xilinx_axi_i2c_bus* bus)
331{
332  return xilinx_axi_i2c_reg_read(bus, REG_SR);
333}
334
335static inline uint32_t
336xilinx_axi_i2c_read_rx_level(const xilinx_axi_i2c_bus* bus)
337{
338  if ((xilinx_axi_i2c_read_sr(bus) & SR_RX_FIFO_EMPTY) != 0)
339    return 0;
340  return xilinx_axi_i2c_reg_read(bus, REG_RX_FIFO_OCY) + 1;
341}
342
343static inline void
344xilinx_axi_i2c_write_rx_pirq(const xilinx_axi_i2c_bus* bus, uint32_t level)
345{
346  if (level != 0)
347    xilinx_axi_i2c_reg_write(bus, REG_RX_FIFO_PIRQ, level - 1);
348  else
349    xilinx_axi_i2c_reg_write(bus, REG_RX_FIFO_PIRQ, level);
350}
351
352static inline uint32_t
353xilinx_axi_i2c_read_tx_space(const xilinx_axi_i2c_bus* bus)
354{
355  if ((xilinx_axi_i2c_read_sr(bus) & SR_TX_FIFO_EMPTY) != 0)
356    return TX_FIFO_SIZE;
357  return TX_FIFO_SIZE - xilinx_axi_i2c_reg_read(bus, REG_TX_FIFO_OCY) - 1;
358}
359
360static void
361xilinx_axi_i2c_write_tx_fifo_data(xilinx_axi_i2c_bus* bus, uint32_t data)
362{
363  axi_trace_append(AXI_I2C_TX_FIFO, data, 0, 0);
364  xilinx_axi_i2c_reg_write(bus, REG_TX_FIFO, data);
365}
366
367static inline uint32_t
368xilinx_axi_i2c_read_rx_fifo_data(xilinx_axi_i2c_bus* bus)
369{
370  uint32_t data = xilinx_axi_i2c_reg_read(bus, REG_RX_FIFO);
371  axi_trace_append(AXI_I2C_RX_FIFO, data, 0, 0);
372  return data;
373}
374
375static void
376xilinx_axi_i2c_reset(xilinx_axi_i2c_bus* bus)
377{
378  xilinx_axi_i2c_reg_write(bus, REG_SOFTR, 0x0a);
379  if ((bus->timing.valid_mask & XILINX_AIX_I2C_ALL_REGS) != 0)
380  {
381    static const uint32_t r[8] = {
382      REG_TSUSTA,
383      REG_TSUSTO,
384      REG_THDSTA,
385      REG_TSUDAT,
386      REG_TBUF,
387      REG_THIGH,
388      REG_TLOW,
389      REG_THDDAT
390    };
391    static const uint32_t m[8] = {
392      XILINX_AIX_I2C_TSUSTA,
393      XILINX_AIX_I2C_TSUSTO,
394      XILINX_AIX_I2C_THDSTA,
395      XILINX_AIX_I2C_TSUDAT,
396      XILINX_AIX_I2C_TBUF,
397      XILINX_AIX_I2C_THIGH,
398      XILINX_AIX_I2C_TLOW,
399      XILINX_AIX_I2C_THDDAT
400    };
401    uint32_t        vm = bus->timing.valid_mask;
402    const uint32_t* u = &bus->timing.TSUSTA;
403    size_t          i;
404    for (i = 0; i < (sizeof(r) / sizeof(r[0])); ++i, ++u) {
405      if ((vm & m[i]) != 0) {
406        xilinx_axi_i2c_reg_write(bus, r[i], *u);
407      }
408    }
409  }
410}
411
412
413static void
414xilinx_axi_i2c_reinit(xilinx_axi_i2c_bus* bus)
415{
416  drv_printk("axi-i2c: reinit\n");
417  xilinx_axi_i2c_reset(bus);
418  xilinx_axi_i2c_write_rx_pirq(bus, RX_FIFO_SIZE);
419  xilinx_axi_i2c_write_cr(bus, CR_TX_FIFO_RESET);
420  xilinx_axi_i2c_write_cr(bus, CR_EN);
421  xilinx_axi_i2c_clear_enable_irq(bus, INT_ARB_LOST);
422}
423
424static void
425xilinx_axi_i2c_wakeup(xilinx_axi_i2c_bus* bus)
426{
427  axi_trace_append(AXI_I2C_WAKE, bus->task_id, bus->irqstatus, 0);
428  drv_printk("axi-i2c: wakeup: irqstatus: %08lx\n", bus->irqstatus);
429  rtems_status_code sc = rtems_event_transient_send(bus->task_id);
430  _Assert(sc == RTEMS_SUCCESSFUL);
431  (void) sc;
432}
433
434static void
435xilinx_axi_i2c_next_byte(xilinx_axi_i2c_bus* bus)
436{
437  --bus->current_todo;
438  --bus->current_msg_todo;
439  ++bus->current_msg_byte;
440  if (bus->current_msg_todo == 0) {
441    if (bus->msgs_remaining != 0 &&
442        (bus->msgs[0].flags & I2C_M_NOSTART) != 0) {
443      bus->current_msg_todo = bus->msgs[0].len;
444      bus->current_msg_byte = bus->msgs[0].buf;
445      ++bus->msgs;
446      --bus->msgs_remaining;
447    }
448  }
449}
450
451static void
452xilinx_axi_i2c_read_rx_byte(xilinx_axi_i2c_bus* bus)
453{
454  *bus->current_msg_byte = (uint8_t) xilinx_axi_i2c_read_rx_fifo_data(bus);
455  xilinx_axi_i2c_next_byte(bus);
456}
457
458static void
459xilinx_axi_i2c_read_rx_bytes(xilinx_axi_i2c_bus* bus, uint32_t count)
460{
461  while (count-- > 0)
462    xilinx_axi_i2c_read_rx_byte(bus);
463}
464
465static void
466xilinx_axi_i2c_set_rx_fifo_level(xilinx_axi_i2c_bus* bus)
467{
468  uint32_t size;
469  if (bus->current_todo > RX_FIFO_SIZE) {
470    size = RX_FIFO_SIZE;
471  } else {
472    size = bus->current_todo - 1;
473  }
474  axi_trace_append(AXI_I2C_RX_FIFO_LEVEL, size, 0, 0);
475  xilinx_axi_i2c_write_rx_pirq(bus, size);
476}
477
478static bool xilinx_axi_i2c_start_transfer(xilinx_axi_i2c_bus* bus);
479
480static bool
481xilinx_axi_i2c_read_rx_fifo(xilinx_axi_i2c_bus* bus)
482{
483  drv_printk("axi-i2c: read rx fifo: length:%lu\n", bus->current_todo);
484
485  if (bus->current_todo == 0) {
486    return false;
487  }
488
489  if ((xilinx_axi_i2c_read_sr(bus) & SR_RX_FIFO_EMPTY) == 0) {
490    uint32_t level = xilinx_axi_i2c_read_rx_level(bus);
491    bool     active;
492
493    drv_printk("axi-i2c: read rx fifo: level:%lu\n", level);
494
495    if (level > bus->current_todo)
496      level = bus->current_todo;
497
498    switch (bus->current_todo - level) {
499      case 1:
500        drv_printk("axi-i2c: read rx fifo: one more\n");
501        /*
502         * One more byte to be received. This is set up by programming the RX
503         * FIFO programmable depth interrupt register with a value that is 2
504         * less than the number we need (the register is minus 1). When we have
505         * one byte left disable the TX error interrupt because setting the NO
506         * ACK bit in the command register causes a TX error interrupt. Set the
507         * TXAK bit in the CR to not-acknowledge the next byte received telling
508         * the slave sender the master accepts no more data, then read the
509         * FIFO. If the FIFO is ready before the TXAK bit is set the slave will
510         * see a request for more data. We will come back to the next case
511         * statement for the last byte once it has been received.
512         */
513        xilinx_axi_i2c_disable_clear_irq(bus, INT_TX_ERROR);
514        xilinx_axi_i2c_set_cr(bus, CR_TXAK);
515        xilinx_axi_i2c_read_rx_bytes(bus, level);
516        /*
517         * Set the RX PIRQ to 0 after the RX data has been read. There is an
518         * observed timing issue and glitch if written before.
519         */
520        xilinx_axi_i2c_write_rx_pirq(bus, 0);
521        break;
522
523      case 0:
524        drv_printk("axi-i2c: read rx fifo: no more\n");
525        /*
526         * We should have 1 byte in the FIFO which is the last byte received
527         * with a NACK. If there are no more message we need to send a STOP by
528         * clearing he MSMS bit in the CR and then waiting for the bus to not
529         * be busy.
530         */
531        xilinx_axi_i2c_disable_clear_irq(bus,
532                                         INT_RX_FIFO_FULL | INT_TX_ERROR);
533        if (bus->msgs_remaining == 0) {
534          xilinx_axi_i2c_clear_cr(bus, CR_MSMS);
535          xilinx_axi_i2c_clear_enable_irq(bus, INT_BUS_NOT_BUSY);
536          active = true;
537        }
538        xilinx_axi_i2c_read_rx_byte(bus);
539        if (bus->msgs_remaining != 0)
540          active = xilinx_axi_i2c_start_transfer(bus);
541        return active;
542
543      default:
544        drv_printk("axi-i2c: read rx fifo: more:%lu\n", bus->current_todo - level);
545        /*
546         * All the requested data is in the FIFO so read it and update the PIRQ
547         * level. The PIRQ size is always one less than the maximum size.
548         */
549        xilinx_axi_i2c_read_rx_bytes(bus, level);
550        if (bus->current_todo > RX_FIFO_SIZE) {
551          xilinx_axi_i2c_write_rx_pirq(bus, RX_FIFO_SIZE);
552        } else {
553          xilinx_axi_i2c_write_rx_pirq(bus, bus->current_todo - 1);
554        }
555        break;
556    }
557  }
558
559  return true;
560}
561
562static void
563xilinx_axi_i2c_write_tx_byte(xilinx_axi_i2c_bus* bus)
564{
565  xilinx_axi_i2c_write_tx_fifo_data(bus, *bus->current_msg_byte);
566  xilinx_axi_i2c_next_byte(bus);
567}
568
569static void
570xilinx_axi_i2c_write_tx_bytes(xilinx_axi_i2c_bus* bus)
571{
572  uint32_t space = xilinx_axi_i2c_read_tx_space(bus);
573  uint32_t level = bus->current_todo - 1;
574  uint32_t i;
575  drv_printk("axi-i2c: tx fifo load: space:%lu level:%lu\n", space, level);
576  if (level < space)
577    space = level;
578  for (i = 0; i < space; ++i)
579    xilinx_axi_i2c_write_tx_byte(bus);
580}
581
582static bool
583xilinx_axi_i2c_write_tx_fifo(xilinx_axi_i2c_bus* bus)
584{
585  bool more = true;
586  drv_printk("axi-i2c: write tx fifo: current_todo: %lu\n", bus->current_todo);
587  switch (bus->current_todo) {
588    case 0:
589      xilinx_axi_i2c_disable_clear_irq(bus,
590                                       INT_TX_FIFO_EMPTY |
591                                       INT_TX_FIFO_HALF_FULL |
592                                       INT_TX_ERROR |
593                                       INT_BUS_NOT_BUSY);
594      more = xilinx_axi_i2c_start_transfer(bus);
595      break;
596    case 1:
597      /*
598       * If transmitting and the last byte issue a stop and wait for the bus to
599       * not be busy.
600       */
601      if (!bus->read && bus->msgs_remaining == 0) {
602        xilinx_axi_i2c_clear_cr(bus, CR_MSMS);
603        xilinx_axi_i2c_clear_enable_irq(bus, INT_BUS_NOT_BUSY);
604      }
605      xilinx_axi_i2c_write_tx_byte(bus);
606      break;
607    default:
608      xilinx_axi_i2c_write_tx_bytes(bus);
609      break;
610  }
611  return more;
612}
613
614static void
615xilinx_axi_i2c_write_address(xilinx_axi_i2c_bus* bus)
616{
617  if ((bus->addr & ADDR_GPO) != 0)
618    xilinx_axi_i2c_reg_write(bus, REG_GPO, (bus->addr >> 12) & 0xf);
619  if ((bus->addr & ADDR_TEN) != 0)
620    xilinx_axi_i2c_write_tx_fifo_data(bus, (bus->addr >> 8) & 0xff);
621  xilinx_axi_i2c_write_tx_fifo_data(bus, bus->addr & 0xff);
622}
623
624static void
625xilinx_axi_i2c_start_read(xilinx_axi_i2c_bus* bus)
626{
627  uint32_t cr;
628  uint32_t set = INT_RX_FIFO_FULL;
629  axi_trace_append(AXI_I2C_READ, bus->current_todo, 0, 0);
630  drv_printk("axi-i2c: start read: size: %lu\n", bus->current_todo);
631  /*
632   * Is this a restart? If there is no active STOP it is a restart.
633   */
634  cr = xilinx_axi_i2c_read_cr(bus);
635  if ((cr & CR_MSMS) != 0) {
636    cr |= CR_RSTA;
637    xilinx_axi_i2c_write_cr(bus, cr);
638  }
639  xilinx_axi_i2c_write_address(bus);
640  xilinx_axi_i2c_set_rx_fifo_level(bus);
641  /*
642   * We must NACK the last byte so if we are receiving a single byte issue a
643   * NACK.
644   */
645  cr &= ~(CR_TX | CR_TXAK);
646  if (bus->current_todo == 1) {
647    cr |= CR_TXAK;
648  } else {
649    set |= INT_TX_ERROR;
650  }
651  /*
652   * Issue a start.
653   */
654  cr |= CR_MSMS;
655  xilinx_axi_i2c_clear_enable_irq(bus, set);
656  xilinx_axi_i2c_write_cr(bus, cr);
657}
658
659static void
660xilinx_axi_i2c_start_write(xilinx_axi_i2c_bus* bus)
661{
662  uint32_t space;
663  uint32_t enable;
664  uint32_t cr;
665  axi_trace_append(AXI_I2C_WRITE, bus->current_todo, 0, 0);
666  cr = xilinx_axi_i2c_read_cr(bus);
667  /*
668   * If a master issue a restart if there is no active STOP on the bus.
669   */
670  if ((cr & CR_MSMS) != 0) {
671    cr |= CR_RSTA;
672    xilinx_axi_i2c_write_cr(bus, cr);
673  }
674  xilinx_axi_i2c_write_address(bus);
675  if (bus->current_todo > 1)
676    xilinx_axi_i2c_write_tx_bytes(bus);
677  space = xilinx_axi_i2c_read_tx_space(bus);
678  enable = INT_TX_FIFO_EMPTY | INT_TX_ERROR;
679  if (space > TX_FIFO_HALF_SIZE && bus->current_todo > 1) {
680    enable |= INT_TX_FIFO_HALF_FULL;
681  }
682  xilinx_axi_i2c_clear_enable_irq(bus, enable);
683  cr &= ~CR_TXAK;
684  cr |= CR_MSMS | CR_TX;
685  xilinx_axi_i2c_write_cr(bus, cr);
686}
687
688static bool
689xilinx_axi_i2c_start_transfer(xilinx_axi_i2c_bus* bus)
690{
691  const i2c_msg* msgs = bus->msgs;
692  uint32_t       msg_todo = bus->msgs_remaining;
693  uint32_t       i;
694
695  axi_trace_append(AXI_I2C_START_TRANSFER, msg_todo, 0, 0);
696  drv_printk("axi-i2c: start transfer: messages: %lu\n", msg_todo);
697
698  if (msg_todo == 0) {
699    xilinx_axi_i2c_clear_cr(bus, CR_MSMS);
700    return false;
701  }
702
703  /*
704   * Get the amount of data to transfer. It can span message buffers if the
705   * I2C_M_NOSTART flag is set.
706   */
707  bus->current_todo = msgs[0].len;
708  for (i = 1; i < msg_todo && (msgs[i].flags & I2C_M_NOSTART) != 0; ++i) {
709    bus->current_todo += msgs[i].len;
710  }
711
712  bus->read = (msgs->flags & I2C_M_RD) != 0;
713
714  if ((msgs->flags & I2C_M_TEN) != 0) {
715    bus->addr = (ADDR_TEN |
716                 ((msgs->addr & (3 << 8)) << 1) |
717                 ((bus->read ? 1 : 0) << 8) |
718                 (msgs->addr & 0xff));
719  }
720  else {
721    bus->addr = (msgs->addr & 0x7f) << 1 | (bus->read ? 1 : 0);
722  }
723
724  if (bus->gpo_address)
725    bus->addr |= ADDR_GPO | (msgs->addr & 0xf000);
726
727  axi_trace_append(AXI_I2C_TRANSFER,
728                   bus->msgs_remaining,
729                   bus->current_todo, bus->addr);
730
731  /*
732   * The bus->msgs is left pointing to the next message because we may need to
733   * start a new message while completing the current message.
734   */
735  bus->current_msg_todo = msgs[0].len;
736  bus->current_msg_byte = msgs[0].buf;
737  ++bus->msgs;
738  --bus->msgs_remaining;
739
740  if (bus->read) {
741    xilinx_axi_i2c_start_read(bus);
742  } else {
743    xilinx_axi_i2c_start_write(bus);
744  }
745
746  return true;
747}
748
749static void
750  xilinx_axi_i2c_interrupt(void* arg)
751{
752  xilinx_axi_i2c_bus* bus = arg;
753  uint32_t            status = xilinx_axi_i2c_read_irq_status(bus);
754  uint32_t            enabled = xilinx_axi_i2c_read_irq_enabled(bus);
755  uint32_t            active = status & enabled;
756  uint32_t            clear = 0;
757  int                 done = 0;
758
759  axi_trace_append(AXI_I2C_INT, active, status, enabled);
760
761  drv_printk("axi-i2c: interrupt: active:%02lx isr:%02lx ier:%02lx\n",
762             active, status, enabled);
763
764  /*
765   * An error or we lost arbitration. If transmitting and there is more data to
766   * send a INT_TX_ERROR means the slave issue a NOT ACK because there was not
767   * slave at the address or the addressed slave will not accept any more data.
768   *
769   * Clean up and wake the user.
770   */
771  if (((active & INT_ARB_LOST) != 0) ||
772      (!bus->read && (active & INT_TX_ERROR) != 0)) {
773    bus->irqstatus = active & (INT_ARB_LOST | INT_TX_ERROR);
774    axi_trace_append(AXI_I2C_INT_ERROR, bus->irqstatus, 0, 0);
775    xilinx_axi_i2c_reinit(bus);
776    xilinx_axi_i2c_clear_cr(bus, CR_EN);
777    xilinx_axi_i2c_wakeup(bus);
778    return;
779  }
780
781  /*
782   * RX FIFO full?
783   */
784  if ((active & INT_RX_FIFO_FULL) != 0) {
785    clear |= INT_RX_FIFO_FULL;
786
787    if (bus->read && !xilinx_axi_i2c_read_rx_fifo(bus)) {
788      ++done;
789      axi_trace_append(AXI_I2C_INT_DONE, done, clear, 0);
790    }
791
792    if (bus->current_todo == 0) {
793      clear |= status & INT_TX_ERROR;
794    }
795  }
796
797  /*
798   * TX FIFO empty or half empty?
799   */
800  if ((active & (INT_TX_FIFO_EMPTY | INT_TX_FIFO_HALF_FULL)) != 0) {
801    clear |= active & (INT_TX_FIFO_EMPTY | INT_TX_FIFO_HALF_FULL);
802
803    if (!bus->read && !xilinx_axi_i2c_write_tx_fifo(bus)) {
804      ++done;
805      axi_trace_append(AXI_I2C_INT_DONE, done, clear, 1);
806    }
807  }
808
809  /*
810   * Gate the bus not busy interrupt with the bus busy status to know the bus
811   * is really not busy. It could be an interrupt left over from starting the
812   * transmission.
813   */
814  if ((active & INT_BUS_NOT_BUSY) != 0) {
815    if ((xilinx_axi_i2c_read_sr(bus) & SR_BB) == 0) {
816      xilinx_axi_i2c_disable_clear_irq(bus, INT_BUS_NOT_BUSY);
817      if (bus->read && !xilinx_axi_i2c_read_rx_fifo(bus)) {
818        ++done;
819        axi_trace_append(AXI_I2C_BUS_NOT_BUSY, done, clear, 0);
820      }
821      else if (!bus->read && !xilinx_axi_i2c_write_tx_fifo(bus)) {
822        ++done;
823        axi_trace_append(AXI_I2C_BUS_NOT_BUSY, done, clear, 1);
824      }
825    }
826    else {
827      clear |= INT_BUS_NOT_BUSY;
828    }
829  }
830
831  if (clear != 0)
832    xilinx_axi_i2c_clear_irq(bus, clear);
833
834  if (done != 0) {
835    xilinx_axi_i2c_disable_interrupts(bus);
836    xilinx_axi_i2c_clear_cr(bus, CR_EN);
837    xilinx_axi_i2c_wakeup(bus);
838  }
839}
840
841static int xilinx_axi_i2c_transfer(i2c_bus* base,
842                                   i2c_msg* msgs,
843                                   uint32_t msg_count)
844{
845  xilinx_axi_i2c_bus* bus = (xilinx_axi_i2c_bus *) base;
846  rtems_status_code   sc;
847  int                 r = 0;
848
849  axi_trace_reset();
850  axi_trace_append(AXI_I2C_BEGIN, msg_count, 0, 0);
851
852  drv_printk("axi-i2c: i2c transfer\n");
853
854  _Assert(msg_count > 0);
855
856  bus->msgs = &msgs[0];
857  bus->msgs_remaining = msg_count;
858  bus->irqstatus = 0;
859  bus->task_id = rtems_task_self();
860
861  xilinx_axi_i2c_reinit(bus);
862  xilinx_axi_i2c_start_transfer(bus);
863  xilinx_axi_i2c_enable_interrupts(bus);
864
865  sc = rtems_event_transient_receive(RTEMS_WAIT, bus->base.timeout);
866  if (sc != RTEMS_SUCCESSFUL) {
867    axi_trace_append(AXI_I2C_TIMEOUT, 0, 0, 0);
868    xilinx_axi_i2c_reinit(bus);
869    rtems_event_transient_clear();
870    r = -ETIMEDOUT;
871  }
872
873  if (r == 0 && bus->irqstatus != 0)
874    r = -EIO;
875
876  axi_trace_append(AXI_I2C_END, bus->irqstatus, r, 0);
877
878  return r;
879}
880
881static int xilinx_axi_i2c_set_clock(i2c_bus *base, unsigned long clock)
882{
883  xilinx_axi_i2c_bus* bus = (xilinx_axi_i2c_bus*) base;
884
885  if ((bus->timing.valid_mask & XILINX_AIX_I2C_AXI_CLOCK) == 0)
886    return -EIO;
887
888  bus->timing.THIGH =
889    (bus->timing.AXI_CLOCK / (2 * clock)) - 7 - bus->timing.SCL_INERTIAL_DELAY;
890  bus->timing.TLOW = bus->timing.THIGH;
891
892  bus->timing.valid_mask |= XILINX_AIX_I2C_THIGH | XILINX_AIX_I2C_TLOW;
893
894  return 0;
895}
896
897static void xilinx_axi_i2c_destroy(i2c_bus* base)
898{
899  xilinx_axi_i2c_bus* bus = (xilinx_axi_i2c_bus*) base;
900  rtems_status_code sc;
901
902  sc = rtems_interrupt_handler_remove(bus->irq, xilinx_axi_i2c_interrupt, bus);
903  _Assert(sc == RTEMS_SUCCESSFUL);
904  (void) sc;
905
906  i2c_bus_destroy_and_free(&bus->base);
907}
908
909int
910i2c_bus_register_xilinx_aix_i2c(const char*                  bus_path,
911                                uintptr_t                    register_base,
912                                rtems_vector_number          irq,
913                                bool                         gpo_address,
914                                const xilinx_aix_i2c_timing* timing)
915{
916  xilinx_axi_i2c_bus* bus;
917  rtems_status_code   sc;
918
919  bus = (xilinx_axi_i2c_bus*) i2c_bus_alloc_and_init(sizeof(*bus));
920  if (bus == NULL) {
921    return -1;
922  }
923
924  bus->regs = register_base;
925  bus->irq = irq;
926  bus->gpo_address = gpo_address;
927  bus->timing = *timing;
928
929  sc = rtems_interrupt_handler_install(irq,
930                                       "Xilinx AXI I2C",
931                                       RTEMS_INTERRUPT_UNIQUE,
932                                       xilinx_axi_i2c_interrupt,
933                                       bus);
934  if (sc != RTEMS_SUCCESSFUL) {
935    drv_printk("axi-i2c: interrupt attach failed\n");
936    (*bus->base.destroy)(&bus->base);
937    rtems_set_errno_and_return_minus_one(EIO);
938  }
939
940  bus->base.transfer = xilinx_axi_i2c_transfer;
941  bus->base.set_clock = xilinx_axi_i2c_set_clock;
942  bus->base.destroy = xilinx_axi_i2c_destroy;
943
944  axi_i2c_bus = bus;
945
946  return i2c_bus_register(&bus->base, bus_path);
947}
Note: See TracBrowser for help on using the repository browser.