summaryrefslogtreecommitdiff
path: root/board/MAI/AmigaOneG3SE
diff options
context:
space:
mode:
authorwdenk <wdenk>2002-11-19 11:04:11 +0000
committerwdenk <wdenk>2002-11-19 11:04:11 +0000
commitc7de829c796978e519984df2f1c8cfcf921a39a4 (patch)
tree43e42aa9a09f5265783c1622a5cea080471ef50e /board/MAI/AmigaOneG3SE
parent2262cfeef91458b01a1bfe3812ccbbfdf8b82807 (diff)
downloadu-boot-imx-c7de829c796978e519984df2f1c8cfcf921a39a4.zip
u-boot-imx-c7de829c796978e519984df2f1c8cfcf921a39a4.tar.gz
u-boot-imx-c7de829c796978e519984df2f1c8cfcf921a39a4.tar.bz2
* Patch by Thomas Frieden, 13 Nov 2002:
Add code for AmigaOne board (preliminary merge to U-Boot, still WIP) * Patch by Jon Diekema, 12 Nov 2002: - Adding URL for IEEE OUI lookup - Making the autoboot #defines dependent on CONFIG_AUTOBOOT_KEYED being defined. - In the CONFIG_EXTRA_ENV_SETTINGS #define, the root-on-initrd and root-on-nfs macros are designed to switch how the default boot method gets defined.
Diffstat (limited to 'board/MAI/AmigaOneG3SE')
-rw-r--r--board/MAI/AmigaOneG3SE/AmigaOneG3SE.c116
-rw-r--r--board/MAI/AmigaOneG3SE/Makefile53
-rw-r--r--board/MAI/AmigaOneG3SE/articiaS.c704
-rw-r--r--board/MAI/AmigaOneG3SE/articiaS.h143
-rw-r--r--board/MAI/AmigaOneG3SE/articiaS_pci.c573
-rw-r--r--board/MAI/AmigaOneG3SE/board_asm_init.S157
-rw-r--r--board/MAI/AmigaOneG3SE/cmd_boota.c123
-rw-r--r--board/MAI/AmigaOneG3SE/config.mk33
-rw-r--r--board/MAI/AmigaOneG3SE/enet.c886
-rw-r--r--board/MAI/AmigaOneG3SE/flash.c35
-rw-r--r--board/MAI/AmigaOneG3SE/flash_new.c652
-rw-r--r--board/MAI/AmigaOneG3SE/i8259.c230
-rw-r--r--board/MAI/AmigaOneG3SE/i8259.h56
-rw-r--r--board/MAI/AmigaOneG3SE/interrupts.c268
-rw-r--r--board/MAI/AmigaOneG3SE/macros.h84
-rw-r--r--board/MAI/AmigaOneG3SE/memio.S74
-rw-r--r--board/MAI/AmigaOneG3SE/memio.h113
-rw-r--r--board/MAI/AmigaOneG3SE/memory_dump30
-rw-r--r--board/MAI/AmigaOneG3SE/nvram.c37
-rw-r--r--board/MAI/AmigaOneG3SE/ps2kbd.c699
-rw-r--r--board/MAI/AmigaOneG3SE/ps2kbd.h41
-rw-r--r--board/MAI/AmigaOneG3SE/serial.c247
-rw-r--r--board/MAI/AmigaOneG3SE/short_types.h36
-rw-r--r--board/MAI/AmigaOneG3SE/smbus.c206
-rw-r--r--board/MAI/AmigaOneG3SE/smbus.h22
-rw-r--r--board/MAI/AmigaOneG3SE/start.txt201
-rw-r--r--board/MAI/AmigaOneG3SE/todo.txt3
-rw-r--r--board/MAI/AmigaOneG3SE/u-boot.lds131
-rw-r--r--board/MAI/AmigaOneG3SE/usb_uhci.c1179
-rw-r--r--board/MAI/AmigaOneG3SE/usb_uhci.h194
-rw-r--r--board/MAI/AmigaOneG3SE/via686.c299
-rw-r--r--board/MAI/AmigaOneG3SE/via686.h29
-rw-r--r--board/MAI/AmigaOneG3SE/video.c539
33 files changed, 8193 insertions, 0 deletions
diff --git a/board/MAI/AmigaOneG3SE/AmigaOneG3SE.c b/board/MAI/AmigaOneG3SE/AmigaOneG3SE.c
new file mode 100644
index 0000000..0cf5388
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/AmigaOneG3SE.c
@@ -0,0 +1,116 @@
+/*
+ * (C) Copyright 2002
+ * Hyperion Entertainment, ThomasF@hyperion-entertainment.com
+ * 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 <common.h>
+#include <command.h>
+#include <pci.h>
+#include "articiaS.h"
+#include "memio.h"
+#include "via686.h"
+
+__asm(" .globl send_kb \n
+ send_kb: \n
+ lis r9, 0xfe00 \n
+ \n
+ li r4, 0x10 # retries \n
+ mtctr r4 \n
+ \n
+ idle: \n
+ lbz r4, 0x64(r9) \n
+ andi. r4, r4, 0x02 \n
+ bne idle \n
+ \n
+ ready: \n
+ stb r3, 0x60(r9) \n
+ \n
+ check: \n
+ lbz r4, 0x64(r9) \n
+ andi. r4, r4, 0x01 \n
+ beq check \n
+ \n
+ lbz r4, 0x60(r9) \n
+ cmpwi r4, 0xfa \n
+ beq done \n
+ \n
+ bdnz idle \n
+ \n
+ li r3, 0 \n
+ blr \n
+ \n
+ done: \n
+ li r3, 1 \n
+ blr \n
+ \n
+ .globl test_kb \n
+ test_kb: \n
+ mflr r10 \n
+ li r3, 0xed \n
+ bl send_kb \n
+ li r3, 0x01 \n
+ bl send_kb \n
+ mtlr r10 \n
+ blr \n
+");
+
+
+int checkboard (void)
+{
+ printf ("AmigaOneG3SE\n");
+
+ return 1;
+}
+
+long initdram (int board_type)
+{
+ return articiaS_ram_init ();
+}
+
+
+
+void after_reloc (ulong dest_addr)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ board_init_r (gd, dest_addr);
+}
+
+
+int misc_init_r (void)
+{
+ extern pci_dev_t video_dev;
+ extern void drv_video_init (void);
+
+ if (video_dev != ~0)
+ drv_video_init ();
+
+ return (0);
+}
+
+
+void pci_init (void)
+{
+#ifndef CONFIG_RAMBOOT
+ articiaS_pci_init ();
+#endif
+}
diff --git a/board/MAI/AmigaOneG3SE/Makefile b/board/MAI/AmigaOneG3SE/Makefile
new file mode 100644
index 0000000..7271746
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/Makefile
@@ -0,0 +1,53 @@
+#
+# (C) Copyright 2002
+# 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
+
+COBJS = $(BOARD).o articiaS.o flash.o serial.o smbus.o articiaS_pci.o \
+ via686.o i8259.o ../bios_emulator/x86interface.o \
+ ../bios_emulator/bios.o ../bios_emulator/glue.o \
+ interrupts.o ps2kbd.o video.o usb_uhci.o enet.o \
+ ../menu/cmd_menu.o cmd_boota.o nvram.o
+
+AOBJS = board_asm_init.o memio.o
+
+OBJS = $(COBJS) $(AOBJS)
+
+## FIXME !!!
+# EMUOBJS = ../bios_emulator/scitech/src/x86emu/*.o
+
+
+$(LIB): .depend $(OBJS) $(EMUOBJS)
+ -rm $(LIB)
+ $(AR) crv $@ $(OBJS) $(EMUOBJS)
+
+#########################################################################
+
+.depend: Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c)
+ $(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/board/MAI/AmigaOneG3SE/articiaS.c b/board/MAI/AmigaOneG3SE/articiaS.c
new file mode 100644
index 0000000..af85444
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/articiaS.c
@@ -0,0 +1,704 @@
+/*
+ * (C) Copyright 2002
+ * Hyperion Entertainment, ThomasF@hyperion-entertainment.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 <common.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include "memio.h"
+#include "articiaS.h"
+#include "smbus.h"
+#include "via686.h"
+
+#undef DEBUG
+
+struct dimm_bank {
+ uint8 used; /* Bank is populated */
+ uint32 rows; /* Number of row addresses */
+ uint32 columns; /* Number of column addresses */
+ uint8 registered; /* SIMM is registered */
+ uint8 ecc; /* SIMM has ecc */
+ uint8 burst_len; /* Supported burst lengths */
+ uint32 cas_lat; /* Supported CAS latencies */
+ uint32 cas_used; /* CAS to use (not set by user) */
+ uint32 trcd; /* RAS to CAS latency */
+ uint32 trp; /* Precharge latency */
+ uint32 tclk_hi; /* SDRAM cycle time (highest CAS latency) */
+ uint32 tclk_2hi; /* SDRAM second highest CAS latency */
+ uint32 size; /* Size of bank in bytes */
+ uint8 auto_refresh; /* Module supports auto refresh */
+ uint32 refresh_time; /* Refresh time (in ns) */
+};
+
+
+/*
+** Based in part on the evb64260 code
+*/
+
+/*
+ * translate ns.ns/10 coding of SPD timing values
+ * into 10 ps unit values
+ */
+static inline unsigned short NS10to10PS (unsigned char spd_byte)
+{
+ unsigned short ns, ns10;
+
+ /* isolate upper nibble */
+ ns = (spd_byte >> 4) & 0x0F;
+ /* isolate lower nibble */
+ ns10 = (spd_byte & 0x0F);
+
+ return (ns * 100 + ns10 * 10);
+}
+
+/*
+ * translate ns coding of SPD timing values
+ * into 10 ps unit values
+ */
+static inline unsigned short NSto10PS (unsigned char spd_byte)
+{
+ return (spd_byte * 100);
+}
+
+
+long detect_sdram (uint8 * rom, int dimmNum, struct dimm_bank *banks)
+{
+ int dimm_address = (dimmNum == 0) ? SM_DIMM0_ADDR : SM_DIMM1_ADDR;
+ uint32 busclock = get_bus_freq (0);
+ uint32 memclock = busclock;
+ uint32 tmemclock = 1000000000 / (memclock / 100);
+ uint32 datawidth;
+
+ if (sm_get_data (rom, dimm_address) == 0) {
+ /* Nothing in slot, make both banks empty */
+ debug ("Slot %d: vacant\n", dimmNum);
+ banks[0].used = 0;
+ banks[1].used = 0;
+ return 0;
+ }
+
+ if (rom[2] != 0x04) {
+ debug ("Slot %d: No SDRAM\n", dimmNum);
+ banks[0].used = 0;
+ banks[1].used = 0;
+ return 0;
+ }
+
+ /* Determine number of banks/rows */
+ if (rom[5] == 1) {
+ banks[0].used = 1;
+ banks[1].used = 0;
+ } else {
+ banks[0].used = 1;
+ banks[1].used = 1;
+ }
+
+ /* Determine number of row addresses */
+ if (rom[3] & 0xf0) {
+ /* Different banks sizes */
+ banks[0].rows = rom[3] & 0x0f;
+ banks[1].rows = (rom[3] & 0xf0) >> 4;
+ } else {
+ /* Equal sized banks */
+ banks[0].rows = rom[3] & 0x0f;
+ banks[1].rows = banks[0].rows;
+ }
+
+ /* Determine number of column addresses */
+ if (rom[4] & 0xf0) {
+ /* Different bank sizes */
+ banks[0].columns = rom[4] & 0x0f;
+ banks[1].columns = (rom[4] & 0xf0) >> 4;
+ } else {
+ banks[0].columns = rom[4] & 0x0f;
+ banks[1].columns = banks[0].columns;
+ }
+
+ /* Check Jedec revision, and modify row/column accordingly */
+ if (rom[62] > 0x10) {
+ if (banks[0].rows <= 3)
+ banks[0].rows += 15;
+ if (banks[1].rows <= 3)
+ banks[1].rows += 15;
+ if (banks[0].columns <= 3)
+ banks[0].columns += 15;
+ if (banks[0].columns <= 3)
+ banks[0].columns += 15;
+ }
+
+ /* Check registered/unregisterd */
+ if (rom[21] & 0x12) {
+ banks[0].registered = 1;
+ banks[1].registered = 1;
+ } else {
+ banks[0].registered = 0;
+ banks[1].registered = 0;
+ }
+
+#ifdef CONFIG_ECC
+ /* Check parity/ECC */
+ banks[0].ecc = (rom[11] == 0x02);
+ banks[1].ecc = (rom[11] == 0x02);
+#endif
+
+ /* Find burst lengths supported */
+ banks[0].burst_len = rom[16] & 0x8f;
+ banks[1].burst_len = rom[16] & 0x8f;
+
+ /* Find possible cas latencies */
+ banks[0].cas_lat = rom[18] & 0x7F;
+ banks[1].cas_lat = rom[18] & 0x7F;
+
+ /* RAS/CAS latency */
+ banks[0].trcd = (NSto10PS (rom[29]) + (tmemclock - 1)) / tmemclock;
+ banks[1].trcd = (NSto10PS (rom[29]) + (tmemclock - 1)) / tmemclock;
+
+ /* Precharge latency */
+ banks[0].trp = (NSto10PS (rom[27]) + (tmemclock - 1)) / tmemclock;
+ banks[1].trp = (NSto10PS (rom[27]) + (tmemclock - 1)) / tmemclock;
+
+ /* highest CAS latency */
+ banks[0].tclk_hi = NS10to10PS (rom[9]);
+ banks[1].tclk_hi = NS10to10PS (rom[9]);
+
+ /* second highest CAS latency */
+ banks[0].tclk_2hi = NS10to10PS (rom[23]);
+ banks[1].tclk_2hi = NS10to10PS (rom[23]);
+
+ /* bank sizes */
+ datawidth = rom[13] & 0x7f;
+ banks[0].size =
+ (1L << (banks[0].rows + banks[0].columns)) *
+ /* FIXME datawidth */ 8 * rom[17];
+ if (rom[13] & 0x80)
+ banks[1].size = 2 * banks[0].size;
+ else
+ banks[1].size = (1L << (banks[1].rows + banks[1].columns)) *
+ /* FIXME datawidth */ 8 * rom[17];
+
+ /* Refresh */
+ if (rom[12] & 0x80) {
+ banks[0].auto_refresh = 1;
+ banks[1].auto_refresh = 1;
+ } else {
+ banks[0].auto_refresh = 0;
+ banks[1].auto_refresh = 0;
+ }
+
+ switch (rom[12] & 0x7f) {
+ case 0:
+ banks[0].refresh_time = (1562500 + (tmemclock - 1)) / tmemclock;
+ banks[1].refresh_time = (1562500 + (tmemclock - 1)) / tmemclock;
+ break;
+ case 1:
+ banks[0].refresh_time = (390600 + (tmemclock - 1)) / tmemclock;
+ banks[1].refresh_time = (390600 + (tmemclock - 1)) / tmemclock;
+ break;
+ case 2:
+ banks[0].refresh_time = (781200 + (tmemclock - 1)) / tmemclock;
+ banks[1].refresh_time = (781200 + (tmemclock - 1)) / tmemclock;
+ break;
+ case 3:
+ banks[0].refresh_time = (3125000 + (tmemclock - 1)) / tmemclock;
+ banks[1].refresh_time = (3125000 + (tmemclock - 1)) / tmemclock;
+ break;
+ case 4:
+ banks[0].refresh_time = (6250000 + (tmemclock - 1)) / tmemclock;
+ banks[1].refresh_time = (6250000 + (tmemclock - 1)) / tmemclock;
+ break;
+ case 5:
+ banks[0].refresh_time = (12500000 + (tmemclock - 1)) / tmemclock;
+ banks[1].refresh_time = (12500000 + (tmemclock - 1)) / tmemclock;
+ break;
+ default:
+ banks[0].refresh_time = 0x100; /* Default of Articia S */
+ banks[1].refresh_time = 0x100;
+ break;
+ }
+
+#ifdef DEBUG
+ printf ("\nInformation for SIMM bank %ld:\n", dimmNum);
+ printf ("Number of banks: %ld\n", banks[0].used + banks[1].used);
+ printf ("Number of row addresses: %ld\n", banks[0].rows);
+ printf ("Number of coumns addresses: %ld\n", banks[0].columns);
+ printf ("SIMM is %sregistered\n",
+ banks[0].registered == 0 ? "not " : "");
+#ifdef CONFIG_ECC
+ printf ("SIMM %s ECC\n",
+ banks[0].ecc == 1 ? "supports" : "doesn't support");
+#endif
+ printf ("Supported burst lenghts: %s %s %s %s %s\n",
+ banks[0].burst_len & 0x08 ? "8" : " ",
+ banks[0].burst_len & 0x04 ? "4" : " ",
+ banks[0].burst_len & 0x02 ? "2" : " ",
+ banks[0].burst_len & 0x01 ? "1" : " ",
+ banks[0].burst_len & 0x80 ? "PAGE" : " ");
+ printf ("Supported CAS latencies: %s %s %s\n",
+ banks[0].cas_lat & 0x04 ? "CAS 3" : " ",
+ banks[0].cas_lat & 0x02 ? "CAS 2" : " ",
+ banks[0].cas_lat & 0x01 ? "CAS 1" : " ");
+ printf ("RAS to CAS latency: %ld\n", banks[0].trcd);
+ printf ("Precharge latency: %ld\n", banks[0].trp);
+ printf ("SDRAM highest CAS latency: %ld\n", banks[0].tclk_hi);
+ printf ("SDRAM 2nd highest CAS latency: %ld\n", banks[0].tclk_2hi);
+ printf ("SDRAM data width: %ld\n", datawidth);
+ printf ("Auto Refresh %ssupported\n",
+ banks[0].auto_refresh ? "" : "not ");
+ printf ("Refresh time: %ld clocks\n", banks[0].refresh_time);
+ if (banks[0].used)
+ printf ("Bank 0 size: %ld MB\n", banks[0].size / 1024 / 1024);
+ if (banks[1].used)
+ printf ("Bank 1 size: %ld MB\n", banks[1].size / 1024 / 1024);
+
+ printf ("\n");
+#endif
+
+ sm_term ();
+ return 1;
+}
+
+void select_cas (struct dimm_bank *banks, uint8 fast)
+{
+ if (!banks[0].used) {
+ banks[0].cas_used = 0;
+ banks[0].cas_used = 0;
+ return;
+ }
+
+ if (fast) {
+ /* Search for fast CAS */
+ uint32 i;
+ uint32 c = 0x01;
+
+ for (i = 1; i < 5; i++) {
+ if (banks[0].cas_lat & c) {
+ banks[0].cas_used = i;
+ banks[1].cas_used = i;
+ debug ("Using CAS %d (fast)\n", i);
+ return;
+ }
+ c <<= 1;
+ }
+
+ /* Default to CAS 3 */
+ banks[0].cas_used = 3;
+ banks[1].cas_used = 3;
+ debug ("Using CAS 3 (fast)\n");
+
+ return;
+ } else {
+ /* Search for slow cas */
+ uint32 i;
+ uint32 c = 0x08;
+
+ for (i = 4; i > 1; i--) {
+ if (banks[0].cas_lat & c) {
+ banks[0].cas_used = i;
+ banks[1].cas_used = i;
+ debug ("Using CAS %d (slow)\n", i);
+ return;
+ }
+ c >>= 1;
+ }
+
+ /* Default to CAS 3 */
+ banks[0].cas_used = 3;
+ banks[1].cas_used = 3;
+ debug ("Using CAS 3 (slow)\n");
+
+ return;
+ }
+
+ banks[0].cas_used = 3;
+ banks[1].cas_used = 3;
+ debug ("Using CAS 3\n");
+
+ return;
+}
+
+uint32 get_reg_setting (uint32 banks, uint32 rows, uint32 columns, uint32 size)
+{
+ uint32 i;
+
+ struct RowColumnSize {
+ uint32 banks;
+ uint32 rows;
+ uint32 columns;
+ uint32 size;
+ uint32 register_value;
+ };
+
+ struct RowColumnSize rcs_map[] = {
+ /* Sbk Radr Cadr MB Value */
+ {1, 11, 8, 8, 0x00840f00},
+ {1, 11, 9, 16, 0x00925f00},
+ {1, 11, 10, 32, 0x00a64f00},
+ {2, 12, 8, 32, 0x00c55f00},
+ {2, 12, 9, 64, 0x00d66f00},
+ {2, 12, 10, 128, 0x00e77f00},
+ {2, 12, 11, 256, 0x00ff8f00},
+ {2, 13, 11, 512, 0x00ff9f00},
+ {0, 0, 0, 0, 0x00000000}
+ };
+
+
+ i = 0;
+
+ while (rcs_map[i].banks != 0) {
+ if (rows == rcs_map[i].rows
+ && columns == rcs_map[i].columns
+ && (size / 1024 / 1024) == rcs_map[i].size)
+ return rcs_map[i].register_value;
+
+ i++;
+ }
+
+ return 0;
+}
+
+uint32 burst_to_len (uint32 support)
+{
+ if (support & 0x80)
+ return 0x7;
+ else if (support & 0x8)
+ return 0x3;
+ else if (support & 0x4)
+ return 0x2;
+ else if (support & 0x2)
+ return 0x1;
+ else if (support & 0x1)
+ return 0x0;
+
+ return 0;
+}
+
+long articiaS_ram_init (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ register uint32 i;
+ register uint32 value1;
+ register uint32 value2;
+ uint8 rom[128];
+ uint32 burst_len;
+ uint32 burst_support;
+ uint32 total_ram = 0;
+
+ struct dimm_bank banks[4]; /* FIXME: Move to initram */
+ uint32 busclock = get_bus_freq (0);
+ uint32 memclock = busclock;
+ uint32 reg32;
+ uint32 refresh_clocks;
+ uint8 auto_refresh;
+
+ memset (banks, 0, sizeof (struct dimm_bank) * 4);
+
+ detect_sdram (rom, 0, &banks[0]);
+ detect_sdram (rom, 1, &banks[2]);
+
+ for (i = 0; i < 4; i++) {
+ total_ram = total_ram + (banks[i].used * banks[i].size);
+ }
+
+ pci_write_cfg_long (0, 0, GLOBALINFO0, 0x117430c0);
+ pci_write_cfg_long (0, 0, HBUSACR0, 0x1f0100b0);
+ pci_write_cfg_long (0, 0, SRAM_CR, 0x00f12000); /* Note: Might also try 0x00f10000 (original: 0x00f12000) */
+ pci_write_cfg_byte (0, 0, DRAM_RAS_CTL0, 0x3f);
+ pci_write_cfg_byte (0, 0, DRAM_RAS_CTL1, 0x00); /* was: 0x04); */
+ pci_write_cfg_word (0, 0, DRAM_ECC0, 0x2020); /* was: 0x2400); No ECC yet */
+
+ /* FIXME: Move this stuff to seperate function, like setup_dimm_bank */
+ if (banks[0].used) {
+ value1 = get_reg_setting (banks[0].used + banks[1].used,
+ banks[0].rows, banks[0].columns,
+ banks[0].size);
+ } else {
+ value1 = 0;
+ }
+
+ if (banks[1].used) {
+ value2 = get_reg_setting (banks[0].used + banks[1].used,
+ banks[1].rows, banks[1].columns,
+ banks[1].size);
+ } else {
+ value2 = 0;
+ }
+
+ pci_write_cfg_long (0, 0, DIMM0_B0_SCR0, value1);
+ pci_write_cfg_long (0, 0, DIMM0_B1_SCR0, value2);
+
+ debug ("DIMM0_B0_SCR0 = 0x%08x\n", value1);
+ debug ("DIMM0_B1_SCR0 = 0x%08x\n", value2);
+
+ if (banks[2].used) {
+ value1 = get_reg_setting (banks[2].used + banks[3].used,
+ banks[2].rows, banks[2].columns,
+ banks[2].size);
+ } else {
+ value1 = 0;
+ }
+
+ if (banks[3].used) {
+ value2 = get_reg_setting (banks[2].used + banks[3].used,
+ banks[3].rows, banks[3].columns,
+ banks[3].size);
+ } else {
+ value2 = 0;
+ }
+
+ pci_write_cfg_long (0, 0, DIMM1_B2_SCR0, value1);
+ pci_write_cfg_long (0, 0, DIMM1_B3_SCR0, value2);
+
+ debug ("DIMM0_B2_SCR0 = 0x%08x\n", value1);
+ debug ("DIMM0_B3_SCR0 = 0x%08x\n", value2);
+
+ pci_write_cfg_long (0, 0, DIMM2_B4_SCR0, 0);
+ pci_write_cfg_long (0, 0, DIMM2_B5_SCR0, 0);
+ pci_write_cfg_long (0, 0, DIMM3_B6_SCR0, 0);
+ pci_write_cfg_long (0, 0, DIMM3_B7_SCR0, 0);
+
+ /* Determine timing */
+ select_cas (&banks[0], 0);
+ select_cas (&banks[2], 0);
+
+ /* FIXME: What about write recovery */
+ /* Auto refresh Precharge */
+#if 0
+ reg32 = (0x3 << 13) | (0x7 << 10) | ((banks[0].trp - 2) << 8) |
+ /* Write recovery CAS Latency */
+ (0x1 << 6) | (banks[0].cas_used << 4) |
+ /* RAS/CAS latency */
+ ((banks[0].trcd - 1) << 0);
+
+ reg32 |= ((0x3 << 13) | (0x7 << 10) | ((banks[2].trp - 2) << 8) |
+ (0x1 << 6) | (banks[2].cas_used << 4) |
+ ((banks[2].trcd - 1) << 0)) << 16;
+#else
+ if (100000000 == gd->bus_clk)
+ reg32 = 0x71737173;
+ else
+ reg32 = 0x69736973;
+#endif
+ pci_write_cfg_long (0, 0, DIMM0_TCR0, reg32);
+ debug ("DIMM0_TCR0 = 0x%08x\n", reg32);
+
+ /* Write default in DIMM2/3 (not used on A1) */
+ pci_write_cfg_long (0, 0, DIMM2_TCR0, 0x7d737d73);
+
+
+ /* Determine buffered/unbuffered mode for each SIMM. Uses first bank as reference (second, if present, uses the same) */
+ reg32 = pci_read_cfg_long (0, 0, DRAM_GCR0);
+ reg32 &= 0xFF00FFFF;
+
+#if 0
+ if (banks[0].used && banks[0].registered)
+ reg32 |= 0x1 << 16;
+
+ if (banks[2].used && banks[2].registered)
+ reg32 |= 0x1 << 18;
+#else
+ if (banks[0].registered || banks[2].registered)
+ reg32 |= 0x55 << 16;
+#endif
+ pci_write_cfg_long (0, 0, DRAM_GCR0, reg32);
+ debug ("DRAM_GCR0 = 0x%08x\n", reg32);
+
+ /* Determine refresh */
+ refresh_clocks = 0xffffffff;
+ auto_refresh = 1;
+
+ for (i = 0; i < 4; i++) {
+ if (banks[i].used) {
+ if (banks[i].auto_refresh == 0)
+ auto_refresh = 0;
+ if (banks[i].refresh_time < refresh_clocks)
+ refresh_clocks = banks[i].refresh_time;
+ }
+ }
+
+
+#if 1
+ /* It seems this is suggested by the ArticiaS data book */
+ if (100000000 == gd->bus_clk)
+ refresh_clocks = 1561;
+ else
+ refresh_clocks = 2083;
+#endif
+
+
+ debug ("Refresh set to %ld clocks, auto refresh %s\n",
+ refresh_clocks, auto_refresh ? "on" : "off");
+
+ pci_write_cfg_long (0, 0, DRAM_REFRESH0,
+ (1 << 16) | (1 << 15) | (auto_refresh << 12) |
+ (refresh_clocks));
+ debug ("DRAM_REFRESH0 = 0x%08x\n",
+ (1 << 16) | (1 << 15) | (auto_refresh << 12) |
+ (refresh_clocks));
+
+/* pci_write_cfg_long(0, 0, DRAM_REFRESH0, 0x00019400); */
+
+ /* Set mode registers */
+ /* FIXME: For now, set same burst len for all modules. Dunno if that's necessary */
+ /* Find a common burst len */
+ burst_support = 0xff;
+
+ if (banks[0].used)
+ burst_support = banks[0].burst_len;
+ if (banks[1].used)
+ burst_support = banks[1].burst_len;
+ if (banks[2].used)
+ burst_support = banks[2].burst_len;
+ if (banks[3].used)
+ burst_support = banks[3].burst_len;
+
+ /*
+ ** Mode register:
+ ** Bits Use
+ ** 0-2 Burst len
+ ** 3 Burst type (0 = sequential, 1 = interleave)
+ ** 4-6 CAS latency
+ ** 7-8 Operation mode (0 = default, all others invalid)
+ ** 9 Write burst
+ ** 10-11 Reserved
+ **
+ ** Mode register burst table:
+ ** A2 A1 A0 lenght
+ ** 0 0 0 1
+ ** 0 0 1 2
+ ** 0 1 0 4
+ ** 0 1 1 8
+ ** 1 0 0 invalid
+ ** 1 0 1 invalid
+ ** 1 1 0 invalid
+ ** 1 1 1 page (only valid for non-interleaved)
+ */
+
+ burst_len = burst_to_len (burst_support);
+ burst_len = 2; /* FIXME */
+
+ if (banks[0].used) {
+ pci_write_cfg_word (0, 0, DRAM_PCR0,
+ 0x8000 | burst_len | (banks[0].cas_used << 4));
+ debug ("Mode bank 0: 0x%08x\n",
+ 0x8000 | burst_len | (banks[0].cas_used << 4));
+ } else {
+ /* Seems to be needed to disable the bank */
+ pci_write_cfg_word (0, 0, DRAM_PCR0, 0x0000 | 0x032);
+ }
+
+ if (banks[1].used) {
+ pci_write_cfg_word (0, 0, DRAM_PCR0,
+ 0x9000 | burst_len | (banks[1].cas_used << 4));
+ debug ("Mode bank 1: 0x%08x\n",
+ 0x8000 | burst_len | (banks[1].cas_used << 4));
+ } else {
+ /* Seems to be needed to disable the bank */
+ pci_write_cfg_word (0, 0, DRAM_PCR0, 0x1000 | 0x032);
+ }
+
+
+ if (banks[2].used) {
+ pci_write_cfg_word (0, 0, DRAM_PCR0,
+ 0xa000 | burst_len | (banks[2].cas_used << 4));
+ debug ("Mode bank 2: 0x%08x\n",
+ 0x8000 | burst_len | (banks[2].cas_used << 4));
+ } else {
+ /* Seems to be needed to disable the bank */
+ pci_write_cfg_word (0, 0, DRAM_PCR0, 0x2000 | 0x032);
+ }
+
+
+ if (banks[3].used) {
+ pci_write_cfg_word (0, 0, DRAM_PCR0,
+ 0xb000 | burst_len | (banks[3].cas_used << 4));
+ debug ("Mode bank 3: 0x%08x\n",
+ 0x8000 | burst_len | (banks[3].cas_used << 4));
+ } else {
+ /* Seems to be needed to disable the bank */
+ pci_write_cfg_word (0, 0, DRAM_PCR0, 0x3000 | 0x032);
+ }
+
+
+ pci_write_cfg_word (0, 0, 0xba, 0x00);
+
+ return total_ram;
+}
+
+extern int drv_isa_kbd_init (void);
+
+int last_stage_init (void)
+{
+ drv_isa_kbd_init ();
+ return 0;
+}
+
+int overwrite_console (void)
+{
+ return (0);
+}
+
+#define in_8 read_byte
+#define out_8 write_byte
+
+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));
+}
+
+int board_pre_init (void)
+{
+ unsigned char c_value = 0;
+ unsigned long msr;
+
+ /* Basic init of PS/2 keyboard (needed for some reason)... */
+ /* Ripped from John's code */
+ while ((in_8 ((unsigned char *) 0xfe000064) & 0x02) != 0);
+ out_8 ((unsigned char *) 0xfe000064, 0xaa);
+ while ((in_8 ((unsigned char *) 0xfe000064) & 0x01) == 0);
+ c_value = in_8 ((unsigned char *) 0xfe000060);
+ while ((in_8 ((unsigned char *) 0xfe000064) & 0x02) != 0);
+ out_8 ((unsigned char *) 0xfe000064, 0xab);
+ while ((in_8 ((unsigned char *) 0xfe000064) & 0x01) == 0);
+ c_value = in_8 ((unsigned char *) 0xfe000060);
+ while ((in_8 ((unsigned char *) 0xfe000064) & 0x02) != 0);
+ out_8 ((unsigned char *) 0xfe000064, 0xae);
+/* while ((in_8((unsigned char *)0xfe000064) & 0x01) == 0); */
+/* c_value = in_8((unsigned char *)0xfe000060); */
+
+ /* Enable FPU */
+ msr = get_msr ();
+ set_msr (msr | MSR_FP);
+
+ via_calibrate_bus_freq ();
+
+ return 0;
+}
diff --git a/board/MAI/AmigaOneG3SE/articiaS.h b/board/MAI/AmigaOneG3SE/articiaS.h
new file mode 100644
index 0000000..158d70a
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/articiaS.h
@@ -0,0 +1,143 @@
+#ifndef ARTICIAS_H
+#define ARTICIAS_H
+
+#include "short_types.h"
+#include <common.h>
+
+#define REG_GROUP 0xF0
+
+/* ArticiaS registers */
+#define GLOBALINFO0 0x50
+#define GLOBALINFO1 0x51
+#define GLOBALINFO2 0x52
+#define GLOBALINFO3 0x53
+#define GLOBALCTL0 0x54
+#define GLOBALCTL1 0x55
+#define NVRAMCTL 0x56
+#define PCI1ACR0 0x58
+#define PCI1ACR1 0x59
+#define PCI1ACR2 0x5a
+#define PCI1ACR3 0x5b
+#define HBUSACR0 0x5c
+#define HBUSACR1 0x5d
+#define HBUSACR2 0x5e
+#define HBUSACR3 0x5f
+#define HOSTINT0 0x68
+#define HOSTINT1 0x69
+#define HOSTINT2 0x6a
+#define HOSTINT3 0x6b
+#define HOSTRBCR 0x70
+#define XDBCR 0x74
+
+#define LBSBCR2 0xd2
+
+
+/* Memory controller */
+
+#define DIMM0_B0_SCR0 0x90
+#define DIMM0_B1_SCR0 0x94
+#define DIMM1_B2_SCR0 0x98
+#define DIMM1_B3_SCR0 0x9c
+#define DIMM2_B4_SCR0 0xa0
+#define DIMM2_B5_SCR0 0xa4
+#define DIMM3_B6_SCR0 0xa8
+#define DIMM3_B7_SCR0 0xac
+
+#define DIMM0_TCR0 0xb0
+#define DIMM1_TCR0 0xb2
+#define DIMM2_TCR0 0xb4
+#define DIMM3_TCR0 0xb6
+
+#define DRAM_REFRESH0 0xb8
+#define DRAM_GCR0 0xc0
+#define DRAM_PCR0 0xc6
+#define DRAM_ECC0 0xc4
+#define SRAM_CR 0xc8
+#define DRAM_RAS_CTL0 0xcc
+#define DRAM_RAS_CTL1 0xcd
+
+/* Bits for REG_GROUP */
+#define REG_GROUP_MULTI (1<<1)
+#define REG_GROUP_SPECIAL (1<<3)
+#define REG_GROUP_DIAG (0x1<<4)
+#define REG_GROUP_POWER (0x2<<4)
+
+
+#define GLOBALINFO0_BO (1<<7)
+
+
+#define GLOBALINFO2_B1ARBITER (1<<6)
+
+
+#define HBUSACR0_CPUAPC (1<<0)
+#define HBUSACR0_NUMREQ_2 (0<<1)
+#define HBUSACR0_NUMREQ_3 (1<<1)
+#define HBUSACR0_NUMREQ_4 (2<<1)
+#define HBUSACR0_NUMREQ_MASK (7<<1)
+#define HBUSACR0_RAW (1<<6)
+#define HBUSACR0_WAIT (1<<7)
+#define HBUSACR0_RESERVED (0x30)
+
+
+#define HBUSACR2_BURST (1<<0)
+#define HBUSACR2_LAT (1<<1)
+
+
+#define HBUSACR3_LMWC_SM (1<<0)
+#define HBUSACR3_LMWC_PCI1 (1<<1)
+#define HBUSACR3_LMWC_PCI0 (1<<2)
+#define HBUSACR3_PMWC_PCI1 (1<<3)
+#define HBUSACR3_PMWC_PCI0 (1<<4)
+#define HBUSACR3_FKH (1<<5)
+#define HBUSACR3_92H_EN (1<<6)
+#define HBUSACR3_60H_64H_EN (1<<7)
+
+
+#define HOSTRBCR_PREFETCH (1<<4)
+
+
+#define XDBCR_HWTOXD (1<<0)
+#define XDBCR_KBTOXD (1<<1)
+#define XDBCR_RTCTOXD (1<<2)
+#define XDBCR_SCALE_1_1 (0x0<<3)
+#define XDBCR_SCALE_2_2 (0x1<<3)
+#define XDBCR_SCALE_3_2 (0x2<<3)
+#define XDBCR_SCALE_4_4 (0x3<<3)
+#define XDBCR_SCALE_5_8 (0x4<<3)
+#define XDBCR_SCALE_6_8 (0x5<<3)
+#define XDBCR_SCALE_8_8 (0x6<<3)
+#define XDBCR_SCALE_0_16 (0x7<<3)
+#define XDBCR_XDPROM (1<<7)
+
+
+#define LBSBCR2_1_RWAC (1<<2)
+
+
+/* PCI controller */
+#define ARTICIAS_PCI_CFGADDR 0xfec00cf8
+#define ARTICIAS_PCI_CFGDATA 0xfee00cfc
+
+#define ARTICIAS_PCI_BUS 0x80000000
+#define ARTICIAS_PCI_MAXSIZE 0x7cffffff
+#define ARTICIAS_PCI_PHYS 0x80000000
+
+#define ARTICIAS_SYS_BUS 0x00000000
+#define ARTICIAS_SYS_MAXSIZE 0x7fffffff
+#define ARTICIAS_SYS_PHYS 0x00000000
+
+#define ARTICIAS_PCIIO_BUS 0x00800000
+#define ARTICIAS_PCIIO_MAXSIZE 0x003fffff
+#define ARTICIAS_PCIIO_PHYS 0xfe800000
+
+#define ARTICIAS_ISAIO_BUS 0x00002000
+#define ARTICIAS_ISAIO_MAXSIZE 0x0000d000
+#define ARTICIAS_ISAIO_PHYS 0xfe002000
+
+
+
+/* Prototypes */
+long articiaS_ram_init(void);
+void articiaS_pci_init(void);
+
+
+#endif
diff --git a/board/MAI/AmigaOneG3SE/articiaS_pci.c b/board/MAI/AmigaOneG3SE/articiaS_pci.c
new file mode 100644
index 0000000..774c32d
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/articiaS_pci.c
@@ -0,0 +1,573 @@
+/*
+ * (C) Copyright 2002
+ * Hyperion Entertainment, Hans-JoergF@hyperion-entertainment.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 <common.h>
+#include <pci.h>
+#include "memio.h"
+#include "articiaS.h"
+
+//#define ARTICIA_PCI_DEBUG
+
+#ifdef ARTICIA_PCI_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+struct pci_controller articiaS_hose;
+
+long irq_alloc(long wanted);
+
+static pci_dev_t pci_hose_find_class(struct pci_controller *hose, int bus, short find_class, int index);
+static int articiaS_init_vga(void);
+static void pci_cfgfunc_dummy(struct pci_controller *host, pci_dev_t dev, struct pci_config_table *table);
+unsigned char pci_irq_alloc(void);
+
+extern void via_cfgfunc_via686(struct pci_controller * host, pci_dev_t dev, struct pci_config_table *table);
+extern void via_cfgfunc_ide_init(struct pci_controller *host, pci_dev_t dev, struct pci_config_table *table);
+extern void via_init_irq_routing(uint8 []);
+extern void via_init_afterscan(void);
+
+#define cfgfunc_via686 1
+#define cfgfunc_dummy 2
+#define cfgfunc_ide_init 3
+
+static struct pci_config_table config_table[] =
+{
+ {
+ 0x1106, PCI_ANY_ID, PCI_CLASS_BRIDGE_ISA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ (void *)cfgfunc_via686, {0, 0, 0}
+ },
+ {
+ 0x1106, PCI_ANY_ID, PCI_ANY_ID, 0,7,4,
+ (void *)cfgfunc_dummy, {0,0,0}
+ },
+ {
+ 0x1106, 0x3068, PCI_ANY_ID, 0, 7, PCI_ANY_ID,
+ (void *)cfgfunc_dummy, {0,0,0}
+ },
+ {
+ 0x1106, PCI_ANY_ID, PCI_ANY_ID, 0,7,1,
+ (void *)cfgfunc_ide_init, {0,0,0}
+ },
+ {
+ 0,
+ }
+};
+
+
+void pci_cfgfunc_dummy(struct pci_controller *host, pci_dev_t dev, struct pci_config_table *table)
+{
+
+
+}
+
+unsigned long irq_penalties[16] =
+{
+ 1000, /* 0:timer */
+ 1000, /* 1:keyboard */
+ 1000, /* 2:cascade */
+ 50, /* 3:serial (COM2) */
+ 50, /* 4:serial (COM1) */
+ 4, /* 5:USB2 */
+ 100, /* 6:floppy */
+ 3, /* 7:parallel */
+ 50, /* 8:AC97/MC97 */
+ 0, /* 9: */
+ 3, /* 10:: */
+ 0, /* 11: */
+ 3, /* 12: USB1 */
+ 0, /* 13: */
+ 100, /* 14: ide0 */
+ 100, /* 15: ide1 */
+};
+
+
+/*
+ * The following defines a hard-coded interrupt mapping for the
+ * know devices on the board.
+ * If a device isn't found here, assumed to be a device that's
+ * plugged into a PCI or AGP slot
+ * NOTE: This table is machine dependant.
+ */
+
+struct pci_irq_fixup_table
+{
+ uint8 bus; /* Bus number */
+ uint8 device; /* Device number */
+ uint8 func; /* Function number */
+ uint8 interrupt; /* Interrupt to use (0xff to disable) */
+};
+
+struct pci_irq_fixup_table fixuptab [] =
+{
+ { 0, 0, 0, 0xff}, /* Articia S host bridge */
+ { 0, 1, 0, 0xff}, /* Articia S AGP bridge */
+// { 0, 6, 0, 0x05}, /* 3COM ethernet */
+ { 0, 7, 0, 0xff}, /* VIA southbridge */
+ { 0, 7, 1, 0x0e}, /* IDE controller in legacy mode */
+// { 0, 7, 2, 0x05}, /* First USB controller */
+// { 0, 7, 3, 0x0c}, /* Second USB controller (shares interrupt with ethernet) */
+ { 0, 7, 4, 0xff}, /* ACPI Power Management */
+// { 0, 7, 5, 0x08}, /* AC97 */
+// { 0, 7, 6, 0x08}, /* MC97 */
+ { 0xff, 0xff, 0xff, 0xff}
+};
+
+
+/*
+ * This table maps IRQ's to PCI interrupts
+ */
+
+uint8 pci_intmap[4] = {0, 0, 0, 0};
+
+/*
+ * Map PCI slots to interrupt routings
+ * This table lists the device number assigned to a card inserted
+ * into the slot, along with a permutation for the slot's IRQ routing.
+ * NOTE: This table is machine dependant.
+ */
+
+struct pci_slot_irq_routing
+{
+ uint8 bus;
+ uint8 device;
+
+ uint8 ints[4];
+};
+
+struct pci_slot_irq_routing amigaone_pci_routing[] =
+{
+ {0, 8, {0, 1, 2, 3}}, /* Slot 1 (left of riser slot) */
+ {0, 9, {1, 2, 3, 0}}, /* Slot 2 (middle slot) */
+ {0, 10, {2, 3, 0, 1}}, /* Slot 3 (leftmost slot) */
+ {1, 0, {1, 0, 2, 3}}, /* AGP slot (only IRQA and IRQB) */
+ {1, 1, {1, 2, 3, 0}}, /* PCI slot on AGP bus */
+ {0, 6, {3, 3, 3, 3}}, /* On board ethernet */
+ {0, 7, {0, 1, 2, 3}}, /* Southbridge */
+ {0xff, 0, {0, 0, 0, 0}}
+};
+
+void articiaS_pci_irq_init(void)
+{
+ char *s;
+
+ s = getenv("pci_irqa");
+ if (s)
+ pci_intmap[0] = simple_strtoul (s, NULL, 10);
+ else
+ pci_intmap[0] = pci_irq_alloc();
+
+ s = getenv("pci_irqb");
+ if (s)
+ pci_intmap[1] = simple_strtoul (s, NULL, 10);
+ else
+ pci_intmap[1] = pci_irq_alloc();
+
+ s = getenv("pci_irqc");
+ if (s)
+ pci_intmap[2] = simple_strtoul (s, NULL, 10);
+ else
+ pci_intmap[2] = pci_irq_alloc();
+
+ s = getenv("pci_irqd");
+ if (s)
+ pci_intmap[3] = simple_strtoul (s, NULL, 10);
+ else
+ pci_intmap[3] = pci_irq_alloc();
+}
+
+
+unsigned char pci_irq_alloc(void)
+{
+ int i;
+ int interrupt = 10;
+ unsigned long min_penalty = 1000;
+
+ /* Search for the minimal penalty, favoring interrupts at the end */
+ for (i = 0; i < 16; i++)
+ {
+ if (irq_penalties[i] <= min_penalty)
+ {
+ interrupt = i;
+ min_penalty = irq_penalties[i];
+ }
+ }
+
+ PRINTF("pci_irq_alloc: Minimal penalty is %ld for %d\n", min_penalty, interrupt);
+
+ irq_penalties[interrupt]++;
+
+ return interrupt;
+}
+
+
+void articiaS_pci_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+ int8 bus, device, func, pin, line;
+ int i;
+
+ bus = PCI_BUS(dev);
+ device = PCI_DEV(dev);
+ func = PCI_FUNC(dev);
+
+ PRINTF("Fixup irq of %d:%d.%d\n", bus, device, func);
+
+ /* Search for the device in the table */
+ for (i = 0; fixuptab[i].bus != 0xff; i++)
+ {
+ if (bus == fixuptab[i].bus && device == fixuptab[i].device && func == fixuptab[i].func)
+ {
+ /* If the device needs an interrupt, write it */
+ if (fixuptab[i].interrupt != 0xff)
+ {
+ PRINTF("Assigning IRQ %d (fixed)\n", fixuptab[i].interrupt);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, fixuptab[i].interrupt);
+ }
+ else
+ {
+ /* Otherwise, see if it wants an interrupt, and disable it if needed */
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin)
+ {
+ PRINTF("Disabling IRQ\n");
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 0xff);
+ }
+ }
+
+ return;
+ }
+ }
+
+ /* If we get here, we have another PCI device in a slot... find the appropriate IRQ */
+
+ /* Find matching pin */
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ pin--;
+
+ /* Search for it's map */
+ for (i = 0; amigaone_pci_routing[i].bus != 0xff; i++)
+ {
+ if (bus == amigaone_pci_routing[i].bus && device == amigaone_pci_routing[i].device)
+ {
+ line = pci_intmap[amigaone_pci_routing[i].ints[pin]];
+ PRINTF("Assigning IRQ %d (pin %d)\n", line, pin);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, line);
+ return;
+ }
+ }
+
+ PRINTF("Unkonwn PCI device found\n");
+}
+
+void articiaS_pci_init (void)
+{
+ int i;
+ char *s;
+
+ PRINTF("atriciaS_pci_init\n");
+
+ // Why aren't these relocated??
+ for (i=0; config_table[i].config_device; i++)
+ {
+ switch((int)config_table[i].config_device)
+ {
+ case cfgfunc_via686: config_table[i].config_device = via_cfgfunc_via686; break;
+ case cfgfunc_dummy: config_table[i].config_device = pci_cfgfunc_dummy; break;
+ case cfgfunc_ide_init: config_table[i].config_device = via_cfgfunc_ide_init; break;
+ default: PRINTF("Error: Unknown constant\n");
+ }
+ }
+
+ articiaS_hose.first_busno = 0;
+ articiaS_hose.last_busno = 0xff;
+ articiaS_hose.config_table = config_table;
+ articiaS_hose.fixup_irq = articiaS_pci_fixup_irq;
+
+ articiaS_pci_irq_init();
+
+ /* System memory */
+ pci_set_region(articiaS_hose.regions + 0,
+ ARTICIAS_SYS_BUS,
+ ARTICIAS_SYS_PHYS,
+ ARTICIAS_SYS_MAXSIZE,
+ PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(articiaS_hose.regions + 1,
+ ARTICIAS_PCI_BUS,
+ ARTICIAS_PCI_PHYS,
+ ARTICIAS_PCI_MAXSIZE,
+ PCI_REGION_MEM);
+
+ /* PCI io space */
+ pci_set_region(articiaS_hose.regions + 2,
+ ARTICIAS_PCIIO_BUS,
+ ARTICIAS_PCIIO_PHYS,
+ ARTICIAS_PCIIO_MAXSIZE,
+ PCI_REGION_IO);
+
+ /* PCI/ISA io space */
+ pci_set_region(articiaS_hose.regions + 3,
+ ARTICIAS_ISAIO_BUS,
+ ARTICIAS_ISAIO_PHYS,
+ ARTICIAS_ISAIO_MAXSIZE,
+ PCI_REGION_IO);
+
+
+
+ articiaS_hose.region_count = 4;
+
+ pci_setup_indirect(&articiaS_hose, ARTICIAS_PCI_CFGADDR, ARTICIAS_PCI_CFGDATA);
+ PRINTF("Registering articia hose...\n");
+ pci_register_hose(&articiaS_hose);
+ PRINTF("Enabling AGP...\n");
+ pci_write_config_byte(PCI_BDF(0,0,0), 0x58, 0x01);
+ PRINTF("Scanning bus...\n");
+ articiaS_hose.last_busno = pci_hose_scan(&articiaS_hose);
+
+ via_init_irq_routing(pci_intmap);
+
+ PRINTF("After-Scan results:\n");
+ PRINTF("Bus range: %d - %d\n", articiaS_hose.first_busno , articiaS_hose.last_busno);
+
+ via_init_afterscan();
+
+ pci_write_config_byte(PCI_BDF(0,1,0), PCI_INTERRUPT_LINE, 0xFF);
+
+ s = getenv("as_irq");
+ if (s)
+ {
+ pci_write_config_byte(PCI_BDF(0,0,0), PCI_INTERRUPT_LINE, simple_strtoul (s, NULL, 10));
+ }
+
+ s = getenv("x86_run_bios");
+ if (!s || (s && strcmp(s, "on")==0))
+ {
+ if (articiaS_init_vga() == -1)
+ {
+ /* If the VGA didn't init and we have stdout set to VGA, reset to serial */
+/* s = getenv("stdout"); */
+/* if (s && strcmp(s, "vga") == 0) */
+/* { */
+/* setenv("stdout", "serial"); */
+/* } */
+ }
+ }
+ pci_write_config_byte(PCI_BDF(0,1,0), PCI_INTERRUPT_LINE, 0xFF);
+
+}
+
+pci_dev_t pci_hose_find_class(struct pci_controller *hose, int bus, short find_class, int index)
+{
+ unsigned int sub_bus, found_multi=0;
+ unsigned short vendor, class;
+ unsigned char header_type;
+ pci_dev_t dev;
+ u8 c1, c2;
+
+ sub_bus = bus;
+
+ for (dev = PCI_BDF(bus,0,0);
+ dev < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1);
+ dev += PCI_BDF(0,0,1))
+ {
+ if ( dev == PCI_BDF(hose->first_busno,0,0) )
+ continue;
+
+ if (PCI_FUNC(dev) && !found_multi)
+ continue;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
+
+ pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor);
+
+ if (vendor != 0xffff && vendor != 0x0000)
+ {
+
+ if (!PCI_FUNC(dev))
+ found_multi = header_type & 0x80;
+ pci_hose_read_config_byte(hose, dev, 0x0B, &c1);
+ pci_hose_read_config_byte(hose, dev, 0x0A, &c2);
+ class = c1<<8 | c2;
+ //printf("At %02x:%02x:%02x: class %x\n",
+ // PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev), class);
+ if (class == find_class)
+ {
+ if (index == 0)
+ return dev;
+ else index--;
+ }
+ }
+ }
+
+ return ~0;
+}
+
+
+/*
+ * For a given bus number, find the bridge on this hose that provides this
+ * bus number. The function scans for bridges and peeks config space offset
+ * 0x19 (PCI_SECONDARY_BUS).
+ */
+pci_dev_t pci_find_bridge_for_bus(struct pci_controller *hose, int busnr)
+{
+ pci_dev_t dev;
+ int bus;
+ unsigned int found_multi=0;
+ unsigned char header_type;
+ unsigned short vendor;
+ unsigned char secondary_bus;
+
+ if (hose == NULL) hose = &articiaS_hose;
+
+ if (busnr < hose->first_busno || busnr > hose->last_busno) return PCI_ANY_ID; // Not in range
+
+ /*
+ * The bridge must be on a lower bus number
+ */
+ for (bus = hose->first_busno; bus < busnr; bus++)
+ {
+ for (dev = PCI_BDF(bus,0,0);
+ dev < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1);
+ dev += PCI_BDF(0,0,1))
+ {
+ if ( dev == PCI_BDF(hose->first_busno,0,0) )
+ continue;
+
+ if (PCI_FUNC(dev) && !found_multi)
+ continue;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
+
+ pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor);
+
+ if (vendor != 0xffff && vendor != 0x0000)
+ {
+
+ if (!PCI_FUNC(dev))
+ found_multi = header_type & 0x80;
+ if (header_type == 1) // Bridge device header
+ {
+ pci_hose_read_config_byte(hose, dev, PCI_SECONDARY_BUS, &secondary_bus);
+ if ((int)secondary_bus == busnr) return dev;
+ }
+
+ }
+ }
+ }
+ return PCI_ANY_ID;
+}
+
+static short classes[] =
+{
+ PCI_CLASS_DISPLAY_VGA,
+ PCI_CLASS_DISPLAY_XGA,
+ PCI_CLASS_DISPLAY_3D,
+ PCI_CLASS_DISPLAY_OTHER,
+ ~0
+};
+
+extern int execute_bios(pci_dev_t gr_dev, void *);
+
+pci_dev_t video_dev;
+
+int articiaS_init_vga (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ extern void shutdown_bios(void);
+ pci_dev_t dev = ~0;
+ int busnr = 0;
+ int classnr = 0;
+
+ video_dev = PCI_ANY_ID;
+
+ printf("VGA: ");
+
+ PRINTF("Trying to initialize x86 VGA Card(s)\n");
+
+ while (dev == ~0)
+ {
+ PRINTF("Searching for class 0x%x on bus %d\n", classes[classnr], busnr);
+ /* Find the first of this class on this bus */
+ dev = pci_hose_find_class(&articiaS_hose, busnr, classes[classnr], 0);
+ if (dev != ~0) break;
+ busnr++;
+ if (busnr > articiaS_hose.last_busno)
+ {
+ busnr = 0;
+ classnr ++;
+ if (classes[classnr] == ~0)
+ {
+ printf("NOT PRESENT\n");
+ return -1;
+ }
+ }
+ }
+
+ /*
+ * If we get here we have found the first graphics card.
+ * If the bus number is not 0, then it is probably behind a bridge, and the
+ * bridge needs to be told to forward VGA access.
+ */
+
+ if (PCI_BUS(dev) != 0)
+ {
+ pci_dev_t bridge;
+ PRINTF("Behind bridge, looking for bridge\n");
+ bridge = pci_find_bridge_for_bus(&articiaS_hose, PCI_BUS(dev));
+ if (dev != PCI_ANY_ID)
+ {
+ unsigned char agp_control_0;
+ PRINTF("Got the bridge at %02x:%02x:%02x\n",
+ PCI_BUS(bridge), PCI_DEV(bridge), PCI_FUNC(bridge));
+ pci_hose_read_config_byte(&articiaS_hose, bridge, 0x3E, &agp_control_0);
+ agp_control_0 |= 0x18;
+ pci_hose_write_config_byte(&articiaS_hose, bridge, 0x3E, agp_control_0);
+ PRINTF("Configured for VGA forwarding\n");
+ }
+ }
+
+ /*
+ * Now try to run the bios
+ */
+
+ if (execute_bios(dev, gd->relocaddr))
+ {
+ printf("OK\n");
+ video_dev = dev;
+ }
+ else
+ {
+ printf("ERROR\n");
+ }
+
+ PRINTF("Done scanning.\n");
+
+ shutdown_bios();
+
+ if (dev == PCI_ANY_ID) return -1;
+ else return 0;
+
+}
diff --git a/board/MAI/AmigaOneG3SE/board_asm_init.S b/board/MAI/AmigaOneG3SE/board_asm_init.S
new file mode 100644
index 0000000..a421c5d
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/board_asm_init.S
@@ -0,0 +1,157 @@
+ #include "macros.h"
+
+
+
+#define GLOBALINFO0 0x50
+#define GLOBALINFO0_BO (1<<7)
+#define GLOBALINFO2_B1ARBITER (1<<6)
+#define HBUSACR0 0x5c
+#define HBUSACR2_BURST (1<<0)
+#define HBUSACR2_LAT (1<<1)
+
+#define RECEIVER_HOLDING 0
+#define TRANSMITTER_HOLDING 0
+#define INTERRUPT_ENABLE 1
+#define INTERRUPT_STATUS 2
+#define FIFO_CONTROL 2
+#define LINE_CONTROL 3
+#define MODEM_CONTROL 4
+#define LINE_STATUS 5
+#define MODEM_STATUS 6
+#define SCRATCH_PAD 7
+
+#define DIVISOR_LATCH_LSB 0
+#define DIVISOR_LATCH_MSB 1
+#define PRESCALER_DIVISION 5
+
+#define UART(x) (0x3f8+(x))
+
+#define GLOBALINFO0 0x50
+#define GLOBALINFO0_BO (1<<7)
+#define GLOBALINFO2_B1ARBITER (1<<6)
+#define HBUSACR0 0x5c
+#define HBUSACR2_BURST (1<<0)
+#define HBUSACR2_LAT (1<<1)
+
+#define SUPERIO_1 ((7 << 3) | (0))
+#define SUPERIO_2 ((7 << 3) | (1))
+
+ .globl board_asm_init
+
+board_asm_init:
+ mflr r29
+ /* Set 'Must-set' register */
+ li r3, 0
+ li r4, 0
+ li r5, 0x5e
+ bl pci_read_cfg_byte
+ ori r3, r3, (1<<1)
+ xori r6, r3, (1<<1)
+ li r3, 0
+ bl pci_write_cfg_byte
+
+ li r3, 0
+ li r5, 0x52
+ bl pci_read_cfg_byte
+ ori r6, r3, (1<<6)
+ li r3, 0
+ bl pci_write_cfg_byte
+
+ li r3, 0
+ li r4, 0x08
+ li r5, 0xd2
+ bl pci_read_cfg_byte
+ ori r6, r3, (1<<2)
+ li r3, 0
+ bl pci_write_cfg_byte
+
+
+ /* Do PCI reset */
+/* li r3, 0
+ li r4, 0x38
+ li r5, 0x47
+ bl pci_read_cfg_byte
+ ori r6, r3, 0x01
+ li r3, 0
+ li r4, 0x38
+ li r5, 0x47
+ bl pci_write_cfg_byte*/
+
+
+ /* Enable NVRAM for environment */
+ li r3, 0
+ li r4, 0
+ li r5, 0x56
+ li r6, 0x0B
+ bl pci_write_cfg_byte
+
+
+ /* Init Super-I/O chips */
+
+ siowb 0x40, 0x08
+ siowb 0x41, 0x01
+ siowb 0x45, 0x80
+ siowb 0x46, 0x60
+ siowb 0x47, 0x20
+ siowb 0x48, 0x01
+ siowb 0x4a, 0xc4
+ siowb 0x50, 0x0e
+ siowb 0x51, 0x76
+ siowb 0x52, 0x34
+ siowb 0x54, 0x00
+ siowb 0x55, 0x90
+ siowb 0x56, 0x99
+ siowb 0x57, 0x90
+ siowb 0x85, 0x01
+
+ /* Enable configuration mode for SuperIO */
+ li r3, 0
+ li r4, (7<<3)
+ li r5, 0x85
+ bl pci_read_cfg_byte
+ ori r6, r3, 0x02
+ mr r31, r6
+ li r3,0
+ bl pci_write_cfg_byte
+
+ /* COM1 as 3f8 */
+ outb 0x3f0, 0xe7
+ outb 0x3f1, 0xfe
+
+ /* COM2 as 2f8 */
+ outb 0x3f0, 0xe8
+ outb 0x3f1, 0xeb
+
+ /* Enable */
+ outb 0x3f0, 0xe2
+ inb r3, 0x3f1
+ ori r3, r3, 0x0c
+ outb 0x3f0, 0xe2
+ outbr 0x3f1, r3
+
+ /* Disable configuration mode */
+ li r3, 0
+ li r4, (7<<3)
+ li r5, 0x85
+ mr r6, r31
+ bl pci_write_cfg_byte
+
+ /* Set line control */
+ outb UART(LINE_CONTROL), 0x83
+ outb UART(DIVISOR_LATCH_LSB), 0x0c
+ outb UART(DIVISOR_LATCH_MSB), 0x00
+ outb UART(LINE_CONTROL), 0x3
+
+ mtlr r29
+ blr
+
+
+ .globl new_reset
+ .globl new_reset_end
+new_reset:
+ li r0, 0x100
+ oris r0, r0, 0xFFF0
+ mtlr r0
+ blr
+
+new_reset_end: \ No newline at end of file
diff --git a/board/MAI/AmigaOneG3SE/cmd_boota.c b/board/MAI/AmigaOneG3SE/cmd_boota.c
new file mode 100644
index 0000000..140aaff
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/cmd_boota.c
@@ -0,0 +1,123 @@
+#include <common.h>
+#include <command.h>
+#include <cmd_boota.h>
+#include "../disk/part_amiga.h"
+#include <asm/cache.h>
+
+
+#undef BOOTA_DEBUG
+
+#ifdef BOOTA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+struct block_header {
+ u32 id;
+ u32 summed_longs;
+ s32 chk_sum;
+};
+
+extern block_dev_desc_t *ide_get_dev (int dev);
+extern struct bootcode_block *get_bootcode (block_dev_desc_t * dev_desc);
+extern int sum_block (struct block_header *header);
+
+struct bootcode_block bblk;
+
+int do_boota (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ unsigned char *load_address = (unsigned char *) CFG_LOAD_ADDR;
+ unsigned char *base_address;
+ unsigned long offset;
+
+ unsigned long part_number = 0;
+ block_dev_desc_t *boot_disk;
+ char *s;
+ struct bootcode_block *boot_code;
+
+ /* Get parameters */
+
+ switch (argc) {
+ case 2:
+ load_address = (unsigned char *) simple_strtol (argv[1], NULL, 16);
+ part_number = 0;
+ break;
+ case 3:
+ load_address = (unsigned char *) simple_strtol (argv[1], NULL, 16);
+ part_number = simple_strtol (argv[2], NULL, 16);
+ break;
+ }
+
+ base_address = load_address;
+
+ PRINTF ("Loading boot code from disk %d to %p\n", part_number,
+ load_address);
+
+ /* Find the appropriate disk device */
+ boot_disk = ide_get_dev (part_number);
+ if (!boot_disk) {
+ PRINTF ("Unknown disk %d\n", part_number);
+ return 1;
+ }
+
+ /* Find the bootcode block */
+ boot_code = get_bootcode (boot_disk);
+ if (!boot_code) {
+ PRINTF ("Not a bootable disk %d\n", part_number);
+ return 1;
+ }
+
+ /* Only use the offset from the first block */
+ offset = boot_code->load_data[0];
+ memcpy (load_address, &boot_code->load_data[1], 122 * 4);
+ load_address += 122 * 4;
+
+ /* Setup for the loop */
+ bblk.next = boot_code->next;
+ boot_code = &bblk;
+
+ /* Scan the chain, and copy the loader succesively into the destination area */
+ while (0xffffffff != boot_code->next) {
+ PRINTF ("Loading block %d\n", boot_code->next);
+
+ /* Load block */
+ if (1 !=
+ boot_disk->block_read (boot_disk->dev, boot_code->next, 1,
+ (ulong *) & bblk)) {
+ PRINTF ("Read error\n");
+ return 1;
+ }
+
+ /* check sum */
+ if (sum_block ((struct block_header *) (ulong *) & bblk) != 0) {
+ PRINTF ("Checksum error\n");
+ return 1;
+ }
+
+ /* Ok, concatenate it to the already loaded code */
+ memcpy (load_address, boot_code->load_data, 123 * 4);
+ load_address += 123 * 4;
+ }
+
+ printf ("Bootcode loaded to %p (size %d)\n", base_address,
+ load_address - base_address);
+ printf ("Entry point at %p\n", base_address + offset);
+
+ flush_cache (base_address, load_address - base_address);
+
+
+ s = getenv ("autostart");
+ if (s && strcmp (s, "yes") == 0) {
+ DECLARE_GLOBAL_DATA_PTR;
+
+ void (*boot) (bd_t *, char *, block_dev_desc_t *);
+ char *args;
+
+ boot = (void (*)(bd_t *, char *, block_dev_desc_t *)) (base_address + offset);
+ boot (gd->bd, getenv ("amiga_bootargs"), boot_disk);
+ }
+
+
+ return 0;
+}
diff --git a/board/MAI/AmigaOneG3SE/config.mk b/board/MAI/AmigaOneG3SE/config.mk
new file mode 100644
index 0000000..0537cd9
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2002
+# 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
+#
+
+#
+# AmigaOneG3SE boards
+#
+
+X86EMU = -I../bios_emulator/scitech/include -I../bios_emulator/scitech/src/x86emu
+
+TEXT_BASE = 0xfff00000
+
+PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -Wa,-mregnames -DEASTEREGG $(X86EMU) #-DDEBUG
+
diff --git a/board/MAI/AmigaOneG3SE/enet.c b/board/MAI/AmigaOneG3SE/enet.c
new file mode 100644
index 0000000..0aaa8bf
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/enet.c
@@ -0,0 +1,886 @@
+/*
+ * (C) Copyright 2002
+ * Adam Kowalczyk, ACK Software Controls Inc. akowalczyk@cogeco.ca
+ *
+ * Some portions taken from 3c59x.c Written 1996-1999 by Donald Becker.
+ *
+ * Outline of the program based on eepro100.c which is
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#include "articiaS.h"
+#include "memio.h"
+
+/* 3Com Ethernet PCI definitions*/
+
+// #define PCI_VENDOR_ID_3COM 0x10B7
+#define PCI_DEVICE_ID_3COM_3C905C 0x9200
+
+/* 3Com Commands, top 5 bits are command and bottom 11 bits are parameters */
+
+#define TotalReset (0<<11)
+#define SelectWindow (1<<11)
+#define StartCoax (2<<11)
+#define RxDisable (3<<11)
+#define RxEnable (4<<11)
+#define RxReset (5<<11)
+#define UpStall (6<<11)
+#define UpUnstall (6<<11)+1
+#define DownStall (6<<11)+2
+#define DownUnstall (6<<11)+3
+#define RxDiscard (8<<11)
+#define TxEnable (9<<11)
+#define TxDisable (10<<11)
+#define TxReset (11<<11)
+#define FakeIntr (12<<11)
+#define AckIntr (13<<11)
+#define SetIntrEnb (14<<11)
+#define SetStatusEnb (15<<11)
+#define SetRxFilter (16<<11)
+#define SetRxThreshold (17<<11)
+#define SetTxThreshold (18<<11)
+#define SetTxStart (19<<11)
+#define StartDMAUp (20<<11)
+#define StartDMADown (20<<11)+1
+#define StatsEnable (21<<11)
+#define StatsDisable (22<<11)
+#define StopCoax (23<<11)
+#define SetFilterBit (25<<11)
+
+/* The SetRxFilter command accepts the following classes */
+
+#define RxStation 1
+#define RxMulticast 2
+#define RxBroadcast 4
+#define RxProm 8
+
+/* 3Com status word defnitions */
+
+#define IntLatch 0x0001
+#define HostError 0x0002
+#define TxComplete 0x0004
+#define TxAvailable 0x0008
+#define RxComplete 0x0010
+#define RxEarly 0x0020
+#define IntReq 0x0040
+#define StatsFull 0x0080
+#define DMADone (1<<8)
+#define DownComplete (1<<9)
+#define UpComplete (1<<10)
+#define DMAInProgress (1<<11) /* DMA controller is still busy.*/
+#define CmdInProgress (1<<12) /* EL3_CMD is still busy.*/
+
+/* Polling Registers */
+
+#define DnPoll 0x2d
+#define UpPoll 0x3d
+
+/* Register window 0 offets */
+
+#define Wn0EepromCmd 10 /* Window 0: EEPROM command register. */
+#define Wn0EepromData 12 /* Window 0: EEPROM results register. */
+#define IntrStatus 0x0E /* Valid in all windows. */
+
+/* Register window 0 EEPROM bits */
+
+#define EEPROM_Read 0x80
+#define EEPROM_WRITE 0x40
+#define EEPROM_ERASE 0xC0
+#define EEPROM_EWENB 0x30 /* Enable erasing/writing for 10 msec. */
+#define EEPROM_EWDIS 0x00 /* Disable EWENB before 10 msec timeout. */
+
+/* EEPROM locations. */
+
+#define PhysAddr01 0
+#define PhysAddr23 1
+#define PhysAddr45 2
+#define ModelID 3
+#define EtherLink3ID 7
+#define IFXcvrIO 8
+#define IRQLine 9
+#define NodeAddr01 10
+#define NodeAddr23 11
+#define NodeAddr45 12
+#define DriverTune 13
+#define Checksum 15
+
+/* Register window 1 offsets, the window used in normal operation */
+
+#define TX_FIFO 0x10
+#define RX_FIFO 0x10
+#define RxErrors 0x14
+#define RxStatus 0x18
+#define Timer 0x1A
+#define TxStatus 0x1B
+#define TxFree 0x1C /* Remaining free bytes in Tx buffer. */
+
+/* Register Window 2 */
+
+#define Wn2_ResetOptions 12
+
+/* Register Window 3: MAC/config bits */
+
+#define Wn3_Config 0 /* Internal Configuration */
+#define Wn3_MAC_Ctrl 6
+#define Wn3_Options 8
+
+#define BFEXT(value, offset, bitcount) \
+ ((((unsigned long)(value)) >> (offset)) & ((1 << (bitcount)) - 1))
+
+#define BFINS(lhs, rhs, offset, bitcount) \
+ (((lhs) & ~((((1 << (bitcount)) - 1)) << (offset))) | \
+ (((rhs) & ((1 << (bitcount)) - 1)) << (offset)))
+
+#define RAM_SIZE(v) BFEXT(v, 0, 3)
+#define RAM_WIDTH(v) BFEXT(v, 3, 1)
+#define RAM_SPEED(v) BFEXT(v, 4, 2)
+#define ROM_SIZE(v) BFEXT(v, 6, 2)
+#define RAM_SPLIT(v) BFEXT(v, 16, 2)
+#define XCVR(v) BFEXT(v, 20, 4)
+#define AUTOSELECT(v) BFEXT(v, 24, 1)
+
+/* Register Window 4: Xcvr/media bits */
+
+#define Wn4_FIFODiag 4
+#define Wn4_NetDiag 6
+#define Wn4_PhysicalMgmt 8
+#define Wn4_Media 10
+
+#define Media_SQE 0x0008 /* Enable SQE error counting for AUI. */
+#define Media_10TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
+#define Media_Lnk 0x0080 /* Enable just link beat for 100TX/100FX. */
+#define Media_LnkBeat 0x0800
+
+/* Register Window 7: Bus Master control */
+
+#define Wn7_MasterAddr 0
+#define Wn7_MasterLen 6
+#define Wn7_MasterStatus 12
+
+/* Boomerang bus master control registers. */
+
+#define PktStatus 0x20
+#define DownListPtr 0x24
+#define FragAddr 0x28
+#define FragLen 0x2c
+#define TxFreeThreshold 0x2f
+#define UpPktStatus 0x30
+#define UpListPtr 0x38
+
+/* The Rx and Tx descriptor lists. */
+
+#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */
+#define DN_COMPLETE 0x00010000 /* This packet has been downloaded */
+
+struct rx_desc_3com {
+ u32 next; /* Last entry points to 0 */
+ u32 status; /* FSH -> Frame Start Header */
+ u32 addr; /* Up to 63 addr/len pairs possible */
+ u32 length; /* Set LAST_FRAG to indicate last pair */
+};
+
+/* Values for the Rx status entry. */
+
+#define RxDComplete 0x00008000
+#define RxDError 0x4000
+#define IPChksumErr (1<<25)
+#define TCPChksumErr (1<<26)
+#define UDPChksumErr (1<<27)
+#define IPChksumValid (1<<29)
+#define TCPChksumValid (1<<30)
+#define UDPChksumValid (1<<31)
+
+struct tx_desc_3com {
+ u32 next; /* Last entry points to 0 */
+ u32 status; /* bits 0:12 length, others see below */
+ u32 addr;
+ u32 length;
+};
+
+/* Values for the Tx status entry. */
+
+#define CRCDisable 0x2000
+#define TxDComplete 0x8000
+#define AddIPChksum 0x02000000
+#define AddTCPChksum 0x04000000
+#define AddUDPChksum 0x08000000
+#define TxIntrUploaded 0x80000000 /* IRQ when in FIFO, but maybe not sent. */
+
+/* XCVR Types */
+
+#define XCVR_10baseT 0
+#define XCVR_AUI 1
+#define XCVR_10baseTOnly 2
+#define XCVR_10base2 3
+#define XCVR_100baseTx 4
+#define XCVR_100baseFx 5
+#define XCVR_MII 6
+#define XCVR_NWAY 8
+#define XCVR_ExtMII 9
+#define XCVR_Default 10 /* I don't think this is correct -> should have been 0x10 if Auto Negotiate */
+
+struct descriptor { /* A generic descriptor. */
+ u32 next; /* Last entry points to 0 */
+ u32 status; /* FSH -> Frame Start Header */
+ u32 addr; /* Up to 63 addr/len pairs possible */
+ u32 length; /* Set LAST_FRAG to indicate last pair */
+};
+
+/* Misc. definitions */
+
+#define NUM_RX_DESC PKTBUFSRX * 10
+#define NUM_TX_DESC 1 /* Number of TX descriptors */
+
+#define TOUT_LOOP 1000000
+
+#define ETH_ALEN 6
+
+#define EL3WINDOW(dev, win_num) ETH_OUTW(dev, SelectWindow + (win_num), EL3_CMD)
+#define EL3_CMD 0x0e
+#define EL3_STATUS 0x0e
+
+
+#undef ETH_DEBUG
+
+#ifdef ETH_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+
+static struct rx_desc_3com *rx_ring; /* RX descriptor ring */
+static struct tx_desc_3com *tx_ring; /* TX descriptor ring */
+static u8 rx_buffer[NUM_RX_DESC][PKTSIZE_ALIGN]; /* storage for the incoming messages */
+static int rx_next = 0; /* RX descriptor ring pointer */
+static int tx_next = 0; /* TX descriptor ring pointer */
+static int tx_threshold;
+
+static void init_rx_ring(struct eth_device* dev);
+static void purge_tx_ring(struct eth_device* dev);
+
+static void read_hw_addr(struct eth_device* dev, bd_t * bis);
+
+static int eth_3com_init(struct eth_device* dev, bd_t *bis);
+static int eth_3com_send(struct eth_device* dev, volatile void *packet, int length);
+static int eth_3com_recv(struct eth_device* dev);
+static void eth_3com_halt(struct eth_device* dev);
+
+#define io_to_phys(a) pci_io_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_io(a) pci_phys_to_io((pci_dev_t)dev->priv, a)
+#define mem_to_phys(a) pci_mem_to_phys((pci_dev_t)dev->priv, a)
+#define phys_to_mem(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
+
+static inline int ETH_INL(struct eth_device* dev, u_long addr)
+{
+ __asm volatile ("eieio");
+ return le32_to_cpu(*(volatile u32 *)io_to_phys(addr + dev->iobase));
+}
+
+static inline int ETH_INW(struct eth_device* dev, u_long addr)
+{
+ __asm volatile ("eieio");
+ return le16_to_cpu(*(volatile u16 *)io_to_phys(addr + dev->iobase));
+}
+
+static inline int ETH_INB(struct eth_device* dev, u_long addr)
+{
+ __asm volatile ("eieio");
+ return *(volatile u8 *)io_to_phys(addr + dev->iobase);
+}
+
+static inline void ETH_OUTB(struct eth_device* dev, int command, u_long addr)
+{
+ *(volatile u8 *)io_to_phys(addr + dev->iobase) = command;
+ __asm volatile ("eieio");
+}
+
+static inline void ETH_OUTW(struct eth_device* dev, int command, u_long addr)
+{
+ *(volatile u16 *)io_to_phys(addr + dev->iobase) = cpu_to_le16(command);
+ __asm volatile ("eieio");
+}
+
+static inline void ETH_OUTL(struct eth_device* dev, int command, u_long addr)
+{
+ *(volatile u32 *)io_to_phys(addr + dev->iobase) = cpu_to_le32(command);
+ __asm volatile ("eieio");
+}
+
+static inline int ETH_STATUS(struct eth_device* dev)
+{
+ __asm volatile ("eieio");
+ return le16_to_cpu(*(volatile u16 *)io_to_phys(EL3_STATUS + dev->iobase));
+}
+
+static inline void ETH_CMD(struct eth_device* dev, int command)
+{
+ *(volatile u16 *)io_to_phys(EL3_CMD + dev->iobase) = cpu_to_le16(command);
+ __asm volatile ("eieio");
+}
+
+/* Command register is always in the same spot in all the register windows */
+/* This function issues a command and waits for it so complete by checking the CmdInProgress bit */
+
+static int issue_and_wait(struct eth_device* dev, int command)
+{
+
+ int i, status;
+
+ ETH_CMD(dev, command);
+ for (i = 0; i < 2000; i++) {
+ status = ETH_STATUS(dev);
+ //printf ("Issue: status 0x%4x.\n", status);
+ if (!(status & CmdInProgress))
+ return 1;
+ }
+
+ /* OK, that didn't work. Do it the slow way. One second */
+ for (i = 0; i < 100000; i++) {
+ status = ETH_STATUS(dev);
+ //printf ("Issue: status 0x%4x.\n", status);
+ return 1;
+ udelay(10);
+ }
+ PRINTF("Ethernet command: 0x%4x did not complete! Status: 0x%4x\n", command, ETH_STATUS(dev) );
+ return 0;
+}
+
+/* Determine network media type and set up 3com accordingly */
+/* I think I'm going to start with something known first like 10baseT */
+
+static int auto_negotiate(struct eth_device* dev)
+{
+ int i;
+
+ EL3WINDOW(dev, 1);
+
+ // Wait for Auto negotiation to complete
+ for (i = 0; i <= 1000; i++)
+ {
+ if (ETH_INW(dev, 2) & 0x04)
+ break;
+ udelay(100);
+
+ if (i == 1000)
+ {
+ PRINTF("Error: Auto negotiation failed\n");
+ return 0;
+ }
+ }
+
+
+
+ return 1;
+}
+
+void eth_interrupt(struct eth_device *dev)
+{
+ u16 status = ETH_STATUS(dev);
+
+ printf("eth0: status = 0x%04x\n", status);
+
+ if (!(status & IntLatch))
+ return;
+
+ if (status & (1<<6))
+ {
+ ETH_CMD(dev, AckIntr | (1<<6));
+ printf("Acknowledged Interrupt command\n");
+ }
+
+ if (status & DownComplete)
+ {
+ ETH_CMD(dev, AckIntr | DownComplete);
+ printf("Acknowledged DownComplete\n");
+ }
+
+ if (status & UpComplete)
+ {
+ ETH_CMD(dev, AckIntr | UpComplete);
+ printf("Acknowledged UpComplete\n");
+ }
+
+ ETH_CMD(dev, AckIntr | IntLatch);
+ printf("Acknowledged IntLatch\n");
+}
+
+int eth_3com_initialize(bd_t *bis)
+{
+ u32 eth_iobase = 0, status;
+ int card_number = 0, ret;
+ struct eth_device* dev;
+ pci_dev_t devno;
+ char *s;
+
+ s = getenv("3com_base");
+
+ /* Find ethernet controller on the PCI bus */
+
+ if ((devno = pci_find_device(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905C, 0)) < 0)
+ {
+ PRINTF("Error: Cannot find the ethernet device on the PCI bus\n");
+ goto Done;
+ }
+
+ if (s)
+ {
+ unsigned long base = atoi(s);
+ pci_write_config_dword(devno, PCI_BASE_ADDRESS_0, base | 0x01);
+ }
+
+ ret = pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &eth_iobase);
+ eth_iobase &= ~0xf;
+
+ PRINTF("eth: 3Com Found at Address: 0x%x\n", eth_iobase);
+
+ pci_write_config_dword(devno, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ /* Check if I/O accesses and Bus Mastering are enabled */
+
+ ret = pci_read_config_dword(devno, PCI_COMMAND, &status);
+
+ if (!(status & PCI_COMMAND_IO))
+ {
+ printf("Error: Cannot enable IO access.\n");
+ goto Done;
+ }
+
+ if (!(status & PCI_COMMAND_MEMORY))
+ {
+ printf("Error: Cannot enable MEMORY access.\n");
+ goto Done;
+ }
+
+ if (!(status & PCI_COMMAND_MASTER))
+ {
+ printf("Error: Cannot enable Bus Mastering.\n");
+ goto Done;
+ }
+
+ dev = (struct eth_device*) malloc(sizeof(*dev)); //struct eth_device));
+
+ sprintf(dev->name, "3Com 3c920c#%d", card_number);
+ dev->iobase = eth_iobase;
+ dev->priv = (void*) devno;
+ dev->init = eth_3com_init;
+ dev->halt = eth_3com_halt;
+ dev->send = eth_3com_send;
+ dev->recv = eth_3com_recv;
+
+ eth_register(dev);
+
+/* { */
+/* char interrupt; */
+/* devno = pci_find_device(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905C, 0); */
+/* pci_read_config_byte(devno, PCI_INTERRUPT_LINE, &interrupt); */
+
+/* printf("Installing eth0 interrupt handler to %d\n", interrupt); */
+/* irq_install_handler(interrupt, eth_interrupt, dev); */
+/* } */
+
+ card_number++;
+
+ /* Set the latency timer for value */
+ s = getenv("3com_latency");
+ if (s)
+ {
+ ret = pci_write_config_byte(devno, PCI_LATENCY_TIMER, (unsigned char)atoi(s));
+ }
+ else ret = pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x0a);
+
+ read_hw_addr(dev, bis); /* get the MAC address from Window 2*/
+
+ /* Reset the ethernet controller */
+
+ PRINTF ("Issuing reset command....\n");
+ if (!issue_and_wait(dev, TotalReset))
+ {
+ printf("Error: Cannot reset ethernet controller.\n");
+ goto Done;
+ }
+ else
+ PRINTF ("Ethernet controller reset.\n");
+
+ /* allocate memory for rx and tx rings */
+
+ if(!(rx_ring = memalign(sizeof(struct rx_desc_3com) * NUM_RX_DESC, 16)))
+ {
+ PRINTF ("Cannot allocate memory for RX_RING.....\n");
+ goto Done;
+ }
+
+ if (!(tx_ring = memalign(sizeof(struct tx_desc_3com) * NUM_TX_DESC, 16)))
+ {
+ PRINTF ("Cannot allocate memory for TX_RING.....\n");
+ goto Done;
+ }
+
+Done:
+ return status;
+}
+
+
+static int eth_3com_init(struct eth_device* dev, bd_t *bis)
+{
+ int i, status = 0;
+ int tx_cur, loop;
+ u16 status_enable, intr_enable;
+ struct descriptor *ias_cmd;
+
+ /* Determine what type of network the machine is connected to */
+ /* presently drops the connect to 10Mbps */
+
+ if (!auto_negotiate(dev))
+ {
+ printf("Error: Cannot determine network media.\n");
+ goto Done;
+ }
+
+ issue_and_wait(dev, TxReset);
+ issue_and_wait(dev, RxReset|0x04);
+
+ /* Switch to register set 7 for normal use. */
+ EL3WINDOW(dev, 7);
+
+ /* Initialize Rx and Tx rings */
+
+ init_rx_ring(dev);
+ purge_tx_ring(dev);
+
+ ETH_CMD(dev, SetRxFilter | RxStation | RxBroadcast | RxProm);
+
+ issue_and_wait(dev,SetTxStart|0x07ff);
+
+ /* Below sets which indication bits to be seen. */
+
+ status_enable = SetStatusEnb | HostError | DownComplete | UpComplete | (1<<6);
+ ETH_CMD(dev, status_enable);
+
+ /* Below sets no bits are to cause an interrupt since this is just polling */
+
+ intr_enable = SetIntrEnb;
+// intr_enable = SetIntrEnb | (1<<9) | (1<<10) | (1<<6);
+ ETH_CMD(dev, intr_enable);
+ ETH_OUTB(dev, 127, UpPoll);
+
+ /* Ack all pending events, and set active indicator mask */
+
+ ETH_CMD(dev, AckIntr | IntLatch | TxAvailable | RxEarly | IntReq);
+ ETH_CMD(dev, intr_enable);
+
+ /* Tell the adapter where the RX ring is located */
+
+ issue_and_wait(dev,UpStall); /* Stall and set the UplistPtr */
+ ETH_OUTL(dev, (u32)&rx_ring[rx_next], UpListPtr);
+ ETH_CMD(dev, RxEnable); /* Enable the receiver. */
+ issue_and_wait(dev,UpUnstall);
+
+ /* Send the Individual Address Setup frame */
+
+ tx_cur = tx_next;
+ tx_next = ((tx_next+1) % NUM_TX_DESC);
+
+ ias_cmd = (struct descriptor *)&tx_ring[tx_cur];
+ ias_cmd->status = cpu_to_le32(1<<31); /* set DnIndicate bit. */
+ ias_cmd->next = 0;
+ ias_cmd->addr = cpu_to_le32((u32)&bis->bi_enetaddr[0]);
+ ias_cmd->length = cpu_to_le32(6 | LAST_FRAG);
+
+ /* Tell the adapter where the TX ring is located */
+
+ ETH_CMD(dev, TxEnable); /* Enable transmitter. */
+ issue_and_wait(dev, DownStall); /* Stall and set the DownListPtr. */
+ ETH_OUTL(dev, (u32)&tx_ring[tx_cur], DownListPtr);
+ issue_and_wait(dev, DownUnstall);
+ for (i=0; !(ETH_STATUS(dev) & DownComplete); i++)
+ {
+ if (i >= TOUT_LOOP)
+ {
+ PRINTF("TX Ring status (Init): 0x%4x\n", le32_to_cpu(tx_ring[tx_cur].status));
+ PRINTF("ETH_STATUS: 0x%x\n", ETH_STATUS(dev));
+ goto Done;
+ }
+ }
+ if (ETH_STATUS(dev) & DownComplete) /* If DownLoad Complete ACK the bit */
+ {
+ ETH_CMD(dev, AckIntr | DownComplete); /* acknowledge the indication bit */
+ issue_and_wait(dev, DownStall); /* stall and clear DownListPtr */
+ ETH_OUTL(dev, 0, DownListPtr);
+ issue_and_wait(dev, DownUnstall);
+ }
+ status = 1;
+
+Done:
+ return status;
+}
+
+int eth_3com_send(struct eth_device* dev, volatile void *packet, int length)
+{
+ int i, status = 0;
+ int tx_cur;
+
+ if (length <= 0)
+ {
+ PRINTF("eth: bad packet size: %d\n", length);
+ goto Done;
+ }
+
+ tx_cur = tx_next;
+ tx_next = (tx_next+1) % NUM_TX_DESC;
+
+ tx_ring[tx_cur].status = cpu_to_le32(1<<31); /* set DnIndicate bit */
+ tx_ring[tx_cur].next = 0;
+ tx_ring[tx_cur].addr = cpu_to_le32(((u32) packet));
+ tx_ring[tx_cur].length = cpu_to_le32(length | LAST_FRAG);
+
+ /* Send the packet */
+
+ issue_and_wait(dev, DownStall); /* stall and set the DownListPtr */
+ ETH_OUTL(dev, (u32) &tx_ring[tx_cur], DownListPtr);
+ issue_and_wait(dev, DownUnstall);
+
+ for (i=0; !(ETH_STATUS(dev) & DownComplete); i++)
+ {
+ if (i >= TOUT_LOOP)
+ {
+ PRINTF("TX Ring status (send): 0x%4x\n", le32_to_cpu(tx_ring[tx_cur].status));
+ goto Done;
+ }
+ }
+ if (ETH_STATUS(dev) & DownComplete) /* If DownLoad Complete ACK the bit */
+ {
+ ETH_CMD(dev, AckIntr | DownComplete); /* acknowledge the indication bit */
+ issue_and_wait(dev, DownStall); /* stall and clear DownListPtr */
+ ETH_OUTL(dev, 0, DownListPtr);
+ issue_and_wait(dev, DownUnstall);
+ }
+ status=1;
+ Done:
+ return status;
+}
+
+void PrintPacket (uchar *packet, int length)
+{
+int loop;
+uchar *ptr;
+
+ printf ("Printing packet of length %x.\n\n", length);
+ ptr = packet;
+ for (loop = 1; loop <= length; loop++)
+ {
+ printf ("%2x ", *ptr++);
+ if ((loop % 40)== 0)
+ printf ("\n");
+ }
+}
+
+int eth_3com_recv(struct eth_device* dev)
+{
+ u16 stat = 0;
+ u32 status;
+ int rx_prev, length = 0;
+
+ while (!(ETH_STATUS(dev) & UpComplete)) /* wait on receipt of packet */
+ ;
+
+ status = le32_to_cpu(rx_ring[rx_next].status); /* packet status */
+
+ while (status & (1<<15))
+ {
+ /* A packet has been received */
+
+ if (status & (1<<15))
+ {
+ /* A valid frame received */
+
+ length = le32_to_cpu(rx_ring[rx_next].status) & 0x1fff; /* length is in bits 0 - 12 */
+
+ /* Pass the packet up to the protocol layers */
+
+ NetReceive((uchar *)le32_to_cpu(rx_ring[rx_next].addr), length);
+ rx_ring[rx_next].status = 0; /* clear the status word */
+ ETH_CMD(dev, AckIntr | UpComplete);
+ issue_and_wait(dev, UpUnstall);
+ }
+ else
+ if (stat & HostError)
+ {
+ /* There was an error */
+
+ printf("Rx error status: 0x%4x\n", stat);
+ init_rx_ring(dev);
+ goto Done;
+ }
+
+ rx_prev = rx_next;
+ rx_next = (rx_next + 1) % NUM_RX_DESC;
+ stat = ETH_STATUS(dev); /* register status */
+ status = le32_to_cpu(rx_ring[rx_next].status); /* packet status */
+ }
+
+Done:
+ return length;
+}
+
+void eth_3com_halt(struct eth_device* dev)
+{
+ if (!(dev->iobase))
+ {
+ goto Done;
+ }
+
+ issue_and_wait(dev, DownStall); /* shut down transmit and receive */
+ issue_and_wait(dev, UpStall);
+ issue_and_wait(dev, RxDisable);
+ issue_and_wait(dev, TxDisable);
+
+// free(tx_ring); /* release memory allocated to the DPD and UPD rings */
+// free(rx_ring);
+
+Done:
+ return;
+}
+
+static void init_rx_ring(struct eth_device* dev)
+{
+ int i;
+
+ PRINTF("Initializing rx_ring. rx_buffer = %p\n", rx_buffer);
+ issue_and_wait(dev, UpStall);
+
+ for (i = 0; i < NUM_RX_DESC; i++)
+ {
+ rx_ring[i].next = cpu_to_le32(((u32) &rx_ring[(i+1) % NUM_RX_DESC]));
+ rx_ring[i].status = 0;
+ rx_ring[i].addr = cpu_to_le32(((u32) &rx_buffer[i][0]));
+ rx_ring[i].length = cpu_to_le32(PKTSIZE_ALIGN | LAST_FRAG);
+ }
+ rx_next = 0;
+}
+
+static void purge_tx_ring(struct eth_device* dev)
+{
+ int i;
+
+ PRINTF("Purging tx_ring.\n");
+
+ tx_next = 0;
+
+ for (i = 0; i < NUM_TX_DESC; i++)
+ {
+ tx_ring[i].next = 0;
+ tx_ring[i].status = 0;
+ tx_ring[i].addr = 0;
+ tx_ring[i].length = 0;
+ }
+}
+
+static void read_hw_addr(struct eth_device* dev, bd_t *bis)
+{
+ u8 hw_addr[ETH_ALEN];
+ unsigned int eeprom[0x40];
+ unsigned int checksum = 0;
+ int i, j, timer;
+
+ /* Read the station address from the EEPROM. */
+
+ EL3WINDOW(dev, 0);
+ for (i = 0; i < 0x40; i++)
+ {
+ ETH_OUTW(dev, EEPROM_Read + i, Wn0EepromCmd);
+ /* Pause for at least 162 us. for the read to take place. */
+ for (timer = 10; timer >= 0; timer--)
+ {
+ udelay(162);
+ if ((ETH_INW(dev, Wn0EepromCmd) & 0x8000) == 0)
+ break;
+ }
+ eeprom[i] = ETH_INW(dev, Wn0EepromData);
+ }
+
+ /* Checksum calculation. I'm not sure about this part and there seems to be a bug on the 3com side of things */
+
+ for (i = 0; i < 0x21; i++)
+ checksum ^= eeprom[i];
+ checksum = (checksum ^ (checksum >> 8)) & 0xff;
+
+ if (checksum != 0xbb)
+ printf(" *** INVALID EEPROM CHECKSUM %4.4x *** \n", checksum);
+
+ for (i = 0, j = 0; i < 3; i++)
+ {
+ hw_addr[j++] = (u8)((eeprom[i+10] >> 8) & 0xff);
+ hw_addr[j++] = (u8)(eeprom[i+10] & 0xff);
+ }
+
+ /* MAC Address is in window 2, write value from EEPROM to window 2 */
+
+ EL3WINDOW(dev, 2);
+ for (i = 0; i < 6; i++)
+ ETH_OUTB(dev, hw_addr[i], i);
+
+ for (j = 0; j < ETH_ALEN; j+=2)
+ {
+ hw_addr[j] = (u8)(ETH_INW(dev, j) & 0xff);
+ hw_addr[j+1] = (u8)((ETH_INW(dev, j) >> 8) & 0xff);
+ }
+
+ for (i=0;i<ETH_ALEN;i++)
+ {
+ if (hw_addr[i] != bis->bi_enetaddr[i])
+ {
+/* printf("Warning: HW address don't match:\n"); */
+/* printf("Address in 3Com Window 2 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 U-Boot 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; */
+ char buffer[256];
+ if (bis->bi_enetaddr[0] == 0 && bis->bi_enetaddr[1] == 0 &&
+ bis->bi_enetaddr[2] == 0 && bis->bi_enetaddr[3] == 0 &&
+ bis->bi_enetaddr[4] == 0 && bis->bi_enetaddr[5] == 0)
+ {
+
+ sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X",
+ hw_addr[0], hw_addr[1], hw_addr[2],
+ hw_addr[3], hw_addr[4], hw_addr[5]);
+ setenv("ethaddr", buffer);
+ }
+ }
+ }
+
+ for(i=0; i<ETH_ALEN; i++) dev->enetaddr[i] = hw_addr[i];
+
+Done:
+ return;
+}
+
diff --git a/board/MAI/AmigaOneG3SE/flash.c b/board/MAI/AmigaOneG3SE/flash.c
new file mode 100644
index 0000000..409b955
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/flash.c
@@ -0,0 +1,35 @@
+#include <common.h>
+#include <flash.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+
+unsigned long flash_init(void)
+{
+ int i;
+
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
+ {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ flash_info[i].sector_count = 0;
+ flash_info[i].size = 0;
+ }
+
+
+ return 1;
+}
+
+int flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+ return 1;
+}
+
+void flash_print_info(flash_info_t *info)
+{
+ printf("No flashrom installed\n");
+}
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ return 0;
+}
diff --git a/board/MAI/AmigaOneG3SE/flash_new.c b/board/MAI/AmigaOneG3SE/flash_new.c
new file mode 100644
index 0000000..6eebeba
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/flash_new.c
@@ -0,0 +1,652 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * (C) Copyright 2002
+ * 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 <common.h>
+#include <flash.h>
+#include <asm/io.h>
+#include "memio.h"
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+//#define DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+static ulong flash_get_size (ulong addr, flash_info_t *info);
+static int flash_get_offsets (ulong base, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_reset (ulong addr);
+
+int flash_xd_nest;
+
+static void flash_to_xd(void)
+{
+ unsigned char x;
+
+ flash_xd_nest ++;
+
+ if (flash_xd_nest == 1)
+ {
+ DEBUGF("Flash on XD\n");
+ x = pci_read_cfg_byte(0, 0, 0x74);
+ pci_write_cfg_byte(0, 0, 0x74, x|1);
+ }
+}
+
+static void flash_to_mem(void)
+{
+ unsigned char x;
+
+ flash_xd_nest --;
+
+ if (flash_xd_nest == 0)
+ {
+ DEBUGF("Flash on memory bus\n");
+ x = pci_read_cfg_byte(0, 0, 0x74);
+ pci_write_cfg_byte(0, 0, 0x74, x&0xFE);
+ }
+}
+
+unsigned long flash_init_old(void)
+{
+ int i;
+
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
+ {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ flash_info[i].sector_count = 0;
+ flash_info[i].size = 0;
+ }
+
+
+ return 1;
+}
+
+unsigned long flash_init (void)
+{
+ unsigned int i;
+ unsigned long flash_size = 0;
+
+ flash_xd_nest = 0;
+
+ flash_to_xd();
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ flash_info[i].sector_count = 0;
+ flash_info[i].size = 0;
+ }
+
+ DEBUGF("\n## Get flash size @ 0x%08x\n", CFG_FLASH_BASE);
+
+ flash_size = flash_get_size (CFG_FLASH_BASE, flash_info);
+
+ DEBUGF("## Flash bank size: %08lx\n", flash_size);
+
+ if (flash_size) {
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE && \
+ CFG_MONITOR_BASE < CFG_FLASH_BASE + CFG_FLASH_MAX_SIZE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
+ &flash_info[0]);
+#endif
+
+ } else {
+ puts ("Warning: the BOOT Flash is not initialised !");
+ }
+
+ flash_to_mem();
+
+ return flash_size;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (ulong addr, flash_info_t *info)
+{
+ short i;
+ uchar value;
+ uchar *x = (uchar *)addr;
+
+ flash_to_xd();
+
+ /* Write auto select command: read Manufacturer ID */
+ x[0x0555] = 0xAA;
+ __asm volatile ("sync\n eieio");
+ x[0x02AA] = 0x55;
+ __asm volatile ("sync\n eieio");
+ x[0x0555] = 0x90;
+ __asm volatile ("sync\n eieio");
+
+ value = x[0];
+ __asm volatile ("sync\n eieio");
+
+ DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);
+
+ switch (value | (value << 16)) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+
+ case STM_MANUFACT:
+ info->flash_id = FLASH_MAN_STM;
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ flash_reset (addr);
+ return 0;
+ }
+
+ value = x[1];
+ __asm volatile ("sync\n eieio");
+
+ DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value);
+
+ switch (value) {
+ case AMD_ID_F040B:
+ DEBUGF("Am29F040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ case AMD_ID_LV040B:
+ DEBUGF("Am29LV040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ case AMD_ID_LV400T:
+ DEBUGF("Am29LV400T\n");
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ DEBUGF("Am29LV400B\n");
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ DEBUGF("Am29LV800T\n");
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ DEBUGF("Am29LV400B\n");
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ DEBUGF("Am29LV160T\n");
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ DEBUGF("Am29LV160B\n");
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV320T:
+ DEBUGF("Am29LV320T\n");
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+#if 0
+ /* Has the same ID as AMD_ID_LV320T, to be fixed */
+ case AMD_ID_LV320B:
+ DEBUGF("Am29LV320B\n");
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+
+ case AMD_ID_LV033C:
+ DEBUGF("Am29LV033C\n");
+ info->flash_id += FLASH_AM033C;
+ info->sector_count = 64;
+ info->size = 0x01000000;
+ break; /* => 16Mb */
+
+ case STM_ID_F040B:
+ DEBUGF("M29F040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ flash_reset (addr);
+ flash_to_mem();
+ return (0); /* => no or unknown flash */
+
+ }
+
+ if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CFG_MAX_FLASH_SECT);
+ info->sector_count = CFG_MAX_FLASH_SECT;
+ }
+
+ if (! flash_get_offsets (addr, info)) {
+ flash_reset (addr);
+ flash_to_mem();
+ return 0;
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ value = in8(info->start[i] + 2);
+ iobarrier_rw();
+ info->protect[i] = (value & 1) != 0;
+ }
+
+ /*
+ * Reset bank to read mode
+ */
+ flash_reset (addr);
+
+ flash_to_mem();
+
+ return (info->size);
+}
+
+static int flash_get_offsets (ulong base, flash_info_t *info)
+{
+ unsigned int i;
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040:
+ /* set sector offsets for uniform sector type */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + i * info->size /
+ info->sector_count;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ volatile ulong addr = info->start[0];
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ flash_to_xd();
+
+ if (s_first < 0 || s_first > s_last) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ flash_to_mem();
+ return 1;
+ }
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ flash_to_mem();
+ return 1;
+ }
+
+ 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();
+
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+ out8(addr + 0x555, 0x80);
+ iobarrier_rw();
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = info->start[sect];
+ out8(addr, 0x30);
+ iobarrier_rw();
+ 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 = info->start[l_sect];
+
+ DEBUGF ("Start erase timeout: %d\n", CFG_FLASH_ERASE_TOUT);
+
+ while ((in8(addr) & 0x80) != 0x80) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ flash_reset (info->start[0]);
+ flash_to_mem();
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ iobarrier_rw();
+ }
+
+DONE:
+ /* reset to read mode */
+ flash_reset (info->start[0]);
+ flash_to_mem();
+
+ printf (" done\n");
+ return 0;
+}
+
+/*
+ * 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;
+
+ flash_to_xd();
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++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) {
+ flash_to_mem();
+ 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) {
+ flash_to_mem();
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ flash_to_mem();
+ 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);
+ }
+
+
+ flash_to_mem();
+ 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 ulong addr = info->start[0];
+ ulong start;
+ int i;
+
+ flash_to_xd();
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((in32(dest) & data) != data) {
+ flash_to_mem();
+ return (2);
+ }
+
+ /* write each byte out */
+ for (i = 0; i < 4; i++) {
+ char *data_ch = (char *)&data;
+ int flag = disable_interrupts();
+
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+ out8(addr + 0x555, 0xA0);
+ iobarrier_rw();
+ out8(dest+i, data_ch[i]);
+ iobarrier_rw();
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ flash_reset (addr);
+ flash_to_mem();
+ return (1);
+ }
+ iobarrier_rw();
+ }
+ }
+
+ flash_reset (addr);
+ flash_to_mem();
+ return (0);
+}
+
+/*
+ * Reset bank to read mode
+ */
+static void flash_reset (ulong addr)
+{
+ flash_to_xd();
+ out8(addr, 0xF0); /* reset bank */
+ iobarrier_rw();
+ flash_to_mem();
+}
+
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ 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;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
+ case FLASH_MAN_STM: printf ("SGS THOMSON "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+ break;
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ if (info->size % 0x100000 == 0) {
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size / 0x100000, info->sector_count);
+ } else if (info->size % 0x400 == 0) {
+ printf (" Size: %ld KB in %d Sectors\n",
+ info->size / 0x400, info->sector_count);
+ } else {
+ printf (" Size: %ld B in %d Sectors\n",
+ info->size, info->sector_count);
+ }
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+}
diff --git a/board/MAI/AmigaOneG3SE/i8259.c b/board/MAI/AmigaOneG3SE/i8259.c
new file mode 100644
index 0000000..6cdfc60
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/i8259.c
@@ -0,0 +1,230 @@
+/*
+ * (C) Copyright 2002
+ * John W. Linville, linville@tuxdriver.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 <common.h>
+#include "i8259.h"
+
+#undef IRQ_DEBUG
+
+#ifdef IRQ_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+static inline unsigned char read_byte(volatile unsigned char* from)
+{
+ int x;
+ asm volatile ("lbz %0,%1\n eieio" : "=r" (x) : "m" (*from));
+ return (unsigned char)x;
+}
+
+static inline void write_byte(volatile unsigned char *to, int x)
+{
+ asm volatile ("stb %1,%0\n eieio" : "=m" (*to) : "r" (x));
+}
+
+static inline unsigned long read_long_little(volatile unsigned long *from)
+{
+ unsigned long x;
+ asm volatile ("lwbrx %0,0,%1\n eieio\n sync" : "=r" (x) : "r" (from), "m"(*from));
+ return (unsigned long)x;
+}
+
+#ifdef out8
+#undef out8
+#endif
+
+#ifdef in8
+#undef in8
+#endif
+
+#define out8(addr, byte) write_byte(0xFE000000 | addr, byte)
+#define in8(addr) read_byte(0xFE000000 | addr)
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ */
+static char cached_imr[2] = {0xff, 0xff};
+
+#define cached_imr1 (cached_imr[0])
+#define cached_imr2 (cached_imr[1])
+
+void i8259_init(void)
+{
+ char dummy;
+ PRINTF("Initializing Interrupt controller\n");
+ /* init master interrupt controller */
+ out8(0x20, 0x11); //0x19); // was: 0x11); /* Start init sequence */
+ out8(0x21, 0x00); /* Vector base */
+ out8(0x21, 0x04); /* edge tiggered, Cascade (slave) on IRQ2 */
+ out8(0x21, 0x11); // was: 0x01); /* Select 8086 mode */
+
+ /* init slave interrupt controller */
+ out8(0xA0, 0x11); //0x19); // was: 0x11); /* Start init sequence */
+ out8(0xA1, 0x08); /* Vector base */
+ out8(0xA1, 0x02); /* edge triggered, Cascade (slave) on IRQ2 */
+ out8(0xA1, 0x11); // was: 0x01); /* Select 8086 mode */
+
+ /* always read ISR */
+ out8(0x20, 0x0B);
+ dummy = in8(ISR_1);
+ out8(0xA0, 0x0B);
+ dummy = in8(ISR_2);
+
+/* out8(0x43, 0x30); */
+/* out8(0x40, 0); */
+/* out8(0x40, 0); */
+/* out8(0x43, 0x70); */
+/* out8(0x41, 0); */
+/* out8(0x41, 0); */
+/* out8(0x43, 0xb0); */
+/* out8(0x42, 0); */
+/* out8(0x42, 0); */
+
+ /* Mask all interrupts */
+ out8(IMR_2, cached_imr2);
+ out8(IMR_1, cached_imr1);
+
+ i8259_unmask_irq(2);
+#if 0
+ {
+ int i;
+ for (i=0; i<16; i++)
+ {
+ i8259_unmask_irq(i);
+ }
+ }
+#endif
+}
+
+static volatile char *pci_intack = (void *)0xFEF00000;
+
+int i8259_irq(void)
+{
+ int irq;
+
+ irq = read_long_little(pci_intack) & 0xff;
+ if (irq==7) {
+ /*
+ * This may be a spurious interrupt.
+ *
+ * Read the interrupt status register (ISR). If the most
+ * significant bit is not set then there is no valid
+ * interrupt.
+ */
+ if(~in8(0x20)&0x80) {
+ irq = -1;
+ }
+ }
+
+ return irq;
+}
+int i8259_get_irq(struct pt_regs *regs)
+{
+ unsigned char irq;
+
+ /*
+ * Perform an interrupt acknowledge cycle on controller 1
+ */
+ out8(OCW3_1, 0x0C); /* prepare for poll */
+ irq = in8(IPL_1) & 7;
+ if (irq == 2) {
+ /*
+ * Interrupt is cascaded so perform interrupt
+ * acknowledge on controller 2
+ */
+ out8(OCW3_2, 0x0C); /* prepare for poll */
+ irq = (in8(IPL_2) & 7) + 8;
+ if (irq == 15) {
+ /*
+ * This may be a spurious interrupt
+ *
+ * Read the interrupt status register. If the most
+ * significant bit is not set then there is no valid
+ * interrupt
+ */
+ out8(OCW3_2, 0x0b);
+ if (~(in8(ISR_2) & 0x80)) {
+ return -1;
+ }
+ }
+ } else if (irq == 7) {
+ /*
+ * This may be a spurious interrupt
+ *
+ * Read the interrupt status register. If the most
+ * significant bit is not set then there is no valid
+ * interrupt
+ */
+ out8(OCW3_1, 0x0b);
+ if (~(in8(ISR_1) & 0x80)) {
+ return -1;
+ }
+ }
+ return irq;
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+void i8259_mask_and_ack(int irq)
+{
+ if (irq > 7) {
+ cached_imr2 |= (1 << (irq - 8));
+ in8(IMR_2); /* DUMMY */
+ out8(IMR_2, cached_imr2);
+ out8(OCW2_2, 0x20); /* Non-specific EOI */
+ out8(OCW2_1, 0x20); /* Non-specific EOI to cascade */
+ } else {
+ cached_imr1 |= (1 << irq);
+ in8(IMR_1); /* DUMMY */
+ out8(IMR_1, cached_imr1);
+ out8(OCW2_1, 0x20); /* Non-specific EOI */
+ }
+}
+
+void i8259_mask_irq(int irq)
+{
+ if (irq & 8) {
+ cached_imr2 |= (1 << (irq & 7));
+ out8(IMR_2, cached_imr2);
+ } else {
+ cached_imr1 |= (1 << irq);
+ out8(IMR_1, cached_imr1);
+ }
+}
+
+void i8259_unmask_irq(int irq)
+{
+ if (irq & 8) {
+ cached_imr2 &= ~(1 << (irq & 7));
+ out8(IMR_2, cached_imr2);
+ } else {
+ cached_imr1 &= ~(1 << irq);
+ out8(IMR_1, cached_imr1);
+ }
+}
diff --git a/board/MAI/AmigaOneG3SE/i8259.h b/board/MAI/AmigaOneG3SE/i8259.h
new file mode 100644
index 0000000..05c4052
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/i8259.h
@@ -0,0 +1,56 @@
+/*
+ * (C) Copyright 2002
+ * John W. Linville, linville@tuxdriver.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
+ */
+
+#define ICW1_1 CFG_ISA_IO_BASE_ADDRESS + ISA_INT1_ICW1
+#define ICW1_2 CFG_ISA_IO_BASE_ADDRESS + ISA_INT2_ICW1
+#define ICW2_1 CFG_ISA_IO_BASE_ADDRESS + ISA_INT1_ICW2
+#define ICW2_2 CFG_ISA_IO_BASE_ADDRESS + ISA_INT2_ICW2
+#define ICW3_1 CFG_ISA_IO_BASE_ADDRESS + ISA_INT1_ICW3
+#define ICW3_2 CFG_ISA_IO_BASE_ADDRESS + ISA_INT2_ICW3
+#define ICW4_1 CFG_ISA_IO_BASE_ADDRESS + ISA_INT1_ICW4
+#define ICW4_2 CFG_ISA_IO_BASE_ADDRESS + ISA_INT2_ICW4
+#define OCW1_1 CFG_ISA_IO_BASE_ADDRESS + ISA_INT1_OCW1
+#define OCW1_2 CFG_ISA_IO_BASE_ADDRESS + ISA_INT2_OCW1
+#define OCW2_1 CFG_ISA_IO_BASE_ADDRESS + ISA_INT1_OCW2
+#define OCW2_2 CFG_ISA_IO_BASE_ADDRESS + ISA_INT2_OCW2
+#define OCW3_1 CFG_ISA_IO_BASE_ADDRESS + ISA_INT1_OCW3
+#define OCW3_2 CFG_ISA_IO_BASE_ADDRESS + ISA_INT2_OCW3
+
+#define IMR_1 OCW1_1
+#define IMR_2 OCW1_2
+
+#define ISR_1 ICW1_1
+#define ISR_2 ICW1_2
+
+#define IPL_1 ICW1_1
+#define IPL_2 ICW1_2
+
+extern void i8259_init(void);
+
+extern int i8259_get_irq(struct pt_regs *regs);
+
+extern void i8259_mask_and_ack(int irq);
+
+extern void i8259_mask_irq(int irq);
+
+extern void i8259_unmask_irq(int irq);
diff --git a/board/MAI/AmigaOneG3SE/interrupts.c b/board/MAI/AmigaOneG3SE/interrupts.c
new file mode 100644
index 0000000..bb93ea0
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/interrupts.c
@@ -0,0 +1,268 @@
+/*
+ * (C) Copyright 2002
+ * John W. Linville <linville@tuxdriver.com>
+ *
+ * Copied and modified from original code by Josh Huber. Original
+ * copyright notice preserved below.
+ *
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, 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 <common.h>
+#include <asm/processor.h>
+#include <command.h>
+#include "i8259.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+#define NR_IRQS 16
+
+void irq_alloc_init(void);
+long irq_alloc(long wanted);
+
+/****************************************************************************/
+
+unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ ulong count;
+};
+
+static struct irq_action irq_handlers[NR_IRQS];
+
+/****************************************************************************/
+
+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;
+
+ msr = get_msr();
+ set_msr (msr & ~MSR_EE);
+ return ((msr & MSR_EE) != 0);
+}
+
+/****************************************************************************/
+
+int interrupt_init (void)
+{
+ extern void new_reset(void);
+ extern void new_reset_end(void);
+#ifdef DEBUG
+ puts("interrupt_init: setting decrementer_count\n");
+#endif
+ decrementer_count = get_tbclk() / CFG_HZ;
+
+#ifdef DEBUG
+ puts("interrupt_init: setting actual decremter\n");
+#endif
+ set_dec (get_tbclk() / CFG_HZ);
+
+#ifdef DEBUG
+ puts("interrupt_init: clearing external interrupt table\n");
+#endif
+ /* clear external interrupt table here */
+ memset(irq_handlers, 0, sizeof(irq_handlers));
+
+#ifdef DEBUG
+ puts("interrupt_init: initializing interrupt controller\n");
+#endif
+ i8259_init();
+
+#ifdef DEBUG
+ puts("Copying reset trampoline\n");
+#endif
+ /* WARNING: Assmues that the first megabyte is CACHEINHIBIT! */
+ memcpy((void *)0x100, new_reset, new_reset_end - new_reset);
+
+#ifdef DEBUG
+ PRINTF("interrupt_init: enabling interrupts (msr = %08x)\n",
+ get_msr());
+#endif
+ set_msr (get_msr() | MSR_EE);
+
+#ifdef DEBUG
+ PRINTF("interrupt_init: done. (msr = %08x)\n", get_msr());
+#endif
+
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void
+external_interrupt(struct pt_regs *regs)
+{
+ extern int i8259_irq(void);
+
+ int irq, unmask = 1;
+
+ irq = i8259_irq(); //i8259_get_irq(regs);
+// printf("irq = %d, handler at %p ack=%d\n", irq, irq_handlers[irq].handler, *(volatile unsigned char *)0xFEF00000);
+ i8259_mask_and_ack(irq);
+
+ if (irq_handlers[irq].handler != NULL)
+ (*irq_handlers[irq].handler)(irq_handlers[irq].arg);
+ else {
+ PRINTF ("\nBogus External Interrupt IRQ %d\n", irq);
+ /*
+ * turn off the bogus interrupt, otherwise it
+ * might repeat forever
+ */
+ unmask = 0;
+ }
+
+ if (unmask) i8259_unmask_irq(irq);
+}
+
+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 irq, interrupt_handler_t *handler, void *arg)
+{
+ if (irq < 0 || irq >= NR_IRQS) {
+ PRINTF("irq_install_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ if (irq_handlers[irq].handler != NULL)
+ PRINTF("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+ (ulong)handler, (ulong)irq_handlers[irq].handler);
+
+ irq_handlers[irq].handler = handler;
+ irq_handlers[irq].arg = arg;
+
+ i8259_unmask_irq(irq);
+}
+
+void
+irq_free_handler(int irq)
+{
+ if (irq < 0 || irq >= NR_IRQS) {
+ PRINTF("irq_free_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ i8259_mask_irq(irq);
+
+ irq_handlers[irq].handler = NULL;
+ irq_handlers[irq].arg = NULL;
+}
+
+/****************************************************************************/
+
+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/board/MAI/AmigaOneG3SE/macros.h b/board/MAI/AmigaOneG3SE/macros.h
new file mode 100644
index 0000000..0fbe39b
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/macros.h
@@ -0,0 +1,84 @@
+
+#ifndef _MACROS_H
+#define _MACROS_H
+
+ /*
+ ** Load a long integer into a register
+ */
+ .macro liw reg, value
+ lis \reg, \value@h
+ ori \reg, \reg, \value@l
+ .endm
+
+
+ /*
+ ** Generate config_addr request
+ ** This macro expects the values in registers:
+ ** r3 - bus
+ ** r4 - devfn
+ ** r5 - offset
+ */
+ .macro config_addr
+ rlwinm r9, r5, 24, 0, 6
+ rlwinm r8, r4, 16, 0, 31
+ rlwinm r7, r3, 8, 0, 31
+ or r9, r8, r9
+ or r9, r7, r9
+ ori r9, r9, 0x80
+ liw r10, 0xfec00cf8
+ stw r9, 0(r10)
+ eieio
+ sync
+ .endm
+
+
+ /*
+ ** Generate config_data address
+ */
+ .macro config_data mask
+ andi. r9, r5, \mask
+ addi r9, r9, 0xcfc
+ oris r9, r9, 0xfee0
+ .endm
+
+
+ /*
+ ** Write a byte value to an output port
+ */
+ .macro outb port, value
+ lis r2, 0xfe00
+ li r0, \value
+ stb r0, \port(r2)
+ .endm
+
+
+ /*
+ ** Write a register byte value to an output port
+ */
+ .macro outbr port, value
+ lis r2, 0xfe00
+ stb \value, \port(r2)
+ .endm
+
+
+ /*
+ ** Read a byte value from a port into a specified register
+ */
+ .macro inb reg, port
+ lis r2, 0xfe00
+ lbz \reg, \port(r2)
+ .endm
+
+
+ /*
+ ** Write a byte to the SuperIO config area
+ */
+ .macro siowb offset, value
+ li r3, 0
+ li r4, (7<<3)
+ li r5, \offset
+ li r6, \value
+ bl pci_write_cfg_byte
+ .endm
+
+#endif
diff --git a/board/MAI/AmigaOneG3SE/memio.S b/board/MAI/AmigaOneG3SE/memio.S
new file mode 100644
index 0000000..c4a09aa
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/memio.S
@@ -0,0 +1,74 @@
+#include "macros.h"
+
+
+
+ .globl pci_read_cfg_byte
+
+pci_read_cfg_byte:
+ config_addr
+ config_data 3
+ eieio
+ sync
+ lbz r3, 0(r9)
+ blr
+
+
+
+ .globl pci_write_cfg_byte
+
+pci_write_cfg_byte:
+ config_addr
+ config_data 3
+ stb r6, 0(r9)
+ eieio
+ sync
+ blr
+
+
+
+ .globl pci_read_cfg_word
+
+pci_read_cfg_word:
+ config_addr
+ config_data 2
+ lhbrx r3, 0, r9
+ eieio
+ sync
+ blr
+
+
+
+ .globl pci_write_cfg_word
+
+pci_write_cfg_word:
+ config_addr
+ config_data 2
+ sthbrx r6, 0, r9
+ eieio
+ sync
+ blr
+
+
+
+ .globl pci_read_cfg_long
+
+pci_read_cfg_long:
+ config_addr
+ config_data 0
+ lwbrx r3, 0, r9
+ eieio
+ sync
+ blr
+
+
+
+ .globl pci_write_cfg_long
+
+pci_write_cfg_long:
+ config_addr
+ config_data 0
+ stwbrx r6, 0, r9
+ eieio
+ sync
+ blr
+
diff --git a/board/MAI/AmigaOneG3SE/memio.h b/board/MAI/AmigaOneG3SE/memio.h
new file mode 100644
index 0000000..df0839f
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/memio.h
@@ -0,0 +1,113 @@
+/*
+ * Memory mapped IO
+ *
+ * (C) Copyright 2002
+ * Hyperion Entertainment, ThomasF@hyperion-entertainment.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.
+ * You may also use this under a BSD license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MEMIO_H
+#define _MEMIO_H
+
+#include "short_types.h"
+
+#define IOBASE 0xFE000000
+
+#define in_byte(from) read_byte( (uint8 *)(IOBASE | (from)))
+#define in_word(from) read_word_little((uint16 *)(IOBASE | (from)))
+#define in_long(from) read_long_little((uint32 *)(IOBASE | (from)))
+#define out_byte(to, val) write_byte((uint8 *)(IOBASE | (to)), val)
+#define out_word(to, val) write_word_little((uint16 *)(IOBASE | (to)), val)
+#define out_long(to, val) write_long_little((uint32 *)(IOBASE | (to)), val)
+
+
+static inline uint8 read_byte(volatile uint8 *from)
+{
+ int x;
+ asm volatile ("lbz %0,%1\n eieio\n sync" : "=r" (x) : "m" (*from));
+ return (uint8)x;
+}
+
+
+static inline void write_byte(volatile uint8 *to, uint8 x)
+{
+ asm volatile ("stb %1,%0\n eieio\n sync" : "=m" (*to) : "r" (x));
+}
+
+static inline uint16 read_word_little(volatile uint16 *from)
+{
+ int x;
+ asm volatile ("lhbrx %0,0,%1\n eieio\n sync" : "=r" (x) : "r" (from), "m" (*from));
+ return (uint16)x;
+}
+
+static inline uint16 read_word_big(volatile uint16 *from)
+{
+ int x;
+ asm volatile ("lhz %0,%1\n eieio\n sync" : "=r" (x) : "m" (*from));
+ return (uint16)x;
+}
+
+static inline void write_word_little(volatile uint16 *to, int x)
+{
+ asm volatile ("sthbrx %1,0,%2\n eieio\n sync" : "=m" (*to) : "r" (x), "r" (to));
+}
+
+static inline void write_word_big(volatile uint16 *to, int x)
+{
+ asm volatile ("sth %1,%0\n eieio\n sync" : "=m" (*to) : "r" (x));
+}
+
+static inline uint32 read_long_little(volatile uint32 *from)
+{
+ unsigned long x;
+ asm volatile ("lwbrx %0,0,%1\n eieio\n sync" : "=r" (x) : "r" (from), "m"(*from));
+ return (uint32)x;
+}
+
+static inline uint32 read_long_big(volatile uint32 *from)
+{
+ unsigned long x;
+ asm volatile ("lwz %0,%1\n eieio\n sync" : "=r" (x) : "m" (*from));
+ return (uint32)x;
+}
+
+static inline void write_long_little(volatile uint32 *to, uint32 x)
+{
+ asm volatile ("stwbrx %1,0,%2\n eieio\n sync" : "=m" (*to) : "r" (x), "r" (to));
+}
+
+static inline void write_long_big(volatile uint32 *to, uint32 x)
+{
+ asm volatile ("stw %1,%0\n eieio\n sync" : "=m" (*to) : "r" (x));
+}
+
+#define CONFIG_ADDR(bus, devfn, offset) \
+ write_long_big((uint32 *)0xFEC00CF8, \
+ ((offset & 0xFC)<<24) | (devfn << 16) \
+ | (bus<<8) | 0x80);
+#define CONFIG_DATA(offset,mask) ((void *)(0xFEE00CFC+(offset & mask)))
+
+
+uint8 pci_read_cfg_byte(int32 bus, int32 devfn, int32 offset);
+void pci_write_cfg_byte(int32 bus, int32 devfn, int32 offset, uint8 x);
+uint16 pci_read_cfg_word(int32 bus, int32 devfn, int32 offset);
+void pci_write_cfg_word(int32 bus, int32 devfn, int32 offset, uint16 x);
+uint32 pci_read_cfg_long(int32 bus, int32 devfn, int32 offset);
+void pci_write_cfg_long(int32 bus, int32 devfn, int32 offset, uint32 x);
+
+
+#endif
diff --git a/board/MAI/AmigaOneG3SE/memory_dump b/board/MAI/AmigaOneG3SE/memory_dump
new file mode 100644
index 0000000..65e7936
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/memory_dump
@@ -0,0 +1,30 @@
+64 MB:
+0x00: 80 08 04 0c 09 01 40 00 01 a0 60 00 80 08 00 01
+0x10: 8f 04 04 01 01 00 06 a0 60 00 00 14 10 14 2d 10
+0x20: 20 10 20 10 00 00 00 00 00 00 00 00 00 00 00 00
+0x30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 f2
+0x40: 7f 61 00 00 00 00 00 00 46 04 00 ff ff ff ff ff
+0x50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+0x60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+0x70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff 64 f4
+
+512 MB:
+0x00: 80 08 04 0d 0a 02 40 00 01 75 54 00 82 08 00 01
+0x10: 8f 04 04 01 01 00 0f 00 00 00 00 14 0f 14 2d 40
+0x20: 15 08 15 08 00 00 00 00 00 00 00 00 00 00 00 00
+0x30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 d2
+0x40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0x50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0x60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0x70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 fd
+
+256 MB:
+0x00: 80 08 04 0c 0a 02 40 00 01 75 54 00 80 08 00 01
+0x10: 8f 04 06 01 01 00 0e a0 60 00 00 14 0f 14 2d 20
+0x20: 15 08 15 08 00 00 00 00 00 00 00 00 00 00 00 00
+0x30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 b0
+0x40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0x50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0x60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0x70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 f6
+
diff --git a/board/MAI/AmigaOneG3SE/nvram.c b/board/MAI/AmigaOneG3SE/nvram.c
new file mode 100644
index 0000000..5dde15b
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/nvram.c
@@ -0,0 +1,37 @@
+/*
+ * (C) Copyright 2002
+ * Thomas Frieden, Hyperion Entertainment
+ * ThomasF@hyperion-entertainment.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 <common.h>
+#include "memio.h"
+
+void enable_nvram(void)
+{
+ pci_write_cfg_byte(0, 0, 0x56, 0x0b);
+}
+
+void disable_nvram(void)
+{
+ pci_write_cfg_byte(0, 0, 0x56, 0x0);
+}
+
diff --git a/board/MAI/AmigaOneG3SE/ps2kbd.c b/board/MAI/AmigaOneG3SE/ps2kbd.c
new file mode 100644
index 0000000..a6d67be
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/ps2kbd.c
@@ -0,0 +1,699 @@
+/*
+ * (C) Copyright 2002
+ * John W. Linville, linville@tuxdriver.com
+ *
+ * Modified from code for support of MIP405 and PIP405 boards. Previous
+ * copyright follows.
+ *
+ * (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
+ *
+ *
+ * Source partly derived from:
+ * linux/drivers/char/pc_keyb.c
+ *
+ *
+ */
+#include <common.h>
+#include <asm/processor.h>
+#include <devices.h>
+#include "ps2kbd.h"
+
+
+unsigned char kbd_read_status(void);
+unsigned char kbd_read_input(void);
+void kbd_send_data(unsigned char data);
+void i8259_mask_irq(unsigned int irq);
+void i8259_unmask_irq(unsigned int irq);
+
+/* used only by send_data - set by keyboard_interrupt */
+
+
+#undef KBG_DEBUG
+//#define KBG_DEBUG
+
+#ifdef KBG_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#define KBD_STAT_KOBF 0x01
+#define KBD_STAT_IBF 0x02
+#define KBD_STAT_SYS 0x04
+#define KBD_STAT_CD 0x08
+#define KBD_STAT_LOCK 0x10
+#define KBD_STAT_MOBF 0x20
+#define KBD_STAT_TI_OUT 0x40
+#define KBD_STAT_PARERR 0x80
+
+#define KBD_INIT_TIMEOUT 2000 /* Timeout in ms for initializing the keyboard */
+#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
+#define KBD_TIMEOUT 2000 /* Timeout in ms for keyboard command acknowledge */
+/*
+ * Keyboard Controller Commands
+ */
+
+#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
+#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
+#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
+#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
+#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
+#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
+ initiated by the auxiliary device */
+#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
+
+/*
+ * Keyboard Commands
+ */
+
+#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
+#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
+#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
+#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */
+#define KBD_CMD_RESET 0xFF /* Reset */
+
+/*
+ * Keyboard Replies
+ */
+
+#define KBD_REPLY_POR 0xAA /* Power on reset */
+#define KBD_REPLY_ACK 0xFA /* Command ACK */
+#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
+
+/*
+ * Status Register Bits
+ */
+
+#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
+#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
+#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
+#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
+#define KBD_STAT_PERR 0x80 /* Parity error */
+
+#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
+
+/*
+ * Controller Mode Register Bits
+ */
+
+#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
+#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS 0x04 /* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
+#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
+#define KBD_MODE_RFU 0x80
+
+
+#define KDB_DATA_PORT 0x60
+#define KDB_COMMAND_PORT 0x64
+
+#define LED_SCR 0x01 /* scroll lock led */
+#define LED_CAP 0x04 /* caps lock led */
+#define LED_NUM 0x02 /* num lock led */
+
+#define KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
+
+
+
+
+static volatile char kbd_buffer[KBD_BUFFER_LEN];
+static volatile int in_pointer = 0;
+static volatile int out_pointer = 0;
+
+
+static unsigned char num_lock = 0;
+static unsigned char caps_lock = 0;
+static unsigned char scroll_lock = 0;
+static unsigned char shift = 0;
+static unsigned char ctrl = 0;
+static unsigned char alt = 0;
+static unsigned char e0 = 0;
+static unsigned char leds = 0;
+
+#define DEVNAME "ps2kbd"
+
+/* Simple translation table for the keys */
+
+static unsigned char kbd_plain_xlate[] = {
+ 0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t', /* 0x00 - 0x0f */
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's', /* 0x10 - 0x1f */
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v', /* 0x20 - 0x2f */
+ 'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
+ '\r',0xff,0xff
+ };
+
+static unsigned char kbd_shift_xlate[] = {
+ 0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t', /* 0x00 - 0x0f */
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S', /* 0x10 - 0x1f */
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V', /* 0x20 - 0x2f */
+ 'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
+ '\r',0xff,0xff
+ };
+
+static unsigned char kbd_ctrl_xlate[] = {
+ 0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t', /* 0x00 - 0x0f */
+ 0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13, /* 0x10 - 0x1f */
+ 0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16, /* 0x20 - 0x2f */
+ 0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
+ '\r',0xff,0xff
+ };
+
+/******************************************************************
+ * Init
+ ******************************************************************/
+
+int isa_kbd_init(void)
+{
+ char* result;
+ result=kbd_initialize();
+ if (result != NULL)
+ {
+ result = kbd_initialize();
+ }
+ if(result==NULL) {
+ printf("AT Keyboard initialized\n");
+ irq_install_handler(KBD_INTERRUPT, (interrupt_handler_t *)kbd_interrupt, NULL);
+ return (1);
+ }
+ else {
+ printf("%s\n",result);
+ return (-1);
+ }
+}
+
+#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console (void);
+#else
+int overwrite_console (void)
+{
+ return (0);
+}
+#endif
+
+int drv_isa_kbd_init (void)
+{
+ int error;
+ device_t kbddev ;
+ char *stdinname = getenv ("stdin");
+
+ if(isa_kbd_init()==-1)
+ return -1;
+ memset (&kbddev, 0, sizeof(kbddev));
+ strcpy(kbddev.name, DEVNAME);
+ kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ kbddev.putc = NULL ;
+ kbddev.puts = NULL ;
+ kbddev.getc = kbd_getc ;
+ kbddev.tstc = kbd_testc ;
+
+ error = device_register (&kbddev);
+ if(error==0) {
+ /* check if this is the standard input device */
+ if(strcmp(stdinname,DEVNAME)==0) {
+ /* reassign the console */
+ if(overwrite_console()) {
+ return 1;
+ }
+ error=console_assign(stdin,DEVNAME);
+ if(error==0)
+ return 1;
+ else
+ return error;
+ }
+ return 1;
+ }
+ return error;
+}
+
+/******************************************************************
+ * Queue handling
+ ******************************************************************/
+/* puts character in the queue and sets up the in and out pointer */
+void kbd_put_queue(char data)
+{
+ if((in_pointer+1)==KBD_BUFFER_LEN) {
+ if(out_pointer==0) {
+ return; /* buffer full */
+ } else{
+ in_pointer=0;
+ }
+ } else {
+ if((in_pointer+1)==out_pointer)
+ return; /* buffer full */
+ in_pointer++;
+ }
+ kbd_buffer[in_pointer]=data;
+ return;
+}
+
+/* test if a character is in the queue */
+int kbd_testc(void)
+{
+ if(in_pointer==out_pointer)
+ return(0); /* no data */
+ else
+ return(1);
+}
+/* gets the character from the queue */
+int kbd_getc(void)
+{
+ char c;
+
+ while(in_pointer==out_pointer);
+ if((out_pointer+1)==KBD_BUFFER_LEN)
+ out_pointer=0;
+ else
+ out_pointer++;
+ c=kbd_buffer[out_pointer];
+ return (int)c;
+
+}
+
+
+/* set LEDs */
+
+void kbd_set_leds(void)
+{
+ if(caps_lock==0)
+ leds&=~LED_CAP; /* switch caps_lock off */
+ else
+ leds|=LED_CAP; /* switch on LED */
+ if(num_lock==0)
+ leds&=~LED_NUM; /* switch LED off */
+ else
+ leds|=LED_NUM; /* switch on LED */
+ if(scroll_lock==0)
+ leds&=~LED_SCR; /* switch LED off */
+ else
+ leds|=LED_SCR; /* switch on LED */
+ kbd_send_data(KBD_CMD_SET_LEDS);
+ kbd_send_data(leds);
+}
+
+
+void handle_keyboard_event(unsigned char scancode)
+{
+ unsigned char keycode;
+
+ /* Convert scancode to keycode */
+ PRINTF("scancode %x\n",scancode);
+ if(scancode==0xe0) {
+ e0=1; /* special charakters */
+ return;
+ }
+ if(e0==1) {
+ e0=0; /* delete flag */
+ if(!( ((scancode&0x7F)==0x38)|| /* the right ctrl key */
+ ((scancode&0x7F)==0x1D)|| /* the right alt key */
+ ((scancode&0x7F)==0x35)|| /* the right '/' key */
+ ((scancode&0x7F)==0x1C)|| /* the right enter key */
+ ((scancode)==0x48)|| /* arrow up */
+ ((scancode)==0x50)|| /* arrow down */
+ ((scancode)==0x4b)|| /* arrow left */
+ ((scancode)==0x4d))) /* arrow right */
+ /* we swallow unknown e0 codes */
+ return;
+ }
+ /* special cntrl keys */
+ switch(scancode)
+ {
+ case 0x48:
+ kbd_put_queue(27);
+ kbd_put_queue(91);
+ kbd_put_queue('A');
+ return;
+ case 0x50:
+ kbd_put_queue(27);
+ kbd_put_queue(91);
+ kbd_put_queue('B');
+ return;
+ case 0x4b:
+ kbd_put_queue(27);
+ kbd_put_queue(91);
+ kbd_put_queue('D');
+ return;
+ case 0x4D:
+ kbd_put_queue(27);
+ kbd_put_queue(91);
+ kbd_put_queue('C');
+ return;
+ case 0x58: /* F12 key */
+ if (ctrl == 1)
+ {
+ extern int console_changed;
+ setenv("stdin", DEVNAME);
+ setenv("stdout", "vga");
+ console_changed = 1;
+ }
+ return;
+ case 0x2A:
+ case 0x36: /* shift pressed */
+ shift=1;
+ return; /* do nothing else */
+ case 0xAA:
+ case 0xB6: /* shift released */
+ shift=0;
+ return; /* do nothing else */
+ case 0x38: /* alt pressed */
+ alt=1;
+ return; /* do nothing else */
+ case 0xB8: /* alt released */
+ alt=0;
+ return; /* do nothing else */
+ case 0x1d: /* ctrl pressed */
+ ctrl=1;
+ return; /* do nothing else */
+ case 0x9d: /* ctrl released */
+ ctrl=0;
+ return; /* do nothing else */
+ case 0x46: /* scrollock pressed */
+ scroll_lock=~scroll_lock;
+ kbd_set_leds();
+ return; /* do nothing else */
+ case 0x3A: /* capslock pressed */
+ caps_lock=~caps_lock;
+ kbd_set_leds();
+ return;
+ case 0x45: /* numlock pressed */
+ num_lock=~num_lock;
+ kbd_set_leds();
+ return;
+ case 0xC6: /* scroll lock released */
+ case 0xC5: /* num lock released */
+ case 0xBA: /* caps lock released */
+ return; /* just swallow */
+ }
+ if((scancode&0x80)==0x80) /* key released */
+ return;
+ /* now, decide which table we need */
+ if(scancode > (sizeof(kbd_plain_xlate)/sizeof(kbd_plain_xlate[0]))) { /* scancode not in list */
+ PRINTF("unkown scancode %X\n",scancode);
+ return; /* swallow it */
+ }
+ /* setup plain code first */
+ keycode=kbd_plain_xlate[scancode];
+ if(caps_lock==1) { /* caps_lock is pressed, overwrite plain code */
+ if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
+ PRINTF("unkown caps-locked scancode %X\n",scancode);
+ return; /* swallow it */
+ }
+ keycode=kbd_shift_xlate[scancode];
+ if(keycode<'A') { /* we only want the alphas capital */
+ keycode=kbd_plain_xlate[scancode];
+ }
+ }
+ if(shift==1) { /* shift overwrites caps_lock */
+ if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
+ PRINTF("unkown shifted scancode %X\n",scancode);
+ return; /* swallow it */
+ }
+ keycode=kbd_shift_xlate[scancode];
+ }
+ if(ctrl==1) { /* ctrl overwrites caps_lock and shift */
+ if(scancode > (sizeof(kbd_ctrl_xlate)/sizeof(kbd_ctrl_xlate[0]))) { /* scancode not in list */
+ PRINTF("unkown ctrl scancode %X\n",scancode);
+ return; /* swallow it */
+ }
+ keycode=kbd_ctrl_xlate[scancode];
+ }
+ /* check if valid keycode */
+ if(keycode==0xff) {
+ PRINTF("unkown scancode %X\n",scancode);
+ return; /* swallow unknown codes */
+ }
+
+ kbd_put_queue(keycode);
+ PRINTF("%x\n",keycode);
+}
+
+/*
+ * This reads the keyboard status port, and does the
+ * appropriate action.
+ *
+ */
+unsigned char handle_kbd_event(void)
+{
+ unsigned char status = kbd_read_status();
+ unsigned int work = 10000;
+
+ while ((--work > 0) && (status & KBD_STAT_OBF)) {
+ unsigned char scancode;
+
+ scancode = kbd_read_input();
+
+ /* Error bytes must be ignored to make the
+ Synaptics touchpads compaq use work */
+ /* Ignore error bytes */
+ if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
+ {
+ if (status & KBD_STAT_MOUSE_OBF)
+ ; /* not supported: handle_mouse_event(scancode); */
+ else
+ handle_keyboard_event(scancode);
+ }
+ status = kbd_read_status();
+ }
+ if (!work)
+ PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
+ return status;
+}
+
+
+
+/******************************************************************************
+ * Lowlevel Part of keyboard section
+ */
+unsigned char kbd_read_status(void)
+{
+ return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT));
+}
+
+unsigned char kbd_read_input(void)
+{
+ return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT));
+}
+
+void kbd_write_command(unsigned char cmd)
+{
+ out8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT,cmd);
+}
+
+void kbd_write_output(unsigned char data)
+{
+ out8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT, data);
+}
+
+int kbd_read_data(void)
+{
+ int val;
+ unsigned char status;
+
+ val=-1;
+ status = kbd_read_status();
+ if (status & KBD_STAT_OBF) {
+ val = kbd_read_input();
+ if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
+ val = -2;
+ }
+ return val;
+}
+
+int kbd_wait_for_input(void)
+{
+ unsigned long timeout;
+ int val;
+
+ timeout = KBD_TIMEOUT;
+ val=kbd_read_data();
+ while(val < 0)
+ {
+ if(timeout--==0)
+ return -1;
+ udelay(1000);
+ val=kbd_read_data();
+ }
+ return val;
+}
+
+
+int kb_wait(void)
+{
+ unsigned long timeout = KBC_TIMEOUT * 10;
+
+ do {
+ unsigned char status = handle_kbd_event();
+ if (!(status & KBD_STAT_IBF))
+ return 0; /* ok */
+ udelay(1000);
+ timeout--;
+ } while (timeout);
+ return 1;
+}
+
+void kbd_write_command_w(int data)
+{
+ if(kb_wait())
+ PRINTF("timeout in kbd_write_command_w\n");
+ kbd_write_command(data);
+}
+
+void kbd_write_output_w(int data)
+{
+ if(kb_wait())
+ PRINTF("timeout in kbd_write_output_w\n");
+ kbd_write_output(data);
+}
+
+void kbd_send_data(unsigned char data)
+{
+ unsigned char status;
+ i8259_mask_irq(KBD_INTERRUPT); /* disable interrupt */
+ kbd_write_output_w(data);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ i8259_unmask_irq(KBD_INTERRUPT); /* enable interrupt */
+}
+
+
+char * kbd_initialize(void)
+{
+ int status;
+
+ in_pointer = 0; /* delete in Buffer */
+ out_pointer = 0;
+ /*
+ * Test the keyboard interface.
+ * This seems to be the only way to get it going.
+ * If the test is successful a x55 is placed in the input buffer.
+ */
+ kbd_write_command_w(KBD_CCMD_SELF_TEST);
+ if (kbd_wait_for_input() != 0x55)
+ return "Kbd: failed self test";
+ /*
+ * Perform a keyboard interface test. This causes the controller
+ * to test the keyboard clock and data lines. The results of the
+ * test are placed in the input buffer.
+ */
+ kbd_write_command_w(KBD_CCMD_KBD_TEST);
+ if (kbd_wait_for_input() != 0x00)
+ return "Kbd: interface failed self test";
+ /*
+ * Enable the keyboard by allowing the keyboard clock to run.
+ */
+ kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
+ status = kbd_wait_for_input();
+ /*
+ * Reset keyboard. If the read times out
+ * then the assumption is that no keyboard is
+ * plugged into the machine.
+ * This defaults the keyboard to scan-code set 2.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
+ */
+ do {
+ kbd_write_output_w(KBD_CMD_RESET);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ if (status != KBD_REPLY_RESEND)
+ {
+ PRINTF("status: %X\n",status);
+ return "Kbd: reset failed, no ACK";
+ }
+ } while (1);
+ if (kbd_wait_for_input() != KBD_REPLY_POR)
+ return "Kbd: reset failed, no POR";
+
+ /*
+ * Set keyboard controller mode. During this, the keyboard should be
+ * in the disabled state.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
+ */
+ do {
+ kbd_write_output_w(KBD_CMD_DISABLE);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ if (status != KBD_REPLY_RESEND)
+ return "Kbd: disable keyboard: no ACK";
+ } while (1);
+
+ kbd_write_command_w(KBD_CCMD_WRITE_MODE);
+ kbd_write_output_w(KBD_MODE_KBD_INT
+ | KBD_MODE_SYS
+ | KBD_MODE_DISABLE_MOUSE
+ | KBD_MODE_KCC);
+
+ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+ kbd_write_command_w(KBD_CCMD_READ_MODE);
+ if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+ /*
+ * If the controller does not support conversion,
+ * Set the keyboard to scan-code set 1.
+ */
+ kbd_write_output_w(0xF0);
+ kbd_wait_for_input();
+ kbd_write_output_w(0x01);
+ kbd_wait_for_input();
+ }
+ kbd_write_output_w(KBD_CMD_ENABLE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Kbd: enable keyboard: no ACK";
+
+ /*
+ * Finally, set the typematic rate to maximum.
+ */
+ kbd_write_output_w(KBD_CMD_SET_RATE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Kbd: Set rate: no ACK";
+ kbd_write_output_w(0x00);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Kbd: Set rate: no ACK";
+ return NULL;
+}
+
+void kbd_interrupt(void)
+{
+ handle_kbd_event();
+}
+
+
+
+/* eof */
+
diff --git a/board/MAI/AmigaOneG3SE/ps2kbd.h b/board/MAI/AmigaOneG3SE/ps2kbd.h
new file mode 100644
index 0000000..95fc14d
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/ps2kbd.h
@@ -0,0 +1,41 @@
+/*
+ * (C) Copyright 2002
+ * John W. Linville, linville@tuxdriver.com
+ *
+ * Modified from code for support of MIP405 and PIP405 boards. Previous
+ * copyright follows.
+ *
+ * (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
+ *
+ */
+
+#ifndef _KBD_H_
+#define _KBD_H_
+
+extern int kbd_testc(void);
+extern int kbd_getc(void);
+extern void kbd_interrupt(void);
+extern char *kbd_initialize(void);
+
+unsigned char kbd_is_init(void);
+#define KBD_INTERRUPT 1
+#endif
diff --git a/board/MAI/AmigaOneG3SE/serial.c b/board/MAI/AmigaOneG3SE/serial.c
new file mode 100644
index 0000000..e83fb46
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/serial.c
@@ -0,0 +1,247 @@
+#include <common.h>
+#include <ns16550.h>
+#include "short_types.h"
+#include "memio.h"
+#include "articiaS.h"
+
+#ifndef CFG_NS16550
+static uint32 ComPort1;
+
+uint16 SerialEcho = 1;
+
+
+#define RECEIVER_HOLDING 0
+#define TRANSMITTER_HOLDING 0
+#define INTERRUPT_ENABLE 1
+#define INTERRUPT_STATUS 2
+#define FIFO_CONTROL 2
+#define LINE_CONTROL 3
+#define MODEM_CONTROL 4
+#define LINE_STATUS 5
+#define MODEM_STATUS 6
+#define SCRATCH_PAD 7
+
+#define DIVISOR_LATCH_LSB 0
+#define DIVISOR_LATCH_MSB 1
+#define PRESCALER_DIVISION 5
+
+#define COM_WRITE_BYTE(reg, byte) out_byte((ComPort1+reg), byte)
+#define COM_READ_BYTE(reg) in_byte((ComPort1+reg))
+
+static int serial_init_done = 0;
+
+void serial_init (void)
+{
+#if 0
+ uint32 clock_divisor = 115200 / baudrate;
+ uint8 cfg;
+ uint8 a;
+ uint16 devfn = 7 << 3;
+
+ if (serial_init_done)
+ return;
+
+ /* Enter configuration mode */
+ cfg = pci_read_cfg_byte (0, devfn, 0x85);
+ pci_write_cfg_byte (0, devfn, 0x85, cfg | 0x02);
+
+ /* Set serial port COM1 as 3F8 */
+ out_byte (0x3F0, 0xE7);
+ out_byte (0x3f1, 0xfe);
+
+ /* Set serial port COM2 as 2F8 */
+ out_byte (0x3f0, 0xe8);
+ out_byte (0x3f1, 0xeb);
+
+ /* Enable */
+ out_byte (0x3f0, 0xe2);
+ a = in_byte (0x3f1);
+ a |= 0xc;
+ out_byte (0x3f0, 0xe2);
+ out_byte (0x3f1, a);
+
+ /* Reset the configuration mode */
+ pci_write_cfg_byte (0, devfn, 0x85, cfg);
+#endif
+
+ ComPort1 = 0x3F8;
+
+ /* Disable interrupts */
+ COM_WRITE_BYTE (INTERRUPT_ENABLE, 0x00);
+
+ /* Set baud rate */
+ /* COM_WRITE_BYTE(LINE_CONTROL, 0x83); */
+ /* COM_WRITE_BYTE(DIVISOR_LATCH_LSB, (uint8)(clock_divisor & 0xFF)); */
+ /* COM_WRITE_BYTE(DIVISOR_LATCH_MSB, (uint8)(clock_divisor >> 8)); */
+ /* __asm("eieio"); */
+
+ /* Set 8-N-1 */
+ COM_WRITE_BYTE (LINE_CONTROL, 0x03);
+ __asm ("eieio");
+
+ /* Disable FIFO */
+ COM_WRITE_BYTE (MODEM_CONTROL, 0x03);
+ COM_WRITE_BYTE (FIFO_CONTROL, 0x07);
+
+ __asm ("eieio");
+ serial_init_done = 1;
+}
+
+extern int console_changed;
+
+void serial_putc (const char sendme)
+{
+ if (sendme == '\n') {
+ while ((in_byte (0x3FD) & 0x40) == 0);
+ out_byte (0x3f8, 0x0D);
+ }
+
+ while ((in_byte (0x3FD) & 0x40) == 0);
+ out_byte (0x3f8, sendme);
+}
+
+int serial_getc (void)
+{
+#if 0
+ uint8 c;
+
+ for (;;) {
+ uint8 x = in_byte (0x3FD);
+
+ if (x & 0x01)
+ break;
+
+ if (x & 0x0C)
+ out_byte (0x3fd, 0x0c);
+ }
+
+ c = in_byte (0x3F8);
+
+ return c;
+#else
+ while ((in_byte (0x3FD) & 0x01) == 0) {
+ if (console_changed != 0) {
+ printf ("Console changed\n");
+ console_changed = 0;
+ return 0;
+ }
+ }
+ return in_byte (0x3F8);
+#endif
+}
+
+int serial_tstc (void)
+{
+ return (in_byte (0x03FD) & 0x01) != 0;
+}
+
+void serial_debug_putc (int c)
+{
+ serial_puts ("DBG");
+ serial_putc (c);
+ serial_putc (0x0d);
+ serial_putc (0x0A);
+}
+
+#else
+
+const NS16550_t Com0 = (NS16550_t) CFG_NS16550_COM1;
+const NS16550_t Com1 = (NS16550_t) CFG_NS16550_COM2;
+
+int serial_init (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ uint32 clock_divisor = 115200 / gd->baudrate;
+
+ NS16550_init (Com0, clock_divisor);
+ /* NS16550_reinit(Com1, clock_divisor); */
+ /* serial_puts("COM1: 3F8h initalized"); */
+
+ return (0);
+}
+
+#if 0
+void serial_putc (const char c)
+{
+ NS16550_putc (Com0, c);
+ if (c == '\n')
+ NS16550_putc (Com0, 0x0D);
+}
+
+int serial_getc (void)
+{
+ return (int) NS16550_getc (Com0);
+}
+
+int serial_tstc (void)
+{
+ return NS16550_tstc (Com0);
+}
+#else
+void serial_putc (const char sendme)
+{
+ if (sendme == '\n') {
+ while ((in_byte (0x3FD) & 0x40) == 0);
+ out_byte (0x3f8, 0x0D);
+ }
+
+ while ((in_byte (0x3FD) & 0x40) == 0);
+ out_byte (0x3f8, sendme);
+}
+
+
+extern int console_changed;
+
+int serial_getc (void)
+{
+#if 0
+ uint8 c;
+
+ for (;;) {
+ uint8 x = in_byte (0x3FD);
+
+ if (x & 0x01)
+ break;
+
+ if (x & 0x0C)
+ out_byte (0x3fd, 0x0c);
+ }
+
+ c = in_byte (0x3F8);
+
+ return c;
+#else
+ while ((in_byte (0x3FD) & 0x01) == 0) {
+ if (console_changed != 0) {
+ console_changed = 0;
+ return 0;
+ }
+ }
+
+ return in_byte (0x3F8);
+#endif
+}
+
+int serial_tstc (void)
+{
+ return (in_byte (0x03FD) & 0x01) != 0;
+}
+#endif
+
+#endif
+
+void serial_puts (const char *string)
+{
+ while (*string)
+ serial_putc (*string++);
+}
+
+void serial_setbrg (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ uint32 clock_divisor = 115200 / gd->baudrate;
+
+ NS16550_init (Com0, clock_divisor);
+}
diff --git a/board/MAI/AmigaOneG3SE/short_types.h b/board/MAI/AmigaOneG3SE/short_types.h
new file mode 100644
index 0000000..22df3c9
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/short_types.h
@@ -0,0 +1,36 @@
+/*
+ * short type names
+ *
+ * (C) Copyright 2002
+ * Hyperion Entertainment, ThomasF@hyperion-entertainment.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 _SHORT_TYPES_H
+#define _SHORT_TYPES_H
+
+typedef unsigned long uint32;
+typedef long int32;
+typedef unsigned short uint16;
+typedef short int16;
+typedef unsigned char uint8;
+typedef signed char int8;
+
+#endif
diff --git a/board/MAI/AmigaOneG3SE/smbus.c b/board/MAI/AmigaOneG3SE/smbus.c
new file mode 100644
index 0000000..616005e
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/smbus.c
@@ -0,0 +1,206 @@
+#include "memio.h"
+#include "articiaS.h"
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+void sm_write_mode(void)
+{
+ out_byte(0xA539, 0x00);
+ out_byte(0xA53A, 0x03);
+}
+
+void sm_read_mode(void)
+{
+ out_byte(0xA53A, 0x02);
+ out_byte(0xA539, 0x02);
+}
+
+void sm_write_byte(uint8 writeme)
+{
+ int i;
+ int level;
+
+ out_byte(0xA539, 0x00);
+
+ level = 0;
+
+ for (i=0; i<8; i++)
+ {
+ if ((writeme & 0x80) == (level<<7))
+ {
+ /* Bit did not change, rewrite strobe */
+ out_byte(0xA539, level | 0x02);
+ out_byte(0xA539, level);
+ }
+ else
+ {
+ /* Bit changed, set bit, then strobe */
+ level = (writeme & 0x80) >> 7;
+ out_byte(0xA539, level);
+ out_byte(0xA539, level | 0x02);
+ out_byte(0xA539, level);
+ }
+ writeme <<= 1;
+ }
+ out_byte(0xA539, 0x00);
+}
+
+uint8 sm_read_byte(void)
+{
+ uint8 retme, r;
+ int i;
+
+ retme = 0;
+ for (i=0; i<8; i++)
+ {
+ retme <<= 1;
+ out_byte(0xA539, 0x00);
+ out_byte(0xA539, 0x02);
+ r = in_byte(0xA538) & 0x01;
+ retme |= r;
+ }
+
+ return retme;
+}
+
+int sm_get_ack(void)
+{
+ uint8 r;
+ r = in_byte(0xA538);
+ if ((r&0x01) == 0) return TRUE;
+ else return FALSE;
+}
+
+void sm_write_ack(void)
+{
+ out_byte(0xA539, 0x00);
+ out_byte(0xA539, 0x02);
+ out_byte(0xA539, 0x00);
+}
+
+void sm_write_nack(void)
+{
+ out_byte(0xA539, 0x01);
+ out_byte(0xA539, 0x03);
+ out_byte(0xA539, 0x01);
+}
+
+void sm_send_start(void)
+{
+ out_byte(0xA539, 0x03);
+ out_byte(0xA539, 0x02);
+}
+
+void sm_send_stop(void)
+{
+ out_byte(0xA539, 0x02);
+ out_byte(0xA539, 0x03);
+}
+
+int sm_read_byte_from_device(uint8 addr, uint8 reg, uint8 *storage)
+{
+ // S Addr Wr
+ sm_write_mode();
+ sm_send_start();
+ sm_write_byte((addr<<1));
+
+ // [A]
+ sm_read_mode();
+ if (sm_get_ack() == FALSE) return FALSE;
+
+ // Comm
+ sm_write_mode();
+ sm_write_byte(reg);
+
+ // [A]
+ sm_read_mode();
+ if (sm_get_ack() == FALSE) return FALSE;
+
+ // S Addr Rd
+ sm_write_mode();
+ sm_send_start();
+ sm_write_byte((addr<<1)|1);
+
+ // [A]
+ sm_read_mode();
+ if (sm_get_ack() == FALSE) return FALSE;
+
+ // [Data]
+ *storage = sm_read_byte();
+
+ // NA
+ sm_write_mode();
+ sm_write_nack();
+ sm_send_stop();
+
+ return TRUE;
+}
+
+void sm_init(void)
+{
+ /* Switch to PMC mode */
+ pci_write_cfg_byte(0, 0, REG_GROUP, (uint8)(REG_GROUP_SPECIAL|REG_GROUP_POWER));
+
+ /* Set GPIO Base */
+ pci_write_cfg_long(0, 0, 0x40, 0xa500);
+
+ /* Enable GPIO */
+ pci_write_cfg_byte(0, 0, 0x44, 0x11);
+
+ /* Set both GPIO 0 and 1 as output */
+ out_byte(0xA53A, 0x03);
+}
+
+
+void sm_term(void)
+{
+ /* Switch to normal mode */
+ pci_write_cfg_byte(0, 0, REG_GROUP, 0);
+}
+
+
+int sm_get_data(uint8 *DataArray, int dimm_socket)
+{
+ int j;
+
+#if 0
+ /* Switch to PMC mode */
+ pci_write_cfg_byte(0, 0, REG_GROUP, (uint8)(REG_GROUP_SPECIAL|REG_GROUP_POWER));
+
+ /* Set GPIO Base */
+ pci_write_cfg_long(0, 0, 0x40, 0xa500);
+
+ /* Enable GPIO */
+ pci_write_cfg_byte(0, 0, 0x44, 0x11);
+
+ /* Set both GPIO 0 and 1 as output */
+ out_byte(0xA53A, 0x03);
+#endif
+
+ sm_init();
+ /* Start reading the rom */
+
+ j = 0;
+
+ do
+ {
+ if (sm_read_byte_from_device(dimm_socket, (uint8)j, DataArray) == FALSE)
+ {
+ sm_term();
+ return FALSE;
+ }
+
+ DataArray++;
+ j++;
+ } while (j < 128);
+
+ sm_term();
+ return TRUE;
+}
diff --git a/board/MAI/AmigaOneG3SE/smbus.h b/board/MAI/AmigaOneG3SE/smbus.h
new file mode 100644
index 0000000..beeb6a0
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/smbus.h
@@ -0,0 +1,22 @@
+#ifndef _SMBUS_H_
+#define _SMBUS_H_
+
+#include "short_types.h"
+
+#define SM_DIMM0_ADDR 0x51
+#define SM_DIMM1_ADDR 0x52
+
+void sm_write_mode(void);
+void sm_read_mode(void);
+void sm_write_byte(uint8 writeme);
+uint8 sm_read_byte(void);
+int sm_get_ack(void);
+void sm_write_ack(void);
+void sm_write_nack(void);
+void sm_send_start(void);
+void sm_send_stop(void);
+int sm_read_byte_from_device(uint8 addr, uint8 reg, uint8 *storage);
+int sm_get_data(uint8 *DataArray, int dimm_socket);
+void sm_init(void);
+void sm_term(void);
+#endif
diff --git a/board/MAI/AmigaOneG3SE/start.txt b/board/MAI/AmigaOneG3SE/start.txt
new file mode 100644
index 0000000..5c7b541
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/start.txt
@@ -0,0 +1,201 @@
+
+ /*------------------------------------------------------*/
+ /* TERON Articia / SDRAM Init */
+ /*------------------------------------------------------*/
+
+* XD_CTL = 0x81000000 (0x74)
+
+* HBUS_ACC_CTL_0 &= 0xFFFFFDFF (0x5c)
+ /* host bus access ctl reg 2(5e) */
+ /* set - CPU read from memory data one clock after data is latched */
+
+* GLOBL_INFO_0 |= 0x00004000 (0x50)
+ /* global info register 2 (52), AGP/PCI bus 1 arbiter is addressed in Articia S */
+
+ PCI_1_SB_CONFIG_0 |= 0x00000400 (0x80d0)
+ /* PCI1 side band config reg 2 (d2), enable read acces while write buffer not empty */
+
+ MEM_RAS_CTL_0 |= 0x3f000000 (0xcc)
+ &= 0x3fffffff
+ /* RAS park control reg 0(cc), park access enable is set */
+
+ HOST_RDBUF_CTL |= 0x10000000 (0x70)
+ &= 0x10ffffff
+ /* host read buffer control reg, enable prefetch for CPU read from DRAM control */
+
+ HBUS_ACC_CTL_0 |= 0x0100001f (0x5c)
+ &= 0xf1ffffff
+ /* host bus access control register, enable CPU address bus pipe control */
+ /* two outstanding requests, *** changed to 2 from 3 */
+ /* enable line merge write control for CPU write to system memory, PCI 1 */
+ /* and PCI 0 bus memory; enable page merge write control for write to */
+ /* PCI bus 0 & bus 1 memory */
+
+ SRAM_CTL |= 0x00004000 (0xc8)
+ &= 0xffbff7ff
+ /* DRAM detail timing control register 1 (ca), bit 3 set to 0 */
+ /* DRAM start access latency control - wait for one clock */
+ /* ff9f changed to ffbf */
+
+ DIM0_TIM_CTL_0 = 0x737d737d (0xc9)
+ /* DRAM timing control for dimm0 & dimm1; set wait one clock */
+ /* cycle for next data access */
+
+ DIM2_TIM_CTL_0 = 0x737d737d (0xca)
+ /* DRAM timing control for dimm2 & dimm3; set wait one clock */
+ /* cycle for next data access */
+
+ DIM0_BNK0_CTL_0 = BNK0_RAM_SIZ_128MB (0x90)
+ /* set dimm0 bank0 for 128 MB */
+
+ DIM0_BNK1_CTL_0 = BNK1_RAM_SIZ_128MB (0x94)
+ /* set dimm0 for bank1 */
+
+ DIM0_TIM_CTL_0 = 0xf3bf0000 (0xc9)
+ /* dimm0 timing control register; RAS - CAS latency - 4 clock */
+ /* CAS access latency - 3 wait; pre-charge latency - 3 wait */
+ /* pre-charge command period control - 5 clock; wait one clock */
+ /* cycle for next data access; read to write access latency control */
+ /* - 2 clock cycles */
+
+ DRAM_GBL_CTL_0 |= 0x00000100 (0xc0)
+ &= 0xffff01ff
+ /* memory global control register - support buffer sdram on bank 0 */
+
+ DRAM_ECC_CTL_0 |= 0x00260000 (0xc4)
+ &= 0xff26ffff
+ /* enable ECC; enable read, modify, write control */
+
+ DRAM_REF_CTL_0 = DRAM_REF_DATA (0xb8)
+ /* set DRAM refresh parameters *** changed to 00940100 */
+
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ DRAM_ECC_CTL_0 |= 0x20243280 (0xc4)
+ /* turn off ecc */
+ /* for SDRAM bank 0 */
+
+ DRAM_ECC_CTL_0 |= 0x20243290 (0xc4) ?
+ /* for SDRAM bank 1 */
+
+
+/* Additional Stuff...*/
+
+ GLOBL_CTRL |= 0x20000b00 (0x54)
+
+ PCI_0_SB_CONFIG |= 0x04100007 (0xd0)
+ /* PCI 0 Side band config reg*/
+
+ 0x8000083c |= 0x00080000
+ /* Disable VGA decode on PCI Bus 1 */
+
+
+/*End Additional Stuff..*/
+
+ /*--------------------------------------------------------------*/
+ /* TERON serial port initialization code */
+ /*--------------------------------------------------------------*/
+
+ 0x84380080 |= 0x00030000
+ /* enable super IO configuration VIA chip Register 85 */
+ /* Enable super I/O config mode */
+
+ 0xfe0003f0 = 0xe2
+ bl delay1
+
+ 0xfe0003f1 = 0x0f
+ bl delay1
+ /* enable com1 & com2, parallel port disabled */
+
+ 0xfe0003f0 = 0xe7
+ bl delay1
+ /* let's make com1 base as 0x3f8 */
+
+ 0xfe0003f1 = 0xfe
+ bl delay1
+
+ 0xfe0003f0 = 0xe8
+ bl delay1
+ /* let's make com2 base as 0x2f8 */
+
+ 0xfe0003f1 = 0xbe
+
+ 0x84380080 &= 0xfffdffff
+ /* closing super IO configuration VIA chip Register 85 */
+
+
+/* -------------------------------*/
+
+ 0xfe0003fb = 0x83
+ bl delay1
+ /*latch enable word length -8 bit */ /* set mslab bit */
+ 0xfe0003f8 = 0x0c
+ bl delay1
+ /* set baud rate lsb for 9600 baud */
+ 0xfe0003f9 = 0x0
+ bl delay1
+ /* set baud rate msb for 9600 baud */
+ 0xfe0003fb = 0x03
+ bl delay1
+ /* reset mslab */
+
+ /*--------------------------------------------------------------*/
+ /* END TERON Serial Port Initialization Code */
+ /*--------------------------------------------------------------*/
+
+
+
+ /*--------------------------------------------------------------*/
+ /* END TERON Articia / SDRAM Initialization code */
+ /*--------------------------------------------------------------*/
+
+Proposed from Documentation:
+
+write dmem 0xfec00cf8 0x50000080
+write dmem 0xfee00cfc 0xc0305411
+
+ Writes to index 0x50-0x53.
+ 0x50: Global Information Register 0
+ 0xC0 = Little Endian CPU, Sequential order Burst
+ 0x51: Global Information Register 1
+ Read only, 0x30 = Provides PowerPC and X86 support
+ 0x52: Global Information Register 2
+ 0x05 = 64/128 bit CPU bus support
+ 0x53: Global Information Register 3
+ 0x80 = PCI Bus 0 grant active time is 1 clock after REQ# deasserted
+
+write dmem 0xfec00cf8 0x5c000080
+write dmem 0xfee00cfc 0xb300011F
+
+write dmem 0xfec00cf8 0xc8000080
+write dmem 0xfee00cfc 0x0020f100
+
+write dmem 0xfec00cf8 0x90000080
+write dmem 0xfee00cfc 0x007fe700
+
+write dmem 0xfec00cf8 0x9400080
+write dmem 0xfee00cfc 0x007fe700
+
+write dmem 0xfec00cf8 0xb0000080
+write dmem 0xfee00cfc 0x737d737d
+
+write dmem 0xfec00cf8 0xb4000080
+write dmem 0xfee00cfc 0x737d737d
+
+write dmem 0xfec00cf8 0xc0000080
+write dmem 0xfee00cfc 0x40005500
+
+write dmem 0xfec00cf8 0xb8000080
+write dmem 0xfee00cfc 0x00940100
+
+write dmem 0xfec00cf8 0xc4000080
+write dmem 0xfee00cfc 0x00003280
+
+write dmem 0xfec00cf8 0xc4000080
+write dmem 0xfee00cfc 0x00003290
+
+
diff --git a/board/MAI/AmigaOneG3SE/todo.txt b/board/MAI/AmigaOneG3SE/todo.txt
new file mode 100644
index 0000000..df25e3d
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/todo.txt
@@ -0,0 +1,3 @@
+- Init interrupt controller
+- init sdram
+- init ide controller \ No newline at end of file
diff --git a/board/MAI/AmigaOneG3SE/u-boot.lds b/board/MAI/AmigaOneG3SE/u-boot.lds
new file mode 100644
index 0000000..d36a7e1
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/u-boot.lds
@@ -0,0 +1,131 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * (C) Copyright 2002
+ * 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
+ */
+
+/*
+ * u-boot.lds - linker script for U-Boot on the AmigaOneG3SE 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/74xx_7xx/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 = ALIGN(4) /*.*/ ;
+ PROVIDE (end = ALIGN(4) /*.*/);
+}
diff --git a/board/MAI/AmigaOneG3SE/usb_uhci.c b/board/MAI/AmigaOneG3SE/usb_uhci.c
new file mode 100644
index 0000000..fd8cb4e
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/usb_uhci.c
@@ -0,0 +1,1179 @@
+/*
+ * (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
+ *
+ * Note: Part of this code has been derived from linux
+ *
+ */
+
+/**********************************************************************
+ * How it works:
+ * -------------
+ * The framelist / Transfer descriptor / Queue Heads are similar like
+ * in the linux usb_uhci.c.
+ *
+ * During initialization, the following skeleton is allocated in init_skel:
+ *
+ * framespecific | common chain
+ *
+ * framelist[]
+ * [ 0 ]-----> TD ---------\
+ * [ 1 ]-----> TD ----------> TD ------> QH -------> QH -------> QH ---> NULL
+ * ... TD ---------/
+ * [1023]-----> TD --------/
+ *
+ * ^^ ^^ ^^ ^^ ^^
+ * 7 TDs for 1 TD for Start of Start of End Chain
+ * INT (2-128ms) 1ms-INT CTRL Chain BULK Chain
+ *
+ *
+ * Since this is a bootloader, the isochronous transfer descriptor have been removed.
+ *
+ * Interrupt Transfers.
+ * --------------------
+ * For Interupt transfers USB_MAX_TEMP_INT_TD Transfer descriptor are available. They
+ * will be inserted after the appropriate (depending the interval setting) skeleton TD.
+ * If an interrupt has been detected the dev->irqhandler is called. The status and number
+ * of transfered bytes is stored in dev->irq_status resp. dev->irq_act_len. If the
+ * dev->irqhandler returns 0, the interrupt TD is removed and disabled. If an 1 is returned,
+ * the interrupt TD will be reactivated.
+ *
+ * Control Transfers
+ * -----------------
+ * Control Transfers are issued by filling the tmp_td with the appropriate data and connect
+ * them to the qh_cntrl queue header. Before other control/bulk transfers can be issued,
+ * the programm has to wait for completion. This does not allows asynchronous data transfer.
+ *
+ * Bulk Transfers
+ * --------------
+ * Bulk Transfers are issued by filling the tmp_td with the appropriate data and connect
+ * them to the qh_bulk queue header. Before other control/bulk transfers can be issued,
+ * the programm has to wait for completion. This does not allows asynchronous data transfer.
+ *
+ *
+ */
+
+#include <common.h>
+#include <pci.h>
+
+#ifdef CONFIG_USB_UHCI
+
+#include <usb.h>
+#include "usb_uhci.h"
+
+#define USB_MAX_TEMP_TD 128 /* number of temporary TDs for bulk and control transfers */
+#define USB_MAX_TEMP_INT_TD 32 /* number of temporary TDs for Interrupt transfers */
+
+
+//#define USB_UHCI_DEBUG
+
+#ifdef USB_UHCI_DEBUG
+#define USB_UHCI_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define USB_UHCI_PRINTF(fmt,args...)
+#endif
+
+
+static int irqvec = -1; /* irq vector, if -1 uhci is stopped / reseted */
+unsigned int usb_base_addr; /* base address */
+
+static uhci_td_t td_int[8]; /* Interrupt Transfer descriptors */
+static uhci_qh_t qh_cntrl; /* control Queue Head */
+static uhci_qh_t qh_bulk; /* bulk Queue Head */
+static uhci_qh_t qh_end; /* end Queue Head */
+static uhci_td_t td_last; /* last TD (linked with end chain) */
+
+/* temporary tds */
+static uhci_td_t tmp_td[USB_MAX_TEMP_TD]; /* temporary bulk/control td's */
+static uhci_td_t tmp_int_td[USB_MAX_TEMP_INT_TD]; /* temporary interrupt td's */
+
+static unsigned long framelist[1024] __attribute__ ((aligned (0x1000))); /* frame list */
+
+static struct virt_root_hub rh; /* struct for root hub */
+
+/**********************************************************************
+ * some forward decleration
+ */
+int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len,struct devrequest *setup);
+
+/* fill a td with the approproiate data. Link, status, info and buffer
+ * are used by the USB controller itselfes, dev is used to identify the
+ * "connected" device
+ */
+void usb_fill_td(uhci_td_t* td,unsigned long link,unsigned long status,
+ unsigned long info, unsigned long buffer, unsigned long dev)
+{
+ td->link=swap_32(link);
+ td->status=swap_32(status);
+ td->info=swap_32(info);
+ td->buffer=swap_32(buffer);
+ td->dev_ptr=dev;
+}
+
+/* fill a qh with the approproiate data. Head and element are used by the USB controller
+ * itselfes. As soon as a valid dev_ptr is filled, a td chain is connected to the qh.
+ * Please note, that after completion of the td chain, the entry element is removed /
+ * marked invalid by the USB controller.
+ */
+void usb_fill_qh(uhci_qh_t* qh,unsigned long head,unsigned long element)
+{
+ qh->head=swap_32(head);
+ qh->element=swap_32(element);
+ qh->dev_ptr=0L;
+}
+
+/* get the status of a td->status
+ */
+unsigned long usb_uhci_td_stat(unsigned long status)
+{
+ unsigned long result=0;
+ result |= (status & TD_CTRL_NAK) ? USB_ST_NAK_REC : 0;
+ result |= (status & TD_CTRL_STALLED) ? USB_ST_STALLED : 0;
+ result |= (status & TD_CTRL_DBUFERR) ? USB_ST_BUF_ERR : 0;
+ result |= (status & TD_CTRL_BABBLE) ? USB_ST_BABBLE_DET : 0;
+ result |= (status & TD_CTRL_CRCTIMEO) ? USB_ST_CRC_ERR : 0;
+ result |= (status & TD_CTRL_BITSTUFF) ? USB_ST_BIT_ERR : 0;
+ result |= (status & TD_CTRL_ACTIVE) ? USB_ST_NOT_PROC : 0;
+ return result;
+}
+
+/* get the status and the transfered len of a td chain.
+ * called from the completion handler
+ */
+int usb_get_td_status(uhci_td_t *td,struct usb_device *dev)
+{
+ unsigned long temp,info;
+ unsigned long stat;
+ uhci_td_t *mytd=td;
+
+ if(dev->devnum==rh.devnum)
+ return 0;
+ dev->act_len=0;
+ stat=0;
+ do {
+ temp=swap_32((unsigned long)mytd->status);
+ stat=usb_uhci_td_stat(temp);
+ info=swap_32((unsigned long)mytd->info);
+ if(((info & 0xff)!= USB_PID_SETUP) &&
+ (((info >> 21) & 0x7ff)!= 0x7ff) &&
+ (temp & 0x7FF)!=0x7ff)
+ { /* if not setup and not null data pack */
+ dev->act_len+=(temp & 0x7FF) + 1; /* the transfered len is act_len + 1 */
+ }
+ if(stat) { /* status no ok */
+ dev->status=stat;
+ return -1;
+ }
+ temp=swap_32((unsigned long)mytd->link);
+ mytd=(uhci_td_t *)(temp & 0xfffffff0);
+ }while((temp & 0x1)==0); /* process all TDs */
+ dev->status=stat;
+ return 0; /* Ok */
+}
+
+
+/*-------------------------------------------------------------------
+ * LOW LEVEL STUFF
+ * assembles QHs und TDs for control, bulk and iso
+ *-------------------------------------------------------------------*/
+
+/* Submits a control message. That is a Setup, Data and Status transfer.
+ * Routine does not wait for completion.
+ */
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len,struct devrequest *setup)
+{
+ unsigned long destination, status;
+ int maxsze = usb_maxpacket(dev, pipe);
+ unsigned long dataptr;
+ int len;
+ int pktsze;
+ int i=0;
+
+ if (!maxsze) {
+ USB_UHCI_PRINTF("uhci_submit_control_urb: pipesize for pipe %lx is zero\n", pipe);
+ return -1;
+ }
+ if(((pipe>>8)&0x7f)==rh.devnum) {
+ /* this is the root hub -> redirect it */
+ return uhci_submit_rh_msg(dev,pipe,buffer,transfer_len,setup);
+ }
+ USB_UHCI_PRINTF("uhci_submit_control start len %x, maxsize %x\n",transfer_len,maxsze);
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; /* Setup stage */
+ /* 3 errors */
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+ /* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD); */
+ /* Build the TD for the control request, try forever, 8 bytes of data */
+ usb_fill_td(&tmp_td[i],UHCI_PTR_TERM ,status, destination | (7 << 21),(unsigned long)setup,(unsigned long)dev);
+#if 0
+ {
+ char *sp=(char *)setup;
+ printf("SETUP to pipe %lx: %x %x %x %x %x %x %x %x\n", pipe,
+ sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
+ }
+#endif
+ dataptr = (unsigned long)buffer;
+ len=transfer_len;
+
+ /* If direction is "send", change the frame from SETUP (0x2D)
+ to OUT (0xE1). Else change it from SETUP to IN (0x69). */
+ destination = (pipe & PIPE_DEVEP_MASK) | ((pipe & USB_DIR_IN)==0 ? USB_PID_OUT : USB_PID_IN);
+ while (len > 0) {
+ /* data stage */
+ pktsze = len;
+ i++;
+ if (pktsze > maxsze)
+ pktsze = maxsze;
+ destination ^= 1 << TD_TOKEN_TOGGLE; /* toggle DATA0/1 */
+ usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status, destination | ((pktsze - 1) << 21),dataptr,(unsigned long)dev); /* Status, pktsze bytes of data */
+ tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]);
+
+ dataptr += pktsze;
+ len -= pktsze;
+ }
+
+ /* Build the final TD for control status */
+ /* It's only IN if the pipe is out AND we aren't expecting data */
+
+ destination &= ~UHCI_PID;
+ if (((pipe & USB_DIR_IN)==0) || (transfer_len == 0))
+ destination |= USB_PID_IN;
+ else
+ destination |= USB_PID_OUT;
+ destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */
+ i++;
+ status &=~TD_CTRL_SPD;
+ /* no limit on errors on final packet , 0 bytes of data */
+ usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),0,(unsigned long)dev);
+ tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]); /* queue status td */
+ /* usb_show_td(i+1);*/
+ USB_UHCI_PRINTF("uhci_submit_control end (%d tmp_tds used)\n",i);
+ /* first mark the control QH element terminated */
+ qh_cntrl.element=0xffffffffL;
+ /* set qh active */
+ qh_cntrl.dev_ptr=(unsigned long)dev;
+ /* fill in tmp_td_chain */
+ qh_cntrl.element=swap_32((unsigned long)&tmp_td[0]);
+ return 0;
+}
+
+/*-------------------------------------------------------------------
+ * Prepare TDs for bulk transfers.
+ */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len)
+{
+ unsigned long destination, status,info;
+ unsigned long dataptr;
+ int maxsze = usb_maxpacket(dev, pipe);
+ int len;
+ int i=0;
+
+ if(transfer_len < 0) {
+ printf("Negative transfer length in submit_bulk\n");
+ return -1;
+ }
+ if (!maxsze)
+ return -1;
+ /* The "pipe" thing contains the destination in bits 8--18. */
+ destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+ /* 3 errors */
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+ /* ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27); */
+ /* Build the TDs for the bulk request */
+ len = transfer_len;
+ dataptr = (unsigned long)buffer;
+ do {
+ int pktsze = len;
+ if (pktsze > maxsze)
+ pktsze = maxsze;
+ /* pktsze bytes of data */
+ info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
+ (usb_gettoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+ if((len-pktsze)==0)
+ status |= TD_CTRL_IOC; /* last one generates INT */
+
+ usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status, info,dataptr,(unsigned long)dev); /* Status, pktsze bytes of data */
+ if(i>0)
+ tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]);
+ i++;
+ dataptr += pktsze;
+ len -= pktsze;
+ usb_dotoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+ } while (len > 0);
+ /* first mark the bulk QH element terminated */
+ qh_bulk.element=0xffffffffL;
+ /* set qh active */
+ qh_bulk.dev_ptr=(unsigned long)dev;
+ /* fill in tmp_td_chain */
+ qh_bulk.element=swap_32((unsigned long)&tmp_td[0]);
+ return 0;
+}
+
+
+/* search a free interrupt td
+ */
+uhci_td_t *uhci_alloc_int_td(void)
+{
+ int i;
+ for(i=0;i<USB_MAX_TEMP_INT_TD;i++) {
+ if(tmp_int_td[i].dev_ptr==0) /* no device assigned -> free TD */
+ return &tmp_int_td[i];
+ }
+ return NULL;
+}
+
+#if 0
+void uhci_show_temp_int_td(void)
+{
+ int i;
+ for(i=0;i<USB_MAX_TEMP_INT_TD;i++) {
+ if((tmp_int_td[i].dev_ptr&0x01)!=0x1L) /* no device assigned -> free TD */
+ printf("temp_td %d is assigned to dev %lx\n",i,tmp_int_td[i].dev_ptr);
+ }
+ printf("all others temp_tds are free\n");
+}
+#endif
+/*-------------------------------------------------------------------
+ * submits USB interrupt (ie. polling ;-)
+ */
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len, int interval)
+{
+ int nint, n;
+ unsigned long status, destination;
+ unsigned long info,tmp;
+ uhci_td_t *mytd;
+ if (interval < 0 || interval >= 256)
+ return -1;
+
+ if (interval == 0)
+ nint = 0;
+ else {
+ for (nint = 0, n = 1; nint <= 8; nint++, n += n) /* round interval down to 2^n */
+ {
+ if(interval < n) {
+ interval = n / 2;
+ break;
+ }
+ }
+ nint--;
+ }
+
+ USB_UHCI_PRINTF("Rounded interval to %i, chain %i\n", interval, nint);
+ mytd=uhci_alloc_int_td();
+ if(mytd==NULL) {
+ printf("No free INT TDs found\n");
+ return -1;
+ }
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | (3 << 27);
+/* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+*/
+
+ destination =(pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe) | (((transfer_len - 1) & 0x7ff) << 21);
+
+ info = destination | (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE);
+ tmp = swap_32(td_int[nint].link);
+ usb_fill_td(mytd,tmp,status, info,(unsigned long)buffer,(unsigned long)dev);
+ /* Link it */
+ tmp = swap_32((unsigned long)mytd);
+ td_int[nint].link=tmp;
+
+ usb_dotoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+ return 0;
+}
+
+/**********************************************************************
+ * Low Level functions
+ */
+
+
+void reset_hc(void)
+{
+
+ /* Global reset for 100ms */
+ out16r( usb_base_addr + USBPORTSC1,0x0204);
+ out16r( usb_base_addr + USBPORTSC2,0x0204);
+ out16r( usb_base_addr + USBCMD,USBCMD_GRESET | USBCMD_RS);
+ /* Turn off all interrupts */
+ out16r(usb_base_addr + USBINTR,0);
+ wait_ms(50);
+ out16r( usb_base_addr + USBCMD,0);
+ wait_ms(10);
+}
+
+void start_hc(void)
+{
+ int timeout = 1000;
+
+ while(in16r(usb_base_addr + USBCMD) & USBCMD_HCRESET) {
+ if (!--timeout) {
+ printf("USBCMD_HCRESET timed out!\n");
+ break;
+ }
+ }
+ /* Turn on all interrupts */
+ out16r(usb_base_addr + USBINTR,USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);
+ /* Start at frame 0 */
+ out16r(usb_base_addr + USBFRNUM,0);
+ /* set Framebuffer base address */
+ out32r(usb_base_addr+USBFLBASEADD,(unsigned long)&framelist);
+ /* Run and mark it configured with a 64-byte max packet */
+ out16r(usb_base_addr + USBCMD,USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
+}
+
+/* Initialize the skeleton
+ */
+void usb_init_skel(void)
+{
+ unsigned long temp;
+ int n;
+
+ for(n=0;n<USB_MAX_TEMP_INT_TD;n++)
+ tmp_int_td[n].dev_ptr=0L; /* no devices connected */
+ /* last td */
+ usb_fill_td(&td_last,UHCI_PTR_TERM,TD_CTRL_IOC ,0,0,0L);
+ /* usb_fill_td(&td_last,UHCI_PTR_TERM,0,0,0); */
+ /* End Queue Header */
+ usb_fill_qh(&qh_end,UHCI_PTR_TERM,(unsigned long)&td_last);
+ /* Bulk Queue Header */
+ temp=(unsigned long)&qh_end;
+ usb_fill_qh(&qh_bulk,temp | UHCI_PTR_QH,UHCI_PTR_TERM);
+ /* Control Queue Header */
+ temp=(unsigned long)&qh_bulk;
+ usb_fill_qh(&qh_cntrl, temp | UHCI_PTR_QH,UHCI_PTR_TERM);
+ /* 1ms Interrupt td */
+ temp=(unsigned long)&qh_cntrl;
+ usb_fill_td(&td_int[0],temp | UHCI_PTR_QH,0,0,0,0L);
+ temp=(unsigned long)&td_int[0];
+ for(n=1; n<8; n++)
+ usb_fill_td(&td_int[n],temp,0,0,0,0L);
+ for (n = 0; n < 1024; n++) {
+ /* link all framelist pointers to one of the interrupts */
+ int m, o;
+ if ((n&127)==127)
+ framelist[n]= swap_32((unsigned long)&td_int[0]);
+ else
+ for (o = 1, m = 2; m <= 128; o++, m += m)
+ if ((n & (m - 1)) == ((m - 1) / 2))
+ framelist[n]= swap_32((unsigned long)&td_int[o]);
+ }
+}
+
+/* check the common skeleton for completed transfers, and update the status
+ * of the "connected" device. Called from the IRQ routine.
+ */
+void usb_check_skel(void)
+{
+ struct usb_device *dev;
+ /* start with the control qh */
+ if(qh_cntrl.dev_ptr!=0) /* it's a device assigned check if this caused IRQ */
+ {
+ dev=(struct usb_device *)qh_cntrl.dev_ptr;
+ usb_get_td_status(&tmp_td[0],dev); /* update status */
+ if(!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */
+ qh_cntrl.dev_ptr=0;
+ }
+ }
+ /* now process the bulk */
+ if(qh_bulk.dev_ptr!=0) /* it's a device assigned check if this caused IRQ */
+ {
+ dev=(struct usb_device *)qh_bulk.dev_ptr;
+ usb_get_td_status(&tmp_td[0],dev); /* update status */
+ if(!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */
+ qh_bulk.dev_ptr=0;
+ }
+ }
+}
+
+/* check the interrupt chain, ubdate the status of the appropriate device,
+ * call the appropriate irqhandler and reactivate the TD if the irqhandler
+ * returns with 1
+ */
+void usb_check_int_chain(void)
+{
+ int i,res;
+ unsigned long link,status;
+ struct usb_device *dev;
+ uhci_td_t *td,*prevtd;
+
+ for(i=0;i<8;i++) {
+ prevtd=&td_int[i]; /* the first previous td is the skeleton td */
+ link=swap_32(td_int[i].link) & 0xfffffff0; /* next in chain */
+ td=(uhci_td_t *)link; /* assign it */
+ /* all interrupt TDs are finally linked to the td_int[0].
+ * so we process all until we find the td_int[0].
+ * if int0 chain points to a QH, we're also done
+ */
+ while(((i>0) && (link != (unsigned long)&td_int[0])) ||
+ ((i==0) && !(swap_32(td->link) & UHCI_PTR_QH)))
+ {
+ /* check if a device is assigned with this td */
+ status=swap_32(td->status);
+ if((td->dev_ptr!=0L) && !(status & TD_CTRL_ACTIVE)) {
+ /* td is not active and a device is assigned -> call irqhandler */
+ dev=(struct usb_device *)td->dev_ptr;
+ dev->irq_act_len=((status & 0x7FF)==0x7FF) ? 0 : (status & 0x7FF) + 1; /* transfered length */
+ dev->irq_status=usb_uhci_td_stat(status); /* get status */
+ res=dev->irq_handle(dev); /* call irqhandler */
+ if(res==1) {
+ /* reactivate */
+ status|=TD_CTRL_ACTIVE;
+ td->status=swap_32(status);
+ prevtd=td; /* previous td = this td */
+ }
+ else {
+ prevtd->link=td->link; /* link previous td directly to the nex td -> unlinked */
+ /* remove device pointer */
+ td->dev_ptr=0L;
+ }
+ } /* if we call the irq handler */
+ link=swap_32(td->link) & 0xfffffff0; /* next in chain */
+ td=(uhci_td_t *)link; /* assign it */
+ } /* process all td in this int chain */
+ } /* next interrupt chain */
+}
+
+
+/* usb interrupt service routine.
+ */
+void handle_usb_interrupt(void)
+{
+ unsigned short status;
+
+ /*
+ * Read the interrupt status, and write it back to clear the
+ * interrupt cause
+ */
+
+ status = in16r(usb_base_addr + USBSTS);
+
+ if (!status) /* shared interrupt, not mine */
+ return;
+ if (status != 1) {
+ /* remove host controller halted state */
+ if ((status&0x20) && ((in16r(usb_base_addr+USBCMD) && USBCMD_RS)==0)) {
+ out16r(usb_base_addr + USBCMD, USBCMD_RS | in16r(usb_base_addr + USBCMD));
+ }
+ }
+ usb_check_int_chain(); /* call interrupt handlers for int tds */
+ usb_check_skel(); /* call completion handler for common transfer routines */
+ out16r(usb_base_addr+USBSTS,status);
+}
+
+
+/* init uhci
+ */
+int usb_lowlevel_init(void)
+{
+ unsigned char temp;
+ int busdevfunc;
+/*
+ * HJF - configure IRQ and base from variables optionally.
+ */
+ char *s;
+
+
+ busdevfunc=pci_find_device(USB_UHCI_VEND_ID,USB_UHCI_DEV_ID,0); /* get PCI Device ID */
+ if(busdevfunc==-1) {
+ printf("Error USB UHCI (%04X,%04X) not found\n",USB_UHCI_VEND_ID,USB_UHCI_DEV_ID);
+ return -1;
+ }
+
+#if 1
+ s = getenv("usb_irq");
+ if (s)
+ {
+ temp = atoi(s);
+ pci_write_config_byte(busdevfunc, PCI_INTERRUPT_LINE, temp);
+ }
+ else
+#endif
+ pci_read_config_byte(busdevfunc,PCI_INTERRUPT_LINE,&temp);
+
+ s = getenv("usb_base");
+ if (s)
+ {
+ unsigned long temp2;
+ temp2 = atoi(s);
+ pci_write_config_dword(busdevfunc, PCI_BASE_ADDRESS_4, temp2|0x01);
+ }
+
+ irqvec = temp;
+ irq_free_handler(irqvec);
+ USB_UHCI_PRINTF("Interrupt Line = %d\n",irqvec);
+ pci_read_config_byte(busdevfunc,PCI_INTERRUPT_PIN,&temp);
+ USB_UHCI_PRINTF("Interrupt Pin = %ld\n",temp);
+ pci_read_config_dword(busdevfunc,PCI_BASE_ADDRESS_4,&usb_base_addr);
+ USB_UHCI_PRINTF("IO Base Address = 0x%lx\n",usb_base_addr);
+ usb_base_addr&=0xFFFFFFF0;
+ usb_base_addr+=CFG_ISA_IO_BASE_ADDRESS;
+ rh.devnum = 0;
+ usb_init_skel();
+ reset_hc();
+ start_hc();
+ irq_install_handler(irqvec, (interrupt_handler_t *)handle_usb_interrupt, NULL);
+ irq_install_handler(0, (interrupt_handler_t *)handle_usb_interrupt, NULL);
+
+ return 0;
+}
+
+/* stop uhci
+ */
+int usb_lowlevel_stop(void)
+{
+ if(irqvec==-1)
+ return 1;
+ irq_free_handler(irqvec);
+ irq_free_handler(0);
+ reset_hc();
+ irqvec=-1;
+ return 0;
+}
+
+/*******************************************************************************************
+ * Virtual Root Hub
+ * Since the uhci does not have a real HUB, we simulate one ;-)
+ */
+#undef USB_RH_DEBUG
+
+#ifdef USB_RH_DEBUG
+#define USB_RH_PRINTF(fmt,args...) printf (fmt ,##args)
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex);
+static void usb_display_Req(unsigned short req);
+#else
+#define USB_RH_PRINTF(fmt,args...)
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex) {}
+static void usb_display_Req(unsigned short req) {}
+#endif
+
+static unsigned char root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x00, /* __u16 bcdUSB; v1.0 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x01, /* __u8 iManufacturer; */
+ 0x00, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static unsigned char root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+
+static unsigned char root_hub_hub_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
+ 0x02, /* __u8 bNbrPorts; */
+ 0x00, /* __u16 wHubCharacteristics; */
+ 0x00,
+ 0x01, /* __u8 bPwrOn2pwrGood; 2ms */
+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
+ 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
+ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 28, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'U', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'C', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'I', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+
+/*
+ * Root Hub Control Pipe (interrupt Pipes are not supported)
+ */
+
+
+int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len,struct devrequest *cmd)
+{
+ void *data = buffer;
+ int leni = transfer_len;
+ int len = 0;
+ int status = 0;
+ int stat = 0;
+ int i;
+
+ unsigned short cstatus;
+
+ unsigned short bmRType_bReq;
+ unsigned short wValue;
+ unsigned short wIndex;
+ unsigned short wLength;
+
+ if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ printf("Root-Hub submit IRQ: NOT implemented\n");
+#if 0
+ uhci->rh.urb = urb;
+ uhci->rh.send = 1;
+ uhci->rh.interval = urb->interval;
+ rh_init_int_timer (urb);
+#endif
+ return 0;
+ }
+ bmRType_bReq = cmd->requesttype | cmd->request << 8;
+ wValue = swap_16(cmd->value);
+ wIndex = swap_16(cmd->index);
+ wLength = swap_16(cmd->length);
+ usb_display_Req(bmRType_bReq);
+ for (i = 0; i < 8; i++)
+ rh.c_p_r[i] = 0;
+ USB_RH_PRINTF("Root-Hub: adr: %2x cmd(%1x): %02x%02x %04x %04x %04x\n",
+ dev->devnum, 8, cmd->requesttype,cmd->request, wValue, wIndex, wLength);
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(unsigned short *) data = swap_16(1);
+ len=2;
+ break;
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(unsigned short *) data = swap_16(0);
+ len=2;
+ break;
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(unsigned short *) data = swap_16(0);
+ len=2;
+ break;
+ case RH_GET_STATUS | RH_CLASS:
+ *(unsigned long *) data = swap_32(0);
+ len=4;
+ break; /* hub power ** */
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+
+ status = in16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1));
+ cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+ ((status & USBPORTSC_PEC) >> (3 - 1)) |
+ (rh.c_p_r[wIndex - 1] << (0 + 4));
+ status = (status & USBPORTSC_CCS) |
+ ((status & USBPORTSC_PE) >> (2 - 1)) |
+ ((status & USBPORTSC_SUSP) >> (12 - 2)) |
+ ((status & USBPORTSC_PR) >> (9 - 4)) |
+ (1 << 8) | /* power on ** */
+ ((status & USBPORTSC_LSDA) << (-8 + 9));
+
+ *(unsigned short *) data = swap_16(status);
+ *(unsigned short *) (data + 2) = swap_16(cstatus);
+ len=4;
+ break;
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case (RH_ENDPOINT_STALL):
+ len=0;
+ break;
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case (RH_C_HUB_OVER_CURRENT):
+ len=0; /* hub power over current ** */
+ break;
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ usb_display_wValue(wValue,wIndex);
+ switch (wValue) {
+ case (RH_PORT_ENABLE):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) & ~USBPORTSC_PE;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_PORT_SUSPEND):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) & ~USBPORTSC_SUSP;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_PORT_POWER):
+ len=0; /* port power ** */
+ break;
+ case (RH_C_PORT_CONNECTION):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_CSC;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_C_PORT_ENABLE):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_PEC;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+ len=0;
+ break;
+ case (RH_C_PORT_OVER_CURRENT):
+ len=0;
+ break;
+ case (RH_C_PORT_RESET):
+ rh.c_p_r[wIndex - 1] = 0;
+ len=0;
+ break;
+ }
+ break;
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ usb_display_wValue(wValue,wIndex);
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_SUSP;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_PORT_RESET):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_PR;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ wait_ms(10);
+ status = (status & 0xfff5) & ~USBPORTSC_PR;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ udelay(10);
+ status = (status & 0xfff5) | USBPORTSC_PE;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ wait_ms(10);
+ status = (status & 0xfff5) | 0xa;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_PORT_POWER):
+ len=0; /* port power ** */
+ break;
+ case (RH_PORT_ENABLE):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_PE;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ }
+ break;
+
+ case RH_SET_ADDRESS:
+ rh.devnum = wValue;
+ len=0;
+ break;
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ i=sizeof(root_hub_config_des);
+ status=i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_dev_des, len);
+ break;
+ case (0x02): /* configuration descriptor */
+ i=sizeof(root_hub_config_des);
+ status=i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_config_des, len);
+ break;
+ case (0x03): /*string descriptors */
+ if(wValue==0x0300) {
+ i=sizeof(root_hub_str_index0);
+ status = i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_str_index0, len);
+ break;
+ }
+ if(wValue==0x0301) {
+ i=sizeof(root_hub_str_index1);
+ status = i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_str_index1, len);
+ break;
+ }
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ root_hub_hub_des[2] = 2;
+ i=sizeof(root_hub_hub_des);
+ status= i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_hub_des, len);
+ break;
+ case RH_GET_CONFIGURATION:
+ *(unsigned char *) data = 0x01;
+ len = 1;
+ break;
+ case RH_SET_CONFIGURATION:
+ len=0;
+ break;
+ default:
+ stat = USB_ST_STALLED;
+ }
+ USB_RH_PRINTF("Root-Hub stat %lx port1: %x port2: %x\n\n",stat,
+ in16r(usb_base_addr + USBPORTSC1), in16r(usb_base_addr + USBPORTSC2));
+ dev->act_len=len;
+ dev->status=stat;
+ return stat;
+
+}
+
+/********************************************************************************
+ * Some Debug Routines
+ */
+
+#ifdef USB_RH_DEBUG
+
+static void usb_display_Req(unsigned short req)
+{
+ USB_RH_PRINTF("- Root-Hub Request: ");
+ switch (req) {
+ case RH_GET_STATUS:
+ USB_RH_PRINTF("Get Status ");
+ break;
+ case RH_GET_STATUS | RH_INTERFACE:
+ USB_RH_PRINTF("Get Status Interface ");
+ break;
+ case RH_GET_STATUS | RH_ENDPOINT:
+ USB_RH_PRINTF("Get Status Endpoint ");
+ break;
+ case RH_GET_STATUS | RH_CLASS:
+ USB_RH_PRINTF("Get Status Class");
+ break; /* hub power ** */
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ USB_RH_PRINTF("Get Status Class Others");
+ break;
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ USB_RH_PRINTF("Clear Feature Endpoint ");
+ break;
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ USB_RH_PRINTF("Clear Feature Class ");
+ break;
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ USB_RH_PRINTF("Clear Feature Other Class ");
+ break;
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ USB_RH_PRINTF("Set Feature Other Class ");
+ break;
+ case RH_SET_ADDRESS:
+ USB_RH_PRINTF("Set Address ");
+ break;
+ case RH_GET_DESCRIPTOR:
+ USB_RH_PRINTF("Get Descriptor ");
+ break;
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ USB_RH_PRINTF("Get Descriptor Class ");
+ break;
+ case RH_GET_CONFIGURATION:
+ USB_RH_PRINTF("Get Configuration ");
+ break;
+ case RH_SET_CONFIGURATION:
+ USB_RH_PRINTF("Get Configuration ");
+ break;
+ default:
+ USB_RH_PRINTF("****UNKNOWN**** 0x%04X ",req);
+ }
+ USB_RH_PRINTF("\n");
+
+}
+
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex)
+{
+ switch (wValue) {
+ case (RH_PORT_ENABLE):
+ USB_RH_PRINTF("Root-Hub: Enable Port %d\n",wIndex);
+ break;
+ case (RH_PORT_SUSPEND):
+ USB_RH_PRINTF("Root-Hub: Suspend Port %d\n",wIndex);
+ break;
+ case (RH_PORT_POWER):
+ USB_RH_PRINTF("Root-Hub: Port Power %d\n",wIndex);
+ break;
+ case (RH_C_PORT_CONNECTION):
+ USB_RH_PRINTF("Root-Hub: C Port Connection Port %d\n",wIndex);
+ break;
+ case (RH_C_PORT_ENABLE):
+ USB_RH_PRINTF("Root-Hub: C Port Enable Port %d\n",wIndex);
+ break;
+ case (RH_C_PORT_SUSPEND):
+ USB_RH_PRINTF("Root-Hub: C Port Suspend Port %d\n",wIndex);
+ break;
+ case (RH_C_PORT_OVER_CURRENT):
+ USB_RH_PRINTF("Root-Hub: C Port Over Current Port %d\n",wIndex);
+ break;
+ case (RH_C_PORT_RESET):
+ USB_RH_PRINTF("Root-Hub: C Port reset Port %d\n",wIndex);
+ break;
+ default:
+ USB_RH_PRINTF("Root-Hub: unknown %x %x\n",wValue,wIndex);
+ break;
+ }
+}
+
+#endif
+
+
+
+#ifdef USB_UHCI_DEBUG
+
+static int usb_display_td(uhci_td_t *td)
+{
+ unsigned long tmp;
+ int valid;
+
+ printf("TD at %p:\n",td);
+
+ tmp=swap_32(td->link);
+ printf("Link points to 0x%08lX, %s first, %s, %s\n",tmp&0xfffffff0,
+ ((tmp & 0x4)==0x4) ? "Depth" : "Breath",
+ ((tmp & 0x2)==0x2) ? "QH" : "TD",
+ ((tmp & 0x1)==0x1) ? "invalid" : "valid");
+ valid=((tmp & 0x1)==0x0);
+ tmp=swap_32(td->status);
+ printf(" %s %ld Errors %s %s %s \n %s %s %s %s %s %s\n Len 0x%lX\n",
+ (((tmp>>29)&0x1)==0x1) ? "SPD Enable" : "SPD Disable",
+ ((tmp>>28)&0x3),
+ (((tmp>>26)&0x1)==0x1) ? "Low Speed" : "Full Speed",
+ (((tmp>>25)&0x1)==0x1) ? "ISO " : "",
+ (((tmp>>24)&0x1)==0x1) ? "IOC " : "",
+ (((tmp>>23)&0x1)==0x1) ? "Active " : "Inactive ",
+ (((tmp>>22)&0x1)==0x1) ? "Stalled" : "",
+ (((tmp>>21)&0x1)==0x1) ? "Data Buffer Error" : "",
+ (((tmp>>20)&0x1)==0x1) ? "Babble" : "",
+ (((tmp>>19)&0x1)==0x1) ? "NAK" : "",
+ (((tmp>>18)&0x1)==0x1) ? "Bitstuff Error" : "",
+ (tmp&0x7ff));
+ tmp=swap_32(td->info);
+ printf(" MaxLen 0x%lX\n",((tmp>>21)&0x7FF));
+ printf(" %s Endpoint 0x%lX Dev Addr 0x%lX PID 0x%lX\n",((tmp>>19)&0x1)==0x1 ? "TOGGLE" : "",
+ ((tmp>>15)&0xF),((tmp>>8)&0x7F),tmp&0xFF);
+ tmp=swap_32(td->buffer);
+ printf(" Buffer 0x%08lX\n",tmp);
+ printf(" DEV %08lX\n",td->dev_ptr);
+ return valid;
+}
+
+
+void usb_show_td(int max)
+{
+ int i;
+ if(max>0) {
+ for(i=0;i<max;i++) {
+ usb_display_td(&tmp_td[i]);
+ }
+ }
+ else {
+ i=0;
+ do {
+ printf("tmp_td[%d]\n",i);
+ }while(usb_display_td(&tmp_td[i++]));
+ }
+}
+
+
+#endif
+#endif /* CONFIG_USB_UHCI */
+
+/* EOF */
diff --git a/board/MAI/AmigaOneG3SE/usb_uhci.h b/board/MAI/AmigaOneG3SE/usb_uhci.h
new file mode 100644
index 0000000..7fda60b
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/usb_uhci.h
@@ -0,0 +1,194 @@
+/*
+ * (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
+ *
+ * Note: Part of this code has been derived from linux
+ *
+ */
+#ifndef _USB_UHCI_H_
+#define _USB_UHCI_H_
+
+#undef USB_UHCI_VEND_ID
+#define USB_UHCI_VEND_ID PCI_VENDOR_ID_VIA
+#undef USB_UHCI_DEV_ID
+#define USB_UHCI_DEV_ID 0x3038
+
+/* Command register */
+#define USBCMD 0
+#define USBCMD_RS 0x0001 /* Run/Stop */
+#define USBCMD_HCRESET 0x0002 /* Host reset */
+#define USBCMD_GRESET 0x0004 /* Global reset */
+#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */
+#define USBCMD_FGR 0x0010 /* Force Global Resume */
+#define USBCMD_SWDBG 0x0020 /* SW Debug mode */
+#define USBCMD_CF 0x0040 /* Config Flag (sw only) */
+#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS 2
+#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */
+#define USBSTS_ERROR 0x0002 /* Interrupt due to error */
+#define USBSTS_RD 0x0004 /* Resume Detect */
+#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */
+#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */
+#define USBSTS_HCH 0x0020 /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR 4
+#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */
+#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */
+#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */
+#define USBINTR_SP 0x0008 /* Short packet interrupt enable */
+
+#define USBFRNUM 6
+#define USBFLBASEADD 8
+#define USBSOF 12
+
+/* USB port status and control registers */
+#define USBPORTSC1 16
+#define USBPORTSC2 18
+#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */
+#define USBPORTSC_CSC 0x0002 /* Connect Status Change */
+#define USBPORTSC_PE 0x0004 /* Port Enable */
+#define USBPORTSC_PEC 0x0008 /* Port Enable Change */
+#define USBPORTSC_LS 0x0030 /* Line Status */
+#define USBPORTSC_RD 0x0040 /* Resume Detect */
+#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */
+#define USBPORTSC_PR 0x0200 /* Port Reset */
+#define USBPORTSC_SUSP 0x1000 /* Suspend */
+
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE 0x7ff /* for UHCI controller TD */
+#define UHCI_PID 0xff /* PID MASK */
+
+#define UHCI_PTR_BITS 0x000F
+#define UHCI_PTR_TERM 0x0001
+#define UHCI_PTR_QH 0x0002
+#define UHCI_PTR_DEPTH 0x0004
+
+/* for TD <status>: */
+#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */
+#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
+#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
+#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
+#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */
+#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */
+#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */
+#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */
+#define TD_CTRL_NAK (1 << 19) /* NAK Received */
+#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK 0x7ff /* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+ TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define TD_TOKEN_TOGGLE 19
+
+/* ------------------------------------------------------------------------------------
+ Virtual Root HUB
+ ------------------------------------------------------------------------------------ */
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP 0x00
+
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+
+/* Transfer descriptor structure */
+typedef struct {
+ unsigned long link; /* next td/qh (LE)*/
+ unsigned long status; /* status of the td */
+ unsigned long info; /* Max Lenght / Endpoint / device address and PID */
+ unsigned long buffer; /* pointer to data buffer (LE) */
+ unsigned long dev_ptr; /* pointer to the assigned device (BE) */
+ unsigned long res[3]; /* reserved (TDs must be 8Byte aligned) */
+} uhci_td_t, *puhci_td_t;
+
+/* Queue Header structure */
+typedef struct {
+ unsigned long head; /* Next QH (LE)*/
+ unsigned long element; /* Queue element pointer (LE) */
+ unsigned long res[5]; /* reserved */
+ unsigned long dev_ptr; /* if 0 no tds have been assigned to this qh */
+} uhci_qh_t, *puhci_qh_t;
+
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ int numports; /* number of ports */
+ int c_p_r[8]; /* C_PORT_RESET */
+};
+
+
+#endif /* _USB_UHCI_H_ */
+
+
diff --git a/board/MAI/AmigaOneG3SE/via686.c b/board/MAI/AmigaOneG3SE/via686.c
new file mode 100644
index 0000000..0483ca9
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/via686.c
@@ -0,0 +1,299 @@
+/*
+ * (C) Copyright 2002
+ * Hyperion Entertainment, Hans-JoergF@hyperion-entertainment.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 <common.h>
+#include <pci.h>
+#include <ata.h>
+#include "memio.h"
+#include "articiaS.h"
+#include "via686.h"
+#include "i8259.h"
+
+#undef VIA_DEBUG
+
+#ifdef VIA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+
+/* Setup the ISA-to-PCI host bridge */
+void via_isa_init(pci_dev_t dev, struct pci_config_table *table)
+{
+ char regval;
+ if (PCI_FUNC(dev) == 0)
+ {
+ PRINTF("... PCI-to-ISA bridge, dev=0x%X\n", dev);
+
+ /* Enable I/O Recovery time */
+ pci_write_config_byte(dev, 0x40, 0x08);
+
+ /* Enable ISA refresh */
+ pci_write_config_byte(dev, 0x41, 0x41); /* was 01 */
+
+ /* Enable ISA line buffer */
+ pci_write_config_byte(dev, 0x45, 0x80);
+
+ /* Gate INTR, and flush line buffer */
+ pci_write_config_byte(dev, 0x46, 0x60);
+
+ /* Enable EISA ports 4D0/4D1. Do we need this ? */
+ pci_write_config_byte(dev, 0x47, 0xe6); /* was 20 */
+
+ /* 512 K PCI Decode */
+ pci_write_config_byte(dev, 0x48, 0x01);
+
+ /* Wait for PGNT before grant to ISA Master/DMA */
+ /* ports 0-FF to SDBus */
+ /* IRQ 14 and 15 for ide 0/1 */
+ pci_write_config_byte(dev, 0x4a, 0x04); /* Was c4 */
+
+ /* Plug'n'Play */
+ /* Parallel DRQ 3, Floppy DRQ 2 (default) */
+ pci_write_config_byte(dev, 0x50, 0x0e);
+
+ /* IRQ Routing for Floppy and Parallel port */
+ /* IRQ 6 for floppy, IRQ 7 for parallel port */
+ pci_write_config_byte(dev, 0x51, 0x76);
+
+ /* IRQ Routing for serial ports (take IRQ 3 and 4) */
+ pci_write_config_byte(dev, 0x52, 0x34);
+
+ /* All IRQ's level triggered. */
+ pci_write_config_byte(dev, 0x54, 0x00);
+
+ /* PCI IRQ's all at IRQ 9 */
+ pci_write_config_byte(dev, 0x55, 0x90);
+ pci_write_config_byte(dev, 0x56, 0x99);
+ pci_write_config_byte(dev, 0x57, 0x90);
+
+ /* Enable Keyboard */
+ pci_read_config_byte(dev, 0x5A, &regval);
+ regval |= 0x01;
+ pci_write_config_byte(dev, 0x5A, regval);
+
+ pci_write_config_byte(dev, 0x80, 0);
+ pci_write_config_byte(dev, 0x85, 0x01);
+
+/* pci_write_config_byte(dev, 0x77, 0x00); */
+ }
+}
+
+/*
+ * Initialize PNP irq routing
+ */
+
+void via_init_irq_routing(uint8 irq_map[])
+{
+ char *s;
+ uint8 level_edge_bits = 0xf;
+
+ /* Set irq routings */
+ pci_write_cfg_byte(0, 7<<3, 0x55, irq_map[0]<<4);
+ pci_write_cfg_byte(0, 7<<3, 0x56, irq_map[1] | irq_map[2]<<4);
+ pci_write_cfg_byte(0, 7<<3, 0x57, irq_map[3]<<4);
+
+ /*
+ * Gather level/edge bits
+ * Default is to assume level triggered
+ */
+
+ s = getenv("pci_irqa_select");
+ if (s && strcmp(s, "level") == 0)
+ level_edge_bits &= ~0x01;
+
+ s = getenv("pci_irqb_select");
+ if (s && strcmp(s, "level") == 0)
+ level_edge_bits &= ~0x02;
+
+ s = getenv("pci_irqc_select");
+ if (s && strcmp(s, "level") == 0)
+ level_edge_bits &= ~0x04;
+
+ s = getenv("pci_irqd_select");
+ if (s && strcmp(s, "level") == 0)
+ level_edge_bits &= ~0x08;
+
+ PRINTF("IRQ map\n");
+ PRINTF("%d: %s\n", irq_map[0], level_edge_bits&0x1 ? "edge" : "level");
+ PRINTF("%d: %s\n", irq_map[1], level_edge_bits&0x2 ? "edge" : "level");
+ PRINTF("%d: %s\n", irq_map[2], level_edge_bits&0x4 ? "edge" : "level");
+ PRINTF("%d: %s\n", irq_map[3], level_edge_bits&0x8 ? "edge" : "level");
+ pci_write_cfg_byte(0, 7<<3, 0x54, level_edge_bits);
+
+ PRINTF("%02x %02x %02x %02x\n", pci_read_cfg_byte(0, 7<<3, 0x54),
+ pci_read_cfg_byte(0, 7<<3, 0x55), pci_read_cfg_byte(0, 7<<3, 0x56),
+ pci_read_cfg_byte(0, 7<<3, 0x57));
+}
+
+
+/* Setup the IDE controller. This doesn't seem to work yet. I/O to an IDE controller port */
+/* always return the last character output on the serial port (!) */
+/* This function is called by the pnp-library when it encounters 0:7:1 */
+void via_cfgfunc_ide_init(struct pci_controller *host, pci_dev_t dev, struct pci_config_table *table)
+{
+ PRINTF("... IDE controller, dev=0x%X\n", dev);
+
+ /* Enable both IDE channels. */
+ pci_write_config_byte(dev, 0x40, 0x03);
+ /* udelay(10000); */
+ /* udelay(10000); */
+
+ /* Enable IO Space */
+ pci_write_config_word(dev, 0x04, 0x03);
+
+ /* Set to compatibility mode */
+ pci_write_config_byte(dev, 0x09, 0x8A); /* WAS: 0x8f); */
+
+ /* Set to legacy interrupt mode */
+ pci_write_config_byte(dev, 0x3d, 0x00); /* WAS: 0x01); */
+
+}
+
+
+/* Set the base address of the floppy controller to 0x3F0 */
+void via_fdc_init(pci_dev_t dev)
+{
+ unsigned char c;
+ /* Enable Configuration mode */
+ pci_read_config_byte(dev, 0x85, &c);
+ c |= 0x02;
+ pci_write_config_byte(dev, 0x85, c);
+
+ /* Set floppy controller port to 0x3F0. */
+ SIO_WRITE_CONFIG(0xE3, (0x3F<<2));
+
+ /* Enable floppy controller */
+ SIO_READ_CONFIG(0xE2, c);
+ c |= 0x10;
+ SIO_WRITE_CONFIG(0xE2, c);
+
+ /* Switch of configuration mode */
+ pci_read_config_byte(dev, 0x85, &c);
+ c &= ~0x02;
+ pci_write_config_byte(dev, 0x85, c);
+}
+
+/* Init function 0 of the via southbridge. Called by the pnp-library */
+void via_cfgfunc_via686(struct pci_controller *host, pci_dev_t dev, struct pci_config_table *table)
+{
+ if (PCI_FUNC(dev) == 0)
+ {
+ /* FIXME: Try to generate a PCI reset */
+ /* unsigned char c; */
+ /* pci_read_config_byte(dev, 0x47, &c); */
+ /* pci_write_config_byte(dev, 0x47, c | 0x01); */
+
+ via_isa_init(dev, table);
+ via_fdc_init(dev);
+ }
+}
+
+__asm (" .globl via_calibrate_time_base \n"
+ "via_calibrate_time_base: \n"
+ " lis 9, 0xfe00 \n"
+ " li 0, 0x00 \n"
+ " mttbu 0 \n"
+ " mttbl 0 \n"
+ "ctb_loop: \n"
+ " lbz 0, 0x61(9) \n"
+ " eieio \n"
+ " andi. 0, 0, 0x20 \n"
+ " beq ctb_loop \n"
+ "ctb_done: \n"
+ " mftb 3 \n"
+ " blr");
+
+extern unsigned long via_calibrate_time_base(void);
+
+void via_calibrate_bus_freq(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ unsigned long tb;
+
+ /* This is 20 microseconds */
+ #define CALIBRATE_TIME 28636
+
+
+ /* Enable the timer (and disable speaker) */
+ unsigned char c;
+ c = in_byte(0x61);
+ out_byte(0x61, ((c & ~0x02) | 0x01));
+
+ /* Set timer 2 to low/high writing */
+ out_byte(0x43, 0xb0);
+ out_byte(0x42, CALIBRATE_TIME & 0xff);
+ out_byte(0x42, CALIBRATE_TIME >>8);
+
+ /* Read the time base */
+ tb = via_calibrate_time_base();
+
+ if (tb >= 700000)
+ gd->bus_clk = 133333333;
+ else
+ gd->bus_clk = 100000000;
+
+}
+
+
+void ide_led(uchar led, uchar status)
+{
+/* unsigned char c = in_byte(0x92); */
+
+/* if (!status) */
+/* out_byte(0x92, c | 0xC0); */
+/* else */
+/* out_byte(0x92, c & ~0xC0); */
+}
+
+
+void via_init_afterscan(void)
+{
+ /* Modify IDE controller setup */
+ pci_write_cfg_byte(0, 7<<3|1, PCI_LATENCY_TIMER, 0x20);
+ pci_write_cfg_byte(0, 7<<3|1, PCI_COMMAND, PCI_COMMAND_IO|PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER);
+ pci_write_cfg_byte(0, 7<<3|1, PCI_INTERRUPT_LINE, 0xff);
+ pci_write_cfg_byte(0, 7<<3|1, 0x40, 0x0b); /* FIXME: Might depend on drives connected */
+ pci_write_cfg_byte(0, 7<<3|1, 0x41, 0x42); /* FIXME: Might depend on drives connected */
+ pci_write_cfg_byte(0, 7<<3|1, 0x43, 0x05);
+ pci_write_cfg_byte(0, 7<<3|1, 0x44, 0x18);
+ pci_write_cfg_byte(0, 7<<3|1, 0x45, 0x10);
+ pci_write_cfg_byte(0, 7<<3|1, 0x4e, 0x22); /* FIXME: Not documented, but set in PC bios */
+ pci_write_cfg_byte(0, 7<<3|1, 0x4f, 0x20); /* FIXME: Not documented */
+
+ /* Modify some values in the USB controller */
+ pci_write_cfg_byte(0, 7<<3|2, 0x05, 0x17);
+ pci_write_cfg_byte(0, 7<<3|2, 0x06, 0x01);
+ pci_write_cfg_byte(0, 7<<3|2, 0x41, 0x12);
+ pci_write_cfg_byte(0, 7<<3|2, 0x42, 0x03);
+ pci_write_cfg_byte(0, 7<<3|2, PCI_LATENCY_TIMER, 0x40);
+
+ pci_write_cfg_byte(0, 7<<3|3, 0x05, 0x17);
+ pci_write_cfg_byte(0, 7<<3|3, 0x06, 0x01);
+ pci_write_cfg_byte(0, 7<<3|3, 0x41, 0x12);
+ pci_write_cfg_byte(0, 7<<3|3, 0x42, 0x03);
+ pci_write_cfg_byte(0, 7<<3|3, PCI_LATENCY_TIMER, 0x40);
+
+
+}
diff --git a/board/MAI/AmigaOneG3SE/via686.h b/board/MAI/AmigaOneG3SE/via686.h
new file mode 100644
index 0000000..2a06a05
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/via686.h
@@ -0,0 +1,29 @@
+#ifndef VIA686_H_
+#define VIA686_H_
+
+
+#define CMOS_ADDR 0x70
+#define CMOS_DATA 0x71
+
+#define I8259_MASTER_CONTROL 0x20
+#define I8259_MASTER_MASK 0x21
+
+#define I8259_SLAVE_CONTROL 0xA0
+#define I8259_SLAVE_MASK 0xA1
+
+#define SIO_CONFIG_ADDR 0x3F0
+#define SIO_CONFIG_DATA 0x3F1
+
+#define SIO_WRITE_CONFIG(addr, byte) \
+ out_byte(SIO_CONFIG_ADDR, addr); \
+ out_byte(SIO_CONFIG_DATA, byte);
+
+#define SIO_READ_CONFIG(addr, byte) \
+ out_byte(SIO_CONFIG_ADDR, addr); \
+ byte = in_byte(SIO_CONFIG_DATA);
+
+void via_init(void);
+
+void via_calibrate_bus_freq(void);
+
+#endif
diff --git a/board/MAI/AmigaOneG3SE/video.c b/board/MAI/AmigaOneG3SE/video.c
new file mode 100644
index 0000000..d0e366c
--- /dev/null
+++ b/board/MAI/AmigaOneG3SE/video.c
@@ -0,0 +1,539 @@
+/*
+ * (C) Copyright 2002
+ * Hyperion Entertainment, Hans-JoergF@hyperion-entertainment.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 <common.h>
+#include <devices.h>
+#include "memio.h"
+#include <part.h>
+
+unsigned char *cursor_position;
+unsigned int cursor_row;
+unsigned int cursor_col;
+
+unsigned char current_attr;
+
+unsigned int video_numrows = 25;
+unsigned int video_numcols = 80;
+unsigned int video_scrolls = 0;
+
+#define VIDEO_BASE (unsigned char *)0xFD0B8000
+#define VIDEO_ROWS video_numrows
+#define VIDEO_COLS video_numcols
+#define VIDEO_PITCH (2 * video_numcols)
+#define VIDEO_SIZE (video_numrows * video_numcols * 2)
+#define VIDEO_NAME "vga"
+
+void video_test(void);
+void video_putc(char ch);
+void video_puts(char *string);
+void video_scroll(int rows);
+void video_banner(void);
+int video_init(void);
+int video_start(void);
+int video_rows(void);
+int video_cols(void);
+
+char *prompt_string = "=>";
+
+void video_set_color(unsigned char attr)
+{
+ unsigned char *fb = (unsigned char *)VIDEO_BASE;
+ int i;
+
+ current_attr = video_get_attr();
+
+ for (i=0; i<VIDEO_SIZE; i+=2)
+ {
+ *(fb+i+1) = current_attr;
+ }
+}
+
+unsigned char video_get_attr(void)
+{
+ char *s;
+ unsigned char attr;
+
+ attr = 0x0f;
+
+ s = getenv("vga_fg_color");
+ if (s)
+ {
+ attr = atoi(s);
+ }
+
+ s = getenv("vga_bg_color");
+ if (s)
+ {
+ attr |= atoi(s)<<4;
+ }
+
+ return attr;
+}
+
+int video_inited = 0;
+
+int drv_video_init(void)
+{
+ int error, devices = 1 ;
+ device_t vgadev ;
+ if (video_inited) return 1;
+ video_inited = 1;
+ video_init();
+ memset (&vgadev, 0, sizeof(vgadev));
+
+ strcpy(vgadev.name, VIDEO_NAME);
+ vgadev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
+ vgadev.putc = video_putc;
+ vgadev.puts = video_puts;
+ vgadev.getc = NULL;
+ vgadev.tstc = NULL;
+ vgadev.start = video_start;
+
+ error = device_register (&vgadev);
+
+ if (error == 0)
+ {
+ char *s = getenv("stdout");
+ if (s && strcmp(s, VIDEO_NAME)==0)
+ {
+ if (overwrite_console()) return 1;
+ error = console_assign(stdout, VIDEO_NAME);
+ if (error == 0) return 1;
+ else return error;
+ }
+ return 1;
+ }
+
+ return error;
+}
+
+int video_init(void)
+{
+ cursor_position = VIDEO_BASE; // Color text display base
+ cursor_row = 0;
+ cursor_col = 0;
+ current_attr = video_get_attr(); // Currently selected value for attribute.
+// video_test();
+ video_set_color(current_attr);
+
+ return 0;
+}
+
+void video_set_cursor(int line, int column)
+{
+ unsigned short offset = line*video_numcols + column;
+ cursor_position = VIDEO_BASE + line*VIDEO_PITCH + column*2;
+ out_byte(0x3D4, 0x0E);
+ out_byte(0x3D5, offset/256);
+ out_byte(0x3D4, 0x0F);
+ out_byte(0x3D5, offset%256);
+}
+
+void video_write_char(int character)
+{
+ *cursor_position = character;
+ *(cursor_position+1) = current_attr;
+}
+
+void video_test(void)
+{
+
+}
+
+void video_putc(char ch)
+{
+ switch(ch)
+ {
+ case '\n':
+ cursor_col = 0;
+ cursor_row += 1;
+ break;
+ case '\r':
+ cursor_col = 0;
+ break;
+ case '\b':
+ if (cursor_col) cursor_col--;
+ else return;
+ break;
+ case '\t':
+ cursor_col = (cursor_col/8+1)*8;
+ break;
+ default:
+ video_write_char(ch);
+ cursor_col++;
+ if (cursor_col > VIDEO_COLS-1)
+ {
+ cursor_row++;
+ cursor_col=0;
+ }
+ }
+
+ if (cursor_row > VIDEO_ROWS-1)
+ video_scroll(1);
+ video_set_cursor(cursor_row, cursor_col);
+}
+
+void video_scroll(int rows)
+{
+ unsigned short clear = ((unsigned short)current_attr) | (' '<<8);
+ unsigned short* addr16 = &((unsigned short *)VIDEO_BASE)[(VIDEO_ROWS-rows)*VIDEO_COLS];
+ int i;
+ char *s;
+
+ s = getenv("vga_askscroll");
+ video_scrolls += rows;
+
+ if (video_scrolls >= video_numrows)
+ {
+ if (s && strcmp(s, "yes"))
+ {
+ while (-1 == tstc());
+ }
+
+ video_scrolls = 0;
+ }
+
+
+ memcpy(VIDEO_BASE, VIDEO_BASE+rows*(VIDEO_COLS*2), (VIDEO_ROWS-rows)*(VIDEO_COLS*2));
+ for (i = 0 ; i < rows * VIDEO_COLS ; i++)
+ addr16[i] = clear;
+ cursor_row-=rows;
+ cursor_col=0;
+}
+
+void video_puts(char *string)
+{
+ while (*string)
+ {
+ video_putc(*string);
+ string++;
+ }
+}
+
+int video_start(void)
+{
+ return 0;
+}
+
+unsigned char video_single_box[] =
+{
+ 218, 196, 191,
+ 179, 179,
+ 192, 196, 217
+};
+
+unsigned char video_double_box[] =
+{
+ 201, 205, 187,
+ 186, 186,
+ 200, 205, 188
+};
+
+unsigned char video_single_title[] =
+{
+ 195, 196, 180, 180, 195
+};
+
+unsigned char video_double_title[] =
+{
+ 204, 205, 185, 181, 198
+};
+
+#define SINGLE_BOX 0
+#define DOUBLE_BOX 1
+
+unsigned char *video_addr(int x, int y)
+{
+ return VIDEO_BASE + 2*(VIDEO_COLS*y) + 2*x;
+}
+
+void video_bios_print_string(char *s, int x, int y, int attr, int count)
+{
+ int cattr = current_attr;
+ if (attr != -1) current_attr = attr;
+ video_set_cursor(x,y);
+ while (count)
+ {
+ char c = *s++;
+ if (attr == -1) current_attr = *s++;
+ video_putc(c);
+ count--;
+ }
+}
+
+void video_draw_box(int style, int attr, char *title, int separate, int x, int y, int w, int h)
+{
+ unsigned char *fb, *fb2;
+ unsigned char *st = (style == SINGLE_BOX)?video_single_box : video_double_box;
+ unsigned char *ti = (style == SINGLE_BOX)?video_single_title : video_double_title;
+ int i;
+
+ fb = video_addr(x,y);
+ *(fb) = st[0];
+ *(fb+1) = attr;
+ fb += 2;
+
+ fb2 = video_addr(x,y+h-1);
+ *(fb2) = st[5];
+ *(fb2+1) = attr;
+ fb2 += 2;
+
+ for (i=0; i<w-2;i++)
+ {
+ *fb = st[1];
+ fb++;
+ *fb = attr;
+ fb++;
+
+ *fb2 = st[6];
+ fb2++;
+ *fb2 = attr;
+ fb2++;
+
+ }
+ *fb = st[2];
+ *(fb+1) = attr;
+
+ *fb2 = st[7];
+ *(fb2+1) = attr;
+
+ fb = video_addr(x, y+1);
+ fb2 = video_addr(x+w-1, y+1);
+ for (i=0; i<h-2; i++)
+ {
+ *fb = st[3];
+ *(fb+1) = attr; fb += 2*VIDEO_COLS;
+
+ *fb2 = st[4];
+ *(fb2+1) = attr; fb2 += 2*VIDEO_COLS;
+ }
+
+ // Draw title
+ if (title)
+ {
+ if (separate == 0)
+ {
+ fb = video_addr(x+1, y);
+ *fb = ti[3];
+ fb += 2;
+ *fb = ' ';
+ fb += 2;
+ while (*title)
+ {
+ *fb = *title;
+ fb ++;
+ *fb = attr;
+ fb++; title++;
+ }
+ *fb = ' ';
+ fb += 2;
+ *fb = ti[4];
+ }
+ else
+ {
+ fb = video_addr(x, y+2);
+ *fb = ti[0];
+ fb += 2;
+ for (i=0; i<w-2; i++)
+ {
+ *fb = ti[1];
+ *(fb+1) = attr;
+ fb += 2;
+ }
+ *fb = ti[2];
+ *(fb+1) = attr;
+ fb = video_addr(x+1, y+1);
+ for (i=0; i<w-2; i++)
+ {
+ *fb = ' ';
+ *(fb+1) = attr;
+ fb += 2;
+ }
+ fb = video_addr(x+2, y+1);
+
+ while (*title)
+ {
+ *fb = *title;
+ *(fb+1) = attr;
+ fb += 2;
+ title++;
+ }
+ }
+ }
+
+}
+
+void video_draw_text(int x, int y, int attr, char *text)
+{
+ unsigned char *fb = video_addr(x,y);
+ while (*text)
+ {
+ *fb++ = *text++;
+ *fb++ = attr;
+ }
+}
+
+void video_save_rect(int x, int y, int w, int h, void *save_area, int clearchar, int clearattr)
+{
+ unsigned char *save = (unsigned char *)save_area;
+ unsigned char *fb = video_addr(x,y);
+ int i,j;
+ for (i=0; i<h; i++)
+ {
+ unsigned char *fbb = fb;
+ for (j=0; j<w; j++)
+ {
+ *save ++ = *fb;
+ if (clearchar > 0) *fb = clearchar;
+ fb ++;
+ *save ++ = *fb;
+ if (clearattr > 0) *fb = clearattr;
+ }
+ fb = fbb + 2*VIDEO_COLS;
+ }
+}
+
+void video_restore_rect(int x, int y, int w, int h, void *save_area)
+{
+ unsigned char *save = (unsigned char *)save_area;
+ unsigned char *fb = video_addr(x,y);
+ int i,j;
+ for (i=0; i<h; i++)
+ {
+ unsigned char *fbb = fb;
+ for (j=0; j<w; j++)
+ {
+ *fb ++ = *save ++;
+ *fb ++ = *save ++;
+ }
+ fb = fbb + 2*VIDEO_COLS;
+ }
+
+}
+
+int video_rows(void)
+{
+ return VIDEO_ROWS;
+}
+
+int video_cols(void)
+{
+ return VIDEO_COLS;
+}
+
+void video_size(int cols, int rows)
+{
+ video_numrows = rows;
+ video_numcols = cols;
+}
+
+void video_clear(void)
+{
+ unsigned short *fbb = (unsigned short *)0xFD0B8000;
+ int i,j;
+ unsigned short val = 0x2000 | current_attr;
+
+ for (i=0; i<video_rows(); i++)
+ {
+ for (j=0; j<video_cols(); j++)
+ {
+ *fbb++ = val;
+ }
+ }
+ video_set_cursor(0,0);
+ cursor_row = 0;
+ cursor_col = 0;
+}
+
+#ifdef EASTEREGG
+int video_easteregg_active = 0;
+
+void video_easteregg(void)
+{
+ video_easteregg_active = 1;
+}
+#endif
+
+extern bd_t *bd_global;
+extern block_dev_desc_t * ide_get_dev(int dev);
+extern char version_string[];
+
+void video_banner(void)
+{
+ block_dev_desc_t *ide;
+ int i;
+ char *s;
+ int maxdev;
+
+
+ if (video_inited == 0) return;
+#ifdef EASTEREGG
+ if (video_easteregg_active)
+ {
+ prompt_string="";
+ video_clear();
+ printf("\n");
+ printf(" **** COMMODORE 64 BASIC X2 ****\n\n");
+ printf(" 64K RAM SYSTEM 38911 BASIC BYTES FREE\n\n");
+ printf("READY\n");
+ }
+ else
+ {
+#endif
+ s = getenv("ide_maxbus");
+ if (s)
+ maxdev = atoi(s) * 2;
+ else
+ maxdev = 4;
+
+ s = getenv("stdout");
+ if (s && strcmp(s, "serial") == 0)
+ return;
+
+ video_clear();
+ printf("%s\n\nCPU: ", version_string);
+ checkcpu();
+ printf("DRAM: %ld MB\n", bd_global->bi_memsize/(1024*1024));
+ printf("FSB: %ld MHz\n", bd_global->bi_busfreq/1000000);
+
+ printf("\n---- Disk summary ----\n");
+ for (i = 0; i < maxdev; i++)
+ {
+ ide = ide_get_dev(i);
+ printf("Device %d: ", i);
+ dev_print(ide);
+ }
+
+/*
+ video_draw_box(SINGLE_BOX, 0x0F, "Test 1", 0, 0,18, 72, 4);
+ video_draw_box(DOUBLE_BOX, 0x0F, "Test 2", 1, 4,10, 50, 6);
+ video_draw_box(DOUBLE_BOX, 0x0F, "Test 3", 0, 40, 3, 20, 5);
+
+ video_draw_text(1, 4, 0x2F, "Highlighted options");
+ video_draw_text(1, 5, 0x0F, "Non-selected option");
+ video_draw_text(1, 6, 0x07, "disabled option");
+*/
+#ifdef EASTEREGG
+ }
+#endif
+}