blob: e02a3b3de37d31375ff896310a3945d572804bad [file] [log] [blame]
T Karthik Reddy73701e72022-05-12 04:05:32 -06001// 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>
9#include <common.h>
10#include <memalign.h>
11#include <wait_bit.h>
12#include <asm/io.h>
13#include <asm/gpio.h>
14#include <asm/cache.h>
15#include <cpu_func.h>
16#include <zynqmp_firmware.h>
17#include <asm/arch/hardware.h>
18#include "cadence_qspi.h"
19#include <dt-bindings/power/xlnx-versal-power.h>
20
21#define CMD_4BYTE_READ 0x13
22#define CMD_4BYTE_FAST_READ 0x0C
23
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060024int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
T Karthik Reddy73701e72022-05-12 04:05:32 -060025 const struct spi_mem_op *op)
26{
27 u32 reg, ret, rx_rem, n_rx, bytes_to_dma, data;
28 u8 opcode, addr_bytes, *rxbuf, dummy_cycles;
29
30 n_rx = op->data.nbytes;
31 rxbuf = op->data.buf.in;
32 rx_rem = n_rx % 4;
33 bytes_to_dma = n_rx - rx_rem;
34
35 if (bytes_to_dma) {
T Karthik Reddy3b49fbf2022-05-12 04:05:34 -060036 cadence_qspi_apb_enable_linear_mode(false);
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060037 reg = readl(priv->regbase + CQSPI_REG_CONFIG);
T Karthik Reddy73701e72022-05-12 04:05:32 -060038 reg |= CQSPI_REG_CONFIG_ENBL_DMA;
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060039 writel(reg, priv->regbase + CQSPI_REG_CONFIG);
T Karthik Reddy73701e72022-05-12 04:05:32 -060040
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060041 writel(bytes_to_dma, priv->regbase + CQSPI_REG_INDIRECTRDBYTES);
T Karthik Reddy73701e72022-05-12 04:05:32 -060042
43 writel(CQSPI_DFLT_INDIR_TRIG_ADDR_RANGE,
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060044 priv->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE);
T Karthik Reddy73701e72022-05-12 04:05:32 -060045 writel(CQSPI_DFLT_DMA_PERIPH_CFG,
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060046 priv->regbase + CQSPI_REG_DMA_PERIPH_CFG);
Venkatesh Yadav Abbarapucf014982023-10-11 08:45:15 +053047 writel(lower_32_bits((unsigned long)rxbuf), priv->regbase +
T Karthik Reddy73701e72022-05-12 04:05:32 -060048 CQSPI_DMA_DST_ADDR_REG);
Venkatesh Yadav Abbarapucf014982023-10-11 08:45:15 +053049 writel(upper_32_bits((unsigned long)rxbuf), priv->regbase +
50 CQSPI_DMA_DST_ADDR_MSB_REG);
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060051 writel(priv->trigger_address, priv->regbase +
T Karthik Reddy73701e72022-05-12 04:05:32 -060052 CQSPI_DMA_SRC_RD_ADDR_REG);
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060053 writel(bytes_to_dma, priv->regbase +
T Karthik Reddy73701e72022-05-12 04:05:32 -060054 CQSPI_DMA_DST_SIZE_REG);
55 flush_dcache_range((unsigned long)rxbuf,
56 (unsigned long)rxbuf + bytes_to_dma);
57 writel(CQSPI_DFLT_DST_CTRL_REG_VAL,
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060058 priv->regbase + CQSPI_DMA_DST_CTRL_REG);
T Karthik Reddy73701e72022-05-12 04:05:32 -060059
60 /* Start the indirect read transfer */
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060061 writel(CQSPI_REG_INDIRECTRD_START, priv->regbase +
T Karthik Reddy73701e72022-05-12 04:05:32 -060062 CQSPI_REG_INDIRECTRD);
63 /* Wait for dma to complete transfer */
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060064 ret = cadence_qspi_apb_wait_for_dma_cmplt(priv);
T Karthik Reddy73701e72022-05-12 04:05:32 -060065 if (ret)
66 return ret;
67
68 /* Clear indirect completion status */
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060069 writel(CQSPI_REG_INDIRECTRD_DONE, priv->regbase +
T Karthik Reddy73701e72022-05-12 04:05:32 -060070 CQSPI_REG_INDIRECTRD);
71 rxbuf += bytes_to_dma;
72 }
73
74 if (rx_rem) {
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060075 reg = readl(priv->regbase + CQSPI_REG_CONFIG);
T Karthik Reddy73701e72022-05-12 04:05:32 -060076 reg &= ~CQSPI_REG_CONFIG_ENBL_DMA;
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060077 writel(reg, priv->regbase + CQSPI_REG_CONFIG);
T Karthik Reddy73701e72022-05-12 04:05:32 -060078
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060079 reg = readl(priv->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
T Karthik Reddy73701e72022-05-12 04:05:32 -060080 reg += bytes_to_dma;
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060081 writel(reg, priv->regbase + CQSPI_REG_CMDADDRESS);
T Karthik Reddy73701e72022-05-12 04:05:32 -060082
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060083 addr_bytes = readl(priv->regbase + CQSPI_REG_SIZE) &
T Karthik Reddy73701e72022-05-12 04:05:32 -060084 CQSPI_REG_SIZE_ADDRESS_MASK;
85
86 opcode = CMD_4BYTE_FAST_READ;
87 dummy_cycles = 8;
88 writel((dummy_cycles << CQSPI_REG_RD_INSTR_DUMMY_LSB) | opcode,
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060089 priv->regbase + CQSPI_REG_RD_INSTR);
T Karthik Reddy73701e72022-05-12 04:05:32 -060090
91 reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
92 reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
93 reg |= (addr_bytes & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) <<
94 CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
95 reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
Ashok Reddy Somaf5817652022-08-24 05:38:47 -060096 dummy_cycles = (readl(priv->regbase + CQSPI_REG_RD_INSTR) >>
T Karthik Reddy73701e72022-05-12 04:05:32 -060097 CQSPI_REG_RD_INSTR_DUMMY_LSB) &
98 CQSPI_REG_RD_INSTR_DUMMY_MASK;
99 reg |= (dummy_cycles & CQSPI_REG_CMDCTRL_DUMMY_MASK) <<
100 CQSPI_REG_CMDCTRL_DUMMY_LSB;
101 reg |= (((rx_rem - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) <<
102 CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
Ashok Reddy Somaf5817652022-08-24 05:38:47 -0600103 ret = cadence_qspi_apb_exec_flash_cmd(priv->regbase, reg);
T Karthik Reddy73701e72022-05-12 04:05:32 -0600104 if (ret)
105 return ret;
106
Ashok Reddy Somaf5817652022-08-24 05:38:47 -0600107 data = readl(priv->regbase + CQSPI_REG_CMDREADDATALOWER);
T Karthik Reddy73701e72022-05-12 04:05:32 -0600108 memcpy(rxbuf, &data, rx_rem);
109 }
110
111 return 0;
112}
113
Ashok Reddy Somaf5817652022-08-24 05:38:47 -0600114int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv)
T Karthik Reddy73701e72022-05-12 04:05:32 -0600115{
116 u32 timeout = CQSPI_DMA_TIMEOUT;
117
Ashok Reddy Somaf5817652022-08-24 05:38:47 -0600118 while (!(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG) &
T Karthik Reddy73701e72022-05-12 04:05:32 -0600119 CQSPI_DMA_DST_I_STS_DONE) && timeout--)
120 udelay(1);
121
122 if (!timeout) {
123 printf("DMA timeout\n");
124 return -ETIMEDOUT;
125 }
126
Ashok Reddy Somaf5817652022-08-24 05:38:47 -0600127 writel(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG),
128 priv->regbase + CQSPI_DMA_DST_I_STS_REG);
T Karthik Reddy73701e72022-05-12 04:05:32 -0600129 return 0;
130}
T Karthik Reddy3d71b2d2022-05-12 04:05:33 -0600131
132#if defined(CONFIG_DM_GPIO)
Ashok Reddy Somaad269af2022-08-24 05:38:45 -0600133int cadence_qspi_versal_flash_reset(struct udevice *dev)
T Karthik Reddy3d71b2d2022-05-12 04:05:33 -0600134{
135 struct gpio_desc gpio;
136 u32 reset_gpio;
137 int ret;
138
139 /* request gpio and set direction as output set to 1 */
140 ret = gpio_request_by_name(dev, "reset-gpios", 0, &gpio,
141 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
142 if (ret) {
143 printf("%s: unable to reset ospi flash device", __func__);
144 return ret;
145 }
146
147 reset_gpio = PMIO_NODE_ID_BASE + gpio.offset;
148
149 /* Request for pin */
150 xilinx_pm_request(PM_PINCTRL_REQUEST, reset_gpio, 0, 0, 0, NULL);
151
152 /* Enable hysteresis in cmos receiver */
153 xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, reset_gpio,
154 PM_PINCTRL_CONFIG_SCHMITT_CMOS,
155 PM_PINCTRL_INPUT_TYPE_SCHMITT, 0, NULL);
156
157 /* Disable Tri-state */
158 xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, reset_gpio,
159 PM_PINCTRL_CONFIG_TRI_STATE,
160 PM_PINCTRL_TRI_STATE_DISABLE, 0, NULL);
161 udelay(1);
162
163 /* Set value 0 to pin */
164 dm_gpio_set_value(&gpio, 0);
165 udelay(1);
166
167 /* Set value 1 to pin */
168 dm_gpio_set_value(&gpio, 1);
169 udelay(1);
Ashok Reddy Somab6421112023-06-14 06:04:52 -0600170
T Karthik Reddy3d71b2d2022-05-12 04:05:33 -0600171 return 0;
172}
173#else
Ashok Reddy Somaad269af2022-08-24 05:38:45 -0600174int cadence_qspi_versal_flash_reset(struct udevice *dev)
T Karthik Reddy3d71b2d2022-05-12 04:05:33 -0600175{
176 /* CRP WPROT */
177 writel(0, WPROT_CRP);
178 /* GPIO Reset */
179 writel(0, RST_GPIO);
180
181 /* disable IOU write protection */
182 writel(0, WPROT_LPD_MIO);
183
184 /* set direction as output */
185 writel((readl(BOOT_MODE_DIR) | BIT(FLASH_RESET_GPIO)),
Ashok Reddy Soma8a456eb2022-11-16 07:11:54 -0700186 BOOT_MODE_DIR);
T Karthik Reddy3d71b2d2022-05-12 04:05:33 -0600187
188 /* Data output enable */
189 writel((readl(BOOT_MODE_OUT) | BIT(FLASH_RESET_GPIO)),
Ashok Reddy Soma8a456eb2022-11-16 07:11:54 -0700190 BOOT_MODE_OUT);
T Karthik Reddy3d71b2d2022-05-12 04:05:33 -0600191
192 /* IOU SLCR write enable */
193 writel(0, WPROT_PMC_MIO);
194
195 /* set MIO as GPIO */
196 writel(0x60, MIO_PIN_12);
197
198 /* Set value 1 to pin */
199 writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
200 udelay(10);
201
202 /* Disable Tri-state */
203 writel((readl(BANK0_TRI) & ~BIT(FLASH_RESET_GPIO)), BANK0_TRI);
204 udelay(1);
205
206 /* Set value 0 to pin */
207 writel((readl(BANK0_OUTPUT) & ~BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
208 udelay(10);
209
210 /* Set value 1 to pin */
211 writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
212 udelay(10);
213
214 return 0;
215}
216#endif
T Karthik Reddy3b49fbf2022-05-12 04:05:34 -0600217
218void cadence_qspi_apb_enable_linear_mode(bool enable)
219{
Simon Glassf65db342023-02-05 15:44:33 -0700220 if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
T Karthik Reddy3b49fbf2022-05-12 04:05:34 -0600221 if (enable)
222 /* ahb read mode */
223 xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
224 IOCTL_OSPI_MUX_SELECT,
225 PM_OSPI_MUX_SEL_LINEAR, 0, NULL);
226 else
227 /* DMA mode */
228 xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
229 IOCTL_OSPI_MUX_SELECT,
230 PM_OSPI_MUX_SEL_DMA, 0, NULL);
231 } else {
232 if (enable)
233 writel(readl(VERSAL_AXI_MUX_SEL) |
234 VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
235 else
236 writel(readl(VERSAL_AXI_MUX_SEL) &
237 ~VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
238 }
239}