]> Zhao Yanbai Git Server - minix.git/commitdiff
kernel: oxpcie serial card support.
authorBen Gras <ben@minix3.org>
Wed, 19 May 2010 10:00:02 +0000 (10:00 +0000)
committerBen Gras <ben@minix3.org>
Wed, 19 May 2010 10:00:02 +0000 (10:00 +0000)
ask to map in oxpcie i/o memory and support serial i/o for it in the
kernel. set oxpcie=<address> 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).

kernel/arch/i386/Makefile.inc
kernel/arch/i386/arch_system.c
kernel/arch/i386/memory.c
kernel/arch/i386/oxpcie.c [new file with mode: 0644]
kernel/arch/i386/oxpcie.h [new file with mode: 0644]
kernel/arch/i386/serial.h [new file with mode: 0644]
kernel/kernel.h
kernel/proto.h
kernel/start.c

index 5f4a96aa07262f7dda9fcda6b6b9960caf6936cc..e40cde29f82a243dad0475d4e06e9b1de2f9979d 100644 (file)
@@ -14,6 +14,7 @@ SRCS+=        arch_do_vmctl.c \
        i8259.c \
        klib.S \
        memory.c \
+       oxpcie.c \
        protect.c \
        arch_system.c \
        apic.c \
index 1b9e45ef96745889ab33bc72e206779e2e25de91..ac74007f7a90572bdab37be75ff2f01157d8d5a0 100644 (file)
@@ -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;
index b4c6111ad6bb454aef93bd486a18e46c0bd56b27..e3bc551beee5750fadcd3809d6664d4ab739e4ab 100644 (file)
 #include <string.h>
 #include <assert.h>
 #include <signal.h>
+#include <stdlib.h>
 
 #include <machine/vm.h>
 
+#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 (file)
index 0000000..67c8cd0
--- /dev/null
@@ -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 (file)
index 0000000..7ac39b3
--- /dev/null
@@ -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 (file)
index 0000000..230fd85
--- /dev/null
@@ -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
index b1ccf6097a70ad699dbba7805aad07a86b577b37..6652a27c7a648db57ba35e81812e3925a551b7cc 100644 (file)
@@ -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.
  */
index 0aa7e677d47594a0bec81e0b74eb76ebae1c4be0..38db7fbbc27f81545b16ba46fd1818f32fe4e11a 100644 (file)
@@ -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)    );
index 68abd312148753fba64ef3e66d601e425efcff57..3b4786309799653693e5a342e491ac9e5babffd1 100644 (file)
@@ -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);
+}
+