Blame view

drivers/spi/rk_spi.c 14.8 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
2
3
4
  /*
   * spi driver for rockchip
   *
8aa6c921f   Philipp Tomsich   rockchip: spi: ad...
5
6
   * (C) 2019 Theobroma Systems Design und Consulting GmbH
   *
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
7
8
9
10
   * (C) Copyright 2015 Google, Inc
   *
   * (C) Copyright 2008-2013 Rockchip Electronics
   * Peter, Software Engineering, <superpeter.cai@gmail.com>.
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
11
12
13
14
15
   */
  
  #include <common.h>
  #include <clk.h>
  #include <dm.h>
6e019c4f2   Simon Glass   rockchip: spi: Ad...
16
  #include <dt-structs.h>
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
17
18
  #include <errno.h>
  #include <spi.h>
1045315df   Simon Glass   common: Move get_...
19
  #include <time.h>
1221ce459   Masahiro Yamada   treewide: replace...
20
  #include <linux/errno.h>
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
21
  #include <asm/io.h>
15f09a1a8   Kever Yang   rockchip: use 'ar...
22
23
  #include <asm/arch-rockchip/clock.h>
  #include <asm/arch-rockchip/periph.h>
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
24
25
  #include <dm/pinctrl.h>
  #include "rk_spi.h"
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
26
27
  /* Change to 1 to output registers at the start of each transaction */
  #define DEBUG_RK_SPI	0
dbbdc81c6   Jagan Teki   spi: rk: Limit tr...
28
29
30
31
32
  /*
   * ctrlr1 is 16-bits, so we should support lengths of 0xffff + 1. However,
   * the controller seems to hang when given 0x10000, so stick with this for now.
   */
  #define ROCKCHIP_SPI_MAX_TRANLEN		0xffff
51a644a1b   Philipp Tomsich   rockchip: spi: ad...
33
34
35
36
  struct rockchip_spi_params {
  	/* RXFIFO overruns and TXFIFO underruns stop the master clock */
  	bool master_manages_fifo;
  };
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
37
  struct rockchip_spi_platdata {
6e019c4f2   Simon Glass   rockchip: spi: Ad...
38
39
40
  #if CONFIG_IS_ENABLED(OF_PLATDATA)
  	struct dtd_rockchip_rk3288_spi of_plat;
  #endif
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
41
42
43
  	s32 frequency;		/* Default clock frequency, -1 for none */
  	fdt_addr_t base;
  	uint deactivate_delay_us;	/* Delay to wait after deactivate */
183a3a0f6   Simon Glass   rockchip: spi: Im...
44
  	uint activate_delay_us;		/* Delay to wait after activate */
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
45
46
47
48
  };
  
  struct rockchip_spi_priv {
  	struct rockchip_spi *regs;
135aa9500   Stephen Warren   clk: convert API ...
49
  	struct clk clk;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
50
51
  	unsigned int max_freq;
  	unsigned int mode;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
52
  	ulong last_transaction_us;	/* Time of last transaction end */
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
53
  	unsigned int speed_hz;
28a943c11   Simon Glass   rockchip: spi: Re...
54
  	unsigned int last_speed_hz;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	uint input_rate;
  };
  
  #define SPI_FIFO_DEPTH		32
  
  static void rkspi_dump_regs(struct rockchip_spi *regs)
  {
  	debug("ctrl0: \t\t0x%08x
  ", readl(&regs->ctrlr0));
  	debug("ctrl1: \t\t0x%08x
  ", readl(&regs->ctrlr1));
  	debug("ssienr: \t\t0x%08x
  ", readl(&regs->enr));
  	debug("ser: \t\t0x%08x
  ", readl(&regs->ser));
  	debug("baudr: \t\t0x%08x
  ", readl(&regs->baudr));
  	debug("txftlr: \t\t0x%08x
  ", readl(&regs->txftlr));
  	debug("rxftlr: \t\t0x%08x
  ", readl(&regs->rxftlr));
  	debug("txflr: \t\t0x%08x
  ", readl(&regs->txflr));
  	debug("rxflr: \t\t0x%08x
  ", readl(&regs->rxflr));
  	debug("sr: \t\t0x%08x
  ", readl(&regs->sr));
  	debug("imr: \t\t0x%08x
  ", readl(&regs->imr));
  	debug("isr: \t\t0x%08x
  ", readl(&regs->isr));
  	debug("dmacr: \t\t0x%08x
  ", readl(&regs->dmacr));
  	debug("dmatdlr: \t0x%08x
  ", readl(&regs->dmatdlr));
  	debug("dmardlr: \t0x%08x
  ", readl(&regs->dmardlr));
  }
  
  static void rkspi_enable_chip(struct rockchip_spi *regs, bool enable)
  {
  	writel(enable ? 1 : 0, &regs->enr);
  }
  
  static void rkspi_set_clk(struct rockchip_spi_priv *priv, uint speed)
  {
9fc354e24   Philipp Tomsich   rockchip: spi: re...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  	/*
  	 * We should try not to exceed the speed requested by the caller:
  	 * when selecting a divider, we need to make sure we round up.
  	 */
  	uint clk_div = DIV_ROUND_UP(priv->input_rate, speed);
  
  	/* The baudrate register (BAUDR) is defined as a 32bit register where
  	 * the upper 16bit are reserved and having 'Fsclk_out' in the lower
  	 * 16bits with 'Fsclk_out' defined as follows:
  	 *
  	 *   Fsclk_out = Fspi_clk/ SCKDV
  	 *   Where SCKDV is any even value between 2 and 65534.
  	 */
  	if (clk_div > 0xfffe) {
  		clk_div = 0xfffe;
11f12c17d   Heinrich Schuchardt   rockchip: spi: th...
116
117
  		debug("%s: can't divide down to %d Hz (actual will be %d Hz)
  ",
9fc354e24   Philipp Tomsich   rockchip: spi: re...
118
119
120
121
122
  		      __func__, speed, priv->input_rate / clk_div);
  	}
  
  	/* Round up to the next even 16bit number */
  	clk_div = (clk_div + 1) & 0xfffe;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
123

1b2fd5bf4   Simon Glass   rockchip: Add SPI...
124
125
  	debug("spi speed %u, div %u
  ", speed, clk_div);
9fc354e24   Philipp Tomsich   rockchip: spi: re...
126
  	clrsetbits_le32(&priv->regs->baudr, 0xffff, clk_div);
28a943c11   Simon Glass   rockchip: spi: Re...
127
  	priv->last_speed_hz = speed;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  }
  
  static int rkspi_wait_till_not_busy(struct rockchip_spi *regs)
  {
  	unsigned long start;
  
  	start = get_timer(0);
  	while (readl(&regs->sr) & SR_BUSY) {
  		if (get_timer(start) > ROCKCHIP_SPI_TIMEOUT_MS) {
  			debug("RK SPI: Status keeps busy for 1000us after a read/write!
  ");
  			return -ETIMEDOUT;
  		}
  	}
  
  	return 0;
  }
183a3a0f6   Simon Glass   rockchip: spi: Im...
145
  static void spi_cs_activate(struct udevice *dev, uint cs)
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
146
  {
183a3a0f6   Simon Glass   rockchip: spi: Im...
147
148
149
150
  	struct udevice *bus = dev->parent;
  	struct rockchip_spi_platdata *plat = bus->platdata;
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
  	struct rockchip_spi *regs = priv->regs;
b42524744   Simon Glass   rockchip: spi: Ho...
151
152
153
154
  	/* If it's too soon to do another transaction, wait */
  	if (plat->deactivate_delay_us && priv->last_transaction_us) {
  		ulong delay_us;		/* The delay completed so far */
  		delay_us = timer_get_us() - priv->last_transaction_us;
f92cf0adc   Philipp Tomsich   rockchip: spi: ad...
155
156
157
158
159
160
161
162
  		if (delay_us < plat->deactivate_delay_us) {
  			ulong additional_delay_us =
  				plat->deactivate_delay_us - delay_us;
  			debug("%s: delaying by %ld us
  ",
  			      __func__, additional_delay_us);
  			udelay(additional_delay_us);
  		}
b42524744   Simon Glass   rockchip: spi: Ho...
163
  	}
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
164
165
166
  	debug("activate cs%u
  ", cs);
  	writel(1 << cs, &regs->ser);
183a3a0f6   Simon Glass   rockchip: spi: Im...
167
168
  	if (plat->activate_delay_us)
  		udelay(plat->activate_delay_us);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
169
  }
183a3a0f6   Simon Glass   rockchip: spi: Im...
170
  static void spi_cs_deactivate(struct udevice *dev, uint cs)
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
171
  {
183a3a0f6   Simon Glass   rockchip: spi: Im...
172
173
174
175
  	struct udevice *bus = dev->parent;
  	struct rockchip_spi_platdata *plat = bus->platdata;
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
  	struct rockchip_spi *regs = priv->regs;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
176
177
178
  	debug("deactivate cs%u
  ", cs);
  	writel(0, &regs->ser);
183a3a0f6   Simon Glass   rockchip: spi: Im...
179
180
181
182
  
  	/* Remember time of this transaction so we can honour the bus delay */
  	if (plat->deactivate_delay_us)
  		priv->last_transaction_us = timer_get_us();
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
183
  }
6e019c4f2   Simon Glass   rockchip: spi: Ad...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  #if CONFIG_IS_ENABLED(OF_PLATDATA)
  static int conv_of_platdata(struct udevice *dev)
  {
  	struct rockchip_spi_platdata *plat = dev->platdata;
  	struct dtd_rockchip_rk3288_spi *dtplat = &plat->of_plat;
  	struct rockchip_spi_priv *priv = dev_get_priv(dev);
  	int ret;
  
  	plat->base = dtplat->reg[0];
  	plat->frequency = 20000000;
  	ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
  	if (ret < 0)
  		return ret;
  	dev->req_seq = 0;
  
  	return 0;
  }
  #endif
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
202
203
  static int rockchip_spi_ofdata_to_platdata(struct udevice *bus)
  {
6e019c4f2   Simon Glass   rockchip: spi: Ad...
204
205
  #if !CONFIG_IS_ENABLED(OF_PLATDATA)
  	struct rockchip_spi_platdata *plat = dev_get_platdata(bus);
71037d1ca   Simon Glass   rockchip: spi: Up...
206
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
207
  	int ret;
d27c27390   Philipp Tomsich   rockchip: spi: Co...
208
  	plat->base = dev_read_addr(bus);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
209

71037d1ca   Simon Glass   rockchip: spi: Up...
210
211
212
213
214
215
216
  	ret = clk_get_by_index(bus, 0, &priv->clk);
  	if (ret < 0) {
  		debug("%s: Could not get clock for %s: %d
  ", __func__,
  		      bus->name, ret);
  		return ret;
  	}
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
217

6c65577ce   Philipp Tomsich   rockchip: spi: dm...
218
219
220
221
222
223
  	plat->frequency =
  		dev_read_u32_default(bus, "spi-max-frequency", 50000000);
  	plat->deactivate_delay_us =
  		dev_read_u32_default(bus, "spi-deactivate-delay", 0);
  	plat->activate_delay_us =
  		dev_read_u32_default(bus, "spi-activate-delay", 0);
90a28470f   Simon Glass   rockchip: spi: Re...
224
225
226
  	debug("%s: base=%x, max-frequency=%d, deactivate_delay=%d
  ",
  	      __func__, (uint)plat->base, plat->frequency,
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
227
  	      plat->deactivate_delay_us);
6e019c4f2   Simon Glass   rockchip: spi: Ad...
228
  #endif
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
229
230
231
  
  	return 0;
  }
bd3767143   Philipp Tomsich   rockchip: spi: rk...
232
233
  static int rockchip_spi_calc_modclk(ulong max_freq)
  {
d16120a6d   Philipp Tomsich   rockchip: spi: en...
234
235
236
237
238
239
240
  	/*
  	 * While this is not strictly correct for the RK3368, as the
  	 * GPLL will be 576MHz, things will still work, as the
  	 * clk_set_rate(...) implementation in our clock-driver will
  	 * chose the next closest rate not exceeding what we request
  	 * based on the output of this function.
  	 */
bd3767143   Philipp Tomsich   rockchip: spi: rk...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  	unsigned div;
  	const unsigned long gpll_hz = 594000000UL;
  
  	/*
  	 * We need to find an input clock that provides at least twice
  	 * the maximum frequency and can be generated from the assumed
  	 * speed of GPLL (594MHz) using an integer divider.
  	 *
  	 * To give us more achievable bitrates at higher speeds (these
  	 * are generated by dividing by an even 16-bit integer from
  	 * this frequency), we try to have an input frequency of at
  	 * least 4x our max_freq.
  	 */
  
  	div = DIV_ROUND_UP(gpll_hz, max_freq * 4);
  	return gpll_hz / div;
  }
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
258
259
260
261
262
263
264
265
  static int rockchip_spi_probe(struct udevice *bus)
  {
  	struct rockchip_spi_platdata *plat = dev_get_platdata(bus);
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
  	int ret;
  
  	debug("%s: probe
  ", __func__);
6e019c4f2   Simon Glass   rockchip: spi: Ad...
266
267
268
269
270
  #if CONFIG_IS_ENABLED(OF_PLATDATA)
  	ret = conv_of_platdata(bus);
  	if (ret)
  		return ret;
  #endif
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
271
272
273
274
  	priv->regs = (struct rockchip_spi *)plat->base;
  
  	priv->last_transaction_us = timer_get_us();
  	priv->max_freq = plat->frequency;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
275

bd3767143   Philipp Tomsich   rockchip: spi: rk...
276
277
278
279
280
281
282
  	/* Clamp the value from the DTS against any hardware limits */
  	if (priv->max_freq > ROCKCHIP_SPI_MAX_RATE)
  		priv->max_freq = ROCKCHIP_SPI_MAX_RATE;
  
  	/* Find a module-input clock that fits with the max_freq setting */
  	ret = clk_set_rate(&priv->clk,
  			   rockchip_spi_calc_modclk(priv->max_freq));
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
283
284
285
286
287
288
289
290
  	if (ret < 0) {
  		debug("%s: Failed to set clock: %d
  ", __func__, ret);
  		return ret;
  	}
  	priv->input_rate = ret;
  	debug("%s: rate = %u
  ", __func__, priv->input_rate);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
291
292
293
294
295
296
297
  
  	return 0;
  }
  
  static int rockchip_spi_claim_bus(struct udevice *dev)
  {
  	struct udevice *bus = dev->parent;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
298
299
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
  	struct rockchip_spi *regs = priv->regs;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
300
  	uint ctrlr0;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
301
302
  
  	/* Disable the SPI hardware */
b6101e906   Philipp Tomsich   rockchip: spi: co...
303
  	rkspi_enable_chip(regs, false);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
304

28a943c11   Simon Glass   rockchip: spi: Re...
305
306
  	if (priv->speed_hz != priv->last_speed_hz)
  		rkspi_set_clk(priv, priv->speed_hz);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
307
308
309
310
311
  
  	/* Operation Mode */
  	ctrlr0 = OMOD_MASTER << OMOD_SHIFT;
  
  	/* Data Frame Size */
0e661b6df   Philipp Tomsich   rockchip: spi: re...
312
  	ctrlr0 |= DFS_8BIT << DFS_SHIFT;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  
  	/* set SPI mode 0..3 */
  	if (priv->mode & SPI_CPOL)
  		ctrlr0 |= SCOL_HIGH << SCOL_SHIFT;
  	if (priv->mode & SPI_CPHA)
  		ctrlr0 |= SCPH_TOGSTA << SCPH_SHIFT;
  
  	/* Chip Select Mode */
  	ctrlr0 |= CSM_KEEP << CSM_SHIFT;
  
  	/* SSN to Sclk_out delay */
  	ctrlr0 |= SSN_DELAY_ONE << SSN_DELAY_SHIFT;
  
  	/* Serial Endian Mode */
  	ctrlr0 |= SEM_LITTLE << SEM_SHIFT;
  
  	/* First Bit Mode */
  	ctrlr0 |= FBM_MSB << FBM_SHIFT;
  
  	/* Byte and Halfword Transform */
0e661b6df   Philipp Tomsich   rockchip: spi: re...
333
  	ctrlr0 |= HALF_WORD_OFF << HALF_WORD_TX_SHIFT;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
334
335
336
337
338
339
340
341
  
  	/* Rxd Sample Delay */
  	ctrlr0 |= 0 << RXDSD_SHIFT;
  
  	/* Frame Format */
  	ctrlr0 |= FRF_SPI << FRF_SHIFT;
  
  	/* Tx and Rx mode */
0e661b6df   Philipp Tomsich   rockchip: spi: re...
342
  	ctrlr0 |= TMOD_TR << TMOD_SHIFT;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
343
344
  
  	writel(ctrlr0, &regs->ctrlr0);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
345
346
347
348
349
350
  
  	return 0;
  }
  
  static int rockchip_spi_release_bus(struct udevice *dev)
  {
e15af8e2c   Simon Glass   rockchip: spi: Co...
351
352
353
354
  	struct udevice *bus = dev->parent;
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
  
  	rkspi_enable_chip(priv->regs, false);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
355
356
  	return 0;
  }
8aa6c921f   Philipp Tomsich   rockchip: spi: ad...
357
358
359
360
361
362
363
364
365
366
367
368
369
  static inline int rockchip_spi_16bit_reader(struct udevice *dev,
  					    u8 **din, int *len)
  {
  	struct udevice *bus = dev->parent;
  	const struct rockchip_spi_params * const data =
  		(void *)dev_get_driver_data(bus);
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
  	struct rockchip_spi *regs = priv->regs;
  	const u32 saved_ctrlr0 = readl(&regs->ctrlr0);
  #if defined(DEBUG)
  	u32 statistics_rxlevels[33] = { };
  #endif
  	u32 frames = *len / 2;
2236149e4   Philipp Tomsich   rockchip: spi: ma...
370
  	u8 *in = (u8 *)(*din);
8aa6c921f   Philipp Tomsich   rockchip: spi: ad...
371
372
373
374
375
376
  	u32 max_chunk_size = SPI_FIFO_DEPTH;
  
  	if (!frames)
  		return 0;
  
  	/*
51a644a1b   Philipp Tomsich   rockchip: spi: ad...
377
378
379
380
381
382
  	 * If we know that the hardware will manage RXFIFO overruns
  	 * (i.e. stop the SPI clock until there's space in the FIFO),
  	 * we the allow largest possible chunk size that can be
  	 * represented in CTRLR1.
  	 */
  	if (data && data->master_manages_fifo)
dbbdc81c6   Jagan Teki   spi: rk: Limit tr...
383
  		max_chunk_size = ROCKCHIP_SPI_MAX_TRANLEN;
51a644a1b   Philipp Tomsich   rockchip: spi: ad...
384

8aa6c921f   Philipp Tomsich   rockchip: spi: ad...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  	// rockchip_spi_configure(dev, mode, size)
  	rkspi_enable_chip(regs, false);
  	clrsetbits_le32(&regs->ctrlr0,
  			TMOD_MASK << TMOD_SHIFT,
  			TMOD_RO << TMOD_SHIFT);
  	/* 16bit data frame size */
  	clrsetbits_le32(&regs->ctrlr0, DFS_MASK, DFS_16BIT);
  
  	/* Update caller's context */
  	const u32 bytes_to_process = 2 * frames;
  	*din += bytes_to_process;
  	*len -= bytes_to_process;
  
  	/* Process our frames */
  	while (frames) {
  		u32 chunk_size = min(frames, max_chunk_size);
  
  		frames -= chunk_size;
  
  		writew(chunk_size - 1, &regs->ctrlr1);
  		rkspi_enable_chip(regs, true);
  
  		do {
  			u32 rx_level = readw(&regs->rxflr);
  #if defined(DEBUG)
  			statistics_rxlevels[rx_level]++;
  #endif
  			chunk_size -= rx_level;
2236149e4   Philipp Tomsich   rockchip: spi: ma...
413
414
415
416
417
  			while (rx_level--) {
  				u16 val = readw(regs->rxdr);
  				*in++ = val & 0xff;
  				*in++ = val >> 8;
  			}
8aa6c921f   Philipp Tomsich   rockchip: spi: ad...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  		} while (chunk_size);
  
  		rkspi_enable_chip(regs, false);
  	}
  
  #if defined(DEBUG)
  	debug("%s: observed rx_level during processing:
  ", __func__);
  	for (int i = 0; i <= 32; ++i)
  		if (statistics_rxlevels[i])
  			debug("\t%2d: %d
  ", i, statistics_rxlevels[i]);
  #endif
  	/* Restore the original transfer setup and return error-free. */
  	writel(saved_ctrlr0, &regs->ctrlr0);
  	return 0;
  }
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
435
436
437
438
439
440
441
442
443
444
445
  static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
  			   const void *dout, void *din, unsigned long flags)
  {
  	struct udevice *bus = dev->parent;
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
  	struct rockchip_spi *regs = priv->regs;
  	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
  	int len = bitlen >> 3;
  	const u8 *out = dout;
  	u8 *in = din;
  	int toread, towrite;
8aa6c921f   Philipp Tomsich   rockchip: spi: ad...
446
  	int ret = 0;
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
447
448
449
450
451
452
453
454
455
  
  	debug("%s: dout=%p, din=%p, len=%x, flags=%lx
  ", __func__, dout, din,
  	      len, flags);
  	if (DEBUG_RK_SPI)
  		rkspi_dump_regs(regs);
  
  	/* Assert CS before transfer */
  	if (flags & SPI_XFER_BEGIN)
183a3a0f6   Simon Glass   rockchip: spi: Im...
456
  		spi_cs_activate(dev, slave_plat->cs);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
457

8aa6c921f   Philipp Tomsich   rockchip: spi: ad...
458
459
460
461
462
463
464
465
466
467
  	/*
  	 * To ensure fast loading of firmware images (e.g. full U-Boot
  	 * stage, ATF, Linux kernel) from SPI flash, we optimise the
  	 * case of read-only transfers by using the full 16bits of each
  	 * FIFO element.
  	 */
  	if (!out)
  		ret = rockchip_spi_16bit_reader(dev, &in, &len);
  
  	/* This is the original 8bit reader/writer code */
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
468
  	while (len > 0) {
dbbdc81c6   Jagan Teki   spi: rk: Limit tr...
469
  		int todo = min(len, ROCKCHIP_SPI_MAX_TRANLEN);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
470

e15af8e2c   Simon Glass   rockchip: spi: Co...
471
  		rkspi_enable_chip(regs, false);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  		writel(todo - 1, &regs->ctrlr1);
  		rkspi_enable_chip(regs, true);
  
  		toread = todo;
  		towrite = todo;
  		while (toread || towrite) {
  			u32 status = readl(&regs->sr);
  
  			if (towrite && !(status & SR_TF_FULL)) {
  				writel(out ? *out++ : 0, regs->txdr);
  				towrite--;
  			}
  			if (toread && !(status & SR_RF_EMPT)) {
  				u32 byte = readl(regs->rxdr);
  
  				if (in)
  					*in++ = byte;
  				toread--;
  			}
  		}
7e0e5c552   Philipp Tomsich   rockchip: spi: on...
492
493
494
495
496
497
498
499
500
501
502
  
  		/*
  		 * In case that there's a transmit-component, we need to wait
  		 * until the control goes idle before we can disable the SPI
  		 * control logic (as this will implictly flush the FIFOs).
  		 */
  		if (out) {
  			ret = rkspi_wait_till_not_busy(regs);
  			if (ret)
  				break;
  		}
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
503
504
505
506
507
  		len -= todo;
  	}
  
  	/* Deassert CS after transfer */
  	if (flags & SPI_XFER_END)
183a3a0f6   Simon Glass   rockchip: spi: Im...
508
  		spi_cs_deactivate(dev, slave_plat->cs);
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
509
510
511
512
513
514
515
516
517
  
  	rkspi_enable_chip(regs, false);
  
  	return ret;
  }
  
  static int rockchip_spi_set_speed(struct udevice *bus, uint speed)
  {
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
bd3767143   Philipp Tomsich   rockchip: spi: rk...
518
  	/* Clamp to the maximum frequency specified in the DTS */
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
519
520
  	if (speed > priv->max_freq)
  		speed = priv->max_freq;
bd3767143   Philipp Tomsich   rockchip: spi: rk...
521

1b2fd5bf4   Simon Glass   rockchip: Add SPI...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
  	priv->speed_hz = speed;
  
  	return 0;
  }
  
  static int rockchip_spi_set_mode(struct udevice *bus, uint mode)
  {
  	struct rockchip_spi_priv *priv = dev_get_priv(bus);
  
  	priv->mode = mode;
  
  	return 0;
  }
  
  static const struct dm_spi_ops rockchip_spi_ops = {
  	.claim_bus	= rockchip_spi_claim_bus,
  	.release_bus	= rockchip_spi_release_bus,
  	.xfer		= rockchip_spi_xfer,
  	.set_speed	= rockchip_spi_set_speed,
  	.set_mode	= rockchip_spi_set_mode,
  	/*
  	 * cs_info is not needed, since we require all chip selects to be
  	 * in the device tree explicitly
  	 */
  };
51a644a1b   Philipp Tomsich   rockchip: spi: ad...
547
548
549
  const  struct rockchip_spi_params rk3399_spi_params = {
  	.master_manages_fifo = true,
  };
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
550
551
  static const struct udevice_id rockchip_spi_ids[] = {
  	{ .compatible = "rockchip,rk3288-spi" },
51a644a1b   Philipp Tomsich   rockchip: spi: ad...
552
553
554
555
  	{ .compatible = "rockchip,rk3368-spi",
  	  .data = (ulong)&rk3399_spi_params },
  	{ .compatible = "rockchip,rk3399-spi",
  	  .data = (ulong)&rk3399_spi_params },
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
556
557
558
559
  	{ }
  };
  
  U_BOOT_DRIVER(rockchip_spi) = {
6e019c4f2   Simon Glass   rockchip: spi: Ad...
560
561
562
  #if CONFIG_IS_ENABLED(OF_PLATDATA)
  	.name	= "rockchip_rk3288_spi",
  #else
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
563
  	.name	= "rockchip_spi",
6e019c4f2   Simon Glass   rockchip: spi: Ad...
564
  #endif
1b2fd5bf4   Simon Glass   rockchip: Add SPI...
565
566
567
568
569
570
571
572
  	.id	= UCLASS_SPI,
  	.of_match = rockchip_spi_ids,
  	.ops	= &rockchip_spi_ops,
  	.ofdata_to_platdata = rockchip_spi_ofdata_to_platdata,
  	.platdata_auto_alloc_size = sizeof(struct rockchip_spi_platdata),
  	.priv_auto_alloc_size = sizeof(struct rockchip_spi_priv),
  	.probe	= rockchip_spi_probe,
  };