blob: 3d0080998625632f5586741337c9cc30b4418bf3 [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>
Simon Glassf7ae49f2020-05-10 11:40:05 -060014#include <log.h>
Stefan Roese5eee9de2018-08-16 10:48:48 +020015#include <spi.h>
16#include <wait_bit.h>
Simon Glasscd93d622020-05-10 11:40:13 -060017#include <linux/bitops.h>
Stefan Roese5eee9de2018-08-16 10:48:48 +020018#include <linux/io.h>
Simon Glass1e94b462023-09-14 18:21:46 -060019#include <linux/printk.h>
Stefan Roese5eee9de2018-08-16 10:48:48 +020020
Weijie Gao54a6b8e2019-09-25 17:45:24 +080021#define MT7621_RX_FIFO_LEN 32
22#define MT7621_TX_FIFO_LEN 36
Stefan Roese5eee9de2018-08-16 10:48:48 +020023
24#define MT7621_SPI_TRANS 0x00
25#define MT7621_SPI_TRANS_START BIT(8)
26#define MT7621_SPI_TRANS_BUSY BIT(16)
Weijie Gao43405e02019-09-25 17:45:25 +080027#define TRANS_ADDR_SZ GENMASK(20, 19)
28#define TRANS_ADDR_SZ_SHIFT 19
29#define TRANS_MOSI_BCNT GENMASK(3, 0)
30#define TRANS_MOSI_BCNT_SHIFT 0
Stefan Roese5eee9de2018-08-16 10:48:48 +020031
32#define MT7621_SPI_OPCODE 0x04
33#define MT7621_SPI_DATA0 0x08
34#define MT7621_SPI_DATA4 0x18
35#define MT7621_SPI_MASTER 0x28
36#define MT7621_SPI_MOREBUF 0x2c
37#define MT7621_SPI_POLAR 0x38
38
39#define MT7621_LSB_FIRST BIT(3)
40#define MT7621_CPOL BIT(4)
41#define MT7621_CPHA BIT(5)
42
43#define MASTER_MORE_BUFMODE BIT(2)
44#define MASTER_RS_CLK_SEL GENMASK(27, 16)
45#define MASTER_RS_CLK_SEL_SHIFT 16
46#define MASTER_RS_SLAVE_SEL GENMASK(31, 29)
47
Weijie Gao54a6b8e2019-09-25 17:45:24 +080048#define MOREBUF_CMD_CNT GENMASK(29, 24)
49#define MOREBUF_CMD_CNT_SHIFT 24
50#define MOREBUF_MISO_CNT GENMASK(20, 12)
51#define MOREBUF_MISO_CNT_SHIFT 12
52#define MOREBUF_MOSI_CNT GENMASK(8, 0)
53#define MOREBUF_MOSI_CNT_SHIFT 0
54
Stefan Roese5eee9de2018-08-16 10:48:48 +020055struct mt7621_spi {
56 void __iomem *base;
57 unsigned int sys_freq;
Stefan Roese5eee9de2018-08-16 10:48:48 +020058};
59
Stefan Roese5eee9de2018-08-16 10:48:48 +020060static void mt7621_spi_set_cs(struct mt7621_spi *rs, int cs, int enable)
61{
Stefan Roese5eee9de2018-08-16 10:48:48 +020062 debug("%s: cs#%d -> %s\n", __func__, cs, enable ? "enable" : "disable");
Weijie Gao43405e02019-09-25 17:45:25 +080063
64 if (enable) {
65 setbits_le32(rs->base + MT7621_SPI_MASTER,
66 MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE);
67 iowrite32(BIT(cs), rs->base + MT7621_SPI_POLAR);
68 } else {
69 iowrite32(0, rs->base + MT7621_SPI_POLAR);
70 iowrite32((2 << TRANS_ADDR_SZ_SHIFT) |
71 (1 << TRANS_MOSI_BCNT_SHIFT),
72 rs->base + MT7621_SPI_TRANS);
73 clrbits_le32(rs->base + MT7621_SPI_MASTER,
74 MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE);
75 }
Stefan Roese5eee9de2018-08-16 10:48:48 +020076}
77
78static int mt7621_spi_set_mode(struct udevice *bus, uint mode)
79{
80 struct mt7621_spi *rs = dev_get_priv(bus);
81 u32 reg;
82
83 debug("%s: mode=0x%08x\n", __func__, mode);
84 reg = ioread32(rs->base + MT7621_SPI_MASTER);
85
86 reg &= ~MT7621_LSB_FIRST;
87 if (mode & SPI_LSB_FIRST)
88 reg |= MT7621_LSB_FIRST;
89
90 reg &= ~(MT7621_CPHA | MT7621_CPOL);
91 switch (mode & (SPI_CPOL | SPI_CPHA)) {
92 case SPI_MODE_0:
93 break;
94 case SPI_MODE_1:
95 reg |= MT7621_CPHA;
96 break;
97 case SPI_MODE_2:
98 reg |= MT7621_CPOL;
99 break;
100 case SPI_MODE_3:
101 reg |= MT7621_CPOL | MT7621_CPHA;
102 break;
103 }
104 iowrite32(reg, rs->base + MT7621_SPI_MASTER);
105
106 return 0;
107}
108
109static int mt7621_spi_set_speed(struct udevice *bus, uint speed)
110{
111 struct mt7621_spi *rs = dev_get_priv(bus);
112 u32 rate;
113 u32 reg;
114
115 debug("%s: speed=%d\n", __func__, speed);
116 rate = DIV_ROUND_UP(rs->sys_freq, speed);
117 debug("rate:%u\n", rate);
118
119 if (rate > 4097)
120 return -EINVAL;
121
122 if (rate < 2)
123 rate = 2;
124
125 reg = ioread32(rs->base + MT7621_SPI_MASTER);
126 reg &= ~MASTER_RS_CLK_SEL;
127 reg |= (rate - 2) << MASTER_RS_CLK_SEL_SHIFT;
128 iowrite32(reg, rs->base + MT7621_SPI_MASTER);
129
130 return 0;
131}
132
133static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs)
134{
135 int ret;
136
137 ret = wait_for_bit_le32(rs->base + MT7621_SPI_TRANS,
138 MT7621_SPI_TRANS_BUSY, 0, 10, 0);
139 if (ret)
140 pr_err("Timeout in %s!\n", __func__);
141
142 return ret;
143}
144
Weijie Gao54a6b8e2019-09-25 17:45:24 +0800145static int mt7621_spi_read(struct mt7621_spi *rs, u8 *buf, size_t len)
146{
147 size_t rx_len;
148 int i, ret;
149 u32 val = 0;
150
151 while (len) {
152 rx_len = min_t(size_t, len, MT7621_RX_FIFO_LEN);
153
154 iowrite32((rx_len * 8) << MOREBUF_MISO_CNT_SHIFT,
155 rs->base + MT7621_SPI_MOREBUF);
156 iowrite32(MT7621_SPI_TRANS_START, rs->base + MT7621_SPI_TRANS);
157
158 ret = mt7621_spi_wait_till_ready(rs);
159 if (ret)
160 return ret;
161
162 for (i = 0; i < rx_len; i++) {
163 if ((i % 4) == 0)
164 val = ioread32(rs->base + MT7621_SPI_DATA0 + i);
165 *buf++ = val & 0xff;
166 val >>= 8;
167 }
168
169 len -= rx_len;
170 }
171
172 return ret;
173}
174
175static int mt7621_spi_write(struct mt7621_spi *rs, const u8 *buf, size_t len)
176{
177 size_t tx_len, opcode_len, dido_len;
178 int i, ret;
179 u32 val;
180
181 while (len) {
182 tx_len = min_t(size_t, len, MT7621_TX_FIFO_LEN);
183
184 opcode_len = min_t(size_t, tx_len, 4);
185 dido_len = tx_len - opcode_len;
186
187 val = 0;
188 for (i = 0; i < opcode_len; i++) {
189 val <<= 8;
190 val |= *buf++;
191 }
192
193 iowrite32(val, rs->base + MT7621_SPI_OPCODE);
194
195 val = 0;
196 for (i = 0; i < dido_len; i++) {
197 val |= (*buf++) << ((i % 4) * 8);
198
199 if ((i % 4 == 3) || (i == dido_len - 1)) {
200 iowrite32(val, rs->base + MT7621_SPI_DATA0 +
201 (i & ~3));
202 val = 0;
203 }
204 }
205
206 iowrite32(((opcode_len * 8) << MOREBUF_CMD_CNT_SHIFT) |
207 ((dido_len * 8) << MOREBUF_MOSI_CNT_SHIFT),
208 rs->base + MT7621_SPI_MOREBUF);
209 iowrite32(MT7621_SPI_TRANS_START, rs->base + MT7621_SPI_TRANS);
210
211 ret = mt7621_spi_wait_till_ready(rs);
212 if (ret)
213 return ret;
214
215 len -= tx_len;
216 }
217
218 return 0;
219}
220
Stefan Roese5eee9de2018-08-16 10:48:48 +0200221static int mt7621_spi_xfer(struct udevice *dev, unsigned int bitlen,
222 const void *dout, void *din, unsigned long flags)
223{
224 struct udevice *bus = dev->parent;
225 struct mt7621_spi *rs = dev_get_priv(bus);
Stefan Roese5eee9de2018-08-16 10:48:48 +0200226 int total_size = bitlen >> 3;
Weijie Gao54a6b8e2019-09-25 17:45:24 +0800227 int ret = 0;
Stefan Roese5eee9de2018-08-16 10:48:48 +0200228
229 debug("%s: dout=%p, din=%p, len=%x, flags=%lx\n", __func__, dout, din,
230 total_size, flags);
231
232 /*
233 * This driver only supports half-duplex, so complain and bail out
234 * upon full-duplex messages
235 */
236 if (dout && din) {
237 printf("Only half-duplex SPI transfer supported\n");
238 return -EIO;
239 }
240
Stefan Roese5eee9de2018-08-16 10:48:48 +0200241 mt7621_spi_wait_till_ready(rs);
242
243 /*
244 * Set CS active upon start of SPI message. This message can
245 * be split upon multiple calls to this xfer function
246 */
247 if (flags & SPI_XFER_BEGIN)
248 mt7621_spi_set_cs(rs, spi_chip_select(dev), 1);
249
Weijie Gao54a6b8e2019-09-25 17:45:24 +0800250 if (din)
251 ret = mt7621_spi_read(rs, din, total_size);
252 else if (dout)
253 ret = mt7621_spi_write(rs, dout, total_size);
Stefan Roese5eee9de2018-08-16 10:48:48 +0200254
Stefan Roese5eee9de2018-08-16 10:48:48 +0200255 if (flags & SPI_XFER_END)
256 mt7621_spi_set_cs(rs, spi_chip_select(dev), 0);
257
Weijie Gao54a6b8e2019-09-25 17:45:24 +0800258 return ret;
Stefan Roese5eee9de2018-08-16 10:48:48 +0200259}
260
261static int mt7621_spi_probe(struct udevice *dev)
262{
263 struct mt7621_spi *rs = dev_get_priv(dev);
Weijie Gaof0997852019-09-25 17:45:23 +0800264 struct clk clk;
265 int ret;
Stefan Roese5eee9de2018-08-16 10:48:48 +0200266
267 rs->base = dev_remap_addr(dev);
268 if (!rs->base)
269 return -EINVAL;
270
Weijie Gaof0997852019-09-25 17:45:23 +0800271 ret = clk_get_by_index(dev, 0, &clk);
272 if (ret < 0) {
273 printf("Please provide a clock!\n");
274 return ret;
275 }
276
277 clk_enable(&clk);
278
279 rs->sys_freq = clk_get_rate(&clk);
Stefan Roese5eee9de2018-08-16 10:48:48 +0200280 if (!rs->sys_freq) {
Weijie Gaof0997852019-09-25 17:45:23 +0800281 printf("Please provide a valid clock!\n");
Stefan Roese5eee9de2018-08-16 10:48:48 +0200282 return -EINVAL;
283 }
284
Stefan Roese5eee9de2018-08-16 10:48:48 +0200285 return 0;
286}
287
288static const struct dm_spi_ops mt7621_spi_ops = {
289 .set_mode = mt7621_spi_set_mode,
290 .set_speed = mt7621_spi_set_speed,
291 .xfer = mt7621_spi_xfer,
292 /*
293 * cs_info is not needed, since we require all chip selects to be
294 * in the device tree explicitly
295 */
296};
297
298static const struct udevice_id mt7621_spi_ids[] = {
299 { .compatible = "ralink,mt7621-spi" },
300 { }
301};
302
303U_BOOT_DRIVER(mt7621_spi) = {
304 .name = "mt7621_spi",
305 .id = UCLASS_SPI,
306 .of_match = mt7621_spi_ids,
307 .ops = &mt7621_spi_ops,
Simon Glass41575d82020-12-03 16:55:17 -0700308 .priv_auto = sizeof(struct mt7621_spi),
Stefan Roese5eee9de2018-08-16 10:48:48 +0200309 .probe = mt7621_spi_probe,
310};