From patchwork Tue Apr 30 16:08:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrice CHOTARD X-Patchwork-Id: 1093359 X-Patchwork-Delegate: patrice.chotard@st.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=st.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=st.com header.i=@st.com header.b="USx14C1B"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 44tmhp6v1vz9sB3 for ; Wed, 1 May 2019 02:10:34 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 5C4D0C21E77; Tue, 30 Apr 2019 16:09:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id E23E1C21E75; Tue, 30 Apr 2019 16:08:58 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id B782BC21E57; Tue, 30 Apr 2019 16:08:36 +0000 (UTC) Received: from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by lists.denx.de (Postfix) with ESMTPS id B1BA2C21D83 for ; Tue, 30 Apr 2019 16:08:32 +0000 (UTC) Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx08-00178001.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x3UFpPfx005729; Tue, 30 Apr 2019 18:08:32 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=STMicroelectronics; bh=1WXM1drwuXDp2sGCiuYiiVt9N8wFTBYrKBIfQbuUXak=; b=USx14C1Bd2NTyhgNIvrMBrPqLu4iqIKimCjDviEgwmBROQkWdsBD4jNAFxdyg/2S8g0q hc4X1JIfBWLqs6Ph0FjkIPykcw+DBba2BAwFM1dbWWML+OjoT241H9uemdV0NjNIEE2f X/drtfHw4O16nrSd/uEtqn0+ToDA3cePP6jsQuBJIn3bIyTACqZTyJrfzKjfgDbnV5XN JHrnJn1fTNwL7MfzYxHkLYyP7TPr9do0HU65lRjb+MJ6VzDaABCpLtjNZNR+YE/cB9b5 ar68c5T7hhkNtbtUpdJmSh0sBusRMp3OPDdIxEaP+j8UWCpHy/6ao3/m1S4t5ckpp/aC Aw== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-00178001.pphosted.com with ESMTP id 2s61r0f26p-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Tue, 30 Apr 2019 18:08:32 +0200 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id B54A831; Tue, 30 Apr 2019 16:08:30 +0000 (GMT) Received: from Webmail-eu.st.com (sfhdag6node3.st.com [10.75.127.18]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id C209B2997; Tue, 30 Apr 2019 16:08:30 +0000 (GMT) Received: from localhost (10.75.127.44) by SFHDAG6NODE3.st.com (10.75.127.18) with Microsoft SMTP Server (TLS) id 15.0.1347.2; Tue, 30 Apr 2019 18:08:30 +0200 From: Patrice Chotard To: Date: Tue, 30 Apr 2019 18:08:27 +0200 Message-ID: <1556640509-27836-2-git-send-email-patrice.chotard@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1556640509-27836-1-git-send-email-patrice.chotard@st.com> References: <1556640509-27836-1-git-send-email-patrice.chotard@st.com> MIME-Version: 1.0 X-Originating-IP: [10.75.127.44] X-ClientProxiedBy: SFHDAG5NODE1.st.com (10.75.127.13) To SFHDAG6NODE3.st.com (10.75.127.18) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-04-30_08:, , signatures=0 Cc: U-Boot STM32 Subject: [U-Boot] [PATCH 1/3] clk: stm32mp1: Add SPI1 clock entry X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add missing SPI1 clock needed by SPI1 instance. Signed-off-by: Patrice Chotard --- drivers/clk/clk_stm32mp1.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 24859fd..800ded7 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -90,6 +90,7 @@ #define RCC_PLL4CSGR 0x8A4 #define RCC_I2C12CKSELR 0x8C0 #define RCC_I2C35CKSELR 0x8C4 +#define RCC_SPI2S1CKSELR 0x8D8 #define RCC_UART6CKSELR 0x8E4 #define RCC_UART24CKSELR 0x8E8 #define RCC_UART35CKSELR 0x8EC @@ -298,6 +299,7 @@ enum stm32mp1_parent_sel { _STGEN_SEL, _DSI_SEL, _ADC12_SEL, + _SPI1_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; @@ -519,6 +521,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 8, SPI1_K, _SPI1_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3), @@ -589,6 +592,8 @@ static const u8 usbo_parents[] = {_PLL4_R, _USB_PHY_48}; static const u8 stgen_parents[] = {_HSI_KER, _HSE_KER}; static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P}; static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q}; +static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER, + _PLL3_R}; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents), @@ -613,6 +618,7 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents), + STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), }; #ifdef STM32MP1_CLOCK_TREE_INIT @@ -727,6 +733,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { [_STGEN_SEL] = "STGEN", [_DSI_SEL] = "DSI", [_ADC12_SEL] = "ADC12", + [_SPI1_SEL] = "SPI1", }; static const struct stm32mp1_clk_data stm32mp1_data = { From patchwork Tue Apr 30 16:08:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrice CHOTARD X-Patchwork-Id: 1093360 X-Patchwork-Delegate: patrice.chotard@st.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=st.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=st.com header.i=@st.com header.b="qVUSTJvG"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 44tmj00y6jz9sB3 for ; Wed, 1 May 2019 02:10:44 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id CAB9FC21ED6; Tue, 30 Apr 2019 16:10:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id E7364C21D72; Tue, 30 Apr 2019 16:09:58 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 80B20C21EB1; Tue, 30 Apr 2019 16:08:55 +0000 (UTC) Received: from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by lists.denx.de (Postfix) with ESMTPS id 7AC8DC21D56 for ; Tue, 30 Apr 2019 16:08:50 +0000 (UTC) Received: from pps.filterd (m0046660.ppops.net [127.0.0.1]) by mx08-00178001.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x3UFpPW5022565; Tue, 30 Apr 2019 18:08:33 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=STMicroelectronics; bh=dKpPujPLaHMQwMt8Zya0NU9tjbn8bVR0O7uUQrc2jRM=; b=qVUSTJvGPmpdCg53rku7N9GgZ2FIhcZGfbIDDAwdi5VfqC6deuPTyMi01FnlJ0x0JXx9 XavuAMbDJ967xrl8isY6wh0HGP7ViiwOZ7QeTogWYq/q3RR0BqqGgNKrqmRrkugfy7eY tpNJiS0hnfejIFOuwcfwv86hsG82MNGtC31u9y7qpZBVZtQLE3+8EXMJFZBZB8L7h3rD HPmKDbo2iGZfdCKL1FM9UsAdQ+GklgUEKnmH+NOb+m09sMzlhDJcOCMa7QJ11ZeLdvFY JwbzFl1lLpeac1QBl4ZU4LEfpMV5bdHFrUKpWzZ3trh/srb132UDxpAxrsSHhf2kQbZF Tg== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-00178001.pphosted.com with ESMTP id 2s61r46ydf-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Tue, 30 Apr 2019 18:08:33 +0200 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 01C2F34; Tue, 30 Apr 2019 16:08:31 +0000 (GMT) Received: from Webmail-eu.st.com (sfhdag6node3.st.com [10.75.127.18]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id B8BF02998; Tue, 30 Apr 2019 16:08:31 +0000 (GMT) Received: from localhost (10.75.127.47) by SFHDAG6NODE3.st.com (10.75.127.18) with Microsoft SMTP Server (TLS) id 15.0.1347.2; Tue, 30 Apr 2019 18:08:31 +0200 From: Patrice Chotard To: Date: Tue, 30 Apr 2019 18:08:28 +0200 Message-ID: <1556640509-27836-3-git-send-email-patrice.chotard@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1556640509-27836-1-git-send-email-patrice.chotard@st.com> References: <1556640509-27836-1-git-send-email-patrice.chotard@st.com> MIME-Version: 1.0 X-Originating-IP: [10.75.127.47] X-ClientProxiedBy: SFHDAG3NODE3.st.com (10.75.127.9) To SFHDAG6NODE3.st.com (10.75.127.18) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-04-30_08:, , signatures=0 Cc: Alexander Graf , Ryder Lee , Heinrich Schuchardt , Michal Simek , Krzysztof Kozlowski , U-Boot STM32 , Stefan Roese Subject: [U-Boot] [PATCH 2/3] spi: stm32: Add Serial Peripheral Interface driver for STM32MP X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add SPI driver support for STM32MP SoCs family. Signed-off-by: Patrice Chotard --- MAINTAINERS | 1 + drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/stm32_spi.c | 615 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 625 insertions(+) create mode 100644 drivers/spi/stm32_spi.c diff --git a/MAINTAINERS b/MAINTAINERS index 09f31cd..020dcd2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -311,6 +311,7 @@ F: drivers/ram/stm32mp1/ F: drivers/misc/stm32_rcc.c F: drivers/reset/stm32-reset.c F: drivers/spi/stm32_qspi.c +F: drivers/spi/stm32_spi.c ARM STM STV0991 M: Vikas Manocha diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index fb794ad..49bc940 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -228,6 +228,14 @@ config STM32_QSPI used to access the SPI NOR flash chips on platforms embedding this ST IP core. +config STM32_SPI + bool "STM32 SPI driver" + depends on ARCH_STM32MP + help + Enable the STM32 Serial Peripheral Interface (SPI) driver for STM32MP + SoCs. This uses driver model and requires a device tree binding to + operate. + config TEGRA114_SPI bool "nVidia Tegra114 SPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8be9a4b..3f9f2fa 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_SPI_SUNXI) += spi-sunxi.o obj-$(CONFIG_SH_SPI) += sh_spi.o obj-$(CONFIG_SH_QSPI) += sh_qspi.o obj-$(CONFIG_STM32_QSPI) += stm32_qspi.o +obj-$(CONFIG_STM32_SPI) += stm32_spi.o obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c new file mode 100644 index 0000000..34b2175 --- /dev/null +++ b/drivers/spi/stm32_spi.c @@ -0,0 +1,615 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + * + * Driver for STMicroelectronics Serial peripheral interface (SPI) + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* STM32 SPI registers */ +#define STM32_SPI_CR1 0x00 +#define STM32_SPI_CR2 0x04 +#define STM32_SPI_CFG1 0x08 +#define STM32_SPI_CFG2 0x0C +#define STM32_SPI_SR 0x14 +#define STM32_SPI_IFCR 0x18 +#define STM32_SPI_TXDR 0x20 +#define STM32_SPI_RXDR 0x30 +#define STM32_SPI_I2SCFGR 0x50 + +/* STM32_SPI_CR1 bit fields */ +#define SPI_CR1_SPE BIT(0) +#define SPI_CR1_MASRX BIT(8) +#define SPI_CR1_CSTART BIT(9) +#define SPI_CR1_CSUSP BIT(10) +#define SPI_CR1_HDDIR BIT(11) +#define SPI_CR1_SSI BIT(12) + +/* STM32_SPI_CR2 bit fields */ +#define SPI_CR2_TSIZE GENMASK(15, 0) + +/* STM32_SPI_CFG1 bit fields */ +#define SPI_CFG1_DSIZE GENMASK(4, 0) +#define SPI_CFG1_DSIZE_MIN 3 +#define SPI_CFG1_FTHLV_SHIFT 5 +#define SPI_CFG1_FTHLV GENMASK(8, 5) +#define SPI_CFG1_MBR_SHIFT 28 +#define SPI_CFG1_MBR GENMASK(30, 28) +#define SPI_CFG1_MBR_MIN 0 +#define SPI_CFG1_MBR_MAX FIELD_GET(SPI_CFG1_MBR, SPI_CFG1_MBR) + +/* STM32_SPI_CFG2 bit fields */ +#define SPI_CFG2_COMM_SHIFT 17 +#define SPI_CFG2_COMM GENMASK(18, 17) +#define SPI_CFG2_MASTER BIT(22) +#define SPI_CFG2_LSBFRST BIT(23) +#define SPI_CFG2_CPHA BIT(24) +#define SPI_CFG2_CPOL BIT(25) +#define SPI_CFG2_SSM BIT(26) +#define SPI_CFG2_AFCNTR BIT(31) + +/* STM32_SPI_SR bit fields */ +#define SPI_SR_RXP BIT(0) +#define SPI_SR_TXP BIT(1) +#define SPI_SR_EOT BIT(3) +#define SPI_SR_TXTF BIT(4) +#define SPI_SR_OVR BIT(6) +#define SPI_SR_SUSP BIT(11) +#define SPI_SR_RXPLVL_SHIFT 13 +#define SPI_SR_RXPLVL GENMASK(14, 13) +#define SPI_SR_RXWNE BIT(15) + +/* STM32_SPI_IFCR bit fields */ +#define SPI_IFCR_ALL GENMASK(11, 3) + +/* STM32_SPI_I2SCFGR bit fields */ +#define SPI_I2SCFGR_I2SMOD BIT(0) + +#define MAX_CS_COUNT 4 + +/* SPI Master Baud Rate min/max divisor */ +#define STM32_MBR_DIV_MIN (2 << SPI_CFG1_MBR_MIN) +#define STM32_MBR_DIV_MAX (2 << SPI_CFG1_MBR_MAX) + +#define STM32_SPI_TIMEOUT_US 100000 + +/* SPI Communication mode */ +#define SPI_FULL_DUPLEX 0 +#define SPI_SIMPLEX_TX 1 +#define SPI_SIMPLEX_RX 2 +#define SPI_HALF_DUPLEX 3 + +struct stm32_spi_priv { + void __iomem *base; + struct clk clk; + struct reset_ctl rst_ctl; + struct gpio_desc cs_gpios[MAX_CS_COUNT]; + ulong bus_clk_rate; + unsigned int fifo_size; + unsigned int cur_bpw; + unsigned int cur_hz; + unsigned int cur_xferlen; /* current transfer length in bytes */ + int tx_len; /* number of data to be written in bytes */ + int rx_len; /* number of data to be read in bytes */ + const void *tx_buf; /* data to be written, or NULL */ + void *rx_buf; /* data to be read, or NULL */ + u32 cur_mode; + bool cs_high; +}; + +static void stm32_spi_write_txfifo(struct stm32_spi_priv *priv) +{ + while ((priv->tx_len > 0) && + (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP)) { + u32 offs = priv->cur_xferlen - priv->tx_len; + + if (priv->tx_len >= sizeof(u32) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u32))) { + const u32 *tx_buf32 = (const u32 *)(priv->tx_buf + offs); + + writel(*tx_buf32, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u32); + } else if (priv->tx_len >= sizeof(u16) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u16))) { + const u16 *tx_buf16 = (const u16 *)(priv->tx_buf + offs); + + writew(*tx_buf16, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u16); + } else { + const u8 *tx_buf8 = (const u8 *)(priv->tx_buf + offs); + + writeb(*tx_buf8, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u8); + } + } + + debug("%s: %d bytes left\n", __func__, priv->tx_len); +} + +static void stm32_spi_read_rxfifo(struct stm32_spi_priv *priv) +{ + u32 sr = readl(priv->base + STM32_SPI_SR); + u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + + while ((priv->rx_len > 0) && + ((sr & SPI_SR_RXP) || + ((sr & SPI_SR_EOT) && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) { + u32 offs = priv->cur_xferlen - priv->rx_len; + + if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u32)) && + (priv->rx_len >= sizeof(u32) || (sr & SPI_SR_RXWNE))) { + u32 *rx_buf32 = (u32 *)(priv->rx_buf + offs); + + *rx_buf32 = readl(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u32); + } else if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u16)) && + (priv->rx_len >= sizeof(u16) || + (!(sr & SPI_SR_RXWNE) && + (rxplvl >= 2 || priv->cur_bpw > 8)))) { + u16 *rx_buf16 = (u16 *)(priv->rx_buf + offs); + + *rx_buf16 = readw(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u16); + } else { + u8 *rx_buf8 = (u8 *)(priv->rx_buf + offs); + + *rx_buf8 = readb(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u8); + } + + sr = readl(priv->base + STM32_SPI_SR); + rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + } + + debug("%s: %d bytes left\n", __func__, priv->rx_len); +} + +static int stm32_spi_enable(struct stm32_spi_priv *priv) +{ + debug("%s\n", __func__); + + /* Enable the SPI hardware */ + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + + return 0; +} + +static int stm32_spi_disable(struct stm32_spi_priv *priv) +{ + debug("%s\n", __func__); + + /* Disable the SPI hardware */ + clrbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + + return 0; +} + +static int stm32_spi_claim_bus(struct udevice *slave) +{ + struct udevice *bus = dev_get_parent(slave); + struct stm32_spi_priv *priv = dev_get_priv(bus); + + debug("%s\n", __func__); + + /* Enable the SPI hardware */ + return stm32_spi_enable(priv); +} + +static int stm32_spi_release_bus(struct udevice *slave) +{ + struct udevice *bus = dev_get_parent(slave); + struct stm32_spi_priv *priv = dev_get_priv(bus); + + debug("%s\n", __func__); + + /* Disable the SPI hardware */ + return stm32_spi_disable(priv); +} + +static void stm32_spi_stopxfer(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 cr1, sr; + int ret; + + debug("%s\n", __func__); + + cr1 = readl(priv->base + STM32_SPI_CR1); + + if (!(cr1 & SPI_CR1_SPE)) + return; + + /* Wait on EOT or suspend the flow */ + ret = readl_poll_timeout(priv->base + STM32_SPI_SR, sr, + !(sr & SPI_SR_EOT), 100000); + if (ret < 0) { + if (cr1 & SPI_CR1_CSTART) { + writel(cr1 | SPI_CR1_CSUSP, priv->base + STM32_SPI_CR1); + if (readl_poll_timeout(priv->base + STM32_SPI_SR, + sr, !(sr & SPI_SR_SUSP), + 100000) < 0) + dev_err(dev, "Suspend request timeout\n"); + } + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); +} + +static int stm32_spi_set_cs(struct udevice *dev, unsigned int cs, bool enable) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + + debug("%s: cs=%d enable=%d\n", __func__, cs, enable); + + if (cs >= MAX_CS_COUNT) + return -ENODEV; + + if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) + return -EINVAL; + + if (priv->cs_high) + enable = !enable; + + return dm_gpio_set_value(&priv->cs_gpios[cs], enable ? 1 : 0); +} + +static int stm32_spi_set_mode(struct udevice *bus, uint mode) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 cfg2_clrb = 0, cfg2_setb = 0; + + debug("%s: mode=%d\n", __func__, mode); + + if (mode & SPI_CPOL) + cfg2_setb |= SPI_CFG2_CPOL; + else + cfg2_clrb |= SPI_CFG2_CPOL; + + if (mode & SPI_CPHA) + cfg2_setb |= SPI_CFG2_CPHA; + else + cfg2_clrb |= SPI_CFG2_CPHA; + + if (mode & SPI_LSB_FIRST) + cfg2_setb |= SPI_CFG2_LSBFRST; + else + cfg2_clrb |= SPI_CFG2_LSBFRST; + + if (cfg2_clrb || cfg2_setb) + clrsetbits_le32(priv->base + STM32_SPI_CFG2, + cfg2_clrb, cfg2_setb); + + if (mode & SPI_CS_HIGH) + priv->cs_high = true; + else + priv->cs_high = false; + return 0; +} + +static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 fthlv, half_fifo; + + /* data packet should not exceed 1/2 of fifo space */ + half_fifo = (priv->fifo_size / 2); + + /* data_packet should not exceed transfer length */ + fthlv = (half_fifo > xfer_len) ? xfer_len : half_fifo; + + /* align packet size with data registers access */ + fthlv -= (fthlv % 4); + + if (!fthlv) + fthlv = 1; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_FTHLV, + (fthlv - 1) << SPI_CFG1_FTHLV_SHIFT); + + return 0; +} + +static int stm32_spi_set_speed(struct udevice *bus, uint hz) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 div, mbrdiv; + + debug("%s: hz=%d\n", __func__, hz); + + if (priv->cur_hz == hz) + return 0; + + div = DIV_ROUND_UP(priv->bus_clk_rate, hz); + + if (div < STM32_MBR_DIV_MIN || + div > STM32_MBR_DIV_MAX) + return -EINVAL; + + /* Determine the first power of 2 greater than or equal to div */ + if (div & (div - 1)) + mbrdiv = fls(div); + else + mbrdiv = fls(div) - 1; + + if ((mbrdiv - 1) < 0) + return -EINVAL; + + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_MBR, + (mbrdiv - 1) << SPI_CFG1_MBR_SHIFT); + + priv->cur_hz = hz; + + return 0; +} + +static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(slave); + struct dm_spi_slave_platdata *slave_plat; + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 sr; + u32 ifcr = 0; + u32 xferlen; + u32 mode; + int xfer_status = 0; + + xferlen = bitlen / 8; + + if (xferlen <= SPI_CR2_TSIZE) + writel(xferlen, priv->base + STM32_SPI_CR2); + else + return -EMSGSIZE; + + priv->tx_buf = dout; + priv->rx_buf = din; + priv->tx_len = priv->tx_buf ? bitlen / 8 : 0; + priv->rx_len = priv->rx_buf ? bitlen / 8 : 0; + + mode = SPI_FULL_DUPLEX; + if (!priv->tx_buf) + mode = SPI_SIMPLEX_RX; + else if (!priv->rx_buf) + mode = SPI_SIMPLEX_TX; + + if (priv->cur_xferlen != xferlen || priv->cur_mode != mode) { + priv->cur_mode = mode; + priv->cur_xferlen = xferlen; + + /* Disable the SPI hardware to unlock CFG1/CFG2 registers */ + stm32_spi_disable(priv); + + clrsetbits_le32(priv->base + STM32_SPI_CFG2, SPI_CFG2_COMM, + mode << SPI_CFG2_COMM_SHIFT); + + stm32_spi_set_fthlv(bus, xferlen); + + /* Enable the SPI hardware */ + stm32_spi_enable(priv); + } + + debug("%s: priv->tx_len=%d priv->rx_len=%d\n", __func__, + priv->tx_len, priv->rx_len); + + slave_plat = dev_get_parent_platdata(slave); + if (flags & SPI_XFER_BEGIN) + stm32_spi_set_cs(bus, slave_plat->cs, false); + + /* Be sure to have data in fifo before starting data transfer */ + if (priv->tx_buf) + stm32_spi_write_txfifo(priv); + + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_CSTART); + + while (1) { + sr = readl(priv->base + STM32_SPI_SR); + + if (sr & SPI_SR_OVR) { + dev_err(bus, "Overrun: RX data lost\n"); + xfer_status = -EIO; + break; + } + + if (sr & SPI_SR_SUSP) { + dev_warn(bus, "System too slow is limiting data throughput\n"); + + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + ifcr |= SPI_SR_SUSP; + } + + if (sr & SPI_SR_TXTF) + ifcr |= SPI_SR_TXTF; + + if (sr & SPI_SR_TXP) + if (priv->tx_buf && priv->tx_len > 0) + stm32_spi_write_txfifo(priv); + + if (sr & SPI_SR_RXP) + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + if (sr & SPI_SR_EOT) { + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + break; + } + + writel(ifcr, priv->base + STM32_SPI_IFCR); + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); + stm32_spi_stopxfer(bus); + + if (flags & SPI_XFER_END) + stm32_spi_set_cs(bus, slave_plat->cs, true); + + return xfer_status; +} + +static int stm32_spi_get_fifo_size(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 count = 0; + + stm32_spi_enable(priv); + + while (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP) + writeb(++count, priv->base + STM32_SPI_TXDR); + + stm32_spi_disable(priv); + + debug("%s %d x 8-bit fifo size\n", __func__, count); + + return count; +} + +static int stm32_spi_probe(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + unsigned long clk_rate; + int ret; + int i; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + /* enable clock */ + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret < 0) + return ret; + + ret = clk_enable(&priv->clk); + if (ret < 0) + return ret; + + clk_rate = clk_get_rate(&priv->clk); + if (!clk_rate) { + ret = -EINVAL; + goto clk_err; + } + + priv->bus_clk_rate = clk_rate; + + /* perform reset */ + ret = reset_get_by_index(dev, 0, &priv->rst_ctl); + if (ret < 0) + goto clk_err; + + reset_assert(&priv->rst_ctl); + udelay(2); + reset_deassert(&priv->rst_ctl); + + ret = gpio_request_list_by_name(dev, "cs-gpios", priv->cs_gpios, + ARRAY_SIZE(priv->cs_gpios), 0); + if (ret < 0) { + pr_err("Can't get %s cs gpios: %d", dev->name, ret); + goto reset_err; + } + + priv->fifo_size = stm32_spi_get_fifo_size(dev); + + priv->cur_mode = SPI_FULL_DUPLEX; + priv->cur_xferlen = 0; + priv->cur_bpw = SPI_DEFAULT_WORDLEN; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, + priv->cur_bpw - 1); + + for (i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { + if (!dm_gpio_is_valid(&priv->cs_gpios[i])) + continue; + + dm_gpio_set_dir_flags(&priv->cs_gpios[i], + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + } + + /* Ensure I2SMOD bit is kept cleared */ + clrbits_le32(priv->base + STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD); + + /* + * - SS input value high + * - transmitter half duplex direction + * - automatic communication suspend when RX-Fifo is full + */ + setbits_le32(priv->base + STM32_SPI_CR1, + SPI_CR1_SSI | SPI_CR1_HDDIR | SPI_CR1_MASRX); + + /* + * - Set the master mode (default Motorola mode) + * - Consider 1 master/n slaves configuration and + * SS input value is determined by the SSI bit + * - keep control of all associated GPIOs + */ + setbits_le32(priv->base + STM32_SPI_CFG2, + SPI_CFG2_MASTER | SPI_CFG2_SSM | SPI_CFG2_AFCNTR); + + return 0; + +reset_err: + reset_free(&priv->rst_ctl); + +clk_err: + clk_disable(&priv->clk); + clk_free(&priv->clk); + + return ret; +}; + +static int stm32_spi_remove(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + int ret; + + stm32_spi_stopxfer(dev); + stm32_spi_disable(priv); + + ret = reset_assert(&priv->rst_ctl); + if (ret < 0) + return ret; + + reset_free(&priv->rst_ctl); + + ret = clk_disable(&priv->clk); + if (ret < 0) + return ret; + + clk_free(&priv->clk); + + return ret; +}; + +static const struct dm_spi_ops stm32_spi_ops = { + .claim_bus = stm32_spi_claim_bus, + .release_bus = stm32_spi_release_bus, + .set_mode = stm32_spi_set_mode, + .set_speed = stm32_spi_set_speed, + .xfer = stm32_spi_xfer, +}; + +static const struct udevice_id stm32_spi_ids[] = { + { .compatible = "st,stm32h7-spi", }, + { } +}; + +U_BOOT_DRIVER(stm32_spi) = { + .name = "stm32_spi", + .id = UCLASS_SPI, + .of_match = stm32_spi_ids, + .ops = &stm32_spi_ops, + .priv_auto_alloc_size = sizeof(struct stm32_spi_priv), + .probe = stm32_spi_probe, + .remove = stm32_spi_remove, +}; From patchwork Tue Apr 30 16:08:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrice CHOTARD X-Patchwork-Id: 1093358 X-Patchwork-Delegate: patrice.chotard@st.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=st.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=st.com header.i=@st.com header.b="pp+t0EEr"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 44tmhB3Tqxz9sB8 for ; Wed, 1 May 2019 02:10:02 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 13E11C21EAE; Tue, 30 Apr 2019 16:09:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 5F5B2C21DD4; Tue, 30 Apr 2019 16:08:48 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 8C37AC21DFD; Tue, 30 Apr 2019 16:08:37 +0000 (UTC) Received: from mx07-00178001.pphosted.com (mx07-00178001.pphosted.com [62.209.51.94]) by lists.denx.de (Postfix) with ESMTPS id 81877C21E2F for ; Tue, 30 Apr 2019 16:08:33 +0000 (UTC) Received: from pps.filterd (m0046668.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x3UFotQU023993; Tue, 30 Apr 2019 18:08:33 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=STMicroelectronics; bh=6DRoG2cf4ure2e2kQdb/2jnzVN7fRfFsUaRA7s8kYro=; b=pp+t0EErWPlxQQiWVm5oBQK6w9VT77Aq8XFEHYgFrewYaJ93dMwBOGHJ5jf/MrdyRarE ecKh7f1mfGHXXwPIZLluM/ywZr6JZzJpfyXTQMAmQe0Q0AKA1Zqx1xjbrj4r/6ic1gLq ircQTxKQPxOmSaCXEtddXrZP3qERbbsGXahpbido/emo31dSwewMsc05evN/IaXS+FuC 0zNw9oLd64z+sZxEWmJxHoPD8ccFfUY+3l9gisrHtZ3Sx5QpFN9VB+NtEcGCYlqgCRZG d2qxTTAG0d2CIcAEeh0n9aP9r3RDDigy2/Q4QjdeK6U04PiMiAonYeNimqlQaGQ1GS5e 2g== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 2s6rs8g82t-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Tue, 30 Apr 2019 18:08:33 +0200 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id A106D3D; Tue, 30 Apr 2019 16:08:32 +0000 (GMT) Received: from Webmail-eu.st.com (sfhdag6node3.st.com [10.75.127.18]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 80797299A; Tue, 30 Apr 2019 16:08:32 +0000 (GMT) Received: from localhost (10.75.127.44) by SFHDAG6NODE3.st.com (10.75.127.18) with Microsoft SMTP Server (TLS) id 15.0.1347.2; Tue, 30 Apr 2019 18:08:32 +0200 From: Patrice Chotard To: Date: Tue, 30 Apr 2019 18:08:29 +0200 Message-ID: <1556640509-27836-4-git-send-email-patrice.chotard@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1556640509-27836-1-git-send-email-patrice.chotard@st.com> References: <1556640509-27836-1-git-send-email-patrice.chotard@st.com> MIME-Version: 1.0 X-Originating-IP: [10.75.127.44] X-ClientProxiedBy: SFHDAG1NODE3.st.com (10.75.127.3) To SFHDAG6NODE3.st.com (10.75.127.18) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-04-30_08:, , signatures=0 Cc: U-Boot STM32 Subject: [U-Boot] [PATCH 3/3] configs: stm32mp15: Enable SPI relative flags X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Enable STM32_SPI, SPI, DM_SPI and CMD_SPI flags. This enables the SPI support for STM32MP15. Signed-off-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 4 ++++ configs/stm32mp15_trusted_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index bd75df8..1fe7e1d 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -29,6 +29,7 @@ CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y +CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_CACHE=y @@ -68,6 +69,9 @@ CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_STM32_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_USB_GADGET=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index f82b770..f29cd55 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -22,6 +22,7 @@ CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y +CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_CACHE=y @@ -58,6 +59,9 @@ CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_STM32_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_USB_GADGET=y