From 9d26506a9ca9b13f114acae470bd9c8352484397 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 22 Nov 2018 11:01:05 +0100 Subject: spi: Add Amlogic Meson SPI Flash Controller driver The Amlogic Meson SoCs embeds a Flash oriented SPI Controller name SPIFC. This driver, ported from the Linux meson-spi-spifc driver, add support for this controller on the Amlogic Meson GX SoCs in U-Boot. Tested-by: Jerome Brunet Reviewed-by: Jagan Teki Signed-off-by: Neil Armstrong --- drivers/spi/Kconfig | 8 ++ drivers/spi/Makefile | 1 + drivers/spi/meson_spifc.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 drivers/spi/meson_spifc.c (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 516188ea88..6085788481 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -116,6 +116,14 @@ config ICH_SPI access the SPI NOR flash on platforms embedding this Intel ICH IP core. +config MESON_SPIFC + bool "Amlogic Meson SPI Flash Controller driver" + depends on ARCH_MESON + help + Enable the Amlogic Meson SPI Flash Controller SPIFC) driver. + This driver can be used to access the SPI NOR flash chips on + Amlogic Meson SoCs. + config MT7621_SPI bool "MediaTek MT7621 SPI driver" depends on ARCH_MT7620 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7242ea7e40..67b42daf4e 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o obj-$(CONFIG_ICH_SPI) += ich.o obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o +obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o diff --git a/drivers/spi/meson_spifc.c b/drivers/spi/meson_spifc.c new file mode 100644 index 0000000000..3d551694cb --- /dev/null +++ b/drivers/spi/meson_spifc.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Beniamino Galvani + * Copyright (C) 2018 BayLibre, SAS + * Author: Neil Armstrong + * + * Amlogic Meson SPI Flash Controller driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* register map */ +#define REG_CMD 0x00 +#define REG_ADDR 0x04 +#define REG_CTRL 0x08 +#define REG_CTRL1 0x0c +#define REG_STATUS 0x10 +#define REG_CTRL2 0x14 +#define REG_CLOCK 0x18 +#define REG_USER 0x1c +#define REG_USER1 0x20 +#define REG_USER2 0x24 +#define REG_USER3 0x28 +#define REG_USER4 0x2c +#define REG_SLAVE 0x30 +#define REG_SLAVE1 0x34 +#define REG_SLAVE2 0x38 +#define REG_SLAVE3 0x3c +#define REG_C0 0x40 +#define REG_B8 0x60 +#define REG_MAX 0x7c + +/* register fields */ +#define CMD_USER BIT(18) +#define CTRL_ENABLE_AHB BIT(17) +#define CLOCK_SOURCE BIT(31) +#define CLOCK_DIV_SHIFT 12 +#define CLOCK_DIV_MASK (0x3f << CLOCK_DIV_SHIFT) +#define CLOCK_CNT_HIGH_SHIFT 6 +#define CLOCK_CNT_HIGH_MASK (0x3f << CLOCK_CNT_HIGH_SHIFT) +#define CLOCK_CNT_LOW_SHIFT 0 +#define CLOCK_CNT_LOW_MASK (0x3f << CLOCK_CNT_LOW_SHIFT) +#define USER_DIN_EN_MS BIT(0) +#define USER_CMP_MODE BIT(2) +#define USER_CLK_NOT_INV BIT(7) +#define USER_UC_DOUT_SEL BIT(27) +#define USER_UC_DIN_SEL BIT(28) +#define USER_UC_MASK ((BIT(5) - 1) << 27) +#define USER1_BN_UC_DOUT_SHIFT 17 +#define USER1_BN_UC_DOUT_MASK (0xff << 16) +#define USER1_BN_UC_DIN_SHIFT 8 +#define USER1_BN_UC_DIN_MASK (0xff << 8) +#define USER4_CS_POL_HIGH BIT(23) +#define USER4_IDLE_CLK_HIGH BIT(29) +#define USER4_CS_ACT BIT(30) +#define SLAVE_TRST_DONE BIT(4) +#define SLAVE_OP_MODE BIT(30) +#define SLAVE_SW_RST BIT(31) + +#define SPIFC_BUFFER_SIZE 64 + +struct meson_spifc_priv { + struct regmap *regmap; + struct clk clk; +}; + +/** + * meson_spifc_drain_buffer() - copy data from device buffer to memory + * @spifc: the Meson SPI device + * @buf: the destination buffer + * @len: number of bytes to copy + */ +static void meson_spifc_drain_buffer(struct meson_spifc_priv *spifc, + u8 *buf, int len) +{ + u32 data; + int i = 0; + + while (i < len) { + regmap_read(spifc->regmap, REG_C0 + i, &data); + + if (len - i >= 4) { + *((u32 *)buf) = data; + buf += 4; + } else { + memcpy(buf, &data, len - i); + break; + } + i += 4; + } +} + +/** + * meson_spifc_fill_buffer() - copy data from memory to device buffer + * @spifc: the Meson SPI device + * @buf: the source buffer + * @len: number of bytes to copy + */ +static void meson_spifc_fill_buffer(struct meson_spifc_priv *spifc, + const u8 *buf, int len) +{ + u32 data = 0; + int i = 0; + + while (i < len) { + if (len - i >= 4) + data = *(u32 *)buf; + else + memcpy(&data, buf, len - i); + + regmap_write(spifc->regmap, REG_C0 + i, data); + + buf += 4; + i += 4; + } +} + +/** + * meson_spifc_txrx() - transfer a chunk of data + * @spifc: the Meson SPI device + * @dout: data buffer for TX + * @din: data buffer for RX + * @offset: offset of the data to transfer + * @len: length of the data to transfer + * @last_xfer: whether this is the last transfer of the message + * @last_chunk: whether this is the last chunk of the transfer + * Return: 0 on success, a negative value on error + */ +static int meson_spifc_txrx(struct meson_spifc_priv *spifc, + const u8 *dout, u8 *din, int offset, + int len, bool last_xfer, bool last_chunk) +{ + bool keep_cs = true; + u32 data; + int ret; + + if (dout) + meson_spifc_fill_buffer(spifc, dout + offset, len); + + /* enable DOUT stage */ + regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK, + USER_UC_DOUT_SEL); + regmap_write(spifc->regmap, REG_USER1, + (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT); + + /* enable data input during DOUT */ + regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS, + USER_DIN_EN_MS); + + if (last_chunk && last_xfer) + keep_cs = false; + + regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT, + keep_cs ? USER4_CS_ACT : 0); + + /* clear transition done bit */ + regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0); + /* start transfer */ + regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER); + + /* wait for the current operation to terminate */ + ret = regmap_read_poll_timeout(spifc->regmap, REG_SLAVE, data, + (data & SLAVE_TRST_DONE), + 0, 5 * CONFIG_SYS_HZ); + + if (!ret && din) + meson_spifc_drain_buffer(spifc, din + offset, len); + + return ret; +} + +/** + * meson_spifc_xfer() - perform a single transfer + * @dev: the SPI controller device + * @bitlen: length of the transfer + * @dout: data buffer for TX + * @din: data buffer for RX + * @flags: transfer flags + * Return: 0 on success, a negative value on error + */ +static int meson_spifc_xfer(struct udevice *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct meson_spifc_priv *spifc = dev_get_priv(slave->parent); + int blen = bitlen / 8; + int len, done = 0, ret = 0; + + if (bitlen % 8) + return -EINVAL; + + debug("xfer len %d (%d) dout %p din %p\n", bitlen, blen, dout, din); + + regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0); + + while (done < blen && !ret) { + len = min_t(int, blen - done, SPIFC_BUFFER_SIZE); + ret = meson_spifc_txrx(spifc, dout, din, done, len, + flags & SPI_XFER_END, + done + len >= blen); + done += len; + } + + regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, + CTRL_ENABLE_AHB); + + return ret; +} + +/** + * meson_spifc_set_speed() - program the clock divider + * @dev: the SPI controller device + * @speed: desired speed in Hz + */ +static int meson_spifc_set_speed(struct udevice *dev, uint speed) +{ + struct meson_spifc_priv *spifc = dev_get_priv(dev); + unsigned long parent, value; + int n; + + parent = clk_get_rate(&spifc->clk); + n = max_t(int, parent / speed - 1, 1); + + debug("parent %lu, speed %u, n %d\n", parent, speed, n); + + value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK; + value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK; + value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) & + CLOCK_CNT_HIGH_MASK; + + regmap_write(spifc->regmap, REG_CLOCK, value); + + return 0; +} + +/** + * meson_spifc_set_mode() - setups the SPI bus mode + * @dev: the SPI controller device + * @mode: desired mode bitfield + * Return: 0 on success, -ENODEV on error + */ +static int meson_spifc_set_mode(struct udevice *dev, uint mode) +{ + struct meson_spifc_priv *spifc = dev_get_priv(dev); + + if (mode & (SPI_CPHA | SPI_RX_QUAD | SPI_RX_DUAL | + SPI_TX_QUAD | SPI_TX_DUAL)) + return -ENODEV; + + regmap_update_bits(spifc->regmap, REG_USER, USER_CLK_NOT_INV, + mode & SPI_CPOL ? USER_CLK_NOT_INV : 0); + + regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_POL_HIGH, + mode & SPI_CS_HIGH ? USER4_CS_POL_HIGH : 0); + + return 0; +} + +/** + * meson_spifc_hw_init() - reset and initialize the SPI controller + * @spifc: the Meson SPI device + */ +static void meson_spifc_hw_init(struct meson_spifc_priv *spifc) +{ + /* reset device */ + regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST, + SLAVE_SW_RST); + /* disable compatible mode */ + regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0); + /* set master mode */ + regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0); +} + +static const struct dm_spi_ops meson_spifc_ops = { + .xfer = meson_spifc_xfer, + .set_speed = meson_spifc_set_speed, + .set_mode = meson_spifc_set_mode, +}; + +static int meson_spifc_probe(struct udevice *dev) +{ + struct meson_spifc_priv *priv = dev_get_priv(dev); + int ret; + + ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); + if (ret) + return ret; + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + meson_spifc_hw_init(priv); + + return 0; +} + +static const struct udevice_id meson_spifc_ids[] = { + { .compatible = "amlogic,meson-gxbb-spifc", }, + { } +}; + +U_BOOT_DRIVER(meson_spifc) = { + .name = "meson_spifc", + .id = UCLASS_SPI, + .of_match = meson_spifc_ids, + .ops = &meson_spifc_ops, + .probe = meson_spifc_probe, + .priv_auto_alloc_size = sizeof(struct meson_spifc_priv), +}; -- cgit v1.2.3 From 052cafd2a56e90270aea7f0335a232ca2dea3c99 Mon Sep 17 00:00:00 2001 From: Guochun Mao Date: Fri, 12 Oct 2018 15:01:06 +0800 Subject: spi: mtk_qspi: add qspi driver for MT7629 SoC This patch adds MT7629 qspi driver for accessing SPI NOR flash. Signed-off-by: Guochun Mao Reviewed-by: Simon Glass Reviewed-by: Jagan Teki --- drivers/spi/Kconfig | 7 + drivers/spi/Makefile | 1 + drivers/spi/mtk_qspi.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 367 insertions(+) create mode 100644 drivers/spi/mtk_qspi.c (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 6085788481..4a8a38b863 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -132,6 +132,13 @@ config MT7621_SPI the SPI NOR flash on platforms embedding this Ralink / MediaTek SPI core, like MT7621/7628/7688. +config MTK_QSPI + bool "Mediatek QSPI driver" + help + Enable the Mediatek QSPI driver. This driver can be + used to access the SPI NOR flash on platforms embedding this + Mediatek QSPI IP core. + config MVEBU_A3700_SPI bool "Marvell Armada 3700 SPI driver" select CLK_ARMADA_3720 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 67b42daf4e..392a925795 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o +obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o obj-$(CONFIG_MXC_SPI) += mxc_spi.o diff --git a/drivers/spi/mtk_qspi.c b/drivers/spi/mtk_qspi.c new file mode 100644 index 0000000000..b510733e92 --- /dev/null +++ b/drivers/spi/mtk_qspi.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek, Inc. + * Author : Guochun.Mao@mediatek.com + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Register Offset */ +struct mtk_qspi_regs { + u32 cmd; + u32 cnt; + u32 rdsr; + u32 rdata; + u32 radr[3]; + u32 wdata; + u32 prgdata[6]; + u32 shreg[10]; + u32 cfg[2]; + u32 shreg10; + u32 mode_mon; + u32 status[4]; + u32 flash_time; + u32 flash_cfg; + u32 reserved_0[3]; + u32 sf_time; + u32 pp_dw_data; + u32 reserved_1; + u32 delsel_0[2]; + u32 intrstus; + u32 intren; + u32 reserved_2; + u32 cfg3; + u32 reserved_3; + u32 chksum; + u32 aaicmd; + u32 wrprot; + u32 radr3; + u32 dual; + u32 delsel_1[3]; +}; + +struct mtk_qspi_platdata { + fdt_addr_t reg_base; + fdt_addr_t mem_base; +}; + +struct mtk_qspi_priv { + struct mtk_qspi_regs *regs; + unsigned long *mem_base; + u8 op; + u8 tx[3]; /* only record max 3 bytes paras, when it's address. */ + u32 txlen; /* dout buffer length - op code length */ + u8 *rx; + u32 rxlen; +}; + +#define MTK_QSPI_CMD_POLLINGREG_US 500000 +#define MTK_QSPI_WRBUF_SIZE 256 +#define MTK_QSPI_COMMAND_ENABLE 0x30 + +/* NOR flash controller commands */ +#define MTK_QSPI_RD_TRIGGER BIT(0) +#define MTK_QSPI_READSTATUS BIT(1) +#define MTK_QSPI_PRG_CMD BIT(2) +#define MTK_QSPI_WR_TRIGGER BIT(4) +#define MTK_QSPI_WRITESTATUS BIT(5) +#define MTK_QSPI_AUTOINC BIT(7) + +#define MTK_QSPI_MAX_RX_TX_SHIFT 0x6 +#define MTK_QSPI_MAX_SHIFT 0x8 + +#define MTK_QSPI_WR_BUF_ENABLE 0x1 +#define MTK_QSPI_WR_BUF_DISABLE 0x0 + +static int mtk_qspi_execute_cmd(struct mtk_qspi_priv *priv, u8 cmd) +{ + u8 tmp; + u8 val = cmd & ~MTK_QSPI_AUTOINC; + + writeb(cmd, &priv->regs->cmd); + + return readb_poll_timeout(&priv->regs->cmd, tmp, !(val & tmp), + MTK_QSPI_CMD_POLLINGREG_US); +} + +static int mtk_qspi_tx_rx(struct mtk_qspi_priv *priv) +{ + int len = 1 + priv->txlen + priv->rxlen; + int i, ret, idx; + + if (len > MTK_QSPI_MAX_SHIFT) + return -ERR_INVAL; + + writeb(len * 8, &priv->regs->cnt); + + /* start at PRGDATA5, go down to PRGDATA0 */ + idx = MTK_QSPI_MAX_RX_TX_SHIFT - 1; + + /* opcode */ + writeb(priv->op, &priv->regs->prgdata[idx]); + idx--; + + /* program TX data */ + for (i = 0; i < priv->txlen; i++, idx--) + writeb(priv->tx[i], &priv->regs->prgdata[idx]); + + /* clear out rest of TX registers */ + while (idx >= 0) { + writeb(0, &priv->regs->prgdata[idx]); + idx--; + } + + ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_PRG_CMD); + if (ret) + return ret; + + /* restart at first RX byte */ + idx = priv->rxlen - 1; + + /* read out RX data */ + for (i = 0; i < priv->rxlen; i++, idx--) + priv->rx[i] = readb(&priv->regs->shreg[idx]); + + return 0; +} + +static int mtk_qspi_read(struct mtk_qspi_priv *priv, + u32 addr, u8 *buf, u32 len) +{ + memcpy(buf, (u8 *)priv->mem_base + addr, len); + return 0; +} + +static void mtk_qspi_set_addr(struct mtk_qspi_priv *priv, u32 addr) +{ + int i; + + for (i = 0; i < 3; i++) { + writeb(addr & 0xff, &priv->regs->radr[i]); + addr >>= 8; + } +} + +static int mtk_qspi_write_single_byte(struct mtk_qspi_priv *priv, + u32 addr, u32 length, const u8 *data) +{ + int i, ret; + + mtk_qspi_set_addr(priv, addr); + + for (i = 0; i < length; i++) { + writeb(*data++, &priv->regs->wdata); + ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER); + if (ret < 0) + return ret; + } + return 0; +} + +static int mtk_qspi_write_buffer(struct mtk_qspi_priv *priv, u32 addr, + const u8 *buf) +{ + int i, data; + + mtk_qspi_set_addr(priv, addr); + + for (i = 0; i < MTK_QSPI_WRBUF_SIZE; i += 4) { + data = buf[i + 3] << 24 | buf[i + 2] << 16 | + buf[i + 1] << 8 | buf[i]; + writel(data, &priv->regs->pp_dw_data); + } + + return mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER); +} + +static int mtk_qspi_write(struct mtk_qspi_priv *priv, + u32 addr, const u8 *buf, u32 len) +{ + int ret; + + /* setting pre-fetch buffer for page program */ + writel(MTK_QSPI_WR_BUF_ENABLE, &priv->regs->cfg[1]); + while (len >= MTK_QSPI_WRBUF_SIZE) { + ret = mtk_qspi_write_buffer(priv, addr, buf); + if (ret < 0) + return ret; + + len -= MTK_QSPI_WRBUF_SIZE; + addr += MTK_QSPI_WRBUF_SIZE; + buf += MTK_QSPI_WRBUF_SIZE; + } + /* disable pre-fetch buffer for page program */ + writel(MTK_QSPI_WR_BUF_DISABLE, &priv->regs->cfg[1]); + + if (len) + return mtk_qspi_write_single_byte(priv, addr, len, buf); + + return 0; +} + +static int mtk_qspi_claim_bus(struct udevice *dev) +{ + /* nothing to do */ + return 0; +} + +static int mtk_qspi_release_bus(struct udevice *dev) +{ + /* nothing to do */ + return 0; +} + +static int mtk_qspi_transfer(struct mtk_qspi_priv *priv, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + u32 bytes = DIV_ROUND_UP(bitlen, 8); + u32 addr; + + if (!bytes) + return -ERR_INVAL; + + if (dout) { + if (flags & SPI_XFER_BEGIN) { + /* parse op code and potential paras first */ + priv->op = *(u8 *)dout; + if (bytes > 1) + memcpy(priv->tx, (u8 *)dout + 1, + bytes <= 4 ? bytes - 1 : 3); + priv->txlen = bytes - 1; + } + + if (flags == SPI_XFER_ONCE) { + /* operations without receiving or sending data. + * for example: erase, write flash register or write + * enable... + */ + priv->rx = NULL; + priv->rxlen = 0; + return mtk_qspi_tx_rx(priv); + } + + if (flags & SPI_XFER_END) { + /* here, dout should be data to be written. + * and priv->tx should be filled 3Bytes address. + */ + addr = priv->tx[0] << 16 | priv->tx[1] << 8 | + priv->tx[2]; + return mtk_qspi_write(priv, addr, (u8 *)dout, bytes); + } + } + + if (din) { + if (priv->txlen >= 3) { + /* if run to here, priv->tx[] should be the address + * where read data from, + * and, din is the buf to receive data. + */ + addr = priv->tx[0] << 16 | priv->tx[1] << 8 | + priv->tx[2]; + return mtk_qspi_read(priv, addr, (u8 *)din, bytes); + } + + /* should be reading flash's register */ + priv->rx = (u8 *)din; + priv->rxlen = bytes; + return mtk_qspi_tx_rx(priv); + } + + return 0; +} + +static int mtk_qspi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev->parent; + struct mtk_qspi_priv *priv = dev_get_priv(bus); + + return mtk_qspi_transfer(priv, bitlen, dout, din, flags); +} + +static int mtk_qspi_set_speed(struct udevice *bus, uint speed) +{ + /* nothing to do */ + return 0; +} + +static int mtk_qspi_set_mode(struct udevice *bus, uint mode) +{ + /* nothing to do */ + return 0; +} + +static int mtk_qspi_ofdata_to_platdata(struct udevice *bus) +{ + struct resource res_reg, res_mem; + struct mtk_qspi_platdata *plat = bus->platdata; + int ret; + + ret = dev_read_resource_byname(bus, "reg_base", &res_reg); + if (ret) { + debug("can't get reg_base resource(ret = %d)\n", ret); + return -ENOMEM; + } + + ret = dev_read_resource_byname(bus, "mem_base", &res_mem); + if (ret) { + debug("can't get map_base resource(ret = %d)\n", ret); + return -ENOMEM; + } + + plat->mem_base = res_mem.start; + plat->reg_base = res_reg.start; + + return 0; +} + +static int mtk_qspi_probe(struct udevice *bus) +{ + struct mtk_qspi_platdata *plat = dev_get_platdata(bus); + struct mtk_qspi_priv *priv = dev_get_priv(bus); + + priv->regs = (struct mtk_qspi_regs *)plat->reg_base; + priv->mem_base = (unsigned long *)plat->mem_base; + + writel(MTK_QSPI_COMMAND_ENABLE, &priv->regs->wrprot); + + return 0; +} + +static const struct dm_spi_ops mtk_qspi_ops = { + .claim_bus = mtk_qspi_claim_bus, + .release_bus = mtk_qspi_release_bus, + .xfer = mtk_qspi_xfer, + .set_speed = mtk_qspi_set_speed, + .set_mode = mtk_qspi_set_mode, +}; + +static const struct udevice_id mtk_qspi_ids[] = { + { .compatible = "mediatek,mt7629-qspi" }, + { } +}; + +U_BOOT_DRIVER(mtk_qspi) = { + .name = "mtk_qspi", + .id = UCLASS_SPI, + .of_match = mtk_qspi_ids, + .ops = &mtk_qspi_ops, + .ofdata_to_platdata = mtk_qspi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct mtk_qspi_platdata), + .priv_auto_alloc_size = sizeof(struct mtk_qspi_priv), + .probe = mtk_qspi_probe, +}; -- cgit v1.2.3 From 3deb1f731d9b122c86c246a7ec53bcd1d67af66f Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 14 Nov 2018 15:28:05 +0530 Subject: spi: pl022: Simplify platdata code pl022 spi driver support both OF_CONTROL and PLATDATA, this patch is trying to simplify the code that differentiating platdata vs of_control. - Move OF_CONTROL code at one place - Handle clock setup code directly in pl022_spi_ofdata_to_platdata Acked-by: Quentin Schulz Signed-off-by: Jagan Teki --- drivers/spi/pl022_spi.c | 48 +++++++++++++++--------------------- include/dm/platform_data/pl022_spi.h | 7 ------ 2 files changed, 20 insertions(+), 35 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c index 86b71d2e21..05f4f6f481 100644 --- a/drivers/spi/pl022_spi.c +++ b/drivers/spi/pl022_spi.c @@ -72,11 +72,7 @@ struct pl022_spi_slave { void *base; -#if !CONFIG_IS_ENABLED(OF_PLATDATA) - struct clk clk; -#else unsigned int freq; -#endif }; /* @@ -96,30 +92,13 @@ static int pl022_is_supported(struct pl022_spi_slave *ps) return 0; } -#if !CONFIG_IS_ENABLED(OF_PLATDATA) -static int pl022_spi_ofdata_to_platdata(struct udevice *bus) -{ - struct pl022_spi_pdata *plat = bus->platdata; - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(bus); - - plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size); - - return clk_get_by_index(bus, 0, &plat->clk); -} -#endif - static int pl022_spi_probe(struct udevice *bus) { struct pl022_spi_pdata *plat = dev_get_platdata(bus); struct pl022_spi_slave *ps = dev_get_priv(bus); ps->base = ioremap(plat->addr, plat->size); -#if !CONFIG_IS_ENABLED(OF_PLATDATA) - ps->clk = plat->clk; -#else ps->freq = plat->freq; -#endif /* Check the PL022 version */ if (!pl022_is_supported(ps)) @@ -240,11 +219,7 @@ static int pl022_spi_set_speed(struct udevice *bus, uint speed) u16 scr = SSP_SCR_MIN, cr0 = 0, cpsr = SSP_CPSR_MIN, best_scr = scr, best_cpsr = cpsr; u32 min, max, best_freq = 0, tmp; -#if !CONFIG_IS_ENABLED(OF_PLATDATA) - u32 rate = clk_get_rate(&ps->clk); -#else u32 rate = ps->freq; -#endif bool found = false; max = spi_rate(rate, SSP_CPSR_MIN, SSP_SCR_MIN); @@ -316,6 +291,25 @@ static const struct dm_spi_ops pl022_spi_ops = { }; #if !CONFIG_IS_ENABLED(OF_PLATDATA) +static int pl022_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct pl022_spi_pdata *plat = bus->platdata; + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(bus); + struct clk clkdev; + int ret; + + plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size); + + ret = clk_get_by_index(bus, 0, &clkdev); + if (ret) + return ret; + + plat->freq = clk_get_rate(&clkdev); + + return 0; +} + static const struct udevice_id pl022_spi_ids[] = { { .compatible = "arm,pl022-spi" }, { } @@ -327,11 +321,9 @@ U_BOOT_DRIVER(pl022_spi) = { .id = UCLASS_SPI, #if !CONFIG_IS_ENABLED(OF_PLATDATA) .of_match = pl022_spi_ids, -#endif - .ops = &pl022_spi_ops, -#if !CONFIG_IS_ENABLED(OF_PLATDATA) .ofdata_to_platdata = pl022_spi_ofdata_to_platdata, #endif + .ops = &pl022_spi_ops, .platdata_auto_alloc_size = sizeof(struct pl022_spi_pdata), .priv_auto_alloc_size = sizeof(struct pl022_spi_slave), .probe = pl022_spi_probe, diff --git a/include/dm/platform_data/pl022_spi.h b/include/dm/platform_data/pl022_spi.h index 77fe6da3cb..df8870169d 100644 --- a/include/dm/platform_data/pl022_spi.h +++ b/include/dm/platform_data/pl022_spi.h @@ -10,19 +10,12 @@ #ifndef __PL022_SPI_H__ #define __PL022_SPI_H__ -#if !CONFIG_IS_ENABLED(OF_PLATDATA) -#include -#endif #include struct pl022_spi_pdata { fdt_addr_t addr; fdt_size_t size; -#if !CONFIG_IS_ENABLED(OF_PLATDATA) - struct clk clk; -#else unsigned int freq; -#endif }; #endif -- cgit v1.2.3 From e6f76d555e3b1d23dec3c9c7b73a51ea1ac3ec30 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Thu, 22 Nov 2018 11:53:23 +0530 Subject: spi: pl022: Drop unnecessary include files This patch can drop unnecessary include files in pl022_spi driver. Acked-by: Quentin Schulz Signed-off-by: Jagan Teki --- drivers/spi/pl022_spi.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c index 05f4f6f481..f2e5367225 100644 --- a/drivers/spi/pl022_spi.c +++ b/drivers/spi/pl022_spi.c @@ -9,16 +9,11 @@ * Driver for ARM PL022 SPI Controller. */ -#include #include #include #include #include -#include -#include -#include #include -#include #include #define SSP_CR0 0x000 -- cgit v1.2.3 From 3ae6030cf9587d310ee9cb8c3b17e9a8693f7636 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Thu, 22 Nov 2018 11:54:08 +0530 Subject: dm: platform_data: spi: s/pl022_spi.h/spi_pl022.h Rename platform_data include file as spi_pl022.h from pl022_spi.h, this is generic notation used for spi platdata include files. Acked-by: Quentin Schulz Signed-off-by: Jagan Teki --- drivers/spi/pl022_spi.c | 2 +- include/dm/platform_data/pl022_spi.h | 21 --------------------- include/dm/platform_data/spi_pl022.h | 21 +++++++++++++++++++++ 3 files changed, 22 insertions(+), 22 deletions(-) delete mode 100644 include/dm/platform_data/pl022_spi.h create mode 100644 include/dm/platform_data/spi_pl022.h (limited to 'drivers/spi') diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c index f2e5367225..32bb8c8d21 100644 --- a/drivers/spi/pl022_spi.c +++ b/drivers/spi/pl022_spi.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/dm/platform_data/pl022_spi.h b/include/dm/platform_data/pl022_spi.h deleted file mode 100644 index df8870169d..0000000000 --- a/include/dm/platform_data/pl022_spi.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (C) Copyright 2018 - * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com - * - * Structure for use with U_BOOT_DEVICE for pl022 SPI devices or to use - * in ofdata_to_platdata. - */ - -#ifndef __PL022_SPI_H__ -#define __PL022_SPI_H__ - -#include - -struct pl022_spi_pdata { - fdt_addr_t addr; - fdt_size_t size; - unsigned int freq; -}; - -#endif diff --git a/include/dm/platform_data/spi_pl022.h b/include/dm/platform_data/spi_pl022.h new file mode 100644 index 0000000000..63a58ee453 --- /dev/null +++ b/include/dm/platform_data/spi_pl022.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 + * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com + * + * Structure for use with U_BOOT_DEVICE for pl022 SPI devices or to use + * in ofdata_to_platdata. + */ + +#ifndef __spi_pl022_h +#define __spi_pl022_h + +#include + +struct pl022_spi_pdata { + fdt_addr_t addr; + fdt_size_t size; + unsigned int freq; +}; + +#endif /* __spi_pl022_h */ -- cgit v1.2.3 From e2cae514725568bb4d3f8588c816f6ca521fa68f Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Tue, 20 Nov 2018 15:06:35 +0530 Subject: spi: Remove unused spi_init Remove spi_init definition which never used on respective code since from many years. Signed-off-by: Jagan Teki --- drivers/net/e1000_spi.c | 3 --- drivers/spi/atmel_spi.c | 5 ----- drivers/spi/davinci_spi.c | 5 ----- drivers/spi/fsl_dspi.c | 5 ----- drivers/spi/fsl_espi.c | 5 ----- drivers/spi/lpc32xx_ssp.c | 9 --------- drivers/spi/mxc_spi.c | 4 ---- drivers/spi/mxs_spi.c | 4 ---- drivers/spi/omap3_spi.c | 5 ----- drivers/spi/sh_qspi.c | 5 ----- drivers/spi/sh_spi.c | 4 ---- drivers/spi/soft_spi_legacy.c | 7 ------- include/spi.h | 7 ------- 13 files changed, 68 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/net/e1000_spi.c b/drivers/net/e1000_spi.c index b38f4df9f3..aecd290d72 100644 --- a/drivers/net/e1000_spi.c +++ b/drivers/net/e1000_spi.c @@ -77,9 +77,6 @@ static inline struct e1000_hw *e1000_hw_from_spi(struct spi_slave *spi) return container_of(spi, struct e1000_hw, spi); } -/* Not sure why all of these are necessary */ -void spi_init(void) { /* Nothing to do */ } - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 1db8bbef2b..cf4de9ee1a 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -34,11 +34,6 @@ static int spi_has_wdrbt(struct atmel_spi_slave *slave) return (ATMEL_SPI_VERSION_REV(ver) >= 0x210); } -void spi_init() -{ - -} - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 07fa5e3b8a..4d2c106440 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -388,11 +388,6 @@ void spi_cs_deactivate(struct spi_slave *slave) /* do nothing */ } -void spi_init(void) -{ - /* do nothing */ -} - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c index f7ed8fbe08..764c94215e 100644 --- a/drivers/spi/fsl_dspi.c +++ b/drivers/spi/fsl_dspi.c @@ -390,11 +390,6 @@ static int fsl_dspi_cfg_speed(struct fsl_dspi_priv *priv, uint speed) return 0; } #ifndef CONFIG_DM_SPI -void spi_init(void) -{ - /* Nothing to do */ -} - int spi_cs_is_valid(unsigned int bus, unsigned int cs) { if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8))) diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index e9941593f5..7444ae1a06 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -118,11 +118,6 @@ void spi_free_slave(struct spi_slave *slave) free(fsl); } -void spi_init(void) -{ - -} - int spi_claim_bus(struct spi_slave *slave) { struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); diff --git a/drivers/spi/lpc32xx_ssp.c b/drivers/spi/lpc32xx_ssp.c index ce12eee657..4b09366317 100644 --- a/drivers/spi/lpc32xx_ssp.c +++ b/drivers/spi/lpc32xx_ssp.c @@ -47,15 +47,6 @@ static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave( return container_of(slave, struct lpc32xx_spi_slave, slave); } -/* spi_init is called during boot when CONFIG_CMD_SPI is defined */ -void spi_init(void) -{ - /* - * nothing to do: clocking was enabled in lpc32xx_ssp_enable() - * and configuration will be done in spi_setup_slave() - */ -} - /* the following is called in sequence by do_spi_xfer() */ struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 0dccc38b82..b2636909ce 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -400,10 +400,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, return mxc_spi_xfer_internal(mxcs, bitlen, dout, din, flags); } -void spi_init(void) -{ -} - /* * Some SPI devices require active chip-select over multiple * transactions, we achieve this using a GPIO. Still, the SPI diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c index 006fe8281c..5065e407f8 100644 --- a/drivers/spi/mxs_spi.c +++ b/drivers/spi/mxs_spi.c @@ -39,10 +39,6 @@ static inline struct mxs_spi_slave *to_mxs_slave(struct spi_slave *slave) return container_of(slave, struct mxs_spi_slave, slave); } -void spi_init(void) -{ -} - int spi_cs_is_valid(unsigned int bus, unsigned int cs) { /* MXS SPI: 4 ports and 3 chip selects maximum */ diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index ecf54bb714..c7fcf050a5 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -461,11 +461,6 @@ static inline struct omap3_spi_priv *to_omap3_spi(struct spi_slave *slave) return container_of(slave, struct omap3_spi_priv, slave); } -void spi_init(void) -{ - /* do nothing */ -} - void spi_free_slave(struct spi_slave *slave) { struct omap3_spi_priv *priv = to_omap3_spi(slave); diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c index 64dfd748d6..5ae203d8d4 100644 --- a/drivers/spi/sh_qspi.c +++ b/drivers/spi/sh_qspi.c @@ -247,11 +247,6 @@ void spi_cs_deactivate(struct spi_slave *slave) sh_qspi_cs_deactivate(ss); } -void spi_init(void) -{ - /* nothing to do */ -} - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/drivers/spi/sh_spi.c b/drivers/spi/sh_spi.c index bc2bd638e6..c58fd0ebc4 100644 --- a/drivers/spi/sh_spi.c +++ b/drivers/spi/sh_spi.c @@ -66,10 +66,6 @@ static int write_fifo_empty_wait(struct sh_spi *ss) return 0; } -void spi_init(void) -{ -} - static void sh_spi_set_cs(struct sh_spi *ss, unsigned int cs) { unsigned long val = 0; diff --git a/drivers/spi/soft_spi_legacy.c b/drivers/spi/soft_spi_legacy.c index 0aac0c065d..cc5ab5f991 100644 --- a/drivers/spi/soft_spi_legacy.c +++ b/drivers/spi/soft_spi_legacy.c @@ -36,13 +36,6 @@ static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave) /* Public Functions */ /*=====================================================================*/ -/*----------------------------------------------------------------------- - * Initialization - */ -void spi_init (void) -{ -} - struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { diff --git a/include/spi.h b/include/spi.h index 938627bc01..92427e5f32 100644 --- a/include/spi.h +++ b/include/spi.h @@ -117,13 +117,6 @@ struct spi_slave { #define SPI_XFER_MMAP_END BIT(3) /* Memory Mapped End */ }; -/** - * Initialization, must be called once on start up. - * - * TODO: I don't think we really need this. - */ -void spi_init(void); - /** * spi_do_alloc_slave - Allocate a new SPI slave (internal) * -- cgit v1.2.3 From f34d0315e9fec21baed198500d58d1613cf4d17c Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 21 Nov 2018 08:51:57 +0000 Subject: spi: mpc8xx: Migrate to DM_SPI Drop non-dm code and migrate into DM_SPI. Signed-off-by: Christophe Leroy [jagan: Move config menu in DM_SPI area] Signed-off-by: Jagan Teki --- drivers/spi/Kconfig | 12 ++-- drivers/spi/mpc8xx_spi.c | 179 ++++++++--------------------------------------- 2 files changed, 36 insertions(+), 155 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 4a8a38b863..a7bb5b35c2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -124,6 +124,12 @@ config MESON_SPIFC This driver can be used to access the SPI NOR flash chips on Amlogic Meson SoCs. +config MPC8XX_SPI + bool "MPC8XX SPI Driver" + depends on MPC8xx + help + Enable support for SPI on MPC8XX + config MT7621_SPI bool "MediaTek MT7621 SPI driver" depends on ARCH_MT7620 @@ -343,12 +349,6 @@ config LPC32XX_SSP help Enable support for SPI on LPC32xx -config MPC8XX_SPI - bool "MPC8XX SPI Driver" - depends on MPC8xx - help - Enable support for SPI on MPC8XX - config MPC8XXX_SPI bool "MPC8XXX SPI Driver" help diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c index 285fd4d2cc..b020ce2b9d 100644 --- a/drivers/spi/mpc8xx_spi.c +++ b/drivers/spi/mpc8xx_spi.c @@ -17,64 +17,19 @@ */ #include +#include #include +#include + #include -#include -#include -#include -#include - -#define SPI_EEPROM_WREN 0x06 -#define SPI_EEPROM_RDSR 0x05 -#define SPI_EEPROM_READ 0x03 -#define SPI_EEPROM_WRITE 0x02 - -/* --------------------------------------------------------------- - * Offset for initial SPI buffers in DPRAM: - * We need a 520 byte scratch DPRAM area to use at an early stage. - * It is used between the two initialization calls (spi_init_f() - * and spi_init_r()). - * The value 0xb00 makes it far enough from the start of the data - * area (as well as from the stack pointer). - * --------------------------------------------------------------- */ -#ifndef CONFIG_SYS_SPI_INIT_OFFSET -#define CONFIG_SYS_SPI_INIT_OFFSET 0xB00 -#endif +#include #define CPM_SPI_BASE_RX CPM_SPI_BASE #define CPM_SPI_BASE_TX (CPM_SPI_BASE + sizeof(cbd_t)) -/* ------------------- - * Function prototypes - * ------------------- */ -ssize_t spi_xfer(size_t); - -/* ------------------- - * Variables - * ------------------- */ - #define MAX_BUFFER 0x104 -/* ---------------------------------------------------------------------- - * Initially we place the RX and TX buffers at a fixed location in DPRAM! - * ---------------------------------------------------------------------- */ -static uchar *rxbuf = - (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem - [CONFIG_SYS_SPI_INIT_OFFSET]; -static uchar *txbuf = - (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem - [CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER]; - -/* ************************************************************************** - * - * Function: spi_init_f - * - * Description: Init SPI-Controller (ROM part) - * - * return: --- - * - * *********************************************************************** */ -void spi_init_f(void) +static int mpc8xx_spi_probe(struct udevice *dev) { immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; cpm8xx_t __iomem *cp = &immr->im_cpm; @@ -180,117 +135,24 @@ void spi_init_f(void) clrbits_be16(&tbdf->cbd_sc, BD_SC_READY); clrbits_be16(&rbdf->cbd_sc, BD_SC_EMPTY); - /* Set the bd's rx and tx buffer address pointers */ - out_be32(&rbdf->cbd_bufaddr, (ulong)rxbuf); - out_be32(&tbdf->cbd_bufaddr, (ulong)txbuf); - /* 10 + 11 */ out_8(&cp->cp_spim, 0); /* Mask all SPI events */ out_8(&cp->cp_spie, SPI_EMASK); /* Clear all SPI events */ - return; + return 0; } -/* ************************************************************************** - * - * Function: spi_init_r - * - * Description: Init SPI-Controller (RAM part) - - * The malloc engine is ready and we can move our buffers to - * normal RAM - * - * return: --- - * - * *********************************************************************** */ -void spi_init_r(void) +static int mpc8xx_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) { immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; cpm8xx_t __iomem *cp = &immr->im_cpm; - spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dparam[PROFF_SPI]; - cbd_t __iomem *tbdf, *rbdf; - - /* Disable relocation */ - out_be16(&spi->spi_rpbase, 0); - - /* tx and rx buffer descriptors */ - tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX]; - rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX]; - - /* Allocate memory for RX and TX buffers */ - rxbuf = (uchar *)malloc(MAX_BUFFER); - txbuf = (uchar *)malloc(MAX_BUFFER); - - out_be32(&rbdf->cbd_bufaddr, (ulong)rxbuf); - out_be32(&tbdf->cbd_bufaddr, (ulong)txbuf); - - return; -} - -/**************************************************************************** - * Function: spi_write - **************************************************************************** */ -ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len) -{ - int i; - - memset(rxbuf, 0, MAX_BUFFER); - memset(txbuf, 0, MAX_BUFFER); - *txbuf = SPI_EEPROM_WREN; /* write enable */ - spi_xfer(1); - memcpy(txbuf, addr, alen); - *txbuf = SPI_EEPROM_WRITE; /* WRITE memory array */ - memcpy(alen + txbuf, buffer, len); - spi_xfer(alen + len); - /* ignore received data */ - for (i = 0; i < 1000; i++) { - *txbuf = SPI_EEPROM_RDSR; /* read status */ - txbuf[1] = 0; - spi_xfer(2); - if (!(rxbuf[1] & 1)) - break; - udelay(1000); - } - if (i >= 1000) - printf("*** spi_write: Time out while writing!\n"); - - return len; -} - -/**************************************************************************** - * Function: spi_read - **************************************************************************** */ -ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len) -{ - memset(rxbuf, 0, MAX_BUFFER); - memset(txbuf, 0, MAX_BUFFER); - memcpy(txbuf, addr, alen); - *txbuf = SPI_EEPROM_READ; /* READ memory array */ - - /* - * There is a bug in 860T (?) that cuts the last byte of input - * if we're reading into DPRAM. The solution we choose here is - * to always read len+1 bytes (we have one extra byte at the - * end of the buffer). - */ - spi_xfer(alen + len + 1); - memcpy(buffer, alen + rxbuf, len); - - return len; -} - -/**************************************************************************** - * Function: spi_xfer - **************************************************************************** */ -ssize_t spi_xfer(size_t count) -{ - immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; - cpm8xx_t __iomem *cp = &immr->im_cpm; - spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dparam[PROFF_SPI]; cbd_t __iomem *tbdf, *rbdf; int tm; + size_t count = (bitlen + 7) / 8; - /* Disable relocation */ - out_be16(&spi->spi_rpbase, 0); + if (count > MAX_BUFFER) + return -EINVAL; tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX]; rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX]; @@ -299,10 +161,12 @@ ssize_t spi_xfer(size_t count) clrbits_be32(&cp->cp_pbdat, 0x0001); /* Setting tx bd status and data length */ + out_be32(&tbdf->cbd_bufaddr, (ulong)dout); out_be16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_LAST | BD_SC_WRAP); out_be16(&tbdf->cbd_datlen, count); /* Setting rx bd status and data length */ + out_be32(&rbdf->cbd_bufaddr, (ulong)din); out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_WRAP); out_be16(&rbdf->cbd_datlen, 0); /* rx length has no significance */ @@ -333,3 +197,20 @@ ssize_t spi_xfer(size_t count) return count; } + +static const struct dm_spi_ops mpc8xx_spi_ops = { + .xfer = mpc8xx_spi_xfer, +}; + +static const struct udevice_id mpc8xx_spi_ids[] = { + { .compatible = "fsl,mpc8xx-spi" }, + { } +}; + +U_BOOT_DRIVER(mpc8xx_spi) = { + .name = "mpc8xx_spi", + .id = UCLASS_SPI, + .of_match = mpc8xx_spi_ids, + .ops = &mpc8xx_spi_ops, + .probe = mpc8xx_spi_probe, +}; -- cgit v1.2.3