1c1cd6cb6SAndy Yan /* 2c6d59f03SAndy Yan * SFC driver for rockchip 3c1cd6cb6SAndy Yan * 4c6d59f03SAndy Yan * (C) Copyright 2017 Rockchip Electronics Co., Ltd 5c1cd6cb6SAndy Yan * Yifeng.zhao, Software Engineering, <zhao0116@gmail.com>. 6c1cd6cb6SAndy Yan * 7c1cd6cb6SAndy Yan * SPDX-License-Identifier: GPL-2.0+ 8c1cd6cb6SAndy Yan */ 9c1cd6cb6SAndy Yan 10c1cd6cb6SAndy Yan #include <common.h> 1137911cf6SAndy Yan #include <bouncebuf.h> 12c1cd6cb6SAndy Yan #include <clk.h> 13c1cd6cb6SAndy Yan #include <dm.h> 14c1cd6cb6SAndy Yan #include <dt-structs.h> 15c1cd6cb6SAndy Yan #include <errno.h> 16c1cd6cb6SAndy Yan #include <spi.h> 17c1cd6cb6SAndy Yan #include <linux/errno.h> 18c1cd6cb6SAndy Yan #include <asm/io.h> 19c1cd6cb6SAndy Yan #include <asm/arch/clock.h> 20c1cd6cb6SAndy Yan #include <asm/arch/periph.h> 21c1cd6cb6SAndy Yan #include <dm/pinctrl.h> 22c1cd6cb6SAndy Yan 23c1cd6cb6SAndy Yan DECLARE_GLOBAL_DATA_PTR; 24c1cd6cb6SAndy Yan 2539b850deSJon Lin #ifdef SFC_DEBUG 2639b850deSJon Lin #define SFC_DBG printf 2739b850deSJon Lin #else 2839b850deSJon Lin #define SFC_DBG(args...) 2939b850deSJon Lin #endif 3039b850deSJon Lin 31c6d59f03SAndy Yan struct rockchip_sfc_reg { 32c6d59f03SAndy Yan u32 ctrl; 33c6d59f03SAndy Yan u32 imr; 34c6d59f03SAndy Yan u32 iclr; 35c6d59f03SAndy Yan u32 ftlr; 36c6d59f03SAndy Yan u32 rcvr; 37c6d59f03SAndy Yan u32 ax; 38c6d59f03SAndy Yan u32 abit; 39c6d59f03SAndy Yan u32 isr; 40c6d59f03SAndy Yan u32 fsr; 41c6d59f03SAndy Yan u32 sr; 42c6d59f03SAndy Yan u32 risr; 43c6d59f03SAndy Yan u32 reserved[21]; 44c6d59f03SAndy Yan u32 dmatr; 45c6d59f03SAndy Yan u32 dmaaddr; 46c6d59f03SAndy Yan u32 reserved1[30]; 47c6d59f03SAndy Yan u32 cmd; 48c6d59f03SAndy Yan u32 addr; 49c6d59f03SAndy Yan u32 data; 50c6d59f03SAndy Yan }; 5139b850deSJon Lin 52c6d59f03SAndy Yan check_member(rockchip_sfc_reg, data, 0x108); 53c6d59f03SAndy Yan 54c6d59f03SAndy Yan /*SFC_CTRL*/ 55c6d59f03SAndy Yan #define SFC_DATA_WIDTH_SHIFT 12 56c6d59f03SAndy Yan #define SFC_DATA_WIDTH_MASK GENMASK(13, 12) 57c6d59f03SAndy Yan #define SFC_ADDR_WIDTH_SHIFT 10 58c6d59f03SAndy Yan #define SFC_ADDR_WIDTH_MASK GENMASK(11, 10) 59c6d59f03SAndy Yan #define SFC_CMD_WIDTH_SHIFT 8 60c6d59f03SAndy Yan #define SFC_CMD_WIDTH_MASK GENMASK(9, 8) 61c6d59f03SAndy Yan #define SFC_DATA_SHIFT_NEGETIVE BIT(1) 62c6d59f03SAndy Yan 63c6d59f03SAndy Yan /*SFC_CMD*/ 64c6d59f03SAndy Yan #define SFC_DUMMY_BITS_SHIFT 8 65c6d59f03SAndy Yan #define SFC_RW_SHIFT 12 66c6d59f03SAndy Yan #define SFC_WR 1 67c6d59f03SAndy Yan #define SFC_RD 0 68c6d59f03SAndy Yan #define SFC_ADDR_BITS_SHIFT 14 69c6d59f03SAndy Yan #define SFC_ADDR_BITS_MASK GENMASK(15, 14) 70c6d59f03SAndy Yan #define SFC_ADDR_0BITS 0 71c6d59f03SAndy Yan #define SFC_ADDR_24BITS 1 72c6d59f03SAndy Yan #define SFC_ADDR_32BITS 2 73c6d59f03SAndy Yan #define SFC_ADDR_XBITS 3 74c6d59f03SAndy Yan #define SFC_TRB_SHIFT (16) 75c6d59f03SAndy Yan #define SFC_TRB_MASK GENMASK(29, 16) 76c6d59f03SAndy Yan 77c6d59f03SAndy Yan /* Dma start trigger signal. Auto cleared after write */ 78c6d59f03SAndy Yan #define SFC_DMA_START BIT(0) 79c6d59f03SAndy Yan 80c6d59f03SAndy Yan #define SFC_RESET BIT(0) 81c6d59f03SAndy Yan 82c6d59f03SAndy Yan /*SFC_FSR*/ 83c6d59f03SAndy Yan #define SFC_RXLV_SHIFT (16) 84c6d59f03SAndy Yan #define SFC_RXLV_MASK GENMASK(20, 16) 85c6d59f03SAndy Yan #define SFC_TXLV_SHIFT (8) 86c6d59f03SAndy Yan #define SFC_TXLV_MASK GENMASK(12, 8) 87c6d59f03SAndy Yan #define SFC_RX_FULL BIT(3) /* rx fifo full */ 88c6d59f03SAndy Yan #define SFC_RX_EMPTY BIT(2) /* rx fifo empty */ 89c6d59f03SAndy Yan #define SFC_TX_EMPTY BIT(1) /* tx fifo empty */ 90c6d59f03SAndy Yan #define SFC_TX_FULL BIT(0) /* tx fifo full */ 91c6d59f03SAndy Yan 92c6d59f03SAndy Yan #define SFC_BUSY BIT(0) /* sfc busy flag */ 93c6d59f03SAndy Yan 94c6d59f03SAndy Yan /*SFC_RISR*/ 95c6d59f03SAndy Yan #define DMA_FINISH_INT BIT(7) /* dma interrupt */ 96c6d59f03SAndy Yan #define SPI_ERR_INT BIT(6) /* Nspi error interrupt */ 97c6d59f03SAndy Yan #define AHB_ERR_INT BIT(5) /* Ahb bus error interrupt */ 98c6d59f03SAndy Yan #define TRANS_FINISH_INT BIT(4) /* Transfer finish interrupt */ 99c6d59f03SAndy Yan #define TX_EMPTY_INT BIT(3) /* Tx fifo empty interrupt */ 100c6d59f03SAndy Yan #define TX_OF_INT BIT(2) /* Tx fifo overflow interrupt */ 101c6d59f03SAndy Yan #define RX_UF_INT BIT(1) /* Rx fifo underflow interrupt */ 102c6d59f03SAndy Yan #define RX_FULL_INT BIT(0) /* Rx fifo full interrupt */ 103c6d59f03SAndy Yan 104c6d59f03SAndy Yan #define SFC_MAX_TRB (512 * 31) 105c6d59f03SAndy Yan 106ae52cbcbSJon Lin #define SFC_MAX_RATE (150 * 1000 * 1000) 107ae52cbcbSJon Lin #define SFC_DEFAULT_RATE (80 * 1000 * 1000) 108ae52cbcbSJon Lin #define SFC_MIN_RATE (10 * 1000 * 1000) 109ae52cbcbSJon Lin 110c1cd6cb6SAndy Yan enum rockchip_sfc_if_type { 111c1cd6cb6SAndy Yan IF_TYPE_STD, 112c1cd6cb6SAndy Yan IF_TYPE_DUAL, 113c1cd6cb6SAndy Yan IF_TYPE_QUAD, 114c1cd6cb6SAndy Yan }; 115c1cd6cb6SAndy Yan 116c1cd6cb6SAndy Yan struct rockchip_sfc_platdata { 117c1cd6cb6SAndy Yan s32 frequency; 11814b86dc9SJon Lin void *base; 119c1cd6cb6SAndy Yan }; 120c1cd6cb6SAndy Yan 121c1cd6cb6SAndy Yan struct rockchip_sfc { 122c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regbase; 123c1cd6cb6SAndy Yan struct clk clk; 124c1cd6cb6SAndy Yan unsigned int max_freq; 125c1cd6cb6SAndy Yan unsigned int mode; 126c1cd6cb6SAndy Yan unsigned int speed_hz; 127c1cd6cb6SAndy Yan u32 cmd; 128c1cd6cb6SAndy Yan u32 addr; 129da4954b7SAndy Yan u8 addr_bits; 13088ea3acbSJon Lin u8 addr_xbits_ext; 131da4954b7SAndy Yan u8 dummy_bits; 132da4954b7SAndy Yan u8 rw; 133da4954b7SAndy Yan u32 trb; 134c1cd6cb6SAndy Yan }; 135c1cd6cb6SAndy Yan 136c1cd6cb6SAndy Yan static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus) 137c1cd6cb6SAndy Yan { 138c1cd6cb6SAndy Yan struct rockchip_sfc_platdata *plat = dev_get_platdata(bus); 139c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 14014b86dc9SJon Lin ofnode subnode; 141c1cd6cb6SAndy Yan int ret; 142c1cd6cb6SAndy Yan 14314b86dc9SJon Lin plat->base = dev_read_addr_ptr(bus); 144c1cd6cb6SAndy Yan ret = clk_get_by_index(bus, 0, &sfc->clk); 145c1cd6cb6SAndy Yan if (ret < 0) { 14614b86dc9SJon Lin printf("Could not get clock for %s: %d\n", bus->name, ret); 147c1cd6cb6SAndy Yan return ret; 148c1cd6cb6SAndy Yan } 149c1cd6cb6SAndy Yan 15014b86dc9SJon Lin subnode = dev_read_first_subnode(bus); 15114b86dc9SJon Lin if (!ofnode_valid(subnode)) { 15214b86dc9SJon Lin printf("Error: subnode with SPI flash config missing!\n"); 153c1cd6cb6SAndy Yan return -ENODEV; 154c1cd6cb6SAndy Yan } 155c1cd6cb6SAndy Yan 15614b86dc9SJon Lin plat->frequency = ofnode_read_u32_default(subnode, "spi-max-frequency", 157c1cd6cb6SAndy Yan 100000000); 158ae52cbcbSJon Lin if (plat->frequency > SFC_MAX_RATE || plat->frequency < SFC_MIN_RATE) 159ae52cbcbSJon Lin plat->frequency = SFC_DEFAULT_RATE; 160ae52cbcbSJon Lin sfc->max_freq = plat->frequency; 161c1cd6cb6SAndy Yan 162c1cd6cb6SAndy Yan return 0; 163c1cd6cb6SAndy Yan } 164c1cd6cb6SAndy Yan 165c1cd6cb6SAndy Yan static int rockchip_sfc_probe(struct udevice *bus) 166c1cd6cb6SAndy Yan { 167c1cd6cb6SAndy Yan struct rockchip_sfc_platdata *plat = dev_get_platdata(bus); 168c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 169ae52cbcbSJon Lin struct dm_spi_bus *dm_spi_bus; 170c1cd6cb6SAndy Yan 171ae52cbcbSJon Lin dm_spi_bus = bus->uclass_priv; 172ae52cbcbSJon Lin dm_spi_bus->max_hz = plat->frequency; 173c1cd6cb6SAndy Yan sfc->regbase = (struct rockchip_sfc_reg *)plat->base; 174c1cd6cb6SAndy Yan 175c1cd6cb6SAndy Yan return 0; 176c1cd6cb6SAndy Yan } 177c1cd6cb6SAndy Yan 178c1cd6cb6SAndy Yan static int rockchip_sfc_reset(struct rockchip_sfc *sfc) 179c1cd6cb6SAndy Yan { 180c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 181c1cd6cb6SAndy Yan int tbase = get_timer(0); 182c1cd6cb6SAndy Yan u32 rcvr; 183c1cd6cb6SAndy Yan int ret = 0; 184c1cd6cb6SAndy Yan 185c1cd6cb6SAndy Yan writel(SFC_RESET, ®s->rcvr); 186c1cd6cb6SAndy Yan do { 187c1cd6cb6SAndy Yan rcvr = readl(®s->rcvr); 188c1cd6cb6SAndy Yan if (get_timer(tbase) > 1000) { 189c1cd6cb6SAndy Yan debug("sfc reset timeout\n"); 190c1cd6cb6SAndy Yan ret = -ETIMEDOUT; 191c1cd6cb6SAndy Yan break; 192c1cd6cb6SAndy Yan } 193c1cd6cb6SAndy Yan udelay(1); 194c1cd6cb6SAndy Yan } while (rcvr); 195c1cd6cb6SAndy Yan 196c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 197c1cd6cb6SAndy Yan 198c1cd6cb6SAndy Yan debug("sfc reset\n"); 199c1cd6cb6SAndy Yan 200c1cd6cb6SAndy Yan return ret; 201c1cd6cb6SAndy Yan } 202c1cd6cb6SAndy Yan 203915fcf0cSAndy Yan /* The SFC_CTRL register is a global control register, 204915fcf0cSAndy Yan * when the controller is in busy state(SFC_SR), 205915fcf0cSAndy Yan * SFC_CTRL cannot be set. 206915fcf0cSAndy Yan */ 207915fcf0cSAndy Yan static int rockchip_sfc_wait_idle(struct rockchip_sfc *sfc, 208915fcf0cSAndy Yan u32 timeout_ms) 209915fcf0cSAndy Yan { 210915fcf0cSAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 211915fcf0cSAndy Yan unsigned long tbase = get_timer(0); 212915fcf0cSAndy Yan u32 sr, fsr; 213915fcf0cSAndy Yan 214915fcf0cSAndy Yan while (1) { 215915fcf0cSAndy Yan sr = readl(®s->sr); 216915fcf0cSAndy Yan fsr = readl(®s->fsr); 21739b850deSJon Lin if ((fsr & SFC_TX_EMPTY) && 21839b850deSJon Lin (fsr & SFC_RX_EMPTY) && 21939b850deSJon Lin !(sr & SFC_BUSY)) 220915fcf0cSAndy Yan break; 221915fcf0cSAndy Yan if (get_timer(tbase) > timeout_ms) { 222915fcf0cSAndy Yan printf("waite sfc idle timeout(sr:0x%08x fsr:0x%08x)\n", 223915fcf0cSAndy Yan sr, fsr); 224915fcf0cSAndy Yan rockchip_sfc_reset(sfc); 225915fcf0cSAndy Yan return -ETIMEDOUT; 226915fcf0cSAndy Yan } 227915fcf0cSAndy Yan udelay(100); 228915fcf0cSAndy Yan } 229915fcf0cSAndy Yan 230915fcf0cSAndy Yan return 0; 231915fcf0cSAndy Yan } 232915fcf0cSAndy Yan 233c1cd6cb6SAndy Yan static u8 rockchip_sfc_get_if_type(struct rockchip_sfc *sfc) 234c1cd6cb6SAndy Yan { 235c1cd6cb6SAndy Yan int type = IF_TYPE_STD; 236c1cd6cb6SAndy Yan 237da4954b7SAndy Yan if (sfc->rw == SFC_WR) { 238c1cd6cb6SAndy Yan if (sfc->mode & SPI_TX_QUAD) 239c1cd6cb6SAndy Yan type = IF_TYPE_QUAD; 240c1cd6cb6SAndy Yan else if (sfc->mode & SPI_TX_DUAL) 241c1cd6cb6SAndy Yan type = IF_TYPE_DUAL; 242c1cd6cb6SAndy Yan else 243c1cd6cb6SAndy Yan type = IF_TYPE_STD; 244c1cd6cb6SAndy Yan } else { 245c1cd6cb6SAndy Yan if (sfc->mode & SPI_RX_QUAD) 246c1cd6cb6SAndy Yan type = IF_TYPE_QUAD; 247c1cd6cb6SAndy Yan else if (sfc->mode & SPI_RX_DUAL) 248c1cd6cb6SAndy Yan type = IF_TYPE_DUAL; 249c1cd6cb6SAndy Yan else 250c1cd6cb6SAndy Yan type = IF_TYPE_STD; 251c1cd6cb6SAndy Yan } 252c1cd6cb6SAndy Yan 253c1cd6cb6SAndy Yan return type; 254c1cd6cb6SAndy Yan } 255c1cd6cb6SAndy Yan 256da4954b7SAndy Yan static void rockchip_sfc_setup_xfer(struct rockchip_sfc *sfc, u32 trb) 257c1cd6cb6SAndy Yan { 258c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 259c1cd6cb6SAndy Yan u32 val = 0x02; 260c1cd6cb6SAndy Yan u8 data_width = IF_TYPE_STD; 261c1cd6cb6SAndy Yan 26239b850deSJon Lin SFC_DBG("--- sfc.addr_bit %x\n", sfc->addr_bits); 26339b850deSJon Lin 26439b850deSJon Lin if (sfc->addr_bits == SFC_ADDR_24BITS || 26539b850deSJon Lin sfc->addr_bits == SFC_ADDR_32BITS) 266c1cd6cb6SAndy Yan data_width = rockchip_sfc_get_if_type(sfc); 267c1cd6cb6SAndy Yan 268*113ced8fSJon Lin if (sfc->addr_bits == SFC_ADDR_XBITS) 26988ea3acbSJon Lin writel(sfc->addr_xbits_ext - 1, ®s->abit); 27088ea3acbSJon Lin 271c1cd6cb6SAndy Yan val |= (data_width << SFC_DATA_WIDTH_SHIFT); 272c1cd6cb6SAndy Yan 273915fcf0cSAndy Yan rockchip_sfc_wait_idle(sfc, 10); 274915fcf0cSAndy Yan 27539b850deSJon Lin SFC_DBG("--- sfc.ctrl %x\n", val); 276c1cd6cb6SAndy Yan writel(val, ®s->ctrl); 277da4954b7SAndy Yan 278da4954b7SAndy Yan val = sfc->cmd; 279da4954b7SAndy Yan val |= trb << SFC_TRB_SHIFT; 280da4954b7SAndy Yan val |= sfc->rw << SFC_RW_SHIFT; 281da4954b7SAndy Yan val |= sfc->addr_bits << SFC_ADDR_BITS_SHIFT; 282da4954b7SAndy Yan val |= sfc->dummy_bits << SFC_DUMMY_BITS_SHIFT; 283da4954b7SAndy Yan 28439b850deSJon Lin SFC_DBG("--- sfc.cmd %x\n", val); 285da4954b7SAndy Yan writel(val, ®s->cmd); 286da4954b7SAndy Yan 28739b850deSJon Lin if (sfc->addr_bits & SFC_ADDR_XBITS) { 28839b850deSJon Lin SFC_DBG("--- sfc.addr %x\n", sfc->addr); 289c1cd6cb6SAndy Yan writel(sfc->addr, ®s->addr); 290c1cd6cb6SAndy Yan } 29139b850deSJon Lin } 292c1cd6cb6SAndy Yan 29330f161d1SAndy Yan static int rockchip_sfc_dma_xfer(struct rockchip_sfc *sfc, void *buffer, size_t trb) 294c1cd6cb6SAndy Yan { 295c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 29637911cf6SAndy Yan struct bounce_buffer bb; 29737911cf6SAndy Yan unsigned int bb_flags; 298c1cd6cb6SAndy Yan int timeout = 1000; 299c1cd6cb6SAndy Yan int ret = 0; 300c1cd6cb6SAndy Yan int risr; 301c1cd6cb6SAndy Yan unsigned long tbase; 302c1cd6cb6SAndy Yan 30337911cf6SAndy Yan if (sfc->rw == SFC_WR) 30437911cf6SAndy Yan bb_flags = GEN_BB_READ; 30537911cf6SAndy Yan else 30637911cf6SAndy Yan bb_flags = GEN_BB_WRITE; 30737911cf6SAndy Yan 30830f161d1SAndy Yan ret = bounce_buffer_start(&bb, buffer, trb, bb_flags); 30937911cf6SAndy Yan if (ret) 31037911cf6SAndy Yan return ret; 31130f161d1SAndy Yan 31237911cf6SAndy Yan rockchip_sfc_setup_xfer(sfc, bb.len_aligned); 313c1cd6cb6SAndy Yan 314c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 31514b86dc9SJon Lin writel((unsigned long)bb.bounce_buffer, ®s->dmaaddr); 316c1cd6cb6SAndy Yan writel(SFC_DMA_START, ®s->dmatr); 317c1cd6cb6SAndy Yan 318c1cd6cb6SAndy Yan tbase = get_timer(0); 319c1cd6cb6SAndy Yan do { 320c1cd6cb6SAndy Yan udelay(1); 321c1cd6cb6SAndy Yan risr = readl(®s->risr); 322c1cd6cb6SAndy Yan if (get_timer(tbase) > timeout) { 323c1cd6cb6SAndy Yan debug("dma timeout\n"); 324c1cd6cb6SAndy Yan ret = -ETIMEDOUT; 325c1cd6cb6SAndy Yan break; 326c1cd6cb6SAndy Yan } 327c1cd6cb6SAndy Yan } while (!(risr & TRANS_FINISH_INT)); 328c1cd6cb6SAndy Yan 329c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 330c1cd6cb6SAndy Yan 33137911cf6SAndy Yan bounce_buffer_stop(&bb); 33237911cf6SAndy Yan 333c1cd6cb6SAndy Yan return ret; 334c1cd6cb6SAndy Yan } 335c1cd6cb6SAndy Yan 336da4954b7SAndy Yan static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int rw, 337c1cd6cb6SAndy Yan u32 timeout) 338c1cd6cb6SAndy Yan { 339c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 340c1cd6cb6SAndy Yan unsigned long tbase = get_timer(0); 341c1cd6cb6SAndy Yan u8 level; 342c1cd6cb6SAndy Yan u32 fsr; 343c1cd6cb6SAndy Yan 344c1cd6cb6SAndy Yan do { 345c1cd6cb6SAndy Yan fsr = readl(®s->fsr); 346da4954b7SAndy Yan if (rw == SFC_WR) 347c1cd6cb6SAndy Yan level = (fsr & SFC_TXLV_MASK) >> SFC_TXLV_SHIFT; 348c1cd6cb6SAndy Yan else 349c1cd6cb6SAndy Yan level = (fsr & SFC_RXLV_MASK) >> SFC_RXLV_SHIFT; 350c1cd6cb6SAndy Yan if (get_timer(tbase) > timeout) 351c1cd6cb6SAndy Yan return -ETIMEDOUT; 352c1cd6cb6SAndy Yan udelay(1); 353c1cd6cb6SAndy Yan } while (!level); 354c1cd6cb6SAndy Yan 355c1cd6cb6SAndy Yan return level; 356c1cd6cb6SAndy Yan } 357c1cd6cb6SAndy Yan 358da4954b7SAndy Yan static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len) 359c1cd6cb6SAndy Yan { 360c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 361c1cd6cb6SAndy Yan u32 bytes = len & 0x3; 362c1cd6cb6SAndy Yan u32 words = len >> 2; 363915fcf0cSAndy Yan int tx_level = 0; 364c1cd6cb6SAndy Yan u32 val = 0; 365c1cd6cb6SAndy Yan u8 count; 366c1cd6cb6SAndy Yan 367c1cd6cb6SAndy Yan while (words) { 368da4954b7SAndy Yan tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000); 369c1cd6cb6SAndy Yan if (tx_level <= 0) 370c1cd6cb6SAndy Yan return tx_level; 371915fcf0cSAndy Yan count = min(words, (u32)tx_level); 372c1cd6cb6SAndy Yan writesl(®s->data, buf, count); 373c1cd6cb6SAndy Yan buf += count; 374c1cd6cb6SAndy Yan words -= count; 375c1cd6cb6SAndy Yan } 376c1cd6cb6SAndy Yan 377da4954b7SAndy Yan /* handle the last non 4byte aligned bytes */ 378c1cd6cb6SAndy Yan if (bytes) { 379da4954b7SAndy Yan tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000); 380c1cd6cb6SAndy Yan if (tx_level <= 0) 381c1cd6cb6SAndy Yan return tx_level; 382c1cd6cb6SAndy Yan memcpy(&val, buf, bytes); 383c1cd6cb6SAndy Yan writel(val, ®s->data); 384c1cd6cb6SAndy Yan } 385c1cd6cb6SAndy Yan 386c1cd6cb6SAndy Yan return 0; 387c1cd6cb6SAndy Yan } 388c1cd6cb6SAndy Yan 389da4954b7SAndy Yan static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len) 390c1cd6cb6SAndy Yan { 391c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 392c1cd6cb6SAndy Yan u32 bytes = len & 0x3; 393c1cd6cb6SAndy Yan u32 words = len >> 2; 394915fcf0cSAndy Yan int rx_level = 0; 395c1cd6cb6SAndy Yan u32 count; 396c1cd6cb6SAndy Yan u32 val; 397c1cd6cb6SAndy Yan 398c1cd6cb6SAndy Yan while (words) { 399da4954b7SAndy Yan rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000); 400c1cd6cb6SAndy Yan if (rx_level <= 0) 401c1cd6cb6SAndy Yan return rx_level; 402915fcf0cSAndy Yan count = min(words, (u32)rx_level); 403c1cd6cb6SAndy Yan readsl(®s->data, buf, count); 404c1cd6cb6SAndy Yan buf += count; 405c1cd6cb6SAndy Yan words -= count; 406c1cd6cb6SAndy Yan } 407c1cd6cb6SAndy Yan 408da4954b7SAndy Yan /* handle the last non 4 bytes aligned bytes */ 409c1cd6cb6SAndy Yan if (bytes) { 410da4954b7SAndy Yan rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000); 411c1cd6cb6SAndy Yan if (rx_level <= 0) 412c1cd6cb6SAndy Yan return rx_level; 413c1cd6cb6SAndy Yan val = readl(®s->data); 414c1cd6cb6SAndy Yan memcpy(buf, &val, bytes); 415c1cd6cb6SAndy Yan } 416c1cd6cb6SAndy Yan 417c1cd6cb6SAndy Yan return 0; 418c1cd6cb6SAndy Yan } 419c1cd6cb6SAndy Yan 42030f161d1SAndy Yan static int rockchip_sfc_pio_xfer(struct rockchip_sfc *sfc, void *buf, u32 len) 421c1cd6cb6SAndy Yan { 422c1cd6cb6SAndy Yan int ret = 0; 423c1cd6cb6SAndy Yan 424da4954b7SAndy Yan rockchip_sfc_setup_xfer(sfc, len); 42530f161d1SAndy Yan 426c1cd6cb6SAndy Yan if (len) { 427da4954b7SAndy Yan if (sfc->rw == SFC_WR) 42830f161d1SAndy Yan ret = rockchip_sfc_write_fifo(sfc, (u32 *)buf, len); 429c1cd6cb6SAndy Yan else 43030f161d1SAndy Yan ret = rockchip_sfc_read_fifo(sfc, (u32 *)buf, len); 431c1cd6cb6SAndy Yan } 432c1cd6cb6SAndy Yan 433c1cd6cb6SAndy Yan return ret; 434c1cd6cb6SAndy Yan } 435c1cd6cb6SAndy Yan 43630f161d1SAndy Yan static int rockchip_sfc_read(struct rockchip_sfc *sfc, u32 offset, 43730f161d1SAndy Yan void *buf, size_t len) 438c1cd6cb6SAndy Yan { 4396bf64646SAndy Yan u32 dma_trans; 44030f161d1SAndy Yan u32 trb; 44130f161d1SAndy Yan u8 bytes; 44230f161d1SAndy Yan int ret; 443c1cd6cb6SAndy Yan 44437911cf6SAndy Yan if (len >= ARCH_DMA_MINALIGN) { 44530f161d1SAndy Yan bytes = len & (ARCH_DMA_MINALIGN - 1); 4466bf64646SAndy Yan dma_trans = len - bytes; 4476bf64646SAndy Yan } else { 4486bf64646SAndy Yan dma_trans = 0; 4496bf64646SAndy Yan bytes = len; 4506bf64646SAndy Yan } 4516bf64646SAndy Yan 45230f161d1SAndy Yan while (dma_trans) { 45330f161d1SAndy Yan trb = min_t(size_t, dma_trans, SFC_MAX_TRB); 45430f161d1SAndy Yan ret = rockchip_sfc_dma_xfer(sfc, buf, trb); 45530f161d1SAndy Yan if (ret < 0) 45630f161d1SAndy Yan return ret; 45730f161d1SAndy Yan dma_trans -= trb; 45830f161d1SAndy Yan sfc->addr += trb; 45930f161d1SAndy Yan buf += trb; 4606bf64646SAndy Yan } 4616bf64646SAndy Yan 4626bf64646SAndy Yan /* 46330f161d1SAndy Yan * transfer the last non dma anligned byte by pio mode 4646bf64646SAndy Yan */ 46530f161d1SAndy Yan if (bytes) 4666bf64646SAndy Yan ret = rockchip_sfc_pio_xfer(sfc, buf, bytes); 467c1cd6cb6SAndy Yan 46830f161d1SAndy Yan return 0; 46930f161d1SAndy Yan } 47030f161d1SAndy Yan 47130f161d1SAndy Yan static int rockchip_sfc_write(struct rockchip_sfc *sfc, u32 offset, 47230f161d1SAndy Yan void *buf, size_t len) 47330f161d1SAndy Yan { 47430f161d1SAndy Yan if (len > SFC_MAX_TRB) { 47530f161d1SAndy Yan printf("out of the max sfc trb"); 47630f161d1SAndy Yan return -EINVAL; 47730f161d1SAndy Yan } 47830f161d1SAndy Yan 47930f161d1SAndy Yan if (len && !(len & (ARCH_DMA_MINALIGN - 1))) 48030f161d1SAndy Yan return rockchip_sfc_dma_xfer(sfc, buf, len); 48130f161d1SAndy Yan else 48230f161d1SAndy Yan return rockchip_sfc_pio_xfer(sfc, buf, len); 48330f161d1SAndy Yan 48430f161d1SAndy Yan return 0; 48530f161d1SAndy Yan } 48630f161d1SAndy Yan 48730f161d1SAndy Yan static int rockchip_sfc_do_xfer(struct rockchip_sfc *sfc, void *buf, size_t len) 48830f161d1SAndy Yan { 48930f161d1SAndy Yan if (sfc->rw) 49030f161d1SAndy Yan return rockchip_sfc_write(sfc, sfc->addr, buf, len); 49130f161d1SAndy Yan else 49230f161d1SAndy Yan return rockchip_sfc_read(sfc, sfc->addr, buf, len); 493c1cd6cb6SAndy Yan } 494c1cd6cb6SAndy Yan 495c1cd6cb6SAndy Yan static int rockchip_sfc_xfer(struct udevice *dev, unsigned int bitlen, 496c1cd6cb6SAndy Yan const void *dout, void *din, unsigned long flags) 497c1cd6cb6SAndy Yan { 498c1cd6cb6SAndy Yan struct udevice *bus = dev->parent; 499c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 500c1cd6cb6SAndy Yan int len = bitlen >> 3; 501c1cd6cb6SAndy Yan u8 *pcmd = (u8 *)dout; 50230f161d1SAndy Yan void *data_buf; 503c1cd6cb6SAndy Yan int ret = 0; 504c1cd6cb6SAndy Yan 505c1cd6cb6SAndy Yan if (flags & SPI_XFER_BEGIN) { 506c1cd6cb6SAndy Yan sfc->cmd = pcmd[0]; 5076e121371SJon Lin switch (len) { 5086e121371SJon Lin case 6: /* Nor >16MB 0x6b dummy op */ 5096e121371SJon Lin sfc->addr_bits = SFC_ADDR_32BITS; 5106e121371SJon Lin sfc->dummy_bits = 8; 5116e121371SJon Lin sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24); 5126e121371SJon Lin break; 5136e121371SJon Lin case 5: /* Nor <=16MB 0x6b dummy op, Nor >16MB no dummy op */ 51498730755SJon Lin if (sfc->cmd == 0x6b) { 51598730755SJon Lin sfc->addr_bits = SFC_ADDR_24BITS; 51698730755SJon Lin sfc->dummy_bits = 8; 51798730755SJon Lin sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16); 51898730755SJon Lin } else { 5196e121371SJon Lin sfc->addr_bits = SFC_ADDR_32BITS; 5206e121371SJon Lin sfc->dummy_bits = 0; 5216e121371SJon Lin sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24); 52298730755SJon Lin } 5236e121371SJon Lin break; 5246e121371SJon Lin case 4: /* Nand erase and read, Nor <=16MB no dummy op */ 5256e121371SJon Lin sfc->addr_bits = SFC_ADDR_24BITS; 5266e121371SJon Lin sfc->dummy_bits = 0; 527c1cd6cb6SAndy Yan sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16); 5286e121371SJon Lin break; 5296e121371SJon Lin case 3: /* Nand prog, */ 5306e121371SJon Lin sfc->addr_bits = SFC_ADDR_XBITS; 53188ea3acbSJon Lin sfc->addr_xbits_ext = 16; 53239b850deSJon Lin sfc->dummy_bits = 0; 53339b850deSJon Lin sfc->addr = pcmd[2] | pcmd[1] << 8; 5346e121371SJon Lin break; 5356e121371SJon Lin case 2: /* Nand read/write feature */ 5366e121371SJon Lin sfc->addr_bits = SFC_ADDR_XBITS; 53788ea3acbSJon Lin sfc->addr_xbits_ext = 8; 53839b850deSJon Lin sfc->dummy_bits = 0; 53939b850deSJon Lin sfc->addr = pcmd[1]; 5406e121371SJon Lin break; 5416e121371SJon Lin default: /* Nand/Nor Read/Write status */ 5426e121371SJon Lin sfc->addr_bits = SFC_ADDR_0BITS; 543da4954b7SAndy Yan sfc->dummy_bits = 0; 544da4954b7SAndy Yan sfc->addr = 0; 5456e121371SJon Lin break; 546c1cd6cb6SAndy Yan } 5476e121371SJon Lin SFC_DBG("%s %d %x %d %d %x\n", __func__, len, sfc->cmd, sfc->addr_bits, 5486e121371SJon Lin sfc->dummy_bits, sfc->addr); 549c1cd6cb6SAndy Yan } 550c1cd6cb6SAndy Yan if (flags & SPI_XFER_END) { 551da4954b7SAndy Yan if (din) { 552da4954b7SAndy Yan sfc->rw = SFC_RD; 55330f161d1SAndy Yan data_buf = din; 55430f161d1SAndy Yan } else { 555da4954b7SAndy Yan sfc->rw = SFC_WR; 55630f161d1SAndy Yan data_buf = (void *)dout; 557c1cd6cb6SAndy Yan } 55830f161d1SAndy Yan 55930f161d1SAndy Yan if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) { 56030f161d1SAndy Yan len = 0; 56130f161d1SAndy Yan data_buf = NULL; 56230f161d1SAndy Yan } 56330f161d1SAndy Yan 56430f161d1SAndy Yan ret = rockchip_sfc_do_xfer(sfc, data_buf, len); 565da4954b7SAndy Yan } 566c1cd6cb6SAndy Yan 567c1cd6cb6SAndy Yan return ret; 568c1cd6cb6SAndy Yan } 569c1cd6cb6SAndy Yan 570c1cd6cb6SAndy Yan static int rockchip_sfc_set_speed(struct udevice *bus, uint speed) 571c1cd6cb6SAndy Yan { 572c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 573c1cd6cb6SAndy Yan 574c1cd6cb6SAndy Yan if (speed > sfc->max_freq) 575c1cd6cb6SAndy Yan speed = sfc->max_freq; 576c1cd6cb6SAndy Yan 577c1cd6cb6SAndy Yan sfc->speed_hz = speed; 578ae52cbcbSJon Lin clk_set_rate(&sfc->clk, sfc->speed_hz); 579ae52cbcbSJon Lin SFC_DBG("%s clk= %ld\n", __func__, clk_get_rate(&sfc->clk)); 580c1cd6cb6SAndy Yan 581c1cd6cb6SAndy Yan return 0; 582c1cd6cb6SAndy Yan } 583c1cd6cb6SAndy Yan 584c1cd6cb6SAndy Yan static int rockchip_sfc_set_mode(struct udevice *bus, uint mode) 585c1cd6cb6SAndy Yan { 586c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 587c1cd6cb6SAndy Yan 588c1cd6cb6SAndy Yan sfc->mode = mode; 589c1cd6cb6SAndy Yan 590c1cd6cb6SAndy Yan return 0; 591c1cd6cb6SAndy Yan } 592c1cd6cb6SAndy Yan 593c1cd6cb6SAndy Yan static const struct dm_spi_ops rockchip_sfc_ops = { 594c1cd6cb6SAndy Yan .xfer = rockchip_sfc_xfer, 595c1cd6cb6SAndy Yan .set_speed = rockchip_sfc_set_speed, 596c1cd6cb6SAndy Yan .set_mode = rockchip_sfc_set_mode, 597c1cd6cb6SAndy Yan }; 598c1cd6cb6SAndy Yan 599c1cd6cb6SAndy Yan static const struct udevice_id rockchip_sfc_ids[] = { 600c1cd6cb6SAndy Yan { .compatible = "rockchip,sfc" }, 601c1cd6cb6SAndy Yan { } 602c1cd6cb6SAndy Yan }; 603c1cd6cb6SAndy Yan 604c1cd6cb6SAndy Yan U_BOOT_DRIVER(rockchip_sfc_driver) = { 605c1cd6cb6SAndy Yan .name = "rockchip_sfc", 606c1cd6cb6SAndy Yan .id = UCLASS_SPI, 607c1cd6cb6SAndy Yan .of_match = rockchip_sfc_ids, 608c1cd6cb6SAndy Yan .ops = &rockchip_sfc_ops, 609c1cd6cb6SAndy Yan .ofdata_to_platdata = rockchip_sfc_ofdata_to_platdata, 610c1cd6cb6SAndy Yan .platdata_auto_alloc_size = sizeof(struct rockchip_sfc_platdata), 611c1cd6cb6SAndy Yan .priv_auto_alloc_size = sizeof(struct rockchip_sfc), 612c1cd6cb6SAndy Yan .probe = rockchip_sfc_probe, 613c1cd6cb6SAndy Yan }; 614