diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux-5.4/linux-yocto-5.4.69-amdx86/0001-spi-spi-amd-Add-AMD-SPI-controller-driver-support.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux-5.4/linux-yocto-5.4.69-amdx86/0001-spi-spi-amd-Add-AMD-SPI-controller-driver-support.patch | 397 |
1 files changed, 0 insertions, 397 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux-5.4/linux-yocto-5.4.69-amdx86/0001-spi-spi-amd-Add-AMD-SPI-controller-driver-support.patch b/meta-amd-bsp/recipes-kernel/linux-5.4/linux-yocto-5.4.69-amdx86/0001-spi-spi-amd-Add-AMD-SPI-controller-driver-support.patch deleted file mode 100644 index 65e4aa9a..00000000 --- a/meta-amd-bsp/recipes-kernel/linux-5.4/linux-yocto-5.4.69-amdx86/0001-spi-spi-amd-Add-AMD-SPI-controller-driver-support.patch +++ /dev/null @@ -1,397 +0,0 @@ -From 8bc785f4b21ad0d1bb660a3b20750835ef0f47a0 Mon Sep 17 00:00:00 2001 -From: Sanjay R Mehta <sanju.mehta@amd.com> -Date: Sat, 25 Apr 2020 14:59:48 -0500 -Subject: [PATCH 01/21] spi: spi-amd: Add AMD SPI controller driver support - -This driver supports SPI Controller for AMD SOCs.This driver -supports SPI operations using FIFO mode of transfer. - -Signed-off-by: Sanjay R Mehta <sanju.mehta@amd.com> -Signed-off-by: Mark Brown <broonie@kernel.org> -Link: https://lore.kernel.org/r/1587844788-33997-1-git-send-email-sanju.mehta@amd.com -Signed-off-by: Mark Brown <broonie@kernel.org> -Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com> ---- - drivers/spi/Kconfig | 6 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-amd.c | 333 ++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 340 insertions(+) - mode change 100644 => 100755 drivers/spi/Kconfig - mode change 100644 => 100755 drivers/spi/Makefile - create mode 100755 drivers/spi/spi-amd.c - -diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig -old mode 100644 -new mode 100755 -index 5bf754208777..6404cacb377b ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -876,6 +876,12 @@ config SPI_ZYNQMP_GQSPI - help - Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC. - -+config SPI_AMD -+ tristate "AMD SPI controller" -+ depends on SPI_MASTER || COMPILE_TEST -+ help -+ Enables SPI controller driver for AMD SoC. -+ - # - # Add new SPI master controllers in alphabetical order above this line - # -diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile -old mode 100644 -new mode 100755 -index bb49c9e6d0a0..7af5aca3ed04 ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -122,6 +122,7 @@ obj-$(CONFIG_SPI_XLP) += spi-xlp.o - obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o - obj-$(CONFIG_SPI_ZYNQ_QSPI) += spi-zynq-qspi.o - obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o -+obj-$(CONFIG_SPI_AMD) += spi-amd.o - - # SPI slave protocol handlers - obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o -diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c -new file mode 100755 -index 000000000000..0d9debe1386e ---- /dev/null -+++ b/drivers/spi/spi-amd.c -@@ -0,0 +1,333 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -+// -+// AMD SPI controller driver -+// -+// Copyright (c) 2020, Advanced Micro Devices, Inc. -+// -+// Author: Sanjay R Mehta <sanju.mehta@amd.com> -+ -+#include <linux/acpi.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/delay.h> -+#include <linux/spi/spi.h> -+ -+#define AMD_SPI_CTRL0_REG 0x00 -+#define AMD_SPI_EXEC_CMD BIT(16) -+#define AMD_SPI_FIFO_CLEAR BIT(20) -+#define AMD_SPI_BUSY BIT(31) -+ -+#define AMD_SPI_OPCODE_MASK 0xFF -+ -+#define AMD_SPI_ALT_CS_REG 0x1D -+#define AMD_SPI_ALT_CS_MASK 0x3 -+ -+#define AMD_SPI_FIFO_BASE 0x80 -+#define AMD_SPI_TX_COUNT_REG 0x48 -+#define AMD_SPI_RX_COUNT_REG 0x4B -+#define AMD_SPI_STATUS_REG 0x4C -+ -+#define AMD_SPI_MEM_SIZE 200 -+ -+/* M_CMD OP codes for SPI */ -+#define AMD_SPI_XFER_TX 1 -+#define AMD_SPI_XFER_RX 2 -+ -+struct amd_spi { -+ void __iomem *io_remap_addr; -+ unsigned long io_base_addr; -+ u32 rom_addr; -+ struct spi_master *master; -+ u8 chip_select; -+}; -+ -+static inline u8 amd_spi_readreg8(struct spi_master *master, int idx) -+{ -+ struct amd_spi *amd_spi = spi_master_get_devdata(master); -+ -+ return ioread8((u8 __iomem *)amd_spi->io_remap_addr + idx); -+} -+ -+static inline void amd_spi_writereg8(struct spi_master *master, int idx, -+ u8 val) -+{ -+ struct amd_spi *amd_spi = spi_master_get_devdata(master); -+ -+ iowrite8(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); -+} -+ -+static inline void amd_spi_setclear_reg8(struct spi_master *master, int idx, -+ u8 set, u8 clear) -+{ -+ u8 tmp = amd_spi_readreg8(master, idx); -+ -+ tmp = (tmp & ~clear) | set; -+ amd_spi_writereg8(master, idx, tmp); -+} -+ -+static inline u32 amd_spi_readreg32(struct spi_master *master, int idx) -+{ -+ struct amd_spi *amd_spi = spi_master_get_devdata(master); -+ -+ return ioread32((u8 __iomem *)amd_spi->io_remap_addr + idx); -+} -+ -+static inline void amd_spi_writereg32(struct spi_master *master, int idx, -+ u32 val) -+{ -+ struct amd_spi *amd_spi = spi_master_get_devdata(master); -+ -+ iowrite32(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); -+} -+ -+static inline void amd_spi_setclear_reg32(struct spi_master *master, int idx, -+ u32 set, u32 clear) -+{ -+ u32 tmp = amd_spi_readreg32(master, idx); -+ -+ tmp = (tmp & ~clear) | set; -+ amd_spi_writereg32(master, idx, tmp); -+} -+ -+static void amd_spi_select_chip(struct spi_master *master) -+{ -+ struct amd_spi *amd_spi = spi_master_get_devdata(master); -+ u8 chip_select = amd_spi->chip_select; -+ -+ amd_spi_setclear_reg8(master, AMD_SPI_ALT_CS_REG, chip_select, -+ AMD_SPI_ALT_CS_MASK); -+} -+ -+static void amd_spi_clear_fifo_ptr(struct spi_master *master) -+{ -+ amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, AMD_SPI_FIFO_CLEAR, -+ AMD_SPI_FIFO_CLEAR); -+} -+ -+static void amd_spi_set_opcode(struct spi_master *master, u8 cmd_opcode) -+{ -+ amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, cmd_opcode, -+ AMD_SPI_OPCODE_MASK); -+} -+ -+static inline void amd_spi_set_rx_count(struct spi_master *master, -+ u8 rx_count) -+{ -+ amd_spi_setclear_reg8(master, AMD_SPI_RX_COUNT_REG, rx_count, 0xff); -+} -+ -+static inline void amd_spi_set_tx_count(struct spi_master *master, -+ u8 tx_count) -+{ -+ amd_spi_setclear_reg8(master, AMD_SPI_TX_COUNT_REG, tx_count, 0xff); -+} -+ -+static inline int amd_spi_busy_wait(struct amd_spi *amd_spi) -+{ -+ bool spi_busy; -+ int timeout = 100000; -+ -+ /* poll for SPI bus to become idle */ -+ spi_busy = (ioread32((u8 __iomem *)amd_spi->io_remap_addr + -+ AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY; -+ while (spi_busy) { -+ usleep_range(10, 20); -+ if (timeout-- < 0) -+ return -ETIMEDOUT; -+ -+ spi_busy = (ioread32((u8 __iomem *)amd_spi->io_remap_addr + -+ AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY; -+ } -+ -+ return 0; -+} -+ -+static void amd_spi_execute_opcode(struct spi_master *master) -+{ -+ struct amd_spi *amd_spi = spi_master_get_devdata(master); -+ -+ /* Set ExecuteOpCode bit in the CTRL0 register */ -+ amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, AMD_SPI_EXEC_CMD, -+ AMD_SPI_EXEC_CMD); -+ -+ amd_spi_busy_wait(amd_spi); -+} -+ -+static int amd_spi_master_setup(struct spi_device *spi) -+{ -+ struct spi_master *master = spi->master; -+ -+ amd_spi_clear_fifo_ptr(master); -+ -+ return 0; -+} -+ -+static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, -+ struct spi_message *message) -+{ -+ struct spi_master *master = amd_spi->master; -+ struct spi_transfer *xfer = NULL; -+ u8 cmd_opcode, opcode = 0; -+ u8 *buf = NULL; -+ u32 m_cmd = 0; -+ u32 i = 0; -+ u32 tx_len = 0, rx_len = 0; -+ -+ list_for_each_entry(xfer, &message->transfers, -+ transfer_list) { -+ if (xfer->rx_buf) -+ m_cmd = AMD_SPI_XFER_RX; -+ if (xfer->tx_buf) -+ m_cmd = AMD_SPI_XFER_TX; -+ -+ if (m_cmd & AMD_SPI_XFER_TX) { -+ buf = (u8 *)xfer->tx_buf; -+ tx_len = xfer->len - 1; -+ cmd_opcode = *(u8 *)xfer->tx_buf; -+ buf++; -+ amd_spi_set_opcode(master, cmd_opcode); -+ -+ /* Write data into the FIFO. */ -+ for (i = 0; i < tx_len; i++) { -+ iowrite8(buf[i], -+ ((u8 __iomem *)amd_spi->io_remap_addr + -+ AMD_SPI_FIFO_BASE + i)); -+ } -+ -+ amd_spi_set_tx_count(master, tx_len); -+ amd_spi_clear_fifo_ptr(master); -+ /* Execute command */ -+ amd_spi_execute_opcode(master); -+ } -+ if (m_cmd & AMD_SPI_XFER_RX) { -+ /* -+ * Store no. of bytes to be received from -+ * FIFO -+ */ -+ rx_len = xfer->len; -+ buf = (u8 *)xfer->rx_buf; -+ amd_spi_set_rx_count(master, rx_len); -+ amd_spi_clear_fifo_ptr(master); -+ /* Execute command */ -+ amd_spi_execute_opcode(master); -+ /* Read data from FIFO to receive buffer */ -+ for (i = 0; i < rx_len; i++) -+ buf[i] = amd_spi_readreg8(master, -+ AMD_SPI_FIFO_BASE + -+ tx_len + i); -+ } -+ } -+ -+ /* Update statistics */ -+ message->actual_length = tx_len + rx_len + 1; -+ /* complete the transaction */ -+ message->status = 0; -+ spi_finalize_current_message(master); -+ -+ return 0; -+} -+ -+static int amd_spi_master_transfer(struct spi_master *master, -+ struct spi_message *msg) -+{ -+ struct amd_spi *amd_spi = spi_master_get_devdata(master); -+ struct spi_device *spi = msg->spi; -+ -+ amd_spi->chip_select = spi->chip_select; -+ amd_spi_select_chip(master); -+ -+ /* -+ * Extract spi_transfers from the spi message and -+ * program the controller. -+ */ -+ amd_spi_fifo_xfer(amd_spi, msg); -+ -+ return 0; -+} -+ -+static int amd_spi_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct spi_master *master; -+ struct amd_spi *amd_spi; -+ struct resource *res; -+ int err = 0; -+ -+ /* Allocate storage for spi_master and driver private data */ -+ master = spi_alloc_master(dev, sizeof(struct amd_spi)); -+ if (!master) { -+ dev_err(dev, "Error allocating SPI master\n"); -+ return -ENOMEM; -+ } -+ -+ amd_spi = spi_master_get_devdata(master); -+ amd_spi->master = master; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ amd_spi->io_remap_addr = devm_ioremap_resource(&pdev->dev, res); -+ -+ if (!amd_spi->io_remap_addr) { -+ dev_err(dev, "error %d ioremap of SPI registers failed\n", err); -+ err = -ENOMEM; -+ goto err_free_master; -+ } -+ dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr); -+ -+ /* Initialize the spi_master fields */ -+ master->bus_num = 0; -+ master->num_chipselect = 4; -+ master->mode_bits = 0; -+ master->flags = SPI_MASTER_HALF_DUPLEX; -+ master->setup = amd_spi_master_setup; -+ master->transfer_one_message = amd_spi_master_transfer; -+ -+ /* Register the controller with SPI framework */ -+ err = spi_register_master(master); -+ if (err) { -+ dev_err(dev, "error %d registering SPI controller\n", err); -+ goto err_iounmap; -+ } -+ platform_set_drvdata(pdev, amd_spi); -+ -+ return 0; -+ -+err_iounmap: -+ iounmap(amd_spi->io_remap_addr); -+err_free_master: -+ spi_master_put(master); -+ -+ return 0; -+} -+ -+static int amd_spi_remove(struct platform_device *pdev) -+{ -+ struct amd_spi *amd_spi = platform_get_drvdata(pdev); -+ -+ spi_unregister_master(amd_spi->master); -+ spi_master_put(amd_spi->master); -+ platform_set_drvdata(pdev, NULL); -+ -+ return 0; -+} -+ -+static const struct acpi_device_id spi_acpi_match[] = { -+ { "AMDI0061", 0 }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(acpi, spi_acpi_match); -+ -+static struct platform_driver amd_spi_driver = { -+ .driver = { -+ .name = "amd_spi", -+ .acpi_match_table = ACPI_PTR(spi_acpi_match), -+ }, -+ .probe = amd_spi_probe, -+ .remove = amd_spi_remove, -+}; -+ -+module_platform_driver(amd_spi_driver); -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Sanjay Mehta <sanju.mehta@amd.com>"); -+MODULE_DESCRIPTION("AMD SPI Master Controller Driver"); --- -2.17.1 - |