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=<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).
This commit is contained in:
parent
dcc81d73e8
commit
9ba760e603
9 changed files with 216 additions and 22 deletions
|
@ -14,6 +14,7 @@ SRCS+= arch_do_vmctl.c \
|
|||
i8259.c \
|
||||
klib.S \
|
||||
memory.c \
|
||||
oxpcie.c \
|
||||
protect.c \
|
||||
arch_system.c \
|
||||
apic.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;
|
||||
|
|
|
@ -12,9 +12,11 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
|
|
83
kernel/arch/i386/oxpcie.c
Normal file
83
kernel/arch/i386/oxpcie.c
Normal file
|
@ -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
|
31
kernel/arch/i386/oxpcie.h
Normal file
31
kernel/arch/i386/oxpcie.h
Normal file
|
@ -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. */
|
||||
|
20
kernel/arch/i386/serial.h
Normal file
20
kernel/arch/i386/serial.h
Normal file
|
@ -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
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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) );
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue