From a2a728c416c8fe03742847415f29f792c778a1f9 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 9 May 2013 11:52:45 +0200 Subject: [PATCH 01/25] scripts: new kwbimage manipulation tool for Marvell SoC boot images The Marvell EBU SoCs (Kirkwood, Armada 370, Armada XP) have a BootROM that understand a specific image format, composed of a main header, several extension headers and a paylod. This image can be booted from NAND, SPI, SATA, UART, NOR, etc. This patch adds a tool that allows to extract the components and configuration of existing images, and to create new images. Signed-off-by: Thomas Petazzoni Tested-by: Gregory CLEMENT Signed-off-by: Sascha Hauer --- scripts/.gitignore | 1 + scripts/Makefile | 1 + scripts/kwbimage.c | 1448 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1450 insertions(+) create mode 100644 scripts/kwbimage.c diff --git a/scripts/.gitignore b/scripts/.gitignore index bff805ddf..a28ea5292 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -2,6 +2,7 @@ bareboxenv bin2c gen_netx_image kallsyms +kwbimage mk-am35xx-spi-image mkimage mkublheader diff --git a/scripts/Makefile b/scripts/Makefile index f062fc011..e0b986842 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -8,6 +8,7 @@ hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-y += bin2c hostprogs-y += mkimage hostprogs-y += bareboxenv +hostprogs-$(CONFIG_ARCH_MVEBU) += kwbimage hostprogs-$(CONFIG_ARCH_NETX) += gen_netx_image hostprogs-$(CONFIG_ARCH_OMAP) += omap_signGP mk-am35xx-spi-image hostprogs-$(CONFIG_ARCH_S5PCxx) += s5p_cksum diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c new file mode 100644 index 000000000..90714aa35 --- /dev/null +++ b/scripts/kwbimage.c @@ -0,0 +1,1448 @@ +/* + * Image manipulator for Kirkwood, Armada 370 and Armada XP platforms. + * + * (C) Copyright 2013 Thomas Petazzoni + * + * + * 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. + * + * This tool allows to extract and create bootable images for Marvell + * Kirkwood, Marvell Armada 370 and Armada XP SoCs. It supports two + * versions of the bootable image format: version 0 (used on Marvell + * Kirkwood) and version 1 (used on Marvell Armada 370/XP). + * + * To extract an image, run: + * ./scripts/kwbimage -x -i -o + * + * In , kwbimage will output 'kwbimage.cfg', the + * configuration file that describes the image, 'payload', which is + * the bootloader code itself, and it may output a 'binary.0' file + * that corresponds to a binary blob (only possible in version 1 + * images). + * + * To create an image, run: + * ./scripts/kwbimage -c -i -o + * + * The given configuration file is in the format of the 'kwbimage.cfg' + * file, and should reference the payload file (generally the + * bootloader code) and optionally a binary blob. + * + * Not implemented: support for the register headers and secure + * headers in v1 images + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1)) + +/* Structure of the main header, version 0 (Kirkwood) */ +struct main_hdr_v0 { + uint8_t blockid; /*0 */ + uint8_t nandeccmode; /*1 */ + uint16_t nandpagesize; /*2-3 */ + uint32_t blocksize; /*4-7 */ + uint32_t rsvd1; /*8-11 */ + uint32_t srcaddr; /*12-15 */ + uint32_t destaddr; /*16-19 */ + uint32_t execaddr; /*20-23 */ + uint8_t satapiomode; /*24 */ + uint8_t rsvd3; /*25 */ + uint16_t ddrinitdelay; /*26-27 */ + uint16_t rsvd2; /*28-29 */ + uint8_t ext; /*30 */ + uint8_t checksum; /*31 */ +}; + +struct ext_hdr_v0_reg { + uint32_t raddr; + uint32_t rdata; +}; + +#define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20)/sizeof(struct ext_hdr_v0_reg)) + +struct ext_hdr_v0 { + uint32_t offset; + uint8_t reserved[0x20 - sizeof(uint32_t)]; + struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT]; + uint8_t reserved2[7]; + uint8_t checksum; +}; + +/* Structure of the main header, version 1 (Armada 370, Armada XP) */ +struct main_hdr_v1 { + uint8_t blockid; /* 0 */ + uint8_t reserved1; /* 1 */ + uint16_t reserved2; /* 2-3 */ + uint32_t blocksize; /* 4-7 */ + uint8_t version; /* 8 */ + uint8_t headersz_msb; /* 9 */ + uint16_t headersz_lsb; /* A-B */ + uint32_t srcaddr; /* C-F */ + uint32_t destaddr; /* 10-13 */ + uint32_t execaddr; /* 14-17 */ + uint8_t reserved3; /* 18 */ + uint8_t nandblocksize; /* 19 */ + uint8_t nandbadblklocation; /* 1A */ + uint8_t reserved4; /* 1B */ + uint16_t reserved5; /* 1C-1D */ + uint8_t ext; /* 1E */ + uint8_t checksum; /* 1F */ +}; + +/* + * Header for the optional headers, version 1 (Armada 370, Armada XP) + */ +struct opt_hdr_v1 { + uint8_t headertype; + uint8_t headersz_msb; + uint16_t headersz_lsb; + char data[0]; +}; + +/* + * Various values for the opt_hdr_v1->headertype field, describing the + * different types of optional headers. The "secure" header contains + * informations related to secure boot (encryption keys, etc.). The + * "binary" header contains ARM binary code to be executed prior to + * executing the main payload (usually the bootloader). This is + * typically used to execute DDR3 training code. The "register" header + * allows to describe a set of (address, value) tuples that are + * generally used to configure the DRAM controller. + */ +#define OPT_HDR_V1_SECURE_TYPE 0x1 +#define OPT_HDR_V1_BINARY_TYPE 0x2 +#define OPT_HDR_V1_REGISTER_TYPE 0x3 + +#define KWBHEADER_V1_SIZE(hdr) \ + (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb) + +struct boot_mode { + unsigned int id; + const char *name; +}; + +struct boot_mode boot_modes[] = { + { 0x4D, "i2c" }, + { 0x5A, "spi" }, + { 0x8B, "nand" }, + { 0x78, "sata" }, + { 0x9C, "pex" }, + { 0x69, "uart" }, + {}, +}; + +struct nand_ecc_mode { + unsigned int id; + const char *name; +}; + +struct nand_ecc_mode nand_ecc_modes[] = { + { 0x00, "default" }, + { 0x01, "hamming" }, + { 0x02, "rs" }, + { 0x03, "disabled" }, + {}, +}; + +/* Used to identify an undefined execution or destination address */ +#define ADDR_INVALID ((uint32_t)-1) + +#define BINARY_MAX_ARGS 8 + +/* In-memory representation of a line of the configuration file */ +struct image_cfg_element { + enum { + IMAGE_CFG_VERSION = 0x1, + IMAGE_CFG_BOOT_FROM, + IMAGE_CFG_DEST_ADDR, + IMAGE_CFG_EXEC_ADDR, + IMAGE_CFG_NAND_BLKSZ, + IMAGE_CFG_NAND_BADBLK_LOCATION, + IMAGE_CFG_BINARY, + IMAGE_CFG_PAYLOAD, + IMAGE_CFG_DATA, + } type; + union { + unsigned int version; + unsigned int bootfrom; + struct { + const char *file; + unsigned int args[BINARY_MAX_ARGS]; + unsigned int nargs; + } binary; + const char *payload; + unsigned int dstaddr; + unsigned int execaddr; + unsigned int nandblksz; + unsigned int nandbadblklocation; + struct ext_hdr_v0_reg regdata; + }; +}; + +#define IMAGE_CFG_ELEMENT_MAX 256 + +/* + * Byte 8 of the image header contains the version number. In the v0 + * header, byte 8 was reserved, and always set to 0. In the v1 header, + * byte 8 has been changed to a proper field, set to 1. + */ +static unsigned int image_version(void *header) +{ + unsigned char *ptr = header; + return ptr[8]; +} + +/* + * Utility functions to manipulate boot mode and ecc modes (convert + * them back and forth between description strings and the + * corresponding numerical identifiers). + */ + +static const char *image_boot_mode_name(unsigned int id) +{ + int i; + for (i = 0; boot_modes[i].name; i++) + if (boot_modes[i].id == id) + return boot_modes[i].name; + return NULL; +} + +unsigned int image_boot_mode_id(const char *boot_mode_name) +{ + int i; + for (i = 0; boot_modes[i].name; i++) + if (!strcmp(boot_modes[i].name, boot_mode_name)) + return boot_modes[i].id; + + return 0; +} + +static const char *image_nand_ecc_mode_name(unsigned int id) +{ + int i; + for (i = 0; nand_ecc_modes[i].name; i++) + if (nand_ecc_modes[i].id == id) + return nand_ecc_modes[i].name; + return NULL; +} + +static struct image_cfg_element * +image_find_option(struct image_cfg_element *image_cfg, + int cfgn, unsigned int optiontype) +{ + int i; + + for (i = 0; i < cfgn; i++) { + if (image_cfg[i].type == optiontype) + return &image_cfg[i]; + } + + return NULL; +} + +/* + * Compute a 8-bit checksum of a memory area. This algorithm follows + * the requirements of the Marvell SoC BootROM specifications. + */ +static uint8_t image_checksum8(void *start, uint32_t len) +{ + uint8_t csum = 0; + uint8_t *p = start; + + /* check len and return zero checksum if invalid */ + if (!len) + return 0; + + do { + csum += *p; + p++; + } while (--len); + + return csum; +} + +static uint32_t image_checksum32 (void *start, uint32_t len) +{ + uint32_t csum = 0; + uint32_t *p = start; + + /* check len and return zero checksum if invalid */ + if (!len) + return 0; + + if (len % sizeof(uint32_t)) { + fprintf (stderr, "Length %d is not in multiple of %zu\n", + len, sizeof(uint32_t)); + return 0; + } + + do { + csum += *p; + p++; + len -= sizeof(uint32_t); + } while (len > 0); + + return csum; +} + +static void usage(const char *prog) +{ + printf("Usage: %s [-c | -x] -i -o \n", prog); + printf(" -c: create a new image\n"); + printf(" -x: extract an existing image\n"); + printf(" -i: input file\n"); + printf(" when used with -c, should point to a kwbimage.cfg file\n"); + printf(" when used with -x, should point to the image to be extracted\n"); + printf(" -o: output file/directory\n"); + printf(" when used with -c, should point to the image file to create\n"); + printf(" when used with -x, should point to a directory when the image will be extracted\n"); + printf(" -v: verbose\n"); + printf(" -h: this help text\n"); + printf(" Options specific to image creation:\n"); + printf(" -p: path to payload image. Overrides the PAYLOAD line from kwbimage.cfg\n"); + printf(" -m: boot media. Overrides the BOOT_FROM line from kwbimage.cfg\n"); + printf(" -d: load address. Overrides the DEST_ADDR line from kwbimage.cfg\n"); + printf(" -e: exec address. Overrides the EXEC_ADDR line from kwbimage.cfg\n"); +} + +static int image_extract_payload(void *payload, size_t sz, const char *output) +{ + char *imageoutname; + FILE *imageout; + int ret; + + ret = asprintf(&imageoutname, "%s/payload", output); + if (ret < 0) { + fprintf(stderr, "Cannot allocate memory\n"); + return -1; + } + + imageout = fopen(imageoutname, "w+"); + if (!imageout) { + fprintf(stderr, "Could not open output file %s\n", + imageoutname); + free(imageoutname); + return -1; + } + + ret = fwrite(payload, sz, 1, imageout); + if (ret != 1) { + fprintf(stderr, "Could not write to open file %s\n", + imageoutname); + fclose(imageout); + free(imageoutname); + return -1; + } + + fclose(imageout); + free(imageoutname); + return 0; +} + +static int image_extract_v0(void *fdimap, const char *output, FILE *focfg) +{ + struct main_hdr_v0 *main_hdr = fdimap; + struct ext_hdr_v0 *ext_hdr; + const char *boot_mode_name; + uint32_t *img_checksum; + size_t payloadsz; + int cksum, i; + + /* + * Verify checksum. When calculating the header, discard the + * last byte of the header, which itself contains the + * checksum. + */ + cksum = image_checksum8(main_hdr, sizeof(struct main_hdr_v0)-1); + if (cksum != main_hdr->checksum) { + fprintf(stderr, + "Invalid main header checksum: 0x%08x vs. 0x%08x\n", + cksum, main_hdr->checksum); + return -1; + } + + boot_mode_name = image_boot_mode_name(main_hdr->blockid); + if (!boot_mode_name) { + fprintf(stderr, "Invalid boot ID: 0x%x\n", + main_hdr->blockid); + return -1; + } + + fprintf(focfg, "VERSION 0\n"); + fprintf(focfg, "BOOT_FROM %s\n", boot_mode_name); + fprintf(focfg, "DESTADDR %08x\n", main_hdr->destaddr); + fprintf(focfg, "EXECADDR %08x\n", main_hdr->execaddr); + + if (!strcmp(boot_mode_name, "nand")) { + const char *nand_ecc_mode = + image_nand_ecc_mode_name(main_hdr->nandeccmode); + fprintf(focfg, "NAND_ECC_MODE %s\n", + nand_ecc_mode); + fprintf(focfg, "NAND_PAGE_SIZE %08x\n", + main_hdr->nandpagesize); + } + + /* No extension header, we're done */ + if (!main_hdr->ext) + return 0; + + ext_hdr = fdimap + sizeof(struct main_hdr_v0); + + for (i = 0; i < EXT_HDR_V0_REG_COUNT; i++) { + if (ext_hdr->rcfg[i].raddr == 0 && + ext_hdr->rcfg[i].rdata == 0) + break; + + fprintf(focfg, "DATA %08x %08x\n", + ext_hdr->rcfg[i].raddr, + ext_hdr->rcfg[i].rdata); + } + + /* The image is concatenated with a 32 bits checksum */ + payloadsz = main_hdr->blocksize - sizeof(uint32_t); + img_checksum = (uint32_t *) (fdimap + main_hdr->srcaddr + payloadsz); + + if (*img_checksum != image_checksum32(fdimap + main_hdr->srcaddr, + payloadsz)) { + fprintf(stderr, "The image checksum does not match\n"); + return -1; + } + + /* Finally, handle the image itself */ + fprintf(focfg, "PAYLOAD %s/payload\n", output); + return image_extract_payload(fdimap + main_hdr->srcaddr, + payloadsz, output); +} + +static int image_extract_binary_hdr_v1(const void *binary, const char *output, + FILE *focfg, int hdrnum, size_t binsz) +{ + char *binaryoutname; + FILE *binaryout; + const unsigned int *args; + unsigned int nargs; + int ret, i; + + args = binary; + nargs = args[0]; + args++; + + ret = asprintf(&binaryoutname, "%s/binary.%d", output, + hdrnum); + if (ret < 0) { + fprintf(stderr, "Couldn't not allocate memory\n"); + return ret; + } + + binaryout = fopen(binaryoutname, "w+"); + if (!binaryout) { + fprintf(stderr, "Couldn't open output file %s\n", + binaryoutname); + free(binaryoutname); + return -1; + } + + ret = fwrite(binary + (nargs + 1) * sizeof(unsigned int), + binsz - (nargs + 1) * sizeof(unsigned int), 1, + binaryout); + if (ret != 1) { + fprintf(stderr, "Could not write to output file %s\n", + binaryoutname); + fclose(binaryout); + free(binaryoutname); + return -1; + } + + fclose(binaryout); + + fprintf(focfg, "BINARY %s", binaryoutname); + for (i = 0; i < nargs; i++) + fprintf(focfg, " %08x", args[i]); + fprintf(focfg, "\n"); + + free(binaryoutname); + + return 0; +} + +static int image_extract_v1(void *fdimap, const char *output, FILE *focfg) +{ + struct main_hdr_v1 *main_hdr = fdimap; + struct opt_hdr_v1 *opt_hdr; + const char *boot_mode_name; + int headersz = KWBHEADER_V1_SIZE(main_hdr); + int hasheaders; + uint8_t cksum; + int opthdrid; + + /* + * Verify the checkum. We have to substract the checksum + * itself, because when the checksum is calculated, the + * checksum field is 0. + */ + cksum = image_checksum8(main_hdr, headersz); + cksum -= main_hdr->checksum; + + if (cksum != main_hdr->checksum) { + fprintf(stderr, + "Invalid main header checksum: 0x%08x vs. 0x%08x\n", + cksum, main_hdr->checksum); + return -1; + } + + /* First, take care of the main header */ + boot_mode_name = image_boot_mode_name(main_hdr->blockid); + if (!boot_mode_name) { + fprintf(stderr, "Invalid boot ID: 0x%x\n", + main_hdr->blockid); + return -1; + } + + fprintf(focfg, "VERSION 1\n"); + fprintf(focfg, "BOOT_FROM %s\n", boot_mode_name); + fprintf(focfg, "DESTADDR %08x\n", main_hdr->destaddr); + fprintf(focfg, "EXECADDR %08x\n", main_hdr->execaddr); + fprintf(focfg, "NAND_BLKSZ %08x\n", + main_hdr->nandblocksize * 64 * 1024); + fprintf(focfg, "NAND_BADBLK_LOCATION %02x\n", + main_hdr->nandbadblklocation); + + hasheaders = main_hdr->ext; + opt_hdr = fdimap + sizeof(struct main_hdr_v1); + opthdrid = 0; + + /* Then, go through all the extension headers */ + while (hasheaders) { + int opthdrsz = KWBHEADER_V1_SIZE(opt_hdr); + + switch (opt_hdr->headertype) { + case OPT_HDR_V1_BINARY_TYPE: + image_extract_binary_hdr_v1(opt_hdr->data, output, + focfg, opthdrid, + opthdrsz - + sizeof(struct opt_hdr_v1)); + break; + case OPT_HDR_V1_SECURE_TYPE: + case OPT_HDR_V1_REGISTER_TYPE: + fprintf(stderr, + "Support for header type 0x%x not implemented\n", + opt_hdr->headertype); + exit(1); + break; + default: + fprintf(stderr, "Invalid header type 0x%x\n", + opt_hdr->headertype); + exit(1); + } + + /* + * The first byte of the last double word of the + * current header indicates whether there is a next + * header or not. + */ + hasheaders = ((char *)opt_hdr)[opthdrsz - 4]; + + /* Move to the next header */ + opt_hdr = ((void *)opt_hdr) + opthdrsz; + opthdrid++; + } + + /* Finally, handle the image itself */ + fprintf(focfg, "PAYLOAD %s/payload\n", output); + return image_extract_payload(fdimap + main_hdr->srcaddr, + main_hdr->blocksize - 4, + output); +} + +static int image_extract(const char *input, const char *output) +{ + int fdi, ret; + struct stat fdistat, fdostat; + void *fdimap; + char *focfgname; + FILE *focfg; + + fdi = open(input, O_RDONLY); + if (fdi < 0) { + fprintf(stderr, "Cannot open input file %s: %m\n", + input); + return -1; + } + + ret = fstat(fdi, &fdistat); + if (ret < 0) { + fprintf(stderr, "Cannot stat input file %s: %m\n", + input); + close(fdi); + return -1; + } + + fdimap = mmap(NULL, fdistat.st_size, PROT_READ, MAP_PRIVATE, fdi, 0); + if (fdimap == MAP_FAILED) { + fprintf(stderr, "Cannot map input file %s: %m\n", + input); + close(fdi); + return -1; + } + + close(fdi); + + ret = stat(output, &fdostat); + if (ret < 0) { + fprintf(stderr, "Cannot stat output directory %s: %m\n", + output); + munmap(fdimap, fdistat.st_size); + return -1; + } + + if (!S_ISDIR(fdostat.st_mode)) { + fprintf(stderr, "Output %s should be a directory\n", + output); + munmap(fdimap, fdistat.st_size); + return -1; + } + + ret = asprintf(&focfgname, "%s/kwbimage.cfg", output); + if (ret < 0) { + fprintf(stderr, "Failed to allocate memory\n"); + munmap(fdimap, fdistat.st_size); + return -1; + } + + focfg = fopen(focfgname, "w+"); + if (!focfg) { + fprintf(stderr, "Output file %s could not be created\n", + focfgname); + free(focfgname); + munmap(fdimap, fdistat.st_size); + return -1; + } + + free(focfgname); + + if (image_version(fdimap) == 0) + ret = image_extract_v0(fdimap, output, focfg); + else if (image_version(fdimap) == 1) + ret = image_extract_v1(fdimap, output, focfg); + else { + fprintf(stderr, "Invalid image version %d\n", + image_version(fdimap)); + ret = -1; + } + + fclose(focfg); + munmap(fdimap, fdistat.st_size); + return ret; +} + +static int image_create_payload(void *payload_start, size_t payloadsz, + const char *payload_filename) +{ + FILE *payload; + uint32_t *payload_checksum = + (uint32_t *) (payload_start + payloadsz); + int ret; + + payload = fopen(payload_filename, "r"); + if (!payload) { + fprintf(stderr, "Cannot open payload file %s\n", + payload_filename); + return -1; + } + + ret = fread(payload_start, payloadsz, 1, payload); + if (ret != 1) { + fprintf(stderr, "Cannot read payload file %s\n", + payload_filename); + return -1; + } + + fclose(payload); + + *payload_checksum = image_checksum32(payload_start, payloadsz); + return 0; +} + +static void *image_create_v0(struct image_cfg_element *image_cfg, + int cfgn, const char *output, size_t *imagesz) +{ + struct image_cfg_element *e, *payloade; + size_t headersz, payloadsz, totalsz; + struct main_hdr_v0 *main_hdr; + struct ext_hdr_v0 *ext_hdr; + void *image; + int has_ext = 0; + int cfgi, ret; + + /* Calculate the size of the header and the size of the + * payload */ + headersz = sizeof(struct main_hdr_v0); + payloadsz = 0; + + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_DATA); + if (e) { + has_ext = 1; + headersz += sizeof(struct ext_hdr_v0); + } + + payloade = image_find_option(image_cfg, cfgn, IMAGE_CFG_PAYLOAD); + if (payloade) { + struct stat s; + int ret; + + ret = stat(payloade->payload, &s); + if (ret < 0) { + fprintf(stderr, "Cannot stat payload file %s\n", + payloade->payload); + return NULL; + } + + payloadsz = s.st_size; + } + + /* Headers, payload and 32-bits checksum */ + totalsz = headersz + payloadsz + sizeof(uint32_t); + + image = malloc(totalsz); + if (!image) { + fprintf(stderr, "Cannot allocate memory for image\n"); + return NULL; + } + + memset(image, 0, totalsz); + + main_hdr = image; + + /* Fill in the main header */ + main_hdr->blocksize = payloadsz + sizeof(uint32_t); + main_hdr->srcaddr = headersz; + main_hdr->ext = has_ext; + for (cfgi = 0; cfgi < cfgn; cfgi++) { + struct image_cfg_element *el = &image_cfg[cfgi]; + if (el->type == IMAGE_CFG_BOOT_FROM) + main_hdr->blockid = el->bootfrom; + else if (el->type == IMAGE_CFG_DEST_ADDR) + main_hdr->destaddr = el->dstaddr; + else if (el->type == IMAGE_CFG_EXEC_ADDR) + main_hdr->execaddr = el->execaddr; + else if (el->type != IMAGE_CFG_VERSION) + break; + } + + main_hdr->checksum = image_checksum8(image, + sizeof(struct main_hdr_v0)); + + /* Generate the ext header */ + if (has_ext) { + int datai = 0; + + ext_hdr = image + sizeof(struct main_hdr_v0); + ext_hdr->offset = 0x40; + + for (; cfgi < cfgn; cfgi++) { + struct image_cfg_element *el = &image_cfg[cfgi]; + if (el->type == IMAGE_CFG_DATA) { + ext_hdr->rcfg[datai].raddr = el->regdata.raddr; + ext_hdr->rcfg[datai].rdata = el->regdata.rdata; + datai++; + } + else if (el->type == IMAGE_CFG_PAYLOAD) + break; + else { + fprintf(stderr, "Invalid element of type %d\n", + el->type); + return NULL; + } + } + + ext_hdr->checksum = image_checksum8(ext_hdr, + sizeof(struct ext_hdr_v0)); + } + + if (payloade) { + ret = image_create_payload(image + headersz, payloadsz, + payloade->payload); + if (ret < 0) + return NULL; + } + + *imagesz = totalsz; + return image; +} + +static void *image_create_v1(struct image_cfg_element *image_cfg, + int cfgn, const char *output, size_t *imagesz) +{ + struct image_cfg_element *e, *payloade; + struct main_hdr_v1 *main_hdr; + size_t headersz, payloadsz, totalsz; + void *image, *cur; + int hasext = 0; + int cfgi, ret; + + /* Calculate the size of the header and the size of the + * payload */ + headersz = sizeof(struct main_hdr_v1); + payloadsz = 0; + + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_BINARY); + if (e) { + struct stat s; + + ret = stat(e->binary.file, &s); + if (ret < 0) { + char *cwd = get_current_dir_name(); + fprintf(stderr, + "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n" + "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n" + "image for your board. See 'kwbimage -x' to extract it from an existing image.\n", + e->binary.file, cwd); + free(cwd); + return NULL; + } + + headersz += s.st_size + + e->binary.nargs * sizeof(unsigned int); + hasext = 1; + } + + payloade = image_find_option(image_cfg, cfgn, IMAGE_CFG_PAYLOAD); + if (payloade) { + struct stat s; + + ret = stat(payloade->payload, &s); + if (ret < 0) { + fprintf(stderr, "Cannot stat payload file %s\n", + payloade->payload); + return NULL; + } + + payloadsz = s.st_size; + } + + /* The payload should be aligned on some reasonable + * boundary */ + headersz = ALIGN_SUP(headersz, 4096); + + /* The total size includes the headers, the payload, and the + * 32 bits checksum at the end of the payload */ + totalsz = headersz + payloadsz + sizeof(uint32_t); + + image = malloc(totalsz); + if (!image) { + fprintf(stderr, "Cannot allocate memory for image\n"); + return NULL; + } + + memset(image, 0, totalsz); + + cur = main_hdr = image; + cur += sizeof(struct main_hdr_v1); + + main_hdr->blocksize = payloadsz + sizeof(uint32_t); + main_hdr->headersz_lsb = headersz & 0xFFFF; + main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16; + main_hdr->srcaddr = headersz; + main_hdr->ext = hasext; + + /* First, take care of filling the main header */ + for (cfgi = 0; cfgi < cfgn; cfgi++) { + struct image_cfg_element *el = &image_cfg[cfgi]; + if (el->type == IMAGE_CFG_VERSION) + main_hdr->version = 1; + else if (el->type == IMAGE_CFG_BOOT_FROM) + main_hdr->blockid = el->bootfrom; + else if (el->type == IMAGE_CFG_DEST_ADDR) + main_hdr->destaddr = el->dstaddr; + else if (el->type == IMAGE_CFG_EXEC_ADDR) + main_hdr->execaddr = el->execaddr; + else if (el->type == IMAGE_CFG_NAND_BLKSZ) + main_hdr->nandblocksize = el->nandblksz / (64 * 1024); + else if (el->type == IMAGE_CFG_NAND_BADBLK_LOCATION) + main_hdr->nandbadblklocation = el->nandbadblklocation; + else + break; + } + + /* Then, fill the extension headers */ + for (; cfgi < cfgn; cfgi++) { + struct image_cfg_element *el = &image_cfg[cfgi]; + + if (el->type == IMAGE_CFG_BINARY) { + struct opt_hdr_v1 *hdr = cur; + unsigned int *args; + size_t binhdrsz; + struct stat s; + int argi; + FILE *bin; + + hdr->headertype = OPT_HDR_V1_BINARY_TYPE; + + bin = fopen(el->binary.file, "r"); + if (!bin) { + fprintf(stderr, "Cannot open binary file %s\n", + el->binary.file); + return NULL; + } + + fstat(fileno(bin), &s); + + binhdrsz = sizeof(struct opt_hdr_v1) + + (el->binary.nargs + 1) * sizeof(unsigned int) + + s.st_size; + hdr->headersz_lsb = binhdrsz & 0xFFFF; + hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; + + cur += sizeof(struct opt_hdr_v1); + + args = cur; + *args = el->binary.nargs; + args++; + for (argi = 0; argi < el->binary.nargs; argi++) + args[argi] = el->binary.args[argi]; + + cur += (el->binary.nargs + 1) * sizeof(unsigned int); + + ret = fread(cur, s.st_size, 1, bin); + if (ret != 1) { + fprintf(stderr, + "Could not read binary image %s\n", + el->binary.file); + return NULL; + } + + fclose(bin); + + cur += s.st_size; + + /* See if we have a next header or not, and if + * so, add the marker indicating that we are + * not the last header */ + if ((cfgi < (cfgn - 1)) && + (image_cfg[cfgi + 1].type != IMAGE_CFG_PAYLOAD)) + *((unsigned char *) cur) = 1; + cur += sizeof(uint32_t); + } else if (el->type == IMAGE_CFG_PAYLOAD) + break; + else { + fprintf(stderr, "Invalid element type %d (cfgi=%d)\n", + el->type, cfgi); + return NULL; + } + } + + /* Calculate and set the header checksum */ + main_hdr->checksum = image_checksum8(main_hdr, headersz); + + if (payloade) { + ret = image_create_payload(image + headersz, payloadsz, + payloade->payload); + if (ret < 0) + return NULL; + } + + *imagesz = totalsz; + return image; +} + +static int image_create_config_parse_oneline(char *line, + struct image_cfg_element *el) +{ + char *keyword, *saveptr; + + keyword = strtok_r(line, " ", &saveptr); + if (!strcmp(keyword, "VERSION")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_VERSION; + el->version = atoi(value); + } else if (!strcmp(keyword, "BOOT_FROM")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_BOOT_FROM; + el->bootfrom = image_boot_mode_id(value); + if (!el->bootfrom) { + fprintf(stderr, + "Invalid boot media '%s'\n", value); + return -1; + } + } else if (!strcmp(keyword, "DESTADDR")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_DEST_ADDR; + el->dstaddr = strtol(value, NULL, 16); + } else if (!strcmp(keyword, "EXECADDR")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_EXEC_ADDR; + el->execaddr = strtol(value, NULL, 16); + } else if (!strcmp(keyword, "NAND_BLKSZ")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_NAND_BLKSZ; + el->nandblksz = strtol(value, NULL, 16); + } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_NAND_BADBLK_LOCATION; + el->nandbadblklocation = + strtol(value, NULL, 16); + } else if (!strcmp(keyword, "BINARY")) { + char *value = strtok_r(NULL, " ", &saveptr); + int argi = 0; + + el->type = IMAGE_CFG_BINARY; + el->binary.file = strdup(value); + while (1) { + value = strtok_r(NULL, " ", &saveptr); + if (!value) + break; + el->binary.args[argi] = strtol(value, NULL, 16); + argi++; + if (argi >= BINARY_MAX_ARGS) { + fprintf(stderr, + "Too many argument for binary\n"); + return -1; + } + } + el->binary.nargs = argi; + } else if (!strcmp(keyword, "DATA")) { + char *value1 = strtok_r(NULL, " ", &saveptr); + char *value2 = strtok_r(NULL, " ", &saveptr); + + if (!value1 || !value2) { + fprintf(stderr, "Invalid number of arguments for DATA\n"); + return -1; + } + + el->type = IMAGE_CFG_DATA; + el->regdata.raddr = strtol(value1, NULL, 16); + el->regdata.rdata = strtol(value2, NULL, 16); + } else if (!strcmp(keyword, "PAYLOAD")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_PAYLOAD; + el->payload = strdup(value); + } else { + fprintf(stderr, "Ignoring unknown line '%s'\n", line); + } + + return 0; +} + +/* + * Parse the configuration file 'fcfg' into the array of configuration + * elements 'image_cfg', and return the number of configuration + * elements in 'cfgn'. + */ +static int image_create_config_parse(FILE *fcfg, + struct image_cfg_element *image_cfg, + int *cfgn) +{ + int ret; + int cfgi = 0; + + /* Parse the configuration file */ + while (!feof(fcfg)) { + char *line; + char buf[256]; + + /* Read the current line */ + memset(buf, 0, sizeof(buf)); + line = fgets(buf, sizeof(buf), fcfg); + if (!line) + break; + + /* Ignore useless lines */ + if (line[0] == '\n' || line[0] == '#') + continue; + + /* Strip final newline */ + if (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = 0; + + /* Parse the current line */ + ret = image_create_config_parse_oneline(line, + &image_cfg[cfgi]); + if (ret) + return ret; + + cfgi++; + + if (cfgi >= IMAGE_CFG_ELEMENT_MAX) { + fprintf(stderr, "Too many configuration elements in .cfg file\n"); + return -1; + } + } + + *cfgn = cfgi; + return 0; +} + +static int image_override_payload(struct image_cfg_element *image_cfg, + int *cfgn, const char *payload) +{ + struct image_cfg_element *e; + int cfgi = *cfgn; + + if (!payload) + return 0; + + e = image_find_option(image_cfg, *cfgn, IMAGE_CFG_PAYLOAD); + if (e) { + e->payload = payload; + return 0; + } + + image_cfg[cfgi].type = IMAGE_CFG_PAYLOAD; + image_cfg[cfgi].payload = payload; + cfgi++; + + *cfgn = cfgi; + return 0; +} + +static int image_override_bootmedia(struct image_cfg_element *image_cfg, + int *cfgn, const char *bootmedia) +{ + struct image_cfg_element *e; + int bootfrom; + int cfgi = *cfgn; + + if (!bootmedia) + return 0; + + bootfrom = image_boot_mode_id(bootmedia); + if (!bootfrom) { + fprintf(stderr, + "Invalid boot media '%s'\n", bootmedia); + return -1; + } + + e = image_find_option(image_cfg, *cfgn, IMAGE_CFG_BOOT_FROM); + if (e) { + e->bootfrom = bootfrom; + return 0; + } + + image_cfg[cfgi].type = IMAGE_CFG_BOOT_FROM; + image_cfg[cfgi].bootfrom = bootfrom; + cfgi++; + + *cfgn = cfgi; + return 0; +} + +static int image_override_dstaddr(struct image_cfg_element *image_cfg, + int *cfgn, uint32_t dstaddr) +{ + struct image_cfg_element *e; + int cfgi = *cfgn; + + if (dstaddr == ADDR_INVALID) + return 0; + + e = image_find_option(image_cfg, *cfgn, IMAGE_CFG_DEST_ADDR); + if (e) { + e->dstaddr = dstaddr; + return 0; + } + + image_cfg[cfgi].type = IMAGE_CFG_DEST_ADDR; + image_cfg[cfgi].dstaddr = dstaddr; + cfgi++; + + *cfgn = cfgi; + return 0; +} + +static int image_override_execaddr(struct image_cfg_element *image_cfg, + int *cfgn, uint32_t execaddr) +{ + struct image_cfg_element *e; + int cfgi = *cfgn; + + if (execaddr == ADDR_INVALID) + return 0; + + e = image_find_option(image_cfg, *cfgn, IMAGE_CFG_EXEC_ADDR); + if (e) { + e->execaddr = execaddr; + return 0; + } + + image_cfg[cfgi].type = IMAGE_CFG_EXEC_ADDR; + image_cfg[cfgi].execaddr = execaddr; + cfgi++; + + *cfgn = cfgi; + return 0; +} + +static int image_get_version(struct image_cfg_element *image_cfg, + int cfgn) +{ + struct image_cfg_element *e; + + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_VERSION); + if (!e) + return -1; + + return e->version; +} + +static void image_dump_config(struct image_cfg_element *image_cfg, + int cfgn) +{ + int cfgi; + + printf("== configuration dump\n"); + + for (cfgi = 0; cfgi < cfgn; cfgi++) { + struct image_cfg_element *e = &image_cfg[cfgi]; + switch (e->type) { + case IMAGE_CFG_VERSION: + printf("VERSION %d\n", e->version); + break; + case IMAGE_CFG_BOOT_FROM: + printf("BOOTFROM %s\n", + image_boot_mode_name(e->bootfrom)); + break; + case IMAGE_CFG_DEST_ADDR: + printf("DESTADDR 0x%x\n", e->dstaddr); + break; + case IMAGE_CFG_EXEC_ADDR: + printf("EXECADDR 0x%x\n", e->execaddr); + break; + case IMAGE_CFG_NAND_BLKSZ: + printf("NANDBLKSZ 0x%x\n", e->nandblksz); + break; + case IMAGE_CFG_NAND_BADBLK_LOCATION: + printf("NANDBADBLK 0x%x\n", e->nandbadblklocation); + break; + case IMAGE_CFG_BINARY: + printf("BINARY %s (%d args)\n", e->binary.file, + e->binary.nargs); + break; + case IMAGE_CFG_PAYLOAD: + printf("PAYLOAD %s\n", e->payload); + break; + case IMAGE_CFG_DATA: + printf("DATA 0x%x 0x%x\n", + e->regdata.raddr, + e->regdata.rdata); + break; + default: + printf("Error, unknown type\n"); + break; + } + } + + printf("== end configuration dump\n"); +} + +static int image_create(const char *input, const char *output, + const char *payload, const char *bootmedia, + uint32_t dstaddr, uint32_t execaddr, + int verbose) +{ + struct image_cfg_element *image_cfg; + FILE *fcfg, *outputimg; + void *image = NULL; + int version; + size_t imagesz; + int cfgn; + int ret; + + fcfg = fopen(input, "r"); + if (!fcfg) { + fprintf(stderr, "Could not open input file %s\n", + input); + return -1; + } + + image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX * + sizeof(struct image_cfg_element)); + if (!image_cfg) { + fprintf(stderr, "Cannot allocate memory\n"); + fclose(fcfg); + return -1; + } + + memset(image_cfg, 0, + IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element)); + rewind(fcfg); + + ret = image_create_config_parse(fcfg, image_cfg, &cfgn); + if (ret) { + free(image_cfg); + return -1; + } + + image_override_payload(image_cfg, &cfgn, payload); + image_override_bootmedia(image_cfg, &cfgn, bootmedia); + image_override_dstaddr(image_cfg, &cfgn, dstaddr); + image_override_execaddr(image_cfg, &cfgn, execaddr); + + if (!image_find_option(image_cfg, cfgn, IMAGE_CFG_BOOT_FROM) || + !image_find_option(image_cfg, cfgn, IMAGE_CFG_DEST_ADDR) || + !image_find_option(image_cfg, cfgn, IMAGE_CFG_EXEC_ADDR)) { + fprintf(stderr, + "Missing information (either boot media, exec addr or dest addr)\n"); + free(image_cfg); + return -1; + } + + if (verbose) + image_dump_config(image_cfg, cfgn); + + version = image_get_version(image_cfg, cfgn); + + if (version == 0) + image = image_create_v0(image_cfg, cfgn, output, &imagesz); + else if (version == 1) + image = image_create_v1(image_cfg, cfgn, output, &imagesz); + else if (version == -1) { + fprintf(stderr, "File %s does not have the VERSION field\n", + input); + free(image_cfg); + return -1; + } + + if (!image) { + fprintf(stderr, "Could not create image\n"); + free(image_cfg); + return -1; + } + + free(image_cfg); + + outputimg = fopen(output, "w"); + if (!outputimg) { + fprintf(stderr, "Cannot open output image %s for writing\n", + output); + free(image); + return -1; + } + + ret = fwrite(image, imagesz, 1, outputimg); + if (ret != 1) { + fprintf(stderr, "Cannot write to output image %s\n", + output); + fclose(outputimg); + free(image); + return -1; + } + + fclose(outputimg); + free(image); + + return 0; +} + +enum { + ACTION_CREATE, + ACTION_EXTRACT, + ACTION_DUMP, + ACTION_HELP, +}; + +int main(int argc, char *argv[]) +{ + int action = -1, opt, verbose = 0; + const char *input = NULL, *output = NULL, + *payload = NULL, *bootmedia = NULL; + uint32_t execaddr = ADDR_INVALID, dstaddr = ADDR_INVALID; + + while ((opt = getopt(argc, argv, "hxci:o:p:m:e:d:v")) != -1) { + switch (opt) { + case 'x': + action = ACTION_EXTRACT; + break; + case 'c': + action = ACTION_CREATE; + break; + case 'i': + input = optarg; + break; + case 'o': + output = optarg; + break; + case 'p': + payload = optarg; + break; + case 'm': + bootmedia = optarg; + break; + case 'e': + execaddr = strtol(optarg, NULL, 0); + break; + case 'd': + dstaddr = strtol(optarg, NULL, 0); + break; + case 'v': + verbose = 1; + break; + case 'h': + action = ACTION_HELP; + break; + } + } + + /* We should have consumed all arguments */ + if (optind != argc) { + usage(argv[0]); + exit(1); + } + + if (action != ACTION_HELP && !input) { + fprintf(stderr, "Missing input file\n"); + usage(argv[0]); + exit(1); + } + + if ((action == ACTION_EXTRACT || action == ACTION_CREATE) && + !output) { + fprintf(stderr, "Missing output file\n"); + usage(argv[0]); + exit(1); + } + + if (action == ACTION_EXTRACT && + (bootmedia || payload || + (execaddr != ADDR_INVALID) || (dstaddr != ADDR_INVALID))) { + fprintf(stderr, + "-m, -p, -e or -d do not make sense when extracting an image"); + usage(argv[0]); + exit(1); + } + + switch (action) { + case ACTION_EXTRACT: + return image_extract(input, output); + case ACTION_CREATE: + return image_create(input, output, payload, + bootmedia, dstaddr, execaddr, + verbose); + case ACTION_HELP: + usage(argv[0]); + return 0; + default: + fprintf(stderr, "No action specified\n"); + usage(argv[0]); + exit(1); + } + + return 0; +} From 0535713bbfa059c1bc20da24d33bb183c4f555dc Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 9 May 2013 11:52:46 +0200 Subject: [PATCH 02/25] scripts: add kwboot tool This tool is used with Marvell EBU SoC to trigger the UART boot mode provided by the SoC BootROM, and push the bootloader image to the target using the Xmodem protocol. It has been taken from the U-Boot source code, with minor modifications to make it work with Armada 370/XP platforms. Signed-off-by: Thomas Petazzoni Tested-by: Gregory CLEMENT Signed-off-by: Sascha Hauer --- scripts/.gitignore | 1 + scripts/Makefile | 2 +- scripts/kwboot.c | 717 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 719 insertions(+), 1 deletion(-) create mode 100644 scripts/kwboot.c diff --git a/scripts/.gitignore b/scripts/.gitignore index a28ea5292..6518c0f07 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -3,6 +3,7 @@ bin2c gen_netx_image kallsyms kwbimage +kwboot mk-am35xx-spi-image mkimage mkublheader diff --git a/scripts/Makefile b/scripts/Makefile index e0b986842..cd0b97692 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -8,7 +8,7 @@ hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-y += bin2c hostprogs-y += mkimage hostprogs-y += bareboxenv -hostprogs-$(CONFIG_ARCH_MVEBU) += kwbimage +hostprogs-$(CONFIG_ARCH_MVEBU) += kwbimage kwboot hostprogs-$(CONFIG_ARCH_NETX) += gen_netx_image hostprogs-$(CONFIG_ARCH_OMAP) += omap_signGP mk-am35xx-spi-image hostprogs-$(CONFIG_ARCH_S5PCxx) += s5p_cksum diff --git a/scripts/kwboot.c b/scripts/kwboot.c new file mode 100644 index 000000000..afc849316 --- /dev/null +++ b/scripts/kwboot.c @@ -0,0 +1,717 @@ +/* + * Boot a Marvell Kirkwood SoC, with Xmodem over UART0. + * + * (c) 2012 Daniel Stodden + * + * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281 + * Integrated Controller: Functional Specifications" December 2, + * 2008. Chapter 24.2 "BootROM Firmware". + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Marvell BootROM UART Sensing + */ + +static unsigned char kwboot_msg_boot[] = { + 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 +}; + +static unsigned char kwboot_msg_debug[] = { + 0xDD, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 +}; + +#define KWBOOT_MSG_REQ_DELAY 1000 /* ms */ +#define KWBOOT_MSG_RSP_TIMEO 1000 /* ms */ + +/* + * Xmodem Transfers + */ + +#define SOH 1 /* sender start of block header */ +#define EOT 4 /* sender end of block transfer */ +#define ACK 6 /* target block ack */ +#define NAK 21 /* target block negative ack */ +#define CAN 24 /* target/sender transfer cancellation */ + +struct kwboot_block { + uint8_t soh; + uint8_t pnum; + uint8_t _pnum; + uint8_t data[128]; + uint8_t csum; +} __attribute((packed)); + +#define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */ + +static int kwboot_verbose; + +static void +kwboot_printv(const char *fmt, ...) +{ + va_list ap; + + if (kwboot_verbose) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + fflush(stdout); + } +} + +static void +__spinner(void) +{ + const char seq[] = { '-', '\\', '|', '/' }; + const int div = 8; + static int state, bs; + + if (state % div == 0) { + fputc(bs, stdout); + fputc(seq[state / div % sizeof(seq)], stdout); + fflush(stdout); + } + + bs = '\b'; + state++; +} + +static void +kwboot_spinner(void) +{ + if (kwboot_verbose) + __spinner(); +} + +static void +__progress(int pct, char c) +{ + const int width = 70; + static const char *nl = ""; + static int pos; + + if (pos % width == 0) + printf("%s%3d %% [", nl, pct); + + fputc(c, stdout); + + nl = "]\n"; + pos++; + + if (pct == 100) { + while (pos++ < width) + fputc(' ', stdout); + fputs(nl, stdout); + } + + fflush(stdout); + +} + +static void +kwboot_progress(int _pct, char c) +{ + static int pct; + + if (_pct != -1) + pct = _pct; + + if (kwboot_verbose) + __progress(pct, c); +} + +static int +kwboot_tty_recv(int fd, void *buf, size_t len, int timeo) +{ + int rc, nfds; + fd_set rfds; + struct timeval tv; + ssize_t n; + + rc = -1; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + tv.tv_sec = 0; + tv.tv_usec = timeo * 1000; + if (tv.tv_usec > 1000000) { + tv.tv_sec += tv.tv_usec / 1000000; + tv.tv_usec %= 1000000; + } + + do { + nfds = select(fd + 1, &rfds, NULL, NULL, &tv); + if (nfds < 0) + goto out; + if (!nfds) { + errno = ETIMEDOUT; + goto out; + } + + n = read(fd, buf, len); + if (n < 0) + goto out; + + buf = (char *)buf + n; + len -= n; + } while (len > 0); + + rc = 0; +out: + return rc; +} + +static int +kwboot_tty_send(int fd, const void *buf, size_t len) +{ + int rc; + ssize_t n; + + rc = -1; + + do { + n = write(fd, buf, len); + if (n < 0) + goto out; + + buf = (char *)buf + n; + len -= n; + } while (len > 0); + + rc = tcdrain(fd); +out: + return rc; +} + +static int +kwboot_tty_send_char(int fd, unsigned char c) +{ + return kwboot_tty_send(fd, &c, 1); +} + +static speed_t +kwboot_tty_speed(int baudrate) +{ + switch (baudrate) { + case 115200: + return B115200; + case 57600: + return B57600; + case 38400: + return B38400; + case 19200: + return B19200; + case 9600: + return B9600; + } + + return -1; +} + +static int +kwboot_open_tty(const char *path, speed_t speed) +{ + int rc, fd; + struct termios tio; + + rc = -1; + + fd = open(path, O_RDWR|O_NOCTTY|O_NDELAY); + if (fd < 0) + goto out; + + memset(&tio, 0, sizeof(tio)); + + tio.c_iflag = 0; + tio.c_cflag = CREAD|CLOCAL|CS8; + + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 10; + + cfsetospeed(&tio, speed); + cfsetispeed(&tio, speed); + + rc = tcsetattr(fd, TCSANOW, &tio); + if (rc) + goto out; + + rc = fd; +out: + if (rc < 0) { + if (fd >= 0) + close(fd); + } + + return rc; +} + +static int +kwboot_bootmsg(int tty, void *msg) +{ + int rc; + char c; + + kwboot_printv("Sending boot message. Please reboot the target..."); + + do { + rc = tcflush(tty, TCIOFLUSH); + if (rc) + break; + + rc = kwboot_tty_send(tty, msg, 8); + if (rc) { + usleep(KWBOOT_MSG_REQ_DELAY * 1000); + continue; + } + + rc = kwboot_tty_recv(tty, &c, 1, KWBOOT_MSG_RSP_TIMEO); + + kwboot_spinner(); + + } while (rc || c != NAK); + + kwboot_printv("\n"); + + return rc; +} + +static int +kwboot_debugmsg(int tty, void *msg) +{ + int rc; + + kwboot_printv("Sending debug message. Please reboot the target..."); + + do { + char buf[16]; + + rc = tcflush(tty, TCIOFLUSH); + if (rc) + break; + + rc = kwboot_tty_send(tty, msg, 8); + if (rc) { + usleep(KWBOOT_MSG_REQ_DELAY * 1000); + continue; + } + + rc = kwboot_tty_recv(tty, buf, 16, KWBOOT_MSG_RSP_TIMEO); + + kwboot_spinner(); + + } while (rc); + + kwboot_printv("\n"); + + return rc; +} + +static int +kwboot_xm_makeblock(struct kwboot_block *block, const void *data, + size_t size, int pnum) +{ + const size_t blksz = sizeof(block->data); + size_t n; + int i; + + block->pnum = pnum; + block->_pnum = ~block->pnum; + + n = size < blksz ? size : blksz; + memcpy(&block->data[0], data, n); + memset(&block->data[n], 0, blksz - n); + + block->csum = 0; + for (i = 0; i < n; i++) + block->csum += block->data[i]; + + return n; +} + +static int +kwboot_xm_sendblock(int fd, struct kwboot_block *block) +{ + int rc, retries; + char c; + + retries = 16; + do { + rc = kwboot_tty_send(fd, block, sizeof(*block)); + if (rc) + break; + + do { + rc = kwboot_tty_recv(fd, &c, 1, KWBOOT_BLK_RSP_TIMEO); + if (rc) + break; + + if (c != ACK && c!= NAK && c != CAN) + printf("%c", c); + + } while (c != ACK && c != NAK && c != CAN); + + if (c != ACK) + kwboot_progress(-1, '+'); + + } while (c == NAK && retries-- > 0); + + rc = -1; + + switch (c) { + case ACK: + rc = 0; + break; + case NAK: + errno = EBADMSG; + break; + case CAN: + errno = ECANCELED; + break; + default: + errno = EPROTO; + break; + } + + return rc; +} + +static int +kwboot_xmodem(int tty, const void *_data, size_t size) +{ + const uint8_t *data = _data; + int rc, pnum, N, err; + + pnum = 1; + N = 0; + + kwboot_printv("Sending boot image...\n"); + + do { + struct kwboot_block block; + int n; + + n = kwboot_xm_makeblock(&block, + data + N, size - N, + pnum++); + if (n < 0) + goto can; + + if (!n) + break; + + rc = kwboot_xm_sendblock(tty, &block); + if (rc) + goto out; + + N += n; + kwboot_progress(N * 100 / size, '.'); + } while (1); + + rc = kwboot_tty_send_char(tty, EOT); + +out: + return rc; + +can: + err = errno; + kwboot_tty_send_char(tty, CAN); + errno = err; + goto out; +} + +static int +kwboot_term_pipe(int in, int out, char *quit, int *s) +{ + ssize_t nin, nout; + char _buf[128], *buf = _buf; + + nin = read(in, buf, sizeof(buf)); + if (nin < 0) + return -1; + + if (quit) { + int i; + + for (i = 0; i < nin; i++) { + if (*buf == quit[*s]) { + (*s)++; + if (!quit[*s]) + return 0; + buf++; + nin--; + } else + while (*s > 0) { + nout = write(out, quit, *s); + if (nout <= 0) + return -1; + (*s) -= nout; + } + } + } + + while (nin > 0) { + nout = write(out, buf, nin); + if (nout <= 0) + return -1; + nin -= nout; + } + + return 0; +} + +static int +kwboot_terminal(int tty) +{ + int rc, in, s; + char *quit = "\34c"; + struct termios otio, tio; + + rc = -1; + + in = STDIN_FILENO; + if (isatty(in)) { + rc = tcgetattr(in, &otio); + if (!rc) { + tio = otio; + cfmakeraw(&tio); + rc = tcsetattr(in, TCSANOW, &tio); + } + if (rc) { + perror("tcsetattr"); + goto out; + } + + kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n", + quit[0]|0100, quit[1]); + } else + in = -1; + + rc = 0; + s = 0; + + do { + fd_set rfds; + int nfds = 0; + + FD_SET(tty, &rfds); + nfds = nfds < tty ? tty : nfds; + + if (in >= 0) { + FD_SET(in, &rfds); + nfds = nfds < in ? in : nfds; + } + + nfds = select(nfds + 1, &rfds, NULL, NULL, NULL); + if (nfds < 0) + break; + + if (FD_ISSET(tty, &rfds)) { + rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL); + if (rc) + break; + } + + if (FD_ISSET(in, &rfds)) { + rc = kwboot_term_pipe(in, tty, quit, &s); + if (rc) + break; + } + } while (quit[s] != 0); + + tcsetattr(in, TCSANOW, &otio); +out: + return rc; +} + +static void * +kwboot_mmap_image(const char *path, size_t *size, int prot) +{ + int rc, fd, flags; + struct stat st; + void *img; + + rc = -1; + fd = -1; + img = NULL; + + fd = open(path, O_RDONLY); + if (fd < 0) + goto out; + + rc = fstat(fd, &st); + if (rc) + goto out; + + flags = (prot & PROT_WRITE) ? MAP_PRIVATE : MAP_SHARED; + + img = mmap(NULL, st.st_size, prot, flags, fd, 0); + if (img == MAP_FAILED) { + img = NULL; + goto out; + } + + rc = 0; + *size = st.st_size; +out: + if (rc && img) { + munmap(img, st.st_size); + img = NULL; + } + if (fd >= 0) + close(fd); + + return img; +} + +static void +kwboot_usage(FILE *stream, char *progname) +{ + fprintf(stream, + "Usage: %s [-d | -b ] [ -p ] [ -t ] " + "[-B ] \n", progname); + fprintf(stream, "\n"); + fprintf(stream, " -b : boot \n"); + fprintf(stream, " -d: enter debug mode\n"); + fprintf(stream, "\n"); + fprintf(stream, " -t: mini terminal\n"); + fprintf(stream, "\n"); + fprintf(stream, " -B : set baud rate\n"); + fprintf(stream, "\n"); +} + +int +main(int argc, char **argv) +{ + const char *ttypath, *imgpath; + int rv, rc, tty, term; + void *bootmsg; + void *debugmsg; + void *img; + size_t size; + speed_t speed; + + rv = 1; + tty = -1; + bootmsg = NULL; + debugmsg = NULL; + imgpath = NULL; + img = NULL; + term = 0; + size = 0; + speed = B115200; + + kwboot_verbose = isatty(STDOUT_FILENO); + + do { + int c = getopt(argc, argv, "hb:dptB:"); + if (c < 0) + break; + + switch (c) { + case 'b': + bootmsg = kwboot_msg_boot; + imgpath = optarg; + break; + + case 'd': + debugmsg = kwboot_msg_debug; + break; + + case 't': + term = 1; + break; + + case 'B': + speed = kwboot_tty_speed(atoi(optarg)); + if (speed == -1) + goto usage; + break; + + case 'h': + rv = 0; + default: + goto usage; + } + } while (1); + + if (!bootmsg && !term && !debugmsg) + goto usage; + + if (argc - optind < 1) + goto usage; + + ttypath = argv[optind++]; + + tty = kwboot_open_tty(ttypath, speed); + if (tty < 0) { + perror(ttypath); + goto out; + } + + if (imgpath) { + img = kwboot_mmap_image(imgpath, &size, PROT_READ); + if (!img) { + perror(imgpath); + goto out; + } + } + + if (debugmsg) { + rc = kwboot_debugmsg(tty, debugmsg); + if (rc) { + perror("debugmsg"); + goto out; + } + } + + if (bootmsg) { + rc = kwboot_bootmsg(tty, bootmsg); + if (rc) { + perror("bootmsg"); + goto out; + } + } + + if (img) { + rc = kwboot_xmodem(tty, img, size); + if (rc) { + perror("xmodem"); + goto out; + } + } + + if (term) { + rc = kwboot_terminal(tty); + if (rc && !(errno == EINTR)) { + perror("terminal"); + goto out; + } + } + + rv = 0; +out: + if (tty >= 0) + close(tty); + + if (img) + munmap(img, size); + + return rv; + +usage: + kwboot_usage(rv ? stderr : stdout, basename(argv[0])); + goto out; +} From b3522a5b80a30c1b91c68bca4321af75c5f68757 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 9 May 2013 11:52:47 +0200 Subject: [PATCH 03/25] arm: initial support for Marvell Armada 370/XP SoCs This commit adds minimal support for the Armada 370 and Armada XP SoCs from Marvell. Signed-off-by: Thomas Petazzoni Tested-by: Gregory CLEMENT Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 8 ++ arch/arm/Makefile | 1 + arch/arm/mach-mvebu/Kconfig | 40 ++++++ arch/arm/mach-mvebu/Makefile | 1 + arch/arm/mach-mvebu/core.c | 142 ++++++++++++++++++++ arch/arm/mach-mvebu/include/mach/debug_ll.h | 40 ++++++ arch/arm/mach-mvebu/include/mach/mvebu.h | 22 +++ drivers/clocksource/Kconfig | 4 + drivers/clocksource/Makefile | 1 + drivers/clocksource/mvebu.c | 90 +++++++++++++ 10 files changed, 349 insertions(+) create mode 100644 arch/arm/mach-mvebu/Kconfig create mode 100644 arch/arm/mach-mvebu/Makefile create mode 100644 arch/arm/mach-mvebu/core.c create mode 100644 arch/arm/mach-mvebu/include/mach/debug_ll.h create mode 100644 arch/arm/mach-mvebu/include/mach/mvebu.h create mode 100644 drivers/clocksource/mvebu.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0a4f82181..a044ab336 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -79,6 +79,13 @@ config ARCH_IMX select WATCHDOG_IMX_RESET_SOURCE select HAS_DEBUG_LL +config ARCH_MVEBU + bool "Marvell EBU platforms" + select COMMON_CLK + select CLOCKSOURCE_MVEBU + select CLKDEV_LOOKUP + select HAS_DEBUG_LL + config ARCH_MXS bool "Freescale i.MX23/28 (mxs) based" select GENERIC_GPIO @@ -161,6 +168,7 @@ source arch/arm/mach-ep93xx/Kconfig source arch/arm/mach-highbank/Kconfig source arch/arm/mach-imx/Kconfig source arch/arm/mach-mxs/Kconfig +source arch/arm/mach-mvebu/Kconfig source arch/arm/mach-netx/Kconfig source arch/arm/mach-nomadik/Kconfig source arch/arm/mach-omap/Kconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index d506b1210..bb4750666 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -58,6 +58,7 @@ machine-$(CONFIG_ARCH_EP93XX) := ep93xx machine-$(CONFIG_ARCH_HIGHBANK) := highbank machine-$(CONFIG_ARCH_IMX) := imx machine-$(CONFIG_ARCH_MXS) := mxs +machine-$(CONFIG_ARCH_MVEBU) := mvebu machine-$(CONFIG_ARCH_NOMADIK) := nomadik machine-$(CONFIG_ARCH_NETX) := netx machine-$(CONFIG_ARCH_OMAP) := omap diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig new file mode 100644 index 000000000..c7afcaed4 --- /dev/null +++ b/arch/arm/mach-mvebu/Kconfig @@ -0,0 +1,40 @@ +if ARCH_MVEBU + +config ARCH_TEXT_BASE + hex + +#config BOARDINFO +# default + +choice + prompt "Marvell EBU Processor" + +config ARCH_ARMADA_370 + bool "Armada 370" + select CPU_V7 + +config ARCH_ARMADA_XP + bool "Armada XP" + select CPU_V7 + +endchoice + +if ARCH_ARMADA_370 + +#choice +# prompt "Armada 370 Board Type" +# +#endchoice + +endif # ARCH_ARMADA_370 + +if ARCH_ARMADA_XP + +#choice +# prompt "Armada XP Board Type" +# +#endchoice + +endif # ARCH_ARMADA_XP + +endif # ARCH_MVEBU diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile new file mode 100644 index 000000000..820eb10ac --- /dev/null +++ b/arch/arm/mach-mvebu/Makefile @@ -0,0 +1 @@ +obj-y += core.o diff --git a/arch/arm/mach-mvebu/core.c b/arch/arm/mach-mvebu/core.c new file mode 100644 index 000000000..f4672a362 --- /dev/null +++ b/arch/arm/mach-mvebu/core.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MVEBU_INT_REGS_BASE (0xd0000000) +#define MVEBU_UART0_BASE (MVEBU_INT_REGS_BASE + 0x12000) +#define MVEBU_SYSCTL_BASE (MVEBU_INT_REGS_BASE + 0x18200) +#define MVEBU_SDRAM_WIN_BASE (MVEBU_INT_REGS_BASE + 0x20180) +#define MVEBU_TIMER_BASE (MVEBU_INT_REGS_BASE + 0x20300) +#define MVEBU_SAR_BASE (MVEBU_INT_REGS_BASE + 0x18230) + +#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) +#define DDR_BASE_CS_HIGH_MASK 0xf +#define DDR_BASE_CS_LOW_MASK 0xff000000 +#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3)) +#define DDR_SIZE_ENABLED (1 << 0) +#define DDR_SIZE_CS_MASK 0x1c +#define DDR_SIZE_CS_SHIFT 2 +#define DDR_SIZE_MASK 0xff000000 + +#define SAR_LOW_REG_OFF 0 +#define SAR_TCLK_FREQ_BIT 20 +#define SAR_HIGH_REG_OFF 0x4 + +static struct clk *tclk; + +static inline void mvebu_memory_find(unsigned long *phys_base, + unsigned long *phys_size) +{ + void __iomem *sdram_win = IOMEM(MVEBU_SDRAM_WIN_BASE); + int cs; + + *phys_base = ~0; + *phys_size = 0; + + for (cs = 0; cs < 4; cs++) { + uint32_t base = readl(sdram_win + DDR_BASE_CS_OFF(cs)); + uint32_t ctrl = readl(sdram_win + DDR_SIZE_CS_OFF(cs)); + + /* Skip non-enabled CS */ + if (! (ctrl & DDR_SIZE_ENABLED)) + continue; + + base &= DDR_BASE_CS_LOW_MASK; + if (base < *phys_base) + *phys_base = base; + *phys_size += (ctrl | ~DDR_SIZE_MASK) + 1; + } +} + +void __naked __noreturn mvebu_barebox_entry(void) +{ + unsigned long phys_base, phys_size; + mvebu_memory_find(&phys_base, &phys_size); + barebox_arm_entry(phys_base, phys_size, 0); +} + +static struct NS16550_plat uart0_plat = { + .shift = 2, +}; + +int mvebu_add_uart0(void) +{ + uart0_plat.clock = clk_get_rate(tclk); + add_ns16550_device(DEVICE_ID_DYNAMIC, MVEBU_UART0_BASE, 32, + IORESOURCE_MEM_32BIT, &uart0_plat); + return 0; +} + +#if defined(CONFIG_ARCH_ARMADA_370) +static int mvebu_init_clocks(void) +{ + uint32_t val; + unsigned int rate; + void __iomem *sar = IOMEM(MVEBU_SAR_BASE) + SAR_LOW_REG_OFF; + + val = readl(sar); + + /* On Armada 370, the TCLK frequency can be either 166 Mhz or + * 200 Mhz */ + if (val & (1 << SAR_TCLK_FREQ_BIT)) + rate = 200 * 1000 * 1000; + else + rate = 166 * 1000 * 1000; + + tclk = clk_fixed("tclk", rate); + return clk_register_clkdev(tclk, NULL, "mvebu-timer"); +} +#endif + +#if defined(CONFIG_ARCH_ARMADA_XP) +static int mvebu_init_clocks(void) +{ + /* On Armada XP, the TCLK frequency is always 250 Mhz */ + tclk = clk_fixed("tclk", 250 * 1000 * 1000); + return clk_register_clkdev(tclk, NULL, "mvebu-timer"); +} +#endif + +static int mvebu_init_soc(void) +{ + unsigned long phys_base, phys_size; + + mvebu_init_clocks(); + add_generic_device("mvebu-timer", DEVICE_ID_SINGLE, NULL, + MVEBU_TIMER_BASE, 0x30, IORESOURCE_MEM, + NULL); + mvebu_memory_find(&phys_base, &phys_size); + arm_add_mem_device("ram0", phys_base, phys_size); + return 0; +} + +postcore_initcall(mvebu_init_soc); + +void __noreturn reset_cpu(unsigned long addr) +{ + writel(0x1, MVEBU_SYSCTL_BASE + 0x60); + writel(0x1, MVEBU_SYSCTL_BASE + 0x64); + while (1) + ; +} +EXPORT_SYMBOL(reset_cpu); diff --git a/arch/arm/mach-mvebu/include/mach/debug_ll.h b/arch/arm/mach-mvebu/include/mach/debug_ll.h new file mode 100644 index 000000000..265357391 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/debug_ll.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#ifndef __MACH_DEBUG_LL_H__ +#define __MACH_DEBUG_LL_H__ + +#include + +#define UART_BASE 0xd0012000 +#define UART_THR 0x0 +#define UART_LSR 0x14 +#define UART_LSR_THRE (1 << 5) + +static inline void PUTC_LL(char c) +{ + /* Wait until there is space in the FIFO */ + while (!(readl(UART_BASE + UART_LSR) & UART_LSR_THRE)) + ; + + /* Send the character */ + writel(c, UART_BASE + UART_THR) + ; + + /* Wait to make sure it hits the line, in case we die too soon. */ + while (!(readl(UART_BASE + UART_LSR) & UART_LSR_THRE)) + ; +} +#endif diff --git a/arch/arm/mach-mvebu/include/mach/mvebu.h b/arch/arm/mach-mvebu/include/mach/mvebu.h new file mode 100644 index 000000000..e13a446fc --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/mvebu.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#ifndef __MACH_MVEBU_H +#define __MACH_MVEBU_H + +int mvebu_add_uart0(void); +void __naked __noreturn mvebu_barebox_entry(void); + +#endif /* __MACH_MVEBU_H */ diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 9f3558b6e..dfc89ddea 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -14,6 +14,10 @@ config CLOCKSOURCE_CLPS711X bool depends on ARCH_CLPS711X +config CLOCKSOURCE_MVEBU + bool + depends on ARCH_MVEBU + config CLOCKSOURCE_NOMADIK bool depends on ARM diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index d919881fb..0b42ce48d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_AMBA_SP804) += amba-sp804.o obj-$(CONFIG_ARM_SMP_TWD) += arm_smp_twd.o obj-$(CONFIG_CLOCKSOURCE_BCM2835) += bcm2835.o obj-$(CONFIG_CLOCKSOURCE_CLPS711X) += clps711x.o +obj-$(CONFIG_CLOCKSOURCE_MVEBU) += mvebu.o obj-$(CONFIG_CLOCKSOURCE_NOMADIK) += nomadik.o diff --git a/drivers/clocksource/mvebu.c b/drivers/clocksource/mvebu.c new file mode 100644 index 000000000..2b48a5c91 --- /dev/null +++ b/drivers/clocksource/mvebu.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#define TIMER_CTRL_OFF 0x0000 +#define TIMER0_EN 0x0001 +#define TIMER0_RELOAD_EN 0x0002 +#define TIMER0_25MHZ 0x0800 +#define TIMER0_DIV(div) ((div) << 19) +#define TIMER1_EN 0x0004 +#define TIMER1_RELOAD_EN 0x0008 +#define TIMER1_25MHZ 0x1000 +#define TIMER1_DIV(div) ((div) << 22) +#define TIMER_EVENTS_STATUS 0x0004 +#define TIMER0_CLR_MASK (~0x1) +#define TIMER1_CLR_MASK (~0x100) +#define TIMER0_RELOAD_OFF 0x0010 +#define TIMER0_VAL_OFF 0x0014 +#define TIMER1_RELOAD_OFF 0x0018 +#define TIMER1_VAL_OFF 0x001c + +#define TIMER_DIVIDER_SHIFT 5 + +static __iomem void *timer_base; + +uint64_t mvebu_clocksource_read(void) +{ + return __raw_readl(timer_base + TIMER0_VAL_OFF); +} + +static struct clocksource cs = { + .read = mvebu_clocksource_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 10, +}; + +static int mvebu_timer_probe(struct device_d *dev) +{ + struct clk *tclk; + u32 val; + + timer_base = dev_request_mem_region(dev, 0); + + tclk = clk_get(dev, "tclk"); + + val = __raw_readl(timer_base + TIMER_CTRL_OFF); + val &= ~TIMER0_25MHZ; + __raw_writel(val, timer_base + TIMER_CTRL_OFF); + + __raw_writel(0xffffffff, timer_base + TIMER0_VAL_OFF); + __raw_writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); + + val = __raw_readl(timer_base + TIMER_CTRL_OFF); + val |= TIMER0_EN | TIMER0_RELOAD_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT); + __raw_writel(val, timer_base + TIMER_CTRL_OFF); + + cs.mult = clocksource_hz2mult(clk_get_rate(tclk), cs.shift); + + init_clock(&cs); + + return 0; +} + +static struct driver_d mvebu_timer_driver = { + .name = "mvebu-timer", + .probe = mvebu_timer_probe, +}; + +static int mvebu_timer_init(void) +{ + return platform_driver_register(&mvebu_timer_driver); +} +postcore_initcall(mvebu_timer_init); From 6bb3a08cd3864f3ee1b9f4becf26b55ac9c0a524 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 9 May 2013 11:52:48 +0200 Subject: [PATCH 04/25] arm: integrate kwbimage in the image generation When a ARCH_MVEBU platform is selected, generate barebox.kwb and barebox.kwbuart images from barebox.bin, using kwbimage. barebox.kwb is generated by executing kwbimage on the board kwbimage.cfg file, and is therefore designed to be booted from the default boot media of the board, as defined by kwbimage.cfg (typically a NAND flash or SPI flash). barebox.kwbuart is generated by executing kwbimage on the board kwbimage.cfg file, but by overriding the boot media to be UART. This image is suitable for usage with the kwbtool and is generally useful for recovery purposes. Signed-off-by: Thomas Petazzoni Tested-by: Gregory CLEMENT Signed-off-by: Sascha Hauer Squashed this fixup: arm: ensure the build doesn't fail when kwbimage lacks the binary blob mach-mvebu images for Armada 370 and Armada XP SoC require a DDR3 training code which should be extracted from existing bootable images for the relevant board. When such binary blob has not been extracted, the build of the .kwb and .kwbuart images will fail. This is annoying as it makes the build of all Armada 370/XP defconfig fail, which can be a problem for automated builds. This proposal makes the failure of kwbimage not a fatal failure for the build process, and shows a warning. The user therefore sees: ==================================================================== KWB barebox.kwb Didn't find the file 'plathome-openblocks-ax3-binary.0' in '/home/thomas/projets/barebox' which is mandatory to generate the image This file generally contains the DDR3 training code, and should be extracted from an existing bootable image for your board. See 'kwbimage -x' to extract it from an existing image. Could not create image WARNING: Couldn't create KWB image due to previous errors. KWBUART barebox.kwbuart Didn't find the file 'plathome-openblocks-ax3-binary.0' in '/home/thomas/projets/barebox' which is mandatory to generate the image This file generally contains the DDR3 training code, and should be extracted from an existing bootable image for your board. See 'kwbimage -x' to extract it from an existing image. Could not create image WARNING Couldn't create KWB image due to previous errors. ==================================================================== The only drawback is that barebox-flash-image, which normally points to barebox.kwb, becomes a stale symbolic link. Signed-off-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- Makefile | 2 +- arch/arm/Makefile | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f91999381..9fcdd7837 100644 --- a/Makefile +++ b/Makefile @@ -970,7 +970,7 @@ CLEAN_FILES += barebox System.map include/generated/barebox_default_env.h \ .tmp_kallsyms* common/barebox_default_env* barebox.ldr \ scripts/bareboxenv-target barebox-flash-image \ Doxyfile.version barebox.srec barebox.s5p barebox.ubl \ - barebox.uimage barebox.spi + barebox.uimage barebox.spi barebox.kwb barebox.kwbuart # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include2 usr/include diff --git a/arch/arm/Makefile b/arch/arm/Makefile index bb4750666..dd1f5578a 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -263,6 +263,28 @@ KBUILD_TARGET := barebox.zynq KBUILD_IMAGE := barebox.zynq endif +KWBIMAGE_OPTS = \ + -c -i $(srctree)/$(BOARD)/kwbimage.cfg -d $(TEXT_BASE) -e $(TEXT_BASE) + +quiet_cmd_kwbimage = KWB $@ + cmd_kwbimage = scripts/kwbimage -p $< $(KWBIMAGE_OPTS) -o $@ || \ + echo "WARNING: Couldn't create KWB image due to previous errors." + +quiet_cmd_kwbimage_uart = KWBUART $@ + cmd_kwbimage_uart = scripts/kwbimage -m uart -p $< $(KWBIMAGE_OPTS) -o $@ || \ + echo "WARNING Couldn't create KWB image due to previous errors." + +barebox.kwb: $(KBUILD_BINARY) FORCE + $(call if_changed,kwbimage) + +barebox.kwbuart: $(KBUILD_BINARY) FORCE + $(call if_changed,kwbimage_uart) + +ifeq ($(CONFIG_ARCH_MVEBU),y) +KBUILD_TARGET := barebox.kwb barebox.kwbuart +KBUILD_IMAGE := barebox.kwb barebox.kwbuart +endif + pbl := arch/arm/pbl zbarebox.S zbarebox.bin zbarebox: barebox.bin $(Q)$(MAKE) $(build)=$(pbl) $(pbl)/$@ From af4086fbc30bef696b0866e73f9bc877c461df2b Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 9 May 2013 11:52:49 +0200 Subject: [PATCH 05/25] arm: add basic support for Armada XP OpenBlocks AX3 platform The OpenBlocks AX3 platform is manufactured by PlatHome and uses the MV78260 dual-core SoC from the Armada XP family. Signed-off-by: Thomas Petazzoni Tested-by: Gregory CLEMENT Signed-off-by: Sascha Hauer --- arch/arm/Makefile | 1 + .../boards/plathome-openblocks-ax3/Makefile | 2 ++ .../boards/plathome-openblocks-ax3/config.h | 4 +++ .../plathome-openblocks-ax3/kwbimage.cfg | 3 +++ .../boards/plathome-openblocks-ax3/lowlevel.c | 25 +++++++++++++++++++ .../plathome-openblocks-ax3.c | 25 +++++++++++++++++++ .../configs/plathome_openblocks_ax3_defconfig | 9 +++++++ arch/arm/mach-mvebu/Kconfig | 16 +++++++----- 8 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 arch/arm/boards/plathome-openblocks-ax3/Makefile create mode 100644 arch/arm/boards/plathome-openblocks-ax3/config.h create mode 100644 arch/arm/boards/plathome-openblocks-ax3/kwbimage.cfg create mode 100644 arch/arm/boards/plathome-openblocks-ax3/lowlevel.c create mode 100644 arch/arm/boards/plathome-openblocks-ax3/plathome-openblocks-ax3.c create mode 100644 arch/arm/configs/plathome_openblocks_ax3_defconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index dd1f5578a..3c0814851 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -143,6 +143,7 @@ board-$(CONFIG_MACH_GUF_CUPID) := guf-cupid board-$(CONFIG_MACH_MINI2440) := friendlyarm-mini2440 board-$(CONFIG_MACH_MINI6410) := friendlyarm-mini6410 board-$(CONFIG_MACH_TINY6410) := friendlyarm-tiny6410 +board-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_AX3) := plathome-openblocks-ax3 board-$(CONFIG_MACH_QIL_A9260) := qil-a9260 board-$(CONFIG_MACH_TNY_A9260) := tny-a926x board-$(CONFIG_MACH_TNY_A9263) := tny-a926x diff --git a/arch/arm/boards/plathome-openblocks-ax3/Makefile b/arch/arm/boards/plathome-openblocks-ax3/Makefile new file mode 100644 index 000000000..91dc76465 --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-ax3/Makefile @@ -0,0 +1,2 @@ +obj-y = plathome-openblocks-ax3.o +lwl-y += lowlevel.o diff --git a/arch/arm/boards/plathome-openblocks-ax3/config.h b/arch/arm/boards/plathome-openblocks-ax3/config.h new file mode 100644 index 000000000..ca1513681 --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-ax3/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/plathome-openblocks-ax3/kwbimage.cfg b/arch/arm/boards/plathome-openblocks-ax3/kwbimage.cfg new file mode 100644 index 000000000..69fd1fd1c --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-ax3/kwbimage.cfg @@ -0,0 +1,3 @@ +VERSION 1 +BOOT_FROM spi +BINARY plathome-openblocks-ax3-binary.0 0000005b 00000068 diff --git a/arch/arm/boards/plathome-openblocks-ax3/lowlevel.c b/arch/arm/boards/plathome-openblocks-ax3/lowlevel.c new file mode 100644 index 000000000..e9b2e30cb --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-ax3/lowlevel.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include + +void __naked barebox_arm_reset_vector(void) +{ + arm_cpu_lowlevel_init(); + mvebu_barebox_entry(); +} diff --git a/arch/arm/boards/plathome-openblocks-ax3/plathome-openblocks-ax3.c b/arch/arm/boards/plathome-openblocks-ax3/plathome-openblocks-ax3.c new file mode 100644 index 000000000..9daf020a0 --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-ax3/plathome-openblocks-ax3.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include + +static int plathome_openblocks_ax3_console_init(void) +{ + return mvebu_add_uart0(); +} + +console_initcall(plathome_openblocks_ax3_console_init); diff --git a/arch/arm/configs/plathome_openblocks_ax3_defconfig b/arch/arm/configs/plathome_openblocks_ax3_defconfig new file mode 100644 index 000000000..95449c974 --- /dev/null +++ b/arch/arm/configs/plathome_openblocks_ax3_defconfig @@ -0,0 +1,9 @@ +CONFIG_ARCH_MVEBU=y +CONFIG_ARCH_ARMADA_XP=y +CONFIG_AEABI=y +CONFIG_DEBUG_LL=y +CONFIG_CMD_LOADY=y +CONFIG_CMD_LOADS=y +CONFIG_CMD_RESET=y +CONFIG_CMD_CLK=y +CONFIG_DRIVER_SERIAL_NS16550=y diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index c7afcaed4..975ea7e33 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -2,9 +2,10 @@ if ARCH_MVEBU config ARCH_TEXT_BASE hex + default 0x2000000 if MACH_PLATHOME_OPENBLOCKS_AX3 -#config BOARDINFO -# default +config BOARDINFO + default "PlatHome OpenBlocks AX3" if MACH_PLATHOME_OPENBLOCKS_AX3 choice prompt "Marvell EBU Processor" @@ -30,10 +31,13 @@ endif # ARCH_ARMADA_370 if ARCH_ARMADA_XP -#choice -# prompt "Armada XP Board Type" -# -#endchoice +choice + prompt "Armada XP Board Type" + +config MACH_PLATHOME_OPENBLOCKS_AX3 + bool "PlatHome OpenBlocks AX3" + +endchoice endif # ARCH_ARMADA_XP From 1d0f6f036336e73490b7f5d87227a5ae1832e780 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 9 May 2013 11:52:50 +0200 Subject: [PATCH 06/25] arm: add basic support for the Armada 370 Mirabox platform The Mirabox is a platform manufactured by Globalscale, and based on the Marvell Armada 370 SoC. Signed-off-by: Thomas Petazzoni Tested-by: Gregory CLEMENT Signed-off-by: Sascha Hauer --- arch/arm/Makefile | 1 + arch/arm/boards/globalscale-mirabox/Makefile | 2 ++ arch/arm/boards/globalscale-mirabox/config.h | 4 +++ .../globalscale-mirabox/globalscale-mirabox.c | 26 +++++++++++++++++++ .../boards/globalscale-mirabox/kwbimage.cfg | 5 ++++ .../arm/boards/globalscale-mirabox/lowlevel.c | 26 +++++++++++++++++++ .../arm/configs/globalscale_mirabox_defconfig | 8 ++++++ arch/arm/mach-mvebu/Kconfig | 13 +++++++--- 8 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 arch/arm/boards/globalscale-mirabox/Makefile create mode 100644 arch/arm/boards/globalscale-mirabox/config.h create mode 100644 arch/arm/boards/globalscale-mirabox/globalscale-mirabox.c create mode 100644 arch/arm/boards/globalscale-mirabox/kwbimage.cfg create mode 100644 arch/arm/boards/globalscale-mirabox/lowlevel.c create mode 100644 arch/arm/configs/globalscale_mirabox_defconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 3c0814851..2456f3de1 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -102,6 +102,7 @@ board-$(CONFIG_MACH_EUKREA_CPUIMX51SD) := eukrea_cpuimx51 board-$(CONFIG_MACH_FREESCALE_MX25_3STACK) := freescale-mx25-3-stack board-$(CONFIG_MACH_FREESCALE_MX35_3STACK) := freescale-mx35-3-stack board-$(CONFIG_MACH_GE863) := telit-evk-pro3 +board-$(CONFIG_MACH_GLOBALSCALE_MIRABOX) := globalscale-mirabox board-$(CONFIG_MACH_HIGHBANK) := highbank board-$(CONFIG_MACH_IMX21ADS) := imx21ads board-$(CONFIG_MACH_IMX27ADS) := imx27ads diff --git a/arch/arm/boards/globalscale-mirabox/Makefile b/arch/arm/boards/globalscale-mirabox/Makefile new file mode 100644 index 000000000..bd5d47e3c --- /dev/null +++ b/arch/arm/boards/globalscale-mirabox/Makefile @@ -0,0 +1,2 @@ +obj-y = globalscale-mirabox.o +lwl-y += lowlevel.o diff --git a/arch/arm/boards/globalscale-mirabox/config.h b/arch/arm/boards/globalscale-mirabox/config.h new file mode 100644 index 000000000..ca1513681 --- /dev/null +++ b/arch/arm/boards/globalscale-mirabox/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/globalscale-mirabox/globalscale-mirabox.c b/arch/arm/boards/globalscale-mirabox/globalscale-mirabox.c new file mode 100644 index 000000000..b8f4bffdd --- /dev/null +++ b/arch/arm/boards/globalscale-mirabox/globalscale-mirabox.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include + +static int globalscale_mirabox_console_init(void) +{ + return mvebu_add_uart0(); +} + +console_initcall(globalscale_mirabox_console_init); diff --git a/arch/arm/boards/globalscale-mirabox/kwbimage.cfg b/arch/arm/boards/globalscale-mirabox/kwbimage.cfg new file mode 100644 index 000000000..72283d9b6 --- /dev/null +++ b/arch/arm/boards/globalscale-mirabox/kwbimage.cfg @@ -0,0 +1,5 @@ +VERSION 1 +BOOT_FROM nand +NAND_BLKSZ 00020000 +NAND_BADBLK_LOCATION 01 +BINARY globalscale-mirabox-binary.0 0000005b 00000068 diff --git a/arch/arm/boards/globalscale-mirabox/lowlevel.c b/arch/arm/boards/globalscale-mirabox/lowlevel.c new file mode 100644 index 000000000..3ca202e0a --- /dev/null +++ b/arch/arm/boards/globalscale-mirabox/lowlevel.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +void __naked barebox_arm_reset_vector(void) +{ + arm_cpu_lowlevel_init(); + mvebu_barebox_entry(); +} diff --git a/arch/arm/configs/globalscale_mirabox_defconfig b/arch/arm/configs/globalscale_mirabox_defconfig new file mode 100644 index 000000000..ed9d94d86 --- /dev/null +++ b/arch/arm/configs/globalscale_mirabox_defconfig @@ -0,0 +1,8 @@ +CONFIG_ARCH_MVEBU=y +CONFIG_AEABI=y +CONFIG_DEBUG_LL=y +CONFIG_CMD_LOADY=y +CONFIG_CMD_LOADS=y +CONFIG_CMD_RESET=y +CONFIG_CMD_CLK=y +CONFIG_DRIVER_SERIAL_NS16550=y diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 975ea7e33..84893352d 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -3,9 +3,11 @@ if ARCH_MVEBU config ARCH_TEXT_BASE hex default 0x2000000 if MACH_PLATHOME_OPENBLOCKS_AX3 + default 0x2000000 if MACH_GLOBALSCALE_MIRABOX config BOARDINFO default "PlatHome OpenBlocks AX3" if MACH_PLATHOME_OPENBLOCKS_AX3 + default "Globalscale Mirabox" if MACH_GLOBALSCALE_MIRABOX choice prompt "Marvell EBU Processor" @@ -22,10 +24,13 @@ endchoice if ARCH_ARMADA_370 -#choice -# prompt "Armada 370 Board Type" -# -#endchoice +choice + prompt "Armada 370 Board Type" + +config MACH_GLOBALSCALE_MIRABOX + bool "Globalscale Mirabox" + +endchoice endif # ARCH_ARMADA_370 From 40ee51a48d9e8756730af705119f58a001a61012 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 9 May 2013 11:52:51 +0200 Subject: [PATCH 07/25] arm: add basic support for the Armada XP GP platform The Armada XP GP platform is an evaluation platform designed by Marvell, that uses the MV78460 quad-core SoC from the Armada XP family. Signed-off-by: Thomas Petazzoni Tested-by: Gregory CLEMENT Signed-off-by: Sascha Hauer --- arch/arm/Makefile | 1 + arch/arm/boards/marvell-armada-xp-gp/Makefile | 2 ++ arch/arm/boards/marvell-armada-xp-gp/config.h | 4 +++ .../boards/marvell-armada-xp-gp/kwbimage.cfg | 3 +++ .../boards/marvell-armada-xp-gp/lowlevel.c | 25 +++++++++++++++++++ .../marvell-armada-xp-gp.c | 25 +++++++++++++++++++ .../configs/marvell_armada_xp_gp_defconfig | 10 ++++++++ arch/arm/mach-mvebu/Kconfig | 5 ++++ 8 files changed, 75 insertions(+) create mode 100644 arch/arm/boards/marvell-armada-xp-gp/Makefile create mode 100644 arch/arm/boards/marvell-armada-xp-gp/config.h create mode 100644 arch/arm/boards/marvell-armada-xp-gp/kwbimage.cfg create mode 100644 arch/arm/boards/marvell-armada-xp-gp/lowlevel.c create mode 100644 arch/arm/boards/marvell-armada-xp-gp/marvell-armada-xp-gp.c create mode 100644 arch/arm/configs/marvell_armada_xp_gp_defconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 2456f3de1..af8294d0f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -107,6 +107,7 @@ board-$(CONFIG_MACH_HIGHBANK) := highbank board-$(CONFIG_MACH_IMX21ADS) := imx21ads board-$(CONFIG_MACH_IMX27ADS) := imx27ads board-$(CONFIG_MACH_IMX233_OLINUXINO) := imx233-olinuxino +board-$(CONFIG_MACH_MARVELL_ARMADA_XP_GP) := marvell-armada-xp-gp board-$(CONFIG_MACH_MIOA701) := mioa701 board-$(CONFIG_MACH_MMCCPU) := mmccpu board-$(CONFIG_MACH_NOMADIK_8815NHK) := nhk8815 diff --git a/arch/arm/boards/marvell-armada-xp-gp/Makefile b/arch/arm/boards/marvell-armada-xp-gp/Makefile new file mode 100644 index 000000000..ea899633b --- /dev/null +++ b/arch/arm/boards/marvell-armada-xp-gp/Makefile @@ -0,0 +1,2 @@ +obj-y = marvell-armada-xp-gp.o +lwl-y += lowlevel.o diff --git a/arch/arm/boards/marvell-armada-xp-gp/config.h b/arch/arm/boards/marvell-armada-xp-gp/config.h new file mode 100644 index 000000000..ca1513681 --- /dev/null +++ b/arch/arm/boards/marvell-armada-xp-gp/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/marvell-armada-xp-gp/kwbimage.cfg b/arch/arm/boards/marvell-armada-xp-gp/kwbimage.cfg new file mode 100644 index 000000000..db75969fe --- /dev/null +++ b/arch/arm/boards/marvell-armada-xp-gp/kwbimage.cfg @@ -0,0 +1,3 @@ +VERSION 1 +BOOT_FROM spi +BINARY marvell-armada-xp-gp-binary.0 0000005b 00000068 diff --git a/arch/arm/boards/marvell-armada-xp-gp/lowlevel.c b/arch/arm/boards/marvell-armada-xp-gp/lowlevel.c new file mode 100644 index 000000000..e9b2e30cb --- /dev/null +++ b/arch/arm/boards/marvell-armada-xp-gp/lowlevel.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include + +void __naked barebox_arm_reset_vector(void) +{ + arm_cpu_lowlevel_init(); + mvebu_barebox_entry(); +} diff --git a/arch/arm/boards/marvell-armada-xp-gp/marvell-armada-xp-gp.c b/arch/arm/boards/marvell-armada-xp-gp/marvell-armada-xp-gp.c new file mode 100644 index 000000000..735132947 --- /dev/null +++ b/arch/arm/boards/marvell-armada-xp-gp/marvell-armada-xp-gp.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include + +static int marvell_armada_xp_gp_console_init(void) +{ + return mvebu_add_uart0(); +} + +console_initcall(marvell_armada_xp_gp_console_init); diff --git a/arch/arm/configs/marvell_armada_xp_gp_defconfig b/arch/arm/configs/marvell_armada_xp_gp_defconfig new file mode 100644 index 000000000..5a7ef52b5 --- /dev/null +++ b/arch/arm/configs/marvell_armada_xp_gp_defconfig @@ -0,0 +1,10 @@ +CONFIG_ARCH_MVEBU=y +CONFIG_ARCH_ARMADA_XP=y +CONFIG_MACH_MARVELL_ARMADA_XP_GP=y +CONFIG_AEABI=y +CONFIG_DEBUG_LL=y +CONFIG_CMD_LOADY=y +CONFIG_CMD_LOADS=y +CONFIG_CMD_RESET=y +CONFIG_CMD_CLK=y +CONFIG_DRIVER_SERIAL_NS16550=y diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 84893352d..e553e2dc0 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -4,10 +4,12 @@ config ARCH_TEXT_BASE hex default 0x2000000 if MACH_PLATHOME_OPENBLOCKS_AX3 default 0x2000000 if MACH_GLOBALSCALE_MIRABOX + default 0x2000000 if MACH_MARVELL_ARMADA_XP_GP config BOARDINFO default "PlatHome OpenBlocks AX3" if MACH_PLATHOME_OPENBLOCKS_AX3 default "Globalscale Mirabox" if MACH_GLOBALSCALE_MIRABOX + default "Marvell Armada XP GP" if MACH_MARVELL_ARMADA_XP_GP choice prompt "Marvell EBU Processor" @@ -42,6 +44,9 @@ choice config MACH_PLATHOME_OPENBLOCKS_AX3 bool "PlatHome OpenBlocks AX3" +config MACH_MARVELL_ARMADA_XP_GP + bool "Marvell Armada XP GP" + endchoice endif # ARCH_ARMADA_XP From 52792003d1008c96e28ad201f4a7715cd1e2c7cb Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sun, 12 May 2013 13:59:55 +0200 Subject: [PATCH 08/25] gitignore: add kwb binary images to gitignore file This adds barebox.kwb and barebox.kwbuart to the list of files to be ignored by git. Signed-off-by: Sebastian Hesselbarth Acked-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d1971967f..a08c6c1ec 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,8 @@ barebox.ubl barebox.zynq barebox.uimage barebox.map +barebox.kwb +barebox.kwbuart barebox-flash-image System.map Module.symvers From 2f4fcf15696d56d80a0cf5d52824d9ba06295c03 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sun, 12 May 2013 15:09:02 +0200 Subject: [PATCH 09/25] scripts: kwbimage: add references to Marvell Dove SoC This adds some references to Marvell Dove as it is also supported by kwbimage. Signed-off-by: Sebastian Hesselbarth Acked-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- scripts/kwbimage.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index 90714aa35..14b35e781 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -1,5 +1,6 @@ /* - * Image manipulator for Kirkwood, Armada 370 and Armada XP platforms. + * Image manipulator for Marvell SoCs + * supports Kirkwood, Dove, Armada 370, and Armada XP * * (C) Copyright 2013 Thomas Petazzoni * @@ -15,9 +16,9 @@ * GNU General Public License for more details. * * This tool allows to extract and create bootable images for Marvell - * Kirkwood, Marvell Armada 370 and Armada XP SoCs. It supports two + * Kirkwood, Dove, Armada 370, and Armada XP SoCs. It supports two * versions of the bootable image format: version 0 (used on Marvell - * Kirkwood) and version 1 (used on Marvell Armada 370/XP). + * Kirkwood and Dove) and version 1 (used on Marvell Armada 370/XP). * * To extract an image, run: * ./scripts/kwbimage -x -i -o @@ -53,7 +54,7 @@ #define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1)) -/* Structure of the main header, version 0 (Kirkwood) */ +/* Structure of the main header, version 0 (Kirkwood, Dove) */ struct main_hdr_v0 { uint8_t blockid; /*0 */ uint8_t nandeccmode; /*1 */ From 87f486c7f1878cdd9de45c4e7962e3009092d270 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sun, 12 May 2013 15:09:03 +0200 Subject: [PATCH 10/25] scripts: kwboot: add support for Marvell Dove Marvell Dove SoC also has an UART bootmode to upload payload after powerup. In contrast to Kirkwood and Armada 370/XP, Dove does not respond to a special sequence sent on UART0 but requires to be booted into UART bootmode by bootstraps. This is usually done by pressing a push button that will set bootstraps accordingly. This patch adds a new option, documentation and corresponding prompts to support the above requirements. Also a left-over option ('-p') is removed. Signed-off-by: Sebastian Hesselbarth Acked-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- scripts/kwboot.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/scripts/kwboot.c b/scripts/kwboot.c index afc849316..33c94b3a8 100644 --- a/scripts/kwboot.c +++ b/scripts/kwboot.c @@ -1,5 +1,6 @@ /* - * Boot a Marvell Kirkwood SoC, with Xmodem over UART0. + * Boot a Marvell SoC, with Xmodem over UART0. + * supports Kirkwood, Dove, Armada 370, Armada XP * * (c) 2012 Daniel Stodden * @@ -180,6 +181,9 @@ kwboot_tty_send(int fd, const void *buf, size_t len) int rc; ssize_t n; + if (!buf) + return 0; + rc = -1; do { @@ -264,7 +268,10 @@ kwboot_bootmsg(int tty, void *msg) int rc; char c; - kwboot_printv("Sending boot message. Please reboot the target..."); + if (msg == NULL) + kwboot_printv("Please reboot the target into UART boot mode..."); + else + kwboot_printv("Sending boot message. Please reboot the target..."); do { rc = tcflush(tty, TCIOFLUSH); @@ -580,10 +587,13 @@ static void kwboot_usage(FILE *stream, char *progname) { fprintf(stream, - "Usage: %s [-d | -b ] [ -p ] [ -t ] " - "[-B ] \n", progname); + "Usage: %s [-d | -b | -D ] [ -t ] [-B ] \n", + progname); fprintf(stream, "\n"); - fprintf(stream, " -b : boot \n"); + fprintf(stream, + " -b : boot with preamble (Kirkwood, Armada 370/XP)\n"); + fprintf(stream, + " -D : boot without preamble (Dove)\n"); fprintf(stream, " -d: enter debug mode\n"); fprintf(stream, "\n"); fprintf(stream, " -t: mini terminal\n"); @@ -616,7 +626,7 @@ main(int argc, char **argv) kwboot_verbose = isatty(STDOUT_FILENO); do { - int c = getopt(argc, argv, "hb:dptB:"); + int c = getopt(argc, argv, "hb:dtB:D:"); if (c < 0) break; @@ -626,6 +636,11 @@ main(int argc, char **argv) imgpath = optarg; break; + case 'D': + bootmsg = NULL; + imgpath = optarg; + break; + case 'd': debugmsg = kwboot_msg_debug; break; @@ -675,9 +690,7 @@ main(int argc, char **argv) perror("debugmsg"); goto out; } - } - - if (bootmsg) { + } else { rc = kwboot_bootmsg(tty, bootmsg); if (rc) { perror("bootmsg"); From 98a8c2f28bf93bcdf410bc4e560c4690f9994f93 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sun, 12 May 2013 15:09:04 +0200 Subject: [PATCH 11/25] arm: initial support for Marvell Dove SoCs This commit adds minimal support for the Marvell Dove SoC (88AP510) as first SoC of the Marvell Orion family. Orion SoCs have a different timer, therefore current mach-mvebu and Armada 370/XP Kconfig and Makefiles are slightly modified and a new clocksource drivers is added. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 1 - arch/arm/mach-mvebu/Kconfig | 16 ++ arch/arm/mach-mvebu/Makefile | 4 +- arch/arm/mach-mvebu/dove.c | 161 +++++++++++++++++++ arch/arm/mach-mvebu/include/mach/dove-regs.h | 59 +++++++ arch/arm/mach-mvebu/include/mach/dove.h | 23 +++ drivers/clocksource/Kconfig | 4 + drivers/clocksource/Makefile | 1 + drivers/clocksource/orion.c | 76 +++++++++ 9 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-mvebu/dove.c create mode 100644 arch/arm/mach-mvebu/include/mach/dove-regs.h create mode 100644 arch/arm/mach-mvebu/include/mach/dove.h create mode 100644 drivers/clocksource/orion.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a044ab336..cfb82b051 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -82,7 +82,6 @@ config ARCH_IMX config ARCH_MVEBU bool "Marvell EBU platforms" select COMMON_CLK - select CLOCKSOURCE_MVEBU select CLKDEV_LOOKUP select HAS_DEBUG_LL diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index e553e2dc0..c02eea1c8 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -17,10 +17,17 @@ choice config ARCH_ARMADA_370 bool "Armada 370" select CPU_V7 + select CLOCKSOURCE_MVEBU config ARCH_ARMADA_XP bool "Armada XP" select CPU_V7 + select CLOCKSOURCE_MVEBU + +config ARCH_DOVE + bool "Dove 88AP510" + select CPU_V7 + select CLOCKSOURCE_ORION endchoice @@ -51,4 +58,13 @@ endchoice endif # ARCH_ARMADA_XP +if ARCH_DOVE + +choice + prompt "Dove 88AP510 Board Type" + +endchoice + +endif # ARCH_DOVE + endif # ARCH_MVEBU diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 820eb10ac..0257b732e 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -1 +1,3 @@ -obj-y += core.o +obj-$(CONFIG_ARCH_ARMADA_370) += core.o +obj-$(CONFIG_ARCH_ARMADA_XP) += core.o +obj-$(CONFIG_ARCH_DOVE) += dove.o diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c new file mode 100644 index 000000000..f073596cc --- /dev/null +++ b/arch/arm/mach-mvebu/dove.c @@ -0,0 +1,161 @@ +/* + * Copyright + * (C) 2013 Sebastian Hesselbarth + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct clk *tclk; + +static inline void dove_remap_reg_base(uint32_t intbase, + uint32_t mcbase) +{ + uint32_t val; + + /* remap ahb slave base */ + val = readl(DOVE_CPU_CTRL) & 0xffff0000; + val |= (mcbase & 0xffff0000) >> 16; + writel(val, DOVE_CPU_CTRL); + + /* remap axi bridge address */ + val = readl(DOVE_AXI_CTRL) & 0x007fffff; + val |= mcbase & 0xff800000; + writel(val, DOVE_AXI_CTRL); + + /* remap memory controller base address */ + val = readl(DOVE_SDRAM_BASE + SDRAM_REGS_BASE_DECODE) & 0x0000ffff; + val |= mcbase & 0xffff0000; + writel(val, DOVE_SDRAM_BASE + SDRAM_REGS_BASE_DECODE); + + /* remap internal register */ + val = intbase & 0xfff00000; + writel(val, DOVE_BRIDGE_BASE + INT_REGS_BASE_MAP); +} + +static inline void dove_memory_find(unsigned long *phys_base, + unsigned long *phys_size) +{ + int n; + + *phys_base = ~0; + *phys_size = 0; + + for (n = 0; n < 2; n++) { + uint32_t map = readl(DOVE_SDRAM_BASE + SDRAM_MAPn(n)); + uint32_t base, size; + + /* skip disabled areas */ + if ((map & SDRAM_MAP_VALID) != SDRAM_MAP_VALID) + continue; + + base = map & SDRAM_START_MASK; + if (base < *phys_base) + *phys_base = base; + + /* real size is encoded as ld(2^(16+length)) */ + size = (map & SDRAM_LENGTH_MASK) >> SDRAM_LENGTH_SHIFT; + *phys_size += 1 << (16 + size); + } +} + +void __naked __noreturn dove_barebox_entry(void) +{ + unsigned long phys_base, phys_size; + dove_memory_find(&phys_base, &phys_size); + barebox_arm_entry(phys_base, phys_size, 0); +} + +static struct NS16550_plat uart_plat[] = { + [0] = { .shift = 2, }, + [1] = { .shift = 2, }, + [2] = { .shift = 2, }, + [3] = { .shift = 2, }, +}; + +int dove_add_uart(int num) +{ + struct NS16550_plat *plat; + + if (num < 0 || num > 4) + return -EINVAL; + + plat = &uart_plat[num]; + plat->clock = clk_get_rate(tclk); + if (!add_ns16550_device(DEVICE_ID_DYNAMIC, + (unsigned int)DOVE_UARTn_BASE(num), + 32, IORESOURCE_MEM_32BIT, plat)) + return -ENODEV; + return 0; +} + +/* + * Dove TCLK sample-at-reset configuation + * + * SAR0[24:23] : TCLK frequency + * 0 = 166 MHz + * 1 = 125 MHz + * others reserved. + */ +static int dove_init_clocks(void) +{ + uint32_t strap, sar = readl(DOVE_SAR_BASE + SAR0); + unsigned int rate; + + strap = (sar & TCLK_FREQ_MASK) >> TCLK_FREQ_SHIFT; + switch (strap) { + case 0: + rate = 166666667; + break; + case 1: + rate = 125000000; + break; + default: + panic("Unknown TCLK strapping %d\n", strap); + } + + tclk = clk_fixed("tclk", rate); + return clk_register_clkdev(tclk, NULL, "orion-timer"); +} + +static int dove_init_soc(void) +{ + unsigned long phys_base, phys_size; + + dove_init_clocks(); + add_generic_device("orion-timer", DEVICE_ID_SINGLE, NULL, + (unsigned int)DOVE_TIMER_BASE, 0x30, + IORESOURCE_MEM, NULL); + dove_memory_find(&phys_base, &phys_size); + arm_add_mem_device("ram0", phys_base, phys_size); + return 0; +} +postcore_initcall(dove_init_soc); + +void __noreturn reset_cpu(unsigned long addr) +{ + /* enable and assert RSTOUTn */ + writel(SOFT_RESET_OUT_EN, DOVE_BRIDGE_BASE + BRIDGE_RSTOUT_MASK); + writel(SOFT_RESET_EN, DOVE_BRIDGE_BASE + BRIDGE_SYS_SOFT_RESET); + while (1) + ; +} +EXPORT_SYMBOL(reset_cpu); diff --git a/arch/arm/mach-mvebu/include/mach/dove-regs.h b/arch/arm/mach-mvebu/include/mach/dove-regs.h new file mode 100644 index 000000000..5e203688d --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/dove-regs.h @@ -0,0 +1,59 @@ +/* + * Copyright + * (C) 2013 Sebastian Hesselbarth + * + * 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. + * + */ + +#ifndef __MACH_MVEBU_DOVE_REGS_H +#define __MACH_MVEBU_DOVE_REGS_H + +/* At Boot-up register base is at 0xd000000 */ +#define DOVE_INT_REGS_BOOTUP 0xd0000000 +#define DOVE_MC_REGS_BOOTUP 0xd0800000 +/* Linux wants it remapped to 0xf1000000 */ +#define DOVE_INT_REGS_REMAP 0xf1000000 +#define DOVE_MC_REGS_REMAP 0xf1800000 + +#define DOVE_INT_REGS_BASE IOMEM(DOVE_INT_REGS_BOOTUP) +#define DOVE_MC_REGS_BASE IOMEM(DOVE_MC_REGS_BOOTUP) + +#define DOVE_UART_BASE (DOVE_INT_REGS_BASE + 0x12000) +#define DOVE_UARTn_BASE(n) (DOVE_UART_BASE + ((n) * 0x100)) + +#define DOVE_BRIDGE_BASE (DOVE_INT_REGS_BASE + 0x20000) +#define INT_REGS_BASE_MAP 0x080 +#define BRIDGE_RSTOUT_MASK 0x108 +#define SOFT_RESET_OUT_EN BIT(2) +#define BRIDGE_SYS_SOFT_RESET 0x10c +#define SOFT_RESET_EN BIT(0) +#define DOVE_TIMER_BASE (DOVE_INT_REGS_BASE + 0x20300) + +#define DOVE_SAR_BASE (DOVE_INT_REGS_BASE + 0xd0214) +#define SAR0 0x000 +#define TCLK_FREQ_SHIFT 23 +#define TCLK_FREQ_MASK (0x3 << TCLK_FREQ_SHIFT) +#define SAR1 0x004 + +#define DOVE_AXI_CTRL (DOVE_INT_REGS_BASE + 0xd0224) +#define DOVE_CPU_CTRL (DOVE_INT_REGS_BASE + 0xd025c) + +#define DOVE_SDRAM_BASE (DOVE_MC_REGS_BASE) +#define SDRAM_REGS_BASE_DECODE 0x010 +#define SDRAM_MAPn(n) (0x100 + ((n) * 0x10)) +#define SDRAM_START_MASK (0x1ff << 23) +#define SDRAM_LENGTH_SHIFT 16 +#define SDRAM_LENGTH_MASK (0x00f << SDRAM_LENGTH_SHIFT) +#define SDRAM_ADDRESS_MASK (0x1ff << 7) +#define SDRAM_MAP_VALID BIT(0) + +#endif /* __MACH_MVEBU_DOVE_REGS_H */ diff --git a/arch/arm/mach-mvebu/include/mach/dove.h b/arch/arm/mach-mvebu/include/mach/dove.h new file mode 100644 index 000000000..1712fa7a1 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/dove.h @@ -0,0 +1,23 @@ +/* + * Copyright + * (C) 2013 Sebastian Hesselbarth + * + * 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. + * + */ + +#ifndef __MACH_MVEBU_DOVE_H +#define __MACH_MVEBU_DOVE_H + +int dove_add_uart(int num); +void __naked __noreturn dove_barebox_entry(void); + +#endif /* __MACH_MVEBU_DOVE_H */ diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index dfc89ddea..4ef25ec45 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -21,3 +21,7 @@ config CLOCKSOURCE_MVEBU config CLOCKSOURCE_NOMADIK bool depends on ARM + +config CLOCKSOURCE_ORION + bool + depends on ARCH_MVEBU diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 0b42ce48d..25b7f460d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_CLOCKSOURCE_BCM2835) += bcm2835.o obj-$(CONFIG_CLOCKSOURCE_CLPS711X) += clps711x.o obj-$(CONFIG_CLOCKSOURCE_MVEBU) += mvebu.o obj-$(CONFIG_CLOCKSOURCE_NOMADIK) += nomadik.o +obj-$(CONFIG_CLOCKSOURCE_ORION) += orion.o diff --git a/drivers/clocksource/orion.c b/drivers/clocksource/orion.c new file mode 100644 index 000000000..604b41474 --- /dev/null +++ b/drivers/clocksource/orion.c @@ -0,0 +1,76 @@ +/* + * Copyright + * (C) 2013 Sebastian Hesselbarth + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#define TIMER_CTRL 0x00 +#define TIMER0_EN BIT(0) +#define TIMER0_RELOAD_EN BIT(1) +#define TIMER1_EN BIT(2) +#define TIMER1_RELOAD_EN BIT(3) +#define TIMER0_RELOAD 0x10 +#define TIMER0_VAL 0x14 +#define TIMER1_RELOAD 0x18 +#define TIMER1_VAL 0x1c + +static __iomem void *timer_base; + +static uint64_t orion_clocksource_read(void) +{ + return __raw_readl(timer_base + TIMER0_VAL); +} + +static struct clocksource clksrc = { + .read = orion_clocksource_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 10, +}; + +static int orion_timer_probe(struct device_d *dev) +{ + struct clk *tclk; + uint32_t val; + + timer_base = dev_request_mem_region(dev, 0); + tclk = clk_get(dev, "tclk"); + + /* setup TIMER0 as free-running clock source */ + __raw_writel(~0, timer_base + TIMER0_VAL); + __raw_writel(~0, timer_base + TIMER0_RELOAD); + val = __raw_readl(timer_base + TIMER_CTRL); + __raw_writel(val | TIMER0_EN | TIMER0_RELOAD_EN, + timer_base + TIMER_CTRL); + + clksrc.mult = clocksource_hz2mult(clk_get_rate(tclk), clksrc.shift); + init_clock(&clksrc); + + return 0; +} + +static struct driver_d orion_timer_driver = { + .name = "orion-timer", + .probe = orion_timer_probe, +}; + +static int orion_timer_init(void) +{ + return platform_driver_register(&orion_timer_driver); +} +postcore_initcall(orion_timer_init); From 8a39074328e6576589cb69ff109587988fcc9f77 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sun, 12 May 2013 22:28:53 +0200 Subject: [PATCH 12/25] arm: add basic support for SolidRun CuBox The SolidRun CuBox is a small cubic platform based on the Marvell Dove SoC. There is nothing more than a console, yet. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- arch/arm/Makefile | 1 + arch/arm/boards/solidrun-cubox/Makefile | 2 + arch/arm/boards/solidrun-cubox/config.h | 4 ++ arch/arm/boards/solidrun-cubox/kwbimage.cfg | 39 +++++++++++++++++++ arch/arm/boards/solidrun-cubox/lowlevel.c | 26 +++++++++++++ .../boards/solidrun-cubox/solidrun-cubox.c | 25 ++++++++++++ arch/arm/configs/solidrun_cubox_defconfig | 9 +++++ arch/arm/mach-mvebu/Kconfig | 5 +++ 8 files changed, 111 insertions(+) create mode 100644 arch/arm/boards/solidrun-cubox/Makefile create mode 100644 arch/arm/boards/solidrun-cubox/config.h create mode 100644 arch/arm/boards/solidrun-cubox/kwbimage.cfg create mode 100644 arch/arm/boards/solidrun-cubox/lowlevel.c create mode 100644 arch/arm/boards/solidrun-cubox/solidrun-cubox.c create mode 100644 arch/arm/configs/solidrun_cubox_defconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index af8294d0f..8f17e7e57 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -147,6 +147,7 @@ board-$(CONFIG_MACH_MINI6410) := friendlyarm-mini6410 board-$(CONFIG_MACH_TINY6410) := friendlyarm-tiny6410 board-$(CONFIG_MACH_PLATHOME_OPENBLOCKS_AX3) := plathome-openblocks-ax3 board-$(CONFIG_MACH_QIL_A9260) := qil-a9260 +board-$(CONFIG_MACH_SOLIDRUN_CUBOX) := solidrun-cubox board-$(CONFIG_MACH_TNY_A9260) := tny-a926x board-$(CONFIG_MACH_TNY_A9263) := tny-a926x board-$(CONFIG_MACH_TNY_A9G20) := tny-a926x diff --git a/arch/arm/boards/solidrun-cubox/Makefile b/arch/arm/boards/solidrun-cubox/Makefile new file mode 100644 index 000000000..6dfe2c8ec --- /dev/null +++ b/arch/arm/boards/solidrun-cubox/Makefile @@ -0,0 +1,2 @@ +obj-y = solidrun-cubox.o +lwl-y += lowlevel.o diff --git a/arch/arm/boards/solidrun-cubox/config.h b/arch/arm/boards/solidrun-cubox/config.h new file mode 100644 index 000000000..ca1513681 --- /dev/null +++ b/arch/arm/boards/solidrun-cubox/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/solidrun-cubox/kwbimage.cfg b/arch/arm/boards/solidrun-cubox/kwbimage.cfg new file mode 100644 index 000000000..cb0c360d7 --- /dev/null +++ b/arch/arm/boards/solidrun-cubox/kwbimage.cfg @@ -0,0 +1,39 @@ +VERSION 0 +BOOT_FROM spi +DESTADDR ffffffff # overwritten by kwbimage -c +EXECADDR ffffffff # overwritten by kwbimage -c +DATA d0020104 00000000 +DATA d0800020 00022430 +DATA d0800030 00022430 +DATA d0800050 911500c3 +DATA d0800060 646602c4 +DATA d0800190 c2003053 +DATA d08001c0 34f4a187 +DATA d0800650 000f0121 +DATA d0800660 04040200 +DATA d0800080 00000000 +DATA d0800090 00080000 +DATA d08000f0 c0000000 +DATA d08001a0 20c0c009 +DATA d0800280 010e0202 +DATA d0800760 00000000 +DATA d0800770 0000000a +DATA d0800140 20004044 +DATA d08001d0 133c2339 +DATA d08001e0 07700330 +DATA d08001f0 00000033 +DATA d0800200 0011311c +DATA d0800210 00300000 +DATA d0800240 80000000 +DATA d0800510 010e0101 +DATA d0800230 2028006a +DATA d0800e10 00280062 +DATA d0800e20 00280062 +DATA d0800e30 00280062 +DATA d0800100 000d0001 +DATA d0800110 200d0001 +DATA d0020104 00000000 +DATA d0020104 00000000 +DATA d0020104 00000000 +DATA d0020104 00000000 +DATA d0020104 00000000 diff --git a/arch/arm/boards/solidrun-cubox/lowlevel.c b/arch/arm/boards/solidrun-cubox/lowlevel.c new file mode 100644 index 000000000..8a06cbc7e --- /dev/null +++ b/arch/arm/boards/solidrun-cubox/lowlevel.c @@ -0,0 +1,26 @@ +/* + * Copyright + * (C) 2013 Sebastian Hesselbarth + * + * 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. + * + */ + +#include +#include +#include +#include + +void __naked barebox_arm_reset_vector(void) +{ + arm_cpu_lowlevel_init(); + dove_barebox_entry(); +} diff --git a/arch/arm/boards/solidrun-cubox/solidrun-cubox.c b/arch/arm/boards/solidrun-cubox/solidrun-cubox.c new file mode 100644 index 000000000..1abce2f35 --- /dev/null +++ b/arch/arm/boards/solidrun-cubox/solidrun-cubox.c @@ -0,0 +1,25 @@ +/* + * Copyright + * (C) 2013 Sebastian Hesselbarth + * + * 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. + * + */ + +#include +#include +#include + +static int solidrun_cubox_console_init(void) +{ + return dove_add_uart(0); +} +console_initcall(solidrun_cubox_console_init); diff --git a/arch/arm/configs/solidrun_cubox_defconfig b/arch/arm/configs/solidrun_cubox_defconfig new file mode 100644 index 000000000..1a27d815a --- /dev/null +++ b/arch/arm/configs/solidrun_cubox_defconfig @@ -0,0 +1,9 @@ +CONFIG_ARCH_MVEBU=y +CONFIG_ARCH_DOVE=y +CONFIG_AEABI=y +CONFIG_DEBUG_LL=y +CONFIG_CMD_LOADY=y +CONFIG_CMD_LOADS=y +CONFIG_CMD_RESET=y +CONFIG_CMD_CLK=y +CONFIG_DRIVER_SERIAL_NS16550=y diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index c02eea1c8..3d8c2c3ec 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -5,11 +5,13 @@ config ARCH_TEXT_BASE default 0x2000000 if MACH_PLATHOME_OPENBLOCKS_AX3 default 0x2000000 if MACH_GLOBALSCALE_MIRABOX default 0x2000000 if MACH_MARVELL_ARMADA_XP_GP + default 0x2000000 if MACH_SOLIDRUN_CUBOX config BOARDINFO default "PlatHome OpenBlocks AX3" if MACH_PLATHOME_OPENBLOCKS_AX3 default "Globalscale Mirabox" if MACH_GLOBALSCALE_MIRABOX default "Marvell Armada XP GP" if MACH_MARVELL_ARMADA_XP_GP + default "SolidRun CuBox" if MACH_SOLIDRUN_CUBOX choice prompt "Marvell EBU Processor" @@ -63,6 +65,9 @@ if ARCH_DOVE choice prompt "Dove 88AP510 Board Type" +config MACH_SOLIDRUN_CUBOX + bool "SolidRun CuBox" + endchoice endif # ARCH_DOVE From 2434ae9f50c0b83afebe46e6578753c7e39818a3 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sun, 12 May 2013 22:29:44 +0200 Subject: [PATCH 13/25] arm: mach-mvebu: rename Armada 370/XP core code There are more than Armada 370/XP in Marvell MVEBU SoC familiy. To avoid irritation with source file nameing, we rename setup source file for Armada 370/XP from core.c to armada-370-xp.c. Signed-off-by: Sebastian Hesselbarth Acked-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- arch/arm/mach-mvebu/Makefile | 4 ++-- arch/arm/mach-mvebu/{core.c => armada-370-xp.c} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename arch/arm/mach-mvebu/{core.c => armada-370-xp.c} (100%) diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 0257b732e..043f08f5d 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -1,3 +1,3 @@ -obj-$(CONFIG_ARCH_ARMADA_370) += core.o -obj-$(CONFIG_ARCH_ARMADA_XP) += core.o +obj-$(CONFIG_ARCH_ARMADA_370) += armada-370-xp.o +obj-$(CONFIG_ARCH_ARMADA_XP) += armada-370-xp.o obj-$(CONFIG_ARCH_DOVE) += dove.o diff --git a/arch/arm/mach-mvebu/core.c b/arch/arm/mach-mvebu/armada-370-xp.c similarity index 100% rename from arch/arm/mach-mvebu/core.c rename to arch/arm/mach-mvebu/armada-370-xp.c From 87f6faa4508c8e66a828ccf425663375ca681017 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:27 +0200 Subject: [PATCH 14/25] scripts/kwbimage: add a new function image_count_options() This function returns the number of configuration elements that match a given type. Will be used to do some sanity checking of the number of options. Signed-off-by: Thomas Petazzoni Tested-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- scripts/kwbimage.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index 14b35e781..0d5dcac31 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -259,6 +259,20 @@ image_find_option(struct image_cfg_element *image_cfg, return NULL; } +static unsigned int +image_count_options(struct image_cfg_element *image_cfg, + int cfgn, unsigned int optiontype) +{ + int i; + unsigned int count = 0; + + for (i = 0; i < cfgn; i++) + if (image_cfg[i].type == optiontype) + count++; + + return count; +} + /* * Compute a 8-bit checksum of a memory area. This algorithm follows * the requirements of the Marvell SoC BootROM specifications. From d60819c62691a40c23b97d1bdf2da428af40544d Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:28 +0200 Subject: [PATCH 15/25] scripts/kwbimage: add a few sanity checks This commit uses the newly introduced image_count_options() function to: - See if there is any DATA option that require the creation of an extended header for v0 header. - Verify that no more than one payload has been provided when creating a v0 header. - Verify that no more than one binary payload has been provided when creating a v1 header. Technically speaking, it is possible to support several payloads, but in real life, only one gets used, so we will only support that to make the code simpler for now. It can always be extended later on if needed. - Verify that no more than one payload has been provided when creating a v1 header. Signed-off-by: Thomas Petazzoni Tested-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- scripts/kwbimage.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index 0d5dcac31..cca20abdc 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -712,12 +712,16 @@ static void *image_create_v0(struct image_cfg_element *image_cfg, headersz = sizeof(struct main_hdr_v0); payloadsz = 0; - e = image_find_option(image_cfg, cfgn, IMAGE_CFG_DATA); - if (e) { + if (image_count_options(image_cfg, cfgn, IMAGE_CFG_DATA) > 0) { has_ext = 1; headersz += sizeof(struct ext_hdr_v0); } + if (image_count_options(image_cfg, cfgn, IMAGE_CFG_PAYLOAD) > 1) { + fprintf(stderr, "More than one payload, not possible\n"); + return NULL; + } + payloade = image_find_option(image_cfg, cfgn, IMAGE_CFG_PAYLOAD); if (payloade) { struct stat s; @@ -818,6 +822,16 @@ static void *image_create_v1(struct image_cfg_element *image_cfg, headersz = sizeof(struct main_hdr_v1); payloadsz = 0; + if (image_count_options(image_cfg, cfgn, IMAGE_CFG_BINARY) > 1) { + fprintf(stderr, "More than one binary blob, not supported\n"); + return NULL; + } + + if (image_count_options(image_cfg, cfgn, IMAGE_CFG_PAYLOAD) > 1) { + fprintf(stderr, "More than one payload, not possible\n"); + return NULL; + } + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_BINARY); if (e) { struct stat s; From e91abe2ec433d665a692c3095517f7ac0bbe1d5a Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:29 +0200 Subject: [PATCH 16/25] scripts/kwbimage: make the v0 image creation more flexible Until now, the v0 image creation function was expecting the configuration parameters to be ordered with first the configuration parameters affecting the main header, then the DATA configuration parameters that affect the extended header, then the payload. However, with the recently added ability to override the destination address or execution address, the configuration options corresponding to those values may now appear at the end of the configuration options. This commit allows to handle that by making the image creation more flexible: - The configuration options for the main header are just searched amongst all options, the first match is used. - When building the extension header with the DATA options, all DATA options from the configuration file are used, in the order in which they appear in the kwbimage.cfg file. This will for example allow a kwbimage.cfg for a v0 image to not specify any destination or execution address, and simply override it from the command line. Signed-off-by: Thomas Petazzoni Tested-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- scripts/kwbimage.c | 48 +++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index cca20abdc..d4f65a8b4 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -705,7 +705,7 @@ static void *image_create_v0(struct image_cfg_element *image_cfg, struct ext_hdr_v0 *ext_hdr; void *image; int has_ext = 0; - int cfgi, ret; + int ret; /* Calculate the size of the header and the size of the * payload */ @@ -754,42 +754,34 @@ static void *image_create_v0(struct image_cfg_element *image_cfg, main_hdr->blocksize = payloadsz + sizeof(uint32_t); main_hdr->srcaddr = headersz; main_hdr->ext = has_ext; - for (cfgi = 0; cfgi < cfgn; cfgi++) { - struct image_cfg_element *el = &image_cfg[cfgi]; - if (el->type == IMAGE_CFG_BOOT_FROM) - main_hdr->blockid = el->bootfrom; - else if (el->type == IMAGE_CFG_DEST_ADDR) - main_hdr->destaddr = el->dstaddr; - else if (el->type == IMAGE_CFG_EXEC_ADDR) - main_hdr->execaddr = el->execaddr; - else if (el->type != IMAGE_CFG_VERSION) - break; - } - + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_BOOT_FROM); + if (e) + main_hdr->blockid = e->bootfrom; + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_DEST_ADDR); + if (e) + main_hdr->destaddr = e->dstaddr; + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_EXEC_ADDR); + if (e) + main_hdr->execaddr = e->execaddr; main_hdr->checksum = image_checksum8(image, sizeof(struct main_hdr_v0)); /* Generate the ext header */ if (has_ext) { - int datai = 0; + int cfgi, datai; ext_hdr = image + sizeof(struct main_hdr_v0); ext_hdr->offset = 0x40; - for (; cfgi < cfgn; cfgi++) { - struct image_cfg_element *el = &image_cfg[cfgi]; - if (el->type == IMAGE_CFG_DATA) { - ext_hdr->rcfg[datai].raddr = el->regdata.raddr; - ext_hdr->rcfg[datai].rdata = el->regdata.rdata; - datai++; - } - else if (el->type == IMAGE_CFG_PAYLOAD) - break; - else { - fprintf(stderr, "Invalid element of type %d\n", - el->type); - return NULL; - } + for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) { + e = &image_cfg[cfgi]; + + if (e->type != IMAGE_CFG_DATA) + continue; + + ext_hdr->rcfg[datai].raddr = e->regdata.raddr; + ext_hdr->rcfg[datai].rdata = e->regdata.rdata; + datai++; } ext_hdr->checksum = image_checksum8(ext_hdr, From 25547d663c4f9b302771007db03b8f2f1d3c7421 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:30 +0200 Subject: [PATCH 17/25] scripts/kwbimage: simplify the v1 image creation We now assume that at most one binary header can be added, so we no longer need to loop for all configuration options to find the binary blobs. We simply find the binary blob configuration option in 'binarye' and use that when we need to generate the corresponding header. Also, just like we did for the v0 image creation, use image_find_option() to find the value of the different options needed to create the main header. Signed-off-by: Thomas Petazzoni Tested-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- scripts/kwbimage.c | 163 +++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 87 deletions(-) diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index d4f65a8b4..631f131e9 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -802,12 +802,12 @@ static void *image_create_v0(struct image_cfg_element *image_cfg, static void *image_create_v1(struct image_cfg_element *image_cfg, int cfgn, const char *output, size_t *imagesz) { - struct image_cfg_element *e, *payloade; + struct image_cfg_element *e, *payloade, *binarye; struct main_hdr_v1 *main_hdr; size_t headersz, payloadsz, totalsz; void *image, *cur; int hasext = 0; - int cfgi, ret; + int ret; /* Calculate the size of the header and the size of the * payload */ @@ -824,24 +824,24 @@ static void *image_create_v1(struct image_cfg_element *image_cfg, return NULL; } - e = image_find_option(image_cfg, cfgn, IMAGE_CFG_BINARY); - if (e) { + binarye = image_find_option(image_cfg, cfgn, IMAGE_CFG_BINARY); + if (binarye) { struct stat s; - ret = stat(e->binary.file, &s); + ret = stat(binarye->binary.file, &s); if (ret < 0) { char *cwd = get_current_dir_name(); fprintf(stderr, "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n" "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n" "image for your board. See 'kwbimage -x' to extract it from an existing image.\n", - e->binary.file, cwd); + binarye->binary.file, cwd); free(cwd); return NULL; } headersz += s.st_size + - e->binary.nargs * sizeof(unsigned int); + binarye->binary.nargs * sizeof(unsigned int); hasext = 1; } @@ -878,96 +878,85 @@ static void *image_create_v1(struct image_cfg_element *image_cfg, cur = main_hdr = image; cur += sizeof(struct main_hdr_v1); + /* Fill the main header */ main_hdr->blocksize = payloadsz + sizeof(uint32_t); main_hdr->headersz_lsb = headersz & 0xFFFF; main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16; main_hdr->srcaddr = headersz; main_hdr->ext = hasext; + main_hdr->version = 1; + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_BOOT_FROM); + if (e) + main_hdr->blockid = e->bootfrom; + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_DEST_ADDR); + if (e) + main_hdr->destaddr = e->dstaddr; + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_EXEC_ADDR); + if (e) + main_hdr->execaddr = e->execaddr; + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_NAND_BLKSZ); + if (e) + main_hdr->nandblocksize = e->nandblksz / (64 * 1024); + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_NAND_BADBLK_LOCATION); + if (e) + main_hdr->nandbadblklocation = e->nandbadblklocation; - /* First, take care of filling the main header */ - for (cfgi = 0; cfgi < cfgn; cfgi++) { - struct image_cfg_element *el = &image_cfg[cfgi]; - if (el->type == IMAGE_CFG_VERSION) - main_hdr->version = 1; - else if (el->type == IMAGE_CFG_BOOT_FROM) - main_hdr->blockid = el->bootfrom; - else if (el->type == IMAGE_CFG_DEST_ADDR) - main_hdr->destaddr = el->dstaddr; - else if (el->type == IMAGE_CFG_EXEC_ADDR) - main_hdr->execaddr = el->execaddr; - else if (el->type == IMAGE_CFG_NAND_BLKSZ) - main_hdr->nandblocksize = el->nandblksz / (64 * 1024); - else if (el->type == IMAGE_CFG_NAND_BADBLK_LOCATION) - main_hdr->nandbadblklocation = el->nandbadblklocation; - else - break; - } + if (binarye) { + struct opt_hdr_v1 *hdr = cur; + unsigned int *args; + size_t binhdrsz; + struct stat s; + int argi; + FILE *bin; - /* Then, fill the extension headers */ - for (; cfgi < cfgn; cfgi++) { - struct image_cfg_element *el = &image_cfg[cfgi]; + hdr->headertype = OPT_HDR_V1_BINARY_TYPE; - if (el->type == IMAGE_CFG_BINARY) { - struct opt_hdr_v1 *hdr = cur; - unsigned int *args; - size_t binhdrsz; - struct stat s; - int argi; - FILE *bin; - - hdr->headertype = OPT_HDR_V1_BINARY_TYPE; - - bin = fopen(el->binary.file, "r"); - if (!bin) { - fprintf(stderr, "Cannot open binary file %s\n", - el->binary.file); - return NULL; - } - - fstat(fileno(bin), &s); - - binhdrsz = sizeof(struct opt_hdr_v1) + - (el->binary.nargs + 1) * sizeof(unsigned int) + - s.st_size; - hdr->headersz_lsb = binhdrsz & 0xFFFF; - hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; - - cur += sizeof(struct opt_hdr_v1); - - args = cur; - *args = el->binary.nargs; - args++; - for (argi = 0; argi < el->binary.nargs; argi++) - args[argi] = el->binary.args[argi]; - - cur += (el->binary.nargs + 1) * sizeof(unsigned int); - - ret = fread(cur, s.st_size, 1, bin); - if (ret != 1) { - fprintf(stderr, - "Could not read binary image %s\n", - el->binary.file); - return NULL; - } - - fclose(bin); - - cur += s.st_size; - - /* See if we have a next header or not, and if - * so, add the marker indicating that we are - * not the last header */ - if ((cfgi < (cfgn - 1)) && - (image_cfg[cfgi + 1].type != IMAGE_CFG_PAYLOAD)) - *((unsigned char *) cur) = 1; - cur += sizeof(uint32_t); - } else if (el->type == IMAGE_CFG_PAYLOAD) - break; - else { - fprintf(stderr, "Invalid element type %d (cfgi=%d)\n", - el->type, cfgi); + bin = fopen(binarye->binary.file, "r"); + if (!bin) { + fprintf(stderr, "Cannot open binary file %s\n", + binarye->binary.file); return NULL; } + + fstat(fileno(bin), &s); + + binhdrsz = sizeof(struct opt_hdr_v1) + + (binarye->binary.nargs + 1) * sizeof(unsigned int) + + s.st_size; + hdr->headersz_lsb = binhdrsz & 0xFFFF; + hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; + + cur += sizeof(struct opt_hdr_v1); + + args = cur; + *args = binarye->binary.nargs; + args++; + for (argi = 0; argi < binarye->binary.nargs; argi++) + args[argi] = binarye->binary.args[argi]; + + cur += (binarye->binary.nargs + 1) * sizeof(unsigned int); + + ret = fread(cur, s.st_size, 1, bin); + if (ret != 1) { + fprintf(stderr, + "Could not read binary image %s\n", + binarye->binary.file); + return NULL; + } + + fclose(bin); + + cur += s.st_size; + + /* + * For now, we don't support more than one binary + * header, and no other header types are + * supported. So, the binary header is necessarily the + * last one + */ + *((unsigned char *) cur) = 0; + + cur += sizeof(uint32_t); } /* Calculate and set the header checksum */ From e041f86013652680a356d3340cc36d43bfc070ad Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:31 +0200 Subject: [PATCH 18/25] scripts/kwbimage: make image_boot_mode_id() return -1 on failure The function image_boot_mode_id() converts the name of a boot media into the corresponding Marvell specific code. However, 0 that we currently used to indicate that the boot media name wasn't found, could potentially be a valid value. So instead we use -1 to indicate a failure. This is also done in preparation to the introduction of image_nand_ecc_mode_id(), which will convert a NAND ECC mode name into the corresponding identifier. And in this case 0 is a valid identifier of a NAND ECC mode, so we cannot use it to indicate a failure. Since we want image_boot_mode_id() and image_nand_ecc_mode_id() to have a consistent behavior, we change the former in this commit. The latter is introduced in the next commit. Signed-off-by: Thomas Petazzoni Tested-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- scripts/kwbimage.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index 631f131e9..0127e2b6f 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -226,14 +226,14 @@ static const char *image_boot_mode_name(unsigned int id) return NULL; } -unsigned int image_boot_mode_id(const char *boot_mode_name) +int image_boot_mode_id(const char *boot_mode_name) { int i; for (i = 0; boot_modes[i].name; i++) if (!strcmp(boot_modes[i].name, boot_mode_name)) return boot_modes[i].id; - return 0; + return -1; } static const char *image_nand_ecc_mode_name(unsigned int id) @@ -987,7 +987,7 @@ static int image_create_config_parse_oneline(char *line, char *value = strtok_r(NULL, " ", &saveptr); el->type = IMAGE_CFG_BOOT_FROM; el->bootfrom = image_boot_mode_id(value); - if (!el->bootfrom) { + if (el->bootfrom < 0) { fprintf(stderr, "Invalid boot media '%s'\n", value); return -1; From 3b40d183eb5843d6afb675a727ec5fa5cfbca849 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:32 +0200 Subject: [PATCH 19/25] scripts/kwbimage: add support for NAND ECC and page size header fields The v0 header, used on Kirkwood, has some fields to indicate the type of the NAND ECC, and the page size of the NAND. This commit adds support for such fields, which are needed to support the Kirkwood Guruplug platform. Signed-off-by: Thomas Petazzoni Tested-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- scripts/kwbimage.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index 0127e2b6f..4ebb07fe2 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -177,6 +177,8 @@ struct image_cfg_element { IMAGE_CFG_EXEC_ADDR, IMAGE_CFG_NAND_BLKSZ, IMAGE_CFG_NAND_BADBLK_LOCATION, + IMAGE_CFG_NAND_ECC_MODE, + IMAGE_CFG_NAND_PAGESZ, IMAGE_CFG_BINARY, IMAGE_CFG_PAYLOAD, IMAGE_CFG_DATA, @@ -194,6 +196,8 @@ struct image_cfg_element { unsigned int execaddr; unsigned int nandblksz; unsigned int nandbadblklocation; + unsigned int nandeccmode; + unsigned int nandpagesz; struct ext_hdr_v0_reg regdata; }; }; @@ -245,6 +249,15 @@ static const char *image_nand_ecc_mode_name(unsigned int id) return NULL; } +int image_nand_ecc_mode_id(const char *nand_ecc_mode_name) +{ + int i; + for (i = 0; nand_ecc_modes[i].name; i++) + if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name)) + return nand_ecc_modes[i].id; + return -1; +} + static struct image_cfg_element * image_find_option(struct image_cfg_element *image_cfg, int cfgn, unsigned int optiontype) @@ -409,9 +422,9 @@ static int image_extract_v0(void *fdimap, const char *output, FILE *focfg) if (!strcmp(boot_mode_name, "nand")) { const char *nand_ecc_mode = image_nand_ecc_mode_name(main_hdr->nandeccmode); - fprintf(focfg, "NAND_ECC_MODE %s\n", + fprintf(focfg, "NAND_ECCMODE %s\n", nand_ecc_mode); - fprintf(focfg, "NAND_PAGE_SIZE %08x\n", + fprintf(focfg, "NAND_PAGESZ %08x\n", main_hdr->nandpagesize); } @@ -763,6 +776,12 @@ static void *image_create_v0(struct image_cfg_element *image_cfg, e = image_find_option(image_cfg, cfgn, IMAGE_CFG_EXEC_ADDR); if (e) main_hdr->execaddr = e->execaddr; + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_NAND_ECC_MODE); + if (e) + main_hdr->nandeccmode = e->nandeccmode; + e = image_find_option(image_cfg, cfgn, IMAGE_CFG_NAND_PAGESZ); + if (e) + main_hdr->nandpagesize = e->nandpagesz; main_hdr->checksum = image_checksum8(image, sizeof(struct main_hdr_v0)); @@ -1009,6 +1028,19 @@ static int image_create_config_parse_oneline(char *line, el->type = IMAGE_CFG_NAND_BADBLK_LOCATION; el->nandbadblklocation = strtol(value, NULL, 16); + } else if (!strcmp(keyword, "NAND_ECCMODE")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_NAND_ECC_MODE; + el->nandeccmode = image_nand_ecc_mode_id(value); + if (el->nandeccmode < 0) { + fprintf(stderr, + "Invalid NAND ECC mode '%s'\n", value); + return -1; + } + } else if (!strcmp(keyword, "NAND_PAGESZ")) { + char *value = strtok_r(NULL, " ", &saveptr); + el->type = IMAGE_CFG_NAND_PAGESZ; + el->nandpagesz = strtol(value, NULL, 16); } else if (!strcmp(keyword, "BINARY")) { char *value = strtok_r(NULL, " ", &saveptr); int argi = 0; @@ -1241,6 +1273,12 @@ static void image_dump_config(struct image_cfg_element *image_cfg, case IMAGE_CFG_NAND_BADBLK_LOCATION: printf("NANDBADBLK 0x%x\n", e->nandbadblklocation); break; + case IMAGE_CFG_NAND_ECC_MODE: + printf("NAND_ECCMODE 0x%x\n", e->nandeccmode); + break; + case IMAGE_CFG_NAND_PAGESZ: + printf("NAND_PAGESZ 0x%x\n", e->nandpagesz); + break; case IMAGE_CFG_BINARY: printf("BINARY %s (%d args)\n", e->binary.file, e->binary.nargs); From 4f7c4267cac331cfbd6df31cde10cad29794ffaf Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:33 +0200 Subject: [PATCH 20/25] arm: mvebu: add Feroceon CPU type The Kirkwood Marvell SoC uses a Marvell-specific implementation of an ARMv5TE compatible ARM core, the Feroceon. This patch introduces a Kconfig option that allows to select this CPU type. Signed-off-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- arch/arm/cpu/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig index 86bc17410..aed4cb7c6 100644 --- a/arch/arm/cpu/Kconfig +++ b/arch/arm/cpu/Kconfig @@ -39,6 +39,14 @@ config CPU_ARM926T Say Y if you want support for the ARM926T processor. Otherwise, say N. +# Feroceon +config CPU_FEROCEON + bool + select CPU_32v5 + help + This is a Marvell implementation of an ARMv5TE compatible + ARM core, used in the Marvell Kirkwood SoC family. + # ARMv6 config CPU_V6 bool From 6cd2c76b2fcd680ddca30a18de9c8192096ae6b1 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:34 +0200 Subject: [PATCH 21/25] arm: mvebu: initial support for Marvell Kirkwood SoCs Marvell Kirkwood SoCs are based on a ARMv5 compatible core designed by Marvell, and a large number of peripherals with Marvell Dove, Marvell Armada 370 and Marvell Armada XP SoCs. The Marvell Kirkwood are used in a large number of consumer-grade NAS devices, for example. Signed-off-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- arch/arm/mach-mvebu/Kconfig | 14 +++ arch/arm/mach-mvebu/Makefile | 1 + .../mach-mvebu/include/mach/kirkwood-regs.h | 37 ++++++ arch/arm/mach-mvebu/include/mach/kirkwood.h | 22 ++++ arch/arm/mach-mvebu/kirkwood.c | 111 ++++++++++++++++++ 5 files changed, 185 insertions(+) create mode 100644 arch/arm/mach-mvebu/include/mach/kirkwood-regs.h create mode 100644 arch/arm/mach-mvebu/include/mach/kirkwood.h create mode 100644 arch/arm/mach-mvebu/kirkwood.c diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 3d8c2c3ec..92ba00915 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -31,6 +31,11 @@ config ARCH_DOVE select CPU_V7 select CLOCKSOURCE_ORION +config ARCH_KIRKWOOD + bool "Kirkwood" + select CPU_FEROCEON + select CLOCKSOURCE_ORION + endchoice if ARCH_ARMADA_370 @@ -72,4 +77,13 @@ endchoice endif # ARCH_DOVE +if ARCH_KIRKWOOD + +choice + prompt "Kirkwood Board Type" + +endchoice + +endif # ARCH_KIRKWOOD + endif # ARCH_MVEBU diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 043f08f5d..8047725e9 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_ARCH_ARMADA_370) += armada-370-xp.o obj-$(CONFIG_ARCH_ARMADA_XP) += armada-370-xp.o obj-$(CONFIG_ARCH_DOVE) += dove.o +obj-$(CONFIG_ARCH_KIRKWOOD) += kirkwood.o diff --git a/arch/arm/mach-mvebu/include/mach/kirkwood-regs.h b/arch/arm/mach-mvebu/include/mach/kirkwood-regs.h new file mode 100644 index 000000000..23e221ba9 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/kirkwood-regs.h @@ -0,0 +1,37 @@ +/* + * Copyright + * (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#ifndef __MACH_MVEBU_KIRKWOOD_REGS_H +#define __MACH_MVEBU_KIRKWOOD_REGS_H + +#define KIRKWOOD_INT_REGS_BASE IOMEM(0xd0000000) + +#define KIRKWOOD_SDRAM_WIN_BASE (KIRKWOOD_INT_REGS_BASE + 0x1500) +#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) +#define DDR_BASE_CS_HIGH_MASK 0xf +#define DDR_BASE_CS_LOW_MASK 0xff000000 +#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3)) +#define DDR_SIZE_ENABLED (1 << 0) +#define DDR_SIZE_CS_MASK 0x1c +#define DDR_SIZE_CS_SHIFT 2 +#define DDR_SIZE_MASK 0xff000000 +#define KIRKWOOD_SAR_BASE (KIRKWOOD_INT_REGS_BASE + 0x10030) +#define KIRKWOOD_TCLK_BIT 21 +#define KIRKWOOD_UART_BASE (KIRKWOOD_INT_REGS_BASE + 0x12000) +#define KIRKWOOD_CPUCTRL_BASE (KIRKWOOD_INT_REGS_BASE + 0x20100) +#define KIRKWOOD_TIMER_BASE (KIRKWOOD_INT_REGS_BASE + 0x20300) + +#endif /* __MACH_MVEBU_KIRKWOOD_REGS_H */ diff --git a/arch/arm/mach-mvebu/include/mach/kirkwood.h b/arch/arm/mach-mvebu/include/mach/kirkwood.h new file mode 100644 index 000000000..7fe002d44 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/kirkwood.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#ifndef __MACH_KIRKWOOD_H +#define __MACH_KIRKWOOD_H + +int kirkwood_add_uart0(void); +void __naked __noreturn kirkwood_barebox_entry(void); + +#endif /* __MACH_KIRKWOOD_H */ diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c new file mode 100644 index 000000000..b5b6aaf9a --- /dev/null +++ b/arch/arm/mach-mvebu/kirkwood.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct clk *tclk; + +static inline void kirkwood_memory_find(unsigned long *phys_base, + unsigned long *phys_size) +{ + void __iomem *sdram_win = IOMEM(KIRKWOOD_SDRAM_WIN_BASE); + int cs; + + *phys_base = ~0; + *phys_size = 0; + + for (cs = 0; cs < 4; cs++) { + uint32_t base = readl(sdram_win + DDR_BASE_CS_OFF(cs)); + uint32_t ctrl = readl(sdram_win + DDR_SIZE_CS_OFF(cs)); + + /* Skip non-enabled CS */ + if (! (ctrl & DDR_SIZE_ENABLED)) + continue; + + base &= DDR_BASE_CS_LOW_MASK; + if (base < *phys_base) + *phys_base = base; + *phys_size += (ctrl | ~DDR_SIZE_MASK) + 1; + } +} + +void __naked __noreturn kirkwood_barebox_entry(void) +{ + unsigned long phys_base, phys_size; + kirkwood_memory_find(&phys_base, &phys_size); + writel('E', 0xD0012000); + barebox_arm_entry(phys_base, phys_size, 0); +} + +static struct NS16550_plat uart_plat = { + .shift = 2, +}; + +int kirkwood_add_uart0(void) +{ + uart_plat.clock = clk_get_rate(tclk); + if (!add_ns16550_device(DEVICE_ID_DYNAMIC, + (unsigned int)KIRKWOOD_UART_BASE, + 32, IORESOURCE_MEM_32BIT, &uart_plat)) + return -ENODEV; + return 0; +} + +static int kirkwood_init_clocks(void) +{ + uint32_t sar = readl(KIRKWOOD_SAR_BASE); + unsigned int rate; + + if (sar & (1 << KIRKWOOD_TCLK_BIT)) + rate = 166666667; + else + rate = 200000000; + + tclk = clk_fixed("tclk", rate); + return clk_register_clkdev(tclk, NULL, "orion-timer"); +} + +static int kirkwood_init_soc(void) +{ + unsigned long phys_base, phys_size; + + kirkwood_init_clocks(); + add_generic_device("orion-timer", DEVICE_ID_SINGLE, NULL, + (unsigned int)KIRKWOOD_TIMER_BASE, 0x30, + IORESOURCE_MEM, NULL); + kirkwood_memory_find(&phys_base, &phys_size); + arm_add_mem_device("ram0", phys_base, phys_size); + + return 0; +} + +postcore_initcall(kirkwood_init_soc); + +void __noreturn reset_cpu(unsigned long addr) +{ + writel(0x4, KIRKWOOD_CPUCTRL_BASE + 0x8); + writel(0x1, KIRKWOOD_CPUCTRL_BASE + 0xC); + for(;;) + ; +} +EXPORT_SYMBOL(reset_cpu); From 1590cb888eb11d71403e89a9b7ed77fb9ce1b039 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:35 +0200 Subject: [PATCH 22/25] arm: mvebu: add basic support for Globalscale Guruplug board The Globalscale Guruplug board is a small NAS-type plug platform that uses a Marvell Kirkwood SoC. Signed-off-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- arch/arm/Makefile | 1 + arch/arm/boards/globalscale-guruplug/Makefile | 2 ++ arch/arm/boards/globalscale-guruplug/config.h | 4 +++ .../globalscale-guruplug.c | 26 ++++++++++++++++++ .../boards/globalscale-guruplug/kwbimage.cfg | 27 +++++++++++++++++++ .../boards/globalscale-guruplug/lowlevel.c | 26 ++++++++++++++++++ .../configs/globalscale_guruplug_defconfig | 6 +++++ arch/arm/mach-mvebu/Kconfig | 5 ++++ 8 files changed, 97 insertions(+) create mode 100644 arch/arm/boards/globalscale-guruplug/Makefile create mode 100644 arch/arm/boards/globalscale-guruplug/config.h create mode 100644 arch/arm/boards/globalscale-guruplug/globalscale-guruplug.c create mode 100644 arch/arm/boards/globalscale-guruplug/kwbimage.cfg create mode 100644 arch/arm/boards/globalscale-guruplug/lowlevel.c create mode 100644 arch/arm/configs/globalscale_guruplug_defconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 8f17e7e57..1e7ace4e4 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -103,6 +103,7 @@ board-$(CONFIG_MACH_FREESCALE_MX25_3STACK) := freescale-mx25-3-stack board-$(CONFIG_MACH_FREESCALE_MX35_3STACK) := freescale-mx35-3-stack board-$(CONFIG_MACH_GE863) := telit-evk-pro3 board-$(CONFIG_MACH_GLOBALSCALE_MIRABOX) := globalscale-mirabox +board-$(CONFIG_MACH_GLOBALSCALE_GURUPLUG) := globalscale-guruplug board-$(CONFIG_MACH_HIGHBANK) := highbank board-$(CONFIG_MACH_IMX21ADS) := imx21ads board-$(CONFIG_MACH_IMX27ADS) := imx27ads diff --git a/arch/arm/boards/globalscale-guruplug/Makefile b/arch/arm/boards/globalscale-guruplug/Makefile new file mode 100644 index 000000000..3b48b32cc --- /dev/null +++ b/arch/arm/boards/globalscale-guruplug/Makefile @@ -0,0 +1,2 @@ +obj-y = globalscale-guruplug.o +lwl-y += lowlevel.o diff --git a/arch/arm/boards/globalscale-guruplug/config.h b/arch/arm/boards/globalscale-guruplug/config.h new file mode 100644 index 000000000..ca1513681 --- /dev/null +++ b/arch/arm/boards/globalscale-guruplug/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/globalscale-guruplug/globalscale-guruplug.c b/arch/arm/boards/globalscale-guruplug/globalscale-guruplug.c new file mode 100644 index 000000000..dfc1d1ab2 --- /dev/null +++ b/arch/arm/boards/globalscale-guruplug/globalscale-guruplug.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include + +static int globalscale_guruplug_console_init(void) +{ + return kirkwood_add_uart0(); +} + +console_initcall(globalscale_guruplug_console_init); diff --git a/arch/arm/boards/globalscale-guruplug/kwbimage.cfg b/arch/arm/boards/globalscale-guruplug/kwbimage.cfg new file mode 100644 index 000000000..d0f3bdb01 --- /dev/null +++ b/arch/arm/boards/globalscale-guruplug/kwbimage.cfg @@ -0,0 +1,27 @@ +VERSION 0 +BOOT_FROM nand +NAND_ECCMODE default +NAND_PAGESZ 00000800 +DATA ffd100e0 1b1b9b9b +DATA ffd01400 43000c30 +DATA ffd01404 37543000 +DATA ffd01408 22125451 +DATA ffd0140c 00000a33 +DATA ffd01410 000000cc +DATA ffd01414 00000000 +DATA ffd01418 00000000 +DATA ffd0141c 00000c52 +DATA ffd01420 00000040 +DATA ffd01424 0000f17f +DATA ffd01428 00085520 +DATA ffd0147c 00008552 +DATA ffd01500 00000000 +DATA ffd01504 0ffffff1 +DATA ffd01508 10000000 +DATA ffd0150c 0ffffff5 +DATA ffd01514 00000000 +DATA ffd0151c 00000000 +DATA ffd01494 00030000 +DATA ffd01498 00000000 +DATA ffd0149c 0000e803 +DATA ffd01480 00000001 diff --git a/arch/arm/boards/globalscale-guruplug/lowlevel.c b/arch/arm/boards/globalscale-guruplug/lowlevel.c new file mode 100644 index 000000000..d270cda23 --- /dev/null +++ b/arch/arm/boards/globalscale-guruplug/lowlevel.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +void __naked barebox_arm_reset_vector(void) +{ + arm_cpu_lowlevel_init(); + kirkwood_barebox_entry(); +} diff --git a/arch/arm/configs/globalscale_guruplug_defconfig b/arch/arm/configs/globalscale_guruplug_defconfig new file mode 100644 index 000000000..d21de45c5 --- /dev/null +++ b/arch/arm/configs/globalscale_guruplug_defconfig @@ -0,0 +1,6 @@ +CONFIG_ARCH_MVEBU=y +CONFIG_ARCH_KIRKWOOD=y +CONFIG_TEXT_BASE=0x2000000 +CONFIG_DEBUG_LL=y +CONFIG_CMD_RESET=y +CONFIG_DRIVER_SERIAL_NS16550=y diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 92ba00915..1d46f8717 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -4,12 +4,14 @@ config ARCH_TEXT_BASE hex default 0x2000000 if MACH_PLATHOME_OPENBLOCKS_AX3 default 0x2000000 if MACH_GLOBALSCALE_MIRABOX + default 0x2000000 if MACH_GLOBALSCALE_GURUPLUG default 0x2000000 if MACH_MARVELL_ARMADA_XP_GP default 0x2000000 if MACH_SOLIDRUN_CUBOX config BOARDINFO default "PlatHome OpenBlocks AX3" if MACH_PLATHOME_OPENBLOCKS_AX3 default "Globalscale Mirabox" if MACH_GLOBALSCALE_MIRABOX + default "Globalscale Guruplug" if MACH_GLOBALSCALE_GURUPLUG default "Marvell Armada XP GP" if MACH_MARVELL_ARMADA_XP_GP default "SolidRun CuBox" if MACH_SOLIDRUN_CUBOX @@ -82,6 +84,9 @@ if ARCH_KIRKWOOD choice prompt "Kirkwood Board Type" +config MACH_GLOBALSCALE_GURUPLUG + bool "Guruplug" + endchoice endif # ARCH_KIRKWOOD From cd07f67a300f7c938952c38d909a70d4bc45db57 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 15 May 2013 09:36:36 +0200 Subject: [PATCH 23/25] arm: mvebu: remove useless lines in kwbimage.cfg for CuBox Thanks to the improvements brought into the kwbimage tool, it is no longer necessary to have dummy DEST_ADDR and EXEC_ADDR lines in the kwbimage.cfg file if those values are passed on the command line to the kwbimage tool, which is what the Barebox build process does. Signed-off-by: Thomas Petazzoni Tested-by: Sebastian Hesselbarth Signed-off-by: Sascha Hauer --- arch/arm/boards/solidrun-cubox/kwbimage.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/boards/solidrun-cubox/kwbimage.cfg b/arch/arm/boards/solidrun-cubox/kwbimage.cfg index cb0c360d7..db35acacd 100644 --- a/arch/arm/boards/solidrun-cubox/kwbimage.cfg +++ b/arch/arm/boards/solidrun-cubox/kwbimage.cfg @@ -1,7 +1,5 @@ VERSION 0 BOOT_FROM spi -DESTADDR ffffffff # overwritten by kwbimage -c -EXECADDR ffffffff # overwritten by kwbimage -c DATA d0020104 00000000 DATA d0800020 00022430 DATA d0800030 00022430 From df8d29462bc0bdd13571a5ae8daf6ee6c6999ffd Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sun, 19 May 2013 20:23:45 +0200 Subject: [PATCH 24/25] arm: mvebu: add more visible SoC separators to Kconfig This just add more visible separators between each subconfig of the supported Marvell EBU SoCs. Signed-off-by: Sebastian Hesselbarth Acked-by: Thomas Petazzoni Tested-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- arch/arm/mach-mvebu/Kconfig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 1d46f8717..400e41bdb 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -40,6 +40,10 @@ config ARCH_KIRKWOOD endchoice +# +# Armada 370 SoC boards +# + if ARCH_ARMADA_370 choice @@ -52,6 +56,10 @@ endchoice endif # ARCH_ARMADA_370 +# +# Armada XP SoC boards +# + if ARCH_ARMADA_XP choice @@ -67,6 +75,10 @@ endchoice endif # ARCH_ARMADA_XP +# +# Dove 88AP510 SoC boards +# + if ARCH_DOVE choice @@ -79,6 +91,10 @@ endchoice endif # ARCH_DOVE +# +# Kirkwood SoC boards +# + if ARCH_KIRKWOOD choice From 7286acab6715691c1262b320e9d22a480804ba49 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Sun, 19 May 2013 20:23:46 +0200 Subject: [PATCH 25/25] arm: mvebu: introduce common lowlevel and early init At early stage after boot, all MVEBU SoCs are similar enough to have a common lowlevel and barebox entry. We also remap the internal register base address to 0xf100000 as it gives some 512M more of contiguous address space. As we cannot determine real memory size that early, we start with a default memory size of 64M and probe correct size later in SoC init. Signed-off-by: Sebastian Hesselbarth Acked-by: Thomas Petazzoni Tested-by: Thomas Petazzoni Signed-off-by: Sascha Hauer --- arch/arm/boards/globalscale-guruplug/Makefile | 3 +- .../board.c} | 12 +-- .../globalscale-guruplug.c | 26 ----- .../boards/globalscale-guruplug/lowlevel.c | 26 ----- arch/arm/boards/globalscale-mirabox/Makefile | 3 +- .../board.c} | 13 +-- .../globalscale-mirabox/globalscale-mirabox.c | 26 ----- arch/arm/boards/marvell-armada-xp-gp/Makefile | 3 +- arch/arm/boards/marvell-armada-xp-gp/board.c | 17 +++ .../boards/plathome-openblocks-ax3/Makefile | 3 +- .../boards/plathome-openblocks-ax3/board.c | 17 +++ .../boards/plathome-openblocks-ax3/lowlevel.c | 25 ----- arch/arm/boards/solidrun-cubox/Makefile | 3 +- .../lowlevel.c => solidrun-cubox/board.c} | 14 +-- arch/arm/mach-mvebu/Kconfig | 14 +++ arch/arm/mach-mvebu/Makefile | 2 + arch/arm/mach-mvebu/armada-370-xp.c | 101 +++++++----------- arch/arm/mach-mvebu/common.c | 57 ++++++++++ arch/arm/mach-mvebu/dove.c | 56 ++++------ .../include/mach/armada-370-xp-regs.h | 47 ++++++++ .../include/mach/common.h} | 16 ++- arch/arm/mach-mvebu/include/mach/debug_ll.h | 23 ++-- arch/arm/mach-mvebu/include/mach/dove-regs.h | 19 ++-- .../mach-mvebu/include/mach/kirkwood-regs.h | 43 +++++--- .../include/mach/lowlevel.h} | 16 ++- arch/arm/mach-mvebu/kirkwood.c | 44 ++++---- .../lowlevel.c | 6 +- 27 files changed, 316 insertions(+), 319 deletions(-) rename arch/arm/boards/{solidrun-cubox/solidrun-cubox.c => globalscale-guruplug/board.c} (67%) delete mode 100644 arch/arm/boards/globalscale-guruplug/globalscale-guruplug.c delete mode 100644 arch/arm/boards/globalscale-guruplug/lowlevel.c rename arch/arm/boards/{solidrun-cubox/lowlevel.c => globalscale-mirabox/board.c} (66%) delete mode 100644 arch/arm/boards/globalscale-mirabox/globalscale-mirabox.c create mode 100644 arch/arm/boards/marvell-armada-xp-gp/board.c create mode 100644 arch/arm/boards/plathome-openblocks-ax3/board.c delete mode 100644 arch/arm/boards/plathome-openblocks-ax3/lowlevel.c rename arch/arm/boards/{marvell-armada-xp-gp/lowlevel.c => solidrun-cubox/board.c} (64%) create mode 100644 arch/arm/mach-mvebu/common.c create mode 100644 arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h rename arch/arm/{boards/marvell-armada-xp-gp/marvell-armada-xp-gp.c => mach-mvebu/include/mach/common.h} (65%) rename arch/arm/{boards/plathome-openblocks-ax3/plathome-openblocks-ax3.c => mach-mvebu/include/mach/lowlevel.h} (64%) rename arch/arm/{boards/globalscale-mirabox => mach-mvebu}/lowlevel.c (80%) diff --git a/arch/arm/boards/globalscale-guruplug/Makefile b/arch/arm/boards/globalscale-guruplug/Makefile index 3b48b32cc..dcfc2937d 100644 --- a/arch/arm/boards/globalscale-guruplug/Makefile +++ b/arch/arm/boards/globalscale-guruplug/Makefile @@ -1,2 +1 @@ -obj-y = globalscale-guruplug.o -lwl-y += lowlevel.o +obj-y += board.o diff --git a/arch/arm/boards/solidrun-cubox/solidrun-cubox.c b/arch/arm/boards/globalscale-guruplug/board.c similarity index 67% rename from arch/arm/boards/solidrun-cubox/solidrun-cubox.c rename to arch/arm/boards/globalscale-guruplug/board.c index 1abce2f35..9c800c541 100644 --- a/arch/arm/boards/solidrun-cubox/solidrun-cubox.c +++ b/arch/arm/boards/globalscale-guruplug/board.c @@ -1,6 +1,6 @@ /* * Copyright - * (C) 2013 Sebastian Hesselbarth + * (C) 2013 Thomas Petazzoni * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -14,12 +14,4 @@ * */ -#include -#include -#include - -static int solidrun_cubox_console_init(void) -{ - return dove_add_uart(0); -} -console_initcall(solidrun_cubox_console_init); +/* empty */ diff --git a/arch/arm/boards/globalscale-guruplug/globalscale-guruplug.c b/arch/arm/boards/globalscale-guruplug/globalscale-guruplug.c deleted file mode 100644 index dfc1d1ab2..000000000 --- a/arch/arm/boards/globalscale-guruplug/globalscale-guruplug.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2013 Thomas Petazzoni - * - * 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. - * - */ - -#include -#include -#include -#include - -static int globalscale_guruplug_console_init(void) -{ - return kirkwood_add_uart0(); -} - -console_initcall(globalscale_guruplug_console_init); diff --git a/arch/arm/boards/globalscale-guruplug/lowlevel.c b/arch/arm/boards/globalscale-guruplug/lowlevel.c deleted file mode 100644 index d270cda23..000000000 --- a/arch/arm/boards/globalscale-guruplug/lowlevel.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2013 Thomas Petazzoni - * - * 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. - * - */ - -#include -#include -#include -#include -#include - -void __naked barebox_arm_reset_vector(void) -{ - arm_cpu_lowlevel_init(); - kirkwood_barebox_entry(); -} diff --git a/arch/arm/boards/globalscale-mirabox/Makefile b/arch/arm/boards/globalscale-mirabox/Makefile index bd5d47e3c..9320510ba 100644 --- a/arch/arm/boards/globalscale-mirabox/Makefile +++ b/arch/arm/boards/globalscale-mirabox/Makefile @@ -1,2 +1 @@ -obj-y = globalscale-mirabox.o -lwl-y += lowlevel.o +obj-y += board.c diff --git a/arch/arm/boards/solidrun-cubox/lowlevel.c b/arch/arm/boards/globalscale-mirabox/board.c similarity index 66% rename from arch/arm/boards/solidrun-cubox/lowlevel.c rename to arch/arm/boards/globalscale-mirabox/board.c index 8a06cbc7e..9c800c541 100644 --- a/arch/arm/boards/solidrun-cubox/lowlevel.c +++ b/arch/arm/boards/globalscale-mirabox/board.c @@ -1,6 +1,6 @@ /* * Copyright - * (C) 2013 Sebastian Hesselbarth + * (C) 2013 Thomas Petazzoni * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -14,13 +14,4 @@ * */ -#include -#include -#include -#include - -void __naked barebox_arm_reset_vector(void) -{ - arm_cpu_lowlevel_init(); - dove_barebox_entry(); -} +/* empty */ diff --git a/arch/arm/boards/globalscale-mirabox/globalscale-mirabox.c b/arch/arm/boards/globalscale-mirabox/globalscale-mirabox.c deleted file mode 100644 index b8f4bffdd..000000000 --- a/arch/arm/boards/globalscale-mirabox/globalscale-mirabox.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2013 Thomas Petazzoni - * - * 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. - * - */ - -#include -#include -#include -#include - -static int globalscale_mirabox_console_init(void) -{ - return mvebu_add_uart0(); -} - -console_initcall(globalscale_mirabox_console_init); diff --git a/arch/arm/boards/marvell-armada-xp-gp/Makefile b/arch/arm/boards/marvell-armada-xp-gp/Makefile index ea899633b..dcfc2937d 100644 --- a/arch/arm/boards/marvell-armada-xp-gp/Makefile +++ b/arch/arm/boards/marvell-armada-xp-gp/Makefile @@ -1,2 +1 @@ -obj-y = marvell-armada-xp-gp.o -lwl-y += lowlevel.o +obj-y += board.o diff --git a/arch/arm/boards/marvell-armada-xp-gp/board.c b/arch/arm/boards/marvell-armada-xp-gp/board.c new file mode 100644 index 000000000..9c800c541 --- /dev/null +++ b/arch/arm/boards/marvell-armada-xp-gp/board.c @@ -0,0 +1,17 @@ +/* + * Copyright + * (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +/* empty */ diff --git a/arch/arm/boards/plathome-openblocks-ax3/Makefile b/arch/arm/boards/plathome-openblocks-ax3/Makefile index 91dc76465..dcfc2937d 100644 --- a/arch/arm/boards/plathome-openblocks-ax3/Makefile +++ b/arch/arm/boards/plathome-openblocks-ax3/Makefile @@ -1,2 +1 @@ -obj-y = plathome-openblocks-ax3.o -lwl-y += lowlevel.o +obj-y += board.o diff --git a/arch/arm/boards/plathome-openblocks-ax3/board.c b/arch/arm/boards/plathome-openblocks-ax3/board.c new file mode 100644 index 000000000..9c800c541 --- /dev/null +++ b/arch/arm/boards/plathome-openblocks-ax3/board.c @@ -0,0 +1,17 @@ +/* + * Copyright + * (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +/* empty */ diff --git a/arch/arm/boards/plathome-openblocks-ax3/lowlevel.c b/arch/arm/boards/plathome-openblocks-ax3/lowlevel.c deleted file mode 100644 index e9b2e30cb..000000000 --- a/arch/arm/boards/plathome-openblocks-ax3/lowlevel.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2013 Thomas Petazzoni - * - * 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. - * - */ - -#include -#include -#include -#include - -void __naked barebox_arm_reset_vector(void) -{ - arm_cpu_lowlevel_init(); - mvebu_barebox_entry(); -} diff --git a/arch/arm/boards/solidrun-cubox/Makefile b/arch/arm/boards/solidrun-cubox/Makefile index 6dfe2c8ec..9320510ba 100644 --- a/arch/arm/boards/solidrun-cubox/Makefile +++ b/arch/arm/boards/solidrun-cubox/Makefile @@ -1,2 +1 @@ -obj-y = solidrun-cubox.o -lwl-y += lowlevel.o +obj-y += board.c diff --git a/arch/arm/boards/marvell-armada-xp-gp/lowlevel.c b/arch/arm/boards/solidrun-cubox/board.c similarity index 64% rename from arch/arm/boards/marvell-armada-xp-gp/lowlevel.c rename to arch/arm/boards/solidrun-cubox/board.c index e9b2e30cb..a28f4197d 100644 --- a/arch/arm/boards/marvell-armada-xp-gp/lowlevel.c +++ b/arch/arm/boards/solidrun-cubox/board.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Thomas Petazzoni + * Copyright (C) 2013 + * Sebastian Hesselbarth * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -13,13 +14,4 @@ * */ -#include -#include -#include -#include - -void __naked barebox_arm_reset_vector(void) -{ - arm_cpu_lowlevel_init(); - mvebu_barebox_entry(); -} +/* empty */ diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 400e41bdb..11e4550ec 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -107,4 +107,18 @@ endchoice endif # ARCH_KIRKWOOD +# +# Common options +# + +config MVEBU_CONSOLE_UART + int "UART number for console" + default 0 + range 0 1 if ARCH_ARMADA_370 + range 0 1 if ARCH_ARMADA_XP + range 0 3 if ARCH_DOVE + range 0 1 if ARCH_KIRKWOOD + help + Select the UART number the barebox console will sit on. + endif # ARCH_MVEBU diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 8047725e9..80b3947cc 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -1,3 +1,5 @@ +lwl-y += lowlevel.o +obj-y += common.o obj-$(CONFIG_ARCH_ARMADA_370) += armada-370-xp.o obj-$(CONFIG_ARCH_ARMADA_XP) += armada-370-xp.o obj-$(CONFIG_ARCH_DOVE) += dove.o diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index f4672a362..2cdc3b0cb 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Thomas Petazzoni + * Copyright + * (C) 2013 Thomas Petazzoni * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -16,49 +17,31 @@ #include #include #include +#include #include #include -#include #include -#include +#include -#define MVEBU_INT_REGS_BASE (0xd0000000) -#define MVEBU_UART0_BASE (MVEBU_INT_REGS_BASE + 0x12000) -#define MVEBU_SYSCTL_BASE (MVEBU_INT_REGS_BASE + 0x18200) -#define MVEBU_SDRAM_WIN_BASE (MVEBU_INT_REGS_BASE + 0x20180) -#define MVEBU_TIMER_BASE (MVEBU_INT_REGS_BASE + 0x20300) -#define MVEBU_SAR_BASE (MVEBU_INT_REGS_BASE + 0x18230) - -#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) -#define DDR_BASE_CS_HIGH_MASK 0xf -#define DDR_BASE_CS_LOW_MASK 0xff000000 -#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3)) -#define DDR_SIZE_ENABLED (1 << 0) -#define DDR_SIZE_CS_MASK 0x1c -#define DDR_SIZE_CS_SHIFT 2 -#define DDR_SIZE_MASK 0xff000000 - -#define SAR_LOW_REG_OFF 0 -#define SAR_TCLK_FREQ_BIT 20 -#define SAR_HIGH_REG_OFF 0x4 +#define CONSOLE_UART_BASE \ + ARMADA_370_XP_UARTn_BASE(CONFIG_MVEBU_CONSOLE_UART) static struct clk *tclk; -static inline void mvebu_memory_find(unsigned long *phys_base, - unsigned long *phys_size) +static inline void armada_370_xp_memory_find(unsigned long *phys_base, + unsigned long *phys_size) { - void __iomem *sdram_win = IOMEM(MVEBU_SDRAM_WIN_BASE); int cs; *phys_base = ~0; *phys_size = 0; for (cs = 0; cs < 4; cs++) { - uint32_t base = readl(sdram_win + DDR_BASE_CS_OFF(cs)); - uint32_t ctrl = readl(sdram_win + DDR_SIZE_CS_OFF(cs)); + u32 base = readl(ARMADA_370_XP_SDRAM_BASE + DDR_BASE_CSn(cs)); + u32 ctrl = readl(ARMADA_370_XP_SDRAM_BASE + DDR_SIZE_CSn(cs)); /* Skip non-enabled CS */ - if (! (ctrl & DDR_SIZE_ENABLED)) + if ((ctrl & DDR_SIZE_ENABLED) != DDR_SIZE_ENABLED) continue; base &= DDR_BASE_CS_LOW_MASK; @@ -68,74 +51,70 @@ static inline void mvebu_memory_find(unsigned long *phys_base, } } -void __naked __noreturn mvebu_barebox_entry(void) -{ - unsigned long phys_base, phys_size; - mvebu_memory_find(&phys_base, &phys_size); - barebox_arm_entry(phys_base, phys_size, 0); -} - -static struct NS16550_plat uart0_plat = { +static struct NS16550_plat uart_plat = { .shift = 2, }; -int mvebu_add_uart0(void) +static int armada_370_xp_add_uart(void) { - uart0_plat.clock = clk_get_rate(tclk); - add_ns16550_device(DEVICE_ID_DYNAMIC, MVEBU_UART0_BASE, 32, - IORESOURCE_MEM_32BIT, &uart0_plat); + uart_plat.clock = clk_get_rate(tclk); + if (!add_ns16550_device(DEVICE_ID_DYNAMIC, + (unsigned int)CONSOLE_UART_BASE, 32, + IORESOURCE_MEM_32BIT, &uart_plat)) + return -ENODEV; return 0; } #if defined(CONFIG_ARCH_ARMADA_370) -static int mvebu_init_clocks(void) +static int armada_370_init_clocks(void) { - uint32_t val; + u32 val = readl(ARMADA_370_XP_SAR_BASE + SAR_LOW); unsigned int rate; - void __iomem *sar = IOMEM(MVEBU_SAR_BASE) + SAR_LOW_REG_OFF; - val = readl(sar); - - /* On Armada 370, the TCLK frequency can be either 166 Mhz or - * 200 Mhz */ - if (val & (1 << SAR_TCLK_FREQ_BIT)) - rate = 200 * 1000 * 1000; + /* + * On Armada 370, the TCLK frequency can be either + * 166 Mhz or 200 Mhz + */ + if ((val & SAR_TCLK_FREQ) == SAR_TCLK_FREQ) + rate = 200000000; else - rate = 166 * 1000 * 1000; + rate = 166000000; tclk = clk_fixed("tclk", rate); return clk_register_clkdev(tclk, NULL, "mvebu-timer"); } +#define armada_370_xp_init_clocks() armada_370_init_clocks() #endif #if defined(CONFIG_ARCH_ARMADA_XP) -static int mvebu_init_clocks(void) +static int armada_xp_init_clocks(void) { /* On Armada XP, the TCLK frequency is always 250 Mhz */ - tclk = clk_fixed("tclk", 250 * 1000 * 1000); + tclk = clk_fixed("tclk", 250000000); return clk_register_clkdev(tclk, NULL, "mvebu-timer"); } +#define armada_370_xp_init_clocks() armada_xp_init_clocks() #endif -static int mvebu_init_soc(void) +static int armada_370_xp_init_soc(void) { unsigned long phys_base, phys_size; - mvebu_init_clocks(); + armada_370_xp_init_clocks(); add_generic_device("mvebu-timer", DEVICE_ID_SINGLE, NULL, - MVEBU_TIMER_BASE, 0x30, IORESOURCE_MEM, - NULL); - mvebu_memory_find(&phys_base, &phys_size); + (unsigned int)ARMADA_370_XP_TIMER_BASE, 0x30, + IORESOURCE_MEM, NULL); + armada_370_xp_memory_find(&phys_base, &phys_size); arm_add_mem_device("ram0", phys_base, phys_size); + armada_370_xp_add_uart(); return 0; } - -postcore_initcall(mvebu_init_soc); +postcore_initcall(armada_370_xp_init_soc); void __noreturn reset_cpu(unsigned long addr) { - writel(0x1, MVEBU_SYSCTL_BASE + 0x60); - writel(0x1, MVEBU_SYSCTL_BASE + 0x64); + writel(0x1, ARMADA_370_XP_SYSCTL_BASE + 0x60); + writel(0x1, ARMADA_370_XP_SYSCTL_BASE + 0x64); while (1) ; } diff --git a/arch/arm/mach-mvebu/common.c b/arch/arm/mach-mvebu/common.c new file mode 100644 index 000000000..e2092c870 --- /dev/null +++ b/arch/arm/mach-mvebu/common.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 + * Thomas Petazzoni + * Sebastian Hesselbarth + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +/* + * All MVEBU SoCs start with internal registers at 0xd0000000. + * To get more contiguous address space and as Linux expects them + * there, we remap them early to 0xf1000000. + * + * There is no way to determine internal registers base address + * safely later on, as the remap register itself is within the + * internal registers. + */ +#define MVEBU_BOOTUP_INT_REG_BASE 0xd0000000 +#define MVEBU_BRIDGE_REG_BASE 0x20000 +#define DEVICE_INTERNAL_BASE_ADDR (MVEBU_BRIDGE_REG_BASE + 0x80) + +static void mvebu_remap_registers(void) +{ + writel(MVEBU_REMAP_INT_REG_BASE, + IOMEM(MVEBU_BOOTUP_INT_REG_BASE) + DEVICE_INTERNAL_BASE_ADDR); +} + +/* + * Determining the actual memory size is highly SoC dependent, + * but for all SoCs RAM starts at 0x00000000. Therefore, we start + * with a minimal memory setup of 64M and probe correct memory size + * later. + */ +#define MVEBU_BOOTUP_MEMORY_BASE 0x00000000 +#define MVEBU_BOOTUP_MEMORY_SIZE SZ_64M + +void __naked __noreturn mvebu_barebox_entry(void) +{ + mvebu_remap_registers(); + barebox_arm_entry(MVEBU_BOOTUP_MEMORY_BASE, + MVEBU_BOOTUP_MEMORY_SIZE, 0); +} diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c index f073596cc..6e8e1130e 100644 --- a/arch/arm/mach-mvebu/dove.c +++ b/arch/arm/mach-mvebu/dove.c @@ -17,38 +17,35 @@ #include #include #include +#include #include #include -#include -#include #include -#include +#include + +#define CONSOLE_UART_BASE DOVE_UARTn_BASE(CONFIG_MVEBU_CONSOLE_UART) static struct clk *tclk; -static inline void dove_remap_reg_base(uint32_t intbase, - uint32_t mcbase) +static inline void dove_remap_mc_regs(void) { + void __iomem *mcboot = IOMEM(DOVE_BOOTUP_MC_REGS); uint32_t val; /* remap ahb slave base */ val = readl(DOVE_CPU_CTRL) & 0xffff0000; - val |= (mcbase & 0xffff0000) >> 16; + val |= (DOVE_REMAP_MC_REGS & 0xffff0000) >> 16; writel(val, DOVE_CPU_CTRL); /* remap axi bridge address */ val = readl(DOVE_AXI_CTRL) & 0x007fffff; - val |= mcbase & 0xff800000; + val |= DOVE_REMAP_MC_REGS & 0xff800000; writel(val, DOVE_AXI_CTRL); /* remap memory controller base address */ - val = readl(DOVE_SDRAM_BASE + SDRAM_REGS_BASE_DECODE) & 0x0000ffff; - val |= mcbase & 0xffff0000; - writel(val, DOVE_SDRAM_BASE + SDRAM_REGS_BASE_DECODE); - - /* remap internal register */ - val = intbase & 0xfff00000; - writel(val, DOVE_BRIDGE_BASE + INT_REGS_BASE_MAP); + val = readl(mcboot + SDRAM_REGS_BASE_DECODE) & 0x0000ffff; + val |= DOVE_REMAP_MC_REGS & 0xffff0000; + writel(val, mcboot + SDRAM_REGS_BASE_DECODE); } static inline void dove_memory_find(unsigned long *phys_base, @@ -77,32 +74,16 @@ static inline void dove_memory_find(unsigned long *phys_base, } } -void __naked __noreturn dove_barebox_entry(void) -{ - unsigned long phys_base, phys_size; - dove_memory_find(&phys_base, &phys_size); - barebox_arm_entry(phys_base, phys_size, 0); -} - -static struct NS16550_plat uart_plat[] = { - [0] = { .shift = 2, }, - [1] = { .shift = 2, }, - [2] = { .shift = 2, }, - [3] = { .shift = 2, }, +static struct NS16550_plat uart_plat = { + .shift = 2, }; -int dove_add_uart(int num) +static int dove_add_uart(void) { - struct NS16550_plat *plat; - - if (num < 0 || num > 4) - return -EINVAL; - - plat = &uart_plat[num]; - plat->clock = clk_get_rate(tclk); + uart_plat.clock = clk_get_rate(tclk); if (!add_ns16550_device(DEVICE_ID_DYNAMIC, - (unsigned int)DOVE_UARTn_BASE(num), - 32, IORESOURCE_MEM_32BIT, plat)) + (unsigned int)CONSOLE_UART_BASE, 32, + IORESOURCE_MEM_32BIT, &uart_plat)) return -ENODEV; return 0; } @@ -140,12 +121,15 @@ static int dove_init_soc(void) { unsigned long phys_base, phys_size; + dove_remap_mc_regs(); dove_init_clocks(); add_generic_device("orion-timer", DEVICE_ID_SINGLE, NULL, (unsigned int)DOVE_TIMER_BASE, 0x30, IORESOURCE_MEM, NULL); dove_memory_find(&phys_base, &phys_size); arm_add_mem_device("ram0", phys_base, phys_size); + dove_add_uart(); + return 0; } postcore_initcall(dove_init_soc); diff --git a/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h b/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h new file mode 100644 index 000000000..5fd16e573 --- /dev/null +++ b/arch/arm/mach-mvebu/include/mach/armada-370-xp-regs.h @@ -0,0 +1,47 @@ +/* + * Copyright + * (C) 2013 Thomas Petazzoni + * + * 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. + * + */ + +#ifndef __MACH_MVEBU_ARMADA_370_XP_REGS_H +#define __MACH_MVEBU_ARMADA_370_XP_REGS_H + +#include + +#define ARMADA_370_XP_INT_REGS_BASE IOMEM(MVEBU_REMAP_INT_REG_BASE) +#define ARMADA_370_XP_UART_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x12000) +#define ARMADA_370_XP_UARTn_BASE(n) \ + (ARMADA_370_XP_UART_BASE + ((n) * 0x100)) + +#define ARMADA_370_XP_SYSCTL_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x18200) +#define ARMADA_370_XP_SAR_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x18230) +#define SAR_LOW 0x00 +#define SAR_TCLK_FREQ BIT(20) +#define SAR_HIGH 0x04 + +#define ARMADA_370_XP_SDRAM_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x20000) +#define DDR_BASE_CS 0x180 +#define DDR_BASE_CSn(n) (DDR_BASE_CS + ((n) * 0x8)) +#define DDR_BASE_CS_HIGH_MASK 0x0000000f +#define DDR_BASE_CS_LOW_MASK 0xff000000 +#define DDR_SIZE_CS 0x184 +#define DDR_SIZE_CSn(n) (DDR_SIZE_CS + ((n) * 0x8)) +#define DDR_SIZE_ENABLED BIT(0) +#define DDR_SIZE_CS_MASK 0x0000001c +#define DDR_SIZE_CS_SHIFT 2 +#define DDR_SIZE_MASK 0xff000000 + +#define ARMADA_370_XP_TIMER_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x20300) + +#endif /* __MACH_MVEBU_DOVE_REGS_H */ diff --git a/arch/arm/boards/marvell-armada-xp-gp/marvell-armada-xp-gp.c b/arch/arm/mach-mvebu/include/mach/common.h similarity index 65% rename from arch/arm/boards/marvell-armada-xp-gp/marvell-armada-xp-gp.c rename to arch/arm/mach-mvebu/include/mach/common.h index 735132947..3cc1bf71c 100644 --- a/arch/arm/boards/marvell-armada-xp-gp/marvell-armada-xp-gp.c +++ b/arch/arm/mach-mvebu/include/mach/common.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2013 Thomas Petazzoni + * Copyright (C) 2013 + * Thomas Petazzoni + * Sebastian Hesselbarth * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -13,13 +15,9 @@ * */ -#include -#include -#include +#ifndef __MACH_COMMON_H__ +#define __MACH_COMMON_H__ -static int marvell_armada_xp_gp_console_init(void) -{ - return mvebu_add_uart0(); -} +#define MVEBU_REMAP_INT_REG_BASE 0xf1000000 -console_initcall(marvell_armada_xp_gp_console_init); +#endif diff --git a/arch/arm/mach-mvebu/include/mach/debug_ll.h b/arch/arm/mach-mvebu/include/mach/debug_ll.h index 265357391..1cf821ee2 100644 --- a/arch/arm/mach-mvebu/include/mach/debug_ll.h +++ b/arch/arm/mach-mvebu/include/mach/debug_ll.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Thomas Petazzoni + * Copyright (C) 2013 + * Thomas Petazzoni * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,23 +19,25 @@ #include -#define UART_BASE 0xd0012000 -#define UART_THR 0x0 -#define UART_LSR 0x14 -#define UART_LSR_THRE (1 << 5) +#define UART_BASE 0xf1012000 +#define UARTn_BASE(n) (UART_BASE + ((n) * 0x100)) +#define UART_THR 0x00 +#define UART_LSR 0x14 +#define LSR_THRE BIT(5) + +#define EARLY_UART UARTn_BASE(CONFIG_MVEBU_CONSOLE_UART) static inline void PUTC_LL(char c) { /* Wait until there is space in the FIFO */ - while (!(readl(UART_BASE + UART_LSR) & UART_LSR_THRE)) + while (!(readl(EARLY_UART + UART_LSR) & LSR_THRE)) ; /* Send the character */ - writel(c, UART_BASE + UART_THR) - ; + writel(c, EARLY_UART + UART_THR); - /* Wait to make sure it hits the line, in case we die too soon. */ - while (!(readl(UART_BASE + UART_LSR) & UART_LSR_THRE)) + /* Wait to make sure it hits the line */ + while (!(readl(EARLY_UART + UART_LSR) & LSR_THRE)) ; } #endif diff --git a/arch/arm/mach-mvebu/include/mach/dove-regs.h b/arch/arm/mach-mvebu/include/mach/dove-regs.h index 5e203688d..519457e3d 100644 --- a/arch/arm/mach-mvebu/include/mach/dove-regs.h +++ b/arch/arm/mach-mvebu/include/mach/dove-regs.h @@ -17,15 +17,18 @@ #ifndef __MACH_MVEBU_DOVE_REGS_H #define __MACH_MVEBU_DOVE_REGS_H -/* At Boot-up register base is at 0xd000000 */ -#define DOVE_INT_REGS_BOOTUP 0xd0000000 -#define DOVE_MC_REGS_BOOTUP 0xd0800000 -/* Linux wants it remapped to 0xf1000000 */ -#define DOVE_INT_REGS_REMAP 0xf1000000 -#define DOVE_MC_REGS_REMAP 0xf1800000 +#include -#define DOVE_INT_REGS_BASE IOMEM(DOVE_INT_REGS_BOOTUP) -#define DOVE_MC_REGS_BASE IOMEM(DOVE_MC_REGS_BOOTUP) +/* + * Even after MVEBU SoC internal register base remap. Dove MC + * registers are still at 0xd0800000. We remap it right after + * internal registers to 0xf1800000. +*/ +#define DOVE_BOOTUP_MC_REGS 0xd0800000 +#define DOVE_REMAP_MC_REGS 0xf1800000 + +#define DOVE_INT_REGS_BASE IOMEM(MVEBU_REMAP_INT_REG_BASE) +#define DOVE_MC_REGS_BASE IOMEM(DOVE_REMAP_MC_REGS) #define DOVE_UART_BASE (DOVE_INT_REGS_BASE + 0x12000) #define DOVE_UARTn_BASE(n) (DOVE_UART_BASE + ((n) * 0x100)) diff --git a/arch/arm/mach-mvebu/include/mach/kirkwood-regs.h b/arch/arm/mach-mvebu/include/mach/kirkwood-regs.h index 23e221ba9..39fa37900 100644 --- a/arch/arm/mach-mvebu/include/mach/kirkwood-regs.h +++ b/arch/arm/mach-mvebu/include/mach/kirkwood-regs.h @@ -17,21 +17,34 @@ #ifndef __MACH_MVEBU_KIRKWOOD_REGS_H #define __MACH_MVEBU_KIRKWOOD_REGS_H -#define KIRKWOOD_INT_REGS_BASE IOMEM(0xd0000000) +#include -#define KIRKWOOD_SDRAM_WIN_BASE (KIRKWOOD_INT_REGS_BASE + 0x1500) -#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) -#define DDR_BASE_CS_HIGH_MASK 0xf -#define DDR_BASE_CS_LOW_MASK 0xff000000 -#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3)) -#define DDR_SIZE_ENABLED (1 << 0) -#define DDR_SIZE_CS_MASK 0x1c -#define DDR_SIZE_CS_SHIFT 2 -#define DDR_SIZE_MASK 0xff000000 -#define KIRKWOOD_SAR_BASE (KIRKWOOD_INT_REGS_BASE + 0x10030) -#define KIRKWOOD_TCLK_BIT 21 -#define KIRKWOOD_UART_BASE (KIRKWOOD_INT_REGS_BASE + 0x12000) -#define KIRKWOOD_CPUCTRL_BASE (KIRKWOOD_INT_REGS_BASE + 0x20100) -#define KIRKWOOD_TIMER_BASE (KIRKWOOD_INT_REGS_BASE + 0x20300) +#define KIRKWOOD_INT_REGS_BASE IOMEM(MVEBU_REMAP_INT_REG_BASE) + +#define KIRKWOOD_SDRAM_BASE (KIRKWOOD_INT_REGS_BASE + 0x00000) +#define DDR_BASE_CS 0x1500 +#define DDR_BASE_CSn(n) (DDR_BASE_CS + ((n) * 0x8)) +#define DDR_BASE_CS_HIGH_MASK 0x0000000f +#define DDR_BASE_CS_LOW_MASK 0xff000000 +#define DDR_SIZE_CS 0x1504 +#define DDR_SIZE_CSn(n) (DDR_SIZE_CS + ((n) * 0x8)) +#define DDR_SIZE_ENABLED BIT(0) +#define DDR_SIZE_CS_MASK 0x1c +#define DDR_SIZE_CS_SHIFT 2 +#define DDR_SIZE_MASK 0xff000000 + +#define KIRKWOOD_SAR_BASE (KIRKWOOD_INT_REGS_BASE + 0x10030) +#define SAR_TCLK_FREQ BIT(21) + +#define KIRKWOOD_UART_BASE (KIRKWOOD_INT_REGS_BASE + 0x12000) +#define KIRKWOOD_UARTn_BASE(n) (KIRKWOOD_UART_BASE + ((n) * 0x100)) + +#define KIRKWOOD_BRIDGE_BASE (KIRKWOOD_INT_REGS_BASE + 0x20000) +#define BRIDGE_RSTOUT_MASK 0x108 +#define SOFT_RESET_OUT_EN BIT(2) +#define BRIDGE_SYS_SOFT_RESET 0x10c +#define SOFT_RESET_EN BIT(0) + +#define KIRKWOOD_TIMER_BASE (KIRKWOOD_INT_REGS_BASE + 0x20300) #endif /* __MACH_MVEBU_KIRKWOOD_REGS_H */ diff --git a/arch/arm/boards/plathome-openblocks-ax3/plathome-openblocks-ax3.c b/arch/arm/mach-mvebu/include/mach/lowlevel.h similarity index 64% rename from arch/arm/boards/plathome-openblocks-ax3/plathome-openblocks-ax3.c rename to arch/arm/mach-mvebu/include/mach/lowlevel.h index 9daf020a0..e86d928f6 100644 --- a/arch/arm/boards/plathome-openblocks-ax3/plathome-openblocks-ax3.c +++ b/arch/arm/mach-mvebu/include/mach/lowlevel.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2013 Thomas Petazzoni + * Copyright (C) 2013 + * Thomas Petazzoni + * Sebastian Hesselbarth * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -13,13 +15,9 @@ * */ -#include -#include -#include +#ifndef __MACH_LOWLEVEL_H__ +#define __MACH_LOWLEVEL_H__ -static int plathome_openblocks_ax3_console_init(void) -{ - return mvebu_add_uart0(); -} +void mvebu_barebox_entry(void); -console_initcall(plathome_openblocks_ax3_console_init); +#endif diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c index b5b6aaf9a..3e16f410b 100644 --- a/arch/arm/mach-mvebu/kirkwood.c +++ b/arch/arm/mach-mvebu/kirkwood.c @@ -16,30 +16,30 @@ #include #include #include +#include #include #include -#include -#include #include -#include +#include + +#define CONSOLE_UART_BASE KIRKWOOD_UARTn_BASE(CONFIG_MVEBU_CONSOLE_UART) static struct clk *tclk; static inline void kirkwood_memory_find(unsigned long *phys_base, - unsigned long *phys_size) + unsigned long *phys_size) { - void __iomem *sdram_win = IOMEM(KIRKWOOD_SDRAM_WIN_BASE); int cs; *phys_base = ~0; *phys_size = 0; for (cs = 0; cs < 4; cs++) { - uint32_t base = readl(sdram_win + DDR_BASE_CS_OFF(cs)); - uint32_t ctrl = readl(sdram_win + DDR_SIZE_CS_OFF(cs)); + u32 base = readl(KIRKWOOD_SDRAM_BASE + DDR_BASE_CSn(cs)); + u32 ctrl = readl(KIRKWOOD_SDRAM_BASE + DDR_SIZE_CSn(cs)); /* Skip non-enabled CS */ - if (! (ctrl & DDR_SIZE_ENABLED)) + if ((ctrl & DDR_SIZE_ENABLED) != DDR_SIZE_ENABLED) continue; base &= DDR_BASE_CS_LOW_MASK; @@ -49,34 +49,30 @@ static inline void kirkwood_memory_find(unsigned long *phys_base, } } -void __naked __noreturn kirkwood_barebox_entry(void) -{ - unsigned long phys_base, phys_size; - kirkwood_memory_find(&phys_base, &phys_size); - writel('E', 0xD0012000); - barebox_arm_entry(phys_base, phys_size, 0); -} - static struct NS16550_plat uart_plat = { .shift = 2, }; -int kirkwood_add_uart0(void) +static int kirkwood_add_uart(void) { uart_plat.clock = clk_get_rate(tclk); if (!add_ns16550_device(DEVICE_ID_DYNAMIC, - (unsigned int)KIRKWOOD_UART_BASE, - 32, IORESOURCE_MEM_32BIT, &uart_plat)) + (unsigned int)CONSOLE_UART_BASE, 32, + IORESOURCE_MEM_32BIT, &uart_plat)) return -ENODEV; return 0; } static int kirkwood_init_clocks(void) { - uint32_t sar = readl(KIRKWOOD_SAR_BASE); + u32 val = readl(KIRKWOOD_SAR_BASE); unsigned int rate; - if (sar & (1 << KIRKWOOD_TCLK_BIT)) + /* + * On Kirkwood, the TCLK frequency can be either + * 166 Mhz or 200 Mhz + */ + if ((val & SAR_TCLK_FREQ) == SAR_TCLK_FREQ) rate = 166666667; else rate = 200000000; @@ -95,16 +91,16 @@ static int kirkwood_init_soc(void) IORESOURCE_MEM, NULL); kirkwood_memory_find(&phys_base, &phys_size); arm_add_mem_device("ram0", phys_base, phys_size); + kirkwood_add_uart(); return 0; } - postcore_initcall(kirkwood_init_soc); void __noreturn reset_cpu(unsigned long addr) { - writel(0x4, KIRKWOOD_CPUCTRL_BASE + 0x8); - writel(0x1, KIRKWOOD_CPUCTRL_BASE + 0xC); + writel(SOFT_RESET_OUT_EN, KIRKWOOD_BRIDGE_BASE + BRIDGE_RSTOUT_MASK); + writel(SOFT_RESET_EN, KIRKWOOD_BRIDGE_BASE + BRIDGE_SYS_SOFT_RESET); for(;;) ; } diff --git a/arch/arm/boards/globalscale-mirabox/lowlevel.c b/arch/arm/mach-mvebu/lowlevel.c similarity index 80% rename from arch/arm/boards/globalscale-mirabox/lowlevel.c rename to arch/arm/mach-mvebu/lowlevel.c index 3ca202e0a..3f64c4a5b 100644 --- a/arch/arm/boards/globalscale-mirabox/lowlevel.c +++ b/arch/arm/mach-mvebu/lowlevel.c @@ -1,5 +1,7 @@ /* - * Copyright (C) 2013 Thomas Petazzoni + * Copyright (C) 2013 + * Thomas Petazzoni + * Sebastian Hesselbarth * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,7 +19,7 @@ #include #include #include -#include +#include void __naked barebox_arm_reset_vector(void) {