summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/mediatek/common/include/soc/spi_common.h91
-rw-r--r--src/soc/mediatek/common/spi.c261
-rw-r--r--src/soc/mediatek/mt8173/Makefile.inc8
-rw-r--r--src/soc/mediatek/mt8173/include/soc/spi.h69
-rw-r--r--src/soc/mediatek/mt8173/spi.c269
5 files changed, 364 insertions, 334 deletions
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 0000000000..162db59f94
--- /dev/null
+++ b/src/soc/mediatek/common/include/soc/spi_common.h
@@ -0,0 +1,91 @@
+/*
+ * 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>
+
+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 0000000000..5d2dab4b04
--- /dev/null
+++ b/src/soc/mediatek/common/spi.c
@@ -0,0 +1,261 @@
+/*
+ * 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>
+
+#define MTK_SPI_DEBUG 0
+
+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(&regs->spi_cmd_reg, SPI_CMD_RST_EN);
+ clrbits_le32(&regs->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;
+
+ assert(bus < SPI_BUS_NUMBER);
+
+ 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));
+
+ mtk_spi_set_timing(regs, sck_ticks, cs_ticks);
+
+ clrsetbits_le32(&regs->spi_cmd_reg,
+ (SPI_CMD_CPHA_EN | SPI_CMD_CPOL_EN |
+ SPI_CMD_TX_ENDIAN_EN | SPI_CMD_RX_ENDIAN_EN |
+ SPI_CMD_TX_DMA_EN | SPI_CMD_RX_DMA_EN |
+ SPI_CMD_PAUSE_EN | SPI_CMD_DEASSERT_EN),
+ (SPI_CMD_TXMSBF_EN | SPI_CMD_RXMSBF_EN |
+ SPI_CMD_FINISH_IE_EN | SPI_CMD_PAUSE_IE_EN));
+
+ mtk_spi_set_gpio_pinmux(bus, pad_select);
+
+ clrsetbits_le32(&regs->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)
+{
+ if (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");
+ }
+}
+
+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(&regs->spi_cmd_reg, 1 << SPI_CMD_PAUSE_EN_SHIFT);
+ mtk_slave->state = MTK_SPI_IDLE;
+
+ return 0;
+}
+
+static int do_transfer(const struct spi_slave *slave, void *in, const void *out,
+ size_t *bytes_in, size_t *bytes_out)
+{
+ struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave);
+ struct mtk_spi_regs *regs = mtk_slave->regs;
+ uint32_t reg_val = 0;
+ uint32_t i;
+ struct stopwatch sw;
+ size_t size;
+
+ if (*bytes_out == 0)
+ size = *bytes_in;
+ else if (*bytes_in == 0)
+ size = *bytes_out;
+ else
+ size = MIN(*bytes_in, *bytes_out);
+
+ clrsetbits_le32(&regs->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));
+
+ if (*bytes_out) {
+ const uint8_t *outb = (const uint8_t *)out;
+ for (i = 0; i < size; i++) {
+ reg_val |= outb[i] << ((i % 4) * 8);
+ if (i % 4 == 3) {
+ write32(&regs->spi_tx_data_reg, reg_val);
+ reg_val = 0;
+ }
+ }
+
+ if (i % 4 != 0)
+ write32(&regs->spi_tx_data_reg, reg_val);
+
+ 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.
+ */
+ uint32_t word_count = div_round_up(size, sizeof(u32));
+ for (i = 0; i < word_count; i++)
+ write32(&regs->spi_tx_data_reg, MTK_ARBITRARY_VALUE);
+ }
+
+ if (mtk_slave->state == MTK_SPI_IDLE) {
+ setbits_le32(&regs->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(&regs->spi_cmd_reg, SPI_CMD_RESUME_EN);
+ }
+
+ stopwatch_init_usecs_expire(&sw, MTK_TXRX_TIMEOUT_US);
+ while ((read32(&regs->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(&regs->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 (*bytes_in) {
+ uint8_t *inb = (uint8_t *)in;
+ for (i = 0; i < size; i++) {
+ if (i % 4 == 0)
+ reg_val = read32(&regs->spi_rx_data_reg);
+ inb[i] = (reg_val >> ((i % 4) * 8)) & 0xff;
+ }
+ mtk_spi_dump_data("the inb data is", inb, size);
+
+ *bytes_in -= size;
+ }
+
+ if (*bytes_out)
+ *bytes_out -= 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)
+{
+ while (bytes_out || bytes_in) {
+ size_t in_now = MIN(bytes_in, MTK_FIFO_DEPTH);
+ size_t out_now = MIN(bytes_out, MTK_FIFO_DEPTH);
+ size_t in_rem = in_now;
+ size_t out_rem = out_now;
+
+ int ret = do_transfer(slave, din, dout, &in_rem, &out_rem);
+ if (ret != 0)
+ return ret;
+
+ if (bytes_out) {
+ size_t sent = out_now - out_rem;
+ bytes_out -= sent;
+ dout += sent;
+ }
+
+ if (bytes_in) {
+ size_t received = in_now - in_rem;
+ bytes_in -= received;
+ din += received;
+ }
+ }
+
+ 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(&regs->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 1a5ee80c07..2aa7b8d978 100644
--- a/src/soc/mediatek/mt8173/Makefile.inc
+++ b/src/soc/mediatek/mt8173/Makefile.inc
@@ -19,7 +19,7 @@ bootblock-y += bootblock.c
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 @@ bootblock-y += ../common/mmu_operations.c mmu_operations.c
################################################################################
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-y += timer.c
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 @@ romstage-y += rtc.c
################################################################################
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 52f4f4cef3..aaef3aa25c 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 {
@@ -35,7 +36,6 @@ typedef struct mtk_spi_regs {
check_member(mtk_spi_regs, spi_pad_macro_sel_reg, 0x24);
-/* SPI_CFG0_REG */
enum {
SPI_CFG0_SCK_HIGH_SHIFT = 0,
SPI_CFG0_SCK_LOW_SHIFT = 8,
@@ -43,67 +43,4 @@ enum {
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 b15685a352..8e6c2d084c 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(&regs->spi_cmd_reg, SPI_CMD_RST_EN);
- clrbits_le32(&regs->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 @@ static void mtk_spi_set_gpio_pinmux(enum spi_pad_mask pad_select)
gpio_set_mode(GPIO(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(&regs->spi_cfg0_reg,
((sck_ticks - 1) << SPI_CFG0_SCK_HIGH_SHIFT) |
((sck_ticks - 1) << SPI_CFG0_SCK_LOW_SHIFT) |
@@ -104,200 +47,6 @@ void mtk_spi_init(unsigned int bus, unsigned int pad_select,
((cs_ticks - 1) << SPI_CFG0_CS_SETUP_SHIFT));
clrsetbits_le32(&regs->spi_cfg1_reg, SPI_CFG1_CS_IDLE_MASK,
((cs_ticks - 1) << SPI_CFG1_CS_IDLE_SHIFT));
-
- reg_val = read32(&regs->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(&regs->spi_cmd_reg, reg_val);
-
- mtk_spi_set_gpio_pinmux(pad_select);
- /* pad select */
- clrsetbits_le32(&regs->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(&regs->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(&regs->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(&regs->spi_tx_data_reg, MTK_ARBITRARY_VALUE);
- }
- if (outb) {
- for (i = 0; i < word_count; i++)
- write32(&regs->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(&regs->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(&regs->spi_cmd_reg, SPI_CMD_RESUME_EN);
- }
-
- stopwatch_init_usecs_expire(&sw, MTK_TXRX_TIMEOUT_US);
- while ((read32(&regs->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(&regs->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(&regs->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(&regs->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 @@ static const struct spi_ctrlr spi_flash_ctrlr = {
.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,