1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2015 Marvell International Ltd. 4 * 5 * Copyright (C) 2016 Stefan Roese <sr (at) denx.de> 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <malloc.h> 11 #include <spi.h> 12 #include <clk.h> 13 #include <wait_bit.h> 14 #include <asm/io.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 #define MVEBU_SPI_A3700_XFER_RDY BIT(1) 19 #define MVEBU_SPI_A3700_FIFO_FLUSH BIT(9) 20 #define MVEBU_SPI_A3700_BYTE_LEN BIT(5) 21 #define MVEBU_SPI_A3700_CLK_PHA BIT(6) 22 #define MVEBU_SPI_A3700_CLK_POL BIT(7) 23 #define MVEBU_SPI_A3700_FIFO_EN BIT(17) 24 #define MVEBU_SPI_A3700_SPI_EN_0 BIT(16) 25 #define MVEBU_SPI_A3700_CLK_PRESCALE_MASK 0x1f 26 27 28 /* SPI registers */ 29 struct spi_reg { 30 u32 ctrl; /* 0x10600 */ 31 u32 cfg; /* 0x10604 */ 32 u32 dout; /* 0x10608 */ 33 u32 din; /* 0x1060c */ 34 }; 35 36 struct mvebu_spi_platdata { 37 struct spi_reg *spireg; 38 struct clk clk; 39 }; 40 41 static void spi_cs_activate(struct spi_reg *reg, int cs) 42 { 43 setbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); 44 } 45 46 static void spi_cs_deactivate(struct spi_reg *reg, int cs) 47 { 48 clrbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); 49 } 50 51 /** 52 * spi_legacy_shift_byte() - triggers the real SPI transfer 53 * @bytelen: Indicate how many bytes to transfer. 54 * @dout: Buffer address of what to send. 55 * @din: Buffer address of where to receive. 56 * 57 * This function triggers the real SPI transfer in legacy mode. It 58 * will shift out char buffer from @dout, and shift in char buffer to 59 * @din, if necessary. 60 * 61 * This function assumes that only one byte is shifted at one time. 62 * However, it is not its responisbility to set the transfer type to 63 * one-byte. Also, it does not guarantee that it will work if transfer 64 * type becomes two-byte. See spi_set_legacy() for details. 65 * 66 * In legacy mode, simply write to the SPI_DOUT register will trigger 67 * the transfer. 68 * 69 * If @dout == NULL, which means no actual data needs to be sent out, 70 * then the function will shift out 0x00 in order to shift in data. 71 * The XFER_RDY flag is checked every time before accessing SPI_DOUT 72 * and SPI_DIN register. 73 * 74 * The number of transfers to be triggerred is decided by @bytelen. 75 * 76 * Return: 0 - cool 77 * -ETIMEDOUT - XFER_RDY flag timeout 78 */ 79 static int spi_legacy_shift_byte(struct spi_reg *reg, unsigned int bytelen, 80 const void *dout, void *din) 81 { 82 const u8 *dout_8; 83 u8 *din_8; 84 int ret; 85 86 /* Use 0x00 as dummy dout */ 87 const u8 dummy_dout = 0x0; 88 u32 pending_dout = 0x0; 89 90 /* dout_8: pointer of current dout */ 91 dout_8 = dout; 92 /* din_8: pointer of current din */ 93 din_8 = din; 94 95 while (bytelen) { 96 ret = wait_for_bit_le32(®->ctrl, 97 MVEBU_SPI_A3700_XFER_RDY, 98 true,100, false); 99 if (ret) 100 return ret; 101 102 if (dout) 103 pending_dout = (u32)*dout_8; 104 else 105 pending_dout = (u32)dummy_dout; 106 107 /* Trigger the xfer */ 108 writel(pending_dout, ®->dout); 109 110 if (din) { 111 ret = wait_for_bit_le32(®->ctrl, 112 MVEBU_SPI_A3700_XFER_RDY, 113 true, 100, false); 114 if (ret) 115 return ret; 116 117 /* Read what is transferred in */ 118 *din_8 = (u8)readl(®->din); 119 } 120 121 /* Don't increment the current pointer if NULL */ 122 if (dout) 123 dout_8++; 124 if (din) 125 din_8++; 126 127 bytelen--; 128 } 129 130 return 0; 131 } 132 133 static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, 134 const void *dout, void *din, unsigned long flags) 135 { 136 struct udevice *bus = dev->parent; 137 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 138 struct spi_reg *reg = plat->spireg; 139 unsigned int bytelen; 140 int ret; 141 142 bytelen = bitlen / 8; 143 144 if (dout && din) 145 debug("This is a duplex transfer.\n"); 146 147 /* Activate CS */ 148 if (flags & SPI_XFER_BEGIN) { 149 debug("SPI: activate cs.\n"); 150 spi_cs_activate(reg, spi_chip_select(dev)); 151 } 152 153 /* Send and/or receive */ 154 if (dout || din) { 155 ret = spi_legacy_shift_byte(reg, bytelen, dout, din); 156 if (ret) 157 return ret; 158 } 159 160 /* Deactivate CS */ 161 if (flags & SPI_XFER_END) { 162 ret = wait_for_bit_le32(®->ctrl, 163 MVEBU_SPI_A3700_XFER_RDY, 164 true, 100, false); 165 if (ret) 166 return ret; 167 168 debug("SPI: deactivate cs.\n"); 169 spi_cs_deactivate(reg, spi_chip_select(dev)); 170 } 171 172 return 0; 173 } 174 175 static int mvebu_spi_set_speed(struct udevice *bus, uint hz) 176 { 177 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 178 struct spi_reg *reg = plat->spireg; 179 u32 data, prescale; 180 181 data = readl(®->cfg); 182 183 prescale = DIV_ROUND_UP(clk_get_rate(&plat->clk), hz); 184 if (prescale > 0x1f) 185 prescale = 0x1f; 186 else if (prescale > 0xf) 187 prescale = 0x10 + (prescale + 1) / 2; 188 189 data &= ~MVEBU_SPI_A3700_CLK_PRESCALE_MASK; 190 data |= prescale & MVEBU_SPI_A3700_CLK_PRESCALE_MASK; 191 192 writel(data, ®->cfg); 193 194 return 0; 195 } 196 197 static int mvebu_spi_set_mode(struct udevice *bus, uint mode) 198 { 199 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 200 struct spi_reg *reg = plat->spireg; 201 202 /* 203 * Set SPI polarity 204 * 0: Serial interface clock is low when inactive 205 * 1: Serial interface clock is high when inactive 206 */ 207 if (mode & SPI_CPOL) 208 setbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_POL); 209 else 210 clrbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_POL); 211 if (mode & SPI_CPHA) 212 setbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_PHA); 213 else 214 clrbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_PHA); 215 216 return 0; 217 } 218 219 static int mvebu_spi_probe(struct udevice *bus) 220 { 221 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 222 struct spi_reg *reg = plat->spireg; 223 u32 data; 224 int ret; 225 226 /* 227 * Settings SPI controller to be working in legacy mode, which 228 * means use only DO pin (I/O 1) for Data Out, and DI pin (I/O 0) 229 * for Data In. 230 */ 231 232 /* Flush read/write FIFO */ 233 data = readl(®->cfg); 234 writel(data | MVEBU_SPI_A3700_FIFO_FLUSH, ®->cfg); 235 ret = wait_for_bit_le32(®->cfg, MVEBU_SPI_A3700_FIFO_FLUSH, 236 false, 1000, false); 237 if (ret) 238 return ret; 239 240 /* Disable FIFO mode */ 241 data &= ~MVEBU_SPI_A3700_FIFO_EN; 242 243 /* Always shift 1 byte at a time */ 244 data &= ~MVEBU_SPI_A3700_BYTE_LEN; 245 246 writel(data, ®->cfg); 247 248 return 0; 249 } 250 251 static int mvebu_spi_ofdata_to_platdata(struct udevice *bus) 252 { 253 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 254 int ret; 255 256 plat->spireg = (struct spi_reg *)devfdt_get_addr(bus); 257 258 ret = clk_get_by_index(bus, 0, &plat->clk); 259 if (ret) { 260 dev_err(bus, "cannot get clock\n"); 261 return ret; 262 } 263 264 return 0; 265 } 266 267 static int mvebu_spi_remove(struct udevice *bus) 268 { 269 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 270 271 clk_free(&plat->clk); 272 273 return 0; 274 } 275 276 static const struct dm_spi_ops mvebu_spi_ops = { 277 .xfer = mvebu_spi_xfer, 278 .set_speed = mvebu_spi_set_speed, 279 .set_mode = mvebu_spi_set_mode, 280 /* 281 * cs_info is not needed, since we require all chip selects to be 282 * in the device tree explicitly 283 */ 284 }; 285 286 static const struct udevice_id mvebu_spi_ids[] = { 287 { .compatible = "marvell,armada-3700-spi" }, 288 { } 289 }; 290 291 U_BOOT_DRIVER(mvebu_spi) = { 292 .name = "mvebu_spi", 293 .id = UCLASS_SPI, 294 .of_match = mvebu_spi_ids, 295 .ops = &mvebu_spi_ops, 296 .ofdata_to_platdata = mvebu_spi_ofdata_to_platdata, 297 .platdata_auto_alloc_size = sizeof(struct mvebu_spi_platdata), 298 .probe = mvebu_spi_probe, 299 .remove = mvebu_spi_remove, 300 }; 301