1*09258a9dSJon Lin // SPDX-License-Identifier: GPL-2.0-only 2c1cd6cb6SAndy Yan /* 3*09258a9dSJon Lin * Rockchip Serial Flash Controller Driver 4c1cd6cb6SAndy Yan * 5*09258a9dSJon Lin * Copyright (c) 2017-2021, Rockchip Inc. 6*09258a9dSJon Lin * Author: Shawn Lin <shawn.lin@rock-chips.com> 7*09258a9dSJon Lin * Chris Morgan <macromorgan@hotmail.com> 8*09258a9dSJon Lin * Jon Lin <Jon.lin@rock-chips.com> 9c1cd6cb6SAndy Yan */ 10c1cd6cb6SAndy Yan 11*09258a9dSJon Lin #include <asm/io.h> 1237911cf6SAndy Yan #include <bouncebuf.h> 13c1cd6cb6SAndy Yan #include <clk.h> 14c1cd6cb6SAndy Yan #include <dm.h> 15*09258a9dSJon Lin #include <linux/bitops.h> 16*09258a9dSJon Lin #include <linux/delay.h> 17*09258a9dSJon Lin #include <linux/iopoll.h> 18c1cd6cb6SAndy Yan #include <spi.h> 19*09258a9dSJon Lin #include <spi-mem.h> 20c1cd6cb6SAndy Yan 21*09258a9dSJon Lin /* System control */ 22*09258a9dSJon Lin #define SFC_CTRL 0x0 23*09258a9dSJon Lin #define SFC_CTRL_PHASE_SEL_NEGETIVE BIT(1) 24*09258a9dSJon Lin #define SFC_CTRL_CMD_BITS_SHIFT 8 25*09258a9dSJon Lin #define SFC_CTRL_ADDR_BITS_SHIFT 10 26*09258a9dSJon Lin #define SFC_CTRL_DATA_BITS_SHIFT 12 27c1cd6cb6SAndy Yan 28*09258a9dSJon Lin /* Interrupt mask */ 29*09258a9dSJon Lin #define SFC_IMR 0x4 30*09258a9dSJon Lin #define SFC_IMR_RX_FULL BIT(0) 31*09258a9dSJon Lin #define SFC_IMR_RX_UFLOW BIT(1) 32*09258a9dSJon Lin #define SFC_IMR_TX_OFLOW BIT(2) 33*09258a9dSJon Lin #define SFC_IMR_TX_EMPTY BIT(3) 34*09258a9dSJon Lin #define SFC_IMR_TRAN_FINISH BIT(4) 35*09258a9dSJon Lin #define SFC_IMR_BUS_ERR BIT(5) 36*09258a9dSJon Lin #define SFC_IMR_NSPI_ERR BIT(6) 37*09258a9dSJon Lin #define SFC_IMR_DMA BIT(7) 3839b850deSJon Lin 39*09258a9dSJon Lin /* Interrupt clear */ 40*09258a9dSJon Lin #define SFC_ICLR 0x8 41*09258a9dSJon Lin #define SFC_ICLR_RX_FULL BIT(0) 42*09258a9dSJon Lin #define SFC_ICLR_RX_UFLOW BIT(1) 43*09258a9dSJon Lin #define SFC_ICLR_TX_OFLOW BIT(2) 44*09258a9dSJon Lin #define SFC_ICLR_TX_EMPTY BIT(3) 45*09258a9dSJon Lin #define SFC_ICLR_TRAN_FINISH BIT(4) 46*09258a9dSJon Lin #define SFC_ICLR_BUS_ERR BIT(5) 47*09258a9dSJon Lin #define SFC_ICLR_NSPI_ERR BIT(6) 48*09258a9dSJon Lin #define SFC_ICLR_DMA BIT(7) 4939b850deSJon Lin 50*09258a9dSJon Lin /* FIFO threshold level */ 51*09258a9dSJon Lin #define SFC_FTLR 0xc 52*09258a9dSJon Lin #define SFC_FTLR_TX_SHIFT 0 53*09258a9dSJon Lin #define SFC_FTLR_TX_MASK 0x1f 54*09258a9dSJon Lin #define SFC_FTLR_RX_SHIFT 8 55*09258a9dSJon Lin #define SFC_FTLR_RX_MASK 0x1f 56c6d59f03SAndy Yan 57*09258a9dSJon Lin /* Reset FSM and FIFO */ 58*09258a9dSJon Lin #define SFC_RCVR 0x10 59*09258a9dSJon Lin #define SFC_RCVR_RESET BIT(0) 60c6d59f03SAndy Yan 61*09258a9dSJon Lin /* Enhanced mode */ 62*09258a9dSJon Lin #define SFC_AX 0x14 63c6d59f03SAndy Yan 64*09258a9dSJon Lin /* Address Bit number */ 65*09258a9dSJon Lin #define SFC_ABIT 0x18 66c6d59f03SAndy Yan 67*09258a9dSJon Lin /* Interrupt status */ 68*09258a9dSJon Lin #define SFC_ISR 0x1c 69*09258a9dSJon Lin #define SFC_ISR_RX_FULL_SHIFT BIT(0) 70*09258a9dSJon Lin #define SFC_ISR_RX_UFLOW_SHIFT BIT(1) 71*09258a9dSJon Lin #define SFC_ISR_TX_OFLOW_SHIFT BIT(2) 72*09258a9dSJon Lin #define SFC_ISR_TX_EMPTY_SHIFT BIT(3) 73*09258a9dSJon Lin #define SFC_ISR_TX_FINISH_SHIFT BIT(4) 74*09258a9dSJon Lin #define SFC_ISR_BUS_ERR_SHIFT BIT(5) 75*09258a9dSJon Lin #define SFC_ISR_NSPI_ERR_SHIFT BIT(6) 76*09258a9dSJon Lin #define SFC_ISR_DMA_SHIFT BIT(7) 77c6d59f03SAndy Yan 78*09258a9dSJon Lin /* FIFO status */ 79*09258a9dSJon Lin #define SFC_FSR 0x20 80*09258a9dSJon Lin #define SFC_FSR_TX_IS_FULL BIT(0) 81*09258a9dSJon Lin #define SFC_FSR_TX_IS_EMPTY BIT(1) 82*09258a9dSJon Lin #define SFC_FSR_RX_IS_EMPTY BIT(2) 83*09258a9dSJon Lin #define SFC_FSR_RX_IS_FULL BIT(3) 84*09258a9dSJon Lin #define SFC_FSR_TXLV_MASK GENMASK(12, 8) 85*09258a9dSJon Lin #define SFC_FSR_TXLV_SHIFT 8 86*09258a9dSJon Lin #define SFC_FSR_RXLV_MASK GENMASK(20, 16) 87*09258a9dSJon Lin #define SFC_FSR_RXLV_SHIFT 16 88c6d59f03SAndy Yan 89*09258a9dSJon Lin /* FSM status */ 90*09258a9dSJon Lin #define SFC_SR 0x24 91*09258a9dSJon Lin #define SFC_SR_IS_IDLE 0x0 92*09258a9dSJon Lin #define SFC_SR_IS_BUSY 0x1 93c6d59f03SAndy Yan 94*09258a9dSJon Lin /* Raw interrupt status */ 95*09258a9dSJon Lin #define SFC_RISR 0x28 96*09258a9dSJon Lin #define SFC_RISR_RX_FULL BIT(0) 97*09258a9dSJon Lin #define SFC_RISR_RX_UNDERFLOW BIT(1) 98*09258a9dSJon Lin #define SFC_RISR_TX_OVERFLOW BIT(2) 99*09258a9dSJon Lin #define SFC_RISR_TX_EMPTY BIT(3) 100*09258a9dSJon Lin #define SFC_RISR_TRAN_FINISH BIT(4) 101*09258a9dSJon Lin #define SFC_RISR_BUS_ERR BIT(5) 102*09258a9dSJon Lin #define SFC_RISR_NSPI_ERR BIT(6) 103*09258a9dSJon Lin #define SFC_RISR_DMA BIT(7) 104c6d59f03SAndy Yan 105*09258a9dSJon Lin /* Version */ 106*09258a9dSJon Lin #define SFC_VER 0x2C 107fa413375SJon Lin #define SFC_VER_3 0x3 108fa413375SJon Lin #define SFC_VER_4 0x4 10932ed8ff2SJon Lin #define SFC_VER_5 0x5 110fa413375SJon Lin 111*09258a9dSJon Lin /* Delay line controller resiter */ 112*09258a9dSJon Lin #define SFC_DLL_CTRL0 0x3C 113*09258a9dSJon Lin #define SFC_DLL_CTRL0_SCLK_SMP_DLL BIT(15) 114*09258a9dSJon Lin #define SFC_DLL_CTRL0_DLL_MAX_VER4 0xFFU 115*09258a9dSJon Lin #define SFC_DLL_CTRL0_DLL_MAX_VER5 0x1FFU 1163959311fSJon Lin 117*09258a9dSJon Lin /* Master trigger */ 118*09258a9dSJon Lin #define SFC_DMA_TRIGGER 0x80 119c1cd6cb6SAndy Yan 120*09258a9dSJon Lin /* Src or Dst addr for master */ 121*09258a9dSJon Lin #define SFC_DMA_ADDR 0x84 122*09258a9dSJon Lin 123*09258a9dSJon Lin /* Length control register extension 32GB */ 124*09258a9dSJon Lin #define SFC_LEN_CTRL 0x88 125*09258a9dSJon Lin #define SFC_LEN_CTRL_TRB_SEL 1 126*09258a9dSJon Lin #define SFC_LEN_EXT 0x8C 127*09258a9dSJon Lin 128*09258a9dSJon Lin /* Command */ 129*09258a9dSJon Lin #define SFC_CMD 0x100 130*09258a9dSJon Lin #define SFC_CMD_IDX_SHIFT 0 131*09258a9dSJon Lin #define SFC_CMD_DUMMY_SHIFT 8 132*09258a9dSJon Lin #define SFC_CMD_DIR_SHIFT 12 133*09258a9dSJon Lin #define SFC_CMD_DIR_RD 0 134*09258a9dSJon Lin #define SFC_CMD_DIR_WR 1 135*09258a9dSJon Lin #define SFC_CMD_ADDR_SHIFT 14 136*09258a9dSJon Lin #define SFC_CMD_ADDR_0BITS 0 137*09258a9dSJon Lin #define SFC_CMD_ADDR_24BITS 1 138*09258a9dSJon Lin #define SFC_CMD_ADDR_32BITS 2 139*09258a9dSJon Lin #define SFC_CMD_ADDR_XBITS 3 140*09258a9dSJon Lin #define SFC_CMD_TRAN_BYTES_SHIFT 16 141*09258a9dSJon Lin #define SFC_CMD_CS_SHIFT 30 142*09258a9dSJon Lin 143*09258a9dSJon Lin /* Address */ 144*09258a9dSJon Lin #define SFC_ADDR 0x104 145*09258a9dSJon Lin 146*09258a9dSJon Lin /* Data */ 147*09258a9dSJon Lin #define SFC_DATA 0x108 148*09258a9dSJon Lin 149*09258a9dSJon Lin /* The controller and documentation reports that it supports up to 4 CS 150*09258a9dSJon Lin * devices (0-3), however I have only been able to test a single CS (CS 0) 151*09258a9dSJon Lin * due to the configuration of my device. 152*09258a9dSJon Lin */ 153*09258a9dSJon Lin #define SFC_MAX_CHIPSELECT_NUM 4 154*09258a9dSJon Lin 155*09258a9dSJon Lin /* The SFC can transfer max 16KB - 1 at one time 156*09258a9dSJon Lin * we set it to 15.5KB here for alignment. 157*09258a9dSJon Lin */ 158*09258a9dSJon Lin #define SFC_MAX_IOSIZE_VER3 (512 * 31) 159*09258a9dSJon Lin 160*09258a9dSJon Lin #define SFC_MAX_IOSIZE_VER4 (0xFFFFFFFFU) 161*09258a9dSJon Lin 162*09258a9dSJon Lin /* DMA is only enabled for large data transmission */ 163*09258a9dSJon Lin #define SFC_DMA_TRANS_THRETHOLD (0x40) 164*09258a9dSJon Lin 165*09258a9dSJon Lin /* Maximum clock values from datasheet suggest keeping clock value under 166*09258a9dSJon Lin * 150MHz. No minimum or average value is suggested, but the U-boot BSP driver 167*09258a9dSJon Lin * has a minimum of 10MHz and a default of 80MHz which seems reasonable. 168*09258a9dSJon Lin */ 169*09258a9dSJon Lin #define SFC_MIN_SPEED_HZ (10 * 1000 * 1000) 170*09258a9dSJon Lin #define SFC_DEFAULT_SPEED_HZ (80 * 1000 * 1000) 171*09258a9dSJon Lin #define SFC_MAX_SPEED_HZ (150 * 1000 * 1000) 172c1cd6cb6SAndy Yan 173c1cd6cb6SAndy Yan struct rockchip_sfc { 174*09258a9dSJon Lin void __iomem *regbase; 175*09258a9dSJon Lin struct clk hclk; 176c1cd6cb6SAndy Yan struct clk clk; 177*09258a9dSJon Lin u32 max_freq; 178*09258a9dSJon Lin u32 speed; 179*09258a9dSJon Lin bool use_dma; 180fa413375SJon Lin u32 max_iosize; 181*09258a9dSJon Lin u16 version; 182c1cd6cb6SAndy Yan }; 183c1cd6cb6SAndy Yan 184*09258a9dSJon Lin static int rockchip_sfc_reset(struct rockchip_sfc *sfc) 185*09258a9dSJon Lin { 186*09258a9dSJon Lin int err; 187*09258a9dSJon Lin u32 status; 188*09258a9dSJon Lin 189*09258a9dSJon Lin writel(SFC_RCVR_RESET, sfc->regbase + SFC_RCVR); 190*09258a9dSJon Lin 191*09258a9dSJon Lin err = readl_poll_timeout(sfc->regbase + SFC_RCVR, status, 192*09258a9dSJon Lin !(status & SFC_RCVR_RESET), 193*09258a9dSJon Lin 1000000); 194*09258a9dSJon Lin if (err) 195*09258a9dSJon Lin printf("SFC reset never finished\n"); 196*09258a9dSJon Lin 197*09258a9dSJon Lin /* Still need to clear the masked interrupt from RISR */ 198*09258a9dSJon Lin writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); 199*09258a9dSJon Lin 200*09258a9dSJon Lin debug("reset\n"); 201*09258a9dSJon Lin 202*09258a9dSJon Lin return err; 203*09258a9dSJon Lin } 204*09258a9dSJon Lin 205*09258a9dSJon Lin static u16 rockchip_sfc_get_version(struct rockchip_sfc *sfc) 206*09258a9dSJon Lin { 207*09258a9dSJon Lin return (u16)(readl(sfc->regbase + SFC_VER) & 0xffff); 208*09258a9dSJon Lin } 209*09258a9dSJon Lin 210*09258a9dSJon Lin static u32 rockchip_sfc_get_max_iosize(struct rockchip_sfc *sfc) 211*09258a9dSJon Lin { 212*09258a9dSJon Lin if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) 213*09258a9dSJon Lin return SFC_MAX_IOSIZE_VER4; 214*09258a9dSJon Lin 215*09258a9dSJon Lin return SFC_MAX_IOSIZE_VER3; 216*09258a9dSJon Lin } 217*09258a9dSJon Lin 218*09258a9dSJon Lin static int rockchip_sfc_init(struct rockchip_sfc *sfc) 219*09258a9dSJon Lin { 220*09258a9dSJon Lin writel(0, sfc->regbase + SFC_CTRL); 221*09258a9dSJon Lin if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) 222*09258a9dSJon Lin writel(SFC_LEN_CTRL_TRB_SEL, sfc->regbase + SFC_LEN_CTRL); 223*09258a9dSJon Lin 224*09258a9dSJon Lin return 0; 225*09258a9dSJon Lin } 226*09258a9dSJon Lin 227c1cd6cb6SAndy Yan static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus) 228c1cd6cb6SAndy Yan { 229*09258a9dSJon Lin struct rockchip_sfc *sfc = dev_get_platdata(bus); 2305b4dcfe0SJason Zhu 231*09258a9dSJon Lin sfc->regbase = dev_read_addr_ptr(bus); 232*09258a9dSJon Lin if (ofnode_read_bool(dev_ofnode(bus), "sfc-no-dma")) 233*09258a9dSJon Lin sfc->use_dma = false; 234*09258a9dSJon Lin else 235*09258a9dSJon Lin sfc->use_dma = true; 236*09258a9dSJon Lin 2375b4dcfe0SJason Zhu #if CONFIG_IS_ENABLED(CLK) 238c1cd6cb6SAndy Yan int ret; 239c1cd6cb6SAndy Yan 240c1cd6cb6SAndy Yan ret = clk_get_by_index(bus, 0, &sfc->clk); 241c1cd6cb6SAndy Yan if (ret < 0) { 24214b86dc9SJon Lin printf("Could not get clock for %s: %d\n", bus->name, ret); 243c1cd6cb6SAndy Yan return ret; 244c1cd6cb6SAndy Yan } 245*09258a9dSJon Lin 246*09258a9dSJon Lin ret = clk_get_by_index(bus, 1, &sfc->hclk); 247*09258a9dSJon Lin if (ret < 0) { 248*09258a9dSJon Lin printf("Could not get ahb clock for %s: %d\n", bus->name, ret); 249*09258a9dSJon Lin return ret; 250*09258a9dSJon Lin } 2515b4dcfe0SJason Zhu #endif 252c1cd6cb6SAndy Yan 253c1cd6cb6SAndy Yan return 0; 254c1cd6cb6SAndy Yan } 255c1cd6cb6SAndy Yan 256c1cd6cb6SAndy Yan static int rockchip_sfc_probe(struct udevice *bus) 257c1cd6cb6SAndy Yan { 258*09258a9dSJon Lin struct rockchip_sfc *sfc = dev_get_platdata(bus); 259*09258a9dSJon Lin int ret; 260c1cd6cb6SAndy Yan 261*09258a9dSJon Lin #if CONFIG_IS_ENABLED(CLK) 262*09258a9dSJon Lin ret = clk_enable(&sfc->hclk); 263*09258a9dSJon Lin if (ret) 264*09258a9dSJon Lin debug("Enable ahb clock fail %s: %d\n", bus->name, ret); 265*09258a9dSJon Lin 266*09258a9dSJon Lin ret = clk_enable(&sfc->clk); 267*09258a9dSJon Lin if (ret) 268*09258a9dSJon Lin debug("Enable clock fail for %s: %d\n", bus->name, ret); 269*09258a9dSJon Lin 270*09258a9dSJon Lin ret = clk_set_rate(&sfc->clk, SFC_DEFAULT_SPEED_HZ); 271*09258a9dSJon Lin if (ret) 272*09258a9dSJon Lin debug("Could not set sfc clock for %s: %d\n", bus->name, ret); 273*09258a9dSJon Lin #endif 274*09258a9dSJon Lin 275*09258a9dSJon Lin ret = rockchip_sfc_init(sfc); 276*09258a9dSJon Lin if (ret) 277*09258a9dSJon Lin goto err_init; 278*09258a9dSJon Lin 279*09258a9dSJon Lin sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc); 280*09258a9dSJon Lin sfc->version = rockchip_sfc_get_version(sfc); 281*09258a9dSJon Lin sfc->speed = SFC_DEFAULT_SPEED_HZ; 282fa413375SJon Lin 283c1cd6cb6SAndy Yan return 0; 284c1cd6cb6SAndy Yan 285*09258a9dSJon Lin err_init: 286*09258a9dSJon Lin #if CONFIG_IS_ENABLED(CLK) 287*09258a9dSJon Lin clk_disable(&sfc->clk); 288*09258a9dSJon Lin clk_disable(&sfc->hclk); 289*09258a9dSJon Lin #endif 290c1cd6cb6SAndy Yan 291c1cd6cb6SAndy Yan return ret; 292c1cd6cb6SAndy Yan } 293c1cd6cb6SAndy Yan 294*09258a9dSJon Lin static inline int rockchip_sfc_get_fifo_level(struct rockchip_sfc *sfc, int wr) 2957ddc1c35SJon Lin { 296*09258a9dSJon Lin u32 fsr = readl(sfc->regbase + SFC_FSR); 297*09258a9dSJon Lin int level; 2987ddc1c35SJon Lin 299*09258a9dSJon Lin if (wr) 300*09258a9dSJon Lin level = (fsr & SFC_FSR_TXLV_MASK) >> SFC_FSR_TXLV_SHIFT; 301*09258a9dSJon Lin else 302*09258a9dSJon Lin level = (fsr & SFC_FSR_RXLV_MASK) >> SFC_FSR_RXLV_SHIFT; 3037ddc1c35SJon Lin 304*09258a9dSJon Lin return level; 3057ddc1c35SJon Lin } 3067ddc1c35SJon Lin 307*09258a9dSJon Lin static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int wr, u32 timeout) 308915fcf0cSAndy Yan { 309915fcf0cSAndy Yan unsigned long tbase = get_timer(0); 310*09258a9dSJon Lin int level; 311915fcf0cSAndy Yan 312*09258a9dSJon Lin while (!(level = rockchip_sfc_get_fifo_level(sfc, wr))) { 313*09258a9dSJon Lin if (get_timer(tbase) > timeout) { 314*09258a9dSJon Lin debug("%s fifo timeout\n", wr ? "write" : "read"); 3157ddc1c35SJon Lin return -ETIMEDOUT; 316*09258a9dSJon Lin } 317*09258a9dSJon Lin udelay(1); 318*09258a9dSJon Lin } 3197ddc1c35SJon Lin 320*09258a9dSJon Lin return level; 321*09258a9dSJon Lin } 322*09258a9dSJon Lin 323*09258a9dSJon Lin static void rockchip_sfc_adjust_op_work(struct spi_mem_op *op) 324*09258a9dSJon Lin { 325*09258a9dSJon Lin if (unlikely(op->dummy.nbytes && !op->addr.nbytes)) { 326*09258a9dSJon Lin /* 327*09258a9dSJon Lin * SFC not support output DUMMY cycles right after CMD cycles, so 328*09258a9dSJon Lin * treat it as ADDR cycles. 329*09258a9dSJon Lin */ 330*09258a9dSJon Lin op->addr.nbytes = op->dummy.nbytes; 331*09258a9dSJon Lin op->addr.buswidth = op->dummy.buswidth; 332*09258a9dSJon Lin op->addr.val = 0xFFFFFFFFF; 333*09258a9dSJon Lin 334*09258a9dSJon Lin op->dummy.nbytes = 0; 335*09258a9dSJon Lin } 336*09258a9dSJon Lin } 337*09258a9dSJon Lin 338*09258a9dSJon Lin static int rockchip_sfc_wait_for_dma_finished(struct rockchip_sfc *sfc, int timeout) 339*09258a9dSJon Lin { 340*09258a9dSJon Lin unsigned long tbase; 341*09258a9dSJon Lin 342*09258a9dSJon Lin /* Wait for the DMA interrupt status */ 343*09258a9dSJon Lin tbase = get_timer(0); 344*09258a9dSJon Lin while (!(readl(sfc->regbase + SFC_RISR) & SFC_RISR_DMA)) { 345*09258a9dSJon Lin if (get_timer(tbase) > timeout) { 346*09258a9dSJon Lin printf("dma timeout\n"); 347915fcf0cSAndy Yan rockchip_sfc_reset(sfc); 348*09258a9dSJon Lin 349915fcf0cSAndy Yan return -ETIMEDOUT; 350915fcf0cSAndy Yan } 351*09258a9dSJon Lin 352*09258a9dSJon Lin udelay(1); 353915fcf0cSAndy Yan } 354915fcf0cSAndy Yan 355*09258a9dSJon Lin writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); 356*09258a9dSJon Lin 357915fcf0cSAndy Yan return 0; 358915fcf0cSAndy Yan } 359915fcf0cSAndy Yan 360*09258a9dSJon Lin static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc, 361*09258a9dSJon Lin struct spi_slave *mem, 362*09258a9dSJon Lin const struct spi_mem_op *op, 363*09258a9dSJon Lin u32 len) 364c1cd6cb6SAndy Yan { 365*09258a9dSJon Lin struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(mem->dev); 366*09258a9dSJon Lin u32 ctrl = 0, cmd = 0; 367c1cd6cb6SAndy Yan 368*09258a9dSJon Lin /* set CMD */ 369*09258a9dSJon Lin cmd = op->cmd.opcode; 370*09258a9dSJon Lin ctrl |= ((op->cmd.buswidth >> 1) << SFC_CTRL_CMD_BITS_SHIFT); 371*09258a9dSJon Lin 372*09258a9dSJon Lin /* set ADDR */ 373*09258a9dSJon Lin if (op->addr.nbytes) { 374*09258a9dSJon Lin if (op->addr.nbytes == 4) { 375*09258a9dSJon Lin cmd |= SFC_CMD_ADDR_32BITS << SFC_CMD_ADDR_SHIFT; 376*09258a9dSJon Lin } else if (op->addr.nbytes == 3) { 377*09258a9dSJon Lin cmd |= SFC_CMD_ADDR_24BITS << SFC_CMD_ADDR_SHIFT; 378c1cd6cb6SAndy Yan } else { 379*09258a9dSJon Lin cmd |= SFC_CMD_ADDR_XBITS << SFC_CMD_ADDR_SHIFT; 380*09258a9dSJon Lin writel(op->addr.nbytes * 8 - 1, sfc->regbase + SFC_ABIT); 381*09258a9dSJon Lin } 382*09258a9dSJon Lin 383*09258a9dSJon Lin ctrl |= ((op->addr.buswidth >> 1) << SFC_CTRL_ADDR_BITS_SHIFT); 384*09258a9dSJon Lin } 385*09258a9dSJon Lin 386*09258a9dSJon Lin /* set DUMMY */ 387*09258a9dSJon Lin if (op->dummy.nbytes) { 388*09258a9dSJon Lin if (op->dummy.buswidth == 4) 389*09258a9dSJon Lin cmd |= op->dummy.nbytes * 2 << SFC_CMD_DUMMY_SHIFT; 390*09258a9dSJon Lin else if (op->dummy.buswidth == 2) 391*09258a9dSJon Lin cmd |= op->dummy.nbytes * 4 << SFC_CMD_DUMMY_SHIFT; 392c1cd6cb6SAndy Yan else 393*09258a9dSJon Lin cmd |= op->dummy.nbytes * 8 << SFC_CMD_DUMMY_SHIFT; 394c1cd6cb6SAndy Yan } 395c1cd6cb6SAndy Yan 396*09258a9dSJon Lin /* set DATA */ 397*09258a9dSJon Lin if (sfc->version >= SFC_VER_4) /* Clear it if no data to transfer */ 398*09258a9dSJon Lin writel(len, sfc->regbase + SFC_LEN_EXT); 399*09258a9dSJon Lin else 400*09258a9dSJon Lin cmd |= len << SFC_CMD_TRAN_BYTES_SHIFT; 401*09258a9dSJon Lin if (len) { 402*09258a9dSJon Lin if (op->data.dir == SPI_MEM_DATA_OUT) 403*09258a9dSJon Lin cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT; 404*09258a9dSJon Lin 405*09258a9dSJon Lin ctrl |= ((op->data.buswidth >> 1) << SFC_CTRL_DATA_BITS_SHIFT); 406*09258a9dSJon Lin } 407*09258a9dSJon Lin if (!len && op->addr.nbytes) 408*09258a9dSJon Lin cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT; 409*09258a9dSJon Lin 410*09258a9dSJon Lin /* set the Controller */ 411*09258a9dSJon Lin ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE; 412*09258a9dSJon Lin cmd |= plat->cs << SFC_CMD_CS_SHIFT; 413*09258a9dSJon Lin 414*09258a9dSJon Lin debug("addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n", 415*09258a9dSJon Lin op->addr.nbytes, op->addr.buswidth, 416*09258a9dSJon Lin op->dummy.nbytes, op->dummy.buswidth); 417*09258a9dSJon Lin debug("ctrl=%x cmd=%x addr=%llx len=%x\n", 418*09258a9dSJon Lin ctrl, cmd, op->addr.val, len); 419*09258a9dSJon Lin 420*09258a9dSJon Lin writel(ctrl, sfc->regbase + SFC_CTRL); 421*09258a9dSJon Lin writel(cmd, sfc->regbase + SFC_CMD); 422*09258a9dSJon Lin if (op->addr.nbytes) 423*09258a9dSJon Lin writel(op->addr.val, sfc->regbase + SFC_ADDR); 424*09258a9dSJon Lin 425*09258a9dSJon Lin return 0; 426c1cd6cb6SAndy Yan } 427c1cd6cb6SAndy Yan 428*09258a9dSJon Lin static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, const u8 *buf, int len) 429c1cd6cb6SAndy Yan { 430*09258a9dSJon Lin u8 bytes = len & 0x3; 431*09258a9dSJon Lin u32 dwords; 432*09258a9dSJon Lin int tx_level; 433*09258a9dSJon Lin u32 write_words; 434*09258a9dSJon Lin u32 tmp = 0; 435c1cd6cb6SAndy Yan 436*09258a9dSJon Lin dwords = len >> 2; 437*09258a9dSJon Lin while (dwords) { 438*09258a9dSJon Lin tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_WR, 1000); 439*09258a9dSJon Lin if (tx_level < 0) 440*09258a9dSJon Lin return tx_level; 441*09258a9dSJon Lin write_words = min_t(u32, tx_level, dwords); 442*09258a9dSJon Lin writesl(sfc->regbase + SFC_DATA, buf, write_words); 443*09258a9dSJon Lin buf += write_words << 2; 444*09258a9dSJon Lin dwords -= write_words; 445fa413375SJon Lin } 446c1cd6cb6SAndy Yan 447*09258a9dSJon Lin /* write the rest non word aligned bytes */ 448*09258a9dSJon Lin if (bytes) { 449*09258a9dSJon Lin tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_WR, 1000); 450*09258a9dSJon Lin if (tx_level < 0) 451*09258a9dSJon Lin return tx_level; 452*09258a9dSJon Lin memcpy(&tmp, buf, bytes); 453*09258a9dSJon Lin writel(tmp, sfc->regbase + SFC_DATA); 45439b850deSJon Lin } 455c1cd6cb6SAndy Yan 456*09258a9dSJon Lin return len; 457*09258a9dSJon Lin } 458*09258a9dSJon Lin 459*09258a9dSJon Lin static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len) 460c1cd6cb6SAndy Yan { 461*09258a9dSJon Lin u8 bytes = len & 0x3; 462*09258a9dSJon Lin u32 dwords; 463*09258a9dSJon Lin u8 read_words; 464*09258a9dSJon Lin int rx_level; 465*09258a9dSJon Lin int tmp; 466*09258a9dSJon Lin 467*09258a9dSJon Lin /* word aligned access only */ 468*09258a9dSJon Lin dwords = len >> 2; 469*09258a9dSJon Lin while (dwords) { 470*09258a9dSJon Lin rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_RD, 1000); 471*09258a9dSJon Lin if (rx_level < 0) 472*09258a9dSJon Lin return rx_level; 473*09258a9dSJon Lin read_words = min_t(u32, rx_level, dwords); 474*09258a9dSJon Lin readsl(sfc->regbase + SFC_DATA, buf, read_words); 475*09258a9dSJon Lin buf += read_words << 2; 476*09258a9dSJon Lin dwords -= read_words; 477*09258a9dSJon Lin } 478*09258a9dSJon Lin 479*09258a9dSJon Lin /* read the rest non word aligned bytes */ 480*09258a9dSJon Lin if (bytes) { 481*09258a9dSJon Lin rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_RD, 1000); 482*09258a9dSJon Lin if (rx_level < 0) 483*09258a9dSJon Lin return rx_level; 484*09258a9dSJon Lin tmp = readl(sfc->regbase + SFC_DATA); 485*09258a9dSJon Lin memcpy(buf, &tmp, bytes); 486*09258a9dSJon Lin } 487*09258a9dSJon Lin 488*09258a9dSJon Lin return len; 489*09258a9dSJon Lin } 490*09258a9dSJon Lin 491*09258a9dSJon Lin static int rockchip_sfc_fifo_transfer_dma(struct rockchip_sfc *sfc, dma_addr_t dma_buf, size_t len) 492*09258a9dSJon Lin { 493*09258a9dSJon Lin writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); 494*09258a9dSJon Lin writel((u32)dma_buf, sfc->regbase + SFC_DMA_ADDR); 495*09258a9dSJon Lin writel(0x1, sfc->regbase + SFC_DMA_TRIGGER); 496*09258a9dSJon Lin 497*09258a9dSJon Lin return len; 498*09258a9dSJon Lin } 499*09258a9dSJon Lin 500*09258a9dSJon Lin static int rockchip_sfc_xfer_data_poll(struct rockchip_sfc *sfc, 501*09258a9dSJon Lin const struct spi_mem_op *op, u32 len) 502*09258a9dSJon Lin { 503*09258a9dSJon Lin debug("xfer_poll len=%x\n", len); 504*09258a9dSJon Lin 505*09258a9dSJon Lin if (op->data.dir == SPI_MEM_DATA_OUT) 506*09258a9dSJon Lin return rockchip_sfc_write_fifo(sfc, op->data.buf.out, len); 507*09258a9dSJon Lin else 508*09258a9dSJon Lin return rockchip_sfc_read_fifo(sfc, op->data.buf.in, len); 509*09258a9dSJon Lin } 510*09258a9dSJon Lin 511*09258a9dSJon Lin static int rockchip_sfc_xfer_data_dma(struct rockchip_sfc *sfc, 512*09258a9dSJon Lin const struct spi_mem_op *op, u32 len) 513*09258a9dSJon Lin { 51437911cf6SAndy Yan struct bounce_buffer bb; 51537911cf6SAndy Yan unsigned int bb_flags; 516*09258a9dSJon Lin void *dma_buf; 517*09258a9dSJon Lin int ret; 518c1cd6cb6SAndy Yan 519*09258a9dSJon Lin debug("xfer_dma len=%x\n", len); 520*09258a9dSJon Lin 521*09258a9dSJon Lin if (op->data.dir == SPI_MEM_DATA_OUT) { 522*09258a9dSJon Lin dma_buf = (void *)op->data.buf.out; 52337911cf6SAndy Yan bb_flags = GEN_BB_READ; 524*09258a9dSJon Lin } else { 525*09258a9dSJon Lin dma_buf = (void *)op->data.buf.in; 52637911cf6SAndy Yan bb_flags = GEN_BB_WRITE; 527*09258a9dSJon Lin } 52837911cf6SAndy Yan 529*09258a9dSJon Lin ret = bounce_buffer_start(&bb, dma_buf, len, bb_flags); 53037911cf6SAndy Yan if (ret) 53137911cf6SAndy Yan return ret; 53230f161d1SAndy Yan 533*09258a9dSJon Lin ret = rockchip_sfc_fifo_transfer_dma(sfc, (dma_addr_t)bb.bounce_buffer, len); 534*09258a9dSJon Lin rockchip_sfc_wait_for_dma_finished(sfc, len * 10); 53537911cf6SAndy Yan bounce_buffer_stop(&bb); 53637911cf6SAndy Yan 537c1cd6cb6SAndy Yan return ret; 538c1cd6cb6SAndy Yan } 539c1cd6cb6SAndy Yan 540*09258a9dSJon Lin static int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us) 5417ddc1c35SJon Lin { 542c1cd6cb6SAndy Yan unsigned long tbase = get_timer(0); 543c1cd6cb6SAndy Yan int ret = 0; 544*09258a9dSJon Lin u32 timeout = timeout_us; 545c1cd6cb6SAndy Yan 546*09258a9dSJon Lin while (readl(sfc->regbase + SFC_SR) & SFC_SR_IS_BUSY) { 547*09258a9dSJon Lin if (get_timer(tbase) > timeout) { 548*09258a9dSJon Lin printf("wait sfc idle timeout\n"); 549*09258a9dSJon Lin rockchip_sfc_reset(sfc); 55030f161d1SAndy Yan 551*09258a9dSJon Lin return -ETIMEDOUT; 552*09258a9dSJon Lin } 553*09258a9dSJon Lin 554*09258a9dSJon Lin udelay(1); 555c1cd6cb6SAndy Yan } 556c1cd6cb6SAndy Yan 557c1cd6cb6SAndy Yan return ret; 558c1cd6cb6SAndy Yan } 559c1cd6cb6SAndy Yan 560*09258a9dSJon Lin static int rockchip_sfc_exec_op(struct spi_slave *mem, 561*09258a9dSJon Lin const struct spi_mem_op *op) 562c1cd6cb6SAndy Yan { 563*09258a9dSJon Lin struct rockchip_sfc *sfc = dev_get_platdata(mem->dev->parent); 564*09258a9dSJon Lin u32 len = min_t(u32, op->data.nbytes, sfc->max_iosize); 56530f161d1SAndy Yan int ret; 566c1cd6cb6SAndy Yan 5673959311fSJon Lin #if CONFIG_IS_ENABLED(CLK) 568*09258a9dSJon Lin if (unlikely(mem->max_hz != sfc->speed)) { 569*09258a9dSJon Lin ret = clk_set_rate(&sfc->clk, clamp(mem->max_hz, (uint)SFC_MIN_SPEED_HZ, 570*09258a9dSJon Lin (uint)SFC_MAX_SPEED_HZ)); 571*09258a9dSJon Lin if (ret < 0) { 572*09258a9dSJon Lin printf("set_freq=%dHz fail, check if it's the cru support level\n", 573*09258a9dSJon Lin mem->max_hz); 574*09258a9dSJon Lin return ret; 5753959311fSJon Lin } 5763959311fSJon Lin 577*09258a9dSJon Lin sfc->max_freq = mem->max_hz; 578*09258a9dSJon Lin sfc->speed = mem->max_hz; 579*09258a9dSJon Lin debug("set_freq=%dHz real_freq=%dHz\n", sfc->max_freq, sfc->speed); 5803959311fSJon Lin } 5813959311fSJon Lin #endif 5823959311fSJon Lin 583*09258a9dSJon Lin rockchip_sfc_adjust_op_work((struct spi_mem_op *)op); 584*09258a9dSJon Lin 585*09258a9dSJon Lin rockchip_sfc_xfer_setup(sfc, mem, op, len); 586*09258a9dSJon Lin if (len) { 587*09258a9dSJon Lin if (likely(sfc->use_dma) && !(len & 0x3) && len >= SFC_DMA_TRANS_THRETHOLD) 588*09258a9dSJon Lin ret = rockchip_sfc_xfer_data_dma(sfc, op, len); 589*09258a9dSJon Lin else 590*09258a9dSJon Lin ret = rockchip_sfc_xfer_data_poll(sfc, op, len); 591*09258a9dSJon Lin 592*09258a9dSJon Lin if (ret != len) { 593*09258a9dSJon Lin printf("xfer data failed ret %d dir %d\n", ret, op->data.dir); 594*09258a9dSJon Lin 595*09258a9dSJon Lin return -EIO; 596*09258a9dSJon Lin } 597*09258a9dSJon Lin } 598*09258a9dSJon Lin 599*09258a9dSJon Lin return rockchip_sfc_xfer_done(sfc, 100000); 600*09258a9dSJon Lin } 601*09258a9dSJon Lin 602*09258a9dSJon Lin static int rockchip_sfc_adjust_op_size(struct spi_slave *mem, struct spi_mem_op *op) 603c1cd6cb6SAndy Yan { 604*09258a9dSJon Lin struct rockchip_sfc *sfc = dev_get_platdata(mem->dev->parent); 605c1cd6cb6SAndy Yan 606*09258a9dSJon Lin op->data.nbytes = min(op->data.nbytes, sfc->max_iosize); 607*09258a9dSJon Lin return 0; 608c1cd6cb6SAndy Yan } 609c1cd6cb6SAndy Yan 610c1cd6cb6SAndy Yan static int rockchip_sfc_set_speed(struct udevice *bus, uint speed) 611c1cd6cb6SAndy Yan { 612*09258a9dSJon Lin /* We set up speed later for each transmission. 613*09258a9dSJon Lin */ 614c1cd6cb6SAndy Yan return 0; 615c1cd6cb6SAndy Yan } 616c1cd6cb6SAndy Yan 617c1cd6cb6SAndy Yan static int rockchip_sfc_set_mode(struct udevice *bus, uint mode) 618c1cd6cb6SAndy Yan { 619c1cd6cb6SAndy Yan return 0; 620c1cd6cb6SAndy Yan } 621c1cd6cb6SAndy Yan 622*09258a9dSJon Lin static const struct spi_controller_mem_ops rockchip_sfc_mem_ops = { 623*09258a9dSJon Lin .adjust_op_size = rockchip_sfc_adjust_op_size, 624*09258a9dSJon Lin .exec_op = rockchip_sfc_exec_op, 625*09258a9dSJon Lin }; 626*09258a9dSJon Lin 627c1cd6cb6SAndy Yan static const struct dm_spi_ops rockchip_sfc_ops = { 628*09258a9dSJon Lin .mem_ops = &rockchip_sfc_mem_ops, 629c1cd6cb6SAndy Yan .set_speed = rockchip_sfc_set_speed, 630c1cd6cb6SAndy Yan .set_mode = rockchip_sfc_set_mode, 631c1cd6cb6SAndy Yan }; 632c1cd6cb6SAndy Yan 633c1cd6cb6SAndy Yan static const struct udevice_id rockchip_sfc_ids[] = { 634c1cd6cb6SAndy Yan { .compatible = "rockchip,sfc"}, 635*09258a9dSJon Lin {}, 636c1cd6cb6SAndy Yan }; 637c1cd6cb6SAndy Yan 638c1cd6cb6SAndy Yan U_BOOT_DRIVER(rockchip_sfc_driver) = { 639c1cd6cb6SAndy Yan .name = "rockchip_sfc", 640c1cd6cb6SAndy Yan .id = UCLASS_SPI, 641c1cd6cb6SAndy Yan .of_match = rockchip_sfc_ids, 642c1cd6cb6SAndy Yan .ops = &rockchip_sfc_ops, 643c1cd6cb6SAndy Yan .ofdata_to_platdata = rockchip_sfc_ofdata_to_platdata, 644*09258a9dSJon Lin .platdata_auto_alloc_size = sizeof(struct rockchip_sfc), 645c1cd6cb6SAndy Yan .probe = rockchip_sfc_probe, 646c1cd6cb6SAndy Yan }; 647