18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Joshua Henderson <joshua.henderson@microchip.com> 48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <asm/mach-pic32/pic32.h> 78c2ecf20Sopenharmony_ci#include <asm/fw/fw.h> 88c2ecf20Sopenharmony_ci#include <asm/setup.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "pic32mzda.h" 118c2ecf20Sopenharmony_ci#include "early_pin.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* Default early console parameters */ 148c2ecf20Sopenharmony_ci#define EARLY_CONSOLE_PORT 1 158c2ecf20Sopenharmony_ci#define EARLY_CONSOLE_BAUDRATE 115200 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define UART_ENABLE BIT(15) 188c2ecf20Sopenharmony_ci#define UART_ENABLE_RX BIT(12) 198c2ecf20Sopenharmony_ci#define UART_ENABLE_TX BIT(10) 208c2ecf20Sopenharmony_ci#define UART_TX_FULL BIT(9) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* UART1(x == 0) - UART6(x == 5) */ 238c2ecf20Sopenharmony_ci#define UART_BASE(x) ((x) * 0x0200) 248c2ecf20Sopenharmony_ci#define U_MODE(x) UART_BASE(x) 258c2ecf20Sopenharmony_ci#define U_STA(x) (UART_BASE(x) + 0x10) 268c2ecf20Sopenharmony_ci#define U_TXR(x) (UART_BASE(x) + 0x20) 278c2ecf20Sopenharmony_ci#define U_BRG(x) (UART_BASE(x) + 0x40) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void __iomem *uart_base; 308c2ecf20Sopenharmony_cistatic int console_port = -1; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int __init configure_uart_pins(int port) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci switch (port) { 358c2ecf20Sopenharmony_ci case 1: 368c2ecf20Sopenharmony_ci pic32_pps_input(IN_FUNC_U2RX, IN_RPB0); 378c2ecf20Sopenharmony_ci pic32_pps_output(OUT_FUNC_U2TX, OUT_RPG9); 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci case 5: 408c2ecf20Sopenharmony_ci pic32_pps_input(IN_FUNC_U6RX, IN_RPD0); 418c2ecf20Sopenharmony_ci pic32_pps_output(OUT_FUNC_U6TX, OUT_RPB8); 428c2ecf20Sopenharmony_ci break; 438c2ecf20Sopenharmony_ci default: 448c2ecf20Sopenharmony_ci return -1; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void __init configure_uart(int port, int baud) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci u32 pbclk; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci pbclk = pic32_get_pbclk(2); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci __raw_writel(0, uart_base + U_MODE(port)); 578c2ecf20Sopenharmony_ci __raw_writel(((pbclk / baud) / 16) - 1, uart_base + U_BRG(port)); 588c2ecf20Sopenharmony_ci __raw_writel(UART_ENABLE, uart_base + U_MODE(port)); 598c2ecf20Sopenharmony_ci __raw_writel(UART_ENABLE_TX | UART_ENABLE_RX, 608c2ecf20Sopenharmony_ci uart_base + PIC32_SET(U_STA(port))); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void __init setup_early_console(int port, int baud) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci if (configure_uart_pins(port)) 668c2ecf20Sopenharmony_ci return; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci console_port = port; 698c2ecf20Sopenharmony_ci configure_uart(console_port, baud); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic char * __init pic32_getcmdline(void) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * arch_mem_init() has not been called yet, so we don't have a real 768c2ecf20Sopenharmony_ci * command line setup if using CONFIG_CMDLINE_BOOL. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci#ifdef CONFIG_CMDLINE_OVERRIDE 798c2ecf20Sopenharmony_ci return CONFIG_CMDLINE; 808c2ecf20Sopenharmony_ci#else 818c2ecf20Sopenharmony_ci return fw_getcmdline(); 828c2ecf20Sopenharmony_ci#endif 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int __init get_port_from_cmdline(char *arch_cmdline) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci char *s; 888c2ecf20Sopenharmony_ci int port = -1; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (!arch_cmdline || *arch_cmdline == '\0') 918c2ecf20Sopenharmony_ci goto _out; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci s = strstr(arch_cmdline, "earlyprintk="); 948c2ecf20Sopenharmony_ci if (s) { 958c2ecf20Sopenharmony_ci s = strstr(s, "ttyS"); 968c2ecf20Sopenharmony_ci if (s) 978c2ecf20Sopenharmony_ci s += 4; 988c2ecf20Sopenharmony_ci else 998c2ecf20Sopenharmony_ci goto _out; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci port = (*s) - '0'; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci_out: 1058c2ecf20Sopenharmony_ci return port; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int __init get_baud_from_cmdline(char *arch_cmdline) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci char *s; 1118c2ecf20Sopenharmony_ci int baud = -1; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!arch_cmdline || *arch_cmdline == '\0') 1148c2ecf20Sopenharmony_ci goto _out; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci s = strstr(arch_cmdline, "earlyprintk="); 1178c2ecf20Sopenharmony_ci if (s) { 1188c2ecf20Sopenharmony_ci s = strstr(s, "ttyS"); 1198c2ecf20Sopenharmony_ci if (s) 1208c2ecf20Sopenharmony_ci s += 6; 1218c2ecf20Sopenharmony_ci else 1228c2ecf20Sopenharmony_ci goto _out; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci baud = 0; 1258c2ecf20Sopenharmony_ci while (*s >= '0' && *s <= '9') 1268c2ecf20Sopenharmony_ci baud = baud * 10 + *s++ - '0'; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci_out: 1308c2ecf20Sopenharmony_ci return baud; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_civoid __init fw_init_early_console(void) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci char *arch_cmdline = pic32_getcmdline(); 1368c2ecf20Sopenharmony_ci int baud, port; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci uart_base = ioremap(PIC32_BASE_UART, 0xc00); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci baud = get_baud_from_cmdline(arch_cmdline); 1418c2ecf20Sopenharmony_ci port = get_port_from_cmdline(arch_cmdline); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (port == -1) 1448c2ecf20Sopenharmony_ci port = EARLY_CONSOLE_PORT; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (baud == -1) 1478c2ecf20Sopenharmony_ci baud = EARLY_CONSOLE_BAUDRATE; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci setup_early_console(port, baud); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_civoid prom_putchar(char c) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci if (console_port >= 0) { 1558c2ecf20Sopenharmony_ci while (__raw_readl( 1568c2ecf20Sopenharmony_ci uart_base + U_STA(console_port)) & UART_TX_FULL) 1578c2ecf20Sopenharmony_ci ; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci __raw_writel(c, uart_base + U_TXR(console_port)); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci} 162