blob: ab8f53016f6573a4153af7f74424c0c073e91acd [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 Narayanana6935c22016-03-02 16:57:10 +0530301}
302
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530303/*
304 * Function to write data to OUTPUT FIFO
305 */
306static void spi_write_byte(struct ipq_spi_slave *ds, unsigned char data)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530307{
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530308 /* Wait for space in the FIFO */
309 while ((read32(ds->regs->qup_operational) & OUTPUT_FIFO_FULL))
310 udelay(1);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530311
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530312 /* Write the byte of data */
313 write32(ds->regs->qup_output_fifo, data);
314}
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530315
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530316/*
317 * Function to read data from Input FIFO
318 */
319static unsigned char spi_read_byte(struct ipq_spi_slave *ds)
320{
321 /* Wait for Data in FIFO */
322 while (!(read32(ds->regs->qup_operational) & INPUT_FIFO_NOT_EMPTY))
323 udelay(1);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530324
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530325 /* Read a byte of data */
326 return read32(ds->regs->qup_input_fifo) & 0xff;
327}
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530328
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530329/*
Martin Roth26f97f92021-10-01 14:53:22 -0600330 * Function to check whether Input or Output FIFO
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530331 * has data to be serviced
332 */
333static int check_fifo_status(void *reg_addr)
334{
335 unsigned int count = TIMEOUT_CNT;
336 unsigned int status_flag;
337 unsigned int val;
338
339 do {
340 val = read32(reg_addr);
341 count--;
342 if (count == 0)
343 return -ETIMEDOUT;
344 status_flag = ((val & OUTPUT_SERVICE_FLAG) |
345 (val & INPUT_SERVICE_FLAG));
346 } while (!status_flag);
347
348 return SUCCESS;
349}
350
351/*
352 * Function to configure Input and Output enable/disable
353 */
354static void enable_io_config(struct ipq_spi_slave *ds,
355 uint32_t write_cnt, uint32_t read_cnt)
356{
357
358 if (write_cnt) {
Julius Werner55009af2019-12-02 22:03:27 -0800359 clrsetbits32(ds->regs->qup_config,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530360 QUP_CONF_OUTPUT_MSK, QUP_CONF_OUTPUT_ENA);
361 } else {
Julius Werner55009af2019-12-02 22:03:27 -0800362 clrsetbits32(ds->regs->qup_config,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530363 QUP_CONF_OUTPUT_MSK, QUP_CONF_NO_OUTPUT);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530364 }
365
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530366 if (read_cnt) {
Julius Werner55009af2019-12-02 22:03:27 -0800367 clrsetbits32(ds->regs->qup_config,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530368 QUP_CONF_INPUT_MSK, QUP_CONF_INPUT_ENA);
369 } else {
Julius Werner55009af2019-12-02 22:03:27 -0800370 clrsetbits32(ds->regs->qup_config,
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530371 QUP_CONF_INPUT_MSK, QUP_CONF_NO_INPUT);
372 }
373
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530374}
375
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530376/*
377 * Function to read bytes number of data from the Input FIFO
378 */
379static int __blsp_spi_read(struct ipq_spi_slave *ds, u8 *data_buffer,
380 unsigned int bytes)
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530381{
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530382 uint32_t val;
383 unsigned int i;
384 unsigned int fifo_count;
385 int ret = SUCCESS;
386 int state_config;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530387
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530388 /* Configure no of bytes to read */
389 state_config = config_spi_state(ds, QUP_STATE_RESET);
390 if (state_config)
391 return state_config;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530392
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530393 /* Configure input and output enable */
394 enable_io_config(ds, 0, bytes);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530395
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530396 write32(ds->regs->qup_mx_input_count, bytes);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530397
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530398 state_config = config_spi_state(ds, QUP_STATE_RUN);
399 if (state_config)
400 return state_config;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530401
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530402 while (bytes) {
403 ret = check_fifo_status(ds->regs->qup_operational);
404 if (ret != SUCCESS)
405 goto out;
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530406
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530407 val = read32(ds->regs->qup_operational);
408 if (val & INPUT_SERVICE_FLAG) {
409 /*
410 * acknowledge to hw that software will
411 * read input data
412 */
413 val &= INPUT_SERVICE_FLAG;
414 write32(ds->regs->qup_operational, val);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530415
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530416 fifo_count = ((bytes > SPI_INPUT_BLOCK_SIZE) ?
417 SPI_INPUT_BLOCK_SIZE : bytes);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530418
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530419 for (i = 0; i < fifo_count; i++) {
420 *data_buffer = spi_read_byte(ds);
421 data_buffer++;
422 bytes--;
423 }
424 }
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530425 }
426
427out:
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530428 /*
429 * Put the SPI Core back in the Reset State
430 * to end the transfer
431 */
432 (void)config_spi_state(ds, QUP_STATE_RESET);
433 return ret;
434}
435
436static int blsp_spi_read(struct ipq_spi_slave *ds, u8 *data_buffer,
437 unsigned int bytes)
438{
439 int length, ret;
440
441 while (bytes) {
442 length = (bytes < MAX_COUNT_SIZE) ? bytes : MAX_COUNT_SIZE;
443
444 ret = __blsp_spi_read(ds, data_buffer, length);
445 if (ret != SUCCESS)
446 return ret;
447
448 data_buffer += length;
449 bytes -= length;
450 }
451
452 return 0;
453}
454
455/*
456 * Function to write data to the Output FIFO
457 */
458static int __blsp_spi_write(struct ipq_spi_slave *ds, const u8 *cmd_buffer,
459 unsigned int bytes)
460{
461 uint32_t val;
462 unsigned int i;
463 unsigned int write_len = bytes;
464 unsigned int read_len = bytes;
465 unsigned int fifo_count;
466 int ret = SUCCESS;
467 int state_config;
468
469 state_config = config_spi_state(ds, QUP_STATE_RESET);
470 if (state_config)
471 return state_config;
472
473 /* No of bytes to be written in Output FIFO */
474 write32(ds->regs->qup_mx_output_count, bytes);
475 write32(ds->regs->qup_mx_input_count, bytes);
476 state_config = config_spi_state(ds, QUP_STATE_RUN);
477 if (state_config)
478 return state_config;
479
480 /* Configure input and output enable */
481 enable_io_config(ds, write_len, read_len);
482
483 /*
484 * read_len considered to ensure that we read the dummy data for the
485 * write we performed. This is needed to ensure with WR-RD transaction
486 * to get the actual data on the subsequent read cycle that happens
487 */
488 while (write_len || read_len) {
489
490 ret = check_fifo_status(ds->regs->qup_operational);
491 if (ret != SUCCESS)
492 goto out;
493
494 val = read32(ds->regs->qup_operational);
495 if (val & OUTPUT_SERVICE_FLAG) {
496 /*
497 * acknowledge to hw that software will write
498 * expected output data
499 */
500 val &= OUTPUT_SERVICE_FLAG;
501 write32(ds->regs->qup_operational, val);
502
503 if (write_len > SPI_OUTPUT_BLOCK_SIZE)
504 fifo_count = SPI_OUTPUT_BLOCK_SIZE;
505 else
506 fifo_count = write_len;
507
508 for (i = 0; i < fifo_count; i++) {
509 /* Write actual data to output FIFO */
510 spi_write_byte(ds, *cmd_buffer);
511 cmd_buffer++;
512 write_len--;
513 }
514 }
515 if (val & INPUT_SERVICE_FLAG) {
516 /*
517 * acknowledge to hw that software
518 * will read input data
519 */
520 val &= INPUT_SERVICE_FLAG;
521 write32(ds->regs->qup_operational, val);
522
523 if (read_len > SPI_INPUT_BLOCK_SIZE)
524 fifo_count = SPI_INPUT_BLOCK_SIZE;
525 else
526 fifo_count = read_len;
527
528 for (i = 0; i < fifo_count; i++) {
529 /* Read dummy data for the data written */
530 (void)spi_read_byte(ds);
531
532 /* Decrement the read count after reading the
533 * dummy data from the device. This is to make
534 * sure we read dummy data before we write the
535 * data to fifo
536 */
537 read_len--;
538 }
539 }
540 }
541
542out:
543 /*
544 * Put the SPI Core back in the Reset State
545 * to end the transfer
546 */
547 (void)config_spi_state(ds, QUP_STATE_RESET);
548
549 return ret;
550}
551
552static int blsp_spi_write(struct ipq_spi_slave *ds, u8 *cmd_buffer,
553 unsigned int bytes)
554{
555 int length, ret;
556
557 while (bytes) {
558 length = (bytes < MAX_COUNT_SIZE) ? bytes : MAX_COUNT_SIZE;
559
560 ret = __blsp_spi_write(ds, cmd_buffer, length);
561 if (ret != SUCCESS)
562 return ret;
563
564 cmd_buffer += length;
565 bytes -= length;
566 }
567
568 return 0;
569}
570
571/*
572 * This function is invoked with either tx_buf or rx_buf.
573 * Calling this function with both null does a chip select change.
574 */
Furquan Shaikh94f86992016-12-01 07:12:32 -0800575static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
576 size_t out_bytes, void *din, size_t in_bytes)
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530577{
578 struct ipq_spi_slave *ds = to_ipq_spi(slave);
579 u8 *txp = (u8 *)dout;
580 u8 *rxp = (u8 *)din;
581 int ret;
582
Aaron Durbin9a1bb362018-04-19 16:58:13 -0600583 /* Driver implementation does not support full duplex. */
584 if (dout && din)
585 return -1;
586
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530587 ret = config_spi_state(ds, QUP_STATE_RESET);
588 if (ret != SUCCESS)
589 return ret;
590
591 write_force_cs(slave, 1);
592
593 if (dout != NULL) {
Elyes Haouas97767382022-11-18 15:08:13 +0100594 ret = blsp_spi_write(ds, txp, (unsigned int)out_bytes);
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530595 if (ret != SUCCESS)
596 goto out;
597 }
598
599 if (din != NULL) {
600 ret = blsp_spi_read(ds, rxp, in_bytes);
601 if (ret != SUCCESS)
602 goto out;
603 }
604
605out:
606 write_force_cs(slave, 0);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530607
608 /*
609 * Put the SPI Core back in the Reset State
610 * to end the transfer
611 */
Varadarajan Narayanan25967642016-03-08 15:02:56 +0530612 (void)config_spi_state(ds, QUP_STATE_RESET);
Varadarajan Narayanana6935c22016-03-02 16:57:10 +0530613
614 return ret;
615}
Furquan Shaikh94f86992016-12-01 07:12:32 -0800616
Furquan Shaikhe424a592017-05-18 14:40:58 -0700617static int spi_ctrlr_setup(const struct spi_slave *slave)
Furquan Shaikh94f86992016-12-01 07:12:32 -0800618{
619 struct ipq_spi_slave *ds = NULL;
620 int i;
Julius Werner7c712bb2019-05-01 16:51:20 -0700621 int bus = slave->bus;
622 int cs = slave->cs;
Furquan Shaikh94f86992016-12-01 07:12:32 -0800623
624 if ((bus < BLSP0_SPI) || (bus > BLSP1_SPI)
625 || ((bus == BLSP0_SPI) && (cs > 2))
626 || ((bus == BLSP1_SPI) && (cs > 0))) {
627 printk(BIOS_ERR,
Martin Roth26f97f92021-10-01 14:53:22 -0600628 "SPI error: unsupported bus %d (Supported buses 0, 1 and 2) "
Elyes HAOUAS88607a42018-10-05 10:36:45 +0200629 "or chipselect\n", bus);
Furquan Shaikh94f86992016-12-01 07:12:32 -0800630 return -1;
631 }
632
633 for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) {
634 if (spi_slave_pool[i].allocated)
635 continue;
636 ds = spi_slave_pool + i;
637
Furquan Shaikhe424a592017-05-18 14:40:58 -0700638 ds->slave.bus = bus;
639 ds->slave.cs = cs;
Furquan Shaikh94f86992016-12-01 07:12:32 -0800640 ds->regs = &spi_reg[bus];
641
642 /*
643 * TODO(vbendeb):
644 * hardcoded frequency and mode - we might need to find a way
645 * to configure this
646 */
647 ds->freq = 10000000;
648 ds->mode = SPI_MODE3;
649 ds->allocated = 1;
650
651 return 0;
652 }
653
654 printk(BIOS_ERR, "SPI error: all %d pools busy\n", i);
655 return -1;
656}
Furquan Shaikhe424a592017-05-18 14:40:58 -0700657
658static const struct spi_ctrlr spi_ctrlr = {
659 .setup = spi_ctrlr_setup,
660 .claim_bus = spi_ctrlr_claim_bus,
661 .release_bus = spi_ctrlr_release_bus,
662 .xfer = spi_ctrlr_xfer,
Furquan Shaikhe424a592017-05-18 14:40:58 -0700663 .max_xfer_size = MAX_PACKET_COUNT,
664};
665
666const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
667 {
668 .ctrlr = &spi_ctrlr,
669 .bus_start = BLSP0_SPI,
670 .bus_end = BLSP1_SPI,
671 },
672};
673
674const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);