diff options
author | wdenk <wdenk> | 2003-05-31 18:35:21 +0000 |
---|---|---|
committer | wdenk <wdenk> | 2003-05-31 18:35:21 +0000 |
commit | 7a8e9bed17d7924a9c5c4699b1f6a3a0359524ed (patch) | |
tree | 5c273df9c5efa7b1b6a4ca88904e48039ef591e8 /cpu/i386 | |
parent | 3b57fe0a70b903f4db66c558bb9828bc58acf06b (diff) | |
download | u-boot-imx-7a8e9bed17d7924a9c5c4699b1f6a3a0359524ed.zip u-boot-imx-7a8e9bed17d7924a9c5c4699b1f6a3a0359524ed.tar.gz u-boot-imx-7a8e9bed17d7924a9c5c4699b1f6a3a0359524ed.tar.bz2 |
* Patch by Marc Singer, 29 May 2003:
Fixed rarp boot method for IA32 and other little-endian CPUs.
* Patch by Marc Singer, 28 May 2003:
Added port I/O commands.
* Patch by Matthew McClintock, 28 May 2003
- cpu/mpc824x/start.S: fix relocation code when booting from RAM
- minor patches for utx8245
* Patch by Daniel Engström, 28 May 2003:
x86 update
* Patch by Dave Ellis, 9 May 2003 + 27 May 2003:
add nand flash support to SXNI855T configuration
fix/extend nand flash support:
- fix 'nand erase' command so does not erase bad blocks
- fix 'nand write' command so does not write to bad blocks
- fix nand_probe() so handles no flash detected properly
- add doc/README.nand
- add .jffs2 and .oob options to nand read/write
- add 'nand bad' command to list bad blocks
- add 'clean' option to 'nand erase' to write JFFS2 clean markers
- make NAND read/write faster
* Patch by Rune Torgersen, 23 May 2003:
Update for MPC8266ADS board
Diffstat (limited to 'cpu/i386')
-rw-r--r-- | cpu/i386/Makefile | 13 | ||||
-rw-r--r-- | cpu/i386/config.mk | 4 | ||||
-rw-r--r-- | cpu/i386/cpu.c | 7 | ||||
-rw-r--r-- | cpu/i386/interrupts.c | 67 | ||||
-rw-r--r-- | cpu/i386/sc520.c | 502 | ||||
-rw-r--r-- | cpu/i386/sc520_asm.S | 536 | ||||
-rw-r--r-- | cpu/i386/serial.c | 153 | ||||
-rw-r--r-- | cpu/i386/start16.S | 4 |
8 files changed, 1177 insertions, 109 deletions
diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile index 1482398..7067a06 100644 --- a/cpu/i386/Makefile +++ b/cpu/i386/Makefile @@ -26,17 +26,18 @@ include $(TOPDIR)/config.mk LIB = lib$(CPU).a START = start.o start16.o reset.o -OBJS = serial.o interrupts.o cpu.o timer.o - +COBJS = serial.o interrupts.o cpu.o timer.o sc520.o +AOBJS = sc520_asm.o + all: .depend $(START) $(LIB) -$(LIB): $(OBJS) - $(AR) crv $@ $(OBJS) +$(LIB): $(COBJS) $(AOBJS) + $(AR) crv $@ $(COBJS) $(AOBJS) ######################################################################### -.depend: Makefile $(START:.o=.S) $(OBJS:.o=.c) - $(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@ +.depend: Makefile $(START:.o=.S) $(COBJS:.o=.c) $(AOBJS:.o=.S) + $(CC) -M $(CFLAGS) $(START:.o=.S) $(COBJS:.o=.c) $(AOBJS:.o=.S) > $@ sinclude .depend diff --git a/cpu/i386/config.mk b/cpu/i386/config.mk index 70caeb2..c7cf151 100644 --- a/cpu/i386/config.mk +++ b/cpu/i386/config.mk @@ -21,6 +21,6 @@ # MA 02111-1307 USA # -PLATFORM_RELFLAGS += # -pipe -mpreferred-stack-boundary=2 -fno-builtin -nostdinc -nostdlib +PLATFORM_RELFLAGS += -PLATFORM_CPPFLAGS += -march=i386 +PLATFORM_CPPFLAGS += -march=i386 -Werror diff --git a/cpu/i386/cpu.c b/cpu/i386/cpu.c index 669823f..3c67c12 100644 --- a/cpu/i386/cpu.c +++ b/cpu/i386/cpu.c @@ -38,6 +38,13 @@ int cpu_init(void) { + /* initialize FPU, reset EM, set MP and NE */ + asm ("fninit\n" \ + "movl %cr0, %eax\n" \ + "andl $~0x4, %eax\n" \ + "orl $0x22, %eax\n" \ + "movl %eax, %cr0\n" ); + return 0; } diff --git a/cpu/i386/interrupts.c b/cpu/i386/interrupts.c index 81d6881..614d408 100644 --- a/cpu/i386/interrupts.c +++ b/cpu/i386/interrupts.c @@ -29,22 +29,6 @@ #include <asm/ibmpc.h> -#if 0 -/* done */ -int interrupt_init (void); -void irq_install_handler(int, interrupt_handler_t *, void *); -void irq_free_handler (int); -void enable_interrupts (void); -int disable_interrupts (void); - -/* todo */ -void timer_interrupt (struct pt_regs *); -void external_interrupt (struct pt_regs *); -void reset_timer (void); -ulong get_timer (ulong base); -void set_timer (ulong t); - -#endif struct idt_entry { u16 base_low; @@ -76,43 +60,30 @@ typedef struct { static irq_desc_t irq_table[MAX_IRQ]; -/* syscall stuff, very untested - * the current approach which includes copying - * part of the stack will work badly for - * varargs functions. - * if we were to store the top three words on the - * stack (eip, ss, eflags) somwhere and add 14 to - * %esp .... - */ + asm(".globl syscall_entry\n" \ "syscall_entry:\n" \ - "movl 12(%esp), %eax\n" \ - "movl %esp, %ebx\n" \ - "addl $16, %ebx\n" \ - "pushl %ebx\n" \ - "pushl %eax\n" \ - "call do_syscall\n" \ - "addl $8, %esp\n" \ - "iret\n"); + "popl %ebx\n" /* throw away the return address, flags */ \ + "popl %ebx\n" /* and segment that the INT instruction pushed */ \ + "popl %ebx\n" /* on to the stack */ \ + "movl %eax, %ecx\n" /* load the syscall nr argument*/ \ + "movl syscall_tbl, %eax\n" /* load start of syscall table */ \ + "cmpl $(11-1), %ecx\n" /* FixMe: find a way to use NR_SYSCALLS macro here */ \ + "ja bad_syscall\n" \ + "movl (%eax, %ecx, 4), %eax\n" /* load the handler of the syscall*/ \ + "test %eax, %eax\n" /* test for null */ \ + "je bad_syscall\n" \ + "popl %ecx\n" \ + "popl %ebx\n" \ + "sti \n" \ + "jmp *%eax\n" \ +"bad_syscall: movl $0xffffffff, %eax\n" \ + "popl %ecx\n" \ + "popl %ebx\n" \ + "ret"); void __attribute__ ((regparm(0))) syscall_entry(void); -int __attribute__ ((regparm(0))) do_syscall(u32 nr, u32 *stack) -{ - if (nr<NR_SYSCALLS) { - /* We copy 8 args of the syscall, - * this will be a problem with the - * printf syscall .... */ - int (*fp)(u32, u32, u32, u32, - u32, u32, u32, u32); - fp = syscall_tbl[nr]; - return fp(stack[0], stack[1], stack[2], stack[3], - stack[4], stack[5], stack[6], stack[7]); - } - - return -1; -} - asm ("irq_return:\n" " addl $4, %esp\n" diff --git a/cpu/i386/sc520.c b/cpu/i386/sc520.c new file mode 100644 index 0000000..500089a --- /dev/null +++ b/cpu/i386/sc520.c @@ -0,0 +1,502 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>. + * + * 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 + */ + +/* stuff specific for the sc520, + * but idependent of implementation */ + +#include <config.h> + +#ifdef CONFIG_SC520 + +#include <common.h> +#include <config.h> +#include <pci.h> +#include <ssi.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <asm/ic/sc520.h> + +/* + * utility functions for boards based on the AMD sc520 + * + * void write_mmcr_byte(u16 mmcr, u8 data) + * void write_mmcr_word(u16 mmcr, u16 data) + * void write_mmcr_long(u16 mmcr, u32 data) + * + * u8 read_mmcr_byte(u16 mmcr) + * u16 read_mmcr_word(u16 mmcr) + * u32 read_mmcr_long(u16 mmcr) + * + * void init_sc520(void) + * unsigned long init_sc520_dram(void) + * void pci_sc520_init(struct pci_controller *hose) + * + * void reset_timer(void) + * ulong get_timer(ulong base) + * void set_timer(ulong t) + * void udelay(unsigned long usec) + * + */ + +static u32 mmcr_base= 0xfffef000; + +void write_mmcr_byte(u16 mmcr, u8 data) +{ + writeb(data, mmcr+mmcr_base); +} + +void write_mmcr_word(u16 mmcr, u16 data) +{ + writew(data, mmcr+mmcr_base); +} + +void write_mmcr_long(u16 mmcr, u32 data) +{ + writel(data, mmcr+mmcr_base); +} + +u8 read_mmcr_byte(u16 mmcr) +{ + return readb(mmcr+mmcr_base); +} + +u16 read_mmcr_word(u16 mmcr) +{ + return readw(mmcr+mmcr_base); +} + +u32 read_mmcr_long(u16 mmcr) +{ + return readl(mmcr+mmcr_base); +} + + +void init_sc520(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + /* Set the UARTxCTL register at it's slower, + * baud clock giving us a 1.8432 MHz reference + */ + write_mmcr_byte(SC520_UART1CTL, 7); + write_mmcr_byte(SC520_UART2CTL, 7); + + /* first set the timer pin mapping */ + write_mmcr_byte(SC520_CLKSEL, 0x72); /* no clock frequency selected, use 1.1892MHz */ + + /* enable PCI bus arbitrer */ + write_mmcr_byte(SC520_SYSARBCTL,0x02); /* enable concurrent mode */ + + write_mmcr_word(SC520_SYSARBMENB,0x1f); /* enable external grants */ + write_mmcr_word(SC520_HBCTL,0x04); /* enable posted-writes */ + + + if (CFG_SC520_HIGH_SPEED) { + write_mmcr_byte(SC520_CPUCTL, 0x2); /* set it to 133 MHz and write back */ + gd->cpu_clk = 133000000; + printf("## CPU Speed set to 133MHz\n"); + } else { + write_mmcr_byte(SC520_CPUCTL, 1); /* set CPU to 100 MHz and write back cache */ + printf("## CPU Speed set to 100MHz\n"); + gd->cpu_clk = 100000000; + } + + + /* wait at least one millisecond */ + asm("movl $0x2000,%%ecx\n" + "wait_loop: pushl %%ecx\n" + "popl %%ecx\n" + "loop wait_loop\n": : : "ecx"); + + /* turn on the SDRAM write buffer */ + write_mmcr_byte(SC520_DBCTL, 0x11); + + /* turn on the cache and disable write through */ + asm("movl %%cr0, %%eax\n" + "andl $0x9fffffff, %%eax\n" + "movl %%eax, %%cr0\n" : : : "eax"); +} + +unsigned long init_sc520_dram(void) +{ + DECLARE_GLOBAL_DATA_PTR; + bd_t *bd = gd->bd; + + u32 dram_present=0; + u32 dram_ctrl; + + int val; + + int cas_precharge_delay = CFG_SDRAM_PRECHARGE_DELAY; + int refresh_rate = CFG_SDRAM_REFRESH_RATE; + int ras_cas_delay = CFG_SDRAM_RAS_CAS_DELAY; + + /* set SDRAM speed here */ + + refresh_rate/=78; + if (refresh_rate<=1) { + val = 0; /* 7.8us */ + } else if (refresh_rate==2) { + val = 1; /* 15.6us */ + } else if (refresh_rate==3 || refresh_rate==4) { + val = 2; /* 31.2us */ + } else { + val = 3; /* 62.4us */ + } + write_mmcr_byte(SC520_DRCCTL, (read_mmcr_byte(SC520_DRCCTL) & 0xcf) | (val<<4)); + + val = read_mmcr_byte(SC520_DRCTMCTL); + val &= 0xf0; + + if (cas_precharge_delay==3) { + val |= 0x04; /* 3T */ + } else if (cas_precharge_delay==4) { + val |= 0x08; /* 4T */ + } else if (cas_precharge_delay>4) { + val |= 0x0c; + } + + if (ras_cas_delay > 3) { + val |= 2; + } else { + val |= 1; + } + write_mmcr_byte(SC520_DRCTMCTL, val); + + + /* We read-back the configuration of the dram + * controller that the assembly code wrote */ + dram_ctrl = read_mmcr_long(SC520_DRCBENDADR); + + + bd->bi_dram[0].start = 0; + if (dram_ctrl & 0x80) { + /* bank 0 enabled */ + dram_present = bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22; + bd->bi_dram[0].size = bd->bi_dram[1].start; + + } else { + bd->bi_dram[0].size = 0; + bd->bi_dram[1].start = bd->bi_dram[0].start; + } + + if (dram_ctrl & 0x8000) { + /* bank 1 enabled */ + dram_present = bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14; + bd->bi_dram[1].size = bd->bi_dram[2].start - bd->bi_dram[1].start; + } else { + bd->bi_dram[1].size = 0; + bd->bi_dram[2].start = bd->bi_dram[1].start; + } + + if (dram_ctrl & 0x800000) { + /* bank 2 enabled */ + dram_present = bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6; + bd->bi_dram[2].size = bd->bi_dram[3].start - bd->bi_dram[2].start; + } else { + bd->bi_dram[2].size = 0; + bd->bi_dram[3].start = bd->bi_dram[2].start; + } + + if (dram_ctrl & 0x80000000) { + /* bank 3 enabled */ + dram_present = (dram_ctrl & 0x7f000000) >> 2; + bd->bi_dram[3].size = dram_present - bd->bi_dram[3].start; + } else { + bd->bi_dram[3].size = 0; + } + + +#if 0 + printf("Configured %d bytes of dram\n", dram_present); +#endif + gd->ram_size = dram_present; + + return dram_present; +} + + +#ifdef CONFIG_PCI + + +static struct { + u8 priority; + u16 level_reg; + u8 level_bit; +} sc520_irq[] = { + { SC520_IRQ0, SC520_MPICMODE, 0x01 }, + { SC520_IRQ1, SC520_MPICMODE, 0x02 }, + { SC520_IRQ2, SC520_SL1PICMODE, 0x02 }, + { SC520_IRQ3, SC520_MPICMODE, 0x08 }, + { SC520_IRQ4, SC520_MPICMODE, 0x10 }, + { SC520_IRQ5, SC520_MPICMODE, 0x20 }, + { SC520_IRQ6, SC520_MPICMODE, 0x40 }, + { SC520_IRQ7, SC520_MPICMODE, 0x80 }, + + { SC520_IRQ8, SC520_SL1PICMODE, 0x01 }, + { SC520_IRQ9, SC520_SL1PICMODE, 0x02 }, + { SC520_IRQ10, SC520_SL1PICMODE, 0x04 }, + { SC520_IRQ11, SC520_SL1PICMODE, 0x08 }, + { SC520_IRQ12, SC520_SL1PICMODE, 0x10 }, + { SC520_IRQ13, SC520_SL1PICMODE, 0x20 }, + { SC520_IRQ14, SC520_SL1PICMODE, 0x40 }, + { SC520_IRQ15, SC520_SL1PICMODE, 0x80 } +}; + + +/* The interrupt used for PCI INTA-INTD */ +int sc520_pci_ints[15] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1 +}; + +/* utility function to configure a pci interrupt */ +int pci_sc520_set_irq(int pci_pin, int irq) +{ + int i; + +# if 0 + printf("set_irq(): map INT%c to IRQ%d\n", pci_pin + 'A', irq); +#endif + if (irq < 0 || irq > 15) { + return -1; /* illegal irq */ + } + + if (pci_pin < 0 || pci_pin > 15) { + return -1; /* illegal pci int pin */ + } + + /* first disable any non-pci interrupt source that use + * this level */ + for (i=SC520_GPTMR0MAP;i<=SC520_GP10IMAP;i++) { + if (i>=SC520_PCIINTAMAP&&i<=SC520_PCIINTDMAP) { + continue; + } + if (read_mmcr_byte(i) == sc520_irq[irq].priority) { + write_mmcr_byte(i, SC520_IRQ_DISABLED); + } + } + + /* Set the trigger to level */ + write_mmcr_byte(sc520_irq[irq].level_reg, + read_mmcr_byte(sc520_irq[irq].level_reg) | sc520_irq[irq].level_bit); + + + if (pci_pin < 4) { + /* PCI INTA-INTD */ + /* route the interrupt */ + write_mmcr_byte(SC520_PCIINTAMAP + pci_pin, sc520_irq[irq].priority); + + + } else { + /* GPIRQ0-GPIRQ10 used for additional PCI INTS */ + write_mmcr_byte(SC520_GP0IMAP + pci_pin - 4, sc520_irq[irq].priority); + + /* also set the polarity in this case */ + write_mmcr_word(SC520_INTPINPOL, + read_mmcr_word(SC520_INTPINPOL) | (1 << (pci_pin-4))); + + } + + /* register the pin */ + sc520_pci_ints[pci_pin] = irq; + + + return 0; /* OK */ +} + +void pci_sc520_init(struct pci_controller *hose) +{ + hose->first_busno = 0; + hose->last_busno = 0xff; + + /* System memory space */ + pci_set_region(hose->regions + 0, + SC520_PCI_MEMORY_BUS, + SC520_PCI_MEMORY_PHYS, + SC520_PCI_MEMORY_SIZE, + PCI_REGION_MEM | PCI_REGION_MEMORY); + + /* PCI memory space */ + pci_set_region(hose->regions + 1, + SC520_PCI_MEM_BUS, + SC520_PCI_MEM_PHYS, + SC520_PCI_MEM_SIZE, + PCI_REGION_MEM); + + /* ISA/PCI memory space */ + pci_set_region(hose->regions + 2, + SC520_ISA_MEM_BUS, + SC520_ISA_MEM_PHYS, + SC520_ISA_MEM_SIZE, + PCI_REGION_MEM); + + /* PCI I/O space */ + pci_set_region(hose->regions + 3, + SC520_PCI_IO_BUS, + SC520_PCI_IO_PHYS, + SC520_PCI_IO_SIZE, + PCI_REGION_IO); + + /* ISA/PCI I/O space */ + pci_set_region(hose->regions + 4, + SC520_ISA_IO_BUS, + SC520_ISA_IO_PHYS, + SC520_ISA_IO_SIZE, + PCI_REGION_IO); + + hose->region_count = 5; + + pci_setup_type1(hose, + SC520_REG_ADDR, + SC520_REG_DATA); + + pci_register_hose(hose); + + hose->last_busno = pci_hose_scan(hose); + + /* enable target memory acceses on host brige */ + pci_write_config_word(0, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + +} + + + +#endif + +#ifdef CFG_TIMER_SC520 + + +void reset_timer(void) +{ + write_mmcr_word(SC520_GPTMR0CNT, 0); + write_mmcr_word(SC520_GPTMR0CTL, 0x6001); + +} + +ulong get_timer(ulong base) +{ + /* fixme: 30 or 33 */ + return read_mmcr_word(SC520_GPTMR0CNT) / 33; +} + +void set_timer(ulong t) +{ + /* FixMe: use two cascade coupled timers */ + write_mmcr_word(SC520_GPTMR0CTL, 0x4001); + write_mmcr_word(SC520_GPTMR0CNT, t*33); + write_mmcr_word(SC520_GPTMR0CTL, 0x6001); +} + + +void udelay(unsigned long usec) +{ + int m=0; + long u; + + read_mmcr_word(SC520_SWTMRMILLI); + read_mmcr_word(SC520_SWTMRMICRO); + +#if 0 + /* do not enable this line, udelay is used in the serial driver -> recursion */ + printf("udelay: %ld m.u %d.%d tm.tu %d.%d\n", usec, m, u, tm, tu); +#endif + while (1) { + + m += read_mmcr_word(SC520_SWTMRMILLI); + u = read_mmcr_word(SC520_SWTMRMICRO) + (m * 1000); + + if (usec <= u) { + break; + } + } +} + +#endif + +int ssi_set_interface(int freq, int lsb_first, int inv_clock, int inv_phase) +{ + u8 temp=0; + + if (freq >= 8192) { + temp |= CTL_CLK_SEL_4; + } else if (freq >= 4096) { + temp |= CTL_CLK_SEL_8; + } else if (freq >= 2048) { + temp |= CTL_CLK_SEL_16; + } else if (freq >= 1024) { + temp |= CTL_CLK_SEL_32; + } else if (freq >= 512) { + temp |= CTL_CLK_SEL_64; + } else if (freq >= 256) { + temp |= CTL_CLK_SEL_128; + } else if (freq >= 128) { + temp |= CTL_CLK_SEL_256; + } else { + temp |= CTL_CLK_SEL_512; + } + + if (!lsb_first) { + temp |= MSBF_ENB; + } + + if (inv_clock) { + temp |= CLK_INV_ENB; + } + + if (inv_phase) { + temp |= PHS_INV_ENB; + } + + write_mmcr_byte(SC520_SSICTL, temp); + + return 0; +} + +u8 ssi_txrx_byte(u8 data) +{ + write_mmcr_byte(SC520_SSIXMIT, data); + while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY); + write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMITRCV); + while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY); + return read_mmcr_byte(SC520_SSIRCV); +} + + +void ssi_tx_byte(u8 data) +{ + write_mmcr_byte(SC520_SSIXMIT, data); + while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY); + write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMIT); +} + +u8 ssi_rx_byte(void) +{ + while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY); + write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_RCV); + while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY); + return read_mmcr_byte(SC520_SSIRCV); +} + +#endif /* CONFIG_SC520 */ diff --git a/cpu/i386/sc520_asm.S b/cpu/i386/sc520_asm.S new file mode 100644 index 0000000..7a957c7 --- /dev/null +++ b/cpu/i386/sc520_asm.S @@ -0,0 +1,536 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is largely based on code obtned from AMD. AMD's original + * copyright is included below + */ + +/* + * ============================================================================= + * + * Copyright 1999 Advanced Micro Devices, Inc. + * + * This software is the property of Advanced Micro Devices, Inc (AMD) which + * specifically grants the user the right to modify, use and distribute this + * software provided this COPYRIGHT NOTICE is not removed or altered. All + * other rights are reserved by AMD. + * + * THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY + * OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF + * THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY PARTICULAR PURPOSE. + * IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER + * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS + * INTERRUPTION, LOSS OF INFORMAITON) ARISING OUT OF THE USE OF OR INABILITY + * TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. BECAUSE SOME JURSIDICTIONS PROHIBIT THE EXCLUSION OR + * LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE + * LIMITATION MAY NOT APPLY TO YOU. + * + * AMD does not assume any responsibility for any errors that may appear in + * the Materials nor any responsibility to support or update the Materials. + * AMD retains the right to make changes to its test specifications at any + * time, without notice. + * + * So that all may benefit from your experience, please report any problems + * or suggestions about this software back to AMD. Please include your name, + * company, telephone number, AMD product requiring support and question or + * problem encountered. + * + * Advanced Micro Devices, Inc. Worldwide support and contact + * Embedded Processor Division information available at: + * Systems Engineering epd.support@amd.com + * 5204 E. Ben White Blvd. -or- + * Austin, TX 78741 http://www.amd.com/html/support/techsup.html + * ============================================================================ + */ + + +/******************************************************************************* + * AUTHOR : Buddy Fey - Original. + ******************************************************************************* + */ + + +/******************************************************************************* + * FUNCTIONAL DESCRIPTION: + * This routine is called to autodetect the geometry of the DRAM. + * + * This routine is called to determine the number of column bits for the DRAM + * devices in this external bank. This routine assumes that the external bank + * has been configured for an 11-bit column and for 4 internal banks. This gives + * us the maximum address reach in memory. By writing a test value to the max + * address and locating where it aliases to, we can determine the number of valid + * column bits. + * + * This routine is called to determine the number of internal banks each DRAM + * device has. The external bank (under test) is configured for maximum reach + * with 11-bit columns and 4 internal banks. This routine will write to a max + * address (BA1 and BA0 = 1) and then read from an address with BA1=0 to see if + * that column is a "don't care". If BA1 does not affect write/read of data, + * then this device has only 2 internal banks. + * + * This routine is called to determine the ending address for this external + * bank of SDRAM. We write to a max address with a data value and then disable + * row address bits looking for "don't care" locations. Each "don't care" bit + * represents a dividing of the maximum density (128M) by 2. By dividing the + * maximum of 32 4M chunks in an external bank down by all the "don't care" bits + * determined during sizing, we set the proper density. + * + * WARNINGS. + * bp must be preserved because it is used for return linkage. + * + * EXIT + * nothing returned - but the memory subsystem is enabled + ******************************************************************************* + */ + +#include <config.h> +#ifdef CONFIG_SC520 + +.section .text +.equ DRCCTL, 0x0fffef010 /* DRAM control register */ +.equ DRCTMCTL, 0x0fffef012 /* DRAM timing control register */ +.equ DRCCFG, 0x0fffef014 /* DRAM bank configuration register */ +.equ DRCBENDADR, 0x0fffef018 /* DRAM bank ending address register */ +.equ ECCCTL, 0x0fffef020 /* DRAM ECC control register */ +.equ DBCTL, 0x0fffef040 /* DRAM buffer control register */ + +.equ CACHELINESZ, 0x00000010 /* size of our cache line (read buffer) */ +.equ COL11_ADR, 0x0e001e00 /* 11 col addrs */ +.equ COL10_ADR, 0x0e000e00 /* 10 col addrs */ +.equ COL09_ADR, 0x0e000600 /* 9 col addrs */ +.equ COL08_ADR, 0x0e000200 /* 8 col addrs */ +.equ ROW14_ADR, 0x0f000000 /* 14 row addrs */ +.equ ROW13_ADR, 0x07000000 /* 13 row addrs */ +.equ ROW12_ADR, 0x03000000 /* 12 row addrs */ +.equ ROW11_ADR, 0x01000000 /* 11 row addrs/also bank switch */ +.equ ROW10_ADR, 0x00000000 /* 10 row addrs/also bank switch */ +.equ COL11_DATA, 0x0b0b0b0b /* 11 col addrs */ +.equ COL10_DATA, 0x0a0a0a0a /* 10 col data */ +.equ COL09_DATA, 0x09090909 /* 9 col data */ +.equ COL08_DATA, 0x08080808 /* 8 col data */ +.equ ROW14_DATA, 0x3f3f3f3f /* 14 row data (MASK) */ +.equ ROW13_DATA, 0x1f1f1f1f /* 13 row data (MASK) */ +.equ ROW12_DATA, 0x0f0f0f0f /* 12 row data (MASK) */ +.equ ROW11_DATA, 0x07070707 /* 11 row data/also bank switch (MASK) */ +.equ ROW10_DATA, 0xaaaaaaaa /* 10 row data/also bank switch (MASK) */ + + + /* + * initialize dram controller registers + */ +.globl mem_init +mem_init: + xorw %ax,%ax + movl $DBCTL, %edi + movb %al, (%edi) /* disable write buffer */ + + movl $ECCCTL, %edi + movb %al, (%edi) /* disable ECC */ + + movl $DRCTMCTL, %edi + movb $0x1E,%al /* Set SDRAM timing for slowest */ + movb %al, (%edi) + + /* + * setup loop to do 4 external banks starting with bank 3 + */ + movl $0xff000000,%eax /* enable last bank and setup */ + movl $DRCBENDADR, %edi /* ending address register */ + movl %eax, (%edi) + + movl $DRCCFG, %edi /* setup */ + movw $0xbbbb,%ax /* dram config register for */ + movw %ax, (%edi) + + /* + * issue a NOP to all DRAMs + */ + movl $DRCCTL, %edi /* setup DRAM control register with */ + movb $0x1,%al /* Disable refresh,disable write buffer */ + movb %al, (%edi) + movl $CACHELINESZ, %esi /* just a dummy address to write for */ + movw %ax, (%esi) + /* + * delay for 100 usec? 200? + * ******this is a cludge for now ************* + */ + movw $100,%cx +sizdelay: + loop sizdelay /* we need 100 usec here */ + /***********************************************/ + + /* + * issue all banks precharge + */ + movb $0x2,%al /* All banks precharge */ + movb %al, (%edi) + movw %ax, (%esi) + + /* + * issue 2 auto refreshes to all banks + */ + movb $0x4,%al /* Auto refresh cmd */ + movb %al, (%edi) + movw $2,%cx +refresh1: + movw %ax, (%esi) + loop refresh1 + + /* + * issue LOAD MODE REGISTER command + */ + movb $0x3,%al /* Load mode register cmd */ + movb %al, (%edi) + movw %ax, (%esi) + + /* + * issue 8 more auto refreshes to all banks + */ + movb $0x4,%al /* Auto refresh cmd */ + movb %al, (%edi) + movw $8,%cx +refresh2: + movw %ax, (%esi) + loop refresh2 + + /* + * set control register to NORMAL mode + */ + movb $0x0,%al /* Normal mode value */ + movb %al, (%edi) + + /* + * size dram starting with external bank 3 moving to external bank 0 + */ + movl $0x3,%ecx /* start with external bank 3 */ + +nextbank: + + /* + * write col 11 wrap adr + */ + movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ + movl $COL11_DATA, %eax /* pattern for max supported columns(11) */ + movl %eax, (%esi) /* write max col pattern at max col adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 10 wrap adr + */ + + movl $COL10_ADR, %esi /* set address to 10 col wrap address */ + movl $COL10_DATA, %eax /* pattern for 10 col wrap */ + movl %eax, (%esi) /* write 10 col pattern @ 10 col wrap adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 9 wrap adr + */ + movl $COL09_ADR, %esi /* set address to 9 col wrap address */ + movl $COL09_DATA, %eax /* pattern for 9 col wrap */ + movl %eax, (%esi) /* write 9 col pattern @ 9 col wrap adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 8 wrap adr + */ + movl $COL08_ADR, %esi /* set address to min(8) col wrap address */ + movl $COL08_DATA, %eax /* pattern for min (8) col wrap */ + movl %eax, (%esi) /* write min col pattern @ min col adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 14 wrap adr + */ + movl $ROW14_ADR, %esi /* set address to max row (14) wrap addr */ + movl $ROW14_DATA, %eax /* pattern for max supported rows(14) */ + movl %eax, (%esi) /* write max row pattern at max row adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 13 wrap adr + */ + movl $ROW13_ADR, %esi /* set address to 13 row wrap address */ + movl $ROW13_DATA, %eax /* pattern for 13 row wrap */ + movl %eax, (%esi) /* write 13 row pattern @ 13 row wrap adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 12 wrap adr + */ + movl $ROW12_ADR, %esi /* set address to 12 row wrap address */ + movl $ROW12_DATA, %eax /* pattern for 12 row wrap */ + movl %eax, (%esi) /* write 12 row pattern @ 12 row wrap adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 11 wrap adr + */ + movl $ROW11_ADR, %edi /* set address to 11 row wrap address */ + movl $ROW11_DATA, %eax /* pattern for 11 row wrap */ + movl %eax, (%edi) /* write 11 row pattern @ 11 row wrap adr */ + movl (%edi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 10 wrap adr --- this write is really to determine number of banks + */ + movl $ROW10_ADR, %edi /* set address to 10 row wrap address */ + movl $ROW10_DATA, %eax /* pattern for 10 row wrap (AA) */ + movl %eax, (%edi) /* write 10 row pattern @ 10 row wrap adr */ + movl (%edi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * read data @ row 12 wrap adr to determine * banks, + * and read data @ row 14 wrap adr to determine * rows. + * if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM. + * if data @ row 12 wrap == AA, we only have 2 banks, NOT 4 + * if data @ row 12 wrap == 11 or 12, we have 4 banks, + */ + xorw %di,%di /* value for 2 banks in DI */ + movl (%esi), %ebx /* read from 12 row wrap to check banks + * (esi is setup from the write to row 12 wrap) */ + cmpl %ebx,%eax /* check for AA pattern (eax holds the aa pattern) */ + jz only2 /* if pattern == AA, we only have 2 banks */ + + /* 4 banks */ + + movw $8,%di /* value for 4 banks in DI (BNK_CNT bit) */ + cmpl $ROW11_DATA, %ebx /* only other legitimate values are 11 */ + jz only2 + cmpl $ROW12_DATA, %ebx /* and 12 */ + jnz bad_ram /* its bad if not 11 or 12! */ + + /* fall through */ +only2: + /* + * validate row mask + */ + movl $ROW14_ADR, %esi /* set address back to max row wrap addr */ + movl (%esi), %eax /* read actual number of rows @ row14 adr */ + + cmpl $ROW11_DATA, %eax /* row must be greater than 11 pattern */ + jb bad_ram + + cmpl $ROW14_DATA, %eax /* and row must be less than 14 pattern */ + ja bad_ram + + cmpb %ah,%al /* verify all 4 bytes of dword same */ + jnz bad_ram + movl %eax,%ebx + shrl $16,%ebx + cmpw %bx,%ax + jnz bad_ram + /* + * read col 11 wrap adr for real column data value + */ + movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ + movl (%esi), %eax /* read real col number at max col adr */ + /* + * validate column data + */ + cmpl $COL08_DATA, %eax /* col must be greater than 8 pattern */ + jb bad_ram + + cmpl $COL11_DATA, %eax /* and row must be less than 11 pattern */ + ja bad_ram + + subl $COL08_DATA, %eax /* normalize column data to zero */ + jc bad_ram + cmpb %ah,%al /* verify all 4 bytes of dword equal */ + jnz bad_ram + movl %eax,%edx + shrl $16,%edx + cmpw %dx,%ax + jnz bad_ram + /* + * merge bank and col data together + */ + addw %di,%dx /* merge of bank and col info in dl */ + /* + * fix ending addr mask based upon col info + */ + movb $3,%al + subb %dh,%al /* dh contains the overflow from the bank/col merge */ + movb %bl,%dh /* bl contains the row mask (aa, 07, 0f, 1f or 3f) */ + xchgw %cx,%ax /* cx = ax = 3 or 2 depending on 2 or 4 bank device */ + shrb %cl,%dh /* */ + incb %dh /* ending addr is 1 greater than real end */ + xchgw %cx,%ax /* cx is bank number again */ + /* + * issue all banks precharge + */ +bad_reint: + movl $DRCCTL, %esi /* setup DRAM control register with */ + movb $0x2,%al /* All banks precharge */ + movb %al, (%esi) + movl $CACHELINESZ, %esi /* address to init read buffer */ + movw %ax, (%esi) + + /* + * update ENDING ADDRESS REGISTER + */ + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movl %ecx,%ebx + addl %ebx, %edi + movb %dh, (%edi) + /* + * update CONFIG REGISTER + */ + xorb %dh,%dh + movw $0x00f,%bx + movw %cx,%ax + shlw $2,%ax + xchgw %cx,%ax + shlw %cl,%dx + shlw %cl,%bx + notw %bx + xchgw %cx,%ax + movl $DRCCFG, %edi + mov (%edi), %ax + andw %bx,%ax + orw %dx,%ax + movw %ax, (%edi) + jcxz cleanup + + decw %cx + movl %ecx,%ebx + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movb $0xff,%al + addl %ebx, %edi + movb %al, (%edi) + /* + * set control register to NORMAL mode + */ + movl $DRCCTL, %esi /* setup DRAM control register with */ + movb $0x0,%al /* Normal mode value */ + movb %al, (%esi) + movl $CACHELINESZ, %esi /* address to init read buffer */ + movw %ax, (%esi) + jmp nextbank + +cleanup: + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movw $4,%cx + xorw %ax,%ax +cleanuplp: + movb (%edi), %al + orb %al,%al + jz emptybank + + addb %ah,%al + jns nottoomuch + + movb $0x7f,%al +nottoomuch: + movb %al,%ah + orb $0x80,%al + movb %al, (%edi) +emptybank: + incl %edi + loop cleanuplp + +#if defined(CFG_SDRAM_CAS_LATENCY_2T) || defined(CFG_SDRAM_CAS_LATENCY_3T) + /* set the CAS latency now since it is hard to do + * when we run from the RAM */ + movl $DRCTMCTL, %edi /* DRAM timing register */ + movb (%edi), %al +#ifdef CFG_SDRAM_CAS_LATENCY_2T + andb $0xef, %al +#endif +#ifdef CFG_SDRAM_CAS_LATENCY_3T + orb $0x10, %al +#endif + movb %al, (%edi) +#endif + movl $DRCCTL, %edi /* DRAM Control register */ + movb $0x3,%al /* Load mode register cmd */ + movb %al, (%edi) + movw %ax, (%esi) + + + movl $DRCCTL, %edi /* DRAM Control register */ + movb $0x18,%al /* Enable refresh and NORMAL mode */ + movb %al, (%edi) + + jmp dram_done + +bad_ram: + xorl %edx,%edx + xorl %edi,%edi + jmp bad_reint + +dram_done: + + /* readback DRCBENDADR and return the number + * of available ram bytes in %eax */ + + movl $DRCBENDADR, %edi /* DRAM ending address register */ + + movl (%edi), %eax + movl %eax, %ecx + andl $0x80000000, %ecx + jz bank2 + andl $0x7f000000, %eax + shrl $2, %eax + movl %eax, %ebx + +bank2: movl (%edi), %eax + movl %eax, %ecx + andl $0x00800000, %ecx + jz bank1 + andl $0x007f0000, %eax + shll $6, %eax + movl %eax, %ebx + +bank1: movl (%edi), %eax + movl %eax, %ecx + andl $0x00008000, %ecx + jz bank0 + andl $0x00007f00, %eax + shll $14, %eax + movl %eax, %ebx + +bank0: movl (%edi), %eax + movl %eax, %ecx + andl $0x00000080, %ecx + jz done + andl $0x0000007f, %eax + shll $22, %eax + movl %eax, %ebx + +done: movl %ebx, %eax + + jmp *%ebp + + +#endif /* CONFIG_SC520 */ diff --git a/cpu/i386/serial.c b/cpu/i386/serial.c index c0d2e8a..22c3c2a 100644 --- a/cpu/i386/serial.c +++ b/cpu/i386/serial.c @@ -24,6 +24,7 @@ * MA 02111-1307 USA */ /*------------------------------------------------------------------------------+ */ + /* * This source code has been made available to you by IBM on an AS-IS * basis. Anyone receiving this source is licensed under IBM @@ -89,13 +90,15 @@ typedef struct { char *rx_buffer; ulong rx_put; ulong rx_get; + int cts; } serial_buffer_t; -volatile static serial_buffer_t buf_info; +volatile serial_buffer_t buf_info; +static int serial_buffer_active=0; #endif -static int serial_div (int baudrate ) +static int serial_div(int baudrate) { switch (baudrate) { @@ -112,7 +115,8 @@ static int serial_div (int baudrate ) case 115200: return 1; } - hang (); + + return 12; } @@ -121,7 +125,7 @@ static int serial_div (int baudrate ) * as serial console interface. */ -int serial_init (void) +int serial_init(void) { DECLARE_GLOBAL_DATA_PTR; @@ -134,24 +138,24 @@ int serial_init (void) outb(bdiv, UART0_BASE + UART_DLL); /* set baudrate divisor */ outb(bdiv >> 8, UART0_BASE + UART_DLM);/* set baudrate divisor */ outb(0x03, UART0_BASE + UART_LCR); /* clear DLAB; set 8 bits, no parity */ - outb(0x00, UART0_BASE + UART_FCR); /* disable FIFO */ - outb(0x00, UART0_BASE + UART_MCR); /* no modem control DTR RTS */ + outb(0x01, UART0_BASE + UART_FCR); /* enable FIFO */ + outb(0x0b, UART0_BASE + UART_MCR); /* Set DTR and RTS active */ val = inb(UART0_BASE + UART_LSR); /* clear line status */ val = inb(UART0_BASE + UART_RBR); /* read receive buffer */ outb(0x00, UART0_BASE + UART_SCR); /* set scratchpad */ outb(0x00, UART0_BASE + UART_IER); /* set interrupt enable reg */ - return (0); + return 0; } -void serial_setbrg (void) +void serial_setbrg(void) { DECLARE_GLOBAL_DATA_PTR; unsigned short bdiv; - bdiv = serial_div (gd->baudrate); + bdiv = serial_div(gd->baudrate); outb(0x80, UART0_BASE + UART_LCR); /* set DLAB bit */ outb(bdiv&0xff, UART0_BASE + UART_DLL); /* set baudrate divisor */ @@ -160,7 +164,7 @@ void serial_setbrg (void) } -void serial_putc (const char c) +void serial_putc(const char c) { int i; @@ -169,31 +173,38 @@ void serial_putc (const char c) /* check THRE bit, wait for transmiter available */ for (i = 1; i < 3500; i++) { - if ((inb (UART0_BASE + UART_LSR) & 0x20) == 0x20) + if ((inb (UART0_BASE + UART_LSR) & 0x20) == 0x20) { break; - udelay (100); + } + udelay(100); } outb(c, UART0_BASE + UART_THR); /* put character out */ } -void serial_puts (const char *s) +void serial_puts(const char *s) { while (*s) { - serial_putc (*s++); + serial_putc(*s++); } } -int serial_getc () +int serial_getc(void) { unsigned char status = 0; +#if CONFIG_SERIAL_SOFTWARE_FIFO + if (serial_buffer_active) { + return serial_buffered_getc(); + } +#endif + while (1) { #if defined(CONFIG_HW_WATCHDOG) - WATCHDOG_RESET (); /* Reset HW Watchdog, if needed */ + WATCHDOG_RESET(); /* Reset HW Watchdog, if needed */ #endif /* CONFIG_HW_WATCHDOG */ - status = inb (UART0_BASE + UART_LSR); + status = inb(UART0_BASE + UART_LSR); if ((status & asyncLSRDataReady1) != 0x0) { break; } @@ -211,11 +222,17 @@ int serial_getc () } -int serial_tstc () +int serial_tstc(void) { unsigned char status; - status = inb (UART0_BASE + UART_LSR); +#if CONFIG_SERIAL_SOFTWARE_FIFO + if (serial_buffer_active) { + return serial_buffered_tstc(); + } +#endif + + status = inb(UART0_BASE + UART_LSR); if ((status & asyncLSRDataReady1) != 0x0) { return (1); } @@ -234,36 +251,50 @@ int serial_tstc () #if CONFIG_SERIAL_SOFTWARE_FIFO -void serial_isr (void *arg) +void serial_isr(void *arg) { int space; int c; - const int rx_get = buf_info.rx_get; int rx_put = buf_info.rx_put; - if (rx_get <= rx_put) { - space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - rx_get); + if (buf_info.rx_get <= rx_put) { + space = CONFIG_SERIAL_SOFTWARE_FIFO - (rx_put - buf_info.rx_get); } else { - space = rx_get - rx_put; + space = buf_info.rx_get - rx_put; } - while (serial_tstc ()) { - c = serial_getc (); + + while (inb(UART0_BASE + UART_LSR) & 1) { + c = inb(UART0_BASE); if (space) { buf_info.rx_buffer[rx_put++] = c; space--; + + if (rx_put == buf_info.rx_get) { + buf_info.rx_get++; + if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO) { + buf_info.rx_get = 0; + } + } + + if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO) { + rx_put = 0; + if (0 == buf_info.rx_get) { + buf_info.rx_get = 1; + } + + } + } - if (rx_put == CONFIG_SERIAL_SOFTWARE_FIFO) - rx_put = 0; if (space < CONFIG_SERIAL_SOFTWARE_FIFO / 4) { /* Stop flow by setting RTS inactive */ - outb(inb (UART0_BASE + UART_MCR) & (0xFF ^ 0x02), + outb(inb(UART0_BASE + UART_MCR) & (0xFF ^ 0x02), UART0_BASE + UART_MCR); } } buf_info.rx_put = rx_put; } -void serial_buffered_init (void) +void serial_buffered_init(void) { serial_puts ("Switching to interrupt driven serial input mode.\n"); buf_info.rx_buffer = malloc (CONFIG_SERIAL_SOFTWARE_FIFO); @@ -272,8 +303,10 @@ void serial_buffered_init (void) if (inb (UART0_BASE + UART_MSR) & 0x10) { serial_puts ("Check CTS signal present on serial port: OK.\n"); + buf_info.cts = 1; } else { serial_puts ("WARNING: CTS signal not present on serial port.\n"); + buf_info.cts = 0; } irq_install_handler ( VECNUM_U0 /*UART0 *//*int vec */ , @@ -283,32 +316,49 @@ void serial_buffered_init (void) /* Enable "RX Data Available" Interrupt on UART */ /* outb(inb(UART0_BASE + UART_IER) |0x01, UART0_BASE + UART_IER); */ outb(0x01, UART0_BASE + UART_IER); - /* Set DTR active */ - outb(inb (UART0_BASE + UART_MCR) | 0x01, UART0_BASE + UART_MCR); - /* Start flow by setting RTS active */ - outb(inb (UART0_BASE + UART_MCR) | 0x02, UART0_BASE + UART_MCR); - /* Setup UART FIFO: RX trigger level: 4 byte, Enable FIFO */ - outb((1 << 6) | 1, UART0_BASE + UART_FCR); + + /* Set DTR and RTS active, enable interrupts */ + outb(inb (UART0_BASE + UART_MCR) | 0x0b, UART0_BASE + UART_MCR); + + /* Setup UART FIFO: RX trigger level: 1 byte, Enable FIFO */ + outb( /*(1 << 6) |*/ 1, UART0_BASE + UART_FCR); + + serial_buffer_active = 1; } void serial_buffered_putc (const char c) { + int i; /* Wait for CTS */ #if defined(CONFIG_HW_WATCHDOG) while (!(inb (UART0_BASE + UART_MSR) & 0x10)) WATCHDOG_RESET (); #else - while (!(inb (UART0_BASE + UART_MSR) & 0x10)); + if (buf_info.cts) { + for (i=0;i<1000;i++) { + if ((inb (UART0_BASE + UART_MSR) & 0x10)) { + break; + } + } + if (i!=1000) { + buf_info.cts = 0; + } + } else { + if ((inb (UART0_BASE + UART_MSR) & 0x10)) { + buf_info.cts = 1; + } + } + #endif serial_putc (c); } -void serial_buffered_puts (const char *s) +void serial_buffered_puts(const char *s) { serial_puts (s); } -int serial_buffered_getc (void) +int serial_buffered_getc(void) { int space; int c; @@ -322,8 +372,9 @@ int serial_buffered_getc (void) while (rx_get == buf_info.rx_put); #endif c = buf_info.rx_buffer[rx_get++]; - if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO) + if (rx_get == CONFIG_SERIAL_SOFTWARE_FIFO) { rx_get = 0; + } buf_info.rx_get = rx_get; rx_put = buf_info.rx_put; @@ -340,7 +391,7 @@ int serial_buffered_getc (void) return c; } -int serial_buffered_tstc (void) +int serial_buffered_tstc(void) { return (buf_info.rx_get != buf_info.rx_put) ? 1 : 0; } @@ -358,7 +409,7 @@ int serial_buffered_tstc (void) configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE */ #if (CONFIG_KGDB_SER_INDEX & 2) -void kgdb_serial_init (void) +void kgdb_serial_init(void) { DECLARE_GLOBAL_DATA_PTR; @@ -381,7 +432,7 @@ void kgdb_serial_init (void) } -void putDebugChar (const char c) +void putDebugChar(const char c) { if (c == '\n') serial_putc ('\r'); @@ -393,7 +444,7 @@ void putDebugChar (const char c) } -void putDebugStr (const char *s) +void putDebugStr(const char *s) { while (*s) { serial_putc(*s++); @@ -401,7 +452,7 @@ void putDebugStr (const char *s) } -int getDebugChar (void) +int getDebugChar(void) { unsigned char status = 0; @@ -424,34 +475,34 @@ int getDebugChar (void) } -void kgdb_interruptible (int yes) +void kgdb_interruptible(int yes) { return; } #else /* ! (CONFIG_KGDB_SER_INDEX & 2) */ -void kgdb_serial_init (void) +void kgdb_serial_init(void) { serial_printf ("[on serial] "); } -void putDebugChar (int c) +void putDebugChar(int c) { serial_putc (c); } -void putDebugStr (const char *str) +void putDebugStr(const char *str) { serial_puts (str); } -int getDebugChar (void) +int getDebugChar(void) { return serial_getc (); } -void kgdb_interruptible (int yes) +void kgdb_interruptible(int yes) { return; } diff --git a/cpu/i386/start16.S b/cpu/i386/start16.S index 590a5a6..a34642f 100644 --- a/cpu/i386/start16.S +++ b/cpu/i386/start16.S @@ -1,7 +1,7 @@ /* * U-boot - i386 Startup Code * - * Copyright (c) 2002 Omicron Ceti AB, Daniel Engström <denaiel@omicron.se> + * Copyright (c) 2002, 2003 Omicron Ceti AB, Daniel Engström <denaiel@omicron.se> * * See file CREDITS for list of people who contributed to this * project. @@ -40,7 +40,7 @@ board_init16_ret: /* Turn of cache (this might require a 486-class CPU) */ movl %cr0, %eax - orl $060000000,%eax + orl $0x60000000,%eax movl %eax, %cr0 wbinvd |