blob: da7a6d3560826e2f5d3cec7af483febc44f84aa8 [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>
Furquan Shaikhc28984d2016-11-20 21:04:00 -08004#include <console/console.h>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +05305#include <delay.h>
6#include <gpio.h>
7#include <soc/iomap.h>
8#include <soc/spi.h>
Varadarajan Narayanana6935c22016-03-02 16:57:10 +05309
Varadarajan Narayanan25967642016-03-08 15:02:56 +053010static const struct blsp_spi spi_reg[] = {
11 /* BLSP0 registers for SPI interface */
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053012 {
Varadarajan Narayanan25967642016-03-08 15:02:56 +053013 BLSP0_SPI_CONFIG_REG,
14 BLSP0_SPI_IO_CONTROL_REG,
15 BLSP0_SPI_ERROR_FLAGS_REG,
16 BLSP0_SPI_ERROR_FLAGS_EN_REG,
17 BLSP0_QUP_CONFIG_REG,
18 BLSP0_QUP_ERROR_FLAGS_REG,
19 BLSP0_QUP_ERROR_FLAGS_EN_REG,
20 BLSP0_QUP_OPERATIONAL_REG,
21 BLSP0_QUP_IO_MODES_REG,
22 BLSP0_QUP_STATE_REG,
23 BLSP0_QUP_INPUT_FIFOc_REG(0),
24 BLSP0_QUP_OUTPUT_FIFOc_REG(0),
25 BLSP0_QUP_MX_INPUT_COUNT_REG,
26 BLSP0_QUP_MX_OUTPUT_COUNT_REG,
27 BLSP0_QUP_SW_RESET_REG,
28 0,
29 0,
30 BLSP0_QUP_OPERATIONAL_MASK,
31 BLSP0_SPI_DEASSERT_WAIT_REG,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053032 },
Varadarajan Narayanan25967642016-03-08 15:02:56 +053033 /* BLSP1 registers for SPI interface */
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053034 {
Varadarajan Narayanan25967642016-03-08 15:02:56 +053035 BLSP1_SPI_CONFIG_REG,
36 BLSP1_SPI_IO_CONTROL_REG,
37 BLSP1_SPI_ERROR_FLAGS_REG,
38 BLSP1_SPI_ERROR_FLAGS_EN_REG,
39 BLSP1_QUP_CONFIG_REG,
40 BLSP1_QUP_ERROR_FLAGS_REG,
41 BLSP1_QUP_ERROR_FLAGS_EN_REG,
42 BLSP1_QUP_OPERATIONAL_REG,
43 BLSP1_QUP_IO_MODES_REG,
44 BLSP1_QUP_STATE_REG,
45 BLSP1_QUP_INPUT_FIFOc_REG(0),
46 BLSP1_QUP_OUTPUT_FIFOc_REG(0),
47 BLSP1_QUP_MX_INPUT_COUNT_REG,
48 BLSP1_QUP_MX_OUTPUT_COUNT_REG,
49 BLSP1_QUP_SW_RESET_REG,
50 0,
51 0,
52 BLSP1_QUP_OPERATIONAL_MASK,
53 BLSP1_SPI_DEASSERT_WAIT_REG,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053054 },
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053055};
56
Varadarajan Narayanan25967642016-03-08 15:02:56 +053057static int check_bit_state(void *reg_addr, int mask,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053058 int val, int us_delay)
59{
60 unsigned int count = TIMEOUT_CNT;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053061
Varadarajan Narayanan25967642016-03-08 15:02:56 +053062 while ((read32(reg_addr) & mask) != val) {
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053063 count--;
64 if (count == 0)
65 return -ETIMEDOUT;
66 udelay(us_delay);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053067 }
68
69 return SUCCESS;
70}
71
72/*
Varadarajan Narayanan25967642016-03-08 15:02:56 +053073 * Check whether QUPn State is valid
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053074 */
75static int check_qup_state_valid(struct ipq_spi_slave *ds)
76{
77
Varadarajan Narayanan25967642016-03-08 15:02:56 +053078 return check_bit_state(ds->regs->qup_state, QUP_STATE_VALID_MASK,
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053079 QUP_STATE_VALID, 1);
80
81}
82
83/*
Varadarajan Narayanan25967642016-03-08 15:02:56 +053084 * Configure QUPn Core state
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053085 */
86static int config_spi_state(struct ipq_spi_slave *ds, unsigned int state)
87{
88 uint32_t val;
Varadarajan Narayanan25967642016-03-08 15:02:56 +053089 int ret = SUCCESS;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +053090
91 ret = check_qup_state_valid(ds);
92 if (ret != SUCCESS)
93 return ret;
94
95 switch (state) {
Varadarajan Narayanan25967642016-03-08 15:02:56 +053096 case QUP_STATE_RUN:
97 /* Set the state to RUN */
98 val = ((read32(ds->regs->qup_state) & ~QUP_STATE_MASK)
99 | QUP_STATE_RUN);
100 write32(ds->regs->qup_state, val);
101 ret = check_qup_state_valid(ds);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530102 break;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530103 case QUP_STATE_RESET:
104 /* Set the state to RESET */
105 val = ((read32(ds->regs->qup_state) & ~QUP_STATE_MASK)
106 | QUP_STATE_RESET);
107 write32(ds->regs->qup_state, val);
108 ret = check_qup_state_valid(ds);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530109 break;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530110 default:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530111 printk(BIOS_ERR, "unsupported QUP SPI state : %d\n", state);
112 ret = -EINVAL;
113 break;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530114 }
115
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530116 return ret;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530117}
118
119/*
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530120 * Set QUPn SPI Mode
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530121 */
122static void spi_set_mode(struct ipq_spi_slave *ds, unsigned int mode)
123{
124 unsigned int clk_idle_state;
125 unsigned int input_first_mode;
126 uint32_t val;
127
128 switch (mode) {
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530129 case SPI_MODE0:
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530130 clk_idle_state = 0;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530131 input_first_mode = SPI_CONFIG_INPUT_FIRST;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530132 break;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530133 case SPI_MODE1:
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530134 clk_idle_state = 0;
135 input_first_mode = 0;
136 break;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530137 case SPI_MODE2:
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530138 clk_idle_state = 1;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530139 input_first_mode = SPI_CONFIG_INPUT_FIRST;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530140 break;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530141 case SPI_MODE3:
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530142 clk_idle_state = 1;
143 input_first_mode = 0;
144 break;
145 default:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530146 printk(BIOS_ERR, "unsupported spi mode : %d\n", mode);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530147 return;
148 }
149
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530150 val = read32(ds->regs->spi_config);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530151 val |= input_first_mode;
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530152 write32(ds->regs->spi_config, val);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530153
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530154 val = read32(ds->regs->io_control);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530155 if (clk_idle_state)
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530156 val |= SPI_IO_CTRL_CLOCK_IDLE_HIGH;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530157 else
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530158 val &= ~SPI_IO_CTRL_CLOCK_IDLE_HIGH;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530159
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530160 write32(ds->regs->io_control, val);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530161}
162
163/*
164 * Reset entire QUP and all mini cores
165 */
166static void spi_reset(struct ipq_spi_slave *ds)
167{
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530168 write32(ds->regs->qup_sw_reset, 0x1);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530169 udelay(5);
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530170 check_qup_state_valid(ds);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530171}
172
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530173static struct ipq_spi_slave spi_slave_pool[2];
174
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800175static struct ipq_spi_slave *to_ipq_spi(const struct spi_slave *slave)
176{
177 struct ipq_spi_slave *ds;
178 size_t i;
179
180 for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) {
181 ds = spi_slave_pool + i;
182
183 if (!ds->allocated)
184 continue;
185
186 if ((ds->slave.bus == slave->bus) &&
187 (ds->slave.cs == slave->cs))
188 return ds;
189 }
190
191 return NULL;
192}
193
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530194/*
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530195 * BLSP QUPn SPI Hardware Initialisation
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530196 */
197static int spi_hw_init(struct ipq_spi_slave *ds)
198{
199 int ret;
200
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530201 ds->initialized = 0;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530202
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530203 /* QUPn module configuration */
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530204 spi_reset(ds);
205
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530206 /* Set the QUPn state */
207 ret = config_spi_state(ds, QUP_STATE_RESET);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530208 if (ret)
209 return ret;
210
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530211 /*
212 * Configure Mini core to SPI core with Input Output enabled,
213 * SPI master, N = 8 bits
214 */
Julius Werner55009af2019-12-02 22:03:27 -0800215 clrsetbits32(ds->regs->qup_config, QUP_CONFIG_MINI_CORE_MSK |
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530216 QUP_CONF_INPUT_MSK |
217 QUP_CONF_OUTPUT_MSK |
218 QUP_CONF_N_MASK,
219 QUP_CONFIG_MINI_CORE_SPI |
220 QUP_CONF_INPUT_ENA |
221 QUP_CONF_OUTPUT_ENA |
222 QUP_CONF_N_SPI_8_BIT_WORD);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530223
224 /*
225 * Configure Input first SPI protocol,
226 * SPI master mode and no loopback
227 */
Julius Werner55009af2019-12-02 22:03:27 -0800228 clrsetbits32(ds->regs->spi_config, SPI_CONFIG_LOOP_BACK_MSK |
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530229 SPI_CONFIG_NO_SLAVE_OPER_MSK,
230 SPI_CONFIG_NO_LOOP_BACK |
231 SPI_CONFIG_NO_SLAVE_OPER);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530232
233 /*
234 * Configure SPI IO Control Register
235 * CLK_ALWAYS_ON = 0
236 * MX_CS_MODE = 0
237 * NO_TRI_STATE = 1
238 */
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530239 write32(ds->regs->io_control, SPI_IO_CTRL_CLK_ALWAYS_ON |
240 SPI_IO_CTRL_NO_TRI_STATE);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530241
242 /*
243 * Configure SPI IO Modes.
244 * OUTPUT_BIT_SHIFT_EN = 1
245 * INPUT_MODE = Block Mode
246 * OUTPUT MODE = Block Mode
247 */
Julius Werner55009af2019-12-02 22:03:27 -0800248 clrsetbits32(ds->regs->qup_io_modes,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530249 QUP_IO_MODES_OUTPUT_BIT_SHIFT_MSK |
250 QUP_IO_MODES_INPUT_MODE_MSK |
251 QUP_IO_MODES_OUTPUT_MODE_MSK,
252 QUP_IO_MODES_OUTPUT_BIT_SHIFT_EN |
253 QUP_IO_MODES_INPUT_BLOCK_MODE |
254 QUP_IO_MODES_OUTPUT_BLOCK_MODE);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530255
256 spi_set_mode(ds, ds->mode);
257
258 /* Disable Error mask */
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530259 write32(ds->regs->error_flags_en, 0);
260 write32(ds->regs->qup_error_flags_en, 0);
261
262 write32(ds->regs->qup_deassert_wait, 0);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530263
264 ds->initialized = 1;
265
266 return SUCCESS;
267}
268
Furquan Shaikh94f86992016-12-01 07:12:32 -0800269static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530270{
271 struct ipq_spi_slave *ds = to_ipq_spi(slave);
272 unsigned int ret;
273
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530274 ret = spi_hw_init(ds);
275 if (ret)
276 return -EIO;
277
278 return SUCCESS;
279}
280
Furquan Shaikh94f86992016-12-01 07:12:32 -0800281static void spi_ctrlr_release_bus(const struct spi_slave *slave)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530282{
283 struct ipq_spi_slave *ds = to_ipq_spi(slave);
284
285 /* Reset the SPI hardware */
286 spi_reset(ds);
287 ds->initialized = 0;
288}
289
Furquan Shaikh0dba0252016-11-30 04:34:22 -0800290static void write_force_cs(const struct spi_slave *slave, int assert)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530291{
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530292 struct ipq_spi_slave *ds = to_ipq_spi(slave);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530293
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530294 if (assert)
Julius Werner55009af2019-12-02 22:03:27 -0800295 clrsetbits32(ds->regs->io_control,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530296 SPI_IO_CTRL_FORCE_CS_MSK, SPI_IO_CTRL_FORCE_CS_EN);
297 else
Julius Werner55009af2019-12-02 22:03:27 -0800298 clrsetbits32(ds->regs->io_control,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530299 SPI_IO_CTRL_FORCE_CS_MSK, SPI_IO_CTRL_FORCE_CS_DIS);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530300
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530301 return;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530302}
303
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530304/*
305 * Function to write data to OUTPUT FIFO
306 */
307static void spi_write_byte(struct ipq_spi_slave *ds, unsigned char data)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530308{
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530309 /* Wait for space in the FIFO */
310 while ((read32(ds->regs->qup_operational) & OUTPUT_FIFO_FULL))
311 udelay(1);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530312
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530313 /* Write the byte of data */
314 write32(ds->regs->qup_output_fifo, data);
315}
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530316
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530317/*
318 * Function to read data from Input FIFO
319 */
320static unsigned char spi_read_byte(struct ipq_spi_slave *ds)
321{
322 /* Wait for Data in FIFO */
323 while (!(read32(ds->regs->qup_operational) & INPUT_FIFO_NOT_EMPTY))
324 udelay(1);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530325
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530326 /* Read a byte of data */
327 return read32(ds->regs->qup_input_fifo) & 0xff;
328}
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530329
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530330/*
331 * Function to check wheather Input or Output FIFO
332 * has data to be serviced
333 */
334static int check_fifo_status(void *reg_addr)
335{
336 unsigned int count = TIMEOUT_CNT;
337 unsigned int status_flag;
338 unsigned int val;
339
340 do {
341 val = read32(reg_addr);
342 count--;
343 if (count == 0)
344 return -ETIMEDOUT;
345 status_flag = ((val & OUTPUT_SERVICE_FLAG) |
346 (val & INPUT_SERVICE_FLAG));
347 } while (!status_flag);
348
349 return SUCCESS;
350}
351
352/*
353 * Function to configure Input and Output enable/disable
354 */
355static void enable_io_config(struct ipq_spi_slave *ds,
356 uint32_t write_cnt, uint32_t read_cnt)
357{
358
359 if (write_cnt) {
Julius Werner55009af2019-12-02 22:03:27 -0800360 clrsetbits32(ds->regs->qup_config,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530361 QUP_CONF_OUTPUT_MSK, QUP_CONF_OUTPUT_ENA);
362 } else {
Julius Werner55009af2019-12-02 22:03:27 -0800363 clrsetbits32(ds->regs->qup_config,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530364 QUP_CONF_OUTPUT_MSK, QUP_CONF_NO_OUTPUT);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530365 }
366
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530367 if (read_cnt) {
Julius Werner55009af2019-12-02 22:03:27 -0800368 clrsetbits32(ds->regs->qup_config,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530369 QUP_CONF_INPUT_MSK, QUP_CONF_INPUT_ENA);
370 } else {
Julius Werner55009af2019-12-02 22:03:27 -0800371 clrsetbits32(ds->regs->qup_config,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530372 QUP_CONF_INPUT_MSK, QUP_CONF_NO_INPUT);
373 }
374
375 return;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530376}
377
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530378/*
379 * Function to read bytes number of data from the Input FIFO
380 */
381static int __blsp_spi_read(struct ipq_spi_slave *ds, u8 *data_buffer,
382 unsigned int bytes)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530383{
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530384 uint32_t val;
385 unsigned int i;
386 unsigned int fifo_count;
387 int ret = SUCCESS;
388 int state_config;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530389
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530390 /* Configure no of bytes to read */
391 state_config = config_spi_state(ds, QUP_STATE_RESET);
392 if (state_config)
393 return state_config;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530394
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530395 /* Configure input and output enable */
396 enable_io_config(ds, 0, bytes);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530397
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530398 write32(ds->regs->qup_mx_input_count, bytes);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530399
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530400 state_config = config_spi_state(ds, QUP_STATE_RUN);
401 if (state_config)
402 return state_config;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530403
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530404 while (bytes) {
405 ret = check_fifo_status(ds->regs->qup_operational);
406 if (ret != SUCCESS)
407 goto out;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530408
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530409 val = read32(ds->regs->qup_operational);
410 if (val & INPUT_SERVICE_FLAG) {
411 /*
412 * acknowledge to hw that software will
413 * read input data
414 */
415 val &= INPUT_SERVICE_FLAG;
416 write32(ds->regs->qup_operational, val);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530417
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530418 fifo_count = ((bytes > SPI_INPUT_BLOCK_SIZE) ?
419 SPI_INPUT_BLOCK_SIZE : bytes);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530420
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530421 for (i = 0; i < fifo_count; i++) {
422 *data_buffer = spi_read_byte(ds);
423 data_buffer++;
424 bytes--;
425 }
426 }
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530427 }
428
429out:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530430 /*
431 * Put the SPI Core back in the Reset State
432 * to end the transfer
433 */
434 (void)config_spi_state(ds, QUP_STATE_RESET);
435 return ret;
436}
437
438static int blsp_spi_read(struct ipq_spi_slave *ds, u8 *data_buffer,
439 unsigned int bytes)
440{
441 int length, ret;
442
443 while (bytes) {
444 length = (bytes < MAX_COUNT_SIZE) ? bytes : MAX_COUNT_SIZE;
445
446 ret = __blsp_spi_read(ds, data_buffer, length);
447 if (ret != SUCCESS)
448 return ret;
449
450 data_buffer += length;
451 bytes -= length;
452 }
453
454 return 0;
455}
456
457/*
458 * Function to write data to the Output FIFO
459 */
460static int __blsp_spi_write(struct ipq_spi_slave *ds, const u8 *cmd_buffer,
461 unsigned int bytes)
462{
463 uint32_t val;
464 unsigned int i;
465 unsigned int write_len = bytes;
466 unsigned int read_len = bytes;
467 unsigned int fifo_count;
468 int ret = SUCCESS;
469 int state_config;
470
471 state_config = config_spi_state(ds, QUP_STATE_RESET);
472 if (state_config)
473 return state_config;
474
475 /* No of bytes to be written in Output FIFO */
476 write32(ds->regs->qup_mx_output_count, bytes);
477 write32(ds->regs->qup_mx_input_count, bytes);
478 state_config = config_spi_state(ds, QUP_STATE_RUN);
479 if (state_config)
480 return state_config;
481
482 /* Configure input and output enable */
483 enable_io_config(ds, write_len, read_len);
484
485 /*
486 * read_len considered to ensure that we read the dummy data for the
487 * write we performed. This is needed to ensure with WR-RD transaction
488 * to get the actual data on the subsequent read cycle that happens
489 */
490 while (write_len || read_len) {
491
492 ret = check_fifo_status(ds->regs->qup_operational);
493 if (ret != SUCCESS)
494 goto out;
495
496 val = read32(ds->regs->qup_operational);
497 if (val & OUTPUT_SERVICE_FLAG) {
498 /*
499 * acknowledge to hw that software will write
500 * expected output data
501 */
502 val &= OUTPUT_SERVICE_FLAG;
503 write32(ds->regs->qup_operational, val);
504
505 if (write_len > SPI_OUTPUT_BLOCK_SIZE)
506 fifo_count = SPI_OUTPUT_BLOCK_SIZE;
507 else
508 fifo_count = write_len;
509
510 for (i = 0; i < fifo_count; i++) {
511 /* Write actual data to output FIFO */
512 spi_write_byte(ds, *cmd_buffer);
513 cmd_buffer++;
514 write_len--;
515 }
516 }
517 if (val & INPUT_SERVICE_FLAG) {
518 /*
519 * acknowledge to hw that software
520 * will read input data
521 */
522 val &= INPUT_SERVICE_FLAG;
523 write32(ds->regs->qup_operational, val);
524
525 if (read_len > SPI_INPUT_BLOCK_SIZE)
526 fifo_count = SPI_INPUT_BLOCK_SIZE;
527 else
528 fifo_count = read_len;
529
530 for (i = 0; i < fifo_count; i++) {
531 /* Read dummy data for the data written */
532 (void)spi_read_byte(ds);
533
534 /* Decrement the read count after reading the
535 * dummy data from the device. This is to make
536 * sure we read dummy data before we write the
537 * data to fifo
538 */
539 read_len--;
540 }
541 }
542 }
543
544out:
545 /*
546 * Put the SPI Core back in the Reset State
547 * to end the transfer
548 */
549 (void)config_spi_state(ds, QUP_STATE_RESET);
550
551 return ret;
552}
553
554static int blsp_spi_write(struct ipq_spi_slave *ds, u8 *cmd_buffer,
555 unsigned int bytes)
556{
557 int length, ret;
558
559 while (bytes) {
560 length = (bytes < MAX_COUNT_SIZE) ? bytes : MAX_COUNT_SIZE;
561
562 ret = __blsp_spi_write(ds, cmd_buffer, length);
563 if (ret != SUCCESS)
564 return ret;
565
566 cmd_buffer += length;
567 bytes -= length;
568 }
569
570 return 0;
571}
572
573/*
574 * This function is invoked with either tx_buf or rx_buf.
575 * Calling this function with both null does a chip select change.
576 */
Furquan Shaikh94f86992016-12-01 07:12:32 -0800577static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
578 size_t out_bytes, void *din, size_t in_bytes)
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530579{
580 struct ipq_spi_slave *ds = to_ipq_spi(slave);
581 u8 *txp = (u8 *)dout;
582 u8 *rxp = (u8 *)din;
583 int ret;
584
Aaron Durbin9a1bb362018-04-19 16:58:13 -0600585 /* Driver implementation does not support full duplex. */
586 if (dout && din)
587 return -1;
588
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530589 ret = config_spi_state(ds, QUP_STATE_RESET);
590 if (ret != SUCCESS)
591 return ret;
592
593 write_force_cs(slave, 1);
594
595 if (dout != NULL) {
596 ret = blsp_spi_write(ds, txp, (unsigned int) out_bytes);
597 if (ret != SUCCESS)
598 goto out;
599 }
600
601 if (din != NULL) {
602 ret = blsp_spi_read(ds, rxp, in_bytes);
603 if (ret != SUCCESS)
604 goto out;
605 }
606
607out:
608 write_force_cs(slave, 0);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530609
610 /*
611 * Put the SPI Core back in the Reset State
612 * to end the transfer
613 */
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530614 (void)config_spi_state(ds, QUP_STATE_RESET);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530615
616 return ret;
617}
Furquan Shaikh94f86992016-12-01 07:12:32 -0800618
Furquan Shaikhe424a592017-05-18 14:40:58 -0700619static int spi_ctrlr_setup(const struct spi_slave *slave)
Furquan Shaikh94f86992016-12-01 07:12:32 -0800620{
621 struct ipq_spi_slave *ds = NULL;
622 int i;
Julius Werner7c712bb2019-05-01 16:51:20 -0700623 int bus = slave->bus;
624 int cs = slave->cs;
Furquan Shaikh94f86992016-12-01 07:12:32 -0800625
626 if ((bus < BLSP0_SPI) || (bus > BLSP1_SPI)
627 || ((bus == BLSP0_SPI) && (cs > 2))
628 || ((bus == BLSP1_SPI) && (cs > 0))) {
629 printk(BIOS_ERR,
630 "SPI error: unsupported bus %d (Supported busses 0, 1 and 2) "
Elyes HAOUAS88607a42018-10-05 10:36:45 +0200631 "or chipselect\n", bus);
Furquan Shaikh94f86992016-12-01 07:12:32 -0800632 return -1;
633 }
634
635 for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) {
636 if (spi_slave_pool[i].allocated)
637 continue;
638 ds = spi_slave_pool + i;
639
Furquan Shaikhe424a592017-05-18 14:40:58 -0700640 ds->slave.bus = bus;
641 ds->slave.cs = cs;
Furquan Shaikh94f86992016-12-01 07:12:32 -0800642 ds->regs = &spi_reg[bus];
643
644 /*
645 * TODO(vbendeb):
646 * hardcoded frequency and mode - we might need to find a way
647 * to configure this
648 */
649 ds->freq = 10000000;
650 ds->mode = SPI_MODE3;
651 ds->allocated = 1;
652
653 return 0;
654 }
655
656 printk(BIOS_ERR, "SPI error: all %d pools busy\n", i);
657 return -1;
658}
Furquan Shaikhe424a592017-05-18 14:40:58 -0700659
660static const struct spi_ctrlr spi_ctrlr = {
661 .setup = spi_ctrlr_setup,
662 .claim_bus = spi_ctrlr_claim_bus,
663 .release_bus = spi_ctrlr_release_bus,
664 .xfer = spi_ctrlr_xfer,
Furquan Shaikhe424a592017-05-18 14:40:58 -0700665 .max_xfer_size = MAX_PACKET_COUNT,
666};
667
668const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
669 {
670 .ctrlr = &spi_ctrlr,
671 .bus_start = BLSP0_SPI,
672 .bus_end = BLSP1_SPI,
673 },
674};
675
676const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);