Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
3 : : * Copyright(c) 2018 Synopsys, Inc. All rights reserved.
4 : : */
5 : :
6 : : #include "axgbe_ethdev.h"
7 : : #include "axgbe_common.h"
8 : :
9 : : #define AXGBE_ABORT_COUNT 500
10 : : #define AXGBE_DISABLE_COUNT 1000
11 : :
12 : : #define AXGBE_STD_SPEED 1
13 : :
14 : : #define AXGBE_INTR_RX_FULL BIT(IC_RAW_INTR_STAT_RX_FULL_INDEX)
15 : : #define AXGBE_INTR_TX_EMPTY BIT(IC_RAW_INTR_STAT_TX_EMPTY_INDEX)
16 : : #define AXGBE_INTR_TX_ABRT BIT(IC_RAW_INTR_STAT_TX_ABRT_INDEX)
17 : : #define AXGBE_INTR_STOP_DET BIT(IC_RAW_INTR_STAT_STOP_DET_INDEX)
18 : : #define AXGBE_DEFAULT_INT_MASK (AXGBE_INTR_RX_FULL | \
19 : : AXGBE_INTR_TX_EMPTY | \
20 : : AXGBE_INTR_TX_ABRT | \
21 : : AXGBE_INTR_STOP_DET)
22 : :
23 : : #define AXGBE_I2C_READ BIT(8)
24 : : #define AXGBE_I2C_STOP BIT(9)
25 : :
26 : 0 : static int axgbe_i2c_abort(struct axgbe_port *pdata)
27 : : {
28 : : unsigned int wait = AXGBE_ABORT_COUNT;
29 : :
30 : : /* Must be enabled to recognize the abort request */
31 : 0 : XI2C_IOWRITE_BITS(pdata, IC_ENABLE, EN, 1);
32 : :
33 : : /* Issue the abort */
34 : 0 : XI2C_IOWRITE_BITS(pdata, IC_ENABLE, ABORT, 1);
35 : :
36 [ # # ]: 0 : while (wait--) {
37 [ # # ]: 0 : if (!XI2C_IOREAD_BITS(pdata, IC_ENABLE, ABORT))
38 : : return 0;
39 : 0 : rte_delay_us(500);
40 : : }
41 : :
42 : : return -EBUSY;
43 : : }
44 : :
45 : 0 : static int axgbe_i2c_set_enable(struct axgbe_port *pdata, bool enable)
46 : : {
47 : : unsigned int wait = AXGBE_DISABLE_COUNT;
48 : 0 : unsigned int mode = enable ? 1 : 0;
49 : :
50 [ # # ]: 0 : while (wait--) {
51 : 0 : XI2C_IOWRITE_BITS(pdata, IC_ENABLE, EN, mode);
52 [ # # ]: 0 : if (XI2C_IOREAD_BITS(pdata, IC_ENABLE_STATUS, EN) == mode)
53 : : return 0;
54 : :
55 : 0 : rte_delay_us(100);
56 : : }
57 : :
58 : : return -EBUSY;
59 : : }
60 : :
61 : 0 : static int axgbe_i2c_disable(struct axgbe_port *pdata)
62 : : {
63 : : unsigned int ret;
64 : :
65 : 0 : ret = axgbe_i2c_set_enable(pdata, false);
66 [ # # ]: 0 : if (ret) {
67 : : /* Disable failed, try an abort */
68 : 0 : ret = axgbe_i2c_abort(pdata);
69 [ # # ]: 0 : if (ret)
70 : : return ret;
71 : :
72 : : /* Abort succeeded, try to disable again */
73 : 0 : ret = axgbe_i2c_set_enable(pdata, false);
74 : : }
75 : :
76 : 0 : return ret;
77 : : }
78 : :
79 : : static int axgbe_i2c_enable(struct axgbe_port *pdata)
80 : : {
81 : 0 : return axgbe_i2c_set_enable(pdata, true);
82 : : }
83 : :
84 : : static void axgbe_i2c_clear_all_interrupts(struct axgbe_port *pdata)
85 : : {
86 : 0 : XI2C_IOREAD(pdata, IC_CLR_INTR);
87 : 0 : }
88 : :
89 : : static void axgbe_i2c_disable_interrupts(struct axgbe_port *pdata)
90 : : {
91 : 0 : XI2C_IOWRITE(pdata, IC_INTR_MASK, 0);
92 : : }
93 : :
94 : : static void axgbe_i2c_enable_interrupts(struct axgbe_port *pdata)
95 : : {
96 : 0 : XI2C_IOWRITE(pdata, IC_INTR_MASK, AXGBE_DEFAULT_INT_MASK);
97 : : }
98 : :
99 : 0 : static void axgbe_i2c_write(struct axgbe_port *pdata)
100 : : {
101 : : struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
102 : : unsigned int tx_slots;
103 : : unsigned int cmd;
104 : :
105 : : /* Configured to never receive Rx overflows, so fill up Tx fifo */
106 : 0 : tx_slots = pdata->i2c.tx_fifo_size - XI2C_IOREAD(pdata, IC_TXFLR);
107 [ # # # # ]: 0 : while (tx_slots && state->tx_len) {
108 [ # # ]: 0 : if (state->op->cmd == AXGBE_I2C_CMD_READ)
109 : : cmd = AXGBE_I2C_READ;
110 : : else
111 : 0 : cmd = *state->tx_buf++;
112 : :
113 [ # # ]: 0 : if (state->tx_len == 1)
114 : 0 : XI2C_SET_BITS(cmd, IC_DATA_CMD, STOP, 1);
115 : :
116 : 0 : XI2C_IOWRITE(pdata, IC_DATA_CMD, cmd);
117 : :
118 : 0 : tx_slots--;
119 : 0 : state->tx_len--;
120 : : }
121 : :
122 : : /* No more Tx operations, so ignore TX_EMPTY and return */
123 [ # # ]: 0 : if (!state->tx_len)
124 : 0 : XI2C_IOWRITE_BITS(pdata, IC_INTR_MASK, TX_EMPTY, 0);
125 : 0 : }
126 : :
127 : 0 : static void axgbe_i2c_read(struct axgbe_port *pdata)
128 : : {
129 : : struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
130 : : unsigned int rx_slots;
131 : :
132 : : /* Anything to be read? */
133 [ # # ]: 0 : if (state->op->cmd != AXGBE_I2C_CMD_READ)
134 : : return;
135 : :
136 : 0 : rx_slots = XI2C_IOREAD(pdata, IC_RXFLR);
137 [ # # # # ]: 0 : while (rx_slots && state->rx_len) {
138 : 0 : *state->rx_buf++ = XI2C_IOREAD(pdata, IC_DATA_CMD);
139 : 0 : state->rx_len--;
140 : 0 : rx_slots--;
141 : : }
142 : : }
143 : :
144 : : static void axgbe_i2c_clear_isr_interrupts(struct axgbe_port *pdata,
145 : : unsigned int isr)
146 : : {
147 : : struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
148 : :
149 [ # # ]: 0 : if (isr & AXGBE_INTR_TX_ABRT) {
150 : 0 : state->tx_abort_source = XI2C_IOREAD(pdata, IC_TX_ABRT_SOURCE);
151 : 0 : XI2C_IOREAD(pdata, IC_CLR_TX_ABRT);
152 : : }
153 : :
154 [ # # ]: 0 : if (isr & AXGBE_INTR_STOP_DET)
155 : 0 : XI2C_IOREAD(pdata, IC_CLR_STOP_DET);
156 : : }
157 : :
158 : 0 : static int axgbe_i2c_isr(struct axgbe_port *pdata)
159 : : {
160 : : struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
161 : : unsigned int isr;
162 : :
163 : 0 : isr = XI2C_IOREAD(pdata, IC_RAW_INTR_STAT);
164 : :
165 : 0 : PMD_DRV_LOG_LINE(DEBUG, "I2C interrupt received: status=%#010x", isr);
166 : :
167 : : axgbe_i2c_clear_isr_interrupts(pdata, isr);
168 : :
169 [ # # ]: 0 : if (isr & AXGBE_INTR_TX_ABRT) {
170 : 0 : PMD_DRV_LOG_LINE(DEBUG,
171 : : "I2C TX_ABRT received (%#010x) for target %#04x",
172 : : state->tx_abort_source, state->op->target);
173 : :
174 : : axgbe_i2c_disable_interrupts(pdata);
175 : :
176 : 0 : state->ret = -EIO;
177 : 0 : goto out;
178 : : }
179 : :
180 : : /* Check for data in the Rx fifo */
181 : 0 : axgbe_i2c_read(pdata);
182 : :
183 : : /* Fill up the Tx fifo next */
184 : 0 : axgbe_i2c_write(pdata);
185 : :
186 : 0 : out:
187 : : /* Complete on an error or STOP condition */
188 [ # # # # ]: 0 : if (state->ret || XI2C_GET_BITS(isr, IC_RAW_INTR_STAT, STOP_DET))
189 : 0 : return 1;
190 : :
191 : : return 0;
192 : : }
193 : :
194 : : static void axgbe_i2c_set_mode(struct axgbe_port *pdata)
195 : : {
196 : : unsigned int reg;
197 : :
198 : 0 : reg = XI2C_IOREAD(pdata, IC_CON);
199 : : XI2C_SET_BITS(reg, IC_CON, MASTER_MODE, 1);
200 : : XI2C_SET_BITS(reg, IC_CON, SLAVE_DISABLE, 1);
201 : : XI2C_SET_BITS(reg, IC_CON, RESTART_EN, 1);
202 : : XI2C_SET_BITS(reg, IC_CON, SPEED, AXGBE_STD_SPEED);
203 : 0 : XI2C_SET_BITS(reg, IC_CON, RX_FIFO_FULL_HOLD, 1);
204 : 0 : XI2C_IOWRITE(pdata, IC_CON, reg);
205 : : }
206 : :
207 : : static void axgbe_i2c_get_features(struct axgbe_port *pdata)
208 : : {
209 : : struct axgbe_i2c *i2c = &pdata->i2c;
210 : : unsigned int reg;
211 : :
212 : 0 : reg = XI2C_IOREAD(pdata, IC_COMP_PARAM_1);
213 : 0 : i2c->max_speed_mode = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
214 : : MAX_SPEED_MODE);
215 : 0 : i2c->rx_fifo_size = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
216 : : RX_BUFFER_DEPTH);
217 : 0 : i2c->tx_fifo_size = XI2C_GET_BITS(reg, IC_COMP_PARAM_1,
218 : : TX_BUFFER_DEPTH);
219 : : }
220 : :
221 : : static void axgbe_i2c_set_target(struct axgbe_port *pdata, unsigned int addr)
222 : : {
223 : 0 : XI2C_IOWRITE(pdata, IC_TAR, addr);
224 : : }
225 : :
226 : 0 : static int axgbe_i2c_xfer(struct axgbe_port *pdata, struct axgbe_i2c_op *op)
227 : : {
228 : 0 : struct axgbe_i2c_op_state *state = &pdata->i2c.op_state;
229 : : int ret;
230 : : uint64_t timeout;
231 : :
232 : 0 : pthread_mutex_lock(&pdata->i2c_mutex);
233 : 0 : ret = axgbe_i2c_disable(pdata);
234 [ # # ]: 0 : if (ret) {
235 : 0 : PMD_DRV_LOG_LINE(ERR, "failed to disable i2c master");
236 : 0 : pthread_mutex_unlock(&pdata->i2c_mutex);
237 : 0 : return ret;
238 : : }
239 : :
240 : 0 : axgbe_i2c_set_target(pdata, op->target);
241 : :
242 : : memset(state, 0, sizeof(*state));
243 : 0 : state->op = op;
244 : 0 : state->tx_len = op->len;
245 : 0 : state->tx_buf = (unsigned char *)op->buf;
246 : 0 : state->rx_len = op->len;
247 : 0 : state->rx_buf = (unsigned char *)op->buf;
248 : :
249 : : axgbe_i2c_clear_all_interrupts(pdata);
250 : : ret = axgbe_i2c_enable(pdata);
251 [ # # ]: 0 : if (ret) {
252 : 0 : PMD_DRV_LOG_LINE(ERR, "failed to enable i2c master");
253 : 0 : pthread_mutex_unlock(&pdata->i2c_mutex);
254 : 0 : return ret;
255 : : }
256 : :
257 : : /* Enabling the interrupts will cause the TX FIFO empty interrupt to
258 : : * fire and begin to process the command via the ISR.
259 : : */
260 : : axgbe_i2c_enable_interrupts(pdata);
261 : 0 : timeout = rte_get_timer_cycles() + rte_get_timer_hz();
262 : :
263 [ # # ]: 0 : while (time_before(rte_get_timer_cycles(), timeout)) {
264 : 0 : rte_delay_us(100);
265 [ # # ]: 0 : if (XI2C_IOREAD(pdata, IC_RAW_INTR_STAT)) {
266 [ # # ]: 0 : if (axgbe_i2c_isr(pdata))
267 : 0 : goto success;
268 : : }
269 : : }
270 : :
271 : 0 : PMD_DRV_LOG_LINE(ERR, "i2c operation timed out");
272 : : axgbe_i2c_disable_interrupts(pdata);
273 : 0 : axgbe_i2c_disable(pdata);
274 : : ret = -ETIMEDOUT;
275 : 0 : goto unlock;
276 : :
277 : : success:
278 : 0 : ret = state->ret;
279 [ # # ]: 0 : if (ret) {
280 [ # # ]: 0 : if (state->tx_abort_source & IC_TX_ABRT_7B_ADDR_NOACK)
281 : : ret = -ENOTCONN;
282 [ # # ]: 0 : else if (state->tx_abort_source & IC_TX_ABRT_ARB_LOST)
283 : : ret = -EAGAIN;
284 : : }
285 : :
286 : 0 : unlock:
287 : 0 : pthread_mutex_unlock(&pdata->i2c_mutex);
288 : 0 : return ret;
289 : : }
290 : :
291 : 0 : static void axgbe_i2c_stop(struct axgbe_port *pdata)
292 : : {
293 [ # # ]: 0 : if (!pdata->i2c.started)
294 : : return;
295 : :
296 : 0 : PMD_DRV_LOG_LINE(DEBUG, "stopping I2C");
297 : :
298 : 0 : pdata->i2c.started = 0;
299 : : axgbe_i2c_disable_interrupts(pdata);
300 : 0 : axgbe_i2c_disable(pdata);
301 : : axgbe_i2c_clear_all_interrupts(pdata);
302 : : }
303 : :
304 : 0 : static int axgbe_i2c_start(struct axgbe_port *pdata)
305 : : {
306 [ # # ]: 0 : if (pdata->i2c.started)
307 : : return 0;
308 : :
309 : 0 : PMD_DRV_LOG_LINE(DEBUG, "starting I2C");
310 : :
311 : 0 : pdata->i2c.started = 1;
312 : :
313 : 0 : return 0;
314 : : }
315 : :
316 : 0 : static int axgbe_i2c_init(struct axgbe_port *pdata)
317 : : {
318 : : int ret;
319 : :
320 : : axgbe_i2c_disable_interrupts(pdata);
321 : :
322 : 0 : ret = axgbe_i2c_disable(pdata);
323 [ # # ]: 0 : if (ret) {
324 : 0 : PMD_DRV_LOG_LINE(ERR, "failed to disable i2c master");
325 : 0 : return ret;
326 : : }
327 : :
328 : : axgbe_i2c_get_features(pdata);
329 : :
330 : : axgbe_i2c_set_mode(pdata);
331 : :
332 : : axgbe_i2c_clear_all_interrupts(pdata);
333 : :
334 : 0 : return 0;
335 : : }
336 : :
337 : 0 : void axgbe_init_function_ptrs_i2c(struct axgbe_i2c_if *i2c_if)
338 : : {
339 : 0 : i2c_if->i2c_init = axgbe_i2c_init;
340 : 0 : i2c_if->i2c_start = axgbe_i2c_start;
341 : 0 : i2c_if->i2c_stop = axgbe_i2c_stop;
342 : 0 : i2c_if->i2c_xfer = axgbe_i2c_xfer;
343 : 0 : }
|