Angel Pons | 7c1d70e | 2020-04-04 18:51:19 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 2 | |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 3 | #include <device/mmio.h> |
Furquan Shaikh | c28984d | 2016-11-20 21:04:00 -0800 | [diff] [blame] | 4 | #include <console/console.h> |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 5 | #include <delay.h> |
Julius Werner | eaa9c45 | 2014-09-24 15:40:49 -0700 | [diff] [blame] | 6 | #include <gpio.h> |
Julius Werner | 73d1ed6 | 2014-10-20 13:20:49 -0700 | [diff] [blame] | 7 | #include <soc/iomap.h> |
| 8 | #include <soc/spi.h> |
Elyes HAOUAS | 17b1a16 | 2019-06-23 07:08:12 +0200 | [diff] [blame] | 9 | #include <types.h> |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 10 | |
| 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 Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 28 | /* Arbitrarily assigned error code values */ |
| 29 | #define ETIMEDOUT -10 |
| 30 | #define EINVAL -11 |
| 31 | #define EIO -12 |
| 32 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 33 | #define GSBI_IDX_TO_GSBI(idx) (idx + 5) |
| 34 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 35 | /* 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 Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 39 | /* |
| 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 | */ |
| 47 | static 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 | */ |
| 107 | static 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 | */ |
| 125 | static 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 | */ |
| 137 | static 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 Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 143 | static int check_bit_state(uint32_t reg_addr, int bit_num, int val, int us_delay) |
| 144 | { |
| 145 | unsigned int count = TIMEOUT_CNT; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 146 | unsigned int bit_val = ((readl_i(reg_addr) >> bit_num) & 0x01); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 147 | |
| 148 | while (bit_val != val) { |
| 149 | count--; |
| 150 | if (count == 0) |
| 151 | return -ETIMEDOUT; |
| 152 | udelay(us_delay); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 153 | bit_val = ((readl_i(reg_addr) >> bit_num) & 0x01); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 154 | } |
| 155 | |
| 156 | return SUCCESS; |
| 157 | } |
| 158 | |
| 159 | /* |
| 160 | * Check whether GSBIn_QUP State is valid |
| 161 | */ |
| 162 | static 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 | */ |
| 173 | static int config_spi_state(struct ipq_spi_slave *ds, unsigned int state) |
| 174 | { |
| 175 | uint32_t val; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 176 | int ret; |
| 177 | uint32_t new_state; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 178 | |
| 179 | ret = check_qup_state_valid(ds); |
| 180 | if (ret != SUCCESS) |
| 181 | return ret; |
| 182 | |
| 183 | switch (state) { |
| 184 | case SPI_RUN_STATE: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 185 | new_state = QUP_STATE_RUN_STATE; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 186 | break; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 187 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 188 | case SPI_RESET_STATE: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 189 | new_state = QUP_STATE_RESET_STATE; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 190 | break; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 191 | |
| 192 | case SPI_PAUSE_STATE: |
| 193 | new_state = QUP_STATE_PAUSE_STATE; |
| 194 | break; |
| 195 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 196 | default: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 197 | printk(BIOS_ERR, |
| 198 | "err: unsupported GSBI SPI state : %d\n", state); |
| 199 | return -EINVAL; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 200 | } |
| 201 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 202 | /* 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 Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | /* |
| 210 | * Set GSBIn SPI Mode |
| 211 | */ |
| 212 | static 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 Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 236 | printk(BIOS_ERR, |
| 237 | "err : unsupported spi mode : %d\n", mode); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 238 | return; |
| 239 | } |
| 240 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 241 | val = readl_i(ds->regs->spi_config); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 242 | val |= input_first_mode; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 243 | writel_i(val, ds->regs->spi_config); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 244 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 245 | val = readl_i(ds->regs->io_control); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 246 | if (clk_idle_state) |
| 247 | val |= SPI_IO_CONTROL_CLOCK_IDLE_HIGH; |
| 248 | else |
| 249 | val &= ~SPI_IO_CONTROL_CLOCK_IDLE_HIGH; |
| 250 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 251 | writel_i(val, ds->regs->io_control); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | /* |
| 255 | * Check for HCLK state |
| 256 | */ |
| 257 | static int check_hclk_state(unsigned int core_num, int enable) |
| 258 | { |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 259 | 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 | */ |
| 266 | static int check_qup_clk_state(unsigned int core_num, int enable) |
| 267 | { |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 268 | 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 | */ |
| 275 | static 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 Bendebury | d36ef6a | 2014-07-25 17:34:42 -0700 | [diff] [blame] | 278 | void *addr = GPIO_IN_OUT_ADDR(cs_gpio); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 279 | uint32_t val = readl_i(addr); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 280 | |
Vadim Bendebury | 0b70bd1 | 2014-06-23 10:41:38 -0700 | [diff] [blame] | 281 | val &= (~(1 << GPIO_OUTPUT)); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 282 | if (!enable) |
Vadim Bendebury | 0b70bd1 | 2014-06-23 10:41:38 -0700 | [diff] [blame] | 283 | val |= (1 << GPIO_OUTPUT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 284 | write32(addr, val); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 285 | } |
| 286 | |
| 287 | /* |
| 288 | * GSBIn TLMM configuration |
| 289 | */ |
| 290 | static 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 Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 295 | clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(port_num)), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 296 | 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 | */ |
| 331 | static int gsbi_clock_init(struct ipq_spi_slave *ds) |
| 332 | { |
| 333 | int ret; |
| 334 | |
| 335 | /* Hold the GSBIn (core_num) core in reset */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 336 | clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 337 | GSBI1_RESET_MSK, GSBI1_RESET); |
| 338 | |
| 339 | /* Disable GSBIn (core_num) QUP core clock branch */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 340 | clrsetbits32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 341 | QUP_CLK_BRANCH_DIS); |
| 342 | |
| 343 | ret = check_qup_clk_state(ds->slave.bus, 1); |
| 344 | if (ret) { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 345 | printk(BIOS_ERR, |
| 346 | "QUP Clock Halt For GSBI%d failed!\n", ds->slave.bus); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 347 | return ret; |
| 348 | } |
| 349 | |
| 350 | /* Disable M/N:D counter and hold M/N:D counter in reset */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 351 | clrsetbits32_i(ds->regs->qup_ns_reg, (MNCNTR_MSK | MNCNTR_RST_MSK), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 352 | (MNCNTR_RST_ENA | MNCNTR_DIS)); |
| 353 | |
| 354 | /* Disable GSBIn (core_num) QUP core clock root */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 355 | clrsetbits32_i(ds->regs->qup_ns_reg, CLK_ROOT_ENA_MSK, CLK_ROOT_DIS); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 356 | |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 357 | clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_PLL_SRC_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 358 | GSBIn_PLL_SRC_PLL8); |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 359 | clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_PRE_DIV_SEL_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 360 | (0 << GSBI_PRE_DIV_SEL_SHFT)); |
| 361 | |
| 362 | /* Program M/N:D values for GSBIn_QUP_APPS_CLK @50MHz */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 363 | clrsetbits32_i(ds->regs->qup_md_reg, GSBIn_M_VAL_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 364 | (0x01 << GSBI_M_VAL_SHFT)); |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 365 | clrsetbits32_i(ds->regs->qup_md_reg, GSBIn_D_VAL_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 366 | (0xF7 << GSBI_D_VAL_SHFT)); |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 367 | clrsetbits32_i(ds->regs->qup_ns_reg, GSBIn_N_VAL_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 368 | (0xF8 << GSBI_N_VAL_SHFT)); |
| 369 | |
| 370 | /* Set MNCNTR_MODE = 0: Bypass mode */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 371 | clrsetbits32_i(ds->regs->qup_ns_reg, MNCNTR_MODE_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 372 | MNCNTR_MODE_DUAL_EDGE); |
| 373 | |
| 374 | /* De-assert the M/N:D counter reset */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 375 | 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 Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 377 | |
| 378 | /* |
| 379 | * Enable the GSBIn (core_num) QUP core clock root. |
| 380 | * Keep MND counter disabled |
| 381 | */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 382 | clrsetbits32_i(ds->regs->qup_ns_reg, CLK_ROOT_ENA_MSK, CLK_ROOT_ENA); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 383 | |
| 384 | /* Enable GSBIn (core_num) QUP core clock branch */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 385 | clrsetbits32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 386 | QUP_CLK_BRANCH_ENA); |
| 387 | |
| 388 | ret = check_qup_clk_state(ds->slave.bus, 0); |
| 389 | if (ret) { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 390 | printk(BIOS_ERR, |
| 391 | "QUP Clock Enable For GSBI%d" |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 392 | " failed!\n", ds->slave.bus); |
| 393 | return ret; |
| 394 | } |
| 395 | |
| 396 | /* Enable GSBIn (core_num) core clock branch */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 397 | clrsetbits32_i(GSBIn_HCLK_CTL_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 398 | GSBI_CLK_BRANCH_ENA_MSK, GSBI_CLK_BRANCH_ENA); |
| 399 | |
| 400 | ret = check_hclk_state(ds->slave.bus, 0); |
| 401 | if (ret) { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 402 | printk(BIOS_ERR, |
| 403 | "HCLK Enable For GSBI%d failed!\n", ds->slave.bus); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 404 | return ret; |
| 405 | } |
| 406 | |
| 407 | /* Release GSBIn (core_num) core from reset */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 408 | clrsetbits32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 409 | GSBI1_RESET_MSK, 0); |
| 410 | udelay(50); |
| 411 | |
| 412 | return SUCCESS; |
| 413 | } |
| 414 | |
| 415 | /* |
| 416 | * Reset entire QUP and all mini cores |
| 417 | */ |
| 418 | static void spi_reset(struct ipq_spi_slave *ds) |
| 419 | { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 420 | writel_i(0x1, ds->regs->qup_sw_reset); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 421 | udelay(5); |
| 422 | } |
| 423 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 424 | static 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 | }; |
| 489 | static struct ipq_spi_slave spi_slave_pool[2]; |
| 490 | |
Furquan Shaikh | 36b81af | 2016-12-01 01:02:44 -0800 | [diff] [blame] | 491 | static 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 Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 510 | /* |
| 511 | * GSBIn SPI Hardware Initialisation |
| 512 | */ |
| 513 | static int spi_hw_init(struct ipq_spi_slave *ds) |
| 514 | { |
| 515 | int ret; |
| 516 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 517 | if (ds->initialized) |
| 518 | return 0; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 519 | |
| 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 Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 529 | clrsetbits32_i(ds->regs->gsbi_ctrl, PROTOCOL_CODE_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 530 | PROTOCOL_CODE_SPI); |
| 531 | |
| 532 | /* |
| 533 | * Configure Mini core to SPI core with Input Output enabled, |
| 534 | * SPI master, N = 8 bits |
| 535 | */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 536 | clrsetbits32_i(ds->regs->qup_config, (QUP_CONFIG_MINI_CORE_MSK | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 537 | SPI_QUP_CONF_INPUT_MSK | |
| 538 | SPI_QUP_CONF_OUTPUT_MSK | |
| 539 | SPI_BIT_WORD_MSK), |
| 540 | (QUP_CONFIG_MINI_CORE_SPI | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 541 | SPI_QUP_CONF_NO_INPUT | |
| 542 | SPI_QUP_CONF_NO_OUTPUT | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 543 | SPI_8_BIT_WORD)); |
| 544 | |
| 545 | /* |
| 546 | * Configure Input first SPI protocol, |
| 547 | * SPI master mode and no loopback |
| 548 | */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 549 | clrsetbits32_i(ds->regs->spi_config, (LOOP_BACK_MSK | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 550 | 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 Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 560 | writel_i((CLK_ALWAYS_ON | MX_CS_MODE | NO_TRI_STATE), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 561 | 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 Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 569 | clrsetbits32_i(ds->regs->qup_io_modes, (OUTPUT_BIT_SHIFT_MSK | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 570 | 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 Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 579 | writel_i(0, ds->regs->error_flags_en); |
| 580 | writel_i(0, ds->regs->qup_error_flags_en); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 581 | |
| 582 | ds->initialized = 1; |
| 583 | |
| 584 | return SUCCESS; |
| 585 | } |
| 586 | |
Furquan Shaikh | 94f8699 | 2016-12-01 07:12:32 -0800 | [diff] [blame] | 587 | static int spi_ctrlr_claim_bus(const struct spi_slave *slave) |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 588 | { |
| 589 | struct ipq_spi_slave *ds = to_ipq_spi(slave); |
| 590 | unsigned int ret; |
| 591 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 592 | if (ds->initialized) |
| 593 | return SUCCESS; |
| 594 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 595 | /* 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 Shaikh | 94f8699 | 2016-12-01 07:12:32 -0800 | [diff] [blame] | 610 | static void spi_ctrlr_release_bus(const struct spi_slave *slave) |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 611 | { |
| 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 Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 619 | static int spi_xfer_tx_packet(struct ipq_spi_slave *ds, |
Martin Roth | 57e8909 | 2019-10-23 21:45:23 -0600 | [diff] [blame] | 620 | const uint8_t *dout, unsigned int out_bytes) |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 621 | { |
| 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 | |
| 647 | static int spi_xfer_rx_packet(struct ipq_spi_slave *ds, |
Martin Roth | 57e8909 | 2019-10-23 21:45:23 -0600 | [diff] [blame] | 648 | uint8_t *din, unsigned int in_bytes) |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 649 | { |
| 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 Shaikh | 94f8699 | 2016-12-01 07:12:32 -0800 | [diff] [blame] | 675 | static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, |
| 676 | size_t out_bytes, void *din, size_t in_bytes) |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 677 | { |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 678 | int ret; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 679 | struct ipq_spi_slave *ds = to_ipq_spi(slave); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 680 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 681 | /* 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 Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 695 | clrsetbits32_i(ds->regs->qup_config, SPI_QUP_CONF_OUTPUT_MSK, |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 696 | SPI_QUP_CONF_OUTPUT_ENA); |
| 697 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 698 | while (out_bytes) { |
Martin Roth | 57e8909 | 2019-10-23 21:45:23 -0600 | [diff] [blame] | 699 | unsigned int todo = MIN(out_bytes, MAX_PACKET_COUNT); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 700 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 701 | ret = spi_xfer_tx_packet(ds, dout, todo); |
| 702 | if (ret) |
| 703 | break; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 704 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 705 | out_bytes -= todo; |
| 706 | dout += todo; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 707 | } |
| 708 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 709 | if (ret) |
| 710 | goto out; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 711 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 712 | spi_receive: |
| 713 | if (!in_bytes) /* Nothing to read. */ |
| 714 | goto out; |
| 715 | |
| 716 | /* Enable input FIFO */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 717 | clrsetbits32_i(ds->regs->qup_config, SPI_QUP_CONF_INPUT_MSK, |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 718 | SPI_QUP_CONF_INPUT_ENA); |
| 719 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 720 | while (in_bytes) { |
Martin Roth | 57e8909 | 2019-10-23 21:45:23 -0600 | [diff] [blame] | 721 | unsigned int todo = MIN(in_bytes, MAX_PACKET_COUNT); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 722 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 723 | ret = spi_xfer_rx_packet(ds, din, todo); |
| 724 | if (ret) |
| 725 | break; |
| 726 | |
| 727 | in_bytes -= todo; |
| 728 | din += todo; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 729 | } |
| 730 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 731 | out: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 732 | /* Deassert CS */ |
| 733 | CS_change(ds->slave.bus, ds->slave.cs, CS_DEASSERT); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 734 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 735 | /* |
| 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 Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 740 | |
| 741 | return ret; |
| 742 | } |
Furquan Shaikh | 94f8699 | 2016-12-01 07:12:32 -0800 | [diff] [blame] | 743 | |
Furquan Shaikh | e424a59 | 2017-05-18 14:40:58 -0700 | [diff] [blame] | 744 | static int spi_ctrlr_setup(const struct spi_slave *slave) |
Furquan Shaikh | 94f8699 | 2016-12-01 07:12:32 -0800 | [diff] [blame] | 745 | { |
| 746 | struct ipq_spi_slave *ds = NULL; |
| 747 | int i; |
Julius Werner | 7c712bb | 2019-05-01 16:51:20 -0700 | [diff] [blame] | 748 | int bus = slave->bus; |
| 749 | int cs = slave->cs; |
Furquan Shaikh | 94f8699 | 2016-12-01 07:12:32 -0800 | [diff] [blame] | 750 | |
| 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 Roth | 26f97f9 | 2021-10-01 14:53:22 -0600 | [diff] [blame] | 761 | "(Supported buses 0,1 and 2) or chipselect\n", bus); |
Furquan Shaikh | 94f8699 | 2016-12-01 07:12:32 -0800 | [diff] [blame] | 762 | } |
| 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 Shaikh | e424a59 | 2017-05-18 14:40:58 -0700 | [diff] [blame] | 769 | ds->slave.bus = bus; |
| 770 | ds->slave.cs = cs; |
Furquan Shaikh | 94f8699 | 2016-12-01 07:12:32 -0800 | [diff] [blame] | 771 | 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 Shaikh | e424a59 | 2017-05-18 14:40:58 -0700 | [diff] [blame] | 788 | |
| 789 | static 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 | |
| 797 | const 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 | |
| 805 | const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map); |