Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2012 The Linux Foundation. All rights reserved. |
| 3 | */ |
| 4 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 5 | #include <arch/io.h> |
| 6 | #include <delay.h> |
Julius Werner | eaa9c45 | 2014-09-24 15:40:49 -0700 | [diff] [blame] | 7 | #include <gpio.h> |
Julius Werner | 73d1ed6 | 2014-10-20 13:20:49 -0700 | [diff] [blame] | 8 | #include <soc/iomap.h> |
| 9 | #include <soc/spi.h> |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 10 | #include <stdlib.h> |
| 11 | #include <string.h> |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 12 | |
| 13 | #define SUCCESS 0 |
| 14 | |
| 15 | #define DUMMY_DATA_VAL 0 |
| 16 | #define TIMEOUT_CNT 100 |
| 17 | #define CS_ASSERT 1 |
| 18 | #define CS_DEASSERT 0 |
| 19 | #define NUM_PORTS 3 |
| 20 | #define NUM_GSBI_PINS 3 |
| 21 | #define TLMM_ARGS 6 |
| 22 | #define NUM_CS 4 |
| 23 | #define GSBI_PIN_IDX 0 |
| 24 | #define FUNC_SEL_IDX 1 |
| 25 | #define GPIO_DIR_IDX 2 |
| 26 | #define PULL_CONF_IDX 3 |
| 27 | #define DRV_STR_IDX 4 |
| 28 | #define GPIO_EN_IDX 5 |
| 29 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 30 | /* Arbitrarily assigned error code values */ |
| 31 | #define ETIMEDOUT -10 |
| 32 | #define EINVAL -11 |
| 33 | #define EIO -12 |
| 34 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 35 | #define GSBI_IDX_TO_GSBI(idx) (idx + 5) |
| 36 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 37 | |
| 38 | /* MX_INPUT_COUNT and MX_OUTPUT_COUNT are 16-bits. Zero has a special meaning |
| 39 | * (count function disabled) and does not hold significance in the count. */ |
| 40 | #define MAX_PACKET_COUNT ((64 * KiB) - 1) |
| 41 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 42 | /* |
| 43 | * TLMM Configuration for SPI NOR |
| 44 | * gsbi_pin_conf[bus_num][GPIO_NUM, FUNC_SEL, I/O, |
| 45 | * PULL UP/DOWN, DRV_STR, GPIO_FUNC] |
| 46 | * gsbi_pin_conf[0][x][y] -- GSBI5 |
| 47 | * gsbi_pin_conf[1][x][y] -- GSBI6 |
| 48 | * gsbi_pin_conf[2][x][y] -- GSBI7 |
| 49 | */ |
| 50 | static unsigned int gsbi_pin_conf[NUM_PORTS][NUM_GSBI_PINS][TLMM_ARGS] = { |
| 51 | { |
| 52 | /* GSBI5 CLK */ |
| 53 | { |
| 54 | GSBI5_SPI_CLK, FUNC_SEL_1, GPIO_INPUT, |
| 55 | GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE |
| 56 | }, |
| 57 | /* GSBI5 MISO */ |
| 58 | { |
| 59 | GSBI5_SPI_MISO, FUNC_SEL_1, GPIO_INPUT, |
| 60 | GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE |
| 61 | }, |
| 62 | /* GSBI5 MOSI */ |
| 63 | { |
| 64 | GSBI5_SPI_MOSI, FUNC_SEL_1, GPIO_INPUT, |
| 65 | GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE |
| 66 | } |
| 67 | }, |
| 68 | { |
| 69 | /* GSBI6 CLK */ |
| 70 | { |
| 71 | GSBI6_SPI_CLK, FUNC_SEL_3, GPIO_INPUT, |
| 72 | GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE |
| 73 | }, |
| 74 | /* GSBI6 MISO */ |
| 75 | { |
| 76 | GSBI6_SPI_MISO, FUNC_SEL_3, GPIO_INPUT, |
| 77 | GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE |
| 78 | }, |
| 79 | /* GSBI6 MOSI */ |
| 80 | { |
| 81 | GSBI6_SPI_MOSI, FUNC_SEL_3, GPIO_INPUT, |
| 82 | GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE |
| 83 | } |
| 84 | }, |
| 85 | { |
| 86 | /* GSBI7 CLK */ |
| 87 | { |
| 88 | GSBI7_SPI_CLK, FUNC_SEL_1, GPIO_INPUT, |
| 89 | GPIO_PULL_DOWN, GPIO_DRV_STR_11MA, GPIO_FUNC_DISABLE |
| 90 | }, |
| 91 | /* GSBI7 MISO */ |
| 92 | { |
| 93 | GSBI7_SPI_MISO, FUNC_SEL_1, GPIO_INPUT, |
| 94 | GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE |
| 95 | }, |
| 96 | /* GSBI7 MOSI */ |
| 97 | { |
| 98 | GSBI7_SPI_MOSI, FUNC_SEL_1, GPIO_INPUT, |
| 99 | GPIO_PULL_DOWN, GPIO_DRV_STR_10MA, GPIO_FUNC_DISABLE |
| 100 | } |
| 101 | } |
| 102 | }; |
| 103 | |
| 104 | /* |
| 105 | * CS GPIO number array cs_gpio_array[port_num][cs_num] |
| 106 | * cs_gpio_array[0][x] -- GSBI5 |
| 107 | * cs_gpio_array[1][x] -- GSBI6 |
| 108 | * cs_gpio_array[2][x] -- GSBI7 |
| 109 | */ |
| 110 | static unsigned int cs_gpio_array[NUM_PORTS][NUM_CS] = { |
| 111 | { |
| 112 | GSBI5_SPI_CS_0, GSBI5_SPI_CS_1, GSBI5_SPI_CS_2, GSBI5_SPI_CS_3 |
| 113 | }, |
| 114 | { |
| 115 | GSBI6_SPI_CS_0, 0, 0, 0 |
| 116 | }, |
| 117 | { |
| 118 | GSBI7_SPI_CS_0, 0, 0, 0 |
| 119 | } |
| 120 | }; |
| 121 | |
| 122 | /* |
| 123 | * GSBI HCLK state register bit |
| 124 | * hclk_state[0] -- GSBI5 |
| 125 | * hclk_state[1] -- GSBI6 |
| 126 | * hclk_state[2] -- GSBI7 |
| 127 | */ |
| 128 | static unsigned int hclk_state[NUM_PORTS] = { |
| 129 | GSBI5_HCLK, |
| 130 | GSBI6_HCLK, |
| 131 | GSBI7_HCLK |
| 132 | }; |
| 133 | |
| 134 | /* |
| 135 | * GSBI QUP_APPS_CLK state register bit |
| 136 | * qup_apps_clk_state[0] -- GSBI5 |
| 137 | * qup_apps_clk_state[1] -- GSBI6 |
| 138 | * qup_apps_clk_state[2] -- GSBI7 |
| 139 | */ |
| 140 | static unsigned int qup_apps_clk_state[NUM_PORTS] = { |
| 141 | GSBI5_QUP_APPS_CLK, |
| 142 | GSBI6_QUP_APPS_CLK, |
| 143 | GSBI7_QUP_APPS_CLK |
| 144 | }; |
| 145 | |
| 146 | |
| 147 | static int check_bit_state(uint32_t reg_addr, int bit_num, int val, int us_delay) |
| 148 | { |
| 149 | unsigned int count = TIMEOUT_CNT; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 150 | unsigned int bit_val = ((readl_i(reg_addr) >> bit_num) & 0x01); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 151 | |
| 152 | while (bit_val != val) { |
| 153 | count--; |
| 154 | if (count == 0) |
| 155 | return -ETIMEDOUT; |
| 156 | udelay(us_delay); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 157 | bit_val = ((readl_i(reg_addr) >> bit_num) & 0x01); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | return SUCCESS; |
| 161 | } |
| 162 | |
| 163 | /* |
| 164 | * Check whether GSBIn_QUP State is valid |
| 165 | */ |
| 166 | static int check_qup_state_valid(struct ipq_spi_slave *ds) |
| 167 | { |
| 168 | |
| 169 | return check_bit_state(ds->regs->qup_state, QUP_STATE_VALID_BIT, |
| 170 | QUP_STATE_VALID, 1); |
| 171 | |
| 172 | } |
| 173 | |
| 174 | /* |
| 175 | * Configure GSBIn Core state |
| 176 | */ |
| 177 | static int config_spi_state(struct ipq_spi_slave *ds, unsigned int state) |
| 178 | { |
| 179 | uint32_t val; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 180 | int ret; |
| 181 | uint32_t new_state; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 182 | |
| 183 | ret = check_qup_state_valid(ds); |
| 184 | if (ret != SUCCESS) |
| 185 | return ret; |
| 186 | |
| 187 | switch (state) { |
| 188 | case SPI_RUN_STATE: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 189 | new_state = QUP_STATE_RUN_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 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 192 | case SPI_RESET_STATE: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 193 | new_state = QUP_STATE_RESET_STATE; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 194 | break; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 195 | |
| 196 | case SPI_PAUSE_STATE: |
| 197 | new_state = QUP_STATE_PAUSE_STATE; |
| 198 | break; |
| 199 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 200 | default: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 201 | printk(BIOS_ERR, |
| 202 | "err: unsupported GSBI SPI state : %d\n", state); |
| 203 | return -EINVAL; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 204 | } |
| 205 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 206 | /* Set the state as requested */ |
| 207 | val = (readl_i(ds->regs->qup_state) & ~QUP_STATE_MASK) |
| 208 | | new_state; |
| 209 | writel_i(val, ds->regs->qup_state); |
| 210 | return check_qup_state_valid(ds); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | /* |
| 214 | * Set GSBIn SPI Mode |
| 215 | */ |
| 216 | static void spi_set_mode(struct ipq_spi_slave *ds, unsigned int mode) |
| 217 | { |
| 218 | unsigned int clk_idle_state; |
| 219 | unsigned int input_first_mode; |
| 220 | uint32_t val; |
| 221 | |
| 222 | switch (mode) { |
| 223 | case GSBI_SPI_MODE_0: |
| 224 | clk_idle_state = 0; |
| 225 | input_first_mode = SPI_INPUT_FIRST_MODE; |
| 226 | break; |
| 227 | case GSBI_SPI_MODE_1: |
| 228 | clk_idle_state = 0; |
| 229 | input_first_mode = 0; |
| 230 | break; |
| 231 | case GSBI_SPI_MODE_2: |
| 232 | clk_idle_state = 1; |
| 233 | input_first_mode = SPI_INPUT_FIRST_MODE; |
| 234 | break; |
| 235 | case GSBI_SPI_MODE_3: |
| 236 | clk_idle_state = 1; |
| 237 | input_first_mode = 0; |
| 238 | break; |
| 239 | default: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 240 | printk(BIOS_ERR, |
| 241 | "err : unsupported spi mode : %d\n", mode); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 242 | return; |
| 243 | } |
| 244 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 245 | val = readl_i(ds->regs->spi_config); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 246 | val |= input_first_mode; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 247 | writel_i(val, ds->regs->spi_config); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 248 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 249 | val = readl_i(ds->regs->io_control); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 250 | if (clk_idle_state) |
| 251 | val |= SPI_IO_CONTROL_CLOCK_IDLE_HIGH; |
| 252 | else |
| 253 | val &= ~SPI_IO_CONTROL_CLOCK_IDLE_HIGH; |
| 254 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 255 | writel_i(val, ds->regs->io_control); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 256 | } |
| 257 | |
| 258 | /* |
| 259 | * Check for HCLK state |
| 260 | */ |
| 261 | static int check_hclk_state(unsigned int core_num, int enable) |
| 262 | { |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 263 | return check_bit_state(CLK_HALT_CFPB_STATEB_REG, |
| 264 | hclk_state[core_num], enable, 5); |
| 265 | } |
| 266 | |
| 267 | /* |
| 268 | * Check for QUP APPS CLK state |
| 269 | */ |
| 270 | static int check_qup_clk_state(unsigned int core_num, int enable) |
| 271 | { |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 272 | return check_bit_state(CLK_HALT_CFPB_STATEB_REG, |
| 273 | qup_apps_clk_state[core_num], enable, 5); |
| 274 | } |
| 275 | |
| 276 | /* |
| 277 | * Function to assert and De-assert chip select |
| 278 | */ |
| 279 | static void CS_change(int port_num, int cs_num, int enable) |
| 280 | { |
| 281 | unsigned int cs_gpio = cs_gpio_array[port_num][cs_num]; |
Vadim Bendebury | d36ef6a | 2014-07-25 17:34:42 -0700 | [diff] [blame] | 282 | void *addr = GPIO_IN_OUT_ADDR(cs_gpio); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 283 | uint32_t val = readl_i(addr); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 284 | |
Vadim Bendebury | 0b70bd1 | 2014-06-23 10:41:38 -0700 | [diff] [blame] | 285 | val &= (~(1 << GPIO_OUTPUT)); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 286 | if (!enable) |
Vadim Bendebury | 0b70bd1 | 2014-06-23 10:41:38 -0700 | [diff] [blame] | 287 | val |= (1 << GPIO_OUTPUT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 288 | write32(addr, val); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 289 | } |
| 290 | |
| 291 | /* |
| 292 | * GSBIn TLMM configuration |
| 293 | */ |
| 294 | static void gsbi_pin_config(unsigned int port_num, int cs_num) |
| 295 | { |
| 296 | unsigned int gpio; |
| 297 | unsigned int i; |
| 298 | /* Hold the GSBIn (core_num) core in reset */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 299 | clrsetbits_le32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(port_num)), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 300 | GSBI1_RESET_MSK, GSBI1_RESET); |
| 301 | |
| 302 | /* |
| 303 | * Configure SPI_CLK, SPI_MISO and SPI_MOSI |
| 304 | */ |
| 305 | for (i = 0; i < NUM_GSBI_PINS; i++) { |
| 306 | unsigned int func_sel; |
| 307 | unsigned int io_config; |
| 308 | unsigned int pull_config; |
| 309 | unsigned int drv_strength; |
| 310 | unsigned int gpio_en; |
| 311 | unsigned int *ptr; |
| 312 | |
| 313 | ptr = gsbi_pin_conf[port_num][i]; |
| 314 | gpio = *(ptr + GSBI_PIN_IDX); |
| 315 | func_sel = *(ptr + FUNC_SEL_IDX); |
| 316 | io_config = *(ptr + GPIO_DIR_IDX); |
| 317 | pull_config = *(ptr + PULL_CONF_IDX); |
| 318 | drv_strength = *(ptr + DRV_STR_IDX); |
| 319 | gpio_en = *(ptr + GPIO_EN_IDX); |
| 320 | |
| 321 | gpio_tlmm_config(gpio, func_sel, io_config, |
| 322 | pull_config, drv_strength, gpio_en); |
| 323 | } |
| 324 | |
| 325 | gpio = cs_gpio_array[port_num][cs_num]; |
| 326 | /* configure CS */ |
| 327 | gpio_tlmm_config(gpio, FUNC_SEL_GPIO, GPIO_OUTPUT, GPIO_PULL_UP, |
| 328 | GPIO_DRV_STR_10MA, GPIO_FUNC_ENABLE); |
| 329 | CS_change(port_num, cs_num, CS_DEASSERT); |
| 330 | } |
| 331 | |
| 332 | /* |
| 333 | * Clock configuration for GSBIn Core |
| 334 | */ |
| 335 | static int gsbi_clock_init(struct ipq_spi_slave *ds) |
| 336 | { |
| 337 | int ret; |
| 338 | |
| 339 | /* Hold the GSBIn (core_num) core in reset */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 340 | clrsetbits_le32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 341 | GSBI1_RESET_MSK, GSBI1_RESET); |
| 342 | |
| 343 | /* Disable GSBIn (core_num) QUP core clock branch */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 344 | clrsetbits_le32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 345 | QUP_CLK_BRANCH_DIS); |
| 346 | |
| 347 | ret = check_qup_clk_state(ds->slave.bus, 1); |
| 348 | if (ret) { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 349 | printk(BIOS_ERR, |
| 350 | "QUP Clock Halt For GSBI%d failed!\n", ds->slave.bus); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 351 | return ret; |
| 352 | } |
| 353 | |
| 354 | /* Disable M/N:D counter and hold M/N:D counter in reset */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 355 | clrsetbits_le32_i(ds->regs->qup_ns_reg, (MNCNTR_MSK | MNCNTR_RST_MSK), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 356 | (MNCNTR_RST_ENA | MNCNTR_DIS)); |
| 357 | |
| 358 | /* Disable GSBIn (core_num) QUP core clock root */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 359 | clrsetbits_le32_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] | 360 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 361 | clrsetbits_le32_i(ds->regs->qup_ns_reg, GSBIn_PLL_SRC_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 362 | GSBIn_PLL_SRC_PLL8); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 363 | clrsetbits_le32_i(ds->regs->qup_ns_reg, GSBIn_PRE_DIV_SEL_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 364 | (0 << GSBI_PRE_DIV_SEL_SHFT)); |
| 365 | |
| 366 | /* Program M/N:D values for GSBIn_QUP_APPS_CLK @50MHz */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 367 | clrsetbits_le32_i(ds->regs->qup_md_reg, GSBIn_M_VAL_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 368 | (0x01 << GSBI_M_VAL_SHFT)); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 369 | clrsetbits_le32_i(ds->regs->qup_md_reg, GSBIn_D_VAL_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 370 | (0xF7 << GSBI_D_VAL_SHFT)); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 371 | clrsetbits_le32_i(ds->regs->qup_ns_reg, GSBIn_N_VAL_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 372 | (0xF8 << GSBI_N_VAL_SHFT)); |
| 373 | |
| 374 | /* Set MNCNTR_MODE = 0: Bypass mode */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 375 | clrsetbits_le32_i(ds->regs->qup_ns_reg, MNCNTR_MODE_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 376 | MNCNTR_MODE_DUAL_EDGE); |
| 377 | |
| 378 | /* De-assert the M/N:D counter reset */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 379 | clrsetbits_le32_i(ds->regs->qup_ns_reg, MNCNTR_RST_MSK, MNCNTR_RST_DIS); |
| 380 | clrsetbits_le32_i(ds->regs->qup_ns_reg, MNCNTR_MSK, MNCNTR_EN); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 381 | |
| 382 | /* |
| 383 | * Enable the GSBIn (core_num) QUP core clock root. |
| 384 | * Keep MND counter disabled |
| 385 | */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 386 | clrsetbits_le32_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] | 387 | |
| 388 | /* Enable GSBIn (core_num) QUP core clock branch */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 389 | clrsetbits_le32_i(ds->regs->qup_ns_reg, QUP_CLK_BRANCH_ENA_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 390 | QUP_CLK_BRANCH_ENA); |
| 391 | |
| 392 | ret = check_qup_clk_state(ds->slave.bus, 0); |
| 393 | if (ret) { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 394 | printk(BIOS_ERR, |
| 395 | "QUP Clock Enable For GSBI%d" |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 396 | " failed!\n", ds->slave.bus); |
| 397 | return ret; |
| 398 | } |
| 399 | |
| 400 | /* Enable GSBIn (core_num) core clock branch */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 401 | clrsetbits_le32_i(GSBIn_HCLK_CTL_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 402 | GSBI_CLK_BRANCH_ENA_MSK, GSBI_CLK_BRANCH_ENA); |
| 403 | |
| 404 | ret = check_hclk_state(ds->slave.bus, 0); |
| 405 | if (ret) { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 406 | printk(BIOS_ERR, |
| 407 | "HCLK Enable For GSBI%d failed!\n", ds->slave.bus); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 408 | return ret; |
| 409 | } |
| 410 | |
| 411 | /* Release GSBIn (core_num) core from reset */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 412 | clrsetbits_le32_i(GSBIn_RESET_REG(GSBI_IDX_TO_GSBI(ds->slave.bus)), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 413 | GSBI1_RESET_MSK, 0); |
| 414 | udelay(50); |
| 415 | |
| 416 | return SUCCESS; |
| 417 | } |
| 418 | |
| 419 | /* |
| 420 | * Reset entire QUP and all mini cores |
| 421 | */ |
| 422 | static void spi_reset(struct ipq_spi_slave *ds) |
| 423 | { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 424 | writel_i(0x1, ds->regs->qup_sw_reset); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 425 | udelay(5); |
| 426 | } |
| 427 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 428 | static const struct gsbi_spi spi_reg[] = { |
| 429 | /* GSBI5 registers for SPI interface */ |
| 430 | { |
| 431 | GSBI5_SPI_CONFIG_REG, |
| 432 | GSBI5_SPI_IO_CONTROL_REG, |
| 433 | GSBI5_SPI_ERROR_FLAGS_REG, |
| 434 | GSBI5_SPI_ERROR_FLAGS_EN_REG, |
| 435 | GSBI5_GSBI_CTRL_REG_REG, |
| 436 | GSBI5_QUP_CONFIG_REG, |
| 437 | GSBI5_QUP_ERROR_FLAGS_REG, |
| 438 | GSBI5_QUP_ERROR_FLAGS_EN_REG, |
| 439 | GSBI5_QUP_OPERATIONAL_REG, |
| 440 | GSBI5_QUP_IO_MODES_REG, |
| 441 | GSBI5_QUP_STATE_REG, |
| 442 | GSBI5_QUP_INPUT_FIFOc_REG(0), |
| 443 | GSBI5_QUP_OUTPUT_FIFOc_REG(0), |
| 444 | GSBI5_QUP_MX_INPUT_COUNT_REG, |
| 445 | GSBI5_QUP_MX_OUTPUT_COUNT_REG, |
| 446 | GSBI5_QUP_SW_RESET_REG, |
| 447 | GSBIn_QUP_APPS_NS_REG(5), |
| 448 | GSBIn_QUP_APPS_MD_REG(5), |
| 449 | }, |
| 450 | /* GSBI6 registers for SPI interface */ |
| 451 | { |
| 452 | GSBI6_SPI_CONFIG_REG, |
| 453 | GSBI6_SPI_IO_CONTROL_REG, |
| 454 | GSBI6_SPI_ERROR_FLAGS_REG, |
| 455 | GSBI6_SPI_ERROR_FLAGS_EN_REG, |
| 456 | GSBI6_GSBI_CTRL_REG_REG, |
| 457 | GSBI6_QUP_CONFIG_REG, |
| 458 | GSBI6_QUP_ERROR_FLAGS_REG, |
| 459 | GSBI6_QUP_ERROR_FLAGS_EN_REG, |
| 460 | GSBI6_QUP_OPERATIONAL_REG, |
| 461 | GSBI6_QUP_IO_MODES_REG, |
| 462 | GSBI6_QUP_STATE_REG, |
| 463 | GSBI6_QUP_INPUT_FIFOc_REG(0), |
| 464 | GSBI6_QUP_OUTPUT_FIFOc_REG(0), |
| 465 | GSBI6_QUP_MX_INPUT_COUNT_REG, |
| 466 | GSBI6_QUP_MX_OUTPUT_COUNT_REG, |
| 467 | GSBI6_QUP_SW_RESET_REG, |
| 468 | GSBIn_QUP_APPS_NS_REG(6), |
| 469 | GSBIn_QUP_APPS_MD_REG(6), |
| 470 | }, |
| 471 | /* GSBI7 registers for SPI interface */ |
| 472 | { |
| 473 | GSBI7_SPI_CONFIG_REG, |
| 474 | GSBI7_SPI_IO_CONTROL_REG, |
| 475 | GSBI7_SPI_ERROR_FLAGS_REG, |
| 476 | GSBI7_SPI_ERROR_FLAGS_EN_REG, |
| 477 | GSBI7_GSBI_CTRL_REG_REG, |
| 478 | GSBI7_QUP_CONFIG_REG, |
| 479 | GSBI7_QUP_ERROR_FLAGS_REG, |
| 480 | GSBI7_QUP_ERROR_FLAGS_EN_REG, |
| 481 | GSBI7_QUP_OPERATIONAL_REG, |
| 482 | GSBI7_QUP_IO_MODES_REG, |
| 483 | GSBI7_QUP_STATE_REG, |
| 484 | GSBI7_QUP_INPUT_FIFOc_REG(0), |
| 485 | GSBI7_QUP_OUTPUT_FIFOc_REG(0), |
| 486 | GSBI7_QUP_MX_INPUT_COUNT_REG, |
| 487 | GSBI7_QUP_MX_OUTPUT_COUNT_REG, |
| 488 | GSBI7_QUP_SW_RESET_REG, |
| 489 | GSBIn_QUP_APPS_NS_REG(7), |
| 490 | GSBIn_QUP_APPS_MD_REG(7), |
| 491 | } |
| 492 | }; |
| 493 | static struct ipq_spi_slave spi_slave_pool[2]; |
| 494 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 495 | void spi_init() |
| 496 | { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 497 | /* just in case */ |
| 498 | memset(spi_slave_pool, 0, sizeof(spi_slave_pool)); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 499 | } |
| 500 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 501 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs) |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 502 | { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 503 | struct ipq_spi_slave *ds = NULL; |
| 504 | int i; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 505 | |
| 506 | /* |
| 507 | * IPQ GSBI (Generic Serial Bus Interface) supports SPI Flash |
| 508 | * on different GSBI5, GSBI6 and GSBI7 |
| 509 | * with different number of chip selects (CS, channels): |
| 510 | */ |
| 511 | if ((bus < GSBI5_SPI) || (bus > GSBI7_SPI) |
| 512 | || ((bus == GSBI5_SPI) && (cs > 3)) |
| 513 | || ((bus == GSBI6_SPI) && (cs > 0)) |
| 514 | || ((bus == GSBI7_SPI) && (cs > 0))) { |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 515 | printk(BIOS_ERR, "SPI error: unsupported bus %d " |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 516 | "(Supported busses 0,1 and 2) or chipselect\n", bus); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 517 | } |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 518 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 519 | for (i = 0; i < ARRAY_SIZE(spi_slave_pool); i++) { |
| 520 | if (spi_slave_pool[i].allocated) |
| 521 | continue; |
| 522 | ds = spi_slave_pool + i; |
| 523 | ds->slave.bus = bus; |
| 524 | ds->slave.cs = cs; |
| 525 | ds->regs = &spi_reg[bus]; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 526 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 527 | /* |
| 528 | * TODO(vbendeb): |
| 529 | * hardcoded frequency and mode - we might need to find a way |
| 530 | * to configure this |
| 531 | */ |
| 532 | ds->freq = 10000000; |
| 533 | ds->mode = GSBI_SPI_MODE_0; |
| 534 | ds->allocated = 1; |
| 535 | |
| 536 | return &ds->slave; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 537 | } |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 538 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 539 | printk(BIOS_ERR, "SPI error: all %d pools busy\n", i); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 540 | return NULL; |
| 541 | } |
| 542 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 543 | /* |
| 544 | * GSBIn SPI Hardware Initialisation |
| 545 | */ |
| 546 | static int spi_hw_init(struct ipq_spi_slave *ds) |
| 547 | { |
| 548 | int ret; |
| 549 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 550 | if (ds->initialized) |
| 551 | return 0; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 552 | |
| 553 | /* GSBI module configuration */ |
| 554 | spi_reset(ds); |
| 555 | |
| 556 | /* Set the GSBIn QUP state */ |
| 557 | ret = config_spi_state(ds, SPI_RESET_STATE); |
| 558 | if (ret) |
| 559 | return ret; |
| 560 | |
| 561 | /* Configure GSBI_CTRL register to set protocol_mode to SPI:011 */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 562 | clrsetbits_le32_i(ds->regs->gsbi_ctrl, PROTOCOL_CODE_MSK, |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 563 | PROTOCOL_CODE_SPI); |
| 564 | |
| 565 | /* |
| 566 | * Configure Mini core to SPI core with Input Output enabled, |
| 567 | * SPI master, N = 8 bits |
| 568 | */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 569 | clrsetbits_le32_i(ds->regs->qup_config, (QUP_CONFIG_MINI_CORE_MSK | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 570 | SPI_QUP_CONF_INPUT_MSK | |
| 571 | SPI_QUP_CONF_OUTPUT_MSK | |
| 572 | SPI_BIT_WORD_MSK), |
| 573 | (QUP_CONFIG_MINI_CORE_SPI | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 574 | SPI_QUP_CONF_NO_INPUT | |
| 575 | SPI_QUP_CONF_NO_OUTPUT | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 576 | SPI_8_BIT_WORD)); |
| 577 | |
| 578 | /* |
| 579 | * Configure Input first SPI protocol, |
| 580 | * SPI master mode and no loopback |
| 581 | */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 582 | clrsetbits_le32_i(ds->regs->spi_config, (LOOP_BACK_MSK | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 583 | SLAVE_OPERATION_MSK), |
| 584 | (NO_LOOP_BACK | |
| 585 | SLAVE_OPERATION)); |
| 586 | |
| 587 | /* |
| 588 | * Configure SPI IO Control Register |
| 589 | * CLK_ALWAYS_ON = 0 |
| 590 | * MX_CS_MODE = 0 |
| 591 | * NO_TRI_STATE = 1 |
| 592 | */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 593 | writel_i((CLK_ALWAYS_ON | MX_CS_MODE | NO_TRI_STATE), |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 594 | ds->regs->io_control); |
| 595 | |
| 596 | /* |
| 597 | * Configure SPI IO Modes. |
| 598 | * OUTPUT_BIT_SHIFT_EN = 1 |
| 599 | * INPUT_MODE = Block Mode |
| 600 | * OUTPUT MODE = Block Mode |
| 601 | */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 602 | clrsetbits_le32_i(ds->regs->qup_io_modes, (OUTPUT_BIT_SHIFT_MSK | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 603 | INPUT_BLOCK_MODE_MSK | |
| 604 | OUTPUT_BLOCK_MODE_MSK), |
| 605 | (OUTPUT_BIT_SHIFT_EN | |
| 606 | INPUT_BLOCK_MODE | |
| 607 | OUTPUT_BLOCK_MODE)); |
| 608 | |
| 609 | spi_set_mode(ds, ds->mode); |
| 610 | |
| 611 | /* Disable Error mask */ |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 612 | writel_i(0, ds->regs->error_flags_en); |
| 613 | writel_i(0, ds->regs->qup_error_flags_en); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 614 | |
| 615 | ds->initialized = 1; |
| 616 | |
| 617 | return SUCCESS; |
| 618 | } |
| 619 | |
| 620 | int spi_claim_bus(struct spi_slave *slave) |
| 621 | { |
| 622 | struct ipq_spi_slave *ds = to_ipq_spi(slave); |
| 623 | unsigned int ret; |
| 624 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 625 | if (ds->initialized) |
| 626 | return SUCCESS; |
| 627 | |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 628 | /* GPIO Configuration for SPI port */ |
| 629 | gsbi_pin_config(ds->slave.bus, ds->slave.cs); |
| 630 | |
| 631 | /* Clock configuration */ |
| 632 | ret = gsbi_clock_init(ds); |
| 633 | if (ret) |
| 634 | return ret; |
| 635 | |
| 636 | ret = spi_hw_init(ds); |
| 637 | if (ret) |
| 638 | return -EIO; |
| 639 | |
| 640 | return SUCCESS; |
| 641 | } |
| 642 | |
| 643 | void spi_release_bus(struct spi_slave *slave) |
| 644 | { |
| 645 | struct ipq_spi_slave *ds = to_ipq_spi(slave); |
| 646 | |
| 647 | /* Reset the SPI hardware */ |
| 648 | spi_reset(ds); |
| 649 | ds->initialized = 0; |
| 650 | } |
| 651 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 652 | static int spi_xfer_tx_packet(struct ipq_spi_slave *ds, |
| 653 | const uint8_t *dout, unsigned out_bytes) |
| 654 | { |
| 655 | int ret; |
| 656 | |
| 657 | writel_i(out_bytes, ds->regs->qup_mx_output_count); |
| 658 | |
| 659 | ret = config_spi_state(ds, SPI_RUN_STATE); |
| 660 | if (ret) |
| 661 | return ret; |
| 662 | |
| 663 | while (out_bytes) { |
| 664 | if (readl_i(ds->regs->qup_operational) & QUP_OUTPUT_FIFO_FULL) |
| 665 | continue; |
| 666 | |
| 667 | writel_i(*dout++, ds->regs->qup_output_fifo); |
| 668 | out_bytes--; |
| 669 | |
| 670 | /* Wait for output FIFO to drain. */ |
| 671 | if (!out_bytes) |
| 672 | while (readl_i(ds->regs->qup_operational) & |
| 673 | QUP_OUTPUT_FIFO_NOT_EMPTY) |
| 674 | ; |
| 675 | } |
| 676 | |
| 677 | return config_spi_state(ds, SPI_RESET_STATE); |
| 678 | } |
| 679 | |
| 680 | static int spi_xfer_rx_packet(struct ipq_spi_slave *ds, |
| 681 | uint8_t *din, unsigned in_bytes) |
| 682 | { |
| 683 | int ret; |
| 684 | |
| 685 | writel_i(in_bytes, ds->regs->qup_mx_input_count); |
| 686 | writel_i(in_bytes, ds->regs->qup_mx_output_count); |
| 687 | |
| 688 | ret = config_spi_state(ds, SPI_RUN_STATE); |
| 689 | if (ret) |
| 690 | return ret; |
| 691 | |
| 692 | /* Seed clocking */ |
| 693 | writel_i(0xff, ds->regs->qup_output_fifo); |
| 694 | while (in_bytes) { |
| 695 | if (!(readl_i(ds->regs->qup_operational) & |
| 696 | QUP_INPUT_FIFO_NOT_EMPTY)) |
| 697 | continue; |
| 698 | /* Keep it clocking */ |
| 699 | writel_i(0xff, ds->regs->qup_output_fifo); |
| 700 | |
| 701 | *din++ = readl_i(ds->regs->qup_input_fifo) & 0xff; |
| 702 | in_bytes--; |
| 703 | } |
| 704 | |
| 705 | return config_spi_state(ds, SPI_RESET_STATE); |
| 706 | } |
| 707 | |
Patrick Georgi | 3b1c238 | 2015-04-16 17:15:02 +0200 | [diff] [blame] | 708 | unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len) |
| 709 | { |
| 710 | return min(MAX_PACKET_COUNT, buf_len); |
| 711 | } |
| 712 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 713 | int spi_xfer(struct spi_slave *slave, const void *dout, |
| 714 | unsigned out_bytes, void *din, unsigned in_bytes) |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 715 | { |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 716 | int ret; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 717 | struct ipq_spi_slave *ds = to_ipq_spi(slave); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 718 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 719 | /* Assert the chip select */ |
| 720 | CS_change(ds->slave.bus, ds->slave.cs, CS_ASSERT); |
| 721 | |
| 722 | ret = config_spi_state(ds, SPI_RESET_STATE); |
| 723 | if (ret) |
| 724 | goto out; |
| 725 | |
| 726 | if (!out_bytes) |
| 727 | goto spi_receive; |
| 728 | |
| 729 | /* |
| 730 | * Let's do the write side of the transaction first. Enable output |
| 731 | * FIFO. |
| 732 | */ |
| 733 | clrsetbits_le32_i(ds->regs->qup_config, SPI_QUP_CONF_OUTPUT_MSK, |
| 734 | SPI_QUP_CONF_OUTPUT_ENA); |
| 735 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 736 | while (out_bytes) { |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 737 | unsigned todo = MIN(out_bytes, MAX_PACKET_COUNT); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 738 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 739 | ret = spi_xfer_tx_packet(ds, dout, todo); |
| 740 | if (ret) |
| 741 | break; |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 742 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 743 | out_bytes -= todo; |
| 744 | dout += todo; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 745 | } |
| 746 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 747 | if (ret) |
| 748 | goto out; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 749 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 750 | spi_receive: |
| 751 | if (!in_bytes) /* Nothing to read. */ |
| 752 | goto out; |
| 753 | |
| 754 | /* Enable input FIFO */ |
| 755 | clrsetbits_le32_i(ds->regs->qup_config, SPI_QUP_CONF_INPUT_MSK, |
| 756 | SPI_QUP_CONF_INPUT_ENA); |
| 757 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 758 | while (in_bytes) { |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 759 | unsigned todo = MIN(in_bytes, MAX_PACKET_COUNT); |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 760 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 761 | ret = spi_xfer_rx_packet(ds, din, todo); |
| 762 | if (ret) |
| 763 | break; |
| 764 | |
| 765 | in_bytes -= todo; |
| 766 | din += todo; |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 767 | } |
| 768 | |
David Hendricks | 68ec2fc | 2014-07-25 12:59:48 -0700 | [diff] [blame] | 769 | out: |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 770 | /* Deassert CS */ |
| 771 | CS_change(ds->slave.bus, ds->slave.cs, CS_DEASSERT); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 772 | |
Vadim Bendebury | dffd892 | 2014-04-30 13:25:12 -0700 | [diff] [blame] | 773 | /* |
| 774 | * Put the SPI Core back in the Reset State |
| 775 | * to end the transfer |
| 776 | */ |
| 777 | (void)config_spi_state(ds, SPI_RESET_STATE); |
Vadim Bendebury | 3afa03e | 2014-04-10 14:20:39 -0700 | [diff] [blame] | 778 | |
| 779 | return ret; |
| 780 | } |