coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
i2c.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <commonlib/helpers.h>
5 #include <console/console.h>
6 #include <delay.h>
7 #include <device/device.h>
8 #include <device/i2c_simple.h>
9 #include <device/pci.h>
10 #include <soc/i2c.h>
11 #include <soc/ramstage.h>
12 #include <soc/reg_access.h>
13 #include <timer.h>
14 
15 static void i2c_disable(I2C_REGS *regs)
16 {
17  uint32_t status;
18  uint32_t timeout;
19 
20  /* Disable I2C controller */
21  regs->ic_enable = 0;
22 
23  /* Wait for the enable bit to clear */
24  timeout = 1 * 1000 * 1000;
25  status = regs->ic_enable_status;
26  while (status & IC_ENABLE_CONTROLLER) {
27  udelay(1);
28  if (--timeout == 0)
30  "ERROR - I2C failed to disable!\n");
31  status = regs->ic_enable_status;
32  }
33 
34  /* Clear any pending interrupts */
35  status = regs->ic_clr_intr;
36 }
37 
38 static int platform_i2c_write(uint32_t restart, uint8_t *tx_buffer, int length,
39  uint32_t stop, uint8_t *rx_buffer, struct stopwatch *timeout)
40 {
41  int bytes_transferred;
42  uint32_t cmd;
43  I2C_REGS *regs;
44  uint32_t status;
45 
46  ASSERT(tx_buffer != NULL);
47  ASSERT(timeout != NULL);
49 
50  /* Fill the FIFO with the write operation */
51  bytes_transferred = 0;
52  do {
53  status = regs->ic_raw_intr_stat;
54 
55  /* Check for errors */
56  if (status & (IC_INTR_RX_OVER | IC_INTR_RX_UNDER
59  if (CONFIG(I2C_DEBUG))
61  "0x%08x: ic_raw_intr_stat, I2C write error!\n",
62  status);
63  return -1;
64  }
65 
66  /* Check for timeout */
67  if (stopwatch_expired(timeout)) {
68  if (CONFIG(I2C_DEBUG))
70  "0x%08x: ic_raw_intr_stat, I2C write timeout!\n",
71  status);
72  return -1;
73  }
74 
75  /* Receive any available data */
76  status = regs->ic_status;
77  if (rx_buffer != NULL) {
78  while (status & IC_STATUS_RFNE) {
79  *rx_buffer++ = (uint8_t)regs->ic_data_cmd;
80  bytes_transferred++;
81  status = regs->ic_status;
82  }
83  }
84 
85  /* Determine if space is available in the FIFO */
86  if (status & IC_STATUS_TFNF) {
87  /* End of the transaction? */
88  cmd = IC_DATA_CMD_WRITE | *tx_buffer++ | restart;
89  if (length == 1)
90  cmd |= stop;
91  restart = 0;
92 
93  /* Place a data byte into the FIFO */
94  regs->ic_data_cmd = cmd;
95  length--;
96  bytes_transferred++;
97  } else
98  udelay(1);
99  } while (length > 0);
100  return bytes_transferred;
101 }
102 
103 static int platform_i2c_read(uint32_t restart, uint8_t *rx_buffer, int length,
104  uint32_t stop, struct stopwatch *timeout)
105 {
106  int bytes_transferred;
107  uint32_t cmd;
108  int fifo_bytes;
109  I2C_REGS *regs;
110  uint32_t status;
111 
112  ASSERT(rx_buffer != NULL);
113  ASSERT(timeout != NULL);
114  regs = get_i2c_address();
115 
116  /* Empty the FIFO */
117  status = regs->ic_status;
118  while (status & IC_STATUS_RFNE) {
119  (void)regs->ic_data_cmd;
120  status = regs->ic_status;
121  }
122 
123  /* Fill the FIFO with read commands */
124  fifo_bytes = MIN(length, 16);
125  bytes_transferred = 0;
126  while (length > 0) {
127  status = regs->ic_raw_intr_stat;
128 
129  /* Check for errors */
130  if (status & (IC_INTR_RX_OVER | IC_INTR_RX_UNDER
132  i2c_disable(regs);
133  if (CONFIG(I2C_DEBUG))
135  "0x%08x: ic_raw_intr_stat, I2C read error!\n",
136  status);
137  return -1;
138  }
139 
140  /* Check for timeout */
141  if (stopwatch_expired(timeout)) {
142  if (CONFIG(I2C_DEBUG))
144  "0x%08x: ic_raw_intr_stat, I2C read timeout!\n",
145  status);
146  return -1;
147  }
148 
149  /* Receive any available data */
150  status = regs->ic_status;
151  if (status & IC_STATUS_RFNE) {
152  /* Save the next data byte, removed from the RX FIFO */
153  *rx_buffer++ = (uint8_t)regs->ic_data_cmd;
154  bytes_transferred++;
155  }
156 
157  if ((status & IC_STATUS_TFNF)
158  || ((status & IC_STATUS_RFNE) && (fifo_bytes > 0))) {
159  /* End of the transaction? */
160  cmd = IC_DATA_CMD_READ | restart;
161  if (length == 1)
162  cmd |= stop;
163  restart = 0;
164 
165  /* Place a read command into the TX FIFO */
166  regs->ic_data_cmd = cmd;
167  if (fifo_bytes > 0)
168  fifo_bytes--;
169  length--;
170  } else
171  udelay(1);
172  }
173  return bytes_transferred;
174 }
175 
176 int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segment,
177  int seg_count)
178 {
179  int bytes_transferred;
180  uint8_t chip;
181  uint32_t cmd;
182  int data_bytes;
183  int index;
184  int length;
185  I2C_REGS *regs;
186  uint32_t restart;
187  uint8_t *rx_buffer;
188  uint32_t status;
189  uint32_t stop;
190  struct stopwatch timeout;
191  int total_bytes;
192  uint8_t *tx_buffer;
193  int tx_bytes;
194 
195  if (CONFIG(I2C_DEBUG)) {
196  for (index = 0; index < seg_count;) {
197  if (index == 0)
198  printk(BIOS_ERR, "I2C Start\n");
200  "I2C segment[%d]: %s 0x%02x %s %p, 0x%08x bytes\n",
201  index,
202  (segment[index].flags & I2C_M_RD) ? "Read from" : "Write to",
203  segment[index].slave,
204  (segment[index].flags & I2C_M_RD) ? "to " : "from",
205  segment[index].buf,
206  segment[index].len);
207  printk(BIOS_ERR, "I2C %s\n",
208  (++index >= seg_count) ? "Stop" : "Restart");
209  }
210  }
211 
212  regs = get_i2c_address();
213 
214  /* Disable the I2C controller to get access to the registers */
215  i2c_disable(regs);
216 
217  /* Set the slave address */
218  ASSERT(seg_count > 0);
219  ASSERT(segment != NULL);
220 
221  /* Clear the start and stop detection */
222  status = regs->ic_clr_start_det;
223  status = regs->ic_clr_stop_det;
224 
225  /* Set addressing mode to 7-bit and fast mode */
226  cmd = regs->ic_con;
227  cmd &= ~(IC_CON_10B | IC_CON_SPEED);
230  regs->ic_con = cmd;
231 
232  /* Set the target chip address */
233  chip = segment->slave;
234  regs->ic_tar = chip;
235 
236  /* Enable the I2C controller */
237  regs->ic_enable = IC_ENABLE_CONTROLLER;
238 
239  /* Clear the interrupts */
240  status = regs->ic_clr_rx_under;
241  status = regs->ic_clr_rx_over;
242  status = regs->ic_clr_tx_over;
243  status = regs->ic_clr_tx_abrt;
244 
245  /* Start the timeout */
246  stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US);
247 
248  /* Process each of the segments */
249  total_bytes = 0;
250  tx_bytes = 0;
251  bytes_transferred = 0;
252  rx_buffer = NULL;
253  restart = 0;
254  index = 0;
255  while (index++ < seg_count) {
256  length = segment->len;
257  total_bytes += length;
258  ASSERT(segment->buf != NULL);
259  ASSERT(length >= 1);
260  ASSERT(segment->slave == chip);
261 
262  /* Determine if this is the last segment of the transaction */
263  stop = (index == seg_count) ? IC_DATA_CMD_STOP : 0;
264 
265  /* Fill the FIFO with the necessary command bytes */
266  if (segment->flags & I2C_M_RD) {
267  /* Place read commands into the FIFO */
268  rx_buffer = segment->buf;
269  data_bytes = platform_i2c_read(restart, rx_buffer,
270  length, stop, &timeout);
271 
272  /* Return any detected error */
273  if (data_bytes < 0) {
274  if (CONFIG(I2C_DEBUG))
276  "I2C segment[%d] failed\n",
277  index);
278  return data_bytes;
279  }
280  bytes_transferred += data_bytes;
281  } else {
282  /* Write the data into the FIFO */
283  tx_buffer = segment->buf;
284  tx_bytes += length;
285  data_bytes = platform_i2c_write(restart, tx_buffer,
286  length, stop, rx_buffer, &timeout);
287 
288  /* Return any detected error */
289  if (data_bytes < 0) {
290  if (CONFIG(I2C_DEBUG))
292  "I2C segment[%d] failed\n",
293  index);
294  return data_bytes;
295  }
296  bytes_transferred += data_bytes;
297  }
298  segment++;
299  restart = IC_DATA_CMD_RESTART;
300  }
301 
302  /* Wait for the end of the transaction */
303  if (rx_buffer != NULL)
304  rx_buffer += bytes_transferred - tx_bytes;
305  do {
306  /* Receive any available data */
307  status = regs->ic_status;
308  if ((rx_buffer != NULL) && (status & IC_STATUS_RFNE)) {
309  *rx_buffer++ = (uint8_t)regs->ic_data_cmd;
310  bytes_transferred++;
311  } else {
312  status = regs->ic_raw_intr_stat;
313  if ((total_bytes == bytes_transferred)
314  && (status & IC_INTR_STOP_DET))
315  break;
316 
317  /* Check for errors */
318  if (status & (IC_INTR_RX_OVER | IC_INTR_RX_UNDER
320  i2c_disable(regs);
321  if (CONFIG(I2C_DEBUG)) {
323  "0x%08x: ic_raw_intr_stat, I2C read error!\n",
324  status);
326  "I2C segment[%d] failed\n",
327  seg_count - 1);
328  }
329  return -1;
330  }
331 
332  /* Check for timeout */
333  if (stopwatch_expired(&timeout)) {
334  if (CONFIG(I2C_DEBUG)) {
336  "0x%08x: ic_raw_intr_stat, I2C read timeout!\n",
337  status);
339  "I2C segment[%d] failed\n",
340  seg_count - 1);
341  }
342  return -1;
343  }
344 
345  /* Delay for a while */
346  udelay(1);
347  }
348  } while (1);
349  i2c_disable(regs);
350  regs->ic_tar = 0;
351 
352  /* Return the number of bytes transferred */
353  if (CONFIG(I2C_DEBUG))
354  printk(BIOS_ERR, "0x%08x: bytes transferred\n",
355  bytes_transferred);
356  return bytes_transferred;
357 }
#define ASSERT(x)
Definition: assert.h:44
#define MIN(a, b)
Definition: helpers.h:37
#define printk(level,...)
Definition: stdlib.h:16
#define die_with_post_code(value, fmt,...)
Definition: console.h:21
@ CONFIG
Definition: dsi_common.h:201
uint64_t length
Definition: fw_cfg_if.h:1
static struct tpm_chip chip
Definition: tis.c:17
#define I2C_M_RD
Definition: i2c.h:34
static int stopwatch_expired(struct stopwatch *sw)
Definition: timer.h:152
static void stopwatch_init_usecs_expire(struct stopwatch *sw, long us)
Definition: timer.h:127
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
static uint8_t * buf
Definition: uart.c:7
#define POST_HW_INIT_FAILURE
Hardware initialization failure.
Definition: post_codes.h:353
int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segment, int seg_count)
Definition: i2c.c:176
static int platform_i2c_read(uint32_t restart, uint8_t *rx_buffer, int length, uint32_t stop, struct stopwatch *timeout)
Definition: i2c.c:103
static int platform_i2c_write(uint32_t restart, uint8_t *tx_buffer, int length, uint32_t stop, uint8_t *rx_buffer, struct stopwatch *timeout)
Definition: i2c.c:38
static void i2c_disable(I2C_REGS *regs)
Definition: i2c.c:15
#define IC_CON_7B
Definition: i2c.h:78
#define IC_INTR_RX_OVER
Definition: i2c.h:104
#define IC_DATA_CMD_RESTART
Definition: i2c.h:85
#define IC_INTR_TX_OVER
Definition: i2c.h:102
#define IC_CON_RESTART_EN
Definition: i2c.h:76
#define IC_INTR_STOP_DET
Definition: i2c.h:97
#define IC_CON_SPEED_400_KHz
Definition: i2c.h:80
volatile struct _I2C_REGS I2C_REGS
#define IC_CON_SPEED
Definition: i2c.h:79
#define IC_STATUS_RFNE
Definition: i2c.h:115
#define IC_CON_MASTER_MODE
Definition: i2c.h:82
#define IC_DATA_CMD_READ
Definition: i2c.h:88
#define IC_STATUS_TFNF
Definition: i2c.h:117
#define IC_INTR_TX_ABRT
Definition: i2c.h:99
#define IC_ENABLE_CONTROLLER
Definition: i2c.h:110
#define IC_CON_10B
Definition: i2c.h:77
#define IC_INTR_RX_UNDER
Definition: i2c.h:105
#define IC_DATA_CMD_WRITE
Definition: i2c.h:89
#define IC_DATA_CMD_STOP
Definition: i2c.h:86
void * get_i2c_address(void)
Definition: reg_access.c:42
static struct spi_slave slave
Definition: spiconsole.c:7
#define NULL
Definition: stddef.h:19
unsigned int uint32_t
Definition: stdint.h:14
unsigned char uint8_t
Definition: stdint.h:8
Definition: device.h:76
struct i2c_msg - an I2C transaction segment beginning with START @addr: Slave address,...
Definition: i2c.h:32
uint16_t len
Definition: i2c.h:39
uint16_t slave
Definition: i2c.h:38
uint16_t flags
Definition: i2c.h:33
uint8_t * buf
Definition: i2c.h:40
static struct am335x_pinmux_regs * regs
Definition: pinmux.c:7
void udelay(uint32_t us)
Definition: udelay.c:15
typedef void(X86APIP X86EMU_intrFuncs)(int num)