blob: 716256ab59cc5ebc6052cf52fe75d7468cfc4aad [file] [log] [blame]
Stefan Roese5eee9de2018-08-16 10:48:48 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Stefan Roese <sr@denx.de>
4 *
5 * Derived from the Linux driver version drivers/spi/spi-mt7621.c
6 * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
7 * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
8 * Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>
9 */
10
11#include <common.h>
Weijie Gaof0997852019-09-25 17:45:23 +080012#include <clk.h>
Stefan Roese5eee9de2018-08-16 10:48:48 +020013#include <dm.h>
14#include <spi.h>
15#include <wait_bit.h>
16#include <linux/io.h>
17
Weijie Gao54a6b8e2019-09-25 17:45:24 +080018#define MT7621_RX_FIFO_LEN 32
19#define MT7621_TX_FIFO_LEN 36
Stefan Roese5eee9de2018-08-16 10:48:48 +020020
21#define MT7621_SPI_TRANS 0x00
22#define MT7621_SPI_TRANS_START BIT(8)
23#define MT7621_SPI_TRANS_BUSY BIT(16)
24
25#define MT7621_SPI_OPCODE 0x04
26#define MT7621_SPI_DATA0 0x08
27#define MT7621_SPI_DATA4 0x18
28#define MT7621_SPI_MASTER 0x28
29#define MT7621_SPI_MOREBUF 0x2c
30#define MT7621_SPI_POLAR 0x38
31
32#define MT7621_LSB_FIRST BIT(3)
33#define MT7621_CPOL BIT(4)
34#define MT7621_CPHA BIT(5)
35
36#define MASTER_MORE_BUFMODE BIT(2)
37#define MASTER_RS_CLK_SEL GENMASK(27, 16)
38#define MASTER_RS_CLK_SEL_SHIFT 16
39#define MASTER_RS_SLAVE_SEL GENMASK(31, 29)
40
Weijie Gao54a6b8e2019-09-25 17:45:24 +080041#define MOREBUF_CMD_CNT GENMASK(29, 24)
42#define MOREBUF_CMD_CNT_SHIFT 24
43#define MOREBUF_MISO_CNT GENMASK(20, 12)
44#define MOREBUF_MISO_CNT_SHIFT 12
45#define MOREBUF_MOSI_CNT GENMASK(8, 0)
46#define MOREBUF_MOSI_CNT_SHIFT 0
47
Stefan Roese5eee9de2018-08-16 10:48:48 +020048struct mt7621_spi {
49 void __iomem *base;
50 unsigned int sys_freq;
Stefan Roese5eee9de2018-08-16 10:48:48 +020051};
52
53static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex)
54{
55 setbits_le32(rs->base + MT7621_SPI_MASTER,
56 MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE);
57}
58
59static void mt7621_spi_set_cs(struct mt7621_spi *rs, int cs, int enable)
60{
61 u32 val = 0;
62
63 debug("%s: cs#%d -> %s\n", __func__, cs, enable ? "enable" : "disable");
64 if (enable)
65 val = BIT(cs);
66 iowrite32(val, rs->base + MT7621_SPI_POLAR);
67}
68
69static int mt7621_spi_set_mode(struct udevice *bus, uint mode)
70{
71 struct mt7621_spi *rs = dev_get_priv(bus);
72 u32 reg;
73
74 debug("%s: mode=0x%08x\n", __func__, mode);
75 reg = ioread32(rs->base + MT7621_SPI_MASTER);
76
77 reg &= ~MT7621_LSB_FIRST;
78 if (mode & SPI_LSB_FIRST)
79 reg |= MT7621_LSB_FIRST;
80
81 reg &= ~(MT7621_CPHA | MT7621_CPOL);
82 switch (mode & (SPI_CPOL | SPI_CPHA)) {
83 case SPI_MODE_0:
84 break;
85 case SPI_MODE_1:
86 reg |= MT7621_CPHA;
87 break;
88 case SPI_MODE_2:
89 reg |= MT7621_CPOL;
90 break;
91 case SPI_MODE_3:
92 reg |= MT7621_CPOL | MT7621_CPHA;
93 break;
94 }
95 iowrite32(reg, rs->base + MT7621_SPI_MASTER);
96
97 return 0;
98}
99
100static int mt7621_spi_set_speed(struct udevice *bus, uint speed)
101{
102 struct mt7621_spi *rs = dev_get_priv(bus);
103 u32 rate;
104 u32 reg;
105
106 debug("%s: speed=%d\n", __func__, speed);
107 rate = DIV_ROUND_UP(rs->sys_freq, speed);
108 debug("rate:%u\n", rate);
109
110 if (rate > 4097)
111 return -EINVAL;
112
113 if (rate < 2)
114 rate = 2;
115
116 reg = ioread32(rs->base + MT7621_SPI_MASTER);
117 reg &= ~MASTER_RS_CLK_SEL;
118 reg |= (rate - 2) << MASTER_RS_CLK_SEL_SHIFT;
119 iowrite32(reg, rs->base + MT7621_SPI_MASTER);
120
121 return 0;
122}
123
124static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs)
125{
126 int ret;
127
128 ret = wait_for_bit_le32(rs->base + MT7621_SPI_TRANS,
129 MT7621_SPI_TRANS_BUSY, 0, 10, 0);
130 if (ret)
131 pr_err("Timeout in %s!\n", __func__);
132
133 return ret;
134}
135
Weijie Gao54a6b8e2019-09-25 17:45:24 +0800136static int mt7621_spi_read(struct mt7621_spi *rs, u8 *buf, size_t len)
137{
138 size_t rx_len;
139 int i, ret;
140 u32 val = 0;
141
142 while (len) {
143 rx_len = min_t(size_t, len, MT7621_RX_FIFO_LEN);
144
145 iowrite32((rx_len * 8) << MOREBUF_MISO_CNT_SHIFT,
146 rs->base + MT7621_SPI_MOREBUF);
147 iowrite32(MT7621_SPI_TRANS_START, rs->base + MT7621_SPI_TRANS);
148
149 ret = mt7621_spi_wait_till_ready(rs);
150 if (ret)
151 return ret;
152
153 for (i = 0; i < rx_len; i++) {
154 if ((i % 4) == 0)
155 val = ioread32(rs->base + MT7621_SPI_DATA0 + i);
156 *buf++ = val & 0xff;
157 val >>= 8;
158 }
159
160 len -= rx_len;
161 }
162
163 return ret;
164}
165
166static int mt7621_spi_write(struct mt7621_spi *rs, const u8 *buf, size_t len)
167{
168 size_t tx_len, opcode_len, dido_len;
169 int i, ret;
170 u32 val;
171
172 while (len) {
173 tx_len = min_t(size_t, len, MT7621_TX_FIFO_LEN);
174
175 opcode_len = min_t(size_t, tx_len, 4);
176 dido_len = tx_len - opcode_len;
177
178 val = 0;
179 for (i = 0; i < opcode_len; i++) {
180 val <<= 8;
181 val |= *buf++;
182 }
183
184 iowrite32(val, rs->base + MT7621_SPI_OPCODE);
185
186 val = 0;
187 for (i = 0; i < dido_len; i++) {
188 val |= (*buf++) << ((i % 4) * 8);
189
190 if ((i % 4 == 3) || (i == dido_len - 1)) {
191 iowrite32(val, rs->base + MT7621_SPI_DATA0 +
192 (i & ~3));
193 val = 0;
194 }
195 }
196
197 iowrite32(((opcode_len * 8) << MOREBUF_CMD_CNT_SHIFT) |
198 ((dido_len * 8) << MOREBUF_MOSI_CNT_SHIFT),
199 rs->base + MT7621_SPI_MOREBUF);
200 iowrite32(MT7621_SPI_TRANS_START, rs->base + MT7621_SPI_TRANS);
201
202 ret = mt7621_spi_wait_till_ready(rs);
203 if (ret)
204 return ret;
205
206 len -= tx_len;
207 }
208
209 return 0;
210}
211
Stefan Roese5eee9de2018-08-16 10:48:48 +0200212static int mt7621_spi_xfer(struct udevice *dev, unsigned int bitlen,
213 const void *dout, void *din, unsigned long flags)
214{
215 struct udevice *bus = dev->parent;
216 struct mt7621_spi *rs = dev_get_priv(bus);
Stefan Roese5eee9de2018-08-16 10:48:48 +0200217 int total_size = bitlen >> 3;
Weijie Gao54a6b8e2019-09-25 17:45:24 +0800218 int ret = 0;
Stefan Roese5eee9de2018-08-16 10:48:48 +0200219
220 debug("%s: dout=%p, din=%p, len=%x, flags=%lx\n", __func__, dout, din,
221 total_size, flags);
222
223 /*
224 * This driver only supports half-duplex, so complain and bail out
225 * upon full-duplex messages
226 */
227 if (dout && din) {
228 printf("Only half-duplex SPI transfer supported\n");
229 return -EIO;
230 }
231
Stefan Roese5eee9de2018-08-16 10:48:48 +0200232 mt7621_spi_wait_till_ready(rs);
233
234 /*
235 * Set CS active upon start of SPI message. This message can
236 * be split upon multiple calls to this xfer function
237 */
238 if (flags & SPI_XFER_BEGIN)
239 mt7621_spi_set_cs(rs, spi_chip_select(dev), 1);
240
Weijie Gao54a6b8e2019-09-25 17:45:24 +0800241 if (din)
242 ret = mt7621_spi_read(rs, din, total_size);
243 else if (dout)
244 ret = mt7621_spi_write(rs, dout, total_size);
Stefan Roese5eee9de2018-08-16 10:48:48 +0200245
Stefan Roese5eee9de2018-08-16 10:48:48 +0200246 if (flags & SPI_XFER_END)
247 mt7621_spi_set_cs(rs, spi_chip_select(dev), 0);
248
Weijie Gao54a6b8e2019-09-25 17:45:24 +0800249 return ret;
Stefan Roese5eee9de2018-08-16 10:48:48 +0200250}
251
252static int mt7621_spi_probe(struct udevice *dev)
253{
254 struct mt7621_spi *rs = dev_get_priv(dev);
Weijie Gaof0997852019-09-25 17:45:23 +0800255 struct clk clk;
256 int ret;
Stefan Roese5eee9de2018-08-16 10:48:48 +0200257
258 rs->base = dev_remap_addr(dev);
259 if (!rs->base)
260 return -EINVAL;
261
Weijie Gaof0997852019-09-25 17:45:23 +0800262 ret = clk_get_by_index(dev, 0, &clk);
263 if (ret < 0) {
264 printf("Please provide a clock!\n");
265 return ret;
266 }
267
268 clk_enable(&clk);
269
270 rs->sys_freq = clk_get_rate(&clk);
Stefan Roese5eee9de2018-08-16 10:48:48 +0200271 if (!rs->sys_freq) {
Weijie Gaof0997852019-09-25 17:45:23 +0800272 printf("Please provide a valid clock!\n");
Stefan Roese5eee9de2018-08-16 10:48:48 +0200273 return -EINVAL;
274 }
275
276 mt7621_spi_reset(rs, 0);
277
278 return 0;
279}
280
281static const struct dm_spi_ops mt7621_spi_ops = {
282 .set_mode = mt7621_spi_set_mode,
283 .set_speed = mt7621_spi_set_speed,
284 .xfer = mt7621_spi_xfer,
285 /*
286 * cs_info is not needed, since we require all chip selects to be
287 * in the device tree explicitly
288 */
289};
290
291static const struct udevice_id mt7621_spi_ids[] = {
292 { .compatible = "ralink,mt7621-spi" },
293 { }
294};
295
296U_BOOT_DRIVER(mt7621_spi) = {
297 .name = "mt7621_spi",
298 .id = UCLASS_SPI,
299 .of_match = mt7621_spi_ids,
300 .ops = &mt7621_spi_ops,
301 .priv_auto_alloc_size = sizeof(struct mt7621_spi),
302 .probe = mt7621_spi_probe,
303};