blob: dd478c4020efb0b83c332ab47870832329dfba3d [file] [log] [blame]
Angel Pons7c1d70e2020-04-04 18:51:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Vadim Bendebury3afa03e2014-04-10 14:20:39 -07002
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>
Vadim Bendeburydffd8922014-04-30 13:25:12 -07005#include <delay.h>
Julius Wernereaa9c452014-09-24 15:40:49 -07006#include <gpio.h>
Julius Werner73d1ed62014-10-20 13:20:49 -07007#include <soc/iomap.h>
8#include <soc/spi.h>
Elyes HAOUAS17b1a162019-06-23 07:08:12 +02009#include <types.h>
Vadim Bendebury3afa03e2014-04-10 14:20:39 -070010
11#define SUCCESS 0
12
13#define DUMMY_DATA_VAL 0
14#define TIMEOUT_CNT 100
15#define CS_ASSERT 1
16#define CS_DEASSERT 0
17#define NUM_PORTS 3
18#define NUM_GSBI_PINS 3
19#define TLMM_ARGS 6
20#define NUM_CS 4
21#define GSBI_PIN_IDX 0
22#define FUNC_SEL_IDX 1
23#define GPIO_DIR_IDX 2
24#define PULL_CONF_IDX 3
25#define DRV_STR_IDX 4
26#define GPIO_EN_IDX 5
27
Vadim Bendeburydffd8922014-04-30 13:25:12 -070028/* Arbitrarily assigned error code values */
29#define ETIMEDOUT -10
30#define EINVAL -11
31#define EIO -12
32
Vadim Bendebury3afa03e2014-04-10 14:20:39 -070033#define GSBI_IDX_TO_GSBI(idx) (idx + 5)
34
David Hendricks68ec2fc2014-07-25 12:59:48 -070035/* MX_INPUT_COUNT and MX_OUTPUT_COUNT are 16-bits. Zero has a special meaning
36 * (count function disabled) and does not hold significance in the count. */
37#define MAX_PACKET_COUNT ((64 * KiB) - 1)
38
Vadim Bendebury3afa03e2014-04-10 14:20:39 -070039/*
40 * TLMM Configuration for SPI NOR
41 * gsbi_pin_conf[bus_num][GPIO_NUM, FUNC_SEL, I/O,
42 * PULL UP/DOWN, DRV_STR, GPIO_FUNC]
43 * gsbi_pin_conf[0][x][y] -- GSBI5
44 * gsbi_pin_conf[1][x][y] -- GSBI6
45 * gsbi_pin_conf[2][x][y] -- GSBI7
46*/
47static unsigned int gsbi_pin_conf[NUM_PORTS][NUM_GSBI_PINS][TLMM_ARGS] = {
48 {
49 /* GSBI5 CLK */
50 {
51 GSBI5_SPI_CLK, FUNC_SEL_1, GPIO_INPUT,
52 GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE
53 },
54 /* GSBI5 MISO */
55 {
56 GSBI5_SPI_MISO, FUNC_SEL_1, GPIO_INPUT,
57 GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE
58 },
59 /* GSBI5 MOSI */
60 {
61 GSBI5_SPI_MOSI, FUNC_SEL_1, GPIO_INPUT,
62 GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE
63 }
64 },
65 {
66 /* GSBI6 CLK */
67 {
68 GSBI6_SPI_CLK, FUNC_SEL_3, GPIO_INPUT,
69 GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE
70 },
71 /* GSBI6 MISO */
72 {
73 GSBI6_SPI_MISO, FUNC_SEL_3, GPIO_INPUT,
74 GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE
75 },
76 /* GSBI6 MOSI */
77 {
78 GSBI6_SPI_MOSI, FUNC_SEL_3, GPIO_INPUT,
79 GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE
80 }
81 },
82 {
83 /* GSBI7 CLK */
84 {
85 GSBI7_SPI_CLK, FUNC_SEL_1, GPIO_INPUT,
86 GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE
87 },
88 /* GSBI7 MISO */
89 {
90 GSBI7_SPI_MISO, FUNC_SEL_1, GPIO_INPUT,
91 GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE
92 },
93 /* GSBI7 MOSI */
94 {
95 GSBI7_SPI_MOSI, FUNC_SEL_1, GPIO_INPUT,
96 GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE
97 }
98 }
99};
100
101/*
102 * CS GPIO number array cs_gpio_array[port_num][cs_num]
103 * cs_gpio_array[0][x] -- GSBI5
104 * cs_gpio_array[1][x] -- GSBI6
105 * cs_gpio_array[2][x] -- GSBI7
106 */
107static unsigned int cs_gpio_array[NUM_PORTS][NUM_CS] = {
108 {
109 GSBI5_SPI_CS_0, GSBI5_SPI_CS_1, GSBI5_SPI_CS_2, GSBI5_SPI_CS_3
110 },
111 {
112 GSBI6_SPI_CS_0, 0, 0, 0
113 },
114 {
115 GSBI7_SPI_CS_0, 0, 0, 0
116 }
117};
118
119/*
120 * GSBI HCLK state register bit
121 * hclk_state[0] -- GSBI5
122 * hclk_state[1] -- GSBI6
123 * hclk_state[2] -- GSBI7
124*/
125static unsigned int hclk_state[NUM_PORTS] = {
126 GSBI5_HCLK,
127 GSBI6_HCLK,
128 GSBI7_HCLK
129};
130
131/*
132 * GSBI QUP_APPS_CLK state register bit
133 * qup_apps_clk_state[0] -- GSBI5
134 * qup_apps_clk_state[1] -- GSBI6
135 * qup_apps_clk_state[2] -- GSBI7
136*/
137static unsigned int qup_apps_clk_state[NUM_PORTS] = {
138 GSBI5_QUP_APPS_CLK,
139 GSBI6_QUP_APPS_CLK,
140 GSBI7_QUP_APPS_CLK
141};
142
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700143static int check_bit_state(uint32_t reg_addr, int bit_num, int val, int us_delay)
144{
145 unsigned int count = TIMEOUT_CNT;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700146 unsigned int bit_val = ((readl_i(reg_addr) >> bit_num) & 0x01);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700147
148 while (bit_val != val) {
149 count--;
150 if (count == 0)
151 return -ETIMEDOUT;
152 udelay(us_delay);
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700153 bit_val = ((readl_i(reg_addr) >> bit_num) & 0x01);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700154 }
155
156 return SUCCESS;
157}
158
159/*
160 * Check whether GSBIn_QUP State is valid
161 */
162static int check_qup_state_valid(struct ipq_spi_slave *ds)
163{
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700164 return check_bit_state(ds->regs->qup_state, QUP_STATE_VALID_BIT,
165 QUP_STATE_VALID, 1);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700166}
167
168/*
169 * Configure GSBIn Core state
170 */
171static int config_spi_state(struct ipq_spi_slave *ds, unsigned int state)
172{
173 uint32_t val;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700174 int ret;
175 uint32_t new_state;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700176
177 ret = check_qup_state_valid(ds);
178 if (ret != SUCCESS)
179 return ret;
180
181 switch (state) {
182 case SPI_RUN_STATE:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700183 new_state = QUP_STATE_RUN_STATE;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700184 break;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700185
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700186 case SPI_RESET_STATE:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700187 new_state = QUP_STATE_RESET_STATE;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700188 break;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700189
190 case SPI_PAUSE_STATE:
191 new_state = QUP_STATE_PAUSE_STATE;
192 break;
193
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700194 default:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700195 printk(BIOS_ERR,
196 "err: unsupported GSBI SPI state : %d\n", state);
197 return -EINVAL;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700198 }
199
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700200 /* Set the state as requested */
201 val = (readl_i(ds->regs->qup_state) & ~QUP_STATE_MASK)
202 | new_state;
203 writel_i(val, ds->regs->qup_state);
204 return check_qup_state_valid(ds);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700205}
206
207/*
208 * Set GSBIn SPI Mode
209 */
210static void spi_set_mode(struct ipq_spi_slave *ds, unsigned int mode)
211{
212 unsigned int clk_idle_state;
213 unsigned int input_first_mode;
214 uint32_t val;
215
216 switch (mode) {
217 case GSBI_SPI_MODE_0:
218 clk_idle_state = 0;
219 input_first_mode = SPI_INPUT_FIRST_MODE;
220 break;
221 case GSBI_SPI_MODE_1:
222 clk_idle_state = 0;
223 input_first_mode = 0;
224 break;
225 case GSBI_SPI_MODE_2:
226 clk_idle_state = 1;
227 input_first_mode = SPI_INPUT_FIRST_MODE;
228 break;
229 case GSBI_SPI_MODE_3:
230 clk_idle_state = 1;
231 input_first_mode = 0;
232 break;
233 default:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700234 printk(BIOS_ERR,
235 "err : unsupported spi mode : %d\n", mode);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700236 return;
237 }
238
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700239 val = readl_i(ds->regs->spi_config);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700240 val |= input_first_mode;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700241 writel_i(val, ds->regs->spi_config);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700242
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700243 val = readl_i(ds->regs->io_control);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700244 if (clk_idle_state)
245 val |= SPI_IO_CONTROL_CLOCK_IDLE_HIGH;
246 else
247 val &= ~SPI_IO_CONTROL_CLOCK_IDLE_HIGH;
248
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700249 writel_i(val, ds->regs->io_control);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700250}
251
252/*
253 * Check for HCLK state
254 */
255static int check_hclk_state(unsigned int core_num, int enable)
256{
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700257 return check_bit_state(CLK_HALT_CFPB_STATEB_REG,
258 hclk_state[core_num], enable, 5);
259}
260
261/*
262 * Check for QUP APPS CLK state
263 */
264static int check_qup_clk_state(unsigned int core_num, int enable)
265{
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700266 return check_bit_state(CLK_HALT_CFPB_STATEB_REG,
267 qup_apps_clk_state[core_num], enable, 5);
268}
269
270/*
271 * Function to assert and De-assert chip select
272 */
273static void CS_change(int port_num, int cs_num, int enable)
274{
275 unsigned int cs_gpio = cs_gpio_array[port_num][cs_num];
Vadim Bendeburyd36ef6a2014-07-25 17:34:42 -0700276 void *addr = GPIO_IN_OUT_ADDR(cs_gpio);
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700277 uint32_t val = readl_i(addr);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700278
Vadim Bendebury0b70bd12014-06-23 10:41:38 -0700279 val &= (~(1 << GPIO_OUTPUT));
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700280 if (!enable)
Vadim Bendebury0b70bd12014-06-23 10:41:38 -0700281 val |= (1 << GPIO_OUTPUT);
Julius Werner2f37bd62015-02-19 14:51:15 -0800282 write32(addr, val);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700283}
284
285/*
286 * GSBIn TLMM configuration
287 */
288static void gsbi_pin_config(unsigned int port_num, int cs_num)
289{
290 unsigned int gpio;
291 unsigned int i;
292 /* Hold the GSBIn (core_num) core in reset */
Julius Werner55009af2019-12-02 22:03:27 -0800293 clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(port_num)),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700294 GSBI1_RESET_MSK, GSBI1_RESET);
295
296 /*
297 * Configure SPI_CLK, SPI_MISO and SPI_MOSI
298 */
299 for (i = 0; i < NUM_GSBI_PINS; i++) {
300 unsigned int func_sel;
301 unsigned int io_config;
302 unsigned int pull_config;
303 unsigned int drv_strength;
304 unsigned int gpio_en;
305 unsigned int *ptr;
306
307 ptr = gsbi_pin_conf[port_num][i];
308 gpio = *(ptr + GSBI_PIN_IDX);
309 func_sel = *(ptr + FUNC_SEL_IDX);
310 io_config = *(ptr + GPIO_DIR_IDX);
311 pull_config = *(ptr + PULL_CONF_IDX);
312 drv_strength = *(ptr + DRV_STR_IDX);
313 gpio_en = *(ptr + GPIO_EN_IDX);
314
315 gpio_tlmm_config(gpio, func_sel, io_config,
316 pull_config, drv_strength, gpio_en);
317 }
318
319 gpio = cs_gpio_array[port_num][cs_num];
320 /* configure CS */
321 gpio_tlmm_config(gpio, FUNC_SEL_GPIO, GPIO_OUTPUT, GPIO_PULL_UP,
322 GPIO_DRV_STR_10MA, GPIO_FUNC_ENABLE);
323 CS_change(port_num, cs_num, CS_DEASSERT);
324}
325
326/*
327 * Clock configuration for GSBIn Core
328 */
329static int gsbi_clock_init(struct ipq_spi_slave *ds)
330{
331 int ret;
332
333 /* Hold the GSBIn (core_num) core in reset */
Julius Werner55009af2019-12-02 22:03:27 -0800334 clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700335 GSBI1_RESET_MSK, GSBI1_RESET);
336
337 /* Disable GSBIn (core_num) QUP core clock branch */
Julius Werner55009af2019-12-02 22:03:27 -0800338 clrsetbits32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700339 QUP_CLK_BRANCH_DIS);
340
341 ret = check_qup_clk_state(ds->slave.bus, 1);
342 if (ret) {
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700343 printk(BIOS_ERR,
344 "QUP Clock Halt For GSBI%d failed!\n", ds->slave.bus);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700345 return ret;
346 }
347
348 /* Disable M/N:D counter and hold M/N:D counter in reset */
Julius Werner55009af2019-12-02 22:03:27 -0800349 clrsetbits32_i(ds->regs->qup_ns_reg, (MNCNTR_MSK | MNCNTR_RST_MSK),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700350 (MNCNTR_RST_ENA | MNCNTR_DIS));
351
352 /* Disable GSBIn (core_num) QUP core clock root */
Julius Werner55009af2019-12-02 22:03:27 -0800353 clrsetbits32_i(ds->regs->qup_ns_reg, CLK_ROOT_ENA_MSK, CLK_ROOT_DIS);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700354
Julius Werner55009af2019-12-02 22:03:27 -0800355 clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_PLL_SRC_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700356 GSBIn_PLL_SRC_PLL8);
Julius Werner55009af2019-12-02 22:03:27 -0800357 clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_PRE_DIV_SEL_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700358 (0 << GSBI_PRE_DIV_SEL_SHFT));
359
360 /* Program M/N:D values for GSBIn_QUP_APPS_CLK @50MHz */
Julius Werner55009af2019-12-02 22:03:27 -0800361 clrsetbits32_i(ds->regs->qup_md_reg, GSBIn_M_VAL_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700362 (0x01 << GSBI_M_VAL_SHFT));
Julius Werner55009af2019-12-02 22:03:27 -0800363 clrsetbits32_i(ds->regs->qup_md_reg, GSBIn_D_VAL_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700364 (0xF7 << GSBI_D_VAL_SHFT));
Julius Werner55009af2019-12-02 22:03:27 -0800365 clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_N_VAL_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700366 (0xF8 << GSBI_N_VAL_SHFT));
367
368 /* Set MNCNTR_MODE = 0: Bypass mode */
Julius Werner55009af2019-12-02 22:03:27 -0800369 clrsetbits32_i(ds->regs->qup_ns_reg, MNCNTR_MODE_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700370 MNCNTR_MODE_DUAL_EDGE);
371
372 /* De-assert the M/N:D counter reset */
Julius Werner55009af2019-12-02 22:03:27 -0800373 clrsetbits32_i(ds->regs->qup_ns_reg, MNCNTR_RST_MSK, MNCNTR_RST_DIS);
374 clrsetbits32_i(ds->regs->qup_ns_reg, MNCNTR_MSK, MNCNTR_EN);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700375
376 /*
377 * Enable the GSBIn (core_num) QUP core clock root.
378 * Keep MND counter disabled
379 */
Julius Werner55009af2019-12-02 22:03:27 -0800380 clrsetbits32_i(ds->regs->qup_ns_reg, CLK_ROOT_ENA_MSK, CLK_ROOT_ENA);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700381
382 /* Enable GSBIn (core_num) QUP core clock branch */
Julius Werner55009af2019-12-02 22:03:27 -0800383 clrsetbits32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700384 QUP_CLK_BRANCH_ENA);
385
386 ret = check_qup_clk_state(ds->slave.bus, 0);
387 if (ret) {
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700388 printk(BIOS_ERR,
389 "QUP Clock Enable For GSBI%d"
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700390 " failed!\n", ds->slave.bus);
391 return ret;
392 }
393
394 /* Enable GSBIn (core_num) core clock branch */
Julius Werner55009af2019-12-02 22:03:27 -0800395 clrsetbits32_i(GSBIn_HCLK_CTL_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700396 GSBI_CLK_BRANCH_ENA_MSK, GSBI_CLK_BRANCH_ENA);
397
398 ret = check_hclk_state(ds->slave.bus, 0);
399 if (ret) {
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700400 printk(BIOS_ERR,
401 "HCLK Enable For GSBI%d failed!\n", ds->slave.bus);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700402 return ret;
403 }
404
405 /* Release GSBIn (core_num) core from reset */
Julius Werner55009af2019-12-02 22:03:27 -0800406 clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700407 GSBI1_RESET_MSK, 0);
408 udelay(50);
409
410 return SUCCESS;
411}
412
413/*
414 * Reset entire QUP and all mini cores
415 */
416static void spi_reset(struct ipq_spi_slave *ds)
417{
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700418 writel_i(0x1, ds->regs->qup_sw_reset);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700419 udelay(5);
420}
421
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700422static const struct gsbi_spi spi_reg[] = {
423 /* GSBI5 registers for SPI interface */
424 {
425 GSBI5_SPI_CONFIG_REG,
426 GSBI5_SPI_IO_CONTROL_REG,
427 GSBI5_SPI_ERROR_FLAGS_REG,
428 GSBI5_SPI_ERROR_FLAGS_EN_REG,
429 GSBI5_GSBI_CTRL_REG_REG,
430 GSBI5_QUP_CONFIG_REG,
431 GSBI5_QUP_ERROR_FLAGS_REG,
432 GSBI5_QUP_ERROR_FLAGS_EN_REG,
433 GSBI5_QUP_OPERATIONAL_REG,
434 GSBI5_QUP_IO_MODES_REG,
435 GSBI5_QUP_STATE_REG,
436 GSBI5_QUP_INPUT_FIFOc_REG(0),
437 GSBI5_QUP_OUTPUT_FIFOc_REG(0),
438 GSBI5_QUP_MX_INPUT_COUNT_REG,
439 GSBI5_QUP_MX_OUTPUT_COUNT_REG,
440 GSBI5_QUP_SW_RESET_REG,
441 GSBIn_QUP_APPS_NS_REG(5),
442 GSBIn_QUP_APPS_MD_REG(5),
443 },
444 /* GSBI6 registers for SPI interface */
445 {
446 GSBI6_SPI_CONFIG_REG,
447 GSBI6_SPI_IO_CONTROL_REG,
448 GSBI6_SPI_ERROR_FLAGS_REG,
449 GSBI6_SPI_ERROR_FLAGS_EN_REG,
450 GSBI6_GSBI_CTRL_REG_REG,
451 GSBI6_QUP_CONFIG_REG,
452 GSBI6_QUP_ERROR_FLAGS_REG,
453 GSBI6_QUP_ERROR_FLAGS_EN_REG,
454 GSBI6_QUP_OPERATIONAL_REG,
455 GSBI6_QUP_IO_MODES_REG,
456 GSBI6_QUP_STATE_REG,
457 GSBI6_QUP_INPUT_FIFOc_REG(0),
458 GSBI6_QUP_OUTPUT_FIFOc_REG(0),
459 GSBI6_QUP_MX_INPUT_COUNT_REG,
460 GSBI6_QUP_MX_OUTPUT_COUNT_REG,
461 GSBI6_QUP_SW_RESET_REG,
462 GSBIn_QUP_APPS_NS_REG(6),
463 GSBIn_QUP_APPS_MD_REG(6),
464 },
465 /* GSBI7 registers for SPI interface */
466 {
467 GSBI7_SPI_CONFIG_REG,
468 GSBI7_SPI_IO_CONTROL_REG,
469 GSBI7_SPI_ERROR_FLAGS_REG,
470 GSBI7_SPI_ERROR_FLAGS_EN_REG,
471 GSBI7_GSBI_CTRL_REG_REG,
472 GSBI7_QUP_CONFIG_REG,
473 GSBI7_QUP_ERROR_FLAGS_REG,
474 GSBI7_QUP_ERROR_FLAGS_EN_REG,
475 GSBI7_QUP_OPERATIONAL_REG,
476 GSBI7_QUP_IO_MODES_REG,
477 GSBI7_QUP_STATE_REG,
478 GSBI7_QUP_INPUT_FIFOc_REG(0),
479 GSBI7_QUP_OUTPUT_FIFOc_REG(0),
480 GSBI7_QUP_MX_INPUT_COUNT_REG,
481 GSBI7_QUP_MX_OUTPUT_COUNT_REG,
482 GSBI7_QUP_SW_RESET_REG,
483 GSBIn_QUP_APPS_NS_REG(7),
484 GSBIn_QUP_APPS_MD_REG(7),
485 }
486};
487static struct ipq_spi_slave spi_slave_pool[2];
488
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800489static struct ipq_spi_slave *to_ipq_spi(const struct spi_slave *slave)
490{
491 struct ipq_spi_slave *ds;
492 size_t i;
493
494 for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) {
495 ds = spi_slave_pool + i;
496
497 if (!ds->allocated)
498 continue;
499
500 if ((ds->slave.bus == slave->bus) &&
501 (ds->slave.cs == slave->cs))
502 return ds;
503 }
504
505 return NULL;
506}
507
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700508/*
509 * GSBIn SPI Hardware Initialisation
510 */
511static int spi_hw_init(struct ipq_spi_slave *ds)
512{
513 int ret;
514
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700515 if (ds->initialized)
516 return 0;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700517
518 /* GSBI module configuration */
519 spi_reset(ds);
520
521 /* Set the GSBIn QUP state */
522 ret = config_spi_state(ds, SPI_RESET_STATE);
523 if (ret)
524 return ret;
525
526 /* Configure GSBI_CTRL register to set protocol_mode to SPI:011 */
Julius Werner55009af2019-12-02 22:03:27 -0800527 clrsetbits32_i(ds->regs->gsbi_ctrl, PROTOCOL_CODE_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700528 PROTOCOL_CODE_SPI);
529
530 /*
531 * Configure Mini core to SPI core with Input Output enabled,
532 * SPI master, N = 8 bits
533 */
Julius Werner55009af2019-12-02 22:03:27 -0800534 clrsetbits32_i(ds->regs->qup_config, (QUP_CONFIG_MINI_CORE_MSK |
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700535 SPI_QUP_CONF_INPUT_MSK |
536 SPI_QUP_CONF_OUTPUT_MSK |
537 SPI_BIT_WORD_MSK),
538 (QUP_CONFIG_MINI_CORE_SPI |
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700539 SPI_QUP_CONF_NO_INPUT |
540 SPI_QUP_CONF_NO_OUTPUT |
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700541 SPI_8_BIT_WORD));
542
543 /*
544 * Configure Input first SPI protocol,
545 * SPI master mode and no loopback
546 */
Julius Werner55009af2019-12-02 22:03:27 -0800547 clrsetbits32_i(ds->regs->spi_config, (LOOP_BACK_MSK |
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700548 SLAVE_OPERATION_MSK),
549 (NO_LOOP_BACK |
550 SLAVE_OPERATION));
551
552 /*
553 * Configure SPI IO Control Register
554 * CLK_ALWAYS_ON = 0
555 * MX_CS_MODE = 0
556 * NO_TRI_STATE = 1
557 */
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700558 writel_i((CLK_ALWAYS_ON | MX_CS_MODE | NO_TRI_STATE),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700559 ds->regs->io_control);
560
561 /*
562 * Configure SPI IO Modes.
563 * OUTPUT_BIT_SHIFT_EN = 1
564 * INPUT_MODE = Block Mode
565 * OUTPUT MODE = Block Mode
566 */
Julius Werner55009af2019-12-02 22:03:27 -0800567 clrsetbits32_i(ds->regs->qup_io_modes, (OUTPUT_BIT_SHIFT_MSK |
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700568 INPUT_BLOCK_MODE_MSK |
569 OUTPUT_BLOCK_MODE_MSK),
570 (OUTPUT_BIT_SHIFT_EN |
571 INPUT_BLOCK_MODE |
572 OUTPUT_BLOCK_MODE));
573
574 spi_set_mode(ds, ds->mode);
575
576 /* Disable Error mask */
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700577 writel_i(0, ds->regs->error_flags_en);
578 writel_i(0, ds->regs->qup_error_flags_en);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700579
580 ds->initialized = 1;
581
582 return SUCCESS;
583}
584
Furquan Shaikh94f86992016-12-01 07:12:32 -0800585static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700586{
587 struct ipq_spi_slave *ds = to_ipq_spi(slave);
588 unsigned int ret;
589
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700590 if (ds->initialized)
591 return SUCCESS;
592
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700593 /* GPIO Configuration for SPI port */
594 gsbi_pin_config(ds->slave.bus, ds->slave.cs);
595
596 /* Clock configuration */
597 ret = gsbi_clock_init(ds);
598 if (ret)
599 return ret;
600
601 ret = spi_hw_init(ds);
602 if (ret)
603 return -EIO;
604
605 return SUCCESS;
606}
607
Furquan Shaikh94f86992016-12-01 07:12:32 -0800608static void spi_ctrlr_release_bus(const struct spi_slave *slave)
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700609{
610 struct ipq_spi_slave *ds = to_ipq_spi(slave);
611
612 /* Reset the SPI hardware */
613 spi_reset(ds);
614 ds->initialized = 0;
615}
616
David Hendricks68ec2fc2014-07-25 12:59:48 -0700617static int spi_xfer_tx_packet(struct ipq_spi_slave *ds,
Martin Roth57e89092019-10-23 21:45:23 -0600618 const uint8_t *dout, unsigned int out_bytes)
David Hendricks68ec2fc2014-07-25 12:59:48 -0700619{
620 int ret;
621
622 writel_i(out_bytes, ds->regs->qup_mx_output_count);
623
624 ret = config_spi_state(ds, SPI_RUN_STATE);
625 if (ret)
626 return ret;
627
628 while (out_bytes) {
629 if (readl_i(ds->regs->qup_operational) & QUP_OUTPUT_FIFO_FULL)
630 continue;
631
632 writel_i(*dout++, ds->regs->qup_output_fifo);
633 out_bytes--;
634
635 /* Wait for output FIFO to drain. */
636 if (!out_bytes)
637 while (readl_i(ds->regs->qup_operational) &
638 QUP_OUTPUT_FIFO_NOT_EMPTY)
639 ;
640 }
641
642 return config_spi_state(ds, SPI_RESET_STATE);
643}
644
645static int spi_xfer_rx_packet(struct ipq_spi_slave *ds,
Martin Roth57e89092019-10-23 21:45:23 -0600646 uint8_t *din, unsigned int in_bytes)
David Hendricks68ec2fc2014-07-25 12:59:48 -0700647{
648 int ret;
649
650 writel_i(in_bytes, ds->regs->qup_mx_input_count);
651 writel_i(in_bytes, ds->regs->qup_mx_output_count);
652
653 ret = config_spi_state(ds, SPI_RUN_STATE);
654 if (ret)
655 return ret;
656
657 /* Seed clocking */
658 writel_i(0xff, ds->regs->qup_output_fifo);
659 while (in_bytes) {
660 if (!(readl_i(ds->regs->qup_operational) &
661 QUP_INPUT_FIFO_NOT_EMPTY))
662 continue;
663 /* Keep it clocking */
664 writel_i(0xff, ds->regs->qup_output_fifo);
665
666 *din++ = readl_i(ds->regs->qup_input_fifo) & 0xff;
667 in_bytes--;
668 }
669
670 return config_spi_state(ds, SPI_RESET_STATE);
671}
672
Furquan Shaikh94f86992016-12-01 07:12:32 -0800673static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
674 size_t out_bytes, void *din, size_t in_bytes)
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700675{
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700676 int ret;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700677 struct ipq_spi_slave *ds = to_ipq_spi(slave);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700678
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700679 /* Assert the chip select */
680 CS_change(ds->slave.bus, ds->slave.cs, CS_ASSERT);
681
682 ret = config_spi_state(ds, SPI_RESET_STATE);
683 if (ret)
684 goto out;
685
686 if (!out_bytes)
687 goto spi_receive;
688
689 /*
690 * Let's do the write side of the transaction first. Enable output
691 * FIFO.
692 */
Julius Werner55009af2019-12-02 22:03:27 -0800693 clrsetbits32_i(ds->regs->qup_config, SPI_QUP_CONF_OUTPUT_MSK,
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700694 SPI_QUP_CONF_OUTPUT_ENA);
695
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700696 while (out_bytes) {
Martin Roth57e89092019-10-23 21:45:23 -0600697 unsigned int todo = MIN(out_bytes, MAX_PACKET_COUNT);
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700698
David Hendricks68ec2fc2014-07-25 12:59:48 -0700699 ret = spi_xfer_tx_packet(ds, dout, todo);
700 if (ret)
701 break;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700702
David Hendricks68ec2fc2014-07-25 12:59:48 -0700703 out_bytes -= todo;
704 dout += todo;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700705 }
706
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700707 if (ret)
708 goto out;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700709
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700710spi_receive:
711 if (!in_bytes) /* Nothing to read. */
712 goto out;
713
714 /* Enable input FIFO */
Julius Werner55009af2019-12-02 22:03:27 -0800715 clrsetbits32_i(ds->regs->qup_config, SPI_QUP_CONF_INPUT_MSK,
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700716 SPI_QUP_CONF_INPUT_ENA);
717
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700718 while (in_bytes) {
Martin Roth57e89092019-10-23 21:45:23 -0600719 unsigned int todo = MIN(in_bytes, MAX_PACKET_COUNT);
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700720
David Hendricks68ec2fc2014-07-25 12:59:48 -0700721 ret = spi_xfer_rx_packet(ds, din, todo);
722 if (ret)
723 break;
724
725 in_bytes -= todo;
726 din += todo;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700727 }
728
David Hendricks68ec2fc2014-07-25 12:59:48 -0700729out:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700730 /* Deassert CS */
731 CS_change(ds->slave.bus, ds->slave.cs, CS_DEASSERT);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700732
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700733 /*
734 * Put the SPI Core back in the Reset State
735 * to end the transfer
736 */
737 (void)config_spi_state(ds, SPI_RESET_STATE);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700738
739 return ret;
740}
Furquan Shaikh94f86992016-12-01 07:12:32 -0800741
Furquan Shaikhe424a592017-05-18 14:40:58 -0700742static int spi_ctrlr_setup(const struct spi_slave *slave)
Furquan Shaikh94f86992016-12-01 07:12:32 -0800743{
744 struct ipq_spi_slave *ds = NULL;
745 int i;
Julius Werner7c712bb2019-05-01 16:51:20 -0700746 int bus = slave->bus;
747 int cs = slave->cs;
Furquan Shaikh94f86992016-12-01 07:12:32 -0800748
749 /*
750 * IPQ GSBI (Generic Serial Bus Interface) supports SPI Flash
751 * on different GSBI5, GSBI6 and GSBI7
752 * with different number of chip selects (CS, channels):
753 */
754 if ((bus < GSBI5_SPI) || (bus > GSBI7_SPI)
755 || ((bus == GSBI5_SPI) && (cs > 3))
756 || ((bus == GSBI6_SPI) && (cs > 0))
757 || ((bus == GSBI7_SPI) && (cs > 0))) {
758 printk(BIOS_ERR, "SPI error: unsupported bus %d "
Martin Roth26f97f92021-10-01 14:53:22 -0600759 "(Supported buses 0,1 and 2) or chipselect\n", bus);
Furquan Shaikh94f86992016-12-01 07:12:32 -0800760 }
761
762 for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) {
763 if (spi_slave_pool[i].allocated)
764 continue;
765 ds = spi_slave_pool + i;
766
Furquan Shaikhe424a592017-05-18 14:40:58 -0700767 ds->slave.bus = bus;
768 ds->slave.cs = cs;
Furquan Shaikh94f86992016-12-01 07:12:32 -0800769 ds->regs = &spi_reg[bus];
770
771 /*
772 * TODO(vbendeb):
773 * hardcoded frequency and mode - we might need to find a way
774 * to configure this
775 */
776 ds->freq = 10000000;
777 ds->mode = GSBI_SPI_MODE_0;
778 ds->allocated = 1;
779
780 return 0;
781 }
782
783 printk(BIOS_ERR, "SPI error: all %d pools busy\n", i);
784 return -1;
785}
Furquan Shaikhe424a592017-05-18 14:40:58 -0700786
787static const struct spi_ctrlr spi_ctrlr = {
788 .setup = spi_ctrlr_setup,
789 .claim_bus = spi_ctrlr_claim_bus,
790 .release_bus = spi_ctrlr_release_bus,
791 .xfer = spi_ctrlr_xfer,
792 .max_xfer_size = MAX_PACKET_COUNT,
793};
794
795const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
796 {
797 .ctrlr = &spi_ctrlr,
798 .bus_start = GSBI5_SPI,
799 .bus_end = GSBI7_SPI,
800 },
801};
802
803const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);