15bef6fd7SStefan Roese /* 25bef6fd7SStefan Roese * Designware master SPI core controller driver 35bef6fd7SStefan Roese * 45bef6fd7SStefan Roese * Copyright (C) 2014 Stefan Roese <sr@denx.de> 55bef6fd7SStefan Roese * 6a72f8020SStefan Roese * Very loosely based on the Linux driver: 7a72f8020SStefan Roese * drivers/spi/spi-dw.c, which is: 85bef6fd7SStefan Roese * Copyright (c) 2009, Intel Corporation. 95bef6fd7SStefan Roese * 105bef6fd7SStefan Roese * SPDX-License-Identifier: GPL-2.0 115bef6fd7SStefan Roese */ 125bef6fd7SStefan Roese 135bef6fd7SStefan Roese #include <common.h> 14*ccb5fa0aSEugeniy Paltsev #include <clk.h> 155bef6fd7SStefan Roese #include <dm.h> 165bef6fd7SStefan Roese #include <errno.h> 175bef6fd7SStefan Roese #include <malloc.h> 185bef6fd7SStefan Roese #include <spi.h> 195bef6fd7SStefan Roese #include <fdtdec.h> 205bef6fd7SStefan Roese #include <linux/compat.h> 215bef6fd7SStefan Roese #include <asm/io.h> 225bef6fd7SStefan Roese 235bef6fd7SStefan Roese DECLARE_GLOBAL_DATA_PTR; 245bef6fd7SStefan Roese 255bef6fd7SStefan Roese /* Register offsets */ 265bef6fd7SStefan Roese #define DW_SPI_CTRL0 0x00 275bef6fd7SStefan Roese #define DW_SPI_CTRL1 0x04 285bef6fd7SStefan Roese #define DW_SPI_SSIENR 0x08 295bef6fd7SStefan Roese #define DW_SPI_MWCR 0x0c 305bef6fd7SStefan Roese #define DW_SPI_SER 0x10 315bef6fd7SStefan Roese #define DW_SPI_BAUDR 0x14 325bef6fd7SStefan Roese #define DW_SPI_TXFLTR 0x18 335bef6fd7SStefan Roese #define DW_SPI_RXFLTR 0x1c 345bef6fd7SStefan Roese #define DW_SPI_TXFLR 0x20 355bef6fd7SStefan Roese #define DW_SPI_RXFLR 0x24 365bef6fd7SStefan Roese #define DW_SPI_SR 0x28 375bef6fd7SStefan Roese #define DW_SPI_IMR 0x2c 385bef6fd7SStefan Roese #define DW_SPI_ISR 0x30 395bef6fd7SStefan Roese #define DW_SPI_RISR 0x34 405bef6fd7SStefan Roese #define DW_SPI_TXOICR 0x38 415bef6fd7SStefan Roese #define DW_SPI_RXOICR 0x3c 425bef6fd7SStefan Roese #define DW_SPI_RXUICR 0x40 435bef6fd7SStefan Roese #define DW_SPI_MSTICR 0x44 445bef6fd7SStefan Roese #define DW_SPI_ICR 0x48 455bef6fd7SStefan Roese #define DW_SPI_DMACR 0x4c 465bef6fd7SStefan Roese #define DW_SPI_DMATDLR 0x50 475bef6fd7SStefan Roese #define DW_SPI_DMARDLR 0x54 485bef6fd7SStefan Roese #define DW_SPI_IDR 0x58 495bef6fd7SStefan Roese #define DW_SPI_VERSION 0x5c 505bef6fd7SStefan Roese #define DW_SPI_DR 0x60 515bef6fd7SStefan Roese 525bef6fd7SStefan Roese /* Bit fields in CTRLR0 */ 535bef6fd7SStefan Roese #define SPI_DFS_OFFSET 0 545bef6fd7SStefan Roese 555bef6fd7SStefan Roese #define SPI_FRF_OFFSET 4 565bef6fd7SStefan Roese #define SPI_FRF_SPI 0x0 575bef6fd7SStefan Roese #define SPI_FRF_SSP 0x1 585bef6fd7SStefan Roese #define SPI_FRF_MICROWIRE 0x2 595bef6fd7SStefan Roese #define SPI_FRF_RESV 0x3 605bef6fd7SStefan Roese 615bef6fd7SStefan Roese #define SPI_MODE_OFFSET 6 625bef6fd7SStefan Roese #define SPI_SCPH_OFFSET 6 635bef6fd7SStefan Roese #define SPI_SCOL_OFFSET 7 645bef6fd7SStefan Roese 655bef6fd7SStefan Roese #define SPI_TMOD_OFFSET 8 665bef6fd7SStefan Roese #define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET) 675bef6fd7SStefan Roese #define SPI_TMOD_TR 0x0 /* xmit & recv */ 685bef6fd7SStefan Roese #define SPI_TMOD_TO 0x1 /* xmit only */ 695bef6fd7SStefan Roese #define SPI_TMOD_RO 0x2 /* recv only */ 705bef6fd7SStefan Roese #define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */ 715bef6fd7SStefan Roese 725bef6fd7SStefan Roese #define SPI_SLVOE_OFFSET 10 735bef6fd7SStefan Roese #define SPI_SRL_OFFSET 11 745bef6fd7SStefan Roese #define SPI_CFS_OFFSET 12 755bef6fd7SStefan Roese 765bef6fd7SStefan Roese /* Bit fields in SR, 7 bits */ 7795e77d90SJagan Teki #define SR_MASK GENMASK(6, 0) /* cover 7 bits */ 78431a9f02SJagan Teki #define SR_BUSY BIT(0) 79431a9f02SJagan Teki #define SR_TF_NOT_FULL BIT(1) 80431a9f02SJagan Teki #define SR_TF_EMPT BIT(2) 81431a9f02SJagan Teki #define SR_RF_NOT_EMPT BIT(3) 82431a9f02SJagan Teki #define SR_RF_FULL BIT(4) 83431a9f02SJagan Teki #define SR_TX_ERR BIT(5) 84431a9f02SJagan Teki #define SR_DCOL BIT(6) 855bef6fd7SStefan Roese 86a72f8020SStefan Roese #define RX_TIMEOUT 1000 /* timeout in ms */ 875bef6fd7SStefan Roese 885bef6fd7SStefan Roese struct dw_spi_platdata { 895bef6fd7SStefan Roese s32 frequency; /* Default clock frequency, -1 for none */ 905bef6fd7SStefan Roese void __iomem *regs; 915bef6fd7SStefan Roese }; 925bef6fd7SStefan Roese 935bef6fd7SStefan Roese struct dw_spi_priv { 945bef6fd7SStefan Roese void __iomem *regs; 955bef6fd7SStefan Roese unsigned int freq; /* Default frequency */ 965bef6fd7SStefan Roese unsigned int mode; 97*ccb5fa0aSEugeniy Paltsev struct clk clk; 98*ccb5fa0aSEugeniy Paltsev unsigned long bus_clk_rate; 995bef6fd7SStefan Roese 1005bef6fd7SStefan Roese int bits_per_word; 1015bef6fd7SStefan Roese u8 cs; /* chip select pin */ 1025bef6fd7SStefan Roese u8 tmode; /* TR/TO/RO/EEPROM */ 1035bef6fd7SStefan Roese u8 type; /* SPI/SSP/MicroWire */ 1045bef6fd7SStefan Roese int len; 1055bef6fd7SStefan Roese 1065bef6fd7SStefan Roese u32 fifo_len; /* depth of the FIFO buffer */ 1075bef6fd7SStefan Roese void *tx; 1085bef6fd7SStefan Roese void *tx_end; 1095bef6fd7SStefan Roese void *rx; 1105bef6fd7SStefan Roese void *rx_end; 1115bef6fd7SStefan Roese }; 1125bef6fd7SStefan Roese 1135bef6fd7SStefan Roese static inline u32 dw_readl(struct dw_spi_priv *priv, u32 offset) 1145bef6fd7SStefan Roese { 1155bef6fd7SStefan Roese return __raw_readl(priv->regs + offset); 1165bef6fd7SStefan Roese } 1175bef6fd7SStefan Roese 1185bef6fd7SStefan Roese static inline void dw_writel(struct dw_spi_priv *priv, u32 offset, u32 val) 1195bef6fd7SStefan Roese { 1205bef6fd7SStefan Roese __raw_writel(val, priv->regs + offset); 1215bef6fd7SStefan Roese } 1225bef6fd7SStefan Roese 1235bef6fd7SStefan Roese static inline u16 dw_readw(struct dw_spi_priv *priv, u32 offset) 1245bef6fd7SStefan Roese { 1255bef6fd7SStefan Roese return __raw_readw(priv->regs + offset); 1265bef6fd7SStefan Roese } 1275bef6fd7SStefan Roese 1285bef6fd7SStefan Roese static inline void dw_writew(struct dw_spi_priv *priv, u32 offset, u16 val) 1295bef6fd7SStefan Roese { 1305bef6fd7SStefan Roese __raw_writew(val, priv->regs + offset); 1315bef6fd7SStefan Roese } 1325bef6fd7SStefan Roese 1335bef6fd7SStefan Roese static int dw_spi_ofdata_to_platdata(struct udevice *bus) 1345bef6fd7SStefan Roese { 1355bef6fd7SStefan Roese struct dw_spi_platdata *plat = bus->platdata; 1365bef6fd7SStefan Roese const void *blob = gd->fdt_blob; 137e160f7d4SSimon Glass int node = dev_of_offset(bus); 1385bef6fd7SStefan Roese 139a821c4afSSimon Glass plat->regs = (struct dw_spi *)devfdt_get_addr(bus); 1405bef6fd7SStefan Roese 1415bef6fd7SStefan Roese /* Use 500KHz as a suitable default */ 1425bef6fd7SStefan Roese plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", 1435bef6fd7SStefan Roese 500000); 1445bef6fd7SStefan Roese debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs, 1455bef6fd7SStefan Roese plat->frequency); 1465bef6fd7SStefan Roese 1475bef6fd7SStefan Roese return 0; 1485bef6fd7SStefan Roese } 1495bef6fd7SStefan Roese 1505bef6fd7SStefan Roese static inline void spi_enable_chip(struct dw_spi_priv *priv, int enable) 1515bef6fd7SStefan Roese { 1525bef6fd7SStefan Roese dw_writel(priv, DW_SPI_SSIENR, (enable ? 1 : 0)); 1535bef6fd7SStefan Roese } 1545bef6fd7SStefan Roese 1555bef6fd7SStefan Roese /* Restart the controller, disable all interrupts, clean rx fifo */ 1565bef6fd7SStefan Roese static void spi_hw_init(struct dw_spi_priv *priv) 1575bef6fd7SStefan Roese { 1585bef6fd7SStefan Roese spi_enable_chip(priv, 0); 1595bef6fd7SStefan Roese dw_writel(priv, DW_SPI_IMR, 0xff); 1605bef6fd7SStefan Roese spi_enable_chip(priv, 1); 1615bef6fd7SStefan Roese 1625bef6fd7SStefan Roese /* 1635bef6fd7SStefan Roese * Try to detect the FIFO depth if not set by interface driver, 1645bef6fd7SStefan Roese * the depth could be from 2 to 256 from HW spec 1655bef6fd7SStefan Roese */ 1665bef6fd7SStefan Roese if (!priv->fifo_len) { 1675bef6fd7SStefan Roese u32 fifo; 1685bef6fd7SStefan Roese 16952091ad1SAxel Lin for (fifo = 1; fifo < 256; fifo++) { 1705bef6fd7SStefan Roese dw_writew(priv, DW_SPI_TXFLTR, fifo); 1715bef6fd7SStefan Roese if (fifo != dw_readw(priv, DW_SPI_TXFLTR)) 1725bef6fd7SStefan Roese break; 1735bef6fd7SStefan Roese } 1745bef6fd7SStefan Roese 17552091ad1SAxel Lin priv->fifo_len = (fifo == 1) ? 0 : fifo; 1765bef6fd7SStefan Roese dw_writew(priv, DW_SPI_TXFLTR, 0); 1775bef6fd7SStefan Roese } 1785bef6fd7SStefan Roese debug("%s: fifo_len=%d\n", __func__, priv->fifo_len); 1795bef6fd7SStefan Roese } 1805bef6fd7SStefan Roese 181*ccb5fa0aSEugeniy Paltsev /* 182*ccb5fa0aSEugeniy Paltsev * We define dw_spi_get_clk function as 'weak' as some targets 183*ccb5fa0aSEugeniy Paltsev * (like SOCFPGA_GEN5 and SOCFPGA_ARRIA10) don't use standard clock API 184*ccb5fa0aSEugeniy Paltsev * and implement dw_spi_get_clk their own way in their clock manager. 185*ccb5fa0aSEugeniy Paltsev */ 186*ccb5fa0aSEugeniy Paltsev __weak int dw_spi_get_clk(struct udevice *bus, ulong *rate) 187*ccb5fa0aSEugeniy Paltsev { 188*ccb5fa0aSEugeniy Paltsev struct dw_spi_priv *priv = dev_get_priv(bus); 189*ccb5fa0aSEugeniy Paltsev int ret; 190*ccb5fa0aSEugeniy Paltsev 191*ccb5fa0aSEugeniy Paltsev ret = clk_get_by_index(bus, 0, &priv->clk); 192*ccb5fa0aSEugeniy Paltsev if (ret) 193*ccb5fa0aSEugeniy Paltsev return ret; 194*ccb5fa0aSEugeniy Paltsev 195*ccb5fa0aSEugeniy Paltsev ret = clk_enable(&priv->clk); 196*ccb5fa0aSEugeniy Paltsev if (ret && ret != -ENOSYS && ret != -ENOTSUPP) 197*ccb5fa0aSEugeniy Paltsev return ret; 198*ccb5fa0aSEugeniy Paltsev 199*ccb5fa0aSEugeniy Paltsev *rate = clk_get_rate(&priv->clk); 200*ccb5fa0aSEugeniy Paltsev if (!*rate) 201*ccb5fa0aSEugeniy Paltsev goto err_rate; 202*ccb5fa0aSEugeniy Paltsev 203*ccb5fa0aSEugeniy Paltsev debug("%s: get spi controller clk via device tree: %lu Hz\n", 204*ccb5fa0aSEugeniy Paltsev __func__, *rate); 205*ccb5fa0aSEugeniy Paltsev 206*ccb5fa0aSEugeniy Paltsev return 0; 207*ccb5fa0aSEugeniy Paltsev 208*ccb5fa0aSEugeniy Paltsev err_rate: 209*ccb5fa0aSEugeniy Paltsev clk_disable(&priv->clk); 210*ccb5fa0aSEugeniy Paltsev clk_free(&priv->clk); 211*ccb5fa0aSEugeniy Paltsev 212*ccb5fa0aSEugeniy Paltsev return -EINVAL; 213*ccb5fa0aSEugeniy Paltsev } 214*ccb5fa0aSEugeniy Paltsev 2155bef6fd7SStefan Roese static int dw_spi_probe(struct udevice *bus) 2165bef6fd7SStefan Roese { 2175bef6fd7SStefan Roese struct dw_spi_platdata *plat = dev_get_platdata(bus); 2185bef6fd7SStefan Roese struct dw_spi_priv *priv = dev_get_priv(bus); 219*ccb5fa0aSEugeniy Paltsev int ret; 2205bef6fd7SStefan Roese 2215bef6fd7SStefan Roese priv->regs = plat->regs; 2225bef6fd7SStefan Roese priv->freq = plat->frequency; 2235bef6fd7SStefan Roese 224*ccb5fa0aSEugeniy Paltsev ret = dw_spi_get_clk(bus, &priv->bus_clk_rate); 225*ccb5fa0aSEugeniy Paltsev if (ret) 226*ccb5fa0aSEugeniy Paltsev return ret; 227*ccb5fa0aSEugeniy Paltsev 2285bef6fd7SStefan Roese /* Currently only bits_per_word == 8 supported */ 2295bef6fd7SStefan Roese priv->bits_per_word = 8; 2305bef6fd7SStefan Roese 2315bef6fd7SStefan Roese priv->tmode = 0; /* Tx & Rx */ 2325bef6fd7SStefan Roese 2335bef6fd7SStefan Roese /* Basic HW init */ 2345bef6fd7SStefan Roese spi_hw_init(priv); 2355bef6fd7SStefan Roese 2365bef6fd7SStefan Roese return 0; 2375bef6fd7SStefan Roese } 2385bef6fd7SStefan Roese 2395bef6fd7SStefan Roese /* Return the max entries we can fill into tx fifo */ 2405bef6fd7SStefan Roese static inline u32 tx_max(struct dw_spi_priv *priv) 2415bef6fd7SStefan Roese { 2425bef6fd7SStefan Roese u32 tx_left, tx_room, rxtx_gap; 2435bef6fd7SStefan Roese 244a72f8020SStefan Roese tx_left = (priv->tx_end - priv->tx) / (priv->bits_per_word >> 3); 2455bef6fd7SStefan Roese tx_room = priv->fifo_len - dw_readw(priv, DW_SPI_TXFLR); 2465bef6fd7SStefan Roese 2475bef6fd7SStefan Roese /* 2485bef6fd7SStefan Roese * Another concern is about the tx/rx mismatch, we 249a72f8020SStefan Roese * thought about using (priv->fifo_len - rxflr - txflr) as 2505bef6fd7SStefan Roese * one maximum value for tx, but it doesn't cover the 2515bef6fd7SStefan Roese * data which is out of tx/rx fifo and inside the 2525bef6fd7SStefan Roese * shift registers. So a control from sw point of 2535bef6fd7SStefan Roese * view is taken. 2545bef6fd7SStefan Roese */ 2555bef6fd7SStefan Roese rxtx_gap = ((priv->rx_end - priv->rx) - (priv->tx_end - priv->tx)) / 256a72f8020SStefan Roese (priv->bits_per_word >> 3); 2575bef6fd7SStefan Roese 2585bef6fd7SStefan Roese return min3(tx_left, tx_room, (u32)(priv->fifo_len - rxtx_gap)); 2595bef6fd7SStefan Roese } 2605bef6fd7SStefan Roese 2615bef6fd7SStefan Roese /* Return the max entries we should read out of rx fifo */ 2625bef6fd7SStefan Roese static inline u32 rx_max(struct dw_spi_priv *priv) 2635bef6fd7SStefan Roese { 264a72f8020SStefan Roese u32 rx_left = (priv->rx_end - priv->rx) / (priv->bits_per_word >> 3); 2655bef6fd7SStefan Roese 2665bef6fd7SStefan Roese return min_t(u32, rx_left, dw_readw(priv, DW_SPI_RXFLR)); 2675bef6fd7SStefan Roese } 2685bef6fd7SStefan Roese 2695bef6fd7SStefan Roese static void dw_writer(struct dw_spi_priv *priv) 2705bef6fd7SStefan Roese { 2715bef6fd7SStefan Roese u32 max = tx_max(priv); 2725bef6fd7SStefan Roese u16 txw = 0; 2735bef6fd7SStefan Roese 2745bef6fd7SStefan Roese while (max--) { 2755bef6fd7SStefan Roese /* Set the tx word if the transfer's original "tx" is not null */ 2765bef6fd7SStefan Roese if (priv->tx_end - priv->len) { 277a72f8020SStefan Roese if (priv->bits_per_word == 8) 2785bef6fd7SStefan Roese txw = *(u8 *)(priv->tx); 2795bef6fd7SStefan Roese else 2805bef6fd7SStefan Roese txw = *(u16 *)(priv->tx); 2815bef6fd7SStefan Roese } 2825bef6fd7SStefan Roese dw_writew(priv, DW_SPI_DR, txw); 2835bef6fd7SStefan Roese debug("%s: tx=0x%02x\n", __func__, txw); 284a72f8020SStefan Roese priv->tx += priv->bits_per_word >> 3; 2855bef6fd7SStefan Roese } 2865bef6fd7SStefan Roese } 2875bef6fd7SStefan Roese 2885bef6fd7SStefan Roese static int dw_reader(struct dw_spi_priv *priv) 2895bef6fd7SStefan Roese { 2905bef6fd7SStefan Roese unsigned start = get_timer(0); 2915bef6fd7SStefan Roese u32 max; 2925bef6fd7SStefan Roese u16 rxw; 2935bef6fd7SStefan Roese 2945bef6fd7SStefan Roese /* Wait for rx data to be ready */ 2955bef6fd7SStefan Roese while (rx_max(priv) == 0) { 2965bef6fd7SStefan Roese if (get_timer(start) > RX_TIMEOUT) 2975bef6fd7SStefan Roese return -ETIMEDOUT; 2985bef6fd7SStefan Roese } 2995bef6fd7SStefan Roese 3005bef6fd7SStefan Roese max = rx_max(priv); 3015bef6fd7SStefan Roese 3025bef6fd7SStefan Roese while (max--) { 3035bef6fd7SStefan Roese rxw = dw_readw(priv, DW_SPI_DR); 3045bef6fd7SStefan Roese debug("%s: rx=0x%02x\n", __func__, rxw); 305a72f8020SStefan Roese 306a72f8020SStefan Roese /* 307a72f8020SStefan Roese * Care about rx only if the transfer's original "rx" is 308a72f8020SStefan Roese * not null 309a72f8020SStefan Roese */ 3105bef6fd7SStefan Roese if (priv->rx_end - priv->len) { 311a72f8020SStefan Roese if (priv->bits_per_word == 8) 3125bef6fd7SStefan Roese *(u8 *)(priv->rx) = rxw; 3135bef6fd7SStefan Roese else 3145bef6fd7SStefan Roese *(u16 *)(priv->rx) = rxw; 3155bef6fd7SStefan Roese } 316a72f8020SStefan Roese priv->rx += priv->bits_per_word >> 3; 3175bef6fd7SStefan Roese } 3185bef6fd7SStefan Roese 3195bef6fd7SStefan Roese return 0; 3205bef6fd7SStefan Roese } 3215bef6fd7SStefan Roese 3225bef6fd7SStefan Roese static int poll_transfer(struct dw_spi_priv *priv) 3235bef6fd7SStefan Roese { 3245bef6fd7SStefan Roese int ret; 3255bef6fd7SStefan Roese 3265bef6fd7SStefan Roese do { 3275bef6fd7SStefan Roese dw_writer(priv); 3285bef6fd7SStefan Roese ret = dw_reader(priv); 3295bef6fd7SStefan Roese if (ret < 0) 3305bef6fd7SStefan Roese return ret; 3315bef6fd7SStefan Roese } while (priv->rx_end > priv->rx); 3325bef6fd7SStefan Roese 3335bef6fd7SStefan Roese return 0; 3345bef6fd7SStefan Roese } 3355bef6fd7SStefan Roese 3365bef6fd7SStefan Roese static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, 3375bef6fd7SStefan Roese const void *dout, void *din, unsigned long flags) 3385bef6fd7SStefan Roese { 3395bef6fd7SStefan Roese struct udevice *bus = dev->parent; 3405bef6fd7SStefan Roese struct dw_spi_priv *priv = dev_get_priv(bus); 3415bef6fd7SStefan Roese const u8 *tx = dout; 3425bef6fd7SStefan Roese u8 *rx = din; 3435bef6fd7SStefan Roese int ret = 0; 3445bef6fd7SStefan Roese u32 cr0 = 0; 3455bef6fd7SStefan Roese u32 cs; 3465bef6fd7SStefan Roese 3475bef6fd7SStefan Roese /* spi core configured to do 8 bit transfers */ 3485bef6fd7SStefan Roese if (bitlen % 8) { 3495bef6fd7SStefan Roese debug("Non byte aligned SPI transfer.\n"); 3505bef6fd7SStefan Roese return -1; 3515bef6fd7SStefan Roese } 3525bef6fd7SStefan Roese 353a72f8020SStefan Roese cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) | 3545bef6fd7SStefan Roese (priv->mode << SPI_MODE_OFFSET) | 3555bef6fd7SStefan Roese (priv->tmode << SPI_TMOD_OFFSET); 3565bef6fd7SStefan Roese 3575bef6fd7SStefan Roese if (rx && tx) 3585bef6fd7SStefan Roese priv->tmode = SPI_TMOD_TR; 3595bef6fd7SStefan Roese else if (rx) 3605bef6fd7SStefan Roese priv->tmode = SPI_TMOD_RO; 3615bef6fd7SStefan Roese else 3625bef6fd7SStefan Roese priv->tmode = SPI_TMOD_TO; 3635bef6fd7SStefan Roese 3645bef6fd7SStefan Roese cr0 &= ~SPI_TMOD_MASK; 3655bef6fd7SStefan Roese cr0 |= (priv->tmode << SPI_TMOD_OFFSET); 3665bef6fd7SStefan Roese 367a72f8020SStefan Roese priv->len = bitlen >> 3; 3685bef6fd7SStefan Roese debug("%s: rx=%p tx=%p len=%d [bytes]\n", __func__, rx, tx, priv->len); 3695bef6fd7SStefan Roese 3705bef6fd7SStefan Roese priv->tx = (void *)tx; 3715bef6fd7SStefan Roese priv->tx_end = priv->tx + priv->len; 3725bef6fd7SStefan Roese priv->rx = rx; 3735bef6fd7SStefan Roese priv->rx_end = priv->rx + priv->len; 3745bef6fd7SStefan Roese 3755bef6fd7SStefan Roese /* Disable controller before writing control registers */ 3765bef6fd7SStefan Roese spi_enable_chip(priv, 0); 3775bef6fd7SStefan Roese 3785bef6fd7SStefan Roese debug("%s: cr0=%08x\n", __func__, cr0); 3795bef6fd7SStefan Roese /* Reprogram cr0 only if changed */ 3805bef6fd7SStefan Roese if (dw_readw(priv, DW_SPI_CTRL0) != cr0) 3815bef6fd7SStefan Roese dw_writew(priv, DW_SPI_CTRL0, cr0); 3825bef6fd7SStefan Roese 3835bef6fd7SStefan Roese /* 3845bef6fd7SStefan Roese * Configure the desired SS (slave select 0...3) in the controller 3855bef6fd7SStefan Roese * The DW SPI controller will activate and deactivate this CS 3865bef6fd7SStefan Roese * automatically. So no cs_activate() etc is needed in this driver. 3875bef6fd7SStefan Roese */ 3885bef6fd7SStefan Roese cs = spi_chip_select(dev); 3895bef6fd7SStefan Roese dw_writel(priv, DW_SPI_SER, 1 << cs); 3905bef6fd7SStefan Roese 3915bef6fd7SStefan Roese /* Enable controller after writing control registers */ 3925bef6fd7SStefan Roese spi_enable_chip(priv, 1); 3935bef6fd7SStefan Roese 3945bef6fd7SStefan Roese /* Start transfer in a polling loop */ 3955bef6fd7SStefan Roese ret = poll_transfer(priv); 3965bef6fd7SStefan Roese 3975bef6fd7SStefan Roese return ret; 3985bef6fd7SStefan Roese } 3995bef6fd7SStefan Roese 4005bef6fd7SStefan Roese static int dw_spi_set_speed(struct udevice *bus, uint speed) 4015bef6fd7SStefan Roese { 4025bef6fd7SStefan Roese struct dw_spi_platdata *plat = bus->platdata; 4035bef6fd7SStefan Roese struct dw_spi_priv *priv = dev_get_priv(bus); 4045bef6fd7SStefan Roese u16 clk_div; 4055bef6fd7SStefan Roese 4065bef6fd7SStefan Roese if (speed > plat->frequency) 4075bef6fd7SStefan Roese speed = plat->frequency; 4085bef6fd7SStefan Roese 4095bef6fd7SStefan Roese /* Disable controller before writing control registers */ 4105bef6fd7SStefan Roese spi_enable_chip(priv, 0); 4115bef6fd7SStefan Roese 4125bef6fd7SStefan Roese /* clk_div doesn't support odd number */ 413*ccb5fa0aSEugeniy Paltsev clk_div = priv->bus_clk_rate / speed; 4145bef6fd7SStefan Roese clk_div = (clk_div + 1) & 0xfffe; 4155bef6fd7SStefan Roese dw_writel(priv, DW_SPI_BAUDR, clk_div); 4165bef6fd7SStefan Roese 4175bef6fd7SStefan Roese /* Enable controller after writing control registers */ 4185bef6fd7SStefan Roese spi_enable_chip(priv, 1); 4195bef6fd7SStefan Roese 4205bef6fd7SStefan Roese priv->freq = speed; 4215bef6fd7SStefan Roese debug("%s: regs=%p speed=%d clk_div=%d\n", __func__, priv->regs, 4225bef6fd7SStefan Roese priv->freq, clk_div); 4235bef6fd7SStefan Roese 4245bef6fd7SStefan Roese return 0; 4255bef6fd7SStefan Roese } 4265bef6fd7SStefan Roese 4275bef6fd7SStefan Roese static int dw_spi_set_mode(struct udevice *bus, uint mode) 4285bef6fd7SStefan Roese { 4295bef6fd7SStefan Roese struct dw_spi_priv *priv = dev_get_priv(bus); 4305bef6fd7SStefan Roese 4315bef6fd7SStefan Roese /* 4325bef6fd7SStefan Roese * Can't set mode yet. Since this depends on if rx, tx, or 4335bef6fd7SStefan Roese * rx & tx is requested. So we have to defer this to the 4345bef6fd7SStefan Roese * real transfer function. 4355bef6fd7SStefan Roese */ 4365bef6fd7SStefan Roese priv->mode = mode; 4375bef6fd7SStefan Roese debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode); 4385bef6fd7SStefan Roese 4395bef6fd7SStefan Roese return 0; 4405bef6fd7SStefan Roese } 4415bef6fd7SStefan Roese 4425bef6fd7SStefan Roese static const struct dm_spi_ops dw_spi_ops = { 4435bef6fd7SStefan Roese .xfer = dw_spi_xfer, 4445bef6fd7SStefan Roese .set_speed = dw_spi_set_speed, 4455bef6fd7SStefan Roese .set_mode = dw_spi_set_mode, 4465bef6fd7SStefan Roese /* 4475bef6fd7SStefan Roese * cs_info is not needed, since we require all chip selects to be 4485bef6fd7SStefan Roese * in the device tree explicitly 4495bef6fd7SStefan Roese */ 4505bef6fd7SStefan Roese }; 4515bef6fd7SStefan Roese 4525bef6fd7SStefan Roese static const struct udevice_id dw_spi_ids[] = { 45374114862SMarek Vasut { .compatible = "snps,dw-apb-ssi" }, 4545bef6fd7SStefan Roese { } 4555bef6fd7SStefan Roese }; 4565bef6fd7SStefan Roese 4575bef6fd7SStefan Roese U_BOOT_DRIVER(dw_spi) = { 4585bef6fd7SStefan Roese .name = "dw_spi", 4595bef6fd7SStefan Roese .id = UCLASS_SPI, 4605bef6fd7SStefan Roese .of_match = dw_spi_ids, 4615bef6fd7SStefan Roese .ops = &dw_spi_ops, 4625bef6fd7SStefan Roese .ofdata_to_platdata = dw_spi_ofdata_to_platdata, 4635bef6fd7SStefan Roese .platdata_auto_alloc_size = sizeof(struct dw_spi_platdata), 4645bef6fd7SStefan Roese .priv_auto_alloc_size = sizeof(struct dw_spi_priv), 4655bef6fd7SStefan Roese .probe = dw_spi_probe, 4665bef6fd7SStefan Roese }; 467