soc: Remove copyright notices
[coreboot.git] / src / soc / nvidia / tegra / i2c.c
blob1feaa21f25751d51edc39d5e49889e9e002d86dc
1 /*
2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <device/mmio.h>
16 #include <console/console.h>
17 #include <delay.h>
18 #include <device/i2c_simple.h>
19 #include <string.h>
20 #include <soc/addressmap.h>
21 #include <stdint.h>
23 #include "i2c.h"
25 static void do_bus_clear(int bus)
27 struct tegra_i2c_bus_info *info = &tegra_i2c_info[bus];
28 struct tegra_i2c_regs * const regs = info->base;
29 uint32_t bc;
30 int i, timeout_ms = 10;
32 // BUS CLEAR regs (from TRM):
33 // 1. Reset the I2C controller (already done)
34 // 2. Set the # of clock pulses required (using default of 9)
35 // 3. Select STOP condition (using default of 1 = STOP)
36 // 4. Set TERMINATE condition (1 = IMMEDIATE)
37 bc = read32(&regs->bus_clear_config);
38 bc |= I2C_BUS_CLEAR_CONFIG_BC_TERMINATE_IMMEDIATE;
39 write32(&regs->bus_clear_config, bc);
40 // 4.1 Set MSTR_CONFIG_LOAD and wait for clear
41 write32(&regs->config_load, I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD_ENABLE);
42 for (i = 0; i < timeout_ms * 10 && (read32(&regs->config_load) &
43 I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD_ENABLE); i++) {
44 printk(BIOS_DEBUG, "%s: wait for MSTR_CONFIG_LOAD to clear\n",
45 __func__);
46 udelay(100);
48 // 5. Set ENABLE to start the bus clear op
49 write32(&regs->bus_clear_config, bc | I2C_BUS_CLEAR_CONFIG_BC_ENABLE);
50 for (i = 0; i < timeout_ms * 10 && (read32(&regs->bus_clear_config) &
51 I2C_BUS_CLEAR_CONFIG_BC_ENABLE); i++) {
52 printk(BIOS_DEBUG, "%s: wait for bus clear completion\n",
53 __func__);
54 udelay(100);
58 static int tegra_i2c_send_recv(int bus, int read,
59 uint32_t *headers, int header_words,
60 uint8_t *data, int data_len)
62 struct tegra_i2c_bus_info *info = &tegra_i2c_info[bus];
63 struct tegra_i2c_regs * const regs = info->base;
65 while (data_len) {
66 uint32_t status = read32(&regs->fifo_status);
67 int tx_empty = status & I2C_FIFO_STATUS_TX_FIFO_EMPTY_CNT_MASK;
68 tx_empty >>= I2C_FIFO_STATUS_TX_FIFO_EMPTY_CNT_SHIFT;
69 int rx_full = status & I2C_FIFO_STATUS_RX_FIFO_FULL_CNT_MASK;
70 rx_full >>= I2C_FIFO_STATUS_RX_FIFO_FULL_CNT_SHIFT;
72 while (header_words && tx_empty) {
73 write32(&regs->tx_packet_fifo, *headers++);
74 header_words--;
75 tx_empty--;
78 if (!header_words) {
79 if (read) {
80 while (data_len && rx_full) {
81 uint32_t word = read32(&regs->rx_fifo);
82 int todo = MIN(data_len, sizeof(word));
84 memcpy(data, &word, todo);
85 data_len -= todo;
86 data += sizeof(word);
87 rx_full--;
89 } else {
90 while (data_len && tx_empty) {
91 uint32_t word;
92 int todo = MIN(data_len, sizeof(word));
94 memcpy(&word, data, todo);
95 write32(&regs->tx_packet_fifo, word);
96 data_len -= todo;
97 data += sizeof(word);
98 tx_empty--;
103 uint32_t transfer_status =
104 read32(&regs->packet_transfer_status);
106 if (transfer_status & I2C_PKT_STATUS_NOACK_ADDR) {
107 printk(BIOS_ERR,
108 "%s: The address was not acknowledged.\n",
109 __func__);
110 info->reset_func(info->reset_bit);
111 i2c_init(bus);
112 return -1;
113 } else if (transfer_status & I2C_PKT_STATUS_NOACK_DATA) {
114 printk(BIOS_ERR,
115 "%s: The data was not acknowledged.\n",
116 __func__);
117 info->reset_func(info->reset_bit);
118 i2c_init(bus);
119 return -1;
120 } else if (transfer_status & I2C_PKT_STATUS_ARB_LOST) {
121 printk(BIOS_ERR,
122 "%s: Lost arbitration.\n",
123 __func__);
124 info->reset_func(info->reset_bit);
126 /* Use Tegra bus clear registers to unlock SDA */
127 do_bus_clear(bus);
129 /* re-init i2c controller */
130 i2c_init(bus);
132 /* Return w/error, let caller decide what to do */
133 return -1;
137 return 0;
140 static int tegra_i2c_request(int bus, unsigned int chip, int cont, int restart,
141 int read, void *data, int data_len)
143 uint32_t headers[3];
145 if (restart && cont) {
146 printk(BIOS_ERR, "%s: Repeat start and continue xfer are "
147 "mutually exclusive.\n", __func__);
148 return -1;
151 headers[0] = (0 << IOHEADER_PROTHDRSZ_SHIFT) |
152 (1 << IOHEADER_PKTID_SHIFT) |
153 (bus << IOHEADER_CONTROLLER_ID_SHIFT) |
154 IOHEADER_PROTOCOL_I2C | IOHEADER_PKTTYPE_REQUEST;
156 headers[1] = (data_len - 1) << IOHEADER_PAYLOADSIZE_SHIFT;
158 uint32_t slave_addr = (chip << 1) | (read ? 1 : 0);
159 headers[2] = IOHEADER_I2C_REQ_ADDR_MODE_7BIT |
160 (slave_addr << IOHEADER_I2C_REQ_SLAVE_ADDR_SHIFT);
161 if (read)
162 headers[2] |= IOHEADER_I2C_REQ_READ;
163 if (restart)
164 headers[2] |= IOHEADER_I2C_REQ_REPEAT_START;
165 if (cont)
166 headers[2] |= IOHEADER_I2C_REQ_CONTINUE_XFER;
168 return tegra_i2c_send_recv(bus, read, headers, ARRAY_SIZE(headers),
169 data, data_len);
172 static int i2c_transfer_segment(unsigned int bus, unsigned int chip, int restart,
173 int read, void *buf, int len)
175 const uint32_t max_payload =
176 (IOHEADER_PAYLOADSIZE_MASK + 1) >> IOHEADER_PAYLOADSIZE_SHIFT;
178 while (len) {
179 int todo = MIN(len, max_payload);
180 int cont = (todo < len);
181 if (tegra_i2c_request(bus, chip, cont, restart,
182 read, buf, todo))
183 return -1;
184 len -= todo;
185 buf += todo;
187 return 0;
190 int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, int count)
192 struct i2c_msg *seg = segments;
193 int i;
195 if (bus >= num_i2c_buses) {
196 printk(BIOS_ERR, "%s: ERROR: invalid I2C bus (%u)\n", __func__,
197 bus);
198 return -1;
201 for (i = 0; i < count; seg++, i++) {
202 if (i2c_transfer_segment(bus, seg->slave, i < count - 1,
203 seg->flags & I2C_M_RD,
204 seg->buf, seg->len))
205 return -1;
207 return 0;
210 void i2c_init(unsigned int bus)
212 struct tegra_i2c_regs *regs;
214 if (bus >= num_i2c_buses) {
215 printk(BIOS_ERR, "%s: ERROR: invalid I2C bus (%u)\n", __func__,
216 bus);
217 return;
220 regs = tegra_i2c_info[bus].base;
222 write32(&regs->cnfg, I2C_CNFG_PACKET_MODE_EN);