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