1 /* 2 * (C) Copyright 2009 3 * Marvell Semiconductor <www.marvell.com> 4 * Written-by: Prafulla Wadaskar <prafulla@marvell.com> 5 * 6 * Derived from drivers/spi/mpc8xxx_spi.c 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <dm.h> 13 #include <malloc.h> 14 #include <spi.h> 15 #include <asm/io.h> 16 #include <asm/arch/soc.h> 17 #ifdef CONFIG_KIRKWOOD 18 #include <asm/arch/mpp.h> 19 #endif 20 #include <asm/arch-mvebu/spi.h> 21 22 static void _spi_cs_activate(struct kwspi_registers *reg) 23 { 24 setbits_le32(®->ctrl, KWSPI_CSN_ACT); 25 } 26 27 static void _spi_cs_deactivate(struct kwspi_registers *reg) 28 { 29 clrbits_le32(®->ctrl, KWSPI_CSN_ACT); 30 } 31 32 static int _spi_xfer(struct kwspi_registers *reg, unsigned int bitlen, 33 const void *dout, void *din, unsigned long flags) 34 { 35 unsigned int tmpdout, tmpdin; 36 int tm, isread = 0; 37 38 debug("spi_xfer: dout %p din %p bitlen %u\n", dout, din, bitlen); 39 40 if (flags & SPI_XFER_BEGIN) 41 _spi_cs_activate(reg); 42 43 /* 44 * handle data in 8-bit chunks 45 * TBD: 2byte xfer mode to be enabled 46 */ 47 clrsetbits_le32(®->cfg, KWSPI_XFERLEN_MASK, KWSPI_XFERLEN_1BYTE); 48 49 while (bitlen > 4) { 50 debug("loopstart bitlen %d\n", bitlen); 51 tmpdout = 0; 52 53 /* Shift data so it's msb-justified */ 54 if (dout) 55 tmpdout = *(u32 *)dout & 0xff; 56 57 clrbits_le32(®->irq_cause, KWSPI_SMEMRDIRQ); 58 writel(tmpdout, ®->dout); /* Write the data out */ 59 debug("*** spi_xfer: ... %08x written, bitlen %d\n", 60 tmpdout, bitlen); 61 62 /* 63 * Wait for SPI transmit to get out 64 * or time out (1 second = 1000 ms) 65 * The NE event must be read and cleared first 66 */ 67 for (tm = 0, isread = 0; tm < KWSPI_TIMEOUT; ++tm) { 68 if (readl(®->irq_cause) & KWSPI_SMEMRDIRQ) { 69 isread = 1; 70 tmpdin = readl(®->din); 71 debug("spi_xfer: din %p..%08x read\n", 72 din, tmpdin); 73 74 if (din) { 75 *((u8 *)din) = (u8)tmpdin; 76 din += 1; 77 } 78 if (dout) 79 dout += 1; 80 bitlen -= 8; 81 } 82 if (isread) 83 break; 84 } 85 if (tm >= KWSPI_TIMEOUT) 86 printf("*** spi_xfer: Time out during SPI transfer\n"); 87 88 debug("loopend bitlen %d\n", bitlen); 89 } 90 91 if (flags & SPI_XFER_END) 92 _spi_cs_deactivate(reg); 93 94 return 0; 95 } 96 97 #ifndef CONFIG_DM_SPI 98 99 static struct kwspi_registers *spireg = 100 (struct kwspi_registers *)MVEBU_SPI_BASE; 101 102 #ifdef CONFIG_KIRKWOOD 103 static u32 cs_spi_mpp_back[2]; 104 #endif 105 106 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 107 unsigned int max_hz, unsigned int mode) 108 { 109 struct spi_slave *slave; 110 u32 data; 111 #ifdef CONFIG_KIRKWOOD 112 static const u32 kwspi_mpp_config[2][2] = { 113 { MPP0_SPI_SCn, 0 }, /* if cs == 0 */ 114 { MPP7_SPI_SCn, 0 } /* if cs != 0 */ 115 }; 116 #endif 117 118 if (!spi_cs_is_valid(bus, cs)) 119 return NULL; 120 121 slave = spi_alloc_slave_base(bus, cs); 122 if (!slave) 123 return NULL; 124 125 writel(KWSPI_SMEMRDY, &spireg->ctrl); 126 127 /* calculate spi clock prescaller using max_hz */ 128 data = ((CONFIG_SYS_TCLK / 2) / max_hz) + 0x10; 129 data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data; 130 data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data; 131 132 /* program spi clock prescaller using max_hz */ 133 writel(KWSPI_ADRLEN_3BYTE | data, &spireg->cfg); 134 debug("data = 0x%08x\n", data); 135 136 writel(KWSPI_SMEMRDIRQ, &spireg->irq_cause); 137 writel(KWSPI_IRQMASK, &spireg->irq_mask); 138 139 #ifdef CONFIG_KIRKWOOD 140 /* program mpp registers to select SPI_CSn */ 141 kirkwood_mpp_conf(kwspi_mpp_config[cs ? 1 : 0], cs_spi_mpp_back); 142 #endif 143 144 return slave; 145 } 146 147 void spi_free_slave(struct spi_slave *slave) 148 { 149 #ifdef CONFIG_KIRKWOOD 150 kirkwood_mpp_conf(cs_spi_mpp_back, NULL); 151 #endif 152 free(slave); 153 } 154 155 #if defined(CONFIG_SYS_KW_SPI_MPP) 156 u32 spi_mpp_backup[4]; 157 #endif 158 159 __attribute__((weak)) int board_spi_claim_bus(struct spi_slave *slave) 160 { 161 return 0; 162 } 163 164 int spi_claim_bus(struct spi_slave *slave) 165 { 166 #if defined(CONFIG_SYS_KW_SPI_MPP) 167 u32 config; 168 u32 spi_mpp_config[4]; 169 170 config = CONFIG_SYS_KW_SPI_MPP; 171 172 if (config & MOSI_MPP6) 173 spi_mpp_config[0] = MPP6_SPI_MOSI; 174 else 175 spi_mpp_config[0] = MPP1_SPI_MOSI; 176 177 if (config & SCK_MPP10) 178 spi_mpp_config[1] = MPP10_SPI_SCK; 179 else 180 spi_mpp_config[1] = MPP2_SPI_SCK; 181 182 if (config & MISO_MPP11) 183 spi_mpp_config[2] = MPP11_SPI_MISO; 184 else 185 spi_mpp_config[2] = MPP3_SPI_MISO; 186 187 spi_mpp_config[3] = 0; 188 spi_mpp_backup[3] = 0; 189 190 /* set new spi mpp and save current mpp config */ 191 kirkwood_mpp_conf(spi_mpp_config, spi_mpp_backup); 192 #endif 193 194 return board_spi_claim_bus(slave); 195 } 196 197 __attribute__((weak)) void board_spi_release_bus(struct spi_slave *slave) 198 { 199 } 200 201 void spi_release_bus(struct spi_slave *slave) 202 { 203 #if defined(CONFIG_SYS_KW_SPI_MPP) 204 kirkwood_mpp_conf(spi_mpp_backup, NULL); 205 #endif 206 207 board_spi_release_bus(slave); 208 } 209 210 #ifndef CONFIG_SPI_CS_IS_VALID 211 /* 212 * you can define this function board specific 213 * define above CONFIG in board specific config file and 214 * provide the function in board specific src file 215 */ 216 int spi_cs_is_valid(unsigned int bus, unsigned int cs) 217 { 218 return bus == 0 && (cs == 0 || cs == 1); 219 } 220 #endif 221 222 void spi_init(void) 223 { 224 } 225 226 void spi_cs_activate(struct spi_slave *slave) 227 { 228 _spi_cs_activate(spireg); 229 } 230 231 void spi_cs_deactivate(struct spi_slave *slave) 232 { 233 _spi_cs_deactivate(spireg); 234 } 235 236 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, 237 const void *dout, void *din, unsigned long flags) 238 { 239 return _spi_xfer(spireg, bitlen, dout, din, flags); 240 } 241 242 #else 243 244 /* Here now the DM part */ 245 246 struct mvebu_spi_platdata { 247 struct kwspi_registers *spireg; 248 }; 249 250 struct mvebu_spi_priv { 251 struct kwspi_registers *spireg; 252 }; 253 254 static int mvebu_spi_set_speed(struct udevice *bus, uint hz) 255 { 256 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 257 struct kwspi_registers *reg = plat->spireg; 258 u32 data; 259 260 /* calculate spi clock prescaller using max_hz */ 261 data = ((CONFIG_SYS_TCLK / 2) / hz) + 0x10; 262 data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data; 263 data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data; 264 265 /* program spi clock prescaler using max_hz */ 266 writel(KWSPI_ADRLEN_3BYTE | data, ®->cfg); 267 debug("data = 0x%08x\n", data); 268 269 return 0; 270 } 271 272 static int mvebu_spi_set_mode(struct udevice *bus, uint mode) 273 { 274 return 0; 275 } 276 277 static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, 278 const void *dout, void *din, unsigned long flags) 279 { 280 struct udevice *bus = dev->parent; 281 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 282 283 return _spi_xfer(plat->spireg, bitlen, dout, din, flags); 284 } 285 286 static int mvebu_spi_probe(struct udevice *bus) 287 { 288 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 289 struct kwspi_registers *reg = plat->spireg; 290 291 writel(KWSPI_SMEMRDY, ®->ctrl); 292 writel(KWSPI_SMEMRDIRQ, ®->irq_cause); 293 writel(KWSPI_IRQMASK, ®->irq_mask); 294 295 return 0; 296 } 297 298 static int mvebu_spi_ofdata_to_platdata(struct udevice *bus) 299 { 300 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 301 302 plat->spireg = (struct kwspi_registers *)dev_get_addr(bus); 303 304 return 0; 305 } 306 307 static const struct dm_spi_ops mvebu_spi_ops = { 308 .xfer = mvebu_spi_xfer, 309 .set_speed = mvebu_spi_set_speed, 310 .set_mode = mvebu_spi_set_mode, 311 /* 312 * cs_info is not needed, since we require all chip selects to be 313 * in the device tree explicitly 314 */ 315 }; 316 317 static const struct udevice_id mvebu_spi_ids[] = { 318 { .compatible = "marvell,armada-380-spi" }, 319 { .compatible = "marvell,armada-xp-spi" }, 320 { } 321 }; 322 323 U_BOOT_DRIVER(mvebu_spi) = { 324 .name = "mvebu_spi", 325 .id = UCLASS_SPI, 326 .of_match = mvebu_spi_ids, 327 .ops = &mvebu_spi_ops, 328 .ofdata_to_platdata = mvebu_spi_ofdata_to_platdata, 329 .platdata_auto_alloc_size = sizeof(struct mvebu_spi_platdata), 330 .priv_auto_alloc_size = sizeof(struct mvebu_spi_priv), 331 .probe = mvebu_spi_probe, 332 }; 333 #endif 334