From: Ben Gras Date: Wed, 19 May 2010 10:00:02 +0000 (+0000) Subject: kernel: oxpcie serial card support. X-Git-Tag: v3.1.7~49 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=9ba760e603eb56aca64d8d9680c68a45e055ba94;p=minix.git kernel: oxpcie serial card support. ask to map in oxpcie i/o memory and support serial i/o for it in the kernel. set oxpcie=
in boot monitor (retrieve address using pci_debug=1 output). (no sanity checking is done on the address currently.) disabled by default. The change also contains some other minor cleanup (a new serial.h to set register info common to UART and the OXPCIe card, in-kernel memory mapping a little more structured and env_get() to get sysenv variables without knowing about the params_buffer). --- diff --git a/kernel/arch/i386/Makefile.inc b/kernel/arch/i386/Makefile.inc index 5f4a96aa0..e40cde29f 100644 --- a/kernel/arch/i386/Makefile.inc +++ b/kernel/arch/i386/Makefile.inc @@ -14,6 +14,7 @@ SRCS+= arch_do_vmctl.c \ i8259.c \ klib.S \ memory.c \ + oxpcie.c \ protect.c \ arch_system.c \ apic.c \ diff --git a/kernel/arch/i386/arch_system.c b/kernel/arch/i386/arch_system.c index 1b9e45ef9..ac74007f7 100644 --- a/kernel/arch/i386/arch_system.c +++ b/kernel/arch/i386/arch_system.c @@ -14,6 +14,8 @@ #include "archconst.h" #include "proto.h" +#include "serial.h" +#include "oxpcie.h" #include "kernel/proc.h" #include "kernel/debug.h" @@ -220,18 +222,15 @@ PUBLIC void arch_init(void) fpu_init(); } -#define COM1_BASE 0x3F8 -#define COM1_THR (COM1_BASE + 0) -#define COM1_RBR (COM1_BASE + 0) -#define COM1_LSR (COM1_BASE + 5) -#define LSR_DR 0x01 -#define LSR_THRE 0x20 - PUBLIC void ser_putc(char c) { int i; int lsr, thr; +#if CONFIG_OXPCIE + oxpcie_putc(c); +#endif + lsr= COM1_LSR; thr= COM1_THR; for (i= 0; i<100000; i++) @@ -249,6 +248,14 @@ PUBLIC void do_ser_debug() { u8_t c, lsr; +#if CONFIG_OXPCIE + { + int oxin; + if((oxin = oxpcie_in()) >= 0) + ser_debug(oxin); + } +#endif + lsr= inb(COM1_LSR); if (!(lsr & LSR_DR)) return; diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index b4c6111ad..e3bc551be 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -12,9 +12,11 @@ #include #include #include +#include #include +#include "oxpcie.h" #include "proto.h" #include "kernel/proto.h" #include "kernel/debug.h" @@ -935,32 +937,70 @@ void i386_freepde(const int pde) freepdes[nfreepdes++] = pde; } +PRIVATE int lapic_mapping_index = -1, oxpcie_mapping_index = -1; + PUBLIC int arch_phys_map(const int index, phys_bytes *addr, phys_bytes *len, int *flags) { + static int first = 1; + int freeidx = 0; + static char *ser_var = NULL; + + if(first) { +#ifdef CONFIG_APIC + if(lapic_addr) + lapic_mapping_index = freeidx++; +#endif + +#ifdef CONFIG_OXPCIE + if((ser_var = env_get("oxpcie"))) { + if(ser_var[0] != '0' || ser_var[1] != 'x') { + printf("oxpcie address in hex please\n"); + } else { + oxpcie_mapping_index = freeidx++; + } + } +#endif + first = 0; + } + #ifdef CONFIG_APIC /* map the local APIC if enabled */ - if (index == 0 && lapic_addr) { + if (index == lapic_mapping_index) { *addr = vir2phys(lapic_addr); *len = 4 << 10 /* 4kB */; *flags = VMMF_UNCACHED; return OK; } - return EINVAL; -#else - /* we don't want anything */ - return EINVAL; #endif + +#if CONFIG_OXPCIE + if(index == oxpcie_mapping_index) { + *addr = strtoul(ser_var+2, NULL, 16); + *len = 0x4000; + *flags = VMMF_UNCACHED; + return OK; + } +#endif + + return EINVAL; } PUBLIC int arch_phys_map_reply(const int index, const vir_bytes addr) { #ifdef CONFIG_APIC /* if local APIC is enabled */ - if (index == 0 && lapic_addr) { + if (index == lapic_mapping_index && lapic_addr) { lapic_addr_vaddr = addr; } #endif + +#if CONFIG_OXPCIE + if (index == oxpcie_mapping_index) { + oxpcie_set_vaddr((unsigned char *) addr); + } +#endif + return OK; } diff --git a/kernel/arch/i386/oxpcie.c b/kernel/arch/i386/oxpcie.c new file mode 100644 index 000000000..67c8cd062 --- /dev/null +++ b/kernel/arch/i386/oxpcie.c @@ -0,0 +1,83 @@ + +#include "kernel/kernel.h" + +#if CONFIG_OXPCIE + +/* Documentation is at http://www.plxtech.com/products/uart/oxpcie952 */ + +#include "oxpcie.h" +#include "serial.h" + +PRIVATE unsigned char *oxpcie_vaddr = NULL; + +PUBLIC void oxpcie_set_vaddr(unsigned char *vaddr) +{ + oxpcie_vaddr = vaddr; +} + +PRIVATE void oxpcie_init(void) +{ + printf("oxpcie_init\n"); + /* Enable access to EFR and DLM+DLL */ + OXPCIE_LCR = 0xBF; + + /* Set FICR[1] to increase FIFO */ + OXPCIE_FICR = 0x01; + + /* Set enhanced mode [4] + * no RTS/CTS [7:6] + * no special char detection [5] + * no in-band receive flow control [1:0] + * no in-band transmit flow control [3:2] + */ + OXPCIE_EFR = 0x10; + + /* Set divisor register to 115200 baud. */ + OXPCIE_DLM = 0x00; + OXPCIE_DLL = 0x22; + + /* Forget DLM and DLL, set LCR to config. */ + OXPCIE_LCR = LCR_CONFIG; + OXPCIE_LCR = LCR_CONFIG; + + OXPCIE_TCR = 0x01; + OXPCIE_CPR = 0x20; + OXPCIE_CPR2 = 0; +} + +PUBLIC void oxpcie_putc(char c) +{ + static int inuse = 0; + + if(vm_running && oxpcie_vaddr && !inuse) { + int i; + static int init_done; + inuse = 1; + + if(!init_done) { + oxpcie_init(); + init_done = 1; + } + + for (i= 0; i<100000; i++) { + if(OXPCIE_LSR & LSR_THRE) + break; + } + OXPCIE_THR = c; + inuse = 0; + } +} + +PUBLIC int oxpcie_in(void) +{ + if(vm_running && oxpcie_vaddr) { + int lsr; + lsr = OXPCIE_LSR; + if(lsr & LSR_DR) + return (int) OXPCIE_RBR; + } + + return -1; +} + +#endif diff --git a/kernel/arch/i386/oxpcie.h b/kernel/arch/i386/oxpcie.h new file mode 100644 index 000000000..7ac39b390 --- /dev/null +++ b/kernel/arch/i386/oxpcie.h @@ -0,0 +1,31 @@ + +_PROTOTYPE( void oxpcie_set_vaddr, (unsigned char *vaddr)); +_PROTOTYPE( void oxpcie_putc, (char c)); +_PROTOTYPE( int oxpcie_in, (void)); + +#include "serial.h" + +/* OXPCIe952 info */ +#define UART1BASE_550 0x1000 +#define UART1BASE_650 0x1090 +#define UART1BASE_950 +#define BASELINEICR (UART1BASE_550 + 0xC0) +#define OXPCIE_THR oxpcie_vaddr[UART1BASE_550 + THRREG] +#define OXPCIE_RBR oxpcie_vaddr[UART1BASE_550 + RBRREG] +#define OXPCIE_LSR oxpcie_vaddr[UART1BASE_550 + LSRREG] +#define OXPCIE_LCR oxpcie_vaddr[UART1BASE_550 + LCRREG] +#define OXPCIE_DLL oxpcie_vaddr[UART1BASE_550 + 0x00] +#define OXPCIE_DLM oxpcie_vaddr[UART1BASE_550 + 0x01] +#define OXPCIE_FICR oxpcie_vaddr[UART1BASE_550 + FICRREG] +#define OXPCIE_SPR oxpcie_vaddr[UART1BASE_550 + SPRREG] +#define OXPCIE_EFR oxpcie_vaddr[UART1BASE_650 + 0x10] +#define OXPCIE_ICR oxpcie_vaddr[UART1BASE_950 + 0x05] + +#define OXPCIE_CPR oxpcie_vaddr[BASELINEICR + 0x01] +#define OXPCIE_TCR oxpcie_vaddr[BASELINEICR + 0x02] +#define OXPCIE_CPR2 oxpcie_vaddr[BASELINEICR + 0x03] +#define OXPCIE_CSR oxpcie_vaddr[BASELINEICR + 0x0C] +#define OXPCIE_PIDX oxpcie_vaddr[BASELINEICR + 0x12] + +#define LCR_CONFIG 0x03 /* bits 6:0 -= 0x03 => 8N1, no break. */ + diff --git a/kernel/arch/i386/serial.h b/kernel/arch/i386/serial.h new file mode 100644 index 000000000..230fd8519 --- /dev/null +++ b/kernel/arch/i386/serial.h @@ -0,0 +1,20 @@ + +#ifndef _KERN_SERIAL_H +#define _KERN_SERIAL_H 1 + +#define THRREG 0 +#define RBRREG 0 +#define FICRREG 2 +#define LSRREG 5 +#define LCRREG 3 +#define SPRREG 7 + +#define COM1_BASE 0x3F8 +#define COM1_THR (COM1_BASE + THRREG) +#define COM1_RBR (COM1_BASE + RBRREG) +#define COM1_LSR (COM1_BASE + LSRREG) +#define LSR_DR 0x01 +#define LSR_THRE 0x20 +#define LCR_DLA 0x80 + +#endif diff --git a/kernel/kernel.h b/kernel/kernel.h index b1ccf6097..6652a27c7 100644 --- a/kernel/kernel.h +++ b/kernel/kernel.h @@ -14,6 +14,9 @@ #define CONFIG_MAX_CPUS 1 #define cpuid 0 +/* OXPCIe952 PCIe with 2 UARTs in-kernel support */ +#define CONFIG_OXPCIE 0 + /* This is the master header for the kernel. It includes some other files * and defines the principal constants. */ diff --git a/kernel/proto.h b/kernel/proto.h index 0aa7e677d..38db7fbbc 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -55,6 +55,7 @@ _PROTOTYPE( void check_ticks_left, (struct proc *p)); /* start.c */ _PROTOTYPE( void cstart, (u16_t cs, u16_t ds, u16_t mds, u16_t parmoff, u16_t parmsize) ); +_PROTOTYPE( char *env_get, (const char *key)); /* system.c */ _PROTOTYPE( int get_priv, (register struct proc *rc, int proc_type) ); diff --git a/kernel/start.c b/kernel/start.c index 68abd3121..3b4786309 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -11,7 +11,6 @@ #include "watchdog.h" #endif -FORWARD _PROTOTYPE( char *get_value, (const char *params, const char *key)); /*===========================================================================* * cstart * *===========================================================================*/ @@ -43,7 +42,7 @@ PUBLIC void cstart( arch_get_params(params_buffer, sizeof(params_buffer)); /* determine verbosity */ - if ((value = get_value(params_buffer, VERBOSEBOOTVARNAME))) + if ((value = env_get(VERBOSEBOOTVARNAME))) verboseboot = atoi(value); DEBUGEXTRA(("cstart\n")); @@ -63,10 +62,10 @@ PUBLIC void cstart( kloadinfo.proc_load_history[h] = 0; /* Processor? Decide if mode is protected for older machines. */ - machine.processor=atoi(get_value(params_buffer, "processor")); + machine.processor=atoi(env_get("processor")); /* XT, AT or MCA bus? */ - value = get_value(params_buffer, "bus"); + value = env_get("bus"); if (value == NULL || strcmp(value, "at") == 0) { machine.pc_at = TRUE; /* PC-AT compatible hardware */ } else if (strcmp(value, "mca") == 0) { @@ -74,22 +73,22 @@ PUBLIC void cstart( } /* Type of VDU: */ - value = get_value(params_buffer, "video"); /* EGA or VGA video unit */ + value = env_get("video"); /* EGA or VGA video unit */ if (strcmp(value, "ega") == 0) machine.vdu_ega = TRUE; if (strcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE; /* Get clock tick frequency. */ - value = get_value(params_buffer, "hz"); + value = env_get("hz"); if(value) system_hz = atoi(value); if(!value || system_hz < 2 || system_hz > 50000) /* sanity check */ system_hz = DEFAULT_HZ; - value = get_value(params_buffer, SERVARNAME); + value = env_get(SERVARNAME); if(value && atoi(value) == 0) do_serial_debug=1; #ifdef CONFIG_APIC - value = get_value(params_buffer, "no_apic"); + value = env_get("no_apic"); if(value) config_no_apic = atoi(value); else @@ -97,7 +96,7 @@ PUBLIC void cstart( #endif #ifdef CONFIG_WATCHDOG - value = get_value(params_buffer, "watchdog"); + value = env_get("watchdog"); if (value) watchdog_enabled = atoi(value); #endif @@ -134,3 +133,12 @@ PRIVATE char *get_value( } return(NULL); } + +/*===========================================================================* + * env_get * + *===========================================================================*/ +PUBLIC char *env_get(const char *name) +{ + return get_value(params_buffer, name); +} +