1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com> 4 */ 5 6 #include <common.h> 7 #include <spl.h> 8 #include <asm/gpio.h> 9 #include <asm/io.h> 10 #include <linux/libfdt.h> 11 12 #ifdef CONFIG_SPL_OS_BOOT 13 #error CONFIG_SPL_OS_BOOT is not supported yet 14 #endif 15 16 /* 17 * This is a very simple U-Boot image loading implementation, trying to 18 * replicate what the boot ROM is doing when loading the SPL. Because we 19 * know the exact pins where the SPI Flash is connected and also know 20 * that the Read Data Bytes (03h) command is supported, the hardware 21 * configuration is very simple and we don't need the extra flexibility 22 * of the SPI framework. Moreover, we rely on the default settings of 23 * the SPI controler hardware registers and only adjust what needs to 24 * be changed. This is good for the code size and this implementation 25 * adds less than 400 bytes to the SPL. 26 * 27 * There are two variants of the SPI controller in Allwinner SoCs: 28 * A10/A13/A20 (sun4i variant) and everything else (sun6i variant). 29 * Both of them are supported. 30 * 31 * The pin mixing part is SoC specific and only A10/A13/A20/H3/A64 are 32 * supported at the moment. 33 */ 34 35 /*****************************************************************************/ 36 /* SUN4I variant of the SPI controller */ 37 /*****************************************************************************/ 38 39 #define SUN4I_SPI0_CCTL (0x01C05000 + 0x1C) 40 #define SUN4I_SPI0_CTL (0x01C05000 + 0x08) 41 #define SUN4I_SPI0_RX (0x01C05000 + 0x00) 42 #define SUN4I_SPI0_TX (0x01C05000 + 0x04) 43 #define SUN4I_SPI0_FIFO_STA (0x01C05000 + 0x28) 44 #define SUN4I_SPI0_BC (0x01C05000 + 0x20) 45 #define SUN4I_SPI0_TC (0x01C05000 + 0x24) 46 47 #define SUN4I_CTL_ENABLE BIT(0) 48 #define SUN4I_CTL_MASTER BIT(1) 49 #define SUN4I_CTL_TF_RST BIT(8) 50 #define SUN4I_CTL_RF_RST BIT(9) 51 #define SUN4I_CTL_XCH BIT(10) 52 53 /*****************************************************************************/ 54 /* SUN6I variant of the SPI controller */ 55 /*****************************************************************************/ 56 57 #define SUN6I_SPI0_CCTL (0x01C68000 + 0x24) 58 #define SUN6I_SPI0_GCR (0x01C68000 + 0x04) 59 #define SUN6I_SPI0_TCR (0x01C68000 + 0x08) 60 #define SUN6I_SPI0_FIFO_STA (0x01C68000 + 0x1C) 61 #define SUN6I_SPI0_MBC (0x01C68000 + 0x30) 62 #define SUN6I_SPI0_MTC (0x01C68000 + 0x34) 63 #define SUN6I_SPI0_BCC (0x01C68000 + 0x38) 64 #define SUN6I_SPI0_TXD (0x01C68000 + 0x200) 65 #define SUN6I_SPI0_RXD (0x01C68000 + 0x300) 66 67 #define SUN6I_CTL_ENABLE BIT(0) 68 #define SUN6I_CTL_MASTER BIT(1) 69 #define SUN6I_CTL_SRST BIT(31) 70 #define SUN6I_TCR_XCH BIT(31) 71 72 /*****************************************************************************/ 73 74 #define CCM_AHB_GATING0 (0x01C20000 + 0x60) 75 #define CCM_SPI0_CLK (0x01C20000 + 0xA0) 76 #define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0) 77 78 #define AHB_RESET_SPI0_SHIFT 20 79 #define AHB_GATE_OFFSET_SPI0 20 80 81 #define SPI0_CLK_DIV_BY_2 0x1000 82 #define SPI0_CLK_DIV_BY_4 0x1001 83 84 /*****************************************************************************/ 85 86 /* 87 * Allwinner A10/A20 SoCs were using pins PC0,PC1,PC2,PC23 for booting 88 * from SPI Flash, everything else is using pins PC0,PC1,PC2,PC3. 89 */ 90 static void spi0_pinmux_setup(unsigned int pin_function) 91 { 92 unsigned int pin; 93 94 for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(2); pin++) 95 sunxi_gpio_set_cfgpin(pin, pin_function); 96 97 if (IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I)) 98 sunxi_gpio_set_cfgpin(SUNXI_GPC(23), pin_function); 99 else 100 sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function); 101 } 102 103 /* 104 * Setup 6 MHz from OSC24M (because the BROM is doing the same). 105 */ 106 static void spi0_enable_clock(void) 107 { 108 /* Deassert SPI0 reset on SUN6I */ 109 if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) 110 setbits_le32(SUN6I_BUS_SOFT_RST_REG0, 111 (1 << AHB_RESET_SPI0_SHIFT)); 112 113 /* Open the SPI0 gate */ 114 setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0)); 115 116 /* Divide by 4 */ 117 writel(SPI0_CLK_DIV_BY_4, IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ? 118 SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL); 119 /* 24MHz from OSC24M */ 120 writel((1 << 31), CCM_SPI0_CLK); 121 122 if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) { 123 /* Enable SPI in the master mode and do a soft reset */ 124 setbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER | 125 SUN6I_CTL_ENABLE | 126 SUN6I_CTL_SRST); 127 /* Wait for completion */ 128 while (readl(SUN6I_SPI0_GCR) & SUN6I_CTL_SRST) 129 ; 130 } else { 131 /* Enable SPI in the master mode and reset FIFO */ 132 setbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER | 133 SUN4I_CTL_ENABLE | 134 SUN4I_CTL_TF_RST | 135 SUN4I_CTL_RF_RST); 136 } 137 } 138 139 static void spi0_disable_clock(void) 140 { 141 /* Disable the SPI0 controller */ 142 if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) 143 clrbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER | 144 SUN6I_CTL_ENABLE); 145 else 146 clrbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER | 147 SUN4I_CTL_ENABLE); 148 149 /* Disable the SPI0 clock */ 150 writel(0, CCM_SPI0_CLK); 151 152 /* Close the SPI0 gate */ 153 clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0)); 154 155 /* Assert SPI0 reset on SUN6I */ 156 if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) 157 clrbits_le32(SUN6I_BUS_SOFT_RST_REG0, 158 (1 << AHB_RESET_SPI0_SHIFT)); 159 } 160 161 static void spi0_init(void) 162 { 163 unsigned int pin_function = SUNXI_GPC_SPI0; 164 165 if (IS_ENABLED(CONFIG_MACH_SUN50I)) 166 pin_function = SUN50I_GPC_SPI0; 167 168 spi0_pinmux_setup(pin_function); 169 spi0_enable_clock(); 170 } 171 172 static void spi0_deinit(void) 173 { 174 /* New SoCs can disable pins, older could only set them as input */ 175 unsigned int pin_function = SUNXI_GPIO_INPUT; 176 if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) 177 pin_function = SUNXI_GPIO_DISABLE; 178 179 spi0_disable_clock(); 180 spi0_pinmux_setup(pin_function); 181 } 182 183 /*****************************************************************************/ 184 185 #define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */ 186 187 static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize, 188 ulong spi_ctl_reg, 189 ulong spi_ctl_xch_bitmask, 190 ulong spi_fifo_reg, 191 ulong spi_tx_reg, 192 ulong spi_rx_reg, 193 ulong spi_bc_reg, 194 ulong spi_tc_reg, 195 ulong spi_bcc_reg) 196 { 197 writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */ 198 writel(4, spi_tc_reg); /* Transfer counter (bytes to send) */ 199 if (spi_bcc_reg) 200 writel(4, spi_bcc_reg); /* SUN6I also needs this */ 201 202 /* Send the Read Data Bytes (03h) command header */ 203 writeb(0x03, spi_tx_reg); 204 writeb((u8)(addr >> 16), spi_tx_reg); 205 writeb((u8)(addr >> 8), spi_tx_reg); 206 writeb((u8)(addr), spi_tx_reg); 207 208 /* Start the data transfer */ 209 setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask); 210 211 /* Wait until everything is received in the RX FIFO */ 212 while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize) 213 ; 214 215 /* Skip 4 bytes */ 216 readl(spi_rx_reg); 217 218 /* Read the data */ 219 while (bufsize-- > 0) 220 *buf++ = readb(spi_rx_reg); 221 222 /* tSHSL time is up to 100 ns in various SPI flash datasheets */ 223 udelay(1); 224 } 225 226 static void spi0_read_data(void *buf, u32 addr, u32 len) 227 { 228 u8 *buf8 = buf; 229 u32 chunk_len; 230 231 while (len > 0) { 232 chunk_len = len; 233 if (chunk_len > SPI_READ_MAX_SIZE) 234 chunk_len = SPI_READ_MAX_SIZE; 235 236 if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) { 237 sunxi_spi0_read_data(buf8, addr, chunk_len, 238 SUN6I_SPI0_TCR, 239 SUN6I_TCR_XCH, 240 SUN6I_SPI0_FIFO_STA, 241 SUN6I_SPI0_TXD, 242 SUN6I_SPI0_RXD, 243 SUN6I_SPI0_MBC, 244 SUN6I_SPI0_MTC, 245 SUN6I_SPI0_BCC); 246 } else { 247 sunxi_spi0_read_data(buf8, addr, chunk_len, 248 SUN4I_SPI0_CTL, 249 SUN4I_CTL_XCH, 250 SUN4I_SPI0_FIFO_STA, 251 SUN4I_SPI0_TX, 252 SUN4I_SPI0_RX, 253 SUN4I_SPI0_BC, 254 SUN4I_SPI0_TC, 255 0); 256 } 257 258 len -= chunk_len; 259 buf8 += chunk_len; 260 addr += chunk_len; 261 } 262 } 263 264 static ulong spi_load_read(struct spl_load_info *load, ulong sector, 265 ulong count, void *buf) 266 { 267 spi0_read_data(buf, sector, count); 268 269 return count; 270 } 271 272 /*****************************************************************************/ 273 274 static int spl_spi_load_image(struct spl_image_info *spl_image, 275 struct spl_boot_device *bootdev) 276 { 277 int ret = 0; 278 struct image_header *header; 279 header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); 280 281 spi0_init(); 282 283 spi0_read_data((void *)header, CONFIG_SYS_SPI_U_BOOT_OFFS, 0x40); 284 285 if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && 286 image_get_magic(header) == FDT_MAGIC) { 287 struct spl_load_info load; 288 289 debug("Found FIT image\n"); 290 load.dev = NULL; 291 load.priv = NULL; 292 load.filename = NULL; 293 load.bl_len = 1; 294 load.read = spi_load_read; 295 ret = spl_load_simple_fit(spl_image, &load, 296 CONFIG_SYS_SPI_U_BOOT_OFFS, header); 297 } else { 298 ret = spl_parse_image_header(spl_image, header); 299 if (ret) 300 return ret; 301 302 spi0_read_data((void *)spl_image->load_addr, 303 CONFIG_SYS_SPI_U_BOOT_OFFS, spl_image->size); 304 } 305 306 spi0_deinit(); 307 308 return ret; 309 } 310 /* Use priorty 0 to override the default if it happens to be linked in */ 311 SPL_LOAD_IMAGE_METHOD("sunxi SPI", 0, BOOT_DEVICE_SPI, spl_spi_load_image); 312