1 /* 2 * Joshua Henderson <joshua.henderson@microchip.com> 3 * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. 4 * 5 * This program is free software; you can distribute it and/or modify it 6 * under the terms of the GNU General Public License (Version 2) as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * for more details. 13 */ 14 #include <asm/mach-pic32/pic32.h> 15 #include <asm/fw/fw.h> 16 17 #include "pic32mzda.h" 18 #include "early_pin.h" 19 20 /* Default early console parameters */ 21 #define EARLY_CONSOLE_PORT 1 22 #define EARLY_CONSOLE_BAUDRATE 115200 23 24 #define UART_ENABLE BIT(15) 25 #define UART_ENABLE_RX BIT(12) 26 #define UART_ENABLE_TX BIT(10) 27 #define UART_TX_FULL BIT(9) 28 29 /* UART1(x == 0) - UART6(x == 5) */ 30 #define UART_BASE(x) ((x) * 0x0200) 31 #define U_MODE(x) UART_BASE(x) 32 #define U_STA(x) (UART_BASE(x) + 0x10) 33 #define U_TXR(x) (UART_BASE(x) + 0x20) 34 #define U_BRG(x) (UART_BASE(x) + 0x40) 35 36 static void __iomem *uart_base; 37 static char console_port = -1; 38 39 static int __init configure_uart_pins(int port) 40 { 41 switch (port) { 42 case 1: 43 pic32_pps_input(IN_FUNC_U2RX, IN_RPB0); 44 pic32_pps_output(OUT_FUNC_U2TX, OUT_RPG9); 45 break; 46 case 5: 47 pic32_pps_input(IN_FUNC_U6RX, IN_RPD0); 48 pic32_pps_output(OUT_FUNC_U6TX, OUT_RPB8); 49 break; 50 default: 51 return -1; 52 } 53 54 return 0; 55 } 56 57 static void __init configure_uart(char port, int baud) 58 { 59 u32 pbclk; 60 61 pbclk = pic32_get_pbclk(2); 62 63 __raw_writel(0, uart_base + U_MODE(port)); 64 __raw_writel(((pbclk / baud) / 16) - 1, uart_base + U_BRG(port)); 65 __raw_writel(UART_ENABLE, uart_base + U_MODE(port)); 66 __raw_writel(UART_ENABLE_TX | UART_ENABLE_RX, 67 uart_base + PIC32_SET(U_STA(port))); 68 } 69 70 static void __init setup_early_console(char port, int baud) 71 { 72 if (configure_uart_pins(port)) 73 return; 74 75 console_port = port; 76 configure_uart(console_port, baud); 77 } 78 79 static char * __init pic32_getcmdline(void) 80 { 81 /* 82 * arch_mem_init() has not been called yet, so we don't have a real 83 * command line setup if using CONFIG_CMDLINE_BOOL. 84 */ 85 #ifdef CONFIG_CMDLINE_OVERRIDE 86 return CONFIG_CMDLINE; 87 #else 88 return fw_getcmdline(); 89 #endif 90 } 91 92 static int __init get_port_from_cmdline(char *arch_cmdline) 93 { 94 char *s; 95 int port = -1; 96 97 if (!arch_cmdline || *arch_cmdline == '\0') 98 goto _out; 99 100 s = strstr(arch_cmdline, "earlyprintk="); 101 if (s) { 102 s = strstr(s, "ttyS"); 103 if (s) 104 s += 4; 105 else 106 goto _out; 107 108 port = (*s) - '0'; 109 } 110 111 _out: 112 return port; 113 } 114 115 static int __init get_baud_from_cmdline(char *arch_cmdline) 116 { 117 char *s; 118 int baud = -1; 119 120 if (!arch_cmdline || *arch_cmdline == '\0') 121 goto _out; 122 123 s = strstr(arch_cmdline, "earlyprintk="); 124 if (s) { 125 s = strstr(s, "ttyS"); 126 if (s) 127 s += 6; 128 else 129 goto _out; 130 131 baud = 0; 132 while (*s >= '0' && *s <= '9') 133 baud = baud * 10 + *s++ - '0'; 134 } 135 136 _out: 137 return baud; 138 } 139 140 void __init fw_init_early_console(char port) 141 { 142 char *arch_cmdline = pic32_getcmdline(); 143 int baud = -1; 144 145 uart_base = ioremap_nocache(PIC32_BASE_UART, 0xc00); 146 147 baud = get_baud_from_cmdline(arch_cmdline); 148 if (port == -1) 149 port = get_port_from_cmdline(arch_cmdline); 150 151 if (port == -1) 152 port = EARLY_CONSOLE_PORT; 153 154 if (baud == -1) 155 baud = EARLY_CONSOLE_BAUDRATE; 156 157 setup_early_console(port, baud); 158 } 159 160 int prom_putchar(char c) 161 { 162 if (console_port >= 0) { 163 while (__raw_readl( 164 uart_base + U_STA(console_port)) & UART_TX_FULL) 165 ; 166 167 __raw_writel(c, uart_base + U_TXR(console_port)); 168 } 169 170 return 1; 171 } 172