]>
Commit | Line | Data |
---|---|---|
1465d055 JT |
1 | /* |
2 | * (C) Copyright 2013 Inc. | |
3 | * | |
4 | * Xilinx Zynq PS SPI controller driver (master mode only) | |
5 | * | |
6 | * SPDX-License-Identifier: GPL-2.0+ | |
7 | */ | |
8 | ||
9 | #include <config.h> | |
10 | #include <common.h> | |
11 | #include <malloc.h> | |
12 | #include <spi.h> | |
13 | #include <asm/io.h> | |
14 | #include <asm/arch/hardware.h> | |
15 | ||
16 | /* zynq spi register bit masks ZYNQ_SPI_<REG>_<BIT>_MASK */ | |
17 | #define ZYNQ_SPI_CR_MSA_MASK (1 << 15) /* Manual start enb */ | |
18 | #define ZYNQ_SPI_CR_MCS_MASK (1 << 14) /* Manual chip select */ | |
19 | #define ZYNQ_SPI_CR_CS_MASK (0xF << 10) /* Chip select */ | |
20 | #define ZYNQ_SPI_CR_BRD_MASK (0x7 << 3) /* Baud rate div */ | |
21 | #define ZYNQ_SPI_CR_CPHA_MASK (1 << 2) /* Clock phase */ | |
22 | #define ZYNQ_SPI_CR_CPOL_MASK (1 << 1) /* Clock polarity */ | |
23 | #define ZYNQ_SPI_CR_MSTREN_MASK (1 << 0) /* Mode select */ | |
24 | #define ZYNQ_SPI_IXR_RXNEMPTY_MASK (1 << 4) /* RX_FIFO_not_empty */ | |
25 | #define ZYNQ_SPI_IXR_TXOW_MASK (1 << 2) /* TX_FIFO_not_full */ | |
26 | #define ZYNQ_SPI_IXR_ALL_MASK 0x7F /* All IXR bits */ | |
27 | #define ZYNQ_SPI_ENR_SPI_EN_MASK (1 << 0) /* SPI Enable */ | |
28 | ||
29 | #define ZYNQ_SPI_FIFO_DEPTH 128 | |
30 | #ifndef CONFIG_SYS_ZYNQ_SPI_WAIT | |
31 | #define CONFIG_SYS_ZYNQ_SPI_WAIT (CONFIG_SYS_HZ/100) /* 10 ms */ | |
32 | #endif | |
33 | ||
34 | /* zynq spi register set */ | |
35 | struct zynq_spi_regs { | |
36 | u32 cr; /* 0x00 */ | |
37 | u32 isr; /* 0x04 */ | |
38 | u32 ier; /* 0x08 */ | |
39 | u32 idr; /* 0x0C */ | |
40 | u32 imr; /* 0x10 */ | |
41 | u32 enr; /* 0x14 */ | |
42 | u32 dr; /* 0x18 */ | |
43 | u32 txdr; /* 0x1C */ | |
44 | u32 rxdr; /* 0x20 */ | |
45 | }; | |
46 | ||
47 | /* zynq spi slave */ | |
48 | struct zynq_spi_slave { | |
49 | struct spi_slave slave; | |
50 | struct zynq_spi_regs *base; | |
51 | u8 mode; | |
52 | u8 fifo_depth; | |
53 | u32 speed_hz; | |
54 | u32 input_hz; | |
55 | u32 req_hz; | |
56 | }; | |
57 | ||
58 | static inline struct zynq_spi_slave *to_zynq_spi_slave(struct spi_slave *slave) | |
59 | { | |
60 | return container_of(slave, struct zynq_spi_slave, slave); | |
61 | } | |
62 | ||
63 | static inline struct zynq_spi_regs *get_zynq_spi_base(int dev) | |
64 | { | |
65 | if (dev) | |
66 | return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR1; | |
67 | else | |
68 | return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR0; | |
69 | } | |
70 | ||
71 | static void zynq_spi_init_hw(struct zynq_spi_slave *zslave) | |
72 | { | |
73 | u32 confr; | |
74 | ||
75 | /* Disable SPI */ | |
76 | writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr); | |
77 | ||
78 | /* Disable Interrupts */ | |
79 | writel(ZYNQ_SPI_IXR_ALL_MASK, &zslave->base->idr); | |
80 | ||
81 | /* Clear RX FIFO */ | |
82 | while (readl(&zslave->base->isr) & | |
83 | ZYNQ_SPI_IXR_RXNEMPTY_MASK) | |
84 | readl(&zslave->base->rxdr); | |
85 | ||
86 | /* Clear Interrupts */ | |
87 | writel(ZYNQ_SPI_IXR_ALL_MASK, &zslave->base->isr); | |
88 | ||
89 | /* Manual slave select and Auto start */ | |
90 | confr = ZYNQ_SPI_CR_MCS_MASK | ZYNQ_SPI_CR_CS_MASK | | |
91 | ZYNQ_SPI_CR_MSTREN_MASK; | |
92 | confr &= ~ZYNQ_SPI_CR_MSA_MASK; | |
93 | writel(confr, &zslave->base->cr); | |
94 | ||
95 | /* Enable SPI */ | |
96 | writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr); | |
97 | } | |
98 | ||
99 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
100 | { | |
101 | /* 2 bus with 3 chipselect */ | |
102 | return bus < 2 && cs < 3; | |
103 | } | |
104 | ||
105 | void spi_cs_activate(struct spi_slave *slave) | |
106 | { | |
107 | struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave); | |
108 | u32 cr; | |
109 | ||
110 | debug("spi_cs_activate: 0x%08x\n", (u32)slave); | |
111 | ||
112 | clrbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK); | |
113 | cr = readl(&zslave->base->cr); | |
114 | /* | |
115 | * CS cal logic: CS[13:10] | |
116 | * xxx0 - cs0 | |
117 | * xx01 - cs1 | |
118 | * x011 - cs2 | |
119 | */ | |
120 | cr |= (~(0x1 << slave->cs) << 10) & ZYNQ_SPI_CR_CS_MASK; | |
121 | writel(cr, &zslave->base->cr); | |
122 | } | |
123 | ||
124 | void spi_cs_deactivate(struct spi_slave *slave) | |
125 | { | |
126 | struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave); | |
127 | ||
128 | debug("spi_cs_deactivate: 0x%08x\n", (u32)slave); | |
129 | ||
130 | setbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK); | |
131 | } | |
132 | ||
133 | void spi_init() | |
134 | { | |
135 | /* nothing to do */ | |
136 | } | |
137 | ||
138 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |
139 | unsigned int max_hz, unsigned int mode) | |
140 | { | |
141 | struct zynq_spi_slave *zslave; | |
142 | ||
143 | if (!spi_cs_is_valid(bus, cs)) | |
144 | return NULL; | |
145 | ||
146 | zslave = spi_alloc_slave(struct zynq_spi_slave, bus, cs); | |
147 | if (!zslave) { | |
148 | printf("SPI_error: Fail to allocate zynq_spi_slave\n"); | |
149 | return NULL; | |
150 | } | |
151 | ||
152 | zslave->base = get_zynq_spi_base(bus); | |
153 | zslave->mode = mode; | |
154 | zslave->fifo_depth = ZYNQ_SPI_FIFO_DEPTH; | |
155 | zslave->input_hz = 166666700; | |
156 | zslave->speed_hz = zslave->input_hz / 2; | |
157 | zslave->req_hz = max_hz; | |
158 | ||
159 | /* init the zynq spi hw */ | |
160 | zynq_spi_init_hw(zslave); | |
161 | ||
162 | return &zslave->slave; | |
163 | } | |
164 | ||
165 | void spi_free_slave(struct spi_slave *slave) | |
166 | { | |
167 | struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave); | |
168 | ||
169 | debug("spi_free_slave: 0x%08x\n", (u32)slave); | |
170 | free(zslave); | |
171 | } | |
172 | ||
173 | int spi_claim_bus(struct spi_slave *slave) | |
174 | { | |
175 | struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave); | |
176 | u32 confr = 0; | |
177 | u8 baud_rate_val = 0; | |
178 | ||
179 | writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr); | |
180 | ||
181 | /* Set the SPI Clock phase and polarities */ | |
182 | confr = readl(&zslave->base->cr); | |
183 | confr &= ~(ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK); | |
184 | if (zslave->mode & SPI_CPHA) | |
185 | confr |= ZYNQ_SPI_CR_CPHA_MASK; | |
186 | if (zslave->mode & SPI_CPOL) | |
187 | confr |= ZYNQ_SPI_CR_CPOL_MASK; | |
188 | ||
189 | /* Set the clock frequency */ | |
190 | if (zslave->req_hz == 0) { | |
191 | /* Set baudrate x8, if the req_hz is 0 */ | |
192 | baud_rate_val = 0x2; | |
193 | } else if (zslave->speed_hz != zslave->req_hz) { | |
194 | while ((baud_rate_val < 8) && | |
195 | ((zslave->input_hz / | |
196 | (2 << baud_rate_val)) > zslave->req_hz)) | |
197 | baud_rate_val++; | |
198 | zslave->speed_hz = zslave->req_hz / (2 << baud_rate_val); | |
199 | } | |
200 | confr &= ~ZYNQ_SPI_CR_BRD_MASK; | |
201 | confr |= (baud_rate_val << 3); | |
202 | writel(confr, &zslave->base->cr); | |
203 | ||
204 | writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr); | |
205 | ||
206 | return 0; | |
207 | } | |
208 | ||
209 | void spi_release_bus(struct spi_slave *slave) | |
210 | { | |
211 | struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave); | |
212 | ||
213 | debug("spi_release_bus: 0x%08x\n", (u32)slave); | |
214 | writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr); | |
215 | } | |
216 | ||
217 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, | |
218 | void *din, unsigned long flags) | |
219 | { | |
220 | struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave); | |
221 | u32 len = bitlen / 8; | |
222 | u32 tx_len = len, rx_len = len, tx_tvl; | |
223 | const u8 *tx_buf = dout; | |
224 | u8 *rx_buf = din, buf; | |
225 | u32 ts, status; | |
226 | ||
227 | debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n", | |
228 | slave->bus, slave->cs, bitlen, len, flags); | |
229 | ||
1465d055 JT |
230 | if (bitlen % 8) { |
231 | debug("spi_xfer: Non byte aligned SPI transfer\n"); | |
232 | return -1; | |
233 | } | |
234 | ||
235 | if (flags & SPI_XFER_BEGIN) | |
236 | spi_cs_activate(slave); | |
237 | ||
238 | while (rx_len > 0) { | |
239 | /* Write the data into TX FIFO - tx threshold is fifo_depth */ | |
240 | tx_tvl = 0; | |
241 | while ((tx_tvl < zslave->fifo_depth) && tx_len) { | |
242 | if (tx_buf) | |
243 | buf = *tx_buf++; | |
244 | else | |
245 | buf = 0; | |
246 | writel(buf, &zslave->base->txdr); | |
247 | tx_len--; | |
248 | tx_tvl++; | |
249 | } | |
250 | ||
251 | /* Check TX FIFO completion */ | |
252 | ts = get_timer(0); | |
253 | status = readl(&zslave->base->isr); | |
254 | while (!(status & ZYNQ_SPI_IXR_TXOW_MASK)) { | |
255 | if (get_timer(ts) > CONFIG_SYS_ZYNQ_SPI_WAIT) { | |
256 | printf("spi_xfer: Timeout! TX FIFO not full\n"); | |
257 | return -1; | |
258 | } | |
259 | status = readl(&zslave->base->isr); | |
260 | } | |
261 | ||
262 | /* Read the data from RX FIFO */ | |
263 | status = readl(&zslave->base->isr); | |
264 | while (status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) { | |
265 | buf = readl(&zslave->base->rxdr); | |
266 | if (rx_buf) | |
267 | *rx_buf++ = buf; | |
268 | status = readl(&zslave->base->isr); | |
269 | rx_len--; | |
270 | } | |
271 | } | |
272 | ||
273 | if (flags & SPI_XFER_END) | |
274 | spi_cs_deactivate(slave); | |
275 | ||
276 | return 0; | |
277 | } |