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; 43*fa413375SJon Lin u32 ver; 44*fa413375SJon Lin u32 reserved[20]; 45c6d59f03SAndy Yan u32 dmatr; 46c6d59f03SAndy Yan u32 dmaaddr; 47*fa413375SJon Lin u32 len_ctrl; 48*fa413375SJon Lin u32 len_ext; 49*fa413375SJon 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 107*fa413375SJon Lin #define SFC_MAX_TRB_VER3 (512 * 31) 108*fa413375SJon Lin #define SFC_MAX_TRB_VER4 (0xFFFFFFFF) 109c6d59f03SAndy Yan 110ae52cbcbSJon Lin #define SFC_MAX_RATE (150 * 1000 * 1000) 111ae52cbcbSJon Lin #define SFC_DEFAULT_RATE (80 * 1000 * 1000) 112ae52cbcbSJon Lin #define SFC_MIN_RATE (10 * 1000 * 1000) 113ae52cbcbSJon Lin 114*fa413375SJon Lin #define SFC_VER_3 0x3 115*fa413375SJon Lin #define SFC_VER_4 0x4 116*fa413375SJon 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; 134*fa413375SJon Lin u32 max_iosize; 135c1cd6cb6SAndy Yan u32 cmd; 136c1cd6cb6SAndy Yan u32 addr; 137da4954b7SAndy Yan u8 addr_bits; 13888ea3acbSJon Lin u8 addr_xbits_ext; 139da4954b7SAndy Yan u8 dummy_bits; 140da4954b7SAndy Yan u8 rw; 141da4954b7SAndy Yan u32 trb; 142c1cd6cb6SAndy Yan }; 143c1cd6cb6SAndy Yan 144c1cd6cb6SAndy Yan static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus) 145c1cd6cb6SAndy Yan { 146c1cd6cb6SAndy Yan struct rockchip_sfc_platdata *plat = dev_get_platdata(bus); 147c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 148c1cd6cb6SAndy Yan int ret; 149c1cd6cb6SAndy Yan 15014b86dc9SJon Lin plat->base = dev_read_addr_ptr(bus); 151c1cd6cb6SAndy Yan ret = clk_get_by_index(bus, 0, &sfc->clk); 152c1cd6cb6SAndy Yan if (ret < 0) { 15314b86dc9SJon Lin printf("Could not get clock for %s: %d\n", bus->name, ret); 154c1cd6cb6SAndy Yan return ret; 155c1cd6cb6SAndy Yan } 156c1cd6cb6SAndy Yan 157c1cd6cb6SAndy Yan return 0; 158c1cd6cb6SAndy Yan } 159c1cd6cb6SAndy Yan 160*fa413375SJon Lin u32 rockchip_sfc_get_version(struct rockchip_sfc *sfc) 161*fa413375SJon Lin { 162*fa413375SJon Lin struct rockchip_sfc_reg *regs = sfc->regbase; 163*fa413375SJon Lin 164*fa413375SJon Lin return (u32)(readl(®s->ver) & 0xFFFF); 165*fa413375SJon Lin } 166*fa413375SJon Lin 167c1cd6cb6SAndy Yan static int rockchip_sfc_probe(struct udevice *bus) 168c1cd6cb6SAndy Yan { 169c1cd6cb6SAndy Yan struct rockchip_sfc_platdata *plat = dev_get_platdata(bus); 170c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 171*fa413375SJon Lin struct rockchip_sfc_reg *regs; 172ae52cbcbSJon Lin struct dm_spi_bus *dm_spi_bus; 173c1cd6cb6SAndy Yan 174ae52cbcbSJon Lin dm_spi_bus = bus->uclass_priv; 175ae52cbcbSJon Lin dm_spi_bus->max_hz = plat->frequency; 176c1cd6cb6SAndy Yan sfc->regbase = (struct rockchip_sfc_reg *)plat->base; 17731e5d7a3SJon Lin sfc->max_freq = SFC_MAX_RATE; 17831e5d7a3SJon Lin sfc->speed_hz = SFC_DEFAULT_RATE; 17931e5d7a3SJon Lin clk_set_rate(&sfc->clk, sfc->speed_hz); 180c1cd6cb6SAndy Yan 181*fa413375SJon Lin regs = sfc->regbase; 182*fa413375SJon Lin if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) { 183*fa413375SJon Lin sfc->max_iosize = SFC_MAX_TRB_VER4; 184*fa413375SJon Lin writel(1, ®s->len_ctrl); 185*fa413375SJon Lin } else { 186*fa413375SJon Lin sfc->max_iosize = SFC_MAX_TRB_VER3; 187*fa413375SJon Lin } 188*fa413375SJon Lin 189c1cd6cb6SAndy Yan return 0; 190c1cd6cb6SAndy Yan } 191c1cd6cb6SAndy Yan 192c1cd6cb6SAndy Yan static int rockchip_sfc_reset(struct rockchip_sfc *sfc) 193c1cd6cb6SAndy Yan { 194c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 195c1cd6cb6SAndy Yan int tbase = get_timer(0); 196c1cd6cb6SAndy Yan u32 rcvr; 197c1cd6cb6SAndy Yan int ret = 0; 198c1cd6cb6SAndy Yan 199c1cd6cb6SAndy Yan writel(SFC_RESET, ®s->rcvr); 200c1cd6cb6SAndy Yan do { 201c1cd6cb6SAndy Yan rcvr = readl(®s->rcvr); 202c1cd6cb6SAndy Yan if (get_timer(tbase) > 1000) { 203c1cd6cb6SAndy Yan debug("sfc reset timeout\n"); 204c1cd6cb6SAndy Yan ret = -ETIMEDOUT; 205c1cd6cb6SAndy Yan break; 206c1cd6cb6SAndy Yan } 207c1cd6cb6SAndy Yan udelay(1); 208c1cd6cb6SAndy Yan } while (rcvr); 209c1cd6cb6SAndy Yan 210c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 211c1cd6cb6SAndy Yan 212c1cd6cb6SAndy Yan debug("sfc reset\n"); 213c1cd6cb6SAndy Yan 214c1cd6cb6SAndy Yan return ret; 215c1cd6cb6SAndy Yan } 216c1cd6cb6SAndy Yan 217915fcf0cSAndy Yan /* The SFC_CTRL register is a global control register, 218915fcf0cSAndy Yan * when the controller is in busy state(SFC_SR), 219915fcf0cSAndy Yan * SFC_CTRL cannot be set. 220915fcf0cSAndy Yan */ 221915fcf0cSAndy Yan static int rockchip_sfc_wait_idle(struct rockchip_sfc *sfc, 222915fcf0cSAndy Yan u32 timeout_ms) 223915fcf0cSAndy Yan { 224915fcf0cSAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 225915fcf0cSAndy Yan unsigned long tbase = get_timer(0); 226915fcf0cSAndy Yan u32 sr, fsr; 227915fcf0cSAndy Yan 228915fcf0cSAndy Yan while (1) { 229915fcf0cSAndy Yan sr = readl(®s->sr); 230915fcf0cSAndy Yan fsr = readl(®s->fsr); 23139b850deSJon Lin if ((fsr & SFC_TX_EMPTY) && 23239b850deSJon Lin (fsr & SFC_RX_EMPTY) && 23339b850deSJon Lin !(sr & SFC_BUSY)) 234915fcf0cSAndy Yan break; 235915fcf0cSAndy Yan if (get_timer(tbase) > timeout_ms) { 236915fcf0cSAndy Yan printf("waite sfc idle timeout(sr:0x%08x fsr:0x%08x)\n", 237915fcf0cSAndy Yan sr, fsr); 238915fcf0cSAndy Yan rockchip_sfc_reset(sfc); 239915fcf0cSAndy Yan return -ETIMEDOUT; 240915fcf0cSAndy Yan } 241915fcf0cSAndy Yan udelay(100); 242915fcf0cSAndy Yan } 243915fcf0cSAndy Yan 244915fcf0cSAndy Yan return 0; 245915fcf0cSAndy Yan } 246915fcf0cSAndy Yan 247c1cd6cb6SAndy Yan static u8 rockchip_sfc_get_if_type(struct rockchip_sfc *sfc) 248c1cd6cb6SAndy Yan { 249c1cd6cb6SAndy Yan int type = IF_TYPE_STD; 250c1cd6cb6SAndy Yan 251da4954b7SAndy Yan if (sfc->rw == SFC_WR) { 252c1cd6cb6SAndy Yan if (sfc->mode & SPI_TX_QUAD) 253c1cd6cb6SAndy Yan type = IF_TYPE_QUAD; 254c1cd6cb6SAndy Yan else if (sfc->mode & SPI_TX_DUAL) 255c1cd6cb6SAndy Yan type = IF_TYPE_DUAL; 256c1cd6cb6SAndy Yan else 257c1cd6cb6SAndy Yan type = IF_TYPE_STD; 258c1cd6cb6SAndy Yan } else { 259c1cd6cb6SAndy Yan if (sfc->mode & SPI_RX_QUAD) 260c1cd6cb6SAndy Yan type = IF_TYPE_QUAD; 261c1cd6cb6SAndy Yan else if (sfc->mode & SPI_RX_DUAL) 262c1cd6cb6SAndy Yan type = IF_TYPE_DUAL; 263c1cd6cb6SAndy Yan else 264c1cd6cb6SAndy Yan type = IF_TYPE_STD; 265c1cd6cb6SAndy Yan } 266c1cd6cb6SAndy Yan 267c1cd6cb6SAndy Yan return type; 268c1cd6cb6SAndy Yan } 269c1cd6cb6SAndy Yan 270da4954b7SAndy Yan static void rockchip_sfc_setup_xfer(struct rockchip_sfc *sfc, u32 trb) 271c1cd6cb6SAndy Yan { 272c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 273*fa413375SJon Lin u32 val; 274c1cd6cb6SAndy Yan u8 data_width = IF_TYPE_STD; 275c1cd6cb6SAndy Yan 276*fa413375SJon Lin rockchip_sfc_wait_idle(sfc, 10); 27739b850deSJon Lin 27839b850deSJon Lin if (sfc->addr_bits == SFC_ADDR_24BITS || 27939b850deSJon Lin sfc->addr_bits == SFC_ADDR_32BITS) 280c1cd6cb6SAndy Yan data_width = rockchip_sfc_get_if_type(sfc); 281c1cd6cb6SAndy Yan 282*fa413375SJon Lin SFC_DBG("--- sfc.addr_bit %x\n", sfc->addr_bits); 283113ced8fSJon Lin if (sfc->addr_bits == SFC_ADDR_XBITS) 28488ea3acbSJon Lin writel(sfc->addr_xbits_ext - 1, ®s->abit); 28588ea3acbSJon Lin 286*fa413375SJon Lin if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) { 287*fa413375SJon Lin SFC_DBG("--- sfc.len_ext %x\n", trb); 288*fa413375SJon Lin writel(trb, ®s->len_ext); 289*fa413375SJon Lin } 290c1cd6cb6SAndy Yan 291*fa413375SJon Lin val = 0x02; 292*fa413375SJon Lin val |= (data_width << SFC_DATA_WIDTH_SHIFT); 293915fcf0cSAndy Yan 29439b850deSJon Lin SFC_DBG("--- sfc.ctrl %x\n", val); 295c1cd6cb6SAndy Yan writel(val, ®s->ctrl); 296da4954b7SAndy Yan 297da4954b7SAndy Yan val = sfc->cmd; 298*fa413375SJon Lin val |= (trb & 0x3fff) << SFC_TRB_SHIFT; 299da4954b7SAndy Yan val |= sfc->rw << SFC_RW_SHIFT; 300da4954b7SAndy Yan val |= sfc->addr_bits << SFC_ADDR_BITS_SHIFT; 301da4954b7SAndy Yan val |= sfc->dummy_bits << SFC_DUMMY_BITS_SHIFT; 302da4954b7SAndy Yan 30339b850deSJon Lin SFC_DBG("--- sfc.cmd %x\n", val); 304da4954b7SAndy Yan writel(val, ®s->cmd); 305da4954b7SAndy Yan 30639b850deSJon Lin if (sfc->addr_bits & SFC_ADDR_XBITS) { 30739b850deSJon Lin SFC_DBG("--- sfc.addr %x\n", sfc->addr); 308c1cd6cb6SAndy Yan writel(sfc->addr, ®s->addr); 309c1cd6cb6SAndy Yan } 31039b850deSJon Lin } 311c1cd6cb6SAndy Yan 312*fa413375SJon Lin static int rockchip_sfc_dma_xfer(struct rockchip_sfc *sfc, void *buffer, 313*fa413375SJon Lin size_t trb) 314c1cd6cb6SAndy Yan { 315c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 31637911cf6SAndy Yan struct bounce_buffer bb; 31737911cf6SAndy Yan unsigned int bb_flags; 318*fa413375SJon Lin int timeout = trb * 1000; 319c1cd6cb6SAndy Yan int ret = 0; 320c1cd6cb6SAndy Yan int risr; 321c1cd6cb6SAndy Yan unsigned long tbase; 322c1cd6cb6SAndy Yan 32337911cf6SAndy Yan if (sfc->rw == SFC_WR) 32437911cf6SAndy Yan bb_flags = GEN_BB_READ; 32537911cf6SAndy Yan else 32637911cf6SAndy Yan bb_flags = GEN_BB_WRITE; 32737911cf6SAndy Yan 32830f161d1SAndy Yan ret = bounce_buffer_start(&bb, buffer, trb, bb_flags); 32937911cf6SAndy Yan if (ret) 33037911cf6SAndy Yan return ret; 33130f161d1SAndy Yan 33237911cf6SAndy Yan rockchip_sfc_setup_xfer(sfc, bb.len_aligned); 333c1cd6cb6SAndy Yan 334c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 33514b86dc9SJon Lin writel((unsigned long)bb.bounce_buffer, ®s->dmaaddr); 336c1cd6cb6SAndy Yan writel(SFC_DMA_START, ®s->dmatr); 337c1cd6cb6SAndy Yan 338c1cd6cb6SAndy Yan tbase = get_timer(0); 339c1cd6cb6SAndy Yan do { 340c1cd6cb6SAndy Yan udelay(1); 341c1cd6cb6SAndy Yan risr = readl(®s->risr); 342c1cd6cb6SAndy Yan if (get_timer(tbase) > timeout) { 343c1cd6cb6SAndy Yan debug("dma timeout\n"); 344c1cd6cb6SAndy Yan ret = -ETIMEDOUT; 345c1cd6cb6SAndy Yan break; 346c1cd6cb6SAndy Yan } 347c1cd6cb6SAndy Yan } while (!(risr & TRANS_FINISH_INT)); 348c1cd6cb6SAndy Yan 349c1cd6cb6SAndy Yan writel(0xFFFFFFFF, ®s->iclr); 350c1cd6cb6SAndy Yan 35137911cf6SAndy Yan bounce_buffer_stop(&bb); 35237911cf6SAndy Yan 353c1cd6cb6SAndy Yan return ret; 354c1cd6cb6SAndy Yan } 355c1cd6cb6SAndy Yan 356da4954b7SAndy Yan static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int rw, 357c1cd6cb6SAndy Yan u32 timeout) 358c1cd6cb6SAndy Yan { 359c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 360c1cd6cb6SAndy Yan unsigned long tbase = get_timer(0); 361c1cd6cb6SAndy Yan u8 level; 362c1cd6cb6SAndy Yan u32 fsr; 363c1cd6cb6SAndy Yan 364c1cd6cb6SAndy Yan do { 365c1cd6cb6SAndy Yan fsr = readl(®s->fsr); 366da4954b7SAndy Yan if (rw == SFC_WR) 367c1cd6cb6SAndy Yan level = (fsr & SFC_TXLV_MASK) >> SFC_TXLV_SHIFT; 368c1cd6cb6SAndy Yan else 369c1cd6cb6SAndy Yan level = (fsr & SFC_RXLV_MASK) >> SFC_RXLV_SHIFT; 370c1cd6cb6SAndy Yan if (get_timer(tbase) > timeout) 371c1cd6cb6SAndy Yan return -ETIMEDOUT; 372c1cd6cb6SAndy Yan udelay(1); 373c1cd6cb6SAndy Yan } while (!level); 374c1cd6cb6SAndy Yan 375c1cd6cb6SAndy Yan return level; 376c1cd6cb6SAndy Yan } 377c1cd6cb6SAndy Yan 378da4954b7SAndy Yan static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len) 379c1cd6cb6SAndy Yan { 380c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 381c1cd6cb6SAndy Yan u32 bytes = len & 0x3; 382c1cd6cb6SAndy Yan u32 words = len >> 2; 383915fcf0cSAndy Yan int tx_level = 0; 384c1cd6cb6SAndy Yan u32 val = 0; 385c1cd6cb6SAndy Yan u8 count; 386c1cd6cb6SAndy Yan 387c1cd6cb6SAndy Yan while (words) { 388da4954b7SAndy Yan tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000); 389c1cd6cb6SAndy Yan if (tx_level <= 0) 390c1cd6cb6SAndy Yan return tx_level; 391915fcf0cSAndy Yan count = min(words, (u32)tx_level); 392c1cd6cb6SAndy Yan writesl(®s->data, buf, count); 393c1cd6cb6SAndy Yan buf += count; 394c1cd6cb6SAndy Yan words -= count; 395c1cd6cb6SAndy Yan } 396c1cd6cb6SAndy Yan 397da4954b7SAndy Yan /* handle the last non 4byte aligned bytes */ 398c1cd6cb6SAndy Yan if (bytes) { 399da4954b7SAndy Yan tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_WR, 1000); 400c1cd6cb6SAndy Yan if (tx_level <= 0) 401c1cd6cb6SAndy Yan return tx_level; 402c1cd6cb6SAndy Yan memcpy(&val, buf, bytes); 403c1cd6cb6SAndy Yan writel(val, ®s->data); 404c1cd6cb6SAndy Yan } 405c1cd6cb6SAndy Yan 406c1cd6cb6SAndy Yan return 0; 407c1cd6cb6SAndy Yan } 408c1cd6cb6SAndy Yan 409da4954b7SAndy Yan static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u32 *buf, u32 len) 410c1cd6cb6SAndy Yan { 411c1cd6cb6SAndy Yan struct rockchip_sfc_reg *regs = sfc->regbase; 412c1cd6cb6SAndy Yan u32 bytes = len & 0x3; 413c1cd6cb6SAndy Yan u32 words = len >> 2; 414915fcf0cSAndy Yan int rx_level = 0; 415c1cd6cb6SAndy Yan u32 count; 416c1cd6cb6SAndy Yan u32 val; 417c1cd6cb6SAndy Yan 418c1cd6cb6SAndy Yan while (words) { 419da4954b7SAndy Yan rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000); 420c1cd6cb6SAndy Yan if (rx_level <= 0) 421c1cd6cb6SAndy Yan return rx_level; 422915fcf0cSAndy Yan count = min(words, (u32)rx_level); 423c1cd6cb6SAndy Yan readsl(®s->data, buf, count); 424c1cd6cb6SAndy Yan buf += count; 425c1cd6cb6SAndy Yan words -= count; 426c1cd6cb6SAndy Yan } 427c1cd6cb6SAndy Yan 428da4954b7SAndy Yan /* handle the last non 4 bytes aligned bytes */ 429c1cd6cb6SAndy Yan if (bytes) { 430da4954b7SAndy Yan rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_RD, 1000); 431c1cd6cb6SAndy Yan if (rx_level <= 0) 432c1cd6cb6SAndy Yan return rx_level; 433c1cd6cb6SAndy Yan val = readl(®s->data); 434c1cd6cb6SAndy Yan memcpy(buf, &val, bytes); 435c1cd6cb6SAndy Yan } 436c1cd6cb6SAndy Yan 437c1cd6cb6SAndy Yan return 0; 438c1cd6cb6SAndy Yan } 439c1cd6cb6SAndy Yan 44030f161d1SAndy Yan static int rockchip_sfc_pio_xfer(struct rockchip_sfc *sfc, void *buf, u32 len) 441c1cd6cb6SAndy Yan { 442c1cd6cb6SAndy Yan int ret = 0; 443c1cd6cb6SAndy Yan 444da4954b7SAndy Yan rockchip_sfc_setup_xfer(sfc, len); 44530f161d1SAndy Yan 446c1cd6cb6SAndy Yan if (len) { 447da4954b7SAndy Yan if (sfc->rw == SFC_WR) 44830f161d1SAndy Yan ret = rockchip_sfc_write_fifo(sfc, (u32 *)buf, len); 449c1cd6cb6SAndy Yan else 45030f161d1SAndy Yan ret = rockchip_sfc_read_fifo(sfc, (u32 *)buf, len); 451c1cd6cb6SAndy Yan } 452c1cd6cb6SAndy Yan 453c1cd6cb6SAndy Yan return ret; 454c1cd6cb6SAndy Yan } 455c1cd6cb6SAndy Yan 45630f161d1SAndy Yan static int rockchip_sfc_read(struct rockchip_sfc *sfc, u32 offset, 45730f161d1SAndy Yan void *buf, size_t len) 458c1cd6cb6SAndy Yan { 4596bf64646SAndy Yan u32 dma_trans; 46030f161d1SAndy Yan u32 trb; 46130f161d1SAndy Yan u8 bytes; 46230f161d1SAndy Yan int ret; 463c1cd6cb6SAndy Yan 46437911cf6SAndy Yan if (len >= ARCH_DMA_MINALIGN) { 46530f161d1SAndy Yan bytes = len & (ARCH_DMA_MINALIGN - 1); 4666bf64646SAndy Yan dma_trans = len - bytes; 4676bf64646SAndy Yan } else { 4686bf64646SAndy Yan dma_trans = 0; 4696bf64646SAndy Yan bytes = len; 4706bf64646SAndy Yan } 4716bf64646SAndy Yan 47230f161d1SAndy Yan while (dma_trans) { 473*fa413375SJon Lin trb = min_t(size_t, dma_trans, sfc->max_iosize); 47430f161d1SAndy Yan ret = rockchip_sfc_dma_xfer(sfc, buf, trb); 47530f161d1SAndy Yan if (ret < 0) 47630f161d1SAndy Yan return ret; 47730f161d1SAndy Yan dma_trans -= trb; 47830f161d1SAndy Yan sfc->addr += trb; 47930f161d1SAndy Yan buf += trb; 4806bf64646SAndy Yan } 4816bf64646SAndy Yan 4826bf64646SAndy Yan /* 48330f161d1SAndy Yan * transfer the last non dma anligned byte by pio mode 4846bf64646SAndy Yan */ 48530f161d1SAndy Yan if (bytes) 4866bf64646SAndy Yan ret = rockchip_sfc_pio_xfer(sfc, buf, bytes); 487c1cd6cb6SAndy Yan 48830f161d1SAndy Yan return 0; 48930f161d1SAndy Yan } 49030f161d1SAndy Yan 49130f161d1SAndy Yan static int rockchip_sfc_write(struct rockchip_sfc *sfc, u32 offset, 49230f161d1SAndy Yan void *buf, size_t len) 49330f161d1SAndy Yan { 494*fa413375SJon Lin if (len > sfc->max_iosize) { 49530f161d1SAndy Yan printf("out of the max sfc trb"); 49630f161d1SAndy Yan return -EINVAL; 49730f161d1SAndy Yan } 49830f161d1SAndy Yan 49930f161d1SAndy Yan if (len && !(len & (ARCH_DMA_MINALIGN - 1))) 50030f161d1SAndy Yan return rockchip_sfc_dma_xfer(sfc, buf, len); 50130f161d1SAndy Yan else 50230f161d1SAndy Yan return rockchip_sfc_pio_xfer(sfc, buf, len); 50330f161d1SAndy Yan 50430f161d1SAndy Yan return 0; 50530f161d1SAndy Yan } 50630f161d1SAndy Yan 50730f161d1SAndy Yan static int rockchip_sfc_do_xfer(struct rockchip_sfc *sfc, void *buf, size_t len) 50830f161d1SAndy Yan { 50930f161d1SAndy Yan if (sfc->rw) 51030f161d1SAndy Yan return rockchip_sfc_write(sfc, sfc->addr, buf, len); 51130f161d1SAndy Yan else 51230f161d1SAndy Yan return rockchip_sfc_read(sfc, sfc->addr, buf, len); 513c1cd6cb6SAndy Yan } 514c1cd6cb6SAndy Yan 515c1cd6cb6SAndy Yan static int rockchip_sfc_xfer(struct udevice *dev, unsigned int bitlen, 516c1cd6cb6SAndy Yan const void *dout, void *din, unsigned long flags) 517c1cd6cb6SAndy Yan { 518c1cd6cb6SAndy Yan struct udevice *bus = dev->parent; 519c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 520c1cd6cb6SAndy Yan int len = bitlen >> 3; 521c1cd6cb6SAndy Yan u8 *pcmd = (u8 *)dout; 52230f161d1SAndy Yan void *data_buf; 523c1cd6cb6SAndy Yan int ret = 0; 524c1cd6cb6SAndy Yan 525c1cd6cb6SAndy Yan if (flags & SPI_XFER_BEGIN) { 526c1cd6cb6SAndy Yan sfc->cmd = pcmd[0]; 5276e121371SJon Lin switch (len) { 5286e121371SJon Lin case 6: /* Nor >16MB 0x6b dummy op */ 5296e121371SJon Lin sfc->addr_bits = SFC_ADDR_32BITS; 5306e121371SJon Lin sfc->dummy_bits = 8; 5316e121371SJon Lin sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24); 5326e121371SJon Lin break; 5336e121371SJon Lin case 5: /* Nor <=16MB 0x6b dummy op, Nor >16MB no dummy op */ 53498730755SJon Lin if (sfc->cmd == 0x6b) { 53598730755SJon Lin sfc->addr_bits = SFC_ADDR_24BITS; 53698730755SJon Lin sfc->dummy_bits = 8; 53798730755SJon Lin sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16); 53898730755SJon Lin } else { 5396e121371SJon Lin sfc->addr_bits = SFC_ADDR_32BITS; 5406e121371SJon Lin sfc->dummy_bits = 0; 5416e121371SJon Lin sfc->addr = pcmd[4] | (pcmd[3] << 8) | (pcmd[2] << 16) | (pcmd[1] << 24); 54298730755SJon Lin } 5436e121371SJon Lin break; 5446e121371SJon Lin case 4: /* Nand erase and read, Nor <=16MB no dummy op */ 5456e121371SJon Lin sfc->addr_bits = SFC_ADDR_24BITS; 5466e121371SJon Lin sfc->dummy_bits = 0; 547c1cd6cb6SAndy Yan sfc->addr = pcmd[3] | (pcmd[2] << 8) | (pcmd[1] << 16); 5486e121371SJon Lin break; 5496e121371SJon Lin case 3: /* Nand prog, */ 5506e121371SJon Lin sfc->addr_bits = SFC_ADDR_XBITS; 55188ea3acbSJon Lin sfc->addr_xbits_ext = 16; 55239b850deSJon Lin sfc->dummy_bits = 0; 55339b850deSJon Lin sfc->addr = pcmd[2] | pcmd[1] << 8; 5546e121371SJon Lin break; 5556e121371SJon Lin case 2: /* Nand read/write feature */ 5566e121371SJon Lin sfc->addr_bits = SFC_ADDR_XBITS; 55788ea3acbSJon Lin sfc->addr_xbits_ext = 8; 55839b850deSJon Lin sfc->dummy_bits = 0; 55939b850deSJon Lin sfc->addr = pcmd[1]; 5606e121371SJon Lin break; 5616e121371SJon Lin default: /* Nand/Nor Read/Write status */ 5626e121371SJon Lin sfc->addr_bits = SFC_ADDR_0BITS; 563da4954b7SAndy Yan sfc->dummy_bits = 0; 564da4954b7SAndy Yan sfc->addr = 0; 5656e121371SJon Lin break; 566c1cd6cb6SAndy Yan } 567*fa413375SJon Lin SFC_DBG("%s %d %x %d %d %x\n", __func__, len, sfc->cmd, 568*fa413375SJon Lin sfc->addr_bits, sfc->dummy_bits, sfc->addr); 569c1cd6cb6SAndy Yan } 570c1cd6cb6SAndy Yan if (flags & SPI_XFER_END) { 571da4954b7SAndy Yan if (din) { 572da4954b7SAndy Yan sfc->rw = SFC_RD; 57330f161d1SAndy Yan data_buf = din; 57430f161d1SAndy Yan } else { 575da4954b7SAndy Yan sfc->rw = SFC_WR; 57630f161d1SAndy Yan data_buf = (void *)dout; 577c1cd6cb6SAndy Yan } 57830f161d1SAndy Yan 57930f161d1SAndy Yan if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) { 58030f161d1SAndy Yan len = 0; 58130f161d1SAndy Yan data_buf = NULL; 58230f161d1SAndy Yan } 58330f161d1SAndy Yan 584cbd9216dSJon Lin if (sfc->cmd == 0x9f && len == 4) { 585cbd9216dSJon Lin /* SPI Nand read id */ 586cbd9216dSJon Lin sfc->addr_bits = SFC_ADDR_XBITS; 587cbd9216dSJon Lin sfc->addr_xbits_ext = 8; 588cbd9216dSJon Lin sfc->dummy_bits = 0; 589cbd9216dSJon Lin sfc->addr = 0; 590cbd9216dSJon Lin ((u8 *)data_buf)[0] = 0xff; 591cbd9216dSJon Lin ret = rockchip_sfc_do_xfer(sfc, &((u8 *)data_buf)[1], 3); 592cbd9216dSJon Lin } else { 59330f161d1SAndy Yan ret = rockchip_sfc_do_xfer(sfc, data_buf, len); 594da4954b7SAndy Yan } 595cbd9216dSJon Lin } 596c1cd6cb6SAndy Yan 597c1cd6cb6SAndy Yan return ret; 598c1cd6cb6SAndy Yan } 599c1cd6cb6SAndy Yan 600c1cd6cb6SAndy Yan static int rockchip_sfc_set_speed(struct udevice *bus, uint speed) 601c1cd6cb6SAndy Yan { 602c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 603c1cd6cb6SAndy Yan 604c1cd6cb6SAndy Yan if (speed > sfc->max_freq) 605c1cd6cb6SAndy Yan speed = sfc->max_freq; 606c1cd6cb6SAndy Yan 607c1cd6cb6SAndy Yan sfc->speed_hz = speed; 608ae52cbcbSJon Lin clk_set_rate(&sfc->clk, sfc->speed_hz); 609ae52cbcbSJon Lin SFC_DBG("%s clk= %ld\n", __func__, clk_get_rate(&sfc->clk)); 610c1cd6cb6SAndy Yan 611c1cd6cb6SAndy Yan return 0; 612c1cd6cb6SAndy Yan } 613c1cd6cb6SAndy Yan 614c1cd6cb6SAndy Yan static int rockchip_sfc_set_mode(struct udevice *bus, uint mode) 615c1cd6cb6SAndy Yan { 616c1cd6cb6SAndy Yan struct rockchip_sfc *sfc = dev_get_priv(bus); 617c1cd6cb6SAndy Yan 618c1cd6cb6SAndy Yan sfc->mode = mode; 619c1cd6cb6SAndy Yan 620c1cd6cb6SAndy Yan return 0; 621c1cd6cb6SAndy Yan } 622c1cd6cb6SAndy Yan 623c1cd6cb6SAndy Yan static const struct dm_spi_ops rockchip_sfc_ops = { 624c1cd6cb6SAndy Yan .xfer = rockchip_sfc_xfer, 625c1cd6cb6SAndy Yan .set_speed = rockchip_sfc_set_speed, 626c1cd6cb6SAndy Yan .set_mode = rockchip_sfc_set_mode, 627c1cd6cb6SAndy Yan }; 628c1cd6cb6SAndy Yan 629c1cd6cb6SAndy Yan static const struct udevice_id rockchip_sfc_ids[] = { 630c1cd6cb6SAndy Yan { .compatible = "rockchip,sfc" }, 631c1cd6cb6SAndy Yan { } 632c1cd6cb6SAndy Yan }; 633c1cd6cb6SAndy Yan 634c1cd6cb6SAndy Yan U_BOOT_DRIVER(rockchip_sfc_driver) = { 635c1cd6cb6SAndy Yan .name = "rockchip_sfc", 636c1cd6cb6SAndy Yan .id = UCLASS_SPI, 637c1cd6cb6SAndy Yan .of_match = rockchip_sfc_ids, 638c1cd6cb6SAndy Yan .ops = &rockchip_sfc_ops, 639c1cd6cb6SAndy Yan .ofdata_to_platdata = rockchip_sfc_ofdata_to_platdata, 640c1cd6cb6SAndy Yan .platdata_auto_alloc_size = sizeof(struct rockchip_sfc_platdata), 641c1cd6cb6SAndy Yan .priv_auto_alloc_size = sizeof(struct rockchip_sfc), 642c1cd6cb6SAndy Yan .probe = rockchip_sfc_probe, 643c1cd6cb6SAndy Yan }; 644