summaryrefslogtreecommitdiffstats
path: root/src/roms/SLOF/board-js2x/rtas/rtas_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/roms/SLOF/board-js2x/rtas/rtas_flash.c')
-rw-r--r--src/roms/SLOF/board-js2x/rtas/rtas_flash.c614
1 files changed, 614 insertions, 0 deletions
diff --git a/src/roms/SLOF/board-js2x/rtas/rtas_flash.c b/src/roms/SLOF/board-js2x/rtas/rtas_flash.c
new file mode 100644
index 0000000..189878d
--- /dev/null
+++ b/src/roms/SLOF/board-js2x/rtas/rtas_flash.c
@@ -0,0 +1,614 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <hw.h>
+#include <rtas.h>
+#include "rtas_board.h"
+#include <bmc.h>
+#include "rtas_flash.h"
+#include <flash/block_lists.h>
+#include "product.h"
+#include "calculatecrc.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define dprintf(_x ...) printf(_x)
+#else
+#define dprintf(_x ...)
+#endif
+
+static uint64_t size;
+static uint64_t flashOffset;
+
+unsigned char manage_flash_buffer[BUFSIZE*2];
+unsigned long check_flash_image(unsigned long rombase, unsigned long length,
+ unsigned long start_crc);
+
+#ifdef DEBUG
+static void
+dump_blocklist(uint64_t *bl, int version)
+{
+ uint64_t bl_size;
+ uint8_t *addr = (uint8_t *)bl;
+
+ if (version == 1) {
+ /* version 1 blocklist */
+ bl_size = *bl & 0x00FFFFFFFFFFFFFFUL;
+
+ } else {
+ bl_size = *bl;
+ }
+
+ printf("\n\rblocklist_dump %lx", bl_size);
+ while (bl_size) {
+ unsigned int tmpCnt = bl_size;
+ unsigned char x;
+ if (tmpCnt > 8)
+ tmpCnt = 8;
+ printf("\n\r%08x: ", addr);
+ /* print hex */
+ while (tmpCnt--) {
+ set_ci();
+ x = *addr++;
+ clr_ci();
+ printf("%02x ", x);
+ }
+ tmpCnt = bl_size;
+ if (tmpCnt > 8)
+ tmpCnt = 8;
+ bl_size -= tmpCnt;
+ /* reset addr ptr to print ascii */
+ addr = addr - tmpCnt;
+ /* print ascii */
+ while (tmpCnt--) {
+ set_ci();
+ x = *addr++;
+ clr_ci();
+ if ((x < 32) || (x >= 127)) {
+ /* non-printable char */
+ x = '.';
+ }
+ printf("%c", x);
+ }
+ }
+ printf("\r\n");
+}
+#endif
+
+void
+rtas_dump_flash(rtas_args_t *rtas_args)
+{
+ int retVal = 0;
+ unsigned int size = rtas_args->args[0];
+ unsigned int offset = rtas_args->args[1];
+ volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+
+ printf("\n\rflash_dump %x %x", size, offset);
+ flash += offset;
+ while (size) {
+ unsigned int tmpCnt = size;
+ unsigned char x;
+ if (tmpCnt > 16)
+ tmpCnt = 16;
+ printf("\n\r%p: ", flash);
+ /* print hex */
+ while (tmpCnt--) {
+ set_ci();
+ x = *flash++;
+ clr_ci();
+ printf("%02x ", x);
+ }
+ tmpCnt = size;
+ if (tmpCnt > 16)
+ tmpCnt = 16;
+ size -= tmpCnt;
+ /* reset flash ptr to print ascii */
+ flash = flash - tmpCnt;
+ /* print ascii */
+ while (tmpCnt--) {
+ set_ci();
+ x = *flash++;
+ clr_ci();
+ if ((x < 32) || (x >= 127)) {
+ /* non-printable char */
+ x = '.';
+ }
+ printf("%c", x);
+ }
+ }
+ printf("\r\n");
+ rtas_args->args[rtas_args->nargs] = retVal;
+}
+
+
+static void
+print_block(int i)
+{
+ int counter = 8;
+
+ while (counter--)
+ printf("\b");
+ printf("%08x", i);
+}
+
+
+
+/* To enter data mode after flash has been in programming mode
+ * a 0xFF has to be written */
+static void
+enter_data_mode(void)
+{
+ volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+
+ set_ci();
+ *flash = 0xFF;
+ eieio();
+ clr_ci();
+}
+
+
+static void
+erase_flash_block(unsigned long offset)
+{
+ volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+
+ flash += offset;
+ set_ci();
+ *flash = 0x20;
+ eieio();
+ *flash = 0xd0;
+ eieio();
+ while (!(*flash & 0x80)) ;
+ clr_ci();
+}
+
+
+void
+write_flash(unsigned long offset, unsigned char *data)
+{
+ int cnt = 32;
+ volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+
+ flash += (offset + flashOffset);
+ set_ci();
+ while (cnt) {
+ if (!((uint64_t)flash & 0x1F)) {
+ while (cnt) {
+ uint64_t tmpcnt = cnt;
+ if (tmpcnt > 0x20)
+ tmpcnt = 0x20;
+ do {
+ *flash = 0xE8;
+ eieio();
+ } while (!(*flash & 0x80));
+ cnt -= tmpcnt;
+ *flash = tmpcnt - 1;
+ while (tmpcnt--) {
+ *flash++ = *data++;
+ }
+ *flash = 0xD0;
+ eieio();
+ while (!(*flash & 0x80)) ;
+ }
+ break;
+ }
+ *flash = 0x40;
+ eieio();
+ *flash++ = *data++;
+ eieio();
+ while (!(*flash & 0x80)) ;
+ cnt--;
+ }
+ clr_ci();
+}
+
+static void
+write_flash_page(unsigned long offset, unsigned short *data)
+{
+ int i = 0;
+
+ for (i = 0; i < BUFSIZE; i += 32, offset += 32) {
+ write_flash(offset, ((unsigned char *)data + i));
+ }
+}
+
+/*
+ * 0 reject temporary image
+ * 1 commit temporary image
+ * */
+static int
+copy_flash(short mode)
+{
+ volatile unsigned char *flash = (volatile unsigned char *)FLASH;
+ uint64_t blockCnt;
+ uint64_t hash = 0;
+ short notmode = mode ^ 0x1;
+
+ if (bmc_set_flashside(notmode) != notmode) {
+ return -1;
+ }
+ printf("\r\nErasing Flash: 0x ");
+
+ for (blockCnt = 0; blockCnt <= FLASHSIZE; blockCnt += FLASH_BLOCK_SIZE) {
+ print_block(blockCnt);
+ erase_flash_block(blockCnt);
+ }
+ enter_data_mode();
+ progress = FLASHSIZE / 38;
+ print_writing();
+
+ for (blockCnt = 0; blockCnt <= FLASHSIZE; blockCnt += BUFSIZE) {
+ uint64_t *srcPtr = (uint64_t *)(flash + blockCnt);
+ uint64_t *destPtr = (uint64_t *)manage_flash_buffer;
+ uint64_t cnt = BUFSIZE / 8;
+ if (bmc_set_flashside(mode) != mode) {
+ return -1;
+ }
+ enter_data_mode();
+ set_ci();
+ while (cnt--) {
+ *destPtr++ = *srcPtr++;
+ }
+ clr_ci();
+
+ if (bmc_set_flashside(notmode) != notmode) {
+ return -1;
+ }
+ write_flash_page(blockCnt,
+ (unsigned short *)manage_flash_buffer);
+
+ /* progress output... */
+ print_progress();
+ if (blockCnt > hash * progress) {
+ print_hash();
+ hash++;
+ }
+ }
+ enter_data_mode();
+ if (bmc_set_flashside(mode) != mode) {
+ return -1;
+ }
+ printf("\b#\n");
+ return 0;
+}
+
+/*
+ * Function: ibm_manage_flash_image
+ * Input:
+ * r3: rtas parm structure
+ * token: 46
+ * in: 1
+ * out: 1
+ * parm0: 0 reject temporary image
+ * 1 commit temporary image
+ * Output:
+ * parm1: Status (hw -1, busy -2, parameter error -3
+ * -9001 cannot overwrite the active firmware image)
+ *
+ */
+
+void
+rtas_ibm_manage_flash_image(rtas_args_t *rtas_args)
+{
+ int side;
+ int result = 0;
+ short mode = rtas_args->args[0];
+
+ if (mode < 0 || mode > 1) {
+ rtas_args->args[rtas_args->nargs] = -3;
+ return;
+ }
+ side = bmc_get_flashside();
+ if (side == 0) {
+ /* we are on the permanent side */
+ if (mode != 0) {
+ rtas_args->args[rtas_args->nargs] = -9001;
+ return;
+ }
+ } else if (side == 1) {
+ /* we are on the temporary side */
+ if (mode != 1) {
+ rtas_args->args[rtas_args->nargs] = -9001;
+ return;
+ }
+ } else {
+ rtas_args->args[rtas_args->nargs] = -1;
+ return;
+ }
+
+ result = copy_flash(mode);
+ bmc_set_flashside(mode);
+ enter_data_mode();
+ rtas_args->args[rtas_args->nargs] = result;
+}
+
+/**
+ * check, if we find the FLASHFS_MAGIC token in bl
+ **/
+static uint8_t
+check_magic(uint64_t *bl, int version)
+{
+ struct stH *pHeader;
+
+ if (version == 1) {
+ /* version 1 blocklist */
+ /* if block list size <= 0x10, it is only block list header */
+ /* and address of block list extension, so look at the extension... */
+ while ((*bl & 0x00FFFFFFFFFFFFFFUL) <= 0x10)
+ bl = (uint64_t *)bl[1];
+
+ /* block list item 2 _should_ be the address of our flashfs image */
+ pHeader = (struct stH *)(bl[2] + 0x28);
+ /* printf("FlashFS Magic: \"%#s\"\r\n", pHeader->magic); */
+ return strncmp(pHeader->magic, FLASHFS_MAGIC, 8);
+ } else {
+ /* block list item 1 _should_ be the address of our flashfs image */
+ pHeader = (struct stH *)(bl[1] + 0x28);
+ /* printf("FlashFS Magic: \"%#s\"\r\n", pHeader->magic); */
+ return strncmp(pHeader->magic, FLASHFS_MAGIC, 8);
+ }
+}
+
+static void
+get_image_name(char *buffer, int maxsize)
+{
+ volatile struct stH *flash_header = (volatile struct stH *)(SB_FLASH_adr + 0x28);
+ /* since we cannot read the fh_magic directly from flash as a string, we need to copy it to memory */
+ uint64_t magic_val = 0;
+ uint64_t addr;
+
+ /* copy fh_magic to magic_val since, we cannot use it as a string from flash */
+ magic_val = load64_ci((uint64_t)(flash_header->magic));
+ if (strncmp((char *)&magic_val, FLASHFS_MAGIC, 8)) {
+ /* magic does not match */
+ sprintf(buffer, "Unknown");
+ buffer[maxsize - 1] = '\0';
+ return;
+ }
+ addr = (uint64_t)flash_header->version;
+ while (--maxsize) {
+ *buffer = load8_ci(addr++);
+ if (!*buffer++)
+ return;
+ }
+ *buffer = '\0';
+}
+
+/**
+ * validate_flash_image
+ * this function checks if the flash will be updated with the given image
+ * @param args[0] - buffer with minimum 4K of the image to flash
+ * @param args[1] - size of the buffer
+ * @param args[2] - status:
+ * 0 success
+ * -1 hw
+ * -2 busy
+ * -3 parameter error
+ * @param args[3] - update result token
+ */
+void
+rtas_ibm_validate_flash_image(rtas_args_t *rtas_args)
+{
+ dprintf("\nrtas_ibm_validate_flash_image\n");
+ unsigned long new_image = rtas_args->args[0];
+ char *ret_str = (char *)new_image;
+ struct stH *flash_header = (struct stH *)(new_image + 0x28);
+ char current_temp_version[16];
+ char current_perm_version[16];
+ char new_version[16];
+ int side = bmc_get_flashside();
+
+ /* fill args[0] with the current values which is needed
+ * in an error case */
+
+ bmc_set_flashside(0);
+ get_image_name(current_perm_version, sizeof(current_perm_version));
+ bmc_set_flashside(1);
+ get_image_name(current_temp_version, sizeof(current_temp_version));
+ bmc_set_flashside(side);
+
+ /* check if the candidate image if valid for this platform */
+ if (strncmp(flash_header->magic, FLASHFS_MAGIC, 8)) {
+ /* magic does not match */
+ rtas_args->args[rtas_args->nargs] = 0;
+ /* No update done, the candidate image is
+ * not valid for this platform */
+ rtas_args->args[rtas_args->nargs + 1] = 2;
+ sprintf(ret_str, "MI %s %s\xaMI %s %s",
+ current_temp_version, current_perm_version,
+ current_temp_version, current_perm_version);
+ return;
+ }
+
+ if (strncmp(flash_header->platform_name, (char *)sig_org, 32)) {
+ /* this image if for a different board */
+ rtas_args->args[rtas_args->nargs] = 0;
+ /* No update done, the candidate image is
+ * not valid for this platform */
+ rtas_args->args[rtas_args->nargs + 1] = 2;
+ sprintf(ret_str, "MI %s %s\xaMI %s %s",
+ current_temp_version, current_perm_version,
+ current_temp_version, current_perm_version);
+ return;
+ }
+
+ /* check header crc */
+ if (check_flash_image(rtas_args->args[0], 0x88, 0)) {
+ /* header crc failed */
+ rtas_args->args[rtas_args->nargs] = 0;
+ /* No update done, the candidate image is
+ * not valid for this platform */
+ rtas_args->args[rtas_args->nargs + 1] = 2;
+ sprintf(ret_str, "MI %s %s\xaMI %s %s",
+ current_temp_version, current_perm_version,
+ current_temp_version, current_perm_version);
+ return;
+ }
+ memcpy(new_version, flash_header->version, 16);
+ sprintf(ret_str, "MI %s %s\xaMI %s %s", current_temp_version,
+ current_perm_version, new_version, current_perm_version);
+ rtas_args->args[rtas_args->nargs] = 0;
+
+ if (strncmp(new_version, current_temp_version, 16) >= 0)
+ rtas_args->args[rtas_args->nargs + 1] = 0;
+ else
+ rtas_args->args[rtas_args->nargs + 1] = 6;
+}
+
+/*
+ * Function: ibm_update_flash_64
+ * Input:
+ * r3: rtas parm structure
+ * token: 7
+ * in: 1
+ * out: 1
+ * parm0: A real pointer to a block list
+ * Output:
+ * parm1: Status (hw -1, bad image -3, programming failed -4)
+ *
+ * Description: flash if addresses above 4GB have to be addressed
+ */
+void
+rtas_update_flash(rtas_args_t *rtas_args)
+{
+ void *bl = (void *)(uint64_t)rtas_args->args[0];
+ int version = get_block_list_version((unsigned char *)bl);
+ uint64_t erase_size;
+ unsigned int i;
+ int perm_check = 1;
+
+#ifdef DEBUG
+ dump_blocklist(bl, version);
+#endif
+
+ /* from SLOF we pass a second (unofficial) parameter, if this parameter is 1, we do not
+ * check wether we are on permanent side. Needed for update-flash -c to work! */
+ if ((rtas_args->nargs > 1) && (rtas_args->args[1] == 1))
+ perm_check = 0;
+
+ /* check magic string */
+ printf("\r\nChecking magic string : ");
+ if (check_magic(bl, version) != 0) {
+ printf("failed!\n");
+ rtas_args->args[rtas_args->nargs] = -3; /* bad image */
+ return;
+ }
+ printf("succeeded!\n");
+
+ /* check platform */
+ printf("Checking platform : ");
+ if (check_platform(bl, 0x48, version) == -1) {
+ printf("failed!\n");
+ rtas_args->args[rtas_args->nargs] = -3; /* bad image */
+ return;
+ }
+ printf("succeeded!\n");
+
+ /* checkcrc */
+ printf("Checking CRC : ");
+ /* the actual CRC is included at the end of the flash image, thus the resulting CRC must be 0! */
+ if (image_check_crc(bl, version) != 0) {
+ printf("failed!\n");
+ rtas_args->args[1] = -3; /* bad image */
+ return;
+ }
+ printf("succeeded!\n");
+
+ /* check if we are running on P
+ * if so, let's switch to temp and flash temp */
+ if (bmc_get_flashside() == 0 && perm_check) {
+ printf("Set flashside: ");
+ bmc_set_flashside(1);
+ printf("Temp!\n");
+ }
+
+#ifdef DEBUG
+ rtas_args_t ra;
+ ra.args[0] = 0x100; /* size; */
+ ra.args[1] = flashOffset;
+ ra.nargs = 2;
+
+ rtas_dump_flash(&ra);
+ printf("\n");
+#endif
+
+ size = get_size(bl, version);
+ erase_size = (size + (FLASH_BLOCK_SIZE - 1)) & ~(FLASH_BLOCK_SIZE - 1);
+ dprintf("Erasing: size: %#x, erase_size: %#x, FLASH_BLOCK_SIZE: %#x\n",
+ size, erase_size, FLASH_BLOCK_SIZE);
+
+ progress = size / 39;
+ printf("Erasing : 0x%08x", 0);
+ for (i = 0; i < erase_size; i += FLASH_BLOCK_SIZE) {
+ print_block(i);
+ erase_flash_block(i);
+ }
+
+ enter_data_mode();
+#ifdef DEBUG
+ rtas_dump_flash(&ra);
+ printf("\n");
+#endif
+ print_writing();
+ write_block_list(bl, version);
+ printf("\b#\n");
+ enter_data_mode();
+
+#ifdef DEBUG
+ rtas_dump_flash(&ra);
+ printf("\n");
+#endif
+
+ /* checkcrc */
+ printf("Recheck CRC : ");
+ if (check_flash_image(FLASH + flashOffset, size, 0) != 0) {
+ /* failed */
+ printf("failed!\n\r");
+ dprintf("flash_addr: %#x, flashOffset: %#x, size: %#x\n", FLASH,
+ flashOffset, size);
+ dprintf("crc: %#x\n",
+ check_flash_image(FLASH + flashOffset, size, 0));
+ rtas_args->args[rtas_args->nargs] = -4; /* programming failed */
+ return;
+ }
+ printf("succeeded!\n");
+ rtas_args->args[rtas_args->nargs] = 0;
+}
+
+/*
+ * Function: ibm_update_flash_64_and_reboot
+ * Input:
+ * r3: rtas parm structure
+ * token: 27
+ * in: 1
+ * out: 1
+ * parm0: A real pointer to a block list
+ * Output:
+ * parm1: Status (hw -1, bad image -3, programming failed -4)
+ * Currently -4 and -1 are not returned
+ *
+ * Description: flash and reboot if addresses above 4GB have to be addressed
+ */
+void
+rtas_ibm_update_flash_64_and_reboot(rtas_args_t *rtas_args)
+{
+ rtas_update_flash(rtas_args);
+ dprintf("rc: %#d\n", rtas_args->args[rtas_args->nargs]);
+ if (rtas_args->args[rtas_args->nargs] == 0) {
+ rtas_system_reboot(rtas_args);
+ }
+}
OpenPOWER on IntegriCloud