summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-09-13 14:56:06 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-09-13 14:56:06 +0200
commit074a8fdc929a9cdb13b2ed7e637055d0acc05de2 (patch)
tree2e6182c70403ad1db43e3128903e3c79531ce1dd
parent0e1892b2e9348a94f58d1a4518e931c8ba46843e (diff)
parent994fa02f5d7d815265b625f6114d19f156547b69 (diff)
downloadbarebox-074a8fdc929a9cdb13b2ed7e637055d0acc05de2.tar.gz
barebox-074a8fdc929a9cdb13b2ed7e637055d0acc05de2.tar.xz
Merge branch 'for-next/socfpga'
-rw-r--r--arch/arm/boards/ebv-socrates/board.c36
-rw-r--r--arch/arm/dts/socfpga_cyclone5_socrates.dts64
-rw-r--r--arch/arm/mach-socfpga/xload.c56
-rw-r--r--common/filetype.c4
-rw-r--r--drivers/clk/socfpga.c25
-rw-r--r--include/filetype.h1
-rw-r--r--scripts/socfpga_mkimage.c144
7 files changed, 246 insertions, 84 deletions
diff --git a/arch/arm/boards/ebv-socrates/board.c b/arch/arm/boards/ebv-socrates/board.c
index 5d2d619914..f3207b88ef 100644
--- a/arch/arm/boards/ebv-socrates/board.c
+++ b/arch/arm/boards/ebv-socrates/board.c
@@ -2,6 +2,9 @@
#include <types.h>
#include <driver.h>
#include <init.h>
+#include <bbu.h>
+#include <bootsource.h>
+#include <filetype.h>
#include <asm/armlinux.h>
#include <linux/micrel_phy.h>
#include <linux/phy.h>
@@ -26,12 +29,45 @@ static int phy_fixup(struct phy_device *dev)
static int socrates_init(void)
{
+ enum bootsource bootsource = bootsource_get();
+ uint32_t flag_qspi = 0;
+ uint32_t flag_mmc = 0;
+
if (!of_machine_is_compatible("ebv,socrates"))
return 0;
if (IS_ENABLED(CONFIG_PHYLIB))
phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, phy_fixup);
+ switch (bootsource) {
+ case BOOTSOURCE_MMC:
+ flag_mmc |= BBU_HANDLER_FLAG_DEFAULT;
+ break;
+ case BOOTSOURCE_SPI:
+ flag_qspi |= BBU_HANDLER_FLAG_DEFAULT;
+ break;
+ default:
+ break;
+ }
+
+ bbu_register_std_file_update("qspi-xload0", flag_qspi,
+ "/dev/mtd0.prebootloader0",
+ filetype_socfpga_xload);
+ bbu_register_std_file_update("qspi-xload1", 0,
+ "/dev/mtd0.prebootloader1",
+ filetype_socfpga_xload);
+ bbu_register_std_file_update("qspi-xload2", 0,
+ "/dev/mtd0.prebootloader2",
+ filetype_socfpga_xload);
+ bbu_register_std_file_update("qspi-xload3", 0,
+ "/dev/mtd0.prebootloader3",
+ filetype_socfpga_xload);
+ bbu_register_std_file_update("qspi", 0, "/dev/mtd0.barebox",
+ filetype_arm_barebox);
+
+ bbu_register_std_file_update("mmc-xload", flag_mmc, "/dev/mmc0.0",
+ filetype_socfpga_xload);
+
return 0;
}
postcore_initcall(socrates_init);
diff --git a/arch/arm/dts/socfpga_cyclone5_socrates.dts b/arch/arm/dts/socfpga_cyclone5_socrates.dts
index 95cdf5d3d5..ea7e6cc102 100644
--- a/arch/arm/dts/socfpga_cyclone5_socrates.dts
+++ b/arch/arm/dts/socfpga_cyclone5_socrates.dts
@@ -19,42 +19,12 @@
#include "socfpga.dtsi"
/ {
- model = "EBV SoCrates";
- compatible = "ebv,socrates", "altr,socfpga";
-
chosen {
stdout-path = &uart0;
};
- leds: gpio-leds {
- };
-};
-
-&gpio0 {
- status = "okay";
-};
-
-&gpio1 {
- status = "okay";
-};
-
-&leds {
- compatible = "gpio-leds";
-
- led@0 {
- label = "0";
- gpios = <&porta 28 1>;
- linux,default-trigger = "heartbeat";
- };
-
- led@1 {
- label = "1";
- gpios = <&portb 19 1>;
- };
-
- led@2 {
- label = "2";
- gpios = <&portb 25 1>;
+ aliases {
+ ethernet0 = &gmac1;
};
};
@@ -75,5 +45,35 @@
cdns,tsd2d-ns = <50>;
cdns,tchsh-ns = <4>;
cdns,tslch-ns = <4>;
+
+ partition@0 {
+ label = "prebootloader0";
+ reg = <0x00000 0x10000>;
+ };
+
+ partition@1 {
+ label = "prebootloader1";
+ reg = <0x10000 0x10000>;
+ };
+
+ partition@2 {
+ label = "prebootloader2";
+ reg = <0x20000 0x10000>;
+ };
+
+ partition@3 {
+ label = "prebootloader3";
+ reg = <0x30000 0x10000>;
+ };
+
+ partition@4 {
+ label = "barebox";
+ reg = <0x40000 0x80000>;
+ };
+
+ partition@5 {
+ label = "data";
+ reg = <0xc0000 0x1f40000>;
+ };
};
};
diff --git a/arch/arm/mach-socfpga/xload.c b/arch/arm/mach-socfpga/xload.c
index 7f8f0320ca..993626966e 100644
--- a/arch/arm/mach-socfpga/xload.c
+++ b/arch/arm/mach-socfpga/xload.c
@@ -20,13 +20,15 @@
#include <mach/system-manager.h>
#include <mach/socfpga-regs.h>
-
-static struct socfpga_barebox_part default_part = {
- .nor_offset = SZ_256K,
- .nor_size = SZ_1M,
- .mmc_disk = "disk0.1",
+static struct socfpga_barebox_part default_parts[] = {
+ {
+ .nor_offset = SZ_256K,
+ .nor_size = SZ_1M,
+ .mmc_disk = "disk0.1",
+ },
+ { /* sentinel */ }
};
-const struct socfpga_barebox_part *barebox_part = &default_part;
+const struct socfpga_barebox_part *barebox_parts = &default_parts;
enum socfpga_clks {
timer, mmc, qspi_clk, uart, clk_max
@@ -109,28 +111,52 @@ static void socfpga_timer_init(void)
static __noreturn int socfpga_xload(void)
{
enum bootsource bootsource = bootsource_get();
- void *buf;
+ struct socfpga_barebox_part *part;
+ void *buf = NULL;
switch (bootsource) {
case BOOTSOURCE_MMC:
socfpga_mmc_init();
- buf = bootstrap_read_disk(barebox_part->mmc_disk, "fat");
+
+ for (part = barebox_parts; part->mmc_disk; part++) {
+ buf = bootstrap_read_disk(barebox_parts->mmc_disk, "fat");
+ if (!buf) {
+ pr_info("failed to load barebox from MMC %s\n",
+ part->mmc_disk);
+ continue;
+ }
+ }
+ if (!buf) {
+ pr_err("failed to load barebox.bin from MMC\n");
+ hang();
+ }
break;
case BOOTSOURCE_SPI:
socfpga_qspi_init();
- buf = bootstrap_read_devfs("mtd0", false, barebox_part->nor_offset,
- barebox_part->nor_size, SZ_1M);
+
+ for (part = barebox_parts; part->nor_size; part++) {
+ buf = bootstrap_read_devfs("mtd0", false,
+ part->nor_offset, part->nor_size, SZ_1M);
+ if (!buf) {
+ pr_info("failed to load barebox from QSPI NOR flash at offset %#x\n",
+ part->nor_offset);
+ continue;
+ }
+
+ break;
+ }
+
+ if (!buf) {
+ pr_err("failed to load barebox from QSPI NOR flash\n");
+ hang();
+ }
+
break;
default:
pr_err("unknown bootsource %d\n", bootsource);
hang();
}
- if (!buf) {
- pr_err("failed to load barebox.bin\n");
- hang();
- }
-
pr_info("starting bootloader...\n");
bootstrap_boot(buf, 0);
diff --git a/common/filetype.c b/common/filetype.c
index a8666a1439..4728f877c9 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -61,6 +61,7 @@ static const struct filetype_str filetype_str[] = {
[filetype_xz_compressed] = { "XZ compressed", "xz" },
[filetype_exe] = { "MS-DOS executable", "exe" },
[filetype_mxs_bootstream] = { "Freescale MXS bootstream", "mxsbs" },
+ [filetype_socfpga_xload] = { "SoCFPGA prebootloader image", "socfpga-xload" },
};
const char *file_type_to_string(enum filetype f)
@@ -294,6 +295,9 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
if (le32_to_cpu(buf[5]) == 0x504d5453)
return filetype_mxs_bootstream;
+ if (buf[16] == 0x31305341)
+ return filetype_socfpga_xload;
+
if (is_barebox_arm_head(_buf))
return filetype_arm_barebox;
if (buf[9] == 0x016f2818 || buf[9] == 0x18286f01)
diff --git a/drivers/clk/socfpga.c b/drivers/clk/socfpga.c
index 37ed038be8..6af0632caf 100644
--- a/drivers/clk/socfpga.c
+++ b/drivers/clk/socfpga.c
@@ -116,18 +116,27 @@ struct clk_periph {
const char *parent;
unsigned regofs;
unsigned int fixed_div;
+ void __iomem *div_reg;
+ unsigned int width;
+ unsigned int shift;
};
static unsigned long clk_periph_recalc_rate(struct clk *clk,
unsigned long parent_rate)
{
struct clk_periph *periph = container_of(clk, struct clk_periph, clk);
- u32 div;
+ u32 div, val;
- if (periph->fixed_div)
+ if (periph->fixed_div) {
div = periph->fixed_div;
- else
+ } else {
+ if (periph->div_reg) {
+ val = readl(periph->div_reg) >> periph->shift;
+ val &= div_mask(periph->width);
+ parent_rate /= (val + 1);
+ }
div = ((readl(clk_mgr_base_addr + periph->regofs) & 0x1ff) + 1);
+ }
return parent_rate / div;
}
@@ -140,6 +149,7 @@ static struct clk *socfpga_periph_clk(struct device_node *node)
{
struct clk_periph *periph;
int ret;
+ u32 div_reg[3];
periph = xzalloc(sizeof(*periph));
@@ -152,6 +162,15 @@ static struct clk *socfpga_periph_clk(struct device_node *node)
periph->clk.name = xstrdup(node->name);
periph->clk.ops = &clk_periph_ops;
+ ret = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+ if (!ret) {
+ periph->div_reg = clk_mgr_base_addr + div_reg[0];
+ periph->shift = div_reg[1];
+ periph->width = div_reg[2];
+ } else {
+ periph->div_reg = 0;
+ }
+
of_property_read_u32(node, "reg", &periph->regofs);
of_property_read_u32(node, "fixed-divider", &periph->fixed_div);
diff --git a/include/filetype.h b/include/filetype.h
index e87ca174a8..cde73c1170 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -36,6 +36,7 @@ enum filetype {
filetype_exe,
filetype_xz_compressed,
filetype_mxs_bootstream,
+ filetype_socfpga_xload,
filetype_max,
};
diff --git a/scripts/socfpga_mkimage.c b/scripts/socfpga_mkimage.c
index 4fbd5c748e..d7fe1b1b69 100644
--- a/scripts/socfpga_mkimage.c
+++ b/scripts/socfpga_mkimage.c
@@ -14,7 +14,10 @@
#define BRANCH_INST 0xea /* ARM opcode for "b" (unconditional branch) */
-#define MAX_IMAGE_SIZE (60 * 1024 - 4)
+#define MAX_V0IMAGE_SIZE (60 * 1024 - 4)
+/* Max size without authentication is 224 KB, due to memory used by
+ * the ROM boot code as a workspace out of the 256 KB of OCRAM */
+#define MAX_V1IMAGE_SIZE (224 * 1024 - 4)
static int add_barebox_header;
@@ -22,10 +25,21 @@ struct socfpga_header {
uint8_t validation_word[4];
uint8_t version;
uint8_t flags;
- uint8_t program_length[2];
- uint8_t spare[2];
- uint8_t checksum[2];
- uint8_t start_vector[4];
+ union {
+ struct {
+ uint8_t program_length[2];
+ uint8_t spare[2];
+ uint8_t checksum[2];
+ uint8_t start_vector[4];
+ } v0;
+ struct {
+ uint8_t header_length[2];
+ uint8_t program_length[4];
+ uint8_t entry_offset[4];
+ uint8_t spare[2];
+ uint8_t checksum[2];
+ } v1;
+ };
};
static uint32_t bb_header[] = {
@@ -87,7 +101,7 @@ static int write_full(int fd, void *buf, size_t size)
return insize;
}
-static uint32_t crc_table[256] = {
+static const uint32_t crc_table[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
@@ -143,47 +157,94 @@ uint32_t crc32(uint32_t crc, void *_buf, int length)
return crc;
}
+/* Create an ARM relative branch instuction
+ * branch is where the instruction will be placed and dest points to where
+ * it should branch too. */
+static void branch(uint8_t *branch, uint8_t *dest)
+{
+ int offset = dest - branch - 8; /* PC is offset +8 bytes on ARM */
+
+ branch[0] = (offset >> 2) & 0xff; /* instruction uses offset/4 */
+ branch[1] = (offset >> 10) & 0xff;
+ branch[2] = (offset >> 18) & 0xff;
+ branch[3] = BRANCH_INST;
+}
+
/* start_addr is where the socfpga header's start instruction should branch to.
* It should be relative to the start of buf */
-static int add_socfpga_header(void *buf, size_t size, unsigned start_addr)
+static int add_socfpga_header(void *buf, size_t size, unsigned start_addr, unsigned version)
{
struct socfpga_header *header = buf + 0x40;
- uint8_t *bufp;
+ void *entry;
+ uint8_t *bufp, *sumendp;
uint32_t *crc;
unsigned checksum;
- size_t length = size >> 2;
if (size & 0x3) {
fprintf(stderr, "%s: size must be multiple of 4\n", __func__);
return -EINVAL;
}
- /* Calculate relative address of requested start_addr from the
- * start_vector's branch instuction PC (+8 bytes on arm). */
- start_addr = start_addr + (int)(buf - (void*)&header->start_vector[0]) - 8;
+ /* Absolute address of entry point in buf */
+ entry = buf + start_addr;
+ if (version == 0) {
+ sumendp = &header->v0.checksum[0];
+ } else {
+ sumendp = &header->v1.checksum[0];
+
+ /* The ROM loader can't handle a negative offset */
+ if (entry < (void*)header) {
+ /* add a trampoline branch inst after end of the header */
+ uint8_t *trampoline = (void*)(header + 1);
+ branch(trampoline, entry);
+
+ /* and then make the trampoline the entry point */
+ entry = trampoline;
+ }
+ /* Calculate start address as offset relative to start of header */
+ start_addr = entry - (void*)header;
+ }
header->validation_word[0] = VALIDATION_WORD & 0xff;
header->validation_word[1] = (VALIDATION_WORD >> 8) & 0xff;
header->validation_word[2] = (VALIDATION_WORD >> 16) & 0xff;
header->validation_word[3] = (VALIDATION_WORD >> 24) & 0xff;
- header->version = 0;
+ header->version = version;
header->flags = 0;
- header->program_length[0] = length & 0xff;
- header->program_length[1] = (length >> 8) & 0xff;
- header->spare[0] = 0;
- header->spare[1] = 0;
- header->start_vector[0] = (start_addr >> 2) & 0xff; /* instruction uses offset/4 */
- header->start_vector[1] = (start_addr >> 10) & 0xff;
- header->start_vector[2] = (start_addr >> 18) & 0xff;
- header->start_vector[3] = BRANCH_INST;
+
+ if (version == 0) {
+ header->v0.program_length[0] = (size >> 2) & 0xff; /* length in words */
+ header->v0.program_length[1] = (size >> 10) & 0xff;
+ header->v0.spare[0] = 0;
+ header->v0.spare[1] = 0;
+ branch(header->v0.start_vector, entry);
+ } else {
+ header->v1.header_length[0] = (sizeof(*header) >> 0) & 0xff;
+ header->v1.header_length[1] = (sizeof(*header) >> 8) & 0xff;
+ header->v1.program_length[0] = (size >> 0) & 0xff;
+ header->v1.program_length[1] = (size >> 8) & 0xff;
+ header->v1.program_length[2] = (size >> 16) & 0xff;
+ header->v1.program_length[3] = (size >> 24) & 0xff;
+ header->v1.entry_offset[0] = (start_addr >> 0) & 0xff;
+ header->v1.entry_offset[1] = (start_addr >> 8) & 0xff;
+ header->v1.entry_offset[2] = (start_addr >> 16) & 0xff;
+ header->v1.entry_offset[3] = (start_addr >> 24) & 0xff;
+ header->v1.spare[0] = 0;
+ header->v1.spare[1] = 0;
+ }
/* Sum from beginning of header to start of checksum field */
checksum = 0;
- for (bufp = (uint8_t*)header; bufp < &header->checksum[0]; bufp++)
+ for (bufp = (uint8_t*)header; bufp < sumendp; bufp++)
checksum += *bufp;
- header->checksum[0] = checksum & 0xff;;
- header->checksum[1] = (checksum >> 8) & 0xff;;
+ if (version == 0) {
+ header->v0.checksum[0] = checksum & 0xff;;
+ header->v0.checksum[1] = (checksum >> 8) & 0xff;;
+ } else {
+ header->v1.checksum[0] = checksum & 0xff;;
+ header->v1.checksum[1] = (checksum >> 8) & 0xff;;
+ }
crc = buf + size - sizeof(uint32_t);
@@ -195,7 +256,7 @@ static int add_socfpga_header(void *buf, size_t size, unsigned start_addr)
static void usage(const char *prgname)
{
- fprintf(stderr, "usage: %s [OPTIONS] <infile>\n", prgname);
+ fprintf(stderr, "usage: %s [-hb] [-v version] <infile> -o <outfile>\n", prgname);
}
int main(int argc, char *argv[])
@@ -205,16 +266,23 @@ int main(int argc, char *argv[])
struct stat s;
void *buf;
int fd;
- int min_image_size = 80;
- int max_image_size = MAX_IMAGE_SIZE;
+ int max_image_size, min_image_size = 80;
int addsize = 0, pad;
+ unsigned int version = 0;
- while ((opt = getopt(argc, argv, "o:hb")) != -1) {
+ while ((opt = getopt(argc, argv, "o:hbv:")) != -1) {
switch (opt) {
+ case 'v':
+ version = atoi(optarg);
+ if (version > 1) {
+ printf("Versions supported: 0 or 1\n");
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
case 'b':
add_barebox_header = 1;
min_image_size = 0;
- max_image_size = MAX_IMAGE_SIZE - 512;
addsize = 512;
break;
case 'h':
@@ -224,15 +292,21 @@ int main(int argc, char *argv[])
outfile = optarg;
break;
default:
+ usage(argv[0]);
exit(1);
}
}
+ if (version == 0) {
+ max_image_size = MAX_V0IMAGE_SIZE;
+ } else {
+ max_image_size = MAX_V1IMAGE_SIZE;
+ }
+ max_image_size -= addsize;
- if (optind == argc) {
+ if (optind == argc || !outfile) {
usage(argv[0]);
exit(1);
}
-
infile = argv[optind];
ret = stat(infile, &s);
@@ -242,7 +316,8 @@ int main(int argc, char *argv[])
}
if (s.st_size < min_image_size) {
- fprintf(stderr, "input image too small. Minimum is 80 bytes\n");
+ fprintf(stderr, "input image too small. Minimum is %d bytes\n",
+ min_image_size);
exit(1);
}
@@ -253,7 +328,7 @@ int main(int argc, char *argv[])
}
fd = open(infile, O_RDONLY);
- if (fd < 0) {
+ if (fd == -1) {
perror("open infile");
exit(1);
}
@@ -280,7 +355,8 @@ int main(int argc, char *argv[])
memcpy(buf, bb_header, sizeof(bb_header));
}
- ret = add_socfpga_header(buf, s.st_size + 4 + addsize + pad, addsize);
+ ret = add_socfpga_header(buf, s.st_size + 4 + addsize + pad, addsize,
+ version);
if (ret)
exit(1);