Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * udbg for zilog scc ports as found on Apple PowerMacs
0004  *
0005  * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
0006  */
0007 #include <linux/types.h>
0008 #include <linux/of.h>
0009 #include <asm/udbg.h>
0010 #include <asm/processor.h>
0011 #include <asm/io.h>
0012 #include <asm/pmac_feature.h>
0013 
0014 extern u8 real_readb(volatile u8 __iomem  *addr);
0015 extern void real_writeb(u8 data, volatile u8 __iomem *addr);
0016 
0017 #define SCC_TXRDY   4
0018 #define SCC_RXRDY   1
0019 
0020 static volatile u8 __iomem *sccc;
0021 static volatile u8 __iomem *sccd;
0022 
0023 static void udbg_scc_putc(char c)
0024 {
0025     if (sccc) {
0026         while ((in_8(sccc) & SCC_TXRDY) == 0)
0027             ;
0028         out_8(sccd,  c);
0029         if (c == '\n')
0030             udbg_scc_putc('\r');
0031     }
0032 }
0033 
0034 static int udbg_scc_getc_poll(void)
0035 {
0036     if (sccc) {
0037         if ((in_8(sccc) & SCC_RXRDY) != 0)
0038             return in_8(sccd);
0039         else
0040             return -1;
0041     }
0042     return -1;
0043 }
0044 
0045 static int udbg_scc_getc(void)
0046 {
0047     if (sccc) {
0048         while ((in_8(sccc) & SCC_RXRDY) == 0)
0049             ;
0050         return in_8(sccd);
0051     }
0052     return -1;
0053 }
0054 
0055 static unsigned char scc_inittab[] = {
0056     13, 0,      /* set baud rate divisor */
0057     12, 0,
0058     14, 1,      /* baud rate gen enable, src=rtxc */
0059     11, 0x50,       /* clocks = br gen */
0060     5,  0xea,       /* tx 8 bits, assert DTR & RTS */
0061     4,  0x46,       /* x16 clock, 1 stop */
0062     3,  0xc1,       /* rx enable, 8 bits */
0063 };
0064 
0065 void __init udbg_scc_init(int force_scc)
0066 {
0067     const u32 *reg;
0068     unsigned long addr;
0069     struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
0070     struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
0071     const char *path;
0072     int i;
0073 
0074     escc = of_find_node_by_name(NULL, "escc");
0075     if (escc == NULL)
0076         goto bail;
0077     macio = of_get_parent(escc);
0078     if (macio == NULL)
0079         goto bail;
0080     path = of_get_property(of_chosen, "linux,stdout-path", NULL);
0081     if (path != NULL)
0082         stdout = of_find_node_by_path(path);
0083     for_each_child_of_node(escc, ch) {
0084         if (ch == stdout)
0085             ch_def = of_node_get(ch);
0086         if (of_node_name_eq(ch, "ch-a"))
0087             ch_a = of_node_get(ch);
0088     }
0089     if (ch_def == NULL && !force_scc)
0090         goto bail;
0091 
0092     ch = ch_def ? ch_def : ch_a;
0093 
0094     /* Get address within mac-io ASIC */
0095     reg = of_get_property(escc, "reg", NULL);
0096     if (reg == NULL)
0097         goto bail;
0098     addr = reg[0];
0099 
0100     /* Get address of mac-io PCI itself */
0101     reg = of_get_property(macio, "assigned-addresses", NULL);
0102     if (reg == NULL)
0103         goto bail;
0104     addr += reg[2];
0105 
0106     /* Lock the serial port */
0107     pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
0108               PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
0109 
0110     if (ch == ch_a)
0111         addr += 0x20;
0112     sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
0113     sccc += addr & ~PAGE_MASK;
0114     sccd = sccc + 0x10;
0115 
0116     mb();
0117 
0118     for (i = 20000; i != 0; --i)
0119         in_8(sccc);
0120     out_8(sccc, 0x09);      /* reset A or B side */
0121     out_8(sccc, 0xc0);
0122 
0123     /* If SCC was the OF output port, read the BRG value, else
0124      * Setup for 38400 or 57600 8N1 depending on the machine
0125      */
0126     if (ch_def != NULL) {
0127         out_8(sccc, 13);
0128         scc_inittab[1] = in_8(sccc);
0129         out_8(sccc, 12);
0130         scc_inittab[3] = in_8(sccc);
0131     } else if (of_machine_is_compatible("RackMac1,1")
0132            || of_machine_is_compatible("RackMac1,2")
0133            || of_machine_is_compatible("MacRISC4")) {
0134         /* Xserves and G5s default to 57600 */
0135         scc_inittab[1] = 0;
0136         scc_inittab[3] = 0;
0137     } else {
0138         /* Others default to 38400 */
0139         scc_inittab[1] = 0;
0140         scc_inittab[3] = 1;
0141     }
0142 
0143     for (i = 0; i < sizeof(scc_inittab); ++i)
0144         out_8(sccc, scc_inittab[i]);
0145 
0146 
0147     udbg_putc = udbg_scc_putc;
0148     udbg_getc = udbg_scc_getc;
0149     udbg_getc_poll = udbg_scc_getc_poll;
0150 
0151     udbg_puts("Hello World !\n");
0152 
0153  bail:
0154     of_node_put(macio);
0155     of_node_put(escc);
0156     of_node_put(stdout);
0157     of_node_put(ch_def);
0158     of_node_put(ch_a);
0159 }
0160 
0161 #ifdef CONFIG_PPC64
0162 static void udbg_real_scc_putc(char c)
0163 {
0164     while ((real_readb(sccc) & SCC_TXRDY) == 0)
0165         ;
0166     real_writeb(c, sccd);
0167     if (c == '\n')
0168         udbg_real_scc_putc('\r');
0169 }
0170 
0171 void __init udbg_init_pmac_realmode(void)
0172 {
0173     sccc = (volatile u8 __iomem *)0x80013020ul;
0174     sccd = (volatile u8 __iomem *)0x80013030ul;
0175 
0176     udbg_putc = udbg_real_scc_putc;
0177     udbg_getc = NULL;
0178     udbg_getc_poll = NULL;
0179 }
0180 #endif /* CONFIG_PPC64 */