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:
Ben Gras 2010-05-19 10:00:02 +00:00
parent dcc81d73e8
commit 9ba760e603
9 changed files with 216 additions and 22 deletions

View 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 \

View 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;

View file

@ -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
View 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
View 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
View 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

View 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.
*/

View 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) );

View 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);
}