137 lines
3.1 KiB
C
137 lines
3.1 KiB
C
#include <common.h>
|
|
#include <io.h>
|
|
#include <spi/imx-spi.h>
|
|
#include <mach/imx6-regs.h>
|
|
#include <mach/generic.h>
|
|
#include <bootsource.h>
|
|
#include <asm/sections.h>
|
|
#include <linux/sizes.h>
|
|
#include <mach/xload.h>
|
|
|
|
static int cspi_2_3_read_data(void __iomem *base, u32 *data)
|
|
{
|
|
u32 r;
|
|
|
|
while (1) {
|
|
if (readl(base + CSPI_2_3_STAT) & CSPI_2_3_STAT_RR)
|
|
break;
|
|
}
|
|
|
|
r = swab32(readl(base + CSPI_2_3_RXDATA));
|
|
if (data)
|
|
*data = r;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cspi_2_3_load(void __iomem *base, unsigned int flash_offset, void *buf, int len)
|
|
{
|
|
int transfer_size = 256;
|
|
u32 val;
|
|
int words, adr = 0;
|
|
int ret;
|
|
|
|
val = readl(base + CSPI_2_3_CTRL);
|
|
val &= ~(0xfff << CSPI_2_3_CTRL_BL_OFFSET);
|
|
val |= CSPI_2_3_CTRL_ENABLE;
|
|
writel(val, base + CSPI_2_3_CTRL);
|
|
|
|
writel(val, base + CSPI_2_3_CTRL);
|
|
|
|
for (adr = 0; adr < len; adr += transfer_size) {
|
|
|
|
val |= ((transfer_size + 4) * 8 - 1) << CSPI_2_3_CTRL_BL_OFFSET;
|
|
writel(val, base + CSPI_2_3_CTRL);
|
|
|
|
/* address */
|
|
writel(swab32(0x3) | (adr + flash_offset), base + CSPI_2_3_TXDATA);
|
|
writel(val | CSPI_2_3_CTRL_XCH, base + CSPI_2_3_CTRL);
|
|
|
|
ret = cspi_2_3_read_data(base, NULL);
|
|
if (ret)
|
|
return ret;
|
|
|
|
words = 0;
|
|
|
|
for (words = 0; words < transfer_size >> 2; words++) {
|
|
writel(0, base + CSPI_2_3_TXDATA);
|
|
cspi_2_3_read_data(base, buf);
|
|
buf += 4;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* imx6_spi_load_image - load an image from SPI NOR
|
|
* @instance: The SPI controller instance (0..4)
|
|
* @flash_offset: The offset in flash where the image starts
|
|
* @buf: The buffer to load the image to
|
|
* @len: The size to load
|
|
*
|
|
* This function loads data from SPI NOR flash on i.MX6. This assumes the
|
|
* SPI controller has already been initialized and the pinctrl / clocks are
|
|
* configured correctly. This is the case when the ROM has loaded the initial
|
|
* portion of the boot loader from exactly this controller.
|
|
*
|
|
* Return: 0 if successful, negative error code otherwise
|
|
*/
|
|
int imx6_spi_load_image(int instance, unsigned int flash_offset, void *buf, int len)
|
|
{
|
|
void *base;
|
|
|
|
switch (instance) {
|
|
case 0:
|
|
base = IOMEM(MX6_ECSPI1_BASE_ADDR);
|
|
break;
|
|
case 1:
|
|
base = IOMEM(MX6_ECSPI2_BASE_ADDR);
|
|
break;
|
|
case 2:
|
|
base = IOMEM(MX6_ECSPI3_BASE_ADDR);
|
|
break;
|
|
case 3:
|
|
base = IOMEM(MX6_ECSPI4_BASE_ADDR);
|
|
break;
|
|
case 4:
|
|
base = IOMEM(MX6_ECSPI5_BASE_ADDR);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
cspi_2_3_load(base, flash_offset, buf, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* imx6_spi_start_image - Load and start an image from SPI NOR flash
|
|
* @instance: The SPI controller instance (0..4)
|
|
*
|
|
* This uses imx6_spi_load_image() to load an image from SPI NOR flash.
|
|
* It is assumed that the image is the currently running barebox image
|
|
* (This information is used to calculate the length of the image). The
|
|
* image is started afterwards.
|
|
*
|
|
* Return: If successul, this function does not return. A negative error
|
|
* code is returned when this function fails.
|
|
*/
|
|
int imx6_spi_start_image(int instance)
|
|
{
|
|
void *buf = (void *)0x10000000;
|
|
int ret, len;
|
|
void __noreturn (*bb)(void);
|
|
|
|
len = imx_image_size();
|
|
|
|
ret = imx6_spi_load_image(instance, 0, buf, len);
|
|
if (ret)
|
|
return ret;
|
|
|
|
bb = buf;
|
|
|
|
bb();
|
|
}
|