blob: 88e9169ec73cc8609ff3740176b1a575b3b3a001 [file] [log] [blame]
Patrick Georgi70517072020-05-10 18:47:05 +02001/* SPDX-License-Identifier: BSD-3-Clause */
Varadarajan Narayanana6935c22016-03-02 16:57:10 +05302
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +05304#include <console/console.h>
5#include <delay.h>
Jes Klinke19baa9d2022-02-22 16:00:09 -08006#include <timer.h>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +05307#include <soc/iomap.h>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +05308#include <soc/qup.h>
9
Varadarajan Narayanan25967642016-03-08 15:02:56 +053010#define TIMEOUT_CNT 100
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053011
Varadarajan Narayanan25967642016-03-08 15:02:56 +053012#define QUP_ADDR(id, reg) (blsp_qup_base(id) + (reg))
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053013
Varadarajan Narayanan25967642016-03-08 15:02:56 +053014#define QUP_DEBUG 0
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053015
Varadarajan Narayanan25967642016-03-08 15:02:56 +053016#define QUPDBG BIOS_ERR, "\t-> "
17
18#if QUP_DEBUG
19#define qup_write32(a, v) do { \
20 write32(a, v); \
Julius Werner540a9802019-12-09 13:03:29 -080021 printk(QUPDBG "%s(%d): write32(%p, 0x%x)\n", \
Varadarajan Narayanan25967642016-03-08 15:02:56 +053022 __func__, __LINE__, a, v); \
23} while (0)
24#else
25#define qup_write32 write32
26#endif
27
28static qup_return_t qup_i2c_master_status(blsp_qup_id_t id)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053029{
Varadarajan Narayanan25967642016-03-08 15:02:56 +053030 uint32_t reg_val = read32(QUP_ADDR(id, QUP_I2C_MASTER_STATUS));
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053031
Varadarajan Narayanan25967642016-03-08 15:02:56 +053032 if (read32(QUP_ADDR(id, QUP_ERROR_FLAGS)))
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053033 return QUP_ERR_XFER_FAIL;
Varadarajan Narayanan25967642016-03-08 15:02:56 +053034
35#if QUP_DEBUG
36 printk(QUPDBG "%s: 0x%x\n", __func__, reg_val);
37#endif
38
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053039 if (reg_val & QUP_I2C_INVALID_READ_ADDR)
40 return QUP_ERR_I2C_INVALID_SLAVE_ADDR;
41 if (reg_val & QUP_I2C_FAILED_MASK)
42 return QUP_ERR_I2C_FAILED;
43 if (reg_val & QUP_I2C_ARB_LOST)
44 return QUP_ERR_I2C_ARB_LOST;
45 if (reg_val & QUP_I2C_BUS_ERROR)
46 return QUP_ERR_I2C_BUS_ERROR;
47 if (reg_val & QUP_I2C_INVALID_WRITE)
48 return QUP_ERR_I2C_INVALID_WRITE;
49 if (reg_val & QUP_I2C_PACKET_NACK)
50 return QUP_ERR_I2C_NACK;
51 if (reg_val & QUP_I2C_INVALID_TAG)
52 return QUP_ERR_I2C_INVALID_TAG;
53
54 return QUP_SUCCESS;
55}
56
57static int check_bit_state(uint32_t *reg, int wait_for)
58{
59 unsigned int count = TIMEOUT_CNT;
60
61 while ((read32(reg) & (QUP_STATE_VALID_MASK | QUP_STATE_MASK)) !=
62 (QUP_STATE_VALID | wait_for)) {
63 if (count == 0)
64 return QUP_ERR_TIMEOUT;
65 count--;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053066 }
67
68 return QUP_SUCCESS;
69}
70
71/*
72 * Check whether GSBIn_QUP State is valid
73 */
Martin Roth57e89092019-10-23 21:45:23 -060074static qup_return_t qup_wait_for_state(blsp_qup_id_t id, unsigned int wait_for)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053075{
Varadarajan Narayanan25967642016-03-08 15:02:56 +053076 return check_bit_state(QUP_ADDR(id, QUP_STATE), wait_for);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053077}
78
Varadarajan Narayanan25967642016-03-08 15:02:56 +053079qup_return_t qup_reset_i2c_master_status(blsp_qup_id_t id)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053080{
81 /*
Varadarajan Narayanan25967642016-03-08 15:02:56 +053082 * The I2C_STATUS is a status register.
83 * Writing any value clears the status bits.
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053084 */
Varadarajan Narayanan25967642016-03-08 15:02:56 +053085 qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_STATUS), 0);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053086 return QUP_SUCCESS;
87}
88
Varadarajan Narayanan25967642016-03-08 15:02:56 +053089static qup_return_t qup_reset_master_status(blsp_qup_id_t id)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053090{
Varadarajan Narayanan25967642016-03-08 15:02:56 +053091 qup_write32(QUP_ADDR(id, QUP_ERROR_FLAGS), 0x3C);
92 qup_write32(QUP_ADDR(id, QUP_ERROR_FLAGS_EN), 0x3C);
93 qup_reset_i2c_master_status(id);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053094 return QUP_SUCCESS;
95}
96
Jes Klinke19baa9d2022-02-22 16:00:09 -080097static qup_return_t qup_fifo_wait_for(blsp_qup_id_t id, uint32_t status,
98 struct stopwatch *timeout)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053099{
100 qup_return_t ret = QUP_ERR_UNDEFINED;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530101
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530102 while (!(read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status)) {
103 ret = qup_i2c_master_status(id);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530104 if (ret)
105 return ret;
Jes Klinke19baa9d2022-02-22 16:00:09 -0800106 if (stopwatch_expired(timeout))
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530107 return QUP_ERR_TIMEOUT;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530108 }
109
110 return QUP_SUCCESS;
111}
112
Jes Klinke19baa9d2022-02-22 16:00:09 -0800113static qup_return_t qup_fifo_wait_while(blsp_qup_id_t id, uint32_t status,
114 struct stopwatch *timeout)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530115{
116 qup_return_t ret = QUP_ERR_UNDEFINED;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530117
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530118 while (read32(QUP_ADDR(id, QUP_OPERATIONAL)) & status) {
119 ret = qup_i2c_master_status(id);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530120 if (ret)
121 return ret;
Jes Klinke19baa9d2022-02-22 16:00:09 -0800122 if (stopwatch_expired(timeout))
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530123 return QUP_ERR_TIMEOUT;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530124 }
125
126 return QUP_SUCCESS;
127}
128
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530129static inline uint32_t qup_i2c_create_output_tag(int stop, u8 data)
130{
131 uint32_t tag;
132
133 if (stop)
134 tag = QUP_I2C_STOP_SEQ | QUP_I2C_DATA(data);
135 else
136 tag = QUP_I2C_DATA_SEQ | QUP_I2C_DATA(data);
137
138 return tag;
139}
140
Jes Klinke19baa9d2022-02-22 16:00:09 -0800141static inline qup_return_t qup_i2c_write_fifo_flush(blsp_qup_id_t id,
142 struct stopwatch *timeout)
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530143{
144 qup_return_t ret = QUP_ERR_UNDEFINED;
145
146 qup_write32(QUP_ADDR(id, QUP_OPERATIONAL), OUTPUT_SERVICE_FLAG);
147
Kan Yan7f3eced2016-06-30 13:46:56 -0700148 mdelay(4); /* TPM seems to need this */
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530149
Jes Klinke19baa9d2022-02-22 16:00:09 -0800150 ret = qup_fifo_wait_while(id, OUTPUT_FIFO_NOT_EMPTY, timeout);
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530151 if (ret)
152 return ret;
153
154 ret = qup_i2c_master_status(id);
155
156 if (ret)
157 printk(BIOS_DEBUG, "%s: error\n", __func__);
158
159 return ret;
160}
161
162static qup_return_t qup_i2c_write_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530163 uint8_t stop_seq)
164{
165 qup_return_t ret = QUP_ERR_UNDEFINED;
166 uint8_t addr = p_tx_obj->p.iic.addr;
167 uint8_t *data_ptr = p_tx_obj->p.iic.data;
Martin Roth57e89092019-10-23 21:45:23 -0600168 unsigned int data_len = p_tx_obj->p.iic.data_len;
169 unsigned int idx = 0;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530170 uint32_t tag, *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO);
Jes Klinke19baa9d2022-02-22 16:00:09 -0800171 struct stopwatch timeout;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530172
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530173 qup_reset_master_status(id);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530174
Varadarajan Narayanane6a2ecf2016-05-17 11:18:30 +0530175 qup_write32(QUP_ADDR(id, QUP_MX_OUTPUT_COUNT), data_len + 1);
176
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530177 qup_set_state(id, QUP_STATE_RUN);
178
179 /*
180 * Since UNPACK enable is set in io mode register, populate 2 tags
181 * for each fifo register.
182 *
183 * Create the first tag as follows, with the start tag and first byte
184 * of the data to be written
185 * +--------+--------+--------+--------+
186 * | STOP / | data | START | ADDR |
187 * |DATA tag| byte | tag | << 1 |
188 * +--------+--------+--------+--------+
189 * rest will be created in the following while loop.
190 */
191 tag = qup_i2c_create_output_tag(data_len == 1 && stop_seq,
192 data_ptr[idx]);
193 tag = ((tag << 16) & 0xffff0000) |
194 (QUP_I2C_START_SEQ | QUP_I2C_ADDR(addr));
195 data_len--;
196 idx++;
197
198 qup_write32(fifo, tag);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530199
Jes Klinke19baa9d2022-02-22 16:00:09 -0800200 stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530201 while (data_len) {
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530202
203 tag = qup_i2c_create_output_tag(data_len == 1 && stop_seq,
204 data_ptr[idx]);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530205 data_len--;
206 idx++;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530207
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530208 if (data_len) {
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530209 tag |= qup_i2c_create_output_tag(
210 data_len == 1 && stop_seq,
211 data_ptr[idx]) << 16;
212 data_len--;
213 idx++;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530214 }
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530215
216 qup_write32(fifo, tag);
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530217
Jes Klinke19baa9d2022-02-22 16:00:09 -0800218 ret = qup_i2c_write_fifo_flush(id, &timeout);
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530219
Varadarajan Narayanane6a2ecf2016-05-17 11:18:30 +0530220 if (ret) {
221 printk(QUPDBG "%s: error\n", __func__);
222 return ret;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530223 }
224 }
225
Jes Klinke19baa9d2022-02-22 16:00:09 -0800226 ret = qup_i2c_write_fifo_flush(id, &timeout);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530227
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530228 qup_set_state(id, QUP_STATE_RESET);
229
230 return ret;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530231}
232
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530233static qup_return_t qup_i2c_write(blsp_qup_id_t id, uint8_t mode,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530234 qup_data_t *p_tx_obj, uint8_t stop_seq)
235{
236 qup_return_t ret = QUP_ERR_UNDEFINED;
237
238 switch (mode) {
239 case QUP_MODE_FIFO:
Varadarajan Narayanane6a2ecf2016-05-17 11:18:30 +0530240 case QUP_MODE_BLOCK:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530241 ret = qup_i2c_write_fifo(id, p_tx_obj, stop_seq);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530242 break;
243 default:
244 ret = QUP_ERR_UNSUPPORTED;
245 }
246
247 if (ret) {
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530248 qup_set_state(id, QUP_STATE_RESET);
249 printk(QUPDBG "%s() failed (%d)\n", __func__, ret);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530250 }
251
252 return ret;
253}
254
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530255static int qup_i2c_parse_tag(uint32_t data, uint8_t *data_ptr, uint32_t len)
256{
257 int i, idx = 0;
258 int max = (len > 2) ? 2 : len;
259
260 for (i = 0; i < max; i++) {
261 switch (QUP_I2C_MI_TAG(data)) {
262 case QUP_I2C_MIDATA_SEQ:
263 data_ptr[idx] = QUP_I2C_DATA(data);
264 idx++;
265 break;
266 case QUP_I2C_MISTOP_SEQ:
267 data_ptr[idx] = QUP_I2C_DATA(data);
268 idx++;
269 return idx;
270 default:
271 printk(QUPDBG "%s: Unexpected tag (0x%x)\n", __func__,
272 QUP_I2C_MI_TAG(data));
273 return -1;
274 }
275
276 data = (data >> 16);
277 }
278
279 return idx;
280}
281
282static qup_return_t qup_i2c_read_fifo(blsp_qup_id_t id, qup_data_t *p_tx_obj)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530283{
284 qup_return_t ret = QUP_ERR_UNDEFINED;
285 uint8_t addr = p_tx_obj->p.iic.addr;
286 uint8_t *data_ptr = p_tx_obj->p.iic.data;
Martin Roth57e89092019-10-23 21:45:23 -0600287 unsigned int data_len = p_tx_obj->p.iic.data_len;
288 unsigned int idx = 0;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530289 uint32_t *fifo = QUP_ADDR(id, QUP_OUTPUT_FIFO);
Jes Klinke19baa9d2022-02-22 16:00:09 -0800290 struct stopwatch timeout;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530291
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530292 qup_reset_master_status(id);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530293
Varadarajan Narayanane6a2ecf2016-05-17 11:18:30 +0530294 qup_write32(QUP_ADDR(id, QUP_IO_MODES),
295 QUP_UNPACK_EN | QUP_PACK_EN |
296 ((QUP_MODE_BLOCK & QUP_MODE_MASK) <<
297 QUP_OUTPUT_MODE_SHFT) |
298 ((QUP_MODE_BLOCK & QUP_MODE_MASK) <<
299 QUP_INPUT_MODE_SHFT));
300
301 qup_write32(QUP_ADDR(id, QUP_MX_INPUT_COUNT), data_len);
302
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530303 qup_set_state(id, QUP_STATE_RUN);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530304
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530305 qup_write32(fifo, (QUP_I2C_START_SEQ |
306 (QUP_I2C_ADDR(addr) | QUP_I2C_SLAVE_READ)) |
307 ((QUP_I2C_RECV_SEQ | data_len) << 16));
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530308
Jes Klinke19baa9d2022-02-22 16:00:09 -0800309 stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US);
310 ret = qup_i2c_write_fifo_flush(id, &timeout);
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530311 if (ret) {
312 printk(QUPDBG "%s: OUTPUT_FIFO_NOT_EMPTY\n", __func__);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530313 return ret;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530314 }
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530315
Jes Klinke19baa9d2022-02-22 16:00:09 -0800316 ret = qup_fifo_wait_for(id, INPUT_SERVICE_FLAG, &timeout);
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530317 if (ret) {
318 printk(QUPDBG "%s: INPUT_SERVICE_FLAG\n", __func__);
319 return ret;
320 }
321
322 fifo = QUP_ADDR(id, QUP_INPUT_FIFO);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530323
324 while (data_len) {
325 uint32_t data;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530326 int count;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530327
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530328 data = read32(fifo);
Varadarajan Narayanane6a2ecf2016-05-17 11:18:30 +0530329 mdelay(1);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530330
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530331 count = qup_i2c_parse_tag(data, data_ptr + idx, data_len);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530332
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530333 if (count < 0) {
334 printk(QUPDBG "%s: Cannot parse tag 0x%x\n",
335 __func__, data);
336 qup_set_state(id, QUP_STATE_PAUSE);
337
338 return QUP_ERR_I2C_INVALID_TAG;
339 }
340
341 idx += count;
342 data_len -= count;
343
Varadarajan Narayanane6a2ecf2016-05-17 11:18:30 +0530344 qup_write32(QUP_ADDR(id, QUP_OPERATIONAL), INPUT_SERVICE_FLAG);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530345 }
346
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530347 p_tx_obj->p.iic.data_len = idx;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530348
349 qup_write32(QUP_ADDR(id, QUP_MX_READ_COUNT), 0);
350
351 qup_set_state(id, QUP_STATE_RESET);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530352
353 return QUP_SUCCESS;
354}
355
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530356static qup_return_t qup_i2c_read(blsp_qup_id_t id, uint8_t mode,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530357 qup_data_t *p_tx_obj)
358{
359 qup_return_t ret = QUP_ERR_UNDEFINED;
360
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530361 qup_set_state(id, QUP_STATE_RESET);
362
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530363 switch (mode) {
364 case QUP_MODE_FIFO:
Varadarajan Narayanane6a2ecf2016-05-17 11:18:30 +0530365 case QUP_MODE_BLOCK:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530366 ret = qup_i2c_read_fifo(id, p_tx_obj);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530367 break;
368 default:
369 ret = QUP_ERR_UNSUPPORTED;
370 }
371
372 if (ret) {
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530373 qup_set_state(id, QUP_STATE_RESET);
374 printk(QUPDBG "%s() failed (%d)\n", __func__, ret);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530375 }
376
377 return ret;
378}
379
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530380qup_return_t qup_init(blsp_qup_id_t id, const qup_config_t *config_ptr)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530381{
382 qup_return_t ret = QUP_ERR_UNDEFINED;
383 uint32_t reg_val;
384
385 /* Reset the QUP core.*/
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530386 qup_write32(QUP_ADDR(id, QUP_SW_RESET), 0x1);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530387
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530388 /* Wait till the reset takes effect */
389 ret = qup_wait_for_state(id, QUP_STATE_RESET);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530390 if (ret)
391 goto bailout;
392
393 /* Reset the config */
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530394 qup_write32(QUP_ADDR(id, QUP_CONFIG), 0);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530395
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530396 /* Program the config register */
397 /* Set N value */
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530398 reg_val = 0x0F;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530399 /* Set protocol */
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530400 switch (config_ptr->protocol) {
401 case QUP_MINICORE_I2C_MASTER:
402 reg_val |= ((config_ptr->protocol &
403 QUP_MINI_CORE_PROTO_MASK) <<
404 QUP_MINI_CORE_PROTO_SHFT);
405 break;
406 default:
407 ret = QUP_ERR_UNSUPPORTED;
408 goto bailout;
409 }
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530410 reg_val |= QUP_APP_CLK_ON_EN | QUP_CORE_CLK_ON_EN;
411 qup_write32(QUP_ADDR(id, QUP_CONFIG), reg_val);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530412
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530413 /* Choose version 1 tag */
414 qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CONFIG), 0);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530415
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530416 /* Reset i2c clk cntl register */
417 qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CLK_CTL), 0);
418
419 /* Set QUP IO Mode */
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530420 switch (config_ptr->mode) {
421 case QUP_MODE_FIFO:
Varadarajan Narayanane6a2ecf2016-05-17 11:18:30 +0530422 case QUP_MODE_BLOCK:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530423 reg_val = QUP_UNPACK_EN | QUP_PACK_EN |
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530424 ((config_ptr->mode & QUP_MODE_MASK) <<
425 QUP_OUTPUT_MODE_SHFT) |
426 ((config_ptr->mode & QUP_MODE_MASK) <<
427 QUP_INPUT_MODE_SHFT);
428 break;
429 default:
430 ret = QUP_ERR_UNSUPPORTED;
431 goto bailout;
432 }
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530433 qup_write32(QUP_ADDR(id, QUP_IO_MODES), reg_val);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530434
435 /*Set i2c clk cntl*/
436 reg_val = (QUP_DIVIDER_MIN_VAL << QUP_HS_DIVIDER_SHFT);
437 reg_val |= ((((config_ptr->src_frequency / config_ptr->clk_frequency)
438 / 2) - QUP_DIVIDER_MIN_VAL) &
439 QUP_FS_DIVIDER_MASK);
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530440 qup_write32(QUP_ADDR(id, QUP_I2C_MASTER_CLK_CTL), reg_val);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530441
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530442 qup_set_state(id, QUP_STATE_RESET);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530443bailout:
444 if (ret)
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530445 printk(QUPDBG "failed to init qup (%d)\n", ret);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530446
447 return ret;
448}
449
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530450qup_return_t qup_set_state(blsp_qup_id_t id, uint32_t state)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530451{
452 qup_return_t ret = QUP_ERR_UNDEFINED;
Martin Roth57e89092019-10-23 21:45:23 -0600453 unsigned int curr_state = read32(QUP_ADDR(id, QUP_STATE));
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530454
Julius Werner7c712bb2019-05-01 16:51:20 -0700455 if (state <= QUP_STATE_PAUSE && (curr_state & QUP_STATE_VALID_MASK)) {
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530456 /*
457 * For PAUSE_STATE to RESET_STATE transition,
458 * two writes of 10[binary]) are required for the
459 * transition to complete.
460 */
461 if (QUP_STATE_PAUSE == curr_state && QUP_STATE_RESET == state) {
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530462 qup_write32(QUP_ADDR(id, QUP_STATE), 0x2);
463 qup_write32(QUP_ADDR(id, QUP_STATE), 0x2);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530464 } else {
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530465 qup_write32(QUP_ADDR(id, QUP_STATE), state);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530466 }
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530467 ret = qup_wait_for_state(id, state);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530468 }
469
470 return ret;
471}
472
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530473static qup_return_t qup_i2c_send_data(blsp_qup_id_t id, qup_data_t *p_tx_obj,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530474 uint8_t stop_seq)
475{
476 qup_return_t ret = QUP_ERR_UNDEFINED;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530477 uint8_t mode = (read32(QUP_ADDR(id, QUP_IO_MODES)) >>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530478 QUP_OUTPUT_MODE_SHFT) & QUP_MODE_MASK;
479
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530480 ret = qup_i2c_write(id, mode, p_tx_obj, stop_seq);
481 if (QUP_DEBUG) {
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530482 int i;
483
484 printk(BIOS_DEBUG, "i2c tx bus %d device %2.2x:",
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530485 id, p_tx_obj->p.iic.addr);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530486 for (i = 0; i < p_tx_obj->p.iic.data_len; i++)
487 printk(BIOS_DEBUG, " %2.2x", p_tx_obj->p.iic.data[i]);
488 printk(BIOS_DEBUG, "\n");
489 }
490
491 return ret;
492}
493
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530494qup_return_t qup_send_data(blsp_qup_id_t id, qup_data_t *p_tx_obj,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530495 uint8_t stop_seq)
496{
497 qup_return_t ret = QUP_ERR_UNDEFINED;
498
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530499 if (p_tx_obj->protocol == ((read32(QUP_ADDR(id, QUP_CONFIG)) >>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530500 QUP_MINI_CORE_PROTO_SHFT) & QUP_MINI_CORE_PROTO_MASK)) {
501 switch (p_tx_obj->protocol) {
502 case QUP_MINICORE_I2C_MASTER:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530503 ret = qup_i2c_send_data(id, p_tx_obj, stop_seq);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530504 break;
505 default:
506 ret = QUP_ERR_UNSUPPORTED;
507 }
508 }
509
510 return ret;
511}
512
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530513static qup_return_t qup_i2c_recv_data(blsp_qup_id_t id, qup_data_t *p_rx_obj)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530514{
515 qup_return_t ret = QUP_ERR_UNDEFINED;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530516 uint8_t mode = (read32(QUP_ADDR(id, QUP_IO_MODES)) >>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530517 QUP_INPUT_MODE_SHFT) & QUP_MODE_MASK;
518
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530519 ret = qup_i2c_read(id, mode, p_rx_obj);
520 if (QUP_DEBUG) {
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530521 int i;
522
523 printk(BIOS_DEBUG, "i2c rxed on bus %d device %2.2x:",
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530524 id, p_rx_obj->p.iic.addr);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530525 for (i = 0; i < p_rx_obj->p.iic.data_len; i++)
526 printk(BIOS_DEBUG, " %2.2x", p_rx_obj->p.iic.data[i]);
527 printk(BIOS_DEBUG, "\n");
528 }
529
530 return ret;
531}
532
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530533qup_return_t qup_recv_data(blsp_qup_id_t id, qup_data_t *p_rx_obj)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530534{
535 qup_return_t ret = QUP_ERR_UNDEFINED;
536
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530537 if (p_rx_obj->protocol == ((read32(QUP_ADDR(id, QUP_CONFIG)) >>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530538 QUP_MINI_CORE_PROTO_SHFT) & QUP_MINI_CORE_PROTO_MASK)) {
539 switch (p_rx_obj->protocol) {
540 case QUP_MINICORE_I2C_MASTER:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530541 ret = qup_i2c_recv_data(id, p_rx_obj);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530542 break;
543 default:
544 ret = QUP_ERR_UNSUPPORTED;
545 }
546 }
547
548 return ret;
549}