linux/arch/powerpc/platforms/powermac/udbg_scc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * udbg for zilog scc ports as found on Apple PowerMacs
   4 *
   5 * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
   6 */
   7#include <linux/types.h>
   8#include <asm/udbg.h>
   9#include <asm/processor.h>
  10#include <asm/io.h>
  11#include <asm/prom.h>
  12#include <asm/pmac_feature.h>
  13
  14extern u8 real_readb(volatile u8 __iomem  *addr);
  15extern void real_writeb(u8 data, volatile u8 __iomem *addr);
  16
  17#define SCC_TXRDY       4
  18#define SCC_RXRDY       1
  19
  20static volatile u8 __iomem *sccc;
  21static volatile u8 __iomem *sccd;
  22
  23static void udbg_scc_putc(char c)
  24{
  25        if (sccc) {
  26                while ((in_8(sccc) & SCC_TXRDY) == 0)
  27                        ;
  28                out_8(sccd,  c);
  29                if (c == '\n')
  30                        udbg_scc_putc('\r');
  31        }
  32}
  33
  34static int udbg_scc_getc_poll(void)
  35{
  36        if (sccc) {
  37                if ((in_8(sccc) & SCC_RXRDY) != 0)
  38                        return in_8(sccd);
  39                else
  40                        return -1;
  41        }
  42        return -1;
  43}
  44
  45static int udbg_scc_getc(void)
  46{
  47        if (sccc) {
  48                while ((in_8(sccc) & SCC_RXRDY) == 0)
  49                        ;
  50                return in_8(sccd);
  51        }
  52        return -1;
  53}
  54
  55static unsigned char scc_inittab[] = {
  56    13, 0,              /* set baud rate divisor */
  57    12, 0,
  58    14, 1,              /* baud rate gen enable, src=rtxc */
  59    11, 0x50,           /* clocks = br gen */
  60    5,  0xea,           /* tx 8 bits, assert DTR & RTS */
  61    4,  0x46,           /* x16 clock, 1 stop */
  62    3,  0xc1,           /* rx enable, 8 bits */
  63};
  64
  65void udbg_scc_init(int force_scc)
  66{
  67        const u32 *reg;
  68        unsigned long addr;
  69        struct device_node *stdout = NULL, *escc = NULL, *macio = NULL;
  70        struct device_node *ch, *ch_def = NULL, *ch_a = NULL;
  71        const char *path;
  72        int i;
  73
  74        escc = of_find_node_by_name(NULL, "escc");
  75        if (escc == NULL)
  76                goto bail;
  77        macio = of_get_parent(escc);
  78        if (macio == NULL)
  79                goto bail;
  80        path = of_get_property(of_chosen, "linux,stdout-path", NULL);
  81        if (path != NULL)
  82                stdout = of_find_node_by_path(path);
  83        for_each_child_of_node(escc, ch) {
  84                if (ch == stdout)
  85                        ch_def = of_node_get(ch);
  86                if (of_node_name_eq(ch, "ch-a"))
  87                        ch_a = of_node_get(ch);
  88        }
  89        if (ch_def == NULL && !force_scc)
  90                goto bail;
  91
  92        ch = ch_def ? ch_def : ch_a;
  93
  94        /* Get address within mac-io ASIC */
  95        reg = of_get_property(escc, "reg", NULL);
  96        if (reg == NULL)
  97                goto bail;
  98        addr = reg[0];
  99
 100        /* Get address of mac-io PCI itself */
 101        reg = of_get_property(macio, "assigned-addresses", NULL);
 102        if (reg == NULL)
 103                goto bail;
 104        addr += reg[2];
 105
 106        /* Lock the serial port */
 107        pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
 108                          PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
 109
 110        if (ch == ch_a)
 111                addr += 0x20;
 112        sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
 113        sccc += addr & ~PAGE_MASK;
 114        sccd = sccc + 0x10;
 115
 116        mb();
 117
 118        for (i = 20000; i != 0; --i)
 119                in_8(sccc);
 120        out_8(sccc, 0x09);              /* reset A or B side */
 121        out_8(sccc, 0xc0);
 122
 123        /* If SCC was the OF output port, read the BRG value, else
 124         * Setup for 38400 or 57600 8N1 depending on the machine
 125         */
 126        if (ch_def != NULL) {
 127                out_8(sccc, 13);
 128                scc_inittab[1] = in_8(sccc);
 129                out_8(sccc, 12);
 130                scc_inittab[3] = in_8(sccc);
 131        } else if (of_machine_is_compatible("RackMac1,1")
 132                   || of_machine_is_compatible("RackMac1,2")
 133                   || of_machine_is_compatible("MacRISC4")) {
 134                /* Xserves and G5s default to 57600 */
 135                scc_inittab[1] = 0;
 136                scc_inittab[3] = 0;
 137        } else {
 138                /* Others default to 38400 */
 139                scc_inittab[1] = 0;
 140                scc_inittab[3] = 1;
 141        }
 142
 143        for (i = 0; i < sizeof(scc_inittab); ++i)
 144                out_8(sccc, scc_inittab[i]);
 145
 146
 147        udbg_putc = udbg_scc_putc;
 148        udbg_getc = udbg_scc_getc;
 149        udbg_getc_poll = udbg_scc_getc_poll;
 150
 151        udbg_puts("Hello World !\n");
 152
 153 bail:
 154        of_node_put(macio);
 155        of_node_put(escc);
 156        of_node_put(stdout);
 157        of_node_put(ch_def);
 158        of_node_put(ch_a);
 159}
 160
 161#ifdef CONFIG_PPC64
 162static void udbg_real_scc_putc(char c)
 163{
 164        while ((real_readb(sccc) & SCC_TXRDY) == 0)
 165                ;
 166        real_writeb(c, sccd);
 167        if (c == '\n')
 168                udbg_real_scc_putc('\r');
 169}
 170
 171void __init udbg_init_pmac_realmode(void)
 172{
 173        sccc = (volatile u8 __iomem *)0x80013020ul;
 174        sccd = (volatile u8 __iomem *)0x80013030ul;
 175
 176        udbg_putc = udbg_real_scc_putc;
 177        udbg_getc = NULL;
 178        udbg_getc_poll = NULL;
 179}
 180#endif /* CONFIG_PPC64 */
 181