view frbl/reconst/boot.c @ 351:0ca005dbab30

fluid-mnf/devices.txt: OM support, safe S71PL-J defaults
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 13 Mar 2020 07:19:37 +0000
parents 4e1d7ce0ee71
children
line wrap: on
line source

/******************************************************************************
 * FLUID (Flash Loader Utility Independent of Device)
 *
 * (C) Delta Technologies 2001.
 * Cleanup, modifications and extensions by Mads Meisner-Jensen, mmj@ti.com.
 *
 * Target Bootloader
 *
 * $Id: boot.c 1.18 Mon, 28 Apr 2003 08:49:16 +0200 tsj $
 *
 ******************************************************************************/

#include "chipset.cfg"
#include "target.h"


#define DEBUG_TRACE 0


// Protocol version of this bootloader

// Version 0: Original, unmodified Delta Technology Bootloader.

// Version 1: First Fluid Bootloader. 'B'audrate command and 'V'ersion
// command. Backward compatibly with version 0.

// Version 2: 'H'ardware chipset query command. Debug/Trace
// functionality. Backward compatibly with version 0, 1. Fixed bug where
// IND$CALL was used to start command interpreter instead of private jump()
// function

// Version 3: Generic 'Q'uery command. Discontinued 'H'ardware query command
// from version 2.

#define BOOTLOADER_VERSION '3'


/******************************************************************************
 * Bootstrap/Init
 ******************************************************************************/

// Initialize stackpointer according to chipset. Note that we ALWAYS do
// this, no matter if we were laoded with JTAG or if we were compiled-in.

#if (CHIPSET == 3)
asm("STACK_INIT      .equ     03000000h");
asm("STACK_ADD       .equ     00020000h ; 128kB");
#elif (CHIPSET == 7 || CHIPSET == 8 || CHIPSET == 10 || CHIPSET == 11)
asm("STACK_INIT      .equ     00800000h");
asm("STACK_ADD       .equ     00020000h ; 128kB");
#elif (CHIPSET == 12)
asm("STACK_INIT      .equ     08000000h");
asm("STACK_ADD       .equ     00020000h ; 128kB");
#else
#error Unknown target hardware selected
#endif

#ifdef FLUID_BOOT_STAND_ALONE
asm("                .def _c_int00    ");
asm("_c_int00:");
#endif

asm("                .state32         ");
asm("        mov     sp,#STACK_INIT");
asm("        add     sp,sp,#STACK_ADD");
asm("        adr     lr,start_end + 1  ; module end address with lsb set");
asm("        bx      lr                ; branch to start");
asm("        nop");
asm("start_end:");



/******************************************************************************
 * Main
 ******************************************************************************/

uint32 uart_base;

void jump(uint32, uint32);

static void putchar(uint8 ch);
uint8 getchar(void);
void uart_init(UBYTE dlh, UBYTE dll);
void hardware_init(uint16 *code);

void fluid_bootloader(void)
{
    uint8  ch;
    uint16 *mem;
    union32_t addr;
    union16_t size;
    union16_t data;
    uint8 uart_dlh, uart_dll;
    uint16 chip_id_code;

    hardware_init(&chip_id_code);

    uart_base = UART_BASE_MODEM;
    uart_init(0, 0x07); // baudrate = 115200kbps
    uart_base = UART_BASE_IRDA;
    uart_init(0, 0x07); // baudrate = 115200kbps

#ifdef TESTBOOT
    while (1) {
        uart_base = UART_BASE_MODEM;
        if ((REGISTER_8_READ(uart_base + UART_LSR) & STAT_RXRDY))
            break;
        uart_base = UART_BASE_IRDA;
        if ((REGISTER_8_READ(uart_base + UART_LSR) & STAT_RXRDY))
            break;
    }
    while (getchar() != 0xAA)
        ;
    while (getchar() != 0x01)
        ;
    while (getchar() != 0xDD)
        ;
#endif

    while (1) {
        uart_base = UART_BASE_MODEM;
        putchar(PROTO_HELLO);
        if ((REGISTER_8_READ(uart_base + UART_LSR) & STAT_RXRDY))
            break;
        uart_base = UART_BASE_IRDA;
        putchar(PROTO_HELLO);
        if ((REGISTER_8_READ(uart_base + UART_LSR) & STAT_RXRDY))
            break;
    }
    while (1) {
        ch = getchar();
        switch (ch) {
        case PROTO_VERSION:
            putchar(BOOTLOADER_VERSION);
            break;
/* FreeCalypso reconstruction of TCS211 boot.obj */
	case PROTO_HARDWARE:
	    putchar('0');
	    break;
/* end FC reconstruction */
        case PROTO_QUERY:
            ch = getchar();
            if (ch == PROTO_QUERY_CHIP) {
                data.i = chip_id_code;
                putchar(data.b[0]);
                putchar(data.b[1]);
                putchar(0);
                putchar(0);
            }
            else {
                putchar(PROTO_ERROR);
            }
            break;
        case PROTO_BAUDRATE:
            ch = getchar(); // Get DLH
        case 0:
            uart_init(ch, getchar());
            break;
        case PROTO_DOWNLOAD:
            addr.b[0] = getchar();
            addr.b[1] = getchar();
            addr.b[2] = getchar();
            addr.b[3] = getchar();
            size.b[0] = getchar();
            size.b[1] = getchar();
            putchar(PROTO_READY);
            mem = (uint16 *) addr.i;
            while (size.i--) {
                // Data bytes arrive in reverse order due to little endian mode
                data.b[1] = getchar();
                data.b[0] = getchar();
                *mem++ = data.i;
            }

#if DEBUG_TRACE
            // Insert convenient tracing here...
#endif
            // Start the program we loaded.
            jump(uart_base, addr.i);
            break;
        default:
            putchar(PROTO_ERROR);
        }
    }
}

// Little assembly function that makes a jump to the address/argument,
// similar to the compiler's IND$CALL. We do not use the compiler's IND$CALL
// because when we compile for non-standalone, IND$CALL is already
// defined. We expect that the base address of the UART is in R0, so it can
// be properly passed on to the command interpreter.
asm("$jump:");
asm("        bx      r1");

static void putchar(uint8 ch)
{
    PUTCHAR_FUNCTION_CODE(uart_base)
}

uint8 getchar(void)
{
    GETCHAR_FUNCTION_CODE(uart_base)
}


/******************************************************************************
 * Initialization
 ******************************************************************************/
#if (CHIPSET == 3)
    #define IQ_MASK (0xFFFFFA02) /* Mask Interrupt Register */
#elif (CHIPSET == 7 || CHIPSET == 8 || CHIPSET == 10 || CHIPSET == 11) \
	|| (CHIPSET == 12) 
    #define IQ_MASK1 (0xFFFFFA08) /* Mask Interrupt Register 1 */
    #define IQ_MASK2 (0xFFFFFA0A) /* Mask Interrupt Register 2 */
#else
  #error Unknown target hardware selected
#endif

/* FreeCalypso reconstruction: definition missing from TCS211 target.h */
#define	CHIP_ID_CODE	0xFFFEF000

void hardware_init(uint16 *chip_id_code)
{
    uint16 clk;
    char chip_set = 0;

    // We read the chipset version directly from the hardware because
    // otherwise the stand-alone bootloader (to be downloaded with JTAG) is
    // obviously not target independent!
    *chip_id_code = *((volatile uint16 *) CHIP_ID_CODE);


    // We should only intialize the hardware if we were downloaded with JTAG

#ifdef FLUID_BOOT_STAND_ALONE

    // FIXME: we should perhaps have different init depending on chipset
    // detected?

    // Mask all interrupts
#if (CHIPSET == 3)
    *((volatile uint16 *) IQ_MASK) = 0xFFFF;
#elif (CHIPSET == 7 || CHIPSET == 8 || CHIPSET == 10 || CHIPSET == 11)
    *((volatile uint16 *) IQ_MASK1) = 0xFFFF;
    *((volatile uint16 *) IQ_MASK2) = 0x001F;
#elif (CHIPSET == 12)
    *((volatile uint16 *) IQ_MASK1) = 0xFFFF;
    *((volatile uint16 *) IQ_MASK2) = 0xFFFF;  //BJO Check IRQ_29_MSK - should it be 0 ?
#endif

    // Disable watchdog timer
    *((volatile uint16 *) WATCHDOG_TIM_MODE) = 0xF5;
    *((volatile uint16 *) WATCHDOG_TIM_MODE) = 0xA0;
#if (CHIPSET == 12)                                      //BJO Check this (documented?)
    *((volatile uint16 *) WATCHDOG_TIM_MODE+80) = 0xF5; // Secure watchdog CALPLUS
    *((volatile uint16 *) WATCHDOG_TIM_MODE+80) = 0xA0; // Secure watchdog CALPLUS
#endif


#if (CHIPSET == 3) || (CHIPSET == 7 || CHIPSET == 8 || CHIPSET == 10 || CHIPSET == 11)
    // FIXME: Describe exactly how the CSs are initialized
    *((volatile uint16 *) CS0_MEM_REG) = 0x2A1;
    *((volatile uint16 *) CS1_MEM_REG) = 0x2A1;
    *((volatile uint16 *) CS2_MEM_REG) = 0x2A1;
    *((volatile uint16 *) CS3_MEM_REG) = 0x283;
    *((volatile uint16 *) CS4_MEM_REG) = 0x283;
    *((volatile uint16 *) CS6_MEM_REG) = 0x2C0;
#elif (CHIPSET == 12)
    *((volatile uint16 *) CS0_MEM_REG) = 0x2A3;  //*BJO  Check these settings
    *((volatile uint16 *) CS1_MEM_REG) = 0x2A3;
    *((volatile uint16 *) CS2_MEM_REG) = 0x2A3;
    *((volatile uint16 *) CS3_MEM_REG) = 0x2A3;
    *((volatile uint16 *) CS4_MEM_REG) = 0x2A3;
    *((volatile uint16 *) CS5_MEM_REG) = 0x2A3;
#endif


#if (CHIPSET == 3)
    clk =  *(volatile uint16 *) CLKM_CNTL_ARM_CLK;
    clk &= ~(0x0C | 0x30);
    clk |= (2 << 4);
    *(volatile uint16 *) CLKM_CNTL_ARM_CLK = clk;

#elif (CHIPSET == 7 || CHIPSET == 8 || CHIPSET == 10 || CHIPSET == 11)

    // Reset DPLL register
    * (volatile uint16 *) MEM_DPLL_ADDR = DPLL_RESET_VALUE;

    // Wait that DPLL is in BYPASS mode
    while (((* (volatile uint16 *) MEM_DPLL_ADDR) & 1) != 1)
        ;

    // Reset CLKM register
    *(volatile uint16 *) MEM_CLKM_ADDR = CLKM_CNTL_ARM_CLK_RST;

#elif (CHIPSET == 12)

    *((volatile uint8*)CTNL_CLK) = 0x91; // Make sure we are set to 26MHz mode (div 2)  // CALPLUS
    *((volatile uint16 *) MEM_DPLL_ADDR) = 0x6012 | (8<<7) | (1<<5); // multiplyer=8, divider=2 (-1) 52MHz!!! // CALPLUS
    // Wait that DPLL is locked
    while (((* (volatile unsigned short *) MEM_DPLL_ADDR) & 1) != 1) ; // CALPLUS

#endif


#endif // ifdef FLUID_BOOT_STAND_ALONE
}

void uart_init(uint8 my_dlh, uint8 my_dll)
{
    uint8 ch;

    /*
     * Transition from the DSP Rhea bus to the MCU Rhea bus.
     */
    BIT_SET (UART_UIR, UART_MASK_IT);
    BIT_CLR (UART_UIR, UART_ACCESS);
    BIT_CLR (UART_UIR, UART_MASK_IT);

    /*
     * Set the UART in reset mode.
     */
    REGISTER_8_WRITE(uart_base + UART_MDR1, CMD_UART_RESET);

    /*
     * FIFO configuration
     */
    REGISTER_8_WRITE(uart_base + UART_LCR, CMD_EFR_EN);
    BIT_SET         (uart_base + UART_EFR, ENHANCED_EN);
    REGISTER_8_WRITE(uart_base + UART_LCR, CMD_FCR_MCR_EN);
    REGISTER_8_WRITE(uart_base + UART_FCR, CMD_FIFO_EN);

    /*
     * Speed configuration
     */
    REGISTER_8_WRITE(uart_base + UART_LCR, CMD_EFR_EN);
    REGISTER_8_WRITE(uart_base + UART_DLL, my_dll);
    REGISTER_8_WRITE(uart_base + UART_DLH, my_dlh);

    /*
     * Character format configuration
     */
    REGISTER_8_WRITE(uart_base + UART_LCR, CMD_CHAR8_STOP1_NOPAR);

    /*
     * Modem configuration
     */
    REGISTER_8_WRITE(uart_base + UART_MDR1, CMD_UART_MODE);

    /*
     * Flush Rx buffer
     */
    while ((REGISTER_8_READ(uart_base + UART_LSR) & STAT_RXRDY))
        ch = (REGISTER_8_READ(uart_base + UART_RHR));
}


/******************************************************************************
 * Debug
 ******************************************************************************/

#if (DEBUG_TRACE == 1)
#include "debug.c"
#endif