Blame view
drivers/spi/sh_qspi.c
7.42 KB
83d290c56
|
1 |
// SPDX-License-Identifier: GPL-2.0 |
16f47c9c5
|
2 3 4 5 6 |
/* * SH QSPI (Quad SPI) driver * * Copyright (C) 2013 Renesas Electronics Corporation * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> |
16f47c9c5
|
7 8 9 |
*/ #include <common.h> |
24b852a7a
|
10 |
#include <console.h> |
16f47c9c5
|
11 12 |
#include <malloc.h> #include <spi.h> |
9573db654
|
13 |
#include <wait_bit.h> |
22e75d6d6
|
14 |
#include <asm/arch/rmobile.h> |
16f47c9c5
|
15 16 17 18 19 20 21 22 23 24 |
#include <asm/io.h> /* SH QSPI register bit masks <REG>_<BIT> */ #define SPCR_MSTR 0x08 #define SPCR_SPE 0x40 #define SPSR_SPRFF 0x80 #define SPSR_SPTEF 0x20 #define SPPCR_IO3FV 0x04 #define SPPCR_IO2FV 0x02 #define SPPCR_IO1FV 0x01 |
ccaa94850
|
25 26 27 28 29 30 |
#define SPBDCR_RXBC0 BIT(0) #define SPCMD_SCKDEN BIT(15) #define SPCMD_SLNDEN BIT(14) #define SPCMD_SPNDEN BIT(13) #define SPCMD_SSLKP BIT(7) #define SPCMD_BRDV0 BIT(2) |
16f47c9c5
|
31 32 33 34 35 |
#define SPCMD_INIT1 SPCMD_SCKDEN | SPCMD_SLNDEN | \ SPCMD_SPNDEN | SPCMD_SSLKP | \ SPCMD_BRDV0 #define SPCMD_INIT2 SPCMD_SPNDEN | SPCMD_SSLKP | \ SPCMD_BRDV0 |
ccaa94850
|
36 37 |
#define SPBFCR_TXRST BIT(7) #define SPBFCR_RXRST BIT(6) |
ea5512eb0
|
38 39 |
#define SPBFCR_TXTRG 0x30 #define SPBFCR_RXTRG 0x07 |
16f47c9c5
|
40 41 42 |
/* SH QSPI register set */ struct sh_qspi_regs { |
0e6fa20b1
|
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
u8 spcr; u8 sslp; u8 sppcr; u8 spsr; u32 spdr; u8 spscr; u8 spssr; u8 spbr; u8 spdcr; u8 spckd; u8 sslnd; u8 spnd; u8 dummy0; u16 spcmd0; u16 spcmd1; u16 spcmd2; u16 spcmd3; u8 spbfcr; u8 dummy1; u16 spbdcr; u32 spbmul0; u32 spbmul1; u32 spbmul2; u32 spbmul3; |
16f47c9c5
|
67 68 69 |
}; struct sh_qspi_slave { |
b3bec2525
|
70 |
#ifndef CONFIG_DM_SPI |
16f47c9c5
|
71 |
struct spi_slave slave; |
b3bec2525
|
72 |
#endif |
16f47c9c5
|
73 74 |
struct sh_qspi_regs *regs; }; |
16f47c9c5
|
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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
static void sh_qspi_init(struct sh_qspi_slave *ss) { /* QSPI initialize */ /* Set master mode only */ writeb(SPCR_MSTR, &ss->regs->spcr); /* Set SSL signal level */ writeb(0x00, &ss->regs->sslp); /* Set MOSI signal value when transfer is in idle state */ writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr); /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */ writeb(0x01, &ss->regs->spbr); /* Disable Dummy Data Transmission */ writeb(0x00, &ss->regs->spdcr); /* Set clock delay value */ writeb(0x00, &ss->regs->spckd); /* Set SSL negation delay value */ writeb(0x00, &ss->regs->sslnd); /* Set next-access delay value */ writeb(0x00, &ss->regs->spnd); /* Set equence command */ writew(SPCMD_INIT2, &ss->regs->spcmd0); /* Reset transfer and receive Buffer */ setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); /* Clear transfer and receive Buffer control bit */ clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); /* Set equence control method. Use equence0 only */ writeb(0x00, &ss->regs->spscr); /* Enable SPI function */ setbits_8(&ss->regs->spcr, SPCR_SPE); } |
b3bec2525
|
117 |
static void sh_qspi_cs_activate(struct sh_qspi_slave *ss) |
16f47c9c5
|
118 |
{ |
16f47c9c5
|
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
/* Set master mode only */ writeb(SPCR_MSTR, &ss->regs->spcr); /* Set command */ writew(SPCMD_INIT1, &ss->regs->spcmd0); /* Reset transfer and receive Buffer */ setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); /* Clear transfer and receive Buffer control bit */ clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); /* Set equence control method. Use equence0 only */ writeb(0x00, &ss->regs->spscr); /* Enable SPI function */ setbits_8(&ss->regs->spcr, SPCR_SPE); } |
b3bec2525
|
137 |
static void sh_qspi_cs_deactivate(struct sh_qspi_slave *ss) |
16f47c9c5
|
138 |
{ |
16f47c9c5
|
139 140 141 |
/* Disable SPI Function */ clrbits_8(&ss->regs->spcr, SPCR_SPE); } |
b3bec2525
|
142 143 |
static int sh_qspi_xfer_common(struct sh_qspi_slave *ss, unsigned int bitlen, const void *dout, void *din, unsigned long flags) |
16f47c9c5
|
144 |
{ |
ea5512eb0
|
145 146 |
u32 nbyte, chunk; int i, ret = 0; |
0e6fa20b1
|
147 148 149 |
u8 dtdata = 0, drdata; u8 *tdata = &dtdata, *rdata = &drdata; u32 *spbmul0 = &ss->regs->spbmul0; |
16f47c9c5
|
150 151 152 |
if (dout == NULL && din == NULL) { if (flags & SPI_XFER_END) |
b3bec2525
|
153 |
sh_qspi_cs_deactivate(ss); |
16f47c9c5
|
154 155 156 157 158 159 160 161 162 163 164 |
return 0; } if (bitlen % 8) { printf("%s: bitlen is not 8bit alined %d", __func__, bitlen); return 1; } nbyte = bitlen / 8; if (flags & SPI_XFER_BEGIN) { |
b3bec2525
|
165 |
sh_qspi_cs_activate(ss); |
16f47c9c5
|
166 167 168 169 170 171 172 173 174 |
/* Set 1048576 byte */ writel(0x100000, spbmul0); } if (flags & SPI_XFER_END) writel(nbyte, spbmul0); if (dout != NULL) |
0e6fa20b1
|
175 |
tdata = (u8 *)dout; |
16f47c9c5
|
176 177 178 179 180 |
if (din != NULL) rdata = din; while (nbyte > 0) { |
ea5512eb0
|
181 182 183 184 185 186 187 188 |
/* * Check if there is 32 Byte chunk and if there is, transfer * it in one burst, otherwise transfer on byte-by-byte basis. */ chunk = (nbyte >= 32) ? 32 : 1; clrsetbits_8(&ss->regs->spbfcr, SPBFCR_TXTRG | SPBFCR_RXTRG, chunk == 32 ? SPBFCR_TXTRG | SPBFCR_RXTRG : 0); |
9573db654
|
189 190 191 192 |
ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPTEF, true, 1000, true); if (ret) return ret; |
16f47c9c5
|
193 |
|
ea5512eb0
|
194 195 196 197 198 |
for (i = 0; i < chunk; i++) { writeb(*tdata, &ss->regs->spdr); if (dout != NULL) tdata++; } |
16f47c9c5
|
199 |
|
9573db654
|
200 201 202 203 |
ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPRFF, true, 1000, true); if (ret) return ret; |
16f47c9c5
|
204 |
|
ea5512eb0
|
205 206 207 208 209 |
for (i = 0; i < chunk; i++) { *rdata = readb(&ss->regs->spdr); if (din != NULL) rdata++; } |
16f47c9c5
|
210 |
|
ea5512eb0
|
211 |
nbyte -= chunk; |
16f47c9c5
|
212 213 214 |
} if (flags & SPI_XFER_END) |
b3bec2525
|
215 |
sh_qspi_cs_deactivate(ss); |
16f47c9c5
|
216 217 218 |
return ret; } |
b3bec2525
|
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
#ifndef CONFIG_DM_SPI static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave) { return container_of(slave, struct sh_qspi_slave, slave); } int spi_cs_is_valid(unsigned int bus, unsigned int cs) { return 1; } void spi_cs_activate(struct spi_slave *slave) { struct sh_qspi_slave *ss = to_sh_qspi(slave); sh_qspi_cs_activate(ss); } void spi_cs_deactivate(struct spi_slave *slave) { struct sh_qspi_slave *ss = to_sh_qspi(slave); sh_qspi_cs_deactivate(ss); } |
b3bec2525
|
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { struct sh_qspi_slave *ss; if (!spi_cs_is_valid(bus, cs)) return NULL; ss = spi_alloc_slave(struct sh_qspi_slave, bus, cs); if (!ss) { printf("SPI_error: Fail to allocate sh_qspi_slave "); return NULL; } ss->regs = (struct sh_qspi_regs *)SH_QSPI_BASE; /* Init SH QSPI */ sh_qspi_init(ss); return &ss->slave; } void spi_free_slave(struct spi_slave *slave) { struct sh_qspi_slave *spi = to_sh_qspi(slave); free(spi); } int spi_claim_bus(struct spi_slave *slave) { return 0; } void spi_release_bus(struct spi_slave *slave) { } int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct sh_qspi_slave *ss = to_sh_qspi(slave); return sh_qspi_xfer_common(ss, bitlen, dout, din, flags); } #else #include <dm.h> static int sh_qspi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct udevice *bus = dev->parent; struct sh_qspi_slave *ss = dev_get_platdata(bus); return sh_qspi_xfer_common(ss, bitlen, dout, din, flags); } static int sh_qspi_set_speed(struct udevice *dev, uint speed) { /* This is a SPI NOR controller, do nothing. */ return 0; } static int sh_qspi_set_mode(struct udevice *dev, uint mode) { /* This is a SPI NOR controller, do nothing. */ return 0; } static int sh_qspi_probe(struct udevice *dev) { struct sh_qspi_slave *ss = dev_get_platdata(dev); sh_qspi_init(ss); return 0; } static int sh_qspi_ofdata_to_platdata(struct udevice *dev) { struct sh_qspi_slave *plat = dev_get_platdata(dev); plat->regs = (struct sh_qspi_regs *)dev_read_addr(dev); return 0; } static const struct dm_spi_ops sh_qspi_ops = { .xfer = sh_qspi_xfer, .set_speed = sh_qspi_set_speed, .set_mode = sh_qspi_set_mode, }; static const struct udevice_id sh_qspi_ids[] = { { .compatible = "renesas,qspi" }, { } }; U_BOOT_DRIVER(sh_qspi) = { .name = "sh_qspi", .id = UCLASS_SPI, .of_match = sh_qspi_ids, .ops = &sh_qspi_ops, .ofdata_to_platdata = sh_qspi_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct sh_qspi_slave), .probe = sh_qspi_probe, }; #endif |