blob: c538c279e89d138ecce6402c200d9eddf51bdf2d [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{
164
165 return check_bit_state(ds->regs->qup_state, QUP_STATE_VALID_BIT,
166 QUP_STATE_VALID, 1);
167
168}
169
170/*
171 * Configure GSBIn Core state
172 */
173static int config_spi_state(struct ipq_spi_slave *ds, unsigned int state)
174{
175 uint32_t val;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700176 int ret;
177 uint32_t new_state;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700178
179 ret = check_qup_state_valid(ds);
180 if (ret != SUCCESS)
181 return ret;
182
183 switch (state) {
184 case SPI_RUN_STATE:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700185 new_state = QUP_STATE_RUN_STATE;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700186 break;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700187
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700188 case SPI_RESET_STATE:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700189 new_state = QUP_STATE_RESET_STATE;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700190 break;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700191
192 case SPI_PAUSE_STATE:
193 new_state = QUP_STATE_PAUSE_STATE;
194 break;
195
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700196 default:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700197 printk(BIOS_ERR,
198 "err: unsupported GSBI SPI state : %d\n", state);
199 return -EINVAL;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700200 }
201
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700202 /* Set the state as requested */
203 val = (readl_i(ds->regs->qup_state) & ~QUP_STATE_MASK)
204 | new_state;
205 writel_i(val, ds->regs->qup_state);
206 return check_qup_state_valid(ds);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700207}
208
209/*
210 * Set GSBIn SPI Mode
211 */
212static void spi_set_mode(struct ipq_spi_slave *ds, unsigned int mode)
213{
214 unsigned int clk_idle_state;
215 unsigned int input_first_mode;
216 uint32_t val;
217
218 switch (mode) {
219 case GSBI_SPI_MODE_0:
220 clk_idle_state = 0;
221 input_first_mode = SPI_INPUT_FIRST_MODE;
222 break;
223 case GSBI_SPI_MODE_1:
224 clk_idle_state = 0;
225 input_first_mode = 0;
226 break;
227 case GSBI_SPI_MODE_2:
228 clk_idle_state = 1;
229 input_first_mode = SPI_INPUT_FIRST_MODE;
230 break;
231 case GSBI_SPI_MODE_3:
232 clk_idle_state = 1;
233 input_first_mode = 0;
234 break;
235 default:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700236 printk(BIOS_ERR,
237 "err : unsupported spi mode : %d\n", mode);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700238 return;
239 }
240
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700241 val = readl_i(ds->regs->spi_config);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700242 val |= input_first_mode;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700243 writel_i(val, ds->regs->spi_config);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700244
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700245 val = readl_i(ds->regs->io_control);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700246 if (clk_idle_state)
247 val |= SPI_IO_CONTROL_CLOCK_IDLE_HIGH;
248 else
249 val &= ~SPI_IO_CONTROL_CLOCK_IDLE_HIGH;
250
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700251 writel_i(val, ds->regs->io_control);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700252}
253
254/*
255 * Check for HCLK state
256 */
257static int check_hclk_state(unsigned int core_num, int enable)
258{
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700259 return check_bit_state(CLK_HALT_CFPB_STATEB_REG,
260 hclk_state[core_num], enable, 5);
261}
262
263/*
264 * Check for QUP APPS CLK state
265 */
266static int check_qup_clk_state(unsigned int core_num, int enable)
267{
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700268 return check_bit_state(CLK_HALT_CFPB_STATEB_REG,
269 qup_apps_clk_state[core_num], enable, 5);
270}
271
272/*
273 * Function to assert and De-assert chip select
274 */
275static void CS_change(int port_num, int cs_num, int enable)
276{
277 unsigned int cs_gpio = cs_gpio_array[port_num][cs_num];
Vadim Bendeburyd36ef6a2014-07-25 17:34:42 -0700278 void *addr = GPIO_IN_OUT_ADDR(cs_gpio);
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700279 uint32_t val = readl_i(addr);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700280
Vadim Bendebury0b70bd12014-06-23 10:41:38 -0700281 val &= (~(1 << GPIO_OUTPUT));
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700282 if (!enable)
Vadim Bendebury0b70bd12014-06-23 10:41:38 -0700283 val |= (1 << GPIO_OUTPUT);
Julius Werner2f37bd62015-02-19 14:51:15 -0800284 write32(addr, val);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700285}
286
287/*
288 * GSBIn TLMM configuration
289 */
290static void gsbi_pin_config(unsigned int port_num, int cs_num)
291{
292 unsigned int gpio;
293 unsigned int i;
294 /* Hold the GSBIn (core_num) core in reset */
Julius Werner55009af2019-12-02 22:03:27 -0800295 clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(port_num)),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700296 GSBI1_RESET_MSK, GSBI1_RESET);
297
298 /*
299 * Configure SPI_CLK, SPI_MISO and SPI_MOSI
300 */
301 for (i = 0; i < NUM_GSBI_PINS; i++) {
302 unsigned int func_sel;
303 unsigned int io_config;
304 unsigned int pull_config;
305 unsigned int drv_strength;
306 unsigned int gpio_en;
307 unsigned int *ptr;
308
309 ptr = gsbi_pin_conf[port_num][i];
310 gpio = *(ptr + GSBI_PIN_IDX);
311 func_sel = *(ptr + FUNC_SEL_IDX);
312 io_config = *(ptr + GPIO_DIR_IDX);
313 pull_config = *(ptr + PULL_CONF_IDX);
314 drv_strength = *(ptr + DRV_STR_IDX);
315 gpio_en = *(ptr + GPIO_EN_IDX);
316
317 gpio_tlmm_config(gpio, func_sel, io_config,
318 pull_config, drv_strength, gpio_en);
319 }
320
321 gpio = cs_gpio_array[port_num][cs_num];
322 /* configure CS */
323 gpio_tlmm_config(gpio, FUNC_SEL_GPIO, GPIO_OUTPUT, GPIO_PULL_UP,
324 GPIO_DRV_STR_10MA, GPIO_FUNC_ENABLE);
325 CS_change(port_num, cs_num, CS_DEASSERT);
326}
327
328/*
329 * Clock configuration for GSBIn Core
330 */
331static int gsbi_clock_init(struct ipq_spi_slave *ds)
332{
333 int ret;
334
335 /* Hold the GSBIn (core_num) core in reset */
Julius Werner55009af2019-12-02 22:03:27 -0800336 clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700337 GSBI1_RESET_MSK, GSBI1_RESET);
338
339 /* Disable GSBIn (core_num) QUP core clock branch */
Julius Werner55009af2019-12-02 22:03:27 -0800340 clrsetbits32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700341 QUP_CLK_BRANCH_DIS);
342
343 ret = check_qup_clk_state(ds->slave.bus, 1);
344 if (ret) {
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700345 printk(BIOS_ERR,
346 "QUP Clock Halt For GSBI%d failed!\n", ds->slave.bus);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700347 return ret;
348 }
349
350 /* Disable M/N:D counter and hold M/N:D counter in reset */
Julius Werner55009af2019-12-02 22:03:27 -0800351 clrsetbits32_i(ds->regs->qup_ns_reg, (MNCNTR_MSK | MNCNTR_RST_MSK),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700352 (MNCNTR_RST_ENA | MNCNTR_DIS));
353
354 /* Disable GSBIn (core_num) QUP core clock root */
Julius Werner55009af2019-12-02 22:03:27 -0800355 clrsetbits32_i(ds->regs->qup_ns_reg, CLK_ROOT_ENA_MSK, CLK_ROOT_DIS);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700356
Julius Werner55009af2019-12-02 22:03:27 -0800357 clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_PLL_SRC_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700358 GSBIn_PLL_SRC_PLL8);
Julius Werner55009af2019-12-02 22:03:27 -0800359 clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_PRE_DIV_SEL_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700360 (0 << GSBI_PRE_DIV_SEL_SHFT));
361
362 /* Program M/N:D values for GSBIn_QUP_APPS_CLK @50MHz */
Julius Werner55009af2019-12-02 22:03:27 -0800363 clrsetbits32_i(ds->regs->qup_md_reg, GSBIn_M_VAL_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700364 (0x01 << GSBI_M_VAL_SHFT));
Julius Werner55009af2019-12-02 22:03:27 -0800365 clrsetbits32_i(ds->regs->qup_md_reg, GSBIn_D_VAL_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700366 (0xF7 << GSBI_D_VAL_SHFT));
Julius Werner55009af2019-12-02 22:03:27 -0800367 clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_N_VAL_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700368 (0xF8 << GSBI_N_VAL_SHFT));
369
370 /* Set MNCNTR_MODE = 0: Bypass mode */
Julius Werner55009af2019-12-02 22:03:27 -0800371 clrsetbits32_i(ds->regs->qup_ns_reg, MNCNTR_MODE_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700372 MNCNTR_MODE_DUAL_EDGE);
373
374 /* De-assert the M/N:D counter reset */
Julius Werner55009af2019-12-02 22:03:27 -0800375 clrsetbits32_i(ds->regs->qup_ns_reg, MNCNTR_RST_MSK, MNCNTR_RST_DIS);
376 clrsetbits32_i(ds->regs->qup_ns_reg, MNCNTR_MSK, MNCNTR_EN);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700377
378 /*
379 * Enable the GSBIn (core_num) QUP core clock root.
380 * Keep MND counter disabled
381 */
Julius Werner55009af2019-12-02 22:03:27 -0800382 clrsetbits32_i(ds->regs->qup_ns_reg, CLK_ROOT_ENA_MSK, CLK_ROOT_ENA);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700383
384 /* Enable GSBIn (core_num) QUP core clock branch */
Julius Werner55009af2019-12-02 22:03:27 -0800385 clrsetbits32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700386 QUP_CLK_BRANCH_ENA);
387
388 ret = check_qup_clk_state(ds->slave.bus, 0);
389 if (ret) {
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700390 printk(BIOS_ERR,
391 "QUP Clock Enable For GSBI%d"
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700392 " failed!\n", ds->slave.bus);
393 return ret;
394 }
395
396 /* Enable GSBIn (core_num) core clock branch */
Julius Werner55009af2019-12-02 22:03:27 -0800397 clrsetbits32_i(GSBIn_HCLK_CTL_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700398 GSBI_CLK_BRANCH_ENA_MSK, GSBI_CLK_BRANCH_ENA);
399
400 ret = check_hclk_state(ds->slave.bus, 0);
401 if (ret) {
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700402 printk(BIOS_ERR,
403 "HCLK Enable For GSBI%d failed!\n", ds->slave.bus);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700404 return ret;
405 }
406
407 /* Release GSBIn (core_num) core from reset */
Julius Werner55009af2019-12-02 22:03:27 -0800408 clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700409 GSBI1_RESET_MSK, 0);
410 udelay(50);
411
412 return SUCCESS;
413}
414
415/*
416 * Reset entire QUP and all mini cores
417 */
418static void spi_reset(struct ipq_spi_slave *ds)
419{
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700420 writel_i(0x1, ds->regs->qup_sw_reset);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700421 udelay(5);
422}
423
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700424static const struct gsbi_spi spi_reg[] = {
425 /* GSBI5 registers for SPI interface */
426 {
427 GSBI5_SPI_CONFIG_REG,
428 GSBI5_SPI_IO_CONTROL_REG,
429 GSBI5_SPI_ERROR_FLAGS_REG,
430 GSBI5_SPI_ERROR_FLAGS_EN_REG,
431 GSBI5_GSBI_CTRL_REG_REG,
432 GSBI5_QUP_CONFIG_REG,
433 GSBI5_QUP_ERROR_FLAGS_REG,
434 GSBI5_QUP_ERROR_FLAGS_EN_REG,
435 GSBI5_QUP_OPERATIONAL_REG,
436 GSBI5_QUP_IO_MODES_REG,
437 GSBI5_QUP_STATE_REG,
438 GSBI5_QUP_INPUT_FIFOc_REG(0),
439 GSBI5_QUP_OUTPUT_FIFOc_REG(0),
440 GSBI5_QUP_MX_INPUT_COUNT_REG,
441 GSBI5_QUP_MX_OUTPUT_COUNT_REG,
442 GSBI5_QUP_SW_RESET_REG,
443 GSBIn_QUP_APPS_NS_REG(5),
444 GSBIn_QUP_APPS_MD_REG(5),
445 },
446 /* GSBI6 registers for SPI interface */
447 {
448 GSBI6_SPI_CONFIG_REG,
449 GSBI6_SPI_IO_CONTROL_REG,
450 GSBI6_SPI_ERROR_FLAGS_REG,
451 GSBI6_SPI_ERROR_FLAGS_EN_REG,
452 GSBI6_GSBI_CTRL_REG_REG,
453 GSBI6_QUP_CONFIG_REG,
454 GSBI6_QUP_ERROR_FLAGS_REG,
455 GSBI6_QUP_ERROR_FLAGS_EN_REG,
456 GSBI6_QUP_OPERATIONAL_REG,
457 GSBI6_QUP_IO_MODES_REG,
458 GSBI6_QUP_STATE_REG,
459 GSBI6_QUP_INPUT_FIFOc_REG(0),
460 GSBI6_QUP_OUTPUT_FIFOc_REG(0),
461 GSBI6_QUP_MX_INPUT_COUNT_REG,
462 GSBI6_QUP_MX_OUTPUT_COUNT_REG,
463 GSBI6_QUP_SW_RESET_REG,
464 GSBIn_QUP_APPS_NS_REG(6),
465 GSBIn_QUP_APPS_MD_REG(6),
466 },
467 /* GSBI7 registers for SPI interface */
468 {
469 GSBI7_SPI_CONFIG_REG,
470 GSBI7_SPI_IO_CONTROL_REG,
471 GSBI7_SPI_ERROR_FLAGS_REG,
472 GSBI7_SPI_ERROR_FLAGS_EN_REG,
473 GSBI7_GSBI_CTRL_REG_REG,
474 GSBI7_QUP_CONFIG_REG,
475 GSBI7_QUP_ERROR_FLAGS_REG,
476 GSBI7_QUP_ERROR_FLAGS_EN_REG,
477 GSBI7_QUP_OPERATIONAL_REG,
478 GSBI7_QUP_IO_MODES_REG,
479 GSBI7_QUP_STATE_REG,
480 GSBI7_QUP_INPUT_FIFOc_REG(0),
481 GSBI7_QUP_OUTPUT_FIFOc_REG(0),
482 GSBI7_QUP_MX_INPUT_COUNT_REG,
483 GSBI7_QUP_MX_OUTPUT_COUNT_REG,
484 GSBI7_QUP_SW_RESET_REG,
485 GSBIn_QUP_APPS_NS_REG(7),
486 GSBIn_QUP_APPS_MD_REG(7),
487 }
488};
489static struct ipq_spi_slave spi_slave_pool[2];
490
Furquan Shaikh36b81af2016-12-01 01:02:44 -0800491static struct ipq_spi_slave *to_ipq_spi(const struct spi_slave *slave)
492{
493 struct ipq_spi_slave *ds;
494 size_t i;
495
496 for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) {
497 ds = spi_slave_pool + i;
498
499 if (!ds->allocated)
500 continue;
501
502 if ((ds->slave.bus == slave->bus) &&
503 (ds->slave.cs == slave->cs))
504 return ds;
505 }
506
507 return NULL;
508}
509
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700510/*
511 * GSBIn SPI Hardware Initialisation
512 */
513static int spi_hw_init(struct ipq_spi_slave *ds)
514{
515 int ret;
516
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700517 if (ds->initialized)
518 return 0;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700519
520 /* GSBI module configuration */
521 spi_reset(ds);
522
523 /* Set the GSBIn QUP state */
524 ret = config_spi_state(ds, SPI_RESET_STATE);
525 if (ret)
526 return ret;
527
528 /* Configure GSBI_CTRL register to set protocol_mode to SPI:011 */
Julius Werner55009af2019-12-02 22:03:27 -0800529 clrsetbits32_i(ds->regs->gsbi_ctrl, PROTOCOL_CODE_MSK,
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700530 PROTOCOL_CODE_SPI);
531
532 /*
533 * Configure Mini core to SPI core with Input Output enabled,
534 * SPI master, N = 8 bits
535 */
Julius Werner55009af2019-12-02 22:03:27 -0800536 clrsetbits32_i(ds->regs->qup_config, (QUP_CONFIG_MINI_CORE_MSK |
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700537 SPI_QUP_CONF_INPUT_MSK |
538 SPI_QUP_CONF_OUTPUT_MSK |
539 SPI_BIT_WORD_MSK),
540 (QUP_CONFIG_MINI_CORE_SPI |
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700541 SPI_QUP_CONF_NO_INPUT |
542 SPI_QUP_CONF_NO_OUTPUT |
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700543 SPI_8_BIT_WORD));
544
545 /*
546 * Configure Input first SPI protocol,
547 * SPI master mode and no loopback
548 */
Julius Werner55009af2019-12-02 22:03:27 -0800549 clrsetbits32_i(ds->regs->spi_config, (LOOP_BACK_MSK |
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700550 SLAVE_OPERATION_MSK),
551 (NO_LOOP_BACK |
552 SLAVE_OPERATION));
553
554 /*
555 * Configure SPI IO Control Register
556 * CLK_ALWAYS_ON = 0
557 * MX_CS_MODE = 0
558 * NO_TRI_STATE = 1
559 */
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700560 writel_i((CLK_ALWAYS_ON | MX_CS_MODE | NO_TRI_STATE),
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700561 ds->regs->io_control);
562
563 /*
564 * Configure SPI IO Modes.
565 * OUTPUT_BIT_SHIFT_EN = 1
566 * INPUT_MODE = Block Mode
567 * OUTPUT MODE = Block Mode
568 */
Julius Werner55009af2019-12-02 22:03:27 -0800569 clrsetbits32_i(ds->regs->qup_io_modes, (OUTPUT_BIT_SHIFT_MSK |
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700570 INPUT_BLOCK_MODE_MSK |
571 OUTPUT_BLOCK_MODE_MSK),
572 (OUTPUT_BIT_SHIFT_EN |
573 INPUT_BLOCK_MODE |
574 OUTPUT_BLOCK_MODE));
575
576 spi_set_mode(ds, ds->mode);
577
578 /* Disable Error mask */
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700579 writel_i(0, ds->regs->error_flags_en);
580 writel_i(0, ds->regs->qup_error_flags_en);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700581
582 ds->initialized = 1;
583
584 return SUCCESS;
585}
586
Furquan Shaikh94f86992016-12-01 07:12:32 -0800587static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700588{
589 struct ipq_spi_slave *ds = to_ipq_spi(slave);
590 unsigned int ret;
591
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700592 if (ds->initialized)
593 return SUCCESS;
594
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700595 /* GPIO Configuration for SPI port */
596 gsbi_pin_config(ds->slave.bus, ds->slave.cs);
597
598 /* Clock configuration */
599 ret = gsbi_clock_init(ds);
600 if (ret)
601 return ret;
602
603 ret = spi_hw_init(ds);
604 if (ret)
605 return -EIO;
606
607 return SUCCESS;
608}
609
Furquan Shaikh94f86992016-12-01 07:12:32 -0800610static void spi_ctrlr_release_bus(const struct spi_slave *slave)
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700611{
612 struct ipq_spi_slave *ds = to_ipq_spi(slave);
613
614 /* Reset the SPI hardware */
615 spi_reset(ds);
616 ds->initialized = 0;
617}
618
David Hendricks68ec2fc2014-07-25 12:59:48 -0700619static int spi_xfer_tx_packet(struct ipq_spi_slave *ds,
Martin Roth57e89092019-10-23 21:45:23 -0600620 const uint8_t *dout, unsigned int out_bytes)
David Hendricks68ec2fc2014-07-25 12:59:48 -0700621{
622 int ret;
623
624 writel_i(out_bytes, ds->regs->qup_mx_output_count);
625
626 ret = config_spi_state(ds, SPI_RUN_STATE);
627 if (ret)
628 return ret;
629
630 while (out_bytes) {
631 if (readl_i(ds->regs->qup_operational) & QUP_OUTPUT_FIFO_FULL)
632 continue;
633
634 writel_i(*dout++, ds->regs->qup_output_fifo);
635 out_bytes--;
636
637 /* Wait for output FIFO to drain. */
638 if (!out_bytes)
639 while (readl_i(ds->regs->qup_operational) &
640 QUP_OUTPUT_FIFO_NOT_EMPTY)
641 ;
642 }
643
644 return config_spi_state(ds, SPI_RESET_STATE);
645}
646
647static int spi_xfer_rx_packet(struct ipq_spi_slave *ds,
Martin Roth57e89092019-10-23 21:45:23 -0600648 uint8_t *din, unsigned int in_bytes)
David Hendricks68ec2fc2014-07-25 12:59:48 -0700649{
650 int ret;
651
652 writel_i(in_bytes, ds->regs->qup_mx_input_count);
653 writel_i(in_bytes, ds->regs->qup_mx_output_count);
654
655 ret = config_spi_state(ds, SPI_RUN_STATE);
656 if (ret)
657 return ret;
658
659 /* Seed clocking */
660 writel_i(0xff, ds->regs->qup_output_fifo);
661 while (in_bytes) {
662 if (!(readl_i(ds->regs->qup_operational) &
663 QUP_INPUT_FIFO_NOT_EMPTY))
664 continue;
665 /* Keep it clocking */
666 writel_i(0xff, ds->regs->qup_output_fifo);
667
668 *din++ = readl_i(ds->regs->qup_input_fifo) & 0xff;
669 in_bytes--;
670 }
671
672 return config_spi_state(ds, SPI_RESET_STATE);
673}
674
Furquan Shaikh94f86992016-12-01 07:12:32 -0800675static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
676 size_t out_bytes, void *din, size_t in_bytes)
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700677{
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700678 int ret;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700679 struct ipq_spi_slave *ds = to_ipq_spi(slave);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700680
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700681 /* Assert the chip select */
682 CS_change(ds->slave.bus, ds->slave.cs, CS_ASSERT);
683
684 ret = config_spi_state(ds, SPI_RESET_STATE);
685 if (ret)
686 goto out;
687
688 if (!out_bytes)
689 goto spi_receive;
690
691 /*
692 * Let's do the write side of the transaction first. Enable output
693 * FIFO.
694 */
Julius Werner55009af2019-12-02 22:03:27 -0800695 clrsetbits32_i(ds->regs->qup_config, SPI_QUP_CONF_OUTPUT_MSK,
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700696 SPI_QUP_CONF_OUTPUT_ENA);
697
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700698 while (out_bytes) {
Martin Roth57e89092019-10-23 21:45:23 -0600699 unsigned int todo = MIN(out_bytes, MAX_PACKET_COUNT);
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700700
David Hendricks68ec2fc2014-07-25 12:59:48 -0700701 ret = spi_xfer_tx_packet(ds, dout, todo);
702 if (ret)
703 break;
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700704
David Hendricks68ec2fc2014-07-25 12:59:48 -0700705 out_bytes -= todo;
706 dout += todo;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700707 }
708
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700709 if (ret)
710 goto out;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700711
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700712spi_receive:
713 if (!in_bytes) /* Nothing to read. */
714 goto out;
715
716 /* Enable input FIFO */
Julius Werner55009af2019-12-02 22:03:27 -0800717 clrsetbits32_i(ds->regs->qup_config, SPI_QUP_CONF_INPUT_MSK,
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700718 SPI_QUP_CONF_INPUT_ENA);
719
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700720 while (in_bytes) {
Martin Roth57e89092019-10-23 21:45:23 -0600721 unsigned int todo = MIN(in_bytes, MAX_PACKET_COUNT);
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700722
David Hendricks68ec2fc2014-07-25 12:59:48 -0700723 ret = spi_xfer_rx_packet(ds, din, todo);
724 if (ret)
725 break;
726
727 in_bytes -= todo;
728 din += todo;
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700729 }
730
David Hendricks68ec2fc2014-07-25 12:59:48 -0700731out:
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700732 /* Deassert CS */
733 CS_change(ds->slave.bus, ds->slave.cs, CS_DEASSERT);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700734
Vadim Bendeburydffd8922014-04-30 13:25:12 -0700735 /*
736 * Put the SPI Core back in the Reset State
737 * to end the transfer
738 */
739 (void)config_spi_state(ds, SPI_RESET_STATE);
Vadim Bendebury3afa03e2014-04-10 14:20:39 -0700740
741 return ret;
742}
Furquan Shaikh94f86992016-12-01 07:12:32 -0800743
Furquan Shaikhe424a592017-05-18 14:40:58 -0700744static int spi_ctrlr_setup(const struct spi_slave *slave)
Furquan Shaikh94f86992016-12-01 07:12:32 -0800745{
746 struct ipq_spi_slave *ds = NULL;
747 int i;
Julius Werner7c712bb2019-05-01 16:51:20 -0700748 int bus = slave->bus;
749 int cs = slave->cs;
Furquan Shaikh94f86992016-12-01 07:12:32 -0800750
751 /*
752 * IPQ GSBI (Generic Serial Bus Interface) supports SPI Flash
753 * on different GSBI5, GSBI6 and GSBI7
754 * with different number of chip selects (CS, channels):
755 */
756 if ((bus < GSBI5_SPI) || (bus > GSBI7_SPI)
757 || ((bus == GSBI5_SPI) && (cs > 3))
758 || ((bus == GSBI6_SPI) && (cs > 0))
759 || ((bus == GSBI7_SPI) && (cs > 0))) {
760 printk(BIOS_ERR, "SPI error: unsupported bus %d "
Martin Roth26f97f92021-10-01 14:53:22 -0600761 "(Supported buses 0,1 and 2) or chipselect\n", bus);
Furquan Shaikh94f86992016-12-01 07:12:32 -0800762 }
763
764 for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) {
765 if (spi_slave_pool[i].allocated)
766 continue;
767 ds = spi_slave_pool + i;
768
Furquan Shaikhe424a592017-05-18 14:40:58 -0700769 ds->slave.bus = bus;
770 ds->slave.cs = cs;
Furquan Shaikh94f86992016-12-01 07:12:32 -0800771 ds->regs = &spi_reg[bus];
772
773 /*
774 * TODO(vbendeb):
775 * hardcoded frequency and mode - we might need to find a way
776 * to configure this
777 */
778 ds->freq = 10000000;
779 ds->mode = GSBI_SPI_MODE_0;
780 ds->allocated = 1;
781
782 return 0;
783 }
784
785 printk(BIOS_ERR, "SPI error: all %d pools busy\n", i);
786 return -1;
787}
Furquan Shaikhe424a592017-05-18 14:40:58 -0700788
789static const struct spi_ctrlr spi_ctrlr = {
790 .setup = spi_ctrlr_setup,
791 .claim_bus = spi_ctrlr_claim_bus,
792 .release_bus = spi_ctrlr_release_bus,
793 .xfer = spi_ctrlr_xfer,
794 .max_xfer_size = MAX_PACKET_COUNT,
795};
796
797const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
798 {
799 .ctrlr = &spi_ctrlr,
800 .bus_start = GSBI5_SPI,
801 .bus_end = GSBI7_SPI,
802 },
803};
804
805const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);