-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[POWERPC] Add non-OF serial console support
Add serial console support for non-OF systems. There is a generic serial console layer which calls a serial console driver. Included is the serial console driver for the ns16550 class of uarts. Necessary support routines are added as well. Signed-off-by: Mark A. Greer <mgreer@mvista.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
- Loading branch information
Mark A. Greer
authored and
Paul Mackerras
committed
Oct 23, 2006
1 parent
6fb4efc
commit 0c176fa
Showing
5 changed files
with
359 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#ifndef _IO_H | ||
#define __IO_H | ||
/* | ||
* Low-level I/O routines. | ||
* | ||
* Copied from <file:include/asm-powerpc/io.h> (which has no copyright) | ||
*/ | ||
static inline int in_8(const volatile unsigned char *addr) | ||
{ | ||
int ret; | ||
|
||
__asm__ __volatile__("lbz%U1%X1 %0,%1; twi 0,%0,0; isync" | ||
: "=r" (ret) : "m" (*addr)); | ||
return ret; | ||
} | ||
|
||
static inline void out_8(volatile unsigned char *addr, int val) | ||
{ | ||
__asm__ __volatile__("stb%U0%X0 %1,%0; sync" | ||
: "=m" (*addr) : "r" (val)); | ||
} | ||
|
||
static inline unsigned in_le32(const volatile unsigned *addr) | ||
{ | ||
unsigned ret; | ||
|
||
__asm__ __volatile__("lwbrx %0,0,%1; twi 0,%0,0; isync" | ||
: "=r" (ret) : "r" (addr), "m" (*addr)); | ||
return ret; | ||
} | ||
|
||
static inline unsigned in_be32(const volatile unsigned *addr) | ||
{ | ||
unsigned ret; | ||
|
||
__asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" | ||
: "=r" (ret) : "m" (*addr)); | ||
return ret; | ||
} | ||
|
||
static inline void out_le32(volatile unsigned *addr, int val) | ||
{ | ||
__asm__ __volatile__("stwbrx %1,0,%2; sync" : "=m" (*addr) | ||
: "r" (val), "r" (addr)); | ||
} | ||
|
||
static inline void out_be32(volatile unsigned *addr, int val) | ||
{ | ||
__asm__ __volatile__("stw%U0%X0 %1,%0; sync" | ||
: "=m" (*addr) : "r" (val)); | ||
} | ||
|
||
#endif /* _IO_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
* 16550 serial console support. | ||
* | ||
* Original copied from <file:arch/ppc/boot/common/ns16550.c> | ||
* (which had no copyright) | ||
* Modifications: 2006 (c) MontaVista Software, Inc. | ||
* | ||
* Modified by: Mark A. Greer <mgreer@mvista.com> | ||
*/ | ||
#include <stdarg.h> | ||
#include <stddef.h> | ||
#include "types.h" | ||
#include "string.h" | ||
#include "stdio.h" | ||
#include "io.h" | ||
#include "ops.h" | ||
|
||
#define UART_DLL 0 /* Out: Divisor Latch Low */ | ||
#define UART_DLM 1 /* Out: Divisor Latch High */ | ||
#define UART_FCR 2 /* Out: FIFO Control Register */ | ||
#define UART_LCR 3 /* Out: Line Control Register */ | ||
#define UART_MCR 4 /* Out: Modem Control Register */ | ||
#define UART_LSR 5 /* In: Line Status Register */ | ||
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ | ||
#define UART_LSR_DR 0x01 /* Receiver data ready */ | ||
#define UART_MSR 6 /* In: Modem Status Register */ | ||
#define UART_SCR 7 /* I/O: Scratch Register */ | ||
|
||
static unsigned char *reg_base; | ||
static u32 reg_shift; | ||
|
||
static int ns16550_open(void) | ||
{ | ||
out_8(reg_base + (UART_FCR << reg_shift), 0x06); | ||
return 0; | ||
} | ||
|
||
static void ns16550_putc(unsigned char c) | ||
{ | ||
while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_THRE) == 0); | ||
out_8(reg_base, c); | ||
} | ||
|
||
static unsigned char ns16550_getc(void) | ||
{ | ||
while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) == 0); | ||
return in_8(reg_base); | ||
} | ||
|
||
static u8 ns16550_tstc(void) | ||
{ | ||
return ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) != 0); | ||
} | ||
|
||
int ns16550_console_init(void *devp, struct serial_console_data *scdp) | ||
{ | ||
int n; | ||
|
||
n = getprop(devp, "virtual-reg", ®_base, sizeof(reg_base)); | ||
if (n != sizeof(reg_base)) | ||
return -1; | ||
|
||
n = getprop(devp, "reg-shift", ®_shift, sizeof(reg_shift)); | ||
if (n != sizeof(reg_shift)) | ||
reg_shift = 0; | ||
|
||
scdp->open = ns16550_open; | ||
scdp->putc = ns16550_putc; | ||
scdp->getc = ns16550_getc; | ||
scdp->tstc = ns16550_tstc; | ||
scdp->close = NULL; | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
/* | ||
* Generic serial console support | ||
* | ||
* Author: Mark A. Greer <mgreer@mvista.com> | ||
* | ||
* Code in serial_edit_cmdline() copied from <file:arch/ppc/boot/simple/misc.c> | ||
* and was written by Matt Porter <mporter@kernel.crashing.org>. | ||
* | ||
* 2001,2006 (c) MontaVista Software, Inc. This file is licensed under | ||
* the terms of the GNU General Public License version 2. This program | ||
* is licensed "as is" without any warranty of any kind, whether express | ||
* or implied. | ||
*/ | ||
#include <stdarg.h> | ||
#include <stddef.h> | ||
#include "types.h" | ||
#include "string.h" | ||
#include "stdio.h" | ||
#include "io.h" | ||
#include "ops.h" | ||
|
||
extern void udelay(long delay); | ||
|
||
static int serial_open(void) | ||
{ | ||
struct serial_console_data *scdp = console_ops.data; | ||
return scdp->open(); | ||
} | ||
|
||
static void serial_write(char *buf, int len) | ||
{ | ||
struct serial_console_data *scdp = console_ops.data; | ||
|
||
while (*buf != '\0') | ||
scdp->putc(*buf++); | ||
} | ||
|
||
static void serial_edit_cmdline(char *buf, int len) | ||
{ | ||
int timer = 0, count; | ||
char ch, *cp; | ||
struct serial_console_data *scdp = console_ops.data; | ||
|
||
cp = buf; | ||
count = strlen(buf); | ||
cp = &buf[count]; | ||
count++; | ||
|
||
while (timer++ < 5*1000) { | ||
if (scdp->tstc()) { | ||
while (((ch = scdp->getc()) != '\n') && (ch != '\r')) { | ||
/* Test for backspace/delete */ | ||
if ((ch == '\b') || (ch == '\177')) { | ||
if (cp != buf) { | ||
cp--; | ||
count--; | ||
printf("\b \b"); | ||
} | ||
/* Test for ^x/^u (and wipe the line) */ | ||
} else if ((ch == '\030') || (ch == '\025')) { | ||
while (cp != buf) { | ||
cp--; | ||
count--; | ||
printf("\b \b"); | ||
} | ||
} else if (count < len) { | ||
*cp++ = ch; | ||
count++; | ||
scdp->putc(ch); | ||
} | ||
} | ||
break; /* Exit 'timer' loop */ | ||
} | ||
udelay(1000); /* 1 msec */ | ||
} | ||
*cp = 0; | ||
} | ||
|
||
static void serial_close(void) | ||
{ | ||
struct serial_console_data *scdp = console_ops.data; | ||
|
||
if (scdp->close) | ||
scdp->close(); | ||
} | ||
|
||
static void *serial_get_stdout_devp(void) | ||
{ | ||
void *devp; | ||
char devtype[MAX_PROP_LEN]; | ||
char path[MAX_PATH_LEN]; | ||
|
||
devp = finddevice("/chosen"); | ||
if (devp == NULL) | ||
goto err_out; | ||
|
||
if (getprop(devp, "linux,stdout-path", path, MAX_PATH_LEN) > 0) { | ||
devp = finddevice(path); | ||
if (devp == NULL) | ||
goto err_out; | ||
|
||
if ((getprop(devp, "device_type", devtype, sizeof(devtype)) > 0) | ||
&& !strcmp(devtype, "serial")) | ||
return devp; | ||
} | ||
err_out: | ||
return NULL; | ||
} | ||
|
||
static struct serial_console_data serial_cd; | ||
|
||
/* Node's "compatible" property determines which serial driver to use */ | ||
int serial_console_init(void) | ||
{ | ||
void *devp; | ||
int rc = -1; | ||
char compat[MAX_PROP_LEN]; | ||
|
||
devp = serial_get_stdout_devp(); | ||
if (devp == NULL) | ||
goto err_out; | ||
|
||
if (getprop(devp, "compatible", compat, sizeof(compat)) < 0) | ||
goto err_out; | ||
|
||
if (!strcmp(compat, "ns16550")) | ||
rc = ns16550_console_init(devp, &serial_cd); | ||
|
||
/* Add other serial console driver calls here */ | ||
|
||
if (!rc) { | ||
console_ops.open = serial_open; | ||
console_ops.write = serial_write; | ||
console_ops.edit_cmdline = serial_edit_cmdline; | ||
console_ops.close = serial_close; | ||
console_ops.data = &serial_cd; | ||
|
||
return 0; | ||
} | ||
err_out: | ||
return -1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* Copied from <file:arch/powerpc/kernel/misc_32.S> | ||
* | ||
* This file contains miscellaneous low-level functions. | ||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
* | ||
* Largely rewritten by Cort Dougan (cort@cs.nmt.edu) | ||
* and Paul Mackerras. | ||
* | ||
* kexec bits: | ||
* Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> | ||
* GameCube/ppc32 port Copyright (C) 2004 Albert Herranz | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the License, or (at your option) any later version. | ||
* | ||
*/ | ||
#include "ppc_asm.h" | ||
|
||
#define SPRN_PVR 0x11F /* Processor Version Register */ | ||
|
||
.text | ||
|
||
/* udelay (on non-601 processors) needs to know the period of the | ||
* timebase in nanoseconds. This used to be hardcoded to be 60ns | ||
* (period of 66MHz/4). Now a variable is used that is initialized to | ||
* 60 for backward compatibility, but it can be overridden as necessary | ||
* with code something like this: | ||
* extern unsigned long timebase_period_ns; | ||
* timebase_period_ns = 1000000000 / bd->bi_tbfreq; | ||
*/ | ||
.data | ||
.globl timebase_period_ns | ||
timebase_period_ns: | ||
.long 60 | ||
|
||
.text | ||
/* | ||
* Delay for a number of microseconds | ||
*/ | ||
.globl udelay | ||
udelay: | ||
mfspr r4,SPRN_PVR | ||
srwi r4,r4,16 | ||
cmpwi 0,r4,1 /* 601 ? */ | ||
bne .udelay_not_601 | ||
00: li r0,86 /* Instructions / microsecond? */ | ||
mtctr r0 | ||
10: addi r0,r0,0 /* NOP */ | ||
bdnz 10b | ||
subic. r3,r3,1 | ||
bne 00b | ||
blr | ||
|
||
.udelay_not_601: | ||
mulli r4,r3,1000 /* nanoseconds */ | ||
/* Change r4 to be the number of ticks using: | ||
* (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns | ||
* timebase_period_ns defaults to 60 (16.6MHz) */ | ||
mflr r5 | ||
bl 0f | ||
0: mflr r6 | ||
mtlr r5 | ||
lis r5,0b@ha | ||
addi r5,r5,0b@l | ||
subf r5,r5,r6 /* In case we're relocated */ | ||
addis r5,r5,timebase_period_ns@ha | ||
lwz r5,timebase_period_ns@l(r5) | ||
add r4,r4,r5 | ||
addi r4,r4,-1 | ||
divw r4,r4,r5 /* BUS ticks */ | ||
1: mftbu r5 | ||
mftb r6 | ||
mftbu r7 | ||
cmpw 0,r5,r7 | ||
bne 1b /* Get [synced] base time */ | ||
addc r9,r6,r4 /* Compute end time */ | ||
addze r8,r5 | ||
2: mftbu r5 | ||
cmpw 0,r5,r8 | ||
blt 2b | ||
bgt 3f | ||
mftb r6 | ||
cmpw 0,r6,r9 | ||
blt 2b | ||
3: blr |