]> Git Repo - J-u-boot.git/blame - drivers/spi/cadence_ospi_versal.c
Merge patch series "net: ksz9477: add support for KSZ GbE switches using SPI bus"
[J-u-boot.git] / drivers / spi / cadence_ospi_versal.c
CommitLineData
cf553bf2
KR
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) Copyright 2018 Xilinx
4 *
5 * Cadence QSPI controller DMA operations
6 */
7
8#include <clk.h>
cf553bf2
KR
9#include <memalign.h>
10#include <wait_bit.h>
11#include <asm/io.h>
12#include <asm/gpio.h>
13#include <asm/cache.h>
14#include <cpu_func.h>
15#include <zynqmp_firmware.h>
16#include <asm/arch/hardware.h>
17#include "cadence_qspi.h"
18#include <dt-bindings/power/xlnx-versal-power.h>
19
f7d4cab1 20int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
cf553bf2
KR
21 const struct spi_mem_op *op)
22{
23 u32 reg, ret, rx_rem, n_rx, bytes_to_dma, data;
24 u8 opcode, addr_bytes, *rxbuf, dummy_cycles;
25
26 n_rx = op->data.nbytes;
27 rxbuf = op->data.buf.in;
28 rx_rem = n_rx % 4;
29 bytes_to_dma = n_rx - rx_rem;
30
31 if (bytes_to_dma) {
248fe9f3 32 cadence_qspi_apb_enable_linear_mode(false);
f7d4cab1 33 reg = readl(priv->regbase + CQSPI_REG_CONFIG);
cf553bf2 34 reg |= CQSPI_REG_CONFIG_ENBL_DMA;
f7d4cab1 35 writel(reg, priv->regbase + CQSPI_REG_CONFIG);
cf553bf2 36
f7d4cab1 37 writel(bytes_to_dma, priv->regbase + CQSPI_REG_INDIRECTRDBYTES);
cf553bf2
KR
38
39 writel(CQSPI_DFLT_INDIR_TRIG_ADDR_RANGE,
f7d4cab1 40 priv->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE);
cf553bf2 41 writel(CQSPI_DFLT_DMA_PERIPH_CFG,
f7d4cab1 42 priv->regbase + CQSPI_REG_DMA_PERIPH_CFG);
20d1836e 43 writel(lower_32_bits((unsigned long)rxbuf), priv->regbase +
cf553bf2 44 CQSPI_DMA_DST_ADDR_REG);
20d1836e
VYA
45 writel(upper_32_bits((unsigned long)rxbuf), priv->regbase +
46 CQSPI_DMA_DST_ADDR_MSB_REG);
f7d4cab1 47 writel(priv->trigger_address, priv->regbase +
cf553bf2 48 CQSPI_DMA_SRC_RD_ADDR_REG);
f7d4cab1 49 writel(bytes_to_dma, priv->regbase +
cf553bf2
KR
50 CQSPI_DMA_DST_SIZE_REG);
51 flush_dcache_range((unsigned long)rxbuf,
52 (unsigned long)rxbuf + bytes_to_dma);
53 writel(CQSPI_DFLT_DST_CTRL_REG_VAL,
f7d4cab1 54 priv->regbase + CQSPI_DMA_DST_CTRL_REG);
cf553bf2
KR
55
56 /* Start the indirect read transfer */
f7d4cab1 57 writel(CQSPI_REG_INDIRECTRD_START, priv->regbase +
cf553bf2
KR
58 CQSPI_REG_INDIRECTRD);
59 /* Wait for dma to complete transfer */
f7d4cab1 60 ret = cadence_qspi_apb_wait_for_dma_cmplt(priv);
cf553bf2
KR
61 if (ret)
62 return ret;
63
64 /* Clear indirect completion status */
f7d4cab1 65 writel(CQSPI_REG_INDIRECTRD_DONE, priv->regbase +
cf553bf2
KR
66 CQSPI_REG_INDIRECTRD);
67 rxbuf += bytes_to_dma;
68 }
69
70 if (rx_rem) {
f7d4cab1 71 reg = readl(priv->regbase + CQSPI_REG_CONFIG);
cf553bf2 72 reg &= ~CQSPI_REG_CONFIG_ENBL_DMA;
f7d4cab1 73 writel(reg, priv->regbase + CQSPI_REG_CONFIG);
cf553bf2 74
f7d4cab1 75 reg = readl(priv->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
cf553bf2 76 reg += bytes_to_dma;
f7d4cab1 77 writel(reg, priv->regbase + CQSPI_REG_CMDADDRESS);
cf553bf2 78
f7d4cab1 79 addr_bytes = readl(priv->regbase + CQSPI_REG_SIZE) &
cf553bf2
KR
80 CQSPI_REG_SIZE_ADDRESS_MASK;
81
82 opcode = CMD_4BYTE_FAST_READ;
83 dummy_cycles = 8;
84 writel((dummy_cycles << CQSPI_REG_RD_INSTR_DUMMY_LSB) | opcode,
f7d4cab1 85 priv->regbase + CQSPI_REG_RD_INSTR);
cf553bf2
KR
86
87 reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
88 reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
89 reg |= (addr_bytes & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) <<
90 CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
91 reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
f7d4cab1 92 dummy_cycles = (readl(priv->regbase + CQSPI_REG_RD_INSTR) >>
cf553bf2
KR
93 CQSPI_REG_RD_INSTR_DUMMY_LSB) &
94 CQSPI_REG_RD_INSTR_DUMMY_MASK;
95 reg |= (dummy_cycles & CQSPI_REG_CMDCTRL_DUMMY_MASK) <<
96 CQSPI_REG_CMDCTRL_DUMMY_LSB;
97 reg |= (((rx_rem - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) <<
98 CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
f7d4cab1 99 ret = cadence_qspi_apb_exec_flash_cmd(priv->regbase, reg);
cf553bf2
KR
100 if (ret)
101 return ret;
102
f7d4cab1 103 data = readl(priv->regbase + CQSPI_REG_CMDREADDATALOWER);
cf553bf2
KR
104 memcpy(rxbuf, &data, rx_rem);
105 }
106
107 return 0;
108}
109
f7d4cab1 110int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv)
cf553bf2
KR
111{
112 u32 timeout = CQSPI_DMA_TIMEOUT;
113
f7d4cab1 114 while (!(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG) &
cf553bf2
KR
115 CQSPI_DMA_DST_I_STS_DONE) && timeout--)
116 udelay(1);
117
118 if (!timeout) {
119 printf("DMA timeout\n");
120 return -ETIMEDOUT;
121 }
122
f7d4cab1
ARS
123 writel(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG),
124 priv->regbase + CQSPI_DMA_DST_I_STS_REG);
cf553bf2
KR
125 return 0;
126}
bf8dae5f
KR
127
128#if defined(CONFIG_DM_GPIO)
68852f32 129int cadence_qspi_versal_flash_reset(struct udevice *dev)
bf8dae5f
KR
130{
131 struct gpio_desc gpio;
132 u32 reset_gpio;
133 int ret;
134
135 /* request gpio and set direction as output set to 1 */
136 ret = gpio_request_by_name(dev, "reset-gpios", 0, &gpio,
137 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
138 if (ret) {
139 printf("%s: unable to reset ospi flash device", __func__);
140 return ret;
141 }
142
143 reset_gpio = PMIO_NODE_ID_BASE + gpio.offset;
144
145 /* Request for pin */
146 xilinx_pm_request(PM_PINCTRL_REQUEST, reset_gpio, 0, 0, 0, NULL);
147
148 /* Enable hysteresis in cmos receiver */
149 xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, reset_gpio,
150 PM_PINCTRL_CONFIG_SCHMITT_CMOS,
151 PM_PINCTRL_INPUT_TYPE_SCHMITT, 0, NULL);
152
153 /* Disable Tri-state */
154 xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, reset_gpio,
155 PM_PINCTRL_CONFIG_TRI_STATE,
156 PM_PINCTRL_TRI_STATE_DISABLE, 0, NULL);
157 udelay(1);
158
159 /* Set value 0 to pin */
160 dm_gpio_set_value(&gpio, 0);
161 udelay(1);
162
163 /* Set value 1 to pin */
164 dm_gpio_set_value(&gpio, 1);
165 udelay(1);
34dec6a4 166
bf8dae5f
KR
167 return 0;
168}
169#else
68852f32 170int cadence_qspi_versal_flash_reset(struct udevice *dev)
bf8dae5f
KR
171{
172 /* CRP WPROT */
173 writel(0, WPROT_CRP);
174 /* GPIO Reset */
175 writel(0, RST_GPIO);
176
177 /* disable IOU write protection */
178 writel(0, WPROT_LPD_MIO);
179
180 /* set direction as output */
181 writel((readl(BOOT_MODE_DIR) | BIT(FLASH_RESET_GPIO)),
ce8adf1a 182 BOOT_MODE_DIR);
bf8dae5f
KR
183
184 /* Data output enable */
185 writel((readl(BOOT_MODE_OUT) | BIT(FLASH_RESET_GPIO)),
ce8adf1a 186 BOOT_MODE_OUT);
bf8dae5f
KR
187
188 /* IOU SLCR write enable */
189 writel(0, WPROT_PMC_MIO);
190
191 /* set MIO as GPIO */
192 writel(0x60, MIO_PIN_12);
193
194 /* Set value 1 to pin */
195 writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
196 udelay(10);
197
198 /* Disable Tri-state */
199 writel((readl(BANK0_TRI) & ~BIT(FLASH_RESET_GPIO)), BANK0_TRI);
200 udelay(1);
201
202 /* Set value 0 to pin */
203 writel((readl(BANK0_OUTPUT) & ~BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
204 udelay(10);
205
206 /* Set value 1 to pin */
207 writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
208 udelay(10);
209
210 return 0;
211}
212#endif
248fe9f3
KR
213
214void cadence_qspi_apb_enable_linear_mode(bool enable)
215{
8581d992 216 if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
248fe9f3
KR
217 if (enable)
218 /* ahb read mode */
219 xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
220 IOCTL_OSPI_MUX_SELECT,
221 PM_OSPI_MUX_SEL_LINEAR, 0, NULL);
222 else
223 /* DMA mode */
224 xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
225 IOCTL_OSPI_MUX_SELECT,
226 PM_OSPI_MUX_SEL_DMA, 0, NULL);
227 } else {
228 if (enable)
229 writel(readl(VERSAL_AXI_MUX_SEL) |
230 VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
231 else
232 writel(readl(VERSAL_AXI_MUX_SEL) &
233 ~VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
234 }
235}
This page took 0.140712 seconds and 4 git commands to generate.