From 6fa45ea17d6639df25ebe75f6312f7fc51f1ce89 Mon Sep 17 00:00:00 2001 From: yafeng_wang Date: Sat, 19 Mar 2022 17:24:07 +0800 Subject: [PATCH] feat: add spi driver for stm32mp157 soc Signed-off-by: yafeng_wang --- common/platform/BUILD.gn | 1 + common/platform/lite.mk | 4 + common/platform/spi/BUILD.gn | 42 + common/platform/spi/Makefile | 43 + common/platform/spi/stm32mp1_spi.c | 945 ++++++++++++++++++ common/platform/spi/stm32mp1_spi.h | 148 +++ .../hdf_config/device_info/device_info.hcs | 16 + stm32mp157/sdk_liteos/hdf_config/hdf.hcs | 1 + .../hdf_config/spi_i2s/spi_i2s_config.hcs | 75 ++ 9 files changed, 1275 insertions(+) create mode 100644 common/platform/spi/BUILD.gn create mode 100755 common/platform/spi/Makefile create mode 100644 common/platform/spi/stm32mp1_spi.c create mode 100644 common/platform/spi/stm32mp1_spi.h create mode 100644 stm32mp157/sdk_liteos/hdf_config/spi_i2s/spi_i2s_config.hcs diff --git a/common/platform/BUILD.gn b/common/platform/BUILD.gn index 7796abe..5433361 100755 --- a/common/platform/BUILD.gn +++ b/common/platform/BUILD.gn @@ -16,6 +16,7 @@ import("//drivers/adapter/khdf/liteos/hdf.gni") group("drivers") { deps = [ "adc", + "spi", "gpio", "i2c", "iwdg", diff --git a/common/platform/lite.mk b/common/platform/lite.mk index d48148c..9f5a97d 100755 --- a/common/platform/lite.mk +++ b/common/platform/lite.mk @@ -25,6 +25,10 @@ ifeq ($(LOSCFG_DRIVERS_HDF_PLATFORM_ADC), y) LIB_SUBDIRS += $(ST_DRIVERS_ROOT)/adc endif +ifeq ($(LOSCFG_DRIVERS_HDF_PLATFORM_SPI), y) + LITEOS_BASELIB += -lhdf_spi + LIB_SUBDIRS += $(ST_DRIVERS_ROOT)/spi +endif ifeq ($(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO), y) LITEOS_BASELIB += -lhdf_gpio diff --git a/common/platform/spi/BUILD.gn b/common/platform/spi/BUILD.gn new file mode 100644 index 0000000..7a8ac8a --- /dev/null +++ b/common/platform/spi/BUILD.gn @@ -0,0 +1,42 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import("//drivers/adapter/khdf/liteos/hdf.gni") + +module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_SPI) +module_name = "hdf_SPI" +hdf_driver(module_name) { + sources = [ + "stm32mp1_spi.c", + ] + include_dirs = [ + "." , + "//device/st/drivers/stm32mp1xx_hal/STM32MP1xx_HAL_Driver/Inc", + + ] +} diff --git a/common/platform/spi/Makefile b/common/platform/spi/Makefile new file mode 100755 index 0000000..634f727 --- /dev/null +++ b/common/platform/spi/Makefile @@ -0,0 +1,43 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(LITEOSTOPDIR)/config.mk +include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk + +MODULE_NAME := hdf_spi + +LOCAL_CFLAGS += $(HDF_INCLUDE) + +LOCAL_SRCS += stm32mp1_spi.c + +LOCAL_INCLUDE += -I ../stm32mp1xx_hal/STM32MP1xx_HAL_Driver/Inc + +LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror -fsigned-char -fno-strict-aliasing -fno-common + +include $(HDF_DRIVER) + diff --git a/common/platform/spi/stm32mp1_spi.c b/common/platform/spi/stm32mp1_spi.c new file mode 100644 index 0000000..3782134 --- /dev/null +++ b/common/platform/spi/stm32mp1_spi.c @@ -0,0 +1,945 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "stm32mp1_spi.h" +#include "device_resource_if.h" +#include "hdf_device_desc.h" +#include "hdf_log.h" +#include "osal_io.h" +#include "osal_mem.h" +#include "osal_irq.h" +#include "osal_time.h" +#include "stm32mp1xx.h" +#include "stm32mp1xx_hal_conf.h" +#include "spi_dev.h" + +#define HDF_LOG_TAG stm32mp1_spi + +static void Mp1xxSpiSetPinMux(struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t value; + uint32_t i; + volatile unsigned char *gpioZBase = NULL; + volatile unsigned char *gpioBase = NULL; + volatile unsigned char *tempBase = NULL; + + gpioZBase = OsalIoRemap(MP1XX_AHB5_GPIOZ_BASE, MP1XX_GPIO_REG_SIZE); + if (gpioZBase == NULL) { + HDF_LOGE("%s: remap regbase failed", __func__); + return; + } + gpioBase = OsalIoRemap(MP1XX_AHB4_GPIO_BASE, MP1XX_GPIO_GROUP_STEP * MP1XX_GPIO_GROUP_NUM); + if (gpioBase == NULL) { + HDF_LOGE("%s: remap regbase failed", __func__); + return; + } + + for (i = 0; i < MP1XX_SPI_PIN_NUM * MP1XX_MEMBER_PER_PIN; i += MP1XX_MEMBER_PER_PIN) { + if (stm32mp1->pins[i + PIN_GROUP] == MP1XX_GPIOZ) { + tempBase = gpioZBase; + } else if (stm32mp1->pins[i + PIN_GROUP] < MP1XX_GPIO_GROUP_NUM){ + tempBase = gpioBase + MP1XX_GPIO_GROUP_STEP * stm32mp1->pins[i + PIN_GROUP]; + } + value = OSAL_READL(tempBase); + value &= ~(MP1XX_MODER_MASK << (MP1XX_GPIO_MODE_BITS * stm32mp1->pins[i + PIN_NUM])); + value |= MP1XX_PIN_AF_MODE << (MP1XX_GPIO_MODE_BITS * stm32mp1->pins[i + PIN_NUM]); + OSAL_WRITEL(value, tempBase); + if (stm32mp1->pins[i + PIN_NUM] < MP1XX_PIN_NUM_PER_AF_REG) { + value = OSAL_READL(tempBase + MP1XX_GPIO_AF_LOW_REG); + + value &= ~(MP1XX_GPIO_AF_MASK << (MP1XX_GPIO_AF_BITS * stm32mp1->pins[i + PIN_NUM])); + value |= stm32mp1->pins[i + PIN_AF] << (MP1XX_GPIO_AF_BITS * stm32mp1->pins[i + PIN_NUM]); + OSAL_WRITEL(value, tempBase + MP1XX_GPIO_AF_LOW_REG); + } else { + value = OSAL_READL(tempBase + MP1XX_GPIO_AF_HIGH_REG); + value &= ~(MP1XX_GPIO_AF_MASK << + (MP1XX_GPIO_AF_BITS * stm32mp1->pins[i + PIN_NUM - MP1XX_PIN_NUM_PER_AF_REG])); + value |= stm32mp1->pins[i + PIN_AF] << + (MP1XX_GPIO_AF_BITS * stm32mp1->pins[i + PIN_NUM - MP1XX_PIN_NUM_PER_AF_REG]); + OSAL_WRITEL(value, tempBase + MP1XX_GPIO_AF_HIGH_REG); + } + } + OsalIoUnmap((void *)gpioZBase); + OsalIoUnmap((void *)gpioBase); +} + +static int32_t Mp1xxSpiCfgCs(struct Mp1xxSpiCntlr *stm32mp1, uint32_t cs) +{ + uint32_t value; + + if ((cs + 1) > stm32mp1->numCs) { + HDF_LOGE("%s: cs %d is big than stm32mp1 csNum %d", __func__, cs, stm32mp1->numCs); + return HDF_FAILURE; + } + if (stm32mp1->numCs == 1) { + return HDF_SUCCESS; + } + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); + value &= ~MP1XX_SPI_CS; + value |= (!!cs ? (cs << MP1XX_SPI_CS_SHIFT) : 0); + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); + + return HDF_SUCCESS; +} + +/* open spi clk */ +static void Mp1xxSpiHwInitCfg(struct Mp1xxSpiCntlr *stm32mp1) +{ + switch (stm32mp1->busNum) { + case 1: + __HAL_RCC_SPI1_CLK_ENABLE(); + break; + case 2: + __HAL_RCC_SPI2_CLK_ENABLE(); + break; + case 3: + __HAL_RCC_SPI3_CLK_ENABLE(); + break; + case 4: + __HAL_RCC_SPI4_CLK_ENABLE(); + break; + case 5: + __HAL_RCC_SPI5_CLK_ENABLE(); + break; + case 6: + __HAL_RCC_SPI6_CLK_ENABLE(); + break; + default: + break; + } +} + +/* close spi clk */ +static void Mp1xxSpiHwExitCfg(struct Mp1xxSpiCntlr *stm32mp1) +{ + switch (stm32mp1->busNum) { + case 1: + __HAL_RCC_SPI1_CLK_DISABLE(); + break; + case 2: + __HAL_RCC_SPI2_CLK_DISABLE(); + break; + case 3: + __HAL_RCC_SPI3_CLK_DISABLE(); + break; + case 4: + __HAL_RCC_SPI4_CLK_DISABLE(); + break; + case 5: + __HAL_RCC_SPI5_CLK_DISABLE(); + break; + case 6: + __HAL_RCC_SPI6_CLK_DISABLE(); + break; + default: + break; + } +} + +static void Mp1xxSpiEnable(const struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t value; + + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET); + if ((value & MP1XX_SPI_MODF_MASK) != 0) { + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); + value |= MP1XX_SPI_SSI; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); + value = MP1XX_SPI_MODF_MASK; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_IFCR_OFFSET); + } + + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); + value |= 0x1U; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); +} + +static void Mp1xxSpiDisable(const struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t value; + + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); + value &= ~0x1U; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); +} + +static void Mp1xxSpiConfigClk(const struct Mp1xxSpiCntlr *stm32mp1, uint32_t clkDiv) +{ + uint32_t value; + uint32_t mbr; + + clkDiv = clkDiv / MP1XX_SPI_MIN_CLK_DIV; + for (mbr = 0; mbr <= MP1XX_SPI_MBR_MAX; mbr++) { + if (clkDiv >> mbr == 0) { + mbr++; + HDF_LOGE("%s:mbr=%u", __func__, mbr); + break; + } + } + + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI_CFG1_OFFSET); + value &= ~MP1XX_SPI_MBR_MASK; + //value |= mbr << MP1XX_SPI_MBR_SHIFT; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI_CFG1_OFFSET); +} + +static void Mp1xxSpiConfigCfg1(const struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t value; + uint32_t temp; + + temp = (stm32mp1->fifoSize > SPI_MAX_LEVEL) ? SPI_MAX_LEVEL : stm32mp1->fifoSize; + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI_CFG1_OFFSET); + value &= ~MP1XX_SPI_FTHLV_MASK; + value |= temp; + + value &= ~MP1XX_SPI_DSIZE_MASK; + value |= stm32mp1->bitsPerWord - 1; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI_CFG1_OFFSET); +} + +static void Mp1xxSpiConfigCfg2(const struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t tmp; + uint32_t value; + + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI_CFG2_OFFSET); + value |= MP1XX_SPI_SSM; + + tmp = (!!(stm32mp1->mode & SPI_CLK_PHASE)) ? (1 << MP1XX_SPI_CPHA_SHIFT) : 0; + value |= tmp; + + tmp = (!!(stm32mp1->mode & SPI_CLK_POLARITY)) ? (1 << MP1XX_SPI_CPOL_SHIFT) : 0; + value |= tmp; + + tmp = (!!(stm32mp1->mode & SPI_MODE_3WIRE)) ? (MP1XX_SPI_HALF_DUPLEX_MODE << MP1XX_SPI_COMM_SHIFT) : 0; + value |= tmp; + + tmp = (!!(stm32mp1->mode & SPI_MODE_LSBFE)) ? (1 << MP1XX_SPI_LSBFRST_SHIFT) : 0; + value |= tmp; + + value |= MP1XX_SPI_MASTER; + value |= MP1XX_SPI_SSOE_MASK; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI_CFG2_OFFSET); +} + +static void Mp1xxSpiConfigFifo(const struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t value; + + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_HWCFGR_OFFSET); + /* Tx FIFO size 32 byte */ + value &= ~MP1XX_SPI_FIFO_MASK; + value |= MP1XX_SPI2S_FIFO_SIZE; + /* Rx FIFO size 32 byte */ + value &= ~(MP1XX_SPI_FIFO_MASK << MP1XX_SPI_RXFCFG_SHIFT); + value |= MP1XX_SPI2S_FIFO_SIZE << MP1XX_SPI_RXFCFG_SHIFT; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_HWCFGR_OFFSET); +} + +#define RX_INT_FIFO_LEVEL (256 - 128) +#define RX_INT_WAIT_TIMEOUT 1000 // ms + +static void Mp1xxSpiConfigIrq(struct Mp1xxSpiCntlr *stm32mp1) +{ + OSAL_WRITEL(SPI_ALL_IRQ_CLEAR, stm32mp1->regBase + MP1XX_SPI2S_IFCR_OFFSET); + if (stm32mp1->transferMode == SPI_POLLING_TRANSFER) { + OSAL_WRITEL(SPI_ALL_IRQ_DISABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET); + } else { + OSAL_WRITEL(SPI_ALL_IRQ_ENABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET); + } +} + +static int32_t Mp1xxSpiConfig(struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t tmp; + uint32_t clkDiv; + + /* Check if we can provide the requested rate */ + if (stm32mp1->speed > stm32mp1->maxSpeedHz) { + HDF_LOGW("%s: invalid speed:%d, use max:%d instead", __func__, stm32mp1->speed, stm32mp1->maxSpeedHz); + stm32mp1->speed = stm32mp1->maxSpeedHz; + } + /* Min possible */ + if (stm32mp1->speed == 0 || stm32mp1->speed < stm32mp1->minSpeedHz) { + HDF_LOGW("%s: invalid speed:%d, use min:%d instead", __func__, stm32mp1->speed, stm32mp1->minSpeedHz); + stm32mp1->speed = stm32mp1->minSpeedHz; + } + + /* Check if we can provide the requested bits_per_word */ + if ((stm32mp1->bitsPerWord < BITS_PER_WORD_MIN) || (stm32mp1->bitsPerWord > BITS_PER_WORD_MAX)) { + HDF_LOGE("%s: stm32mp1->bitsPerWord is %d not support", __func__, stm32mp1->bitsPerWord); + return HDF_FAILURE; + } + + tmp = (stm32mp1->clkRate) / (stm32mp1->speed); + if (tmp < MP1XX_SPI_MIN_CLK_DIV) { + clkDiv = MP1XX_SPI_MIN_CLK_DIV; + } else if (tmp > MP1XX_SPI_MAX_CLK_DIV) { + clkDiv = MP1XX_SPI_MAX_CLK_DIV; + } else { + /* Calculate the closest division factor */ + for (clkDiv = MP1XX_SPI_MIN_CLK_DIV; clkDiv < MP1XX_SPI_MAX_CLK_DIV; clkDiv = clkDiv << 1) { + if (clkDiv < tmp && (clkDiv << 1) > tmp) { + clkDiv = (((clkDiv << 1) - tmp) > (tmp - clkDiv)) ? clkDiv : (clkDiv << 1); + break; + } + } + HDF_LOGE("%s:clkDiv=%u", __func__, clkDiv); + } + + Mp1xxSpiDisable(stm32mp1); + /* config SPICLK */ + Mp1xxSpiConfigClk(stm32mp1, clkDiv); + /* config SPICFG1 register */ + Mp1xxSpiConfigCfg1(stm32mp1); + /* config SPICFG2 register */ + Mp1xxSpiConfigCfg2(stm32mp1); + /* config irq */ + Mp1xxSpiConfigIrq(stm32mp1); + Mp1xxSpiEnable(stm32mp1); + + return HDF_SUCCESS; +} + +static int32_t Mp1xxSpiCheckTimeout(const struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t tmp = 0; + unsigned long value; + + while (1) { + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET); + if ((value & MP1XX_SPI_SR_RXP_MASK) != 0) { + break; + } + if (tmp++ > MAX_WAIT) { + HDF_LOGE("%s: spi transfer wait timeout", __func__); + return HDF_ERR_TIMEOUT; + } + OsalUDelay(1); + } + OSAL_WRITEL(SPI_ALL_IRQ_CLEAR, stm32mp1->regBase + MP1XX_SPI2S_IFCR_OFFSET); + + return HDF_SUCCESS; +} + +static int32_t Mp1xxSpiFlushFifo(const struct Mp1xxSpiCntlr *stm32mp1) +{ + Mp1xxSpiDisable(stm32mp1); + OsalMDelay(1); + Mp1xxSpiEnable(stm32mp1); + + return HDF_SUCCESS; +} + +#define MP1XX_ONE_BYTE 1 +#define MP1XX_TWO_BYTE 2 + +static inline uint8_t Mp1xxSpiToByteWidth(uint8_t bitsPerWord) +{ + if (bitsPerWord <= BITS_PER_WORD_EIGHT) { + return MP1XX_ONE_BYTE; + } else { + return MP1XX_TWO_BYTE; + } +} + +static void Mp1xxSpiWriteFifo(const struct Mp1xxSpiCntlr *stm32mp1, const uint8_t *tx, uint32_t count) +{ + unsigned long value; + uint32_t delay = 0; + uint8_t bytes = Mp1xxSpiToByteWidth(stm32mp1->bitsPerWord); + + for (value = 0; count >= bytes; count -= bytes) { + while (1) { + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET); + if ((value & MP1XX_SPI_SR_TXP_MASK) != 0) { + break; + } + OsalUDelay(1); + delay++; + if (delay >= MAX_WAIT) { + HDF_LOGE("%s: write fifo time out", __func__); + break; + } + } + if (tx != NULL) { + value = (bytes == MP1XX_ONE_BYTE) ? *tx : *((uint16_t *)tx); + tx += bytes; + } + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_TXDR_OFFSET); + } +} + +static void Mp1xxSpiReadFifo(const struct Mp1xxSpiCntlr *stm32mp1, uint8_t *rx, uint32_t count) +{ + unsigned long value; + uint32_t delay = 0; + uint8_t bytes = Mp1xxSpiToByteWidth(stm32mp1->bitsPerWord); + + while (1) { + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET); + if ((value & MP1XX_SPI_SR_RXP_MASK) != 0) { + break; + } + OsalUDelay(1); + delay++; + if (delay >= MAX_WAIT) { + HDF_LOGE("%s: read fifo time out", __func__); + break; + } + } + + for (value = 0; count >= bytes; count -= bytes) { + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_RXDR_OFFSET); + if (rx == NULL) { + continue; + } + if (bytes == MP1XX_ONE_BYTE) { + *rx = (uint8_t)value; + } else { + *((uint16_t *)rx) = (uint16_t)value; + } + rx += bytes; + } +} + +static void Mp1xxSpiStartTransfer(const struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t value; + + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); + value |= MP1XX_SPI_CSTART_MASK; + OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET); +} + +static int32_t Mp1xxSpiTxRx(const struct Mp1xxSpiCntlr *stm32mp1, const struct SpiMsg *msg) +{ + int32_t ret; + uint32_t tmpLen; + uint32_t len = msg->len; + const uint8_t *tx = msg->wbuf; + uint8_t *rx = msg->rbuf; + uint8_t bytes = Mp1xxSpiToByteWidth(stm32mp1->bitsPerWord); + uint32_t burstSize = stm32mp1->fifoSize * bytes; + + if (tx == NULL && rx == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + if (stm32mp1->transferMode != SPI_POLLING_TRANSFER && RX_INT_FIFO_LEVEL < stm32mp1->fifoSize) { + burstSize = RX_INT_FIFO_LEVEL * bytes; + } + + for (tmpLen = 0, len = msg->len; len > 0; len -= tmpLen) { + tmpLen = (len > burstSize) ? burstSize : len; + if (stm32mp1->transferMode != SPI_POLLING_TRANSFER && tmpLen == burstSize) { + OSAL_WRITEL(SPI_ALL_IRQ_ENABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET); + } + Mp1xxSpiWriteFifo(stm32mp1, tx, tmpLen); + Mp1xxSpiStartTransfer(stm32mp1); + tx = (tx == NULL) ? NULL : (tx + tmpLen); + if (stm32mp1->transferMode != SPI_POLLING_TRANSFER && tmpLen == burstSize) { + ret = OsalSemWait((struct OsalSem *)(&stm32mp1->sem), RX_INT_WAIT_TIMEOUT); + } else { + ret = Mp1xxSpiCheckTimeout(stm32mp1); + } + + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: %s timeout", __func__, (stm32mp1->transferMode != SPI_POLLING_TRANSFER) ? + "wait rx fifo int" : "wait tx fifo idle"); + + return ret; + } + Mp1xxSpiReadFifo(stm32mp1, rx, tmpLen); + rx = (rx == NULL) ? NULL : (rx + tmpLen); + } + return HDF_SUCCESS; +} + +static int32_t Mp1xxSpiSetCs(struct Mp1xxSpiCntlr *stm32mp1, uint32_t cs, uint32_t flag) +{ + if (Mp1xxSpiCfgCs(stm32mp1, cs)) { + return HDF_FAILURE; + } + if (flag == SPI_CS_ACTIVE) { + Mp1xxSpiEnable(stm32mp1); + } else { + Mp1xxSpiDisable(stm32mp1); + } + return HDF_SUCCESS; +} + +static struct SpiDev *Mp1xxSpiFindDeviceByCsNum(const struct Mp1xxSpiCntlr *stm32mp1, uint32_t cs) +{ + struct SpiDev *dev = NULL; + struct SpiDev *tmpDev = NULL; + + if (stm32mp1 == NULL || stm32mp1->numCs <= cs) { + return NULL; + } + DLIST_FOR_EACH_ENTRY_SAFE(dev, tmpDev, &(stm32mp1->deviceList), struct SpiDev, list) { + if (dev->csNum == cs) { + break; + } + } + return dev; +} + +static int32_t Mp1xxSpiSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg) +{ + struct Mp1xxSpiCntlr *stm32mp1 = NULL; + struct SpiDev *dev = NULL; + int32_t ret; + + if (cntlr == NULL) { + HDF_LOGE("%s: cntlr is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (cntlr->priv == NULL) { + HDF_LOGE("%s: priv is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (cfg == NULL) { + HDF_LOGE("%s: cfg is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + stm32mp1 = (struct Mp1xxSpiCntlr *)cntlr->priv; + dev = Mp1xxSpiFindDeviceByCsNum(stm32mp1, cntlr->curCs); + if (dev == NULL) { + return HDF_FAILURE; + } + dev->cfg.mode = cfg->mode; + dev->cfg.transferMode = cfg->transferMode; + if (cfg->bitsPerWord < BITS_PER_WORD_MIN || cfg->bitsPerWord > BITS_PER_WORD_MAX) { + HDF_LOGE("%s: bitsPerWord %d not support, use defaule bitsPerWord %d", + __func__, cfg->bitsPerWord, BITS_PER_WORD_EIGHT); + dev->cfg.bitsPerWord = BITS_PER_WORD_EIGHT; + } else { + dev->cfg.bitsPerWord = cfg->bitsPerWord; + } + if (cfg->maxSpeedHz != 0) { + dev->cfg.maxSpeedHz = cfg->maxSpeedHz; + } + ret = Mp1xxSpiConfig(stm32mp1); + if (ret != HDF_SUCCESS) { + return ret; + } + return HDF_SUCCESS; +} + +static int32_t Mp1xxSpiGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg) +{ + struct Mp1xxSpiCntlr *stm32mp1 = NULL; + struct SpiDev *dev = NULL; + + if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) { + HDF_LOGE("%s: cntlr priv or cfg is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + stm32mp1 = (struct Mp1xxSpiCntlr *)cntlr->priv; + dev = Mp1xxSpiFindDeviceByCsNum(stm32mp1, cntlr->curCs); + if (dev == NULL) { + return HDF_FAILURE; + } + *cfg = dev->cfg; + return HDF_SUCCESS; +} + +static int32_t Mp1xxSpiTransferOneMessage(struct Mp1xxSpiCntlr *stm32mp1, struct SpiMsg *msg) +{ + int32_t ret; + + ret = Mp1xxSpiSetCs(stm32mp1, stm32mp1->curCs, SPI_CS_ACTIVE); + if (ret != HDF_SUCCESS) { + return ret; + } + ret = Mp1xxSpiFlushFifo(stm32mp1); + if (ret != HDF_SUCCESS) { + return ret; + } + + stm32mp1->speed = (msg->speed) == 0 ? DEFAULT_SPEED : msg->speed; + ret = Mp1xxSpiConfig(stm32mp1); + if (ret != HDF_SUCCESS) { + return ret; + } + + ret = Mp1xxSpiTxRx(stm32mp1, msg); + if (ret || msg->csChange) { + Mp1xxSpiSetCs(stm32mp1, stm32mp1->curCs, SPI_CS_INACTIVE); + } + return ret; +} + +static int32_t Mp1xxSpiTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count) +{ + int32_t ret; + uint32_t i; + struct Mp1xxSpiCntlr *stm32mp1 = NULL; + struct SpiDev *dev = NULL; + + if (cntlr == NULL || cntlr->priv == NULL) { + HDF_LOGE("%s: invalid controller", __func__); + return HDF_ERR_INVALID_OBJECT; + } + if (msg == NULL || (msg->rbuf == NULL && msg->wbuf == NULL) || count == 0) { + HDF_LOGE("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + + stm32mp1 = (struct Mp1xxSpiCntlr *)cntlr->priv; + dev = Mp1xxSpiFindDeviceByCsNum(stm32mp1, cntlr->curCs); + if (dev == NULL) { + return HDF_FAILURE; + } + Mp1xxSpiDisable(stm32mp1); + stm32mp1->mode = dev->cfg.mode; + stm32mp1->transferMode = dev->cfg.transferMode; + stm32mp1->bitsPerWord = dev->cfg.bitsPerWord; + stm32mp1->maxSpeedHz = dev->cfg.maxSpeedHz; + stm32mp1->curCs = dev->csNum; + for (i = 0; i < count; i++) { + ret = Mp1xxSpiTransferOneMessage(stm32mp1, &(msg[i])); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: transfer error", __func__); + return ret; + } + } + + return HDF_SUCCESS; +} + +int32_t Mp1xxSpiOpen(struct SpiCntlr *cntlr) +{ + (void)cntlr; + return HDF_SUCCESS; +} + +int32_t Mp1xxSpiClose(struct SpiCntlr *cntlr) +{ + (void)cntlr; + return HDF_SUCCESS; +} + +static int32_t Mp1xxSpiProbe(struct Mp1xxSpiCntlr *stm32mp1) +{ + int32_t ret; + + Mp1xxSpiSetPinMux(stm32mp1); + Mp1xxSpiHwInitCfg(stm32mp1); + Mp1xxSpiConfigFifo(stm32mp1); + + ret = Mp1xxSpiConfig(stm32mp1); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: Mp1xxSpiConfig error", __func__); + return ret; + } + + return HDF_SUCCESS; +} + +struct SpiCntlrMethod g_method = { + .Transfer = Mp1xxSpiTransfer, + .SetCfg = Mp1xxSpiSetCfg, + .GetCfg = Mp1xxSpiGetCfg, + .Open = Mp1xxSpiOpen, + .Close = Mp1xxSpiClose, +}; + +static int32_t Mp1xxSpiCreatAndInitDevice(struct Mp1xxSpiCntlr *stm32mp1) +{ + uint32_t i; + struct SpiDev *device = NULL; + + for (i = 0; i < stm32mp1->numCs; i++) { + device = (struct SpiDev *)OsalMemCalloc(sizeof(*device)); + if (device == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return HDF_FAILURE; + } + device->cntlr = stm32mp1->cntlr; + device->csNum = i; + device->cfg.bitsPerWord = stm32mp1->bitsPerWord; + device->cfg.transferMode = stm32mp1->transferMode; + device->cfg.maxSpeedHz = stm32mp1->maxSpeedHz; + device->cfg.mode = stm32mp1->mode; + DListHeadInit(&device->list); + DListInsertTail(&device->list, &stm32mp1->deviceList); + SpiAddDev(device); + } + return HDF_SUCCESS; +} + +static void Mp1xxSpiRelease(struct Mp1xxSpiCntlr *stm32mp1) +{ + struct SpiDev *dev = NULL; + struct SpiDev *tmpDev = NULL; + + DLIST_FOR_EACH_ENTRY_SAFE(dev, tmpDev, &(stm32mp1->deviceList), struct SpiDev, list) { + SpiRemoveDev(dev); + DListRemove(&(dev->list)); + OsalMemFree(dev); + } + if (stm32mp1->irqNum != 0) { + (void)OsalUnregisterIrq(stm32mp1->irqNum, stm32mp1); + } + OsalMemFree(stm32mp1); +} + +static int32_t SpiGetBaseCfgFromHcs(struct Mp1xxSpiCntlr *stm32mp1, const struct DeviceResourceNode *node) +{ + struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + + if (iface == NULL || iface->GetUint8 == NULL || iface->GetUint16 == NULL || iface->GetUint32 == NULL) { + HDF_LOGE("%s: iface is invalid", __func__); + return HDF_FAILURE; + } + if (iface->GetUint32(node, "busNum", &stm32mp1->busNum, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read busNum fail", __func__); + return HDF_FAILURE; + } + if (iface->GetUint32(node, "spi_numCs", &stm32mp1->numCs, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read numCs fail", __func__); + return HDF_FAILURE; + } + if (iface->GetUint32(node, "spi_speed", &stm32mp1->speed, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read speed fail", __func__); + return HDF_FAILURE; + } + if (iface->GetUint32(node, "fifoSize", &stm32mp1->fifoSize, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read fifoSize fail", __func__); + return HDF_FAILURE; + } + if (iface->GetUint32(node, "spi_clkRate", &stm32mp1->clkRate, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read clkRate fail", __func__); + return HDF_FAILURE; + } + if (iface->GetUint16(node, "spi_mode", &stm32mp1->mode, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read mode fail", __func__); + return HDF_FAILURE; + } + if (iface->GetUint8(node, "spi_bitsPerWord", &stm32mp1->bitsPerWord, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read bitsPerWord fail", __func__); + return HDF_FAILURE; + } + if (iface->GetUint8(node, "spi_transferMode", &stm32mp1->transferMode, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read comMode fail", __func__); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +static int32_t SpiGetRegCfgFromHcs(struct Mp1xxSpiCntlr *stm32mp1, const struct DeviceResourceNode *node) +{ + uint32_t regBasePhy; + uint32_t regSize; + int32_t ret; + struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + + if (iface == NULL || iface->GetUint32 == NULL) { + HDF_LOGE("%s: face is invalid", __func__); + return HDF_FAILURE; + } + if (iface->GetUint32(node, "busModeSel", &stm32mp1->busModeSel, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read busModeSel fail", __func__); + return HDF_FAILURE; + } + + if (stm32mp1->busModeSel != SPI2S_SPI_MODE) { + HDF_LOGI("%s: SPI%u is disabled", __func__, stm32mp1->busNum); + return HDF_ERR_NOT_SUPPORT; + } + + if (iface->GetUint32(node, "regPBase", ®BasePhy, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read regBase fail", __func__); + return HDF_FAILURE; + } + if (iface->GetUint32(node, "regSize", ®Size, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read regSize fail", __func__); + return HDF_FAILURE; + } + stm32mp1->regBase = OsalIoRemap(regBasePhy, regSize); + if (stm32mp1->regBase == NULL) { + HDF_LOGE("%s: remap regbase failed", __func__); + return HDF_FAILURE; + } + + if (iface->GetUint32(node, "irqNum", &stm32mp1->irqNum, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read irqNum fail", __func__); + return HDF_FAILURE; + } + + ret = iface->GetUint8Array(node, "pins", stm32mp1->pins, MP1XX_SPI_PIN_NUM * MP1XX_MEMBER_PER_PIN, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: read pins failed", __func__); + return ret; + } + + return HDF_SUCCESS; +} + +static uint32_t Mp1xxSpiIrqHandleNoShare(uint32_t irq, void *data) +{ + unsigned long value; + struct Mp1xxSpiCntlr *stm32mp1 = (struct Mp1xxSpiCntlr *)data; + + (void)irq; + if (stm32mp1 == NULL) { + HDF_LOGE("%s: data is NULL!", __func__); + return HDF_ERR_INVALID_PARAM; + } + + value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET); + if ((value & MP1XX_SPI_MODF_MASK) != 0) { + HDF_LOGE("%s: mode fault detected", __func__); + return HDF_FAILURE; + } + + OSAL_WRITEL(SPI_ALL_IRQ_CLEAR, stm32mp1->regBase + MP1XX_SPI2S_IFCR_OFFSET); + OSAL_WRITEL(SPI_ALL_IRQ_DISABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET); + (void)OsalSemPost(&stm32mp1->sem); + return HDF_SUCCESS; +} + +static int32_t Mp1xxSpiInit(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device) +{ + int32_t ret; + struct Mp1xxSpiCntlr *stm32mp1 = NULL; + + if (device->property == NULL) { + HDF_LOGE("%s: property is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + + stm32mp1 = (struct Mp1xxSpiCntlr *)OsalMemCalloc(sizeof(*stm32mp1)); + if (stm32mp1 == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return HDF_FAILURE; + } + + + ret = SpiGetRegCfgFromHcs(stm32mp1, device->property); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: SpiGetRegCfgFromHcs error", __func__); + OsalMemFree(stm32mp1); + return HDF_FAILURE; + } + ret = SpiGetBaseCfgFromHcs(stm32mp1, device->property); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: SpiGetBaseCfgFromHcs error", __func__); + OsalMemFree(stm32mp1); + return HDF_FAILURE; + } + stm32mp1->maxSpeedHz = MP1XX_SPI_MAX_SPEED; + stm32mp1->minSpeedHz = stm32mp1->clkRate / MP1XX_SPI_MAX_CLK_DIV; + DListHeadInit(&stm32mp1->deviceList); + stm32mp1->cntlr = cntlr; + cntlr->priv = stm32mp1; + cntlr->busNum = stm32mp1->busNum; + cntlr->method = &g_method; + ret = OsalSemInit(&stm32mp1->sem, 0); + if (ret != HDF_SUCCESS) { + OsalMemFree(stm32mp1); + HDF_LOGE("%s: sem init fail", __func__); + return ret; + } + + if (stm32mp1->irqNum != 0) { + OSAL_WRITEL(SPI_ALL_IRQ_DISABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET); + ret = OsalRegisterIrq(stm32mp1->irqNum, 0, Mp1xxSpiIrqHandleNoShare, "SPI_MP1XX", stm32mp1); + if (ret != HDF_SUCCESS) { + OsalMemFree(stm32mp1); + HDF_LOGE("%s: regisiter irq %u fail", __func__, stm32mp1->irqNum); + (void)OsalSemDestroy(&stm32mp1->sem); + return ret; + } + } + + ret = Mp1xxSpiCreatAndInitDevice(stm32mp1); + if (ret != HDF_SUCCESS) { + Mp1xxSpiRelease(stm32mp1); + return ret; + } + return HDF_SUCCESS; +} + +static inline void Mp1xxSpiRemove(struct Mp1xxSpiCntlr *stm32mp1) +{ + Mp1xxSpiHwExitCfg(stm32mp1); + OsalIoUnmap((void *)stm32mp1->regBase); + Mp1xxSpiRelease(stm32mp1); +} + +static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device) +{ + HDF_LOGI("%s: entry", __func__); + if (device == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS; +} + +static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device) +{ + int32_t ret; + struct SpiCntlr *cntlr = NULL; + + HDF_LOGI("%s: entry", __func__); + if (device == NULL) { + HDF_LOGE("%s: ptr is null", __func__); + return HDF_ERR_INVALID_OBJECT; + } + cntlr = SpiCntlrFromDevice(device); + if (cntlr == NULL) { + HDF_LOGE("%s: cntlr is null", __func__); + return HDF_FAILURE; + } + + ret = Mp1xxSpiInit(cntlr, device); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: error init", __func__); + return HDF_FAILURE; + } + + ret = Mp1xxSpiProbe(cntlr->priv); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: error probe", __func__); + } + return ret; +} + +static void HdfSpiDeviceRelease(struct HdfDeviceObject *device) +{ + struct SpiCntlr *cntlr = NULL; + + HDF_LOGI("%s: entry", __func__); + if (device == NULL) { + HDF_LOGE("%s: device is null", __func__); + return; + } + cntlr = SpiCntlrFromDevice(device); + if (cntlr == NULL) { + HDF_LOGE("%s: cntlr is null", __func__); + return; + } + if (cntlr->priv != NULL) { + Mp1xxSpiRemove((struct Mp1xxSpiCntlr *)cntlr->priv); + } + SpiCntlrDestroy(cntlr); +} + +struct HdfDriverEntry g_hdfSpiDevice = { + .moduleVersion = 1, + .moduleName = "stm32mp1_spi_driver", + .Bind = HdfSpiDeviceBind, + .Init = HdfSpiDeviceInit, + .Release = HdfSpiDeviceRelease, +}; + +HDF_INIT(g_hdfSpiDevice); diff --git a/common/platform/spi/stm32mp1_spi.h b/common/platform/spi/stm32mp1_spi.h new file mode 100644 index 0000000..eaa6d47 --- /dev/null +++ b/common/platform/spi/stm32mp1_spi.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef __STM32MP1_SPI_H__ +#define __STM32MP1_SPI_H__ + +#include "osal_sem.h" +#include "spi_core.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define MP1XX_SPI2S_CR1_OFFSET 0x00 +#define MP1XX_SPI_CR2_OFFSET 0x04 +#define MP1XX_SPI_CFG1_OFFSET 0x08 +#define MP1XX_SPI_CFG2_OFFSET 0x0C +#define MP1XX_SPI2S_IER_OFFSET 0x10 +#define MP1XX_SPI2S_SR_OFFSET 0x14 +#define MP1XX_SPI2S_IFCR_OFFSET 0x18 +#define MP1XX_SPI2S_TXDR_OFFSET 0x20 +#define MP1XX_SPI2S_RXDR_OFFSET 0x30 +#define MP1XX_SPI_CRCPOLY_OFFSET 0x40 +#define MP1XX_SPI_TXCRC_OFFSET 0x44 +#define MP1XX_SPI_RXCRC_OFFSET 0x48 +#define MP1XX_SPI_UDRDR_OFFSET 0x4C +#define MP1XX_SPI2S_CFGR_OFFSET 0x50 +#define MP1XX_SPI2S_HWCFGR_OFFSET 0x3F0 +#define MP1XX_SPI2S_VERR_OFFSET 0x3F4 +#define MP1XX_SPI2S_IPIDR_OFFSET 0x3F8 +#define MP1XX_SPI2S_SIDR_OFFSET 0x3FC + +#define MP1XX_SPI_CS_SHIFT 12 +#define MP1XX_SPI_CS (0x1U << MP1XX_SPI_CS_SHIFT) +#define MP1XX_SPI_SSI_SITFT 12 +#define MP1XX_SPI_SSI (0x1U << MP1XX_SPI_SSI_SITFT) +#define MP1XX_SPI_MBR_SHIFT 28 +#define MP1XX_SPI_MBR_MAX 0x7U +#define MP1XX_SPI_MBR_MASK (MP1XX_SPI_MBR_MAX << MP1XX_SPI_MBR_SHIFT) +#define MP1XX_SPI_SSM_SHIFT 26 +#define MP1XX_SPI_SSM (0x1U << MP1XX_SPI_SSM_SHIFT) +#define MP1XX_SPI_CPOL_SHIFT 25 +#define MP1XX_SPI_CPOL (0x1U << MP1XX_SPI_CPOL_SHIFT) +#define MP1XX_SPI_CPHA_SHIFT 24 +#define MP1XX_SPI_CPHA (0x1U << MP1XX_SPI_CPHA_SHIFT) +#define MP1XX_SPI_LSBFRST_SHIFT 23 +#define MP1XX_SPI_LSBFRST (0x1U << MP1XX_SPI_LSBFRST_SHIFT) +#define MP1XX_SPI_MASTER_SHIFT 22 +#define MP1XX_SPI_MASTER (0x1U << MP1XX_SPI_MASTER_SHIFT) +#define MP1XX_SPI_COMM_SHIFT 17 +#define MP1XX_SPI_COMM_MASK (0x3U << MP1XX_SPI_COMM_SHIFT) +#define MP1XX_SPI_HALF_DUPLEX_MODE 0x3U +#define MP1XX_SPI_FTHLV_SHIFT 5 +#define MP1XX_SPI_FTHLV_MASK (0xFU << MP1XX_SPI_FTHLV_SHIFT) +#define MP1XX_SPI_DSIZE_MASK 0x1FU +#define MP1XX_SPI_DSIZE_MASK 0x1FU +#define MP1XX_SPI_FIFO_MASK 0xFU +#define MP1XX_SPI_RXFCFG_SHIFT 4 +#define MP1XX_SPI_CSTART_MASK (0x1U << 9) +#define MP1XX_SPI_SR_TXP_MASK (0x1U << 1) +#define MP1XX_SPI_SR_RXP_MASK 0x1U +#define MP1XX_SPI_SR_TXTF_MASK 0x1U +#define MP1XX_SPI_MODF_MASK (0x1U << 9) +#define MP1XX_SPI_SSOE_MASK (0x1U << 29) + +#define MP1XX_SPI2S_FIFO_SIZE 0x5 // 32 bytes +#define MP1XX_SPI_MAX_SPEED 50000000 +#define MP1XX_SPI_MAX_CLK_DIV 128 +#define MP1XX_SPI_MIN_CLK_DIV 16 +#define BITS_PER_WORD_MIN 4 +#define BITS_PER_WORD_EIGHT 8 +#define BITS_PER_WORD_MAX 16 +#define MAX_WAIT 10000 +#define SPI_MAX_LEVEL 8 +#define DEFAULT_SPEED 2000000 +#define SPI_CS_ACTIVE 0 +#define SPI_CS_INACTIVE 1 + +#define MP1XX_AHB4_GPIO_BASE 0x50002000 +#define MP1XX_AHB5_GPIOZ_BASE 0x54004000 +#define MP1XX_GPIOZ 25 +#define MP1XX_GPIO_MODE_REG 0x0 +#define MP1XX_GPIO_AF_LOW_REG 0x20 +#define MP1XX_GPIO_AF_HIGH_REG 0x24 +#define MP1XX_GPIO_MODE_BITS 2 +#define MP1XX_MODER_MASK 0x3 +#define MP1XX_GPIO_AF_BITS 4 +#define MP1XX_GPIO_AF_MASK 0xF +#define MP1XX_GPIOZ 25 +#define MP1XX_GPIO_GROUP_STEP 0x1000 +#define MP1XX_GPIO_REG_SIZE 0x400 +#define MP1XX_GPIO_GROUP_NUM 11 +#define MP1XX_SPI_PIN_NUM 4 +#define MP1XX_MEMBER_PER_PIN 3 +#define MP1XX_PIN_AF_MODE 0x2 +#define MP1XX_PIN_NUM_PER_AF_REG 8 +#define SPI_ALL_IRQ_DISABLE 0x0 +#define SPI_ALL_IRQ_ENABLE 0x205 +#define SPI_RX_INTR_MASK 0x1 +#define SPI_ALL_IRQ_CLEAR 0xFF8 + +enum busModeSel { + SPI2S_DISABLED = 0, + SPI2S_SPI_MODE = 1, + SPI2S_I2S_MODE = 2, +}; + +enum pinArray { + PIN_GROUP = 0, + PIN_NUM = 1, + PIN_AF = 2, +}; + +struct Mp1xxSpiCntlr { + struct SpiCntlr *cntlr; + struct DListHead deviceList; + struct OsalSem sem; + volatile unsigned char *regBase; + uint32_t irqNum; + uint32_t busNum; + uint32_t numCs; + uint32_t curCs; + uint32_t speed; + uint32_t fifoSize; + uint32_t clkRate; + uint32_t maxSpeedHz; + uint32_t minSpeedHz; + uint32_t busModeSel; + uint8_t pins[MP1XX_SPI_PIN_NUM * MP1XX_MEMBER_PER_PIN]; + uint16_t mode; + uint8_t bitsPerWord; + uint8_t transferMode; +}; + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* __STM32MP1_ADC_H__ */ diff --git a/stm32mp157/sdk_liteos/hdf_config/device_info/device_info.hcs b/stm32mp157/sdk_liteos/hdf_config/device_info/device_info.hcs index caae79f..84c3c4e 100755 --- a/stm32mp157/sdk_liteos/hdf_config/device_info/device_info.hcs +++ b/stm32mp157/sdk_liteos/hdf_config/device_info/device_info.hcs @@ -58,6 +58,22 @@ deviceMatchAttr = "stm32mp1_uart_4"; } } + device_spi :: device { + device0 :: deviceNode { + policy = 2; + priority = 40; + permission = 0644; + moduleName = "stm32mp1_spi_driver"; + serviceName = "HDF_PLATFORM_SPI_1"; + deviceMatchAttr = "st_stm32mp157_spi_1"; + } + device1 :: deviceNode { + policy = 0; + priority = 50; + permission = 0644; + moduleName = "stm32mp157_spi_test"; + } + } device_mmc:: device { device0 :: deviceNode { diff --git a/stm32mp157/sdk_liteos/hdf_config/hdf.hcs b/stm32mp157/sdk_liteos/hdf_config/hdf.hcs index a97efa9..2b325dd 100755 --- a/stm32mp157/sdk_liteos/hdf_config/hdf.hcs +++ b/stm32mp157/sdk_liteos/hdf_config/hdf.hcs @@ -1,5 +1,6 @@ #include "device_info/device_info.hcs" #include "adc/adc_config.hcs" +#include "spi_i2s/spi_i2s_config.hcs" #include "gpio/gpio_config.hcs" #include "i2c/i2c_config.hcs" #include "uart/uart_config.hcs" diff --git a/stm32mp157/sdk_liteos/hdf_config/spi_i2s/spi_i2s_config.hcs b/stm32mp157/sdk_liteos/hdf_config/spi_i2s/spi_i2s_config.hcs new file mode 100644 index 0000000..5cc32bf --- /dev/null +++ b/stm32mp157/sdk_liteos/hdf_config/spi_i2s/spi_i2s_config.hcs @@ -0,0 +1,75 @@ +root { + platform { + spi_i2s_config { + template stm32mp1_spi_i2s_device { + match_attr = ""; + busModeSel = 1; // 0: Disabled; 1: SPI mode; 2: I2S mode. + regPBase = 0x44004000; + regSize = 0x400; + busNum = 0; + fifoSize = 4; // no more than 8. + spi_transferMode = 0; + spi_bitsPerWord = 8; + spi_mode = 19; + spi_clkRate = 200000000; + spi_speed = 10000000; + spi_numCs = 1; + /* + NSS SCK MISO MOSI + pins[port, pin, funcNum, ...] + 0:GPIOA 1:GPIOB 2:GPIOC ...... 10:GPIOK 25:GPIOZ + 0:PIN0 1:PIN1 2:PIN2 ...... + 0-15: AF0-AF15 + */ + pins = [0, 4, 5, 0, 5, 5, 0, 6, 5, 0, 7, 5]; + irqNum = 67; + } + controller_0x44004000 :: stm32mp1_spi_i2s_device { + match_attr = "st_stm32mp157_spi_1"; + busNum = 1; + pins = [0, 0, 15, 25, 0, 5, 25, 1, 5, 25, 2, 5]; + irqNum = 67; + } + controller_0x4000B000 :: stm32mp1_spi_i2s_device { + match_attr = "st_stm32mp157_spi_2"; + regPBase = 0x4000B000; + busModeSel = 0; + busNum = 2; + pins = [1, 12, 5, 1, 13, 5, 1, 14, 5, 1, 15, 5]; + irqNum = 68; + } + controller_0x4000C000 :: stm32mp1_spi_i2s_device { + match_attr = "st_stm32mp157_spi_3"; + regPBase = 0x4000C000; + busModeSel = 0; + busNum = 3; + pins = [0, 15, 6, 2, 10, 6, 2, 11, 6, 2, 12, 6]; + irqNum = 83; + } + controller_0x44005000 :: stm32mp1_spi_i2s_device { + match_attr = "st_stm32mp157_spi_4"; + regPBase = 0x44005000; + busModeSel = 0; + busNum = 4; + pins = [4, 11, 5, 4, 12, 5, 4, 13, 5, 4, 14, 5]; + irqNum = 116; + } + controller_0x44009000 :: stm32mp1_spi_i2s_device { + match_attr = "st_stm32mp157_spi_5"; + regPBase = 0x44009000; + busModeSel = 0; + busNum = 5; + pins = [5, 6, 5, 5, 7, 5, 5, 8, 5, 5, 9, 5]; + irqNum = 117; + } + controller_0x5C001000 :: stm32mp1_spi_i2s_device { + match_attr = "st_stm32mp157_spi_6"; + regPBase = 0x5C001000; + busModeSel = 0; + busNum = 6; + pins = [6, 8, 5, 6, 13, 5, 6, 12, 5, 6, 14, 5]; + irqNum = 118; + } + } + } +} \ No newline at end of file