Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: bcm53xx: driver for SPI controller on Broadcom bcma SoC

Broadcom 53xx ARM SoCs use bcma bus that contains various cores (AKA
devices). If board has a serial flash, it's connected over SPI and the
bcma bus includes a SPI controller. Example log from such a board:
bus0: Found chip with id 53010, rev 0x00 and package 0x02
(...)
bus0: Core 18 found: SPI flash controller (manuf 0x4BF, id 0x50A, rev 0x01, class 0x0)

This patch adds a bcma driver for SPI core, it registers SPI master
controller and "bcm53xxspiflash" SPI device.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Rafał Miłecki and committed by
Mark Brown
0fc6a323 7d1311b9

+374
+6
drivers/spi/Kconfig
··· 112 112 If you say yes to this option, support will be included for the 113 113 PSC SPI controller found on Au1550, Au1200 and Au1300 series. 114 114 115 + config SPI_BCM53XX 116 + tristate "Broadcom BCM53xx SPI controller" 117 + depends on ARCH_BCM_5301X 118 + help 119 + Enable support for the SPI controller on Broadcom BCM53xx ARM SoCs. 120 + 115 121 config SPI_BCM63XX 116 122 tristate "Broadcom BCM63xx SPI controller" 117 123 depends on BCM63XX
+1
drivers/spi/Makefile
··· 15 15 obj-$(CONFIG_SPI_ATH79) += spi-ath79.o 16 16 obj-$(CONFIG_SPI_AU1550) += spi-au1550.o 17 17 obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o 18 + obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o 18 19 obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o 19 20 obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o 20 21 obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
+295
drivers/spi/spi-bcm53xx.c
··· 1 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2 + 3 + #include <linux/kernel.h> 4 + #include <linux/module.h> 5 + #include <linux/slab.h> 6 + #include <linux/delay.h> 7 + #include <linux/bcma/bcma.h> 8 + #include <linux/spi/spi.h> 9 + 10 + #include "spi-bcm53xx.h" 11 + 12 + #define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */ 13 + 14 + /* The longest observed required wait was 19 ms */ 15 + #define BCM53XXSPI_SPE_TIMEOUT_MS 80 16 + 17 + struct bcm53xxspi { 18 + struct bcma_device *core; 19 + struct spi_master *master; 20 + 21 + size_t read_offset; 22 + }; 23 + 24 + static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset) 25 + { 26 + return bcma_read32(b53spi->core, offset); 27 + } 28 + 29 + static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset, 30 + u32 value) 31 + { 32 + bcma_write32(b53spi->core, offset, value); 33 + } 34 + 35 + static inline unsigned int bcm53xxspi_calc_timeout(size_t len) 36 + { 37 + /* Do some magic calculation based on length and buad. Add 10% and 1. */ 38 + return (len * 9000 / BCM53XXSPI_MAX_SPI_BAUD * 110 / 100) + 1; 39 + } 40 + 41 + static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms) 42 + { 43 + unsigned long deadline; 44 + u32 tmp; 45 + 46 + /* SPE bit has to be 0 before we read MSPI STATUS */ 47 + deadline = jiffies + BCM53XXSPI_SPE_TIMEOUT_MS * HZ / 1000; 48 + do { 49 + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); 50 + if (!(tmp & B53SPI_MSPI_SPCR2_SPE)) 51 + break; 52 + udelay(5); 53 + } while (!time_after_eq(jiffies, deadline)); 54 + 55 + if (tmp & B53SPI_MSPI_SPCR2_SPE) 56 + goto spi_timeout; 57 + 58 + /* Check status */ 59 + deadline = jiffies + timeout_ms * HZ / 1000; 60 + do { 61 + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS); 62 + if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) { 63 + bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0); 64 + return 0; 65 + } 66 + 67 + cpu_relax(); 68 + udelay(100); 69 + } while (!time_after_eq(jiffies, deadline)); 70 + 71 + spi_timeout: 72 + bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0); 73 + 74 + pr_err("Timeout waiting for SPI to be ready!\n"); 75 + 76 + return -EBUSY; 77 + } 78 + 79 + static void bcm53xxspi_buf_write(struct bcm53xxspi *b53spi, u8 *w_buf, 80 + size_t len, bool cont) 81 + { 82 + u32 tmp; 83 + int i; 84 + 85 + for (i = 0; i < len; i++) { 86 + /* Transmit Register File MSB */ 87 + bcm53xxspi_write(b53spi, B53SPI_MSPI_TXRAM + 4 * (i * 2), 88 + (unsigned int)w_buf[i]); 89 + } 90 + 91 + for (i = 0; i < len; i++) { 92 + tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL | 93 + B53SPI_CDRAM_PCS_DSCK; 94 + if (!cont && i == len - 1) 95 + tmp &= ~B53SPI_CDRAM_CONT; 96 + tmp &= ~0x1; 97 + /* Command Register File */ 98 + bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp); 99 + } 100 + 101 + /* Set queue pointers */ 102 + bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0); 103 + bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1); 104 + 105 + if (cont) 106 + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1); 107 + 108 + /* Start SPI transfer */ 109 + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); 110 + tmp |= B53SPI_MSPI_SPCR2_SPE; 111 + if (cont) 112 + tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD; 113 + bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp); 114 + 115 + /* Wait for SPI to finish */ 116 + bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len)); 117 + 118 + if (!cont) 119 + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0); 120 + 121 + b53spi->read_offset = len; 122 + } 123 + 124 + static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf, 125 + size_t len, bool cont) 126 + { 127 + u32 tmp; 128 + int i; 129 + 130 + for (i = 0; i < b53spi->read_offset + len; i++) { 131 + tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL | 132 + B53SPI_CDRAM_PCS_DSCK; 133 + if (!cont && i == b53spi->read_offset + len - 1) 134 + tmp &= ~B53SPI_CDRAM_CONT; 135 + tmp &= ~0x1; 136 + /* Command Register File */ 137 + bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp); 138 + } 139 + 140 + /* Set queue pointers */ 141 + bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0); 142 + bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, 143 + b53spi->read_offset + len - 1); 144 + 145 + if (cont) 146 + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1); 147 + 148 + /* Start SPI transfer */ 149 + tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); 150 + tmp |= B53SPI_MSPI_SPCR2_SPE; 151 + if (cont) 152 + tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD; 153 + bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp); 154 + 155 + /* Wait for SPI to finish */ 156 + bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len)); 157 + 158 + if (!cont) 159 + bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0); 160 + 161 + for (i = 0; i < len; ++i) { 162 + int offset = b53spi->read_offset + i; 163 + 164 + /* Data stored in the transmit register file LSB */ 165 + r_buf[i] = (u8)bcm53xxspi_read(b53spi, B53SPI_MSPI_RXRAM + 4 * (1 + offset * 2)); 166 + } 167 + 168 + b53spi->read_offset = 0; 169 + } 170 + 171 + static int bcm53xxspi_transfer_one(struct spi_master *master, 172 + struct spi_device *spi, 173 + struct spi_transfer *t) 174 + { 175 + struct bcm53xxspi *b53spi = spi_master_get_devdata(master); 176 + u8 *buf; 177 + size_t left; 178 + 179 + if (t->tx_buf) { 180 + buf = (u8 *)t->tx_buf; 181 + left = t->len; 182 + while (left) { 183 + size_t to_write = min_t(size_t, 16, left); 184 + bool cont = left - to_write > 0; 185 + 186 + bcm53xxspi_buf_write(b53spi, buf, to_write, cont); 187 + left -= to_write; 188 + buf += to_write; 189 + } 190 + } 191 + 192 + if (t->rx_buf) { 193 + buf = (u8 *)t->rx_buf; 194 + left = t->len; 195 + while (left) { 196 + size_t to_read = min_t(size_t, 16 - b53spi->read_offset, 197 + left); 198 + bool cont = left - to_read > 0; 199 + 200 + bcm53xxspi_buf_read(b53spi, buf, to_read, cont); 201 + left -= to_read; 202 + buf += to_read; 203 + } 204 + } 205 + 206 + return 0; 207 + } 208 + 209 + /************************************************** 210 + * BCMA 211 + **************************************************/ 212 + 213 + struct spi_board_info bcm53xx_info = { 214 + .modalias = "bcm53xxspiflash", 215 + }; 216 + 217 + static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = { 218 + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS), 219 + BCMA_CORETABLE_END 220 + }; 221 + MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl); 222 + 223 + static int bcm53xxspi_bcma_probe(struct bcma_device *core) 224 + { 225 + struct bcm53xxspi *b53spi; 226 + struct spi_master *master; 227 + int err; 228 + 229 + if (core->bus->drv_cc.core->id.rev != 42) { 230 + pr_err("SPI on SoC with unsupported ChipCommon rev\n"); 231 + return -ENOTSUPP; 232 + } 233 + 234 + master = spi_alloc_master(&core->dev, sizeof(*b53spi)); 235 + if (!master) 236 + return -ENOMEM; 237 + 238 + b53spi = spi_master_get_devdata(master); 239 + b53spi->master = master; 240 + b53spi->core = core; 241 + 242 + master->transfer_one = bcm53xxspi_transfer_one; 243 + 244 + bcma_set_drvdata(core, b53spi); 245 + 246 + err = devm_spi_register_master(&core->dev, master); 247 + if (err) { 248 + spi_master_put(master); 249 + bcma_set_drvdata(core, NULL); 250 + goto out; 251 + } 252 + 253 + /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */ 254 + spi_new_device(master, &bcm53xx_info); 255 + 256 + out: 257 + return err; 258 + } 259 + 260 + static void bcm53xxspi_bcma_remove(struct bcma_device *core) 261 + { 262 + struct bcm53xxspi *b53spi = bcma_get_drvdata(core); 263 + 264 + spi_unregister_master(b53spi->master); 265 + } 266 + 267 + static struct bcma_driver bcm53xxspi_bcma_driver = { 268 + .name = KBUILD_MODNAME, 269 + .id_table = bcm53xxspi_bcma_tbl, 270 + .probe = bcm53xxspi_bcma_probe, 271 + .remove = bcm53xxspi_bcma_remove, 272 + }; 273 + 274 + /************************************************** 275 + * Init & exit 276 + **************************************************/ 277 + 278 + static int __init bcm53xxspi_module_init(void) 279 + { 280 + int err = 0; 281 + 282 + err = bcma_driver_register(&bcm53xxspi_bcma_driver); 283 + if (err) 284 + pr_err("Failed to register bcma driver: %d\n", err); 285 + 286 + return err; 287 + } 288 + 289 + static void __exit bcm53xxspi_module_exit(void) 290 + { 291 + bcma_driver_unregister(&bcm53xxspi_bcma_driver); 292 + } 293 + 294 + module_init(bcm53xxspi_module_init); 295 + module_exit(bcm53xxspi_module_exit);
+72
drivers/spi/spi-bcm53xx.h
··· 1 + #ifndef SPI_BCM53XX_H 2 + #define SPI_BCM53XX_H 3 + 4 + #define B53SPI_BSPI_REVISION_ID 0x000 5 + #define B53SPI_BSPI_SCRATCH 0x004 6 + #define B53SPI_BSPI_MAST_N_BOOT_CTRL 0x008 7 + #define B53SPI_BSPI_BUSY_STATUS 0x00c 8 + #define B53SPI_BSPI_INTR_STATUS 0x010 9 + #define B53SPI_BSPI_B0_STATUS 0x014 10 + #define B53SPI_BSPI_B0_CTRL 0x018 11 + #define B53SPI_BSPI_B1_STATUS 0x01c 12 + #define B53SPI_BSPI_B1_CTRL 0x020 13 + #define B53SPI_BSPI_STRAP_OVERRIDE_CTRL 0x024 14 + #define B53SPI_BSPI_FLEX_MODE_ENABLE 0x028 15 + #define B53SPI_BSPI_BITS_PER_CYCLE 0x02c 16 + #define B53SPI_BSPI_BITS_PER_PHASE 0x030 17 + #define B53SPI_BSPI_CMD_AND_MODE_BYTE 0x034 18 + #define B53SPI_BSPI_BSPI_FLASH_UPPER_ADDR_BYTE 0x038 19 + #define B53SPI_BSPI_BSPI_XOR_VALUE 0x03c 20 + #define B53SPI_BSPI_BSPI_XOR_ENABLE 0x040 21 + #define B53SPI_BSPI_BSPI_PIO_MODE_ENABLE 0x044 22 + #define B53SPI_BSPI_BSPI_PIO_IODIR 0x048 23 + #define B53SPI_BSPI_BSPI_PIO_DATA 0x04c 24 + 25 + /* RAF */ 26 + #define B53SPI_RAF_START_ADDR 0x100 27 + #define B53SPI_RAF_NUM_WORDS 0x104 28 + #define B53SPI_RAF_CTRL 0x108 29 + #define B53SPI_RAF_FULLNESS 0x10c 30 + #define B53SPI_RAF_WATERMARK 0x110 31 + #define B53SPI_RAF_STATUS 0x114 32 + #define B53SPI_RAF_READ_DATA 0x118 33 + #define B53SPI_RAF_WORD_CNT 0x11c 34 + #define B53SPI_RAF_CURR_ADDR 0x120 35 + 36 + /* MSPI */ 37 + #define B53SPI_MSPI_SPCR0_LSB 0x200 38 + #define B53SPI_MSPI_SPCR0_MSB 0x204 39 + #define B53SPI_MSPI_SPCR1_LSB 0x208 40 + #define B53SPI_MSPI_SPCR1_MSB 0x20c 41 + #define B53SPI_MSPI_NEWQP 0x210 42 + #define B53SPI_MSPI_ENDQP 0x214 43 + #define B53SPI_MSPI_SPCR2 0x218 44 + #define B53SPI_MSPI_SPCR2_SPE 0x00000040 45 + #define B53SPI_MSPI_SPCR2_CONT_AFTER_CMD 0x00000080 46 + #define B53SPI_MSPI_MSPI_STATUS 0x220 47 + #define B53SPI_MSPI_MSPI_STATUS_SPIF 0x00000001 48 + #define B53SPI_MSPI_CPTQP 0x224 49 + #define B53SPI_MSPI_TXRAM 0x240 /* 32 registers, up to 0x2b8 */ 50 + #define B53SPI_MSPI_RXRAM 0x2c0 /* 32 registers, up to 0x33c */ 51 + #define B53SPI_MSPI_CDRAM 0x340 /* 16 registers, up to 0x37c */ 52 + #define B53SPI_CDRAM_PCS_PCS0 0x00000001 53 + #define B53SPI_CDRAM_PCS_PCS1 0x00000002 54 + #define B53SPI_CDRAM_PCS_PCS2 0x00000004 55 + #define B53SPI_CDRAM_PCS_PCS3 0x00000008 56 + #define B53SPI_CDRAM_PCS_DISABLE_ALL 0x0000000f 57 + #define B53SPI_CDRAM_PCS_DSCK 0x00000010 58 + #define B53SPI_CDRAM_BITSE 0x00000040 59 + #define B53SPI_CDRAM_CONT 0x00000080 60 + #define B53SPI_MSPI_WRITE_LOCK 0x380 61 + #define B53SPI_MSPI_DISABLE_FLUSH_GEN 0x384 62 + 63 + /* Interrupt */ 64 + #define B53SPI_INTR_RAF_LR_FULLNESS_REACHED 0x3a0 65 + #define B53SPI_INTR_RAF_LR_TRUNCATED 0x3a4 66 + #define B53SPI_INTR_RAF_LR_IMPATIENT 0x3a8 67 + #define B53SPI_INTR_RAF_LR_SESSION_DONE 0x3ac 68 + #define B53SPI_INTR_RAF_LR_OVERREAD 0x3b0 69 + #define B53SPI_INTR_MSPI_DONE 0x3b4 70 + #define B53SPI_INTR_MSPI_HALT_SET_TRANSACTION_DONE 0x3b8 71 + 72 + #endif /* SPI_BCM53XX_H */