New files used for two stage loading of the IBL
authorMike Line <m-line1@ti.com>
Mon, 1 Nov 2010 17:46:48 +0000 (13:46 -0400)
committerMike Line <m-line1@ti.com>
Mon, 1 Nov 2010 17:46:48 +0000 (13:46 -0400)
New files for the c6472 version of the two stage load IBL.

src/device/c6472/c6472init.c [new file with mode: 0644]
src/main/iblStage.h [new file with mode: 0644]
src/main/iblinit.c [new file with mode: 0644]
src/make/ibl_c6472/ibl_init.cmd [new file with mode: 0644]
src/make/ibl_c6472/ibl_init.rmd [new file with mode: 0644]
src/make/ibl_c6472/ibl_init_image.rmd [new file with mode: 0644]
src/util/symExtract/symExtract [new file with mode: 0644]

diff --git a/src/device/c6472/c6472init.c b/src/device/c6472/c6472init.c
new file mode 100644 (file)
index 0000000..d4317ff
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * @file c6472init.c
+ *
+ * @brief
+ *             c6472 functions used during the initial stage of the ibl load
+ *
+ */
+#include "ibl.h"
+#include "device.h"
+#include "pllapi.h"
+
+/**
+ * @brief Configure the PLLs
+ *
+ * @details
+ *   The three PLLs are enabled. Only the main PLL has the ability to configure
+ *   the multiplier and dividers.
+ */
+void devicePllConfig (void)
+{
+    if (ibl.pllConfig[ibl_MAIN_PLL].doEnable == TRUE)
+        hwPllSetPll (MAIN_PLL, 
+                     ibl.pllConfig[ibl_MAIN_PLL].prediv,
+                     ibl.pllConfig[ibl_MAIN_PLL].mult,
+                     ibl.pllConfig[ibl_MAIN_PLL].postdiv);
+
+    if (ibl.pllConfig[ibl_DDR_PLL].doEnable == TRUE)
+        hwPllEnable (DDR_PLL);
+
+    if (ibl.pllConfig[ibl_NET_PLL].doEnable == TRUE)
+        hwPllEnable (NET_PLL);
+
+
+}
+
+
+/**
+ * @brief
+ *  Return the endian status of the device
+ *
+ * @details
+ *  Returns true if the device is executing in little endian mode
+ */
+extern cregister volatile unsigned int CSR;
+
+bool deviceIsLittleEndian (void)
+{
+    if ((CSR & (1 << 8)) == 0)    
+        return (FALSE);
+
+    return (TRUE);
+
+}
+
+
+
diff --git a/src/main/iblStage.h b/src/main/iblStage.h
new file mode 100644 (file)
index 0000000..2ac3fdb
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _IBL_STAGE_H
+#define _IBL_STAGE_H
+/**
+ * @file iblStage.h
+ *
+ * @brief
+ *       This file contains global declarations used by both stages of the IBL
+ */
+
+/**
+ * @brief The ibl table is declared.
+ *
+ * @details
+ *   The ibl table is declared uninitialized by this ibl program. An external
+ *   initialization can be performed if the default operation of the ibl is
+ *   not desired.
+ */
+#pragma DATA_SECTION(ibl, ".ibl_config_table")
+ibl_t ibl;
+
+
+/**
+ * @brief The ibl status table is declared.
+ *  
+ * @details
+ *   The ibl status table is declared. It is initialized at run time
+ *   in function main.
+ */
+#pragma DATA_SECTION(iblStatus, ".ibl_status_table")
+iblStatus_t iblStatus;
+
+
+
+
+#endif  /* _IBL_STAGE_H */
diff --git a/src/main/iblinit.c b/src/main/iblinit.c
new file mode 100644 (file)
index 0000000..431b070
--- /dev/null
@@ -0,0 +1,423 @@
+/**
+ *  @file iblinit.c
+ *
+ *  @brief
+ *             This file contains code which runs prior to loading the full IBL
+ *
+ *  @details
+ *             The IBL loads itself in a two stage process. The ROM boot loader
+ *             loads this first stage IBL first. This entire program must be
+ *             endian independent in execution.
+ *
+ *      This first loader reads the IBL parameters, and will endian
+ *      switch them if required. The PLL is configured if indicated
+ *      by the parameters.
+ *
+ *      The I2C block which contains the I2C EEPROM address for both
+ *      the big and little endian images is then read. Based on the
+ *      endianness of the device the rest of the IBL is read from
+ *      the I2C EEPROM, and execution is transferred to the full
+ *      IBL.
+ *
+ *      The subsequent reads are allowed to cross 16 bit i2c EEPROM
+ *      addresses. When the boundary is crossed the i2c address
+ *      field is incremented.
+ *
+ */
+
+#include "ibl.h"
+#include "iblloc.h"
+#include "iblcfg.h"
+#include "device.h"
+#include "iblbtbl.h"
+#include "i2c.h"
+#include <string.h>
+
+
+/**
+ *  @brief
+ *      Data structures shared between the 1st and 2nd stage IBL load
+ *      are declared in a single header file, included in both stages
+ */
+#include "iblStage.h"
+
+/**
+ *  @brief
+ *      byte swapping of i2c data must be done when in little endian mode
+ */
+bool littleEndian;
+
+/**
+ *  @brief
+ *      The boot table processing status is declared in the boot table wrapper,
+ *      and used here in the main status fields.
+ */
+extern Int32 btblWrapEcode;
+
+/**
+ *  @brief
+ *      Ones complement addition
+ */
+inline uint16 onesComplementAdd (uint16 value1, uint16 value2)
+{
+  uint32 result;
+
+  result = (uint32)value1 + (uint32)value2;
+
+  result = (result >> 16) + (result & 0xFFFF); /* add in carry   */
+  result += (result >> 16);                    /* maybe one more */
+  return ((uint16)result);
+}
+
+
+/**
+ *  @brief
+ *      Ones complement checksum computation 
+ */
+uint16 onesComplementChksum (uint16 * restrict p_data, uint16 len)
+{
+  uint16 chksum = 0;
+
+  while (len > 0)
+  {
+    chksum = onesComplementAdd(chksum, *p_data);
+    p_data++;
+    len--;
+  }
+  return (chksum);
+} 
+
+
+
+/**
+ *  @brief
+ *      Do a 4 byte endian swap
+ */
+uint32 swap32val (uint32 v)
+{
+    v =  (((v >> 24) & 0xff) <<  0)  |
+         (((v >> 16) & 0xff) <<  8)  |
+         (((v >>  8) & 0xff) << 16)  |
+         (((v >>  0) & 0xff) << 24);
+
+    return (v);
+
+}
+
+/**
+ *  @brief
+ *      Swap an array of 32 bit values
+ */
+void swap32mem (uint32 *pv, int32 nwords)
+{
+    int32 i;
+
+    for (i = 0; i < nwords; i++)
+        pv[i] = swap32val (pv[i]);
+
+}
+
+/**
+ *  @brief
+ *      The i2c load context consists of the address of the next block 
+ *      to read, and a simple fifo holding any existing data.
+ */
+#define I2C_MAX_BLOCK_SIZE      0x80
+uint32 i2cReadAddress;
+
+uint32 i2cFifoIn  = 0;
+uint32 i2cFifoOut = 0;
+uint8  i2cData[I2C_MAX_BLOCK_SIZE];
+uint16 i2cSum[I2C_MAX_BLOCK_SIZE >> 1];
+
+
+/**
+ *  @brief
+ *      Return the number of elements in the fifo
+ */
+Uint32 i2cFifoCount (void)
+{
+    Int32 count;
+
+    if (i2cFifoIn >= i2cFifoOut)
+        count = i2cFifoIn - i2cFifoOut;
+    else
+        count = i2cFifoIn + I2C_MAX_BLOCK_SIZE - i2cFifoOut;
+
+    return (count);
+
+}
+
+    
+/**
+ *  @brief
+ *      Read a byte from the fifo
+ */
+Uint8 i2cFifoRead(void)
+{
+    Uint8 v;
+
+    v = i2cData[i2cFifoOut];
+
+    i2cFifoOut += 1;
+    if (i2cFifoOut >= I2C_MAX_BLOCK_SIZE)
+        i2cFifoOut = 0;
+
+    return (v);
+
+}
+
+/**
+ *  @brief
+ *      Read a block of data from the I2C eeprom and put it in the fifo
+ */
+void i2cReadBlock (void)
+{
+    uint16 len;
+    int32  i, j;
+    uint32 v;
+
+    for (;;) {
+        while (hwI2cMasterRead (i2cReadAddress & 0xffff,    /* The address on the eeprom of the table */
+                                4,                          /* The number of bytes to read */
+                                i2cData,                    /* Where to store the bytes */
+                                i2cReadAddress >> 16,       /* The bus address of the eeprom */
+                                IBL_I2C_CFG_ADDR_DELAY)     /* The delay between sending the address and reading data */
+    
+             != I2C_RET_OK)  {
+
+            iblStatus.i2cDataRetries += 1;
+        }
+
+        /* Form the length. The received bytes are always in big endian format */
+        len    = (i2cData[0] << 8) | i2cData[1];
+
+
+        if (len > I2C_MAX_BLOCK_SIZE)
+            continue;
+
+
+        while (hwI2cMasterRead (i2cReadAddress & 0xffff,    /* The address on the eeprom of the table */
+                                len,                        /* The number of bytes to read */
+                                i2cData,                    /* Where to store the bytes */
+                                i2cReadAddress >> 16,       /* The bus address of the eeprom */
+                                IBL_I2C_CFG_ADDR_DELAY)     /* The delay between sending the address and reading data */
+    
+             != I2C_RET_OK)  {
+
+            iblStatus.i2cDataRetries += 1;
+        }
+
+
+        /* Must do endian conversion to verify the checksum */
+        for (i = j = 0; i < len; i += 2, j += 1) 
+            i2cSum[j] = (i2cData[i+0] << 8) | i2cData[i+1];
+
+        v = onesComplementChksum (i2cSum, j);
+        if ((v == 0) || (v == 0xffff))
+            break;
+
+        
+        iblStatus.i2cDataRetries += 1;
+
+    }
+
+
+    i2cReadAddress += len;
+    
+    i2cFifoIn  = len;
+    i2cFifoOut = 4;    /* The i2c header is effectively removed */
+
+}
+
+             
+
+
+/**
+ *  @brief
+ *      Read data from the I2C to pass to the interpreter
+ */
+Int32 iblI2cRead (Uint8 *buf, Uint32 num_bytes)
+{
+    int i;
+
+    for (i = 0; i < num_bytes; i++)  {
+
+        if (i2cFifoCount() == 0)
+            i2cReadBlock ();
+
+        buf[i] = i2cFifoRead();
+    }
+
+    return (0);
+
+}
+
+
+
+/**
+ *  @brief
+ *      The module function table used for boot from i2c
+ */
+BOOT_MODULE_FXN_TABLE i2cinit_boot_module = 
+{
+    NULL,           /* Open  API */
+    NULL,           /* Close API */
+    iblI2cRead,     /* Read  API */
+    NULL,           /* Write API */
+    NULL,           /* Peek  API */
+    NULL,           /* Seek  API */
+    NULL            /* Query API */
+};
+
+
+
+/**
+ *  @brief
+ *      The main function
+ *
+ *  @details
+ *      The ibl configuration parameters are read from the i2c, 
+ *      followed by the i2c mapping information. The second stage
+ *      of the IBL is then loaded, and execution transferred 
+ *      to the second stage.
+ */
+void main (void)
+{
+
+    uint16       v;
+    uint32       entry;
+    void         (*exit)();
+    iblI2cMap_t  map;
+
+    memset (&iblStatus, 0, sizeof(iblStatus_t));
+    iblStatus.iblMagic = ibl_MAGIC_VALUE;
+
+    /* Read the endianness setting of the device */
+    littleEndian = deviceIsLittleEndian();
+    
+    /* Load the default configuration table from the i2c. The actual speed of the device
+     * isn't really known here, since it is part of the table, so a compile time
+     * value is used (the pll may have been configured during the initial load) */
+    hwI2Cinit (IBL_I2C_DEV_FREQ_MHZ,        /* The CPU frequency during I2C data load */
+               DEVICE_I2C_MODULE_DIVISOR,   /* The divide down of CPU that drives the i2c */
+               IBL_I2C_CLK_FREQ_KHZ,        /* The I2C data rate used during table load */
+               IBL_I2C_OWN_ADDR);           /* The address used by this device on the i2c bus */
+
+
+    /* Read the i2c configuration tables until the checksum passes and the magic number
+     * matches. The checksum must be verified before the endian re-ordering is done */
+    for (;;)  {
+
+        if (hwI2cMasterRead (IBL_I2C_CFG_TABLE_DATA_ADDR,    /* The address on the eeprom of the table */
+                             sizeof(ibl_t),                  /* The number of bytes to read */
+                             (UINT8 *)&ibl,                  /* Where to store the bytes */
+                             IBL_I2C_CFG_EEPROM_BUS_ADDR,    /* The bus address of the eeprom */
+                             IBL_I2C_CFG_ADDR_DELAY)         /* The delay between sending the address and reading data */
+
+             == I2C_RET_OK)  {
+
+                 if (ibl.chkSum != 0)  {
+
+                    v = onesComplementChksum ((UINT16 *)&ibl, sizeof(ibl_t));
+                    if ((v != 0) && (v != 0xffff))  {
+                        iblStatus.i2cRetries += 1;
+                        continue;
+                    }
+
+                 }  
+
+
+                if (ibl.iblMagic == ibl_MAGIC_VALUE)
+                    break;
+
+                if (swap32val (ibl.iblMagic) == ibl_MAGIC_VALUE)  {
+                    swap32mem ((uint32 *)&ibl, (sizeof(ibl_t) + 3) >> 2);
+                    break;
+                }
+
+                iblStatus.magicRetries += 1;
+
+            }
+
+            iblStatus.i2cRetries += 1;
+    }
+
+    /* Pll configuration is device specific */
+    devicePllConfig ();
+
+    /* The IBL table is in place. Read the I2C map information from the eeprom */
+    for (;;)  {
+        if (hwI2cMasterRead (IBL_I2C_MAP_TABLE_DATA_ADDR,    /* The address on the eeprom of the data mapping */
+                             sizeof(iblI2cMap_t),            /* The number of bytes to read */
+                             (UINT8 *)&map,                  /* Where to store the bytes */
+                             IBL_I2C_CFG_EEPROM_BUS_ADDR,    /* The bus address of the eeprom */
+                             IBL_I2C_CFG_ADDR_DELAY)         /* The delay between sending the address and reading data */
+
+             == I2C_RET_OK)  {
+
+                /* On the I2C EEPROM the table is always formatted with the most significant
+                 * byte first. So if the device is running little endain the endian must be
+                 * swapped */
+                if (littleEndian == TRUE)
+                    swap32mem ((uint32 *)&map, (sizeof(iblI2cMap_t) + 3) >> 2);
+
+                if (map.length != sizeof(iblI2cMap_t))  {
+                    iblStatus.mapSizeFail += 1;
+                    continue;
+                }
+
+                if (map.chkSum != 0)  {
+                    
+                    v = onesComplementChksum ((UINT16 *)&map, sizeof(iblI2cMap_t));
+                    if ((v != 0) && (v != 0xffff))  {
+                        iblStatus.mapRetries += 1;
+                        continue;
+                    }
+                }
+
+                break;
+        }
+
+        iblStatus.mapRetries += 1;
+
+    }
+
+
+    /* The rest of the IBL is in boot table format. Read and process the data */
+    if (littleEndian == TRUE) 
+        i2cReadAddress = map.addrLe;
+    else
+        i2cReadAddress = map.addrBe;
+
+    if (i2cReadAddress == 0xffffffff)  {
+        iblStatus.iblFail = ibl_FAIL_CODE_INVALID_I2C_ADDRESS;
+        for (;;);
+    }
+
+
+    /* Pass control to the boot table processor */
+    iblBootBtbl (&i2cinit_boot_module, &entry);
+
+    if (btblWrapEcode != 0)  {
+        iblStatus.iblFail = ibl_FAIL_CODE_BTBL_FAIL;
+        for (;;);
+    }
+
+    /* jump to the exit point, which will be the entry point for the full IBL */
+    exit = (void (*)())entry;
+    (*exit)();
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/make/ibl_c6472/ibl_init.cmd b/src/make/ibl_c6472/ibl_init.cmd
new file mode 100644 (file)
index 0000000..dc922e6
--- /dev/null
@@ -0,0 +1,50 @@
+/************************************************************************************
+ * FILE PURPOSE: Define the memory usage of the ibl module for the c6455
+ ************************************************************************************
+ * FILE NAME: ibl.cmd
+ *
+ * DESCRIPTION: The memory placement for the IBL is defined
+ *
+ ************************************************************************************/
+
+
+../main/c64x/make/iblinit.oc
+../device/c64x/make/c6472init.oc
+../hw/c64x/make/pll.oc
+../hw/c64x/make/i2c.oc
+../interp/c64x/make/btblwrap.oc
+../interp/c64x/make/btblpr.oc
+../interp/c64x/make/gem.oc
+
+-c
+-stack 0x800
+-heap  0x6000
+
+
+
+MEMORY
+{
+       TEXT   :  origin = 0x801000, length = 0x20000
+       STACK  :  origin = 0x821000, length = 0x0800
+       HEAP   :  origin = 0x821800, length = 0x6000
+       DATA   :  origin = 0x827800, length = 0x3000
+       CFG    :  origin = 0x831800, length = 0x0300
+       STAT :    origin = 0x831b00, length = 0x0200
+}
+
+SECTIONS
+{
+       .stack  > STACK
+       .sysmem > HEAP
+       .cinit  > TEXT
+       .const  > TEXT
+       .text   > TEXT
+       .switch > TEXT
+       .far    > DATA
+       .bss    > DATA
+
+    .ibl_config_table > CFG
+       .ibl_status_table > STAT
+
+}
+
diff --git a/src/make/ibl_c6472/ibl_init.rmd b/src/make/ibl_c6472/ibl_init.rmd
new file mode 100644 (file)
index 0000000..41c1b87
--- /dev/null
@@ -0,0 +1,11 @@
+-a
+-boot
+-e _c_int00
+
+ROMS
+{
+       ROM1:  org = 0x0400, length = 0x20000, memwidth = 32, romwidth = 32
+       files = { ibl_le.b }
+}
+
+
diff --git a/src/make/ibl_c6472/ibl_init_image.rmd b/src/make/ibl_c6472/ibl_init_image.rmd
new file mode 100644 (file)
index 0000000..2d305e7
--- /dev/null
@@ -0,0 +1,10 @@
+-a
+-e _c_int00
+
+ROMS
+{
+       ROM1:  org = 0x801000, length = 0x20000, memwidth = 32, romwidth = 32
+       files = { ibl_le.b }
+}
+
+
diff --git a/src/util/symExtract/symExtract b/src/util/symExtract/symExtract
new file mode 100644 (file)
index 0000000..6cd00fa
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Simple script to extract addresses from a linker command file and
+# reformat for input into a second linker command file
+#
+#  usage:  symExtract <input file> <output file> symbol1 [symbol2 ...]
+#
+
+
+if [ $# -lt 3 ]; then
+ echo usage: $0 \<input file\> \<output file\> symbol1 \[symbol2 ...\]
+ exit
+fi
+
+args=("$@")
+
+rm -f $2
+
+echo "/* File autogenerated by symExtract during build process. Do not edit */" > $2
+
+
+carg=2
+while [ $carg -lt $# ]; do
+ symbol=`cat $1 | sed -n /${args[$carg]}\$/p | sed -n 1p`
+ addr=`echo $symbol | sed -e s/\ .*//`
+ sym=`echo $symbol | sed -e s/^.*\ //`
+ echo $sym=0x$addr\; >> $2
+ let carg=carg+1
+done
+
+
+
+