Commit ab2a63b5 authored by Marek Vasut's avatar Marek Vasut
Browse files

mxssb: Add support for generating DCD block



This patch adds support for generating DCD blocks. The DCD blocks can be
used to write values to memory or preconfigure the hardware or CPU.
Signed-off-by: Marek Vasut's avatarMarek Vasut <marex@denx.de>
parent b04b919d
......@@ -35,7 +35,8 @@ These semantics and rules will be outlined now.
- Each line of the configuration file contains exactly one instruction.
- Every numeric value must be encoded in hexadecimal and in format 0xabcdef12 .
- The configuration file is a concatenation of blocks called "sections".
- The configuration file is a concatenation of blocks called "sections" and
optionally "DCD blocks" (see below).
- Each "section" is started by the "SECTION" instruction.
- The "SECTION" instruction has the following semantics:
......@@ -69,6 +70,11 @@ These semantics and rules will be outlined now.
of u32_IVT_entry_point.
- i.MX28-specific instruction!
LOAD DCD u32_address u32_DCD_block_ID
- Loads the DCD block with ID "u32_DCD_block_ID" onto address
"u32_address" and executes the contents of this DCD block
- i.MX28-specific instruction!
FILL u32_address u32_pattern u32_length
- Starts to write memory from addres "u32_address" with a pattern
specified by "u32_pattern". Writes exactly "u32_length" bytes of the
......@@ -96,6 +102,31 @@ These semantics and rules will be outlined now.
i.MX28, string_mode = USB/I2C/SPI2_FLASH/SPI3_FLASH/NAND_BCH
JTAG/SPI2_EEPROM/SD_SSP0/SD_SSP1
- An optional "DCD" blocks can be added at the begining of the configuration
file. Note that the DCD is only supported on i.MX28.
- The DCD blocks must be inserted before the first "section" in the
configuration file.
- The DCD block has the following semantics:
DCD u32_DCD_block_ID
- u32_DCD_block_ID :: The ID number of the DCD block, must match
the ID number used by "LOAD DCD" instruction.
- The DCD block must be followed by one of the following instructions. All
of the instructions operate either on 1, 2 or 4 bytes. This is selected by
the 'n' suffix of the instruction:
WRITE.n u32_address u32_value
- Write the "u32_value" to the "u32_address" address.
ORR.n u32_address u32_value
- Read the "u32_address", perform a bitwise-OR with the "u32_value" and
write the result back to "u32_address".
ANDC.n u32_address u32_value
- Read the "u32_address", perform a bitwise-AND with the complement of
"u32_value" and write the result back to "u32_address".
- If the verbose output from the BootROM is enabled by passing the "-v" option
to MXSSB, the BootROM will produce a letter on the Debug UART for each
instruction it started processing. Here is a mapping between the above
......
......@@ -25,6 +25,47 @@
#include "mxssb.h"
/*
* DCD block
* |-Write to address command block
* | 0xf00 == 0xf33d
* | 0xba2 == 0xb33f
* |-ORR address with mask command block
* | 0xf00 |= 0x1337
* |-Write to address command block
* | 0xba2 == 0xd00d
* :
*/
#define SB_HAB_DCD_WRITE 0xcc
#define SB_HAB_DCD_CHECK 0xcf
#define SB_HAB_DCD_NOOP 0xc0
enum sb_dcd_cmd {
SB_DCD_WRITE1 = 0xcc000001, /* Addr.1 = Value.1 */
SB_DCD_WRITE2 = 0xcc000002, /* Addr.2 = Value.2 */
SB_DCD_WRITE4 = 0xcc000004, /* Addr.4 = Value.4 */
SB_DCD_ANDC1 = 0xcc000011, /* Addr.1 &= ~Value.1 */
SB_DCD_ANDC2 = 0xcc000012, /* Addr.2 &= ~Value.2 */
SB_DCD_ANDC4 = 0xcc000014, /* Addr.4 &= ~Value.4 */
SB_DCD_ORR1 = 0xcc000019, /* Addr.1 |= Value.1 */
SB_DCD_ORR2 = 0xcc00001a, /* Addr.2 |= Value.2 */
SB_DCD_ORR4 = 0xcc00001c, /* Addr.4 |= Value.4 */
};
struct sb_dcd_ctx {
struct sb_dcd_ctx *dcd;
uint32_t id;
/* The DCD block. */
uint32_t *payload;
/* Size of the whole DCD block. */
uint32_t size;
/* Pointer to previous DCD command block. */
uint32_t *prev_dcd_head;
};
/*
* IMAGE
* |-SECTION
......@@ -68,6 +109,8 @@ struct sb_section_ctx {
};
struct sb_image_ctx {
unsigned int in_section:1;
unsigned int in_dcd:1;
/* Image configuration */
unsigned int verbose_boot:1;
unsigned int silent_dump:1;
......@@ -85,6 +128,9 @@ struct sb_image_ctx {
struct sb_section_ctx *sect_head;
struct sb_section_ctx *sect_tail;
struct sb_dcd_ctx *dcd_head;
struct sb_dcd_ctx *dcd_tail;
EVP_CIPHER_CTX cipher_ctx;
EVP_MD_CTX md_ctx;
uint8_t digest[32];
......@@ -529,6 +575,165 @@ static int sb_token_to_long(char *tok, uint32_t *rid)
return 0;
}
static int sb_grow_dcd(struct sb_dcd_ctx *dctx, unsigned int inc_size)
{
uint32_t *tmp;
if (!inc_size)
return 0;
dctx->size += inc_size;
tmp = realloc(dctx->payload, dctx->size);
if (!tmp)
return -ENOMEM;
dctx->payload = tmp;
/* Assemble and update the HAB DCD header. */
dctx->payload[0] = htonl((SB_HAB_DCD_TAG << 24) |
(dctx->size << 8) |
SB_HAB_VERSION);
return 0;
}
static int sb_build_dcd(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
{
struct sb_dcd_ctx *dctx;
char *tok;
uint32_t id;
int ret;
dctx = calloc(1, sizeof(*dctx));
if (!dctx)
return -ENOMEM;
ret = sb_grow_dcd(dctx, 4);
if (ret)
goto err_dcd;
/* Read DCD block number. */
tok = strtok(cmd->cmd, " ");
if (!tok) {
fprintf(stderr, "#%i ERR: DCD block without number!\n",
cmd->lineno);
ret = -EINVAL;
goto err_dcd;
}
/* Parse the DCD block number. */
ret = sb_token_to_long(tok, &id);
if (ret) {
fprintf(stderr, "#%i ERR: Malformed DCD block number!\n",
cmd->lineno);
goto err_dcd;
}
dctx->id = id;
/*
* The DCD block is now constructed. Append it to the list.
* WARNING: The DCD size is still not computed and will be
* updated while parsing it's commands.
*/
if (!ictx->dcd_head) {
ictx->dcd_head = dctx;
ictx->dcd_tail = dctx;
} else {
ictx->dcd_tail->dcd = dctx;
ictx->dcd_tail = dctx;
}
return 0;
err_dcd:
free(dctx->payload);
free(dctx);
return ret;
}
static int sb_build_dcd_block(struct sb_image_ctx *ictx,
struct sb_cmd_list *cmd,
enum sb_dcd_cmd type)
{
char *tok;
uint32_t address, value, length;
int ret;
struct sb_dcd_ctx *dctx = ictx->dcd_tail;
uint32_t *dcd;
if (dctx->prev_dcd_head &&
((dctx->prev_dcd_head[0] & 0xff0000ff) == type)) {
/* Same instruction as before, just append it. */
ret = sb_grow_dcd(dctx, 8);
if (ret)
return ret;
} else {
/*
* Either a different instruction block started now
* or this is the first instruction block.
*/
ret = sb_grow_dcd(dctx, 12);
if (ret)
return ret;
/* Update DCD command block pointer. */
dctx->prev_dcd_head = dctx->payload +
dctx->size / sizeof(*dctx->payload) - 3;
}
dcd = dctx->payload + dctx->size / sizeof(*dctx->payload) - 2;
/*
* Prepare the command.
*/
tok = strtok(cmd->cmd, " ");
if (!tok) {
fprintf(stderr, "#%i ERR: Missing DCD address!\n",
cmd->lineno);
ret = -EINVAL;
goto err;
}
/* Read DCD destination address. */
ret = sb_token_to_long(tok, &address);
if (ret) {
fprintf(stderr, "#%i ERR: Incorrect DCD address!\n",
cmd->lineno);
goto err;
}
tok = strtok(NULL, " ");
if (!tok) {
fprintf(stderr, "#%i ERR: Missing DCD value!\n",
cmd->lineno);
ret = -EINVAL;
goto err;
}
/* Read DCD operation value. */
ret = sb_token_to_long(tok, &value);
if (ret) {
fprintf(stderr, "#%i ERR: Incorrect DCD value!\n",
cmd->lineno);
goto err;
}
/* Fill in the new DCD entry. */
dcd[0] = htonl(address);
dcd[1] = htonl(value);
/* Update the DCD command block. */
length = dctx->size -
((dctx->prev_dcd_head - dctx->payload) * sizeof(*dctx->payload));
dctx->prev_dcd_head[0] = htonl(type | (length << 8));
err:
return ret;
}
static int sb_build_section(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
{
struct sb_section_ctx *sctx;
......@@ -686,8 +891,8 @@ static int sb_build_command_load(struct sb_image_ctx *ictx, struct sb_cmd_list *
struct sb_cmd_ctx *cctx;
struct sb_command *ccmd;
char *tok;
int ret, is_ivt = 0;
uint32_t dest;
int ret, is_ivt = 0, is_dcd = 0;
uint32_t dest, dcd = 0;
cctx = calloc(1, sizeof(*cctx));
if (!cctx)
......@@ -707,8 +912,11 @@ static int sb_build_command_load(struct sb_image_ctx *ictx, struct sb_cmd_list *
}
/* Check for "IVT" flag. */
if (!strcmp(tok, "IVT")) {
if (!strcmp(tok, "IVT"))
is_ivt = 1;
if (!strcmp(tok, "DCD"))
is_dcd = 1;
if (is_ivt || is_dcd) {
tok = strtok(NULL, " ");
if (!tok) {
fprintf(stderr, "#%i ERR: Missing LOAD address!\n",
......@@ -726,10 +934,11 @@ static int sb_build_command_load(struct sb_image_ctx *ictx, struct sb_cmd_list *
goto err;
}
/* Read filename or IVT entrypoint. */
/* Read filename or IVT entrypoint or DCD block ID. */
tok = strtok(NULL, " ");
if (!tok) {
fprintf(stderr, "#%i ERR: Missing LOAD filename or IVT ep!\n",
fprintf(stderr, "#%i ERR: Missing LOAD filename or "
"IVT ep or DCD block ID!\n",
cmd->lineno);
ret = -EINVAL;
goto err;
......@@ -760,6 +969,46 @@ static int sb_build_command_load(struct sb_image_ctx *ictx, struct sb_cmd_list *
cctx->data = (uint8_t *)ivt;
cctx->length = sizeof(*ivt);
} else if (is_dcd) {
struct sb_dcd_ctx *dctx = ictx->dcd_head;
uint32_t dcdid;
uint8_t *payload;
uint32_t asize;
ret = sb_token_to_long(tok, &dcdid);
if (ret) {
fprintf(stderr,
"#%i ERR: Incorrect DCD block ID!\n",
cmd->lineno);
goto err;
}
while (dctx) {
if (dctx->id == dcdid)
break;
dctx = dctx->dcd;
}
if (!dctx) {
fprintf(stderr, "#%i ERR: DCD block %08x not found!\n",
cmd->lineno, dcdid);
goto err;
}
asize = roundup(dctx->size, SB_BLOCK_SIZE);
payload = calloc(1, asize);
if (!payload) {
ret = -ENOMEM;
goto err;
}
memcpy(payload, dctx->payload, dctx->size);
cctx->data = payload;
cctx->length = asize;
/* Set the Load DCD flag. */
dcd = ROM_LOAD_CMD_FLAG_DCD_LOAD;
} else {
/* Regular LOAD of a file. */
ret = sb_load_file(cctx, tok);
......@@ -780,6 +1029,8 @@ static int sb_build_command_load(struct sb_image_ctx *ictx, struct sb_cmd_list *
*/
ccmd->header.checksum = 0x5a;
ccmd->header.tag = ROM_LOAD_CMD;
ccmd->header.flags = dcd;
ccmd->load.address = dest;
ccmd->load.count = cctx->length;
ccmd->load.crc32 = crc32(cctx->data, cctx->length);
......@@ -1226,33 +1477,62 @@ static int sb_parse_line(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
cmd->cmd = rptr;
/* DCD */
if (!strcmp(tok, "DCD")) {
ictx->in_section = 0;
ictx->in_dcd = 1;
sb_build_dcd(ictx, cmd);
return 0;
}
/* Section */
if (!strcmp(tok, "SECTION")) {
ictx->in_section = 1;
ictx->in_dcd = 0;
sb_build_section(ictx, cmd);
return 0;
}
if (!ictx->sect_tail) {
if (!ictx->in_section && !ictx->in_dcd) {
fprintf(stderr, "#%i ERR: Data outside of a section!\n",
cmd->lineno);
return -EINVAL;
}
/* Commands */
if (!strcmp(tok, "NOP"))
/* Section commands */
if (ictx->in_section && !strcmp(tok, "NOP"))
ret = sb_build_command_nop(ictx);
else if (!strcmp(tok, "TAG"))
else if (ictx->in_section && !strcmp(tok, "TAG"))
ret = sb_build_command_tag(ictx, cmd);
else if (!strcmp(tok, "LOAD"))
else if (ictx->in_section && !strcmp(tok, "LOAD"))
ret = sb_build_command_load(ictx, cmd);
else if (!strcmp(tok, "FILL"))
else if (ictx->in_section && !strcmp(tok, "FILL"))
ret = sb_build_command_fill(ictx, cmd);
else if (!strcmp(tok, "JUMP"))
else if (ictx->in_section && !strcmp(tok, "JUMP"))
ret = sb_build_command_jump(ictx, cmd);
else if (!strcmp(tok, "CALL"))
else if (ictx->in_section && !strcmp(tok, "CALL"))
ret = sb_build_command_call(ictx, cmd);
else if (!strcmp(tok, "MODE"))
else if (ictx->in_section && !strcmp(tok, "MODE"))
ret = sb_build_command_mode(ictx, cmd);
/* DCD commands */
else if (ictx->in_dcd && !strcmp(tok, "WRITE.1"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_WRITE1);
else if (ictx->in_dcd && !strcmp(tok, "WRITE.2"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_WRITE2);
else if (ictx->in_dcd && !strcmp(tok, "WRITE.4"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_WRITE4);
else if (ictx->in_dcd && !strcmp(tok, "ANDC.1"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_ANDC1);
else if (ictx->in_dcd && !strcmp(tok, "ANDC.2"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_ANDC2);
else if (ictx->in_dcd && !strcmp(tok, "ANDC.4"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_ANDC4);
else if (ictx->in_dcd && !strcmp(tok, "ORR.1"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_ORR1);
else if (ictx->in_dcd && !strcmp(tok, "ORR.2"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_ORR2);
else if (ictx->in_dcd && !strcmp(tok, "ORR.4"))
ret = sb_build_dcd_block(ictx, cmd, SB_DCD_ORR4);
else {
fprintf(stderr, "#%i ERR: Unsupported instruction '%s'!\n",
cmd->lineno, tok);
......@@ -1265,7 +1545,7 @@ static int sb_parse_line(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
*
* FIXME -- should the updating happen here ?
*/
if (!ret) {
if (ictx->in_section && !ret) {
ictx->sect_tail->size += ictx->sect_tail->cmd_tail->size;
ictx->sect_tail->payload.section_size = ictx->sect_tail->size / SB_BLOCK_SIZE;
}
......@@ -1814,6 +2094,7 @@ err_open:
static void sb_free_image(struct sb_image_ctx *ictx)
{
struct sb_section_ctx *sctx = ictx->sect_head, *s_head;
struct sb_dcd_ctx *dctx = ictx->dcd_head, *d_head;
struct sb_cmd_ctx *cctx, *c_head;
while (sctx) {
......@@ -1831,6 +2112,13 @@ static void sb_free_image(struct sb_image_ctx *ictx)
sctx = sctx->sect;
free(s_head);
}
while (dctx) {
d_head = dctx;
dctx = dctx->dcd;
free(d_head->payload);
free(d_head);
}
}
static void print_help(const char *pn)
......
......@@ -87,6 +87,8 @@ struct sb_ivt_header {
};
#define SB_HAB_IVT_TAG 0xd1UL
#define SB_HAB_DCD_TAG 0xd2UL
#define SB_HAB_VERSION 0x40UL
/*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment