1101 lines
30 KiB
C
1101 lines
30 KiB
C
/*
|
|
* BaS
|
|
*
|
|
* This file is part of BaS_gcc.
|
|
*
|
|
* BaS_gcc 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* BaS_gcc is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with BaS_gcc. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Copyright 2010 - 2012 F. Aschwanden
|
|
* Copyright 2011 - 2012 V. Riviere
|
|
* Copyright 2012 M. Froeschle
|
|
*/
|
|
|
|
#include <bas_types.h>
|
|
|
|
#include "MCF5475.h"
|
|
#include "startcf.h"
|
|
#include "sysinit.h"
|
|
#include "util.h"
|
|
#include "cache.h"
|
|
#include "bas_printf.h"
|
|
#include "bas_string.h"
|
|
#include "bas_types.h"
|
|
#include "bas_utils.h"
|
|
#include "sd_card.h"
|
|
#include "wait.h"
|
|
|
|
#include "ff.h"
|
|
#include "s19reader.h"
|
|
#include "mmu.h"
|
|
#include "dma.h"
|
|
#include "net.h"
|
|
#include "eth.h"
|
|
#include "nbuf.h"
|
|
#include "nif.h"
|
|
#include "fec.h"
|
|
#include "bootp.h"
|
|
#include "interrupts.h"
|
|
#include "exceptions.h"
|
|
#include "net_timer.h"
|
|
#include "pci.h"
|
|
#include "usb.h"
|
|
#include "video.h"
|
|
#include "driver_mem.h"
|
|
|
|
#include "version.h"
|
|
|
|
// #define DEBUG
|
|
#include "debug.h"
|
|
|
|
/* imported routines */
|
|
extern int vec_init();
|
|
extern void set_ide_access_mode(void);
|
|
|
|
/* Symbols from the linker script */
|
|
extern uint8_t _STRAM_END[];
|
|
#define STRAM_END ((uint32_t)_STRAM_END)
|
|
extern uint8_t _TOS[];
|
|
#define TOS ((uint32_t)_TOS) /* final TOS location */
|
|
extern uint8_t _FASTRAM_END[];
|
|
#define FASTRAM_END ((uint32_t)_FASTRAM_END)
|
|
extern uint8_t _EMUTOS[];
|
|
#define EMUTOS ((uint32_t)_EMUTOS) /* where EmuTOS is stored in flash */
|
|
extern uint8_t _EMUTOS_SIZE[];
|
|
#define EMUTOS_SIZE ((uint32_t)_EMUTOS_SIZE) /* size of EmuTOS, in bytes */
|
|
|
|
bool fpga_configured = false; /* for FPGA JTAG configuration */
|
|
|
|
extern volatile long _VRAM; /* start address of video ram from linker script */
|
|
|
|
|
|
#if defined(MACHINE_FIREBEE)
|
|
|
|
static bool i2c_transfer_finished(void)
|
|
{
|
|
if (MCF_I2C_I2SR & MCF_I2C_I2SR_IIF)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static void wait_i2c_transfer_finished(void)
|
|
{
|
|
waitfor(1000, i2c_transfer_finished); /* wait until interrupt bit has been set */
|
|
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; /* clear interrupt bit (byte transfer finished */
|
|
}
|
|
|
|
static bool i2c_bus_free(void)
|
|
{
|
|
return (MCF_I2C_I2SR & MCF_I2C_I2SR_IBB);
|
|
}
|
|
|
|
/*
|
|
* TFP410 (DVI) on
|
|
*/
|
|
static void dvi_on(void)
|
|
{
|
|
uint8_t receivedByte;
|
|
uint8_t dummyByte; /* only used for a dummy read */
|
|
int num_tries = 0;
|
|
|
|
xprintf("DVI digital video output initialization: ");
|
|
|
|
MCF_I2C_I2FDR = 0x3c; /* divide system clock by 1280: 100kHz standard */
|
|
|
|
do
|
|
{
|
|
/* disable all i2c interrupt routing targets */
|
|
MCF_I2C_I2ICR = 0x0; // ~(MCF_I2C_I2ICR_IE | MCF_I2C_I2ICR_RE | MCF_I2C_I2ICR_TE | MCF_I2C_I2ICR_BNBE);
|
|
|
|
/* disable i2c, disable i2c interrupts, slave, receive, i2c = acknowledge, no repeat start */
|
|
MCF_I2C_I2CR = 0x0;
|
|
|
|
/* repeat start, transmit acknowledge */
|
|
MCF_I2C_I2CR = MCF_I2C_I2CR_RSTA | MCF_I2C_I2CR_TXAK;
|
|
|
|
receivedByte = MCF_I2C_I2DR; /* read a byte */
|
|
MCF_I2C_I2SR = 0x0; /* clear status register */
|
|
MCF_I2C_I2CR = 0x0; /* clear control register */
|
|
|
|
MCF_I2C_I2ICR = MCF_I2C_I2ICR_IE; /* route i2c interrupts to cpu */
|
|
|
|
/* i2c enable, master mode, transmit acknowledge */
|
|
MCF_I2C_I2CR = MCF_I2C_I2CR_IEN | MCF_I2C_I2CR_MSTA | MCF_I2C_I2CR_MTX;
|
|
|
|
MCF_I2C_I2DR = 0x7a; /* send data: address of TFP410 */
|
|
wait_i2c_transfer_finished();
|
|
|
|
if (MCF_I2C_I2SR & MCF_I2C_I2SR_RXAK) /* next try if no acknowledge */
|
|
goto try_again;
|
|
|
|
MCF_I2C_I2DR = 0x00; /* send data: SUB ADRESS 0 */
|
|
wait_i2c_transfer_finished();
|
|
|
|
MCF_I2C_I2CR |= MCF_I2C_I2CR_RSTA; /* repeat start */
|
|
MCF_I2C_I2DR = 0x7b; /* begin read */
|
|
|
|
wait_i2c_transfer_finished();
|
|
if (MCF_I2C_I2SR & MCF_I2C_I2SR_RXAK) /* next try if no acknowledge */
|
|
goto try_again;
|
|
|
|
#ifdef _NOT_USED_
|
|
MCH_I2C_I2CR &= ~MCF_I2C_I2CR_MTX; /* FIXME: not clear where this came from ... */
|
|
#endif /* _NOT_USED_ */
|
|
MCF_I2C_I2CR &= 0xef; /* ... this actually disables the I2C module... */
|
|
dummyByte = MCF_I2C_I2DR; /* dummy read */
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK; /* transmit acknowledge enable */
|
|
receivedByte = MCF_I2C_I2DR; /* read a byte */
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
MCF_I2C_I2CR = MCF_I2C_I2CR_IEN; /* stop */
|
|
|
|
dummyByte = MCF_I2C_I2DR; // dummy read
|
|
|
|
if (receivedByte != 0x4c)
|
|
goto try_again;
|
|
|
|
MCF_I2C_I2CR = 0x0; // stop
|
|
MCF_I2C_I2SR = 0x0; // clear sr
|
|
|
|
waitfor(10000, i2c_bus_free);
|
|
|
|
MCF_I2C_I2CR = 0xb0; // on tx master
|
|
MCF_I2C_I2DR = 0x7A;
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
if (MCF_I2C_I2SR & MCF_I2C_I2SR_RXAK)
|
|
goto try_again;
|
|
|
|
MCF_I2C_I2DR = 0x08; // SUB ADRESS 8
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
MCF_I2C_I2DR = 0xbf; // ctl1: power on, T:M:D:S: enable
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
MCF_I2C_I2CR = 0x80; // stop
|
|
dummyByte = MCF_I2C_I2DR; // dummy read
|
|
MCF_I2C_I2SR = 0x0; // clear sr
|
|
|
|
waitfor(10000, i2c_bus_free);
|
|
|
|
MCF_I2C_I2CR = 0xb0;
|
|
MCF_I2C_I2DR = 0x7A;
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
if (MCF_I2C_I2SR & MCF_I2C_I2SR_RXAK)
|
|
goto try_again;
|
|
|
|
MCF_I2C_I2DR = 0x08; // SUB ADRESS 8
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
MCF_I2C_I2CR |= 0x4; // repeat start
|
|
MCF_I2C_I2DR = 0x7b; // beginn read
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
if (MCF_I2C_I2SR & MCF_I2C_I2SR_RXAK)
|
|
goto try_again;
|
|
|
|
MCF_I2C_I2CR &= 0xef; // switch to rx
|
|
dummyByte = MCF_I2C_I2DR; // dummy read
|
|
|
|
wait_i2c_transfer_finished();
|
|
MCF_I2C_I2CR |= 0x08; // txak=1
|
|
|
|
wait(50);
|
|
|
|
receivedByte = MCF_I2C_I2DR;
|
|
|
|
wait_i2c_transfer_finished();
|
|
|
|
MCF_I2C_I2CR = 0x80; // stop
|
|
|
|
dummyByte = MCF_I2C_I2DR; // dummy read
|
|
|
|
try_again:
|
|
num_tries++;
|
|
} while ((receivedByte != 0xbf) && (num_tries < 10));
|
|
|
|
if (num_tries >= 10)
|
|
{
|
|
xprintf("FAILED!\r\n");
|
|
}
|
|
else
|
|
{
|
|
xprintf("finished\r\n");
|
|
}
|
|
|
|
(void) dummyByte; /* Avoid warning */
|
|
}
|
|
|
|
|
|
/*
|
|
* AC97
|
|
*/
|
|
static void init_ac97(void)
|
|
{
|
|
// PSC2: AC97 ----------
|
|
int i;
|
|
int zm;
|
|
int va;
|
|
int vb;
|
|
int vc;
|
|
|
|
xprintf("AC97 sound chip initialization: ");
|
|
MCF_PAD_PAR_PSC2 = MCF_PAD_PAR_PSC2_PAR_RTS2_RTS // PSC2=TX,RX BCLK,CTS->AC'97
|
|
| MCF_PAD_PAR_PSC2_PAR_CTS2_BCLK
|
|
| MCF_PAD_PAR_PSC2_PAR_TXD2
|
|
| MCF_PAD_PAR_PSC2_PAR_RXD2;
|
|
MCF_PSC2_PSCMR1 = 0x0;
|
|
MCF_PSC2_PSCMR2 = 0x0;
|
|
MCF_PSC2_PSCIMR = 0x0300;
|
|
MCF_PSC2_PSCSICR = 0x03; //AC97
|
|
MCF_PSC2_PSCRFCR = 0x0f000000;
|
|
MCF_PSC2_PSCTFCR = 0x0f000000;
|
|
MCF_PSC2_PSCRFAR = 0x00F0;
|
|
MCF_PSC2_PSCTFAR = 0x00F0;
|
|
|
|
for (zm = 0; zm < 100000; zm++) // wiederholen bis synchron
|
|
{
|
|
MCF_PSC2_PSCCR = 0x20;
|
|
MCF_PSC2_PSCCR = 0x30;
|
|
MCF_PSC2_PSCCR = 0x40;
|
|
MCF_PSC2_PSCCR = 0x05;
|
|
|
|
// MASTER VOLUME -0dB
|
|
MCF_PSC2_PSCTB_AC97 = 0xE0000000; //START SLOT1 + SLOT2, FIRST FRAME
|
|
MCF_PSC2_PSCTB_AC97 = 0x02000000; //SLOT1:WR REG MASTER VOLUME adr 0x02
|
|
|
|
for (i = 2; i < 13; i++)
|
|
{
|
|
MCF_PSC2_PSCTB_AC97 = 0x0; //SLOT2-12:WR REG ALLES 0
|
|
}
|
|
|
|
// read register
|
|
MCF_PSC2_PSCTB_AC97 = 0xc0000000; //START SLOT1 + SLOT2, FIRST FRAME
|
|
MCF_PSC2_PSCTB_AC97 = 0x82000000; //SLOT1:master volume
|
|
|
|
for (i = 2; i < 13; i++)
|
|
{
|
|
MCF_PSC2_PSCTB_AC97 = 0x00000000; //SLOT2-12:RD REG ALLES 0
|
|
}
|
|
wait(50);
|
|
|
|
va = MCF_PSC2_PSCTB_AC97;
|
|
if ((va & 0x80000fff) == 0x80000800) {
|
|
vb = MCF_PSC2_PSCTB_AC97;
|
|
vc = MCF_PSC2_PSCTB_AC97;
|
|
|
|
/* FIXME: that looks more than suspicious (Fredi?) */
|
|
/* fixed with parentheses to avoid compiler warnings, but this looks still more than wrong to me */
|
|
if (((va & 0xE0000fff) == 0xE0000800) & (vb == 0x02000000) & (vc == 0x00000000)) {
|
|
goto livo;
|
|
}
|
|
}
|
|
}
|
|
xprintf(" NOT");
|
|
livo:
|
|
// AUX VOLUME ->-0dB
|
|
MCF_PSC2_PSCTB_AC97 = 0xE0000000; //START SLOT1 + SLOT2, FIRST FRAME
|
|
MCF_PSC2_PSCTB_AC97 = 0x16000000; //SLOT1:WR REG AUX VOLUME adr 0x16
|
|
MCF_PSC2_PSCTB_AC97 = 0x06060000; //SLOT1:VOLUME
|
|
for (i = 3; i < 13; i++) {
|
|
MCF_PSC2_PSCTB_AC97 = 0x0; //SLOT2-12:WR REG ALLES 0
|
|
}
|
|
|
|
// line in VOLUME +12dB
|
|
MCF_PSC2_PSCTB_AC97 = 0xE0000000; //START SLOT1 + SLOT2, FIRST FRAME
|
|
MCF_PSC2_PSCTB_AC97 = 0x10000000; //SLOT1:WR REG MASTER VOLUME adr 0x02
|
|
for (i = 2; i < 13; i++) {
|
|
MCF_PSC2_PSCTB_AC97 = 0x0; //SLOT2-12:WR REG ALLES 0
|
|
}
|
|
// cd in VOLUME 0dB
|
|
MCF_PSC2_PSCTB_AC97 = 0xE0000000; //START SLOT1 + SLOT2, FIRST FRAME
|
|
MCF_PSC2_PSCTB_AC97 = 0x12000000; //SLOT1:WR REG MASTER VOLUME adr 0x02
|
|
for (i = 2; i < 13; i++) {
|
|
MCF_PSC2_PSCTB_AC97 = 0x0; //SLOT2-12:WR REG ALLES 0
|
|
}
|
|
// mono out VOLUME 0dB
|
|
MCF_PSC2_PSCTB_AC97 = 0xE0000000; //START SLOT1 + SLOT2, FIRST FRAME
|
|
MCF_PSC2_PSCTB_AC97 = 0x06000000; //SLOT1:WR REG MASTER VOLUME adr 0x02
|
|
MCF_PSC2_PSCTB_AC97 = 0x00000000; //SLOT1:WR REG MASTER VOLUME adr 0x02
|
|
for (i = 3; i < 13; i++) {
|
|
MCF_PSC2_PSCTB_AC97 = 0x0; //SLOT2-12:WR REG ALLES 0
|
|
}
|
|
MCF_PSC2_PSCTFCR |= MCF_PSC_PSCTFCR_WFR; //set EOF
|
|
MCF_PSC2_PSCTB_AC97 = 0x00000000; //last data
|
|
xprintf(" finished\r\n");
|
|
}
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
#ifdef MACHINE_FIREBEE
|
|
static void wait_pll(void)
|
|
{
|
|
int32_t trgt = MCF_SLT0_SCNT - 100000;
|
|
do
|
|
{
|
|
;
|
|
} while ((* (volatile int16_t *) 0xf0000800 < 0) && MCF_SLT0_SCNT > trgt);
|
|
}
|
|
|
|
static volatile uint8_t *pll_base = (volatile uint8_t *) 0xf0000600;
|
|
|
|
static void init_pll(void)
|
|
{
|
|
xprintf("FPGA PLL initialization: ");
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x48) = 27; /* loopfilter r */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x08) = 1; /* charge pump 1 */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x00) = 12; /* N counter high = 12 */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x40) = 12; /* N counter low = 12 */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x114) = 1; /* ck1 bypass */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x118) = 1; /* ck2 bypass */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x11c) = 1; /* ck3 bypass */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x10) = 1; /* ck0 high = 1 */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x50) = 1; /* ck0 low = 1 */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x144) = 1; /* M odd division */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x44) = 1; /* M low = 1 */
|
|
|
|
wait_pll();
|
|
* (volatile uint16_t *) (pll_base + 0x04) = 145; /* M high = 145 = 146 MHz */
|
|
|
|
wait_pll();
|
|
|
|
* (volatile uint8_t *) 0xf0000800 = 0; /* set */
|
|
|
|
xprintf("finished\r\n");
|
|
}
|
|
|
|
/*
|
|
* INIT VIDEO DDR RAM
|
|
*/
|
|
static void init_video_ddr(void) {
|
|
xprintf("init video RAM: ");
|
|
|
|
* (volatile uint16_t *) 0xf0000400 = 0xb; /* set cke = 1, cs=1, config = 1 */
|
|
NOP();
|
|
|
|
_VRAM = 0x00050400; /* IPALL */
|
|
NOP();
|
|
|
|
_VRAM = 0x00072000; /* load EMR pll on */
|
|
NOP();
|
|
|
|
_VRAM = 0x00070122; /* load MR: reset pll, cl=2, burst=4lw */
|
|
NOP();
|
|
|
|
_VRAM = 0x00050400; /* IPALL */
|
|
NOP();
|
|
|
|
_VRAM = 0x00060000; /* auto refresh */
|
|
NOP();
|
|
|
|
_VRAM = 0x00060000; /* auto refresh */
|
|
NOP();
|
|
|
|
/* FIXME: what's this? */
|
|
_VRAM = 0x00070022; /* load MR dll on */
|
|
NOP();
|
|
|
|
* (uint32_t *) 0xf0000400 = 0x01070082; /* fifo on, refresh on, ddrcs und cke on, video dac on, Falcon shift mode on */
|
|
|
|
xprintf("finished\r\n");
|
|
}
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
|
|
/*
|
|
* check if it is possible to transfer data to PIC
|
|
*/
|
|
static inline bool pic_txready(void)
|
|
{
|
|
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_TXRDY)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* check if it is possible to receive data from PIC
|
|
*/
|
|
static inline bool pic_rxready(void)
|
|
{
|
|
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_RXRDY)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void write_pic_byte(uint8_t value)
|
|
{
|
|
/*
|
|
* Wait until the transmitter is ready or 1000us are passed
|
|
*/
|
|
waitfor(1000, pic_txready);
|
|
|
|
/*
|
|
* Transmit the byte
|
|
*/
|
|
*(volatile uint8_t*)(&MCF_PSC3_PSCTB_8BIT) = value; // Really 8-bit
|
|
}
|
|
|
|
uint8_t read_pic_byte(void)
|
|
{
|
|
/*
|
|
* Wait until a byte has been received or 1000us are passed
|
|
*/
|
|
waitfor(1000, pic_rxready);
|
|
|
|
/*
|
|
* Return the received byte
|
|
*/
|
|
return * (volatile uint8_t *) (&MCF_PSC3_PSCTB_8BIT); // Really 8-bit
|
|
}
|
|
|
|
void pic_init(void)
|
|
{
|
|
char answer[4] = "OLD";
|
|
|
|
xprintf("initialize the PIC: ");
|
|
|
|
/*
|
|
* Send the PIC initialization string
|
|
*/
|
|
write_pic_byte('A');
|
|
write_pic_byte('C');
|
|
write_pic_byte('P');
|
|
write_pic_byte('F');
|
|
|
|
/*
|
|
* Read the 3-char answer string. Should be "OK!".
|
|
*/
|
|
answer[0] = read_pic_byte();
|
|
answer[1] = read_pic_byte();
|
|
answer[2] = read_pic_byte();
|
|
answer[3] = '\0';
|
|
|
|
if (answer[0] != 'O' || answer[1] != 'K' || answer[2] != '!')
|
|
{
|
|
dbg("PIC initialization failed. Already initialized?\r\n");
|
|
}
|
|
else
|
|
{
|
|
xprintf("%s\r\n", answer);
|
|
}
|
|
}
|
|
|
|
void nvram_init(void)
|
|
{
|
|
int i;
|
|
|
|
xprintf("Restore the NVRAM data: ");
|
|
|
|
/* Request for NVRAM backup data */
|
|
write_pic_byte(0x01);
|
|
|
|
/* Check answer type */
|
|
if (read_pic_byte() != 0x81)
|
|
{
|
|
// FIXME: PIC protocol error
|
|
xprintf("FAILED\r\n");
|
|
return;
|
|
}
|
|
|
|
/* Restore the NVRAM backup to the FPGA */
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
uint8_t data = read_pic_byte();
|
|
* (volatile uint8_t*) 0xffff8961 = i;
|
|
* (volatile uint8_t*) 0xffff8963 = data;
|
|
}
|
|
|
|
xprintf("finished\r\n");
|
|
}
|
|
|
|
#define KBD_ACIA_CONTROL * ((uint8_t *) 0xfffffc00)
|
|
#define MIDI_ACIA_CONTROL * ((uint8_t *) 0xfffffc04)
|
|
#define MFP_INTR_IN_SERVICE_A * ((uint8_t *) 0xfffffa0f)
|
|
#define MFP_INTR_IN_SERVICE_B * ((uint8_t *) 0xfffffa11)
|
|
|
|
void acia_init()
|
|
{
|
|
xprintf("init ACIA: ");
|
|
/* init ACIA */
|
|
KBD_ACIA_CONTROL = 3; /* master reset */
|
|
NOP();
|
|
|
|
MIDI_ACIA_CONTROL = 3; /* master reset */
|
|
NOP();
|
|
|
|
KBD_ACIA_CONTROL = 0x96; /* clock div = 64, 8N1, RTS low, TX int disable, RX int enable */
|
|
NOP();
|
|
|
|
MFP_INTR_IN_SERVICE_A = 0xff;
|
|
NOP();
|
|
|
|
MFP_INTR_IN_SERVICE_B = 0xff;
|
|
NOP();
|
|
|
|
xprintf("finished\r\n");
|
|
}
|
|
|
|
void enable_coldfire_interrupts()
|
|
{
|
|
xprintf("enable interrupts: ");
|
|
#if defined(MACHINE_FIREBEE)
|
|
FBEE_INTR_CONTROL = 0L; /* disable all interrupts */
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
MCF_EPORT_EPPAR = 0xaaa8; /* all interrupts on falling edge */
|
|
|
|
#ifdef _NOT_USED_
|
|
#if defined(MACHINE_FIREBEE)
|
|
/*
|
|
* TIN0 on the Coldfire is connected to the FPGA. TIN0 triggers every write
|
|
* access to 0xff8201 (vbasehi), i.e. everytime the video base address is written
|
|
*/
|
|
MCF_GPT0_GMS = MCF_GPT_GMS_ICT(1) | /* timer 0 on, video change capture on rising edge */
|
|
MCF_GPT_GMS_IEN |
|
|
MCF_GPT_GMS_TMS(1); /* route GPT0 interrupt on interrupt controller */
|
|
MCF_INTC_ICR62 = MCF_INTC_ICR_IL(7) |
|
|
MCF_INTC_ICR_IP(6); /* interrupt level 7, interrupt priority 6 */
|
|
MCF_INTC_IMRH = 0xbffffffe; /* psc3 and timer 0 int on */
|
|
#endif
|
|
#endif
|
|
xprintf("finished\r\n");
|
|
}
|
|
|
|
void enable_pci_interrupts()
|
|
{
|
|
dbg("enable PCI interrupts\r\n");
|
|
MCF_EPORT_EPIER = 0xfe; /* int 1-7 on */
|
|
MCF_EPORT_EPFR = 0xff; /* clear all pending interrupts */
|
|
MCF_INTC_IMRL = 0xffffff00; /* int 1-7 on */
|
|
MCF_INTC_IMRH = 0;
|
|
#if defined(MACHINE_FIREBEE)
|
|
FBEE_INTR_ENABLE = FBEE_INTR_INT_IRQ7 | /* enable pseudo bus error */
|
|
FBEE_INTR_INT_MFP_IRQ6 | /* enable MFP interrupts */
|
|
FBEE_INTR_INT_FPGA_IRQ5 | /* enable Firebee (PIC, PCI, ETH PHY, DVI, DSP) interrupts */
|
|
FBEE_INTR_INT_VSYNC_IRQ4 | /* enable vsync interrupts */
|
|
FBEE_INTR_PCI_INTA | /* enable PCI interrupts */
|
|
FBEE_INTR_PCI_INTB |
|
|
FBEE_INTR_PCI_INTC |
|
|
FBEE_INTR_PCI_INTD;
|
|
;
|
|
#elif defined(MACHINE_M5484LITE) || defined(MACHINE_M5475EVB)
|
|
/*
|
|
* MCF 5484 interrupts are configured at the CPLD for the FireEngine
|
|
*/
|
|
|
|
/* TODO: enable PCI interrupts on the LITEKIT */
|
|
#elif defined(MACHINE_M54455)
|
|
/* MCF 54455 interrupts are configured at the FPGA */
|
|
|
|
/* TODO: enable PCI interrupts on the MCF54455 */
|
|
#else
|
|
#error unknown machine!
|
|
#endif
|
|
}
|
|
|
|
void disable_coldfire_interrupts()
|
|
{
|
|
#if defined(MACHINE_FIREBEE)
|
|
FBEE_INTR_ENABLE = 0; /* disable all interrupts */
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
MCF_EPORT_EPIER = 0x0;
|
|
MCF_INTC_IMRL = 0xfffffffe;
|
|
MCF_INTC_IMRH = 0xffffffff;
|
|
}
|
|
|
|
|
|
|
|
NIF nif1;
|
|
#if defined(MACHINE_M5484LITE) || defined(MACHINE_M5475EVB)
|
|
/*
|
|
* on the MCF 5484 LITEKIT, the second FEC interface is usable
|
|
*/
|
|
NIF nif2;
|
|
#endif
|
|
|
|
bool spurious_interrupt_handler(void *arg1, void *arg2)
|
|
{
|
|
err("spurious interrupt\r\n");
|
|
err("IMRH=%lx, IMRL=%lx\r\n", MCF_INTC_IMRH, MCF_INTC_IMRL);
|
|
err("IPRH=%lx, IPRL=%lx\r\n", MCF_INTC_IPRH, MCF_INTC_IPRL);
|
|
err("IRLR=%x\r\n", MCF_INTC_IRLR);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* initialize the interrupt handler tables to dispatch interrupt requests from Coldfire devices
|
|
*/
|
|
void init_isr(void)
|
|
{
|
|
isr_init(); /* need to call that explicitely, otherwise isr table might be full */
|
|
|
|
/*
|
|
* register spurious interrupt handler
|
|
*/
|
|
if (!isr_register_handler(24, 6, 6, spurious_interrupt_handler, NULL, NULL))
|
|
{
|
|
dbg("unable to register spurious interrupt handler\r\n");
|
|
}
|
|
|
|
/*
|
|
* register the FEC interrupt handler
|
|
*/
|
|
if (!isr_register_handler(64 + INT_SOURCE_FEC0, 5, 1, fec0_interrupt_handler, NULL, (void *) &nif1))
|
|
{
|
|
dbg("unable to register isr for FEC0\r\n");
|
|
}
|
|
|
|
/*
|
|
* Register the DMA interrupt handler
|
|
*/
|
|
|
|
if (!isr_register_handler(64 + INT_SOURCE_DMA, 5, 3, dma_interrupt_handler, NULL, NULL))
|
|
{
|
|
dbg("unable to register isr for DMA\r\n");
|
|
}
|
|
|
|
#if defined(MACHINE_FIREBEE)
|
|
/*
|
|
* register GPT0 timer interrupt vector
|
|
*/
|
|
if (!isr_register_handler(64 + INT_SOURCE_GPT0, 5, 2, gpt0_interrupt_handler, NULL, NULL))
|
|
{
|
|
dbg("unable to register isr for GPT0 timer\r\n");
|
|
}
|
|
|
|
/*
|
|
* register the PIC interrupt handler
|
|
*/
|
|
if (!isr_register_handler(64 + INT_SOURCE_PSC3, 5, 5, pic_interrupt_handler, NULL, NULL))
|
|
{
|
|
dbg("Error: unable to register ISR for PSC3\r\n");
|
|
}
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
/*
|
|
* register the XLB PCI interrupt handler
|
|
*/
|
|
if (!isr_register_handler(64 + INT_SOURCE_XLBPCI, 3, 0, xlbpci_interrupt_handler, NULL, NULL))
|
|
{
|
|
dbg("Error: unable to register isr for XLB PCI interrupts\r\n");
|
|
}
|
|
|
|
|
|
/*
|
|
* initialize arbiter timeout registers
|
|
*/
|
|
MCF_XLB_XARB_ADRTO = 0x1fffff;
|
|
MCF_XLB_XARB_DATTO = 0x1fffff;
|
|
MCF_XLB_XARB_BUSTO = 0xffffff;
|
|
|
|
|
|
MCF_XLB_XARB_IMR = MCF_XLB_XARB_IMR_SEAE | /* slave error acknowledge interrupt */
|
|
MCF_XLB_XARB_IMR_MME | /* multiple master at prio 0 interrupt */
|
|
MCF_XLB_XARB_IMR_TTAE | /* TT address only interrupt */
|
|
MCF_XLB_XARB_IMR_TTRE | /* TT reserved interrupt enable */
|
|
MCF_XLB_XARB_IMR_ECWE | /* external control word interrupt */
|
|
MCF_XLB_XARB_IMR_TTME | /* TBST/TSIZ mismatch interrupt */
|
|
MCF_XLB_XARB_IMR_BAE; /* bus activity tenure timeout interrupt */
|
|
|
|
if (!isr_register_handler(64 + INT_SOURCE_PCIARB, 5, 0, pciarb_interrupt_handler, NULL, NULL))
|
|
{
|
|
dbg("Error: unable to register isr for PCIARB interrupts\r\n");
|
|
|
|
return;
|
|
}
|
|
MCF_PCIARB_PACR = MCF_PCIARB_PACR_EXTMINTEN(0x1f) | /* external master broken interrupt */
|
|
MCF_PCIARB_PACR_INTMINTEN; /* internal master broken interrupt */
|
|
|
|
if (!isr_register_handler(64 + INT_SOURCE_XLBARB, 7, 1, xlbarb_interrupt_handler, NULL, NULL))
|
|
{
|
|
dbg("Error: unable to register isr for XLB ARB interrupts\r\n");
|
|
}
|
|
}
|
|
|
|
void ide_init(void)
|
|
{
|
|
/* IDE reset */
|
|
* (volatile uint8_t *) (0xffff8802 - 2) = 14;
|
|
* (volatile uint8_t *) (0xffff8802 - 0) = 0x80;
|
|
wait_ms(1);
|
|
|
|
* (volatile uint8_t *) (0xffff8802 - 0) = 0;
|
|
|
|
set_ide_access_mode();
|
|
}
|
|
|
|
/*
|
|
* probe for NEC compatible USB host controller and install if found
|
|
*/
|
|
void init_usb(void)
|
|
{
|
|
extern struct pci_device_id ohci_usb_pci_table[];
|
|
extern struct pci_device_id ehci_usb_pci_table[];
|
|
struct pci_device_id *board;
|
|
int32_t handle;
|
|
int usb_found = 0;
|
|
int index = 0;
|
|
|
|
/*
|
|
* disabled for now
|
|
*/
|
|
return;
|
|
|
|
inf("USB controller initialization:\r\n");
|
|
|
|
do
|
|
{
|
|
handle = pci_find_classcode(PCI_CLASS_SERIAL_USB | PCI_FIND_BASE_CLASS | PCI_FIND_SUB_CLASS, index++);
|
|
dbg("handle 0x%02x\r\n", handle);
|
|
if (handle > 0)
|
|
{
|
|
long id;
|
|
long pci_class;
|
|
|
|
xprintf("serial USB found at bus=0x%x, dev=0x%x, fnc=0x%x (0x%x)\r\n",
|
|
PCI_BUS_FROM_HANDLE(handle),
|
|
PCI_DEVICE_FROM_HANDLE(handle),
|
|
PCI_FUNCTION_FROM_HANDLE(handle),
|
|
handle);
|
|
id = swpl(pci_read_config_longword(handle, PCIIDR));
|
|
pci_class = swpl(pci_read_config_longword(handle, PCIREV));
|
|
|
|
if (pci_class >> 8 == PCI_CLASS_SERIAL_USB_EHCI)
|
|
{
|
|
board = ehci_usb_pci_table;
|
|
while (board->vendor)
|
|
{
|
|
if ((board->vendor == PCI_VENDOR_ID(id)) && board->device == PCI_DEVICE_ID(id))
|
|
{
|
|
if (usb_init(handle, board) >= 0)
|
|
{
|
|
usb_found++;
|
|
}
|
|
}
|
|
board++;
|
|
}
|
|
}
|
|
if (pci_class >> 8 == PCI_CLASS_SERIAL_USB_OHCI)
|
|
{
|
|
board = ohci_usb_pci_table;
|
|
while (board->vendor)
|
|
{
|
|
if ((board->vendor == PCI_VENDOR_ID(id)) && board->device == PCI_DEVICE_ID(id))
|
|
{
|
|
if (usb_init(handle, board) >= 0)
|
|
usb_found++;
|
|
}
|
|
board++;
|
|
}
|
|
}
|
|
}
|
|
} while (handle >= 0);
|
|
|
|
xprintf("finished (found %d USB controller(s))\r\n", usb_found);
|
|
}
|
|
|
|
|
|
/* Jump into the OS */
|
|
typedef void void_func(void);
|
|
struct rom_header
|
|
{
|
|
void *initial_sp;
|
|
void_func *initial_pc;
|
|
};
|
|
|
|
/*
|
|
* fix ST RAM header (address 0x0 and 0x4). FreeMiNT uses these vectors on CTRL-ALT-DEL.
|
|
*
|
|
* Beware: Newer compilers refuse to dereference pointers to NULL and abort (trap #7) if the following
|
|
* attribute isn't set.
|
|
*/
|
|
static void fix_stram_header() __attribute__((optimize("no-delete-null-pointer-checks")));
|
|
static void fix_stram_header()
|
|
{
|
|
struct rom_header *bas_header = (struct rom_header *) TARGET_ADDRESS;
|
|
struct rom_header *stram_header = (struct rom_header *) 0x0;
|
|
|
|
*stram_header = *bas_header;
|
|
}
|
|
|
|
void BaS(void)
|
|
{
|
|
uint8_t *src;
|
|
uint8_t *dst = (uint8_t *) TOS;
|
|
|
|
/*
|
|
* install (preliminary) exception vectors
|
|
*/
|
|
setup_vectors();
|
|
|
|
xprintf("\n\n");
|
|
xprintf("%s BASIS system (BaS) v %d.%d (%s, %s)\r\n\r\n",
|
|
#if defined(MACHINE_FIREBEE)
|
|
"Firebee"
|
|
#elif MACHINE_M5484LITE
|
|
"m5484 LITEKIT"
|
|
#elif MACHINE_M5475EVB
|
|
"m5475 EVB"
|
|
#else
|
|
"unknown platform"
|
|
#endif
|
|
, MAJOR_VERSION, MINOR_VERSION, __DATE__, __TIME__);
|
|
|
|
/*
|
|
* Determine cause(s) of Reset
|
|
*/
|
|
if (MCF_SIU_RSR & MCF_SIU_RSR_RST)
|
|
xprintf("Reset. Cause: External Reset\r\n");
|
|
if (MCF_SIU_RSR & MCF_SIU_RSR_RSTWD)
|
|
xprintf("Reset. Cause: Watchdog Timer Reset\n");
|
|
if (MCF_SIU_RSR & MCF_SIU_RSR_RSTJTG)
|
|
xprintf("Reset. Cause: BDM/JTAG Reset\r\n");
|
|
|
|
#if defined(MACHINE_FIREBEE) // initialize FireBee specific hardware components */
|
|
fpga_configured = init_fpga();
|
|
|
|
init_pll();
|
|
init_video_ddr();
|
|
dvi_on();
|
|
init_ac97();
|
|
pic_init();
|
|
nvram_init();
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
driver_mem_init();
|
|
|
|
xprintf("initialize MMU: ");
|
|
mmu_init();
|
|
xprintf("finished\r\n");
|
|
|
|
xprintf("initialize Coldfire DMA: ");
|
|
dma_init();
|
|
xprintf("finished\r\n");
|
|
|
|
xprintf("copy EmuTOS: ");
|
|
/* copy EMUTOS */
|
|
src = (uint8_t *) EMUTOS;
|
|
memcpy(dst, src, EMUTOS_SIZE);
|
|
xprintf("finished\r\n");
|
|
|
|
xprintf("flush caches: ");
|
|
flush_and_invalidate_caches();
|
|
xprintf("finished\r\n");
|
|
|
|
xprintf("initialize exception vector table: ");
|
|
vec_init();
|
|
xprintf("finished\r\n");
|
|
|
|
|
|
memset((void *) 0x0200, 0x0, 0x0400);
|
|
|
|
#if defined(MACHINE_FIREBEE)
|
|
xprintf("IDE reset: \r\n");
|
|
ide_init();
|
|
xprintf("finished\r\n");
|
|
|
|
xprintf("enable MMU: ");
|
|
MCF_MMU_MMUCR = MCF_MMU_MMUCR_EN; /* MMU on */
|
|
NOP(); /* force pipeline sync */
|
|
xprintf("finished\r\n");
|
|
|
|
xprintf("enable video: ");
|
|
|
|
/*
|
|
* ATARI video modes "modeline"
|
|
*
|
|
* horizontal:
|
|
* high word: h_total
|
|
* low word: hsync_start
|
|
*
|
|
* vertical:
|
|
* high word v_total
|
|
* low word vsync_start
|
|
*
|
|
* can be calculated with umc ("universal modeline generator")
|
|
*
|
|
*/
|
|
struct atari_video_timing
|
|
{
|
|
uint16_t total;
|
|
uint16_t sync_start;
|
|
};
|
|
|
|
static volatile struct atari_video_timing *hor_640x480 = (volatile struct atari_video_timing *) 0xf0000410;
|
|
static volatile struct atari_video_timing *ver_640x480 = (volatile struct atari_video_timing *) 0xf0000414;
|
|
static volatile struct atari_video_timing *hor_320x240 = (volatile struct atari_video_timing *) 0xf0000418;
|
|
static volatile struct atari_video_timing *ver_320x240 = (volatile struct atari_video_timing *) 0xf000041c;
|
|
|
|
#undef VIDEO_25MHZ
|
|
|
|
#ifdef VIDEO_25MHZ
|
|
hor_640x480->total = 0x320; /* 800 */
|
|
hor_640x480->sync_start = 0x2ba; /* 698 */
|
|
ver_640x480->total = 0x20c; /* 524 */
|
|
ver_640x480->sync_start = 0x20a; /* 522 */
|
|
|
|
hor_320x240->total = 0x190; /* 400 */
|
|
hor_320x240->sync_start = 0x15d; /* 349 */
|
|
ver_320x240->total = 0x20c; /* 524 */
|
|
ver_320x240->sync_start = 0x20a; /* 522 */
|
|
#else /* 32 MHz */
|
|
hor_640x480->total = 0x370; /* 880 */
|
|
hor_640x480->sync_start = 0x2ba; /* 698 */
|
|
ver_640x480->total = 0x20d; /* 525 */
|
|
ver_640x480->sync_start = 0x20a; /* 522 */
|
|
|
|
hor_320x240->total = 0x2a0; /* 672 */
|
|
hor_320x240->sync_start = 0x1e0; /* 480 */
|
|
ver_320x240->total = 0x5a0; /* 480 */
|
|
ver_320x240->sync_start = 0x160; /* 352 */
|
|
#endif
|
|
|
|
/* fifo on, refresh on, ddrcs and cke on, video dac on */
|
|
* (volatile uint32_t *) 0xf0000400 = 0x01070082;
|
|
|
|
xprintf("finished\r\n");
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
sd_card_init();
|
|
|
|
|
|
#if defined(MACHINE_FIREBEE)
|
|
/* set Falcon bus control register */
|
|
/* sets bit 3 and 6. Both are undefined on an original Falcon? */
|
|
|
|
* (volatile uint8_t *) 0xffff8007 = 0x48;
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
/* ST RAM */
|
|
|
|
* (uint32_t *) 0x42e = STRAM_END; /* phystop TOS system variable */
|
|
* (uint32_t *) 0x420 = 0x752019f3; /* memvalid TOS system variable */
|
|
* (uint32_t *) 0x43a = 0x237698aa; /* memval2 TOS system variable */
|
|
* (uint32_t *) 0x51a = 0x5555aaaa; /* memval3 TOS system variable */
|
|
|
|
/* TT-RAM */
|
|
|
|
* (uint32_t *) 0x5a4 = FASTRAM_END; /* ramtop TOS system variable */
|
|
* (uint32_t *) 0x5a8 = 0x1357bd13; /* ramvalid TOS system variable */
|
|
|
|
#if defined(MACHINE_FIREBEE) /* m5484lite has no ACIA and no dip switch... */
|
|
acia_init();
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
srec_execute("BASFLASH.S19");
|
|
|
|
xprintf("BaS initialization finished, enable interrupts\r\n");
|
|
init_isr();
|
|
|
|
enable_coldfire_interrupts();
|
|
MCF_INTC_IMRH = 0;
|
|
MCF_INTC_IMRL = 0;
|
|
|
|
dma_irq_enable();
|
|
fec_irq_enable(0, 5, 1);
|
|
|
|
enable_pci_interrupts();
|
|
init_pci();
|
|
|
|
video_init();
|
|
|
|
/* initialize USB devices */
|
|
// init_usb();
|
|
|
|
set_ipl(7); /* disable interrupts */
|
|
|
|
/*
|
|
* start FireTOS if DIP switch is set accordingly
|
|
*/
|
|
if (!(DIP_SWITCH & (1 << 6)))
|
|
{
|
|
extern uint8_t _FIRETOS[];
|
|
#define FIRETOS ((uint32_t)_FIRETOS) /* where FireTOS is stored in flash */
|
|
|
|
/* make sure MMU is disabled */
|
|
MCF_MMU_MMUCR = 0; /* MMU off */
|
|
NOP(); /* force pipeline sync */
|
|
|
|
|
|
/* ST RAM */
|
|
|
|
* (uint32_t *) 0x42e = STRAM_END; /* phystop TOS system variable */
|
|
* (uint32_t *) 0x420 = 0x752019f3; /* memvalid TOS system variable */
|
|
* (uint32_t *) 0x43a = 0x237698aa; /* memval2 TOS system variable */
|
|
* (uint32_t *) 0x51a = 0x5555aaaa; /* memval3 TOS system variable */
|
|
|
|
/* TT-RAM */
|
|
|
|
* (uint32_t *) 0x5a4 = FASTRAM_END; /* ramtop TOS system variable */
|
|
* (uint32_t *) 0x5a8 = 0x1357bd13; /* ramvalid TOS system variable */
|
|
|
|
xprintf("call FireTOS\r\n");
|
|
/* Jump into FireTOS */
|
|
|
|
void_func* FireTOS = (void_func*) FIRETOS;
|
|
FireTOS(); // Should never return
|
|
}
|
|
|
|
/*
|
|
* fix initial pc/sp in ST RAM for FreeMiNT. It expects valid values there
|
|
* like on original STs (where these values reside in ROM) and uses them on
|
|
* CTRL-ALT-DELETE reboots.
|
|
*/
|
|
fix_stram_header();
|
|
|
|
xprintf("call EmuTOS\r\n");
|
|
struct rom_header *os_header = (struct rom_header *) TOS;
|
|
os_header->initial_pc();
|
|
}
|