Ciao Armando,
Hi Jagan,

On Friday I found another driver implementation already on my desktop, by 
grepping for pl022 in the upper level ../, but it is more general and not easy 
to understand. But maybe it helps us to find the information we need.

This is how I started! Now as patchset based on u-boot-spi.git:


diff --git a/arch/arm/cpu/armv8/hisilicon/pinmux.c 
b/arch/arm/cpu/armv8/hisilicon/pinmux.c
index 3e4c9ce..83f02db 100644
--- a/arch/arm/cpu/armv8/hisilicon/pinmux.c
+++ b/arch/arm/cpu/armv8/hisilicon/pinmux.c
@@ -17,6 +17,24 @@ struct hi6220_pinmux0_regs *pmx0 =
 struct hi6220_pinmux1_regs *pmx1 =
        (struct hi6220_pinmux1_regs *)HI6220_PINMUX1_BASE;
 
+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;
+       }
+}
+
 static void hi6220_uart_config(int peripheral)
 {
        switch (peripheral) {
@@ -164,6 +182,9 @@ static int hi6220_mmc_config(int peripheral)
 int hi6220_pinmux_config(int peripheral)
 {
        switch (peripheral) {
+       case PERIPH_ID_SPI0:
+               hi6220_spi_config(peripheral);
+               break;
        case PERIPH_ID_UART0:
        case PERIPH_ID_UART1:
        case PERIPH_ID_UART2:
diff --git a/arch/arm/include/asm/arch-hi6220/hi6220.h 
b/arch/arm/include/asm/arch-hi6220/hi6220.h
index 3a12c75..1b73f42 100644
--- a/arch/arm/include/asm/arch-hi6220/hi6220.h
+++ b/arch/arm/include/asm/arch-hi6220/hi6220.h
@@ -19,6 +19,8 @@
 #define HI6220_PMUSSI_BASE                     0xF8000000
 
 #define HI6220_PERI_BASE                       0xF7030000
+/*Hi6220V100_Multi-Mode_Application_Processor_Function_Description on p.5-45*/
+#define HI6220_SPI_BASE                                0xF7106000
 
 struct peri_sc_periph_regs {
        u32 ctrl1;              /*0x0*/
diff --git a/arch/arm/include/asm/arch-hi6220/periph.h 
b/arch/arm/include/asm/arch-hi6220/periph.h
index 7155f60..b58a0f7 100644
--- a/arch/arm/include/asm/arch-hi6220/periph.h
+++ b/arch/arm/include/asm/arch-hi6220/periph.h
@@ -25,6 +25,8 @@ enum periph_id {
        PERIPH_ID_SDMMC1,
 
        PERIPH_ID_NONE = -1,
+       PERIPH_ID_SPI0,
+       PERIPH_ID_SPI1,
 };
 
 #endif /* __ASM_ARM_ARCH_PERIPH_H */
diff --git a/board/hisilicon/hikey/hikey.c b/board/hisilicon/hikey/hikey.c
index 72d6334..e90ea74 100644
--- a/board/hisilicon/hikey/hikey.c
+++ b/board/hisilicon/hikey/hikey.c
@@ -21,6 +21,10 @@
 #include <asm/arch/hi6220.h>
 #include <asm/armv8/mmu.h>
 
+#ifdef CONFIG_PL022_SPI
+#include <spi.h>
+#endif
+
 /*TODO drop this table in favour of device tree */
 static const struct hikey_gpio_platdata hi6220_gpio[] = {
        { 0, HI6220_GPIO_BASE(0)},
@@ -335,9 +339,46 @@ int misc_init_r(void)
 {
        return 0;
 }
+#ifdef CONFIG_PL022_SPI
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+       return bus == 0 && cs == 0;
+}
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+//     at91_set_pio_output(AT91_PIO_PORTC, 3, 0);
+       gpio_request(0, "PWR_HOLD_GPIO0_0");
+       gpio_direction_output(0, 1);
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+//     at91_set_pio_output(AT91_PIO_PORTC, 3, 1);
+       gpio_request(0, "PWR_HOLD_GPIO0_0");
+       gpio_direction_output(0, 1);
+}
+
+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 */
 
 int board_init(void)
 {
+#ifdef CONFIG_PL022_SPI
+       hikey_spi0_hw_init();
+#endif
        return 0;
 }
 
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index b1d9e20..a509d93 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -6,6 +6,8 @@
 #
 
 # There are many options which enable SPI, so make this library available
+obj-$(CONFIG_PL022_SPI) += pl022_spi.o
+
 ifdef CONFIG_DM_SPI
 obj-y += spi-uclass.o
 obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c
index e69de29..e80fed3 100644
--- a/drivers/spi/pl022_spi.c
+++ b/drivers/spi/pl022_spi.c
@@ -0,0 +1,321 @@
+/*
+ * (C) Copyright 2012
+ * Armando Visconti, ST Microelectronics, armando.visconti at st.com.
+ *
+ * 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
+ */
+/* Comment by Jagan: 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 */
+/* Comment by Jagan: Something like pl022_spi_regs*/
+struct pl022 {
+       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 */
+};
+
+/* Comment by Jagan: -- 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 */
+
+/* Comment by Jagan: --- TAG -*/
+/* Comment by Jagan: 
+ * 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;
+/* Comment by Jagan: 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;
+}
diff --git a/include/configs/hikey.h b/include/configs/hikey.h
index ffcc4d2..5ac8997 100644
--- a/include/configs/hikey.h
+++ b/include/configs/hikey.h
@@ -76,6 +76,24 @@
 
 #define CONFIG_HIKEY_GPIO
 
+/* Synchronous Serial Port PL022 for SPI */
+#define CONFIG_PL022_SPI
+
+/* SPI Configuration */
+#define CONFIG_SYS_SPI_BASE            0xF7106000
+//#define CONFIG_DAVINCI_SPI
+//#define CONFIG_SYS_SPI_CLK           clk_get_rate(KS2_CLK1_6)
+//#define CONFIG_SYS_SPI_CLK           24000000
+//#define CONFIG_SYS_SPI_CLK           83000000
+#define CONFIG_SYS_SPI_CLK             121000000
+//#define CONFIG_SF_DEFAULT_SPEED              30000000
+//#define CONFIG_ENV_SPI_MAX_HZ                CONFIG_SF_DEFAULT_SPEED
+#ifdef CONFIG_SPL_BUILD
+#undef CONFIG_DM_SPI
+#undef CONFIG_DM_SPI_FLASH
+#endif
+
+
 
 
 
 
Am Mittwoch, September 14, 2016 16:39 CEST, Armando Visconti 
<armando.visco...@st.com> schrieb: 
 
> Ciao Michael,
> 
> On 09/08/2016 04:21 PM, Michael Brandl wrote:
> > Dear U-Boot (SPI) Developers,
> >
> > this patch seems to be my only chance to get spi working without/before 
> > Linux.
> 
> I wrote and used this code for u-boot for a asic
> specified by one of our customers. The patch was generic
> enough to be pushed in u-boot, but I didn't have
> much time to test it on a different, more generic
> platform. So the maintainer decided to drop it...
> 
> Would be nice if you could work on it and resurrect it...
> :)
> 
> Let me know if you have progressed on this or abandoned it.
> 
> >
> > 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
> >
> 
> Yes, I'm currently using HiKey platform for doing my day by day
> job here in office. Nevertheless, I don't think I have enough
> time to take a look into testing this commit.
> 
> > 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.
> >
> 
> Maybe I can try to recover the work that was done to integrate
> this commit into the customer platform I was talking about.
> I'll take a look into it right now...
> 
> > 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
> >
> >
> >
> >
> 
> Rgds,
> Armando
>

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to