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
<[email protected]> 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
[email protected]
http://lists.denx.de/mailman/listinfo/u-boot