Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | /* * udbg for for zilog scc ports as found on Apple PowerMacs * * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp * * 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. */ #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) { 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; 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; /* Get address within mac-io ASIC */ reg = (u32 *)get_property(escc, "reg", NULL); if (reg == NULL) goto bail; addr = reg[0]; /* Get address of mac-io PCI itself */ reg = (u32 *)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); /* Setup for 57600 8N1 */ 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) x = in_8(sccc); out_8(sccc, 0x09); /* reset A or B side */ out_8(sccc, 0xc0); 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 */ |