1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2015 Marvell International Ltd. 4 * 5 * Copyright (C) 2016 Stefan Roese <sr@denx.de> 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <malloc.h> 11 #include <spi.h> 12 #include <wait_bit.h> 13 #include <asm/io.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 #define MVEBU_SPI_A3700_XFER_RDY BIT(1) 18 #define MVEBU_SPI_A3700_FIFO_FLUSH BIT(9) 19 #define MVEBU_SPI_A3700_BYTE_LEN BIT(5) 20 #define MVEBU_SPI_A3700_CLK_PHA BIT(6) 21 #define MVEBU_SPI_A3700_CLK_POL BIT(7) 22 #define MVEBU_SPI_A3700_FIFO_EN BIT(17) 23 #define MVEBU_SPI_A3700_SPI_EN_0 BIT(16) 24 #define MVEBU_SPI_A3700_CLK_PRESCALE_BIT 0 25 #define MVEBU_SPI_A3700_CLK_PRESCALE_MASK \ 26 (0x1f << MVEBU_SPI_A3700_CLK_PRESCALE_BIT) 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 unsigned int frequency; 39 unsigned int clock; 40 }; 41 42 static void spi_cs_activate(struct spi_reg *reg, int cs) 43 { 44 setbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); 45 } 46 47 static void spi_cs_deactivate(struct spi_reg *reg, int cs) 48 { 49 clrbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs); 50 } 51 52 /** 53 * spi_legacy_shift_byte() - triggers the real SPI transfer 54 * @bytelen: Indicate how many bytes to transfer. 55 * @dout: Buffer address of what to send. 56 * @din: Buffer address of where to receive. 57 * 58 * This function triggers the real SPI transfer in legacy mode. It 59 * will shift out char buffer from @dout, and shift in char buffer to 60 * @din, if necessary. 61 * 62 * This function assumes that only one byte is shifted at one time. 63 * However, it is not its responisbility to set the transfer type to 64 * one-byte. Also, it does not guarantee that it will work if transfer 65 * type becomes two-byte. See spi_set_legacy() for details. 66 * 67 * In legacy mode, simply write to the SPI_DOUT register will trigger 68 * the transfer. 69 * 70 * If @dout == NULL, which means no actual data needs to be sent out, 71 * then the function will shift out 0x00 in order to shift in data. 72 * The XFER_RDY flag is checked every time before accessing SPI_DOUT 73 * and SPI_DIN register. 74 * 75 * The number of transfers to be triggerred is decided by @bytelen. 76 * 77 * Return: 0 - cool 78 * -ETIMEDOUT - XFER_RDY flag timeout 79 */ 80 static int spi_legacy_shift_byte(struct spi_reg *reg, unsigned int bytelen, 81 const void *dout, void *din) 82 { 83 const u8 *dout_8; 84 u8 *din_8; 85 int ret; 86 87 /* Use 0x00 as dummy dout */ 88 const u8 dummy_dout = 0x0; 89 u32 pending_dout = 0x0; 90 91 /* dout_8: pointer of current dout */ 92 dout_8 = dout; 93 /* din_8: pointer of current din */ 94 din_8 = din; 95 96 while (bytelen) { 97 ret = wait_for_bit_le32(®->ctrl, 98 MVEBU_SPI_A3700_XFER_RDY, 99 true,100, false); 100 if (ret) 101 return ret; 102 103 if (dout) 104 pending_dout = (u32)*dout_8; 105 else 106 pending_dout = (u32)dummy_dout; 107 108 /* Trigger the xfer */ 109 writel(pending_dout, ®->dout); 110 111 if (din) { 112 ret = wait_for_bit_le32(®->ctrl, 113 MVEBU_SPI_A3700_XFER_RDY, 114 true, 100, false); 115 if (ret) 116 return ret; 117 118 /* Read what is transferred in */ 119 *din_8 = (u8)readl(®->din); 120 } 121 122 /* Don't increment the current pointer if NULL */ 123 if (dout) 124 dout_8++; 125 if (din) 126 din_8++; 127 128 bytelen--; 129 } 130 131 return 0; 132 } 133 134 static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen, 135 const void *dout, void *din, unsigned long flags) 136 { 137 struct udevice *bus = dev->parent; 138 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 139 struct spi_reg *reg = plat->spireg; 140 unsigned int bytelen; 141 int ret; 142 143 bytelen = bitlen / 8; 144 145 if (dout && din) 146 debug("This is a duplex transfer.\n"); 147 148 /* Activate CS */ 149 if (flags & SPI_XFER_BEGIN) { 150 debug("SPI: activate cs.\n"); 151 spi_cs_activate(reg, spi_chip_select(dev)); 152 } 153 154 /* Send and/or receive */ 155 if (dout || din) { 156 ret = spi_legacy_shift_byte(reg, bytelen, dout, din); 157 if (ret) 158 return ret; 159 } 160 161 /* Deactivate CS */ 162 if (flags & SPI_XFER_END) { 163 ret = wait_for_bit_le32(®->ctrl, 164 MVEBU_SPI_A3700_XFER_RDY, 165 true, 100, false); 166 if (ret) 167 return ret; 168 169 debug("SPI: deactivate cs.\n"); 170 spi_cs_deactivate(reg, spi_chip_select(dev)); 171 } 172 173 return 0; 174 } 175 176 static int mvebu_spi_set_speed(struct udevice *bus, uint hz) 177 { 178 struct mvebu_spi_platdata *plat = dev_get_platdata(bus); 179 struct spi_reg *reg = plat->spireg; 180 u32 data; 181 182 data = readl(®->cfg); 183 184 /* Set Prescaler */ 185 data &= ~MVEBU_SPI_A3700_CLK_PRESCALE_MASK; 186 187 /* Calculate Prescaler = (spi_input_freq / spi_max_freq) */ 188 if (hz > plat->frequency) 189 hz = plat->frequency; 190 data |= plat->clock / hz; 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 255 plat->spireg = (struct spi_reg *)devfdt_get_addr(bus); 256 257 /* 258 * FIXME 259 * Right now, mvebu does not have a clock infrastructure in U-Boot 260 * which should be used to query the input clock to the SPI 261 * controller. Once this clock driver is integrated into U-Boot 262 * it should be used to read the input clock and the DT property 263 * can be removed. 264 */ 265 plat->clock = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), 266 "clock-frequency", 160000); 267 plat->frequency = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), 268 "spi-max-frequency", 40000); 269 270 return 0; 271 } 272 273 static const struct dm_spi_ops mvebu_spi_ops = { 274 .xfer = mvebu_spi_xfer, 275 .set_speed = mvebu_spi_set_speed, 276 .set_mode = mvebu_spi_set_mode, 277 /* 278 * cs_info is not needed, since we require all chip selects to be 279 * in the device tree explicitly 280 */ 281 }; 282 283 static const struct udevice_id mvebu_spi_ids[] = { 284 { .compatible = "marvell,armada-3700-spi" }, 285 { } 286 }; 287 288 U_BOOT_DRIVER(mvebu_spi) = { 289 .name = "mvebu_spi", 290 .id = UCLASS_SPI, 291 .of_match = mvebu_spi_ids, 292 .ops = &mvebu_spi_ops, 293 .ofdata_to_platdata = mvebu_spi_ofdata_to_platdata, 294 .platdata_auto_alloc_size = sizeof(struct mvebu_spi_platdata), 295 .probe = mvebu_spi_probe, 296 }; 297