提交 51d3082f 编写于 作者: B Benjamin Herrenschmidt 提交者: Paul Mackerras

[PATCH] powerpc: Unify udbg (#2)

This patch unifies udbg for both ppc32 and ppc64 when building the
merged achitecture. xmon now has a single "back end". The powermac udbg
stuff gets enriched with some ADB capabilities and btext output. In
addition, the early_init callback is now called on ppc32 as well,
approx. in the same order as ppc64 regarding device-tree manipulations.
The init sequences of ppc32 and ppc64 are getting closer, I'll unify
them in a later patch.

For now, you can force udbg to the scc using "sccdbg" or to btext using
"btextdbg" on powermacs. I'll implement a cleaner way of forcing udbg
output to something else than the autodetected OF output device in a
later patch.
Signed-off-by: NBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: NPaul Mackerras <paulus@samba.org>
上级 463ce0e1
......@@ -50,7 +50,7 @@ config PPC
config EARLY_PRINTK
bool
default y if PPC64
default y
config COMPAT
bool
......
......@@ -18,7 +18,7 @@ obj-y += vdso32/
obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
signal_64.o ptrace32.o systbl.o \
paca.o ioctl32.o cpu_setup_power4.o \
firmware.o sysfs.o udbg.o idle_64.o
firmware.o sysfs.o idle_64.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
obj-$(CONFIG_POWER4) += idle_power4.o
......@@ -46,7 +46,7 @@ extra-$(CONFIG_8xx) := head_8xx.o
extra-y += vmlinux.lds
obj-y += process.o init_task.o time.o \
prom.o traps.o setup-common.o
prom.o traps.o setup-common.o udbg.o
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o systbl.o
obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o
obj-$(CONFIG_PPC_OF) += prom_init.o
......@@ -56,8 +56,7 @@ obj-$(CONFIG_6xx) += idle_6xx.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_PPC_MULTIPLATFORM) += legacy_serial.o
obj64-$(CONFIG_PPC_MULTIPLATFORM) += udbg_16550.o
obj64-$(CONFIG_PPC_PMAC) += udbg_scc.o
obj-$(CONFIG_PPC_MULTIPLATFORM) += udbg_16550.o
module-$(CONFIG_PPC64) += module_64.o
obj-$(CONFIG_MODULES) += $(module-y)
......
......@@ -31,15 +31,18 @@ static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);
static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
static int g_loc_X;
static int g_loc_Y;
static int g_max_loc_X;
static int g_max_loc_Y;
#define __force_data __attribute__((__section__(".data")))
static int dispDeviceRowBytes;
static int dispDeviceDepth;
static int dispDeviceRect[4];
static unsigned char *dispDeviceBase, *logicalDisplayBase;
static int g_loc_X __force_data;
static int g_loc_Y __force_data;
static int g_max_loc_X __force_data;
static int g_max_loc_Y __force_data;
static int dispDeviceRowBytes __force_data;
static int dispDeviceDepth __force_data;
static int dispDeviceRect[4] __force_data;
static unsigned char *dispDeviceBase __force_data;
static unsigned char *logicalDisplayBase __force_data;
unsigned long disp_BAT[2] __initdata = {0, 0};
......@@ -47,7 +50,7 @@ unsigned long disp_BAT[2] __initdata = {0, 0};
static unsigned char vga_font[cmapsz];
int boot_text_mapped;
int boot_text_mapped __force_data = 0;
int force_printk_to_btext = 0;
#ifdef CONFIG_PPC32
......@@ -66,8 +69,7 @@ int force_printk_to_btext = 0;
* is really badly aligned, but I didn't encounter this case
* yet.
*/
void __init
btext_prepare_BAT(void)
void __init btext_prepare_BAT(void)
{
unsigned long vaddr = KERNELBASE + 0x10000000;
unsigned long addr;
......@@ -95,12 +97,13 @@ btext_prepare_BAT(void)
}
#endif
/* This function will enable the early boot text when doing OF booting. This
* way, xmon output should work too
/* This function can be used to enable the early boot text when doing
* OF booting or within bootx init. It must be followed by a btext_unmap()
* call before the logical address becomes unuseable
*/
void __init
btext_setup_display(int width, int height, int depth, int pitch,
unsigned long address)
void __init btext_setup_display(int width, int height, int depth, int pitch,
unsigned long address)
{
g_loc_X = 0;
g_loc_Y = 0;
......@@ -116,6 +119,11 @@ btext_setup_display(int width, int height, int depth, int pitch,
boot_text_mapped = 1;
}
void __init btext_unmap(void)
{
boot_text_mapped = 0;
}
/* Here's a small text engine to use during early boot
* or for debugging purposes
*
......@@ -127,7 +135,7 @@ btext_setup_display(int width, int height, int depth, int pitch,
* changes.
*/
void map_boot_text(void)
static void map_boot_text(void)
{
unsigned long base, offset, size;
unsigned char *vbase;
......@@ -175,8 +183,9 @@ int btext_initialize(struct device_node *np)
if (prop)
address = *prop;
/* FIXME: Add support for PCI reg properties */
/* FIXME: Add support for PCI reg properties. Right now, only
* reliable on macs
*/
if (address == 0)
return -EINVAL;
......@@ -184,7 +193,6 @@ int btext_initialize(struct device_node *np)
g_loc_Y = 0;
g_max_loc_X = width / 8;
g_max_loc_Y = height / 16;
logicalDisplayBase = (unsigned char *)address;
dispDeviceBase = (unsigned char *)address;
dispDeviceRowBytes = pitch;
dispDeviceDepth = depth;
......@@ -197,7 +205,7 @@ int btext_initialize(struct device_node *np)
return 0;
}
void __init init_boot_display(void)
int __init btext_find_display(int allow_nonstdout)
{
char *name;
struct device_node *np = NULL;
......@@ -218,8 +226,8 @@ void __init init_boot_display(void)
}
if (np)
rc = btext_initialize(np);
if (rc == 0)
return;
if (rc == 0 || !allow_nonstdout)
return rc;
for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
if (get_property(np, "linux,opened", NULL)) {
......@@ -228,8 +236,9 @@ void __init init_boot_display(void)
printk("result: %d\n", rc);
}
if (rc == 0)
return;
break;
}
return rc;
}
/* Calc the base address of a given point (x,y) */
......@@ -277,44 +286,83 @@ EXPORT_SYMBOL(btext_update_display);
void btext_clearscreen(void)
{
unsigned long *base = (unsigned long *)calc_base(0, 0);
unsigned int *base = (unsigned int *)calc_base(0, 0);
unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
(dispDeviceDepth >> 3)) >> 3;
(dispDeviceDepth >> 3)) >> 2;
int i,j;
for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
{
unsigned long *ptr = base;
unsigned int *ptr = base;
for(j=width; j; --j)
*(ptr++) = 0;
base += (dispDeviceRowBytes >> 3);
base += (dispDeviceRowBytes >> 2);
}
}
void btext_flushscreen(void)
{
unsigned int *base = (unsigned int *)calc_base(0, 0);
unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
(dispDeviceDepth >> 3)) >> 2;
int i,j;
for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++)
{
unsigned int *ptr = base;
for(j = width; j > 0; j -= 8) {
__asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
ptr += 8;
}
base += (dispDeviceRowBytes >> 2);
}
__asm__ __volatile__ ("sync" ::: "memory");
}
void btext_flushline(void)
{
unsigned int *base = (unsigned int *)calc_base(0, g_loc_Y << 4);
unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
(dispDeviceDepth >> 3)) >> 2;
int i,j;
for (i=0; i < 16; i++)
{
unsigned int *ptr = base;
for(j = width; j > 0; j -= 8) {
__asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
ptr += 8;
}
base += (dispDeviceRowBytes >> 2);
}
__asm__ __volatile__ ("sync" ::: "memory");
}
#ifndef NO_SCROLL
static void scrollscreen(void)
{
unsigned long *src = (unsigned long *)calc_base(0,16);
unsigned long *dst = (unsigned long *)calc_base(0,0);
unsigned int *src = (unsigned int *)calc_base(0,16);
unsigned int *dst = (unsigned int *)calc_base(0,0);
unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
(dispDeviceDepth >> 3)) >> 3;
(dispDeviceDepth >> 3)) >> 2;
int i,j;
for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
{
unsigned long *src_ptr = src;
unsigned long *dst_ptr = dst;
unsigned int *src_ptr = src;
unsigned int *dst_ptr = dst;
for(j=width; j; --j)
*(dst_ptr++) = *(src_ptr++);
src += (dispDeviceRowBytes >> 3);
dst += (dispDeviceRowBytes >> 3);
src += (dispDeviceRowBytes >> 2);
dst += (dispDeviceRowBytes >> 2);
}
for (i=0; i<16; i++)
{
unsigned long *dst_ptr = dst;
unsigned int *dst_ptr = dst;
for(j=width; j; --j)
*(dst_ptr++) = 0;
dst += (dispDeviceRowBytes >> 3);
dst += (dispDeviceRowBytes >> 2);
}
}
#endif /* ndef NO_SCROLL */
......@@ -377,6 +425,14 @@ void btext_drawstring(const char *c)
btext_drawchar(*c++);
}
void btext_drawtext(const char *c, unsigned int len)
{
if (!boot_text_mapped)
return;
while (len--)
btext_drawchar(*c++);
}
void btext_drawhex(unsigned long v)
{
char *hex_table = "0123456789abcdef";
......
......@@ -153,6 +153,9 @@ __after_mmu_off:
bl flush_tlbs
bl initial_bats
#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
bl setup_disp_bat
#endif
/*
* Call setup_cpu for CPU 0 and initialize 6xx Idle
......@@ -1306,6 +1309,32 @@ initial_bats:
blr
#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
setup_disp_bat:
/*
* setup the display bat prepared for us in prom.c
*/
mflr r8
bl reloc_offset
mtlr r8
addis r8,r3,disp_BAT@ha
addi r8,r8,disp_BAT@l
cmpwi cr0,r8,0
beqlr
lwz r11,0(r8)
lwz r8,4(r8)
mfspr r9,SPRN_PVR
rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
cmpwi 0,r9,1
beq 1f
mtspr SPRN_DBAT3L,r8
mtspr SPRN_DBAT3U,r11
blr
1: mtspr SPRN_IBAT3L,r8
mtspr SPRN_IBAT3U,r11
blr
#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
#ifdef CONFIG_8260
/* Jump into the system reset for the rom.
* We first disable the MMU, and then jump to the ROM reset address.
......
......@@ -40,6 +40,7 @@
#include <asm/xmon.h>
#include <asm/time.h>
#include <asm/serial.h>
#include <asm/udbg.h>
#include "setup.h"
......@@ -173,12 +174,23 @@ void __init platform_init(void)
*/
void __init machine_init(unsigned long dt_ptr, unsigned long phys)
{
/* If btext is enabled, we might have a BAT setup for early display,
* thus we do enable some very basic udbg output
*/
#ifdef CONFIG_BOOTX_TEXT
udbg_putc = btext_drawchar;
#endif
/* Do some early initialization based on the flat device tree */
early_init_devtree(__va(dt_ptr));
/* Check default command line */
#ifdef CONFIG_CMDLINE
strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
if (cmd_line[0] == 0)
strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
#endif /* CONFIG_CMDLINE */
/* Base init based on machine type */
platform_init();
#ifdef CONFIG_6xx
......@@ -294,21 +306,11 @@ void __init setup_arch(char **cmdline_p)
smp_setup_cpu_maps();
#ifdef CONFIG_BOOTX_TEXT
init_boot_display();
#endif
#ifdef CONFIG_PPC_PMAC
/* This could be called "early setup arch", it must be done
* now because xmon need it
*/
if (_machine == _MACH_Pmac)
pmac_feature_init(); /* New cool way */
#endif
#ifdef CONFIG_XMON_DEFAULT
xmon_init(1);
#endif
/* Register early console */
register_early_udbg_console();
#if defined(CONFIG_KGDB)
if (ppc_md.kgdb_map_scc)
......
......@@ -474,10 +474,6 @@ void __init setup_system(void)
*/
finish_device_tree();
#ifdef CONFIG_BOOTX_TEXT
init_boot_display();
#endif
/*
* Initialize xmon
*/
......
......@@ -16,8 +16,8 @@
#include <linux/console.h>
#include <asm/processor.h>
void (*udbg_putc)(unsigned char c);
unsigned char (*udbg_getc)(void);
void (*udbg_putc)(char c);
char (*udbg_getc)(void);
int (*udbg_getc_poll)(void);
/* udbg library, used by xmon et al */
......@@ -78,7 +78,7 @@ int udbg_read(char *buf, int buflen)
#define UDBG_BUFSIZE 256
void udbg_printf(const char *fmt, ...)
{
unsigned char buf[UDBG_BUFSIZE];
char buf[UDBG_BUFSIZE];
va_list args;
va_start(args, fmt);
......@@ -116,6 +116,8 @@ void __init disable_early_printk(void)
/* called by setup_system */
void register_early_udbg_console(void)
{
if (early_console_initialized)
return;
early_console_initialized = 1;
register_console(&udbg_console);
}
......
......@@ -47,7 +47,7 @@ struct NS16550 {
static volatile struct NS16550 __iomem *udbg_comport;
static void udbg_550_putc(unsigned char c)
static void udbg_550_putc(char c)
{
if (udbg_comport) {
while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
......@@ -69,7 +69,7 @@ static int udbg_550_getc_poll(void)
return -1;
}
static unsigned char udbg_550_getc(void)
static char udbg_550_getc(void)
{
if (udbg_comport) {
while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
......
......@@ -188,6 +188,11 @@ void __init MMU_init(void)
if (ppc_md.progress)
ppc_md.progress("MMU:exit", 0x211);
/* From now on, btext is no longer BAT mapped if it was at all */
#ifdef CONFIG_BOOTX_TEXT
btext_unmap();
#endif
}
/* This is only called until mem_init is done. */
......
......@@ -7,3 +7,4 @@ obj-$(CONFIG_NVRAM) += nvram.o
# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
obj-$(CONFIG_PPC64) += nvram.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PPC_MERGE) += udbg_scc.o udbg_adb.o
......@@ -2607,6 +2607,8 @@ static int __init probe_motherboard(void)
*/
static void __init probe_uninorth(void)
{
u32 *addrp;
phys_addr_t address;
unsigned long actrl;
/* Locate core99 Uni-N */
......@@ -2616,20 +2618,23 @@ static void __init probe_uninorth(void)
uninorth_node = of_find_node_by_name(NULL, "u3");
uninorth_u3 = 1;
}
if (uninorth_node && uninorth_node->n_addrs > 0) {
unsigned long address = uninorth_node->addrs[0].address;
uninorth_base = ioremap(address, 0x40000);
uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
if (uninorth_u3)
u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
} else
uninorth_node = NULL;
if (!uninorth_node)
if (uninorth_node == NULL)
return;
printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
addrp = (u32 *)get_property(uninorth_node, "reg", NULL);
if (addrp == NULL)
return;
address = of_translate_address(uninorth_node, addrp);
if (address == 0)
return;
uninorth_base = ioremap(address, 0x40000);
uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
if (uninorth_u3)
u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
printk(KERN_INFO "Found %s memory controller & host bridge,"
" revision: %d\n", uninorth_u3 ? "U3" : "UniNorth",
uninorth_rev);
printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
/* Set the arbitrer QAck delay according to what Apple does
......@@ -2653,18 +2658,17 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
{
struct device_node* node;
int i;
volatile u32 __iomem * base;
u32* revp;
volatile u32 __iomem *base;
u32 *addrp, *revp;
phys_addr_t addr;
u64 size;
node = find_devices(name);
if (!node || !node->n_addrs)
return;
if (compat)
do {
if (device_is_compatible(node, compat))
break;
node = node->next;
} while (node);
for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {
if (!compat)
break;
if (device_is_compatible(node, compat))
break;
}
if (!node)
return;
for(i=0; i<MAX_MACIO_CHIPS; i++) {
......@@ -2673,14 +2677,28 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
if (macio_chips[i].of_node == node)
return;
}
if (i >= MAX_MACIO_CHIPS) {
printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
return;
}
base = ioremap(node->addrs[0].address, node->addrs[0].size);
addrp = of_get_pci_address(node, 0, &size);
if (addrp == NULL) {
printk(KERN_ERR "pmac_feature: %s: can't find base !\n",
node->full_name);
return;
}
addr = of_translate_address(node, addrp);
if (addr == 0) {
printk(KERN_ERR "pmac_feature: %s, can't translate base !\n",
node->full_name);
return;
}
base = ioremap(addr, (unsigned long)size);
if (!base) {
printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
printk(KERN_ERR "pmac_feature: %s, can't map mac-io chip !\n",
node->full_name);
return;
}
if (type == macio_keylargo) {
......
......@@ -36,7 +36,7 @@
#ifdef DEBUG
#define DBG(x...) do {\
printk(KERN_DEBUG "KW:" x); \
printk(KERN_DEBUG "low_i2c:" x); \
} while(0)
#else
#define DBG(x...)
......@@ -342,7 +342,7 @@ static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr,
static void keywest_low_i2c_add(struct device_node *np)
{
struct low_i2c_host *host = find_low_i2c_host(NULL);
u32 *psteps, *prate, steps, aoffset = 0;
u32 *psteps, *prate, *addrp, steps;
struct device_node *parent;
if (host == NULL) {
......@@ -352,6 +352,16 @@ static void keywest_low_i2c_add(struct device_node *np)
}
memset(host, 0, sizeof(*host));
/* Apple is kind enough to provide a valid AAPL,address property
* on all i2c keywest nodes so far ... we would have to fallback
* to macio parsing if that wasn't the case
*/
addrp = (u32 *)get_property(np, "AAPL,address", NULL);
if (addrp == NULL) {
printk(KERN_ERR "low_i2c: Can't find address for %s\n",
np->full_name);
return;
}
init_MUTEX(&host->mutex);
host->np = of_node_get(np);
psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
......@@ -360,12 +370,10 @@ static void keywest_low_i2c_add(struct device_node *np)
steps >>= 1;
parent = of_get_parent(np);
host->num_channels = 1;
if (parent && parent->name[0] == 'u') {
if (parent && parent->name[0] == 'u')
host->num_channels = 2;
aoffset = 3;
}
/* Select interface rate */
host->speed = KW_I2C_MODE_100KHZ;
host->speed = KW_I2C_MODE_25KHZ;
prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
if (prate) switch(*prate) {
case 100:
......@@ -379,9 +387,12 @@ static void keywest_low_i2c_add(struct device_node *np)
break;
}
printk(KERN_INFO "low_i2c: Bus %s found at 0x%08x, %d channels,"
" speed = %d KHz\n",
np->full_name, *addrp, host->num_channels, prate ? *prate : 25);
host->mode = pmac_low_i2c_mode_std;
host->base = ioremap(np->addrs[0].address + aoffset,
np->addrs[0].size);
host->base = ioremap((*addrp), 0x1000);
host->func = keywest_low_i2c_func;
}
......
......@@ -459,7 +459,7 @@ void __init pmac_pic_init(void)
mpic_setup_cascade(irqctrler2->intrs[0].line,
pmac_u3_cascade, mpic2);
}
#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
#ifdef CONFIG_XMON
{
struct device_node* pswitch;
int nmi_irq;
......
......@@ -77,6 +77,7 @@
#include <asm/pmc.h>
#include <asm/mpic.h>
#include <asm/lmb.h>
#include <asm/udbg.h>
#include "pmac.h"
......@@ -322,16 +323,6 @@ void __init pmac_setup_arch(void)
l2cr_init();
#endif /* CONFIG_PPC32 */
#ifdef CONFIG_PPC64
/* Probe motherboard chipset */
/* this is done earlier in setup_arch for 32-bit */
pmac_feature_init();
/* We can NAP */
powersave_nap = 1;
printk(KERN_INFO "Using native/NAP idle loop\n");
#endif
#ifdef CONFIG_KGDB
zs_kgdb_hook(0);
#endif
......@@ -622,13 +613,26 @@ static void __init pmac_init_early(void)
* and call ioremap
*/
hpte_init_native();
#endif
/* Init SCC */
if (strstr(cmd_line, "sccdbg")) {
sccdbg = 1;
udbg_init_scc(NULL);
/* Enable early btext debug if requested */
if (strstr(cmd_line, "btextdbg")) {
udbg_adb_init_early();
register_early_udbg_console();
}
/* Probe motherboard chipset */
pmac_feature_init();
/* We can NAP */
powersave_nap = 1;
printk(KERN_INFO "Using native/NAP idle loop\n");
/* Initialize debug stuff */
udbg_scc_init(!!strstr(cmd_line, "sccdbg"));
udbg_adb_init(!!strstr(cmd_line, "btextdbg"));
#ifdef CONFIG_PPC64
/* Setup interrupt mapping options */
ppc64_interrupt_controller = IC_OPEN_PIC;
......@@ -638,19 +642,8 @@ static void __init pmac_init_early(void)
static void __init pmac_progress(char *s, unsigned short hex)
{
#ifdef CONFIG_PPC64
if (sccdbg) {
udbg_puts(s);
udbg_puts("\n");
return;
}
#endif
#ifdef CONFIG_BOOTX_TEXT
if (boot_text_mapped) {
btext_drawstring(s);
btext_drawchar('\n');
}
#endif /* CONFIG_BOOTX_TEXT */
udbg_puts(s);
udbg_puts("\n");
}
/*
......@@ -735,7 +728,8 @@ static int __init pmac_probe(int platform)
}
#ifdef CONFIG_PPC64
static int pmac_probe_mode(struct pci_bus *bus)
/* Move that to pci.c */
static int pmac_pci_probe_mode(struct pci_bus *bus)
{
struct device_node *node = bus->sysdata;
......@@ -771,7 +765,7 @@ struct machdep_calls __initdata pmac_md = {
.check_legacy_ioport = pmac_check_legacy_ioport,
.progress = pmac_progress,
#ifdef CONFIG_PPC64
.pci_probe_mode = pmac_probe_mode,
.pci_probe_mode = pmac_pci_probe_mode,
.idle_loop = native_idle,
.enable_pmcs = power4_enable_pmcs,
#ifdef CONFIG_KEXEC
......
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/bitops.h>
#include <linux/ptrace.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/cuda.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/xmon.h>
#include <asm/prom.h>
#include <asm/bootx.h>
#include <asm/machdep.h>
#include <asm/errno.h>
#include <asm/pmac_feature.h>
#include <asm/processor.h>
#include <asm/delay.h>
#include <asm/btext.h>
#include <asm/time.h>
#include <asm/udbg.h>
/*
* This implementation is "special", it can "patch" the current
* udbg implementation and work on top of it. It must thus be
* initialized last
*/
static void (*udbg_adb_old_putc)(char c);
static char (*udbg_adb_old_getc)(void);
static int (*udbg_adb_old_getc_poll)(void);
static enum {
input_adb_none,
input_adb_pmu,
input_adb_cuda,
} input_type = input_adb_none;
static int udbg_adb_use_btext;
int xmon_wants_key, xmon_adb_keycode;
static inline void udbg_adb_poll(void)
{
#ifdef CONFIG_ADB_PMU
if (input_type == input_adb_pmu)
pmu_poll_adb();
#endif /* CONFIG_ADB_PMU */
#ifdef CONFIG_ADB_CUDA
if (input_type == input_adb_cuda)
cuda_poll();
#endif /* CONFIG_ADB_CUDA */
}
#ifdef CONFIG_BOOTX_TEXT
static int xmon_adb_shiftstate;
static unsigned char xmon_keytab[128] =
"asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
"yt123465=97-80]o" /* 0x10 - 0x1f */
"u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
"\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
"\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
"\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
static unsigned char xmon_shift_keytab[128] =
"ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
"YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */
"U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
"\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
"\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
"\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
static char udbg_adb_local_getc(void)
{
int k, t, on;
xmon_wants_key = 1;
for (;;) {
xmon_adb_keycode = -1;
t = 0;
on = 0;
k = -1;
do {
if (--t < 0) {
on = 1 - on;
btext_drawchar(on? 0xdb: 0x20);
btext_drawchar('\b');
t = 200000;
}
udbg_adb_poll();
if (udbg_adb_old_getc_poll)
k = udbg_adb_old_getc_poll();
} while (k == -1 && xmon_adb_keycode == -1);
if (on)
btext_drawstring(" \b");
if (k != -1)
return k;
k = xmon_adb_keycode;
/* test for shift keys */
if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
xmon_adb_shiftstate = (k & 0x80) == 0;
continue;
}
if (k >= 0x80)
continue; /* ignore up transitions */
k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
if (k != 0)
break;
}
xmon_wants_key = 0;
return k;
}
#endif /* CONFIG_BOOTX_TEXT */
static char udbg_adb_getc(void)
{
#ifdef CONFIG_BOOTX_TEXT
if (udbg_adb_use_btext && input_type != input_adb_none)
return udbg_adb_local_getc();
#endif
if (udbg_adb_old_getc)
return udbg_adb_old_getc();
return -1;
}
/* getc_poll() is not really used, unless you have the xmon-over modem
* hack that doesn't quite concern us here, thus we just poll the low level
* ADB driver to prevent it from timing out and call back the original poll
* routine.
*/
static int udbg_adb_getc_poll(void)
{
udbg_adb_poll();
if (udbg_adb_old_getc_poll)
return udbg_adb_old_getc_poll();
return -1;
}
static void udbg_adb_putc(char c)
{
#ifdef CONFIG_BOOTX_TEXT
if (udbg_adb_use_btext)
btext_drawchar(c);
#endif
if (udbg_adb_old_putc)
return udbg_adb_old_putc(c);
}
void udbg_adb_init_early(void)
{
#ifdef CONFIG_BOOTX_TEXT
if (btext_find_display(1) == 0) {
udbg_adb_use_btext = 1;
udbg_putc = udbg_adb_putc;
}
#endif
}
int udbg_adb_init(int force_btext)
{
struct device_node *np;
/* Capture existing callbacks */
udbg_adb_old_putc = udbg_putc;
udbg_adb_old_getc = udbg_getc;
udbg_adb_old_getc_poll = udbg_getc_poll;
/* Check if our early init was already called */
if (udbg_adb_old_putc == udbg_adb_putc ||
udbg_adb_old_putc == btext_drawchar)
udbg_adb_old_putc = NULL;
/* Set ours as output */
udbg_putc = udbg_adb_putc;
udbg_getc = udbg_adb_getc;
udbg_getc_poll = udbg_adb_getc_poll;
#ifdef CONFIG_BOOTX_TEXT
/* Check if we should use btext output */
if (btext_find_display(force_btext) == 0)
udbg_adb_use_btext = 1;
#endif
/* See if there is a keyboard in the device tree with a parent
* of type "adb". If not, we return a failure, but we keep the
* bext output set for now
*/
for (np = NULL; (np = of_find_node_by_name(np, "keyboard")) != NULL;) {
struct device_node *parent = of_get_parent(np);
int found = (parent && !strcmp(parent->type, "adb") == 0);
of_node_put(parent);
if (found)
break;
}
if (np == NULL)
return -ENODEV;
of_node_put(np);
#ifdef CONFIG_ADB_PMU
if (find_via_pmu())
input_type = input_adb_pmu;
#endif
#ifdef CONFIG_ADB_CUDA
if (find_via_cuda())
input_type = input_adb_cuda;
#endif
/* Same as above: nothing found, keep btext set for output */
if (input_type == input_adb_none)
return -ENODEV;
return 0;
}
......@@ -25,7 +25,7 @@ extern void real_writeb(u8 data, volatile u8 __iomem *addr);
static volatile u8 __iomem *sccc;
static volatile u8 __iomem *sccd;
static void udbg_scc_putc(unsigned char c)
static void udbg_scc_putc(char c)
{
if (sccc) {
while ((in_8(sccc) & SCC_TXRDY) == 0)
......@@ -47,7 +47,7 @@ static int udbg_scc_getc_poll(void)
return -1;
}
static unsigned char udbg_scc_getc(void)
static char udbg_scc_getc(void)
{
if (sccc) {
while ((in_8(sccc) & SCC_RXRDY) == 0)
......@@ -67,38 +67,59 @@ static unsigned char scc_inittab[] = {
3, 0xc1, /* rx enable, 8 bits */
};
void udbg_init_scc(struct device_node *np)
void udbg_scc_init(int force_scc)
{
u32 *reg;
unsigned long addr;
struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
char *path;
int i, x;
if (np == NULL)
np = of_find_node_by_name(NULL, "escc");
if (np == NULL || np->parent == NULL)
return;
escc = of_find_node_by_name(NULL, "escc");
if (escc == NULL)
goto bail;
macio = of_get_parent(escc);
if (macio == NULL)
goto bail;
path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
if (path != NULL)
stdout = of_find_node_by_path(path);
for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
if (ch == stdout)
ch_def = of_node_get(ch);
if (strcmp(ch->name, "ch-a") == 0)
ch_a = of_node_get(ch);
}
if (ch_def == NULL && !force_scc)
goto bail;
ch = ch_def ? ch_def : ch_a;
udbg_printf("found SCC...\n");
/* Get address within mac-io ASIC */
reg = (u32 *)get_property(np, "reg", NULL);
reg = (u32 *)get_property(escc, "reg", NULL);
if (reg == NULL)
return;
goto bail;
addr = reg[0];
udbg_printf("local addr: %lx\n", addr);
/* Get address of mac-io PCI itself */
reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL);
reg = (u32 *)get_property(macio, "assigned-addresses", NULL);
if (reg == NULL)
return;
goto bail;
addr += reg[2];
udbg_printf("final addr: %lx\n", addr);
/* Lock the serial port */
pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
/* Setup for 57600 8N1 */
addr += 0x20;
if (ch == ch_a)
addr += 0x20;
sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
sccc += addr & ~PAGE_MASK;
sccd = sccc + 0x10;
udbg_printf("ioremap result sccc: %p\n", sccc);
mb();
for (i = 20000; i != 0; --i)
......@@ -113,9 +134,17 @@ void udbg_init_scc(struct device_node *np)
udbg_getc_poll = udbg_scc_getc_poll;
udbg_puts("Hello World !\n");
bail:
of_node_put(macio);
of_node_put(escc);
of_node_put(stdout);
of_node_put(ch_def);
of_node_put(ch_a);
}
static void udbg_real_scc_putc(unsigned char c)
#ifdef CONFIG_PPC64
static void udbg_real_scc_putc(char c)
{
while ((real_readb(sccc) & SCC_TXRDY) == 0)
;
......@@ -133,3 +162,4 @@ void udbg_init_pmac_realmode(void)
udbg_getc = NULL;
udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC64 */
......@@ -61,7 +61,7 @@ extern void pSeries_find_serial_port(void);
int vtermno; /* virtual terminal# for udbg */
#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
static void udbg_hvsi_putc(unsigned char c)
static void udbg_hvsi_putc(char c)
{
/* packet's seqno isn't used anyways */
uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c };
......@@ -112,7 +112,7 @@ static int udbg_hvsi_getc_poll(void)
return ch;
}
static unsigned char udbg_hvsi_getc(void)
static char udbg_hvsi_getc(void)
{
int ch;
for (;;) {
......@@ -128,7 +128,7 @@ static unsigned char udbg_hvsi_getc(void)
}
}
static void udbg_putcLP(unsigned char c)
static void udbg_putcLP(char c)
{
char buf[16];
unsigned long rc;
......@@ -173,7 +173,7 @@ static int udbg_getc_pollLP(void)
return ch;
}
static unsigned char udbg_getcLP(void)
static char udbg_getcLP(void)
{
int ch;
for (;;) {
......
......@@ -3,9 +3,5 @@
ifdef CONFIG_PPC64
EXTRA_CFLAGS += -mno-minimal-toc
endif
obj-$(CONFIG_8xx) += start_8xx.o
obj-$(CONFIG_6xx) += start_32.o
obj-$(CONFIG_4xx) += start_32.o
obj-$(CONFIG_PPC64) += start_64.o
obj-y += xmon.o ppc-dis.o ppc-opc.o setjmp.o nonstdio.o
obj-y += xmon.o ppc-dis.o ppc-opc.o setjmp.o start.o \
nonstdio.o
/*
* Copyright (C) 1996 Paul Mackerras.
*/
#include <linux/config.h>
#include <linux/string.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/page.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/cuda.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/bitops.h>
#include <asm/xmon.h>
#include <asm/prom.h>
#include <asm/bootx.h>
#include <asm/machdep.h>
#include <asm/errno.h>
#include <asm/pmac_feature.h>
#include <asm/processor.h>
#include <asm/delay.h>
#include <asm/btext.h>
#include <asm/time.h>
#include "nonstdio.h"
static volatile unsigned char __iomem *sccc, *sccd;
unsigned int TXRDY, RXRDY, DLAB;
static int use_serial;
static int use_screen;
static int via_modem;
static int xmon_use_sccb;
static struct device_node *channel_node;
void buf_access(void)
{
if (DLAB)
sccd[3] &= ~DLAB; /* reset DLAB */
}
extern int adb_init(void);
#ifdef CONFIG_PPC_CHRP
/*
* This looks in the "ranges" property for the primary PCI host bridge
* to find the physical address of the start of PCI/ISA I/O space.
* It is basically a cut-down version of pci_process_bridge_OF_ranges.
*/
static unsigned long chrp_find_phys_io_base(void)
{
struct device_node *node;
unsigned int *ranges;
unsigned long base = CHRP_ISA_IO_BASE;
int rlen = 0;
int np;
node = find_devices("isa");
if (node != NULL) {
node = node->parent;
if (node == NULL || node->type == NULL
|| strcmp(node->type, "pci") != 0)
node = NULL;
}
if (node == NULL)
node = find_devices("pci");
if (node == NULL)
return base;
ranges = (unsigned int *) get_property(node, "ranges", &rlen);
np = prom_n_addr_cells(node) + 5;
while ((rlen -= np * sizeof(unsigned int)) >= 0) {
if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
/* I/O space starting at 0, grab the phys base */
base = ranges[np - 3];
break;
}
ranges += np;
}
return base;
}
#endif /* CONFIG_PPC_CHRP */
void xmon_map_scc(void)
{
#ifdef CONFIG_PPC_MULTIPLATFORM
volatile unsigned char __iomem *base;
if (_machine == _MACH_Pmac) {
struct device_node *np;
unsigned long addr;
#ifdef CONFIG_BOOTX_TEXT
if (!use_screen && !use_serial
&& !machine_is_compatible("iMac")) {
/* see if there is a keyboard in the device tree
with a parent of type "adb" */
for (np = find_devices("keyboard"); np; np = np->next)
if (np->parent && np->parent->type
&& strcmp(np->parent->type, "adb") == 0)
break;
/* needs to be hacked if xmon_printk is to be used
from within find_via_pmu() */
#ifdef CONFIG_ADB_PMU
if (np != NULL && boot_text_mapped && find_via_pmu())
use_screen = 1;
#endif
#ifdef CONFIG_ADB_CUDA
if (np != NULL && boot_text_mapped && find_via_cuda())
use_screen = 1;
#endif
}
if (!use_screen && (np = find_devices("escc")) != NULL) {
/*
* look for the device node for the serial port
* we're using and see if it says it has a modem
*/
char *name = xmon_use_sccb? "ch-b": "ch-a";
char *slots;
int l;
np = np->child;
while (np != NULL && strcmp(np->name, name) != 0)
np = np->sibling;
if (np != NULL) {
/* XXX should parse this properly */
channel_node = np;
slots = get_property(np, "slot-names", &l);
if (slots != NULL && l >= 10
&& strcmp(slots+4, "Modem") == 0)
via_modem = 1;
}
}
btext_drawstring("xmon uses ");
if (use_screen)
btext_drawstring("screen and keyboard\n");
else {
if (via_modem)
btext_drawstring("modem on ");
btext_drawstring(xmon_use_sccb? "printer": "modem");
btext_drawstring(" port\n");
}
#endif /* CONFIG_BOOTX_TEXT */
#ifdef CHRP_ESCC
addr = 0xc1013020;
#else
addr = 0xf3013020;
#endif
TXRDY = 4;
RXRDY = 1;
np = find_devices("mac-io");
if (np && np->n_addrs)
addr = np->addrs[0].address + 0x13020;
base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
sccc = base + (addr & ~PAGE_MASK);
sccd = sccc + 0x10;
} else {
base = (volatile unsigned char *) isa_io_base;
#ifdef CONFIG_PPC_CHRP
if (_machine == _MACH_chrp)
base = (volatile unsigned char __iomem *)
ioremap(chrp_find_phys_io_base(), 0x1000);
#endif
sccc = base + 0x3fd;
sccd = base + 0x3f8;
if (xmon_use_sccb) {
sccc -= 0x100;
sccd -= 0x100;
}
TXRDY = 0x20;
RXRDY = 1;
DLAB = 0x80;
}
#elif defined(CONFIG_GEMINI)
/* should already be mapped by the kernel boot */
sccc = (volatile unsigned char __iomem *) 0xffeffb0d;
sccd = (volatile unsigned char __iomem *) 0xffeffb08;
TXRDY = 0x20;
RXRDY = 1;
DLAB = 0x80;
#elif defined(CONFIG_405GP)
sccc = (volatile unsigned char __iomem *)0xef600305;
sccd = (volatile unsigned char __iomem *)0xef600300;
TXRDY = 0x20;
RXRDY = 1;
DLAB = 0x80;
#endif /* platform */
}
static int scc_initialized = 0;
void xmon_init_scc(void);
extern void cuda_poll(void);
static inline void do_poll_adb(void)
{
#ifdef CONFIG_ADB_PMU
if (sys_ctrler == SYS_CTRLER_PMU)
pmu_poll_adb();
#endif /* CONFIG_ADB_PMU */
#ifdef CONFIG_ADB_CUDA
if (sys_ctrler == SYS_CTRLER_CUDA)
cuda_poll();
#endif /* CONFIG_ADB_CUDA */
}
int xmon_write(void *ptr, int nb)
{
char *p = ptr;
int i, c, ct;
#ifdef CONFIG_SMP
static unsigned long xmon_write_lock;
int lock_wait = 1000000;
int locked;
while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
if (--lock_wait == 0)
break;
#endif
#ifdef CONFIG_BOOTX_TEXT
if (use_screen) {
/* write it on the screen */
for (i = 0; i < nb; ++i)
btext_drawchar(*p++);
goto out;
}
#endif
if (!scc_initialized)
xmon_init_scc();
ct = 0;
for (i = 0; i < nb; ++i) {
while ((*sccc & TXRDY) == 0)
do_poll_adb();
c = p[i];
if (c == '\n' && !ct) {
c = '\r';
ct = 1;
--i;
} else {
ct = 0;
}
buf_access();
*sccd = c;
eieio();
}
out:
#ifdef CONFIG_SMP
if (!locked)
clear_bit(0, &xmon_write_lock);
#endif
return nb;
}
int xmon_wants_key;
int xmon_adb_keycode;
#ifdef CONFIG_BOOTX_TEXT
static int xmon_adb_shiftstate;
static unsigned char xmon_keytab[128] =
"asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
"yt123465=97-80]o" /* 0x10 - 0x1f */
"u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
"\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
"\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
"\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
static unsigned char xmon_shift_keytab[128] =
"ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
"YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */
"U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
"\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
"\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
"\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
static int xmon_get_adb_key(void)
{
int k, t, on;
xmon_wants_key = 1;
for (;;) {
xmon_adb_keycode = -1;
t = 0;
on = 0;
do {
if (--t < 0) {
on = 1 - on;
btext_drawchar(on? 0xdb: 0x20);
btext_drawchar('\b');
t = 200000;
}
do_poll_adb();
} while (xmon_adb_keycode == -1);
k = xmon_adb_keycode;
if (on)
btext_drawstring(" \b");
/* test for shift keys */
if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
xmon_adb_shiftstate = (k & 0x80) == 0;
continue;
}
if (k >= 0x80)
continue; /* ignore up transitions */
k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
if (k != 0)
break;
}
xmon_wants_key = 0;
return k;
}
#endif /* CONFIG_BOOTX_TEXT */
int xmon_readchar(void)
{
#ifdef CONFIG_BOOTX_TEXT
if (use_screen)
return xmon_get_adb_key();
#endif
if (!scc_initialized)
xmon_init_scc();
while ((*sccc & RXRDY) == 0)
do_poll_adb();
buf_access();
return *sccd;
}
int xmon_read_poll(void)
{
if ((*sccc & RXRDY) == 0) {
do_poll_adb();
return -1;
}
buf_access();
return *sccd;
}
static unsigned char scc_inittab[] = {
13, 0, /* set baud rate divisor */
12, 1,
14, 1, /* baud rate gen enable, src=rtxc */
11, 0x50, /* clocks = br gen */
5, 0xea, /* tx 8 bits, assert DTR & RTS */
4, 0x46, /* x16 clock, 1 stop */
3, 0xc1, /* rx enable, 8 bits */
};
void xmon_init_scc(void)
{
if ( _machine == _MACH_chrp )
{
sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */
sccd[0] = 12; eieio(); /* DLL = 9600 baud */
sccd[1] = 0; eieio();
sccd[2] = 0; eieio(); /* FCR = 0 */
sccd[3] = 3; eieio(); /* LCR = 8N1 */
sccd[1] = 0; eieio(); /* IER = 0 */
}
else if ( _machine == _MACH_Pmac )
{
int i, x;
unsigned long timeout;
if (channel_node != 0)
pmac_call_feature(
PMAC_FTR_SCC_ENABLE,
channel_node,
PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
printk(KERN_INFO "Serial port locked ON by debugger !\n");
if (via_modem && channel_node != 0) {
unsigned int t0;
pmac_call_feature(
PMAC_FTR_MODEM_ENABLE,
channel_node, 0, 1);
printk(KERN_INFO "Modem powered up by debugger !\n");
t0 = get_tbl();
timeout = 3 * tb_ticks_per_sec;
if (timeout == 0)
/* assume 25MHz if tb_ticks_per_sec not set */
timeout = 75000000;
while (get_tbl() - t0 < timeout)
eieio();
}
/* use the B channel if requested */
if (xmon_use_sccb) {
sccc = (volatile unsigned char *)
((unsigned long)sccc & ~0x20);
sccd = sccc + 0x10;
}
for (i = 20000; i != 0; --i) {
x = *sccc; eieio();
}
*sccc = 9; eieio(); /* reset A or B side */
*sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
for (i = 0; i < sizeof(scc_inittab); ++i) {
*sccc = scc_inittab[i];
eieio();
}
}
scc_initialized = 1;
if (via_modem) {
for (;;) {
xmon_write("ATE1V1\r", 7);
if (xmon_expect("OK", 5)) {
xmon_write("ATA\r", 4);
if (xmon_expect("CONNECT", 40))
break;
}
xmon_write("+++", 3);
xmon_expect("OK", 3);
}
}
}
void xmon_enter(void)
{
#ifdef CONFIG_ADB_PMU
if (_machine == _MACH_Pmac) {
pmu_suspend();
}
#endif
}
void xmon_leave(void)
{
#ifdef CONFIG_ADB_PMU
if (_machine == _MACH_Pmac) {
pmu_resume();
}
#endif
}
/*
* Copyright (C) 1996 Paul Mackerras.
* Copyright (C) 2000 Dan Malek.
* Quick hack of Paul's code to make XMON work on 8xx processors. Lots
* of assumptions, like the SMC1 is used, it has been initialized by the
* loader at some point, and we can just stuff and suck bytes.
* We rely upon the 8xx uart driver to support us, as the interface
* changes between boot up and operational phases of the kernel.
*/
#include <linux/string.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/page.h>
#include <linux/kernel.h>
#include <asm/8xx_immap.h>
#include <asm/mpc8xx.h>
#include <asm/commproc.h>
#include "nonstdio.h"
extern int xmon_8xx_write(char *str, int nb);
extern int xmon_8xx_read_poll(void);
extern int xmon_8xx_read_char(void);
void xmon_map_scc(void)
{
cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
}
void xmon_init_scc(void);
int xmon_write(void *ptr, int nb)
{
return(xmon_8xx_write(ptr, nb));
}
int xmon_readchar(void)
{
return xmon_8xx_read_char();
}
int xmon_read_poll(void)
{
return(xmon_8xx_read_poll());
}
......@@ -744,6 +744,9 @@ void __init setup_arch(char **cmdline_p)
/* so udelay does something sensible, assume <= 1000 bogomips */
loops_per_jiffy = 500000000 / HZ;
if (ppc_md.init_early)
ppc_md.init_early();
#ifdef CONFIG_PPC_MULTIPLATFORM
/* This could be called "early setup arch", it must be done
* now because xmon need it
......
......@@ -505,16 +505,23 @@ static int
create_iface(struct device_node *np, struct device *dev)
{
unsigned long steps;
unsigned bsteps, tsize, i, nchan, addroffset;
unsigned bsteps, tsize, i, nchan;
struct keywest_iface* iface;
u32 *psteps, *prate;
u32 *psteps, *prate, *addrp;
int rc;
if (np->n_intrs < 1 || np->n_addrs < 1) {
printk(KERN_ERR "%s: Missing interrupt or address !\n",
if (np->n_intrs < 1) {
printk(KERN_ERR "%s: Missing interrupt !\n",
np->full_name);
return -ENODEV;
}
addrp = (u32 *)get_property(np, "AAPL,address", NULL);
if (addrp == NULL) {
printk(KERN_ERR "%s: Can't find address !\n",
np->full_name);
return -ENODEV;
}
if (pmac_low_i2c_lock(np))
return -ENODEV;
......@@ -525,13 +532,10 @@ create_iface(struct device_node *np, struct device *dev)
for (bsteps = 0; (steps & 0x01) == 0; bsteps++)
steps >>= 1;
if (np->parent->name[0] == 'u') {
if (np->parent->name[0] == 'u')
nchan = 2;
addroffset = 3;
} else {
addroffset = 0;
else
nchan = 1;
}
tsize = sizeof(struct keywest_iface) +
(sizeof(struct keywest_chan) + 4) * nchan;
......@@ -550,8 +554,7 @@ create_iface(struct device_node *np, struct device *dev)
iface->irq = np->intrs[0].line;
iface->channels = (struct keywest_chan *)
(((unsigned long)(iface + 1) + 3UL) & ~3UL);
iface->base = ioremap(np->addrs[0].address + addroffset,
np->addrs[0].size);
iface->base = ioremap(*addrp, 0x1000);
if (!iface->base) {
printk(KERN_ERR "i2c-keywest: can't map inteface !\n");
kfree(iface);
......
......@@ -127,39 +127,34 @@ struct adb_driver via_cuda_driver = {
#endif /* CONFIG_ADB */
#ifdef CONFIG_PPC
int __init
find_via_cuda(void)
int __init find_via_cuda(void)
{
int err;
struct adb_request req;
phys_addr_t taddr;
u32 *reg;
int err;
if (vias != 0)
return 1;
vias = find_devices("via-cuda");
vias = of_find_node_by_name(NULL, "via-cuda");
if (vias == 0)
return 0;
if (vias->next != 0)
printk(KERN_WARNING "Warning: only using 1st via-cuda\n");
#if 0
{ int i;
printk("find_via_cuda: node = %p, addrs =", vias->node);
for (i = 0; i < vias->n_addrs; ++i)
printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
printk(", intrs =");
for (i = 0; i < vias->n_intrs; ++i)
printk(" %x", vias->intrs[i].line);
printk("\n"); }
#endif
if (vias->n_addrs != 1 || vias->n_intrs != 1) {
printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n",
vias->n_addrs, vias->n_intrs);
if (vias->n_addrs < 1 || vias->n_intrs < 1)
return 0;
reg = (u32 *)get_property(vias, "reg", NULL);
if (reg == NULL) {
printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
goto fail;
}
taddr = of_translate_address(vias, reg);
if (taddr == 0) {
printk(KERN_ERR "via-cuda: Can't translate address !\n");
goto fail;
}
via = ioremap(taddr, 0x2000);
if (via == NULL) {
printk(KERN_ERR "via-cuda: Can't map address !\n");
goto fail;
}
via = ioremap(vias->addrs->address, 0x2000);
cuda_state = idle;
sys_ctrler = SYS_CTRLER_CUDA;
......@@ -185,6 +180,11 @@ find_via_cuda(void)
cuda_poll();
return 1;
fail:
of_node_put(vias);
vias = NULL;
return 0;
}
#endif /* CONFIG_PPC */
......
......@@ -147,6 +147,7 @@ static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
static int pmu_has_adb;
static struct device_node *gpio_node;
static unsigned char __iomem *gpio_reg = NULL;
static int gpio_irq = -1;
static int gpio_irq_enabled = -1;
......@@ -295,22 +296,26 @@ static struct backlight_controller pmu_backlight_controller = {
};
#endif /* CONFIG_PMAC_BACKLIGHT */
int
find_via_pmu(void)
int __init find_via_pmu(void)
{
phys_addr_t taddr;
u32 *reg;
if (via != 0)
return 1;
vias = find_devices("via-pmu");
if (vias == 0)
vias = of_find_node_by_name(NULL, "via-pmu");
if (vias == NULL)
return 0;
if (vias->next != 0)
printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
if (vias->n_addrs < 1 || vias->n_intrs < 1) {
printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
vias->n_addrs, vias->n_intrs);
if (vias->n_addrs < 1 || vias->n_intrs < 1)
return 0;
reg = (u32 *)get_property(vias, "reg", NULL);
if (reg == NULL) {
printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
goto fail;
}
taddr = of_translate_address(vias, reg);
if (taddr == 0) {
printk(KERN_ERR "via-pmu: Can't translate address !\n");
goto fail;
}
spin_lock_init(&pmu_lock);
......@@ -331,7 +336,8 @@ find_via_pmu(void)
pmu_kind = PMU_HEATHROW_BASED;
else if (device_is_compatible(vias->parent, "Keylargo")
|| device_is_compatible(vias->parent, "K2-Keylargo")) {
struct device_node *gpio, *gpiop;
struct device_node *gpiop;
phys_addr_t gaddr = 0;
pmu_kind = PMU_KEYLARGO_BASED;
pmu_has_adb = (find_type_devices("adb") != NULL);
......@@ -341,19 +347,24 @@ find_via_pmu(void)
PMU_INT_TICK |
PMU_INT_ENVIRONMENT;
gpiop = find_devices("gpio");
if (gpiop && gpiop->n_addrs) {
gpio_reg = ioremap(gpiop->addrs->address, 0x10);
gpio = find_devices("extint-gpio1");
if (gpio == NULL)
gpio = find_devices("pmu-interrupt");
if (gpio && gpio->parent == gpiop && gpio->n_intrs)
gpio_irq = gpio->intrs[0].line;
gpiop = of_find_node_by_name(NULL, "gpio");
if (gpiop) {
reg = (u32 *)get_property(gpiop, "reg", NULL);
if (reg)
gaddr = of_translate_address(gpiop, reg);
if (gaddr != 0)
gpio_reg = ioremap(gaddr, 0x10);
}
if (gpio_reg == NULL)
printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n");
} else
pmu_kind = PMU_UNKNOWN;
via = ioremap(vias->addrs->address, 0x2000);
via = ioremap(taddr, 0x2000);
if (via == NULL) {
printk(KERN_ERR "via-pmu: Can't map address !\n");
goto fail;
}
out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
out_8(&via[IFR], 0x7f); /* clear IFR */
......@@ -371,17 +382,19 @@ find_via_pmu(void)
sys_ctrler = SYS_CTRLER_PMU;
return 1;
fail:
of_node_put(vias);
vias = NULL;
return 0;
}
#ifdef CONFIG_ADB
static int
pmu_probe(void)
static int pmu_probe(void)
{
return vias == NULL? -ENODEV: 0;
}
static int __init
pmu_init(void)
static int __init pmu_init(void)
{
if (vias == NULL)
return -ENODEV;
......@@ -405,7 +418,7 @@ static int __init via_pmu_start(void)
bright_req_2.complete = 1;
batt_req.complete = 1;
#if defined(CONFIG_PPC32) && !defined(CONFIG_PPC_MERGE)
#ifndef CONFIG_PPC_MERGE
if (pmu_kind == PMU_KEYLARGO_BASED)
openpic_set_irq_priority(vias->intrs[0].line,
OPENPIC_PRIORITY_DEFAULT + 1);
......@@ -418,10 +431,22 @@ static int __init via_pmu_start(void)
return -EAGAIN;
}
if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {
if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1 ADB", (void *)0))
printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);
gpio_irq_enabled = 1;
if (pmu_kind == PMU_KEYLARGO_BASED) {
gpio_node = of_find_node_by_name(NULL, "extint-gpio1");
if (gpio_node == NULL)
gpio_node = of_find_node_by_name(NULL,
"pmu-interrupt");
if (gpio_node && gpio_node->n_intrs > 0)
gpio_irq = gpio_node->intrs[0].line;
if (gpio_irq != -1) {
if (request_irq(gpio_irq, gpio1_interrupt, 0,
"GPIO1 ADB", (void *)0))
printk(KERN_ERR "pmu: can't get irq %d"
" (GPIO1)\n", gpio_irq);
else
gpio_irq_enabled = 1;
}
}
/* Enable interrupts */
......@@ -1371,7 +1396,6 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
}
pmu_done(req);
} else {
#if defined(CONFIG_XMON) && !defined(CONFIG_PPC64)
if (len == 4 && data[1] == 0x2c) {
extern int xmon_wants_key, xmon_adb_keycode;
if (xmon_wants_key) {
......@@ -1379,7 +1403,6 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
return;
}
}
#endif /* defined(CONFIG_XMON) && !defined(CONFIG_PPC64) */
#ifdef CONFIG_ADB
/*
* XXX On the [23]400 the PMU gives us an up
......
......@@ -7,21 +7,22 @@
#define __PPC_BTEXT_H
#ifdef __KERNEL__
extern void btext_clearscreen(void);
extern void btext_flushscreen(void);
extern int boot_text_mapped;
extern int btext_initialize(struct device_node *np);
extern void map_boot_text(void);
extern void init_boot_display(void);
extern int btext_find_display(int allow_nonstdout);
extern void btext_update_display(unsigned long phys, int width, int height,
int depth, int pitch);
extern void btext_setup_display(int width, int height, int depth, int pitch,
unsigned long address);
extern void btext_prepare_BAT(void);
extern void btext_unmap(void);
extern void btext_drawchar(char c);
extern void btext_drawstring(const char *str);
extern void btext_drawhex(unsigned long v);
extern void btext_drawtext(const char *c, unsigned int len);
extern void btext_clearscreen(void);
extern void btext_flushscreen(void);
extern void btext_flushline(void);
#endif /* __KERNEL__ */
#endif /* __PPC_BTEXT_H */
......@@ -13,8 +13,8 @@
#include <linux/compiler.h>
#include <linux/init.h>
extern void (*udbg_putc)(unsigned char c);
extern unsigned char (*udbg_getc)(void);
extern void (*udbg_putc)(char c);
extern char (*udbg_getc)(void);
extern int (*udbg_getc_poll)(void);
extern void udbg_puts(const char *s);
......@@ -30,5 +30,8 @@ extern unsigned int udbg_probe_uart_speed(void __iomem *comport,
unsigned int clock);
struct device_node;
extern void udbg_init_scc(struct device_node *np);
extern void udbg_scc_init(int force_scc);
extern int udbg_adb_init(int force_btext);
extern void udbg_adb_init_early(void);
#endif /* _ASM_POWERPC_UDBG_H */
......@@ -17,7 +17,7 @@ extern unsigned long disp_BAT[2];
extern boot_infos_t disp_bi;
extern int boot_text_mapped;
extern void init_boot_display(void);
extern void btext_init(boot_infos_t *bi);
extern void btext_welcome(void);
extern void btext_prepare_BAT(void);
extern void btext_setup_display(int width, int height, int depth, int pitch,
......
......@@ -35,8 +35,10 @@ struct machdep_calls {
int (*get_irq)(struct pt_regs *);
/* A general init function, called by ppc_init in init/main.c.
May be NULL. */
May be NULL. DEPRECATED ! */
void (*init)(void);
/* For compatibility with merged platforms */
void (*init_early)(void);
void (*restart)(char *cmd);
void (*power_off)(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册