blob: c2be307f1d87675beaf7debae9b8b4f58546fe6d [file] [log] [blame]
T Karthik Reddycf553bf2022-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
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060021int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
T Karthik Reddycf553bf2022-05-12 04:05:32 -060022 const struct spi_mem_op *op)
23{
24 u32 reg, ret, rx_rem, n_rx, bytes_to_dma, data;
25 u8 opcode, addr_bytes, *rxbuf, dummy_cycles;
26
27 n_rx = op->data.nbytes;
28 rxbuf = op->data.buf.in;
29 rx_rem = n_rx % 4;
30 bytes_to_dma = n_rx - rx_rem;
31
32 if (bytes_to_dma) {
T Karthik Reddy248fe9f2022-05-12 04:05:34 -060033 cadence_qspi_apb_enable_linear_mode(false);
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060034 reg = readl(priv->regbase + CQSPI_REG_CONFIG);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060035 reg |= CQSPI_REG_CONFIG_ENBL_DMA;
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060036 writel(reg, priv->regbase + CQSPI_REG_CONFIG);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060037
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060038 writel(bytes_to_dma, priv->regbase + CQSPI_REG_INDIRECTRDBYTES);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060039
40 writel(CQSPI_DFLT_INDIR_TRIG_ADDR_RANGE,
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060041 priv->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060042 writel(CQSPI_DFLT_DMA_PERIPH_CFG,
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060043 priv->regbase + CQSPI_REG_DMA_PERIPH_CFG);
Venkatesh Yadav Abbarapu20d18362023-10-11 08:45:15 +053044 writel(lower_32_bits((unsigned long)rxbuf), priv->regbase +
T Karthik Reddycf553bf2022-05-12 04:05:32 -060045 CQSPI_DMA_DST_ADDR_REG);
Venkatesh Yadav Abbarapu20d18362023-10-11 08:45:15 +053046 writel(upper_32_bits((unsigned long)rxbuf), priv->regbase +
47 CQSPI_DMA_DST_ADDR_MSB_REG);
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060048 writel(priv->trigger_address, priv->regbase +
T Karthik Reddycf553bf2022-05-12 04:05:32 -060049 CQSPI_DMA_SRC_RD_ADDR_REG);
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060050 writel(bytes_to_dma, priv->regbase +
T Karthik Reddycf553bf2022-05-12 04:05:32 -060051 CQSPI_DMA_DST_SIZE_REG);
52 flush_dcache_range((unsigned long)rxbuf,
53 (unsigned long)rxbuf + bytes_to_dma);
54 writel(CQSPI_DFLT_DST_CTRL_REG_VAL,
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060055 priv->regbase + CQSPI_DMA_DST_CTRL_REG);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060056
57 /* Start the indirect read transfer */
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060058 writel(CQSPI_REG_INDIRECTRD_START, priv->regbase +
T Karthik Reddycf553bf2022-05-12 04:05:32 -060059 CQSPI_REG_INDIRECTRD);
60 /* Wait for dma to complete transfer */
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060061 ret = cadence_qspi_apb_wait_for_dma_cmplt(priv);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060062 if (ret)
63 return ret;
64
65 /* Clear indirect completion status */
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060066 writel(CQSPI_REG_INDIRECTRD_DONE, priv->regbase +
T Karthik Reddycf553bf2022-05-12 04:05:32 -060067 CQSPI_REG_INDIRECTRD);
68 rxbuf += bytes_to_dma;
69 }
70
71 if (rx_rem) {
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060072 reg = readl(priv->regbase + CQSPI_REG_CONFIG);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060073 reg &= ~CQSPI_REG_CONFIG_ENBL_DMA;
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060074 writel(reg, priv->regbase + CQSPI_REG_CONFIG);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060075
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060076 reg = readl(priv->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060077 reg += bytes_to_dma;
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060078 writel(reg, priv->regbase + CQSPI_REG_CMDADDRESS);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060079
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060080 addr_bytes = readl(priv->regbase + CQSPI_REG_SIZE) &
T Karthik Reddycf553bf2022-05-12 04:05:32 -060081 CQSPI_REG_SIZE_ADDRESS_MASK;
82
83 opcode = CMD_4BYTE_FAST_READ;
84 dummy_cycles = 8;
85 writel((dummy_cycles << CQSPI_REG_RD_INSTR_DUMMY_LSB) | opcode,
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060086 priv->regbase + CQSPI_REG_RD_INSTR);
T Karthik Reddycf553bf2022-05-12 04:05:32 -060087
88 reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
89 reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
90 reg |= (addr_bytes & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) <<
91 CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
92 reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -060093 dummy_cycles = (readl(priv->regbase + CQSPI_REG_RD_INSTR) >>
T Karthik Reddycf553bf2022-05-12 04:05:32 -060094 CQSPI_REG_RD_INSTR_DUMMY_LSB) &
95 CQSPI_REG_RD_INSTR_DUMMY_MASK;
96 reg |= (dummy_cycles & CQSPI_REG_CMDCTRL_DUMMY_MASK) <<
97 CQSPI_REG_CMDCTRL_DUMMY_LSB;
98 reg |= (((rx_rem - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) <<
99 CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -0600100 ret = cadence_qspi_apb_exec_flash_cmd(priv->regbase, reg);
T Karthik Reddycf553bf2022-05-12 04:05:32 -0600101 if (ret)
102 return ret;
103
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -0600104 data = readl(priv->regbase + CQSPI_REG_CMDREADDATALOWER);
T Karthik Reddycf553bf2022-05-12 04:05:32 -0600105 memcpy(rxbuf, &data, rx_rem);
106 }
107
108 return 0;
109}
110
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -0600111int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv)
T Karthik Reddycf553bf2022-05-12 04:05:32 -0600112{
113 u32 timeout = CQSPI_DMA_TIMEOUT;
114
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -0600115 while (!(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG) &
T Karthik Reddycf553bf2022-05-12 04:05:32 -0600116 CQSPI_DMA_DST_I_STS_DONE) && timeout--)
117 udelay(1);
118
119 if (!timeout) {
120 printf("DMA timeout\n");
121 return -ETIMEDOUT;
122 }
123
Ashok Reddy Somaf7d4cab2022-08-24 05:38:47 -0600124 writel(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG),
125 priv->regbase + CQSPI_DMA_DST_I_STS_REG);
T Karthik Reddycf553bf2022-05-12 04:05:32 -0600126 return 0;
127}
T Karthik Reddybf8dae52022-05-12 04:05:33 -0600128
129#if defined(CONFIG_DM_GPIO)
Ashok Reddy Soma68852f32022-08-24 05:38:45 -0600130int cadence_qspi_versal_flash_reset(struct udevice *dev)
T Karthik Reddybf8dae52022-05-12 04:05:33 -0600131{
132 struct gpio_desc gpio;
133 u32 reset_gpio;
134 int ret;
135
136 /* request gpio and set direction as output set to 1 */
137 ret = gpio_request_by_name(dev, "reset-gpios", 0, &gpio,
138 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
139 if (ret) {
140 printf("%s: unable to reset ospi flash device", __func__);
141 return ret;
142 }
143
144 reset_gpio = PMIO_NODE_ID_BASE + gpio.offset;
145
146 /* Request for pin */
147 xilinx_pm_request(PM_PINCTRL_REQUEST, reset_gpio, 0, 0, 0, NULL);
148
149 /* Enable hysteresis in cmos receiver */
150 xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, reset_gpio,
151 PM_PINCTRL_CONFIG_SCHMITT_CMOS,
152 PM_PINCTRL_INPUT_TYPE_SCHMITT, 0, NULL);
153
154 /* Disable Tri-state */
155 xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, reset_gpio,
156 PM_PINCTRL_CONFIG_TRI_STATE,
157 PM_PINCTRL_TRI_STATE_DISABLE, 0, NULL);
158 udelay(1);
159
160 /* Set value 0 to pin */
161 dm_gpio_set_value(&gpio, 0);
162 udelay(1);
163
164 /* Set value 1 to pin */
165 dm_gpio_set_value(&gpio, 1);
166 udelay(1);
Ashok Reddy Soma34dec6a2023-06-14 06:04:52 -0600167
T Karthik Reddybf8dae52022-05-12 04:05:33 -0600168 return 0;
169}
170#else
Ashok Reddy Soma68852f32022-08-24 05:38:45 -0600171int cadence_qspi_versal_flash_reset(struct udevice *dev)
T Karthik Reddybf8dae52022-05-12 04:05:33 -0600172{
173 /* CRP WPROT */
174 writel(0, WPROT_CRP);
175 /* GPIO Reset */
176 writel(0, RST_GPIO);
177
178 /* disable IOU write protection */
179 writel(0, WPROT_LPD_MIO);
180
181 /* set direction as output */
182 writel((readl(BOOT_MODE_DIR) | BIT(FLASH_RESET_GPIO)),
Ashok Reddy Somace8adf12022-11-16 07:11:54 -0700183 BOOT_MODE_DIR);
T Karthik Reddybf8dae52022-05-12 04:05:33 -0600184
185 /* Data output enable */
186 writel((readl(BOOT_MODE_OUT) | BIT(FLASH_RESET_GPIO)),
Ashok Reddy Somace8adf12022-11-16 07:11:54 -0700187 BOOT_MODE_OUT);
T Karthik Reddybf8dae52022-05-12 04:05:33 -0600188
189 /* IOU SLCR write enable */
190 writel(0, WPROT_PMC_MIO);
191
192 /* set MIO as GPIO */
193 writel(0x60, MIO_PIN_12);
194
195 /* Set value 1 to pin */
196 writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
197 udelay(10);
198
199 /* Disable Tri-state */
200 writel((readl(BANK0_TRI) & ~BIT(FLASH_RESET_GPIO)), BANK0_TRI);
201 udelay(1);
202
203 /* Set value 0 to pin */
204 writel((readl(BANK0_OUTPUT) & ~BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
205 udelay(10);
206
207 /* Set value 1 to pin */
208 writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
209 udelay(10);
210
211 return 0;
212}
213#endif
T Karthik Reddy248fe9f2022-05-12 04:05:34 -0600214
215void cadence_qspi_apb_enable_linear_mode(bool enable)
216{
Simon Glass8581d992023-02-05 15:44:33 -0700217 if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
T Karthik Reddy248fe9f2022-05-12 04:05:34 -0600218 if (enable)
219 /* ahb read mode */
220 xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
221 IOCTL_OSPI_MUX_SELECT,
222 PM_OSPI_MUX_SEL_LINEAR, 0, NULL);
223 else
224 /* DMA mode */
225 xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
226 IOCTL_OSPI_MUX_SELECT,
227 PM_OSPI_MUX_SEL_DMA, 0, NULL);
228 } else {
229 if (enable)
230 writel(readl(VERSAL_AXI_MUX_SEL) |
231 VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
232 else
233 writel(readl(VERSAL_AXI_MUX_SEL) &
234 ~VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
235 }
236}