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; 43fa413375SJon Lin u32 ver; 44fa413375SJon Lin u32 reserved[20]; 45c6d59f03SAndy Yan u32 dmatr; 46c6d59f03SAndy Yan u32 dmaaddr; 47fa413375SJon Lin u32 len_ctrl; 48fa413375SJon Lin u32 len_ext; 49fa413375SJon Lin u32 reserved1[28]; 50c6d59f03SAndy Yan u32 cmd; 51c6d59f03SAndy Yan u32 addr; 52c6d59f03SAndy Yan u32 data; 53c6d59f03SAndy Yan }; 5439b850deSJon Lin 55c6d59f03SAndy Yan check_member(rockchip_sfc_reg, data, 0x108); 56c6d59f03SAndy Yan 57c6d59f03SAndy Yan /*SFC_CTRL*/ 58c6d59f03SAndy Yan #define SFC_DATA_WIDTH_SHIFT 12 59c6d59f03SAndy Yan #define SFC_DATA_WIDTH_MASK GENMASK(13, 12) 60c6d59f03SAndy Yan #define SFC_ADDR_WIDTH_SHIFT 10 61c6d59f03SAndy Yan #define SFC_ADDR_WIDTH_MASK GENMASK(11, 10) 62c6d59f03SAndy Yan #define SFC_CMD_WIDTH_SHIFT 8 63c6d59f03SAndy Yan #define SFC_CMD_WIDTH_MASK GENMASK(9, 8) 64c6d59f03SAndy Yan #define SFC_DATA_SHIFT_NEGETIVE BIT(1) 65c6d59f03SAndy Yan 66c6d59f03SAndy Yan /*SFC_CMD*/ 67c6d59f03SAndy Yan #define SFC_DUMMY_BITS_SHIFT 8 68c6d59f03SAndy Yan #define SFC_RW_SHIFT 12 69c6d59f03SAndy Yan #define SFC_WR 1 70c6d59f03SAndy Yan #define SFC_RD 0 71c6d59f03SAndy Yan #define SFC_ADDR_BITS_SHIFT 14 72c6d59f03SAndy Yan #define SFC_ADDR_BITS_MASK GENMASK(15, 14) 73c6d59f03SAndy Yan #define SFC_ADDR_0BITS 0 74c6d59f03SAndy Yan #define SFC_ADDR_24BITS 1 75c6d59f03SAndy Yan #define SFC_ADDR_32BITS 2 76c6d59f03SAndy Yan #define SFC_ADDR_XBITS 3 77c6d59f03SAndy Yan #define SFC_TRB_SHIFT (16) 78c6d59f03SAndy Yan #define SFC_TRB_MASK GENMASK(29, 16) 79c6d59f03SAndy Yan 80c6d59f03SAndy Yan /* Dma start trigger signal. Auto cleared after write */ 81c6d59f03SAndy Yan #define SFC_DMA_START BIT(0) 82c6d59f03SAndy Yan 83c6d59f03SAndy Yan #define SFC_RESET BIT(0) 84c6d59f03SAndy Yan 85c6d59f03SAndy Yan /*SFC_FSR*/ 86c6d59f03SAndy Yan #define SFC_RXLV_SHIFT (16) 87c6d59f03SAndy Yan #define SFC_RXLV_MASK GENMASK(20, 16) 88c6d59f03SAndy Yan #define SFC_TXLV_SHIFT (8) 89c6d59f03SAndy Yan #define SFC_TXLV_MASK GENMASK(12, 8) 90c6d59f03SAndy Yan #define SFC_RX_FULL BIT(3) /* rx fifo full */ 91c6d59f03SAndy Yan #define SFC_RX_EMPTY BIT(2) /* rx fifo empty */ 92c6d59f03SAndy Yan #define SFC_TX_EMPTY BIT(1) /* tx fifo empty */ 93c6d59f03SAndy Yan #define SFC_TX_FULL BIT(0) /* tx fifo full */ 94c6d59f03SAndy Yan 95c6d59f03SAndy Yan #define SFC_BUSY BIT(0) /* sfc busy flag */ 96c6d59f03SAndy Yan 97c6d59f03SAndy Yan /*SFC_RISR*/ 98c6d59f03SAndy Yan #define DMA_FINISH_INT BIT(7) /* dma interrupt */ 99c6d59f03SAndy Yan #define SPI_ERR_INT BIT(6) /* Nspi error interrupt */ 100c6d59f03SAndy Yan #define AHB_ERR_INT BIT(5) /* Ahb bus error interrupt */ 101c6d59f03SAndy Yan #define TRANS_FINISH_INT BIT(4) /* Transfer finish interrupt */ 102c6d59f03SAndy Yan #define TX_EMPTY_INT BIT(3) /* Tx fifo empty interrupt */ 103c6d59f03SAndy Yan #define TX_OF_INT BIT(2) /* Tx fifo overflow interrupt */ 104c6d59f03SAndy Yan #define RX_UF_INT BIT(1) /* Rx fifo underflow interrupt */ 105c6d59f03SAndy Yan #define RX_FULL_INT BIT(0) /* Rx fifo full interrupt */ 106c6d59f03SAndy Yan 107fa413375SJon Lin #define SFC_MAX_TRB_VER3 (512 * 31) 108fa413375SJon Lin #define SFC_MAX_TRB_VER4 (0xFFFFFFFF) 109c6d59f03SAndy Yan 11065c35614SJon Lin #define SFC_MAX_RATE (100 * 1000 * 1000) 111ae52cbcbSJon Lin #define SFC_DEFAULT_RATE (80 * 1000 * 1000) 112ae52cbcbSJon Lin #define SFC_MIN_RATE (10 * 1000 * 1000) 113ae52cbcbSJon Lin 114fa413375SJon Lin #define SFC_VER_3 0x3 115fa413375SJon Lin #define SFC_VER_4 0x4 116fa413375SJon Lin 117c1cd6cb6SAndy Yan enum rockchip_sfc_if_type { 118c1cd6cb6SAndy Yan IF_TYPE_STD, 119c1cd6cb6SAndy Yan IF_TYPE_DUAL, 120c1cd6cb6SAndy Yan IF_TYPE_QUAD, 121c1cd6cb6SAndy Yan }; 122c1cd6cb6SAndy Yan 123c1cd6cb6SAndy Yan struct rockchip_sfc_platdata { 124c1cd6cb6SAndy Yan s32 frequency; 12514b86dc9SJon Lin void *base; 126c1cd6cb6SAndy Yan }; 127c1cd6cb6SAndy Yan 128c1cd6cb6SAndy Yan struct rockchip_sfc { 129c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regbase; 130c1cd6cb6SAndy Yan struct clk clk; 131c1cd6cb6SAndy Yan unsigned int max_freq; 132c1cd6cb6SAndy Yan unsigned int mode; 133c1cd6cb6SAndy Yan unsigned int speed_hz; 134fa413375SJon Lin u32 max_iosize; 1357ddc1c35SJon Lin bool prepare; 1367ddc1c35SJon Lin u32 last_prepare_size; 137c1cd6cb6SAndy Yan u32 cmd; 138c1cd6cb6SAndy Yan u32 addr; 139da4954b7SAndy Yan u8 addr_bits; 14088ea3acbSJon Lin u8 addr_xbits_ext; 141da4954b7SAndy Yan u8 dummy_bits; 142da4954b7SAndy Yan u8 rw; 143da4954b7SAndy Yan u32 trb; 144c1cd6cb6SAndy Yan }; 145c1cd6cb6SAndy Yan 146c1cd6cb6SAndy Yan static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus) 147c1cd6cb6SAndy Yan { 148c1cd6cb6SAndy Yan struct rockchip_sfc_platdata *plat = dev_get_platdata(bus); 149*5b4dcfe0SJason Zhu 150*5b4dcfe0SJason Zhu plat->base = dev_read_addr_ptr(bus); 151*5b4dcfe0SJason Zhu #if CONFIG_IS_ENABLED(CLK) 152c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 153c1cd6cb6SAndy Yan int ret; 154c1cd6cb6SAndy Yan 155c1cd6cb6SAndy Yan ret = clk_get_by_index(bus, 0, &sfc->clk); 156c1cd6cb6SAndy Yan if (ret < 0) { 15714b86dc9SJon Lin printf("Could not get clock for %s: %d\n", bus->name, ret); 158c1cd6cb6SAndy Yan return ret; 159c1cd6cb6SAndy Yan } 160*5b4dcfe0SJason Zhu #endif 161c1cd6cb6SAndy Yan 162c1cd6cb6SAndy Yan return 0; 163c1cd6cb6SAndy Yan } 164c1cd6cb6SAndy Yan 165fa413375SJon Lin u32 rockchip_sfc_get_version(struct rockchip_sfc *sfc) 166fa413375SJon Lin { 167fa413375SJon Lin struct rockchip_sfc_reg *regs = sfc->regbase; 168fa413375SJon Lin 169fa413375SJon Lin return (u32)(readl(®s->ver) & 0xFFFF); 170fa413375SJon Lin } 171fa413375SJon Lin 172c1cd6cb6SAndy Yan static int rockchip_sfc_probe(struct udevice *bus) 173c1cd6cb6SAndy Yan { 174c1cd6cb6SAndy Yan struct rockchip_sfc_platdata *plat = dev_get_platdata(bus); 175c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 176fa413375SJon Lin struct rockchip_sfc_reg *regs; 177ae52cbcbSJon Lin struct dm_spi_bus *dm_spi_bus; 178c1cd6cb6SAndy Yan 179ae52cbcbSJon Lin dm_spi_bus = bus->uclass_priv; 180ae52cbcbSJon Lin dm_spi_bus->max_hz = plat->frequency; 181c1cd6cb6SAndy Yan sfc->regbase = (struct rockchip_sfc_reg *)plat->base; 18231e5d7a3SJon Lin sfc->max_freq = SFC_MAX_RATE; 18331e5d7a3SJon Lin sfc->speed_hz = SFC_DEFAULT_RATE; 184*5b4dcfe0SJason Zhu #if CONFIG_IS_ENABLED(CLK) 18531e5d7a3SJon Lin clk_set_rate(&sfc->clk, sfc->speed_hz); 186*5b4dcfe0SJason Zhu #endif 187fa413375SJon Lin regs = sfc->regbase; 188fa413375SJon Lin if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) { 189fa413375SJon Lin sfc->max_iosize = SFC_MAX_TRB_VER4; 190fa413375SJon Lin writel(1, ®s->len_ctrl); 191fa413375SJon Lin } else { 192fa413375SJon Lin sfc->max_iosize = SFC_MAX_TRB_VER3; 193fa413375SJon Lin } 194fa413375SJon Lin 195c1cd6cb6SAndy Yan return 0; 196c1cd6cb6SAndy Yan } 197c1cd6cb6SAndy Yan 198c1cd6cb6SAndy Yan static int rockchip_sfc_reset(struct rockchip_sfc *sfc) 199c1cd6cb6SAndy Yan { 200c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 201c1cd6cb6SAndy Yan int tbase = get_timer(0); 202c1cd6cb6SAndy Yan u32 rcvr; 203c1cd6cb6SAndy Yan int ret = 0; 204c1cd6cb6SAndy Yan 205c1cd6cb6SAndy Yan writel(SFC_RESET, ®s->rcvr); 206c1cd6cb6SAndy Yan do { 207c1cd6cb6SAndy Yan rcvr = readl(®s->rcvr); 208c1cd6cb6SAndy Yan if (get_timer(tbase) > 1000) { 209c1cd6cb6SAndy Yan debug("sfc reset timeout\n"); 210c1cd6cb6SAndy Yan ret = -ETIMEDOUT; 211c1cd6cb6SAndy Yan break; 212c1cd6cb6SAndy Yan } 213c1cd6cb6SAndy Yan udelay(1); 214c1cd6cb6SAndy Yan } while (rcvr); 215c1cd6cb6SAndy Yan 216c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 217c1cd6cb6SAndy Yan 218c1cd6cb6SAndy Yan debug("sfc reset\n"); 219c1cd6cb6SAndy Yan 220c1cd6cb6SAndy Yan return ret; 221c1cd6cb6SAndy Yan } 222c1cd6cb6SAndy Yan 2237ddc1c35SJon Lin static int rockchip_sfc_dma_xfer_wait_finished(struct rockchip_sfc *sfc) 2247ddc1c35SJon Lin { 2257ddc1c35SJon Lin struct rockchip_sfc_reg *regs = sfc->regbase; 2267ddc1c35SJon Lin int timeout = sfc->last_prepare_size * 10; 2277ddc1c35SJon Lin unsigned long tbase; 2287ddc1c35SJon Lin int ret = 0; 2297ddc1c35SJon Lin int risr; 2307ddc1c35SJon Lin 2317ddc1c35SJon Lin tbase = get_timer(0); 2327ddc1c35SJon Lin do { 2337ddc1c35SJon Lin udelay(1); 2347ddc1c35SJon Lin risr = readl(®s->risr); 2357ddc1c35SJon Lin if (get_timer(tbase) > timeout) { 2367ddc1c35SJon Lin debug("dma timeout\n"); 2377ddc1c35SJon Lin ret = -ETIMEDOUT; 2387ddc1c35SJon Lin break; 2397ddc1c35SJon Lin } 2407ddc1c35SJon Lin } while (!(risr & TRANS_FINISH_INT)); 2417ddc1c35SJon Lin sfc->last_prepare_size = 0; 2427ddc1c35SJon Lin 2437ddc1c35SJon Lin return ret; 2447ddc1c35SJon Lin } 2457ddc1c35SJon Lin 246915fcf0cSAndy Yan /* The SFC_CTRL register is a global control register, 247915fcf0cSAndy Yan * when the controller is in busy state(SFC_SR), 248915fcf0cSAndy Yan * SFC_CTRL cannot be set. 249915fcf0cSAndy Yan */ 250915fcf0cSAndy Yan static int rockchip_sfc_wait_idle(struct rockchip_sfc *sfc, 251915fcf0cSAndy Yan u32 timeout_ms) 252915fcf0cSAndy Yan { 253915fcf0cSAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 254915fcf0cSAndy Yan unsigned long tbase = get_timer(0); 255915fcf0cSAndy Yan u32 sr, fsr; 256915fcf0cSAndy Yan 2577ddc1c35SJon Lin if (sfc->last_prepare_size && rockchip_sfc_dma_xfer_wait_finished(sfc)) 2587ddc1c35SJon Lin return -ETIMEDOUT; 2597ddc1c35SJon Lin 260915fcf0cSAndy Yan while (1) { 261915fcf0cSAndy Yan sr = readl(®s->sr); 262915fcf0cSAndy Yan fsr = readl(®s->fsr); 26339b850deSJon Lin if ((fsr & SFC_TX_EMPTY) && 26439b850deSJon Lin (fsr & SFC_RX_EMPTY) && 26539b850deSJon Lin !(sr & SFC_BUSY)) 266915fcf0cSAndy Yan break; 267915fcf0cSAndy Yan if (get_timer(tbase) > timeout_ms) { 268915fcf0cSAndy Yan printf("waite sfc idle timeout(sr:0x%08x fsr:0x%08x)\n", 269915fcf0cSAndy Yan sr, fsr); 270915fcf0cSAndy Yan rockchip_sfc_reset(sfc); 271915fcf0cSAndy Yan return -ETIMEDOUT; 272915fcf0cSAndy Yan } 273915fcf0cSAndy Yan udelay(100); 274915fcf0cSAndy Yan } 275915fcf0cSAndy Yan 276915fcf0cSAndy Yan return 0; 277915fcf0cSAndy Yan } 278915fcf0cSAndy Yan 279c1cd6cb6SAndy Yan static u8 rockchip_sfc_get_if_type(struct rockchip_sfc *sfc) 280c1cd6cb6SAndy Yan { 281c1cd6cb6SAndy Yan int type = IF_TYPE_STD; 282c1cd6cb6SAndy Yan 283da4954b7SAndy Yan if (sfc->rw == SFC_WR) { 284c1cd6cb6SAndy Yan if (sfc->mode & SPI_TX_QUAD) 285c1cd6cb6SAndy Yan type = IF_TYPE_QUAD; 286c1cd6cb6SAndy Yan else if (sfc->mode & SPI_TX_DUAL) 287c1cd6cb6SAndy Yan type = IF_TYPE_DUAL; 288c1cd6cb6SAndy Yan else 289c1cd6cb6SAndy Yan type = IF_TYPE_STD; 290c1cd6cb6SAndy Yan } else { 291c1cd6cb6SAndy Yan if (sfc->mode & SPI_RX_QUAD) 292c1cd6cb6SAndy Yan type = IF_TYPE_QUAD; 293c1cd6cb6SAndy Yan else if (sfc->mode & SPI_RX_DUAL) 294c1cd6cb6SAndy Yan type = IF_TYPE_DUAL; 295c1cd6cb6SAndy Yan else 296c1cd6cb6SAndy Yan type = IF_TYPE_STD; 297c1cd6cb6SAndy Yan } 298c1cd6cb6SAndy Yan 299c1cd6cb6SAndy Yan return type; 300c1cd6cb6SAndy Yan } 301c1cd6cb6SAndy Yan 302da4954b7SAndy Yan static void rockchip_sfc_setup_xfer(struct rockchip_sfc *sfc, u32 trb) 303c1cd6cb6SAndy Yan { 304c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 305fa413375SJon Lin u32 val; 306c1cd6cb6SAndy Yan u8 data_width = IF_TYPE_STD; 307c1cd6cb6SAndy Yan 308fa413375SJon Lin rockchip_sfc_wait_idle(sfc, 10); 30939b850deSJon Lin 31039b850deSJon Lin if (sfc->addr_bits == SFC_ADDR_24BITS || 31139b850deSJon Lin sfc->addr_bits == SFC_ADDR_32BITS) 312c1cd6cb6SAndy Yan data_width = rockchip_sfc_get_if_type(sfc); 313c1cd6cb6SAndy Yan 314fa413375SJon Lin SFC_DBG("--- sfc.addr_bit %x\n", sfc->addr_bits); 315113ced8fSJon Lin if (sfc->addr_bits == SFC_ADDR_XBITS) 31688ea3acbSJon Lin writel(sfc->addr_xbits_ext - 1, ®s->abit); 31788ea3acbSJon Lin 318fa413375SJon Lin if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) { 319fa413375SJon Lin SFC_DBG("--- sfc.len_ext %x\n", trb); 320fa413375SJon Lin writel(trb, ®s->len_ext); 321fa413375SJon Lin } 322c1cd6cb6SAndy Yan 323fa413375SJon Lin val = 0x02; 324fa413375SJon Lin val |= (data_width << SFC_DATA_WIDTH_SHIFT); 325915fcf0cSAndy Yan 32639b850deSJon Lin SFC_DBG("--- sfc.ctrl %x\n", val); 327c1cd6cb6SAndy Yan writel(val, ®s->ctrl); 328da4954b7SAndy Yan 329da4954b7SAndy Yan val = sfc->cmd; 330fa413375SJon Lin val |= (trb & 0x3fff) << SFC_TRB_SHIFT; 331da4954b7SAndy Yan val |= sfc->rw << SFC_RW_SHIFT; 332da4954b7SAndy Yan val |= sfc->addr_bits << SFC_ADDR_BITS_SHIFT; 333da4954b7SAndy Yan val |= sfc->dummy_bits << SFC_DUMMY_BITS_SHIFT; 334da4954b7SAndy Yan 33539b850deSJon Lin SFC_DBG("--- sfc.cmd %x\n", val); 336da4954b7SAndy Yan writel(val, ®s->cmd); 337da4954b7SAndy Yan 33839b850deSJon Lin if (sfc->addr_bits & SFC_ADDR_XBITS) { 33939b850deSJon Lin SFC_DBG("--- sfc.addr %x\n", sfc->addr); 340c1cd6cb6SAndy Yan writel(sfc->addr, ®s->addr); 341c1cd6cb6SAndy Yan } 34239b850deSJon Lin } 343c1cd6cb6SAndy Yan 344fa413375SJon Lin static int rockchip_sfc_dma_xfer(struct rockchip_sfc *sfc, void *buffer, 345fa413375SJon Lin size_t trb) 346c1cd6cb6SAndy Yan { 347c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 34837911cf6SAndy Yan struct bounce_buffer bb; 34937911cf6SAndy Yan unsigned int bb_flags; 350fa413375SJon Lin int timeout = trb * 1000; 351c1cd6cb6SAndy Yan int ret = 0; 352c1cd6cb6SAndy Yan int risr; 353c1cd6cb6SAndy Yan unsigned long tbase; 354c1cd6cb6SAndy Yan 35537911cf6SAndy Yan if (sfc->rw == SFC_WR) 35637911cf6SAndy Yan bb_flags = GEN_BB_READ; 35737911cf6SAndy Yan else 35837911cf6SAndy Yan bb_flags = GEN_BB_WRITE; 35937911cf6SAndy Yan 36030f161d1SAndy Yan ret = bounce_buffer_start(&bb, buffer, trb, bb_flags); 36137911cf6SAndy Yan if (ret) 36237911cf6SAndy Yan return ret; 36330f161d1SAndy Yan 36437911cf6SAndy Yan rockchip_sfc_setup_xfer(sfc, bb.len_aligned); 365c1cd6cb6SAndy Yan 366c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 36714b86dc9SJon Lin writel((unsigned long)bb.bounce_buffer, ®s->dmaaddr); 368c1cd6cb6SAndy Yan writel(SFC_DMA_START, ®s->dmatr); 369c1cd6cb6SAndy Yan 370c1cd6cb6SAndy Yan tbase = get_timer(0); 371c1cd6cb6SAndy Yan do { 372c1cd6cb6SAndy Yan udelay(1); 373c1cd6cb6SAndy Yan risr = readl(®s->risr); 374c1cd6cb6SAndy Yan if (get_timer(tbase) > timeout) { 375c1cd6cb6SAndy Yan debug("dma timeout\n"); 376c1cd6cb6SAndy Yan ret = -ETIMEDOUT; 377c1cd6cb6SAndy Yan break; 378c1cd6cb6SAndy Yan } 379c1cd6cb6SAndy Yan } while (!(risr & TRANS_FINISH_INT)); 380c1cd6cb6SAndy Yan 381c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 382c1cd6cb6SAndy Yan 38337911cf6SAndy Yan bounce_buffer_stop(&bb); 38437911cf6SAndy Yan 385c1cd6cb6SAndy Yan return ret; 386c1cd6cb6SAndy Yan } 387c1cd6cb6SAndy Yan 3887ddc1c35SJon Lin static int rockchip_sfc_dma_xfer_prepare(struct rockchip_sfc *sfc, 3897ddc1c35SJon Lin void *buffer, size_t trb) 3907ddc1c35SJon Lin { 3917ddc1c35SJon Lin struct rockchip_sfc_reg *regs = sfc->regbase; 3927ddc1c35SJon Lin 3937ddc1c35SJon Lin SFC_DBG("sfc_dma_xfer_prepar enter\n"); 3947ddc1c35SJon Lin 3957ddc1c35SJon Lin rockchip_sfc_setup_xfer(sfc, trb); 3967ddc1c35SJon Lin sfc->last_prepare_size = trb; 3977ddc1c35SJon Lin 3987ddc1c35SJon Lin flush_dcache_range((unsigned long)buffer, 3997ddc1c35SJon Lin (unsigned long)buffer + trb); 4007ddc1c35SJon Lin 4017ddc1c35SJon Lin writel(0xFFFFFFFF, ®s->iclr); 4027ddc1c35SJon Lin writel((unsigned long)buffer, ®s->dmaaddr); 4037ddc1c35SJon Lin writel(SFC_DMA_START, ®s->dmatr); 4047ddc1c35SJon Lin 4057ddc1c35SJon Lin return 0; 4067ddc1c35SJon Lin } 4077ddc1c35SJon Lin 408da4954b7SAndy Yan static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int rw, 409c1cd6cb6SAndy Yan u32 timeout) 410c1cd6cb6SAndy Yan { 411c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 412c1cd6cb6SAndy Yan unsigned long tbase = get_timer(0); 413c1cd6cb6SAndy Yan u8 level; 414c1cd6cb6SAndy Yan u32 fsr; 415c1cd6cb6SAndy Yan 416c1cd6cb6SAndy Yan do { 417c1cd6cb6SAndy Yan fsr = readl(®s->fsr); 418da4954b7SAndy Yan if (rw == SFC_WR) 419c1cd6cb6SAndy Yan level = (fsr & SFC_TXLV_MASK) >> SFC_TXLV_SHIFT; 420c1cd6cb6SAndy Yan else 421c1cd6cb6SAndy Yan level = (fsr & SFC_RXLV_MASK) >> SFC_RXLV_SHIFT; 422c1cd6cb6SAndy Yan if (get_timer(tbase) > timeout) 423c1cd6cb6SAndy Yan return -ETIMEDOUT; 424c1cd6cb6SAndy Yan udelay(1); 425c1cd6cb6SAndy Yan } while (!level); 426c1cd6cb6SAndy Yan 427c1cd6cb6SAndy Yan return level; 428c1cd6cb6SAndy Yan } 429c1cd6cb6SAndy Yan 430da4954b7SAndy Yan static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len) 431c1cd6cb6SAndy Yan { 432c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 433c1cd6cb6SAndy Yan u32 bytes = len & 0x3; 434c1cd6cb6SAndy Yan u32 words = len >> 2; 435915fcf0cSAndy Yan int tx_level = 0; 436c1cd6cb6SAndy Yan u32 val = 0; 437c1cd6cb6SAndy Yan u8 count; 438c1cd6cb6SAndy Yan 439c1cd6cb6SAndy Yan while (words) { 440da4954b7SAndy Yan tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000); 441c1cd6cb6SAndy Yan if (tx_level <= 0) 442c1cd6cb6SAndy Yan return tx_level; 443915fcf0cSAndy Yan count = min(words, (u32)tx_level); 444c1cd6cb6SAndy Yan writesl(®s->data, buf, count); 445c1cd6cb6SAndy Yan buf += count; 446c1cd6cb6SAndy Yan words -= count; 447c1cd6cb6SAndy Yan } 448c1cd6cb6SAndy Yan 449da4954b7SAndy Yan /* handle the last non 4byte aligned bytes */ 450c1cd6cb6SAndy Yan if (bytes) { 451da4954b7SAndy Yan tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000); 452c1cd6cb6SAndy Yan if (tx_level <= 0) 453c1cd6cb6SAndy Yan return tx_level; 454c1cd6cb6SAndy Yan memcpy(&val, buf, bytes); 455c1cd6cb6SAndy Yan writel(val, ®s->data); 456c1cd6cb6SAndy Yan } 457c1cd6cb6SAndy Yan 458c1cd6cb6SAndy Yan return 0; 459c1cd6cb6SAndy Yan } 460c1cd6cb6SAndy Yan 461da4954b7SAndy Yan static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len) 462c1cd6cb6SAndy Yan { 463c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 464c1cd6cb6SAndy Yan u32 bytes = len & 0x3; 465c1cd6cb6SAndy Yan u32 words = len >> 2; 466915fcf0cSAndy Yan int rx_level = 0; 467c1cd6cb6SAndy Yan u32 count; 468c1cd6cb6SAndy Yan u32 val; 469c1cd6cb6SAndy Yan 470c1cd6cb6SAndy Yan while (words) { 471da4954b7SAndy Yan rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000); 472c1cd6cb6SAndy Yan if (rx_level <= 0) 473c1cd6cb6SAndy Yan return rx_level; 474915fcf0cSAndy Yan count = min(words, (u32)rx_level); 475c1cd6cb6SAndy Yan readsl(®s->data, buf, count); 476c1cd6cb6SAndy Yan buf += count; 477c1cd6cb6SAndy Yan words -= count; 478c1cd6cb6SAndy Yan } 479c1cd6cb6SAndy Yan 480da4954b7SAndy Yan /* handle the last non 4 bytes aligned bytes */ 481c1cd6cb6SAndy Yan if (bytes) { 482da4954b7SAndy Yan rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000); 483c1cd6cb6SAndy Yan if (rx_level <= 0) 484c1cd6cb6SAndy Yan return rx_level; 485c1cd6cb6SAndy Yan val = readl(®s->data); 486c1cd6cb6SAndy Yan memcpy(buf, &val, bytes); 487c1cd6cb6SAndy Yan } 488c1cd6cb6SAndy Yan 489c1cd6cb6SAndy Yan return 0; 490c1cd6cb6SAndy Yan } 491c1cd6cb6SAndy Yan 49230f161d1SAndy Yan static int rockchip_sfc_pio_xfer(struct rockchip_sfc *sfc, void *buf, u32 len) 493c1cd6cb6SAndy Yan { 494c1cd6cb6SAndy Yan int ret = 0; 495c1cd6cb6SAndy Yan 496da4954b7SAndy Yan rockchip_sfc_setup_xfer(sfc, len); 49730f161d1SAndy Yan 498c1cd6cb6SAndy Yan if (len) { 499da4954b7SAndy Yan if (sfc->rw == SFC_WR) 50030f161d1SAndy Yan ret = rockchip_sfc_write_fifo(sfc, (u32 *)buf, len); 501c1cd6cb6SAndy Yan else 50230f161d1SAndy Yan ret = rockchip_sfc_read_fifo(sfc, (u32 *)buf, len); 503c1cd6cb6SAndy Yan } 504c1cd6cb6SAndy Yan 505c1cd6cb6SAndy Yan return ret; 506c1cd6cb6SAndy Yan } 507c1cd6cb6SAndy Yan 50830f161d1SAndy Yan static int rockchip_sfc_read(struct rockchip_sfc *sfc, u32 offset, 50930f161d1SAndy Yan void *buf, size_t len) 510c1cd6cb6SAndy Yan { 5116bf64646SAndy Yan u32 dma_trans; 51230f161d1SAndy Yan u32 trb; 51330f161d1SAndy Yan u8 bytes; 51430f161d1SAndy Yan int ret; 515c1cd6cb6SAndy Yan 51637911cf6SAndy Yan if (len >= ARCH_DMA_MINALIGN) { 51730f161d1SAndy Yan bytes = len & (ARCH_DMA_MINALIGN - 1); 5186bf64646SAndy Yan dma_trans = len - bytes; 5196bf64646SAndy Yan } else { 5206bf64646SAndy Yan dma_trans = 0; 5216bf64646SAndy Yan bytes = len; 5226bf64646SAndy Yan } 5236bf64646SAndy Yan 52430f161d1SAndy Yan while (dma_trans) { 525fa413375SJon Lin trb = min_t(size_t, dma_trans, sfc->max_iosize); 5267ddc1c35SJon Lin if (sfc->prepare) 5277ddc1c35SJon Lin ret = rockchip_sfc_dma_xfer_prepare(sfc, buf, len); 5287ddc1c35SJon Lin else 52930f161d1SAndy Yan ret = rockchip_sfc_dma_xfer(sfc, buf, trb); 53030f161d1SAndy Yan if (ret < 0) 53130f161d1SAndy Yan return ret; 53230f161d1SAndy Yan dma_trans -= trb; 53330f161d1SAndy Yan sfc->addr += trb; 53430f161d1SAndy Yan buf += trb; 5356bf64646SAndy Yan } 5366bf64646SAndy Yan 5376bf64646SAndy Yan /* 53830f161d1SAndy Yan * transfer the last non dma anligned byte by pio mode 5396bf64646SAndy Yan */ 54030f161d1SAndy Yan if (bytes) 5416bf64646SAndy Yan ret = rockchip_sfc_pio_xfer(sfc, buf, bytes); 542c1cd6cb6SAndy Yan 54330f161d1SAndy Yan return 0; 54430f161d1SAndy Yan } 54530f161d1SAndy Yan 54630f161d1SAndy Yan static int rockchip_sfc_write(struct rockchip_sfc *sfc, u32 offset, 54730f161d1SAndy Yan void *buf, size_t len) 54830f161d1SAndy Yan { 549fa413375SJon Lin if (len > sfc->max_iosize) { 55030f161d1SAndy Yan printf("out of the max sfc trb"); 55130f161d1SAndy Yan return -EINVAL; 55230f161d1SAndy Yan } 55330f161d1SAndy Yan 55430f161d1SAndy Yan if (len && !(len & (ARCH_DMA_MINALIGN - 1))) 55530f161d1SAndy Yan return rockchip_sfc_dma_xfer(sfc, buf, len); 55630f161d1SAndy Yan else 55730f161d1SAndy Yan return rockchip_sfc_pio_xfer(sfc, buf, len); 55830f161d1SAndy Yan 55930f161d1SAndy Yan return 0; 56030f161d1SAndy Yan } 56130f161d1SAndy Yan 56230f161d1SAndy Yan static int rockchip_sfc_do_xfer(struct rockchip_sfc *sfc, void *buf, size_t len) 56330f161d1SAndy Yan { 56430f161d1SAndy Yan if (sfc->rw) 56530f161d1SAndy Yan return rockchip_sfc_write(sfc, sfc->addr, buf, len); 56630f161d1SAndy Yan else 56730f161d1SAndy Yan return rockchip_sfc_read(sfc, sfc->addr, buf, len); 568c1cd6cb6SAndy Yan } 569c1cd6cb6SAndy Yan 570c1cd6cb6SAndy Yan static int rockchip_sfc_xfer(struct udevice *dev, unsigned int bitlen, 571c1cd6cb6SAndy Yan const void *dout, void *din, unsigned long flags) 572c1cd6cb6SAndy Yan { 573c1cd6cb6SAndy Yan struct udevice *bus = dev->parent; 574c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 575c1cd6cb6SAndy Yan int len = bitlen >> 3; 576c1cd6cb6SAndy Yan u8 *pcmd = (u8 *)dout; 57730f161d1SAndy Yan void *data_buf; 578c1cd6cb6SAndy Yan int ret = 0; 579c1cd6cb6SAndy Yan 580c1cd6cb6SAndy Yan if (flags & SPI_XFER_BEGIN) { 581c1cd6cb6SAndy Yan sfc->cmd = pcmd[0]; 5826e121371SJon Lin switch (len) { 5836e121371SJon Lin case 6: /* Nor >16MB 0x6b dummy op */ 5846e121371SJon Lin sfc->addr_bits = SFC_ADDR_32BITS; 5856e121371SJon Lin sfc->dummy_bits = 8; 5866e121371SJon Lin sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24); 5876e121371SJon Lin break; 5886e121371SJon Lin case 5: /* Nor <=16MB 0x6b dummy op, Nor >16MB no dummy op */ 58998730755SJon Lin if (sfc->cmd == 0x6b) { 59098730755SJon Lin sfc->addr_bits = SFC_ADDR_24BITS; 59198730755SJon Lin sfc->dummy_bits = 8; 59298730755SJon Lin sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16); 59398730755SJon Lin } else { 5946e121371SJon Lin sfc->addr_bits = SFC_ADDR_32BITS; 5956e121371SJon Lin sfc->dummy_bits = 0; 5966e121371SJon Lin sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24); 59798730755SJon Lin } 5986e121371SJon Lin break; 5996e121371SJon Lin case 4: /* Nand erase and read, Nor <=16MB no dummy op */ 6006e121371SJon Lin sfc->addr_bits = SFC_ADDR_24BITS; 6016e121371SJon Lin sfc->dummy_bits = 0; 602c1cd6cb6SAndy Yan sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16); 6036e121371SJon Lin break; 6046e121371SJon Lin case 3: /* Nand prog, */ 6056e121371SJon Lin sfc->addr_bits = SFC_ADDR_XBITS; 60688ea3acbSJon Lin sfc->addr_xbits_ext = 16; 60739b850deSJon Lin sfc->dummy_bits = 0; 60839b850deSJon Lin sfc->addr = pcmd[2] | pcmd[1] << 8; 6096e121371SJon Lin break; 6106e121371SJon Lin case 2: /* Nand read/write feature */ 6116e121371SJon Lin sfc->addr_bits = SFC_ADDR_XBITS; 61288ea3acbSJon Lin sfc->addr_xbits_ext = 8; 61339b850deSJon Lin sfc->dummy_bits = 0; 61439b850deSJon Lin sfc->addr = pcmd[1]; 6156e121371SJon Lin break; 6166e121371SJon Lin default: /* Nand/Nor Read/Write status */ 6176e121371SJon Lin sfc->addr_bits = SFC_ADDR_0BITS; 618da4954b7SAndy Yan sfc->dummy_bits = 0; 619da4954b7SAndy Yan sfc->addr = 0; 6206e121371SJon Lin break; 621c1cd6cb6SAndy Yan } 622fa413375SJon Lin SFC_DBG("%s %d %x %d %d %x\n", __func__, len, sfc->cmd, 623fa413375SJon Lin sfc->addr_bits, sfc->dummy_bits, sfc->addr); 624c1cd6cb6SAndy Yan } 625c1cd6cb6SAndy Yan if (flags & SPI_XFER_END) { 626da4954b7SAndy Yan if (din) { 627da4954b7SAndy Yan sfc->rw = SFC_RD; 62830f161d1SAndy Yan data_buf = din; 62930f161d1SAndy Yan } else { 630da4954b7SAndy Yan sfc->rw = SFC_WR; 63130f161d1SAndy Yan data_buf = (void *)dout; 632c1cd6cb6SAndy Yan } 63330f161d1SAndy Yan 63430f161d1SAndy Yan if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) { 63530f161d1SAndy Yan len = 0; 63630f161d1SAndy Yan data_buf = NULL; 63730f161d1SAndy Yan } 63830f161d1SAndy Yan 6397ddc1c35SJon Lin sfc->prepare = flags & SPI_XFER_PREPARE ? true : false; 6407ddc1c35SJon Lin 641cbd9216dSJon Lin if (sfc->cmd == 0x9f && len == 4) { 642cbd9216dSJon Lin /* SPI Nand read id */ 643cbd9216dSJon Lin sfc->addr_bits = SFC_ADDR_XBITS; 644cbd9216dSJon Lin sfc->addr_xbits_ext = 8; 645cbd9216dSJon Lin sfc->dummy_bits = 0; 646cbd9216dSJon Lin sfc->addr = 0; 647cbd9216dSJon Lin ((u8 *)data_buf)[0] = 0xff; 648cbd9216dSJon Lin ret = rockchip_sfc_do_xfer(sfc, &((u8 *)data_buf)[1], 3); 649cbd9216dSJon Lin } else { 65030f161d1SAndy Yan ret = rockchip_sfc_do_xfer(sfc, data_buf, len); 651da4954b7SAndy Yan } 652cbd9216dSJon Lin } 653c1cd6cb6SAndy Yan 654c1cd6cb6SAndy Yan return ret; 655c1cd6cb6SAndy Yan } 656c1cd6cb6SAndy Yan 657c1cd6cb6SAndy Yan static int rockchip_sfc_set_speed(struct udevice *bus, uint speed) 658c1cd6cb6SAndy Yan { 659c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 660c1cd6cb6SAndy Yan 661c1cd6cb6SAndy Yan if (speed > sfc->max_freq) 662c1cd6cb6SAndy Yan speed = sfc->max_freq; 663c1cd6cb6SAndy Yan 664c1cd6cb6SAndy Yan sfc->speed_hz = speed; 665*5b4dcfe0SJason Zhu #if CONFIG_IS_ENABLED(CLK) 666ae52cbcbSJon Lin clk_set_rate(&sfc->clk, sfc->speed_hz); 667ae52cbcbSJon Lin SFC_DBG("%s clk= %ld\n", __func__, clk_get_rate(&sfc->clk)); 668*5b4dcfe0SJason Zhu #endif 669c1cd6cb6SAndy Yan return 0; 670c1cd6cb6SAndy Yan } 671c1cd6cb6SAndy Yan 672c1cd6cb6SAndy Yan static int rockchip_sfc_set_mode(struct udevice *bus, uint mode) 673c1cd6cb6SAndy Yan { 674c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 675c1cd6cb6SAndy Yan 676c1cd6cb6SAndy Yan sfc->mode = mode; 677c1cd6cb6SAndy Yan 678c1cd6cb6SAndy Yan return 0; 679c1cd6cb6SAndy Yan } 680c1cd6cb6SAndy Yan 681c1cd6cb6SAndy Yan static const struct dm_spi_ops rockchip_sfc_ops = { 682c1cd6cb6SAndy Yan .xfer = rockchip_sfc_xfer, 683c1cd6cb6SAndy Yan .set_speed = rockchip_sfc_set_speed, 684c1cd6cb6SAndy Yan .set_mode = rockchip_sfc_set_mode, 685c1cd6cb6SAndy Yan }; 686c1cd6cb6SAndy Yan 687c1cd6cb6SAndy Yan static const struct udevice_id rockchip_sfc_ids[] = { 688c1cd6cb6SAndy Yan { .compatible = "rockchip,sfc" }, 689c1cd6cb6SAndy Yan { } 690c1cd6cb6SAndy Yan }; 691c1cd6cb6SAndy Yan 692c1cd6cb6SAndy Yan U_BOOT_DRIVER(rockchip_sfc_driver) = { 693c1cd6cb6SAndy Yan .name = "rockchip_sfc", 694c1cd6cb6SAndy Yan .id = UCLASS_SPI, 695c1cd6cb6SAndy Yan .of_match = rockchip_sfc_ids, 696c1cd6cb6SAndy Yan .ops = &rockchip_sfc_ops, 697c1cd6cb6SAndy Yan .ofdata_to_platdata = rockchip_sfc_ofdata_to_platdata, 698c1cd6cb6SAndy Yan .platdata_auto_alloc_size = sizeof(struct rockchip_sfc_platdata), 699c1cd6cb6SAndy Yan .priv_auto_alloc_size = sizeof(struct rockchip_sfc), 700c1cd6cb6SAndy Yan .probe = rockchip_sfc_probe, 701c1cd6cb6SAndy Yan }; 702