From: wdenk Date: Fri, 23 Nov 2001 17:38:33 +0000 (+0000) Subject: * Add CPU Support for MPC 75x; X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=b812b2f62ff495640acb3b9911bb108f77bae653;p=users%2Frw%2Fppcboot.git * Add CPU Support for MPC 75x; add board support for Eltec BAB750 board Patch by Andreas Heppel, 22 Nov 2001 --- diff --git a/CHANGELOG b/CHANGELOG index 6d7b918..0dab9d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -56,6 +56,10 @@ To do: Modifications for 1.1.1: ====================================================================== +* Add CPU Support for MPC 75x; + add board support for Eltec BAB750 board + Patch by Andreas Heppel, 22 Nov 2001 + * Fix problem with TFTP server in different subnet, or with "gatewayip" set when not needed. Patch by Nye Liu, 21 Nov 2001 diff --git a/CREDITS b/CREDITS index abd686b..56247a0 100644 --- a/CREDITS +++ b/CREDITS @@ -84,6 +84,10 @@ N: Anne-Sophie Harnois E: Anne-Sophie.Harnois@nextream.fr D: Port to Walnut405 board +N: Andreas Heppel +E: aheppel@sysgo.de +D: CPU Support for MPC 75x; board support for Eltec BAB750 + N: Josh Huber E: huber@alum.wpi.edu D: Port to the Galileo Evaluation Board, and the MPC74xx cpu series. diff --git a/MAKEALL b/MAKEALL index 60b8c98..c7907e5 100755 --- a/MAKEALL +++ b/MAKEALL @@ -72,7 +72,16 @@ LIST_74xx=" \ EVB64260 \ " -LIST_all="${LIST_8xx} ${LIST_8240} ${LIST_8260} ${LIST_4xx}" +######################################################################### +## MPC7xx Systems +######################################################################### + +LIST_7xx=" \ + BAB750 \ +" + +LIST_all="${LIST_8xx} ${LIST_8240} ${LIST_8260} \ + ${LIST_4xx} ${LIST_74xx} ${LIST_7xx}" [ $# = 0 ] && set $LIST_all diff --git a/Makefile b/Makefile index 19ebc73..d7d3433 100644 --- a/Makefile +++ b/Makefile @@ -593,6 +593,19 @@ EVB64260_config: unconfig echo "CPU = mpc74xx" >>config.mk ; \ echo "#include " >config.h +######################################################################### +## MPC7xx Systems +######################################################################### + +BAB750_config: unconfig + @echo "Configuring for $(@:_config=) Board..." ; \ + cd include ; \ + echo "ARCH = ppc" > config.mk ; \ + echo "VENDOR= eltec" >>config.mk ; \ + echo "BOARD = bab750" >>config.mk ; \ + echo "CPU = mpc75x" >>config.mk ; \ + echo "#include " >config.h + ######################################################################### clean: diff --git a/board/eltec/bab750/Makefile b/board/eltec/bab750/Makefile new file mode 100644 index 0000000..0b448bf --- /dev/null +++ b/board/eltec/bab750/Makefile @@ -0,0 +1,48 @@ +# +# (C) Copyright 2001 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = lib$(BOARD).a + +OBJS = $(BOARD).o flash.o ns16550.o ns87308.o serial.o speed.o \ + dc2114x.o w83c553f.o mpc106_pci.o mpc106.o sym53c8xx.o +SOBJS = mpc106_init.o + +$(LIB): .depend $(OBJS) $(SOBJS) + $(AR) crv $@ $^ + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/board/eltec/bab750/bab750.c b/board/eltec/bab750/bab750.c new file mode 100644 index 0000000..bac9fa6 --- /dev/null +++ b/board/eltec/bab750/bab750.c @@ -0,0 +1,112 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + + +int checkboard (void) +{ + printf("BAB 750\n"); + return 0; +} + +int checkflash (void) +{ + /* TODO: XXX XXX XXX */ + printf ("2 MB ## Test not implemented yet ##\n"); + + return (0); +} + +long int dram_size (int board_type) +{ + /* No actual initialisation to do - done when setting up PICRs MCCRs ME/SARs etc + * in ram_init.S. + */ + #if defined(CFG_MEMTEST) + + register unsigned long reg; + + printf("Testing DRAM\n"); + + /* write each mem addr with it's address */ + for (reg = CFG_MEMTEST_START; reg < CFG_MEMTEST_END; reg+=4 + *reg = reg; + + for (reg = CFG_MEMTEST_START; reg < CFG_MEMTEST_END; reg+=4 + { + if (*reg != reg) + return -1; + } + #endif + + /* TODO: calculate amount of dram..for now just return MEMTEST_END */ + return CFG_MEMTEST_END; + +} + +long int initdram(int board_type) +{ + return dram_size(board_type); +} +/* ------------------------------------------------------------------------- */ + +/* + * do_reset is done here because in this case it is board specific, since the + * 7xx CPUs can only be reset by external HW (the RTC in this case). + */ +void +do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) +{ +#if defined(CONFIG_RTC_MK48T59) + /* trigger watchdog immediately */ + rtc_set_watchdog(1, RTC_WD_RB_16TH); +#else + #error "You must define the macro CONFIG_RTC_MK48T59." +#endif +} + +/* ------------------------------------------------------------------------- */ + +#if defined(CONFIG_WATCHDOG) + +/* + * Since the 7xx CPUs don't have an internal watchdog, this function is board specific. + * We use the RTC here. + */ +void watchdog_reset(void) +{ +#if defined(CONFIG_RTC_MK48T59) + /* we use a 32 sec watchdog timer */ + rtc_set_watchdog(8, RTC_WD_RB_4); +#else + #error "You must define the macro CONFIG_RTC_MK48T59." +#endif +} +#endif /* CONFIG_WATCHDOG */ + + diff --git a/board/eltec/bab750/config.mk b/board/eltec/bab750/config.mk new file mode 100644 index 0000000..50f480d --- /dev/null +++ b/board/eltec/bab750/config.mk @@ -0,0 +1,31 @@ +# +# (C) Copyright 2000 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +# +# BAB740 boards +# + +TEXT_BASE = 0xFFC00000 +#TEXT_BASE = 0x400000 + +PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) diff --git a/board/eltec/bab750/dc2114x.c b/board/eltec/bab750/dc2114x.c new file mode 100644 index 0000000..cf8464c --- /dev/null +++ b/board/eltec/bab750/dc2114x.c @@ -0,0 +1,540 @@ +/* + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + + +/* PCI Registers. + */ +#define PCI_CFDA_PSM 0x43 + +#define CFRV_RN 0x000000f0 /* Revision Number */ +#define CBIO_MASK 0xffffff80 + +#define WAKEUP 0x00 /* Power Saving Wakeup */ +#define SLEEP 0x80 /* Power Saving Sleep Mode */ + + +#define DC2114x_VID 0x1011 /* DC2114[23] Manufacturer */ +#define DC2114x_DID 0x0019 /* Unique Device ID # */ +#define DC2114x_BRK 0x0020 /* CFRV break between DC21142 & DC21143 */ +#define DC21142 (DC2114x_DID << 8 | 0x0010) +#define DC21143 (DC2114x_DID << 8 | 0x0030) + +#define is_DC2114x ((vendor == DC2114x_VID) && (device == DC2114x_DID)) + +/* Ethernet chip registers. + */ +#define DE4X5_BMR iobase + 0x000 /* Bus Mode Register */ +#define DE4X5_TPD iobase + 0x008 /* Transmit Poll Demand Reg */ +#define DE4X5_RRBA iobase + 0x018 /* RX Ring Base Address Reg */ +#define DE4X5_TRBA iobase + 0x020 /* TX Ring Base Address Reg */ +#define DE4X5_STS iobase + 0x028 /* Status Register */ +#define DE4X5_OMR iobase + 0x030 /* Operation Mode Register */ +#define DE4X5_SICR iobase + 0x068 /* SIA Connectivity Register */ +#define DE4X5_APROM iobase + 0x048 /* Ethernet Address PROM */ + +/* Register bits. + */ +#define BMR_SWR 0x00000001 /* Software Reset */ +#define STS_TS 0x00700000 /* Transmit Process State */ +#define STS_RS 0x000e0000 /* Receive Process State */ +#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */ +#define OMR_SR 0x00000002 /* Start/Stop Receive */ +#define OMR_PS 0x00040000 /* Port Select */ +#define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */ +#define OMR_PM 0x00000080 /* Pass All Multicast */ + +/* Descriptor bits. + */ +#define R_OWN 0x80000000 /* Own Bit */ +#define RD_RER 0x02000000 /* Receive End Of Ring */ +#define RD_LS 0x00000100 /* Last Descriptor */ +#define RD_ES 0x00008000 /* Error Summary */ +#define TD_TER 0x02000000 /* Transmit End Of Ring */ +#define T_OWN 0x80000000 /* Own Bit */ +#define TD_LS 0x40000000 /* Last Segment */ +#define TD_FS 0x20000000 /* First Segment */ +#define TD_ES 0x00008000 /* Error Summary */ +#define TD_SET 0x08000000 /* Setup Packet */ + + +#define SROM_HWADD 0x0014 /* Hardware Address offset in SROM */ +#define SROM_RD 0x00004000 /* Read from Boot ROM */ +#define SROM_SR 0x00000800 /* Select Serial ROM when set */ + +#define DT_IN 0x00000004 /* Serial Data In */ +#define DT_CLK 0x00000002 /* Serial ROM Clock */ +#define DT_CS 0x00000001 /* Serial ROM Chip Select */ + +#define POLL_DEMAND 1 + +#define RESET_DE4X5 {\ + int i;\ + i=inl(DE4X5_BMR);\ + udelay(1000);\ + outl(i | BMR_SWR, DE4X5_BMR);\ + udelay(1000);\ + outl(i, DE4X5_BMR);\ + udelay(1000);\ + for (i=0;i<5;i++) {inl(DE4X5_BMR); udelay(10000);}\ + udelay(1000);\ +} + +#define START_DE4X5 {\ + s32 omr; \ + omr = inl(DE4X5_OMR);\ + omr |= OMR_ST | OMR_SR;\ + outl(omr, DE4X5_OMR); /* Enable the TX and/or RX */\ +} + +#define STOP_DE4X5 {\ + s32 omr; \ + omr = inl(DE4X5_OMR);\ + omr &= ~(OMR_ST|OMR_SR);\ + outl(omr, DE4X5_OMR); /* Disable the TX and/or RX */ \ +} + +#define NUM_RX_DESC PKTBUFSRX +#define NUM_TX_DESC 1 /* Number of TX descriptors */ +#define RX_BUFF_SZ PKTSIZE_ALIGN + +#define TOUT_LOOP 1000000 + +#define SETUP_FRAME_LEN 192 +#define ETH_ALEN 6 + + +struct de4x5_desc { + volatile s32 status; + u32 des1; + u32 buf; + u32 next; +}; + +static struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */ +static struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */ +static int rx_new; /* RX descriptor ring pointer */ +static int tx_new; /* TX descriptor ring pointer */ + +static char rxRingSize; +static char txRingSize; + +static u_long iobase; + +unsigned int PCI_Read_CFG_Reg(int BusDevFunc, int Reg, int Width); +int PCI_Write_CFG_Reg(int BusDevFunc, int Reg, unsigned int Value, int Width); + +static void send_setup_frame(bd_t * bis); +static void check_hw_addr(bd_t * bis); +static short srom_rd(u_long address, u_char offset); +static void srom_latch(u_int command, u_long address); +static void srom_command(u_int command, u_long address); +static void srom_address(u_int command, u_long address, u_char offset); +static short srom_data(u_int command, u_long address); +static void sendto_srom(u_int command, u_long addr); +static int getfrom_srom(u_long addr); + +static int inl(u_long addr) +{ + return le32_to_cpu(*(volatile u_long *)(addr)); +} + +static void outl (int command, u_long addr) +{ + *(volatile u_long *)(addr) = cpu_to_le32(command); +} + + +int devbusfn = 0; + +int eth_init(bd_t *bis) +{ + int i, status = 0; + int device; + int cfrv; + unsigned char timer; + + devbusfn = PCI_Find_Device(DC2114x_VID, DC2114x_DID); + if (devbusfn == -1) + { + printf("Error: Cannot find an ethernet card on any PCI bus."); + goto Done; + } + + /* Get the chip configuration revision register. */ + cfrv = PCI_Read_CFG_Reg(devbusfn, PCI_CFG_REVISION, 4); + + device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143); + + if (device != DC21143) + { + printf("Error: The chip is not DC21143.\n"); + goto Done; + } + + status = PCI_Read_CFG_Reg(devbusfn, PCI_CFG_COMMAND, 2); + status |= PCI_CMD_MASTER | PCI_CMD_IOEN | PCI_CMD_MEMEN; + PCI_Write_CFG_Reg(devbusfn, PCI_CFG_COMMAND, status, 2); + + /* Check the latency timer for values >= 0x60. */ + timer = PCI_Read_CFG_Reg(devbusfn, PCI_CFG_LATENCY_TIMER, 1); + + if (timer < 0x60) + { + PCI_Write_CFG_Reg(devbusfn, PCI_CFG_LATENCY_TIMER, 0x60, 1); + } + + /* read BAR for memory space access */ + iobase = PCI_Read_CFG_Reg(devbusfn, PCI_CFG_BASE_ADDRESS_1, 4); + + iobase &= CBIO_MASK; + iobase |= CFG_60X_PCI_MEM_OFFSET; + + /* Ensure we're not sleeping. */ + PCI_Write_CFG_Reg(devbusfn, PCI_CFDA_PSM, WAKEUP, 1); + + udelay(10 * 1000); + + check_hw_addr(bis); + + RESET_DE4X5; + + if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) + { + printf("Error: Cannot reset ethernet controller.\n"); + goto Done; + } + + outl(OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR); + + for (i = 0; i < NUM_RX_DESC; i++) + { + rx_ring[i].status = cpu_to_le32(R_OWN); + rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); + rx_ring[i].buf = cpu_to_le32(phys_to_bus((void*)NetRxPackets[i])); + rx_ring[i].next = 0; + } + + for (i=0; i < NUM_TX_DESC; i++) + { + tx_ring[i].status = 0; + tx_ring[i].des1 = 0; + tx_ring[i].buf = 0; + tx_ring[i].next = 0; + } + + rxRingSize = NUM_RX_DESC; + txRingSize = NUM_TX_DESC; + + /* Write the end of list marker to the descriptor lists. */ + rx_ring[rxRingSize - 1].des1 |= cpu_to_le32(RD_RER); + tx_ring[txRingSize - 1].des1 |= cpu_to_le32(TD_TER); + + /* Tell the adapter where the TX/RX rings are located. */ + outl(phys_to_bus(&rx_ring), DE4X5_RRBA); + outl(phys_to_bus(&tx_ring), DE4X5_TRBA); + + START_DE4X5; + + tx_new = 0; + rx_new = 0; + + send_setup_frame(bis); + +Done: + return 0; +} + +int eth_send(volatile void *packet, int length) +{ + int status = 0; + int i; + + if (length <= 0) + { + printf("eth: bad packet size: %d\n", length); + goto out; + } + + for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) + { + if (i >= TOUT_LOOP) + { + printf("eth: tx error buffer not ready\n"); + goto out; + } + } + + tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((void*)packet)); + tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length); + tx_ring[tx_new].status = cpu_to_le32(T_OWN); + + outl(POLL_DEMAND, DE4X5_TPD); + + for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) + { + if (i >= TOUT_LOOP) + { + printf("eth: tx buffer not ready\n"); + goto out; + } + } + +#if 0 /* test-only */ + if (le32_to_cpu(tx_ring[tx_new].status) & TD_ES) + { + printf("TX error status = 0x%08X\n", + le32_to_cpu(tx_ring[tx_new].status)); + status++; + } +#endif + + out: + return status; +} + +int eth_rx(void) +{ + s32 status; + int length = 0; + + for ( ; ; ) { + status = (s32)le32_to_cpu(rx_ring[rx_new].status); + + if (status & R_OWN) { + break; + } + + if (status & RD_LS) { + /* Valid frame status. + */ + if (status & RD_ES) { + /* There was an error. + */ + printf("RX error status = 0x%08X\n", status); + } + else { + /* A valid frame received. + */ + length = (le32_to_cpu(rx_ring[rx_new].status) >> + 16); + + /* Pass the packet up to the protocol + * layers. + */ + NetReceive(NetRxPackets[rx_new], length - 4); + } + + /* Change buffer ownership for this frame, back + * to the adapter. + */ + rx_ring[rx_new].status = cpu_to_le32(R_OWN); + } + + /* Update entry information. + */ + rx_new = (++rx_new) % rxRingSize; + } + + return length; +} + +void eth_halt(void) +{ +#if 1 + STOP_DE4X5; + outl(0, DE4X5_SICR); + if (devbusfn > 0) + PCI_Write_CFG_Reg(devbusfn, PCI_CFDA_PSM, SLEEP, 1); +#endif +} + +static void check_hw_addr(bd_t *bis) +{ + unsigned char hw_addr[ETH_ALEN]; + u_short tmp, *p = (short *)(&hw_addr[0]); + int i, j = 0; + + for (i = 0; i < (ETH_ALEN >> 1); i++) { + tmp = srom_rd(DE4X5_APROM, (SROM_HWADD >> 1) + i); + *p = le16_to_cpu(tmp); + j += *p++; + } + + if ((j == 0) || (j == 0x2fffd)) { + printf("Warning: can't read HW address from SROM.\n"); + goto Done; + } + + for (i = 0; i < ETH_ALEN; i++) { + if (hw_addr[i] != bis->bi_enetaddr[i]) { + printf("Warning: HW addresses don't match:\n"); + printf("Address in SROM is " + "%02X:%02X:%02X:%02X:%02X:%02X\n", + hw_addr[0], hw_addr[1], hw_addr[2], + hw_addr[3], hw_addr[4], hw_addr[5]); + printf("Address used by ppcboot is " + "%02X:%02X:%02X:%02X:%02X:%02X\n", + bis->bi_enetaddr[0], bis->bi_enetaddr[1], + bis->bi_enetaddr[2], bis->bi_enetaddr[3], + bis->bi_enetaddr[4], bis->bi_enetaddr[5]); + goto Done; + } + } + +Done: +} + +static void send_setup_frame(bd_t *bis) +{ + int i; + char setup_frame[SETUP_FRAME_LEN]; + char *pa = &setup_frame[0]; + + memset(pa, 0xff, SETUP_FRAME_LEN); + + for (i = 0; i < ETH_ALEN; i++) { + *(pa + (i & 1)) = bis->bi_enetaddr[i]; + if (i & 0x01) + { + pa += 4; + } + } + + for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { + if (i >= TOUT_LOOP) { + printf("eth: tx error buffer not ready\n"); + goto out; + } + } + + tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus(&setup_frame[0])); + tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET| SETUP_FRAME_LEN); + tx_ring[tx_new].status = cpu_to_le32(T_OWN); + + outl(POLL_DEMAND, DE4X5_TPD); + + for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { + if (i >= TOUT_LOOP) { + printf("eth: tx buffer not ready\n"); + goto out; + } + } + + if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) { + printf("TX error status2 = 0x%08X\n", le32_to_cpu(tx_ring[tx_new].status)); + } +out: +} + +/* SROM Read. + */ +static short +srom_rd(u_long addr, u_char offset) +{ + sendto_srom(SROM_RD | SROM_SR, addr); + + srom_latch(SROM_RD | SROM_SR | DT_CS, addr); + srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr); + srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset); + + return srom_data(SROM_RD | SROM_SR | DT_CS, addr); +} + +static void +srom_latch(u_int command, u_long addr) +{ + sendto_srom(command, addr); + sendto_srom(command | DT_CLK, addr); + sendto_srom(command, addr); + + return; +} + +static void +srom_command(u_int command, u_long addr) +{ + srom_latch(command, addr); + srom_latch(command, addr); + srom_latch((command & 0x0000ff00) | DT_CS, addr); + + return; +} + +static void +srom_address(u_int command, u_long addr, u_char offset) +{ + int i; + signed char a; + + a = (char)(offset << 2); + for (i=0; i<6; i++, a <<= 1) { + srom_latch(command | ((a < 0) ? DT_IN : 0), addr); + } + udelay(1); + + i = (getfrom_srom(addr) >> 3) & 0x01; + + return; +} + +static short +srom_data(u_int command, u_long addr) +{ + int i; + short word = 0; + s32 tmp; + + for (i=0; i<16; i++) { + sendto_srom(command | DT_CLK, addr); + tmp = getfrom_srom(addr); + sendto_srom(command, addr); + + word = (word << 1) | ((tmp >> 3) & 0x01); + } + + sendto_srom(command & 0x0000ff00, addr); + + return word; +} + +static void +sendto_srom(u_int command, u_long addr) +{ + outl(command, addr); + udelay(1); + + return; +} + +static int +getfrom_srom(u_long addr) +{ + s32 tmp; + + tmp = inl(addr); + udelay(1); + + return tmp; +} + diff --git a/board/eltec/bab750/flash.c b/board/eltec/bab750/flash.c new file mode 100644 index 0000000..42943f8 --- /dev/null +++ b/board/eltec/bab750/flash.c @@ -0,0 +1,489 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * 09-18-2001, Andreas Heppel: Reduced the code in here to the usage + * of AMD's 29F040 and 29F016 flashes, since the BAB750 does use + * any other. + */ + +#include +#include +#include + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ + +/*----------------------------------------------------------------------- + * Functions + */ +ulong flash_get_size (vu_long *addr, flash_info_t *info); +static int write_word (flash_info_t *info, ulong dest, ulong data); + +/*flash command address offsets*/ + +#define ADDR0 (0x555) +#define ADDR1 (0x2AA) +#define ADDR3 (0x001) + +#define FLASH_WORD_SIZE unsigned char + +/*----------------------------------------------------------------------- + */ + +unsigned long flash_init (void) +{ + unsigned long size1, size2; + int i; + unsigned long base; + + + /* Init: no FLASHes known */ + for (i=0; iflash_id == FLASH_UNKNOWN) { + printf ("missing or unknown FLASH type\n"); + flash_init(); + } + + if (info->flash_id == FLASH_UNKNOWN) { + printf ("missing or unknown FLASH type\n"); + return; + } + + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_AMD: + printf ("AMD "); + break; + default: + printf ("Unknown Vendor "); + break; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case AMD_ID_F040B: + printf ("AM29F040B (4 Mbit)\n"); + break; + case AMD_ID_F016D: + printf ("AM29F016D (16 Mbit)\n"); + break; + default: + printf ("Unknown Chip Type\n"); + break; + } + + if (info->size >= (1 << 20)) { + printf (" Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count); + } else { + printf (" Size: %ld kB in %d Sectors\n", info->size >> 10, info->sector_count); + } + + printf (" Sector Start Addresses:"); + for (i=0; isector_count; ++i) { + /* + * Check if whole sector is erased + */ + if (i != (info->sector_count-1)) + size = info->start[i+1] - info->start[i]; + else + size = info->start[0] + info->size - info->start[i]; + + erased = 1; + flash = (volatile unsigned long *)info->start[i]; + size = size >> 2; /* divide by 4 for longword access */ + for (k=0; kstart[i], + erased ? " E" : " ", + info->protect[i] ? "RO " : " "); + } + printf ("\n"); +} + + +/*----------------------------------------------------------------------- + */ + +/* + * The following code cannot be run from FLASH! + */ +ulong flash_get_size (vu_long *addr, flash_info_t *info) +{ + short i; + ulong vendor, devid; + ulong base = (ulong)addr; + volatile unsigned char *caddr = (unsigned char *)addr; + +#ifdef DEBUG + printf("flash_get_size for address 0x%lx: \n", (unsigned long)caddr); +#endif + + /* Write auto select command: read Manufacturer ID */ + caddr[0] = 0xF0; /* reset bank */ + udelay(10); + + eieio(); + caddr[0x555] = 0xAA; + udelay(10); + caddr[0x2AA] = 0x55; + udelay(10); + caddr[0x555] = 0x90; + + udelay(10); + + vendor = caddr[0]; + devid = caddr[1]; + +#ifdef DEBUG + printf("Manufacturer: 0x%lx\n", vendor); +#endif + + vendor &= 0xff; + devid &= 0xff; + + /* We accept only two AMD types */ + switch (vendor) { + case (FLASH_WORD_SIZE)AMD_MANUFACT: + info->flash_id = FLASH_MAN_AMD; + break; + default: + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0; + return (0); /* no or unknown flash */ + } + + switch (devid) { + case (FLASH_WORD_SIZE)AMD_ID_F040B: + info->flash_id |= AMD_ID_F040B; + info->sector_count = 8; + info->size = 0x00080000; + break; /* => 0.5 MB */ + + case (FLASH_WORD_SIZE)AMD_ID_F016D: + info->flash_id |= AMD_ID_F016D; + info->sector_count = 32; + info->size = 0x00200000; + break; /* => 2 MB */ + + default: + info->flash_id = FLASH_UNKNOWN; + return (0); /* => no or unknown flash */ + + } + +#ifdef DEBUG + printf("flash id 0x%lx; sector count 0x%x, size 0x%lx\n", info->flash_id, info->sector_count, info->size); +#endif + + /* check for protected sectors */ + for (i = 0; i < info->sector_count; i++) { + /* sector base address */ + info->start[i] = base + i * (info->size / info->sector_count); + /* read sector protection at sector address, (A7 .. A0) = 0x02 */ + /* D0 = 1 if protected */ + caddr = (volatile unsigned char *)(info->start[i]); + info->protect[i] = caddr[2] & 1; + } + + /* + * Prevent writes to uninitialized FLASH. + */ + if (info->flash_id != FLASH_UNKNOWN) { + caddr = (volatile unsigned char *)info->start[0]; + caddr[0] = 0xF0; /* reset bank */ + } + + return (info->size); +} + + +/*----------------------------------------------------------------------- + */ + +int flash_erase (flash_info_t *info, int s_first, int s_last) +{ + volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]); + int flag, prot, sect, l_sect; + ulong start, now, last; + + if ((s_first < 0) || (s_first > s_last)) { + if (info->flash_id == FLASH_UNKNOWN) { + printf ("- missing\n"); + } else { + printf ("- no sectors to erase\n"); + } + return ERR_NOT_ERASED; + } + + if ((info->flash_id == FLASH_UNKNOWN) || (info->flash_id > FLASH_AMD_COMP)) { + printf ("Can't erase unknown flash type - aborted\n"); + return ERR_NOT_ERASED; + } + + prot = 0; + for (sect=s_first; sect<=s_last; ++sect) { + if (info->protect[sect]) { + prot++; + } + } + + if (prot) { + printf ("- Warning: %d protected sectors will not be erased!\n", prot); + } else { + printf ("\n"); + } + + l_sect = -1; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA; + addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055; + addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080; + addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA; + addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055; + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect<=s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + addr = (FLASH_WORD_SIZE *)(info->start[sect]); + if (info->flash_id & FLASH_MAN_SST) { + addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA; + addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055; + addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080; + addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA; + addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055; + addr[0] = (FLASH_WORD_SIZE)0x00500050; /* block erase */ + udelay(30000); /* wait 30 ms */ + } + else + addr[0] = (FLASH_WORD_SIZE)0x00300030; /* sector erase */ + l_sect = sect; + } + } + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + /* wait at least 80us - let's wait 1 ms */ + udelay (1000); + + /* + * We wait for the last triggered sector + */ + if (l_sect < 0) + goto DONE; + + start = get_timer (0); + last = start; + addr = (FLASH_WORD_SIZE *)(info->start[l_sect]); + while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) { + if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { + printf ("Timeout\n"); + return ERR_TIMOUT; + } + /* show that we're waiting */ + if ((now - last) > 1000) { /* every second */ + serial_putc ('.'); + last = now; + } + } + +DONE: + /* reset to read mode */ + addr = (FLASH_WORD_SIZE *)info->start[0]; + addr[0] = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */ + + printf (" done\n"); + return ERR_OK; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ + +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + ulong cp, wp, data; + int i, l, rc; + + wp = (addr & ~3); /* get lower word aligned address */ + + /* + * handle unaligned start bytes + */ + if ((l = addr - wp) != 0) { + data = 0; + for (i=0, cp=wp; i0; ++i) { + data = (data << 8) | *src++; + --cnt; + ++cp; + } + for (; cnt==0 && i<4; ++i, ++cp) { + data = (data << 8) | (*(uchar *)cp); + } + + if ((rc = write_word(info, wp, data)) != 0) { + return (rc); + } + wp += 4; + } + + /* + * handle word aligned part + */ + while (cnt >= 4) { + data = 0; + for (i=0; i<4; ++i) { + data = (data << 8) | *src++; + } + if ((rc = write_word(info, wp, data)) != 0) { + return (rc); + } + wp += 4; + cnt -= 4; + } + + if (cnt == 0) { + return (0); + } + + /* + * handle unaligned tail bytes + */ + data = 0; + for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { + data = (data << 8) | *src++; + --cnt; + } + for (; i<4; ++i, ++cp) { + data = (data << 8) | (*(uchar *)cp); + } + + return (write_word(info, wp, data)); +} + +/*----------------------------------------------------------------------- + * Write a word to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_word (flash_info_t *info, ulong dest, ulong data) +{ + volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)(info->start[0]); + volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *)dest; + volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *)&data; + ulong start; + int flag; + int i; + + /* Check if Flash is (sufficiently) erased */ + if ((*((volatile FLASH_WORD_SIZE *)dest) & + (FLASH_WORD_SIZE)data) != (FLASH_WORD_SIZE)data) { + return (2); + } + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + for (i=0; i<4/sizeof(FLASH_WORD_SIZE); i++) + { + addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA; + addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055; + addr2[ADDR0] = (FLASH_WORD_SIZE)0x00A000A0; + + dest2[i] = data2[i]; + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + /* data polling for D7 */ + start = get_timer (0); + while ((dest2[i] & (FLASH_WORD_SIZE)0x00800080) != + (data2[i] & (FLASH_WORD_SIZE)0x00800080)) { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + return (1); + } + } + } + + return (0); +} + +/*----------------------------------------------------------------------- + */ diff --git a/board/eltec/bab750/mpc106.c b/board/eltec/bab750/mpc106.c new file mode 100644 index 0000000..bfa9c30 --- /dev/null +++ b/board/eltec/bab750/mpc106.c @@ -0,0 +1,50 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * memory routines for the MPC106 CPU. + */ + +#include +#include +#include + + +/* + * The local DRAM may have a different address from the PCI + * point of view, thus buffer addresses have to be modified + * [mapped] appropriately. + */ +unsigned long phys_to_bus(void * address) +{ + if (address == (void *)0) + return 0; + return (unsigned long)address + CFG_PCI_DRAM_OFFSET; +} + +void * bus_to_phys(unsigned long address) +{ + if (address == 0) + return 0; + return (void *)(address - CFG_PCI_DRAM_OFFSET); +} diff --git a/board/eltec/bab750/mpc106_init.S b/board/eltec/bab750/mpc106_init.S new file mode 100644 index 0000000..3b34fb1 --- /dev/null +++ b/board/eltec/bab750/mpc106_init.S @@ -0,0 +1,1331 @@ +#include +#include +#include + +#include +#include + +#define DEFS_ONLY + +#include + + + + .globl set_address_map +set_address_map: + /* + * Switch to address map A if necessary. + */ +#ifdef CFG_ADDRESS_MAP_A + lis r1, 0xfec0 + ori r1, r1, 0x0cf8 + lis r2, 0xfee0 + ori r2, r2, 0xcfc + + lis r3, MPC106_REG@h + ori r3, r3, PCI_PICR1 + stwbrx r3, 0, r1 + sync + lwbrx r4, 0, r2 + sync + lis r0, PICR1_XIO_MODE@h + ori r0, r0, PICR1_XIO_MODE@l + andc r4, r4, r0 + lis r0, PICR1_ADDRESS_MAP@h + ori r0, r0, PICR1_ADDRESS_MAP@l + or r4, r4, r0 + stwbrx r4, 0, r2 + + sync +#endif + blr + + + /* + * This following contains the entry code for the initialization code + * for the MPC 106, a PCI Bridge/Memory Controller. + * Register usage: + * r0 = ramtest scratch register, toggleError loop counter + * r1 = CONFIG_ADDRESS + * r2 = CONFIG_DATA + * r3 = scratch register, subroutine argument and return value, ramtest size + * r4 = scratch register, spdRead clock mask, OutHex loop count + * r5 = ramtest scratch register + * r6 = toggleError 1st value, spdRead port mask + * r7 = toggleError 2nd value, ramtest scratch register, spdRead scratch register (0x00) + * r8 = ramtest scratch register, spdRead scratch register (0x80) + * r9 = ramtest scratch register, toggleError loop end, OutHex digit + * r10 = ramtest scratch register, spdWriteByte parameter, spdReadByte return value, printf pointer to COM1 + * r11 = startType + * r12 = ramtest scratch register, spdRead data mask + * r14 = pointer to GOT + * r15 = scratch register, SPD save + * r16 = bank0 size, total memory size + * r17 = bank1 size + * r18 = bank2 size + * r19 = bank3 size + * r20 = MCCR1, MSAR1 + * r21 = MCCR3, MEAR1 + * r22 = MCCR4, MBER + * r23 = EMSAR1 + * r24 = EMEAR1 + * r25 = save link register 1st level + * r26 = save link register 2nd level + * r27 = save link register 3rd level + * r30 = pointer to GPIO for spdRead + * r31 = pointer to message block + */ + + .globl ram_init +ram_init: + mflr r25 /* save away link register */ + + /* set pointer to message block */ + lis r4, CFG_MONITOR_BASE@h + ori r4, r4, CFG_MONITOR_BASE@l + addi r4, r4, EXC_OFF_SYS_RESET + bl get_startaddr + sub r4, r4,r3 + bl get_msgblk + add r4, r4,r3 + mr r31, r4 + + /* + * Do the init for the SIO. + */ + bl .sioInit + + addi r3, r31, (MinitLogo-MessageBlock) + bl Printf + + addi r3, r31, (Mspd01-MessageBlock) + bl Printf + + /* + * Memory cofiguration using SPD information stored on the SODIMMs + */ + + li r17,0 + li r18,0 + li r19,0 + + li r3, 0x0002 /* get RAM type from spd for bank0/1 */ + bl spdRead + + cmpi 0, 0, r3, -1 /* error ? */ + bne noSpdError + + addi r3, r31, (Mfail-MessageBlock) + bl Printf + + li r6, 0xe0 /* error codes in r6 and r7 */ + li r7, 0x00 + b toggleError /* fail - loop forever */ + +noSpdError: + mr r15, r3 /* save r3 (RAM type) */ + + addi r3, r31, (Mok-MessageBlock) + bl Printf + + cmpli 0, 0, r15, 0x0001 /* FPM ? */ + beq configFPM + cmpli 0, 0, r15, 0x0002 /* EDO ? */ + beq configEDO + cmpli 0, 0, r15, 0x0004 /* SDRAM ? */ + beq configSDRAM + + li r6, 0xe0 /* error codes in r6 and r7 */ + li r7, 0x01 + b toggleError /* fail - loop forever */ + +configSDRAM: + addi r3, r31, (MsdRam-MessageBlock) + bl Printf + + /* set the Memory Configuration Reg. 1 */ + li r3, 0x001f /* get bank size from spd for bank0/1 */ + bl spdRead + + li r20, 0x00ff /* 16-Mbit SDRAM 2 banks */ + + andi. r3,r3,0x0038 /* not 32MB, 64MB or 128MB */ + beq sizeofSDRAM + + li r3, 0x0011 /* get number of internal banks from spd for bank0/1 */ + bl spdRead + + li r20, 0x0055 /* 64-Mbit SDRAM 2 banks */ + + cmpli 0, 0, r3, 0x02 /* 2 banks */ + beq sizeofSDRAM + + li r20, 0x0000 /* 64-Mbit SDRAM 4 banks */ + + cmpli 0, 0, r3, 0x04 /* 4 banks */ + beq sizeofSDRAM + + li r6, 0xe0 /* error codes in r6 and r7 */ + li r7, 0x02 + b toggleError /* fail - loop forever */ + +sizeofSDRAM: + /* set the Memory Configuration Reg. 3 */ + lis r21, 0x8630 /* BSTOPRE = 0x80, REFREC = 6, RDLAT = 3 */ + + /* set the Memory Configuration Reg. 4 */ + lis r22, 0x2430 /* PRETOACT = 2, ACTOPRE = 4, WCBUF = 1, RCBUF = 1 */ + ori r22, r22, 0x2220 /* SDMODE = 0x022, ACTORW = 2 */ + + /* get the size of bank 0-3 */ + + li r3, 0x001f /* get bank size from spd for bank0/1 */ + bl spdRead + + rlwinm r16, r3, 2, 24, 29 /* calculate size in MByte (128 MB max.) */ + + li r3, 0x0005 /* get number of banks from spd for bank0/1 */ + bl spdRead + + cmpi 0, 0, r3, 2 /* 2 banks on module ? */ + bne SDRAMnobank1 + + mr r17, r16 /* save size of bank 1 */ + +SDRAMnobank1: + addi r3, r31, (Mspd23-MessageBlock) + bl Printf + + li r3, 0x0102 /* get RAM type spd for bank2/3 */ + bl spdRead + + cmpli 0, 0, r3, 0x0001 /* FPM ? */ + bne 1f + addi r3, r31, (Mok-MessageBlock) + bl Printf + addi r3, r31, (MfpmRam-MessageBlock) + bl Printf + b configRAMcommon +1: + cmpli 0, 0, r3, 0x0002 /* EDO ? */ + bne 2f + addi r3, r31, (Mok-MessageBlock) + bl Printf + addi r3, r31, (MedoRam-MessageBlock) + bl Printf + b configRAMcommon +2: + cmpli 0, 0, r3, 0x0004 /* SDRAM ? */ + bne 3f + addi r3, r31, (Mok-MessageBlock) + bl Printf + addi r3, r31, (MsdRam-MessageBlock) + bl Printf + b configSDRAM23 +3: + addi r3, r31, (Mfail-MessageBlock) + bl Printf + b configRAMcommon /* bank2/3 is not present or no SDRAM */ + +configSDRAM23: + li r3, 0x011f /* get bank size from spd for bank2/3 */ + bl spdRead + + rlwinm r18, r3, 2, 24, 29 /* calculate size in MByte (128 MB max.) */ + + li r3, 0x0105 /* get number of banks from spd for bank2/3 */ + bl spdRead + + cmpi 0, 0, r3, 2 /* 2 banks ? */ + bne configRAMcommon + + mr r19, r18 /* save size of bank 3 */ + b configRAMcommon + +configFPM: + addi r3, r31, (MfpmRam-MessageBlock) + bl Printf + b configEDO0 +configEDO: + addi r3, r31, (MedoRam-MessageBlock) + bl Printf + +configEDO0: + /* set the Memory Configuration Reg. 1 */ + /* set RAM type to not SDRAM */ + lis r20, MCCR1_TYPE_EDO@h + + li r3, 0x0003 /* get # of row bits from spd for bank0/1 */ + bl spdRead + + ori r20, r20, (MCCR1_BK0_9BITS | MCCR1_BK1_9BITS) + cmpli 0, 0, r3, 0x0009 /* bank0 - 9 row bits */ + beq sizeofEDO + + ori r20, r20, (MCCR1_BK0_10BITS | MCCR1_BK1_10BITS) + cmpli 0, 0, r3, 0x000a /* bank0 - 10 row bits */ + beq sizeofEDO + + ori r20, r20, (MCCR1_BK0_11BITS | MCCR1_BK1_11BITS) + cmpli 0, 0, r3, 0x000b /* bank0 - 11 row bits */ + beq sizeofEDO + + ori r20, r20, (MCCR1_BK0_12BITS | MCCR1_BK1_12BITS) + cmpli 0, 0, r3, 0x000c /* bank0 - 12 row bits */ + beq sizeofEDO + + cmpli 0, 0, r3, 0x000d /* bank0 - 13 row bits */ + beq sizeofEDO + + li r6, 0xe0 /* error codes in r6 and r7 */ + li r7, 0x10 + b toggleError /* fail - loop forever */ + +sizeofEDO: + /* set the Memory Configuration Reg. 3 */ + lis r21, 0x000a /* CPX = 1, RAS6P = 4 */ + ori r21, r21, 0x2293 /* CAS5 = 2, CP4 = 1, CAS3 = 2, RCD2 = 2, RP = 3 */ + + /* set the Memory Configuration Reg. 4 */ + lis r22, 0x0010 /* all SDRAM parameter 0, WCBUF flow through, RCBUF registered */ + + /* get the size of bank 0-3 */ + li r3, 0x0003 /* get row bits from spd for bank0/1 */ + bl spdRead + + li r16, 0 /* bank size is (8 * 2^row * 2^column) / 0x100000 MB */ + ori r16, r16, 0x8000 + rlwnm r16, r16, r3, 0, 31 + + li r3, 0x0004 /* get column bits from spd for bank0/1 */ + bl spdRead + + rlwnm r16, r16, r3, 0, 31 + + li r3, 0x0005 /* get number of banks from spd for bank0/1 */ + bl spdRead + + cmpi 0, 0, r3, 2 /* 2 banks on module ? */ + bne EDOnobank1 + + mr r17, r16 /* save size of bank 1 */ + +EDOnobank1: + addi r3, r31, (Mspd23-MessageBlock) + bl Printf + + li r3, 0x0102 /* get RAM type spd for bank2/3 */ + bl spdRead + + cmpli 0, 0, r3, 0x0001 /* FPM ? */ + bne 1f + addi r3, r31, (Mok-MessageBlock) + bl Printf + addi r3, r31, (MfpmRam-MessageBlock) + bl Printf + b configEDO23 +1: + cmpli 0, 0, r3, 0x0002 /* EDO ? */ + bne 2f + addi r3, r31, (Mok-MessageBlock) + bl Printf + addi r3, r31, (MedoRam-MessageBlock) + bl Printf + b configEDO23 +2: + cmpli 0, 0, r3, 0x0004 /* SDRAM ? */ + bne 3f + addi r3, r31, (Mok-MessageBlock) + bl Printf + addi r3, r31, (MsdRam-MessageBlock) + bl Printf + b configRAMcommon +3: + addi r3, r31, (Mfail-MessageBlock) + bl Printf + b configRAMcommon /* bank2/3 is not present or no SDRAM */ + +configEDO23: + li r3, 0x0103 /* get row bits from spd for bank2/3 */ + bl spdRead + + li r18, 0 /* bank size is (8 * 2^row * 2^column) / 0x100000 MB */ + ori r18, r18, 0x8000 + rlwnm r18, r18, r3, 0, 31 + + li r3, 0x0104 /* get column bits from spd for bank2/3 */ + bl spdRead + + rlwnm r18, r18, r3, 0, 31 + + li r3, 0x0105 /* get number of banks from spd for bank2/3 */ + bl spdRead + + cmpi 0, 0, r3, 2 /* 2 banks ? */ + bne configRAMcommon + + mr r19, r18 /* save size of bank 3 */ + +configRAMcommon: + lis r1, MPC106_REG_ADDR@h + ori r1, r1, MPC106_REG_ADDR@l + lis r2, MPC106_REG_DATA@h + ori r2, r2, MPC106_REG_DATA@l + + li r0, 0 + +/* + * If we are already running in RAM (debug mode), we should + * NOT reset the MEMGO flag. Otherwise we will stop all memory + * accesses. + */ +#ifdef IN_RAM + lis r4, MCCR1_MEMGO@h + ori r4,r4, MCCR1_MEMGO@l + or r20,r20,r4 +#endif + + /* set the Memory Configuration Reg. 1 */ + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_MCCR1 /* register number 0xf0 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + + stwbrx r20, r0, r2 /* write data to CONFIG_DATA */ + + /* set the Memory Configuration Reg. 3 */ + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_MCCR3 /* register number 0xf8 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + + stwbrx r21, r0, r2 /* write data to CONFIG_DATA */ + + /* set the Memory Configuration Reg. 4 */ + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_MCCR4 /* register number 0xfc */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + + stwbrx r22, r0, r2 /* write data to CONFIG_DATA */ + + /* set the memory boundary registers for bank 0-3 */ + li r20, 0 + li r23, 0 + li r24, 0 + subi r21, r16, 1 /* calculate end address bank0 */ + li r22, MBER_BANK0 + + cmpi 0, 0, r17, 0 /* bank1 present ? */ + beq nobank1 + + rlwinm r3, r16, 8, 16, 23 /* calculate start address of bank1 */ + or r20, r20, r3 + + add r16, r16, r17 /* add to total memory size */ + + subi r3, r16, 1 /* calculate end address of bank1 */ + rlwinm r3, r3, 8, 16, 23 + or r21, r21, r3 + + ori r22, r22, MBER_BANK1 /* enable bank1 */ + b bank2 + +nobank1: + ori r23,r23,0x0300 /* set bank1 start to unused area */ + ori r24,r24,0x0300 /* set bank1 end to unused area */ + +bank2: + cmpi 0, 0, r18, 0 /* bank2 present ? */ + beq nobank2 + + andi. r3, r16, 0x00ff /* calculate start address of bank2 */ + andi. r4, r16, 0x0300 + rlwinm r3, r3, 16, 8, 15 + or r20, r20, r3 + rlwinm r3, r4, 8, 8, 15 + or r23, r23, r3 + + add r16, r16, r18 /* add to total memory size */ + + subi r3, r16, 1 /* calculate end address of bank2 */ + andi. r4, r3, 0x0300 + andi. r3, r3, 0x00ff + rlwinm r3, r3, 16, 8, 15 + or r21, r21, r3 + rlwinm r3, r4, 8, 8, 15 + or r24, r24, r3 + + ori r22, r22, (MBER_BANK2) /* enable bank2 */ + b bank3 + +nobank2: + lis r3,0x0003 + or r23,r23,r3 /* set bank2 start to unused area */ + or r24,r24,r3 /* set bank2 end to unused area */ + +bank3: + cmpi 0, 0, r19, 0 /* bank3 present ? */ + beq nobank3 + + andi. r3, r16, 0x00ff /* calculate start address of bank3 */ + andi. r4, r16, 0x0300 + rlwinm r3, r3, 24, 0, 7 + or r20, r20, r3 + rlwinm r3, r4, 16, 0, 7 + or r23, r23, r3 + + add r16, r16, r19 /* add to total memory size */ + + subi r3, r16, 1 /* calculate end address of bank3 */ + andi. r4, r3, 0x0300 + andi. r3, r3, 0x00ff + rlwinm r3, r3, 24, 0, 7 + or r21, r21, r3 + rlwinm r3, r4, 16, 0, 7 + or r24, r24, r3 + + ori r22, r22, (MBER_BANK3) /* enable bank3 */ + b writebound + +nobank3: + lis r3,0x0300 + or r23,r23,r3 /* set bank3 start to unused area */ + or r24,r24,r3 /* set bank3 end to unused area */ + +writebound: + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_MSAR1 /* register number 0x80 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + stwbrx r20, r0, r2 /* write data to CONFIG_DATA */ + + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_MEAR1 /* register number 0x90 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + stwbrx r21, r0, r2 /* write data to CONFIG_DATA */ + + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_EMSAR1 /* register number 0x88 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + stwbrx r23, r0, r2 /* write data to CONFIG_DATA */ + + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_EMEAR1 /* register number 0x98 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + stwbrx r24, r0, r2 /* write data to CONFIG_DATA */ + + /* set boundaries of unused banks to unused address space */ + lis r4, 0x0303 + ori r4, r4, 0x0303 /* bank 4-7 start and end adresses */ + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_EMSAR2 /* register number 0x8C */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + stwbrx r4, r0, r2 /* write data to CONFIG_DATA */ + + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_EMEAR2 /* register number 0x9C */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + stwbrx r4, r0, r2 /* write data to CONFIG_DATA */ + + + /* set the Memory Configuration Reg. 2 */ + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_MCCR2 /* register number 0xf4 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + + li r3, 0x000c /* get refresh from spd for bank0/1 */ + bl spdRead + + cmpi 0, 0, r3, -1 /* error ? */ + bne common1 + + li r6, 0xe0 /* error codes in r6 and r7 */ + li r7, 0x20 + b toggleError /* fail - loop forever */ + +common1: + andi. r15, r3, 0x007f /* mask selfrefresh bit */ + li r3, 0x010c /* get refresh from spd for bank2/3 */ + bl spdRead + + cmpi 0, 0, r3, -1 /* error ? */ + beq common2 + andi. r3, r3, 0x007f /* mask selfrefresh bit */ + cmp 0, 0, r3, r15 /* find the lower */ + blt common3 +common2: + mr r3, r15 +common3: + li r4, 0x1010 /* refesh cycle 1028 clocks left shifted 2 */ + cmpli 0, 0, r3, 0x0000 /* 15.6 us ? */ + beq writeRefresh + + li r4, 0x0808 /* refesh cycle 514 clocks left shifted 2 */ + cmpli 0, 0, r3, 0x0002 /* 7.8 us ? */ + beq writeRefresh + + li r4, 0x2020 /* refesh cycle 2056 clocks left shifted 2 */ + cmpli 0, 0, r3, 0x0003 /* 31.3 us ? */ + beq writeRefresh + + li r4, 0x4040 /* refesh cycle 4112 clocks left shifted 2 */ + cmpli 0, 0, r3, 0x0004 /* 62.5 us ? */ + beq writeRefresh + + li r4, 0 + ori r4, r4, 0x8080 /* refesh cycle 8224 clocks left shifted 2 */ + cmpli 0, 0, r3, 0x0005 /* 125 us ? */ + beq writeRefresh + + li r6, 0xe0 /* error codes in r6 and r7 */ + li r7, 0x21 + b toggleError /* fail - loop forever */ + +writeRefresh: + stwbrx r4, r0, r2 /* write data to CONFIG_DATA */ + + /* DRAM BANKS SHOULD BE ENABLED */ + addi r3, r31, (Mactivate-MessageBlock) + bl Printf + mr r3, r16 + bl OutDec + addi r3, r31, (Mmbyte-MessageBlock) + bl Printf + + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_MBER /* register number 0xa0 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + stb r22, 0(r2) /* write data to CONFIG_DATA */ + + li r8, 0x63 /* PGMAX = 99 */ + + stb r8, 3(r2) /* write data to CONFIG_DATA */ + + /* + DRAM SHOULD NOW BE CONFIGURED AND ENABLED - + MUST WAIT 200us BEFORE ACCESSING + */ + + li r0, 0x3800 + mtctr r0 + +wait200us: + bdnz wait200us + + lis r3, MPC106_REG@h /* start building new reg number */ + ori r3, r3, MPC106_MCCR1 /* register number 0xf0 */ + stwbrx r3, r0, r1 /* write this value to CONFIG_ADDR */ + eieio /* make sure mem. access is complete */ + + lwbrx r4, r0, r2 /* load r4 from CONFIG_DATA */ + + lis r0, MCCR1_MEMGO@h /* MEMGO=1 */ + ori r0, r0, MCCR1_MEMGO@l + or r4, r4, r0 /* set the MEMGO bit */ + stwbrx r4, r0, r2 /* write mdfd data to CONFIG_DATA */ + + li r0, 0x7000 + mtctr r0 +wait8ref: + bdnz wait8ref + + addi r3, r31, (Mok-MessageBlock) + bl Printf + + mtlr r25 + blr + +/* + * Infinite loop called in case of an error during RAM initialisation. + * error codes in r6 and r7. + */ +toggleError: + li r0,0 + lis r9,127 + ori r9,r9,65535 +toggleError1: + addic r0,r0,1 + cmpw cr1,r0,r9 + ble cr1,toggleError1 + li r0,0 + lis r9,127 + ori r9,r9,65535 +toggleError2: + addic r0,r0,1 + cmpw cr1,r0,r9 + ble cr1,toggleError2 + b toggleError + + +/****************************************************************************/ + + .set SIO_LUNINDEX,0x07 /* SIO LUN index register */ + .set SIO_CNFG1,0x21 /* SIO configuration #1 register */ + .set SIO_PCSCI,0x23 /* SIO PCS configuration index reg */ + .set SIO_PCSCD,0x24 /* SIO PCS configuration data reg */ + .set SIO_ACTIVATE,0x30 /* SIO activate register */ + .set SIO_IOBASEHI,0x60 /* SIO I/O port base address, 15:8 */ + .set SIO_IOBASELO,0x61 /* SIO I/O port base address, 7:0 */ + .set SIO_LUNENABLE,0x01 /* SIO LUN enable */ + +/* + * This function performs a basic initialisation of the superio chip + * to enable basic console output and SPD access during RAM initialisation. + * + * Upon completion, SIO resource registers are mapped as follows: + * Resource Enabled Address + * UART1 Yes COM1 3F8-3FF + * UART2 Yes COM2 2F8-2FF + * GPIO Yes 220-227 + */ + +.sioInit: + mfspr r7,8 /* save link register */ + +.sioInit_87308: + + /* + * Get base addr of ISA I/O space + */ + lis r6,CFG_ISA_IO@h + ori r6,r6,CFG_ISA_IO@l + + /* + * Set offset to base address for config registers. + */ +#if defined(CFG_NS87308_BADDR_0x) + addi r4,r0,0x0279 +#elif defined(CFG_NS87308_BADDR_10) + addi r4,r0,0x015C +#elif defined(CFG_NS87308_BADDR_11) + addi r4,r0,0x002E +#endif + + add r6,r6,r4 /* add offset to base */ + or r3,r6,r6 /* make a copy */ + +/* + * PMC (LUN 8) + */ + addi r4,r0,SIO_LUNINDEX /* select PMC LUN */ + addi r5,r0,0x8 + bl .sio_bw + addi r4,r0,SIO_IOBASEHI /* initialize PMC address to 0x460 */ + addi r5,r0,0x04 + bl .sio_bw + addi r4,r0,SIO_IOBASELO + addi r5,r0,0x60 + bl .sio_bw + addi r4,r0,SIO_ACTIVATE /* enable PMC */ + addi r5,r0,SIO_LUNENABLE + bl .sio_bw + + lis r8,CFG_ISA_IO@h + ori r8,r8,0x0460 + li r9,0x03 + stb r9,0(r8) /* select PMC2 register */ + eieio + li r9,0x00 + stb r9,1(r8) /* SuperI/O clock source is 24MHz via X1 */ + eieio + +/* + * map UART1 (LUN 6) or UART2 (LUN 5) to COM1 (0x3F8) + */ + addi r4,r0,SIO_LUNINDEX /* select COM1 LUN */ + addi r5,r0,0x6 + bl .sio_bw + addi r4,r0,SIO_IOBASEHI /* initialize COM1 address to 0x3F8 */ + addi r5,r0,0x03 + bl .sio_bw + addi r4,r0,SIO_IOBASELO + addi r5,r0,0xF8 + bl .sio_bw + addi r4,r0,SIO_ACTIVATE /* enable COM1 */ + addi r5,r0,SIO_LUNENABLE + bl .sio_bw +/* + * Init COM1 for polled output + * + */ + lis r8,CFG_ISA_IO@h + ori r8,r8,0x03f8 + li r9,0x00 + stb r9,1(r8) /* int disabled */ + eieio + li r9,0x00 + stb r9,4(r8) /* modem ctrl */ + eieio + li r9,0x80 + stb r9,3(r8) /* link ctrl, bank select */ + eieio + li r9,115200/CONFIG_BAUDRATE + stb r9,0(r8) /* baud rate (LSB)*/ + eieio + rotrwi r9,r9,8 + stb r9,1(r8) /* baud rate (MSB) */ + eieio + li r9,0x03 + stb r9,3(r8) /* 8 data bits, 1 stop bit, no parity */ + eieio + li r9,0x0b + stb r9,4(r8) /* enable the receiver and transmitter (modem ctrl) */ + eieio +waitEmpty: + lbz r9,5(r8) /* transmit empty */ + andi. r9,r9,0x40 + beq waitEmpty + li r9,0x47 + stb r9,3(r8) /* send break; 8 data bits, 2 stop bit, no parity */ + eieio + + lis r0, 0x0001 /* */ + mtctr r0 +waitCOM1: + lwz r0, 5(r8) /* load from port for delay */ + bdnz waitCOM1 + +waitEmpty1: + lbz r9,5(r8) /* transmit empty */ + andi. r9,r9,0x40 + beq waitEmpty1 + li r9,0x07 + stb r9,3(r8) /* 8 data bits, 2 stop bit, no parity */ + eieio + +/* +; GPIO (LUN 7) +*/ + addi r4,r0,SIO_LUNINDEX /* select GPIO LUN */ + addi r5,r0,0x7 + bl .sio_bw + addi r4,r0,SIO_IOBASEHI /* initialize GPIO address to 0x220 */ + addi r5,r0,0x02 + bl .sio_bw + addi r4,r0,SIO_IOBASELO + addi r5,r0,0x20 + bl .sio_bw + addi r4,r0,SIO_ACTIVATE /* enable GPIO */ + addi r5,r0,SIO_LUNENABLE + bl .sio_bw + +.sioInit_done: + + /* + * Get base addr of ISA I/O space + */ + lis r3,CFG_ISA_IO@h + ori r3,r3,CFG_ISA_IO@l + + addi r3,r3,0x015C /* adjust to superI/O 87308 base */ + or r6,r3,r3 /* make a copy */ +/* +; CS0 +*/ + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x00 + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x00 + bl .sio_bw + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x01 + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x76 + bl .sio_bw + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x02 + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x40 + bl .sio_bw +/* +; CS1 +*/ + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x05 + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x00 + bl .sio_bw + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x05 + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x70 + bl .sio_bw + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x06 + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x1C + bl .sio_bw +/* +; CS2 +*/ + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x08 + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x00 + bl .sio_bw + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x09 + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x71 + bl .sio_bw + addi r4,r0,SIO_PCSCI /* select PCSCIR */ + addi r5,r0,0x0A + bl .sio_bw + addi r4,r0,SIO_PCSCD /* select PCSCDR */ + addi r5,r0,0x1C + bl .sio_bw + + mtspr 8,r7 /* restore link register */ + bclr 20,0 /* return to caller */ + +/* +; routine: sio_bw +; this function writes a register to the SIO chip +; call: +; sio_bw(sioaddr, regnum, value) +; return: +; none +*/ +.sio_bw: + stb r4,0(r3) /* write index register with register offset */ + eieio + sync + stb r5,1(r3) /* 1st write */ + eieio + sync + stb r5,1(r3) /* 2nd write */ + eieio + sync + bclr 20,0 /* return to caller */ +/* +; routine: sio_br +; this function reads a register from the SIO chip +; call: +; sioInit(sioaddr, regnum) +; return: +; register value +*/ +.sio_br: + stb r4,0(r3) /* write index register with register offset */ + eieio + sync + lbz r3,1(r3) /* retrieve specified reg offset contents */ + eieio + sync + bclr 20,0 /* return to caller */ + +/* + * Print a message to COM1 in polling mode + * r10=COM1 port, r3=(char*)string + */ + .globl Printf +Printf: + lis r10,CFG_ISA_IO@h /* COM1 port */ + ori r10,r10,0x03f8 + +WaitChr: + lbz r0,5(r10) /* read link status */ + eieio + andi. r0,r0,0x40 /* mask transmitter empty bit */ + beq cr0,WaitChr /* wait till empty */ + lbzx r0,r0,r3 /* get char */ + stb r0,0(r10) /* write to transmit reg */ + eieio + addi r3,r3,1 /* next char */ + lbzx r0,r0,r3 /* get char */ + cmpwi cr1,r0,0 /* end of string ? */ + bne cr1,WaitChr + blr + +/* + * Print 8/4/2 digits hex value to COM1 in polling mode + * r10=COM1 port, r3=val + */ +OutHex2: + li r9,4 /* shift reg for 2 digits */ + b OHstart +OutHex4: + li r9,12 /* shift reg for 4 digits */ + b OHstart + .globl OutHex +OutHex: + li r9,28 /* shift reg for 8 digits */ +OHstart: + lis r10,CFG_ISA_IO@h /* COM1 port */ + ori r10,r10,0x03f8 +OutDig: + lbz r0,0(r29) /* slow down dummy read */ + lbz r0,5(r10) /* read link status */ + eieio + andi. r0,r0,0x40 /* mask transmitter empty bit */ + beq cr0,OutDig + sraw r0,r3,r9 + clrlwi r0,r0,28 + cmpwi cr1,r0,9 + ble cr1,digIsNum + addic r0,r0,55 + b nextDig +digIsNum: + addic r0,r0,48 +nextDig: + stb r0,0(r10) /* write to transmit reg */ + eieio + addic. r9,r9,-4 + bge OutDig + blr + +/* + * Print 3 digits hdec value to COM1 in polling mode + * r10=COM1 port, r3=val, r7=x00, r8=x0, r9=x, r0,r6=scratch + */ + .globl OutDec +OutDec: + li r6, 10 + divwu r0, r3, r6 /* r0 = r3 / 10, r9 = r3 mod 10 */ + mullw r10, r0, r6 + subf r9, r10, r3 + + mr r3, r0 + divwu r0, r3, r6 /* r0 = r3 / 10, r8 = r3 mod 10 */ + mullw r10, r0, r6 + subf r8, r10, r3 + + mr r3, r0 + divwu r0, r3, r6 /* r0 = r3 / 10, r7 = r3 mod 10 */ + mullw r10, r0, r6 + subf r7, r10, r3 + + lis r10,CFG_ISA_IO@h /* COM1 port */ + ori r10,r10,0x03f8 + + or. r7, r7, r7 + bne noblank1 + li r3, 0x20 + b OutDec4 +noblank1: + addi r3, r7, 48 /* convert to ASCII */ +OutDec4: + lbz r0,0(r31) /* slow down dummy read */ + lbz r0,5(r10) /* read link status */ + eieio + andi. r0,r0,0x40 /* mask transmitter empty bit */ + beq cr0,OutDec4 + stb r3,0(r10) /* x00 to transmit */ + eieio + + or. r7, r7, r8 + beq OutDec5 + + addi r3, r8, 48 /* convert to ASCII */ +OutDec5: + lbz r0,0(r31) /* slow down dummy read */ + lbz r0,5(r10) /* read link status */ + eieio + andi. r0,r0,0x40 /* mask transmitter empty bit */ + beq cr0,OutDec5 + stb r3,0(r10) /* x0 to transmit */ + eieio + + addi r3, r9, 48 /* convert to ASCII */ +OutDec6: + lbz r0,0(r31) /* slow down dummy read */ + lbz r0,5(r10) /* read link status */ + eieio + andi. r0,r0,0x40 /* mask transmitter empty bit */ + beq cr0,OutDec6 + stb r3,0(r10) /* x to transmit */ + eieio + + blr + +/* + * Print a char to COM1 in polling mode + * r10=COM1 port, r3=char + */ + .globl OutChr +OutChr: + lis r10,CFG_ISA_IO@h /* COM1 port */ + ori r10,r10,0x03f8 + +OutChr1: + lbz r0,5(r10) /* read link status */ + eieio + andi. r0,r0,0x40 /* mask transmitter empty bit */ + beq cr0,OutChr1 /* wait till empty */ + stb r3,0(r10) /* write to transmit reg */ + eieio + blr + + +/* + * IN: r3 adr to read + * OUT: r3 val or -1 for error + */ +spdRead: + mfspr r26,8 /* save link register */ + + lis r30, CFG_ISA_IO@h + ori r30, r30, 0x220 /* GPIO Port 1 */ + li r7, 0x00 + li r8, 0x100 + and. r5,r3,r8 + beq spdbank0 + li r12, 0x08 + li r4, 0x10 + li r6, 0x18 + b spdRead1 +spdbank0: + li r12, 0x20 /* set I2C data */ + li r4, 0x40 /* set I2C clock */ + li r6, 0x60 /* set I2C clock and data */ +spdRead1: + li r8, 0x80 + + bl spdStart /* access I2C bus as master */ + + li r10,0xa0 /* write to SPD */ + bl spdWriteByte + bl spdReadAck /* ACK returns in r10 */ + cmpw cr0,r10,r7 + bne AckErr /* r10 must be 0, if ACK received */ + mr r10,r3 /* adr to read */ + bl spdWriteByte + bl spdReadAck + cmpw cr0,r10,r7 + bne AckErr + bl spdStart + li r10,0xa1 /* read from SPD */ + bl spdWriteByte + bl spdReadAck + cmpw cr0,r10,r7 + bne AckErr + bl spdReadByte /* return val in r10 */ + bl spdWriteAck + bl spdStop /* release I2C bus */ + + mr r3,r10 + + mtspr 8,r26 /* restore link register */ + blr + +/* + * ACK error occurred + */ +AckErr: + bl spdStop + orc r3,r0,r0 /* return -1 */ + mtspr 8,r26 /* restore link register */ + blr + +/* + * Routines to read from RAM spd. + * r30 - GPIO Port1 address in all cases. + * r4 - clock mask for SPD + * r6 - port mask for SPD + * r12 - data mask for SPD + */ +waitSpd: + li r0,0x1000 + mtctr r0 +wSpd: bdnz wSpd + bclr 20,0 /* return to caller */ + +/* + * establish START condition on I2C bus + */ +spdStart: + mfspr r27,8 /* save link register */ + stb r6,0(r30) /* set SDA and SCL */ + eieio + stb r6,1(r30) /* switch GPIO to output */ + eieio + bl waitSpd + stb r4,0(r30) /* reset SDA */ + eieio + bl waitSpd + stb r7,0(r30) /* reset SCL */ + eieio + bl waitSpd + mtspr 8,r27 + bclr 20,0 /* return to caller */ + +/* + * establish STOP condition on I2C bus + */ +spdStop: + mfspr r27,8 /* save link register */ + stb r7,0(r30) /* reset SCL and SDA */ + eieio + stb r6,1(r30) /* switch GPIO to output */ + eieio + bl waitSpd + stb r4,0(r30) /* set SCL */ + eieio + bl waitSpd + stb r6,0(r30) /* set SDA and SCL */ + eieio + bl waitSpd + stb r7,1(r30) /* switch GPIO to input */ + eieio + mtspr 8,r27 + bclr 20,0 /* return to caller */ + +spdReadByte: + mfspr r27,8 + stb r4,1(r30) /* set GPIO for SCL output */ + eieio + li r9,0x08 + li r10,0x00 +loopRB: + stb r7,0(r30) /* reset SDA and SCL */ + eieio + bl waitSpd + stb r4,0(r30) /* set SCL */ + eieio + bl waitSpd + lbz r5,0(r30) /* read from GPIO Port1*/ + rlwinm r10, r10, 1, 0, 31 + and. r5,r5,r12 + beq clearBit + ori r10,r10,0x01 /* append _1_ */ +clearBit: + stb r7,0(r30) /* reset SCL */ + eieio + bl waitSpd + addic. r9,r9,-1 + bne loopRB + mtspr 8,r27 + bclr 20,0 /* return (r10) to caller */ + +/* + * spdWriteByte writes bits 24 - 31 of r10 to I2C. + * r8 contains bit mask 0x80 + */ +spdWriteByte: + mfspr r27,8 /* save link register */ + li r9,0x08 /* write octet */ + and. r5,r10,r8 + bne sWB1 + stb r7,0(r30) /* set SDA to _0_ */ + eieio + b sWB2 +sWB1: stb r12,0(r30) /* set SDA to _1_ */ + eieio +sWB2: stb r6,1(r30) /* set GPIO to output */ + eieio +loopWB: + and. r5,r10,r8 + bne sWB3 + stb r7,0(r30) /* set SDA to _0_ */ + eieio + b sWB4 +sWB3: stb r12,0(r30) /* set SDA to _1_ */ + eieio +sWB4: bl waitSpd + and. r5,r10,r8 + bne sWB5 + stb r4,0(r30) /* set SDA to _0_ and SCL */ + eieio + b sWB6 +sWB5: stb r6,0(r30) /* set SDA to _1_ and SCL */ + eieio +sWB6: bl waitSpd + and. r5,r10,r8 + bne sWB7 + stb r7,0(r30) /* set SDA to _0_ and reset SCL */ + eieio + b sWB8 +sWB7: stb r12,0(r30) /* set SDA to _1_ and reset SCL */ + eieio +sWB8: bl waitSpd + rlwinm r10, r10, 1, 0, 31 /* next bit */ + addic. r9,r9,-1 + bne loopWB + mtspr 8,r27 + bclr 20,0 /* return to caller */ + +/* + * Read ACK from SPD, return value in r10 + */ +spdReadAck: + mfspr r27,8 /* save link register */ + stb r4,1(r30) /* set GPIO to output */ + eieio + stb r7,0(r30) /* reset SDA and SCL */ + eieio + bl waitSpd + stb r4,0(r30) /* set SCL */ + eieio + bl waitSpd + lbz r10,0(r30) /* read GPIO Port 1 and mask SDA */ + and r10,r10,r12 + bl waitSpd + stb r7,0(r30) /* reset SDA and SCL */ + eieio + bl waitSpd + mtspr 8,r27 + bclr 20,0 /* return (r10) to caller */ + +spdWriteAck: + mfspr r27,8 + stb r12,0(r30) /* set SCL */ + eieio + stb r6,1(r30) /* set GPIO to output */ + eieio + bl waitSpd + stb r6,0(r30) /* SDA and SCL */ + eieio + bl waitSpd + stb r12,0(r30) /* reset SCL */ + eieio + bl waitSpd + mtspr 8,r27 + bclr 20,0 /* return to caller */ + + + +/* + * Message for outport to console. + */ + .globl MessageBlock +MessageBlock: +Mok: + .ascii "....... OK \015\012\000" +Mfail: + .ascii "... FAILED \015\012\000" +MinitLogo: + .ascii "*** ELTEC Elektronik, Mainz ***\015\012" + .ascii "\015\012" + .ascii "BAB 750\015\012" + .ascii "\015\012" + .ascii "Initialising RAM\015\012\000" +Mspd01: + .ascii " Reading SPD of bank 0/1 ........\000" +Mspd23: + .ascii " Reading SPD of bank 2/3 ........\000" +MfpmRam: + .ascii " RAM-Type: FPM\015\012\000" +MedoRam: + .ascii " RAM-Type: EDO\015\012\000" +MsdRam: + .ascii " RAM-Type: SDRAM\015\012\000" +Mactivate: + .ascii " Activating \000" +Mmbyte: + .ascii " MB ....\000" diff --git a/board/eltec/bab750/mpc106_pci.c b/board/eltec/bab750/mpc106_pci.c new file mode 100644 index 0000000..5086381 --- /dev/null +++ b/board/eltec/bab750/mpc106_pci.c @@ -0,0 +1,1005 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * PCI routines for the MPC106 CPU. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PCI + +/* + * These are the lowest addresses allowed for PCI configuration. + * They correspond to lowest available I/O and Memory addresses. + * In the case where where multiple PMM regs are being used to map + * different PLB to PCI regions, each region should have it's own + * minimum address. + */ +unsigned long LowestMemAddr1 = CFG_MIN_PCI_MEMADDR1; +unsigned long LowestMemAddr2 = CFG_MIN_PCI_MEMADDR2; +unsigned long LowestIOAddr = CFG_PCI_PCI_IOADDR; + +unsigned long MaxBusNum = 0; + +unsigned char ShortPCIListing = 0; + +/* + * Subroutine: pci_init + * + * Description: Initialises the MPC106 PCI Configuration regs. + * + * Inputs: bd board info structure + * + * Return: None + * + */ +void pci_init(bd_t *bd) +{ + unsigned int pcicmd; + unsigned int pcistat; + unsigned int picr1; + unsigned int picr2; + unsigned int pvr = get_pvr(); + + puts("PCI: "); + + picr2 = PCI_Read_CFG_Reg(PCIDEVID_MPC106, PCI_PICR2, 4); + picr2 |= PICR2_CF_SNOOP_WS(3) | + PICR2_CF_FLUSH_L2 | + PICR2_CF_L2_HIT_DELAY(3) | + PICR2_CF_APHASE_WS(3); + picr2 &= ~(PICR2_L2_EN | PICR2_L2_UPDATE_EN); + PCI_Write_CFG_Reg(PCIDEVID_MPC106, PCI_PICR2, picr2, 4); + + pcicmd = PCI_Read_CFG_Reg(PCIDEVID_MPC106, PCI_CFG_COMMAND, 2); + pcicmd |= (CMD_SERR | PCI_CMD_MASTER | PCI_CMD_MEMEN); + PCI_Write_CFG_Reg(PCIDEVID_MPC106, PCI_CFG_COMMAND, pcicmd, 2); + + /* clear non-reserved bits in status register */ + pcistat = PCI_Read_CFG_Reg(PCIDEVID_MPC106, PCI_CFG_STATUS, 2); + pcistat |= PCI_STAT_NO_RSV_BITS; + PCI_Write_CFG_Reg(PCIDEVID_MPC106, PCI_CFG_STATUS, pcistat, 2); + + picr1 = PCI_Read_CFG_Reg(PCIDEVID_MPC106, PCI_PICR1, 4); + if (PVR_VER(pvr) == 0x0008) + picr1 |= PICR1_PROC_TYPE_603; + else + picr1 |= PICR1_PROC_TYPE_604; + + picr1 |= PICR1_CF_CBA(63) | PICR1_CF_BREAD_WS(2); + picr1 |= PICR1_MCP_EN | PICR1_CF_DPARK | + PICR1_CF_LOOP_SNOOP | PICR1_CF_APARK; + PCI_Write_CFG_Reg(PCIDEVID_MPC106, PCI_PICR1, picr1, 4); + +#ifdef CONFIG_PCI_PNP + /* + * Scan the PCI bus and configure devices found. + */ + puts("scanning bus for devices ..."); + + PCI_Scan(0); +#endif /* CONFIG_PCI_PNP */ + puts("OK\n"); +} + +/* + * Subroutine: PCI_Scan + * + * Description: Scan through all allowable PCI IDs and configure + * those for which the vendor ID indicates there is a + * device present. Routine scans only function 0. + * + * Inputs: BusNum Bus number where scanning begins + * + * Return: Number of devices found on the bus. + * + */ +int PCI_Scan(int BusNum) +{ + int Device; + int Function; + int BusDevFunc; + int Found = 0; + unsigned int HeaderType = 0; + unsigned int VendorID = 0; + +#ifdef DEBUG + printf("Scanning PCI bus %d\n", BusNum); +#endif + + /* + * Start with device 0, the MPC106 is device 0. sr: 09-07-2001 + */ + for (Device = 0; Device < CFG_MAX_PCI_DEVICES; Device++) { + HeaderType = 0; + VendorID = 0; + for (Function = 0; Function < CFG_MAX_PCI_FUNCTIONS; Function++) { + /* + * If this is not a multi-function device, we skip the rest + */ + if (Function && !(HeaderType & 0x80)) + break; + + BusDevFunc = (BusNum << 16) | + (Device << 11) | + (Function << 8); + + VendorID = PCI_Read_CFG_Reg (BusDevFunc, + PCI_CFG_VENDOR_ID, 2); + if ((VendorID == 0xFFFF) || (VendorID == 0x0000)) + continue; + + HeaderType = PCI_Read_CFG_Reg(BusDevFunc, + PCI_CFG_HEADER_TYPE, 1); +#ifdef DEBUG + printf("\nPCI Device %d Funtion %d is present\n", + Device, Function); +#endif + if (HeaderType & 0x01) { + /* PCI-PCI Bridge */ + PCI_Config_Bridge(BusDevFunc); + } else { + PCI_Config_Device(BusDevFunc, 6); + } + Found++; + } + } + return Found; +} + +/* + * Subroutine: PCI_Read_CFG_Reg + * + * Description: Read a PCI configuration register + * + * Inputs: BusDevFunc PCI Bus+Device+Function number + * Reg Configuration register number + * Width Number of bytes to read (1, 2, or 4) + * + * Return: Value of the configuration register read. + * For reads shorter than 4 bytes, return value + * is LSB-justified + */ +unsigned int PCI_Read_CFG_Reg(int BusDevFunc, int Reg, int Width) +{ + unsigned int RegAddr; + + /* + * bit 31 must be 1 and bits 1:0 must be 0 (note Little Endian bit notation) + */ + RegAddr = MPC106_REG | ((Reg|BusDevFunc) & 0xFFFFFFFC); + + /* + * Write reg to PCI Config Address + */ + out32r(MPC106_REG_ADDR, RegAddr); + + /* + * Read reg value from PCI Config Data + */ + switch (Width) { + case 1: + return ((unsigned int) in8(MPC106_REG_DATA | (Reg & 0x3))); + case 2: + return ((unsigned int) in16r(MPC106_REG_DATA | (Reg & 0x3))); + case 4: + return (in32r(MPC106_REG_DATA | (Reg & 0x3))); + } + + return 0; /* not reached: just to satisfy the compiler */ +} + +/* + * Subroutine: PCI_Write_CFG_Reg + * + * Description: Write a PCI configuration register. + * + * Inputs: BusDevFunc PCI Bus+Device+Function number + * Reg Configuration register number + * Value Configuration register value + * Width Number of bytes to write (1, 2, or 4) + * + * Return: 0 Successful + * + */ +int PCI_Write_CFG_Reg(int BusDevFunc, int Reg, unsigned int Value, int Width) +{ + unsigned int RegAddr; + + /* + * bit 31 must be 1 and bits 1:0 must be 0 (note Little Endian bit notation) + * (DWORD alignment) + */ + RegAddr = MPC106_REG | ((Reg|BusDevFunc) & 0xFFFFFFFC); + + /* + * Write reg to PCI Config Address + */ + out32r(MPC106_REG_ADDR, RegAddr); + + /* + * Perform a read to update the data register. + */ + in32r(MPC106_REG_DATA | (Reg & 0x3)); + + /* + * Write reg value to PCI Config Data + */ + switch (Width) { + case 1: out8 (MPC106_REG_DATA | (Reg & 0x3), + (unsigned char)(Value & 0xFF)); + break; + case 2: out16r (MPC106_REG_DATA | (Reg & 0x3), + (unsigned short)(Value & 0xFFFF)); + break; + case 4: out32r (MPC106_REG_DATA | (Reg & 0x3), Value); + break; + } + + return 0; +} + +/* + * Subroutine: PCI_Config_Device + * + * Description: Configure a PCI device by examining its I/O and memory + * address space needs and allocating address space to it by + * programming the address decoders in the Base Address Registers. + * + * Inputs: BusDevFunc Bus+Device+Function number + * NumBaseAddr Number of base address registers to + * configure + * + * Return: None + * + */ +void PCI_Config_Device(int BusDevFunc, int NumBaseAddr) +{ + int AddrSlot, i; + unsigned long AddrDesc, AddrProg, Min_Gnt_Val; + + unsigned long pcicmd; + pcicmd = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2); + PCI_Write_CFG_Reg (BusDevFunc, PCI_CFG_COMMAND, + pcicmd & ~(PCI_CMD_MEMEN|PCI_CMD_IOEN), 2); + + for (AddrSlot = 0; AddrSlot < NumBaseAddr; AddrSlot++) { + /* + * Write virtual address into register to check LSB. + * LSB == 1 => IO space, else memory space. + */ + PCI_Write_CFG_Reg (BusDevFunc, + PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot), + 0xFFFFFFFF, 4); + + AddrDesc = PCI_Read_CFG_Reg (BusDevFunc, + PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot), + 4); + + if (AddrDesc == 0) /* unimplemented, stop looking */ + continue; /* 01/04/99 MCG */ + +#ifdef DEBUG + printf ("Read Base Addr Reg %d = 0x%08lx\n", + AddrSlot, AddrDesc); +#endif + + if ((AddrDesc & 1) == 1) { /* I/O space */ + AddrDesc &= 0xFFFFFFFC; + + for (i = 0; (AddrDesc & 1) != 1; i++) + AddrDesc = AddrDesc >> 1; + + AddrDesc = 1 << i; +#ifdef DEBUG + printf(" PCI I/O space = 0x%lx bytes\n", AddrDesc); +#endif + for (AddrProg = CFG_PCI_PCI_IOADDR; + AddrProg < LowestIOAddr; + AddrProg += AddrDesc) { + ; /* empty */ + } + PCI_Write_CFG_Reg (BusDevFunc, + PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot), + AddrProg, 4); +#ifdef DEBUG + printf(" PCI I/O addr = 0x%lx\n", AddrProg); +#endif + LowestIOAddr = AddrProg + AddrDesc; + } else { /* memory space */ + AddrDesc &= 0xFFFFFFF0; + + for (i = 0; (AddrDesc & 1) != 1; i++) + AddrDesc = AddrDesc >> 1; + + AddrDesc = 1 << i; + + if ((unsigned long)AddrDesc < 4096) + AddrDesc = 4096; +#ifdef DEBUG + printf(" PCI memory space = 0x%lx bytes \n",AddrDesc); +#endif + for (AddrProg = CFG_MIN_PCI_MEMADDR1; + AddrProg < LowestMemAddr1; + AddrProg += AddrDesc) { + ; /* empty */ + } + + PCI_Write_CFG_Reg (BusDevFunc, + PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot), + AddrProg, 4); +#ifdef DEBUG + printf(" PCI memory addr = 0x%lx\n", AddrProg); +#endif + LowestMemAddr1 = AddrProg + AddrDesc; + } + } + + /* + * Assign expansion ROM address + */ + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, 0xFFFFFFFE, 4); + + AddrDesc = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, 4); + + if (AddrDesc != 0) { +#ifdef DEBUG + printf("Read Expansion ROM Addr Reg = 0x%08lx\n" , AddrDesc); +#endif + for (i = 0; (AddrDesc & 1) != 1; i++) + AddrDesc = AddrDesc >> 1; + + AddrDesc = 1 << i; +#ifdef DEBUG + printf(" PCI Expansion ROM space = 0x%lx bytes\n", AddrDesc); +#endif + for (AddrProg = CFG_MIN_PCI_MEMADDR1; + AddrProg < LowestMemAddr1; + AddrProg += AddrDesc) { + ; /* empty */ + } + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, AddrProg, 4); +#ifdef DEBUG + printf(" PCI Expansion ROM addr = 0x%lx\n", AddrProg); +#endif + LowestMemAddr1 = AddrProg + AddrDesc; + } + + Min_Gnt_Val = 0x80; + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_LATENCY_TIMER, Min_Gnt_Val, 1); + + /* + * Disable interrupt line, if device says it wants to use interrupts + */ + if (PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_PIN, 1) != 0) + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_LINE, 0xFF, 1); + /* + * Enable i/o space and memory space on this device + */ + PCI_Write_CFG_Reg (BusDevFunc, PCI_CFG_COMMAND, + pcicmd | PCI_CMD_MEMEN | PCI_CMD_IOEN, 2); +} + +/* + * Subroutine: PCI_Config_VGA_Device + * + * Description: Configure a PCI VGA device by examining its I/O and memory + * address space needs and allocating address space to it by + * programming the address decoders in the Base Address Registers. + * + * Inputs: BusDevFunc Bus+Device+Function number + * NumBaseAddr Number of base address registers to + * configure + * + * Return: None + * + */ +void PCI_Config_VGA_Device(int BusDevFunc, int NumBaseAddr) +{ + int AddrSlot, i; + unsigned long AddrDesc, AddrProg, Min_Gnt_Val; + + unsigned long pcicmd; + pcicmd = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2); + PCI_Write_CFG_Reg (BusDevFunc, PCI_CFG_COMMAND, + pcicmd & ~(PCI_CMD_MEMEN|PCI_CMD_IOEN), 2); + + for (AddrSlot = 0; AddrSlot < NumBaseAddr; AddrSlot++) { + /* + * Write virtual address into register to check LSB. + * LSB == 1 => IO space, else memory space. + */ + PCI_Write_CFG_Reg (BusDevFunc, + PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot), + 0xFFFFFFFF, 4); + + AddrDesc = PCI_Read_CFG_Reg (BusDevFunc, + PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot), + 4); + + if (AddrDesc == 0) /* unimplemented, stop looking */ + continue; /* 01/04/99 MCG */ + +#ifdef DEBUG + printf("Read Base Addr Reg %d = 0x%08lx\n",AddrSlot,AddrDesc); +#endif + + if ((AddrDesc & 1) == 1) { /* I/O space */ + AddrDesc &= 0xFFFFFFFC; + + for (i = 0; (AddrDesc & 1) != 1; i++) + AddrDesc = AddrDesc >> 1; + + AddrDesc = 1 << i; +#ifdef DEBUG + printf(" PCI I/O space = 0x%lx bytes \n",AddrDesc); +#endif + for (AddrProg = CFG_PCI_PCI_IOADDR; + AddrProg < LowestIOAddr; + AddrProg += AddrDesc) { + ; /* empty */ + } + + PCI_Write_CFG_Reg (BusDevFunc, + PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot), + AddrProg, 4); + LowestIOAddr = AddrProg + AddrDesc; + } + else { /* memory space */ + AddrDesc &= 0xFFFFFFF0; + + for (i = 0; (AddrDesc & 1) != 1; i++) + AddrDesc = AddrDesc >> 1; + + AddrDesc = 1 << i; + + if ((unsigned long)AddrDesc < 4096) + AddrDesc = 4096; +#ifdef DEBUG + printf(" PCI Memory space = 0x%lx bytes \n",AddrDesc); +#endif + for (AddrProg = CFG_MIN_PCI_MEMADDR2; + AddrProg < LowestMemAddr2; + AddrProg += AddrDesc) { + ; /* empty */ + } + + PCI_Write_CFG_Reg (BusDevFunc, + PCI_CFG_BASE_ADDRESS_0 + (4*AddrSlot), + AddrProg, 4); + LowestMemAddr2 = AddrProg + AddrDesc; + } + } + + /* + * Assign expansion ROM address + */ + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, 0xFFFFFFFE, 4); + + AddrDesc = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, 4); + + if (AddrDesc != 0) { +#ifdef DEBUG + printf("Read Expansion ROM Addr Reg = 0x%08lx\n" , AddrDesc); +#endif + for (i = 0; (AddrDesc & 1) != 1; i++) + AddrDesc = AddrDesc >> 1; + + AddrDesc = 1 << i; +#ifdef DEBUG + printf(" PCI Expansion ROM space = 0x%lx bytes\n", AddrDesc); +#endif + for (AddrProg = CFG_MIN_PCI_MEMADDR2; + AddrProg < LowestMemAddr2; + AddrProg += AddrDesc) { + ; /* empty */ + } + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, AddrProg, 4); +#ifdef DEBUG + printf(" PCI Expansion ROM addr = 0x%lx\n", AddrProg); +#endif + LowestMemAddr2 = AddrProg + AddrDesc; + } + + Min_Gnt_Val = 0x80; + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_LATENCY_TIMER, Min_Gnt_Val, 1); + + /* + * Disable interrupt line, if device says it wants to use interrupts + */ + if (PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_PIN, 1) != 0) + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_LINE, 0xFF, 1); + + /* + * Enable i/o space, memory space and master on this device + */ + PCI_Write_CFG_Reg (BusDevFunc, PCI_CFG_COMMAND, + pcicmd | PCI_CMD_MEMEN | PCI_CMD_IOEN, 2); +} + +/* + * Subroutine: PCI_Config_Bridge + * + * Description: Configure a PCI-PCI bridge + * + * Inputs: BusDevFunc Bus+Device+Function number + * + * Return: None + * + */ +void PCI_Config_Bridge(int BusDevFunc) +{ + int SecondaryBus; + int PrimaryBus; + int CommandReg_Val; + int InitialLowestIOAddr, InitialLowestMemAddr; + int IOBase, MemBase; + int IOLimit, MemLimit; + + InitialLowestIOAddr = LowestIOAddr; + InitialLowestMemAddr = LowestMemAddr1; + + CommandReg_Val = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2); + + /* Configure bridge's base address registers */ + PCI_Config_Device(BusDevFunc, 2); + + /* + * PCI_config_device() for the bridge could have changed the values in + * LowestIOAddr and LowestMemAddr1, if the bridge itself uses + * I/O and/or memory space. + */ + if ( LowestIOAddr > InitialLowestIOAddr ) /* bridge uses IO space? */ + CommandReg_Val |= 0x01; /* enable I/O Space */ + + if ( LowestMemAddr1 > InitialLowestMemAddr ) /* bridge uses memory space? */ + CommandReg_Val |= 0x02; /* enable Memory Space */ + + PrimaryBus = (BusDevFunc >> 16) & 0xFF; + PCI_Write_CFG_Reg(BusDevFunc, PCIPCI_PRIMARYBUS, PrimaryBus, 1); + + SecondaryBus = ++MaxBusNum; + PCI_Write_CFG_Reg(BusDevFunc, PCIPCI_SECONDARYBUS, SecondaryBus, 1); + + /* + * Start with max. possible value for subordinate bus number + * Later, after any additional child busses are found, we'll update this + */ + PCI_Write_CFG_Reg(BusDevFunc, PCIPCI_SUBORDINATEBUS, 0xFF, 1); + + /* IO Base must be on 4Kb boundary. Adjust if needed */ + if ((LowestIOAddr % 4096) != 0) + LowestIOAddr += 4096 - (LowestIOAddr % 4096); + + PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_IOBASE, + (LowestIOAddr>>8) & 0xF0, 1); + PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_IOBASEUPPER16, + (LowestIOAddr>>16) & 0xFFFF, 2); + + IOBase = LowestIOAddr; + + /* Mem Base must be on 1 MB boundary. adjust if needed */ + if ((LowestMemAddr1 % 0x100000) != 0) + LowestMemAddr1 += 0x100000 - (LowestMemAddr1 % 0x100000); + + PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_MEMBASE, + (LowestMemAddr1>>16) & 0xFFF0, 2); + MemBase = LowestMemAddr1; + + /* + * secondary bus on this bridge + */ + PCI_Scan(SecondaryBus); + + PCI_Write_CFG_Reg(BusDevFunc, PCIPCI_SUBORDINATEBUS, MaxBusNum, 1); + + IOLimit = LowestIOAddr; + if (LowestIOAddr > IOBase) { /* IO space used on secondary bus? */ + CommandReg_Val |= 0x01; /* enable IO Space */ + IOLimit--; /* IOLimit is highest used address */ + } + + PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_IOLIMIT, + ((IOLimit)>>8) & 0xF0, 1); + PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_IOLIMITUPPER16, + ((IOLimit)>>16) & 0xFFFF, 2); + + /* + * IOLIMIT is the starting address of a 4K block forwarded by the bridge. + * Round LowestIOAddr up to the next 4K boundary if IO space is enabled. + */ + if ((CommandReg_Val & 0x01) == 0x01) + LowestIOAddr = (IOLimit | 0xFFF) + 1; + + MemLimit = LowestMemAddr1; + if ( LowestMemAddr1 > MemBase ) { /* mem. space is used on secondary bus? */ + CommandReg_Val |= 0x02; /* enable Memory Space */ + MemLimit--; /* MemLimit is highest used address */ + } + + PCI_Write_CFG_Reg (BusDevFunc, PCIPCI_MEMLIMIT, + ((MemLimit)>>16) & 0xFFF0, 2); + + /* + * MEMLIMIT is the starting address of a 1M block forwarded by the bridge. + * Round LowestMemAddr up to the next 1M boundary + * if Memory space is enabled. + */ + + if ( (CommandReg_Val & 0x02) == 0x02 ) + LowestMemAddr1 = (MemLimit | 0xFFFFF) + 1; + + /* Enable Bus Master on secondary bus */ + CommandReg_Val |= 0x04; + + PCI_Write_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, CommandReg_Val, 2); +} + +/* + * Subroutine: PCI_Find_Device + * + * Description: Locate a PCI device by vendor and device number on any bus. + * + * Inputs: VendorID Value of the device's Vendor ID field + * DeviceID Value of the device's Device ID field + * + * Return: < 0 Device not found + * (int) PCI Bus+Device+Function number + * + */ +int PCI_Find_Device(unsigned short VendorID, unsigned short DeviceID) +{ + int Device; + int BusDevFunc; + int BusNum; + +#if CFG_SCSI_SCAN_BUS_REVERSE + for (BusNum = MaxBusNum; BusNum >= 0; BusNum--) { +#else + for (BusNum = 0; BusNum <= MaxBusNum; BusNum++) { +#endif + for (Device = 0; Device < CFG_MAX_PCI_DEVICES; Device++) { + BusDevFunc = (BusNum << 16) | (Device << 11); + + if (PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_VENDOR_ID, 2) == VendorID + && PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEVICE_ID, 2) == DeviceID) { + return (BusDevFunc); + } + } + } + return (-1); +} + + +#if (CONFIG_COMMANDS & CFG_CMD_PCI) +/* + * Follows routines for the output of infos about devices on PCI bus. + */ + +/* + * Subroutine: do_pciinfo + * + * Description: Handler for 'pciinfo' command.. + * + * Inputs: argv[1] may contain the number of the bus to be scanned. + * Default is bus 0. + * + * Return: None + * + */ +void do_pciinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) +{ + char *s; + int bus_no = 0; + + if (argc == 2) + { + bus_no = (int)simple_strtoul(argv[1], NULL, 10); + } + + if ((s = getenv("pci_listing")) != NULL) + ShortPCIListing = (strcmp(s, "short") == 0) ? 1 : 0; + else + ShortPCIListing = 0; + + pciinfo(bus_no); +} + + +/* + * Subroutine: pciinfo + * + * Description: Show information about devices on PCI bus. + * Depending on the define CFG_SHORT_PCI_LISTING + * the output will be more or less exhaustive. + * + * Inputs: bus_no the number of the bus to be scanned. + * + * Return: None + * + */ +void pciinfo(int BusNum) +{ + int Device; + int Function; + unsigned int HeaderType; + unsigned int VendorID; + int BusDevFunc; + + printf("Scanning PCI devices on bus %d\n", BusNum); + + if (ShortPCIListing) { + printf("No. VendorId DeviceId Device Class Sub-Class\n"); + printf("________________________________________________________\n"); + } + + for (Device = 0; Device < CFG_MAX_PCI_DEVICES; Device++) { + HeaderType = 0; + VendorID = 0; + for (Function = 0; Function < CFG_MAX_PCI_FUNCTIONS; Function++) { + /* + * If this is not a multi-function device, we skip the rest. + */ + if (Function && !(HeaderType & 0x80)) + break; + + BusDevFunc = (BusNum << 16) | + (Device << 11) | + (Function << 8); + + VendorID = PCI_Read_CFG_Reg (BusDevFunc, PCI_CFG_VENDOR_ID, 2); + if ((VendorID == 0xFFFF) || (VendorID == 0x0000)) + continue; + + HeaderType = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_HEADER_TYPE, 1); + + if (ShortPCIListing) + printf("%02d.%d ", Device, Function); + else + printf("\nFound PCI device %d, function %d:\n", + Device, Function); + + PCI_Header_Show(BusDevFunc); + } + } +} + + +/* + * Subroutine: PCI_Header_Show + * + * Description: Reads the header of the specified PCI device. + * + * Inputs: BusDevFunc Bus+Device+Function number + * + * Return: None + * + */ +void PCI_Header_Show(int BusDevFunc) +{ + PCI_HEADER_DEVICE headerDevice; + PCI_HEADER_BRIDGE headerBridge; + PCI_HEADER_DEVICE * pD = &headerDevice; + PCI_HEADER_BRIDGE * pB = &headerBridge; + + pD->headerType = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_HEADER_TYPE, 1); + + if (pD->headerType & 0x01) { /* PCI-to-PCI bridge */ + pB->vendorId = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_VENDOR_ID, 2); + pB->deviceId = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEVICE_ID, 2); + pB->command = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2); + pB->status = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_STATUS, 2); + pB->revisionId = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_REVISION, 1); + pB->progIf = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PROGRAMMING_IF, 1); + pB->subClass = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUBCLASS, 1); + pB->classCode = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CLASS, 1); + pB->cacheLine = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CACHE_LINE_SIZE, 1); + pB->latency = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_LATENCY_TIMER, 1); + pB->headerType = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_HEADER_TYPE, 1); + pB->bist = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BIST, 1); + pB->base0 = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_0, 4); + pB->base1 = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_1, 4); + pB->priBus = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRIMARY_BUS, 1); + pB->secBus = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SECONDARY_BUS, 1); + pB->subBus = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUBORDINATE_BUS, 1); + pB->secLatency = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SEC_LATENCY, 1); + pB->ioBase = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_IO_BASE, 1); + pB->ioLimit = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_IO_LIMIT, 1); + pB->secStatus = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SEC_STATUS, 2); + pB->memBase = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_MEM_BASE, 2); + pB->memLimit = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_MEM_LIMIT, 2); + pB->preBase = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRE_MEM_BASE, 2); + pB->preLimit = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRE_MEM_LIMIT, 2); + pB->preBaseUpper = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRE_MEM_BASE_U, 4); + pB->preLimitUpper = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PRE_MEM_LIMIT_U, 4); + pB->ioBaseUpper = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_IO_BASE_U, 2); + pB->ioLimitUpper = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_IO_LIMIT_U, 2); + pB->romBase = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_ROM_BASE, 4); + pB->intLine = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BRG_INT_LINE, 1); + pB->intPin = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BRG_INT_PIN, 1); + pB->control = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BRIDGE_CONTROL, 2); + PCI_Bheader_Print(pB); + } else { /* PCI device */ + pD->vendorId = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_VENDOR_ID, 2); + pD->deviceId = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEVICE_ID, 2); + pD->command = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_COMMAND, 2); + pD->status = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_STATUS, 1); + pD->revisionId = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_REVISION, 1); + pD->progIf = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_PROGRAMMING_IF, 1); + pD->subClass = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUBCLASS, 1); + pD->classCode = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CLASS, 1); + pD->cacheLine = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CACHE_LINE_SIZE, 1); + pD->latency = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_LATENCY_TIMER, 1); + pD->headerType = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_HEADER_TYPE, 1); + pD->bist = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BIST, 1); + pD->base0 = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_0, 4); + pD->base1 = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_1, 4); + pD->base2 = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_2, 4); + pD->base3 = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_3, 4); + pD->base4 = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_4, 4); + pD->base5 = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_BASE_ADDRESS_5, 4); + pD->cis = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_CIS, 4); + pD->subVendorId = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUB_VENDER_ID, 2); + pD->subSystemId = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_SUB_SYSTEM_ID, 2); + pD->romBase = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_EXPANSION_ROM, 4); + pD->intLine = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_LINE, 1); + pD->intPin = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_DEV_INT_PIN, 1); + pD->minGrant = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_MIN_GRANT, 1); + pD->maxLatency = PCI_Read_CFG_Reg(BusDevFunc, PCI_CFG_MAX_LATENCY, 1); + PCI_Dheader_Print(pD); + } +} + +static char *PCI_classes[] = { + "Build before PCI Rev2.0", + "Mass storage controller", + "Network controller ", + "Display controller ", + "Multimedia device ", + "Memory controller ", + "Bridge device ", + "Simple comm. controller", + "Base system peripheral ", + "Input device ", + "Docking station ", + "Processor ", + "Serial bus controller ", + "Reserved entry ", + "Does not fit any class " +}; + +/* + * Subroutine: PCI_Dheader_Print + * + * Description: Prints the header of the specified PCI device. + * + * Inputs: pD pointer to device header info + * + * Return: None + * + */ +void PCI_Dheader_Print(PCI_HEADER_DEVICE * pD) +{ + if (ShortPCIListing) { + printf("0x%.4x 0x%.4x %s 0x%.2x\n", + (ushort)pD->vendorId, + (ushort)pD->deviceId, + PCI_classes[(uchar)pD->classCode], + (uchar)pD->subClass); + } else { + printf(" vendor ID = 0x%.4x\n", (ushort)pD->vendorId); + printf(" device ID = 0x%.4x\n", (ushort)pD->deviceId); + printf(" command register = 0x%.4x\n", (ushort)pD->command); + printf(" status register = 0x%.4x\n", (ushort)pD->status); + printf(" revision ID = 0x%.2x\n", (uchar)pD->revisionId); + printf(" class code = 0x%.2x (%s)\n", + (uchar)pD->classCode, + PCI_classes[(int)pD->classCode]); + printf(" sub class code = 0x%.2x\n", (uchar)pD->subClass); + printf(" programming interface = 0x%.2x\n", (uchar)pD->progIf); + printf(" cache line = 0x%.2x\n", (uchar)pD->cacheLine); + printf(" latency time = 0x%.2x\n", (uchar)pD->latency); + printf(" header type = 0x%.2x\n", (uchar)pD->headerType); + printf(" BIST = 0x%.2x\n", (uchar)pD->bist); + printf(" base address 0 = 0x%.8x\n", pD->base0); + printf(" base address 1 = 0x%.8x\n", pD->base1); + printf(" base address 2 = 0x%.8x\n", pD->base2); + printf(" base address 3 = 0x%.8x\n", pD->base3); + printf(" base address 4 = 0x%.8x\n", pD->base4); + printf(" base address 5 = 0x%.8x\n", pD->base5); + printf(" cardBus CIS pointer = 0x%.8x\n", pD->cis); + printf(" sub system vendor ID = 0x%.4x\n", (ushort)pD->subVendorId); + printf(" sub system ID = 0x%.4x\n", (ushort)pD->subSystemId); + printf(" expansion ROM base address = 0x%.8x\n", pD->romBase); + printf(" interrupt line = 0x%.2x\n", (uchar)pD->intLine); + printf(" interrupt pin = 0x%.2x\n", (uchar)pD->intPin); + printf(" min Grant = 0x%.2x\n", (uchar)pD->minGrant); + printf(" max Latency = 0x%.2x\n", (uchar)pD->maxLatency); + } +} + +/* + * Subroutine: PCI_Bheader_Print + * + * Description: Prints the header of the specified PCI-to-PCI bridge. + * + * Inputs: pB pointer to bridge header info + * + * Return: None + * + */ +void PCI_Bheader_Print (PCI_HEADER_BRIDGE * pB) +{ + if (ShortPCIListing) { + printf("0x%.4x 0x%.4x %s 0x%.2x\n", + (ushort)pB->vendorId, + (ushort)pB->deviceId, + PCI_classes[(uchar)pB->classCode], + (uchar)pB->subClass); + } else { + printf (" vendor ID = 0x%.4x\n", (ushort)pB->vendorId); + printf (" device ID = 0x%.4x\n", (ushort)pB->deviceId); + printf (" command register = 0x%.4x\n", (ushort)pB->command); + printf (" status register = 0x%.4x\n", (ushort)pB->status); + printf (" revision ID = 0x%.2x\n", (uchar)pB->revisionId); + printf (" class code = 0x%.2x (%s)\n", + (uchar)pB->classCode, + PCI_classes[(int)pB->classCode]); + printf (" sub class code = 0x%.2x\n", (uchar)pB->subClass); + printf (" programming interface = 0x%.2x\n", (uchar)pB->progIf); + printf (" cache line = 0x%.2x\n", (uchar)pB->cacheLine); + printf (" latency time = 0x%.2x\n", (uchar)pB->latency); + printf (" header type = 0x%.2x\n", (uchar)pB->headerType); + printf (" BIST = 0x%.2x\n", (uchar)pB->bist); + printf (" base address 0 = 0x%.8x\n", pB->base0); + printf (" base address 1 = 0x%.8x\n", pB->base1); + printf (" primary bus number = 0x%.2x\n", (uchar)pB->priBus); + printf (" secondary bus number = 0x%.2x\n", (uchar)pB->secBus); + printf (" subordinate bus number = 0x%.2x\n", (uchar)pB->subBus); + printf (" secondary latency timer = 0x%.2x\n", (uchar)pB->secLatency); + printf (" IO base = 0x%.2x\n", (uchar)pB->ioBase); + printf (" IO limit = 0x%.2x\n", (uchar)pB->ioLimit); + printf (" secondary status = 0x%.4x\n", (ushort)pB->secStatus); + printf (" memory base = 0x%.4x\n", (ushort)pB->memBase); + printf (" memory limit = 0x%.4x\n", (ushort)pB->memLimit); + printf (" prefetch memory base = 0x%.4x\n", (ushort)pB->preBase); + printf (" prefetch memory limit = 0x%.4x\n", (ushort)pB->preLimit); + printf (" prefetch memory base upper = 0x%.8x\n", pB->preBaseUpper); + printf (" prefetch memory limit upper = 0x%.8x\n", pB->preLimitUpper); + printf (" IO base upper 16 bits = 0x%.4x\n", (ushort)pB->ioBaseUpper); + printf (" IO limit upper 16 bits = 0x%.4x\n", (ushort)pB->ioLimitUpper); + printf (" expansion ROM base address = 0x%.8x\n", pB->romBase); + printf (" interrupt line = 0x%.2x\n", (uchar)pB->intLine); + printf (" interrupt pin = 0x%.2x\n", (uchar)pB->intPin); + printf (" bridge control = 0x%.4x\n", (ushort)pB->control); + } +} + +#endif /* CONFIG_COMMANDS & CFG_CMD_PCI */ + +#endif /* CONFIG_PCI */ diff --git a/board/eltec/bab750/ns16550.c b/board/eltec/bab750/ns16550.c new file mode 100644 index 0000000..f2181c5 --- /dev/null +++ b/board/eltec/bab750/ns16550.c @@ -0,0 +1,54 @@ +/* + * COM1 NS16550 support + * originally from linux source (arch/ppc/boot/ns16550.c) + * modified to use CFG_ISA_MEM and new defines + */ + +#include +#include "ns16550.h" + + +void +NS16550_init(volatile struct NS16550 *com_port, int baud_divisor) +{ + com_port->ier = 0x00; /* interrupt enable register */ + com_port->lcr = LCR_BKSE; /* Access baud rate */ + com_port->dll = baud_divisor & 0xff; /* 9600 baud */ + com_port->dlm = (baud_divisor >> 8) & 0xff; + com_port->lcr = LCR_8N1; /* 8 data, 1 stop, no parity */ + com_port->mcr = MCR_DTR | MCR_RTS; /* RTS/DTR */ + com_port->fcr = FCR_FIFO_EN | FCR_RXSR | FCR_TXSR; /* Clear & enable FIFOs */ +} + +void +NS16550_reinit(volatile struct NS16550 *com_port, int baud_divisor) +{ + com_port->ier = 0x00; + com_port->lcr = LCR_BKSE; /* Access baud rate */ + com_port->dll = baud_divisor & 0xff; /* 9600 baud */ + com_port->dlm = (baud_divisor >> 8) & 0xff; + com_port->lcr = LCR_8N1; /* 8 data, 1 stop, no parity */ + com_port->mcr = MCR_DTR | MCR_RTS; /* RTS/DTR */ + com_port->fcr = FCR_FIFO_EN | FCR_RXSR | FCR_TXSR; /* Clear & enable FIFOs */ +} + +void NS16550_putc(volatile struct NS16550 *com_port, unsigned char c) +{ + while ((com_port->lsr & LSR_THRE) == 0) ; + com_port->thr = c; +} + +unsigned char +NS16550_getc(volatile struct NS16550 *com_port) +{ + while ((com_port->lsr & LSR_DR) == 0) ; + return (com_port->rbr); +} + +int NS16550_tstc(volatile struct NS16550 *com_port) +{ + return ((com_port->lsr & LSR_DR) != 0); +} + + + diff --git a/board/eltec/bab750/ns16550.h b/board/eltec/bab750/ns16550.h new file mode 100644 index 0000000..b694e86 --- /dev/null +++ b/board/eltec/bab750/ns16550.h @@ -0,0 +1,76 @@ +/* + * NS16550 Serial Port + * originally from linux source (arch/ppc/boot/ns16550.h) + * modified slightly to + * have addresses as offsets from CFG_ISA_BASE + * added a few more definitions + * added prototypes for ns16550.c + * reduced no of com ports to 2 + * modifications (c) Rob Taylor, Flying Pig Systems. 2000. + */ + + +struct NS16550 + { + unsigned char rbr; /* 0 Rx */ + unsigned char ier; /* 1 interrupt enable register, Divisor Latch High */ + unsigned char fcr; /* 2 fifo control rgister */ + unsigned char lcr; /* 3 line control register */ + unsigned char mcr; /* 4 modem control register */ + unsigned char lsr; /* 5 line status register */ + unsigned char msr; /* 6 modem status register */ + unsigned char scr; /* 7 scratch pad register */ + }; + +typedef struct NS16550 *NS16550_t; + +#define thr rbr /* Tx */ +#define iir fcr /* interrupt identification register */ +#define dll rbr /* divisor latch low */ +#define dlm ier /* divisor latch high */ + +#define FCR_FIFO_EN 0x01 /*fifo enable*/ +#define FCR_RXSR 0x02 /*reciever soft reset*/ +#define FCR_TXSR 0x04 /*transmitter soft reset*/ + + +#define MCR_DTR 0x01 +#define MCR_RTS 0x02 +#define MCR_DMA_EN 0x04 +#define MCR_TX_DFR 0x08 + + +#define LCR_WLS_MSK 0x03 /* character length slect mask*/ +#define LCR_WLS_5 0x00 /* 5 bit character length */ +#define LCR_WLS_6 0x01 /* 6 bit character length */ +#define LCR_WLS_7 0x02 /* 7 bit character length */ +#define LCR_WLS_8 0x03 /* 8 bit character length */ +#define LCR_STB 0x04 /* Number of stop Bits, off = 1, on = 1.5 or 2) */ +#define LCR_PEN 0x08 /* Parity eneble*/ +#define LCR_EPS 0x10 /* Even Parity Select*/ +#define LCR_STKP 0x20 /* Stick Parity*/ +#define LCR_SBRK 0x40 /* Set Break*/ +#define LCR_BKSE 0x80 /* Bank select enable*/ + +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +/* useful defaults for LCR*/ +#define LCR_8N1 0x03 + + +#define COM1 0x03F8 +#define COM2 0x02F8 + +void NS16550_init(volatile struct NS16550 *com_port, int baud_divisor); +void NS16550_reinit(volatile struct NS16550 *com_port, int baud_divisor); +void NS16550_putc(volatile struct NS16550 *com_port, unsigned char c); +unsigned char NS16550_getc(volatile struct NS16550 *com_port); +int NS16550_tstc(volatile struct NS16550 *com_port); + diff --git a/board/eltec/bab750/ns87308.c b/board/eltec/bab750/ns87308.c new file mode 100644 index 0000000..821fac9 --- /dev/null +++ b/board/eltec/bab750/ns87308.c @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * 09-18-2001 Andreas Heppel, Sysgo RTS GmbH: + * Added initialisation of additional logical devices on the chip. + */ + +#include + +#include "ns87308.h" +#include "ns16550.h" /* to configure the 87308's internal 16550's */ +#include /* to configure 87308's RTC */ + +void initialise_ns87308 (void) +{ + unsigned char data; + + /* + * Switch floppy drive to PS/2 mode. + */ + read_pnp_config(SUPOERIO_CONF1, &data); + data &= 0xFB; + write_pnp_config(SUPOERIO_CONF1, data); + + PNP_SET_DEVICE_BASE(LDEV_UART1, COM1); + PNP_SET_DEVICE_BASE(LDEV_UART2, COM2); + + PNP_SET_DEVICE_BASE(LDEV_KBC1, KBC1_BASE); + write_pnp_config(LUN_CONFIG_REG, 0); + write_pnp_config(CBASE_HIGH, 0x00); + write_pnp_config(CBASE_LOW, 0x64); + + PNP_ACTIVATE_DEVICE(LDEV_MOUSE); + + PNP_SET_DEVICE_BASE(LDEV_FDC, FDC_BASE); + write_pnp_config(LUN_CONFIG_REG, 0x40); + + PNP_SET_DEVICE_BASE(LDEV_PARP, LPT_BASE); + PNP_SET_DEVICE_BASE(LDEV_GPIO, GPIO_BASE); + + PNP_SET_DEVICE_BASE(LDEV_RTC_APC, RTC_PORT(0)); + PNP_SET_DEVICE_BASE(LDEV_POWRMAN, PWMAN_BASE); + + /* Enable all units */ + pci_writeb(0x00, CFG_ISA_IO + PWMAN_BASE); + eieio(); + pci_writeb(0x7d, CFG_ISA_IO + PWMAN_BASE + 1); + + pci_writeb(0x01, CFG_ISA_IO + PWMAN_BASE); + eieio(); + pci_writeb(0x87, CFG_ISA_IO + PWMAN_BASE + 1); + + /* SuperI/O clock source is 24MHz via X1 */ + pci_writeb(0x03, CFG_ISA_IO + PWMAN_BASE); + eieio(); + pci_writeb(0x00, CFG_ISA_IO + PWMAN_BASE + 1); + + /* + * set up the NVRAM access registers + * NVRAM's controlled by the configurable CS line from the 87308 + */ + PNP_PGCS_CSLINE_BASE(0, 0x76); + PNP_PGCS_CSLINE_CONF(0, 0x40); + PNP_PGCS_CSLINE_BASE(1, 0x70); + PNP_PGCS_CSLINE_CONF(1, 0x1C); + PNP_PGCS_CSLINE_BASE(2, 0x71); + PNP_PGCS_CSLINE_CONF(2, 0x1C); +} diff --git a/board/eltec/bab750/ns87308.h b/board/eltec/bab750/ns87308.h new file mode 100644 index 0000000..6e78b85 --- /dev/null +++ b/board/eltec/bab750/ns87308.h @@ -0,0 +1,218 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _NS87308_H_ +#define _NS87308_H_ + +#include + +/* Note: I couldn't find a full data sheet for the ns87308, but the ns87307 seems to be pretty + functionally- (and pin-) equivalent to the 87308, but the 308 has better ir support. */ + +void initialise_ns87308(void); + +/* + * The following struct represents the GPIO registers on the NS87308/NS97307 + */ +struct GPIO +{ + unsigned char dta1; /* 0 data port 1 */ + unsigned char dir1; /* 1 direction port 1 */ + unsigned char out1; /* 2 output type port 1 */ + unsigned char puc1; /* 3 pull-up control port 1 */ + unsigned char dta2; /* 4 data port 2 */ + unsigned char dir2; /* 5 direction port 2 */ + unsigned char out2; /* 6 output type port 2 */ + unsigned char puc2; /* 7 pull-up control port 2 */ +}; + +#define GPIO_BASE 0x0220 +#define LPT_BASE 0x0278 +#define KBC1_BASE 0x0060 +#define FDC_BASE 0x03F0 + +#define PWMAN_BASE 0x460 +/* + * The following represents the power management registers on the NS87308/NS97307 + */ +#define PWM_FER1 0 /* 0 function enable reg. 1 */ +#define PWM_FER2 1 /* 1 function enable reg. 2 */ +#define PWM_PMC1 2 /* 2 power mgmt. control 1 */ +#define PWM_PMC2 3 /* 3 power mgmt. control 2 */ +#define PWM_PMC3 4 /* 4 power mgmt. control 3 */ +#define PWM_WDTO 5 /* 5 watchdog time-out */ +#define PWM_WDCF 6 /* 6 watchdog config. */ +#define PWM_WDST 7 /* 7 watchdog status */ + +/*PNP config registers: + * these depend on the stated of BADDR1 and BADDR0 on startup + * so there's three versions here with the last two digits indicating + * for which configuration their valid + * the 1st of the two digits indicates the state of BADDR1 + * the 2st of the two digits indicates the state of BADDR0 + */ + + +#define IO_INDEX_OFFSET_0x 0x0279 /* full PnP isa Mode */ +#define IO_INDEX_OFFSET_10 0x015C /* PnP motherboard mode */ +#define IO_INDEX_OFFSET_11 0x002E /* PnP motherboard mode */ +#define IO_DATA_OFFSET_0x 0x0A79 /* full PnP isa Mode */ +#define IO_DATA_OFFSET_10 0x015D /* PnP motherboard mode */ +#define IO_DATA_OFFSET_11 0x002F /* PnP motherboard mode */ + +#if defined(CFG_NS87308_BADDR_0x) +#define IO_INDEX (CFG_ISA_IO + IO_INDEX_OFFSET_0x) +#define IO_DATA (CFG_ISA_IO + IO_DATA_OFFSET_0x) +#elif defined(CFG_NS87308_BADDR_10) +#define IO_INDEX (CFG_ISA_IO + IO_INDEX_OFFSET_10) +#define IO_DATA (CFG_ISA_IO + IO_DATA_OFFSET_10) +#elif defined(CFG_NS87308_BADDR_11) +#define IO_INDEX (CFG_ISA_IO + IO_INDEX_OFFSET_11) +#define IO_DATA (CFG_ISA_IO + IO_DATA_OFFSET_11) +#endif + +/* PnP register definitions */ + +#define SET_RD_DATA_PORT 0x00 +#define SERIAL_ISOLATION 0x01 +#define CONFIG_CONTROL 0x02 +#define WAKE_CSN 0x03 +#define RES_DATA 0x04 +#define STATUS 0x05 +#define SET_CSN 0x06 +#define LOGICAL_DEVICE 0x07 + +/*vendor defined values */ +#define SID_REG 0x20 +#define SUPOERIO_CONF1 0x21 +#define SUPOERIO_CONF2 0x22 +#define PGCS_INDEX 0x23 +#define PGCS_DATA 0x24 + +/* values above 30 are different for each logical device + but I can't be arsed to enter them all. the ones here + are pretty consistent between all logical devices + feel free to correct the situation if you want.. ;) + */ +#define ACTIVATE 0x30 +#define ACTIVATE_OFF 0x00 +#define ACTIVATE_ON 0x01 + +#define BASE_ADDR_HIGH 0x60 +#define BASE_ADDR_LOW 0x61 +#define LUN_CONFIG_REG 0xF0 +#define DBASE_HIGH 0x60 /* SIO KBC data base address, 15:8 */ +#define DBASE_LOW 0x61 /* SIO KBC data base address, 7:0 */ +#define CBASE_HIGH 0x62 /* SIO KBC command base addr, 15:8 */ +#define CBASE_LOW 0x63 /* SIO KBC command base addr, 7:0 */ + +/* the logical devices*/ +#define LDEV_KBC1 0x00 /* 2 devices for keyboard and mouse controller*/ +#define LDEV_KBC2 0x01 +#define LDEV_MOUSE 0x01 +#define LDEV_RTC_APC 0x02 /*Real Time Clock and Advanced Power Control*/ +#define LDEV_FDC 0x03 /*floppy disk controller*/ +#define LDEV_PARP 0x04 /*Parallel port*/ +#define LDEV_UART1 0x06 +#define LDEV_UART2 0x05 +#define LDEV_GPIO 0x07 /*General Purpose IO and chip select output signals*/ +#define LDEV_POWRMAN 0x08 /*Power Managment*/ + +/*some functions and macro's for doing configuration */ + +static inline void read_pnp_config(unsigned char index, unsigned char *data) +{ + pci_writeb(index,IO_INDEX); + pci_readb(IO_DATA, *data); +} + +static inline void write_pnp_config(unsigned char index, unsigned char data) +{ + pci_writeb(index,IO_INDEX); + pci_writeb(data, IO_DATA); +} + +static inline void pnp_set_device(unsigned char dev) +{ + write_pnp_config(LOGICAL_DEVICE, dev); +} + + +/*void write_pnp_config(unsigned char index, unsigned char data); +void pnp_set_device(unsigned char dev); +*/ + +#define PNP_SET_DEVICE_BASE(dev,base) \ + pnp_set_device(dev); \ + write_pnp_config(ACTIVATE, ACTIVATE_OFF); \ + write_pnp_config(BASE_ADDR_HIGH, ((base) >> 8) & 0xff ); \ + write_pnp_config(BASE_ADDR_LOW, (base) &0xff); \ + write_pnp_config(ACTIVATE, ACTIVATE_ON); + +#define PNP_ACTIVATE_DEVICE(dev) \ + pnp_set_device(dev); \ + write_pnp_config(ACTIVATE, ACTIVATE_ON); + +#define PNP_DEACTIVATE_DEVICE(dev) \ + pnp_set_device(dev); \ + write_pnp_config(ACTIVATE, ACTIVATE_OFF); + + +static inline void write_pgcs_config(unsigned char index, unsigned char data) +{ + write_pnp_config(PGCS_INDEX, index); + write_pnp_config(PGCS_DATA, data); +} + +/* these macrose configure the 3 CS lines + on the sandpoint board these controll NVRAM + CS0 is connected to NVRAMCS + CS1 is connected to NVRAMAS0 + CS2 is connected to NVRAMAS1 + */ +#define PGCS_CS_ASSERT_ON_WRITE 0x10 +#define PGCS_CS_ASSERT_ON_READ 0x20 + +#define PNP_PGCS_CSLINE_BASE(cs, base) \ + write_pgcs_config((cs) << 2, ((base) >> 8) & 0xff ); \ + write_pgcs_config(((cs) << 2) + 1, (base) & 0xff ); + +#define PNP_PGCS_CSLINE_CONF(cs, conf) \ + write_pgcs_config(((cs) << 2) + 2, (conf) ); + + +/* The following sections are for 87308 extensions to the standard compoents it emulates */ + +/* extensions to 16550*/ + +#define MCR_MDSL_MSK 0xe0 /*mode select mask*/ +#define MCR_MDSL_UART 0x00 /*uart, default*/ +#define MCR_MDSL_SHRPIR 0x02 /*Sharp IR*/ +#define MCR_MDSL_SIR 0x03 /*SIR*/ +#define MCR_MDSL_CIR 0x06 /*Consumer IR*/ + +#define FCR_TXFTH0 0x10 /* these bits control threshod of data level in fifo */ +#define FCR_TXFTH1 0x20 /* for interrupt trigger */ + + +#endif /*_NS87308_H_*/ diff --git a/board/eltec/bab750/ppcboot.lds b/board/eltec/bab750/ppcboot.lds new file mode 100644 index 0000000..1440140 --- /dev/null +++ b/board/eltec/bab750/ppcboot.lds @@ -0,0 +1,129 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * ppcboot.lds - linker script for ppcboot on the Galileo Eval Board. + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/mpc75x/start.o (.text) + +/* store the environment in a seperate sector in the boot flash */ +/* . = env_offset; */ +/* common/environment.o(.text) */ + + *(.text) + *(.fixup) + *(.got1) + } + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.rodata) + *(.rodata1) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x00FF) & 0xFFFFFF00; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; + __fixup_entries = (. - _FIXUP_TABLE_)>>2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(256); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(256); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/board/eltec/bab750/ppcboot.lds.mw.debug b/board/eltec/bab750/ppcboot.lds.mw.debug new file mode 100644 index 0000000..59fc9a2 --- /dev/null +++ b/board/eltec/bab750/ppcboot.lds.mw.debug @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems Ltd. robt@flyingpig.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); + +MEMORY { + ram (!rx) : org = 0x00000000 , LENGTH = 8M + code (!rx) : org = 0x00002000 , LENGTH = (4M - 0x2000) + rom (rx) : org = 0xfe000000 , LENGTH = (0x100000000 - 0xfe000000) +} + +SECTIONS +{ + _f_init = .; + PROVIDE(_f_init = .); + _f_init_rom = .; + PROVIDE(_f_init_rom = .); + + .init : { + cpu/mpc8240/start.o (.text) + *(.init) + } > ram + _init_size = SIZEOF(.init); + PROVIDE(_init_size = SIZEOF(.init)); + + ENTRY(_start) + +/* _ftext = .; + _ftext_rom = .; + _text_size = SIZEOF(.text); + */ + .text : { + *(.text) + *(.got1) + } > ram + .rodata : { *(.rodata) } > ram + .dtors : { *(.dtors) } > ram + .data : { *(.data) } > ram + .sdata : { *(.sdata) } > ram + .sdata2 : { *(.sdata2) + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } > ram + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; + __fixup_entries = (. - _FIXUP_TABLE_)>>2; + + .sbss : { *(.sbss) } > ram + .sbss2 : { *(.sbss2) } > ram + .bss : { *(.bss) } > ram + .debug : { *(.debug) } > ram + .line : { *(.line) } > ram + .symtab : { *(.symtab) } > ram + .shrstrtab : { *(.shstrtab) } > ram + .strtab : { *(.strtab) } > ram + /* .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } > ram + */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } > ram + __stop___ex_table = .; + + + .ppcenv : + { + common/environment.o (.ppcenv) + } > ram + + _end = . ; + PROVIDE (end = .); +} + diff --git a/board/eltec/bab750/serial.c b/board/eltec/bab750/serial.c new file mode 100644 index 0000000..98c01ab --- /dev/null +++ b/board/eltec/bab750/serial.c @@ -0,0 +1,86 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "config.h" +#include "ns16550.h" +#include "ns87308.h" + +/* + * Minimal serial functions needed to use one87308's UARTs + * as serial console interface. + */ + +#if (CONFIG_CONS_INDEX == 1) +#define console (CFG_ISA_IO + COM1) +#elif (CONFIG_CONS_INDEX == 2) +#define console (CFG_ISA_IO + COM2) +#else +#error "Invalid COM port for console output (must be 1 or 2)." +#endif + +void +serial_init (unsigned long dummy, int baudrate) +{ + int clock_divisor = 115200/baudrate; + + initialise_ns87308(); + + NS16550_init((NS16550_t)console, clock_divisor); +} + +void +serial_putc(const char c) +{ + if (c == '\n') + NS16550_putc((NS16550_t)console, '\r'); + + NS16550_putc((NS16550_t)console, c); +} + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + + +int +serial_getc(void) +{ + return NS16550_getc((NS16550_t)console); +} + +int +serial_tstc(void) +{ + return NS16550_tstc((NS16550_t)console); +} + +void +serial_setbrg (unsigned long dummy, int baudrate) +{ + int clock_divisor = 115200/baudrate; + NS16550_reinit((NS16550_t)console, clock_divisor); +} diff --git a/board/eltec/bab750/serial.h b/board/eltec/bab750/serial.h new file mode 100644 index 0000000..94ab81e --- /dev/null +++ b/board/eltec/bab750/serial.h @@ -0,0 +1,23 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + diff --git a/board/eltec/bab750/speed.c b/board/eltec/bab750/speed.c new file mode 100644 index 0000000..0582f53 --- /dev/null +++ b/board/eltec/bab750/speed.c @@ -0,0 +1,67 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * 09-18-2001 Andreas Heppel, Sysgo RTS GmbH + * We use the GPIO device on the ns87308 chip to read the bus speed + */ + +#include +#include +#include "ns87308.h" + + +/* Access functions for the Machine State Register */ +static __inline__ unsigned long get_msr(void) +{ + unsigned long msr; + + asm volatile("mfmsr %0" : "=r" (msr) :); + return msr; +} + +static __inline__ void set_msr(unsigned long msr) +{ + asm volatile("mtmsr %0" : : "r" (msr)); +} + +/* ------------------------------------------------------------------------- */ + +ulong get_bus_freq (ulong ignore) +{ + /* + * The GPIO Port 1 on BAB750 reflects the bus speed. + */ + volatile struct GPIO *gpio = (struct GPIO *)(CFG_ISA_IO + GPIO_BASE); + + unsigned char data = gpio->dta1; + + if (data & 0x02) + return 66000000; + + return 83000000; +} + +/* ------------------------------------------------------------------------- */ + + diff --git a/board/eltec/bab750/sym53c8xx.c b/board/eltec/bab750/sym53c8xx.c new file mode 100644 index 0000000..083113e --- /dev/null +++ b/board/eltec/bab750/sym53c8xx.c @@ -0,0 +1,785 @@ +/* + * (C) Copyright 2001 + * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * partly derived from + * linux/drivers/scsi/sym53c8xx.c + * + */ + +/* + * SCSI support based on the chip sym53C810. + * + * 09-19-2001 Andreas Heppel, Sysgo RTS GmbH + * The local version of this driver for the BAB750 board does not + * use interrupts but polls the chip instead (see the call of + * 'handle_scsi_int()' in 'scsi_issue()'. + */ + +#include +#include +#include +#include +#include +#include "sym53c8xx.h" +#include + +#undef SYM53C8XX_DEBUG + +#ifdef SYM53C8XX_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_SCSI) && defined(CONFIG_SCSI_SYM53C8XX) + + +#undef SCSI_SINGLE_STEP +/* + * Single Step is only used for debug purposes + */ +#ifdef SCSI_SINGLE_STEP +static unsigned long start_script_select; +static unsigned long start_script_msgout; +static unsigned long start_script_msgin; +static unsigned long start_script_msg_ext; +static unsigned long start_script_cmd; +static unsigned long start_script_data_in; +static unsigned long start_script_data_out; +static unsigned long start_script_status; +static unsigned long start_script_complete; +static unsigned long start_script_error; +static unsigned long start_script_reselection; +static unsigned int len_script_select; +static unsigned int len_script_msgout; +static unsigned int len_script_msgin; +static unsigned int len_script_msg_ext; +static unsigned int len_script_cmd; +static unsigned int len_script_data_in; +static unsigned int len_script_data_out; +static unsigned int len_script_status; +static unsigned int len_script_complete; +static unsigned int len_script_error; +static unsigned int len_script_reselection; +#endif + + +static unsigned short scsi_int_mask; /* shadow register for SCSI related interrupts */ +static unsigned char script_int_mask; /* shadow register for SCRIPT related interrupts */ +static unsigned long script_select[8]; /* script for selection */ +static unsigned long script_msgout[8]; /* script for message out phase (NOT USED) */ +static unsigned long script_msgin[14]; /* script for message in phase */ +static unsigned long script_msg_ext[32]; /* script for message in phase when more than 1 byte message */ +static unsigned long script_cmd[18]; /* script for command phase */ +static unsigned long script_data_in[8]; /* script for data in phase */ +static unsigned long script_data_out[8]; /* script for data out phase */ +static unsigned long script_status[6]; /* script for status phase */ +static unsigned long script_complete[10]; /* script for complete */ +static unsigned long script_reselection[4]; /* script for reselection (NOT USED) */ +static unsigned long script_error[2]; /* script for error handling */ + +static unsigned long int_stat[3]; /* interrupt status */ +static unsigned long scsi_mem_addr; /* base memory address =SCSI_MEM_ADDRESS; */ + + +#define SCSI_MAX_RETRY 3 /* number of retries in scsi_issue() */ + +#define SCSI_MAX_RETRY_NOT_READY 10 /* number of retries when device is not ready */ +#define SCSI_NOT_READY_TIME_OUT 500 /* timeout per retry when not ready */ + +/********************************************************************************* + * forward declerations + */ + +void scsi_chip_init(void); +void handle_scsi_int(void); + + +/******************************************************************************** + * reports SCSI errors to the user + */ +void scsi_print_error(ccb *pccb) +{ + int i; + printf("SCSI Error: Target %d LUN %d Command %02X\n",pccb->target, pccb->lun, pccb->cmd[0]); + printf(" CCB: "); + for(i=0;icmdlen;i++) + printf("%02X ",pccb->cmd[i]); + printf("(len=%d)\n",pccb->cmdlen); + printf(" Cntrl: "); + switch(pccb->contr_stat) { + case SIR_COMPLETE: printf("Complete (no Error)\n"); break; + case SIR_SEL_ATN_NO_MSG_OUT: printf("Selected with ATN no MSG out phase\n"); break; + case SIR_CMD_OUT_ILL_PH: printf("Command out illegal phase\n"); break; + case SIR_MSG_RECEIVED: printf("MSG received Error\n"); break; + case SIR_DATA_IN_ERR: printf("Data in Error\n"); break; + case SIR_DATA_OUT_ERR: printf("Data out Error\n"); break; + case SIR_SCRIPT_ERROR: printf("Script Error\n"); break; + case SIR_MSG_OUT_NO_CMD: printf("MSG out no Command phase\n"); break; + case SIR_MSG_OVER7: printf("MSG in over 7 bytes\n"); break; + case INT_ON_FY: printf("Interrupt on fly\n"); break; + case SCSI_SEL_TIME_OUT: printf("SCSI Selection Timeout\n"); break; + case SCSI_HNS_TIME_OUT: printf("SCSI Handshake Timeout\n"); break; + case SCSI_MA_TIME_OUT: printf("SCSI Phase Error\n"); break; + case SCSI_UNEXP_DIS: printf("SCSI unexpected disconnect\n"); break; + default: printf("unknown status %lx\n",pccb->contr_stat); break; + } + printf(" Sense: SK %x (",pccb->sense_buf[2]&0x0f); + switch(pccb->sense_buf[2]&0xf) { + case SENSE_NO_SENSE: printf("No Sense)"); break; + case SENSE_RECOVERED_ERROR: printf("Recovered Error)"); break; + case SENSE_NOT_READY: printf("Not Ready)"); break; + case SENSE_MEDIUM_ERROR: printf("Medium Error)"); break; + case SENSE_HARDWARE_ERROR: printf("Hardware Error)"); break; + case SENSE_ILLEGAL_REQUEST: printf("Illegal request)"); break; + case SENSE_UNIT_ATTENTION: printf("Unit Attention)"); break; + case SENSE_DATA_PROTECT: printf("Data Protect)"); break; + case SENSE_BLANK_CHECK: printf("Blank check)"); break; + case SENSE_VENDOR_SPECIFIC: printf("Vendor specific)"); break; + case SENSE_COPY_ABORTED: printf("Copy aborted)"); break; + case SENSE_ABORTED_COMMAND: printf("Aborted Command)"); break; + case SENSE_VOLUME_OVERFLOW: printf("Volume overflow)"); break; + case SENSE_MISCOMPARE: printf("Misscompare\n"); break; + default: printf("Illegal Sensecode\n"); break; + } + printf(" ASC %x ASCQ %x\n",pccb->sense_buf[12],pccb->sense_buf[13]); + printf(" Status: "); + switch(pccb->status) { + case S_GOOD : printf("Good\n"); break; + case S_CHECK_COND: printf("Check condition\n"); break; + case S_COND_MET: printf("Condition Met\n"); break; + case S_BUSY: printf("Busy\n"); break; + case S_INT: printf("Intermediate\n"); break; + case S_INT_COND_MET: printf("Intermediate condition met\n"); break; + case S_CONFLICT: printf("Reservation conflict\n"); break; + case S_TERMINATED: printf("Command terminated\n"); break; + case S_QUEUE_FULL: printf("Task set full\n"); break; + default: printf("unknown: %02X\n",pccb->status); break; + } + +} + + + +/****************************************************************************** + * sets-up the SCSI controller + * the base memory address is retrived via the PCI_Read_CFG_Reg + */ +void scsi_low_level_init(int busdevfunc) +{ + unsigned long cmd; + unsigned long addr; + unsigned char vec; + vec=PCI_Read_CFG_Reg(busdevfunc, PCI_CFG_DEV_INT_LINE, 1); + addr=PCI_Read_CFG_Reg(busdevfunc, PCI_CFG_BASE_ADDRESS_1, 4); + + addr |= CFG_60X_PCI_MEM_OFFSET; + /* + * Enable bus mastering in case this has not been done, yet. + */ + cmd=PCI_Read_CFG_Reg(busdevfunc, PCI_CFG_COMMAND, 4); + cmd |= PCI_CMD_MASTER; + PCI_Write_CFG_Reg(busdevfunc, PCI_CFG_COMMAND, cmd, 4); + + scsi_mem_addr=addr; + scsi_chip_init(); + scsi_bus_reset(); +} + + +/************************************************************************************ + * Low level Part of SCSI Driver + */ + +/* + * big-endian -> little endian conversion for the script + */ +unsigned long swap_script(unsigned long val) +{ + unsigned long tmp; + tmp = ((val>>24)&0xff) | ((val>>8)&0xff00) | ((val<<8)&0xff0000) | ((val<<24)&0xff000000); + return tmp; +} + + +void scsi_write_byte(ulong offset,unsigned char val) +{ + out8(scsi_mem_addr+offset,val); +} + + +unsigned char scsi_read_byte(ulong offset) +{ + return(in8(scsi_mem_addr+offset)); +} + + +/******************************************************************************** + * interrupt handler + */ +void handle_scsi_int(void) +{ + unsigned char stat,stat1,stat2; + unsigned short sstat; + int i; +#ifdef SCSI_SINGLE_STEP + unsigned long tt; +#endif + stat=scsi_read_byte(ISTAT); + if((stat & DIP)==DIP) { /* DMA Interrupt pending */ + stat1=scsi_read_byte(DSTAT); +#ifdef SCSI_SINGLE_STEP + if((stat1 & SSI)==SSI) + { + tt=in32r(scsi_mem_addr+DSP); + if(((tt)>=start_script_select) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_msgout) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_msgin) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_msg_ext) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_cmd) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_data_in) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_data_out) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_status) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_complete) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_error) && ((tt)>2); + goto end_single; + } + if(((tt)>=start_script_reselection) && ((tt)>2); + goto end_single; + } + printf("sc: %lx\n",tt); +end_single: + stat2=scsi_read_byte(DCNTL); + stat2|=STD; + scsi_write_byte(DCNTL,stat2); + } +#endif + if((stat1 & SIR)==SIR) /* script interrupt */ + { + int_stat[0]=in32(scsi_mem_addr+DSPS); + } + if((stat1 & DFE)==0) { /* fifo not epmty */ + scsi_write_byte(CTEST3,CLF); /* Clear DMA FIFO */ + stat2=scsi_read_byte(STEST3); + scsi_write_byte(STEST3,(stat2 | CSF)); /* Clear SCSI FIFO */ + } + } + if((stat & SIP)==SIP) { /* scsi interrupt */ + sstat = (unsigned short)scsi_read_byte(SIST+1); + sstat <<=8; + sstat |= (unsigned short)scsi_read_byte(SIST); + for(i=0;i<3;i++) { + if(int_stat[i]==0) + break; /* found an empty int status */ + } + int_stat[i]=SCSI_INT_STATE | sstat; + stat1=scsi_read_byte(DSTAT); + if((stat1 & DFE)==0) { /* fifo not epmty */ + scsi_write_byte(CTEST3,CLF); /* Clear DMA FIFO */ + stat2=scsi_read_byte(STEST3); + scsi_write_byte(STEST3,(stat2 | CSF)); /* Clear SCSI FIFO */ + } + } + if((stat & INTF)==INTF) { /* interrupt on Fly */ + scsi_write_byte(ISTAT,stat); /* clear it */ + for(i=0;i<3;i++) { + if(int_stat[i]==0) + break; /* found an empty int status */ + } + int_stat[i]=INT_ON_FY; + } +} + +void scsi_bus_reset(void) +{ + unsigned char t; + int i; + int end = CFG_SCSI_SPIN_UP_TIME*1000; + + t=scsi_read_byte(SCNTL1); + scsi_write_byte(SCNTL1,(t | CRST)); + udelay(50); + scsi_write_byte(SCNTL1,t); + + puts("SCSI: waiting for devices to spin up"); + for(i=0;i>8)); + scsi_write_byte(DIEN,script_int_mask); +} + +void scsi_write_dsp(unsigned long start) +{ + unsigned long val; +#ifdef SCSI_SINGLE_STEP + unsigned char t; +#endif + val = start; + out32r(scsi_mem_addr + DSP,start); +#ifdef SCSI_SINGLE_STEP + t=scsi_read_byte(DCNTL); + t|=STD; + scsi_write_byte(DCNTL,t); +#endif +} + +/* only used for debug purposes */ +void scsi_print_script(void) +{ + printf("script_select @ 0x%08lX\n",(unsigned long)&script_select[0]); + printf("script_msgout @ 0x%08lX\n",(unsigned long)&script_msgout[0]); + printf("script_msgin @ 0x%08lX\n",(unsigned long)&script_msgin[0]); + printf("script_msgext @ 0x%08lX\n",(unsigned long)&script_msg_ext[0]); + printf("script_cmd @ 0x%08lX\n",(unsigned long)&script_cmd[0]); + printf("script_data_in @ 0x%08lX\n",(unsigned long)&script_data_in[0]); + printf("script_data_out @ 0x%08lX\n",(unsigned long)&script_data_out[0]); + printf("script_status @ 0x%08lX\n",(unsigned long)&script_status[0]); + printf("script_complete @ 0x%08lX\n",(unsigned long)&script_complete[0]); + printf("script_error @ 0x%08lX\n",(unsigned long)&script_error[0]); +} + + + +void scsi_set_script(ccb *pccb) +{ + int i; + i=0; + script_select[i++]=swap_script(SCR_REG_REG(GPREG, SCR_AND, 0xfe)); + script_select[i++]=0; /* LED ON */ + script_select[i++]=swap_script(SCR_CLR(SCR_TRG)); /* select initiator mode */ + script_select[i++]=0; + /* script_select[i++]=swap_script(SCR_SEL_ABS_ATN | pccb->target << 16); */ + script_select[i++]=swap_script(SCR_SEL_ABS | pccb->target << 16); + script_select[i++]=swap_script(phys_to_bus(&script_cmd[4])); /* error handling */ + script_select[i++]=swap_script(SCR_JUMP); /* next section */ + /* script_select[i++]=swap_script((unsigned long)&script_msgout[0]); */ /* message out */ + script_select[i++]=swap_script(phys_to_bus(&script_cmd[0])); /* command out */ + +#ifdef SCSI_SINGLE_STEP + start_script_select=(unsigned long)&script_select[0]; + len_script_select=i*4; +#endif + + i=0; + script_msgout[i++]=swap_script(SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT))); + script_msgout[i++]=SIR_SEL_ATN_NO_MSG_OUT; + script_msgout[i++]=swap_script( SCR_MOVE_ABS(1) ^ SCR_MSG_OUT); + script_msgout[i++]=swap_script(phys_to_bus(&pccb->msgout[0])); + script_msgout[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_COMMAND))); /* if Command phase */ + script_msgout[i++]=swap_script(phys_to_bus(&script_cmd[0])); /* switch to command */ + script_msgout[i++]=swap_script(SCR_INT); /* interrupt if not */ + script_msgout[i++]=SIR_MSG_OUT_NO_CMD; + +#ifdef SCSI_SINGLE_STEP + start_script_msgout=(unsigned long)&script_msgout[0]; + len_script_msgout=i*4; +#endif + i=0; + script_cmd[i++]=swap_script(SCR_MOVE_ABS(pccb->cmdlen) ^ SCR_COMMAND); + script_cmd[i++]=swap_script(phys_to_bus(&pccb->cmd[0])); + script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN))); /* message in ? */ + script_cmd[i++]=swap_script(phys_to_bus(&script_msgin[0])); + script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT))); /* data out ? */ + script_cmd[i++]=swap_script(phys_to_bus(&script_data_out[0])); + script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN))); /* data in ? */ + script_cmd[i++]=swap_script(phys_to_bus(&script_data_in[0])); + script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_STATUS))); /* status ? */ + script_cmd[i++]=swap_script(phys_to_bus(&script_status[0])); + script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND))); /* command ? */ + script_cmd[i++]=swap_script(phys_to_bus(&script_cmd[0])); + script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT))); /* message out ? */ + script_cmd[i++]=swap_script(phys_to_bus(&script_msgout[0])); + script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN))); /* just for error handling message in ? */ + script_cmd[i++]=swap_script(phys_to_bus(&script_msgin[0])); + script_cmd[i++]=swap_script(SCR_INT); /* interrupt if not */ + script_cmd[i++]=SIR_CMD_OUT_ILL_PH; +#ifdef SCSI_SINGLE_STEP + start_script_cmd=(unsigned long)&script_cmd[0]; + len_script_cmd=i*4; +#endif + i=0; + script_data_out[i++]=swap_script(SCR_MOVE_ABS(pccb->datalen)^ SCR_DATA_OUT); /* move */ + script_data_out[i++]=swap_script(phys_to_bus(pccb->pdata)); /* pointer to buffer */ + script_data_out[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS))); + script_data_out[i++]=swap_script(phys_to_bus(&script_status[0])); + script_data_out[i++]=swap_script(SCR_INT); + script_data_out[i++]=SIR_DATA_OUT_ERR; + +#ifdef SCSI_SINGLE_STEP + start_script_data_out=(unsigned long)&script_data_out[0]; + len_script_data_out=i*4; +#endif + i=0; + script_data_in[i++]=swap_script(SCR_MOVE_ABS(pccb->datalen)^ SCR_DATA_IN); /* move */ + script_data_in[i++]=swap_script(phys_to_bus(pccb->pdata)); /* pointer to buffer */ + script_data_in[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS))); + script_data_in[i++]=swap_script(phys_to_bus(&script_status[0])); + script_data_in[i++]=swap_script(SCR_INT); + script_data_in[i++]=SIR_DATA_IN_ERR; +#ifdef SCSI_SINGLE_STEP + start_script_data_in=(unsigned long)&script_data_in[0]; + len_script_data_in=i*4; +#endif + i=0; + script_msgin[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); + script_msgin[i++]=swap_script(phys_to_bus(&pccb->msgin[0])); + script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE))); + script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0])); + script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT))); + script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0])); + script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP))); + script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0])); + script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP))); + script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0])); + script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED))); + script_msgin[i++]=swap_script(phys_to_bus(&script_msg_ext[0])); + script_msgin[i++]=swap_script(SCR_INT); + script_msgin[i++]=SIR_MSG_RECEIVED; +#ifdef SCSI_SINGLE_STEP + start_script_msgin=(unsigned long)&script_msgin[0]; + len_script_msgin=i*4; +#endif + i=0; + script_msg_ext[i++]=swap_script(SCR_CLR (SCR_ACK)); /* clear ACK */ + script_msg_ext[i++]=0; + script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* assuming this is the msg length */ + script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[1])); + script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); + script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ + script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ + script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[2])); + script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); + script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ + script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ + script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[3])); + script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); + script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ + script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ + script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[4])); + script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); + script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ + script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ + script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[5])); + script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); + script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ + script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ + script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[6])); + script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); + script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ + script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */ + script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[7])); + script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN))); + script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */ + script_msg_ext[i++]=swap_script(SCR_INT); + script_msg_ext[i++]=SIR_MSG_OVER7; +#ifdef SCSI_SINGLE_STEP + start_script_msg_ext=(unsigned long)&script_msg_ext[0]; + len_script_msg_ext=i*4; +#endif + i=0; + script_status[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_STATUS); + script_status[i++]=swap_script(phys_to_bus(&pccb->status)); + script_status[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN))); + script_status[i++]=swap_script(phys_to_bus(&script_msgin[0])); + script_status[i++]=swap_script(SCR_INT); + script_status[i++]=SIR_STATUS_ILL_PH; +#ifdef SCSI_SINGLE_STEP + start_script_status=(unsigned long)&script_status[0]; + len_script_status=i*4; +#endif + i=0; + script_complete[i++]=swap_script(SCR_REG_REG (SCNTL2, SCR_AND, 0x7f)); + script_complete[i++]=0; + script_complete[i++]=swap_script(SCR_CLR (SCR_ACK|SCR_ATN)); + script_complete[i++]=0; + script_complete[i++]=swap_script(SCR_WAIT_DISC); + script_complete[i++]=0; + script_complete[i++]=swap_script(SCR_REG_REG(GPREG, SCR_OR, 0x01)); + script_complete[i++]=0; /* LED OFF */ + script_complete[i++]=swap_script(SCR_INT); + script_complete[i++]=SIR_COMPLETE; +#ifdef SCSI_SINGLE_STEP + start_script_complete=(unsigned long)&script_complete[0]; + len_script_complete=i*4; +#endif + i=0; + script_error[i++]=swap_script(SCR_INT); /* interrupt if error */ + script_error[i++]=SIR_SCRIPT_ERROR; +#ifdef SCSI_SINGLE_STEP + start_script_error=(unsigned long)&script_error[0]; + len_script_error=i*4; +#endif + i=0; + script_reselection[i++]=swap_script(SCR_CLR (SCR_TRG)); /* target status */ + script_reselection[i++]=0; + script_reselection[i++]=swap_script(SCR_WAIT_RESEL); + script_reselection[i++]=swap_script(phys_to_bus(&script_select[0])); /* len = 4 */ +#ifdef SCSI_SINGLE_STEP + start_script_reselection=(unsigned long)&script_reselection[0]; + len_script_reselection=i*4; +#endif +} + + + +void scsi_issue(ccb *pccb) +{ + int i; + unsigned short sstat; + int retrycnt; /* retry counter */ + for(i=0;i<3;i++) + int_stat[i]=0; /* delete all int status */ + /* struct pccb must be set-up correctly */ + retrycnt=0; + PRINTF("ID %d issue cmd %02X\n",pccb->target,pccb->cmd[0]); + pccb->trans_bytes=0; /* no bytes transfered yet */ + scsi_set_script(pccb); /* fill in SCRIPT */ + scsi_int_mask=STO | UDC | MA; /* | CMP; / * Interrupts which are enabled */ + script_int_mask=0xff; /* enable all Ints */ + scsi_int_enable(); + scsi_write_dsp(phys_to_bus(&script_select[0])); /* start script */ + /* now we have to wait for IRQs */ +retry: + /* + * This version of the driver is _not_ interrupt driven, + * but polls the chip's interrupt registers (ISTAT, DSTAT). + */ + while(int_stat[0]==0) + handle_scsi_int(); + + if(int_stat[0]==SIR_COMPLETE) { + if(pccb->msgin[0]==M_DISCONNECT) { + PRINTF("Wait for reselection\n"); + for(i=0;i<3;i++) + int_stat[i]=0; /* delete all int status */ + scsi_write_dsp(phys_to_bus(&script_reselection[0])); /* start reselection script */ + goto retry; + } + pccb->contr_stat=SIR_COMPLETE; + return; + } + if((int_stat[0] & SCSI_INT_STATE)==SCSI_INT_STATE) { /* scsi interrupt */ + sstat=(unsigned short)int_stat[0]; + if((sstat & STO)==STO) { /* selection timeout */ + pccb->contr_stat=SCSI_SEL_TIME_OUT; + scsi_write_byte(GPREG,0x01); + PRINTF("ID: %X Selection Timeout\n",pccb->target); + return; + } + if((sstat & UDC)==UDC) { /* unexpected disconnect */ + pccb->contr_stat=SCSI_UNEXP_DIS; + scsi_write_byte(GPREG,0x01); + PRINTF("ID: %X Unexpected Disconnect\n",pccb->target); + return; + } + if((sstat & RSL)==RSL) { /* reselection */ + pccb->contr_stat=SCSI_UNEXP_DIS; + scsi_write_byte(GPREG,0x01); + PRINTF("ID: %X Unexpected Disconnect\n",pccb->target); + return; + } + if(((sstat & MA)==MA)||((sstat & HTH)==HTH)) { /* phase missmatch */ + if(retrycnttrans_bytes=pccb->datalen - + ((unsigned long)scsi_read_byte(DBC) | + ((unsigned long)scsi_read_byte(DBC+1)<<8) | + ((unsigned long)scsi_read_byte(DBC+2)<<16)); + for(i=0;i<3;i++) + int_stat[i]=0; /* delete all int status */ + retrycnt++; + PRINTF("ID: %X Phase Missmatch Retry %d Phase %02X transfered %lx\n", + pccb->target,retrycnt,scsi_read_byte(SBCL),pccb->trans_bytes); + scsi_write_dsp(phys_to_bus(&script_cmd[4])); /* start retry script */ + goto retry; + } + if((sstat & MA)==MA) + pccb->contr_stat=SCSI_MA_TIME_OUT; + else + pccb->contr_stat=SCSI_HNS_TIME_OUT; + PRINTF("Phase Missmatch stat %lx\n",pccb->contr_stat); + return; + } /* no phase int */ +/* if((sstat & CMP)==CMP) { + pccb->contr_stat=SIR_COMPLETE; + return; + } +*/ + PRINTF("SCSI INT %lX\n",int_stat[0]); + pccb->contr_stat=int_stat[0]; + return; + } /* end scsi int */ + PRINTF("SCRIPT INT %lX phase %02X\n",int_stat[0],scsi_read_byte(SBCL)); + pccb->contr_stat=int_stat[0]; + return; +} + +int scsi_exec(ccb *pccb) +{ + unsigned char tmpcmd[16],tmpstat; + int i,retrycnt,t; + unsigned long transbytes,datalen; + unsigned char *tmpptr; + retrycnt=0; +retry: + scsi_issue(pccb); + if(pccb->contr_stat!=SIR_COMPLETE) + return FALSE; + if(pccb->status==S_GOOD) + return TRUE; + if(pccb->status==S_CHECK_COND) { /* check condition */ + for(i=0;i<16;i++) + tmpcmd[i]=pccb->cmd[i]; + pccb->cmd[0]=SCSI_REQ_SENSE; + pccb->cmd[1]=pccb->lun<<5; + pccb->cmd[2]=0; + pccb->cmd[3]=0; + pccb->cmd[4]=14; + pccb->cmd[5]=0; + pccb->cmdlen=6; + pccb->msgout[0]=SCSI_IDENTIFY; + transbytes=pccb->trans_bytes; + tmpptr=pccb->pdata; + pccb->pdata=&pccb->sense_buf[0]; + datalen=pccb->datalen; + pccb->datalen=14; + tmpstat=pccb->status; + scsi_issue(pccb); + for(i=0;i<16;i++) + pccb->cmd[i]=tmpcmd[i]; + pccb->trans_bytes=transbytes; + pccb->pdata=tmpptr; + pccb->datalen=datalen; + pccb->status=tmpstat; + PRINTF("Request_sense sense key %x ASC %x ASCQ %x\n",pccb->sense_buf[2]&0x0f, + pccb->sense_buf[12],pccb->sense_buf[13]); + switch(pccb->sense_buf[2]&0xf) { + case SENSE_NO_SENSE: + case SENSE_RECOVERED_ERROR: + /* seems to be ok */ + return TRUE; + break; + case SENSE_NOT_READY: + if((pccb->sense_buf[12]!=0x04)||(pccb->sense_buf[13]!=0x01)) { + /* if device is not in process of becoming ready */ + return FALSE; + break; + } /* else fall through */ + case SENSE_UNIT_ATTENTION: + if(retrycnttarget,retrycnt); + for(t=0;ttarget,retrycnt); + return FALSE; + default: + return FALSE; + } + } + PRINTF("Status = %X\n",pccb->status); + return FALSE; +} + + + + +void scsi_chip_init(void) +{ + /* first we issue a soft reset */ + scsi_write_byte(ISTAT,SRST); + udelay(1000); + scsi_write_byte(ISTAT,0); + /* setup chip */ + scsi_write_byte(SCNTL0,0xC0); /* full arbitration no start, no message, parity disabled, master */ + scsi_write_byte(SCNTL1,0x00); + scsi_write_byte(SCNTL2,0x00); + scsi_write_byte(SCNTL3,0x13); /* synchronous clock 40/4=10MHz, asynchronous 40MHz */ + scsi_write_byte(SCID,0x47); /* ID=7, enable reselection */ + scsi_write_byte(SXFER,0x00); /* synchronous transfer period 10MHz, asynchronous */ + scsi_write_byte(SDID,0x00); /* targed SCSI ID = 0 */ + scsi_int_mask=0x0000; /* no Interrupt is enabled */ + script_int_mask=0x00; + scsi_int_enable(); + scsi_write_byte(GPREG,0x01); /* GPIO0 is LED (off) */ + scsi_write_byte(GPCNTL,0x0E); /* GPIO0 is Output */ + scsi_write_byte(STIME0,0x08); /* handshake timer disabled, selection timeout 512msec */ + scsi_write_byte(RESPID,0x80); /* repond only to the own ID (reselection) */ + scsi_write_byte(STEST1,0x00); /* not isolated, SCLK is used */ + scsi_write_byte(STEST2,0x00); /* no Lowlevel Mode? */ + scsi_write_byte(STEST3,0x80); /* enable tolerANT */ + scsi_write_byte(CTEST3,0x04); /* clear FIFO */ + scsi_write_byte(CTEST4,0x00); + scsi_write_byte(CTEST5,0x00); +#ifdef SCSI_SINGLE_STEP +/* scsi_write_byte(DCNTL,IRQM | SSM); */ + scsi_write_byte(DCNTL,IRQD | SSM); + scsi_write_byte(DMODE,MAN); +#else +/* scsi_write_byte(DCNTL,IRQM); */ + scsi_write_byte(DCNTL,IRQD); + scsi_write_byte(DMODE,0x00); +#endif +} +#endif /* (CONFIG_COMMANDS & CFG_CMD_SCSI) */ + + diff --git a/board/eltec/bab750/sym53c8xx.h b/board/eltec/bab750/sym53c8xx.h new file mode 100644 index 0000000..32a78f0 --- /dev/null +++ b/board/eltec/bab750/sym53c8xx.h @@ -0,0 +1,583 @@ +/* + * (C) Copyright 2001 + * Denis Peter, MPL AG Switzerland + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Most of these definitions are derived from + * linux/drivers/scsi/sym53c8xx_defs.h + * + */ + +#ifndef _SYM53C8XX_DEFS_H +#define _SYM53C8XX_DEFS_H + + +#define SCNTL0 0x00 /* full arb., ena parity, par->ATN */ + +#define SCNTL1 0x01 /* no reset */ + #define ISCON 0x10 /* connected to scsi */ + #define CRST 0x08 /* force reset */ + #define IARB 0x02 /* immediate arbitration */ + +#define SCNTL2 0x02 /* no disconnect expected */ + #define SDU 0x80 /* cmd: disconnect will raise error */ + #define CHM 0x40 /* sta: chained mode */ + #define WSS 0x08 /* sta: wide scsi send [W]*/ + #define WSR 0x01 /* sta: wide scsi received [W]*/ + +#define SCNTL3 0x03 /* cnf system clock dependent */ + #define EWS 0x08 /* cmd: enable wide scsi [W]*/ + #define ULTRA 0x80 /* cmd: ULTRA enable */ + /* bits 0-2, 7 rsvd for C1010 */ + +#define SCID 0x04 /* cnf host adapter scsi address */ + #define RRE 0x40 /* r/w:e enable response to resel. */ + #define SRE 0x20 /* r/w:e enable response to select */ + +#define SXFER 0x05 /* ### Sync speed and count */ + /* bits 6-7 rsvd for C1010 */ + +#define SDID 0x06 /* ### Destination-ID */ + +#define GPREG 0x07 /* ??? IO-Pins */ + +#define SFBR 0x08 /* ### First byte in phase */ + +#define SOCL 0x09 + #define CREQ 0x80 /* r/w: SCSI-REQ */ + #define CACK 0x40 /* r/w: SCSI-ACK */ + #define CBSY 0x20 /* r/w: SCSI-BSY */ + #define CSEL 0x10 /* r/w: SCSI-SEL */ + #define CATN 0x08 /* r/w: SCSI-ATN */ + #define CMSG 0x04 /* r/w: SCSI-MSG */ + #define CC_D 0x02 /* r/w: SCSI-C_D */ + #define CI_O 0x01 /* r/w: SCSI-I_O */ + +#define SSID 0x0a + +#define SBCL 0x0b + +#define DSTAT 0x0c + #define DFE 0x80 /* sta: dma fifo empty */ + #define MDPE 0x40 /* int: master data parity error */ + #define BF 0x20 /* int: script: bus fault */ + #define ABRT 0x10 /* int: script: command aborted */ + #define SSI 0x08 /* int: script: single step */ + #define SIR 0x04 /* int: script: interrupt instruct. */ + #define IID 0x01 /* int: script: illegal instruct. */ + +#define SSTAT0 0x0d + #define ILF 0x80 /* sta: data in SIDL register lsb */ + #define ORF 0x40 /* sta: data in SODR register lsb */ + #define OLF 0x20 /* sta: data in SODL register lsb */ + #define AIP 0x10 /* sta: arbitration in progress */ + #define LOA 0x08 /* sta: arbitration lost */ + #define WOA 0x04 /* sta: arbitration won */ + #define IRST 0x02 /* sta: scsi reset signal */ + #define SDP 0x01 /* sta: scsi parity signal */ + +#define SSTAT1 0x0e + #define FF3210 0xf0 /* sta: bytes in the scsi fifo */ + +#define SSTAT2 0x0f + #define ILF1 0x80 /* sta: data in SIDL register msb[W]*/ + #define ORF1 0x40 /* sta: data in SODR register msb[W]*/ + #define OLF1 0x20 /* sta: data in SODL register msb[W]*/ + #define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */ + #define LDSC 0x02 /* sta: disconnect & reconnect */ + +#define DSA 0x10 /* --> Base page */ +#define DSA1 0x11 +#define DSA2 0x12 +#define DSA3 0x13 + +#define ISTAT 0x14 /* --> Main Command and status */ + #define CABRT 0x80 /* cmd: abort current operation */ + #define SRST 0x40 /* mod: reset chip */ + #define SIGP 0x20 /* r/w: message from host to ncr */ + #define SEM 0x10 /* r/w: message between host + ncr */ + #define CON 0x08 /* sta: connected to scsi */ + #define INTF 0x04 /* sta: int on the fly (reset by wr)*/ + #define SIP 0x02 /* sta: scsi-interrupt */ + #define DIP 0x01 /* sta: host/script interrupt */ + + +#define CTEST0 0x18 +#define CTEST1 0x19 +#define CTEST2 0x1a + #define CSIGP 0x40 + /* bits 0-2,7 rsvd for C1010 */ + +#define CTEST3 0x1b + #define FLF 0x08 /* cmd: flush dma fifo */ + #define CLF 0x04 /* cmd: clear dma fifo */ + #define FM 0x02 /* mod: fetch pin mode */ + #define WRIE 0x01 /* mod: write and invalidate enable */ + /* bits 4-7 rsvd for C1010 */ + +#define DFIFO 0x20 +#define CTEST4 0x21 + #define BDIS 0x80 /* mod: burst disable */ + #define MPEE 0x08 /* mod: master parity error enable */ + +#define CTEST5 0x22 + #define DFS 0x20 /* mod: dma fifo size */ + /* bits 0-1, 3-7 rsvd for C1010 */ +#define CTEST6 0x23 + +#define DBC 0x24 /* ### Byte count and command */ +#define DNAD 0x28 /* ### Next command register */ +#define DSP 0x2c /* --> Script Pointer */ +#define DSPS 0x30 /* --> Script pointer save/opcode#2 */ + +#define SCRATCHA 0x34 /* Temporary register a */ +#define SCRATCHA1 0x35 +#define SCRATCHA2 0x36 +#define SCRATCHA3 0x37 + +#define DMODE 0x38 + #define BL_2 0x80 /* mod: burst length shift value +2 */ + #define BL_1 0x40 /* mod: burst length shift value +1 */ + #define ERL 0x08 /* mod: enable read line */ + #define ERMP 0x04 /* mod: enable read multiple */ + #define BOF 0x02 /* mod: burst op code fetch */ + #define MAN 0x01 /* mod: manual start */ + +#define DIEN 0x39 +#define SBR 0x3a + +#define DCNTL 0x3b /* --> Script execution control */ + #define CLSE 0x80 /* mod: cache line size enable */ + #define PFF 0x40 /* cmd: pre-fetch flush */ + #define PFEN 0x20 /* mod: pre-fetch enable */ + #define SSM 0x10 /* mod: single step mode */ + #define IRQM 0x08 /* mod: irq mode (1 = totem pole !) */ + #define STD 0x04 /* cmd: start dma mode */ + #define IRQD 0x02 /* mod: irq disable */ + #define NOCOM 0x01 /* cmd: protect sfbr while reselect */ + /* bits 0-1 rsvd for C1010 */ + +#define ADDER 0x3c + +#define SIEN 0x40 /* -->: interrupt enable */ +#define SIST 0x42 /* <--: interrupt status */ + #define SBMC 0x1000/* sta: SCSI Bus Mode Change (895/6 only) */ + #define STO 0x0400/* sta: timeout (select) */ + #define GEN 0x0200/* sta: timeout (general) */ + #define HTH 0x0100/* sta: timeout (handshake) */ + #define MA 0x80 /* sta: phase mismatch */ + #define CMP 0x40 /* sta: arbitration complete */ + #define SEL 0x20 /* sta: selected by another device */ + #define RSL 0x10 /* sta: reselected by another device*/ + #define SGE 0x08 /* sta: gross error (over/underflow)*/ + #define UDC 0x04 /* sta: unexpected disconnect */ + #define RST 0x02 /* sta: scsi bus reset detected */ + #define PAR 0x01 /* sta: scsi parity error */ + +#define SLPAR 0x44 +#define SWIDE 0x45 +#define MACNTL 0x46 +#define GPCNTL 0x47 +#define STIME0 0x48 /* cmd: timeout for select&handshake*/ +#define STIME1 0x49 /* cmd: timeout user defined */ +#define RESPID 0x4a /* sta: Reselect-IDs */ + +#define STEST0 0x4c + +#define STEST1 0x4d + #define SCLK 0x80 /* Use the PCI clock as SCSI clock */ + #define DBLEN 0x08 /* clock doubler running */ + #define DBLSEL 0x04 /* clock doubler selected */ + + +#define STEST2 0x4e + #define ROF 0x40 /* reset scsi offset (after gross error!) */ + #define EXT 0x02 /* extended filtering */ + +#define STEST3 0x4f + #define TE 0x80 /* c: tolerAnt enable */ + #define HSC 0x20 /* c: Halt SCSI Clock */ + #define CSF 0x02 /* c: clear scsi fifo */ + +#define SIDL 0x50 /* Lowlevel: latched from scsi data */ +#define STEST4 0x52 + #define SMODE 0xc0 /* SCSI bus mode (895/6 only) */ + #define SMODE_HVD 0x40 /* High Voltage Differential */ + #define SMODE_SE 0x80 /* Single Ended */ + #define SMODE_LVD 0xc0 /* Low Voltage Differential */ + #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */ + /* bits 0-5 rsvd for C1010 */ + +#define SODL 0x54 /* Lowlevel: data out to scsi data */ + +#define SBDL 0x58 /* Lowlevel: data from scsi data */ + + + + +/*----------------------------------------------------------- +** +** Utility macros for the script. +** +**----------------------------------------------------------- +*/ + +#define REG(r) (r) + +/*----------------------------------------------------------- +** +** SCSI phases +** +** DT phases illegal for ncr driver. +** +**----------------------------------------------------------- +*/ + +#define SCR_DATA_OUT 0x00000000 +#define SCR_DATA_IN 0x01000000 +#define SCR_COMMAND 0x02000000 +#define SCR_STATUS 0x03000000 +#define SCR_DT_DATA_OUT 0x04000000 +#define SCR_DT_DATA_IN 0x05000000 +#define SCR_MSG_OUT 0x06000000 +#define SCR_MSG_IN 0x07000000 + +#define SCR_ILG_OUT 0x04000000 +#define SCR_ILG_IN 0x05000000 + +/*----------------------------------------------------------- +** +** Data transfer via SCSI. +** +**----------------------------------------------------------- +** +** MOVE_ABS (LEN) +** <> +** +** MOVE_IND (LEN) +** <> +** +** MOVE_TBL +** <> +** +**----------------------------------------------------------- +*/ + +#define OPC_MOVE 0x08000000 + +#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l)) +#define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l)) +#define SCR_MOVE_TBL (0x10000000 | OPC_MOVE) + +#define SCR_CHMOV_ABS(l) ((0x00000000) | (l)) +#define SCR_CHMOV_IND(l) ((0x20000000) | (l)) +#define SCR_CHMOV_TBL (0x10000000) + + +/*----------------------------------------------------------- +** +** Selection +** +**----------------------------------------------------------- +** +** SEL_ABS | SCR_ID (0..15) [ | REL_JMP] +** <> +** +** SEL_TBL | << dnad_offset>> [ | REL_JMP] +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_SEL_ABS 0x40000000 +#define SCR_SEL_ABS_ATN 0x41000000 +#define SCR_SEL_TBL 0x42000000 +#define SCR_SEL_TBL_ATN 0x43000000 + + +#define SCR_JMP_REL 0x04000000 +#define SCR_ID(id) (((unsigned long)(id)) << 16) + +/*----------------------------------------------------------- +** +** Waiting for Disconnect or Reselect +** +**----------------------------------------------------------- +** +** WAIT_DISC +** dummy: <> +** +** WAIT_RESEL +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_WAIT_DISC 0x48000000 +#define SCR_WAIT_RESEL 0x50000000 + +/*----------------------------------------------------------- +** +** Bit Set / Reset +** +**----------------------------------------------------------- +** +** SET (flags {|.. }) +** +** CLR (flags {|.. }) +** +**----------------------------------------------------------- +*/ + +#define SCR_SET(f) (0x58000000 | (f)) +#define SCR_CLR(f) (0x60000000 | (f)) + +#define SCR_CARRY 0x00000400 +#define SCR_TRG 0x00000200 +#define SCR_ACK 0x00000040 +#define SCR_ATN 0x00000008 + + + + +/*----------------------------------------------------------- +** +** Memory to memory move +** +**----------------------------------------------------------- +** +** COPY (bytecount) +** << source_address >> +** << destination_address >> +** +** SCR_COPY sets the NO FLUSH option by default. +** SCR_COPY_F does not set this option. +** +** For chips which do not support this option, +** ncr_copy_and_bind() will remove this bit. +**----------------------------------------------------------- +*/ + +#define SCR_NO_FLUSH 0x01000000 + +#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n)) +#define SCR_COPY_F(n) (0xc0000000 | (n)) + +/*----------------------------------------------------------- +** +** Register move and binary operations +** +**----------------------------------------------------------- +** +** SFBR_REG (reg, op, data) reg = SFBR op data +** << 0 >> +** +** REG_SFBR (reg, op, data) SFBR = reg op data +** << 0 >> +** +** REG_REG (reg, op, data) reg = reg op data +** << 0 >> +** +**----------------------------------------------------------- +** On 810A, 860, 825A, 875, 895 and 896 chips the content +** of SFBR register can be used as data (SCR_SFBR_DATA). +** The 896 has additionnal IO registers starting at +** offset 0x80. Bit 7 of register offset is stored in +** bit 7 of the SCRIPTS instruction first DWORD. +**----------------------------------------------------------- +*/ + +#define SCR_REG_OFS(ofs) ((((ofs) & 0x7f) << 16ul)) /* + ((ofs) & 0x80)) */ + +#define SCR_SFBR_REG(reg,op,data) \ + (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) + +#define SCR_REG_SFBR(reg,op,data) \ + (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) + +#define SCR_REG_REG(reg,op,data) \ + (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) + + +#define SCR_LOAD 0x00000000 +#define SCR_SHL 0x01000000 +#define SCR_OR 0x02000000 +#define SCR_XOR 0x03000000 +#define SCR_AND 0x04000000 +#define SCR_SHR 0x05000000 +#define SCR_ADD 0x06000000 +#define SCR_ADDC 0x07000000 + +#define SCR_SFBR_DATA (0x00800000>>8ul) /* Use SFBR as data */ + +/*----------------------------------------------------------- +** +** FROM_REG (reg) SFBR = reg +** << 0 >> +** +** TO_REG (reg) reg = SFBR +** << 0 >> +** +** LOAD_REG (reg, data) reg = +** << 0 >> +** +** LOAD_SFBR(data) SFBR = +** << 0 >> +** +**----------------------------------------------------------- +*/ + +#define SCR_FROM_REG(reg) \ + SCR_REG_SFBR(reg,SCR_OR,0) + +#define SCR_TO_REG(reg) \ + SCR_SFBR_REG(reg,SCR_OR,0) + +#define SCR_LOAD_REG(reg,data) \ + SCR_REG_REG(reg,SCR_LOAD,data) + +#define SCR_LOAD_SFBR(data) \ + (SCR_REG_SFBR (gpreg, SCR_LOAD, data)) + +/*----------------------------------------------------------- +** +** LOAD from memory to register. +** STORE from register to memory. +** +** Only supported by 810A, 860, 825A, 875, 895 and 896. +** +**----------------------------------------------------------- +** +** LOAD_ABS (LEN) +** <> +** +** LOAD_REL (LEN) (DSA relative) +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_REG_OFS2(ofs) (((ofs) & 0xff) << 16ul) +#define SCR_NO_FLUSH2 0x02000000 +#define SCR_DSA_REL2 0x10000000 + +#define SCR_LOAD_R(reg, how, n) \ + (0xe1000000 | how | (SCR_REG_OFS2(REG(reg))) | (n)) + +#define SCR_STORE_R(reg, how, n) \ + (0xe0000000 | how | (SCR_REG_OFS2(REG(reg))) | (n)) + +#define SCR_LOAD_ABS(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2, n) +#define SCR_LOAD_REL(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n) +#define SCR_LOAD_ABS_F(reg, n) SCR_LOAD_R(reg, 0, n) +#define SCR_LOAD_REL_F(reg, n) SCR_LOAD_R(reg, SCR_DSA_REL2, n) + +#define SCR_STORE_ABS(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2, n) +#define SCR_STORE_REL(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n) +#define SCR_STORE_ABS_F(reg, n) SCR_STORE_R(reg, 0, n) +#define SCR_STORE_REL_F(reg, n) SCR_STORE_R(reg, SCR_DSA_REL2, n) + + +/*----------------------------------------------------------- +** +** Waiting for Disconnect or Reselect +** +**----------------------------------------------------------- +** +** JUMP [ | IFTRUE/IFFALSE ( ... ) ] +** <
> +** +** JUMPR [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** CALL [ | IFTRUE/IFFALSE ( ... ) ] +** <
> +** +** CALLR [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** RETURN [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** INT [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** INT_FLY [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** Conditions: +** WHEN (phase) +** IF (phase) +** CARRYSET +** DATA (data, mask) +** +**----------------------------------------------------------- +*/ + +#define SCR_NO_OP 0x80000000 +#define SCR_JUMP 0x80080000 +#define SCR_JUMP64 0x80480000 +#define SCR_JUMPR 0x80880000 +#define SCR_CALL 0x88080000 +#define SCR_CALLR 0x88880000 +#define SCR_RETURN 0x90080000 +#define SCR_INT 0x98080000 +#define SCR_INT_FLY 0x98180000 + +#define IFFALSE(arg) (0x00080000 | (arg)) +#define IFTRUE(arg) (0x00000000 | (arg)) + +#define WHEN(phase) (0x00030000 | (phase)) +#define IF(phase) (0x00020000 | (phase)) + +#define DATA(D) (0x00040000 | ((D) & 0xff)) +#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff)) + +#define CARRYSET (0x00200000) + + + +#define SIR_COMPLETE 0x10000000 +/* script errors */ +#define SIR_SEL_ATN_NO_MSG_OUT 0x00000001 +#define SIR_CMD_OUT_ILL_PH 0x00000002 +#define SIR_STATUS_ILL_PH 0x00000003 +#define SIR_MSG_RECEIVED 0x00000004 +#define SIR_DATA_IN_ERR 0x00000005 +#define SIR_DATA_OUT_ERR 0x00000006 +#define SIR_SCRIPT_ERROR 0x00000007 +#define SIR_MSG_OUT_NO_CMD 0x00000008 +#define SIR_MSG_OVER7 0x00000009 +/* Fly interrupt */ +#define INT_ON_FY 0x00000080 + +/* Hardware errors are defined in scsi.h */ + +#define SCSI_IDENTIFY 0xC0 + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#endif diff --git a/board/eltec/bab750/w83c553f.c b/board/eltec/bab750/w83c553f.c new file mode 100644 index 0000000..d16ba50 --- /dev/null +++ b/board/eltec/bab750/w83c553f.c @@ -0,0 +1,212 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Initialisation of the PCI-to-ISA bridge and disabling the BIOS + * write protection (for flash) in function 0 of the chip. + * Enabling function 1 (IDE controller of the chip. + */ + +#include +#include +#include + +#include + +#define EIEIO_SYNC __asm__ volatile ("eieio;sync") + +ulong bus_offset[CFG_IDE_MAXBUS]; + +void initialise_pic(void); +void initialise_dma(void); + +void initialise_w83c553f(void) +{ + int regval = 0; + int devbusfn = 0; + + devbusfn = PCI_Find_Device(W83C553F_VID, W83C553F_DID); + if (devbusfn == -1) + { + printf("Error: Cannot find W83C553F controller on any PCI bus."); + return; + } + + regval = PCI_Read_CFG_Reg(devbusfn, PCI_CFG_COMMAND, 2); + regval |= PCI_CMD_MASTER | PCI_CMD_IOEN | PCI_CMD_MEMEN; + PCI_Write_CFG_Reg(devbusfn, PCI_CFG_COMMAND, regval, 2); + + regval = PCI_Read_CFG_Reg(devbusfn, WINBOND_IPADCR, 1); + /* 16 MB ISA memory space */ + regval |= (IPADCR_IPATOM4 | IPADCR_IPATOM5 | IPADCR_IPATOM6 | IPADCR_IPATOM7); + regval &= ~IPADCR_MBE512; + PCI_Write_CFG_Reg(devbusfn, WINBOND_IPADCR, regval, 1); + + regval = PCI_Read_CFG_Reg(devbusfn, WINBOND_CSCR, 1); + /* switch off BIOS write protection */ + regval |= CSCR_UBIOSCSE; + regval &= ~CSCR_BIOSWP; + PCI_Write_CFG_Reg(devbusfn, WINBOND_CSCR, regval, 1); + + /* + * Interrupt routing: + * - IDE -> IRQ 9/0 + * - INTA -> IRQ 10 + * - INTB -> IRQ 11 + * - INTC -> IRQ 14 + * - INTD -> IRQ 15 + */ + PCI_Write_CFG_Reg(devbusfn, WINBOND_IDEIRCR, 0x90, 1); + PCI_Write_CFG_Reg(devbusfn, WINBOND_PCIIRCR, 0xABEF, 2); + + /* + * Read IDE bus offsets from function 1 device. + * We must unmask the LSB indicating that ist is an IO address. + */ + devbusfn |= (1<<8); + + /* + * Switch off legacy IRQ for IDE and IDE port 1. + */ + PCI_Write_CFG_Reg(devbusfn, 0x09, 0x8F, 1); + + regval = PCI_Read_CFG_Reg(devbusfn, WINDOND_IDECSR, 4); + regval &= ~(IDECSR_LEGIRQ | IDECSR_P1EN | IDECSR_P1F16); + PCI_Write_CFG_Reg(devbusfn, WINDOND_IDECSR, regval, 4); + + bus_offset[0] = PCI_Read_CFG_Reg(devbusfn, PCI_CFG_BASE_ADDRESS_0, 4) & ~1; +#if CFG_IDE_MAXBUS > 1 + bus_offset[1] = PCI_Read_CFG_Reg(devbusfn, PCI_CFG_BASE_ADDRESS_2, 4) & ~1; +#endif + + /* + * Enable function 1, IDE -> busmastering and IO space access + */ + regval = PCI_Read_CFG_Reg(devbusfn, PCI_CFG_COMMAND, 2); + regval |= PCI_CMD_MASTER | PCI_CMD_IOEN; + PCI_Write_CFG_Reg(devbusfn, PCI_CFG_COMMAND, regval, 2); + + /* + * Initialise ISA interrupt controller + */ + initialise_pic(); + + /* + * Initialise DMA controller + */ + initialise_dma(); +} + +void initialise_pic(void) +{ + out8(W83C553F_PIC1_ICW1, 0x11); + out8(W83C553F_PIC1_ICW2, 0x08); + out8(W83C553F_PIC1_ICW3, 0x04); + out8(W83C553F_PIC1_ICW4, 0x01); + out8(W83C553F_PIC1_OCW1, 0xfb); + out8(W83C553F_PIC1_ELC, 0x20); + + out8(W83C553F_PIC2_ICW1, 0x11); + out8(W83C553F_PIC2_ICW2, 0x08); + out8(W83C553F_PIC2_ICW3, 0x02); + out8(W83C553F_PIC2_ICW4, 0x01); + out8(W83C553F_PIC2_OCW1, 0xff); + out8(W83C553F_PIC2_ELC, 0xce); + + out8(W83C553F_TMR1_CMOD, 0x74); + + out8(W83C553F_PIC2_OCW1, 0x20); + out8(W83C553F_PIC1_OCW1, 0x20); + + out8(W83C553F_PIC2_OCW1, 0x2b); + out8(W83C553F_PIC1_OCW1, 0x2b); +} + +void initialise_dma(void) +{ + unsigned int channel; + unsigned int rvalue1, rvalue2; + + /* perform a H/W reset of the devices */ + + out8(W83C553F_DMA1 + W83C553F_DMA1_MC, 0x00); + out16(W83C553F_DMA2 + W83C553F_DMA2_MC, 0x0000); + + /* initialise all channels to a sane state */ + + for (channel = 0; channel < 4; channel++) { + /* + * dependent upon the channel, setup the specifics: + * + * demand + * address-increment + * autoinitialize-disable + * verify-transfer + */ + + switch (channel) { + case 0: + rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH0SEL|W83C553F_MODE_TT_VERIFY); + rvalue2 = (W83C553F_MODE_TM_CASCADE|W83C553F_MODE_CH0SEL); + break; + case 1: + rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY); + rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY); + break; + case 2: + rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY); + rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY); + break; + case 3: + rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY); + rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY); + break; + default: + rvalue1 = 0x00; + rvalue2 = 0x00; + break; + } + + /* write to write mode registers */ + + out8(W83C553F_DMA1 + W83C553F_DMA1_WM, rvalue1 & 0xFF); + out16(W83C553F_DMA2 + W83C553F_DMA2_WM, rvalue2 & 0x00FF); + } + + /* enable all channels */ + + out8(W83C553F_DMA1 + W83C553F_DMA1_CM, 0x00); + out16(W83C553F_DMA2 + W83C553F_DMA2_CM, 0x0000); + /* + * initialize the global DMA configuration + * + * DACK# active low + * DREQ active high + * fixed priority + * channel group enable + */ + + out8(W83C553F_DMA1 + W83C553F_DMA1_CS, 0x00); + out16(W83C553F_DMA2 + W83C553F_DMA2_CS, 0x0000); +} + diff --git a/common/board.c b/common/board.c index cf155a7..44ce94b 100644 --- a/common/board.c +++ b/common/board.c @@ -48,6 +48,9 @@ #include #endif #include +#if defined(CONFIG_BAB750) +#include +#endif #undef DEBUG @@ -590,6 +593,18 @@ void board_init_r (bd_t *bd, ulong dest_addr) icache_enable(); /* it's time to enable the instruction cache */ #endif +#if defined(CONFIG_BAB750) + /* + * Do pci configuration on BAB 750 _before_ the flash + * is initialised, because we need the ISA bridge there. + */ + pci_init(bd); + /* + * Initialise the ISA bridge + */ + initialise_w83c553f(); +#endif + asm ("sync ; isync"); /* @@ -654,7 +669,7 @@ void board_init_r (bd_t *bd, ulong dest_addr) watchdog_reset (); #endif /* CONFIG_WATCHDOG */ -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) && !defined(CONFIG_BAB750) /* * Do pci configuration */ diff --git a/common/cmd_ide.c b/common/cmd_ide.c index 2bd30c2..0c4c014 100644 --- a/common/cmd_ide.c +++ b/common/cmd_ide.c @@ -98,8 +98,10 @@ static int curr_device = -1; /* Current offset for IDE0 / IDE1 bus access */ static ulong bus_offset[CFG_IDE_MAXBUS] = { +#if defined(CFG_ATA_IDE0_OFFSET) CFG_ATA_IDE0_OFFSET, -#if CFG_IDE_MAXBUS > 1 +#endif +#if defined(CFG_ATA_IDE1_OFFSET) && (CFG_IDE_MAXBUS > 1) CFG_ATA_IDE1_OFFSET, #endif }; diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 7279ead..de2aabd 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -2,6 +2,9 @@ * (C) Copyright 2000 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * See file CREDITS for list of people who contributed to this * project. * @@ -24,6 +27,23 @@ /* * Support for persistent environment data */ + +/* + * 09-18-2001 Andreas Heppel, Sysgo RTS GmbH + * + * It might not be possible in all cases to use 'memcpy()' to copy + * the environment to NVRAM, as the NVRAM might not be mapped into + * the memory space. (I.e. this is the case for the BAB750). In those + * cases it might be possible to access the NVRAM using a different + * method. For example, the RTC on the BAB750 is accessible in IO + * space using its address and data registers. To enable usage of + * NVRAM in those cases I invented the functions 'nvram_read()' and + * 'nvram_write()', which will be activated upon the configuration + * #define CFG_NVRAM_ACCESS_ROUTINE. Note, that those functions are + * strongly dependent on the used HW, and must be redefined for each + * board that wants to use them. + */ + #include #include #include @@ -90,8 +110,18 @@ typedef struct environment_s { /*--- NVRAM ----------------------------------------------------------*/ #ifdef CFG_ENV_IS_IN_NVRAM /* Environment is in NVRAM */ +#ifdef CFG_NVRAM_ACCESS_ROUTINE + +static env_t *env_ptr = NULL; +void *nvram_read(void *dest, const short src, size_t count); +void nvram_write(short dest, const void *src, size_t count); + +#else + static env_t *env_ptr = (env_t *)CFG_ENV_ADDR; +#endif + /*--- EEPROM ----------------------------------------------------------*/ #elif defined(CFG_ENV_IS_IN_EEPROM) /* Environment is in EEPROM */ static env_t *env_ptr = NULL; @@ -204,6 +234,9 @@ static int envmatch (uchar *, int); #ifdef CFG_ENV_IS_IN_EEPROM static uchar get_env_char_eeprom(int); #endif +#if defined(CFG_ENV_IS_IN_NVRAM) && defined(CFG_NVRAM_ACCESS_ROUTINE) +static uchar get_env_char_nvram(int); +#endif static uchar get_env_char_memory(int); static uchar *get_env_addr_memory(int); @@ -211,6 +244,8 @@ static uchar *get_env_addr_memory(int); static uchar (*get_env_char)(int) = #ifdef CFG_ENV_IS_IN_EEPROM get_env_char_eeprom; +#elif defined(CFG_ENV_IS_IN_NVRAM) && defined(CFG_NVRAM_ACCESS_ROUTINE) + get_env_char_nvram; #else get_env_char_memory; #endif @@ -275,6 +310,11 @@ void env_relocate (ulong offset) eeprom_read (CFG_ENV_OFFSET+offsetof(env_t,data), env_ptr->data, ENV_SIZE); +#elif defined(CFG_ENV_IS_IN_NVRAM) && defined(CFG_NVRAM_ACCESS_ROUTINE) + DEBUGF ("%s[%d] read ENV from NVRAM\n", __FUNCTION__,__LINE__); + nvram_read(env_ptr->data, + CFG_ENV_ADDR + sizeof(long), + ENV_SIZE); # else DEBUGF ("%s[%d] read ENV from NVRAM/FLASH\n",__FUNCTION__,__LINE__); memcpy (env_ptr->data, @@ -314,6 +354,22 @@ static uchar *get_env_addr_memory(int index) } } +#if defined(CFG_ENV_IS_IN_NVRAM) && defined(CFG_NVRAM_ACCESS_ROUTINE) +static uchar get_env_char_nvram(int index) +{ + uchar c; + init_data_t *idata = (init_data_t*)(CFG_INIT_RAM_ADDR+CFG_INIT_DATA_OFFSET); + + /* if the NVRAM crc was bad, use the default environment */ + if (idata->env_valid) + nvram_read(&c, CFG_ENV_ADDR+index, 1); + else + c = default_environment[index]; + + return c; +} +#endif + #ifdef CFG_ENV_IS_IN_EEPROM /* * Utility function when we have to read from serial device @@ -763,8 +819,14 @@ int do_saveenv (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) { int rcode = 0; printf ("Saving Environment to NVRAM...\n"); + +#ifdef CFG_NVRAM_ACCESS_ROUTINE + nvram_write((short)CFG_ENV_ADDR, env_ptr, CFG_ENV_SIZE); + rcode = 0; +#else if (memcpy ((char *)CFG_ENV_ADDR, env_ptr, CFG_ENV_SIZE) == NULL) rcode = 1 ; +#endif return rcode; } @@ -856,6 +918,25 @@ int do_saveenv (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) * We are still running from ROM, so data use is limited */ #ifndef CFG_ENV_IS_IN_EEPROM + +#if defined(CFG_ENV_IS_IN_NVRAM) && defined(CFG_NVRAM_ACCESS_ROUTINE) + +void env_init(init_data_t *idata) +{ + ulong crc; + uchar data[ENV_SIZE]; + nvram_read (&crc, CFG_ENV_ADDR, sizeof(ulong)); + nvram_read (data, CFG_ENV_ADDR+sizeof(ulong), ENV_SIZE); + + if (crc32(0, data, ENV_SIZE) == crc) { + idata->env_addr = (ulong)CFG_ENV_ADDR + sizeof(long); + idata->env_valid = 1; + } else { + idata->env_addr = (ulong)&default_environment[0]; + idata->env_valid = 0; + } +} +#else void env_init(init_data_t *idata) { if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { @@ -866,6 +947,8 @@ void env_init(init_data_t *idata) idata->env_valid = 0; } } +#endif /* defined(CFG_ENV_IS_IN_NVRAM) && defined(CFG_NVRAM_ACCESS_ROUTINE) */ + #else /* CFG_ENV_IS_IN_EEPROM */ /* * Use a (moderately small) buffer on the stack diff --git a/cpu/mpc75x/Makefile b/cpu/mpc75x/Makefile new file mode 100644 index 0000000..3a174d1 --- /dev/null +++ b/cpu/mpc75x/Makefile @@ -0,0 +1,43 @@ +# +# (C) Copyright 2001 +# Josh Huber , Mission Critical Linux, Inc. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = lib$(CPU).a + +START = start.o kgdb.o +OBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o + +all: .depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) crv $@ $(OBJS) kgdb.o start.o + +######################################################################### + +.depend: Makefile $(START:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/cpu/mpc75x/config.mk b/cpu/mpc75x/config.mk new file mode 100644 index 0000000..4a669d4 --- /dev/null +++ b/cpu/mpc75x/config.mk @@ -0,0 +1,26 @@ +# +# (C) Copyright 2001 +# Josh Huber , Mission Critical Linux, Inc. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# 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 program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +PLATFORM_RELFLAGS += -mrelocatable -ffixed-r14 + +PLATFORM_CPPFLAGS += -DCONFIG_75x -ffixed-r2 -mstring diff --git a/cpu/mpc75x/cpu.c b/cpu/mpc75x/cpu.c new file mode 100644 index 0000000..731c9c4 --- /dev/null +++ b/cpu/mpc75x/cpu.c @@ -0,0 +1,129 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * cpu.c + * + * CPU specific code + * + * written or collected and sometimes rewritten by + * Magnus Damm + * + * minor modifications by + * Wolfgang Denk + * + * more minor modifications by + * Andreas Heppel + */ + +#include +#include +#include +#include + +#if !defined(CONFIG_74x) && !defined(CONFIG_75x) && !defined(CONFIG_74xx) +#error CPU undefined +#endif + +int +checkcpu(long clock) +{ + uint pvr = get_pvr(); /* processor version register */ + + switch (PVR_VER(pvr)) { + case 0x0008: + puts("PPC74x/75x "); + break; + + case 0x000c: + puts("PPC7400 "); + break; + + default: + puts("Unknown CPU -- configuration error!\n"); + return -1; + break; + } + + printf("v%d.%d at %ld / %ld MHz\n", (pvr >> 8) & 0xFF, pvr & 0xFF, clock/1000000, get_bus_freq(0)/1000000); + + return 0; +} + +/* these two functions are unimplemented currently [josh] */ + +/* ------------------------------------------------------------------------- */ +/* L1 i-cache */ + +int +checkicache(void) +{ + return 0; /* XXX */ +} + +/* ------------------------------------------------------------------------- */ +/* L1 d-cache */ + +int +checkdcache(void) +{ + return 0; /* XXX */ +} + +/* ------------------------------------------------------------------------- */ + +/* + * For the 603 the TB clock runs at 1/4 the cpu bus speed. + */ +unsigned long +get_tbclk (void) +{ + return get_bus_freq(0) / 4; +} + +/* ------------------------------------------------------------------------- */ + +/* + * The MPC7xx/74xx CPUs do not have an internal watchdog and also do not have + * any possibility to reset on check stop. If any of those features is to be + * used, there must be a board specific solution. Thus, the functions do_reset() + * and watchdog_reset() are not implemented here, but in the board's main file. + */ + +/*void +do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) +{ +} +*/ + +/* ------------------------------------------------------------------------- */ + +/*#if defined(CONFIG_WATCHDOG) +void +watchdog_reset(void) +{ +} +#endif +*/ + +/* ------------------------------------------------------------------------- */ diff --git a/cpu/mpc75x/cpu_init.c b/cpu/mpc75x/cpu_init.c new file mode 100644 index 0000000..34193cc --- /dev/null +++ b/cpu/mpc75x/cpu_init.c @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * cpu_init.c - low level cpu init + */ + +#include +#include + +/* + * Breath some life into the CPU... + * + * there's basically nothing to do here since the memory controller + * isn't on the CPU in this case. + */ + +void l2_enable(void); + +void +cpu_init_f (void) +{ +} + +/* + * initialize higher level parts of CPU like timers and L2 cache + */ +void +cpu_init_r (bd_t *bd) +{ +#if defined(CFG_L2) && (defined(CONFIG_75x) || defined(CONFIG_74xx)) + l2_enable(); +#endif +} diff --git a/cpu/mpc75x/interrupts.c b/cpu/mpc75x/interrupts.c new file mode 100644 index 0000000..33ea7a3 --- /dev/null +++ b/cpu/mpc75x/interrupts.c @@ -0,0 +1,169 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * interrupts.c - just enough support for the decrementer/timer + */ + +#include +#include +#include +#include + +/*#define DEBUG */ + +/****************************************************************************/ + +unsigned decrementer_count; /* count value for 1e6/HZ microseconds */ + +/****************************************************************************/ + +static __inline__ unsigned long +get_msr(void) +{ + unsigned long msr; + + asm volatile("mfmsr %0" : "=r" (msr) :); + return msr; +} + +static __inline__ void +set_msr(unsigned long msr) +{ + asm volatile("mtmsr %0" : : "r" (msr)); +} + +static __inline__ unsigned long +get_dec(void) +{ + unsigned long val; + + asm volatile("mfdec %0" : "=r" (val) :); + return val; +} + + +static __inline__ void +set_dec(unsigned long val) +{ + asm volatile("mtdec %0" : : "r" (val)); +} + + +void +enable_interrupts(void) +{ +/* set_msr (get_msr() | MSR_EE);*/ +} + +/* returns flag if MSR_EE was set before */ +int +disable_interrupts(void) +{ + ulong msr = get_msr(); + set_msr (msr & ~MSR_EE); + return ((msr & MSR_EE) != 0); +} + +/****************************************************************************/ + +void +interrupt_init(bd_t *bd) +{ + decrementer_count = get_tbclk() / CFG_HZ; + + set_dec (decrementer_count); + + enable_interrupts(); +} + +/****************************************************************************/ + +/* + * Handle external interrupts + */ +void +external_interrupt(struct pt_regs *regs) +{ + puts("external_interrupt (oops!)\n"); +} + +volatile ulong timestamp = 0; + +/* + * timer_interrupt - gets called when the decrementer overflows, + * with interrupts disabled. + * Trivial implementation - no need to be really accurate. + */ +void +timer_interrupt(struct pt_regs *regs) +{ + set_dec(decrementer_count); + timestamp++; +} + +/****************************************************************************/ + +void +reset_timer(void) +{ + timestamp = 0; +} + +ulong +get_timer(ulong base) +{ + return (timestamp - base); +} + +void +set_timer(ulong t) +{ + timestamp = t; +} + +/****************************************************************************/ + +/* + * Install and free a interrupt handler. + */ + +void +irq_install_handler(int vec, interrupt_handler_t *handler, void *arg) +{ + +} + +void +irq_free_handler(int vec) +{ + +} + +/****************************************************************************/ + +void +do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) +{ + puts("IRQ related functions are unimplemented currently.\n"); +} diff --git a/cpu/mpc75x/kgdb.S b/cpu/mpc75x/kgdb.S new file mode 100644 index 0000000..f3a6c03 --- /dev/null +++ b/cpu/mpc75x/kgdb.S @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2000 Murray Jensen + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307USA + */ + +/* note - this won't work with the 74xx cpus. needs more work [josh] */ + +#include +#include +#include +#include "version.h" + +#include +#include + +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + + /* + * cache flushing routines for kgdb + */ + + .globl kgdb_flush_cache_all +kgdb_flush_cache_all: + lis r3, IDC_INVALL@h + mtspr DC_CST, r3 + sync + lis r3, IDC_INVALL@h + mtspr IC_CST, r3 + SYNC + blr + + .globl kgdb_flush_cache_range +kgdb_flush_cache_range: + li r5,CFG_CACHELINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,CFG_CACHELINE_SHIFT + beqlr + mtctr r4 + mr r6,r3 +1: dcbst 0,r3 + addi r3,r3,CFG_CACHELINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + mtctr r4 +2: icbi 0,r6 + addi r6,r6,CFG_CACHELINE_SIZE + bdnz 2b + SYNC + blr + +#endif /* CFG_CMD_KGDB */ diff --git a/cpu/mpc75x/speed.c b/cpu/mpc75x/speed.c new file mode 100644 index 0000000..74f5131 --- /dev/null +++ b/cpu/mpc75x/speed.c @@ -0,0 +1,72 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +/* + * 7xx CPU specific modifications by + * Andreas Heppel + */ + + +/* Access functions for the Machine State Register */ +static __inline__ unsigned long +get_msr(void) +{ + unsigned long msr; + + asm volatile("mfmsr %0" : "=r" (msr) :); + return msr; +} + +static __inline__ void +set_msr(unsigned long msr) +{ + asm volatile("mtmsr %0" : : "r" (msr)); +} + +/* ------------------------------------------------------------------------- */ + +/* + * Measure CPU clock speed (core clock GCLK1) + * + * (Approx. GCLK frequency in Hz) + */ +short pllratio_to_factor[] = { + 00, 75, 70, 00, 20, 65, 100, 45, 30, 55, 40, 50, 80, 60, 35, 00, +}; + +ulong +get_gclk_freq (void) +{ + uint hid1 = mfspr(HID1); + + hid1 = (hid1 >> (32-4)) & 0xf; + + return (pllratio_to_factor[hid1] * get_bus_freq(0)) / 10; +} + +/* ------------------------------------------------------------------------- */ + diff --git a/cpu/mpc75x/start.S b/cpu/mpc75x/start.S new file mode 100644 index 0000000..e8ef5cc --- /dev/null +++ b/cpu/mpc75x/start.S @@ -0,0 +1,929 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000 Wolfgang Denk + * Copyright (C) 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* ppcboot - Startup Code for PowerPC based Embedded Boards + * + * + * The processor starts at 0xfff00100 and the code is executed + * from flash. The code is organized to be at an other address + * in memory, but as long we don't jump around before relocating. + * board_init lies at a quite high address and when the cpu has + * jumped there, everything is ok. + */ + +/* Although this file was originally dvelopped for the MPC750 CPU, + * it should be possible to use it for MPC740/MPC7400 CPUs as well + * since there are anly small differences in the basic operation. + * However, the code has been tested with an MPC750 CPU only. + */ + +#include +#include +#include "version.h" + +#include +#include + +#include +#include + +#ifndef CONFIG_IDENT_STRING +#define CONFIG_IDENT_STRING "" +#endif + +/* We don't want the MMU yet. +*/ +#undef MSR_KERNEL +/* Machine Check and Recoverable Interr. */ +#define MSR_KERNEL ( MSR_ME | MSR_RI ) + + +/* + * Set up GOT: Global Offset Table + * + * Use r14 to access the GOT + */ + START_GOT + GOT_ENTRY(_GOT2_TABLE_) + GOT_ENTRY(_FIXUP_TABLE_) + + GOT_ENTRY(_start) + GOT_ENTRY(_start_of_vectors) + GOT_ENTRY(_end_of_vectors) + GOT_ENTRY(transfer_to_handler) + + GOT_ENTRY(MessageBlock) +/* GOT_ENTRY(spdRead)*/ + GOT_ENTRY(_end) + GOT_ENTRY(.bss) + END_GOT + +/* + * r3 - 1st arg to board_init(): IMMP pointer + * r4 - 2nd arg to board_init(): boot flag + */ + .text + .long 0x27051956 /* PPCBOOT Magic Number */ + + .globl version_string +version_string: + .ascii PPCBOOT_VERSION + .ascii " (", __DATE__, " - ", __TIME__, ")" + .ascii CONFIG_IDENT_STRING, "\0" + + . = EXC_OFF_SYS_RESET + .globl _start +_start: + li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH */ + b boot_cold + + . = EXC_OFF_SYS_RESET + 0x10 + + .globl _start_warm +_start_warm: + li r21, BOOTFLAG_WARM /* Software reboot */ + b boot_warm + + /* the boot code is located below the exception table */ + + .globl _start_of_vectors +_start_of_vectors: + +/* Machine check */ + STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data Storage exception. "Never" generated on the 860. */ + STD_EXCEPTION(0x300, DataStorage, UnknownException) + +/* Instruction Storage exception. "Never" generated on the 860. */ + STD_EXCEPTION(0x400, InstStorage, UnknownException) + +/* External Interrupt exception. */ + STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt) + +/* Alignment exception. */ + . = 0x600 +Alignment: + EXCEPTION_PROLOG + mfspr r4,DAR + stw r4,_DAR(r21) + mfspr r5,DSISR + stw r5,_DSISR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + lwz r6,GOT(transfer_to_handler) + mtlr r6 + blrl +.L_Alignment: + .long AlignmentException - _start + EXC_OFF_SYS_RESET + .long int_return - _start + EXC_OFF_SYS_RESET + +/* Program check exception */ + . = 0x700 +ProgramCheck: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + lwz r6,GOT(transfer_to_handler) + mtlr r6 + blrl +.L_ProgramCheck: + .long ProgramCheckException - _start + EXC_OFF_SYS_RESET + .long int_return - _start + EXC_OFF_SYS_RESET + + /* No FPU on MPC8xx. This exception is not supposed to happen. + */ + STD_EXCEPTION(0x800, FPUnavailable, UnknownException) + + /* I guess we could implement decrementer, and may have + * to someday for timekeeping. + */ + STD_EXCEPTION(0x900, Decrementer, timer_interrupt) + STD_EXCEPTION(0xa00, Trap_0a, UnknownException) + STD_EXCEPTION(0xb00, Trap_0b, UnknownException) + + STD_EXCEPTION(0xc00, SystemCall, UnknownException) + STD_EXCEPTION(0xd00, SingleStep, UnknownException) + + STD_EXCEPTION(0xe00, Trap_0e, UnknownException) + STD_EXCEPTION(0xf00, Trap_0f, UnknownException) + + /* On the MPC8xx, this is a software emulation interrupt. It occurs + * for all unimplemented and illegal instructions. + */ + STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException) + + STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException) + STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException) + STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException) + STD_EXCEPTION(0x1400, DataTLBError, UnknownException) + + STD_EXCEPTION(0x1500, Reserved5, UnknownException) + STD_EXCEPTION(0x1600, Reserved6, UnknownException) + STD_EXCEPTION(0x1700, Reserved7, UnknownException) + STD_EXCEPTION(0x1800, Reserved8, UnknownException) + STD_EXCEPTION(0x1900, Reserved9, UnknownException) + STD_EXCEPTION(0x1a00, ReservedA, UnknownException) + STD_EXCEPTION(0x1b00, ReservedB, UnknownException) + + STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException) + STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException) + STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException) + STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException) + + /* PPC documentation says that the vector table ends at 0x3000 */ + .globl _end_of_vectors +_end_of_vectors: + + . = 0x3000 + +boot_cold: +boot_warm: + /* disable everything */ + li r0, 0 + + /* hardware imlementation register */ + mtspr HID0, r0 + sync + mtmsr 0 + + /* invalidate BATs */ + mtspr IBAT0U, r0 + mtspr IBAT1U, r0 + mtspr IBAT2U, r0 + mtspr IBAT3U, r0 + isync + mtspr DBAT0U, r0 + mtspr DBAT1U, r0 + mtspr DBAT2U, r0 + mtspr DBAT3U, r0 + isync + + /* Turn off data and instruction cache control bits */ + mfspr r3, HID0 + isync + rlwinm r4, r3, 0, 18, 15 + sync + isync + mtspr HID0, r4 + isync + + /* invalidate the MPU's data/instruction caches */ + ori r3, r3, 0xCC00 + or r4, r4, r3 + isync + mtspr HID0, r4 + andc r4, r4, r3 + isync + mtspr HID0, r4 + isync + + ori r4, r4, 0x8800 + + /* + * The setting of the instruction cache enable (ICE) bit must be + * preceded by an isync instruction to prevent the cache from being + * enabled or disabled while an instruction access is in progress. + */ + isync + + mtspr HID0, r4 + isync + +#if defined(CFG_L2) && (defined(CONFIG_75x) || defined(CONFIG_74xx)) + /* init the L2 cache */ + addis r3, r0, L2_INIT@h + ori r3, r3, L2_INIT@l + mtspr l2cr, r3 + + /* invalidate the L2 cache */ + sync + oris r3, r3, L2CR_L2I@h + mtspr l2cr, r3 + sync + +invl2: + mfspr r3, l2cr + andi. r3, r3, L2CR_L2IP + bne invl2 + + /* turn off the global invalidate bit */ + mfspr r3, l2cr + rlwinm r3, r3, 0, 11, 9 + mtspr l2cr, r3 +#endif + + /* setup the bats */ + bl setup_bats + sync + +#if CFG_MMU + /*enable address translation */ + bl enable_addr_trans + sync +#endif + + /* + * Calculate absolute address in FLASH and jump there + *------------------------------------------------------*/ + lis r3, CFG_MONITOR_BASE@h + ori r3, r3, CFG_MONITOR_BASE@l + addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET + mtlr r3 + blr + +in_flash: + /* let the C-code set up the rest */ + /* */ + /* Be careful to keep code relocatable ! */ + /*------------------------------------------------------*/ + + GET_GOT /* initialize GOT access */ + + /* + * Change the address map if this is configured + */ + bl set_address_map + + /* + * Since the 7xx/7xxx CPUs do not have any RAM on chip + * we cannot wait to initialise the RAM during board_init_f. + * We need some RAM before we can run C code. + */ + bl ram_init + + /* set up r1 (SP) */ + lis r1,CFG_INIT_RAM_ADDR@h + ori r1,r1,CFG_INIT_SP_OFFSET /* set up the stack in SDRAM */ + stwu r1, -8(r1) /* make room for stack frame header */ + + /* run low-level CPU init code (from Flash) */ + bl cpu_init_f + + /* r3: BOOTFLAG */ + mr r3, r21 + /* run 1st part of board init code (from Flash) */ + bl board_init_f + + /* NOTREACHED */ + + /* setup_bats - set them up to some initial state */ + .globl setup_bats +setup_bats: + + /* + * We need the bats only, if we use the MMU, otherwise they may remain + * invalidated + */ +#ifdef CFG_MMU + addis r0, r0, 0x0000 + + /* IBAT 0 */ + addis r4, r0, CFG_IBAT0L@h + ori r4, r4, CFG_IBAT0L@l + addis r3, r0, CFG_IBAT0U@h + ori r3, r3, CFG_IBAT0U@l + mtspr IBAT0L, r4 + mtspr IBAT0U, r3 + isync + + /* DBAT 0 */ + addis r4, r0, CFG_DBAT0L@h + ori r4, r4, CFG_DBAT0L@l + addis r3, r0, CFG_DBAT0U@h + ori r3, r3, CFG_DBAT0U@l + mtspr DBAT0L, r4 + mtspr DBAT0U, r3 + isync + + /* IBAT 1 */ + addis r4, r0, CFG_IBAT1L@h + ori r4, r4, CFG_IBAT1L@l + addis r3, r0, CFG_IBAT1U@h + ori r3, r3, CFG_IBAT1U@l + mtspr IBAT1L, r4 + mtspr IBAT1U, r3 + isync + + /* DBAT 1 */ + addis r4, r0, CFG_DBAT1L@h + ori r4, r4, CFG_DBAT1L@l + addis r3, r0, CFG_DBAT1U@h + ori r3, r3, CFG_DBAT1U@l + mtspr DBAT1L, r4 + mtspr DBAT1U, r3 + isync + + /* IBAT 2 */ + addis r4, r0, CFG_IBAT2L@h + ori r4, r4, CFG_IBAT2L@l + addis r3, r0, CFG_IBAT2U@h + ori r3, r3, CFG_IBAT2U@l + mtspr IBAT2L, r4 + mtspr IBAT2U, r3 + isync + + /* DBAT 2 */ + addis r4, r0, CFG_DBAT2L@h + ori r4, r4, CFG_DBAT2L@l + addis r3, r0, CFG_DBAT2U@h + ori r3, r3, CFG_DBAT2U@l + mtspr DBAT2L, r4 + mtspr DBAT2U, r3 + isync + + /* IBAT 3 */ + addis r4, r0, CFG_IBAT3L@h + ori r4, r4, CFG_IBAT3L@l + addis r3, r0, CFG_IBAT3U@h + ori r3, r3, CFG_IBAT3U@l + mtspr IBAT3L, r4 + mtspr IBAT3U, r3 + isync + + /* DBAT 3 */ + addis r4, r0, CFG_DBAT3L@h + ori r4, r4, CFG_DBAT3L@l + addis r3, r0, CFG_DBAT3U@h + ori r3, r3, CFG_DBAT3U@l + mtspr DBAT3L, r4 + mtspr DBAT3U, r3 + isync +#endif + + /* now invalidate the TLBs */ + addis r3, 0, 0x0000 +#ifdef CONFIG_74x + addis r5, 0, 0x2 /* upper bound of 0x00020000 for 740 (603e) */ +#endif +#if defined(CONFIG_75x) || defined(CONFIG_74xx) + addis r5, 0, 0x4 /* upper bound of 0x00040000 for 750/7400 */ +#endif + isync + +tlblp: + tlbie r3 + sync + addi r3, r3, 0x1000 + cmp 0, 0, r3, r5 + blt tlblp + + blr + + .globl enable_addr_trans +enable_addr_trans: + /* enable address translation */ + mfmsr r5 + ori r5, r5, (MSR_IR | MSR_DR) + mtmsr r5 + isync + blr + + .globl disable_addr_trans +disable_addr_trans: + /* disable address translation */ + mfmsr r5 + andi. r5, r5, (~(MSR_IR | MSR_DR) & 0xFFFF) + mtmsr r5 + isync + blr + + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception. + * Register r21 is pointer into trap frame, r1 has new stack pointer. + */ + .globl transfer_to_handler +transfer_to_handler: + stw r22,_NIP(r21) + lis r22,MSR_POW@h + andc r23,r23,r22 + stw r23,_MSR(r21) + SAVE_GPR(7, r21) + SAVE_4GPRS(8, r21) + SAVE_8GPRS(12, r21) + SAVE_8GPRS(24, r21) + mflr r23 + andi. r24,r23,0x3f00 /* get vector offset */ + stw r24,TRAP(r21) + li r22,0 + stw r22,RESULT(r21) + mtspr SPRG2,r22 /* r1 is now kernel sp */ + lwz r24,0(r23) /* virtual address of handler */ + lwz r23,4(r23) /* where to go when done */ + mtspr SRR0,r24 + mtspr SRR1,r20 + mtlr r23 + SYNC + rfi /* jump to handler, enable MMU */ + +int_return: + mfmsr r29 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r29,r29,r4 + SYNC /* Some chip revs need this... */ + mtmsr r29 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +/* Cache functions. XXX fix these, I think they're broken [josh]. +*/ + .globl icache_enable +icache_enable: + mfspr r3, HID0 + ori r3, r3, (HID0_ICE | HID0_ICFI) + isync + mtspr HID0, r3 + blr + + .globl icache_disable +icache_disable: + mfspr r3, HID0 + li r4, 0 + ori r4, r4, HID0_ICE + andc r3, r3, r4 + isync + mtspr HID0, r3 + blr + + .globl icache_status +icache_status: + mfspr r3, HID0 + andi. r3, r3, HID0_ICE + blr + + .globl dcache_enable +dcache_enable: + mfspr r3, HID0 + ori r3, r3, (HID0_DCI | HID0_DCE) + sync + mtspr HID0, r3 + blr + + .globl dcache_disable +dcache_disable: + mfspr r3, HID0 + li r4, HID0_DCE + andc r3, r3, r4 + sync + mtspr HID0, r3 + blr + + .globl dcache_status +dcache_status: + mfspr r3, HID0 + andi. r3, r3, HID0_DCE + blr + + .globl l2_enable +l2_enable: + addis r3, r0, L2_ENABLE@h + ori r3, r3, L2_ENABLE@l + mtspr l2cr, r3 + blr + + .globl dc_read +dc_read: + blr + + .globl get_pvr +get_pvr: + mfspr r3, PVR + blr + +/*-----------------------------------------------------------------------*/ + +/* + * void relocate_code (addr_sp, bd, addr_moni) + * + * This "function" does not return, instead it continues in RAM + * after relocating the monitor code. + * + * r3 = dest + * r4 = src + * r5 = length in bytes + * r6 = cachelinesize + */ + .globl relocate_code +relocate_code: + mr r1, r3 /* Set new stack pointer */ + mr r9, r4 /* Save copy of Board Info pointer */ + mr r10, r5 /* Save copy of Destination Address */ + + mr r3, r5 /* Destination Address */ + lis r4, CFG_MONITOR_BASE@h /* Source Address */ + ori r4, r4, CFG_MONITOR_BASE@l + lis r5, CFG_MONITOR_LEN@h /* Length in Bytes */ + ori r5, r5, CFG_MONITOR_LEN@l + li r6, CFG_CACHELINE_SIZE /* Cache Line Size */ + + /* + * Fix GOT pointer: + * + * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address + * + * Offset: + */ + sub r15, r10, r4 /* dest addr - moni base */ + + /* First our own GOT */ + add r14, r14, r15 + /* then the one used by the C code */ + add r30, r30, r15 + + /* + * Now relocate code + */ + + cmplw cr1,r3,r4 /* cmp dest addr /w src addr */ + addi r0,r5,3 + srwi. r0,r0,2 + beq cr1,4f /* In place copy is not necessary */ + beq 7f /* Protect against 0 count */ + mtctr r0 /* ctr contains now moni len in DWORDS */ + bge cr1,2f + + la r8,-4(r4) + la r7,-4(r3) +1: lwzu r0,4(r8) + stwu r0,4(r7) + bdnz 1b + b 4f + +2: slwi r0,r0,2 + add r8,r4,r0 + add r7,r3,r0 +3: lwzu r0,-4(r8) + stwu r0,-4(r7) + bdnz 3b + +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4: + cmpwi r6,0 + add r5,r3,r5 + beq 7f /* Always flush prefetch queue in any case */ + subi r0,r6,1 + andc r3,r3,r0 + mr r4,r3 +5: cmplw r4,r5 + dcbst 0,r4 + add r4,r4,r6 + blt 5b + sync /* Wait for all dcbst to complete on bus */ + mr r4,r3 +6: cmplw r4,r5 + icbi 0,r4 + add r4,r4,r6 + blt 6b + +7: + sync /* Wait for all icbi to complete on bus */ + isync + +/* + * We are done. Do not return, instead branch to second part of board + * initialization, now running from RAM. + */ + addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET + mtlr r0 + blr + +in_ram: + /* + * Relocation Function, r14 point to got2+0x8000 + * + * Adjust got2 pointers, no need to check for 0, this code + * already puts a few entries in the table. + */ + li r0,__got2_entries@sectoff@l + la r3,GOT(_GOT2_TABLE_) + lwz r11,GOT(_GOT2_TABLE_) + mtctr r0 + sub r11,r3,r11 + addi r3,r3,-4 +1: lwzu r0,4(r3) + add r0,r0,r11 + stw r0,0(r3) + bdnz 1b + + /* + * Now adjust the fixups and the pointers to the fixups + * in case we need to move ourselves again. + */ +2: li r0,__fixup_entries@sectoff@l + lwz r3,GOT(_FIXUP_TABLE_) + cmpwi r0,0 + mtctr r0 + addi r3,r3,-4 + beq 4f +3: lwzu r4,4(r3) + lwzux r0,r4,r11 + add r0,r0,r11 + stw r10,0(r3) + stw r0,0(r4) + bdnz 3b +4: +clear_bss: + /* + * Now clear BSS segment + */ + lwz r3,GOT(.bss) + lwz r4,GOT(_end) + + cmplw 0, r3, r4 + beq 6f + + li r0, 0 +5: + stw r0, 0(r3) + addi r3, r3, 4 + cmplw 0, r3, r4 + bne 5b +6: + mr r3, r9 /* Board Info pointer */ + mr r4, r10 /* Destination Address */ + + bl board_init_r + + /* Problems accessing "end" in C, so do it here */ + .globl get_endaddr +get_endaddr: + lwz r3,GOT(_end) + blr + + .globl get_startaddr +get_startaddr: + lwz r3,GOT(_start) + blr + + .globl get_msgblk +get_msgblk: + lwz r3,GOT(MessageBlock) + blr + +/* .globl get_spdread +get_spdread: + lwz r3,GOT(spdRead) + blr + +*/ + /* + * Copy exception vector code to low memory + * + * r3: dest_addr + * r7: source address, r8: end address, r9: target address + */ + .globl trap_init +trap_init: + lwz r7, GOT(_start) + lwz r8, GOT(_end_of_vectors) + + rlwinm r9, r7, 0, 18, 31 /* _start & 0x3FFF */ + + cmplw 0, r7, r8 + bgelr /* return if r7>=r8 - just in case */ + + mflr r4 /* save link register */ +1: + lwz r0, 0(r7) + stw r0, 0(r9) + addi r7, r7, 4 + addi r9, r9, 4 + cmplw 0, r7, r8 + bne 1b + + /* + * relocate `hdlr' and `int_return' entries + */ + li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET + li r8, Alignment - _start + EXC_OFF_SYS_RESET +2: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 2b + + li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET + li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET +3: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 3b + + mtlr r4 /* restore link register */ + blr + + /* + * Function: relocate entries for one exception vector + */ +trap_reloc: + lwz r0, 0(r7) /* hdlr ... */ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 0(r7) + + lwz r0, 4(r7) /* int_return ... */ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 4(r7) + + sync + isync + + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: in8 */ +/* Description: Input 8 bits */ +/* ------------------------------------------------------------------------------- */ + .globl in8 +in8: + lbz r3,0(r3) + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: in16 */ +/* Description: Input 16 bits */ +/* ------------------------------------------------------------------------------- */ + .globl in16 +in16: + lhz r3,0(r3) + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: in16r */ +/* Description: Input 16 bits and byte reverse */ +/* ------------------------------------------------------------------------------- */ + .globl in16r +in16r: + lhbrx r3,0,r3 + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: in32 */ +/* Description: Input 32 bits */ +/* ------------------------------------------------------------------------------- */ + .globl in32 +in32: + lwz 3,0(3) + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: in32r */ +/* Description: Input 32 bits and byte reverse */ +/* ------------------------------------------------------------------------------- */ + .globl in32r +in32r: + lwbrx r3,0,r3 + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: out8 */ +/* Description: Output 8 bits */ +/* ------------------------------------------------------------------------------- */ + .globl out8 +out8: + stb r4,0(r3) + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: out16 */ +/* Description: Output 16 bits */ +/* ------------------------------------------------------------------------------- */ + .globl out16 +out16: + sth r4,0(r3) + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: out16r */ +/* Description: Byte reverse and output 16 bits */ +/* ------------------------------------------------------------------------------- */ + .globl out16r +out16r: + sthbrx r4,0,r3 + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: out32 */ +/* Description: Output 32 bits */ +/* ------------------------------------------------------------------------------- */ + .globl out32 +out32: + stw r4,0(r3) + sync + blr + +/* ------------------------------------------------------------------------------- */ +/* Function: out32r */ +/* Description: Byte reverse and output 32 bits */ +/* ------------------------------------------------------------------------------- */ + .globl out32r +out32r: + stwbrx r4,0,r3 + sync + blr + diff --git a/cpu/mpc75x/traps.c b/cpu/mpc75x/traps.c new file mode 100644 index 0000000..1890d61 --- /dev/null +++ b/cpu/mpc75x/traps.c @@ -0,0 +1,234 @@ +/* + * linux/arch/ppc/kernel/traps.c + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +int (*debugger_exception_handler)(struct pt_regs *) = 0; +#endif + +/* Returns 0 if exception not found and fixup otherwise. */ +extern unsigned long search_exception_table(unsigned long); + +/* THIS NEEDS CHANGING to use the board info structure. +*/ +#define END_OF_MEM 0x02000000 + +/* + * Trap & Exception support + */ + +void +print_backtrace(unsigned long *sp) +{ + int cnt = 0; + unsigned long i; + + printf("Call backtrace: "); + while (sp) { + if ((uint)sp > END_OF_MEM) + break; + + i = sp[1]; + if (cnt++ % 7 == 0) + printf("\n"); + printf("%08lX ", i); + if (cnt > 32) break; + sp = (unsigned long *)*sp; + } + printf("\n"); +} + +void +show_regs(struct pt_regs * regs) +{ + int i; + + printf("NIP: %08lX XER: %08lX LR: %08lX REGS:" + " %p TRAP: %04lx DAR: %08lX\n", + regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); + printf("MSR: %08lx EE: %01x PR: %01x FP:" + " %01x ME: %01x IR/DR: %01x%01x\n", + regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, + regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, + regs->msr&MSR_IR ? 1 : 0, + regs->msr&MSR_DR ? 1 : 0); + + printf("\n"); + for (i = 0; i < 32; i++) { + if ((i % 8) == 0) + { + printf("GPR%02d: ", i); + } + + printf("%08lX ", regs->gpr[i]); + if ((i % 8) == 7) + { + printf("\n"); + } + } +} + + +void +_exception(int signr, struct pt_regs *regs) +{ + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Exception in kernel pc %lx signal %d",regs->nip,signr); +} + +void +MachineCheckException(struct pt_regs *regs) +{ + unsigned long fixup; + + /* Probing PCI using config cycles cause this exception + * when a device is not present. Catch it and return to + * the PCI exception handler. + */ + if ((fixup = search_exception_table(regs->nip)) != 0) { + regs->nip = fixup; + return; + } + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + printf("Machine check in kernel mode.\n"); + printf("Caused by (from msr): "); + printf("regs %p ",regs); + switch( regs->msr & 0x0000F000) + { + case (1<<12) : + printf("Machine check signal - probably due to mm fault\n" + "with mmu off\n"); + break; + case (1<<13) : + printf("Transfer error ack signal\n"); + break; + case (1<<14) : + printf("Data parity signal\n"); + break; + case (1<<15) : + printf("Address parity signal\n"); + break; + default: + printf("Unknown values in msr\n"); + } + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("machine check"); +} + +void +AlignmentException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Alignment Exception"); +} + +void +ProgramCheckException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Program Check Exception"); +} + +void +SoftEmuException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("Software Emulation Exception"); +} + + +void +UnknownException(struct pt_regs *regs) +{ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", + regs->nip, regs->msr, regs->trap); + _exception(0, regs); +} + +/* Probe an address by reading. If not present, return -1, otherwise + * return 0. + */ +int +addr_probe(uint *addr) +{ +#if 0 + int retval; + + __asm__ __volatile__( \ + "1: lwz %0,0(%1)\n" \ + " eieio\n" \ + " li %0,0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,-1\n" \ + " b 2b\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 2\n" \ + " .long 1b,3b\n" \ + ".text" \ + : "=r" (retval) : "r"(addr)); + + return (retval); +#endif + return 0; +} diff --git a/include/config_BAB750.h b/include/config_BAB750.h new file mode 100644 index 0000000..0699d28 --- /dev/null +++ b/include/config_BAB750.h @@ -0,0 +1,378 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * board/config.h - configuration options, board specific + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include + +/*#define DEBUG 1*/ +/* + * High Level Configuration Options + * (easy to change) + */ + +/* these hardware addresses are pretty bogus, please change them to + suit your needs */ + +/* first ethernet */ +#define CONFIG_ETHADDR 00:00:5B:00:6E:8A + +#define CONFIG_IPADDR 172.22.2.112 +#define CONFIG_SERVERIP 172.22.2.111 + +#define CONFIG_ENV_OVERWRITE + +#if 0 + +#define CFG_ENV_IS_IN_FLASH 1 /* use Flash for environment vars */ +#define CFG_ENV_OFFSET 0x70000 /* Last sector of AMD29F040 flash */ +#define CFG_ENV_SECT_SIZE 0x10000 /* Total Size of Environment Sector (64kB) */ + +#else + +#define CFG_ENV_IS_IN_NVRAM 1 /* use NVRAM for environment vars */ +#define CFG_NVRAM_SIZE (8*1024-16) /* NVRAM size (8kB), we must protect the clock data (16 bytes) */ +#define CFG_ENV_SIZE 0x400 /* Size of Environment vars (1kB)*/ +/* + * We store the environment in the upper part of the NVRAM. Thus, + * user applications can use the remaining space for other purposes. + */ +#define CFG_ENV_ADDR (CFG_NVRAM_SIZE-CFG_ENV_SIZE) +#define CFG_NVRAM_ACCESS_ROUTINE 1 /* This board needs a special routine to access the NVRAM */ + +#endif + +#define CONFIG_75x 1 /* This is a MPC75x */ +#define CONFIG_BAB750 1 /* ...on an BAB750 board */ + +#define CONFIG_BAUDRATE 115200 /* console baudrate = 115kbps */ + +#undef CONFIG_WATCHDOG + +/* to change the default ethernet port, use this define (options: 0, 1, 2) */ +#define CONFIG_ETHER_PORT 0 + +#if 1 +#define CONFIG_BOOTDELAY -1 /* autoboot disabled */ +#else +#define CONFIG_BOOTDELAY 5 /* autoboot after 5 seconds */ +#endif +#define CONFIG_ZERO_BOOTDELAY_CHECK + +#undef CONFIG_BOOTARGS + +#define CONFIG_BOOTCOMMAND \ + "bootp 1000000; " \ + "setenv bootargs root=/dev/nfs rw nfsroot=$(serverip):$(rootpath) " \ + "ip=$(ipaddr):$(serverip):$(gatewayip):" \ + "$(netmask):$(hostname):eth0:none; "\ + "bootm" + +#define CONFIG_LOADS_ECHO 0 /* echo off for serial download */ +#define CFG_LOADS_BAUD_CHANGE /* allow baudrate changes */ + +#define CONFIG_BOOTP_MASK (CONFIG_BOOTP_DEFAULT | \ + CONFIG_BOOTP_BOOTFILESIZE) + +#define CONFIG_COMMANDS (CONFIG_CMD_DFL | CFG_CMD_PCI | CFG_CMD_SCSI | CFG_CMD_IDE | CFG_CMD_DATE | CFG_CMD_FDC) + +/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ +#include + +/* + * Miscellaneous configurable options + */ +#define CFG_LONGHELP /* undef to save memory */ +#define CFG_PROMPT "=> " /* Monitor Command Prompt */ + +/* + * choose between COM1 and COM2 as serial console + */ +#define CONFIG_CONS_INDEX 1 + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#define CFG_CBSIZE 1024 /* Console I/O Buffer Size */ +#else +#define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +#endif +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */ +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ + +#define CFG_MEMTEST_START 0x00000000 /* memtest works on */ +#define CFG_MEMTEST_END 0x04000000 /* 0 ... 64 MB in DRAM */ + +#define CFG_LOAD_ADDR 0x100000 /* default load address */ + +#define CFG_HZ 1000 /* decrementer freq: 1 ms ticks */ + +#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200, 230400 } + +/* + * Choose the address mapping scheme for the MPC106 mem controller. + * Default is mapping B (CHRP), set this define to choose mapping A (PReP). + */ +#define CFG_ADDRESS_MAP_A 1 + +/* + * Low Level Configuration Settings + * (address mappings, register initial values, etc.) + * You should know what you are doing if you make changes here. + */ + +/* + * Definitions for initial stack pointer and data area + */ +#define CFG_INIT_RAM_ADDR 0x00fd0000 /* above the memtest region */ +#define CFG_INIT_RAM_END 0x4000 +#define CFG_INIT_DATA_SIZE 64 /* size in bytes reserved for init data */ +#define CFG_INIT_DATA_OFFSET (CFG_INIT_RAM_END - CFG_INIT_DATA_SIZE) +#define CFG_INIT_SP_OFFSET CFG_INIT_DATA_OFFSET + +/* + * Start addresses for the final memory configuration + * (Set up by the startup code) + * Please note that CFG_SDRAM_BASE _must_ start at 0 + */ +#define CFG_SDRAM_BASE 0x00000000 + +/* + * The mapped position of the flashes is independent from + * the chosen address map for the MPC106. + */ +#define CFG_FLASH_BASE 0xFFC00000 +#define FLASH_BASE0_PRELIM 0xFFC00000 +#define FLASH_BASE1_PRELIM 0xFF800000 + +#define CFG_MONITOR_BASE TEXT_BASE + +#ifdef IN_RAM + #define CFG_MONITOR_LEN (4 <<20) /* if we're running in ram, give us plenty of space for debug info*/ + #undef CFG_MEMTEST +#else + #define CFG_MONITOR_LEN (256 << 10) /* Reserve 256 kB for Monitor */ + #undef CFG_MEMTEST +#endif + +#define CFG_MALLOC_LEN (128 << 10) /* Reserve 128 kB for malloc() */ + +#define CFG_CPU_CLK 266000000 +#define CFG_BUS_CLK 6600000 + +/* + * Do NOT change the following table!!! Important mapping information!! + */ +#ifdef CFG_ADDRESS_MAP_A +#define CFG_ISA_MEM 0xC0000000 +#define CFG_ISA_IO_BASE_ADDRESS 0x80000000 +#define CFG_ISA_IO CFG_ISA_IO_BASE_ADDRESS +#define CFG_PCI_IO_BASE_ADDRESS 0x81000000 +#define CFG_PCI_IO CFG_PCI_IO_BASE_ADDRESS +#else +#define CFG_ISA_MEM 0xFD000000 +#define CFG_ISA_IO_BASE_ADDRESS 0xFE000000 +#define CFG_ISA_IO CFG_ISA_IO_BASE_ADDRESS +#define CFG_PCI_IO_BASE_ADDRESS 0xFE800000 +#define CFG_PCI_IO CFG_PCI_IO_BASE_ADDRESS +#endif + +/* + * PCI stuff + */ +#define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_HOST PCI_HOST_AUTO +#define CONFIG_PCI_PNP /* pci plug-and-play */ + +/* + * Do NOT change the following table!!! Important mapping information!! + */ +#ifdef CFG_ADDRESS_MAP_A +#define CFG_PCI_DRAM_OFFSET 0x80000000 +#define CFG_60X_PCI_MEM_OFFSET 0xC0000000 +#define CFG_60X_PCI_IO_OFFSET 0x80000000 +#define CFG_MIN_PCI_MEMADDR1 0x01010000 +#define CFG_MIN_PCI_MEMADDR2 0x01010000 +#define CFG_PCI_PCI_IOADDR 0x01000000 +#else +#define CFG_PCI_DRAM_OFFSET 0x00000000 +#define CFG_60X_PCI_MEM_OFFSET 0x00000000 +#define CFG_60X_PCI_IO_OFFSET 0xFE000000 +#define CFG_MIN_PCI_MEMADDR1 0xF9000000 +#define CFG_MIN_PCI_MEMADDR2 0xFA000000 +#define CFG_PCI_PCI_IOADDR 0x00800000 +#endif + +#define CFG_MAX_PCI_DEVICES 32 +#define CFG_MAX_PCI_FUNCTIONS 8 + +/* + * IDE/ATA stuff + */ +#define CFG_IDE_MAXBUS 1 /* max. 2 IDE busses */ +#define CFG_IDE_MAXDEVICE (CFG_IDE_MAXBUS*2) /* max. 2 drives per IDE bus */ + +#define CFG_ATA_BASE_ADDR CFG_60X_PCI_IO_OFFSET /* base address */ +#define CFG_ATA_IDE0_OFFSET 0x1F0 /* default ide0 offste */ +#define CFG_ATA_IDE1_OFFSET 0x170 /* default ide1 offset */ +#define CFG_ATA_DATA_OFFSET 0 /* data reg offset */ +#define CFG_ATA_REG_OFFSET 0 /* reg offset */ +#define CFG_ATA_ALT_OFFSET 0x200 /* alternate register offset */ + +#undef CONFIG_IDE_PCMCIA /* no pcmcia interface required */ +#undef CONFIG_IDE_LED /* no led for ide supported */ + +/* + * ATAPI support (experimental) + */ +#define CONFIG_ATAPI /* enable ATAPI Support */ + + +/* + * SCSI support (experimental) only SYM53C8xx supported + */ +#define CONFIG_SCSI_SYM53C8XX +#define CONFIG_SCSI_DEV_ID 0x000F /* 53c875 */ +#define CFG_SCSI_MAX_LUN 8 /* number of supported LUNs */ +#define CFG_SCSI_MAX_SCSI_ID 15 /* maximum SCSI ID (0..6) */ +#define CFG_SCSI_MAX_DEVICE CFG_SCSI_MAX_SCSI_ID * CFG_SCSI_MAX_LUN /* maximum Target devices */ +#define CFG_SCSI_SPIN_UP_TIME 2 +#define CFG_SCSI_SCAN_BUS_REVERSE 0 +#define CONFIG_DOS_PARTITION +#define CONFIG_MAC_PARTITION +#define CONFIG_ISO_PARTITION + +#define CFG_WINBOND_83C553 1 /*has a winbond bridge */ +#define CFG_USE_WINBOND_IDE 0 /*use winbond 83c553 internal ide controller */ +#define CFG_WINBOND_ISA_CFG_ADDR 0x80005800 /*pci-isa bridge config addr */ +#define CFG_WINBOND_IDE_CFG_ADDR 0x80005900 /*ide config addr */ +#define CFG_NS87308_BADDR_10 1 + +#define CFG_NS_PC87308UL 1 /* Nat Semi super-io controller on ISA bus */ + +#define CONFIG_RTC_MK48T59 + +/* + * Initial BAT mappings + */ + +/* do we need the MMU? probably not, but if we do, we must use the BATs */ +#undef CFG_MMU + +#ifdef CFG_MMU +/* SDRAM */ +#define CFG_IBAT0L (CFG_SDRAM_BASE | BATL_RW) +#define CFG_IBAT0U (CFG_SDRAM_BASE | BATU_BL_256M | BATU_VS | BATU_VP) +#define CFG_DBAT0L CFG_IBAT1L +#define CFG_DBAT0U CFG_IBAT1U + +/* address range for flashes */ +#define CFG_IBAT1L (CFG_FLASH_BASE | BATL_RW | BATL_CACHEINHIBIT) +#define CFG_IBAT1U (CFG_FLASH_BASE | BATU_BL_16M | BATU_VS | BATU_VP) +#define CFG_DBAT1L CFG_IBAT1L +#define CFG_DBAT1U CFG_IBAT1U + +/* ISA IO space */ +#define CFG_IBAT2L (CFG_ISA_IO | BATL_RW | BATL_CACHEINHIBIT) +#define CFG_IBAT2U (CFG_ISA_IO | BATU_BL_16M | BATU_VS | BATU_VP) +#define CFG_DBAT2L CFG_IBAT2L +#define CFG_DBAT2U CFG_IBAT2U + +/* ISA memory space */ +#define CFG_IBAT3L (CFG_ISA_MEM | BATL_RW | BATL_CACHEINHIBIT) +#define CFG_IBAT3U (CFG_ISA_MEM | BATU_BL_16M | BATU_VS | BATU_VP) +#define CFG_DBAT3L CFG_IBAT3L +#define CFG_DBAT3U CFG_IBAT3U + +#else + +#define CFG_IBAT0L 0 +#define CFG_IBAT0U 0 +#define CFG_DBAT0L CFG_IBAT1L +#define CFG_DBAT0U CFG_IBAT1U + +#define CFG_IBAT1L 0 +#define CFG_IBAT1U 0 +#define CFG_DBAT1L CFG_IBAT1L +#define CFG_DBAT1U CFG_IBAT1U + +/* ISA IO space */ +#define CFG_IBAT2L 0 +#define CFG_IBAT2U 0 +#define CFG_DBAT2L CFG_IBAT2L +#define CFG_DBAT2U CFG_IBAT2U + +/* ISA memory space */ +#define CFG_IBAT3L 0 +#define CFG_IBAT3U 0 +#define CFG_DBAT3L CFG_IBAT3L +#define CFG_DBAT3U CFG_IBAT3U + +#endif + +/* + * For booting Linux, the board info and command line data + * have to be in the first 8 MB of memory, since this is + * the maximum mapped by the Linux kernel during initialization. + */ +#define CFG_BOOTMAPSZ (8 << 20) /* Initial Memory map for Linux */ + +/* + * FLASH organization + */ +#define CFG_MAX_FLASH_BANKS 2 /* max number of memory banks */ +#define CFG_MAX_FLASH_SECT 67 /* max number of sectors on one chip */ + +#define CFG_FLASH_ERASE_TOUT 120000 /* Timeout for Flash Erase (in ms) */ +#define CFG_FLASH_WRITE_TOUT 500 /* Timeout for Flash Write (in ms) */ + +/* + * Cache Configuration + */ +#define CFG_CACHELINE_SIZE 32 /* For all MPC74xx CPUs */ +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#define CFG_CACHELINE_SHIFT 5 /* log base 2 of the above value */ +#endif + +/* + * L2CR setup -- make sure this is right for your board! + * look in include/mpc74xx.h for the defines used here + */ +/*#define CFG_L2*/ +#define L2_INIT (L2CR_L2SIZ_HM | L2CR_L2CLK_3 | L2CR_L2RAM_BURST | \ + L2CR_L2OH_5 | L2CR_L2CTL | L2CR_L2WT) +#define L2_ENABLE (L2_INIT | L2CR_L2E) + +/* + * Internal Definitions + * + * Boot Flags + */ +#define BOOTFLAG_COLD 0x01 /* Normal Power-On: Boot from FLASH */ +#define BOOTFLAG_WARM 0x02 /* Software reboot */ + +#endif /* __CONFIG_H */ diff --git a/include/mk48t59.h b/include/mk48t59.h new file mode 100644 index 0000000..e3483d2 --- /dev/null +++ b/include/mk48t59.h @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Date & Time support for the MK48T59 RTC + */ + + +#if defined(CONFIG_RTC_MK48T59) && (CONFIG_COMMANDS & CFG_CMD_DATE) + +#define RTC_PORT_ADDR0 CFG_ISA_IO + 0x70 +#define RTC_PORT_ADDR1 RTC_PORT_ADDR0 + 0x1 +#define RTC_PORT_DATA CFG_ISA_IO + 0x76 + +/* RTC Offsets */ +#define RTC_SECONDS 0x1FF9 +#define RTC_MINUTES 0x1FFA +#define RTC_HOURS 0x1FFB +#define RTC_DAY_OF_WEEK 0x1FFC +#define RTC_DAY_OF_MONTH 0x1FFD +#define RTC_MONTH 0x1FFE +#define RTC_YEAR 0x1FFF + +#define RTC_CONTROLA 0x1FF8 +#define RTC_CA_WRITE 0x80 +#define RTC_CA_READ 0x40 +#define RTC_CA_CALIB_SIGN 0x20 +#define RTC_CA_CALIB_MASK 0x1f + +#define RTC_CONTROLB 0x1FF9 +#define RTC_CB_STOP 0x80 + +#define RTC_WATCHDOG 0x1FF7 +#define RTC_WDS 0x80 +#define RTC_WD_RB_16TH 0x0 +#define RTC_WD_RB_4TH 0x1 +#define RTC_WD_RB_1 0x2 +#define RTC_WD_RB_4 0x3 + +void rtc_set_watchdog(short multi, short res); +void *nvram_read(void *dest, const short src, size_t count); +void nvram_write(short dest, const void *src, size_t count); + +#endif diff --git a/include/mpc106.h b/include/mpc106.h new file mode 100644 index 0000000..9388b34 --- /dev/null +++ b/include/mpc106.h @@ -0,0 +1,292 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _MPC106_PCI_H +#define _MPC106_PCI_H + +#ifndef DEFS_ONLY +typedef struct pciHeaderDevice { + short vendorId; /* vendor ID */ + short deviceId; /* device ID */ + short command; /* command register */ + short status; /* status register */ + char revisionId; /* revision ID */ + char classCode; /* class code */ + char subClass; /* sub class code */ + char progIf; /* programming interface */ + char cacheLine; /* cache line */ + char latency; /* latency time */ + char headerType; /* header type */ + char bist; /* BIST */ + int base0; /* base address 0 */ + int base1; /* base address 1 */ + int base2; /* base address 2 */ + int base3; /* base address 3 */ + int base4; /* base address 4 */ + int base5; /* base address 5 */ + int cis; /* cardBus CIS pointer */ + short subVendorId; /* sub system vendor ID */ + short subSystemId; /* sub system ID */ + int romBase; /* expansion ROM base address */ + int reserved0; /* reserved */ + int reserved1; /* reserved */ + char intLine; /* interrupt line */ + char intPin; /* interrupt pin */ + char minGrant; /* min Grant */ + char maxLatency; /* max Latency */ +} PCI_HEADER_DEVICE; + +typedef struct pciHeaderBridge { + short vendorId; /* vendor ID */ + short deviceId; /* device ID */ + short command; /* command register */ + short status; /* status register */ + char revisionId; /* revision ID */ + char classCode; /* class code */ + char subClass; /* sub class code */ + char progIf; /* programming interface */ + char cacheLine; /* cache line */ + char latency; /* latency time */ + char headerType; /* header type */ + char bist; /* BIST */ + int base0; /* base address 0 */ + int base1; /* base address 1 */ + char priBus; /* primary bus number */ + char secBus; /* secondary bus number */ + char subBus; /* subordinate bus number */ + char secLatency; /* secondary latency timer */ + char ioBase; /* IO base */ + char ioLimit; /* IO limit */ + short secStatus; /* secondary status */ + short memBase; /* memory base */ + short memLimit; /* memory limit */ + short preBase; /* prefetchable memory base */ + short preLimit; /* prefetchable memory limit */ + int preBaseUpper; /* prefetchable memory base upper 32 bits */ + int preLimitUpper; /* prefetchable memory base upper 32 bits */ + short ioBaseUpper; /* IO base upper 16 bits */ + short ioLimitUpper; /* IO limit upper 16 bits */ + int reserved; /* reserved */ + int romBase; /* expansion ROM base address */ + char intLine; /* interrupt line */ + char intPin; /* interrupt pin */ + short control; /* bridge control */ +} PCI_HEADER_BRIDGE; + +#endif /* DEFS_ONLY */ + + +/* + * Defines for the MPC106 PCI Config address and data registers followed by + * defines for the standard PCI device configuration header. + */ + +#define PCIDEVID_MPC106 0x0 + +/* + * MPC106 Registers + */ +#define MPC106_REG 0x80000000 + +#ifdef CFG_ADDRESS_MAP_A +#define MPC106_REG_ADDR 0x80000cf8 +#define MPC106_REG_DATA 0x80000cfc +#else +#define MPC106_REG_ADDR 0xfec00cf8 +#define MPC106_REG_DATA 0xfee00cfc +#endif + +#define CMD_SERR 0x0100 +#define PCI_CMD_MASTER 0x0004 +#define PCI_CMD_MEMEN 0x0002 +#define PCI_CMD_IOEN 0x0001 + +#define PCI_STAT_NO_RSV_BITS 0xffff + +#define PCI_BUSNUM 0x40 +#define PCI_SUBBUSNUM 0x41 +#define PCI_DISCOUNT 0x42 + +#define PCI_PICR1 0xA8 +#define PICR1_CF_CBA(value) ((value & 0xff) << 24) +#define PICR1_CF_BREAD_WS(value) ((value & 0x3) << 22) +#define PICR1_PROC_TYPE_603 0x40000 +#define PICR1_PROC_TYPE_604 0x60000 +#define PICR1_MCP_EN 0x800 +#define PICR1_CF_DPARK 0x200 +#define PICR1_CF_LOOP_SNOOP 0x10 +#define PICR1_CF_APARK 0x8 +#define PICR1_ADDRESS_MAP 0x10000 +#define PICR1_XIO_MODE 0x80000 + +#define PCI_PICR2 0xAC +#define PICR2_CF_SNOOP_WS(value) ((value & 0x3) << 18) +#define PICR2_CF_FLUSH_L2 0x10000000 +#define PICR2_CF_L2_HIT_DELAY(value) ((value & 0x3) << 9) +#define PICR2_CF_APHASE_WS(value) ((value & 0x3) << 2) +#define PICR2_L2_EN 0x40000000 +#define PICR2_L2_UPDATE_EN 0x80000000 + +/* + * PCI-PCI bridge header + */ +#define PCIPCI_PRIMARYBUS 0x18 +#define PCIPCI_SECONDARYBUS 0x19 +#define PCIPCI_SUBORDINATEBUS 0x1A +#define PCIPCI_SECONDARYLATENCY 0x1B +#define PCIPCI_IOBASE 0x1C +#define PCIPCI_IOLIMIT 0x1D +#define PCIPCI_SECONDARYSTATUS 0x1E +#define PCIPCI_MEMBASE 0x20 +#define PCIPCI_MEMLIMIT 0x22 +#define PCIPCI_PREFETCHMEMBASE 0x24 +#define PCIPCI_PREFETCHMEMLIMIT 0x26 +#define PCIPCI_IOBASEUPPER16 0x30 +#define PCIPCI_IOLIMITUPPER16 0x32 + +/* + * Standard device configuration register offsets + * Note that only modulo-4 addresses are written to the address register + */ +#define PCI_CFG_VENDOR_ID 0x00 +#define PCI_CFG_DEVICE_ID 0x02 +#define PCI_CFG_COMMAND 0x04 +#define PCI_CFG_STATUS 0x06 +#define PCI_CFG_REVISION 0x08 +#define PCI_CFG_PROGRAMMING_IF 0x09 +#define PCI_CFG_SUBCLASS 0x0a +#define PCI_CFG_CLASS 0x0b +#define PCI_CFG_CACHE_LINE_SIZE 0x0c +#define PCI_CFG_LATENCY_TIMER 0x0d +#define PCI_CFG_HEADER_TYPE 0x0e +#define PCI_CFG_BIST 0x0f +#define PCI_CFG_BASE_ADDRESS_0 0x10 +#define PCI_CFG_BASE_ADDRESS_1 0x14 +#define PCI_CFG_BASE_ADDRESS_2 0x18 +#define PCI_CFG_BASE_ADDRESS_3 0x1c +#define PCI_CFG_BASE_ADDRESS_4 0x20 +#define PCI_CFG_BASE_ADDRESS_5 0x24 +#define PCI_CFG_CIS 0x28 +#define PCI_CFG_SUB_VENDER_ID 0x2c +#define PCI_CFG_SUB_SYSTEM_ID 0x2e +#define PCI_CFG_EXPANSION_ROM 0x30 +#define PCI_CFG_RESERVED_0 0x34 +#define PCI_CFG_RESERVED_1 0x38 +#define PCI_CFG_DEV_INT_LINE 0x3c +#define PCI_CFG_DEV_INT_PIN 0x3d +#define PCI_CFG_MIN_GRANT 0x3e +#define PCI_CFG_MAX_LATENCY 0x3f +#define PCI_CFG_SPECIAL_USE 0x41 +#define PCI_CFG_MODE 0x43 + + +/* + * PCI-to-PCI bridge configuration register offsets + * Note that only modulo-4 addresses are written to the address register + */ +#define PCI_CFG_PRIMARY_BUS 0x18 +#define PCI_CFG_SECONDARY_BUS 0x19 +#define PCI_CFG_SUBORDINATE_BUS 0x1a +#define PCI_CFG_SEC_LATENCY 0x1b +#define PCI_CFG_IO_BASE 0x1c +#define PCI_CFG_IO_LIMIT 0x1d +#define PCI_CFG_SEC_STATUS 0x1e +#define PCI_CFG_MEM_BASE 0x20 +#define PCI_CFG_MEM_LIMIT 0x22 +#define PCI_CFG_PRE_MEM_BASE 0x24 +#define PCI_CFG_PRE_MEM_LIMIT 0x26 +#define PCI_CFG_PRE_MEM_BASE_U 0x28 +#define PCI_CFG_PRE_MEM_LIMIT_U 0x2c +#define PCI_CFG_IO_BASE_U 0x30 +#define PCI_CFG_IO_LIMIT_U 0x32 +#define PCI_CFG_ROM_BASE 0x38 +#define PCI_CFG_BRG_INT_LINE 0x3c +#define PCI_CFG_BRG_INT_PIN 0x3d +#define PCI_CFG_BRIDGE_CONTROL 0x3e + + +/* + * Memory controller + */ +#define MPC106_MCCR1 0xF0 +#define MCCR1_TYPE_EDO 0x00020000 +#define MCCR1_BK0_9BITS 0x0 +#define MCCR1_BK0_10BITS 0x1 +#define MCCR1_BK0_11BITS 0x2 +#define MCCR1_BK0_12BITS 0x3 +#define MCCR1_BK1_9BITS 0x0 +#define MCCR1_BK1_10BITS 0x4 +#define MCCR1_BK1_11BITS 0x8 +#define MCCR1_BK1_12BITS 0xC +#define MCCR1_BK2_9BITS 0x00 +#define MCCR1_BK2_10BITS 0x10 +#define MCCR1_BK2_11BITS 0x20 +#define MCCR1_BK2_12BITS 0x30 +#define MCCR1_BK3_9BITS 0x00 +#define MCCR1_BK3_10BITS 0x40 +#define MCCR1_BK3_11BITS 0x80 +#define MCCR1_BK3_12BITS 0xC0 +#define MCCR1_MEMGO 0x00080000 + +#define MPC106_MCCR2 0xF4 +#define MPC106_MCCR3 0xF8 +#define MPC106_MCCR4 0xFC + +#define MPC106_MSAR1 0x80 +#define MPC106_EMSAR1 0x88 +#define MPC106_EMSAR2 0x8C +#define MPC106_MEAR1 0x90 +#define MPC106_EMEAR1 0x98 +#define MPC106_EMEAR2 0x9C + +#define MPC106_MBER 0xA0 +#define MBER_BANK0 0x1 +#define MBER_BANK1 0x2 +#define MBER_BANK2 0x4 +#define MBER_BANK3 0x8 + + +#ifndef DEFS_ONLY + +unsigned int PCI_Read_CFG_Reg(int BusDevFunc, int Reg, int Width); +int PCI_Write_CFG_Reg(int BusDevFunc, int Reg, unsigned int Value, int Width); +int PCI_Scan(int BusNum); +void PCI_Config_Device(int BusDevFunc, int NumBaseAddr); +void PCI_Config_VGA_Device(int BusDevFunc, int NumBaseAddr); +void PCI_Config_Bridge(int BusDevFunc); +int PCI_Find_Device(unsigned short VendorID, unsigned short DeviceID); +void PCI_Header_Show(int BusDevFunc); +void PCI_Dheader_Print(PCI_HEADER_DEVICE * pD); +void PCI_Bheader_Print(PCI_HEADER_BRIDGE * pB); + +/* + * memory mapping functions + */ +unsigned long phys_to_bus(void*); +void *bus_to_phys(unsigned long); + +#endif /* DEFS_ONLY */ + + +#endif + diff --git a/include/mpc75x.h b/include/mpc75x.h new file mode 100644 index 0000000..ddac6e4 --- /dev/null +++ b/include/mpc75x.h @@ -0,0 +1,98 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * mpc75x.h + * + * MPC75x/MPC74xx specific definitions + */ + +#ifndef __MPC75X_H__ +#define __MPC75X_H__ + +/*---------------------------------------------------------------- + * Exception offsets (PowerPC standard) + */ +#define EXC_OFF_SYS_RESET 0x0100 /* default system reset offset */ + +/*---------------------------------------------------------------- + * l2cr values + */ +#define l2cr 1017 + +#define L2CR_L2E 0x80000000 /* bit 0 - enable */ +#define L2CR_L2PE 0x40000000 /* bit 1 - data parity */ +#define L2CR_L2SIZ_2M 0x00000000 /* bits 2-3 - 2MB, MPC7400 only! */ +#define L2CR_L2SIZ_1M 0x30000000 /* ... 1MB */ +#define L2CR_L2SIZ_HM 0x20000000 /* ... 512K */ +#define L2CR_L2SIZ_QM 0x10000000 /* ... 256k */ +#define L2CR_L2CLK_1 0x02000000 /* bits 4-6 clock ratio div 1 */ +#define L2CR_L2CLK_1_5 0x04000000 /* bits 4-6 clock ratio div 1.5 */ +#define L2CR_L2CLK_2 0x08000000 /* bits 4-6 clock ratio div 2 */ +#define L2CR_L2CLK_2_5 0x0a000000 /* bits 4-6 clock ratio div 2.5 */ +#define L2CR_L2CLK_3 0x0c000000 /* bits 4-6 clock ratio div 3 */ +#define L2CR_L2CLK_3_5 0x06000000 /* bits 4-6 clock ratio div 3.5 */ +#define L2CR_L2CLK_4 0x0e000000 /* bits 4-6 clock ratio div 4 */ +#define L2CR_L2RAM_BURST 0x01000000 /* bits 7-8 - burst SRAM */ +#define L2CR_DO 0x00400000 /* bit 9 - enable caching of instr. in L2 */ +#define L2CR_L2I 0x00200000 /* bit 10 - global invalidate bit */ +#define L2CR_L2CTL 0x00100000 /* bit 11 - l2 ram control */ +#define L2CR_L2WT 0x00080000 /* bit 12 - l2 write-through */ +#define L2CR_TS 0x00040000 /* bit 13 - test support on */ +#define L2CR_TS_OFF -L2CR_TS /* bit 13 - test support off */ +#define L2CR_L2OH_5 0x00000000 /* bits 14-15 - output hold time = short */ +#define L2CR_L2OH_1 0x00010000 /* bits 14-15 - output hold time = medium */ +#define L2CR_L2OH_INV 0x00020000 /* bits 14-15 - output hold time = long */ +#define L2CR_L2IP 0x00000001 /* global invalidate in progress */ + +/*---------------------------------------------------------------- + * BAT settings. Look in config_.h for the actual setup + */ + +#define BATU_BL_128K 0x00000000 +#define BATU_BL_256K 0x00000004 +#define BATU_BL_512K 0x0000000c +#define BATU_BL_1M 0x0000001c +#define BATU_BL_2M 0x0000003c +#define BATU_BL_4M 0x0000007c +#define BATU_BL_8M 0x000000fc +#define BATU_BL_16M 0x000001fc +#define BATU_BL_32M 0x000003fc +#define BATU_BL_64M 0x000007fc +#define BATU_BL_128M 0x00000ffc +#define BATU_BL_256M 0x00001ffc + +#define BATU_VS 0x00000002 +#define BATU_VP 0x00000001 +#define BATU_INVALID 0x00000000 + +#define BATL_WRITETHROUGH 0x00000080 +#define BATL_CACHEINHIBIT 0x00000040 +#define BATL_COHERENT 0x00000020 +#define BATL_GUARDED 0x00000010 + +#define BATL_NO_ACCESS 0x00000000 +#define BATL_RO 0x00000001 +#define BATL_RW 0x00000002 + +#endif /* __MPC75X_H__ */ diff --git a/include/ppcboot.h b/include/ppcboot.h index 936ae45..aff0dee 100644 --- a/include/ppcboot.h +++ b/include/ppcboot.h @@ -204,6 +204,7 @@ void inline setenv (char *, char *); defined (CONFIG_DASA_SIM) || \ defined (CONFIG_ERIC) || \ defined (CONFIG_MOUSSE) || \ + defined (CONFIG_BAB750) || \ defined (CONFIG_W7O) /* $(CPU)/405gp_pci.c */ void pci_init (bd_t *); @@ -356,7 +357,10 @@ void dcache_disable(void); void relocate_code (ulong, bd_t *, ulong); ulong get_endaddr (void); void trap_init (ulong); -#ifdef CONFIG_4xx +#if defined (CONFIG_4xx) || \ + defined (CONFIG_74x) || \ + defined (CONFIG_75x) || \ + defined (CONFIG_74xx) unsigned char in8(unsigned int); void out8(unsigned int, unsigned char); unsigned short in16(unsigned int); @@ -392,6 +396,7 @@ void prt_8260_clks (void); defined(CONFIG_EVB64260) || \ defined(CONFIG_IOP480) || \ defined(CONFIG_MOUSSE) || \ + defined(CONFIG_BAB750) || \ defined(CONFIG_SANDPOINT) ulong get_gclk_freq (void); ulong get_OPB_freq (void); diff --git a/include/w83c553f.h b/include/w83c553f.h new file mode 100644 index 0000000..1f8d2bd --- /dev/null +++ b/include/w83c553f.h @@ -0,0 +1,178 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + /* winbond access routines and defines*/ + +/* from the winbond data sheet - + The W83C553F SIO controller with PCI arbiter is a multi-function PCI device. + Function 0 is the ISA bridge, and Function 1 is the bus master IDE controller. +*/ + +/*ISA bridge configuration space*/ + +#define W83C553F_VID 0x10AD +#define W83C553F_DID 0x0565 + +#define WINBOND_PCICONTR 0x40 /*pci control reg*/ +#define WINBOND_SGBAR 0x41 /*scatter/gather base address reg*/ +#define WINBOND_LBCR 0x42 /*Line Buffer Control reg*/ +#define WINBOND_IDEIRCR 0x43 /*IDE Interrupt Routing Control Reg*/ +#define WINBOND_PCIIRCR 0x44 /*PCI Interrupt Routing Control Reg*/ +#define WINBOND_BTBAR 0x46 /*BIOS Timer Base Address Register*/ +#define WINBOND_IPADCR 0x48 /*ISA to PCI Address Decoder Control Register*/ +#define WINBOND_IRADCR 0x49 /*ISA ROM Address Decoder Control Register*/ +#define WINBOND_IPMHSAR 0x4a /*ISA to PCI Memory Hole STart Address Register*/ +#define WINBOND_IPMHSR 0x4b /*ISA to PCI Memory Hols Size Register*/ +#define WINBOND_CDR 0x4c /*Clock Divisor Register*/ +#define WINBOND_CSCR 0x4d /*Chip Select Control Register*/ +#define WINBOND_ATSCR 0x4e /*AT System Control register*/ +#define WINBOND_ATBCR 0x4f /*AT Bus ControL Register*/ +#define WINBOND_IRQBEE0R 0x60 /*IRQ Break Event Enable 0 Register*/ +#define WINBOND_IRQBEE1R 0x61 /*IRQ Break Event Enable 1 Register*/ +#define WINBOND_ABEER 0x62 /*Additional Break Event Enable Register*/ +#define WINBOND_DMABEER 0x63 /*DMA Break Event Enable Register*/ + +#define WINDOND_IDECSR 0x40 /*IDE Control/Status Register, Function 1*/ + +#define IPADCR_MBE512 0x1 +#define IPADCR_MBE640 0x2 +#define IPADCR_IPATOM4 0x10 +#define IPADCR_IPATOM5 0x20 +#define IPADCR_IPATOM6 0x40 +#define IPADCR_IPATOM7 0x80 + +#define CSCR_UBIOSCSE 0x10 +#define CSCR_BIOSWP 0x20 + +#define IDECSR_P0EN 0x01 +#define IDECSR_P0F16 0x02 +#define IDECSR_P1EN 0x10 +#define IDECSR_P1F16 0x20 +#define IDECSR_LEGIRQ 0x800 + +/* + * Interrupt controller + */ +#define W83C553F_PIC1_ICW1 CFG_ISA_IO + 0x20 +#define W83C553F_PIC1_ICW2 CFG_ISA_IO + 0x21 +#define W83C553F_PIC1_ICW3 CFG_ISA_IO + 0x21 +#define W83C553F_PIC1_ICW4 CFG_ISA_IO + 0x21 +#define W83C553F_PIC1_OCW1 CFG_ISA_IO + 0x21 +#define W83C553F_PIC1_OCW2 CFG_ISA_IO + 0x20 +#define W83C553F_PIC1_OCW3 CFG_ISA_IO + 0x20 +#define W83C553F_PIC1_ELC CFG_ISA_IO + 0x4D0 +#define W83C553F_PIC2_ICW1 CFG_ISA_IO + 0xA0 +#define W83C553F_PIC2_ICW2 CFG_ISA_IO + 0xA1 +#define W83C553F_PIC2_ICW3 CFG_ISA_IO + 0xA1 +#define W83C553F_PIC2_ICW4 CFG_ISA_IO + 0xA1 +#define W83C553F_PIC2_OCW1 CFG_ISA_IO + 0xA1 +#define W83C553F_PIC2_OCW2 CFG_ISA_IO + 0xA0 +#define W83C553F_PIC2_OCW3 CFG_ISA_IO + 0xA0 +#define W83C553F_PIC2_ELC CFG_ISA_IO + 0x4D1 + +#define W83C553F_TMR1_CMOD CFG_ISA_IO + 0x43 + +/* + * DMA controller + */ +#define W83C553F_DMA1 CFG_ISA_IO + 0x000 /* channel 0 - 3 */ +#define W83C553F_DMA2 CFG_ISA_IO + 0x0C0 /* channel 4 - 7 */ + +/* command/status register bit definitions */ + +#define W83C553F_CS_COM_DACKAL (1<<7) /* DACK# assert level */ +#define W83C553F_CS_COM_DREQSAL (1<<6) /* DREQ sense assert level */ +#define W83C553F_CS_COM_GAP (1<<4) /* group arbitration priority */ +#define W83C553F_CS_COM_CGE (1<<2) /* channel group enable */ + +#define W83C553F_CS_STAT_CH0REQ (1<<4) /* channel 0 (4) DREQ status */ +#define W83C553F_CS_STAT_CH1REQ (1<<5) /* channel 1 (5) DREQ status */ +#define W83C553F_CS_STAT_CH2REQ (1<<6) /* channel 2 (6) DREQ status */ +#define W83C553F_CS_STAT_CH3REQ (1<<7) /* channel 3 (7) DREQ status */ + +#define W83C553F_CS_STAT_CH0TC (1<<0) /* channel 0 (4) TC status */ +#define W83C553F_CS_STAT_CH1TC (1<<1) /* channel 1 (5) TC status */ +#define W83C553F_CS_STAT_CH2TC (1<<2) /* channel 2 (6) TC status */ +#define W83C553F_CS_STAT_CH3TC (1<<3) /* channel 3 (7) TC status */ + +/* mode register bit definitions */ + +#define W83C553F_MODE_TM_DEMAND (0<<6) /* transfer mode - demand */ +#define W83C553F_MODE_TM_SINGLE (1<<6) /* transfer mode - single */ +#define W83C553F_MODE_TM_BLOCK (2<<6) /* transfer mode - block */ +#define W83C553F_MODE_TM_CASCADE (3<<6) /* transfer mode - cascade */ +#define W83C553F_MODE_ADDRDEC (1<<5) /* address increment/decrement select */ +#define W83C553F_MODE_AUTOINIT (1<<4) /* autoinitialize enable */ +#define W83C553F_MODE_TT_VERIFY (0<<2) /* transfer type - verify */ +#define W83C553F_MODE_TT_WRITE (1<<2) /* transfer type - write */ +#define W83C553F_MODE_TT_READ (2<<2) /* transfer type - read */ +#define W83C553F_MODE_TT_ILLEGAL (3<<2) /* transfer type - illegal */ +#define W83C553F_MODE_CH0SEL (0<<0) /* channel 0 (4) select */ +#define W83C553F_MODE_CH1SEL (1<<0) /* channel 1 (5) select */ +#define W83C553F_MODE_CH2SEL (2<<0) /* channel 2 (6) select */ +#define W83C553F_MODE_CH3SEL (3<<0) /* channel 3 (7) select */ + +/* request register bit definitions */ + +#define W83C553F_REQ_CHSERREQ (1<<2) /* channel service request */ +#define W83C553F_REQ_CH0SEL (0<<0) /* channel 0 (4) select */ +#define W83C553F_REQ_CH1SEL (1<<0) /* channel 1 (5) select */ +#define W83C553F_REQ_CH2SEL (2<<0) /* channel 2 (6) select */ +#define W83C553F_REQ_CH3SEL (3<<0) /* channel 3 (7) select */ + +/* write single mask bit register bit definitions */ + +#define W83C553F_WSMB_CHMASKSEL (1<<2) /* channel mask select */ +#define W83C553F_WSMB_CH0SEL (0<<0) /* channel 0 (4) select */ +#define W83C553F_WSMB_CH1SEL (1<<0) /* channel 1 (5) select */ +#define W83C553F_WSMB_CH2SEL (2<<0) /* channel 2 (6) select */ +#define W83C553F_WSMB_CH3SEL (3<<0) /* channel 3 (7) select */ + +/* read/write all mask bits register bit definitions */ + +#define W83C553F_RWAMB_CH0MASK (1<<0) /* channel 0 (4) mask */ +#define W83C553F_RWAMB_CH1MASK (1<<1) /* channel 1 (5) mask */ +#define W83C553F_RWAMB_CH2MASK (1<<2) /* channel 2 (6) mask */ +#define W83C553F_RWAMB_CH3MASK (1<<3) /* channel 3 (7) mask */ + +/* typedefs */ + +#define W83C553F_DMA1_CS 0x8 +#define W83C553F_DMA1_WR 0x9 +#define W83C553F_DMA1_WSMB 0xA +#define W83C553F_DMA1_WM 0xB +#define W83C553F_DMA1_CBP 0xC +#define W83C553F_DMA1_MC 0xD +#define W83C553F_DMA1_CM 0xE +#define W83C553F_DMA1_RWAMB 0xF + +#define W83C553F_DMA2_CS 0x10 +#define W83C553F_DMA2_WR 0x12 +#define W83C553F_DMA2_WSMB 0x14 +#define W83C553F_DMA2_WM 0x16 +#define W83C553F_DMA2_CBP 0x18 +#define W83C553F_DMA2_MC 0x1A +#define W83C553F_DMA2_CM 0x1C +#define W83C553F_DMA2_RWAMB 0x1E + +void initialise_w83c553f(void); diff --git a/rtc/Makefile b/rtc/Makefile index 45b25aa..5df2439 100644 --- a/rtc/Makefile +++ b/rtc/Makefile @@ -27,7 +27,7 @@ include $(TOPDIR)/config.mk LIB = librtc.a -OBJS = date.o pcf8563.o mpc8xx.o mc146818.o ds174x.o m48t35ax.o +OBJS = date.o pcf8563.o mpc8xx.o mc146818.o ds174x.o m48t35ax.o mk48t59.o all: $(LIB) diff --git a/rtc/mk48t59.c b/rtc/mk48t59.c new file mode 100644 index 0000000..dd29658 --- /dev/null +++ b/rtc/mk48t59.c @@ -0,0 +1,187 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Date & Time support for the MK48T59 RTC + */ + +#undef RTC_DEBUG + +#include +#include +#include +#include +#include + +#if defined(CONFIG_RTC_MK48T59) + +static uchar rtc_read (short reg) +{ + out8(RTC_PORT_ADDR0, reg & 0xFF); + out8(RTC_PORT_ADDR1, (reg>>8) & 0xFF); + return in8(RTC_PORT_DATA); +} + +static void rtc_write (short reg, uchar val) +{ + out8(RTC_PORT_ADDR0, reg & 0xFF); + out8(RTC_PORT_ADDR1, (reg>>8) & 0xFF); + out8(RTC_PORT_DATA, val); +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +/* ------------------------------------------------------------------------- */ + +void *nvram_read(void *dest, const short src, size_t count) +{ + uchar *d = (uchar *) dest; + short s = src; + + while (count--) + *d++ = rtc_read(s++); + + return dest; +} + +void nvram_write(short dest, const void *src, size_t count) +{ + short d = dest; + uchar *s = (uchar *) src; + + while (count--) + rtc_write(d++, *s++); +} + +#if (CONFIG_COMMANDS & CFG_CMD_DATE) + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + uchar save_ctrl_a; + uchar sec, min, hour, mday, wday, mon, year; + + /* Simple: freeze the clock, read it and allow updates again */ + save_ctrl_a = rtc_read(RTC_CONTROLA); + + /* Set the register to read the value. */ + save_ctrl_a |= RTC_CA_READ; + rtc_write(RTC_CONTROLA, save_ctrl_a); + + sec = rtc_read (RTC_SECONDS); + min = rtc_read (RTC_MINUTES); + hour = rtc_read (RTC_HOURS); + mday = rtc_read (RTC_DAY_OF_MONTH); + wday = rtc_read (RTC_DAY_OF_WEEK); + mon = rtc_read (RTC_MONTH); + year = rtc_read (RTC_YEAR); + + /* re-enable update */ + save_ctrl_a &= ~RTC_CA_READ; + rtc_write(RTC_CONTROLA, save_ctrl_a); + +#ifdef RTC_DEBUG + printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, + hour, min, sec ); +#endif + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon & 0x1F); + tmp->tm_year = bcd2bin (year); + tmp->tm_wday = bcd2bin (wday & 0x07); + if(tmp->tm_year<70) + tmp->tm_year+=2000; + else + tmp->tm_year+=1900; + tmp->tm_yday = 0; + tmp->tm_isdst= 0; +#ifdef RTC_DEBUG + printf ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); +#endif +} + +void rtc_set (struct rtc_time *tmp) +{ + uchar save_ctrl_a; + +#ifdef RTC_DEBUG + printf ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); +#endif + save_ctrl_a = rtc_read(RTC_CONTROLA); + + save_ctrl_a |= RTC_CA_WRITE; + rtc_write(RTC_CONTROLA, save_ctrl_a); /* disables the RTC to update the regs */ + + rtc_write (RTC_YEAR, bin2bcd(tmp->tm_year % 100)); + rtc_write (RTC_MONTH, bin2bcd(tmp->tm_mon)); + + rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday)); + rtc_write (RTC_DAY_OF_MONTH, bin2bcd(tmp->tm_mday)); + rtc_write (RTC_HOURS, bin2bcd(tmp->tm_hour)); + rtc_write (RTC_MINUTES, bin2bcd(tmp->tm_min )); + rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec )); + + save_ctrl_a &= ~RTC_CA_WRITE; + rtc_write(RTC_CONTROLA, save_ctrl_a); /* enables the RTC to update the regs */ +} + +void rtc_reset (void) +{ + uchar control_b; + + /* + * Start oscillator here. + */ + control_b = rtc_read(RTC_CONTROLB); + + control_b &= ~RTC_CB_STOP; + rtc_write(RTC_CONTROLB, control_b); +} + +void rtc_set_watchdog(short multi, short res) +{ + uchar wd_value; + + wd_value = RTC_WDS | ((multi & 0x1F) << 2) | (res & 0x3); + rtc_write(RTC_WATCHDOG, wd_value); +} + +#endif /* (CONFIG_COMMANDS & CFG_CMD_DATE) */ +#endif /* CONFIG_RTC_MK48T59 */