18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * udbg for zilog scc ports as found on Apple PowerMacs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <asm/udbg.h> 98c2ecf20Sopenharmony_ci#include <asm/processor.h> 108c2ecf20Sopenharmony_ci#include <asm/io.h> 118c2ecf20Sopenharmony_ci#include <asm/prom.h> 128c2ecf20Sopenharmony_ci#include <asm/pmac_feature.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciextern u8 real_readb(volatile u8 __iomem *addr); 158c2ecf20Sopenharmony_ciextern void real_writeb(u8 data, volatile u8 __iomem *addr); 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define SCC_TXRDY 4 188c2ecf20Sopenharmony_ci#define SCC_RXRDY 1 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic volatile u8 __iomem *sccc; 218c2ecf20Sopenharmony_cistatic volatile u8 __iomem *sccd; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void udbg_scc_putc(char c) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (sccc) { 268c2ecf20Sopenharmony_ci while ((in_8(sccc) & SCC_TXRDY) == 0) 278c2ecf20Sopenharmony_ci ; 288c2ecf20Sopenharmony_ci out_8(sccd, c); 298c2ecf20Sopenharmony_ci if (c == '\n') 308c2ecf20Sopenharmony_ci udbg_scc_putc('\r'); 318c2ecf20Sopenharmony_ci } 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int udbg_scc_getc_poll(void) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci if (sccc) { 378c2ecf20Sopenharmony_ci if ((in_8(sccc) & SCC_RXRDY) != 0) 388c2ecf20Sopenharmony_ci return in_8(sccd); 398c2ecf20Sopenharmony_ci else 408c2ecf20Sopenharmony_ci return -1; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci return -1; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int udbg_scc_getc(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci if (sccc) { 488c2ecf20Sopenharmony_ci while ((in_8(sccc) & SCC_RXRDY) == 0) 498c2ecf20Sopenharmony_ci ; 508c2ecf20Sopenharmony_ci return in_8(sccd); 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci return -1; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic unsigned char scc_inittab[] = { 568c2ecf20Sopenharmony_ci 13, 0, /* set baud rate divisor */ 578c2ecf20Sopenharmony_ci 12, 0, 588c2ecf20Sopenharmony_ci 14, 1, /* baud rate gen enable, src=rtxc */ 598c2ecf20Sopenharmony_ci 11, 0x50, /* clocks = br gen */ 608c2ecf20Sopenharmony_ci 5, 0xea, /* tx 8 bits, assert DTR & RTS */ 618c2ecf20Sopenharmony_ci 4, 0x46, /* x16 clock, 1 stop */ 628c2ecf20Sopenharmony_ci 3, 0xc1, /* rx enable, 8 bits */ 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_civoid udbg_scc_init(int force_scc) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci const u32 *reg; 688c2ecf20Sopenharmony_ci unsigned long addr; 698c2ecf20Sopenharmony_ci struct device_node *stdout = NULL, *escc = NULL, *macio = NULL; 708c2ecf20Sopenharmony_ci struct device_node *ch, *ch_def = NULL, *ch_a = NULL; 718c2ecf20Sopenharmony_ci const char *path; 728c2ecf20Sopenharmony_ci int i; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci escc = of_find_node_by_name(NULL, "escc"); 758c2ecf20Sopenharmony_ci if (escc == NULL) 768c2ecf20Sopenharmony_ci goto bail; 778c2ecf20Sopenharmony_ci macio = of_get_parent(escc); 788c2ecf20Sopenharmony_ci if (macio == NULL) 798c2ecf20Sopenharmony_ci goto bail; 808c2ecf20Sopenharmony_ci path = of_get_property(of_chosen, "linux,stdout-path", NULL); 818c2ecf20Sopenharmony_ci if (path != NULL) 828c2ecf20Sopenharmony_ci stdout = of_find_node_by_path(path); 838c2ecf20Sopenharmony_ci for_each_child_of_node(escc, ch) { 848c2ecf20Sopenharmony_ci if (ch == stdout) 858c2ecf20Sopenharmony_ci ch_def = of_node_get(ch); 868c2ecf20Sopenharmony_ci if (of_node_name_eq(ch, "ch-a")) 878c2ecf20Sopenharmony_ci ch_a = of_node_get(ch); 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci if (ch_def == NULL && !force_scc) 908c2ecf20Sopenharmony_ci goto bail; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ch = ch_def ? ch_def : ch_a; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* Get address within mac-io ASIC */ 958c2ecf20Sopenharmony_ci reg = of_get_property(escc, "reg", NULL); 968c2ecf20Sopenharmony_ci if (reg == NULL) 978c2ecf20Sopenharmony_ci goto bail; 988c2ecf20Sopenharmony_ci addr = reg[0]; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Get address of mac-io PCI itself */ 1018c2ecf20Sopenharmony_ci reg = of_get_property(macio, "assigned-addresses", NULL); 1028c2ecf20Sopenharmony_ci if (reg == NULL) 1038c2ecf20Sopenharmony_ci goto bail; 1048c2ecf20Sopenharmony_ci addr += reg[2]; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* Lock the serial port */ 1078c2ecf20Sopenharmony_ci pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch, 1088c2ecf20Sopenharmony_ci PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (ch == ch_a) 1118c2ecf20Sopenharmony_ci addr += 0x20; 1128c2ecf20Sopenharmony_ci sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ; 1138c2ecf20Sopenharmony_ci sccc += addr & ~PAGE_MASK; 1148c2ecf20Sopenharmony_ci sccd = sccc + 0x10; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci mb(); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci for (i = 20000; i != 0; --i) 1198c2ecf20Sopenharmony_ci in_8(sccc); 1208c2ecf20Sopenharmony_ci out_8(sccc, 0x09); /* reset A or B side */ 1218c2ecf20Sopenharmony_ci out_8(sccc, 0xc0); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* If SCC was the OF output port, read the BRG value, else 1248c2ecf20Sopenharmony_ci * Setup for 38400 or 57600 8N1 depending on the machine 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci if (ch_def != NULL) { 1278c2ecf20Sopenharmony_ci out_8(sccc, 13); 1288c2ecf20Sopenharmony_ci scc_inittab[1] = in_8(sccc); 1298c2ecf20Sopenharmony_ci out_8(sccc, 12); 1308c2ecf20Sopenharmony_ci scc_inittab[3] = in_8(sccc); 1318c2ecf20Sopenharmony_ci } else if (of_machine_is_compatible("RackMac1,1") 1328c2ecf20Sopenharmony_ci || of_machine_is_compatible("RackMac1,2") 1338c2ecf20Sopenharmony_ci || of_machine_is_compatible("MacRISC4")) { 1348c2ecf20Sopenharmony_ci /* Xserves and G5s default to 57600 */ 1358c2ecf20Sopenharmony_ci scc_inittab[1] = 0; 1368c2ecf20Sopenharmony_ci scc_inittab[3] = 0; 1378c2ecf20Sopenharmony_ci } else { 1388c2ecf20Sopenharmony_ci /* Others default to 38400 */ 1398c2ecf20Sopenharmony_ci scc_inittab[1] = 0; 1408c2ecf20Sopenharmony_ci scc_inittab[3] = 1; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(scc_inittab); ++i) 1448c2ecf20Sopenharmony_ci out_8(sccc, scc_inittab[i]); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci udbg_putc = udbg_scc_putc; 1488c2ecf20Sopenharmony_ci udbg_getc = udbg_scc_getc; 1498c2ecf20Sopenharmony_ci udbg_getc_poll = udbg_scc_getc_poll; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci udbg_puts("Hello World !\n"); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci bail: 1548c2ecf20Sopenharmony_ci of_node_put(macio); 1558c2ecf20Sopenharmony_ci of_node_put(escc); 1568c2ecf20Sopenharmony_ci of_node_put(stdout); 1578c2ecf20Sopenharmony_ci of_node_put(ch_def); 1588c2ecf20Sopenharmony_ci of_node_put(ch_a); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 1628c2ecf20Sopenharmony_cistatic void udbg_real_scc_putc(char c) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci while ((real_readb(sccc) & SCC_TXRDY) == 0) 1658c2ecf20Sopenharmony_ci ; 1668c2ecf20Sopenharmony_ci real_writeb(c, sccd); 1678c2ecf20Sopenharmony_ci if (c == '\n') 1688c2ecf20Sopenharmony_ci udbg_real_scc_putc('\r'); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_civoid __init udbg_init_pmac_realmode(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci sccc = (volatile u8 __iomem *)0x80013020ul; 1748c2ecf20Sopenharmony_ci sccd = (volatile u8 __iomem *)0x80013030ul; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci udbg_putc = udbg_real_scc_putc; 1778c2ecf20Sopenharmony_ci udbg_getc = NULL; 1788c2ecf20Sopenharmony_ci udbg_getc_poll = NULL; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */ 181