[U-Boot] [PATCH v6] spi: pl022_spi: Add support for ARM PL022 spi controller

Michael Brandl
2016-09-08T14:21:21Z

Dear U-Boot (SPI) Developers,

this patch seems to be my only chance to get spi working without/before Linux.

I'm a student from Augsburg (Germany) experimenting with the Hikey Board from 96boards.
The hi6220 processor from HiSilicon isn't fully documented, there is just one document called Function Description:
http://mirror.lemaker.org/Hi6220V100_Multi-Mode_Application_Processor_Function_Description.pdf

U-Boot already supports the Hikey Board to be loaded from ARM Trusted Firmware (ATF) but only UART and SDMMC is supported by now.
I cloned the u-boot-spi.git and tried to integrate this patch but I'm not experienced enough to adjust the specific config for the Hikey Board.

Taking a look at armv7 devices with spi support I started like this:

+++ b/arch/arm/include/asm/arch-hi6220/hi6220.h

+/*Hi6220V100_Multi-Mode_Application_Processor_Function_Description on p.5-45*/
+#define HI6220_SPI_BASE 0xF7106000

+++ b/include/configs/hikey.h

+/* Synchronous Serial Port PL022 for SPI */
+#define CONFIG_PL022_SPI

+++ b/board/hisilicon/hikey/hikey.c

int board_init(void)
{
+#ifdef CONFIG_PL022_SPI
+ hikey_spi0_hw_init();
+#endif
return 0;
}

+static void hikey_spi0_hw_init(void)
+{
+ hi6220_pinmux_config(PERIPH_ID_SPI0)
+// at91_set_pio_output(AT91_PIO_PORTC, 3, 1); /* SPI0_CS0 */
+ gpio_request(0, "PWR_HOLD_GPIO0_0");
+ gpio_direction_output(0, 1);
+
+ /* Enable clock */
+// at91_periph_clk_enable(ATMEL_ID_SPI0);
+/* from Kernel { HI6220_SPI_CLK, "spi_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 9, 0, }, */
+ hi6220_clk_enable(PERI_CLK0_SPI0, &peri_sc->clk3_en);
+
+}
+#endif /* CONFIG_PL022_SPI */
+

+++ b/arch/arm/cpu/armv8/hisilicon/pinmux.c

+static void hi6220_spi_config(int peripheral)
+{
+ switch (peripheral) {
+ case PERIPH_ID_SPI0:
+// at91_set_a_periph(AT91_PIO_PORTC, 0, 0); /* SPI0_MISO */
+// at91_set_a_periph(AT91_PIO_PORTC, 1, 0); /* SPI0_MOSI */
+// at91_set_a_periph(AT91_PIO_PORTC, 2, 0); /* SPI0_SPCK */
+ break;
+
+ case PERIPH_ID_SPI1:
+ break;
+
+ default:
+ debug("%s: invalid peripheral %d", __func__, peripheral);
+ return;
+ }
+}

Maybe you can help me to get spi working on Hikey. My overall aim is to port the pl022 driver then to ARM TF ... maybe also that could be interessing for you.

With kind Regards,
Michael Brandl

On Wed, Jan 8, 2014 at 2:49 PM, Armando Visconti
<armando.visconti@st.com <http://lists.denx.de/mailman/listinfo/u-boot>> wrote:
>/Hello Jagan, />//>/Sorry for late reply. />//>//>//>/On 12/20/2013 8:03 PM, Jagan Teki wrote: />>//>>/On Fri, Oct 4, 2013 at 12:20 PM, Jagan Teki <jagannadh.teki@gmail.com
<http://lists.denx.de/mailman/listinfo/u-boot>> />>/wrote: />>>//>>>/Hi Vipin, />>>//>>>/I have few quick comments, please fix it. />>>/Please use the u-boot-spi.git with master-probe branch for testing this />>>/driver. />>>/Let me know for any issues/concerns. />>>//>>>/On Wed, Jun 12, 2013 at 7:55 PM, Jagan Teki <jagannadh.teki@gmail.com
<http://lists.denx.de/mailman/listinfo/u-boot>> />>>/wrote: />>>>//>>>>/Thanks for v6 sent. />>>>//>>>>/Have you tested this? />>>>/on which board, include/configs/*.h file? />>>>//>>>>/-- />>>>/Thanks, />>>>/Jagan. />>>>//>>>>/On Wed, Jun 12, 2013 at 6:17 PM, Armando Visconti />>>>/<armando.visconti@st.com
<http://lists.denx.de/mailman/listinfo/u-boot>> wrote: />>>>>//>>>>>/This patch adds the support for the ARM PL022 SPI controller for the />>>>>/standard />>>>>/variant (0x00041022), which has a 16bit wide and 8 locations deep TX/RX />>>>>/FIFO. />>>>>//>>>>>/Signed-off-by: Armando Visconti <armando.visconti@st.com
<http://lists.denx.de/mailman/listinfo/u-boot>> />>>>>/Signed-off-by: Vipin Kumar <vipin.kumar@st.com
<http://lists.denx.de/mailman/listinfo/u-boot>> />>>>>/Acked-by: Stefan Roese <sr@denx.de
<http://lists.denx.de/mailman/listinfo/u-boot>> />>>>>/--- />>>>>/v5->v6 />>>>>//>>>>>/1. Make use of spi_alloc_slave() macro. />>>>>/2. Changed the identation on 'if statement' as requested />>>>>/by Jagan. />>>>>//>>>>>/drivers/spi/Makefile | 1 + />>>>>/drivers/spi/pl022_spi.c | 308 />>>>>/++++++++++++++++++++++++++++++++++++++++++++++++ />>>>>/2 files changed, 309 insertions(+) />>>>>/create mode 100644 drivers/spi/pl022_spi.c />>>>>//>>>>>/diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile />>>>>/index d08609e..b6443b1 100644 />>>>>/--- a/drivers/spi/Makefile />>>>>/+++ b/drivers/spi/Makefile />>>>>/@@ -47,6 +47,7 @@ COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o />>>>>/COBJS-$(CONFIG_MXS_SPI) += mxs_spi.o />>>>>/COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o />>>>>/COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o />>>>>/+COBJS-$(CONFIG_PL022_SPI) += pl022_spi.o />>>>>/COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o />>>>>/COBJS-$(CONFIG_SH_SPI) += sh_spi.o />>>>>/COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o />>>>>/diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c />>>>>/new file mode 100644 />>>>>/index 0000000..5b47413 />>>>>/--- /dev/null />>>>>/+++ b/drivers/spi/pl022_spi.c />>>>>/@@ -0,0 +1,308 @@ />>>>>/+/* />>>>>/+ * (C) Copyright 2012 />>>>>/+ * Armando Visconti, ST Microelectronics, armando.visconti at st.com.
<http://lists.denx.de/mailman/listinfo/u-boot> />>>>>/+ * />>>>>/+ * Driver for ARM PL022 SPI Controller. Based on atmel_spi.c />>>>>/+ * by Atmel Corporation. />>>>>/+ * />>>>>/+ * 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; either version 2 of />>>>>/+ * the License, or (at your option) any later version. />>>>>/+ * />>>>>/+ * 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. />>>>>/+ * />>>>>/+ * You should have received a copy of the GNU General Public License />>>>>/+ * along with this program; if not, write to the Free Software />>>>>/+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, />>>>>/+ * MA 02111-1307 USA />>>>>/+ */ />>>//>>>/Use latest SPDX-License-Identifier: />>>/check for any existing one. />>>//>>>>>/+ />>>>>/+#include <common.h> />>>>>/+#include <malloc.h> />>>>>/+#include <spi.h> />>>>>/+#include <asm/io.h> />>>>>/+#include <asm/arch/hardware.h> />>>>>/+ />>>>>/+/* SSP registers mapping */ />>>>>/+struct pl022 { />>>//>>>/Something like pl022_spi_regs />>>//>>>>>/+ u32 ssp_cr0; /* 0x000 */ />>>>>/+ u32 ssp_cr1; /* 0x004 */ />>>>>/+ u32 ssp_dr; /* 0x008 */ />>>>>/+ u32 ssp_sr; /* 0x00c */ />>>>>/+ u32 ssp_cpsr; /* 0x010 */ />>>>>/+ u32 ssp_imsc; /* 0x014 */ />>>>>/+ u32 ssp_ris; /* 0x018 */ />>>>>/+ u32 ssp_mis; /* 0x01c */ />>>>>/+ u32 ssp_icr; /* 0x020 */ />>>>>/+ u32 ssp_dmacr; /* 0x024 */ />>>>>/+ u8 reserved_1[0x080 - 0x028]; />>>>>/+ u32 ssp_itcr; /* 0x080 */ />>>>>/+ u32 ssp_itip; /* 0x084 */ />>>>>/+ u32 ssp_itop; /* 0x088 */ />>>>>/+ u32 ssp_tdr; /* 0x08c */ />>>>>/+ u8 reserved_2[0xFE0 - 0x090]; />>>>>/+ u32 ssp_pid0; /* 0xfe0 */ />>>>>/+ u32 ssp_pid1; /* 0xfe4 */ />>>>>/+ u32 ssp_pid2; /* 0xfe8 */ />>>>>/+ u32 ssp_pid3; /* 0xfec */ />>>>>/+ u32 ssp_cid0; /* 0xff0 */ />>>>>/+ u32 ssp_cid1; /* 0xff4 */ />>>>>/+ u32 ssp_cid2; /* 0xff8 */ />>>>>/+ u32 ssp_cid3; /* 0xffc */ />>>>>/+}; />>>>>/+ />>>//>>>/-- TAG+ />>>>>//>>>>>/+/* SSP Control Register 0 - SSP_CR0 */ />>>>>/+#define SSP_CR0_SPO (0x1 << 6) />>>>>/+#define SSP_CR0_SPH (0x1 << 7) />>>>>/+#define SSP_CR0_8BIT_MODE (0x07) />>>>>/+#define SSP_SCR_MAX (0xFF) />>>>>/+#define SSP_SCR_SHFT 8 />>>>>/+ />>>>>/+/* SSP Control Register 0 - SSP_CR1 */ />>>>>/+#define SSP_CR1_MASK_SSE (0x1 << 1) />>>>>/+ />>>>>/+#define SSP_CPSR_MAX (0xFE) />>>>>/+ />>>>>/+/* SSP Status Register - SSP_SR */ />>>>>/+#define SSP_SR_MASK_TFE (0x1 << 0) /* Transmit FIFO />>>>>/empty */ />>>>>/+#define SSP_SR_MASK_TNF (0x1 << 1) /* Transmit FIFO not />>>>>/full */ />>>>>/+#define SSP_SR_MASK_RNE (0x1 << 2) /* Receive FIFO not />>>>>/empty */ />>>>>/+#define SSP_SR_MASK_RFF (0x1 << 3) /* Receive FIFO full />>>>>/*/ />>>>>/+#define SSP_SR_MASK_BSY (0x1 << 4) /* Busy Flag */ />>>>>/+ />>>//>>>/--- TAG - />>>//>>>/Bit mask macros - please place after headers. />>>/We follow a simple format to write spi driver - please check />>>/http://patchwork.ozlabs.org/patch/265683/ />>>//>>>/And try to verify your code w.r.t above format - let me know any />>>/comments. />>>//>>>>>/+struct pl022_spi_slave { />>>>>/+ struct spi_slave slave; />>>>>/+ void *regs; />>>//>>>/Please use the structure pointer instead of void. />>>//>>>>>/+ unsigned int freq; />>>>>/+}; />>>>>/+ />>>>>/+static inline struct pl022_spi_slave *to_pl022_spi(struct spi_slave />>>>>/*slave) />>>>>/+{ />>>>>/+ return container_of(slave, struct pl022_spi_slave, slave); />>>>>/+} />>>>>/+ />>>>>/+/* />>>>>/+ * Following three functions should be provided by the />>>>>/+ * board support package. />>>>>/+ */ />>>>>/+int __weak spi_cs_is_valid(unsigned int bus, unsigned int cs) />>>>>/+{ />>>>>/+ return 1; />>>>>/+} />>>>>/+ />>>>>/+void __weak spi_cs_activate(struct spi_slave *slave) />>>>>/+{ />>>>>/+ /* do nothing */ />>>>>/+} />>>>>/+ />>>>>/+void __weak spi_cs_deactivate(struct spi_slave *slave) />>>>>/+{ />>>>>/+ /* do nothing */ />>>>>/+} />>>>>/+ />>>>>/+void spi_init(void) />>>>>/+{ />>>>>/+ /* do nothing */ />>>>>/+} />>>>>/+ />>>>>/+/* />>>>>/+ * ARM PL022 exists in different 'flavors'. />>>>>/+ * This drivers currently support the standard variant (0x00041022), />>>>>/that has a />>>>>/+ * 16bit wide and 8 locations deep TX/RX FIFO. />>>>>/+ */ />>>>>/+static int pl022_is_supported(struct pl022_spi_slave *ps) />>>>>/+{ />>>>>/+ struct pl022 *pl022 = (struct pl022 *)ps->regs; />>>>>/+ />>>>>/+ /* PL022 version is 0x00041022 */ />>>>>/+ if ((readl(&pl022->ssp_pid0) == 0x22) && />>>>>/+ (readl(&pl022->ssp_pid1) == 0x10) && />>>>>/+ ((readl(&pl022->ssp_pid2) & 0xf) == 0x04) && />>>>>/+ (readl(&pl022->ssp_pid3) == 0x00)) />>>>>/+ return 1; />>>>>/+ />>>>>/+ return 0; />>>>>/+} />>>>>/+ />>>>>/+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, />>>>>/+ unsigned int max_hz, unsigned int mode) />>>>>/+{ />>>>>/+ struct pl022_spi_slave *ps; />>>>>/+ struct pl022 *pl022; />>>>>/+ u16 scr = 1, prescaler, cr0 = 0, cpsr = 0; />>>>>/+ />>>>>/+ if (!spi_cs_is_valid(bus, cs)) />>>>>/+ return NULL; />>>>>/+ />>>>>/+ ps = spi_alloc_slave(struct pl022_spi_slave, bus, cs); />>>>>/+ if (!ps) />>>>>/+ return NULL; />>>>>/+ />>>>>/+ ps->freq = max_hz; />>>>>/+ />>>>>/+ switch (bus) { />>>>>/+ case 0: />>>>>/+ ps->regs = (void *)CONFIG_SYS_SPI_BASE; />>>>>/+ break; />>>>>/+#ifdef CONFIG_SYS_SPI_BASE1 />>>>>/+ case 1: />>>>>/+ ps->regs = (void *)CONFIG_SYS_SPI_BASE1; />>>>>/+ break; />>>>>/+#endif />>>>>/+#ifdef CONFIG_SYS_SPI_BASE2 />>>>>/+ case 2: />>>>>/+ ps->regs = (void *)CONFIG_SYS_SPI_BASE2; />>>>>/+ break; />>>>>/+#endif />>>>>/+#ifdef CONFIG_SYS_SPI_BASE3 />>>>>/+ case 3: />>>>>/+ ps->regs = (void *)CONFIG_SYS_SPI_BASE3; />>>>>/+ break; />>>>>/+#endif />>>>>/+ default: />>>>>/+ free(ps); />>>>>/+ return NULL; />>>>>/+ } />>>>>/+ />>>>>/+ pl022 = (struct pl022 *)ps->regs; />>>>>/+ />>>>>/+ /* Check the PL022 version */ />>>>>/+ if (!pl022_is_supported(ps)) { />>>>>/+ free(ps); />>>>>/+ return NULL; />>>>>/+ } />>>>>/+ />>>>>/+ /* Set requested polarity and 8bit mode */ />>>>>/+ cr0 = SSP_CR0_8BIT_MODE; />>>>>/+ cr0 |= (mode & SPI_CPHA) ? SSP_CR0_SPH : 0; />>>>>/+ cr0 |= (mode & SPI_CPOL) ? SSP_CR0_SPO : 0; />>>>>/+ />>>>>/+ writel(cr0, &pl022->ssp_cr0); />>>>>/+ />>>>>/+ /* Program the SSPClk frequency */ />>>>>/+ prescaler = CONFIG_SYS_SPI_CLK / ps->freq; />>>>>/+ />>>>>/+ if (prescaler <= 0xFF) { />>>>>/+ cpsr = prescaler; />>>>>/+ } else { />>>>>/+ for (scr = 1; scr <= SSP_SCR_MAX; scr++) { />>>>>/+ if (!(prescaler % scr)) { />>>>>/+ cpsr = prescaler / scr; />>>>>/+ if (cpsr <= SSP_CPSR_MAX) />>>>>/+ break; />>>>>/+ } />>>>>/+ } />>>>>/+ />>>>>/+ if (scr > SSP_SCR_MAX) { />>>>>/+ scr = SSP_SCR_MAX; />>>>>/+ cpsr = prescaler / scr; />>>>>/+ cpsr &= SSP_CPSR_MAX; />>>>>/+ } />>>>>/+ } />>>>>/+ />>>>>/+ if (cpsr & 0x1) />>>>>/+ cpsr++; />>>>>/+ />>>>>/+ writel(cpsr, &pl022->ssp_cpsr); />>>>>/+ cr0 = readl(&pl022->ssp_cr0); />>>>>/+ writel(cr0 | (scr - 1) << SSP_SCR_SHFT, &pl022->ssp_cr0); />>>>>/+ />>>>>/+ return &ps->slave; />>>>>/+} />>>>>/+ />>>>>/+void spi_free_slave(struct spi_slave *slave) />>>>>/+{ />>>>>/+ struct pl022_spi_slave *ps = to_pl022_spi(slave); />>>>>/+ />>>>>/+ free(ps); />>>>>/+} />>>>>/+ />>>>>/+int spi_claim_bus(struct spi_slave *slave) />>>>>/+{ />>>>>/+ struct pl022_spi_slave *ps = to_pl022_spi(slave); />>>>>/+ struct pl022 *pl022 = (struct pl022 *)ps->regs; />>>>>/+ />>>>>/+ /* Enable the SPI hardware */ />>>>>/+ setbits_le32(&pl022->ssp_cr1, SSP_CR1_MASK_SSE); />>>>>/+ />>>>>/+ return 0; />>>>>/+} />>>>>/+ />>>>>/+void spi_release_bus(struct spi_slave *slave) />>>>>/+{ />>>>>/+ struct pl022_spi_slave *ps = to_pl022_spi(slave); />>>>>/+ struct pl022 *pl022 = (struct pl022 *)ps->regs; />>>>>/+ />>>>>/+ /* Disable the SPI hardware */ />>>>>/+ writel(0x0, &pl022->ssp_cr1); />>>>>/+} />>>>>/+ />>>>>/+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, />>>>>/+ const void *dout, void *din, unsigned long flags) />>>>>/+{ />>>>>/+ struct pl022_spi_slave *ps = to_pl022_spi(slave); />>>>>/+ struct pl022 *pl022 = (struct pl022 *)ps->regs; />>>>>/+ u32 len_tx = 0, len_rx = 0, len; />>>>>/+ u32 ret = 0; />>>>>/+ const u8 *txp = dout; />>>>>/+ u8 *rxp = din, value; />>>>>/+ />>>>>/+ if (bitlen == 0) />>>>>/+ /* Finish any previously submitted transfers */ />>>>>/+ goto out; />>>>>/+ />>>>>/+ /* />>>>>/+ * TODO: The controller can do non-multiple-of-8 bit />>>>>/+ * transfers, but this driver currently doesn't support it. />>>>>/+ * />>>>>/+ * It's also not clear how such transfers are supposed to be />>>>>/+ * represented as a stream of bytes...this is a limitation of />>>>>/+ * the current SPI interface. />>>>>/+ */ />>>>>/+ if (bitlen % 8) { />>>>>/+ ret = -1; />>>>>/+ />>>>>/+ /* Errors always terminate an ongoing transfer */ />>>>>/+ flags |= SPI_XFER_END; />>>>>/+ goto out; />>>>>/+ } />>>>>/+ />>>>>/+ len = bitlen / 8; />>>>>/+ />>>>>/+ if (flags & SPI_XFER_BEGIN) />>>>>/+ spi_cs_activate(slave); />>>>>/+ />>>>>/+ while (len_tx < len) { />>>>>/+ if (readl(&pl022->ssp_sr) & SSP_SR_MASK_TNF) { />>>>>/+ value = (txp != NULL) ? *txp++ : 0; />>>>>/+ writel(value, &pl022->ssp_dr); />>>>>/+ len_tx++; />>>>>/+ } />>>>>/+ />>>>>/+ if (readl(&pl022->ssp_sr) & SSP_SR_MASK_RNE) { />>>>>/+ value = readl(&pl022->ssp_dr); />>>>>/+ if (rxp) />>>>>/+ *rxp++ = value; />>>>>/+ len_rx++; />>>>>/+ } />>>>>/+ } />>>>>/+ />>>>>/+ while (len_rx < len_tx) { />>>>>/+ if (readl(&pl022->ssp_sr) & SSP_SR_MASK_RNE) { />>>>>/+ value = readl(&pl022->ssp_dr); />>>>>/+ if (rxp) />>>>>/+ *rxp++ = value; />>>>>/+ len_rx++; />>>>>/+ } />>>>>/+ } />>>>>/+ />>>>>/+out: />>>>>/+ if (flags & SPI_XFER_END) />>>>>/+ spi_cs_deactivate(slave); />>>>>/+ />>>>>/+ return ret; />>>>>/+} />>>>>/-- />>>>>/1.7.11.7 />>//>>/Ping />>//>//>/Unfortunately lot of changes happened to our organization />/and we (myself and Vipin) are no longer able to proceed in doing />/this job. />//>/So I think we need to drop this patch, unless someone from the />/u-boot community has the possibility to (and is willing to) proceed />/in implementing and testing the proper changes. /