1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> 4 * Copyright (C) 2018 BayLibre, SAS 5 * Author: Neil Armstrong <narmstrong@baylibre.com> 6 * 7 * Amlogic Meson SPI Flash Controller driver 8 */ 9 10 #include <common.h> 11 #include <spi.h> 12 #include <clk.h> 13 #include <dm.h> 14 #include <regmap.h> 15 #include <errno.h> 16 #include <asm/io.h> 17 #include <linux/bitfield.h> 18 19 /* register map */ 20 #define REG_CMD 0x00 21 #define REG_ADDR 0x04 22 #define REG_CTRL 0x08 23 #define REG_CTRL1 0x0c 24 #define REG_STATUS 0x10 25 #define REG_CTRL2 0x14 26 #define REG_CLOCK 0x18 27 #define REG_USER 0x1c 28 #define REG_USER1 0x20 29 #define REG_USER2 0x24 30 #define REG_USER3 0x28 31 #define REG_USER4 0x2c 32 #define REG_SLAVE 0x30 33 #define REG_SLAVE1 0x34 34 #define REG_SLAVE2 0x38 35 #define REG_SLAVE3 0x3c 36 #define REG_C0 0x40 37 #define REG_B8 0x60 38 #define REG_MAX 0x7c 39 40 /* register fields */ 41 #define CMD_USER BIT(18) 42 #define CTRL_ENABLE_AHB BIT(17) 43 #define CLOCK_SOURCE BIT(31) 44 #define CLOCK_DIV_SHIFT 12 45 #define CLOCK_DIV_MASK (0x3f << CLOCK_DIV_SHIFT) 46 #define CLOCK_CNT_HIGH_SHIFT 6 47 #define CLOCK_CNT_HIGH_MASK (0x3f << CLOCK_CNT_HIGH_SHIFT) 48 #define CLOCK_CNT_LOW_SHIFT 0 49 #define CLOCK_CNT_LOW_MASK (0x3f << CLOCK_CNT_LOW_SHIFT) 50 #define USER_DIN_EN_MS BIT(0) 51 #define USER_CMP_MODE BIT(2) 52 #define USER_CLK_NOT_INV BIT(7) 53 #define USER_UC_DOUT_SEL BIT(27) 54 #define USER_UC_DIN_SEL BIT(28) 55 #define USER_UC_MASK ((BIT(5) - 1) << 27) 56 #define USER1_BN_UC_DOUT_SHIFT 17 57 #define USER1_BN_UC_DOUT_MASK (0xff << 16) 58 #define USER1_BN_UC_DIN_SHIFT 8 59 #define USER1_BN_UC_DIN_MASK (0xff << 8) 60 #define USER4_CS_POL_HIGH BIT(23) 61 #define USER4_IDLE_CLK_HIGH BIT(29) 62 #define USER4_CS_ACT BIT(30) 63 #define SLAVE_TRST_DONE BIT(4) 64 #define SLAVE_OP_MODE BIT(30) 65 #define SLAVE_SW_RST BIT(31) 66 67 #define SPIFC_BUFFER_SIZE 64 68 69 struct meson_spifc_priv { 70 struct regmap *regmap; 71 struct clk clk; 72 }; 73 74 /** 75 * meson_spifc_drain_buffer() - copy data from device buffer to memory 76 * @spifc: the Meson SPI device 77 * @buf: the destination buffer 78 * @len: number of bytes to copy 79 */ 80 static void meson_spifc_drain_buffer(struct meson_spifc_priv *spifc, 81 u8 *buf, int len) 82 { 83 u32 data; 84 int i = 0; 85 86 while (i < len) { 87 regmap_read(spifc->regmap, REG_C0 + i, &data); 88 89 if (len - i >= 4) { 90 *((u32 *)buf) = data; 91 buf += 4; 92 } else { 93 memcpy(buf, &data, len - i); 94 break; 95 } 96 i += 4; 97 } 98 } 99 100 /** 101 * meson_spifc_fill_buffer() - copy data from memory to device buffer 102 * @spifc: the Meson SPI device 103 * @buf: the source buffer 104 * @len: number of bytes to copy 105 */ 106 static void meson_spifc_fill_buffer(struct meson_spifc_priv *spifc, 107 const u8 *buf, int len) 108 { 109 u32 data = 0; 110 int i = 0; 111 112 while (i < len) { 113 if (len - i >= 4) 114 data = *(u32 *)buf; 115 else 116 memcpy(&data, buf, len - i); 117 118 regmap_write(spifc->regmap, REG_C0 + i, data); 119 120 buf += 4; 121 i += 4; 122 } 123 } 124 125 /** 126 * meson_spifc_txrx() - transfer a chunk of data 127 * @spifc: the Meson SPI device 128 * @dout: data buffer for TX 129 * @din: data buffer for RX 130 * @offset: offset of the data to transfer 131 * @len: length of the data to transfer 132 * @last_xfer: whether this is the last transfer of the message 133 * @last_chunk: whether this is the last chunk of the transfer 134 * Return: 0 on success, a negative value on error 135 */ 136 static int meson_spifc_txrx(struct meson_spifc_priv *spifc, 137 const u8 *dout, u8 *din, int offset, 138 int len, bool last_xfer, bool last_chunk) 139 { 140 bool keep_cs = true; 141 u32 data; 142 int ret; 143 144 if (dout) 145 meson_spifc_fill_buffer(spifc, dout + offset, len); 146 147 /* enable DOUT stage */ 148 regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK, 149 USER_UC_DOUT_SEL); 150 regmap_write(spifc->regmap, REG_USER1, 151 (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT); 152 153 /* enable data input during DOUT */ 154 regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS, 155 USER_DIN_EN_MS); 156 157 if (last_chunk && last_xfer) 158 keep_cs = false; 159 160 regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT, 161 keep_cs ? USER4_CS_ACT : 0); 162 163 /* clear transition done bit */ 164 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0); 165 /* start transfer */ 166 regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER); 167 168 /* wait for the current operation to terminate */ 169 ret = regmap_read_poll_timeout(spifc->regmap, REG_SLAVE, data, 170 (data & SLAVE_TRST_DONE), 171 0, 5 * CONFIG_SYS_HZ); 172 173 if (!ret && din) 174 meson_spifc_drain_buffer(spifc, din + offset, len); 175 176 return ret; 177 } 178 179 /** 180 * meson_spifc_xfer() - perform a single transfer 181 * @dev: the SPI controller device 182 * @bitlen: length of the transfer 183 * @dout: data buffer for TX 184 * @din: data buffer for RX 185 * @flags: transfer flags 186 * Return: 0 on success, a negative value on error 187 */ 188 static int meson_spifc_xfer(struct udevice *slave, unsigned int bitlen, 189 const void *dout, void *din, unsigned long flags) 190 { 191 struct meson_spifc_priv *spifc = dev_get_priv(slave->parent); 192 int blen = bitlen / 8; 193 int len, done = 0, ret = 0; 194 195 if (bitlen % 8) 196 return -EINVAL; 197 198 debug("xfer len %d (%d) dout %p din %p\n", bitlen, blen, dout, din); 199 200 regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0); 201 202 while (done < blen && !ret) { 203 len = min_t(int, blen - done, SPIFC_BUFFER_SIZE); 204 ret = meson_spifc_txrx(spifc, dout, din, done, len, 205 flags & SPI_XFER_END, 206 done + len >= blen); 207 done += len; 208 } 209 210 regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 211 CTRL_ENABLE_AHB); 212 213 return ret; 214 } 215 216 /** 217 * meson_spifc_set_speed() - program the clock divider 218 * @dev: the SPI controller device 219 * @speed: desired speed in Hz 220 */ 221 static int meson_spifc_set_speed(struct udevice *dev, uint speed) 222 { 223 struct meson_spifc_priv *spifc = dev_get_priv(dev); 224 unsigned long parent, value; 225 int n; 226 227 parent = clk_get_rate(&spifc->clk); 228 n = max_t(int, parent / speed - 1, 1); 229 230 debug("parent %lu, speed %u, n %d\n", parent, speed, n); 231 232 value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK; 233 value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK; 234 value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) & 235 CLOCK_CNT_HIGH_MASK; 236 237 regmap_write(spifc->regmap, REG_CLOCK, value); 238 239 return 0; 240 } 241 242 /** 243 * meson_spifc_set_mode() - setups the SPI bus mode 244 * @dev: the SPI controller device 245 * @mode: desired mode bitfield 246 * Return: 0 on success, -ENODEV on error 247 */ 248 static int meson_spifc_set_mode(struct udevice *dev, uint mode) 249 { 250 struct meson_spifc_priv *spifc = dev_get_priv(dev); 251 252 if (mode & (SPI_CPHA | SPI_RX_QUAD | SPI_RX_DUAL | 253 SPI_TX_QUAD | SPI_TX_DUAL)) 254 return -ENODEV; 255 256 regmap_update_bits(spifc->regmap, REG_USER, USER_CLK_NOT_INV, 257 mode & SPI_CPOL ? USER_CLK_NOT_INV : 0); 258 259 regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_POL_HIGH, 260 mode & SPI_CS_HIGH ? USER4_CS_POL_HIGH : 0); 261 262 return 0; 263 } 264 265 /** 266 * meson_spifc_hw_init() - reset and initialize the SPI controller 267 * @spifc: the Meson SPI device 268 */ 269 static void meson_spifc_hw_init(struct meson_spifc_priv *spifc) 270 { 271 /* reset device */ 272 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST, 273 SLAVE_SW_RST); 274 /* disable compatible mode */ 275 regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0); 276 /* set master mode */ 277 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0); 278 } 279 280 static const struct dm_spi_ops meson_spifc_ops = { 281 .xfer = meson_spifc_xfer, 282 .set_speed = meson_spifc_set_speed, 283 .set_mode = meson_spifc_set_mode, 284 }; 285 286 static int meson_spifc_probe(struct udevice *dev) 287 { 288 struct meson_spifc_priv *priv = dev_get_priv(dev); 289 int ret; 290 291 ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); 292 if (ret) 293 return ret; 294 295 ret = clk_get_by_index(dev, 0, &priv->clk); 296 if (ret) 297 return ret; 298 299 ret = clk_enable(&priv->clk); 300 if (ret) 301 return ret; 302 303 meson_spifc_hw_init(priv); 304 305 return 0; 306 } 307 308 static const struct udevice_id meson_spifc_ids[] = { 309 { .compatible = "amlogic,meson-gxbb-spifc", }, 310 { } 311 }; 312 313 U_BOOT_DRIVER(meson_spifc) = { 314 .name = "meson_spifc", 315 .id = UCLASS_SPI, 316 .of_match = meson_spifc_ids, 317 .ops = &meson_spifc_ops, 318 .probe = meson_spifc_probe, 319 .priv_auto_alloc_size = sizeof(struct meson_spifc_priv), 320 }; 321