Tristan Hsieh has uploaded this change for review. ( https://review.coreboot.org/27497
Change subject: mediatek: Refactor SPI code among similar SOCs ......................................................................
mediatek: Refactor SPI code among similar SOCs
Refactor SPI code which will be reused amon similar SOCs.
BUG=b:80501386 BRANCH=none TEST=Boots correctly on Elm
Change-Id: If5a6c554dc8361e729cf5c464325b97b2bfb7098 Signed-off-by: Tristan Shieh tristan.shieh@mediatek.com --- A src/soc/mediatek/common/include/soc/spi_common.h A src/soc/mediatek/common/spi.c M src/soc/mediatek/mt8173/Makefile.inc M src/soc/mediatek/mt8173/include/soc/spi.h M src/soc/mediatek/mt8173/spi.c 5 files changed, 381 insertions(+), 333 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/97/27497/1
diff --git a/src/soc/mediatek/common/include/soc/spi_common.h b/src/soc/mediatek/common/include/soc/spi_common.h new file mode 100644 index 0000000..0b0ea1f --- /dev/null +++ b/src/soc/mediatek/common/include/soc/spi_common.h @@ -0,0 +1,92 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MTK_COMMON_SPI_H +#define MTK_COMMON_SPI_H + +#include <spi-generic.h> + +/*SPI_CFG1_REG*/ +enum { + SPI_CFG1_CS_IDLE_SHIFT = 0, + SPI_CFG1_PACKET_LOOP_SHIFT = 8, + SPI_CFG1_PACKET_LENGTH_SHIFT = 16, + + SPI_CFG1_CS_IDLE_MASK = 0xff << SPI_CFG1_CS_IDLE_SHIFT, + SPI_CFG1_PACKET_LOOP_MASK = 0xff << SPI_CFG1_PACKET_LOOP_SHIFT, + SPI_CFG1_PACKET_LENGTH_MASK = 0x3ff << SPI_CFG1_PACKET_LENGTH_SHIFT, +}; + +enum { + SPI_CMD_ACT_SHIFT = 0, + SPI_CMD_RESUME_SHIFT = 1, + SPI_CMD_RST_SHIFT = 2, + SPI_CMD_PAUSE_EN_SHIFT = 4, + SPI_CMD_DEASSERT_SHIFT = 5, + SPI_CMD_CPHA_SHIFT = 8, + SPI_CMD_CPOL_SHIFT = 9, + SPI_CMD_RX_DMA_SHIFT = 10, + SPI_CMD_TX_DMA_SHIFT = 11, + SPI_CMD_TXMSBF_SHIFT = 12, + SPI_CMD_RXMSBF_SHIFT = 13, + SPI_CMD_RX_ENDIAN_SHIFT = 14, + SPI_CMD_TX_ENDIAN_SHIFT = 15, + SPI_CMD_FINISH_IE_SHIFT = 16, + SPI_CMD_PAUSE_IE_SHIFT = 17, + + SPI_CMD_ACT_EN = BIT(SPI_CMD_ACT_SHIFT), + SPI_CMD_RESUME_EN = BIT(SPI_CMD_RESUME_SHIFT), + SPI_CMD_RST_EN = BIT(SPI_CMD_RST_SHIFT), + SPI_CMD_PAUSE_EN = BIT(SPI_CMD_PAUSE_EN_SHIFT), + SPI_CMD_DEASSERT_EN = BIT(SPI_CMD_DEASSERT_SHIFT), + SPI_CMD_CPHA_EN = BIT(SPI_CMD_CPHA_SHIFT), + SPI_CMD_CPOL_EN = BIT(SPI_CMD_CPOL_SHIFT), + SPI_CMD_RX_DMA_EN = BIT(SPI_CMD_RX_DMA_SHIFT), + SPI_CMD_TX_DMA_EN = BIT(SPI_CMD_TX_DMA_SHIFT), + SPI_CMD_TXMSBF_EN = BIT(SPI_CMD_TXMSBF_SHIFT), + SPI_CMD_RXMSBF_EN = BIT(SPI_CMD_RXMSBF_SHIFT), + SPI_CMD_RX_ENDIAN_EN = BIT(SPI_CMD_RX_ENDIAN_SHIFT), + SPI_CMD_TX_ENDIAN_EN = BIT(SPI_CMD_TX_ENDIAN_SHIFT), + SPI_CMD_FINISH_IE_EN = BIT(SPI_CMD_FINISH_IE_SHIFT), + SPI_CMD_PAUSE_IE_EN = BIT(SPI_CMD_PAUSE_IE_SHIFT), +}; + +enum spi_pad_mask { + SPI_PAD0_MASK = 0x0, + SPI_PAD1_MASK = 0x1, + SPI_PAD2_MASK = 0x2, + SPI_PAD3_MASK = 0x3, + SPI_PAD_SEL_MASK = 0x3 +}; + +struct mtk_spi_regs; + +struct mtk_spi_bus { + struct spi_slave slave; + struct mtk_spi_regs *regs; + int initialized; + int state; +}; + +extern const struct spi_ctrlr spi_ctrlr; +extern struct mtk_spi_bus spi_bus[]; + +void mtk_spi_set_gpio_pinmux(unsigned int bus, + enum spi_pad_mask pad_select); +void mtk_spi_set_timing(struct mtk_spi_regs *regs, u32 sck_ticks, u32 cs_ticks); +void mtk_spi_init(unsigned int bus, enum spi_pad_mask pad_select, + unsigned int speed_hz); + +#endif diff --git a/src/soc/mediatek/common/spi.c b/src/soc/mediatek/common/spi.c new file mode 100644 index 0000000..9eaa376 --- /dev/null +++ b/src/soc/mediatek/common/spi.c @@ -0,0 +1,277 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <assert.h> +#include <endian.h> +#include <stdlib.h> +#include <soc/pll.h> +#include <soc/spi.h> +#include <timer.h> + +enum { + MTK_FIFO_DEPTH = 32, + MTK_TXRX_TIMEOUT_US = 1000 * 1000, + MTK_ARBITRARY_VALUE = 0xdeaddead +}; + +enum { + MTK_SPI_IDLE = 0, + MTK_SPI_PAUSE_IDLE = 1 +}; + +enum { + MTK_SPI_BUSY_STATUS = 1, + MTK_SPI_PAUSE_FINISH_INT_STATUS = 3 +}; + +static inline struct mtk_spi_bus *to_mtk_spi(const struct spi_slave *slave) +{ + assert(slave->bus < SPI_BUS_NUMBER); + return &spi_bus[slave->bus]; +} + +static void spi_sw_reset(struct mtk_spi_regs *regs) +{ + setbits_le32(®s->spi_cmd_reg, SPI_CMD_RST_EN); + clrbits_le32(®s->spi_cmd_reg, SPI_CMD_RST_EN); +} + +void mtk_spi_init(unsigned int bus, enum spi_pad_mask pad_select, + unsigned int speed_hz) +{ + u32 div, sck_ticks, cs_ticks, reg_val; + + if (bus >= SPI_BUS_NUMBER) + die("Error: Invalid SPI bus.\n"); + + struct mtk_spi_bus *slave = &spi_bus[bus]; + struct mtk_spi_regs *regs = slave->regs; + + if (speed_hz < SPI_HZ / 2) + div = div_round_up(SPI_HZ, speed_hz); + else + div = 1; + + sck_ticks = div_round_up(div, 2); + cs_ticks = sck_ticks * 2; + + printk(BIOS_DEBUG, "SPI%u(PAD%u) initialized at %u Hz\n", + bus, pad_select, SPI_HZ / (sck_ticks * 2)); + + /* set the timing */ + mtk_spi_set_timing(regs, sck_ticks, cs_ticks); + + reg_val = read32(®s->spi_cmd_reg); + + reg_val &= ~SPI_CMD_CPHA_EN; + reg_val &= ~SPI_CMD_CPOL_EN; + + /* set the mlsbx and mlsbtx */ + reg_val |= SPI_CMD_TXMSBF_EN; + reg_val |= SPI_CMD_RXMSBF_EN; + + /* set the tx/rx endian */ +#ifdef __LITTLE_ENDIAN + reg_val &= ~SPI_CMD_TX_ENDIAN_EN; + reg_val &= ~SPI_CMD_RX_ENDIAN_EN; +#else + reg_val |= SPI_CMD_TX_ENDIAN_EN; + reg_val |= SPI_CMD_RX_ENDIAN_EN; +#endif + + /* clear pause mode */ + reg_val &= ~SPI_CMD_PAUSE_EN; + + /* set finish interrupt always enable */ + reg_val |= SPI_CMD_FINISH_IE_EN; + + /* set pause interrupt always enable */ + reg_val |= SPI_CMD_PAUSE_IE_EN; + + /* disable dma mode */ + reg_val &= ~(SPI_CMD_TX_DMA_EN | SPI_CMD_RX_DMA_EN); + + /* set deassert mode */ + reg_val &= ~SPI_CMD_DEASSERT_EN; + + write32(®s->spi_cmd_reg, reg_val); + + mtk_spi_set_gpio_pinmux(bus, pad_select); + /* pad select */ + clrsetbits_le32(®s->spi_pad_macro_sel_reg, SPI_PAD_SEL_MASK, + pad_select); +} + +static void mtk_spi_dump_data(const char *name, const uint8_t *data, int size) +{ +#ifdef MTK_SPI_DEBUG + int i; + + printk(BIOS_DEBUG, "%s: 0x ", name); + for (i = 0; i < size; i++) + printk(BIOS_INFO, "%#x ", data[i]); + printk(BIOS_DEBUG, "\n"); +#endif +} + +static int spi_ctrlr_claim_bus(const struct spi_slave *slave) +{ + struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave); + struct mtk_spi_regs *regs = mtk_slave->regs; + + setbits_le32(®s->spi_cmd_reg, 1 << SPI_CMD_PAUSE_EN_SHIFT); + mtk_slave->state = MTK_SPI_IDLE; + + return 0; +} + +static int mtk_spi_fifo_transfer(const struct spi_slave *slave, void *in, + const void *out, size_t size) +{ + struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave); + struct mtk_spi_regs *regs = mtk_slave->regs; + uint8_t *inb = (uint8_t *)in; + const uint32_t *outb = (const uint32_t *)out; + uint32_t reg_val = 0; + uint32_t i, word_count; + struct stopwatch sw; + + if (!size || size > MTK_FIFO_DEPTH) + return -1; + + clrsetbits_le32(®s->spi_cfg1_reg, + SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK, + ((size - 1) << SPI_CFG1_PACKET_LENGTH_SHIFT) | + (0 << SPI_CFG1_PACKET_LOOP_SHIFT)); + + word_count = div_round_up(size, sizeof(u32)); + + if (outb) { + for (i = 0; i < word_count; i++) + write32(®s->spi_tx_data_reg, outb[i]); + mtk_spi_dump_data("the outb data is", + (const uint8_t *)outb, size); + } else { + /* The SPI controller will transmit in full-duplex for RX, + * therefore we need arbitrary data on MOSI which the slave + * must ignore. + */ + for (i = 0; i < word_count; i++) + write32(®s->spi_tx_data_reg, MTK_ARBITRARY_VALUE); + } + + if (mtk_slave->state == MTK_SPI_IDLE) { + setbits_le32(®s->spi_cmd_reg, SPI_CMD_ACT_EN); + mtk_slave->state = MTK_SPI_PAUSE_IDLE; + } else if (mtk_slave->state == MTK_SPI_PAUSE_IDLE) { + setbits_le32(®s->spi_cmd_reg, SPI_CMD_RESUME_EN); + } + + stopwatch_init_usecs_expire(&sw, MTK_TXRX_TIMEOUT_US); + while ((read32(®s->spi_status1_reg) & MTK_SPI_BUSY_STATUS) == 0) { + if (stopwatch_expired(&sw)) { + printk(BIOS_ERR, + "Timeout waiting for status1 status.\n"); + goto error; + } + } + stopwatch_init_usecs_expire(&sw, MTK_TXRX_TIMEOUT_US); + while ((read32(®s->spi_status0_reg) & + MTK_SPI_PAUSE_FINISH_INT_STATUS) == 0) { + if (stopwatch_expired(&sw)) { + printk(BIOS_ERR, + "Timeout waiting for status0 status.\n"); + goto error; + } + } + + if (inb) { + for (i = 0; i < size; i++) { + if (i % 4 == 0) + reg_val = read32(®s->spi_rx_data_reg); + *(inb + i) = (reg_val >> ((i % 4) * 8)) & 0xff; + } + mtk_spi_dump_data("the inb data is", inb, size); + } + + return 0; +error: + spi_sw_reset(regs); + mtk_slave->state = MTK_SPI_IDLE; + return -1; +} + +static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, + size_t bytes_out, void *din, size_t bytes_in) +{ + size_t min_size = 0; + int ret; + + /* Driver implementation does not support full duplex. */ + if ((bytes_in && bytes_out) && (bytes_in != bytes_out)) + return -1; + + while (bytes_out || bytes_in) { + if (bytes_in && bytes_out) + min_size = MIN(bytes_out, MTK_FIFO_DEPTH); + else if (bytes_out) + min_size = MIN(bytes_out, MTK_FIFO_DEPTH); + else if (bytes_in) + min_size = MIN(bytes_in, MTK_FIFO_DEPTH); + + ret = mtk_spi_fifo_transfer(slave, din, dout, min_size); + if (ret != 0) + return ret; + + if (bytes_out) { + bytes_out -= min_size; + dout = (const uint8_t *)dout + min_size; + } + + if (bytes_in) { + bytes_in -= min_size; + din = (uint8_t *)din + min_size; + } + } + + return 0; +} + +static void spi_ctrlr_release_bus(const struct spi_slave *slave) +{ + struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave); + struct mtk_spi_regs *regs = mtk_slave->regs; + + clrbits_le32(®s->spi_cmd_reg, SPI_CMD_PAUSE_EN); + spi_sw_reset(regs); + mtk_slave->state = MTK_SPI_IDLE; +} + +static int spi_ctrlr_setup(const struct spi_slave *slave) +{ + struct mtk_spi_bus *eslave = to_mtk_spi(slave); + assert(read32(&eslave->regs->spi_cfg0_reg) != 0); + spi_sw_reset(eslave->regs); + return 0; +} + +const struct spi_ctrlr spi_ctrlr = { + .setup = spi_ctrlr_setup, + .claim_bus = spi_ctrlr_claim_bus, + .release_bus = spi_ctrlr_release_bus, + .xfer = spi_ctrlr_xfer, + .max_xfer_size = 65535, +}; diff --git a/src/soc/mediatek/mt8173/Makefile.inc b/src/soc/mediatek/mt8173/Makefile.inc index 1a5ee80..2aa7b8d 100644 --- a/src/soc/mediatek/mt8173/Makefile.inc +++ b/src/soc/mediatek/mt8173/Makefile.inc @@ -19,7 +19,7 @@ bootblock-$(CONFIG_SPI_FLASH) += flash_controller.c bootblock-y += i2c.c bootblock-y += ../common/pll.c pll.c -bootblock-y += spi.c +bootblock-y += ../common/spi.c spi.c bootblock-y += ../common/timer.c bootblock-y += timer.c
@@ -34,7 +34,7 @@ ################################################################################
verstage-y += i2c.c -verstage-y += spi.c +verstage-y += ../common/spi.c spi.c
verstage-$(CONFIG_DRIVERS_UART) += ../common/uart.c
@@ -53,8 +53,8 @@
romstage-$(CONFIG_DRIVERS_UART) += ../common/uart.c romstage-y += ../common/cbmem.c -romstage-y += spi.c romstage-y += ../common/gpio.c gpio.c +romstage-y += ../common/spi.c spi.c romstage-y += pmic_wrap.c mt6391.c romstage-y += memory.c romstage-y += emi.c dramc_pi_basic_api.c dramc_pi_calibration_api.c @@ -64,7 +64,7 @@ ################################################################################
ramstage-y += ../common/cbmem.c emi.c -ramstage-y += spi.c +ramstage-y += ../common/spi.c spi.c ramstage-$(CONFIG_SPI_FLASH) += flash_controller.c ramstage-y += soc.c ../common/mtcmos.c ramstage-y += ../common/timer.c diff --git a/src/soc/mediatek/mt8173/include/soc/spi.h b/src/soc/mediatek/mt8173/include/soc/spi.h index 52f4f4c..eebadb4 100644 --- a/src/soc/mediatek/mt8173/include/soc/spi.h +++ b/src/soc/mediatek/mt8173/include/soc/spi.h @@ -16,8 +16,9 @@ #ifndef MTK_MT8173_SPI_H #define MTK_MT8173_SPI_H
-#include <spi-generic.h> -#include <types.h> +#include <soc/spi_common.h> + +#define SPI_BUS_NUMBER 1
/* SPI peripheral register map. */ typedef struct mtk_spi_regs { @@ -43,67 +44,4 @@ SPI_CFG0_CS_SETUP_SHIFT = 24, };
-/*SPI_CFG1_REG*/ -enum { - SPI_CFG1_CS_IDLE_SHIFT = 0, - SPI_CFG1_PACKET_LOOP_SHIFT = 8, - SPI_CFG1_PACKET_LENGTH_SHIFT = 16, - - SPI_CFG1_CS_IDLE_MASK = 0xff << SPI_CFG1_CS_IDLE_SHIFT, - SPI_CFG1_PACKET_LOOP_MASK = 0xff << SPI_CFG1_PACKET_LOOP_SHIFT, - SPI_CFG1_PACKET_LENGTH_MASK = 0x3ff << SPI_CFG1_PACKET_LENGTH_SHIFT, -}; - -enum { - SPI_CMD_ACT_SHIFT = 0, - SPI_CMD_RESUME_SHIFT = 1, - SPI_CMD_RST_SHIFT = 2, - SPI_CMD_PAUSE_EN_SHIFT = 4, - SPI_CMD_DEASSERT_SHIFT = 5, - SPI_CMD_CPHA_SHIFT = 8, - SPI_CMD_CPOL_SHIFT = 9, - SPI_CMD_RX_DMA_SHIFT = 10, - SPI_CMD_TX_DMA_SHIFT = 11, - SPI_CMD_TXMSBF_SHIFT = 12, - SPI_CMD_RXMSBF_SHIFT = 13, - SPI_CMD_RX_ENDIAN_SHIFT = 14, - SPI_CMD_TX_ENDIAN_SHIFT = 15, - SPI_CMD_FINISH_IE_SHIFT = 16, - SPI_CMD_PAUSE_IE_SHIFT = 17, - - SPI_CMD_ACT_EN = BIT(SPI_CMD_ACT_SHIFT), - SPI_CMD_RESUME_EN = BIT(SPI_CMD_RESUME_SHIFT), - SPI_CMD_RST_EN = BIT(SPI_CMD_RST_SHIFT), - SPI_CMD_PAUSE_EN = BIT(SPI_CMD_PAUSE_EN_SHIFT), - SPI_CMD_DEASSERT_EN = BIT(SPI_CMD_DEASSERT_SHIFT), - SPI_CMD_CPHA_EN = BIT(SPI_CMD_CPHA_SHIFT), - SPI_CMD_CPOL_EN = BIT(SPI_CMD_CPOL_SHIFT), - SPI_CMD_RX_DMA_EN = BIT(SPI_CMD_RX_DMA_SHIFT), - SPI_CMD_TX_DMA_EN = BIT(SPI_CMD_TX_DMA_SHIFT), - SPI_CMD_TXMSBF_EN = BIT(SPI_CMD_TXMSBF_SHIFT), - SPI_CMD_RXMSBF_EN = BIT(SPI_CMD_RXMSBF_SHIFT), - SPI_CMD_RX_ENDIAN_EN = BIT(SPI_CMD_RX_ENDIAN_SHIFT), - SPI_CMD_TX_ENDIAN_EN = BIT(SPI_CMD_TX_ENDIAN_SHIFT), - SPI_CMD_FINISH_IE_EN = BIT(SPI_CMD_FINISH_IE_SHIFT), - SPI_CMD_PAUSE_IE_EN = BIT(SPI_CMD_PAUSE_IE_SHIFT), -}; - -enum spi_pad_mask { - SPI_PAD0_MASK = 0x0, - SPI_PAD1_MASK = 0x1, - SPI_PAD2_MASK = 0x2, - SPI_PAD3_MASK = 0x3, - SPI_PAD_SEL_MASK = 0x3 -}; - - -struct mtk_spi_bus { - struct spi_slave slave; - struct mtk_spi_regs *regs; - int initialized; - int state; -}; - -void mtk_spi_init(unsigned int bus, unsigned int pad_select, - unsigned int speed_hz); #endif diff --git a/src/soc/mediatek/mt8173/spi.c b/src/soc/mediatek/mt8173/spi.c index 634c46e..669ecf0 100644 --- a/src/soc/mediatek/mt8173/spi.c +++ b/src/soc/mediatek/mt8173/spi.c @@ -15,55 +15,20 @@
#include <arch/io.h> #include <assert.h> -#include <console/console.h> -#include <delay.h> -#include <endian.h> #include <spi_flash.h> -#include <stdlib.h> -#include <string.h> -#include <timer.h> #include <soc/addressmap.h> #include <soc/flash_controller.h> #include <soc/gpio.h> -#include <soc/pll.h> #include <soc/spi.h>
-enum { - MTK_FIFO_DEPTH = 32, - MTK_TXRX_TIMEOUT_US = 1000 * 1000, - MTK_ARBITRARY_VALUE = 0xdeaddead -}; - -enum { - MTK_SPI_IDLE = 0, - MTK_SPI_PAUSE_IDLE = 1 -}; - -enum { - MTK_SPI_BUSY_STATUS = 1, - MTK_SPI_PAUSE_FINISH_INT_STATUS = 3 -}; - -static struct mtk_spi_bus spi_bus[1] = { +struct mtk_spi_bus spi_bus[SPI_BUS_NUMBER] = { { .regs = (void *)SPI_BASE, - .state = MTK_SPI_IDLE, } };
-static inline struct mtk_spi_bus *to_mtk_spi(const struct spi_slave *slave) -{ - assert(slave->bus < ARRAY_SIZE(spi_bus)); - return &spi_bus[slave->bus]; -} - -static void spi_sw_reset(struct mtk_spi_regs *regs) -{ - setbits_le32(®s->spi_cmd_reg, SPI_CMD_RST_EN); - clrbits_le32(®s->spi_cmd_reg, SPI_CMD_RST_EN); -} - -static void mtk_spi_set_gpio_pinmux(enum spi_pad_mask pad_select) +void mtk_spi_set_gpio_pinmux(unsigned int bus, + enum spi_pad_mask pad_select) { /* TODO: implement support for other pads when needed */ assert(pad_select == SPI_PAD1_MASK); @@ -73,30 +38,8 @@ gpio_set_mode(PAD_MSDC2_CMD, PAD_MSDC2_CMD_FUNC_SPI_CS_1); }
-void mtk_spi_init(unsigned int bus, unsigned int pad_select, - unsigned int speed_hz) +void mtk_spi_set_timing(struct mtk_spi_regs *regs, u32 sck_ticks, u32 cs_ticks) { - u32 div, sck_ticks, cs_ticks, reg_val; - - /* mtk spi HW just supports bus 0 */ - if (bus != 0) - die("Error: Only SPI bus 0 is supported.\n"); - - struct mtk_spi_bus *slave = &spi_bus[bus]; - struct mtk_spi_regs *regs = slave->regs; - - if (speed_hz < SPI_HZ / 2) - div = div_round_up(SPI_HZ, speed_hz); - else - div = 1; - - sck_ticks = div_round_up(div, 2); - cs_ticks = sck_ticks * 2; - - printk(BIOS_DEBUG, "SPI%u initialized at %u Hz", - pad_select, SPI_HZ / (sck_ticks * 2)); - - /* set the timing */ write32(®s->spi_cfg0_reg, ((sck_ticks - 1) << SPI_CFG0_SCK_HIGH_SHIFT) | ((sck_ticks - 1) << SPI_CFG0_SCK_LOW_SHIFT) | @@ -104,200 +47,6 @@ ((cs_ticks - 1) << SPI_CFG0_CS_SETUP_SHIFT)); clrsetbits_le32(®s->spi_cfg1_reg, SPI_CFG1_CS_IDLE_MASK, ((cs_ticks - 1) << SPI_CFG1_CS_IDLE_SHIFT)); - - reg_val = read32(®s->spi_cmd_reg); - - reg_val &= ~SPI_CMD_CPHA_EN; - reg_val &= ~SPI_CMD_CPOL_EN; - - /* set the mlsbx and mlsbtx */ - reg_val |= SPI_CMD_TXMSBF_EN; - reg_val |= SPI_CMD_RXMSBF_EN; - - /* set the tx/rx endian */ -#ifdef __LITTLE_ENDIAN - reg_val &= ~SPI_CMD_TX_ENDIAN_EN; - reg_val &= ~SPI_CMD_RX_ENDIAN_EN; -#else - reg_val |= SPI_CMD_TX_ENDIAN_EN; - reg_val |= SPI_CMD_RX_ENDIAN_EN; -#endif - - /* clear pause mode */ - reg_val &= ~SPI_CMD_PAUSE_EN; - - /* set finish interrupt always enable */ - reg_val |= SPI_CMD_FINISH_IE_EN; - - /* set pause interrupt always enable */ - reg_val |= SPI_CMD_PAUSE_IE_EN; - - /* disable dma mode */ - reg_val &= ~(SPI_CMD_TX_DMA_EN | SPI_CMD_RX_DMA_EN); - - /* set deassert mode */ - reg_val &= ~SPI_CMD_DEASSERT_EN; - - write32(®s->spi_cmd_reg, reg_val); - - mtk_spi_set_gpio_pinmux(pad_select); - /* pad select */ - clrsetbits_le32(®s->spi_pad_macro_sel_reg, SPI_PAD_SEL_MASK, - pad_select); -} - -static void mtk_spi_dump_data(const char *name, const uint8_t *data, - int size) -{ -#ifdef MTK_SPI_DEBUG - int i; - - printk(BIOS_DEBUG, "%s: 0x ", name); - for (i = 0; i < size; i++) - printk(BIOS_INFO, "%#x ", data[i]); - printk(BIOS_DEBUG, "\n"); -#endif -} - -static int spi_ctrlr_claim_bus(const struct spi_slave *slave) -{ - struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave); - struct mtk_spi_regs *regs = mtk_slave->regs; - - setbits_le32(®s->spi_cmd_reg, 1 << SPI_CMD_PAUSE_EN_SHIFT); - mtk_slave->state = MTK_SPI_IDLE; - - return 0; -} - -static int mtk_spi_fifo_transfer(const struct spi_slave *slave, void *in, - const void *out, size_t size) -{ - struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave); - struct mtk_spi_regs *regs = mtk_slave->regs; - uint8_t *inb = (uint8_t *)in; - const uint32_t *outb = (const uint32_t *)out; - uint32_t reg_val = 0; - uint32_t i, word_count; - struct stopwatch sw; - - if (!size || size > MTK_FIFO_DEPTH) - return -1; - - clrsetbits_le32(®s->spi_cfg1_reg, - SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK, - ((size - 1) << SPI_CFG1_PACKET_LENGTH_SHIFT) | - (0 << SPI_CFG1_PACKET_LOOP_SHIFT)); - - word_count = div_round_up(size, sizeof(u32)); - if (inb) { - /* The SPI controller will transmit in full-duplex for RX, - * therefore we need arbitrary data on MOSI which the slave - * must ignore. - */ - for (i = 0; i < word_count; i++) - write32(®s->spi_tx_data_reg, MTK_ARBITRARY_VALUE); - } - if (outb) { - for (i = 0; i < word_count; i++) - write32(®s->spi_tx_data_reg, outb[i]); - mtk_spi_dump_data("the outb data is", - (const uint8_t *)outb, size); - } - - if (mtk_slave->state == MTK_SPI_IDLE) { - setbits_le32(®s->spi_cmd_reg, SPI_CMD_ACT_EN); - mtk_slave->state = MTK_SPI_PAUSE_IDLE; - } else if (mtk_slave->state == MTK_SPI_PAUSE_IDLE) { - setbits_le32(®s->spi_cmd_reg, SPI_CMD_RESUME_EN); - } - - stopwatch_init_usecs_expire(&sw, MTK_TXRX_TIMEOUT_US); - while ((read32(®s->spi_status1_reg) & MTK_SPI_BUSY_STATUS) == 0) { - if (stopwatch_expired(&sw)) { - printk(BIOS_ERR, - "Timeout waiting for status1 status.\n"); - goto error; - } - } - stopwatch_init_usecs_expire(&sw, MTK_TXRX_TIMEOUT_US); - while ((read32(®s->spi_status0_reg) & - MTK_SPI_PAUSE_FINISH_INT_STATUS) == 0) { - if (stopwatch_expired(&sw)) { - printk(BIOS_ERR, - "Timeout waiting for status0 status.\n"); - goto error; - } - } - - if (inb) { - for (i = 0; i < size; i++) { - if (i % 4 == 0) - reg_val = read32(®s->spi_rx_data_reg); - *(inb + i) = (reg_val >> ((i % 4) * 8)) & 0xff; - } - mtk_spi_dump_data("the inb data is", inb, size); - } - - return 0; -error: - spi_sw_reset(regs); - mtk_slave->state = MTK_SPI_IDLE; - return -1; -} - -static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, - size_t bytes_out, void *din, size_t bytes_in) -{ - size_t min_size = 0; - int ret; - - /* Driver implementation does not support full duplex. */ - if (bytes_in && bytes_out) - return -1; - - while (bytes_out || bytes_in) { - if (bytes_in && bytes_out) - min_size = MIN(MIN(bytes_out, bytes_in), MTK_FIFO_DEPTH); - else if (bytes_out) - min_size = MIN(bytes_out, MTK_FIFO_DEPTH); - else if (bytes_in) - min_size = MIN(bytes_in, MTK_FIFO_DEPTH); - - ret = mtk_spi_fifo_transfer(slave, din, dout, min_size); - if (ret != 0) - return ret; - - if (bytes_out) { - bytes_out -= min_size; - dout = (const uint8_t *)dout + min_size; - } - - if (bytes_in) { - bytes_in -= min_size; - din = (uint8_t *)din + min_size; - } - } - - return 0; -} - -static void spi_ctrlr_release_bus(const struct spi_slave *slave) -{ - struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave); - struct mtk_spi_regs *regs = mtk_slave->regs; - - clrbits_le32(®s->spi_cmd_reg, SPI_CMD_PAUSE_EN); - spi_sw_reset(regs); - mtk_slave->state = MTK_SPI_IDLE; -} - -static int spi_ctrlr_setup(const struct spi_slave *slave) -{ - struct mtk_spi_bus *eslave = to_mtk_spi(slave); - assert(read32(&eslave->regs->spi_cfg0_reg) != 0); - spi_sw_reset(eslave->regs); - return 0; }
static const struct spi_ctrlr spi_flash_ctrlr = { @@ -305,19 +54,11 @@ .flash_probe = mtk_spi_flash_probe, };
-static const struct spi_ctrlr spi_ctrlr = { - .setup = spi_ctrlr_setup, - .claim_bus = spi_ctrlr_claim_bus, - .release_bus = spi_ctrlr_release_bus, - .xfer = spi_ctrlr_xfer, - .max_xfer_size = 65535, -}; - const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = { { .ctrlr = &spi_ctrlr, .bus_start = 0, - .bus_end = 0, + .bus_end = SPI_BUS_NUMBER - 1, }, { .ctrlr = &spi_flash_ctrlr,