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