2874c5fd28
Based on 1 normalized pattern(s): 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 3029 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070032.746973796@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
181 lines
3.9 KiB
C
181 lines
3.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* udbg for zilog scc ports as found on Apple PowerMacs
|
|
*
|
|
* Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
|
|
*/
|
|
#include <linux/types.h>
|
|
#include <asm/udbg.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/io.h>
|
|
#include <asm/prom.h>
|
|
#include <asm/pmac_feature.h>
|
|
|
|
extern u8 real_readb(volatile u8 __iomem *addr);
|
|
extern void real_writeb(u8 data, volatile u8 __iomem *addr);
|
|
|
|
#define SCC_TXRDY 4
|
|
#define SCC_RXRDY 1
|
|
|
|
static volatile u8 __iomem *sccc;
|
|
static volatile u8 __iomem *sccd;
|
|
|
|
static void udbg_scc_putc(char c)
|
|
{
|
|
if (sccc) {
|
|
while ((in_8(sccc) & SCC_TXRDY) == 0)
|
|
;
|
|
out_8(sccd, c);
|
|
if (c == '\n')
|
|
udbg_scc_putc('\r');
|
|
}
|
|
}
|
|
|
|
static int udbg_scc_getc_poll(void)
|
|
{
|
|
if (sccc) {
|
|
if ((in_8(sccc) & SCC_RXRDY) != 0)
|
|
return in_8(sccd);
|
|
else
|
|
return -1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int udbg_scc_getc(void)
|
|
{
|
|
if (sccc) {
|
|
while ((in_8(sccc) & SCC_RXRDY) == 0)
|
|
;
|
|
return in_8(sccd);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static unsigned char scc_inittab[] = {
|
|
13, 0, /* set baud rate divisor */
|
|
12, 0,
|
|
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 udbg_scc_init(int force_scc)
|
|
{
|
|
const u32 *reg;
|
|
unsigned long addr;
|
|
struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
|
|
struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
|
|
const char *path;
|
|
int i;
|
|
|
|
escc = of_find_node_by_name(NULL, "escc");
|
|
if (escc == NULL)
|
|
goto bail;
|
|
macio = of_get_parent(escc);
|
|
if (macio == NULL)
|
|
goto bail;
|
|
path = of_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 (of_node_name_eq(ch, "ch-a"))
|
|
ch_a = of_node_get(ch);
|
|
}
|
|
if (ch_def == NULL && !force_scc)
|
|
goto bail;
|
|
|
|
ch = ch_def ? ch_def : ch_a;
|
|
|
|
/* Get address within mac-io ASIC */
|
|
reg = of_get_property(escc, "reg", NULL);
|
|
if (reg == NULL)
|
|
goto bail;
|
|
addr = reg[0];
|
|
|
|
/* Get address of mac-io PCI itself */
|
|
reg = of_get_property(macio, "assigned-addresses", NULL);
|
|
if (reg == NULL)
|
|
goto bail;
|
|
addr += reg[2];
|
|
|
|
/* Lock the serial port */
|
|
pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
|
|
PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
|
|
|
|
if (ch == ch_a)
|
|
addr += 0x20;
|
|
sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
|
|
sccc += addr & ~PAGE_MASK;
|
|
sccd = sccc + 0x10;
|
|
|
|
mb();
|
|
|
|
for (i = 20000; i != 0; --i)
|
|
in_8(sccc);
|
|
out_8(sccc, 0x09); /* reset A or B side */
|
|
out_8(sccc, 0xc0);
|
|
|
|
/* If SCC was the OF output port, read the BRG value, else
|
|
* Setup for 38400 or 57600 8N1 depending on the machine
|
|
*/
|
|
if (ch_def != NULL) {
|
|
out_8(sccc, 13);
|
|
scc_inittab[1] = in_8(sccc);
|
|
out_8(sccc, 12);
|
|
scc_inittab[3] = in_8(sccc);
|
|
} else if (of_machine_is_compatible("RackMac1,1")
|
|
|| of_machine_is_compatible("RackMac1,2")
|
|
|| of_machine_is_compatible("MacRISC4")) {
|
|
/* Xserves and G5s default to 57600 */
|
|
scc_inittab[1] = 0;
|
|
scc_inittab[3] = 0;
|
|
} else {
|
|
/* Others default to 38400 */
|
|
scc_inittab[1] = 0;
|
|
scc_inittab[3] = 1;
|
|
}
|
|
|
|
for (i = 0; i < sizeof(scc_inittab); ++i)
|
|
out_8(sccc, scc_inittab[i]);
|
|
|
|
|
|
udbg_putc = udbg_scc_putc;
|
|
udbg_getc = udbg_scc_getc;
|
|
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);
|
|
}
|
|
|
|
#ifdef CONFIG_PPC64
|
|
static void udbg_real_scc_putc(char c)
|
|
{
|
|
while ((real_readb(sccc) & SCC_TXRDY) == 0)
|
|
;
|
|
real_writeb(c, sccd);
|
|
if (c == '\n')
|
|
udbg_real_scc_putc('\r');
|
|
}
|
|
|
|
void __init udbg_init_pmac_realmode(void)
|
|
{
|
|
sccc = (volatile u8 __iomem *)0x80013020ul;
|
|
sccd = (volatile u8 __iomem *)0x80013030ul;
|
|
|
|
udbg_putc = udbg_real_scc_putc;
|
|
udbg_getc = NULL;
|
|
udbg_getc_poll = NULL;
|
|
}
|
|
#endif /* CONFIG_PPC64 */
|