blob: acbbd909bd770710e3c6d0fe1138f8f00fbad1cf [file] [log] [blame]
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -07001/*
Ionela Voinescu49aad6b2014-09-09 20:18:55 +01002 * This file is part of the coreboot project.
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -07003 *
Ionela Voinescu49aad6b2014-09-09 20:18:55 +01004 * Copyright (C) 2014 Imagination Technologies
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -07009 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
Furquan Shaikhc28984d2016-11-20 21:04:00 -080016#include <console/console.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020017#include <device/mmio.h>
Julius Werner08125682014-10-20 13:22:00 -070018#include <soc/cpu.h>
19#include <soc/spi.h>
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010020#include <spi_flash.h>
Ionela Voinescu1d4c3052015-06-07 23:22:34 +010021#include <spi-generic.h>
22#include <stdlib.h>
23#include <string.h>
24#include <timer.h>
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -070025
Vadim Bendeburyf9ff3532014-11-29 15:06:26 -080026/* Imgtec controller uses 16 bit packet length. */
27#define IMGTEC_SPI_MAX_TRANSFER_SIZE ((1 << 16) - 1)
28
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010029struct img_spi_slave {
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010030 /* SPIM instance device parameters */
31 struct spim_device_parameters device_parameters;
32 /* SPIM instance base address */
33 u32 base;
34 /* Boolean property that is TRUE if API has been initialised */
35 int initialised;
36};
37
38/* Allocate memory for the maximum number of devices */
39static struct
40img_spi_slave img_spi_slaves[SPIM_NUM_BLOCKS*SPIM_NUM_PORTS_PER_BLOCK];
41
42/*
43 * Wait for the bit at the shift position to be set in reg
44 * If the bit is not set in SPI_TIMEOUT_VALUE_US return with error
45 */
46static int wait_status(u32 reg, u32 shift)
47{
48 struct stopwatch sw;
49
50 stopwatch_init_usecs_expire(&sw, SPI_TIMEOUT_VALUE_US);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +020051 while (!(read32_x(reg) & (1 << shift))) {
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010052 if (stopwatch_expired(&sw))
53 return -SPIM_TIMEOUT;
54 }
55 return SPIM_OK;
56}
57
Furquan Shaikh36b81af2016-12-01 01:02:44 -080058static struct img_spi_slave *get_img_slave(const struct spi_slave *slave)
59{
60 return img_spi_slaves + slave->bus * SPIM_NUM_PORTS_PER_BLOCK +
61 slave->cs;
62}
63
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010064/* Transmitter function. Fills TX FIFO with data before enabling SPIM */
Furquan Shaikh0dba0252016-11-30 04:34:22 -080065static int transmitdata(const struct spi_slave *slave, u8 *buffer, u32 size)
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010066{
67 u32 blocksize, base, write_data;
68 int ret;
Furquan Shaikh36b81af2016-12-01 01:02:44 -080069 struct img_spi_slave *img_slave = get_img_slave(slave);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010070
Furquan Shaikh36b81af2016-12-01 01:02:44 -080071 base = img_slave->base;
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010072 while (size) {
73 /* Wait until FIFO empty */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +020074 write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_SDE_MASK);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010075 ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
76 SPFI_SDE_SHIFT);
77 if (ret)
78 return ret;
79
80 /*
81 * Write to FIFO in blocks of 16 words (64 bytes)
82 * Do 32bit writes first.
83 */
84 blocksize = SPIM_MAX_BLOCK_BYTES;
85 while ((size >= sizeof(u32)) && blocksize) {
86 memcpy(&write_data, buffer, sizeof(u32));
Kyösti Mälkkia9506db2019-03-20 20:30:02 +020087 write32_x(base + SPFI_SEND_LONG_REG_OFFSET, write_data);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010088 buffer += sizeof(u32);
89 size -= sizeof(u32);
90 blocksize -= sizeof(u32);
91 }
92 while (size && blocksize) {
Kyösti Mälkkia9506db2019-03-20 20:30:02 +020093 write32_x(base + SPFI_SEND_BYTE_REG_OFFSET, *buffer);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +010094 buffer++;
95 size--;
96 blocksize--;
97 }
98 }
99 return SPIM_OK;
100}
101
102/* Receiver function */
Furquan Shaikh0dba0252016-11-30 04:34:22 -0800103static int receivedata(const struct spi_slave *slave, u8 *buffer, u32 size)
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100104{
105 u32 read_data, base;
106 int ret;
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800107 struct img_spi_slave *img_slave = get_img_slave(slave);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100108
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800109 base = img_slave->base;
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100110 /*
111 * Do 32bit reads first. Clear status GDEX32BIT here so that the first
112 * status reg. read gets the actual bit state
113 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200114 write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX32BIT_MASK);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100115 while (size >= sizeof(u32)) {
116 ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
117 SPFI_GDEX32BIT_SHIFT);
118 if (ret)
119 return ret;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200120 read_data = read32_x(base + SPFI_GET_LONG_REG_OFFSET);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100121 memcpy(buffer, &read_data, sizeof(u32));
122 buffer += sizeof(u32);
123 size -= sizeof(u32);
124 /* Clear interrupt status on GDEX32BITL */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200125 write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX32BIT_MASK);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100126 }
127
128 /*
129 * Do the remaining 8bit reads. Clear status GDEX8BIT here so that
130 * the first status reg. read gets the actual bit state
131 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200132 write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX8BIT_MASK);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100133 while (size) {
134 ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
135 SPFI_GDEX8BIT_SHIFT);
136 if (ret)
137 return ret;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200138 *buffer = read32_x(base + SPFI_GET_BYTE_REG_OFFSET);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100139 buffer++;
140 size--;
141 /* Clear interrupt status on SPFI_GDEX8BIT */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200142 write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX8BIT_MASK);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100143 }
144 return SPIM_OK;
145}
146
147/* Sets port parameters in port state register. */
Furquan Shaikh0dba0252016-11-30 04:34:22 -0800148static void setparams(const struct spi_slave *slave, u32 port,
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100149 struct spim_device_parameters *params)
150{
151 u32 spim_parameters, port_state, base;
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800152 struct img_spi_slave *img_slave = get_img_slave(slave);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100153
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800154 base = img_slave->base;
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100155 spim_parameters = 0;
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200156 port_state = read32_x(base + SPFI_PORT_STATE_REG_OFFSET);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100157 port_state &= ~((SPIM_PORT0_MASK>>port)|SPFI_PORT_SELECT_MASK);
158 port_state |= params->cs_idle_level<<(SPIM_CS0_IDLE_SHIFT-port);
159 port_state |=
160 params->data_idle_level<<(SPIM_DATA0_IDLE_SHIFT-port);
161
162 /* Clock idle level and phase */
163 switch (params->spi_mode) {
164 case SPIM_MODE_0:
165 break;
166 case SPIM_MODE_1:
167 port_state |= (1 << (SPIM_CLOCK0_PHASE_SHIFT - port));
168 break;
169 case SPIM_MODE_2:
170 port_state |= (1 << (SPIM_CLOCK0_IDLE_SHIFT - port));
171 break;
172 case SPIM_MODE_3:
173 port_state |= (1 << (SPIM_CLOCK0_IDLE_SHIFT - port)) |
174 (1 << (SPIM_CLOCK0_PHASE_SHIFT - port));
175 break;
176 }
177 /* Set port state register */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200178 write32_x(base + SPFI_PORT_STATE_REG_OFFSET, port_state);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100179
180 /* Set up values to be written to device parameter register */
181 spim_parameters |= params->bitrate << SPIM_CLK_DIVIDE_SHIFT;
182 spim_parameters |= params->cs_setup << SPIM_CS_SETUP_SHIFT;
183 spim_parameters |= params->cs_hold << SPIM_CS_HOLD_SHIFT;
184 spim_parameters |= params->cs_delay << SPIM_CS_DELAY_SHIFT;
185
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200186 write32_x(base + SPFI_PORT_0_PARAM_REG_OFFSET + 4 * port,
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100187 spim_parameters);
188}
189
190/* Sets up transaction register */
191static u32 transaction_reg_setup(struct spim_buffer *first,
192 struct spim_buffer *second)
193{
194 u32 reg = 0;
195
196 /* 2nd transfer exists? */
197 if (second) {
198 /*
199 * If second transfer exists, it's a "command followed by data"
200 * type of transfer and first transfer is defined by
201 * CMD_LENGTH, ADDR_LENGTH, DUMMY_LENGTH... fields of
202 * transaction register
203 */
204 reg = spi_write_reg_field(reg, SPFI_CMD_LENGTH, 1);
205 reg = spi_write_reg_field(reg, SPFI_ADDR_LENGTH,
206 first->size - 1);
207 reg = spi_write_reg_field(reg, SPFI_DUMMY_LENGTH, 0);
208 /* Set data size (size of the second transfer) */
209 reg = spi_write_reg_field(reg, SPFI_TSIZE, second->size);
210 } else {
211 /* Set data size, in this case size of the 1st transfer */
212 reg = spi_write_reg_field(reg, SPFI_TSIZE, first->size);
213 }
214 return reg;
215}
216
217/* Sets up control register */
218static u32 control_reg_setup(struct spim_buffer *first,
219 struct spim_buffer *second)
220{
221 u32 reg;
222
223 /* Enable SPFI */
224 reg = SPFI_EN_MASK;
225 reg |= first->inter_byte_delay ? SPIM_BYTE_DELAY_MASK : 0;
226
227 /* Set up the transfer mode */
228 reg = spi_write_reg_field(reg, SPFI_TRNSFR_MODE_DQ, SPIM_CMD_MODE_0);
229 reg = spi_write_reg_field(reg, SPFI_TRNSFR_MODE, SPIM_DMODE_SINGLE);
Ionela Voinescu1c0d0c02015-01-19 01:05:16 +0000230 reg = spi_write_reg_field(reg, SPIM_EDGE_TX_RX, 1);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100231
232 if (second) {
233 /* Set TX bit if the 2nd transaction is 'send' */
234 reg = spi_write_reg_field(reg, SPFI_TX_RX,
235 second->isread ? 0 : 1);
236 /*
237 * Set send/get DMA for both transactions
238 * (first is always 'send')
239 */
240 reg = spi_write_reg_field(reg, SPIM_SEND_DMA, 1);
241 if (second->isread)
242 reg = spi_write_reg_field(reg, SPIM_GET_DMA, 1);
243
244 } else {
245 /* Set TX bit if the 1st transaction is 'send' */
246 reg |= first->isread ? 0 : SPFI_TX_RX_MASK;
247 /* Set send/get DMA */
248 reg |= first->isread ? SPIM_GET_DMA_MASK : SPIM_SEND_DMA_MASK;
249 }
250 return reg;
251}
252
253/* Checks the given buffer information */
Furquan Shaikh0dba0252016-11-30 04:34:22 -0800254static int check_buffers(const struct spi_slave *slave, struct spim_buffer *first,
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100255 struct spim_buffer *second){
256
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800257 struct img_spi_slave *img_slave = get_img_slave(slave);
258
259 if (!(img_slave->initialised))
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100260 return -SPIM_API_NOT_INITIALISED;
261 /*
262 * First operation must always be defined
263 * It can be either a read or a write and its size cannot be bigge
264 * than SPIM_MAX_TANSFER_BYTES = 64KB - 1 (0xFFFF)
265 */
266 if (!first)
267 return -SPIM_INVALID_READ_WRITE;
268 if (first->size > SPIM_MAX_TRANSFER_BYTES)
269 return -SPIM_INVALID_SIZE;
270 if (first->isread > 1)
271 return -SPIM_INVALID_READ_WRITE;
272 /* Check operation parameters for 'second' */
273 if (second) {
274 /*
275 * If the second operation is defined it must be a read
276 * operation and its size must not be bigger than
277 * SPIM_MAX_TANSFER_BYTES = 64KB - 1 (0xFFFF)
278 */
279 if (second->size > SPIM_MAX_TRANSFER_BYTES)
280 return -SPIM_INVALID_SIZE;
281 if (!second->isread)
282 return -SPIM_INVALID_READ_WRITE;
283 /*
284 * If the second operations is defined, the first operation
285 * must be a write and its size cannot be bigger than
286 * SPIM_MAX_FLASH_COMMAND_BYTES(8): command size (1) +
287 * address size (7).
288 */
289 if (first->isread)
290 return -SPIM_INVALID_READ_WRITE;
291 if (first->size > SPIM_MAX_FLASH_COMMAND_BYTES)
292 return -SPIM_INVALID_SIZE;
293
294 }
295 return SPIM_OK;
296}
297
298/* Checks the set bitrate */
299static int check_bitrate(u32 rate)
300{
301 /* Bitrate must be 1, 2, 4, 8, 16, 32, 64, or 128 */
302 switch (rate) {
303 case 1:
304 case 2:
305 case 4:
306 case 8:
307 case 16:
308 case 32:
309 case 64:
310 case 128:
311 return SPIM_OK;
312 default:
313 return -SPIM_INVALID_BIT_RATE;
314 }
315 return -SPIM_INVALID_BIT_RATE;
316}
317
318/* Checks device parameters for errors */
319static int check_device_params(struct spim_device_parameters *pdev_param)
320{
321 if (pdev_param->spi_mode < SPIM_MODE_0 ||
322 pdev_param->spi_mode > SPIM_MODE_3)
323 return -SPIM_INVALID_SPI_MODE;
324 if (check_bitrate(pdev_param->bitrate) != SPIM_OK)
325 return -SPIM_INVALID_BIT_RATE;
326 if (pdev_param->cs_idle_level > 1)
327 return -SPIM_INVALID_CS_IDLE_LEVEL;
328 if (pdev_param->data_idle_level > 1)
329 return -SPIM_INVALID_DATA_IDLE_LEVEL;
330 return SPIM_OK;
331}
332
333/* Function that carries out read/write operations */
Furquan Shaikh0dba0252016-11-30 04:34:22 -0800334static int spim_io(const struct spi_slave *slave, struct spim_buffer *first,
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100335 struct spim_buffer *second)
336{
337 u32 reg, base;
338 int i, trans_count, ret;
339 struct spim_buffer *transaction[2];
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800340 struct img_spi_slave *img_slave = get_img_slave(slave);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100341
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800342 base = img_slave->base;
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100343
344 ret = check_buffers(slave, first, second);
345 if (ret)
346 return ret;
347
348 /*
349 * Soft reset peripheral internals, this will terminate any
350 * pending transactions
351 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200352 write32_x(base + SPFI_CONTROL_REG_OFFSET, SPIM_SOFT_RESET_MASK);
353 write32_x(base + SPFI_CONTROL_REG_OFFSET, 0);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100354 /* Port state register */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200355 reg = read32_x(base + SPFI_PORT_STATE_REG_OFFSET);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100356 reg = spi_write_reg_field(reg, SPFI_PORT_SELECT, slave->cs);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200357 write32_x(base + SPFI_PORT_STATE_REG_OFFSET, reg);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100358 /* Set transaction register */
359 reg = transaction_reg_setup(first, second);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200360 write32_x(base + SPFI_TRANSACTION_REG_OFFSET, reg);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100361 /* Clear status */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200362 write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, 0xffffffff);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100363 /* Set control register */
364 reg = control_reg_setup(first, second);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200365 write32_x(base + SPFI_CONTROL_REG_OFFSET, reg);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100366 /* First transaction always exists */
367 transaction[0] = first;
368 trans_count = 1;
369 /* Is there a second transaction? */
370 if (second) {
371 transaction[1] = second;
372 trans_count++;
373 }
374 /* Now write/read FIFO's */
375 for (i = 0; i < trans_count; i++)
376 /* Which transaction to execute, "Send" or "Get"? */
377 if (transaction[i]->isread) {
378 /* Get */
379 ret = receivedata(slave, transaction[i]->buffer,
380 transaction[i]->size);
381 if (ret) {
382 printk(BIOS_ERR,
383 "%s: Error: receive data failed.\n",
384 __func__);
385 return ret;
386 }
387 } else {
388 /* Send */
389 ret = transmitdata(slave, transaction[i]->buffer,
390 transaction[i]->size);
391 if (ret) {
392 printk(BIOS_ERR,
393 "%s: Error: transmit data failed.\n",
394 __func__);
395 return ret;
396 }
397 }
398
399 /* Wait for end of the transaction */
400 ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
401 SPFI_ALLDONE_SHIFT);
402 if (ret)
403 return ret;
404 /*
405 * Soft reset peripheral internals, this will terminate any
406 * pending transactions
407 */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200408 write32_x(base + SPFI_CONTROL_REG_OFFSET, SPIM_SOFT_RESET_MASK);
409 write32_x(base + SPFI_CONTROL_REG_OFFSET, 0);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100410
411 return SPIM_OK;
412}
413
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100414/* Claim the bus and prepare it for communication */
Furquan Shaikh94f86992016-12-01 07:12:32 -0800415static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -0700416{
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100417 int ret;
418 struct img_spi_slave *img_slave;
419
420 if (!slave) {
421 printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
422 __func__);
423 return -SPIM_API_NOT_INITIALISED;
424 }
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800425 img_slave = get_img_slave(slave);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100426 if (img_slave->initialised)
427 return SPIM_OK;
428 /* Check device parameters */
429 ret = check_device_params(&(img_slave->device_parameters));
430 if (ret) {
431 printk(BIOS_ERR, "%s: Error: incorrect device parameters.\n",
432 __func__);
433 return ret;
434 }
435 /* Set device parameters */
436 setparams(slave, slave->cs, &(img_slave->device_parameters));
437 /* Soft reset peripheral internals */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200438 write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET,
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100439 SPIM_SOFT_RESET_MASK);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200440 write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET, 0);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100441 img_slave->initialised = IMG_TRUE;
442 return SPIM_OK;
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -0700443}
444
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100445/* Release the SPI bus */
Furquan Shaikh94f86992016-12-01 07:12:32 -0800446static void spi_ctrlr_release_bus(const struct spi_slave *slave)
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -0700447{
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100448 struct img_spi_slave *img_slave;
449
450 if (!slave) {
451 printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
452 __func__);
453 return;
454 }
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800455 img_slave = get_img_slave(slave);
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100456 img_slave->initialised = IMG_FALSE;
457 /* Soft reset peripheral internals */
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200458 write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET,
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100459 SPIM_SOFT_RESET_MASK);
Kyösti Mälkkia9506db2019-03-20 20:30:02 +0200460 write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET, 0);
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -0700461}
462
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100463/* SPI transfer */
Furquan Shaikh0dba0252016-11-30 04:34:22 -0800464static int do_spi_xfer(const struct spi_slave *slave, const void *dout,
465 size_t bytesout, void *din, size_t bytesin)
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -0700466{
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100467 struct spim_buffer buff_0;
468 struct spim_buffer buff_1;
469
Ionela Voinescu49aad6b2014-09-09 20:18:55 +0100470 /* If we only have a read or a write operation
471 * the parameters for it will be put in the first buffer
472 */
473 buff_0.buffer = (dout) ? (void *)dout : (void *)din;
474 buff_0.size = (dout) ? bytesout : bytesin;
475 buff_0.isread = (dout) ? IMG_FALSE : IMG_TRUE;
476 buff_0.inter_byte_delay = 0;
477
478 if (dout && din) {
479 /* Set up the read buffer to receive our data */
480 buff_1.buffer = din;
481 buff_1.size = bytesin;
482 buff_1.isread = IMG_TRUE;
483 buff_1.inter_byte_delay = 0;
484 }
485 return spim_io(slave, &buff_0, (dout && din) ? &buff_1 : NULL);
Vadim Bendeburyb2e465d2014-08-29 16:34:46 -0700486}
Patrick Georgi85497972015-04-20 10:14:19 +0200487
Furquan Shaikh94f86992016-12-01 07:12:32 -0800488static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
Furquan Shaikhc2973d12016-11-29 22:07:42 -0800489 size_t bytesout, void *din, size_t bytesin)
Furquan Shaikhdc34fb62016-11-17 16:17:37 -0800490{
491 unsigned int in_sz, out_sz;
492 int ret;
493
494 if (!slave) {
495 printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
496 __func__);
497 return -SPIM_API_NOT_INITIALISED;
498 }
499 if (!dout && !din) {
500 printk(BIOS_ERR, "%s: Error: both buffers are NULL.\n",
501 __func__);
502 return -SPIM_INVALID_TRANSFER_DESC;
503 }
504
505 while (bytesin || bytesout) {
506 in_sz = min(IMGTEC_SPI_MAX_TRANSFER_SIZE, bytesin);
507 out_sz = min(IMGTEC_SPI_MAX_TRANSFER_SIZE, bytesout);
508
509 ret = do_spi_xfer(slave, dout, out_sz, din, in_sz);
510 if (ret)
511 return ret;
512
513 bytesin -= in_sz;
514 bytesout -= out_sz;
515
516 if (bytesin)
517 din += in_sz;
518 else
519 din = NULL;
520
521 if (bytesout)
522 dout += out_sz;
523 else
524 dout = NULL;
525 }
526
527 return SPIM_OK;
528}
529
Furquan Shaikhe173ee82017-05-18 11:10:20 -0700530static int spi_ctrlr_setup(const struct spi_slave *slave)
Furquan Shaikh94f86992016-12-01 07:12:32 -0800531{
532 struct img_spi_slave *img_slave = NULL;
533 struct spim_device_parameters *device_parameters;
534 u32 base;
535
Furquan Shaikhe173ee82017-05-18 11:10:20 -0700536 switch (slave->bus) {
Furquan Shaikh94f86992016-12-01 07:12:32 -0800537 case 0:
538 base = IMG_SPIM0_BASE_ADDRESS;
539 break;
540 case 1:
541 base = IMG_SPIM1_BASE_ADDRESS;
542 break;
543 default:
544 printk(BIOS_ERR, "%s: Error: unsupported bus.\n",
545 __func__);
546 return -1;
547 }
Furquan Shaikhe173ee82017-05-18 11:10:20 -0700548 if (slave->cs > SPIM_DEVICE4) {
Furquan Shaikh94f86992016-12-01 07:12:32 -0800549 printk(BIOS_ERR, "%s: Error: unsupported chipselect.\n",
550 __func__);
551 return -1;
552 }
553
Furquan Shaikh94f86992016-12-01 07:12:32 -0800554 img_slave = get_img_slave(slave);
555 device_parameters = &(img_slave->device_parameters);
556
557 img_slave->base = base;
558
559 device_parameters->bitrate = 64;
560 device_parameters->cs_setup = 0;
561 device_parameters->cs_hold = 0;
562 device_parameters->cs_delay = 0;
563 device_parameters->spi_mode = SPIM_MODE_0;
564 device_parameters->cs_idle_level = 1;
565 device_parameters->data_idle_level = 0;
566 img_slave->initialised = IMG_FALSE;
567
568 return 0;
569}
Furquan Shaikhe173ee82017-05-18 11:10:20 -0700570
571static const struct spi_ctrlr spi_ctrlr = {
572 .setup = spi_ctrlr_setup,
573 .claim_bus = spi_ctrlr_claim_bus,
574 .release_bus = spi_ctrlr_release_bus,
575 .xfer = spi_ctrlr_xfer,
Furquan Shaikhe173ee82017-05-18 11:10:20 -0700576 .max_xfer_size = IMGTEC_SPI_MAX_TRANSFER_SIZE,
577};
578
579const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
580 {
581 .ctrlr = &spi_ctrlr,
582 .bus_start = 0,
583 .bus_end = 1,
584 },
585};
586
587const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);