238 lines
7.4 KiB
C
238 lines
7.4 KiB
C
|
|
#include <linux/pci_ids.h>
|
|
|
|
#include <asm/e2k_api.h>
|
|
#include <asm/e2k.h>
|
|
#include <asm/bootinfo.h>
|
|
|
|
#include "bios/pci.h"
|
|
#include "bios/bios.h"
|
|
#include "bios/southbridge.h"
|
|
#include "Am85C30.h"
|
|
|
|
#undef DEBUG_CONSOLE_MODE
|
|
#undef DebugC
|
|
#define DEBUG_CONSOLE_MODE 0 /* Console initialization */
|
|
#define DebugC if (DEBUG_CONSOLE_MODE) printk
|
|
|
|
#define PCI_DEVICE_ID_PAR_SER 0x8000
|
|
|
|
#ifdef CONFIG_EIOH
|
|
#define PCI_DEV_ID_SERIAL PCI_DEVICE_ID_MCST_SERIAL
|
|
#define SERIAL_BAR 0
|
|
#else
|
|
#define PCI_DEV_ID_SERIAL PCI_DEVICE_ID_MCST_PARALLEL_SERIAL
|
|
#define SERIAL_BAR 1
|
|
#endif
|
|
|
|
unsigned long com_port;
|
|
|
|
unsigned long ch_a_control;
|
|
unsigned long ch_a_data;
|
|
unsigned long ch_b_control;
|
|
unsigned long ch_b_data;
|
|
|
|
#define NOT_BIOS 0
|
|
|
|
extern boot_info_t *boot_info;
|
|
|
|
static void com_outb(u64 port, u8 byte)
|
|
{
|
|
NATIVE_WRITE_MAS_B(port, byte, MAS_IOADDR);
|
|
}
|
|
|
|
static u8 com_inb(u64 port)
|
|
{
|
|
return NATIVE_READ_MAS_B(port, MAS_IOADDR);
|
|
}
|
|
|
|
static u8 com_inb_command(u64 port, u8 reg_num)
|
|
{
|
|
NATIVE_WRITE_MAS_B(port, reg_num, MAS_IOADDR);
|
|
return NATIVE_READ_MAS_B(port, MAS_IOADDR);
|
|
}
|
|
|
|
static void com_outb_command(u64 port, u8 reg_num, u8 val)
|
|
{
|
|
NATIVE_WRITE_MAS_B(port, reg_num, MAS_IOADDR);
|
|
NATIVE_WRITE_MAS_B(port, val, MAS_IOADDR);
|
|
}
|
|
|
|
void
|
|
serial_putc(unsigned long com_port, unsigned char c)
|
|
{
|
|
while ((com_inb_command(com_port, RR0) & D2) == 0){
|
|
}
|
|
com_outb((com_port + 0x01), c);
|
|
}
|
|
|
|
unsigned char
|
|
serial_getc(unsigned long com_port)
|
|
{
|
|
while (((com_inb_command(com_port, RR0)) & D0) == 0){
|
|
}
|
|
return com_inb(com_port + 0x01);
|
|
}
|
|
|
|
unsigned short zilog_serial_init(void)
|
|
{
|
|
struct bios_pci_dev *dev;
|
|
unsigned char val = 0;
|
|
|
|
rom_printk("Scanning PCI bus for ieee1284/rs232 device ...\n");
|
|
dev = bios_pci_find_device(INTEL_MULTIFUNC_VENDOR,
|
|
PCI_DEVICE_ID_PAR_SER, NULL);
|
|
if (dev == NULL) {
|
|
dev = bios_pci_find_device(PCI_VENDOR_ID_MCST_TMP,
|
|
PCI_DEV_ID_SERIAL, dev);
|
|
}
|
|
if (dev){
|
|
ch_a_control = (dev->base_address[SERIAL_BAR] & ~0x01);
|
|
ch_a_data = (dev->base_address[SERIAL_BAR] & ~0x01) + 0x01;
|
|
ch_b_control = (dev->base_address[SERIAL_BAR] & ~0x01) + 0x02;
|
|
ch_b_data = (dev->base_address[SERIAL_BAR] & ~0x01) + 0x03;
|
|
DebugC("zilog_serial_init: ch_a_control = 0x%x, ch_a_data = 0x%x\n"
|
|
" ch_b_control = 0x%x, ch_b_data = 0x%x\n",
|
|
(unsigned int)ch_a_control, (unsigned int)ch_a_data,
|
|
(unsigned int)ch_b_control, (unsigned int)ch_b_data);
|
|
com_port = ch_a_control;
|
|
/* Hardware Reset */
|
|
val = (val | D7 | D6); /* Force Hardware Reset */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR9 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR9, val);
|
|
/* It seems not neccesary due to WR9 sharing for both channels */
|
|
com_outb_command(ch_b_control, WR9, val);
|
|
#if NOT_BIOS
|
|
/* Enabling interrupts */
|
|
val = 0; val |= D3; /* Master Interrupt Enable */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR9 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR9, val);
|
|
/* It seems not neccesary due to WR9 sharing for both channels */
|
|
com_outb_command(ch_b_control, WR9, val);
|
|
#else
|
|
/* Interrupts disabled */
|
|
#endif
|
|
#if NOT_BIOS
|
|
/* Detailed interrupt installations */
|
|
val = 0;
|
|
val |= D1; /* Transmit interrupt enabling. An interrupt will be
|
|
* generated each time a packet is transmitted */
|
|
val |= D2; /* The parity error for recieved packet is Special
|
|
* Condition from now */
|
|
val |= D4; /* Enabling interrupt for each packet recieving and when
|
|
* Special Condition occurs */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR1 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR1, val);
|
|
com_outb_command(ch_b_control, WR1, val);
|
|
#else
|
|
/* poll mode */
|
|
val = 0;
|
|
DebugC("zilog_serial_init: Hardware Reset: WR1 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR1, val);
|
|
com_outb_command(ch_b_control, WR1, val);
|
|
#endif
|
|
/* Operation mode */
|
|
val = 0;
|
|
#if NOT_BIOS
|
|
val |= D0; /* Parity Enable */
|
|
/* Parity bit is present */
|
|
val |= (D2 | D3); /* Setup stop bits, if any setuped the mode is asynchronus */
|
|
/* 2 stop bits */
|
|
#else
|
|
val |= D2; /* stop bit = 1 */
|
|
#endif
|
|
val |= D6; /* x16 mode */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR4 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR4, val);
|
|
com_outb_command(ch_b_control, WR4, val);
|
|
/* xN Mode Enable */
|
|
val = 0;
|
|
val |= D7; /* xN Mode Enable */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR7 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR7, val);
|
|
com_outb_command(ch_b_control, WR7, val);
|
|
/* setup xN constant */
|
|
val = 0;
|
|
val |= (D0 | D2 | D4); /* 15_h = 21_d; xN = 0.5 * 21 = 10.5 */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR6 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR6, val);
|
|
com_outb_command(ch_b_control, WR6, val);
|
|
/* Bits per symbol to recieve */
|
|
val = 0;
|
|
val |= (D7 | D6); /* 8 bits per symbol */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR3 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR3, val);
|
|
com_outb_command(ch_b_control, WR3, val);
|
|
/* Bits per symbol to transmit */
|
|
val = 0;
|
|
val |= (D6 | D5); /* 8 bits per symbol */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR5 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR5, val);
|
|
com_outb_command(ch_b_control, WR5, val);
|
|
/* Encoding setup */
|
|
val = 0;
|
|
#if NOT_BIOS
|
|
val |= D5; /* NRZI encoding */
|
|
#else
|
|
/* NRZ encoding */
|
|
#endif
|
|
DebugC("zilog_serial_init: Hardware Reset: WR10 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR10, val);
|
|
com_outb_command(ch_b_control, WR10, val);
|
|
/* Clock setup */
|
|
val = 0;
|
|
val |= (D4 | D6); /* Transmit Clock = BRG output;
|
|
* Receive Clock = BRG output */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR11 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR11, val);
|
|
com_outb_command(ch_b_control, WR11, val);
|
|
/* Lower Byte of Time Constant */
|
|
val = 0;
|
|
val |= (D4 | D3 | D2 | D1); /* = 1e_h (4800) */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR12 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR12, val);
|
|
com_outb_command(ch_b_control, WR12, val);
|
|
/* Upper Byte of Time Constant */
|
|
val = 0; /* determine 115200 baud rate when pclk = 4.9152 MHz */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR13 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR13, val);
|
|
com_outb_command(ch_b_control, WR13, val);
|
|
/* Determine synchronization source for BGR */
|
|
val = 0; /* the source is RTxC pin */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR14 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR14, val);
|
|
com_outb_command(ch_b_control, WR14, val);
|
|
/* switch on the reciver */
|
|
val = 0;
|
|
val |= D0; /* turn on */
|
|
val |= (D7 | D6); /* 8 bits per symbol */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR3 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR3, val);
|
|
com_outb_command(ch_b_control, WR3, val);
|
|
/* switch on the transmitter */
|
|
val = 0;
|
|
val |= D3; /* turn on */
|
|
val |= (D6 | D5); /* 8 bits per symbol */
|
|
DebugC("zilog_serial_init: Hardware Reset: WR5 val = 0x%x\n", val);
|
|
com_outb_command(ch_a_control, WR5, val);
|
|
com_outb_command(ch_b_control, WR5, val);
|
|
com_port = ch_a_control;
|
|
rom_printk("Initialization compleete ");
|
|
if (boot_info) {
|
|
boot_info->serial_base = com_port;
|
|
rom_printk("AM85C30 Serial console enabled at "
|
|
"0x%X base\n", com_port);
|
|
} else {
|
|
rom_printk("Unable to init boot_info BUG!!!\n");
|
|
}
|
|
hardware.serial = 1;
|
|
} else {
|
|
rom_printk("!!! NOT FOUND !!!\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|