mirror of
git://projects.qi-hardware.com/f32xbase.git
synced 2024-11-19 06:58:27 +02:00
5ce904b20f
setup. PLATFORM_SETUP now performs early general platform setup, such as turning off the watchdog. - fw/boot/boot.c (main): the first thing we do is to run PLATFORM_SETUP - fw/boot/boot.c (boot_loader): instead of PLATFORM_SETUP, run PLATFORM_ENTER
243 lines
4.5 KiB
C
243 lines
4.5 KiB
C
/*
|
|
* boot/boot.c - Boot loader setup and main loop
|
|
*
|
|
* Written 2008, 2010 by Werner Almesberger
|
|
* Copyright 2008, 2010 Werner Almesberger
|
|
*
|
|
* 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 code follows the register read/write sequences from the examples in
|
|
* SiLabs/MCU/Examples/C8051F326_7/USB_Interrupt/Firmware/F326_USB_Main.c and
|
|
* SiLabs/MCU/Examples/C8051F326_7/USB_Interrupt/Firmware/F326_USB_ISR.c
|
|
*/
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "version.h"
|
|
#include "regs.h"
|
|
#include "uart.h"
|
|
#include "usb.h"
|
|
#include "dfu.h"
|
|
|
|
#include "config.h"
|
|
|
|
|
|
#if !defined(CONFIG_DEBUG) && !defined(CONFIG_ERROR) && !defined(CONFIG_PRINTK)
|
|
#define uart_init(x)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* GTA example:
|
|
*
|
|
|
|
#define PLATFORM_SETUP \
|
|
GPIOCN |= WEAKPUD; \
|
|
I2C_SDA_PULL = 0; \
|
|
delay();
|
|
|
|
// Re-enable pull-ups
|
|
// Don't waste power in pull-down
|
|
#define PLATFORM_EXIT \
|
|
GPIOCN &= ~WEAKPUD; \
|
|
I2C_SDA_PULL = 1;
|
|
|
|
#define PLATFORM_TEST \
|
|
(!I2C_SDA || dfu.state != dfuIDLE)
|
|
*/
|
|
|
|
#ifndef PLATFORM_SETUP
|
|
#define PLATFORM_SETUP
|
|
#endif
|
|
|
|
#ifndef PLATFORM_ENTER
|
|
#define PLATFORM_ENTER
|
|
#endif
|
|
|
|
#ifndef PLATFORM_EXIT
|
|
#define PLATFORM_EXIT
|
|
#endif
|
|
|
|
|
|
void run_payload(void)
|
|
{
|
|
PLATFORM_EXIT;
|
|
|
|
/* No interrupts while jumping between worlds */
|
|
EA = 0;
|
|
|
|
/* Restart USB */
|
|
USB0XCN = 0;
|
|
|
|
/*
|
|
* The USB host must detect a disconnect (pull-ups absent) within 2 and
|
|
* 2.5 us according to parameter Tddis in table 7-13 on page 186 of the
|
|
* Universal Serial Bus Specification Revision 2.0.
|
|
*
|
|
* If our application calls usb_init really really quickly, we may need
|
|
* an extra delay here.
|
|
*/
|
|
|
|
debug("launching payload\n");
|
|
|
|
__asm
|
|
ljmp PAYLOAD_START
|
|
__endasm;
|
|
}
|
|
|
|
|
|
/* ----- Interrupts -------------------------------------------------------- */
|
|
|
|
|
|
/*
|
|
* The boot loader doesn't use interrupts, so we forward all interrupts to the
|
|
* payload.
|
|
*
|
|
* What we'd really like to do here is to say something like
|
|
*
|
|
* void whatever_isr(void) __interrupt(n) __at(PAYLOAD+n*8+1);
|
|
*
|
|
* However, sdcc doesn't support such things yet. So we declare the ISR such
|
|
* that the vector entry gets created, and then we tell the assembler where to
|
|
* find it.
|
|
*
|
|
* Since __asm/__endasm isn't allowed outside a function body, we generate a
|
|
* dummy function for each assignment. The function is "naked", so that no
|
|
* actual code is generated for it.
|
|
*/
|
|
|
|
#define ISR(n) \
|
|
void isr_nr_##n(void) __interrupt(n); \
|
|
void isr_dummy_##n(void) __naked \
|
|
{ \
|
|
__asm \
|
|
_isr_nr_##n = PAYLOAD_START+n*8+3 \
|
|
__endasm; \
|
|
}
|
|
|
|
|
|
ISR(0)
|
|
ISR(1)
|
|
ISR(2)
|
|
ISR(3)
|
|
ISR(4)
|
|
ISR(8)
|
|
ISR(15)
|
|
|
|
|
|
/* ----- The actual boot loader -------------------------------------------- */
|
|
|
|
|
|
static void delay(void)
|
|
{
|
|
int x;
|
|
|
|
for (x = 0; x < 500; x)
|
|
x++;
|
|
}
|
|
|
|
|
|
static void boot_loader(void)
|
|
{
|
|
OSCICN |= IFCN0 | IFCN1; /* SYSCLK = IOSC/1 (12 MHz) */
|
|
|
|
#ifdef LOW_SPEED
|
|
|
|
CLKSEL = 0x10; /* USBCLK = int/2, SYS_INT_OSC = int */
|
|
|
|
#else /* LOW_SPEED */
|
|
|
|
/*
|
|
* Clock multiplier enable sequence, section 10.4
|
|
*
|
|
* - reset the multiplier
|
|
* - select the multiplier input source
|
|
* - enable the multiplier
|
|
* - delay for 5us
|
|
* - initialize the multiplier
|
|
* - poll for multiplier to be ready
|
|
*/
|
|
|
|
CLKMUL = 0;
|
|
CLKMUL |= MULEN;
|
|
delay();
|
|
CLKMUL |= MULINIT | MULEN;
|
|
while (!(CLKMUL & MULRDY));
|
|
CLKSEL = 0; /* USBCLK = 4*int, SYSCLK = int */
|
|
CLKSEL = 0x02; /* F326_USB_Main.c does this (sets 24MHz). Why ? */
|
|
|
|
uart_init(24);
|
|
|
|
#endif /* !LOW_SPEED */
|
|
|
|
printk("%s #%u\n", build_date, build_number);
|
|
|
|
PLATFORM_ENTER;
|
|
|
|
dfu_init();
|
|
usb_init();
|
|
|
|
#ifdef PLATFORM_TEST
|
|
|
|
while (PLATFORM_TEST)
|
|
usb_poll();
|
|
|
|
#else /* PLATFORM_TEST */
|
|
|
|
#define MS_TO_LOOPS(ms) ((uint32_t) (ms)*190)
|
|
|
|
{
|
|
uint32_t loop = 0;
|
|
|
|
while (loop != MS_TO_LOOPS(2000)) {
|
|
usb_poll();
|
|
if (dfu.state == dfuIDLE)
|
|
loop++;
|
|
else
|
|
loop = 0;
|
|
}
|
|
}
|
|
#endif /* !PLATFORM_TEST */
|
|
}
|
|
|
|
|
|
void main(void)
|
|
{
|
|
/*
|
|
* Any early platform setup, such as turning off the watch dog.
|
|
*/
|
|
PLATFORM_SETUP;
|
|
|
|
/*
|
|
* VDD monitor enable sequence, section 7.2
|
|
*
|
|
* - enable voltage monitor
|
|
* - wait for monitor to stabilize
|
|
* - enable VDD monitor reset
|
|
*/
|
|
|
|
VDM0CN = VDMEN;
|
|
while (!(VDM0CN & VDDSTAT));
|
|
RSTSRC = PORSF;
|
|
|
|
/*
|
|
* @@@ if we don't have VBUS, proceed as follows:
|
|
* - stay at 3MHz (current < 2mA, so we're fine with GPIO power)
|
|
* - jump directly to the payload
|
|
*/
|
|
|
|
OSCICN |= IFCN0; /* SYSCLK = IOSC/4 (3 MHz) */
|
|
|
|
uart_init(3);
|
|
|
|
if (REG0CN & VBSTAT)
|
|
boot_loader();
|
|
run_payload();
|
|
}
|