1499853d6Sryan_chen // SPDX-License-Identifier: GPL-2.0+ 2499853d6Sryan_chen /* 3499853d6Sryan_chen * ASPEED AST2500 FMC/SPI Controller driver 4499853d6Sryan_chen * 5499853d6Sryan_chen * Copyright (c) 2015-2018, IBM Corporation. 6499853d6Sryan_chen */ 7499853d6Sryan_chen 8499853d6Sryan_chen #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9499853d6Sryan_chen 10499853d6Sryan_chen #include <common.h> 11499853d6Sryan_chen #include <clk.h> 12499853d6Sryan_chen #include <dm.h> 13499853d6Sryan_chen #include <spi.h> 14499853d6Sryan_chen #include <spi_flash.h> 15499853d6Sryan_chen #include <asm/io.h> 16499853d6Sryan_chen #include <linux/ioport.h> 17499853d6Sryan_chen 18499853d6Sryan_chen #define ASPEED_SPI_MAX_CS 3 19beec505fSChin-Ting Kuo #define FLASH_CALIBRATION_LEN 0x400 20499853d6Sryan_chen 21499853d6Sryan_chen struct aspeed_spi_regs { 22499853d6Sryan_chen u32 conf; /* 0x00 CE Type Setting */ 23499853d6Sryan_chen u32 ctrl; /* 0x04 Control */ 24499853d6Sryan_chen u32 intr_ctrl; /* 0x08 Interrupt Control and Status */ 25499853d6Sryan_chen u32 cmd_ctrl; /* 0x0c Command Control */ 26499853d6Sryan_chen u32 ce_ctrl[ASPEED_SPI_MAX_CS]; /* 0x10 .. 0x18 CEx Control */ 27499853d6Sryan_chen u32 _reserved0[5]; /* .. */ 28499853d6Sryan_chen u32 segment_addr[ASPEED_SPI_MAX_CS]; 29499853d6Sryan_chen /* 0x30 .. 0x38 Segment Address */ 300a73b911SChin-Ting Kuo u32 _reserved1[5]; /* .. */ 310a73b911SChin-Ting Kuo u32 soft_rst_cmd_ctrl; /* 0x50 Auto Soft-Reset Command Control */ 320a73b911SChin-Ting Kuo u32 _reserved2[11]; /* .. */ 33499853d6Sryan_chen u32 dma_ctrl; /* 0x80 DMA Control/Status */ 34499853d6Sryan_chen u32 dma_flash_addr; /* 0x84 DMA Flash Side Address */ 35499853d6Sryan_chen u32 dma_dram_addr; /* 0x88 DMA DRAM Side Address */ 36499853d6Sryan_chen u32 dma_len; /* 0x8c DMA Length Register */ 37499853d6Sryan_chen u32 dma_checksum; /* 0x90 Checksum Calculation Result */ 38499853d6Sryan_chen u32 timings; /* 0x94 Read Timing Compensation */ 39499853d6Sryan_chen 40499853d6Sryan_chen /* not used */ 41499853d6Sryan_chen u32 soft_strap_status; /* 0x9c Software Strap Status */ 42499853d6Sryan_chen u32 write_cmd_filter_ctrl; /* 0xa0 Write Command Filter Control */ 43499853d6Sryan_chen u32 write_addr_filter_ctrl; /* 0xa4 Write Address Filter Control */ 44499853d6Sryan_chen u32 lock_ctrl_reset; /* 0xa8 Lock Control (SRST#) */ 45499853d6Sryan_chen u32 lock_ctrl_wdt; /* 0xac Lock Control (Watchdog) */ 46499853d6Sryan_chen u32 write_addr_filter[5]; /* 0xb0 Write Address Filter */ 47499853d6Sryan_chen }; 48499853d6Sryan_chen 49499853d6Sryan_chen /* CE Type Setting Register */ 50499853d6Sryan_chen #define CONF_ENABLE_W2 BIT(18) 51499853d6Sryan_chen #define CONF_ENABLE_W1 BIT(17) 52499853d6Sryan_chen #define CONF_ENABLE_W0 BIT(16) 53499853d6Sryan_chen #define CONF_FLASH_TYPE2 4 54499853d6Sryan_chen #define CONF_FLASH_TYPE1 2 /* Hardwired to SPI */ 55499853d6Sryan_chen #define CONF_FLASH_TYPE0 0 /* Hardwired to SPI */ 56499853d6Sryan_chen #define CONF_FLASH_TYPE_NOR 0x0 57499853d6Sryan_chen #define CONF_FLASH_TYPE_SPI 0x2 58499853d6Sryan_chen 59499853d6Sryan_chen /* CE Control Register */ 60499853d6Sryan_chen #define CTRL_EXTENDED2 BIT(2) /* 32 bit addressing for SPI */ 61499853d6Sryan_chen #define CTRL_EXTENDED1 BIT(1) /* 32 bit addressing for SPI */ 62499853d6Sryan_chen #define CTRL_EXTENDED0 BIT(0) /* 32 bit addressing for SPI */ 63499853d6Sryan_chen 64499853d6Sryan_chen /* Interrupt Control and Status Register */ 65499853d6Sryan_chen #define INTR_CTRL_DMA_STATUS BIT(11) 66499853d6Sryan_chen #define INTR_CTRL_CMD_ABORT_STATUS BIT(10) 67499853d6Sryan_chen #define INTR_CTRL_WRITE_PROTECT_STATUS BIT(9) 68499853d6Sryan_chen #define INTR_CTRL_DMA_EN BIT(3) 69499853d6Sryan_chen #define INTR_CTRL_CMD_ABORT_EN BIT(2) 70499853d6Sryan_chen #define INTR_CTRL_WRITE_PROTECT_EN BIT(1) 71499853d6Sryan_chen 72499853d6Sryan_chen /* CEx Control Register */ 73499853d6Sryan_chen #define CE_CTRL_IO_MODE_MASK GENMASK(31, 28) 7476e3c7a9Sryan_chen #define CE_CTRL_IO_QPI_DATA BIT(31) 75499853d6Sryan_chen #define CE_CTRL_IO_DUAL_DATA BIT(29) 76cd800046SChin-Ting Kuo #define CE_CTRL_IO_SINGLE 0 77499853d6Sryan_chen #define CE_CTRL_IO_DUAL_ADDR_DATA (BIT(29) | BIT(28)) 78499853d6Sryan_chen #define CE_CTRL_IO_QUAD_DATA BIT(30) 79499853d6Sryan_chen #define CE_CTRL_IO_QUAD_ADDR_DATA (BIT(30) | BIT(28)) 80499853d6Sryan_chen #define CE_CTRL_CMD_SHIFT 16 81499853d6Sryan_chen #define CE_CTRL_CMD_MASK 0xff 82499853d6Sryan_chen #define CE_CTRL_CMD(cmd) \ 83499853d6Sryan_chen (((cmd) & CE_CTRL_CMD_MASK) << CE_CTRL_CMD_SHIFT) 84499853d6Sryan_chen #define CE_CTRL_DUMMY_HIGH_SHIFT 14 85499853d6Sryan_chen #define CE_CTRL_DUMMY_HIGH_MASK 0x1 86499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ_SHIFT 8 87499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ_MASK 0xf 88499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ(div) \ 89499853d6Sryan_chen (((div) & CE_CTRL_CLOCK_FREQ_MASK) << CE_CTRL_CLOCK_FREQ_SHIFT) 907d182336Sryan_chen #define CE_G6_CTRL_CLOCK_FREQ(div) \ 917d182336Sryan_chen ((((div) & CE_CTRL_CLOCK_FREQ_MASK) << CE_CTRL_CLOCK_FREQ_SHIFT) | (((div) & 0xf0) << 20)) 92499853d6Sryan_chen #define CE_CTRL_DUMMY_LOW_SHIFT 6 /* 2 bits [7:6] */ 93499853d6Sryan_chen #define CE_CTRL_DUMMY_LOW_MASK 0x3 94499853d6Sryan_chen #define CE_CTRL_DUMMY(dummy) \ 95499853d6Sryan_chen (((((dummy) >> 2) & CE_CTRL_DUMMY_HIGH_MASK) \ 96499853d6Sryan_chen << CE_CTRL_DUMMY_HIGH_SHIFT) | \ 97499853d6Sryan_chen (((dummy) & CE_CTRL_DUMMY_LOW_MASK) << CE_CTRL_DUMMY_LOW_SHIFT)) 98499853d6Sryan_chen #define CE_CTRL_STOP_ACTIVE BIT(2) 99499853d6Sryan_chen #define CE_CTRL_MODE_MASK 0x3 100499853d6Sryan_chen #define CE_CTRL_READMODE 0x0 101499853d6Sryan_chen #define CE_CTRL_FREADMODE 0x1 102499853d6Sryan_chen #define CE_CTRL_WRITEMODE 0x2 103499853d6Sryan_chen #define CE_CTRL_USERMODE 0x3 104499853d6Sryan_chen 105cd800046SChin-Ting Kuo #define SPI_READ_FROM_FLASH 0x00000001 106cd800046SChin-Ting Kuo #define SPI_WRITE_TO_FLASH 0x00000002 107cd800046SChin-Ting Kuo 1080a73b911SChin-Ting Kuo /* Auto Soft-Reset Command Control */ 1090a73b911SChin-Ting Kuo #define SOFT_RST_CMD_EN GENMASK(1, 0) 1100a73b911SChin-Ting Kuo 111499853d6Sryan_chen /* 112499853d6Sryan_chen * The Segment Register uses a 8MB unit to encode the start address 113499853d6Sryan_chen * and the end address of the AHB window of a SPI flash device. 114499853d6Sryan_chen * Default segment addresses are : 115499853d6Sryan_chen * 116499853d6Sryan_chen * CE0 0x20000000 - 0x2fffffff 128MB 117499853d6Sryan_chen * CE1 0x28000000 - 0x29ffffff 32MB 118499853d6Sryan_chen * CE2 0x2a000000 - 0x2bffffff 32MB 119499853d6Sryan_chen * 120499853d6Sryan_chen * The full address space of the AHB window of the controller is 121499853d6Sryan_chen * covered and CE0 start address and CE2 end addresses are read-only. 122499853d6Sryan_chen */ 123499853d6Sryan_chen #define SEGMENT_ADDR_START(reg) ((((reg) >> 16) & 0xff) << 23) 124499853d6Sryan_chen #define SEGMENT_ADDR_END(reg) ((((reg) >> 24) & 0xff) << 23) 125499853d6Sryan_chen #define SEGMENT_ADDR_VALUE(start, end) \ 126499853d6Sryan_chen (((((start) >> 23) & 0xff) << 16) | ((((end) >> 23) & 0xff) << 24)) 127499853d6Sryan_chen 128da83dd7eSryan_chen #define G6_SEGMENT_ADDR_START(reg) (reg & 0xffff) 129da83dd7eSryan_chen #define G6_SEGMENT_ADDR_END(reg) ((reg >> 16) & 0xffff) 130da83dd7eSryan_chen #define G6_SEGMENT_ADDR_VALUE(start, end) \ 1316167da3dSryan_chen ((((start) >> 16) & 0xffff) | (((end) - 0x100000) & 0xffff0000)) 132da83dd7eSryan_chen 133499853d6Sryan_chen /* DMA Control/Status Register */ 134499853d6Sryan_chen #define DMA_CTRL_DELAY_SHIFT 8 135499853d6Sryan_chen #define DMA_CTRL_DELAY_MASK 0xf 136beec505fSChin-Ting Kuo #define G6_DMA_CTRL_DELAY_MASK 0xff 137499853d6Sryan_chen #define DMA_CTRL_FREQ_SHIFT 4 138f87fadc3Sryan_chen #define G6_DMA_CTRL_FREQ_SHIFT 16 139f87fadc3Sryan_chen 140499853d6Sryan_chen #define DMA_CTRL_FREQ_MASK 0xf 141499853d6Sryan_chen #define TIMING_MASK(div, delay) \ 142499853d6Sryan_chen (((delay & DMA_CTRL_DELAY_MASK) << DMA_CTRL_DELAY_SHIFT) | \ 143499853d6Sryan_chen ((div & DMA_CTRL_FREQ_MASK) << DMA_CTRL_FREQ_SHIFT)) 144f87fadc3Sryan_chen #define G6_TIMING_MASK(div, delay) \ 145beec505fSChin-Ting Kuo (((delay & G6_DMA_CTRL_DELAY_MASK) << DMA_CTRL_DELAY_SHIFT) | \ 146f87fadc3Sryan_chen ((div & DMA_CTRL_FREQ_MASK) << G6_DMA_CTRL_FREQ_SHIFT)) 147499853d6Sryan_chen #define DMA_CTRL_CALIB BIT(3) 148499853d6Sryan_chen #define DMA_CTRL_CKSUM BIT(2) 149499853d6Sryan_chen #define DMA_CTRL_WRITE BIT(1) 150499853d6Sryan_chen #define DMA_CTRL_ENABLE BIT(0) 151499853d6Sryan_chen 1520a73b911SChin-Ting Kuo /* for ast2600 setting */ 1530a73b911SChin-Ting Kuo #define SPI_3B_AUTO_CLR_REG 0x1e6e2510 1540a73b911SChin-Ting Kuo #define SPI_3B_AUTO_CLR BIT(9) 1550a73b911SChin-Ting Kuo 1560a73b911SChin-Ting Kuo 157499853d6Sryan_chen /* 1580a73b911SChin-Ting Kuo * flash related info 159499853d6Sryan_chen */ 160499853d6Sryan_chen struct aspeed_spi_flash { 161499853d6Sryan_chen u8 cs; 162499853d6Sryan_chen bool init; /* Initialized when the SPI bus is 163499853d6Sryan_chen * first claimed 164499853d6Sryan_chen */ 165499853d6Sryan_chen void __iomem *ahb_base; /* AHB Window for this device */ 166499853d6Sryan_chen u32 ahb_size; /* AHB Window segment size */ 167499853d6Sryan_chen u32 ce_ctrl_user; /* CE Control Register for USER mode */ 168499853d6Sryan_chen u32 ce_ctrl_fread; /* CE Control Register for FREAD mode */ 169cd800046SChin-Ting Kuo u32 read_iomode; 170cd800046SChin-Ting Kuo u32 write_iomode; 171499853d6Sryan_chen 172499853d6Sryan_chen struct spi_flash *spi; /* Associated SPI Flash device */ 173499853d6Sryan_chen }; 174499853d6Sryan_chen 175499853d6Sryan_chen struct aspeed_spi_priv { 176499853d6Sryan_chen struct aspeed_spi_regs *regs; 177499853d6Sryan_chen void __iomem *ahb_base; /* AHB Window for all flash devices */ 178499853d6Sryan_chen int new_ver; 179499853d6Sryan_chen u32 ahb_size; /* AHB Window segments size */ 180499853d6Sryan_chen 181499853d6Sryan_chen ulong hclk_rate; /* AHB clock rate */ 182499853d6Sryan_chen u32 max_hz; 183499853d6Sryan_chen u8 num_cs; 184499853d6Sryan_chen bool is_fmc; 185499853d6Sryan_chen 186499853d6Sryan_chen struct aspeed_spi_flash flashes[ASPEED_SPI_MAX_CS]; 187499853d6Sryan_chen u32 flash_count; 188499853d6Sryan_chen 189499853d6Sryan_chen u8 cmd_buf[16]; /* SPI command in progress */ 190499853d6Sryan_chen size_t cmd_len; 191499853d6Sryan_chen }; 192499853d6Sryan_chen 193499853d6Sryan_chen static struct aspeed_spi_flash *aspeed_spi_get_flash(struct udevice *dev) 194499853d6Sryan_chen { 195499853d6Sryan_chen struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); 196499853d6Sryan_chen struct aspeed_spi_priv *priv = dev_get_priv(dev->parent); 197499853d6Sryan_chen u8 cs = slave_plat->cs; 198499853d6Sryan_chen 199499853d6Sryan_chen if (cs >= priv->flash_count) { 200499853d6Sryan_chen pr_err("invalid CS %u\n", cs); 201499853d6Sryan_chen return NULL; 202499853d6Sryan_chen } 203499853d6Sryan_chen 204499853d6Sryan_chen return &priv->flashes[cs]; 205499853d6Sryan_chen } 206499853d6Sryan_chen 207ac86fa8bSryan_chen static u32 aspeed_g6_spi_hclk_divisor(struct aspeed_spi_priv *priv, u32 max_hz) 208499853d6Sryan_chen { 2097d182336Sryan_chen u32 hclk_rate = priv->hclk_rate; 210499853d6Sryan_chen /* HCLK/1 .. HCLK/16 */ 211499853d6Sryan_chen const u8 hclk_masks[] = { 212499853d6Sryan_chen 15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0 213499853d6Sryan_chen }; 2147d182336Sryan_chen u8 base_div = 0; 215f87fadc3Sryan_chen int done = 0; 216f87fadc3Sryan_chen u32 i, j = 0; 2177d182336Sryan_chen u32 hclk_div_setting = 0; 218499853d6Sryan_chen 219f87fadc3Sryan_chen for (j = 0; j < 0xf; i++) { 2207d182336Sryan_chen for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) { 2217d182336Sryan_chen base_div = j * 16; 222f87fadc3Sryan_chen if (max_hz >= (hclk_rate / ((i + 1) + base_div))) { 223f87fadc3Sryan_chen 224f87fadc3Sryan_chen done = 1; 2257d182336Sryan_chen break; 2267d182336Sryan_chen } 2277d182336Sryan_chen } 228f87fadc3Sryan_chen if (done) 229f87fadc3Sryan_chen break; 2307d182336Sryan_chen } 231499853d6Sryan_chen 232f87fadc3Sryan_chen debug("hclk=%d required=%d h_div %d, divisor is %d (mask %x) speed=%d\n", 233f87fadc3Sryan_chen hclk_rate, max_hz, j, i + 1, hclk_masks[i], hclk_rate / (i + 1 + base_div)); 2347d182336Sryan_chen 2357d182336Sryan_chen hclk_div_setting = ((j << 4) | hclk_masks[i]); 2367d182336Sryan_chen 237ac86fa8bSryan_chen return hclk_div_setting; 238ac86fa8bSryan_chen 239ac86fa8bSryan_chen } 240ac86fa8bSryan_chen 241ac86fa8bSryan_chen static u32 aspeed_spi_hclk_divisor(struct aspeed_spi_priv *priv, u32 max_hz) 242ac86fa8bSryan_chen { 243ac86fa8bSryan_chen u32 hclk_rate = priv->hclk_rate; 244ac86fa8bSryan_chen /* HCLK/1 .. HCLK/16 */ 245ac86fa8bSryan_chen const u8 hclk_masks[] = { 246ac86fa8bSryan_chen 15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0 247ac86fa8bSryan_chen }; 248d32338fdSryan_chen u32 i; 249ac86fa8bSryan_chen u32 hclk_div_setting = 0; 250ac86fa8bSryan_chen 251499853d6Sryan_chen for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) { 252499853d6Sryan_chen if (max_hz >= (hclk_rate / (i + 1))) 253499853d6Sryan_chen break; 254499853d6Sryan_chen } 255499853d6Sryan_chen debug("hclk=%d required=%d divisor is %d (mask %x) speed=%d\n", 256499853d6Sryan_chen hclk_rate, max_hz, i + 1, hclk_masks[i], hclk_rate / (i + 1)); 257499853d6Sryan_chen 2587d182336Sryan_chen hclk_div_setting = hclk_masks[i]; 2597d182336Sryan_chen 2607d182336Sryan_chen return hclk_div_setting; 261499853d6Sryan_chen } 262499853d6Sryan_chen 263499853d6Sryan_chen /* 264499853d6Sryan_chen * Use some address/size under the first flash device CE0 265499853d6Sryan_chen */ 266499853d6Sryan_chen static u32 aspeed_spi_fmc_checksum(struct aspeed_spi_priv *priv, u8 div, 267499853d6Sryan_chen u8 delay) 268499853d6Sryan_chen { 269499853d6Sryan_chen u32 flash_addr = (u32)priv->ahb_base + 0x10000; 270beec505fSChin-Ting Kuo u32 flash_len = FLASH_CALIBRATION_LEN; 271499853d6Sryan_chen u32 dma_ctrl; 272499853d6Sryan_chen u32 checksum; 273499853d6Sryan_chen 274499853d6Sryan_chen writel(flash_addr, &priv->regs->dma_flash_addr); 275499853d6Sryan_chen writel(flash_len, &priv->regs->dma_len); 276499853d6Sryan_chen 277499853d6Sryan_chen /* 278499853d6Sryan_chen * When doing calibration, the SPI clock rate in the CE0 279499853d6Sryan_chen * Control Register and the data input delay cycles in the 280499853d6Sryan_chen * Read Timing Compensation Register are replaced by bit[11:4]. 281499853d6Sryan_chen */ 282f87fadc3Sryan_chen if(priv->new_ver) 283f87fadc3Sryan_chen dma_ctrl = DMA_CTRL_ENABLE | DMA_CTRL_CKSUM | DMA_CTRL_CALIB | 284f87fadc3Sryan_chen G6_TIMING_MASK(div, delay); 285f87fadc3Sryan_chen else 286499853d6Sryan_chen dma_ctrl = DMA_CTRL_ENABLE | DMA_CTRL_CKSUM | DMA_CTRL_CALIB | 287499853d6Sryan_chen TIMING_MASK(div, delay); 288499853d6Sryan_chen writel(dma_ctrl, &priv->regs->dma_ctrl); 289499853d6Sryan_chen while (!(readl(&priv->regs->intr_ctrl) & INTR_CTRL_DMA_STATUS)) 290499853d6Sryan_chen ; 291499853d6Sryan_chen 292499853d6Sryan_chen writel(0x0, &priv->regs->intr_ctrl); 293499853d6Sryan_chen 294499853d6Sryan_chen checksum = readl(&priv->regs->dma_checksum); 295499853d6Sryan_chen 296499853d6Sryan_chen writel(0x0, &priv->regs->dma_ctrl); 297499853d6Sryan_chen return checksum; 298499853d6Sryan_chen } 299499853d6Sryan_chen 300499853d6Sryan_chen static u32 aspeed_spi_read_checksum(struct aspeed_spi_priv *priv, u8 div, 301499853d6Sryan_chen u8 delay) 302499853d6Sryan_chen { 303499853d6Sryan_chen /* TODO(clg@kaod.org): the SPI controllers do not have the DMA 304499853d6Sryan_chen * registers. The algorithm is the same. 305499853d6Sryan_chen */ 306499853d6Sryan_chen if (!priv->is_fmc) { 307499853d6Sryan_chen pr_warn("No timing calibration support for SPI controllers"); 308499853d6Sryan_chen return 0xbadc0de; 309499853d6Sryan_chen } 310499853d6Sryan_chen 311499853d6Sryan_chen return aspeed_spi_fmc_checksum(priv, div, delay); 312499853d6Sryan_chen } 313499853d6Sryan_chen 314499853d6Sryan_chen #define TIMING_DELAY_DI_4NS BIT(3) 315499853d6Sryan_chen #define TIMING_DELAY_HCYCLE_MAX 5 316499853d6Sryan_chen 317499853d6Sryan_chen static int aspeed_spi_timing_calibration(struct aspeed_spi_priv *priv) 318499853d6Sryan_chen { 319499853d6Sryan_chen /* HCLK/5 .. HCLK/1 */ 320499853d6Sryan_chen const u8 hclk_masks[] = {13, 6, 14, 7, 15}; 321beec505fSChin-Ting Kuo u32 timing_reg; 322499853d6Sryan_chen u32 checksum, gold_checksum; 323f87fadc3Sryan_chen int i, hcycle, delay_ns; 324beec505fSChin-Ting Kuo 325beec505fSChin-Ting Kuo /* Use the ctrl setting in aspeed_spi_flash_init() to 326beec505fSChin-Ting Kuo * implement calibration process. 327beec505fSChin-Ting Kuo */ 328beec505fSChin-Ting Kuo timing_reg = readl(&priv->regs->timings); 329beec505fSChin-Ting Kuo if (timing_reg != 0) 330beec505fSChin-Ting Kuo return 0; 331499853d6Sryan_chen 332499853d6Sryan_chen debug("Read timing calibration :\n"); 333499853d6Sryan_chen 334499853d6Sryan_chen /* Compute reference checksum at lowest freq HCLK/16 */ 335499853d6Sryan_chen gold_checksum = aspeed_spi_read_checksum(priv, 0, 0); 336499853d6Sryan_chen 337499853d6Sryan_chen /* Increase HCLK freq */ 3387d182336Sryan_chen if (priv->new_ver) { 3397d182336Sryan_chen for (i = 0; i < ARRAY_SIZE(hclk_masks) - 1; i++) { 3407d182336Sryan_chen u32 hdiv = 5 - i; 341f87fadc3Sryan_chen u32 hshift = (hdiv - 2) * 8; 3427d182336Sryan_chen bool pass = false; 3437d182336Sryan_chen u8 delay; 344f87fadc3Sryan_chen u16 first_delay = 0; 345f87fadc3Sryan_chen u16 end_delay = 0; 346f87fadc3Sryan_chen u32 cal_tmp; 347beec505fSChin-Ting Kuo u32 max_window_sz = 0; 348beec505fSChin-Ting Kuo u32 cur_window_sz = 0; 349beec505fSChin-Ting Kuo u32 tmp_delay; 350beec505fSChin-Ting Kuo 351f87fadc3Sryan_chen debug("hdiv %d, hshift %d\n", hdiv, hshift); 3527d182336Sryan_chen if (priv->hclk_rate / hdiv > priv->max_hz) { 3537d182336Sryan_chen debug("skipping freq %ld\n", priv->hclk_rate / hdiv); 3547d182336Sryan_chen continue; 3557d182336Sryan_chen } 3567d182336Sryan_chen 3577d182336Sryan_chen /* Try without the 4ns DI delay */ 358f87fadc3Sryan_chen hcycle = delay = 0; 359f87fadc3Sryan_chen debug("** Dealy Disable **\n"); 360f87fadc3Sryan_chen checksum = aspeed_spi_read_checksum(priv, hclk_masks[i], delay); 3617d182336Sryan_chen pass = (checksum == gold_checksum); 362d32338fdSryan_chen debug("HCLK/%d, no DI delay, %d HCLK cycle : %s\n", 3637d182336Sryan_chen hdiv, hcycle, pass ? "PASS" : "FAIL"); 3647d182336Sryan_chen 3657d182336Sryan_chen /* All good for this freq */ 3667d182336Sryan_chen if (pass) 367f87fadc3Sryan_chen goto next_div; 368f87fadc3Sryan_chen 369beec505fSChin-Ting Kuo /* Try each hcycle delay */ 370f87fadc3Sryan_chen for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) { 371beec505fSChin-Ting Kuo /* Increase DI delay by the step of 0.5ns */ 372f87fadc3Sryan_chen debug("** Delay Enable : hcycle %x ** \n", hcycle); 373f87fadc3Sryan_chen for (delay_ns = 0; delay_ns < 0xf; delay_ns++) { 374beec505fSChin-Ting Kuo tmp_delay = TIMING_DELAY_DI_4NS | hcycle | (delay_ns << 4); 375f87fadc3Sryan_chen checksum = aspeed_spi_read_checksum(priv, hclk_masks[i], 376beec505fSChin-Ting Kuo tmp_delay); 377f87fadc3Sryan_chen pass = (checksum == gold_checksum); 378beec505fSChin-Ting Kuo debug("HCLK/%d, DI delay, %d HCLK cycle, %d delay_ns : %s\n", 379f87fadc3Sryan_chen hdiv, hcycle, delay_ns, pass ? "PASS" : "FAIL"); 380f87fadc3Sryan_chen 381f87fadc3Sryan_chen if (!pass) { 382f87fadc3Sryan_chen if (!first_delay) 383f87fadc3Sryan_chen continue; 384f87fadc3Sryan_chen else { 385f87fadc3Sryan_chen end_delay = (hcycle << 4) | (delay_ns); 386f87fadc3Sryan_chen end_delay = end_delay - 1; 387beec505fSChin-Ting Kuo /* Larger window size is found */ 388beec505fSChin-Ting Kuo if (cur_window_sz > max_window_sz) { 389beec505fSChin-Ting Kuo max_window_sz = cur_window_sz; 390beec505fSChin-Ting Kuo cal_tmp = (first_delay + end_delay) / 2; 391beec505fSChin-Ting Kuo delay = TIMING_DELAY_DI_4NS | 392beec505fSChin-Ting Kuo ((cal_tmp & 0xf) << 4) | 393beec505fSChin-Ting Kuo (cal_tmp >> 4); 394beec505fSChin-Ting Kuo } 395beec505fSChin-Ting Kuo debug("find end_delay %x %d %d\n", end_delay, 396beec505fSChin-Ting Kuo hcycle, delay_ns); 397beec505fSChin-Ting Kuo 398beec505fSChin-Ting Kuo first_delay = 0; 399beec505fSChin-Ting Kuo end_delay = 0; 400beec505fSChin-Ting Kuo cur_window_sz = 0; 401beec505fSChin-Ting Kuo 4027d182336Sryan_chen break; 4037d182336Sryan_chen } 404f87fadc3Sryan_chen } else { 405f87fadc3Sryan_chen if (!first_delay) { 406f87fadc3Sryan_chen first_delay = (hcycle << 4) | delay_ns; 407f87fadc3Sryan_chen debug("find first_delay %x %d %d\n", first_delay, hcycle, delay_ns); 408f87fadc3Sryan_chen } 409beec505fSChin-Ting Kuo /* Record current pass window size */ 410beec505fSChin-Ting Kuo cur_window_sz++; 411beec505fSChin-Ting Kuo } 412f87fadc3Sryan_chen } 413f87fadc3Sryan_chen } 4147d182336Sryan_chen 4157d182336Sryan_chen if (pass) { 416beec505fSChin-Ting Kuo if (cur_window_sz > max_window_sz) { 417beec505fSChin-Ting Kuo max_window_sz = cur_window_sz; 418beec505fSChin-Ting Kuo end_delay = ((hcycle - 1) << 4) | (delay_ns - 1); 419f87fadc3Sryan_chen cal_tmp = (first_delay + end_delay) / 2; 420beec505fSChin-Ting Kuo delay = TIMING_DELAY_DI_4NS | 421beec505fSChin-Ting Kuo ((cal_tmp & 0xf) << 4) | 422beec505fSChin-Ting Kuo (cal_tmp >> 4); 423f87fadc3Sryan_chen } 424f87fadc3Sryan_chen } 425f87fadc3Sryan_chen next_div: 4267d182336Sryan_chen timing_reg &= ~(0xfu << hshift); 4277d182336Sryan_chen timing_reg |= delay << hshift; 428f87fadc3Sryan_chen debug("timing_reg %x, delay %x, hshift bit %d\n",timing_reg, delay, hshift); 4297d182336Sryan_chen } 4307d182336Sryan_chen } else { 431499853d6Sryan_chen for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) { 432499853d6Sryan_chen u32 hdiv = 5 - i; 433499853d6Sryan_chen u32 hshift = (hdiv - 1) << 2; 434499853d6Sryan_chen bool pass = false; 435499853d6Sryan_chen u8 delay; 436499853d6Sryan_chen 437499853d6Sryan_chen if (priv->hclk_rate / hdiv > priv->max_hz) { 438499853d6Sryan_chen debug("skipping freq %ld\n", priv->hclk_rate / hdiv); 439499853d6Sryan_chen continue; 440499853d6Sryan_chen } 441499853d6Sryan_chen 442499853d6Sryan_chen /* Increase HCLK cycles until read succeeds */ 443499853d6Sryan_chen for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) { 444499853d6Sryan_chen /* Try first with a 4ns DI delay */ 445499853d6Sryan_chen delay = TIMING_DELAY_DI_4NS | hcycle; 446499853d6Sryan_chen checksum = aspeed_spi_read_checksum(priv, hclk_masks[i], 447499853d6Sryan_chen delay); 448499853d6Sryan_chen pass = (checksum == gold_checksum); 449499853d6Sryan_chen debug(" HCLK/%d, 4ns DI delay, %d HCLK cycle : %s\n", 450499853d6Sryan_chen hdiv, hcycle, pass ? "PASS" : "FAIL"); 451499853d6Sryan_chen 452499853d6Sryan_chen /* Try again with more HCLK cycles */ 453499853d6Sryan_chen if (!pass) 454499853d6Sryan_chen continue; 455499853d6Sryan_chen 456499853d6Sryan_chen /* Try without the 4ns DI delay */ 457499853d6Sryan_chen delay = hcycle; 458499853d6Sryan_chen checksum = aspeed_spi_read_checksum(priv, hclk_masks[i], 459499853d6Sryan_chen delay); 460499853d6Sryan_chen pass = (checksum == gold_checksum); 461499853d6Sryan_chen debug(" HCLK/%d, no DI delay, %d HCLK cycle : %s\n", 462499853d6Sryan_chen hdiv, hcycle, pass ? "PASS" : "FAIL"); 463499853d6Sryan_chen 464499853d6Sryan_chen /* All good for this freq */ 465499853d6Sryan_chen if (pass) 466499853d6Sryan_chen break; 467499853d6Sryan_chen } 468499853d6Sryan_chen 469499853d6Sryan_chen if (pass) { 470499853d6Sryan_chen timing_reg &= ~(0xfu << hshift); 471499853d6Sryan_chen timing_reg |= delay << hshift; 472499853d6Sryan_chen } 473499853d6Sryan_chen } 4747d182336Sryan_chen } 475beec505fSChin-Ting Kuo 476499853d6Sryan_chen debug("Read Timing Compensation set to 0x%08x\n", timing_reg); 477499853d6Sryan_chen writel(timing_reg, &priv->regs->timings); 478499853d6Sryan_chen 479499853d6Sryan_chen return 0; 480499853d6Sryan_chen } 481499853d6Sryan_chen 482499853d6Sryan_chen static int aspeed_spi_controller_init(struct aspeed_spi_priv *priv) 483499853d6Sryan_chen { 484beec505fSChin-Ting Kuo int cs; 485499853d6Sryan_chen 486499853d6Sryan_chen /* 487499853d6Sryan_chen * Enable write on all flash devices as USER command mode 488499853d6Sryan_chen * requires it. 489499853d6Sryan_chen */ 490499853d6Sryan_chen setbits_le32(&priv->regs->conf, 491499853d6Sryan_chen CONF_ENABLE_W2 | CONF_ENABLE_W1 | CONF_ENABLE_W0); 492499853d6Sryan_chen 493499853d6Sryan_chen /* 494499853d6Sryan_chen * Set safe default settings for each device. These will be 495499853d6Sryan_chen * tuned after the SPI flash devices are probed. 496499853d6Sryan_chen */ 497da83dd7eSryan_chen if (priv->new_ver) { 498499853d6Sryan_chen for (cs = 0; cs < priv->flash_count; cs++) { 499499853d6Sryan_chen struct aspeed_spi_flash *flash = &priv->flashes[cs]; 500499853d6Sryan_chen u32 seg_addr = readl(&priv->regs->segment_addr[cs]); 501d32338fdSryan_chen u32 addr_config = 0; 502499853d6Sryan_chen switch(cs) { 503da83dd7eSryan_chen case 0: 504da83dd7eSryan_chen flash->ahb_base = cs ? (void *)G6_SEGMENT_ADDR_START(seg_addr) : 505da83dd7eSryan_chen priv->ahb_base; 506d32338fdSryan_chen debug("cs0 mem-map : %x \n", (u32)flash->ahb_base); 507da83dd7eSryan_chen break; 508499853d6Sryan_chen case 1: 509aed21223SChin-Ting Kuo flash->ahb_base = priv->flashes[0].ahb_base + 0x8000000; //cs0 + 128Mb : use 64MB 5106167da3dSryan_chen debug("cs1 mem-map : %x end %x \n", (u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000); 5116424f9abSChin-Ting Kuo addr_config = G6_SEGMENT_ADDR_VALUE((u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000); //add 512Mb 512d32338fdSryan_chen writel(addr_config, &priv->regs->segment_addr[cs]); 513499853d6Sryan_chen break; 514499853d6Sryan_chen case 2: 5156167da3dSryan_chen flash->ahb_base = priv->flashes[0].ahb_base + 0xc000000; //cs0 + 192Mb : use 64MB 5166167da3dSryan_chen debug("cs2 mem-map : %x end %x \n", (u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000); 5176424f9abSChin-Ting Kuo addr_config = G6_SEGMENT_ADDR_VALUE((u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000); //add 512Mb 5186167da3dSryan_chen writel(addr_config, &priv->regs->segment_addr[cs]); 519499853d6Sryan_chen break; 520499853d6Sryan_chen } 521da83dd7eSryan_chen flash->cs = cs; 522da83dd7eSryan_chen flash->ce_ctrl_user = CE_CTRL_USERMODE; 523da83dd7eSryan_chen flash->ce_ctrl_fread = CE_CTRL_READMODE; 524499853d6Sryan_chen } 525da83dd7eSryan_chen } else { 526da83dd7eSryan_chen for (cs = 0; cs < priv->flash_count; cs++) { 527da83dd7eSryan_chen struct aspeed_spi_flash *flash = &priv->flashes[cs]; 528da83dd7eSryan_chen u32 seg_addr = readl(&priv->regs->segment_addr[cs]); 529499853d6Sryan_chen /* 530499853d6Sryan_chen * The start address of the AHB window of CE0 is 531499853d6Sryan_chen * read-only and is the same as the address of the 532499853d6Sryan_chen * overall AHB window of the controller for all flash 533499853d6Sryan_chen * devices. 534499853d6Sryan_chen */ 535499853d6Sryan_chen flash->ahb_base = cs ? (void *)SEGMENT_ADDR_START(seg_addr) : 536499853d6Sryan_chen priv->ahb_base; 537499853d6Sryan_chen 538499853d6Sryan_chen flash->cs = cs; 539499853d6Sryan_chen flash->ce_ctrl_user = CE_CTRL_USERMODE; 540499853d6Sryan_chen flash->ce_ctrl_fread = CE_CTRL_READMODE; 541499853d6Sryan_chen } 542da83dd7eSryan_chen } 543499853d6Sryan_chen return 0; 544499853d6Sryan_chen } 545499853d6Sryan_chen 546499853d6Sryan_chen static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf, 547499853d6Sryan_chen size_t len) 548499853d6Sryan_chen { 549499853d6Sryan_chen size_t offset = 0; 550499853d6Sryan_chen 551499853d6Sryan_chen if (!((uintptr_t)buf % 4)) { 552499853d6Sryan_chen readsl(ahb_base, buf, len >> 2); 553499853d6Sryan_chen offset = len & ~0x3; 554499853d6Sryan_chen len -= offset; 555499853d6Sryan_chen } 556499853d6Sryan_chen readsb(ahb_base, (u8 *)buf + offset, len); 557499853d6Sryan_chen 558499853d6Sryan_chen return 0; 559499853d6Sryan_chen } 560499853d6Sryan_chen 561499853d6Sryan_chen static int aspeed_spi_write_to_ahb(void __iomem *ahb_base, const void *buf, 562499853d6Sryan_chen size_t len) 563499853d6Sryan_chen { 564499853d6Sryan_chen size_t offset = 0; 565499853d6Sryan_chen 566499853d6Sryan_chen if (!((uintptr_t)buf % 4)) { 567499853d6Sryan_chen writesl(ahb_base, buf, len >> 2); 568499853d6Sryan_chen offset = len & ~0x3; 569499853d6Sryan_chen len -= offset; 570499853d6Sryan_chen } 571499853d6Sryan_chen writesb(ahb_base, (u8 *)buf + offset, len); 572499853d6Sryan_chen 573499853d6Sryan_chen return 0; 574499853d6Sryan_chen } 575499853d6Sryan_chen 576499853d6Sryan_chen static void aspeed_spi_start_user(struct aspeed_spi_priv *priv, 577499853d6Sryan_chen struct aspeed_spi_flash *flash) 578499853d6Sryan_chen { 579499853d6Sryan_chen u32 ctrl_reg = flash->ce_ctrl_user | CE_CTRL_STOP_ACTIVE; 580499853d6Sryan_chen 581499853d6Sryan_chen /* Deselect CS and set USER command mode */ 582499853d6Sryan_chen writel(ctrl_reg, &priv->regs->ce_ctrl[flash->cs]); 583499853d6Sryan_chen 584499853d6Sryan_chen /* Select CS */ 585499853d6Sryan_chen clrbits_le32(&priv->regs->ce_ctrl[flash->cs], CE_CTRL_STOP_ACTIVE); 586499853d6Sryan_chen } 587499853d6Sryan_chen 588499853d6Sryan_chen static void aspeed_spi_stop_user(struct aspeed_spi_priv *priv, 589499853d6Sryan_chen struct aspeed_spi_flash *flash) 590499853d6Sryan_chen { 591499853d6Sryan_chen /* Deselect CS first */ 592499853d6Sryan_chen setbits_le32(&priv->regs->ce_ctrl[flash->cs], CE_CTRL_STOP_ACTIVE); 593499853d6Sryan_chen 594499853d6Sryan_chen /* Restore default command mode */ 595499853d6Sryan_chen writel(flash->ce_ctrl_fread, &priv->regs->ce_ctrl[flash->cs]); 596499853d6Sryan_chen } 597499853d6Sryan_chen 598499853d6Sryan_chen static int aspeed_spi_read_reg(struct aspeed_spi_priv *priv, 599499853d6Sryan_chen struct aspeed_spi_flash *flash, 600499853d6Sryan_chen u8 opcode, u8 *read_buf, int len) 601499853d6Sryan_chen { 602499853d6Sryan_chen aspeed_spi_start_user(priv, flash); 603499853d6Sryan_chen aspeed_spi_write_to_ahb(flash->ahb_base, &opcode, 1); 604499853d6Sryan_chen aspeed_spi_read_from_ahb(flash->ahb_base, read_buf, len); 605499853d6Sryan_chen aspeed_spi_stop_user(priv, flash); 606499853d6Sryan_chen 607499853d6Sryan_chen return 0; 608499853d6Sryan_chen } 609499853d6Sryan_chen 610499853d6Sryan_chen static int aspeed_spi_write_reg(struct aspeed_spi_priv *priv, 611499853d6Sryan_chen struct aspeed_spi_flash *flash, 612499853d6Sryan_chen u8 opcode, const u8 *write_buf, int len) 613499853d6Sryan_chen { 614499853d6Sryan_chen aspeed_spi_start_user(priv, flash); 615499853d6Sryan_chen aspeed_spi_write_to_ahb(flash->ahb_base, &opcode, 1); 616499853d6Sryan_chen aspeed_spi_write_to_ahb(flash->ahb_base, write_buf, len); 617499853d6Sryan_chen aspeed_spi_stop_user(priv, flash); 618499853d6Sryan_chen 619528cd552Sryan_chen debug("=== write opcode [%x] ==== \n", opcode); 620499853d6Sryan_chen switch(opcode) { 621499853d6Sryan_chen case SPINOR_OP_EN4B: 6220a73b911SChin-Ting Kuo /* For ast2600, if 2 chips ABR mode is enabled, 6230a73b911SChin-Ting Kuo * turn on 3B mode auto clear in order to avoid 6240a73b911SChin-Ting Kuo * the scenario where spi controller is at 4B mode 6250a73b911SChin-Ting Kuo * and flash site is at 3B mode after 3rd switch. 6260a73b911SChin-Ting Kuo */ 6270a73b911SChin-Ting Kuo if (priv->new_ver == 1 && (readl(SPI_3B_AUTO_CLR_REG) & SPI_3B_AUTO_CLR)) 6280a73b911SChin-Ting Kuo writel(readl(&priv->regs->soft_rst_cmd_ctrl) | SOFT_RST_CMD_EN, 6290a73b911SChin-Ting Kuo &priv->regs->soft_rst_cmd_ctrl); 6300a73b911SChin-Ting Kuo 631edbd932bSChin-Ting Kuo writel(readl(&priv->regs->ctrl) | (0x11 << flash->cs), &priv->regs->ctrl); 632499853d6Sryan_chen break; 633499853d6Sryan_chen case SPINOR_OP_EX4B: 634edbd932bSChin-Ting Kuo writel(readl(&priv->regs->ctrl) & ~(0x11 << flash->cs), &priv->regs->ctrl); 635499853d6Sryan_chen break; 636499853d6Sryan_chen } 637499853d6Sryan_chen return 0; 638499853d6Sryan_chen } 639499853d6Sryan_chen 640499853d6Sryan_chen static void aspeed_spi_send_cmd_addr(struct aspeed_spi_priv *priv, 641499853d6Sryan_chen struct aspeed_spi_flash *flash, 642cd800046SChin-Ting Kuo const u8 *cmdbuf, unsigned int cmdlen, uint32_t flag) 643499853d6Sryan_chen { 644499853d6Sryan_chen int i; 645499853d6Sryan_chen u8 byte0 = 0x0; 646499853d6Sryan_chen u8 addrlen = cmdlen - 1; 647499853d6Sryan_chen 648499853d6Sryan_chen /* First, send the opcode */ 649499853d6Sryan_chen aspeed_spi_write_to_ahb(flash->ahb_base, &cmdbuf[0], 1); 650499853d6Sryan_chen 651cd800046SChin-Ting Kuo if(flash->write_iomode == CE_CTRL_IO_QUAD_ADDR_DATA && (flag & SPI_WRITE_TO_FLASH)) 652cd800046SChin-Ting Kuo writel(flash->ce_ctrl_user | flash->write_iomode, &priv->regs->ce_ctrl[flash->cs]); 653cd800046SChin-Ting Kuo else if(flash->read_iomode == CE_CTRL_IO_QUAD_ADDR_DATA && (flag & SPI_READ_FROM_FLASH)) 654cd800046SChin-Ting Kuo writel(flash->ce_ctrl_user | flash->read_iomode, &priv->regs->ce_ctrl[flash->cs]); 655528cd552Sryan_chen 656499853d6Sryan_chen /* 657499853d6Sryan_chen * The controller is configured for 4BYTE address mode. Fix 658499853d6Sryan_chen * the address width and send an extra byte if the SPI Flash 659499853d6Sryan_chen * layer uses 3 bytes addresses. 660499853d6Sryan_chen */ 661499853d6Sryan_chen if (addrlen == 3 && readl(&priv->regs->ctrl) & BIT(flash->cs)) 662499853d6Sryan_chen aspeed_spi_write_to_ahb(flash->ahb_base, &byte0, 1); 663499853d6Sryan_chen 664499853d6Sryan_chen /* Then the address */ 665499853d6Sryan_chen for (i = 1 ; i < cmdlen; i++) 666499853d6Sryan_chen aspeed_spi_write_to_ahb(flash->ahb_base, &cmdbuf[i], 1); 667499853d6Sryan_chen } 668499853d6Sryan_chen 669499853d6Sryan_chen static ssize_t aspeed_spi_read_user(struct aspeed_spi_priv *priv, 670499853d6Sryan_chen struct aspeed_spi_flash *flash, 671499853d6Sryan_chen unsigned int cmdlen, const u8 *cmdbuf, 672499853d6Sryan_chen unsigned int len, u8 *read_buf) 673499853d6Sryan_chen { 674499853d6Sryan_chen u8 dummy = 0xff; 675499853d6Sryan_chen int i; 676499853d6Sryan_chen 677499853d6Sryan_chen aspeed_spi_start_user(priv, flash); 678499853d6Sryan_chen 679499853d6Sryan_chen /* cmd buffer = cmd + addr + dummies */ 680499853d6Sryan_chen aspeed_spi_send_cmd_addr(priv, flash, cmdbuf, 681cd800046SChin-Ting Kuo cmdlen - (flash->spi->read_dummy/8), SPI_READ_FROM_FLASH); 682499853d6Sryan_chen 683499853d6Sryan_chen for (i = 0 ; i < (flash->spi->read_dummy/8); i++) 684499853d6Sryan_chen aspeed_spi_write_to_ahb(flash->ahb_base, &dummy, 1); 685499853d6Sryan_chen 686cd800046SChin-Ting Kuo if (flash->read_iomode) { 687499853d6Sryan_chen clrbits_le32(&priv->regs->ce_ctrl[flash->cs], 688499853d6Sryan_chen CE_CTRL_IO_MODE_MASK); 689cd800046SChin-Ting Kuo setbits_le32(&priv->regs->ce_ctrl[flash->cs], flash->read_iomode); 690499853d6Sryan_chen } 691499853d6Sryan_chen 692499853d6Sryan_chen aspeed_spi_read_from_ahb(flash->ahb_base, read_buf, len); 693499853d6Sryan_chen aspeed_spi_stop_user(priv, flash); 694499853d6Sryan_chen 695499853d6Sryan_chen return 0; 696499853d6Sryan_chen } 697499853d6Sryan_chen 698499853d6Sryan_chen static ssize_t aspeed_spi_write_user(struct aspeed_spi_priv *priv, 699499853d6Sryan_chen struct aspeed_spi_flash *flash, 700499853d6Sryan_chen unsigned int cmdlen, const u8 *cmdbuf, 701499853d6Sryan_chen unsigned int len, const u8 *write_buf) 702499853d6Sryan_chen { 703499853d6Sryan_chen aspeed_spi_start_user(priv, flash); 704499853d6Sryan_chen 70576e3c7a9Sryan_chen /* cmd buffer = cmd + addr : normally cmd is use signle mode*/ 706cd800046SChin-Ting Kuo aspeed_spi_send_cmd_addr(priv, flash, cmdbuf, cmdlen, SPI_WRITE_TO_FLASH); 70776e3c7a9Sryan_chen 70876e3c7a9Sryan_chen /* data will use io mode */ 709cd800046SChin-Ting Kuo if(flash->write_iomode == CE_CTRL_IO_QUAD_DATA) 710cd800046SChin-Ting Kuo writel(flash->ce_ctrl_user | flash->write_iomode, &priv->regs->ce_ctrl[flash->cs]); 71176e3c7a9Sryan_chen 712499853d6Sryan_chen aspeed_spi_write_to_ahb(flash->ahb_base, write_buf, len); 713499853d6Sryan_chen 714499853d6Sryan_chen aspeed_spi_stop_user(priv, flash); 715499853d6Sryan_chen 716499853d6Sryan_chen return 0; 717499853d6Sryan_chen } 718499853d6Sryan_chen 719499853d6Sryan_chen static u32 aspeed_spi_flash_to_addr(struct aspeed_spi_flash *flash, 720499853d6Sryan_chen const u8 *cmdbuf, unsigned int cmdlen) 721499853d6Sryan_chen { 722499853d6Sryan_chen u8 addrlen = cmdlen - 1; 723499853d6Sryan_chen u32 addr = (cmdbuf[1] << 16) | (cmdbuf[2] << 8) | cmdbuf[3]; 724499853d6Sryan_chen 725499853d6Sryan_chen /* 726499853d6Sryan_chen * U-Boot SPI Flash layer uses 3 bytes addresses, but it might 727499853d6Sryan_chen * change one day 728499853d6Sryan_chen */ 729499853d6Sryan_chen if (addrlen == 4) 730499853d6Sryan_chen addr = (addr << 8) | cmdbuf[4]; 731499853d6Sryan_chen 732499853d6Sryan_chen return addr; 733499853d6Sryan_chen } 734499853d6Sryan_chen 735499853d6Sryan_chen /* TODO(clg@kaod.org): add support for XFER_MMAP instead ? */ 736499853d6Sryan_chen static ssize_t aspeed_spi_read(struct aspeed_spi_priv *priv, 737499853d6Sryan_chen struct aspeed_spi_flash *flash, 738499853d6Sryan_chen unsigned int cmdlen, const u8 *cmdbuf, 739499853d6Sryan_chen unsigned int len, u8 *read_buf) 740499853d6Sryan_chen { 741499853d6Sryan_chen /* cmd buffer = cmd + addr + dummies */ 742499853d6Sryan_chen u32 offset = aspeed_spi_flash_to_addr(flash, cmdbuf, 743499853d6Sryan_chen cmdlen - (flash->spi->read_dummy/8)); 744499853d6Sryan_chen 745499853d6Sryan_chen /* 7466424f9abSChin-Ting Kuo * Switch to USER command mode: 7476424f9abSChin-Ting Kuo * - if the AHB window configured for the device is 7486424f9abSChin-Ting Kuo * too small for the read operation 7496424f9abSChin-Ting Kuo * - if read offset is smaller than the decoded start address 7506424f9abSChin-Ting Kuo * and the decoded range is not multiple of flash size 751499853d6Sryan_chen */ 7526424f9abSChin-Ting Kuo if ((offset + len >= flash->ahb_size) || \ 7536424f9abSChin-Ting Kuo (offset < ((int)flash->ahb_base & 0x0FFFFFFF) && \ 7546424f9abSChin-Ting Kuo (((int)flash->ahb_base & 0x0FFFFFFF) % flash->spi->size) != 0)) { 755499853d6Sryan_chen return aspeed_spi_read_user(priv, flash, cmdlen, cmdbuf, 756499853d6Sryan_chen len, read_buf); 757499853d6Sryan_chen } 758499853d6Sryan_chen 759499853d6Sryan_chen memcpy_fromio(read_buf, flash->ahb_base + offset, len); 760499853d6Sryan_chen 761499853d6Sryan_chen return 0; 762499853d6Sryan_chen } 763499853d6Sryan_chen 764499853d6Sryan_chen static int aspeed_spi_xfer(struct udevice *dev, unsigned int bitlen, 765499853d6Sryan_chen const void *dout, void *din, unsigned long flags) 766499853d6Sryan_chen { 767499853d6Sryan_chen struct udevice *bus = dev->parent; 768499853d6Sryan_chen struct aspeed_spi_priv *priv = dev_get_priv(bus); 769499853d6Sryan_chen struct aspeed_spi_flash *flash; 770499853d6Sryan_chen u8 *cmd_buf = priv->cmd_buf; 771499853d6Sryan_chen size_t data_bytes; 772499853d6Sryan_chen int err = 0; 773499853d6Sryan_chen 774499853d6Sryan_chen flash = aspeed_spi_get_flash(dev); 775499853d6Sryan_chen if (!flash) 776499853d6Sryan_chen return -ENXIO; 777499853d6Sryan_chen 778499853d6Sryan_chen if (flags & SPI_XFER_BEGIN) { 779499853d6Sryan_chen /* save command in progress */ 780499853d6Sryan_chen priv->cmd_len = bitlen / 8; 781499853d6Sryan_chen memcpy(cmd_buf, dout, priv->cmd_len); 782499853d6Sryan_chen } 783499853d6Sryan_chen 784499853d6Sryan_chen if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) { 785499853d6Sryan_chen /* if start and end bit are set, the data bytes is 0. */ 786499853d6Sryan_chen data_bytes = 0; 787499853d6Sryan_chen } else { 788499853d6Sryan_chen data_bytes = bitlen / 8; 789499853d6Sryan_chen } 790499853d6Sryan_chen 791499853d6Sryan_chen debug("CS%u: %s cmd %zu bytes data %zu bytes\n", flash->cs, 792499853d6Sryan_chen din ? "read" : "write", priv->cmd_len, data_bytes); 793499853d6Sryan_chen 794499853d6Sryan_chen if ((flags & SPI_XFER_END) || flags == 0) { 795499853d6Sryan_chen if (priv->cmd_len == 0) { 796499853d6Sryan_chen pr_err("No command is progress !\n"); 797499853d6Sryan_chen return -1; 798499853d6Sryan_chen } 799499853d6Sryan_chen 800499853d6Sryan_chen if (din && data_bytes) { 801499853d6Sryan_chen if (priv->cmd_len == 1) 802499853d6Sryan_chen err = aspeed_spi_read_reg(priv, flash, 803499853d6Sryan_chen cmd_buf[0], 804499853d6Sryan_chen din, data_bytes); 805499853d6Sryan_chen else 806499853d6Sryan_chen err = aspeed_spi_read(priv, flash, 807499853d6Sryan_chen priv->cmd_len, 808499853d6Sryan_chen cmd_buf, data_bytes, 809499853d6Sryan_chen din); 810499853d6Sryan_chen } else if (dout) { 811499853d6Sryan_chen if (priv->cmd_len == 1) 812499853d6Sryan_chen err = aspeed_spi_write_reg(priv, flash, 813499853d6Sryan_chen cmd_buf[0], 814499853d6Sryan_chen dout, data_bytes); 815499853d6Sryan_chen else 816499853d6Sryan_chen err = aspeed_spi_write_user(priv, flash, 817499853d6Sryan_chen priv->cmd_len, 818499853d6Sryan_chen cmd_buf, data_bytes, 819499853d6Sryan_chen dout); 820499853d6Sryan_chen } 821499853d6Sryan_chen 822499853d6Sryan_chen if (flags & SPI_XFER_END) { 823499853d6Sryan_chen /* clear command */ 824499853d6Sryan_chen memset(cmd_buf, 0, sizeof(priv->cmd_buf)); 825499853d6Sryan_chen priv->cmd_len = 0; 826499853d6Sryan_chen } 827499853d6Sryan_chen } 828499853d6Sryan_chen 829499853d6Sryan_chen return err; 830499853d6Sryan_chen } 831499853d6Sryan_chen 832499853d6Sryan_chen static int aspeed_spi_child_pre_probe(struct udevice *dev) 833499853d6Sryan_chen { 834499853d6Sryan_chen struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); 835499853d6Sryan_chen 836499853d6Sryan_chen debug("pre_probe slave device on CS%u, max_hz %u, mode 0x%x.\n", 837499853d6Sryan_chen slave_plat->cs, slave_plat->max_hz, slave_plat->mode); 838499853d6Sryan_chen 839499853d6Sryan_chen if (!aspeed_spi_get_flash(dev)) 840499853d6Sryan_chen return -ENXIO; 841499853d6Sryan_chen 842499853d6Sryan_chen return 0; 843499853d6Sryan_chen } 844499853d6Sryan_chen 845499853d6Sryan_chen /* 846499853d6Sryan_chen * It is possible to automatically define a contiguous address space 847499853d6Sryan_chen * on top of all CEs in the AHB window of the controller but it would 848499853d6Sryan_chen * require much more work. Let's start with a simple mapping scheme 849499853d6Sryan_chen * which should work fine for a single flash device. 850499853d6Sryan_chen * 851499853d6Sryan_chen * More complex schemes should probably be defined with the device 852499853d6Sryan_chen * tree. 853499853d6Sryan_chen */ 854499853d6Sryan_chen static int aspeed_spi_flash_set_segment(struct aspeed_spi_priv *priv, 855499853d6Sryan_chen struct aspeed_spi_flash *flash) 856499853d6Sryan_chen { 857499853d6Sryan_chen u32 seg_addr; 858499853d6Sryan_chen 859499853d6Sryan_chen /* could be configured through the device tree */ 860499853d6Sryan_chen flash->ahb_size = flash->spi->size; 861499853d6Sryan_chen 862da83dd7eSryan_chen if (priv->new_ver) { 863da83dd7eSryan_chen seg_addr = G6_SEGMENT_ADDR_VALUE((u32)flash->ahb_base, 864da83dd7eSryan_chen (u32)flash->ahb_base + flash->ahb_size); 865da83dd7eSryan_chen } else { 866499853d6Sryan_chen seg_addr = SEGMENT_ADDR_VALUE((u32)flash->ahb_base, 867499853d6Sryan_chen (u32)flash->ahb_base + flash->ahb_size); 868da83dd7eSryan_chen } 869499853d6Sryan_chen writel(seg_addr, &priv->regs->segment_addr[flash->cs]); 870499853d6Sryan_chen 871499853d6Sryan_chen return 0; 872499853d6Sryan_chen } 873499853d6Sryan_chen 874499853d6Sryan_chen static int aspeed_spi_flash_init(struct aspeed_spi_priv *priv, 875499853d6Sryan_chen struct aspeed_spi_flash *flash, 876499853d6Sryan_chen struct udevice *dev) 877499853d6Sryan_chen { 878beec505fSChin-Ting Kuo int ret; 879499853d6Sryan_chen struct spi_flash *spi_flash = dev_get_uclass_priv(dev); 880499853d6Sryan_chen struct spi_slave *slave = dev_get_parent_priv(dev); 881499853d6Sryan_chen u32 read_hclk; 882499853d6Sryan_chen 883a4e44632SChin-Ting Kuo flash->spi = spi_flash; 884a4e44632SChin-Ting Kuo 885499853d6Sryan_chen /* 886499853d6Sryan_chen * The flash device has not been probed yet. Initial transfers 887499853d6Sryan_chen * to read the JEDEC of the device will use the initial 888499853d6Sryan_chen * default settings of the registers. 889499853d6Sryan_chen */ 890499853d6Sryan_chen if (!spi_flash->name) 891499853d6Sryan_chen return 0; 892499853d6Sryan_chen 893543bff32SChin-Ting Kuo /* 894543bff32SChin-Ting Kuo * The SPI flash device slave should not change, so initialize 895543bff32SChin-Ting Kuo * it only once. 896543bff32SChin-Ting Kuo */ 897543bff32SChin-Ting Kuo if (flash->init) 898543bff32SChin-Ting Kuo return 0; 899543bff32SChin-Ting Kuo 900499853d6Sryan_chen debug("CS%u: init %s flags:%x size:%d page:%d sector:%d erase:%d " 901499853d6Sryan_chen "cmds [ erase:%x read=%x write:%x ] dummy:%d\n", 902499853d6Sryan_chen flash->cs, 903499853d6Sryan_chen spi_flash->name, spi_flash->flags, spi_flash->size, 904499853d6Sryan_chen spi_flash->page_size, spi_flash->sector_size, 905499853d6Sryan_chen spi_flash->erase_size, spi_flash->erase_opcode, 906499853d6Sryan_chen spi_flash->read_opcode, spi_flash->program_opcode, 907499853d6Sryan_chen spi_flash->read_dummy); 908499853d6Sryan_chen 9097d182336Sryan_chen flash->ce_ctrl_user = CE_CTRL_USERMODE; 910499853d6Sryan_chen 911ac86fa8bSryan_chen if(priv->new_ver) 912ac86fa8bSryan_chen read_hclk = aspeed_g6_spi_hclk_divisor(priv, slave->speed); 913ac86fa8bSryan_chen else 9147d182336Sryan_chen read_hclk = aspeed_spi_hclk_divisor(priv, slave->speed); 915499853d6Sryan_chen 916528cd552Sryan_chen switch(flash->spi->read_opcode) { 917528cd552Sryan_chen case SPINOR_OP_READ_1_1_2: 918528cd552Sryan_chen case SPINOR_OP_READ_1_1_2_4B: 919cd800046SChin-Ting Kuo flash->read_iomode = CE_CTRL_IO_DUAL_DATA; 920528cd552Sryan_chen break; 921528cd552Sryan_chen case SPINOR_OP_READ_1_1_4: 922528cd552Sryan_chen case SPINOR_OP_READ_1_1_4_4B: 923cd800046SChin-Ting Kuo flash->read_iomode = CE_CTRL_IO_QUAD_DATA; 924528cd552Sryan_chen break; 925528cd552Sryan_chen case SPINOR_OP_READ_1_4_4: 926528cd552Sryan_chen case SPINOR_OP_READ_1_4_4_4B: 927cd800046SChin-Ting Kuo flash->read_iomode = CE_CTRL_IO_QUAD_ADDR_DATA; 928734f8860SChin-Ting Kuo printf("need modify dummy for 3 bytes\n"); 929528cd552Sryan_chen break; 930499853d6Sryan_chen } 931499853d6Sryan_chen 932cd800046SChin-Ting Kuo switch(flash->spi->program_opcode) { 933cd800046SChin-Ting Kuo case SPINOR_OP_PP: 934cd800046SChin-Ting Kuo case SPINOR_OP_PP_4B: 935cd800046SChin-Ting Kuo flash->write_iomode = CE_CTRL_IO_SINGLE; 936cd800046SChin-Ting Kuo break; 937cd800046SChin-Ting Kuo case SPINOR_OP_PP_1_1_4: 938cd800046SChin-Ting Kuo case SPINOR_OP_PP_1_1_4_4B: 939cd800046SChin-Ting Kuo flash->write_iomode = CE_CTRL_IO_QUAD_DATA; 940cd800046SChin-Ting Kuo break; 941cd800046SChin-Ting Kuo case SPINOR_OP_PP_1_4_4: 942cd800046SChin-Ting Kuo case SPINOR_OP_PP_1_4_4_4B: 943cd800046SChin-Ting Kuo flash->write_iomode = CE_CTRL_IO_QUAD_ADDR_DATA; 944cd800046SChin-Ting Kuo printf("need modify dummy for 3 bytes"); 945cd800046SChin-Ting Kuo break; 946cd800046SChin-Ting Kuo } 947cd800046SChin-Ting Kuo 948d32338fdSryan_chen if(priv->new_ver) { 9497d182336Sryan_chen flash->ce_ctrl_fread = CE_G6_CTRL_CLOCK_FREQ(read_hclk) | 950cd800046SChin-Ting Kuo flash->read_iomode | 9517d182336Sryan_chen CE_CTRL_CMD(flash->spi->read_opcode) | 9527d182336Sryan_chen CE_CTRL_DUMMY((flash->spi->read_dummy/8)) | 9537d182336Sryan_chen CE_CTRL_FREADMODE; 954*b679b8adSChin-Ting Kuo flash->ce_ctrl_user |= CE_G6_CTRL_CLOCK_FREQ(read_hclk); 955d32338fdSryan_chen } else { 956499853d6Sryan_chen flash->ce_ctrl_fread = CE_CTRL_CLOCK_FREQ(read_hclk) | 957cd800046SChin-Ting Kuo flash->read_iomode | 958499853d6Sryan_chen CE_CTRL_CMD(flash->spi->read_opcode) | 959499853d6Sryan_chen CE_CTRL_DUMMY((flash->spi->read_dummy/8)) | 960499853d6Sryan_chen CE_CTRL_FREADMODE; 961d32338fdSryan_chen } 962499853d6Sryan_chen 9639405f2a1SChin-Ting Kuo if (flash->spi->addr_width == 4) 9649405f2a1SChin-Ting Kuo writel(readl(&priv->regs->ctrl) | 0x11 << flash->cs, &priv->regs->ctrl); 9659405f2a1SChin-Ting Kuo 966499853d6Sryan_chen debug("CS%u: USER mode 0x%08x FREAD mode 0x%08x\n", flash->cs, 967499853d6Sryan_chen flash->ce_ctrl_user, flash->ce_ctrl_fread); 968499853d6Sryan_chen 969499853d6Sryan_chen /* Set the CE Control Register default (FAST READ) */ 970499853d6Sryan_chen writel(flash->ce_ctrl_fread, &priv->regs->ce_ctrl[flash->cs]); 971499853d6Sryan_chen 972499853d6Sryan_chen /* Set Address Segment Register for direct AHB accesses */ 973499853d6Sryan_chen aspeed_spi_flash_set_segment(priv, flash); 974499853d6Sryan_chen 975beec505fSChin-Ting Kuo /* 976beec505fSChin-Ting Kuo * Set the Read Timing Compensation Register. This setting 977beec505fSChin-Ting Kuo * applies to all devices. 978beec505fSChin-Ting Kuo */ 979beec505fSChin-Ting Kuo ret = aspeed_spi_timing_calibration(priv); 980beec505fSChin-Ting Kuo if (ret != 0) 981beec505fSChin-Ting Kuo return ret; 982beec505fSChin-Ting Kuo 983499853d6Sryan_chen /* All done */ 984499853d6Sryan_chen flash->init = true; 985499853d6Sryan_chen 986499853d6Sryan_chen return 0; 987499853d6Sryan_chen } 988499853d6Sryan_chen 989499853d6Sryan_chen static int aspeed_spi_claim_bus(struct udevice *dev) 990499853d6Sryan_chen { 991499853d6Sryan_chen struct udevice *bus = dev->parent; 992499853d6Sryan_chen struct aspeed_spi_priv *priv = dev_get_priv(bus); 993499853d6Sryan_chen struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); 994499853d6Sryan_chen struct aspeed_spi_flash *flash; 995499853d6Sryan_chen 996499853d6Sryan_chen debug("%s: claim bus CS%u\n", bus->name, slave_plat->cs); 997499853d6Sryan_chen 998499853d6Sryan_chen flash = aspeed_spi_get_flash(dev); 999499853d6Sryan_chen if (!flash) 1000499853d6Sryan_chen return -ENODEV; 1001499853d6Sryan_chen 1002499853d6Sryan_chen return aspeed_spi_flash_init(priv, flash, dev); 1003499853d6Sryan_chen } 1004499853d6Sryan_chen 1005499853d6Sryan_chen static int aspeed_spi_release_bus(struct udevice *dev) 1006499853d6Sryan_chen { 1007499853d6Sryan_chen struct udevice *bus = dev->parent; 1008499853d6Sryan_chen struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); 1009499853d6Sryan_chen 1010499853d6Sryan_chen debug("%s: release bus CS%u\n", bus->name, slave_plat->cs); 1011499853d6Sryan_chen 1012499853d6Sryan_chen if (!aspeed_spi_get_flash(dev)) 1013499853d6Sryan_chen return -ENODEV; 1014499853d6Sryan_chen 1015499853d6Sryan_chen return 0; 1016499853d6Sryan_chen } 1017499853d6Sryan_chen 1018499853d6Sryan_chen static int aspeed_spi_set_mode(struct udevice *bus, uint mode) 1019499853d6Sryan_chen { 1020499853d6Sryan_chen debug("%s: setting mode to %x\n", bus->name, mode); 1021499853d6Sryan_chen 1022499853d6Sryan_chen if (mode & (SPI_RX_QUAD | SPI_TX_QUAD)) { 102376e3c7a9Sryan_chen #ifndef CONFIG_ASPEED_AST2600 1024499853d6Sryan_chen pr_err("%s invalid QUAD IO mode\n", bus->name); 1025499853d6Sryan_chen return -EINVAL; 102676e3c7a9Sryan_chen #endif 1027499853d6Sryan_chen } 1028499853d6Sryan_chen 1029499853d6Sryan_chen /* The CE Control Register is set in claim_bus() */ 1030499853d6Sryan_chen return 0; 1031499853d6Sryan_chen } 1032499853d6Sryan_chen 1033499853d6Sryan_chen static int aspeed_spi_set_speed(struct udevice *bus, uint hz) 1034499853d6Sryan_chen { 1035499853d6Sryan_chen debug("%s: setting speed to %u\n", bus->name, hz); 1036499853d6Sryan_chen 1037499853d6Sryan_chen /* The CE Control Register is set in claim_bus() */ 1038499853d6Sryan_chen return 0; 1039499853d6Sryan_chen } 1040499853d6Sryan_chen 1041499853d6Sryan_chen static int aspeed_spi_count_flash_devices(struct udevice *bus) 1042499853d6Sryan_chen { 1043499853d6Sryan_chen ofnode node; 1044499853d6Sryan_chen int count = 0; 1045499853d6Sryan_chen 1046499853d6Sryan_chen dev_for_each_subnode(node, bus) { 1047499853d6Sryan_chen if (ofnode_is_available(node) && 1048499853d6Sryan_chen ofnode_device_is_compatible(node, "spi-flash")) 1049499853d6Sryan_chen count++; 1050499853d6Sryan_chen } 1051499853d6Sryan_chen 1052499853d6Sryan_chen return count; 1053499853d6Sryan_chen } 1054499853d6Sryan_chen 1055499853d6Sryan_chen static int aspeed_spi_bind(struct udevice *bus) 1056499853d6Sryan_chen { 1057499853d6Sryan_chen debug("%s assigned req_seq=%d seq=%d\n", bus->name, bus->req_seq, 1058499853d6Sryan_chen bus->seq); 1059499853d6Sryan_chen 1060499853d6Sryan_chen return 0; 1061499853d6Sryan_chen } 1062499853d6Sryan_chen 1063499853d6Sryan_chen static int aspeed_spi_probe(struct udevice *bus) 1064499853d6Sryan_chen { 1065499853d6Sryan_chen struct resource res_regs, res_ahb; 1066499853d6Sryan_chen struct aspeed_spi_priv *priv = dev_get_priv(bus); 1067499853d6Sryan_chen struct clk hclk; 1068499853d6Sryan_chen int ret; 1069499853d6Sryan_chen 1070499853d6Sryan_chen ret = dev_read_resource(bus, 0, &res_regs); 1071499853d6Sryan_chen if (ret < 0) 1072499853d6Sryan_chen return ret; 1073499853d6Sryan_chen 1074499853d6Sryan_chen priv->regs = (void __iomem *)res_regs.start; 1075499853d6Sryan_chen 1076499853d6Sryan_chen ret = dev_read_resource(bus, 1, &res_ahb); 1077499853d6Sryan_chen if (ret < 0) 1078499853d6Sryan_chen return ret; 1079499853d6Sryan_chen 1080499853d6Sryan_chen priv->ahb_base = (void __iomem *)res_ahb.start; 1081499853d6Sryan_chen priv->ahb_size = res_ahb.end - res_ahb.start; 1082499853d6Sryan_chen 1083499853d6Sryan_chen ret = clk_get_by_index(bus, 0, &hclk); 1084499853d6Sryan_chen if (ret < 0) { 1085499853d6Sryan_chen pr_err("%s could not get clock: %d\n", bus->name, ret); 1086499853d6Sryan_chen return ret; 1087499853d6Sryan_chen } 1088499853d6Sryan_chen 1089499853d6Sryan_chen priv->hclk_rate = clk_get_rate(&hclk); 1090499853d6Sryan_chen clk_free(&hclk); 1091499853d6Sryan_chen 1092499853d6Sryan_chen priv->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 1093499853d6Sryan_chen 100000000); 1094499853d6Sryan_chen 1095499853d6Sryan_chen priv->num_cs = dev_read_u32_default(bus, "num-cs", ASPEED_SPI_MAX_CS); 1096499853d6Sryan_chen 1097499853d6Sryan_chen priv->flash_count = aspeed_spi_count_flash_devices(bus); 1098499853d6Sryan_chen if (priv->flash_count > priv->num_cs) { 1099499853d6Sryan_chen pr_err("%s has too many flash devices: %d\n", bus->name, 1100499853d6Sryan_chen priv->flash_count); 1101499853d6Sryan_chen return -EINVAL; 1102499853d6Sryan_chen } 1103499853d6Sryan_chen 1104499853d6Sryan_chen if (!priv->flash_count) { 1105499853d6Sryan_chen pr_err("%s has no flash devices ?!\n", bus->name); 1106499853d6Sryan_chen return -ENODEV; 1107499853d6Sryan_chen } 1108499853d6Sryan_chen 11097d182336Sryan_chen if (device_is_compatible(bus, "aspeed,ast2600-fmc") || 1110f87fadc3Sryan_chen device_is_compatible(bus, "aspeed,ast2600-spi")) { 1111499853d6Sryan_chen priv->new_ver = 1; 1112499853d6Sryan_chen } 1113499853d6Sryan_chen 1114499853d6Sryan_chen /* 1115499853d6Sryan_chen * There are some slight differences between the FMC and the 1116499853d6Sryan_chen * SPI controllers 1117499853d6Sryan_chen */ 1118499853d6Sryan_chen priv->is_fmc = dev_get_driver_data(bus); 1119499853d6Sryan_chen 1120499853d6Sryan_chen ret = aspeed_spi_controller_init(priv); 1121499853d6Sryan_chen if (ret) 1122499853d6Sryan_chen return ret; 1123499853d6Sryan_chen 1124499853d6Sryan_chen debug("%s probed regs=%p ahb_base=%p max-hz=%d cs=%d seq=%d\n", 1125499853d6Sryan_chen bus->name, priv->regs, priv->ahb_base, priv->max_hz, 1126499853d6Sryan_chen priv->flash_count, bus->seq); 1127499853d6Sryan_chen 1128499853d6Sryan_chen return 0; 1129499853d6Sryan_chen } 1130499853d6Sryan_chen 1131499853d6Sryan_chen static const struct dm_spi_ops aspeed_spi_ops = { 1132499853d6Sryan_chen .claim_bus = aspeed_spi_claim_bus, 1133499853d6Sryan_chen .release_bus = aspeed_spi_release_bus, 1134499853d6Sryan_chen .set_mode = aspeed_spi_set_mode, 1135499853d6Sryan_chen .set_speed = aspeed_spi_set_speed, 1136499853d6Sryan_chen .xfer = aspeed_spi_xfer, 1137499853d6Sryan_chen }; 1138499853d6Sryan_chen 1139499853d6Sryan_chen static const struct udevice_id aspeed_spi_ids[] = { 1140499853d6Sryan_chen { .compatible = "aspeed,ast2600-fmc", .data = 1 }, 1141499853d6Sryan_chen { .compatible = "aspeed,ast2600-spi", .data = 0 }, 1142499853d6Sryan_chen { .compatible = "aspeed,ast2500-fmc", .data = 1 }, 1143499853d6Sryan_chen { .compatible = "aspeed,ast2500-spi", .data = 0 }, 1144c4475966Sryan_chen { .compatible = "aspeed,ast2400-fmc", .data = 1 }, 1145499853d6Sryan_chen { } 1146499853d6Sryan_chen }; 1147499853d6Sryan_chen 1148499853d6Sryan_chen U_BOOT_DRIVER(aspeed_spi) = { 1149499853d6Sryan_chen .name = "aspeed_spi", 1150499853d6Sryan_chen .id = UCLASS_SPI, 1151499853d6Sryan_chen .of_match = aspeed_spi_ids, 1152499853d6Sryan_chen .ops = &aspeed_spi_ops, 1153499853d6Sryan_chen .priv_auto_alloc_size = sizeof(struct aspeed_spi_priv), 1154499853d6Sryan_chen .child_pre_probe = aspeed_spi_child_pre_probe, 1155499853d6Sryan_chen .bind = aspeed_spi_bind, 1156499853d6Sryan_chen .probe = aspeed_spi_probe, 1157499853d6Sryan_chen }; 1158